Skip to content

Commit 7f116cb

Browse files
committed
feat(tanstackstart): Add @sentry/tanstackstart-react package and make @sentry/tanstackstart package a utility package
1 parent c27a09a commit 7f116cb

30 files changed

+367
-161
lines changed

.craft.yml

+3
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ targets:
111111
- name: npm
112112
id: '@sentry/tanstackstart'
113113
includeNames: /^sentry-tanstackstart-\d.*\.tgz$/
114+
- name: npm
115+
id: '@sentry/tanstackstart-react'
116+
includeNames: /^sentry-tanstackstart-react-\d.*\.tgz$/
114117
- name: npm
115118
id: '@sentry/gatsby'
116119
includeNames: /^sentry-gatsby-\d.*\.tgz$/

dev-packages/e2e-tests/verdaccio-config/config.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ packages:
176176
unpublish: $all
177177
# proxy: npmjs # Don't proxy for E2E tests!
178178

179+
'@sentry/tanstackstart-react':
180+
access: $all
181+
publish: $all
182+
unpublish: $all
183+
# proxy: npmjs # Don't proxy for E2E tests!
184+
179185
'@sentry/types':
180186
access: $all
181187
publish: $all

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
"packages/svelte",
8181
"packages/sveltekit",
8282
"packages/tanstackstart",
83+
"packages/tanstackstart-react",
8384
"packages/types",
8485
"packages/typescript",
8586
"packages/vercel-edge",
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
node: true,
5+
},
6+
parserOptions: {
7+
jsx: true,
8+
},
9+
extends: ['../../.eslintrc.js'],
10+
};

packages/tanstackstart-react/LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Functional Software, Inc. dba Sentry
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9+
of the Software, and to permit persons to whom the Software is furnished to do
10+
so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<p align="center">
2+
<a href="https://sentry.io/?utm_source=github&utm_medium=logo" target="_blank">
3+
<img src="https://sentry-brand.storage.googleapis.com/sentry-wordmark-dark-280x84.png" alt="Sentry" width="280" height="84">
4+
</a>
5+
</p>
6+
7+
# Official Sentry SDK for TanStack Start React (Alpha)
8+
9+
[![npm version](https://img.shields.io/npm/v/@sentry/tanstackstart-react.svg)](https://www.npmjs.com/package/@sentry/tanstackstart-react)
10+
[![npm dm](https://img.shields.io/npm/dm/@sentry/tanstackstart-react.svg)](https://www.npmjs.com/package/@sentry/tanstackstart-react)
11+
[![npm dt](https://img.shields.io/npm/dt/@sentry/tanstackstart-react.svg)](https://www.npmjs.com/package/@sentry/tanstackstart-react)
12+
13+
> NOTICE: This package is in alpha state and may be subject to breaking changes.
14+
15+
## Getting Started
16+
17+
This SDK does not have docs yet. Stay tuned.
18+
19+
## Compatibility
20+
21+
The minimum supported version of TanStack Start is `1.111.12`.
22+
23+
## Custom Usage
24+
25+
To set context information or to send manual events, you can use `@sentry/tanstackstart-react` as follows:
26+
27+
```ts
28+
import * as Sentry from '@sentry/tanstackstart-react';
29+
30+
// Set user information, as well as tags and further extras
31+
Sentry.setTag('user_mode', 'admin');
32+
Sentry.setUser({ id: '4711' });
33+
Sentry.setContext('application_area', { location: 'checkout' });
34+
35+
// Add a breadcrumb for future events
36+
Sentry.addBreadcrumb({
37+
message: '"Add to cart" clicked',
38+
// ...
39+
});
40+
41+
// Capture exceptions or messages
42+
Sentry.captureException(new Error('Oh no.'));
43+
Sentry.captureMessage('Hello, world!');
44+
```
45+
46+
## Links
47+
48+
<!-- - [Official SDK Docs](https://docs.sentry.io/platforms/javascript/guides/tanstackstart-react/) -->
49+
50+
- [Sentry.io](https://sentry.io/?utm_source=github&utm_medium=npm_tanstackstartreact)
51+
- [Sentry Discord Server](https://discord.gg/Ww9hbqr)
52+
- [Stack Overflow](https://stackoverflow.com/questions/tagged/sentry)
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
{
2+
"name": "@sentry/tanstackstart-react",
3+
"version": "9.5.0",
4+
"description": "Official Sentry SDK for TanStack Start React",
5+
"repository": "git://github.com/getsentry/sentry-javascript.git",
6+
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/tanstackstart-react",
7+
"author": "Sentry",
8+
"license": "MIT",
9+
"engines": {
10+
"node": ">=18"
11+
},
12+
"main": "build/cjs/index.server.js",
13+
"module": "build/esm/index.server.js",
14+
"types": "build/types/index.types.d.ts",
15+
"files": [
16+
"/build"
17+
],
18+
"exports": {
19+
"./package.json": "./package.json",
20+
".": {
21+
"types": "./build/types/index.types.d.ts",
22+
"browser": {
23+
"import": "./build/esm/index.client.js",
24+
"require": "./build/cjs/index.client.js"
25+
},
26+
"node": {
27+
"import": "./build/esm/index.server.js",
28+
"require": "./build/cjs/index.server.js"
29+
}
30+
},
31+
"./import": {
32+
"import": {
33+
"default": "./build/import-hook.mjs"
34+
}
35+
},
36+
"./loader": {
37+
"import": {
38+
"default": "./build/loader-hook.mjs"
39+
}
40+
}
41+
},
42+
"typesVersions": {
43+
"<5.0": {
44+
"build/npm/types/index.d.ts": [
45+
"build/npm/types-ts3.8/index.d.ts"
46+
]
47+
}
48+
},
49+
"publishConfig": {
50+
"access": "public"
51+
},
52+
"dependencies": {
53+
"@opentelemetry/api": "^1.9.0",
54+
"@opentelemetry/semantic-conventions": "^1.30.0",
55+
"@sentry-internal/browser-utils": "9.5.0",
56+
"@sentry/core": "9.5.0",
57+
"@sentry/node": "9.5.0",
58+
"@sentry/opentelemetry": "9.5.0",
59+
"@sentry/react": "9.5.0"
60+
},
61+
"scripts": {
62+
"build": "run-p build:transpile build:types",
63+
"build:dev": "yarn build",
64+
"build:transpile": "rollup -c rollup.npm.config.mjs",
65+
"build:types": "run-s build:types:core build:types:downlevel",
66+
"build:types:core": "tsc -p tsconfig.types.json",
67+
"build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8",
68+
"build:watch": "run-p build:transpile:watch build:types:watch",
69+
"build:dev:watch": "yarn build:watch",
70+
"build:transpile:watch": "nodemon --ext ts --watch src scripts/buildRollup.ts",
71+
"build:types:watch": "tsc -p tsconfig.types.json --watch",
72+
"build:tarball": "npm pack",
73+
"circularDepCheck": "madge --circular src/index.client.ts && madge --circular src/index.server.ts && madge --circular src/index.types.ts",
74+
"clean": "rimraf build coverage sentry-tanstackstart-react-*.tgz",
75+
"fix": "eslint . --format stylish --fix",
76+
"lint": "eslint . --format stylish",
77+
"test": "yarn test:unit",
78+
"test:unit": "vitest run",
79+
"test:watch": "vitest --watch",
80+
"yalc:publish": "yalc publish --push --sig"
81+
},
82+
"volta": {
83+
"extends": "../../package.json"
84+
},
85+
"sideEffects": false
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { makeBaseNPMConfig, makeNPMConfigVariants, makeOtelLoaders } from '@sentry-internal/rollup-utils';
2+
3+
export default [
4+
...makeNPMConfigVariants(
5+
makeBaseNPMConfig({
6+
entrypoints: ['src/index.server.ts', 'src/index.client.ts', 'src/client/index.ts', 'src/server/index.ts'],
7+
}),
8+
),
9+
...makeOtelLoaders('./build', 'sentry-node'),
10+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from '@sentry/react';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* A middleware handler that can be passed to TanStack Start's `createMiddleware().server(...)` method as [global middleware](https://tanstack.com/start/latest/docs/framework/react/middleware#global-middleware) for instrumenting server functions.
3+
*/
4+
export function sentryGlobalServerMiddlewareHandler() {
5+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6+
return function <T>(server: { next: (...args: any[]) => T }): T {
7+
return server.next();
8+
};
9+
}
10+
11+
/**
12+
* Wraps a TanStack Start stream handler with Sentry instrumentation that can be passed to `createStartHandler(...)`.
13+
*/
14+
export function wrapStreamHandlerWithSentry<H>(handler: H): H {
15+
return handler;
16+
}
17+
18+
/**
19+
* Wraps the create root route function with Sentry for server-client tracing with SSR.
20+
*/
21+
export function wrapCreateRootRouteWithSentry<F>(createRootRoute: F): F {
22+
return createRootRoute;
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* Wraps a TanStack Start config.
3+
*/
4+
export function wrapVinxiConfigWithSentry<C>(
5+
config: C,
6+
// TODO: Expand this type in the future. Right now it is just so that TS doesn't complain for our users when they copy paste from the docs.
7+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
8+
sentryBuildOptions: {
9+
org?: string;
10+
project?: string;
11+
silent?: boolean;
12+
authToken?: boolean;
13+
} = {},
14+
): C {
15+
return config;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './client';
2+
export * from './common';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './config';
2+
export * from './server';
3+
export * from './common';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// We export everything from both the client part of the SDK and from the server part. Some of the exports collide,
2+
// which is not allowed, unless we redefine the colliding exports in this file - which we do below.
3+
export * from './config';
4+
export * from './client';
5+
export * from './server';
6+
export * from './common';
7+
8+
import type { Client, Integration, Options, StackParser } from '@sentry/core';
9+
10+
import type * as clientSdk from './client';
11+
import type * as serverSdk from './server';
12+
13+
/** Initializes Sentry TanStack Start SDK */
14+
export declare function init(options: Options | clientSdk.BrowserOptions | serverSdk.NodeOptions): Client | undefined;
15+
16+
export declare const linkedErrorsIntegration: typeof clientSdk.linkedErrorsIntegration;
17+
export declare const contextLinesIntegration: typeof clientSdk.contextLinesIntegration;
18+
19+
export declare const getDefaultIntegrations: (options: Options) => Integration[];
20+
export declare const defaultStackParser: StackParser;
21+
22+
export declare function getSentryRelease(fallback?: string): string | undefined;
23+
24+
export declare const ErrorBoundary: typeof clientSdk.ErrorBoundary;
25+
export declare const createReduxEnhancer: typeof clientSdk.createReduxEnhancer;
26+
export declare const showReportDialog: typeof clientSdk.showReportDialog;
27+
export declare const withErrorBoundary: typeof clientSdk.withErrorBoundary;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
export * from '@sentry/node';
2+
3+
/**
4+
* A passthrough error boundary for the server that doesn't depend on any react. Error boundaries don't catch SSR errors
5+
* so they should simply be a passthrough.
6+
*/
7+
export const ErrorBoundary = (props: React.PropsWithChildren<unknown>): React.ReactNode => {
8+
if (!props.children) {
9+
return null;
10+
}
11+
12+
if (typeof props.children === 'function') {
13+
return (props.children as () => React.ReactNode)();
14+
}
15+
16+
return props.children;
17+
};
18+
19+
/**
20+
* A passthrough redux enhancer for the server that doesn't depend on anything from the `@sentry/react` package.
21+
*/
22+
export function createReduxEnhancer() {
23+
return (createStore: unknown) => createStore;
24+
}
25+
26+
/**
27+
* A passthrough error boundary wrapper for the server that doesn't depend on any react. Error boundaries don't catch
28+
* SSR errors so they should simply be a passthrough.
29+
*/
30+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
31+
export function withErrorBoundary<P extends Record<string, any>>(
32+
WrappedComponent: React.ComponentType<P>,
33+
): React.FC<P> {
34+
return WrappedComponent as React.FC<P>;
35+
}
36+
37+
/**
38+
* Just a passthrough since we're on the server and showing the report dialog on the server doesn't make any sense.
39+
*/
40+
export function showReportDialog(): void {
41+
return;
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { describe, it, expect } from 'vitest';
2+
3+
describe('Basic test suite', () => {
4+
it('should pass', () => {
5+
expect(true).toBe(true);
6+
});
7+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../tsconfig.test.json"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"include": ["src/**/*"],
4+
"compilerOptions": {
5+
"lib": ["es2018", "es2020.string"],
6+
"module": "Node16"
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"include": ["test/**/*", "vite.config.ts"],
4+
"compilerOptions": {
5+
"types": ["node"],
6+
"lib": ["DOM", "ESNext"]
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"declaration": true,
5+
"declarationMap": true,
6+
"emitDeclarationOnly": true,
7+
"outDir": "build/types"
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import baseConfig from '../../vite/vite.config';
2+
3+
export default {
4+
...baseConfig,
5+
test: {
6+
...baseConfig.test,
7+
},
8+
};

0 commit comments

Comments
 (0)