@sentry/tanstackstart-react 10.38.0 → 10.39.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/build/cjs/server/utils.js +1 -1
- package/build/cjs/server/utils.js.map +1 -1
- package/build/cjs/vite/autoInstrumentMiddleware.js +50 -28
- package/build/cjs/vite/autoInstrumentMiddleware.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server/utils.js +1 -1
- package/build/esm/server/utils.js.map +1 -1
- package/build/esm/vite/autoInstrumentMiddleware.js +50 -29
- package/build/esm/vite/autoInstrumentMiddleware.js.map +1 -1
- package/build/types/vite/autoInstrumentMiddleware.d.ts +4 -0
- package/build/types/vite/autoInstrumentMiddleware.d.ts.map +1 -1
- package/build/types-ts3.8/vite/autoInstrumentMiddleware.d.ts +4 -0
- package/package.json +5 -5
|
@@ -23,7 +23,7 @@ function getMiddlewareSpanOptions(name) {
|
|
|
23
23
|
op: 'middleware.tanstackstart',
|
|
24
24
|
name,
|
|
25
25
|
attributes: {
|
|
26
|
-
[node.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: '
|
|
26
|
+
[node.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.middleware.tanstackstart',
|
|
27
27
|
[node.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'middleware.tanstackstart',
|
|
28
28
|
},
|
|
29
29
|
};
|
|
@@ -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 * Extracts the SHA-256 hash from a server function pathname.\n * Server function pathnames are structured as `/_serverFn/<hash>`.\n * This function matches the pattern and returns the hash if found.\n *\n * @param pathname - the pathname of the server function\n * @returns the sha256 of the server function\n */\nexport function extractServerFunctionSha256(pathname: string): string {\n const serverFnMatch = pathname.match(/\\/_serverFn\\/([a-f0-9]{64})/i);\n return serverFnMatch?.[1] ?? 'unknown';\n}\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]: '
|
|
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 * Extracts the SHA-256 hash from a server function pathname.\n * Server function pathnames are structured as `/_serverFn/<hash>`.\n * This function matches the pattern and returns the hash if found.\n *\n * @param pathname - the pathname of the server function\n * @returns the sha256 of the server function\n */\nexport function extractServerFunctionSha256(pathname: string): string {\n const serverFnMatch = pathname.match(/\\/_serverFn\\/([a-f0-9]{64})/i);\n return serverFnMatch?.[1] ?? 'unknown';\n}\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":";;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,2BAA2B,CAAC,QAAQ,EAAkB;AACtE,EAAE,MAAM,gBAAgB,QAAQ,CAAC,KAAK,CAAC,8BAA8B,CAAC;AACtE,EAAE,OAAO,aAAa,GAAG,CAAC,CAAA,IAAK,SAAS;AACxC;;AAEA;AACA;AACA;AACO,SAAS,wBAAwB,CAAC,IAAI,EAA4B;AACzE,EAAE,OAAO;AACT,IAAI,EAAE,EAAE,0BAA0B;AAClC,IAAI,IAAI;AACR,IAAI,UAAU,EAAE;AAChB,MAAM,CAACA,qCAAgC,GAAG,+BAA+B;AACzE,MAAM,CAACC,iCAA4B,GAAG,0BAA0B;AAChE,KAAK;AACL,GAAG;AACH;;;;;"}
|
|
@@ -15,6 +15,10 @@ function wrapMiddlewareArrays(code, id, debug, regex) {
|
|
|
15
15
|
// eslint-disable-next-line no-console
|
|
16
16
|
console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);
|
|
17
17
|
}
|
|
18
|
+
// Handle method call syntax like `.middleware([...])` vs object property syntax like `middleware: [...]`
|
|
19
|
+
if (key.endsWith('(')) {
|
|
20
|
+
return `${key}wrapMiddlewaresWithSentry(${objContents}))`;
|
|
21
|
+
}
|
|
18
22
|
return `${key}: wrapMiddlewaresWithSentry(${objContents})`;
|
|
19
23
|
}
|
|
20
24
|
// Track middlewares that couldn't be auto-wrapped
|
|
@@ -42,6 +46,30 @@ function wrapRouteMiddleware(code, id, debug) {
|
|
|
42
46
|
return wrapMiddlewareArrays(code, id, debug, /(middleware)\s*:\s*\[([^\]]*)\]/g);
|
|
43
47
|
}
|
|
44
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Wraps middleware arrays in createServerFn().middleware([...]) calls.
|
|
51
|
+
*/
|
|
52
|
+
function wrapServerFnMiddleware(code, id, debug) {
|
|
53
|
+
return wrapMiddlewareArrays(code, id, debug, /(\.middleware\s*\()\s*\[([^\]]*)\]\s*\)/g);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Applies a wrap function to the current state and returns the updated state.
|
|
58
|
+
*/
|
|
59
|
+
function applyWrap(
|
|
60
|
+
state,
|
|
61
|
+
wrapFn,
|
|
62
|
+
id,
|
|
63
|
+
debug,
|
|
64
|
+
) {
|
|
65
|
+
const result = wrapFn(state.code, id, debug);
|
|
66
|
+
return {
|
|
67
|
+
code: result.code,
|
|
68
|
+
needsImport: state.needsImport || result.didWrap,
|
|
69
|
+
skippedMiddlewares: [...state.skippedMiddlewares, ...result.skipped],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
45
73
|
/**
|
|
46
74
|
* A Vite plugin that automatically instruments TanStack Start middlewares:
|
|
47
75
|
* - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`
|
|
@@ -67,8 +95,9 @@ function makeAutoInstrumentMiddlewarePlugin(options = {}) {
|
|
|
67
95
|
// Detect file types that should be instrumented
|
|
68
96
|
const isStartFile = id.includes('start') && code.includes('createStart(');
|
|
69
97
|
const isRouteFile = code.includes('createFileRoute(') && /middleware\s*:\s*\[/.test(code);
|
|
98
|
+
const isServerFnFile = code.includes('createServerFn') && /\.middleware\s*\(\s*\[/.test(code);
|
|
70
99
|
|
|
71
|
-
if (!isStartFile && !isRouteFile) {
|
|
100
|
+
if (!isStartFile && !isRouteFile && !isServerFnFile) {
|
|
72
101
|
return null;
|
|
73
102
|
}
|
|
74
103
|
|
|
@@ -77,46 +106,38 @@ function makeAutoInstrumentMiddlewarePlugin(options = {}) {
|
|
|
77
106
|
return null;
|
|
78
107
|
}
|
|
79
108
|
|
|
80
|
-
let
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const result = wrapRouteMiddleware(transformed, id, debug);
|
|
96
|
-
transformed = result.code;
|
|
97
|
-
needsImport = needsImport || result.didWrap;
|
|
98
|
-
skippedMiddlewares.push(...result.skipped);
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
109
|
+
let fileTransformState = {
|
|
110
|
+
code,
|
|
111
|
+
needsImport: false,
|
|
112
|
+
skippedMiddlewares: [],
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Wrap middlewares
|
|
116
|
+
if (isStartFile) {
|
|
117
|
+
fileTransformState = applyWrap(fileTransformState, wrapGlobalMiddleware, id, debug);
|
|
118
|
+
}
|
|
119
|
+
if (isRouteFile) {
|
|
120
|
+
fileTransformState = applyWrap(fileTransformState, wrapRouteMiddleware, id, debug);
|
|
121
|
+
}
|
|
122
|
+
if (isServerFnFile) {
|
|
123
|
+
fileTransformState = applyWrap(fileTransformState, wrapServerFnMiddleware, id, debug);
|
|
101
124
|
}
|
|
102
125
|
|
|
103
126
|
// Warn about middlewares that couldn't be auto-wrapped
|
|
104
|
-
if (skippedMiddlewares.length > 0) {
|
|
127
|
+
if (fileTransformState.skippedMiddlewares.length > 0) {
|
|
105
128
|
// eslint-disable-next-line no-console
|
|
106
129
|
console.warn(
|
|
107
|
-
`[Sentry] Could not auto-instrument ${skippedMiddlewares.join(' and ')} in ${id}. ` +
|
|
130
|
+
`[Sentry] Could not auto-instrument ${fileTransformState.skippedMiddlewares.join(' and ')} in ${id}. ` +
|
|
108
131
|
'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ',
|
|
109
132
|
);
|
|
110
133
|
}
|
|
111
134
|
|
|
112
135
|
// We didn't wrap any middlewares, so we don't need to import the wrapMiddlewaresWithSentry function
|
|
113
|
-
if (!needsImport) {
|
|
136
|
+
if (!fileTransformState.needsImport) {
|
|
114
137
|
return null;
|
|
115
138
|
}
|
|
116
139
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return { code: transformed, map: null };
|
|
140
|
+
return { code: addSentryImport(fileTransformState.code), map: null };
|
|
120
141
|
},
|
|
121
142
|
};
|
|
122
143
|
}
|
|
@@ -174,4 +195,5 @@ exports.arrayToObjectShorthand = arrayToObjectShorthand;
|
|
|
174
195
|
exports.makeAutoInstrumentMiddlewarePlugin = makeAutoInstrumentMiddlewarePlugin;
|
|
175
196
|
exports.wrapGlobalMiddleware = wrapGlobalMiddleware;
|
|
176
197
|
exports.wrapRouteMiddleware = wrapRouteMiddleware;
|
|
198
|
+
exports.wrapServerFnMiddleware = wrapServerFnMiddleware;
|
|
177
199
|
//# sourceMappingURL=autoInstrumentMiddleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoInstrumentMiddleware.js","sources":["../../../src/vite/autoInstrumentMiddleware.ts"],"sourcesContent":["import type { Plugin } from 'vite';\n\ntype AutoInstrumentMiddlewareOptions = {\n enabled?: boolean;\n debug?: boolean;\n};\n\ntype WrapResult = {\n code: string;\n didWrap: boolean;\n skipped: string[];\n};\n\n/**\n * Core function that wraps middleware arrays matching the given regex.\n */\nfunction wrapMiddlewareArrays(code: string, id: string, debug: boolean, regex: RegExp): WrapResult {\n const skipped: string[] = [];\n let didWrap = false;\n\n const transformed = code.replace(regex, (match: string, key: string, contents: string) => {\n const objContents = arrayToObjectShorthand(contents);\n if (objContents) {\n didWrap = true;\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);\n }\n return `${key}: wrapMiddlewaresWithSentry(${objContents})`;\n }\n // Track middlewares that couldn't be auto-wrapped\n // Skip if we matched whitespace only\n if (contents.trim()) {\n skipped.push(key);\n }\n return match;\n });\n\n return { code: transformed, didWrap, skipped };\n}\n\n/**\n * Wraps global middleware arrays (requestMiddleware, functionMiddleware) in createStart() files.\n */\nexport function wrapGlobalMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(requestMiddleware|functionMiddleware)\\s*:\\s*\\[([^\\]]*)\\]/g);\n}\n\n/**\n * Wraps route middleware arrays in createFileRoute() files.\n */\nexport function wrapRouteMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(middleware)\\s*:\\s*\\[([^\\]]*)\\]/g);\n}\n\n/**\n * A Vite plugin that automatically instruments TanStack Start middlewares:\n * - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`\n * - `middleware` arrays in `createFileRoute()` route definitions\n */\nexport function makeAutoInstrumentMiddlewarePlugin(options: AutoInstrumentMiddlewareOptions = {}): Plugin {\n const { enabled = true, debug = false } = options;\n\n return {\n name: 'sentry-tanstack-middleware-auto-instrument',\n enforce: 'pre',\n\n transform(code, id) {\n if (!enabled) {\n return null;\n }\n\n // Skip if not a TS/JS file\n if (!/\\.(ts|tsx|js|jsx|mjs|mts)$/.test(id)) {\n return null;\n }\n\n // Detect file types that should be instrumented\n const isStartFile = id.includes('start') && code.includes('createStart(');\n const isRouteFile = code.includes('createFileRoute(') && /middleware\\s*:\\s*\\[/.test(code);\n\n if (!isStartFile && !isRouteFile) {\n return null;\n }\n\n // Skip if the user already did some manual wrapping\n if (code.includes('wrapMiddlewaresWithSentry')) {\n return null;\n }\n\n let transformed = code;\n let needsImport = false;\n const skippedMiddlewares: string[] = [];\n\n switch (true) {\n // global middleware\n case isStartFile: {\n const result = wrapGlobalMiddleware(transformed, id, debug);\n transformed = result.code;\n needsImport = needsImport || result.didWrap;\n skippedMiddlewares.push(...result.skipped);\n break;\n }\n // route middleware\n case isRouteFile: {\n const result = wrapRouteMiddleware(transformed, id, debug);\n transformed = result.code;\n needsImport = needsImport || result.didWrap;\n skippedMiddlewares.push(...result.skipped);\n break;\n }\n default:\n break;\n }\n\n // Warn about middlewares that couldn't be auto-wrapped\n if (skippedMiddlewares.length > 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `[Sentry] Could not auto-instrument ${skippedMiddlewares.join(' and ')} in ${id}. ` +\n 'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ',\n );\n }\n\n // We didn't wrap any middlewares, so we don't need to import the wrapMiddlewaresWithSentry function\n if (!needsImport) {\n return null;\n }\n\n transformed = addSentryImport(transformed);\n\n return { code: transformed, map: null };\n },\n };\n}\n\n/**\n * Convert array contents to object shorthand syntax.\n * e.g., \"foo, bar, baz\" → \"{ foo, bar, baz }\"\n *\n * Returns null if contents contain non-identifier expressions (function calls, etc.)\n * which cannot be converted to object shorthand.\n */\nexport function arrayToObjectShorthand(contents: string): string | null {\n const items = contents\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n // Only convert if all items are valid identifiers (no complex expressions)\n const allIdentifiers = items.every(item => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(item));\n if (!allIdentifiers || items.length === 0) {\n return null;\n }\n\n // Deduplicate to avoid invalid syntax like { foo, foo }\n const uniqueItems = [...new Set(items)];\n\n return `{ ${uniqueItems.join(', ')} }`;\n}\n\n/**\n * Adds the wrapMiddlewaresWithSentry import to the code.\n * Handles 'use client' and 'use server' directives by inserting the import after them.\n */\nexport function addSentryImport(code: string): string {\n const sentryImport = \"import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\\n\";\n\n // Don't add the import if it already exists\n if (code.includes(sentryImport.trimEnd())) {\n return code;\n }\n\n // Check for 'use server' or 'use client' directives, these need to be before any imports\n const directiveMatch = code.match(/^(['\"])use (client|server)\\1;?\\s*\\n?/);\n\n if (!directiveMatch) {\n return sentryImport + code;\n }\n\n const directive = directiveMatch[0];\n return directive + sentryImport + code.slice(directive.length);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"autoInstrumentMiddleware.js","sources":["../../../src/vite/autoInstrumentMiddleware.ts"],"sourcesContent":["import type { Plugin } from 'vite';\n\ntype AutoInstrumentMiddlewareOptions = {\n enabled?: boolean;\n debug?: boolean;\n};\n\ntype WrapResult = {\n code: string;\n didWrap: boolean;\n skipped: string[];\n};\n\ntype FileTransformState = {\n code: string;\n needsImport: boolean;\n skippedMiddlewares: string[];\n};\n\n/**\n * Core function that wraps middleware arrays matching the given regex.\n */\nfunction wrapMiddlewareArrays(code: string, id: string, debug: boolean, regex: RegExp): WrapResult {\n const skipped: string[] = [];\n let didWrap = false;\n\n const transformed = code.replace(regex, (match: string, key: string, contents: string) => {\n const objContents = arrayToObjectShorthand(contents);\n if (objContents) {\n didWrap = true;\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);\n }\n // Handle method call syntax like `.middleware([...])` vs object property syntax like `middleware: [...]`\n if (key.endsWith('(')) {\n return `${key}wrapMiddlewaresWithSentry(${objContents}))`;\n }\n return `${key}: wrapMiddlewaresWithSentry(${objContents})`;\n }\n // Track middlewares that couldn't be auto-wrapped\n // Skip if we matched whitespace only\n if (contents.trim()) {\n skipped.push(key);\n }\n return match;\n });\n\n return { code: transformed, didWrap, skipped };\n}\n\n/**\n * Wraps global middleware arrays (requestMiddleware, functionMiddleware) in createStart() files.\n */\nexport function wrapGlobalMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(requestMiddleware|functionMiddleware)\\s*:\\s*\\[([^\\]]*)\\]/g);\n}\n\n/**\n * Wraps route middleware arrays in createFileRoute() files.\n */\nexport function wrapRouteMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(middleware)\\s*:\\s*\\[([^\\]]*)\\]/g);\n}\n\n/**\n * Wraps middleware arrays in createServerFn().middleware([...]) calls.\n */\nexport function wrapServerFnMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(\\.middleware\\s*\\()\\s*\\[([^\\]]*)\\]\\s*\\)/g);\n}\n\n/**\n * Applies a wrap function to the current state and returns the updated state.\n */\nfunction applyWrap(\n state: FileTransformState,\n wrapFn: (code: string, id: string, debug: boolean) => WrapResult,\n id: string,\n debug: boolean,\n): FileTransformState {\n const result = wrapFn(state.code, id, debug);\n return {\n code: result.code,\n needsImport: state.needsImport || result.didWrap,\n skippedMiddlewares: [...state.skippedMiddlewares, ...result.skipped],\n };\n}\n\n/**\n * A Vite plugin that automatically instruments TanStack Start middlewares:\n * - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`\n * - `middleware` arrays in `createFileRoute()` route definitions\n */\nexport function makeAutoInstrumentMiddlewarePlugin(options: AutoInstrumentMiddlewareOptions = {}): Plugin {\n const { enabled = true, debug = false } = options;\n\n return {\n name: 'sentry-tanstack-middleware-auto-instrument',\n enforce: 'pre',\n\n transform(code, id) {\n if (!enabled) {\n return null;\n }\n\n // Skip if not a TS/JS file\n if (!/\\.(ts|tsx|js|jsx|mjs|mts)$/.test(id)) {\n return null;\n }\n\n // Detect file types that should be instrumented\n const isStartFile = id.includes('start') && code.includes('createStart(');\n const isRouteFile = code.includes('createFileRoute(') && /middleware\\s*:\\s*\\[/.test(code);\n const isServerFnFile = code.includes('createServerFn') && /\\.middleware\\s*\\(\\s*\\[/.test(code);\n\n if (!isStartFile && !isRouteFile && !isServerFnFile) {\n return null;\n }\n\n // Skip if the user already did some manual wrapping\n if (code.includes('wrapMiddlewaresWithSentry')) {\n return null;\n }\n\n let fileTransformState: FileTransformState = {\n code,\n needsImport: false,\n skippedMiddlewares: [],\n };\n\n // Wrap middlewares\n if (isStartFile) {\n fileTransformState = applyWrap(fileTransformState, wrapGlobalMiddleware, id, debug);\n }\n if (isRouteFile) {\n fileTransformState = applyWrap(fileTransformState, wrapRouteMiddleware, id, debug);\n }\n if (isServerFnFile) {\n fileTransformState = applyWrap(fileTransformState, wrapServerFnMiddleware, id, debug);\n }\n\n // Warn about middlewares that couldn't be auto-wrapped\n if (fileTransformState.skippedMiddlewares.length > 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `[Sentry] Could not auto-instrument ${fileTransformState.skippedMiddlewares.join(' and ')} in ${id}. ` +\n 'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ',\n );\n }\n\n // We didn't wrap any middlewares, so we don't need to import the wrapMiddlewaresWithSentry function\n if (!fileTransformState.needsImport) {\n return null;\n }\n\n return { code: addSentryImport(fileTransformState.code), map: null };\n },\n };\n}\n\n/**\n * Convert array contents to object shorthand syntax.\n * e.g., \"foo, bar, baz\" → \"{ foo, bar, baz }\"\n *\n * Returns null if contents contain non-identifier expressions (function calls, etc.)\n * which cannot be converted to object shorthand.\n */\nexport function arrayToObjectShorthand(contents: string): string | null {\n const items = contents\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n // Only convert if all items are valid identifiers (no complex expressions)\n const allIdentifiers = items.every(item => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(item));\n if (!allIdentifiers || items.length === 0) {\n return null;\n }\n\n // Deduplicate to avoid invalid syntax like { foo, foo }\n const uniqueItems = [...new Set(items)];\n\n return `{ ${uniqueItems.join(', ')} }`;\n}\n\n/**\n * Adds the wrapMiddlewaresWithSentry import to the code.\n * Handles 'use client' and 'use server' directives by inserting the import after them.\n */\nexport function addSentryImport(code: string): string {\n const sentryImport = \"import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\\n\";\n\n // Don't add the import if it already exists\n if (code.includes(sentryImport.trimEnd())) {\n return code;\n }\n\n // Check for 'use server' or 'use client' directives, these need to be before any imports\n const directiveMatch = code.match(/^(['\"])use (client|server)\\1;?\\s*\\n?/);\n\n if (!directiveMatch) {\n return sentryImport + code;\n }\n\n const directive = directiveMatch[0];\n return directive + sentryImport + code.slice(directive.length);\n}\n"],"names":[],"mappings":"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"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.
|
|
1
|
+
{"type":"module","version":"10.39.0","sideEffects":false}
|
|
@@ -21,7 +21,7 @@ function getMiddlewareSpanOptions(name) {
|
|
|
21
21
|
op: 'middleware.tanstackstart',
|
|
22
22
|
name,
|
|
23
23
|
attributes: {
|
|
24
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: '
|
|
24
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.middleware.tanstackstart',
|
|
25
25
|
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'middleware.tanstackstart',
|
|
26
26
|
},
|
|
27
27
|
};
|
|
@@ -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 * Extracts the SHA-256 hash from a server function pathname.\n * Server function pathnames are structured as `/_serverFn/<hash>`.\n * This function matches the pattern and returns the hash if found.\n *\n * @param pathname - the pathname of the server function\n * @returns the sha256 of the server function\n */\nexport function extractServerFunctionSha256(pathname: string): string {\n const serverFnMatch = pathname.match(/\\/_serverFn\\/([a-f0-9]{64})/i);\n return serverFnMatch?.[1] ?? 'unknown';\n}\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]: '
|
|
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 * Extracts the SHA-256 hash from a server function pathname.\n * Server function pathnames are structured as `/_serverFn/<hash>`.\n * This function matches the pattern and returns the hash if found.\n *\n * @param pathname - the pathname of the server function\n * @returns the sha256 of the server function\n */\nexport function extractServerFunctionSha256(pathname: string): string {\n const serverFnMatch = pathname.match(/\\/_serverFn\\/([a-f0-9]{64})/i);\n return serverFnMatch?.[1] ?? 'unknown';\n}\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":[],"mappings":";;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,2BAA2B,CAAC,QAAQ,EAAkB;AACtE,EAAE,MAAM,gBAAgB,QAAQ,CAAC,KAAK,CAAC,8BAA8B,CAAC;AACtE,EAAE,OAAO,aAAa,GAAG,CAAC,CAAA,IAAK,SAAS;AACxC;;AAEA;AACA;AACA;AACO,SAAS,wBAAwB,CAAC,IAAI,EAA4B;AACzE,EAAE,OAAO;AACT,IAAI,EAAE,EAAE,0BAA0B;AAClC,IAAI,IAAI;AACR,IAAI,UAAU,EAAE;AAChB,MAAM,CAAC,gCAAgC,GAAG,+BAA+B;AACzE,MAAM,CAAC,4BAA4B,GAAG,0BAA0B;AAChE,KAAK;AACL,GAAG;AACH;;;;"}
|
|
@@ -13,6 +13,10 @@ function wrapMiddlewareArrays(code, id, debug, regex) {
|
|
|
13
13
|
// eslint-disable-next-line no-console
|
|
14
14
|
console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);
|
|
15
15
|
}
|
|
16
|
+
// Handle method call syntax like `.middleware([...])` vs object property syntax like `middleware: [...]`
|
|
17
|
+
if (key.endsWith('(')) {
|
|
18
|
+
return `${key}wrapMiddlewaresWithSentry(${objContents}))`;
|
|
19
|
+
}
|
|
16
20
|
return `${key}: wrapMiddlewaresWithSentry(${objContents})`;
|
|
17
21
|
}
|
|
18
22
|
// Track middlewares that couldn't be auto-wrapped
|
|
@@ -40,6 +44,30 @@ function wrapRouteMiddleware(code, id, debug) {
|
|
|
40
44
|
return wrapMiddlewareArrays(code, id, debug, /(middleware)\s*:\s*\[([^\]]*)\]/g);
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Wraps middleware arrays in createServerFn().middleware([...]) calls.
|
|
49
|
+
*/
|
|
50
|
+
function wrapServerFnMiddleware(code, id, debug) {
|
|
51
|
+
return wrapMiddlewareArrays(code, id, debug, /(\.middleware\s*\()\s*\[([^\]]*)\]\s*\)/g);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Applies a wrap function to the current state and returns the updated state.
|
|
56
|
+
*/
|
|
57
|
+
function applyWrap(
|
|
58
|
+
state,
|
|
59
|
+
wrapFn,
|
|
60
|
+
id,
|
|
61
|
+
debug,
|
|
62
|
+
) {
|
|
63
|
+
const result = wrapFn(state.code, id, debug);
|
|
64
|
+
return {
|
|
65
|
+
code: result.code,
|
|
66
|
+
needsImport: state.needsImport || result.didWrap,
|
|
67
|
+
skippedMiddlewares: [...state.skippedMiddlewares, ...result.skipped],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
43
71
|
/**
|
|
44
72
|
* A Vite plugin that automatically instruments TanStack Start middlewares:
|
|
45
73
|
* - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`
|
|
@@ -65,8 +93,9 @@ function makeAutoInstrumentMiddlewarePlugin(options = {}) {
|
|
|
65
93
|
// Detect file types that should be instrumented
|
|
66
94
|
const isStartFile = id.includes('start') && code.includes('createStart(');
|
|
67
95
|
const isRouteFile = code.includes('createFileRoute(') && /middleware\s*:\s*\[/.test(code);
|
|
96
|
+
const isServerFnFile = code.includes('createServerFn') && /\.middleware\s*\(\s*\[/.test(code);
|
|
68
97
|
|
|
69
|
-
if (!isStartFile && !isRouteFile) {
|
|
98
|
+
if (!isStartFile && !isRouteFile && !isServerFnFile) {
|
|
70
99
|
return null;
|
|
71
100
|
}
|
|
72
101
|
|
|
@@ -75,46 +104,38 @@ function makeAutoInstrumentMiddlewarePlugin(options = {}) {
|
|
|
75
104
|
return null;
|
|
76
105
|
}
|
|
77
106
|
|
|
78
|
-
let
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const result = wrapRouteMiddleware(transformed, id, debug);
|
|
94
|
-
transformed = result.code;
|
|
95
|
-
needsImport = needsImport || result.didWrap;
|
|
96
|
-
skippedMiddlewares.push(...result.skipped);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
107
|
+
let fileTransformState = {
|
|
108
|
+
code,
|
|
109
|
+
needsImport: false,
|
|
110
|
+
skippedMiddlewares: [],
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Wrap middlewares
|
|
114
|
+
if (isStartFile) {
|
|
115
|
+
fileTransformState = applyWrap(fileTransformState, wrapGlobalMiddleware, id, debug);
|
|
116
|
+
}
|
|
117
|
+
if (isRouteFile) {
|
|
118
|
+
fileTransformState = applyWrap(fileTransformState, wrapRouteMiddleware, id, debug);
|
|
119
|
+
}
|
|
120
|
+
if (isServerFnFile) {
|
|
121
|
+
fileTransformState = applyWrap(fileTransformState, wrapServerFnMiddleware, id, debug);
|
|
99
122
|
}
|
|
100
123
|
|
|
101
124
|
// Warn about middlewares that couldn't be auto-wrapped
|
|
102
|
-
if (skippedMiddlewares.length > 0) {
|
|
125
|
+
if (fileTransformState.skippedMiddlewares.length > 0) {
|
|
103
126
|
// eslint-disable-next-line no-console
|
|
104
127
|
console.warn(
|
|
105
|
-
`[Sentry] Could not auto-instrument ${skippedMiddlewares.join(' and ')} in ${id}. ` +
|
|
128
|
+
`[Sentry] Could not auto-instrument ${fileTransformState.skippedMiddlewares.join(' and ')} in ${id}. ` +
|
|
106
129
|
'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ',
|
|
107
130
|
);
|
|
108
131
|
}
|
|
109
132
|
|
|
110
133
|
// We didn't wrap any middlewares, so we don't need to import the wrapMiddlewaresWithSentry function
|
|
111
|
-
if (!needsImport) {
|
|
134
|
+
if (!fileTransformState.needsImport) {
|
|
112
135
|
return null;
|
|
113
136
|
}
|
|
114
137
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return { code: transformed, map: null };
|
|
138
|
+
return { code: addSentryImport(fileTransformState.code), map: null };
|
|
118
139
|
},
|
|
119
140
|
};
|
|
120
141
|
}
|
|
@@ -167,5 +188,5 @@ function addSentryImport(code) {
|
|
|
167
188
|
return directive + sentryImport + code.slice(directive.length);
|
|
168
189
|
}
|
|
169
190
|
|
|
170
|
-
export { addSentryImport, arrayToObjectShorthand, makeAutoInstrumentMiddlewarePlugin, wrapGlobalMiddleware, wrapRouteMiddleware };
|
|
191
|
+
export { addSentryImport, arrayToObjectShorthand, makeAutoInstrumentMiddlewarePlugin, wrapGlobalMiddleware, wrapRouteMiddleware, wrapServerFnMiddleware };
|
|
171
192
|
//# sourceMappingURL=autoInstrumentMiddleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoInstrumentMiddleware.js","sources":["../../../src/vite/autoInstrumentMiddleware.ts"],"sourcesContent":["import type { Plugin } from 'vite';\n\ntype AutoInstrumentMiddlewareOptions = {\n enabled?: boolean;\n debug?: boolean;\n};\n\ntype WrapResult = {\n code: string;\n didWrap: boolean;\n skipped: string[];\n};\n\n/**\n * Core function that wraps middleware arrays matching the given regex.\n */\nfunction wrapMiddlewareArrays(code: string, id: string, debug: boolean, regex: RegExp): WrapResult {\n const skipped: string[] = [];\n let didWrap = false;\n\n const transformed = code.replace(regex, (match: string, key: string, contents: string) => {\n const objContents = arrayToObjectShorthand(contents);\n if (objContents) {\n didWrap = true;\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);\n }\n return `${key}: wrapMiddlewaresWithSentry(${objContents})`;\n }\n // Track middlewares that couldn't be auto-wrapped\n // Skip if we matched whitespace only\n if (contents.trim()) {\n skipped.push(key);\n }\n return match;\n });\n\n return { code: transformed, didWrap, skipped };\n}\n\n/**\n * Wraps global middleware arrays (requestMiddleware, functionMiddleware) in createStart() files.\n */\nexport function wrapGlobalMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(requestMiddleware|functionMiddleware)\\s*:\\s*\\[([^\\]]*)\\]/g);\n}\n\n/**\n * Wraps route middleware arrays in createFileRoute() files.\n */\nexport function wrapRouteMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(middleware)\\s*:\\s*\\[([^\\]]*)\\]/g);\n}\n\n/**\n * A Vite plugin that automatically instruments TanStack Start middlewares:\n * - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`\n * - `middleware` arrays in `createFileRoute()` route definitions\n */\nexport function makeAutoInstrumentMiddlewarePlugin(options: AutoInstrumentMiddlewareOptions = {}): Plugin {\n const { enabled = true, debug = false } = options;\n\n return {\n name: 'sentry-tanstack-middleware-auto-instrument',\n enforce: 'pre',\n\n transform(code, id) {\n if (!enabled) {\n return null;\n }\n\n // Skip if not a TS/JS file\n if (!/\\.(ts|tsx|js|jsx|mjs|mts)$/.test(id)) {\n return null;\n }\n\n // Detect file types that should be instrumented\n const isStartFile = id.includes('start') && code.includes('createStart(');\n const isRouteFile = code.includes('createFileRoute(') && /middleware\\s*:\\s*\\[/.test(code);\n\n if (!isStartFile && !isRouteFile) {\n return null;\n }\n\n // Skip if the user already did some manual wrapping\n if (code.includes('wrapMiddlewaresWithSentry')) {\n return null;\n }\n\n let transformed = code;\n let needsImport = false;\n const skippedMiddlewares: string[] = [];\n\n switch (true) {\n // global middleware\n case isStartFile: {\n const result = wrapGlobalMiddleware(transformed, id, debug);\n transformed = result.code;\n needsImport = needsImport || result.didWrap;\n skippedMiddlewares.push(...result.skipped);\n break;\n }\n // route middleware\n case isRouteFile: {\n const result = wrapRouteMiddleware(transformed, id, debug);\n transformed = result.code;\n needsImport = needsImport || result.didWrap;\n skippedMiddlewares.push(...result.skipped);\n break;\n }\n default:\n break;\n }\n\n // Warn about middlewares that couldn't be auto-wrapped\n if (skippedMiddlewares.length > 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `[Sentry] Could not auto-instrument ${skippedMiddlewares.join(' and ')} in ${id}. ` +\n 'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ',\n );\n }\n\n // We didn't wrap any middlewares, so we don't need to import the wrapMiddlewaresWithSentry function\n if (!needsImport) {\n return null;\n }\n\n transformed = addSentryImport(transformed);\n\n return { code: transformed, map: null };\n },\n };\n}\n\n/**\n * Convert array contents to object shorthand syntax.\n * e.g., \"foo, bar, baz\" → \"{ foo, bar, baz }\"\n *\n * Returns null if contents contain non-identifier expressions (function calls, etc.)\n * which cannot be converted to object shorthand.\n */\nexport function arrayToObjectShorthand(contents: string): string | null {\n const items = contents\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n // Only convert if all items are valid identifiers (no complex expressions)\n const allIdentifiers = items.every(item => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(item));\n if (!allIdentifiers || items.length === 0) {\n return null;\n }\n\n // Deduplicate to avoid invalid syntax like { foo, foo }\n const uniqueItems = [...new Set(items)];\n\n return `{ ${uniqueItems.join(', ')} }`;\n}\n\n/**\n * Adds the wrapMiddlewaresWithSentry import to the code.\n * Handles 'use client' and 'use server' directives by inserting the import after them.\n */\nexport function addSentryImport(code: string): string {\n const sentryImport = \"import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\\n\";\n\n // Don't add the import if it already exists\n if (code.includes(sentryImport.trimEnd())) {\n return code;\n }\n\n // Check for 'use server' or 'use client' directives, these need to be before any imports\n const directiveMatch = code.match(/^(['\"])use (client|server)\\1;?\\s*\\n?/);\n\n if (!directiveMatch) {\n return sentryImport + code;\n }\n\n const directive = directiveMatch[0];\n return directive + sentryImport + code.slice(directive.length);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"autoInstrumentMiddleware.js","sources":["../../../src/vite/autoInstrumentMiddleware.ts"],"sourcesContent":["import type { Plugin } from 'vite';\n\ntype AutoInstrumentMiddlewareOptions = {\n enabled?: boolean;\n debug?: boolean;\n};\n\ntype WrapResult = {\n code: string;\n didWrap: boolean;\n skipped: string[];\n};\n\ntype FileTransformState = {\n code: string;\n needsImport: boolean;\n skippedMiddlewares: string[];\n};\n\n/**\n * Core function that wraps middleware arrays matching the given regex.\n */\nfunction wrapMiddlewareArrays(code: string, id: string, debug: boolean, regex: RegExp): WrapResult {\n const skipped: string[] = [];\n let didWrap = false;\n\n const transformed = code.replace(regex, (match: string, key: string, contents: string) => {\n const objContents = arrayToObjectShorthand(contents);\n if (objContents) {\n didWrap = true;\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);\n }\n // Handle method call syntax like `.middleware([...])` vs object property syntax like `middleware: [...]`\n if (key.endsWith('(')) {\n return `${key}wrapMiddlewaresWithSentry(${objContents}))`;\n }\n return `${key}: wrapMiddlewaresWithSentry(${objContents})`;\n }\n // Track middlewares that couldn't be auto-wrapped\n // Skip if we matched whitespace only\n if (contents.trim()) {\n skipped.push(key);\n }\n return match;\n });\n\n return { code: transformed, didWrap, skipped };\n}\n\n/**\n * Wraps global middleware arrays (requestMiddleware, functionMiddleware) in createStart() files.\n */\nexport function wrapGlobalMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(requestMiddleware|functionMiddleware)\\s*:\\s*\\[([^\\]]*)\\]/g);\n}\n\n/**\n * Wraps route middleware arrays in createFileRoute() files.\n */\nexport function wrapRouteMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(middleware)\\s*:\\s*\\[([^\\]]*)\\]/g);\n}\n\n/**\n * Wraps middleware arrays in createServerFn().middleware([...]) calls.\n */\nexport function wrapServerFnMiddleware(code: string, id: string, debug: boolean): WrapResult {\n return wrapMiddlewareArrays(code, id, debug, /(\\.middleware\\s*\\()\\s*\\[([^\\]]*)\\]\\s*\\)/g);\n}\n\n/**\n * Applies a wrap function to the current state and returns the updated state.\n */\nfunction applyWrap(\n state: FileTransformState,\n wrapFn: (code: string, id: string, debug: boolean) => WrapResult,\n id: string,\n debug: boolean,\n): FileTransformState {\n const result = wrapFn(state.code, id, debug);\n return {\n code: result.code,\n needsImport: state.needsImport || result.didWrap,\n skippedMiddlewares: [...state.skippedMiddlewares, ...result.skipped],\n };\n}\n\n/**\n * A Vite plugin that automatically instruments TanStack Start middlewares:\n * - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`\n * - `middleware` arrays in `createFileRoute()` route definitions\n */\nexport function makeAutoInstrumentMiddlewarePlugin(options: AutoInstrumentMiddlewareOptions = {}): Plugin {\n const { enabled = true, debug = false } = options;\n\n return {\n name: 'sentry-tanstack-middleware-auto-instrument',\n enforce: 'pre',\n\n transform(code, id) {\n if (!enabled) {\n return null;\n }\n\n // Skip if not a TS/JS file\n if (!/\\.(ts|tsx|js|jsx|mjs|mts)$/.test(id)) {\n return null;\n }\n\n // Detect file types that should be instrumented\n const isStartFile = id.includes('start') && code.includes('createStart(');\n const isRouteFile = code.includes('createFileRoute(') && /middleware\\s*:\\s*\\[/.test(code);\n const isServerFnFile = code.includes('createServerFn') && /\\.middleware\\s*\\(\\s*\\[/.test(code);\n\n if (!isStartFile && !isRouteFile && !isServerFnFile) {\n return null;\n }\n\n // Skip if the user already did some manual wrapping\n if (code.includes('wrapMiddlewaresWithSentry')) {\n return null;\n }\n\n let fileTransformState: FileTransformState = {\n code,\n needsImport: false,\n skippedMiddlewares: [],\n };\n\n // Wrap middlewares\n if (isStartFile) {\n fileTransformState = applyWrap(fileTransformState, wrapGlobalMiddleware, id, debug);\n }\n if (isRouteFile) {\n fileTransformState = applyWrap(fileTransformState, wrapRouteMiddleware, id, debug);\n }\n if (isServerFnFile) {\n fileTransformState = applyWrap(fileTransformState, wrapServerFnMiddleware, id, debug);\n }\n\n // Warn about middlewares that couldn't be auto-wrapped\n if (fileTransformState.skippedMiddlewares.length > 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `[Sentry] Could not auto-instrument ${fileTransformState.skippedMiddlewares.join(' and ')} in ${id}. ` +\n 'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ',\n );\n }\n\n // We didn't wrap any middlewares, so we don't need to import the wrapMiddlewaresWithSentry function\n if (!fileTransformState.needsImport) {\n return null;\n }\n\n return { code: addSentryImport(fileTransformState.code), map: null };\n },\n };\n}\n\n/**\n * Convert array contents to object shorthand syntax.\n * e.g., \"foo, bar, baz\" → \"{ foo, bar, baz }\"\n *\n * Returns null if contents contain non-identifier expressions (function calls, etc.)\n * which cannot be converted to object shorthand.\n */\nexport function arrayToObjectShorthand(contents: string): string | null {\n const items = contents\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n // Only convert if all items are valid identifiers (no complex expressions)\n const allIdentifiers = items.every(item => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(item));\n if (!allIdentifiers || items.length === 0) {\n return null;\n }\n\n // Deduplicate to avoid invalid syntax like { foo, foo }\n const uniqueItems = [...new Set(items)];\n\n return `{ ${uniqueItems.join(', ')} }`;\n}\n\n/**\n * Adds the wrapMiddlewaresWithSentry import to the code.\n * Handles 'use client' and 'use server' directives by inserting the import after them.\n */\nexport function addSentryImport(code: string): string {\n const sentryImport = \"import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\\n\";\n\n // Don't add the import if it already exists\n if (code.includes(sentryImport.trimEnd())) {\n return code;\n }\n\n // Check for 'use server' or 'use client' directives, these need to be before any imports\n const directiveMatch = code.match(/^(['\"])use (client|server)\\1;?\\s*\\n?/);\n\n if (!directiveMatch) {\n return sentryImport + code;\n }\n\n const directive = directiveMatch[0];\n return directive + sentryImport + code.slice(directive.length);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,10 @@ export declare function wrapGlobalMiddleware(code: string, id: string, debug: bo
|
|
|
16
16
|
* Wraps route middleware arrays in createFileRoute() files.
|
|
17
17
|
*/
|
|
18
18
|
export declare function wrapRouteMiddleware(code: string, id: string, debug: boolean): WrapResult;
|
|
19
|
+
/**
|
|
20
|
+
* Wraps middleware arrays in createServerFn().middleware([...]) calls.
|
|
21
|
+
*/
|
|
22
|
+
export declare function wrapServerFnMiddleware(code: string, id: string, debug: boolean): WrapResult;
|
|
19
23
|
/**
|
|
20
24
|
* A Vite plugin that automatically instruments TanStack Start middlewares:
|
|
21
25
|
* - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoInstrumentMiddleware.d.ts","sourceRoot":"","sources":["../../../src/vite/autoInstrumentMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,KAAK,+BAA+B,GAAG;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;
|
|
1
|
+
{"version":3,"file":"autoInstrumentMiddleware.d.ts","sourceRoot":"","sources":["../../../src/vite/autoInstrumentMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,KAAK,+BAA+B,GAAG;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAwCF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,UAAU,CAEzF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,UAAU,CAExF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,UAAU,CAE3F;AAmBD;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,OAAO,GAAE,+BAAoC,GAAG,MAAM,CAiExG;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBtE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAiBpD"}
|
|
@@ -16,6 +16,10 @@ export declare function wrapGlobalMiddleware(code: string, id: string, debug: bo
|
|
|
16
16
|
* Wraps route middleware arrays in createFileRoute() files.
|
|
17
17
|
*/
|
|
18
18
|
export declare function wrapRouteMiddleware(code: string, id: string, debug: boolean): WrapResult;
|
|
19
|
+
/**
|
|
20
|
+
* Wraps middleware arrays in createServerFn().middleware([...]) calls.
|
|
21
|
+
*/
|
|
22
|
+
export declare function wrapServerFnMiddleware(code: string, id: string, debug: boolean): WrapResult;
|
|
19
23
|
/**
|
|
20
24
|
* A Vite plugin that automatically instruments TanStack Start middlewares:
|
|
21
25
|
* - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/tanstackstart-react",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.39.0",
|
|
4
4
|
"description": "Official Sentry SDK for TanStack Start React",
|
|
5
5
|
"repository": "git://github.com/getsentry/sentry-javascript.git",
|
|
6
6
|
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/tanstackstart-react",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@opentelemetry/api": "^1.9.0",
|
|
54
54
|
"@opentelemetry/semantic-conventions": "^1.37.0",
|
|
55
|
-
"@sentry-internal/browser-utils": "10.
|
|
56
|
-
"@sentry/core": "10.
|
|
57
|
-
"@sentry/node": "10.
|
|
58
|
-
"@sentry/react": "10.
|
|
55
|
+
"@sentry-internal/browser-utils": "10.39.0",
|
|
56
|
+
"@sentry/core": "10.39.0",
|
|
57
|
+
"@sentry/node": "10.39.0",
|
|
58
|
+
"@sentry/react": "10.39.0",
|
|
59
59
|
"@sentry/vite-plugin": "^4.8.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|