@sentry/tanstackstart-react 10.54.0 → 10.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/build/cjs/client/sdk.js +10 -0
- package/build/cjs/client/sdk.js.map +1 -1
- package/build/cjs/index.server.js +1 -0
- package/build/cjs/index.server.js.map +1 -1
- package/build/cjs/server/globalMiddleware.js +32 -2
- package/build/cjs/server/globalMiddleware.js.map +1 -1
- package/build/cjs/server/index.js +8 -0
- package/build/cjs/server/index.js.map +1 -1
- package/build/cjs/server/routeParametrization.js +47 -0
- package/build/cjs/server/routeParametrization.js.map +1 -0
- package/build/cjs/server/sdk.js +7 -0
- package/build/cjs/server/sdk.js.map +1 -1
- package/build/cjs/server/utils.js +0 -5
- package/build/cjs/server/utils.js.map +1 -1
- package/build/cjs/server/wrapFetchWithSentry.js +82 -9
- package/build/cjs/server/wrapFetchWithSentry.js.map +1 -1
- package/build/cjs/vite/routePatterns.js +60 -0
- package/build/cjs/vite/routePatterns.js.map +1 -0
- package/build/cjs/vite/sentryTanstackStart.js +7 -6
- package/build/cjs/vite/sentryTanstackStart.js.map +1 -1
- package/build/cjs/vite/sourceMaps.js +6 -1
- package/build/cjs/vite/sourceMaps.js.map +1 -1
- package/build/esm/client/sdk.js +10 -0
- package/build/esm/client/sdk.js.map +1 -1
- package/build/esm/index.server.js +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server/globalMiddleware.js +33 -3
- package/build/esm/server/globalMiddleware.js.map +1 -1
- package/build/esm/server/index.js +8 -1
- package/build/esm/server/index.js.map +1 -1
- package/build/esm/server/routeParametrization.js +44 -0
- package/build/esm/server/routeParametrization.js.map +1 -0
- package/build/esm/server/sdk.js +7 -0
- package/build/esm/server/sdk.js.map +1 -1
- package/build/esm/server/utils.js +1 -5
- package/build/esm/server/utils.js.map +1 -1
- package/build/esm/server/wrapFetchWithSentry.js +84 -11
- package/build/esm/server/wrapFetchWithSentry.js.map +1 -1
- package/build/esm/vite/routePatterns.js +57 -0
- package/build/esm/vite/routePatterns.js.map +1 -0
- package/build/esm/vite/sentryTanstackStart.js +7 -6
- package/build/esm/vite/sentryTanstackStart.js.map +1 -1
- package/build/esm/vite/sourceMaps.js +6 -1
- package/build/esm/vite/sourceMaps.js.map +1 -1
- package/build/types/client/sdk.d.ts.map +1 -1
- package/build/types/index.types.d.ts +1 -0
- package/build/types/index.types.d.ts.map +1 -1
- package/build/types/server/globalMiddleware.d.ts.map +1 -1
- package/build/types/server/index.d.ts +5 -0
- package/build/types/server/index.d.ts.map +1 -1
- package/build/types/server/routeParametrization.d.ts +12 -0
- package/build/types/server/routeParametrization.d.ts.map +1 -0
- package/build/types/server/sdk.d.ts.map +1 -1
- package/build/types/server/utils.d.ts +0 -9
- package/build/types/server/utils.d.ts.map +1 -1
- package/build/types/server/wrapFetchWithSentry.d.ts.map +1 -1
- package/build/types/vite/routePatterns.d.ts +18 -0
- package/build/types/vite/routePatterns.d.ts.map +1 -0
- package/build/types/vite/sentryTanstackStart.d.ts +17 -0
- package/build/types/vite/sentryTanstackStart.d.ts.map +1 -1
- package/build/types/vite/sourceMaps.d.ts +4 -4
- package/build/types/vite/sourceMaps.d.ts.map +1 -1
- package/build/types-ts3.8/index.types.d.ts +1 -0
- package/build/types-ts3.8/server/index.d.ts +5 -0
- package/build/types-ts3.8/server/routeParametrization.d.ts +12 -0
- package/build/types-ts3.8/server/utils.d.ts +0 -9
- package/build/types-ts3.8/vite/routePatterns.d.ts +18 -0
- package/build/types-ts3.8/vite/sentryTanstackStart.d.ts +17 -0
- package/build/types-ts3.8/vite/sourceMaps.d.ts +4 -4
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
</a>
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
# Official Sentry SDK for TanStack Start React (
|
|
7
|
+
# Official Sentry SDK for TanStack Start React (Beta)
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@sentry/tanstackstart-react)
|
|
10
10
|
[](https://www.npmjs.com/package/@sentry/tanstackstart-react)
|
|
11
11
|
[](https://www.npmjs.com/package/@sentry/tanstackstart-react)
|
|
12
12
|
|
|
13
|
-
>
|
|
13
|
+
> This SDK is currently in **BETA**. Beta features are still in progress and may have bugs. Please reach out on
|
|
14
|
+
> [GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if you have any feedback or concerns.
|
|
14
15
|
|
|
15
16
|
> See the [Official Sentry TanStack Start SDK Docs](https://docs.sentry.io/platforms/javascript/guides/tanstackstart-react/) to get started.
|
|
16
17
|
|
package/build/cjs/client/sdk.js
CHANGED
|
@@ -11,6 +11,16 @@ function init(options) {
|
|
|
11
11
|
};
|
|
12
12
|
tunnelRoute.applyTunnelRouteOption(sentryOptions);
|
|
13
13
|
core.applySdkMetadata(sentryOptions, "tanstackstart-react", ["tanstackstart-react", "react"]);
|
|
14
|
+
sentryOptions.ignoreSpans = [
|
|
15
|
+
...sentryOptions.ignoreSpans || [],
|
|
16
|
+
/\/node_modules\//,
|
|
17
|
+
/\/favicon\.ico/,
|
|
18
|
+
/\/@id\//,
|
|
19
|
+
/\/@react-refresh/,
|
|
20
|
+
/\/@tanstack-start\//,
|
|
21
|
+
/\/@fs\//,
|
|
22
|
+
/\/@vite\//
|
|
23
|
+
];
|
|
14
24
|
return react.init(sentryOptions);
|
|
15
25
|
}
|
|
16
26
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/client/sdk.ts"],"sourcesContent":["import type { Client } from '@sentry/core';\nimport { applySdkMetadata } from '@sentry/core';\nimport type { BrowserOptions as ReactBrowserOptions } from '@sentry/react';\nimport { getDefaultIntegrations as getReactDefaultIntegrations, init as initReactSDK } from '@sentry/react';\nimport { applyTunnelRouteOption } from './tunnelRoute';\n\n/**\n * Initializes the TanStack Start React SDK\n *\n * @param options Configuration options for the SDK.\n */\nexport function init(options: ReactBrowserOptions): Client | undefined {\n const sentryOptions: ReactBrowserOptions = {\n defaultIntegrations: [...getReactDefaultIntegrations(options)],\n ...options,\n };\n\n applyTunnelRouteOption(sentryOptions);\n applySdkMetadata(sentryOptions, 'tanstackstart-react', ['tanstackstart-react', 'react']);\n\n return initReactSDK(sentryOptions);\n}\n"],"names":["getReactDefaultIntegrations","applyTunnelRouteOption","applySdkMetadata","initReactSDK"],"mappings":";;;;;;AAWO,SAAS,KAAK,OAAA,EAAkD;AACrE,EAAA,MAAM,aAAA,GAAqC;AAAA,IACzC,mBAAA,EAAqB,CAAC,GAAGA,4BAAA,CAA4B,OAAO,CAAC,CAAA;AAAA,IAC7D,GAAG;AAAA,GACL;AAEA,EAAAC,kCAAA,CAAuB,aAAa,CAAA;AACpC,EAAAC,qBAAA,CAAiB,aAAA,EAAe,qBAAA,EAAuB,CAAC,qBAAA,EAAuB,OAAO,CAAC,CAAA;AAEvF,EAAA,OAAOC,WAAa,aAAa,CAAA;AACnC;;;;"}
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/client/sdk.ts"],"sourcesContent":["import type { Client } from '@sentry/core';\nimport { applySdkMetadata } from '@sentry/core';\nimport type { BrowserOptions as ReactBrowserOptions } from '@sentry/react';\nimport { getDefaultIntegrations as getReactDefaultIntegrations, init as initReactSDK } from '@sentry/react';\nimport { applyTunnelRouteOption } from './tunnelRoute';\n\n/**\n * Initializes the TanStack Start React SDK\n *\n * @param options Configuration options for the SDK.\n */\nexport function init(options: ReactBrowserOptions): Client | undefined {\n const sentryOptions: ReactBrowserOptions = {\n defaultIntegrations: [...getReactDefaultIntegrations(options)],\n ...options,\n };\n\n applyTunnelRouteOption(sentryOptions);\n applySdkMetadata(sentryOptions, 'tanstackstart-react', ['tanstackstart-react', 'react']);\n\n sentryOptions.ignoreSpans = [\n ...(sentryOptions.ignoreSpans || []),\n /\\/node_modules\\//,\n /\\/favicon\\.ico/,\n /\\/@id\\//,\n /\\/@react-refresh/,\n /\\/@tanstack-start\\//,\n /\\/@fs\\//,\n /\\/@vite\\//,\n ];\n\n return initReactSDK(sentryOptions);\n}\n"],"names":["getReactDefaultIntegrations","applyTunnelRouteOption","applySdkMetadata","initReactSDK"],"mappings":";;;;;;AAWO,SAAS,KAAK,OAAA,EAAkD;AACrE,EAAA,MAAM,aAAA,GAAqC;AAAA,IACzC,mBAAA,EAAqB,CAAC,GAAGA,4BAAA,CAA4B,OAAO,CAAC,CAAA;AAAA,IAC7D,GAAG;AAAA,GACL;AAEA,EAAAC,kCAAA,CAAuB,aAAa,CAAA;AACpC,EAAAC,qBAAA,CAAiB,aAAA,EAAe,qBAAA,EAAuB,CAAC,qBAAA,EAAuB,OAAO,CAAC,CAAA;AAEvF,EAAA,aAAA,CAAc,WAAA,GAAc;AAAA,IAC1B,GAAI,aAAA,CAAc,WAAA,IAAe,EAAC;AAAA,IAClC,kBAAA;AAAA,IACA,gBAAA;AAAA,IACA,SAAA;AAAA,IACA,kBAAA;AAAA,IACA,qBAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,OAAOC,WAAa,aAAa,CAAA;AACnC;;;;"}
|
|
@@ -11,6 +11,7 @@ const middleware = require('./server/middleware.js');
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
exports.ErrorBoundary = index.ErrorBoundary;
|
|
14
|
+
exports.replayIntegration = index.replayIntegration;
|
|
14
15
|
exports.tanstackRouterBrowserTracingIntegration = index.tanstackRouterBrowserTracingIntegration;
|
|
15
16
|
exports.withErrorBoundary = index.withErrorBoundary;
|
|
16
17
|
exports.createSentryTunnelRoute = tunnelRoute.createSentryTunnelRoute;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.server.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.server.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -15,6 +15,36 @@ function createSentryMiddlewareHandler(mechanismType) {
|
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
|
+
function createSentryFunctionMiddlewareHandler(mechanismType) {
|
|
19
|
+
return async function sentryFunctionMiddlewareHandler({
|
|
20
|
+
next,
|
|
21
|
+
serverFnMeta
|
|
22
|
+
}) {
|
|
23
|
+
const activeSpan = core.getActiveSpan();
|
|
24
|
+
const spanData = activeSpan ? core.spanToJSON(activeSpan) : void 0;
|
|
25
|
+
if (activeSpan && spanData?.op === "function.tanstackstart") {
|
|
26
|
+
if (serverFnMeta?.name) {
|
|
27
|
+
const method = spanData.description?.split(" ")[0] || "GET";
|
|
28
|
+
core.updateSpanName(activeSpan, `${method} /_serverFn/${serverFnMeta.name}`);
|
|
29
|
+
activeSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
|
|
30
|
+
}
|
|
31
|
+
if (serverFnMeta?.id) {
|
|
32
|
+
activeSpan.setAttribute("tanstackstart.function.id", serverFnMeta.id);
|
|
33
|
+
}
|
|
34
|
+
if (serverFnMeta?.filename) {
|
|
35
|
+
activeSpan.setAttribute("tanstackstart.function.filename", serverFnMeta.filename);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
return await next();
|
|
40
|
+
} catch (e) {
|
|
41
|
+
core.captureException(e, {
|
|
42
|
+
mechanism: { type: mechanismType, handled: false }
|
|
43
|
+
});
|
|
44
|
+
throw e;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
18
48
|
const sentryGlobalRequestMiddleware = {
|
|
19
49
|
"~types": void 0,
|
|
20
50
|
options: {
|
|
@@ -25,8 +55,8 @@ const sentryGlobalRequestMiddleware = {
|
|
|
25
55
|
const sentryGlobalFunctionMiddleware = {
|
|
26
56
|
"~types": void 0,
|
|
27
57
|
options: {
|
|
28
|
-
|
|
29
|
-
|
|
58
|
+
server: createSentryFunctionMiddlewareHandler("auto.middleware.tanstackstart.server_function")
|
|
59
|
+
// eslint-disable-line @typescript-eslint/no-explicit-any
|
|
30
60
|
}
|
|
31
61
|
};
|
|
32
62
|
core.addNonEnumerableProperty(sentryGlobalRequestMiddleware, middleware.SENTRY_INTERNAL, true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"globalMiddleware.js","sources":["../../../src/server/globalMiddleware.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"globalMiddleware.js","sources":["../../../src/server/globalMiddleware.ts"],"sourcesContent":["import {\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n addNonEnumerableProperty,\n captureException,\n getActiveSpan,\n spanToJSON,\n updateSpanName,\n} from '@sentry/core';\nimport type { TanStackMiddlewareBase } from '../common/types';\nimport { SENTRY_INTERNAL } from './middleware';\n\ntype ServerFnMeta = {\n id?: string;\n name?: string;\n filename?: string;\n};\n\nfunction createSentryMiddlewareHandler(mechanismType: string) {\n return async function sentryMiddlewareHandler({ next }: { next: () => Promise<unknown> }): Promise<unknown> {\n try {\n return await next();\n } catch (e) {\n captureException(e, {\n mechanism: { type: mechanismType, handled: false },\n });\n throw e;\n }\n };\n}\n\nfunction createSentryFunctionMiddlewareHandler(mechanismType: string) {\n return async function sentryFunctionMiddlewareHandler({\n next,\n serverFnMeta,\n }: {\n next: () => Promise<unknown>;\n serverFnMeta?: ServerFnMeta;\n }): Promise<unknown> {\n const activeSpan = getActiveSpan();\n const spanData = activeSpan ? spanToJSON(activeSpan) : undefined;\n if (activeSpan && spanData?.op === 'function.tanstackstart') {\n if (serverFnMeta?.name) {\n const method = spanData.description?.split(' ')[0] || 'GET';\n updateSpanName(activeSpan, `${method} /_serverFn/${serverFnMeta.name}`);\n activeSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n }\n if (serverFnMeta?.id) {\n activeSpan.setAttribute('tanstackstart.function.id', serverFnMeta.id);\n }\n if (serverFnMeta?.filename) {\n activeSpan.setAttribute('tanstackstart.function.filename', serverFnMeta.filename);\n }\n }\n\n try {\n return await next();\n } catch (e) {\n captureException(e, {\n mechanism: { type: mechanismType, handled: false },\n });\n throw e;\n }\n };\n}\n\n/**\n * Global request middleware that captures errors from API route requests.\n * Should be added as the first entry in the `requestMiddleware` array of `createStart()`.\n */\nexport const sentryGlobalRequestMiddleware: TanStackMiddlewareBase = {\n '~types': undefined,\n\n options: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n server: createSentryMiddlewareHandler('auto.middleware.tanstackstart.request') as (...args: any[]) => any,\n },\n};\n\n/**\n * Global function middleware that captures errors from server function invocations.\n * Should be added as the first entry in the `functionMiddleware` array of `createStart()`.\n */\nexport const sentryGlobalFunctionMiddleware: TanStackMiddlewareBase = {\n '~types': undefined,\n\n options: {\n server: createSentryFunctionMiddlewareHandler('auto.middleware.tanstackstart.server_function') as (\n ...args: any[] // eslint-disable-line @typescript-eslint/no-explicit-any\n ) => any, // eslint-disable-line @typescript-eslint/no-explicit-any\n },\n};\n\n// Mark as internal so the Vite auto-instrumentation plugin skips these middleware\naddNonEnumerableProperty(sentryGlobalRequestMiddleware, SENTRY_INTERNAL, true);\naddNonEnumerableProperty(sentryGlobalFunctionMiddleware, SENTRY_INTERNAL, true);\n"],"names":["captureException","getActiveSpan","spanToJSON","updateSpanName","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","addNonEnumerableProperty","SENTRY_INTERNAL"],"mappings":";;;;;AAiBA,SAAS,8BAA8B,aAAA,EAAuB;AAC5D,EAAA,OAAO,eAAe,uBAAA,CAAwB,EAAE,IAAA,EAAK,EAAuD;AAC1G,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,EAAK;AAAA,IACpB,SAAS,CAAA,EAAG;AACV,MAAAA,qBAAA,CAAiB,CAAA,EAAG;AAAA,QAClB,SAAA,EAAW,EAAE,IAAA,EAAM,aAAA,EAAe,SAAS,KAAA;AAAM,OAClD,CAAA;AACD,MAAA,MAAM,CAAA;AAAA,IACR;AAAA,EACF,CAAA;AACF;AAEA,SAAS,sCAAsC,aAAA,EAAuB;AACpE,EAAA,OAAO,eAAe,+BAAA,CAAgC;AAAA,IACpD,IAAA;AAAA,IACA;AAAA,GACF,EAGqB;AACnB,IAAA,MAAM,aAAaC,kBAAA,EAAc;AACjC,IAAA,MAAM,QAAA,GAAW,UAAA,GAAaC,eAAA,CAAW,UAAU,CAAA,GAAI,MAAA;AACvD,IAAA,IAAI,UAAA,IAAc,QAAA,EAAU,EAAA,KAAO,wBAAA,EAA0B;AAC3D,MAAA,IAAI,cAAc,IAAA,EAAM;AACtB,QAAA,MAAM,SAAS,QAAA,CAAS,WAAA,EAAa,MAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,KAAA;AACtD,QAAAC,mBAAA,CAAe,YAAY,CAAA,EAAG,MAAM,CAAA,YAAA,EAAe,YAAA,CAAa,IAAI,CAAA,CAAE,CAAA;AACtE,QAAA,UAAA,CAAW,YAAA,CAAaC,uCAAkC,OAAO,CAAA;AAAA,MACnE;AACA,MAAA,IAAI,cAAc,EAAA,EAAI;AACpB,QAAA,UAAA,CAAW,YAAA,CAAa,2BAAA,EAA6B,YAAA,CAAa,EAAE,CAAA;AAAA,MACtE;AACA,MAAA,IAAI,cAAc,QAAA,EAAU;AAC1B,QAAA,UAAA,CAAW,YAAA,CAAa,iCAAA,EAAmC,YAAA,CAAa,QAAQ,CAAA;AAAA,MAClF;AAAA,IACF;AAEA,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,IAAA,EAAK;AAAA,IACpB,SAAS,CAAA,EAAG;AACV,MAAAJ,qBAAA,CAAiB,CAAA,EAAG;AAAA,QAClB,SAAA,EAAW,EAAE,IAAA,EAAM,aAAA,EAAe,SAAS,KAAA;AAAM,OAClD,CAAA;AACD,MAAA,MAAM,CAAA;AAAA,IACR;AAAA,EACF,CAAA;AACF;AAMO,MAAM,6BAAA,GAAwD;AAAA,EACnE,QAAA,EAAU,MAAA;AAAA,EAEV,OAAA,EAAS;AAAA;AAAA,IAEP,MAAA,EAAQ,8BAA8B,uCAAuC;AAAA;AAEjF;AAMO,MAAM,8BAAA,GAAyD;AAAA,EACpE,QAAA,EAAU,MAAA;AAAA,EAEV,OAAA,EAAS;AAAA,IACP,MAAA,EAAQ,sCAAsC,+CAA+C;AAAA;AAAA;AAIjG;AAGAK,6BAAA,CAAyB,6BAAA,EAA+BC,4BAAiB,IAAI,CAAA;AAC7ED,6BAAA,CAAyB,8BAAA,EAAgCC,4BAAiB,IAAI,CAAA;;;;;"}
|
|
@@ -7,6 +7,13 @@ const middleware = require('./middleware.js');
|
|
|
7
7
|
const globalMiddleware = require('./globalMiddleware.js');
|
|
8
8
|
const tunnelRoute = require('./tunnelRoute.js');
|
|
9
9
|
|
|
10
|
+
function replayIntegration(_options) {
|
|
11
|
+
return {
|
|
12
|
+
name: "Replay",
|
|
13
|
+
setup() {
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
10
17
|
function tanstackRouterBrowserTracingIntegration(_router, _options) {
|
|
11
18
|
return {
|
|
12
19
|
name: "BrowserTracing",
|
|
@@ -34,6 +41,7 @@ exports.sentryGlobalFunctionMiddleware = globalMiddleware.sentryGlobalFunctionMi
|
|
|
34
41
|
exports.sentryGlobalRequestMiddleware = globalMiddleware.sentryGlobalRequestMiddleware;
|
|
35
42
|
exports.createSentryTunnelRoute = tunnelRoute.createSentryTunnelRoute;
|
|
36
43
|
exports.ErrorBoundary = ErrorBoundary;
|
|
44
|
+
exports.replayIntegration = replayIntegration;
|
|
37
45
|
exports.tanstackRouterBrowserTracingIntegration = tanstackRouterBrowserTracingIntegration;
|
|
38
46
|
exports.withErrorBoundary = withErrorBoundary;
|
|
39
47
|
Object.prototype.hasOwnProperty.call(node, '__proto__') &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/server/index.ts"],"sourcesContent":["// import/export got a false positive, and affects most of our index barrel files\n// can be removed once following issue is fixed: https://github.com/import-js/eslint-plugin-import/issues/703\n/* eslint-disable import/export */\nimport type { Integration } from '@sentry/core';\n\nexport * from '@sentry/node';\n\nexport { init } from './sdk';\nexport { wrapFetchWithSentry } from './wrapFetchWithSentry';\nexport { wrapMiddlewaresWithSentry } from './middleware';\nexport { sentryGlobalRequestMiddleware, sentryGlobalFunctionMiddleware } from './globalMiddleware';\nexport { createSentryTunnelRoute } from './tunnelRoute';\n\n/**\n * A no-op stub of the browser tracing integration for the server. Router setup code is shared between client and server,\n * so this stub is needed to prevent build errors during SSR bundling.\n */\nexport function tanstackRouterBrowserTracingIntegration(\n _router: unknown,\n _options?: Record<string, unknown>,\n): Integration {\n return {\n name: 'BrowserTracing',\n setup() {},\n };\n}\n\n/**\n * A passthrough error boundary for the server that doesn't depend on any react. Error boundaries don't catch SSR errors\n * so they should simply be a passthrough.\n */\nexport const ErrorBoundary = (props: React.PropsWithChildren<unknown>): React.ReactNode => {\n if (!props.children) {\n return null;\n }\n\n if (typeof props.children === 'function') {\n return (props.children as () => React.ReactNode)();\n }\n\n return props.children;\n};\n\n/**\n * A passthrough error boundary wrapper for the server that doesn't depend on any react. Error boundaries don't catch\n * SSR errors so they should simply be a passthrough.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function withErrorBoundary<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n): React.FC<P> {\n return WrappedComponent as React.FC<P>;\n}\n"],"names":[],"mappings":";;;;;;;;;AAiBO,SAAS,uCAAA,CACd,SACA,QAAA,EACa;AACb,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,KAAA,GAAQ;AAAA,IAAC;AAAA,GACX;AACF;AAMO,MAAM,aAAA,GAAgB,CAAC,KAAA,KAA6D;AACzF,EAAA,IAAI,CAAC,MAAM,QAAA,EAAU;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,KAAA,CAAM,QAAA,KAAa,UAAA,EAAY;AACxC,IAAA,OAAQ,MAAM,QAAA,EAAmC;AAAA,EACnD;AAEA,EAAA,OAAO,KAAA,CAAM,QAAA;AACf;AAOO,SAAS,kBACd,gBAAA,EACa;AACb,EAAA,OAAO,gBAAA;AACT
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/server/index.ts"],"sourcesContent":["// import/export got a false positive, and affects most of our index barrel files\n// can be removed once following issue is fixed: https://github.com/import-js/eslint-plugin-import/issues/703\n/* eslint-disable import/export */\nimport type { Integration } from '@sentry/core';\n\nexport * from '@sentry/node';\n\nexport { init } from './sdk';\nexport { wrapFetchWithSentry } from './wrapFetchWithSentry';\nexport { wrapMiddlewaresWithSentry } from './middleware';\nexport { sentryGlobalRequestMiddleware, sentryGlobalFunctionMiddleware } from './globalMiddleware';\nexport { createSentryTunnelRoute } from './tunnelRoute';\n\n/**\n * A no-op stub of the replay integration for the server. Router setup code is shared between client and server,\n * so this stub is needed to prevent build errors during SSR bundling.\n */\nexport function replayIntegration(_options?: Record<string, unknown>): Integration {\n return {\n name: 'Replay',\n setup() {},\n };\n}\n\n/**\n * A no-op stub of the browser tracing integration for the server. Router setup code is shared between client and server,\n * so this stub is needed to prevent build errors during SSR bundling.\n */\nexport function tanstackRouterBrowserTracingIntegration(\n _router: unknown,\n _options?: Record<string, unknown>,\n): Integration {\n return {\n name: 'BrowserTracing',\n setup() {},\n };\n}\n\n/**\n * A passthrough error boundary for the server that doesn't depend on any react. Error boundaries don't catch SSR errors\n * so they should simply be a passthrough.\n */\nexport const ErrorBoundary = (props: React.PropsWithChildren<unknown>): React.ReactNode => {\n if (!props.children) {\n return null;\n }\n\n if (typeof props.children === 'function') {\n return (props.children as () => React.ReactNode)();\n }\n\n return props.children;\n};\n\n/**\n * A passthrough error boundary wrapper for the server that doesn't depend on any react. Error boundaries don't catch\n * SSR errors so they should simply be a passthrough.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function withErrorBoundary<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n): React.FC<P> {\n return WrappedComponent as React.FC<P>;\n}\n"],"names":[],"mappings":";;;;;;;;;AAiBO,SAAS,kBAAkB,QAAA,EAAiD;AACjF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IACN,KAAA,GAAQ;AAAA,IAAC;AAAA,GACX;AACF;AAMO,SAAS,uCAAA,CACd,SACA,QAAA,EACa;AACb,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,KAAA,GAAQ;AAAA,IAAC;AAAA,GACX;AACF;AAMO,MAAM,aAAA,GAAgB,CAAC,KAAA,KAA6D;AACzF,EAAA,IAAI,CAAC,MAAM,QAAA,EAAU;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,KAAA,CAAM,QAAA,KAAa,UAAA,EAAY;AACxC,IAAA,OAAQ,MAAM,QAAA,EAAmC;AAAA,EACnD;AAEA,EAAA,OAAO,KAAA,CAAM,QAAA;AACf;AAOO,SAAS,kBACd,gBAAA,EACa;AACb,EAAA,OAAO,gBAAA;AACT;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
4
|
+
const core = require('@sentry/core');
|
|
5
|
+
|
|
6
|
+
function patternToRegex(pattern) {
|
|
7
|
+
const segments = pattern.split("/").map((segment) => {
|
|
8
|
+
if (segment.startsWith("$")) {
|
|
9
|
+
return "[^/]+";
|
|
10
|
+
}
|
|
11
|
+
return core.escapeStringForRegex(segment);
|
|
12
|
+
}).join("/");
|
|
13
|
+
return new RegExp(`^${segments}$`);
|
|
14
|
+
}
|
|
15
|
+
function matchUrlToRoutePattern(pathname, patterns) {
|
|
16
|
+
const normalizedPathname = pathname.length > 1 ? pathname.replace(/\/$/, "") : pathname;
|
|
17
|
+
for (const pattern of patterns) {
|
|
18
|
+
if (patternToRegex(pattern).test(normalizedPathname)) {
|
|
19
|
+
return pattern;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return void 0;
|
|
23
|
+
}
|
|
24
|
+
function updateSpanWithRouteParametrization(method, pathname, patterns) {
|
|
25
|
+
const matchedPattern = matchUrlToRoutePattern(pathname, patterns);
|
|
26
|
+
if (!matchedPattern) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const activeSpan = core.getActiveSpan();
|
|
30
|
+
if (!activeSpan) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const rootSpan = core.getRootSpan(activeSpan);
|
|
34
|
+
const rootSpanData = core.spanToJSON(rootSpan).data;
|
|
35
|
+
if (rootSpanData?.[semanticConventions.ATTR_HTTP_ROUTE]) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const transactionName = `${method} ${matchedPattern}`;
|
|
39
|
+
core.updateSpanName(rootSpan, transactionName);
|
|
40
|
+
rootSpan.setAttribute(semanticConventions.ATTR_HTTP_ROUTE, matchedPattern);
|
|
41
|
+
rootSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
|
|
42
|
+
core.getCurrentScope().setTransactionName(transactionName);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
exports.matchUrlToRoutePattern = matchUrlToRoutePattern;
|
|
46
|
+
exports.updateSpanWithRouteParametrization = updateSpanWithRouteParametrization;
|
|
47
|
+
//# sourceMappingURL=routeParametrization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeParametrization.js","sources":["../../../src/server/routeParametrization.ts"],"sourcesContent":["import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {\n escapeStringForRegex,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n updateSpanName,\n} from '@sentry/core';\n\nfunction patternToRegex(pattern: string): RegExp {\n const segments = pattern\n .split('/')\n .map(segment => {\n if (segment.startsWith('$')) {\n return '[^/]+';\n }\n return escapeStringForRegex(segment);\n })\n .join('/');\n return new RegExp(`^${segments}$`);\n}\n\n/**\n * Matches a URL pathname against a list of TanStack Start route patterns.\n * Patterns use `$param` syntax for dynamic segments (e.g., `/users/$id`).\n *\n * Patterns are expected to be pre-sorted by specificity (more segments first, static before dynamic).\n */\nexport function matchUrlToRoutePattern(pathname: string, patterns: string[]): string | undefined {\n const normalizedPathname = pathname.length > 1 ? pathname.replace(/\\/$/, '') : pathname;\n for (const pattern of patterns) {\n if (patternToRegex(pattern).test(normalizedPathname)) {\n return pattern;\n }\n }\n return undefined;\n}\n\n/**\n * Updates the active root span with a parametrized route name.\n */\nexport function updateSpanWithRouteParametrization(method: string, pathname: string, patterns: string[]): void {\n const matchedPattern = matchUrlToRoutePattern(pathname, patterns);\n if (!matchedPattern) {\n return;\n }\n\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n return;\n }\n\n const rootSpan = getRootSpan(activeSpan);\n const rootSpanData = spanToJSON(rootSpan).data;\n if (rootSpanData?.[ATTR_HTTP_ROUTE]) {\n return;\n }\n\n const transactionName = `${method} ${matchedPattern}`;\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttribute(ATTR_HTTP_ROUTE, matchedPattern);\n rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n getCurrentScope().setTransactionName(transactionName);\n}\n"],"names":["escapeStringForRegex","getActiveSpan","getRootSpan","spanToJSON","ATTR_HTTP_ROUTE","updateSpanName","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","getCurrentScope"],"mappings":";;;;;AAWA,SAAS,eAAe,OAAA,EAAyB;AAC/C,EAAA,MAAM,WAAW,OAAA,CACd,KAAA,CAAM,GAAG,CAAA,CACT,IAAI,CAAA,OAAA,KAAW;AACd,IAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAG;AAC3B,MAAA,OAAO,OAAA;AAAA,IACT;AACA,IAAA,OAAOA,0BAAqB,OAAO,CAAA;AAAA,EACrC,CAAC,CAAA,CACA,IAAA,CAAK,GAAG,CAAA;AACX,EAAA,OAAO,IAAI,MAAA,CAAO,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA,CAAG,CAAA;AACnC;AAQO,SAAS,sBAAA,CAAuB,UAAkB,QAAA,EAAwC;AAC/F,EAAA,MAAM,kBAAA,GAAqB,SAAS,MAAA,GAAS,CAAA,GAAI,SAAS,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,GAAI,QAAA;AAC/E,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,IAAI,cAAA,CAAe,OAAO,CAAA,CAAE,IAAA,CAAK,kBAAkB,CAAA,EAAG;AACpD,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAKO,SAAS,kCAAA,CAAmC,MAAA,EAAgB,QAAA,EAAkB,QAAA,EAA0B;AAC7G,EAAA,MAAM,cAAA,GAAiB,sBAAA,CAAuB,QAAA,EAAU,QAAQ,CAAA;AAChE,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,aAAaC,kBAAA,EAAc;AACjC,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,QAAA,GAAWC,iBAAY,UAAU,CAAA;AACvC,EAAA,MAAM,YAAA,GAAeC,eAAA,CAAW,QAAQ,CAAA,CAAE,IAAA;AAC1C,EAAA,IAAI,YAAA,GAAeC,mCAAe,CAAA,EAAG;AACnC,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,eAAA,GAAkB,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,cAAc,CAAA,CAAA;AACnD,EAAAC,mBAAA,CAAe,UAAU,eAAe,CAAA;AACxC,EAAA,QAAA,CAAS,YAAA,CAAaD,qCAAiB,cAAc,CAAA;AACrD,EAAA,QAAA,CAAS,YAAA,CAAaE,uCAAkC,OAAO,CAAA;AAC/D,EAAAC,oBAAA,EAAgB,CAAE,mBAAmB,eAAe,CAAA;AACtD;;;;;"}
|
package/build/cjs/server/sdk.js
CHANGED
|
@@ -9,6 +9,13 @@ function init(options) {
|
|
|
9
9
|
...options
|
|
10
10
|
};
|
|
11
11
|
core.applySdkMetadata(sentryOptions, "tanstackstart-react", ["tanstackstart-react", "node"]);
|
|
12
|
+
sentryOptions.ignoreSpans = [
|
|
13
|
+
...sentryOptions.ignoreSpans || [],
|
|
14
|
+
/\/node_modules\//,
|
|
15
|
+
/\/@id\//,
|
|
16
|
+
/\/@react-refresh/,
|
|
17
|
+
/\/@vite\//
|
|
18
|
+
];
|
|
12
19
|
return node.init(sentryOptions);
|
|
13
20
|
}
|
|
14
21
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import { applySdkMetadata } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getDefaultNodeIntegrations, init as initNodeSdk } from '@sentry/node';\n\n/**\n * Initializes the server side of the TanStack Start React SDK\n */\nexport function init(options: NodeOptions): NodeClient | undefined {\n const sentryOptions: NodeOptions = {\n defaultIntegrations: [...getDefaultNodeIntegrations(options)],\n ...options,\n };\n\n applySdkMetadata(sentryOptions, 'tanstackstart-react', ['tanstackstart-react', 'node']);\n\n return initNodeSdk(sentryOptions);\n}\n"],"names":["getDefaultNodeIntegrations","applySdkMetadata","initNodeSdk"],"mappings":";;;;;AAOO,SAAS,KAAK,OAAA,EAA8C;AACjE,EAAA,MAAM,aAAA,GAA6B;AAAA,IACjC,mBAAA,EAAqB,CAAC,GAAGA,2BAAA,CAA2B,OAAO,CAAC,CAAA;AAAA,IAC5D,GAAG;AAAA,GACL;AAEA,EAAAC,qBAAA,CAAiB,aAAA,EAAe,qBAAA,EAAuB,CAAC,qBAAA,EAAuB,MAAM,CAAC,CAAA;AAEtF,EAAA,OAAOC,UAAY,aAAa,CAAA;AAClC;;;;"}
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import { applySdkMetadata } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getDefaultNodeIntegrations, init as initNodeSdk } from '@sentry/node';\n\n/**\n * Initializes the server side of the TanStack Start React SDK\n */\nexport function init(options: NodeOptions): NodeClient | undefined {\n const sentryOptions: NodeOptions = {\n defaultIntegrations: [...getDefaultNodeIntegrations(options)],\n ...options,\n };\n\n applySdkMetadata(sentryOptions, 'tanstackstart-react', ['tanstackstart-react', 'node']);\n\n sentryOptions.ignoreSpans = [\n ...(sentryOptions.ignoreSpans || []),\n /\\/node_modules\\//,\n /\\/@id\\//,\n /\\/@react-refresh/,\n /\\/@vite\\//,\n ];\n\n return initNodeSdk(sentryOptions);\n}\n"],"names":["getDefaultNodeIntegrations","applySdkMetadata","initNodeSdk"],"mappings":";;;;;AAOO,SAAS,KAAK,OAAA,EAA8C;AACjE,EAAA,MAAM,aAAA,GAA6B;AAAA,IACjC,mBAAA,EAAqB,CAAC,GAAGA,2BAAA,CAA2B,OAAO,CAAC,CAAA;AAAA,IAC5D,GAAG;AAAA,GACL;AAEA,EAAAC,qBAAA,CAAiB,aAAA,EAAe,qBAAA,EAAuB,CAAC,qBAAA,EAAuB,MAAM,CAAC,CAAA;AAEtF,EAAA,aAAA,CAAc,WAAA,GAAc;AAAA,IAC1B,GAAI,aAAA,CAAc,WAAA,IAAe,EAAC;AAAA,IAClC,kBAAA;AAAA,IACA,SAAA;AAAA,IACA,kBAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,OAAOC,UAAY,aAAa,CAAA;AAClC;;;;"}
|
|
@@ -2,10 +2,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
|
|
3
3
|
const node = require('@sentry/node');
|
|
4
4
|
|
|
5
|
-
function extractServerFunctionSha256(pathname) {
|
|
6
|
-
const serverFnMatch = pathname.match(/\/_serverFn\/([a-f0-9]{64})/i);
|
|
7
|
-
return serverFnMatch?.[1] ?? "unknown";
|
|
8
|
-
}
|
|
9
5
|
function getMiddlewareSpanOptions(name) {
|
|
10
6
|
return {
|
|
11
7
|
op: "middleware.tanstackstart",
|
|
@@ -17,6 +13,5 @@ function getMiddlewareSpanOptions(name) {
|
|
|
17
13
|
};
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
exports.extractServerFunctionSha256 = extractServerFunctionSha256;
|
|
21
16
|
exports.getMiddlewareSpanOptions = getMiddlewareSpanOptions;
|
|
22
17
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../src/server/utils.ts"],"sourcesContent":["import type { StartSpanOptions } from '@sentry/core';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/node';\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/server/utils.ts"],"sourcesContent":["import type { StartSpanOptions } from '@sentry/core';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/node';\n\n/**\n * Returns span options for TanStack Start middleware spans.\n */\nexport function getMiddlewareSpanOptions(name: string): StartSpanOptions {\n return {\n op: 'middleware.tanstackstart',\n name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.middleware.tanstackstart',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'middleware.tanstackstart',\n },\n };\n}\n"],"names":["SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP"],"mappings":";;;;AAMO,SAAS,yBAAyB,IAAA,EAAgC;AACvE,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,0BAAA;AAAA,IACJ,IAAA;AAAA,IACA,UAAA,EAAY;AAAA,MACV,CAACA,qCAAgC,GAAG,+BAAA;AAAA,MACpC,CAACC,iCAA4B,GAAG;AAAA;AAClC,GACF;AACF;;;;"}
|
|
@@ -2,8 +2,81 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
4
|
const node = require('@sentry/node');
|
|
5
|
-
const
|
|
5
|
+
const routeParametrization = require('./routeParametrization.js');
|
|
6
6
|
|
|
7
|
+
function addMetaTagToHead(htmlChunk, metaTagsStr) {
|
|
8
|
+
if (typeof htmlChunk !== "string" || !metaTagsStr) {
|
|
9
|
+
return htmlChunk;
|
|
10
|
+
}
|
|
11
|
+
if (htmlChunk.includes('"sentry-trace"')) {
|
|
12
|
+
return htmlChunk;
|
|
13
|
+
}
|
|
14
|
+
let replaced = false;
|
|
15
|
+
return htmlChunk.replace(/"[^"]*"|'[^']*'|(<head>)/g, (match, headTag) => {
|
|
16
|
+
if (headTag && !replaced) {
|
|
17
|
+
replaced = true;
|
|
18
|
+
return `<head>${metaTagsStr}`;
|
|
19
|
+
}
|
|
20
|
+
return match;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function injectMetaTagsInResponse(originalResponse) {
|
|
24
|
+
try {
|
|
25
|
+
const contentType = originalResponse.headers.get("content-type");
|
|
26
|
+
const isPageloadRequest = contentType?.startsWith("text/html");
|
|
27
|
+
if (!isPageloadRequest) {
|
|
28
|
+
return originalResponse;
|
|
29
|
+
}
|
|
30
|
+
const originalBody = originalResponse.body;
|
|
31
|
+
if (!originalBody) {
|
|
32
|
+
return originalResponse;
|
|
33
|
+
}
|
|
34
|
+
const metaTagsStr = core.getTraceMetaTags();
|
|
35
|
+
const decoder = new TextDecoder();
|
|
36
|
+
const newResponseStream = new ReadableStream({
|
|
37
|
+
start: async (controller) => {
|
|
38
|
+
const body = originalBody;
|
|
39
|
+
async function* bodyReporter() {
|
|
40
|
+
try {
|
|
41
|
+
for await (const chunk of body) {
|
|
42
|
+
yield chunk;
|
|
43
|
+
}
|
|
44
|
+
} catch (e) {
|
|
45
|
+
node.captureException(e, {
|
|
46
|
+
mechanism: { type: "auto.http.tanstackstart", handled: false }
|
|
47
|
+
});
|
|
48
|
+
throw e;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
let errored = false;
|
|
52
|
+
try {
|
|
53
|
+
for await (const chunk of bodyReporter()) {
|
|
54
|
+
const html = typeof chunk === "string" ? chunk : decoder.decode(chunk, { stream: true });
|
|
55
|
+
const modifiedHtml = addMetaTagToHead(html, metaTagsStr);
|
|
56
|
+
controller.enqueue(new TextEncoder().encode(modifiedHtml));
|
|
57
|
+
}
|
|
58
|
+
} catch (e) {
|
|
59
|
+
errored = true;
|
|
60
|
+
controller.error(e);
|
|
61
|
+
} finally {
|
|
62
|
+
if (!errored) {
|
|
63
|
+
controller.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return new Response(newResponseStream, {
|
|
69
|
+
status: originalResponse.status,
|
|
70
|
+
statusText: originalResponse.statusText,
|
|
71
|
+
headers: new Headers(originalResponse.headers)
|
|
72
|
+
});
|
|
73
|
+
} catch (e) {
|
|
74
|
+
node.captureException(e, {
|
|
75
|
+
mechanism: { type: "auto.http.tanstackstart", handled: false }
|
|
76
|
+
});
|
|
77
|
+
throw e;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
7
80
|
function wrapFetchWithSentry(serverEntry) {
|
|
8
81
|
if (serverEntry.fetch) {
|
|
9
82
|
serverEntry.fetch = new Proxy(serverEntry.fetch, {
|
|
@@ -13,25 +86,25 @@ function wrapFetchWithSentry(serverEntry) {
|
|
|
13
86
|
const url = new URL(request.url);
|
|
14
87
|
const method = request.method || "GET";
|
|
15
88
|
if (url.pathname.includes("_serverFn") || url.pathname.includes("createServerFn")) {
|
|
16
|
-
const functionSha256 = utils.extractServerFunctionSha256(url.pathname);
|
|
17
89
|
const op = "function.tanstackstart";
|
|
18
|
-
const serverFunctionSpanAttributes = {
|
|
19
|
-
[node.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.tanstackstart.server",
|
|
20
|
-
[node.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
|
|
21
|
-
"tanstackstart.function.hash.sha256": functionSha256
|
|
22
|
-
};
|
|
23
90
|
return await node.startSpan(
|
|
24
91
|
{
|
|
25
92
|
op,
|
|
26
93
|
name: `${method} ${url.pathname}`,
|
|
27
|
-
attributes:
|
|
94
|
+
attributes: {
|
|
95
|
+
[node.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.tanstackstart.server",
|
|
96
|
+
[node.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op
|
|
97
|
+
}
|
|
28
98
|
},
|
|
29
99
|
async () => {
|
|
30
100
|
return target.apply(thisArg, args);
|
|
31
101
|
}
|
|
32
102
|
);
|
|
33
103
|
}
|
|
34
|
-
|
|
104
|
+
if (typeof __SENTRY_ROUTE_PATTERNS__ !== "undefined") {
|
|
105
|
+
routeParametrization.updateSpanWithRouteParametrization(method, url.pathname, __SENTRY_ROUTE_PATTERNS__);
|
|
106
|
+
}
|
|
107
|
+
return injectMetaTagsInResponse(await target.apply(thisArg, args));
|
|
35
108
|
} finally {
|
|
36
109
|
await core.flushIfServerless();
|
|
37
110
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapFetchWithSentry.js","sources":["../../../src/server/wrapFetchWithSentry.ts"],"sourcesContent":["import { flushIfServerless } from '@sentry/core';\nimport {
|
|
1
|
+
{"version":3,"file":"wrapFetchWithSentry.js","sources":["../../../src/server/wrapFetchWithSentry.ts"],"sourcesContent":["import { flushIfServerless, getTraceMetaTags } from '@sentry/core';\nimport {\n captureException,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startSpan,\n} from '@sentry/node';\nimport { updateSpanWithRouteParametrization } from './routeParametrization';\n\ndeclare const __SENTRY_ROUTE_PATTERNS__: string[] | undefined;\n\nexport type ServerEntry = {\n fetch: (request: Request, opts?: unknown) => Promise<Response> | Response;\n};\n\n/**\n * This function optimistically assumes that the HTML coming in chunks will not be split\n * within the <head> tag. If this still happens, we simply won't replace anything.\n */\nfunction addMetaTagToHead(htmlChunk: string, metaTagsStr: string): string {\n if (typeof htmlChunk !== 'string' || !metaTagsStr) {\n return htmlChunk;\n }\n\n if (htmlChunk.includes('\"sentry-trace\"')) {\n return htmlChunk;\n }\n\n // Skip quoted attribute values so we don't match <head> inside e.g. data-code=\"...<head>...\"\n let replaced = false;\n return htmlChunk.replace(/\"[^\"]*\"|'[^']*'|(<head>)/g, (match, headTag) => {\n if (headTag && !replaced) {\n replaced = true;\n return `<head>${metaTagsStr}`;\n }\n return match;\n });\n}\n\nfunction injectMetaTagsInResponse(originalResponse: Response): Response {\n try {\n const contentType = originalResponse.headers.get('content-type');\n\n const isPageloadRequest = contentType?.startsWith('text/html');\n if (!isPageloadRequest) {\n return originalResponse;\n }\n\n // Type case necessary b/c the body's ReadableStream type doesn't include\n // the async iterator that is actually available in Node\n // We later on use the async iterator to read the body chunks\n // see https://github.com/microsoft/TypeScript/issues/39051\n const originalBody = originalResponse.body as NodeJS.ReadableStream | null;\n if (!originalBody) {\n return originalResponse;\n }\n\n const metaTagsStr = getTraceMetaTags();\n const decoder = new TextDecoder();\n\n const newResponseStream = new ReadableStream({\n start: async controller => {\n // Assign to a new variable to avoid TS losing the narrower type checked above.\n const body = originalBody;\n\n async function* bodyReporter(): AsyncGenerator<string | Buffer> {\n try {\n for await (const chunk of body) {\n yield chunk;\n }\n } catch (e) {\n captureException(e, {\n mechanism: { type: 'auto.http.tanstackstart', handled: false },\n });\n throw e;\n }\n }\n\n let errored = false;\n try {\n for await (const chunk of bodyReporter()) {\n const html = typeof chunk === 'string' ? chunk : decoder.decode(chunk, { stream: true });\n const modifiedHtml = addMetaTagToHead(html, metaTagsStr);\n controller.enqueue(new TextEncoder().encode(modifiedHtml));\n }\n } catch (e) {\n errored = true;\n controller.error(e);\n } finally {\n if (!errored) {\n controller.close();\n }\n }\n },\n });\n\n return new Response(newResponseStream, {\n status: originalResponse.status,\n statusText: originalResponse.statusText,\n headers: new Headers(originalResponse.headers),\n });\n } catch (e) {\n captureException(e, {\n mechanism: { type: 'auto.http.tanstackstart', handled: false },\n });\n throw e;\n }\n}\n\n/**\n * This function can be used to wrap the server entry request handler to add tracing to server-side functionality.\n * You must explicitly define a server entry point in your application for this to work. This is done by passing the request handler to the `createServerEntry` function.\n * For more information about the server entry point, see the [TanStack Start documentation](https://tanstack.com/start/docs/server-entry).\n *\n * @example\n * ```ts\n * import { wrapFetchWithSentry } from '@sentry/tanstackstart-react';\n *\n * import handler, { createServerEntry } from '@tanstack/react-start/server-entry';\n * import type { ServerEntry } from '@tanstack/react-start/server-entry';\n *\n * const requestHandler: ServerEntry = wrapFetchWithSentry({\n * fetch(request: Request) {\n * return handler.fetch(request);\n * },\n * });\n *\n * export default serverEntry = createServerEntry(requestHandler);\n * ```\n *\n * @param serverEntry - request handler to wrap\n * @returns - wrapped request handler\n */\nexport function wrapFetchWithSentry(serverEntry: ServerEntry): ServerEntry {\n if (serverEntry.fetch) {\n serverEntry.fetch = new Proxy<typeof serverEntry.fetch>(serverEntry.fetch, {\n async apply(target, thisArg, args) {\n try {\n const request: Request = args[0];\n const url = new URL(request.url);\n const method = request.method || 'GET';\n\n // instrument server functions\n if (url.pathname.includes('_serverFn') || url.pathname.includes('createServerFn')) {\n const op = 'function.tanstackstart';\n\n return await startSpan(\n {\n op,\n name: `${method} ${url.pathname}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.tanstackstart.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n },\n },\n async () => {\n return target.apply(thisArg, args);\n },\n );\n }\n\n if (typeof __SENTRY_ROUTE_PATTERNS__ !== 'undefined') {\n updateSpanWithRouteParametrization(method, url.pathname, __SENTRY_ROUTE_PATTERNS__);\n }\n\n return injectMetaTagsInResponse(await target.apply(thisArg, args));\n } finally {\n await flushIfServerless();\n }\n },\n });\n }\n return serverEntry;\n}\n"],"names":["getTraceMetaTags","captureException","startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","updateSpanWithRouteParametrization","flushIfServerless"],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
function makeRoutePatternPlugin() {
|
|
7
|
+
let resolvedRoot = "";
|
|
8
|
+
return {
|
|
9
|
+
name: "sentry-tanstackstart-route-patterns",
|
|
10
|
+
enforce: "post",
|
|
11
|
+
configResolved(config) {
|
|
12
|
+
resolvedRoot = config.root || process.cwd();
|
|
13
|
+
},
|
|
14
|
+
transform(code, _id) {
|
|
15
|
+
if (!code.includes("__SENTRY_ROUTE_PATTERNS__")) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const routeTreePath = path.resolve(resolvedRoot, "src/routeTree.gen.ts");
|
|
19
|
+
let patterns = [];
|
|
20
|
+
try {
|
|
21
|
+
if (fs.existsSync(routeTreePath)) {
|
|
22
|
+
patterns = extractRoutePatterns(fs.readFileSync(routeTreePath, "utf-8"));
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
code: code.replace(/__SENTRY_ROUTE_PATTERNS__/g, JSON.stringify(patterns)),
|
|
28
|
+
map: null
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function extractRoutePatterns(content) {
|
|
34
|
+
const fullPathsMatch = content.match(/fullPaths:\s*([\s\S]*?)(?:\n\s*\w|\n\})/);
|
|
35
|
+
if (!fullPathsMatch) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
const patterns = [];
|
|
39
|
+
const pathRegex = /['"]([^'"]+)['"]/g;
|
|
40
|
+
let match;
|
|
41
|
+
while ((match = pathRegex.exec(fullPathsMatch[1] || "")) !== null) {
|
|
42
|
+
if (match[1]) {
|
|
43
|
+
patterns.push(match[1]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return [...new Set(patterns)].sort((a, b) => {
|
|
47
|
+
const aSegments = a.split("/");
|
|
48
|
+
const bSegments = b.split("/");
|
|
49
|
+
if (bSegments.length !== aSegments.length) {
|
|
50
|
+
return bSegments.length - aSegments.length;
|
|
51
|
+
}
|
|
52
|
+
const aDynamic = aSegments.filter((s) => s.startsWith("$")).length;
|
|
53
|
+
const bDynamic = bSegments.filter((s) => s.startsWith("$")).length;
|
|
54
|
+
return aDynamic - bDynamic;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
exports.extractRoutePatterns = extractRoutePatterns;
|
|
59
|
+
exports.makeRoutePatternPlugin = makeRoutePatternPlugin;
|
|
60
|
+
//# sourceMappingURL=routePatterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routePatterns.js","sources":["../../../src/vite/routePatterns.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Plugin } from 'vite';\n\n/**\n * Extracts route patterns from TanStack Start's generated routeTree.gen.ts\n * and replaces `__SENTRY_ROUTE_PATTERNS__` references with the extracted patterns.\n *\n * The route tree file is read during `transform` rather than `config` because\n * TanStack Start generates it during the build.\n */\nexport function makeRoutePatternPlugin(): Plugin {\n let resolvedRoot = '';\n\n return {\n name: 'sentry-tanstackstart-route-patterns',\n enforce: 'post',\n\n configResolved(config) {\n resolvedRoot = config.root || process.cwd();\n },\n\n transform(code, _id) {\n // this is set in the `wrapFetchWithSentry` where the paths are getting replaced by their parametrized counterparts\n // so this extraction should only happen once during the build (for the `wrapFetchWithSentry` file)\n if (!code.includes('__SENTRY_ROUTE_PATTERNS__')) {\n return null;\n }\n\n // extract the patterns from the route tree file\n const routeTreePath = path.resolve(resolvedRoot, 'src/routeTree.gen.ts');\n let patterns: string[] = [];\n try {\n if (fs.existsSync(routeTreePath)) {\n patterns = extractRoutePatterns(fs.readFileSync(routeTreePath, 'utf-8'));\n }\n } catch {\n // skip\n }\n\n return {\n code: code.replace(/__SENTRY_ROUTE_PATTERNS__/g, JSON.stringify(patterns)),\n map: null,\n };\n },\n };\n}\n\n/**\n * Extracts full route path patterns from the content of routeTree.gen.ts.\n *\n * Parses the `fullPaths` type union which contains the resolved full paths\n * (e.g., `fullPaths: '/' | '/page-a' | '/users/$userId'`).\n * This is more reliable than `path:` properties which can be relative for nested routes.\n */\nexport function extractRoutePatterns(content: string): string[] {\n const fullPathsMatch = content.match(/fullPaths:\\s*([\\s\\S]*?)(?:\\n\\s*\\w|\\n\\})/);\n if (!fullPathsMatch) {\n return [];\n }\n\n const patterns: string[] = [];\n const pathRegex = /['\"]([^'\"]+)['\"]/g;\n let match;\n while ((match = pathRegex.exec(fullPathsMatch[1] || '')) !== null) {\n if (match[1]) {\n patterns.push(match[1]);\n }\n }\n\n return [...new Set(patterns)].sort((a, b) => {\n const aSegments = a.split('/');\n const bSegments = b.split('/');\n if (bSegments.length !== aSegments.length) {\n return bSegments.length - aSegments.length;\n }\n const aDynamic = aSegments.filter(s => s.startsWith('$')).length;\n const bDynamic = bSegments.filter(s => s.startsWith('$')).length;\n return aDynamic - bDynamic;\n });\n}\n"],"names":[],"mappings":";;;;;AAWO,SAAS,sBAAA,GAAiC;AAC/C,EAAA,IAAI,YAAA,GAAe,EAAA;AAEnB,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,qCAAA;AAAA,IACN,OAAA,EAAS,MAAA;AAAA,IAET,eAAe,MAAA,EAAQ;AACrB,MAAA,YAAA,GAAe,MAAA,CAAO,IAAA,IAAQ,OAAA,CAAQ,GAAA,EAAI;AAAA,IAC5C,CAAA;AAAA,IAEA,SAAA,CAAU,MAAM,GAAA,EAAK;AAGnB,MAAA,IAAI,CAAC,IAAA,CAAK,QAAA,CAAS,2BAA2B,CAAA,EAAG;AAC/C,QAAA,OAAO,IAAA;AAAA,MACT;AAGA,MAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,OAAA,CAAQ,YAAA,EAAc,sBAAsB,CAAA;AACvE,MAAA,IAAI,WAAqB,EAAC;AAC1B,MAAA,IAAI;AACF,QAAA,IAAI,EAAA,CAAG,UAAA,CAAW,aAAa,CAAA,EAAG;AAChC,UAAA,QAAA,GAAW,oBAAA,CAAqB,EAAA,CAAG,YAAA,CAAa,aAAA,EAAe,OAAO,CAAC,CAAA;AAAA,QACzE;AAAA,MACF,CAAA,CAAA,MAAQ;AAAA,MAER;AAEA,MAAA,OAAO;AAAA,QACL,MAAM,IAAA,CAAK,OAAA,CAAQ,8BAA8B,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,QACzE,GAAA,EAAK;AAAA,OACP;AAAA,IACF;AAAA,GACF;AACF;AASO,SAAS,qBAAqB,OAAA,EAA2B;AAC9D,EAAA,MAAM,cAAA,GAAiB,OAAA,CAAQ,KAAA,CAAM,yCAAyC,CAAA;AAC9E,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,WAAqB,EAAC;AAC5B,EAAA,MAAM,SAAA,GAAY,mBAAA;AAClB,EAAA,IAAI,KAAA;AACJ,EAAA,OAAA,CAAQ,KAAA,GAAQ,UAAU,IAAA,CAAK,cAAA,CAAe,CAAC,CAAA,IAAK,EAAE,OAAO,IAAA,EAAM;AACjE,IAAA,IAAI,KAAA,CAAM,CAAC,CAAA,EAAG;AACZ,MAAA,QAAA,CAAS,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA;AAAA,IACxB;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,QAAQ,CAAC,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM;AAC3C,IAAA,MAAM,SAAA,GAAY,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,MAAM,SAAA,GAAY,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,IAAI,SAAA,CAAU,MAAA,KAAW,SAAA,CAAU,MAAA,EAAQ;AACzC,MAAA,OAAO,SAAA,CAAU,SAAS,SAAA,CAAU,MAAA;AAAA,IACtC;AACA,IAAA,MAAM,QAAA,GAAW,UAAU,MAAA,CAAO,CAAA,CAAA,KAAK,EAAE,UAAA,CAAW,GAAG,CAAC,CAAA,CAAE,MAAA;AAC1D,IAAA,MAAM,QAAA,GAAW,UAAU,MAAA,CAAO,CAAA,CAAA,KAAK,EAAE,UAAA,CAAW,GAAG,CAAC,CAAA,CAAE,MAAA;AAC1D,IAAA,OAAO,QAAA,GAAW,QAAA;AAAA,EACpB,CAAC,CAAA;AACH;;;;;"}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
3
|
const autoInstrumentMiddleware = require('./autoInstrumentMiddleware.js');
|
|
4
|
+
const routePatterns = require('./routePatterns.js');
|
|
4
5
|
const sourceMaps = require('./sourceMaps.js');
|
|
5
6
|
const tunnelRoute = require('./tunnelRoute.js');
|
|
6
7
|
|
|
7
8
|
function sentryTanstackStart(options = {}) {
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
|
|
9
|
+
const plugins = [routePatterns.makeRoutePatternPlugin()];
|
|
10
|
+
if (options.tunnelRoute) {
|
|
11
|
+
plugins.push(tunnelRoute.makeTunnelRoutePlugin(options.tunnelRoute, options.debug));
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
plugins.push(tunnelRoutePlugin);
|
|
13
|
+
if (process.env.NODE_ENV === "development") {
|
|
14
|
+
return plugins;
|
|
15
15
|
}
|
|
16
|
+
plugins.push(...sourceMaps.makeAddSentryVitePlugin(options));
|
|
16
17
|
if (options.autoInstrumentMiddleware !== false) {
|
|
17
18
|
plugins.push(autoInstrumentMiddleware.makeAutoInstrumentMiddlewarePlugin({ enabled: true, debug: options.debug }));
|
|
18
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sentryTanstackStart.js","sources":["../../../src/vite/sentryTanstackStart.ts"],"sourcesContent":["import type { BuildTimeOptionsBase } from '@sentry/core';\nimport type { Plugin } from 'vite';\nimport { makeAutoInstrumentMiddlewarePlugin } from './autoInstrumentMiddleware';\nimport { makeAddSentryVitePlugin, makeEnableSourceMapsVitePlugin } from './sourceMaps';\nimport type { TunnelRouteOptions } from './tunnelRoute';\nimport { makeTunnelRoutePlugin } from './tunnelRoute';\n\n/**\n * Build-time options for the Sentry TanStack Start SDK.\n */\nexport interface SentryTanstackStartOptions extends BuildTimeOptionsBase {\n /**\n * If this flag is `true`, the Sentry plugins will automatically instrument TanStack Start middlewares.\n *\n * This wraps global middlewares (`requestMiddleware` and `functionMiddleware`) in `createStart()` with Sentry\n * instrumentation to capture performance data.\n *\n * Set to `false` to disable automatic middleware instrumentation if you prefer to wrap middlewares manually\n * using `wrapMiddlewaresWithSentry`.\n *\n * @default true\n */\n autoInstrumentMiddleware?: boolean;\n\n /**\n * Configures a framework-managed same-origin tunnel route for Sentry envelopes.\n *\n * This creates a TanStack Start server route backed by `createSentryTunnelRoute()` and applies the resulting path\n * as the default `tunnel` option on the client.\n *\n * You can pass:\n * - `true` to generate an opaque route path per dev session or production build.\n * - `'/custom-path'` to use a fixed static route path.\n * - `{ allowedDsns, path }` for full control. If `allowedDsns` is omitted or empty, the tunnel route derives the DSN\n * from the active server Sentry client at runtime.\n *\n * If you also pass `tunnel` to `Sentry.init()`, that explicit runtime option wins and a warning is emitted because\n * the managed tunnel route is being bypassed.\n */\n tunnelRoute?: TunnelRouteOptions;\n}\n\n/**\n * Vite plugins for the Sentry TanStack Start SDK.\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import { sentryTanstackStart } from '@sentry/tanstackstart-react/vite';\n * import { tanstackStart } from '@tanstack/react-start/plugin/vite';\n *\n * export default defineConfig({\n * plugins: [\n * tanstackStart(),\n * sentryTanstackStart({\n * org: 'your-org',\n * project: 'your-project',\n * }),\n * ],\n * });\n * ```\n *\n * @param options - Options to configure the Sentry Vite plugins\n * @returns An array of Vite plugins\n */\nexport function sentryTanstackStart(options: SentryTanstackStartOptions = {}): Plugin[] {\n const
|
|
1
|
+
{"version":3,"file":"sentryTanstackStart.js","sources":["../../../src/vite/sentryTanstackStart.ts"],"sourcesContent":["import type { BuildTimeOptionsBase } from '@sentry/core';\nimport type { Plugin } from 'vite';\nimport { makeAutoInstrumentMiddlewarePlugin } from './autoInstrumentMiddleware';\nimport { makeRoutePatternPlugin } from './routePatterns';\nimport { makeAddSentryVitePlugin, makeEnableSourceMapsVitePlugin } from './sourceMaps';\nimport type { TunnelRouteOptions } from './tunnelRoute';\nimport { makeTunnelRoutePlugin } from './tunnelRoute';\n\n/**\n * Build-time options for the Sentry TanStack Start SDK.\n */\nexport interface SentryTanstackStartOptions extends BuildTimeOptionsBase {\n /**\n * If this flag is `true`, the Sentry plugins will automatically instrument TanStack Start middlewares.\n *\n * This wraps global middlewares (`requestMiddleware` and `functionMiddleware`) in `createStart()` with Sentry\n * instrumentation to capture performance data.\n *\n * Set to `false` to disable automatic middleware instrumentation if you prefer to wrap middlewares manually\n * using `wrapMiddlewaresWithSentry`.\n *\n * @default true\n */\n autoInstrumentMiddleware?: boolean;\n\n /**\n * Options related to react component name annotations.\n * Disabled by default, unless a value is set for this option.\n * When enabled, your app's DOM will automatically be annotated during build-time with their respective component names.\n * This will unlock the capability to search for Replays in Sentry by component name, as well as see component names in breadcrumbs and performance monitoring.\n * Please note that this feature is not currently supported by the esbuild bundler plugins, and will only annotate React components\n */\n reactComponentAnnotation?: {\n /**\n * Whether the component name annotate plugin should be enabled or not.\n */\n enabled?: boolean;\n\n /**\n * A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components.\n */\n ignoredComponents?: string[];\n };\n\n /**\n * Configures a framework-managed same-origin tunnel route for Sentry envelopes.\n *\n * This creates a TanStack Start server route backed by `createSentryTunnelRoute()` and applies the resulting path\n * as the default `tunnel` option on the client.\n *\n * You can pass:\n * - `true` to generate an opaque route path per dev session or production build.\n * - `'/custom-path'` to use a fixed static route path.\n * - `{ allowedDsns, path }` for full control. If `allowedDsns` is omitted or empty, the tunnel route derives the DSN\n * from the active server Sentry client at runtime.\n *\n * If you also pass `tunnel` to `Sentry.init()`, that explicit runtime option wins and a warning is emitted because\n * the managed tunnel route is being bypassed.\n */\n tunnelRoute?: TunnelRouteOptions;\n}\n\n/**\n * Vite plugins for the Sentry TanStack Start SDK.\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import { sentryTanstackStart } from '@sentry/tanstackstart-react/vite';\n * import { tanstackStart } from '@tanstack/react-start/plugin/vite';\n *\n * export default defineConfig({\n * plugins: [\n * tanstackStart(),\n * sentryTanstackStart({\n * org: 'your-org',\n * project: 'your-project',\n * }),\n * ],\n * });\n * ```\n *\n * @param options - Options to configure the Sentry Vite plugins\n * @returns An array of Vite plugins\n */\nexport function sentryTanstackStart(options: SentryTanstackStartOptions = {}): Plugin[] {\n const plugins: Plugin[] = [makeRoutePatternPlugin()];\n\n if (options.tunnelRoute) {\n plugins.push(makeTunnelRoutePlugin(options.tunnelRoute, options.debug));\n }\n\n // only add build-time plugins in production builds\n if (process.env.NODE_ENV === 'development') {\n return plugins;\n }\n\n plugins.push(...makeAddSentryVitePlugin(options));\n\n // middleware auto-instrumentation\n if (options.autoInstrumentMiddleware !== false) {\n plugins.push(makeAutoInstrumentMiddlewarePlugin({ enabled: true, debug: options.debug }));\n }\n\n // source maps\n const sourceMapsDisabled = options.sourcemaps?.disable === true || options.sourcemaps?.disable === 'disable-upload';\n if (!sourceMapsDisabled) {\n plugins.push(...makeEnableSourceMapsVitePlugin(options));\n }\n\n return plugins;\n}\n"],"names":["makeRoutePatternPlugin","makeTunnelRoutePlugin","makeAddSentryVitePlugin","makeAutoInstrumentMiddlewarePlugin","makeEnableSourceMapsVitePlugin"],"mappings":";;;;;;;AAsFO,SAAS,mBAAA,CAAoB,OAAA,GAAsC,EAAC,EAAa;AACtF,EAAA,MAAM,OAAA,GAAoB,CAACA,oCAAA,EAAwB,CAAA;AAEnD,EAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,IAAA,OAAA,CAAQ,KAAKC,iCAAA,CAAsB,OAAA,CAAQ,WAAA,EAAa,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EACxE;AAGA,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,aAAA,EAAe;AAC1C,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,OAAA,CAAQ,IAAA,CAAK,GAAGC,kCAAA,CAAwB,OAAO,CAAC,CAAA;AAGhD,EAAA,IAAI,OAAA,CAAQ,6BAA6B,KAAA,EAAO;AAC9C,IAAA,OAAA,CAAQ,IAAA,CAAKC,4DAAmC,EAAE,OAAA,EAAS,MAAM,KAAA,EAAO,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAAA,EAC1F;AAGA,EAAA,MAAM,qBAAqB,OAAA,CAAQ,UAAA,EAAY,YAAY,IAAA,IAAQ,OAAA,CAAQ,YAAY,OAAA,KAAY,gBAAA;AACnG,EAAA,IAAI,CAAC,kBAAA,EAAoB;AACvB,IAAA,OAAA,CAAQ,IAAA,CAAK,GAAGC,yCAAA,CAA+B,OAAO,CAAC,CAAA;AAAA,EACzD;AAEA,EAAA,OAAO,OAAA;AACT;;;;"}
|
|
@@ -16,7 +16,8 @@ function makeAddSentryVitePlugin(options) {
|
|
|
16
16
|
sentryUrl,
|
|
17
17
|
silent,
|
|
18
18
|
sourcemaps,
|
|
19
|
-
telemetry
|
|
19
|
+
telemetry,
|
|
20
|
+
reactComponentAnnotation
|
|
20
21
|
} = options;
|
|
21
22
|
let resolveFilesToDeleteAfterUpload;
|
|
22
23
|
const filesToDeleteAfterUploadPromise = new Promise((resolve) => {
|
|
@@ -60,6 +61,10 @@ function makeAddSentryVitePlugin(options) {
|
|
|
60
61
|
rewriteSources: sourcemaps?.rewriteSources,
|
|
61
62
|
filesToDeleteAfterUpload: filesToDeleteAfterUploadPromise
|
|
62
63
|
},
|
|
64
|
+
reactComponentAnnotation: {
|
|
65
|
+
enabled: reactComponentAnnotation?.enabled ?? void 0,
|
|
66
|
+
ignoredComponents: reactComponentAnnotation?.ignoredComponents ?? void 0
|
|
67
|
+
},
|
|
63
68
|
telemetry: telemetry ?? true,
|
|
64
69
|
url: sentryUrl,
|
|
65
70
|
_metaOptions: {
|