@sentry/tanstackstart-react 10.37.0 → 10.39.0-alpha.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.
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const index = require('./client/index.js');
4
- const sdk = require('./client/sdk.js');
5
4
  const react = require('@sentry/react');
5
+ const sdk = require('./client/sdk.js');
6
6
 
7
7
 
8
8
 
@@ -2,10 +2,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const index = require('./server/index.js');
4
4
  const sentryTanstackStart = require('./vite/sentryTanstackStart.js');
5
+ const node = require('@sentry/node');
5
6
  const sdk = require('./server/sdk.js');
6
7
  const wrapFetchWithSentry = require('./server/wrapFetchWithSentry.js');
7
8
  const middleware = require('./server/middleware.js');
8
- const node = require('@sentry/node');
9
9
 
10
10
 
11
11
 
@@ -23,7 +23,7 @@ function getMiddlewareSpanOptions(name) {
23
23
  op: 'middleware.tanstackstart',
24
24
  name,
25
25
  attributes: {
26
- [node.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'manual.middleware.tanstackstart',
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]: 'manual.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,iCAAiC;AAC3E,MAAM,CAACC,iCAA4B,GAAG,0BAA0B;AAChE,KAAK;AACL,GAAG;AACH;;;;;"}
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;;;;;"}
@@ -1,8 +1,79 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  /**
4
- * A Vite plugin that automatically instruments TanStack Start middlewares
5
- * by wrapping `requestMiddleware` and `functionMiddleware` arrays in `createStart()`.
4
+ * Core function that wraps middleware arrays matching the given regex.
5
+ */
6
+ function wrapMiddlewareArrays(code, id, debug, regex) {
7
+ const skipped = [];
8
+ let didWrap = false;
9
+
10
+ const transformed = code.replace(regex, (match, key, contents) => {
11
+ const objContents = arrayToObjectShorthand(contents);
12
+ if (objContents) {
13
+ didWrap = true;
14
+ if (debug) {
15
+ // eslint-disable-next-line no-console
16
+ console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);
17
+ }
18
+ // Handle method call syntax like `.middleware([...])` vs object property syntax like `middleware: [...]`
19
+ if (key.endsWith('(')) {
20
+ return `${key}wrapMiddlewaresWithSentry(${objContents}))`;
21
+ }
22
+ return `${key}: wrapMiddlewaresWithSentry(${objContents})`;
23
+ }
24
+ // Track middlewares that couldn't be auto-wrapped
25
+ // Skip if we matched whitespace only
26
+ if (contents.trim()) {
27
+ skipped.push(key);
28
+ }
29
+ return match;
30
+ });
31
+
32
+ return { code: transformed, didWrap, skipped };
33
+ }
34
+
35
+ /**
36
+ * Wraps global middleware arrays (requestMiddleware, functionMiddleware) in createStart() files.
37
+ */
38
+ function wrapGlobalMiddleware(code, id, debug) {
39
+ return wrapMiddlewareArrays(code, id, debug, /(requestMiddleware|functionMiddleware)\s*:\s*\[([^\]]*)\]/g);
40
+ }
41
+
42
+ /**
43
+ * Wraps route middleware arrays in createFileRoute() files.
44
+ */
45
+ function wrapRouteMiddleware(code, id, debug) {
46
+ return wrapMiddlewareArrays(code, id, debug, /(middleware)\s*:\s*\[([^\]]*)\]/g);
47
+ }
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
+
73
+ /**
74
+ * A Vite plugin that automatically instruments TanStack Start middlewares:
75
+ * - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`
76
+ * - `middleware` arrays in `createFileRoute()` route definitions
6
77
  */
7
78
  function makeAutoInstrumentMiddlewarePlugin(options = {}) {
8
79
  const { enabled = true, debug = false } = options;
@@ -21,9 +92,12 @@ function makeAutoInstrumentMiddlewarePlugin(options = {}) {
21
92
  return null;
22
93
  }
23
94
 
24
- // Only wrap requestMiddleware and functionMiddleware in createStart()
25
- // createStart() should always be in a file named start.ts
26
- if (!id.includes('start') || !code.includes('createStart(')) {
95
+ // Detect file types that should be instrumented
96
+ const isStartFile = id.includes('start') && code.includes('createStart(');
97
+ const isRouteFile = code.includes('createFileRoute(') && /middleware\s*:\s*\[/.test(code);
98
+ const isServerFnFile = code.includes('createServerFn') && /\.middleware\s*\(\s*\[/.test(code);
99
+
100
+ if (!isStartFile && !isRouteFile && !isServerFnFile) {
27
101
  return null;
28
102
  }
29
103
 
@@ -32,58 +106,38 @@ function makeAutoInstrumentMiddlewarePlugin(options = {}) {
32
106
  return null;
33
107
  }
34
108
 
35
- let transformed = code;
36
- let needsImport = false;
37
- const skippedMiddlewares = [];
38
-
39
- transformed = transformed.replace(
40
- /(requestMiddleware|functionMiddleware)\s*:\s*\[([^\]]*)\]/g,
41
- (match, key, contents) => {
42
- const objContents = arrayToObjectShorthand(contents);
43
- if (objContents) {
44
- needsImport = true;
45
- if (debug) {
46
- // eslint-disable-next-line no-console
47
- console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);
48
- }
49
- return `${key}: wrapMiddlewaresWithSentry(${objContents})`;
50
- }
51
- // Track middlewares that couldn't be auto-wrapped
52
- // Skip if we matched whitespace only
53
- if (contents.trim()) {
54
- skippedMiddlewares.push(key);
55
- }
56
- return match;
57
- },
58
- );
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);
124
+ }
59
125
 
60
126
  // Warn about middlewares that couldn't be auto-wrapped
61
- if (skippedMiddlewares.length > 0) {
127
+ if (fileTransformState.skippedMiddlewares.length > 0) {
62
128
  // eslint-disable-next-line no-console
63
129
  console.warn(
64
- `[Sentry] Could not auto-instrument ${skippedMiddlewares.join(' and ')} in ${id}. ` +
130
+ `[Sentry] Could not auto-instrument ${fileTransformState.skippedMiddlewares.join(' and ')} in ${id}. ` +
65
131
  'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ',
66
132
  );
67
133
  }
68
134
 
69
135
  // We didn't wrap any middlewares, so we don't need to import the wrapMiddlewaresWithSentry function
70
- if (!needsImport) {
136
+ if (!fileTransformState.needsImport) {
71
137
  return null;
72
138
  }
73
139
 
74
- const sentryImport = "import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\n";
75
-
76
- // Check for 'use server' or 'use client' directives, these need to be before any imports
77
- const directiveMatch = transformed.match(/^(['"])use (client|server)\1;?\s*\n?/);
78
- if (directiveMatch) {
79
- // Insert import after the directive
80
- const directive = directiveMatch[0];
81
- transformed = directive + sentryImport + transformed.slice(directive.length);
82
- } else {
83
- transformed = sentryImport + transformed;
84
- }
85
-
86
- return { code: transformed, map: null };
140
+ return { code: addSentryImport(fileTransformState.code), map: null };
87
141
  },
88
142
  };
89
143
  }
@@ -113,6 +167,33 @@ function arrayToObjectShorthand(contents) {
113
167
  return `{ ${uniqueItems.join(', ')} }`;
114
168
  }
115
169
 
170
+ /**
171
+ * Adds the wrapMiddlewaresWithSentry import to the code.
172
+ * Handles 'use client' and 'use server' directives by inserting the import after them.
173
+ */
174
+ function addSentryImport(code) {
175
+ const sentryImport = "import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\n";
176
+
177
+ // Don't add the import if it already exists
178
+ if (code.includes(sentryImport.trimEnd())) {
179
+ return code;
180
+ }
181
+
182
+ // Check for 'use server' or 'use client' directives, these need to be before any imports
183
+ const directiveMatch = code.match(/^(['"])use (client|server)\1;?\s*\n?/);
184
+
185
+ if (!directiveMatch) {
186
+ return sentryImport + code;
187
+ }
188
+
189
+ const directive = directiveMatch[0];
190
+ return directive + sentryImport + code.slice(directive.length);
191
+ }
192
+
193
+ exports.addSentryImport = addSentryImport;
116
194
  exports.arrayToObjectShorthand = arrayToObjectShorthand;
117
195
  exports.makeAutoInstrumentMiddlewarePlugin = makeAutoInstrumentMiddlewarePlugin;
196
+ exports.wrapGlobalMiddleware = wrapGlobalMiddleware;
197
+ exports.wrapRouteMiddleware = wrapRouteMiddleware;
198
+ exports.wrapServerFnMiddleware = wrapServerFnMiddleware;
118
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\n/**\n * A Vite plugin that automatically instruments TanStack Start middlewares\n * by wrapping `requestMiddleware` and `functionMiddleware` arrays in `createStart()`.\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 // Only wrap requestMiddleware and functionMiddleware in createStart()\n // createStart() should always be in a file named start.ts\n if (!id.includes('start') || !code.includes('createStart(')) {\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 transformed = transformed.replace(\n /(requestMiddleware|functionMiddleware)\\s*:\\s*\\[([^\\]]*)\\]/g,\n (match: string, key: string, contents: string) => {\n const objContents = arrayToObjectShorthand(contents);\n if (objContents) {\n needsImport = 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 skippedMiddlewares.push(key);\n }\n return match;\n },\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 const sentryImport = \"import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\\n\";\n\n // Check for 'use server' or 'use client' directives, these need to be before any imports\n const directiveMatch = transformed.match(/^(['\"])use (client|server)\\1;?\\s*\\n?/);\n if (directiveMatch) {\n // Insert import after the directive\n const directive = directiveMatch[0];\n transformed = directive + sentryImport + transformed.slice(directive.length);\n } else {\n transformed = sentryImport + transformed;\n }\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"],"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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"}
@@ -1,4 +1,4 @@
1
1
  export { wrapMiddlewaresWithSentry } from './client/index.js';
2
- export { init } from './client/sdk.js';
3
2
  export * from '@sentry/react';
3
+ export { init } from './client/sdk.js';
4
4
  //# sourceMappingURL=index.client.js.map
@@ -1,7 +1,7 @@
1
1
  export { ErrorBoundary, withErrorBoundary } from './server/index.js';
2
2
  export { sentryTanstackStart } from './vite/sentryTanstackStart.js';
3
+ export * from '@sentry/node';
3
4
  export { init } from './server/sdk.js';
4
5
  export { wrapFetchWithSentry } from './server/wrapFetchWithSentry.js';
5
6
  export { wrapMiddlewaresWithSentry } from './server/middleware.js';
6
- export * from '@sentry/node';
7
7
  //# sourceMappingURL=index.server.js.map
@@ -1 +1 @@
1
- {"type":"module","version":"10.37.0","sideEffects":false}
1
+ {"type":"module","version":"10.39.0-alpha.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]: 'manual.middleware.tanstackstart',
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]: 'manual.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,iCAAiC;AAC3E,MAAM,CAAC,4BAA4B,GAAG,0BAA0B;AAChE,KAAK;AACL,GAAG;AACH;;;;"}
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;;;;"}
@@ -1,6 +1,77 @@
1
1
  /**
2
- * A Vite plugin that automatically instruments TanStack Start middlewares
3
- * by wrapping `requestMiddleware` and `functionMiddleware` arrays in `createStart()`.
2
+ * Core function that wraps middleware arrays matching the given regex.
3
+ */
4
+ function wrapMiddlewareArrays(code, id, debug, regex) {
5
+ const skipped = [];
6
+ let didWrap = false;
7
+
8
+ const transformed = code.replace(regex, (match, key, contents) => {
9
+ const objContents = arrayToObjectShorthand(contents);
10
+ if (objContents) {
11
+ didWrap = true;
12
+ if (debug) {
13
+ // eslint-disable-next-line no-console
14
+ console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);
15
+ }
16
+ // Handle method call syntax like `.middleware([...])` vs object property syntax like `middleware: [...]`
17
+ if (key.endsWith('(')) {
18
+ return `${key}wrapMiddlewaresWithSentry(${objContents}))`;
19
+ }
20
+ return `${key}: wrapMiddlewaresWithSentry(${objContents})`;
21
+ }
22
+ // Track middlewares that couldn't be auto-wrapped
23
+ // Skip if we matched whitespace only
24
+ if (contents.trim()) {
25
+ skipped.push(key);
26
+ }
27
+ return match;
28
+ });
29
+
30
+ return { code: transformed, didWrap, skipped };
31
+ }
32
+
33
+ /**
34
+ * Wraps global middleware arrays (requestMiddleware, functionMiddleware) in createStart() files.
35
+ */
36
+ function wrapGlobalMiddleware(code, id, debug) {
37
+ return wrapMiddlewareArrays(code, id, debug, /(requestMiddleware|functionMiddleware)\s*:\s*\[([^\]]*)\]/g);
38
+ }
39
+
40
+ /**
41
+ * Wraps route middleware arrays in createFileRoute() files.
42
+ */
43
+ function wrapRouteMiddleware(code, id, debug) {
44
+ return wrapMiddlewareArrays(code, id, debug, /(middleware)\s*:\s*\[([^\]]*)\]/g);
45
+ }
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
+
71
+ /**
72
+ * A Vite plugin that automatically instruments TanStack Start middlewares:
73
+ * - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`
74
+ * - `middleware` arrays in `createFileRoute()` route definitions
4
75
  */
5
76
  function makeAutoInstrumentMiddlewarePlugin(options = {}) {
6
77
  const { enabled = true, debug = false } = options;
@@ -19,9 +90,12 @@ function makeAutoInstrumentMiddlewarePlugin(options = {}) {
19
90
  return null;
20
91
  }
21
92
 
22
- // Only wrap requestMiddleware and functionMiddleware in createStart()
23
- // createStart() should always be in a file named start.ts
24
- if (!id.includes('start') || !code.includes('createStart(')) {
93
+ // Detect file types that should be instrumented
94
+ const isStartFile = id.includes('start') && code.includes('createStart(');
95
+ const isRouteFile = code.includes('createFileRoute(') && /middleware\s*:\s*\[/.test(code);
96
+ const isServerFnFile = code.includes('createServerFn') && /\.middleware\s*\(\s*\[/.test(code);
97
+
98
+ if (!isStartFile && !isRouteFile && !isServerFnFile) {
25
99
  return null;
26
100
  }
27
101
 
@@ -30,58 +104,38 @@ function makeAutoInstrumentMiddlewarePlugin(options = {}) {
30
104
  return null;
31
105
  }
32
106
 
33
- let transformed = code;
34
- let needsImport = false;
35
- const skippedMiddlewares = [];
36
-
37
- transformed = transformed.replace(
38
- /(requestMiddleware|functionMiddleware)\s*:\s*\[([^\]]*)\]/g,
39
- (match, key, contents) => {
40
- const objContents = arrayToObjectShorthand(contents);
41
- if (objContents) {
42
- needsImport = true;
43
- if (debug) {
44
- // eslint-disable-next-line no-console
45
- console.log(`[Sentry] Auto-wrapping ${key} in ${id}`);
46
- }
47
- return `${key}: wrapMiddlewaresWithSentry(${objContents})`;
48
- }
49
- // Track middlewares that couldn't be auto-wrapped
50
- // Skip if we matched whitespace only
51
- if (contents.trim()) {
52
- skippedMiddlewares.push(key);
53
- }
54
- return match;
55
- },
56
- );
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);
122
+ }
57
123
 
58
124
  // Warn about middlewares that couldn't be auto-wrapped
59
- if (skippedMiddlewares.length > 0) {
125
+ if (fileTransformState.skippedMiddlewares.length > 0) {
60
126
  // eslint-disable-next-line no-console
61
127
  console.warn(
62
- `[Sentry] Could not auto-instrument ${skippedMiddlewares.join(' and ')} in ${id}. ` +
128
+ `[Sentry] Could not auto-instrument ${fileTransformState.skippedMiddlewares.join(' and ')} in ${id}. ` +
63
129
  'To instrument these middlewares, use wrapMiddlewaresWithSentry() manually. ',
64
130
  );
65
131
  }
66
132
 
67
133
  // We didn't wrap any middlewares, so we don't need to import the wrapMiddlewaresWithSentry function
68
- if (!needsImport) {
134
+ if (!fileTransformState.needsImport) {
69
135
  return null;
70
136
  }
71
137
 
72
- const sentryImport = "import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\n";
73
-
74
- // Check for 'use server' or 'use client' directives, these need to be before any imports
75
- const directiveMatch = transformed.match(/^(['"])use (client|server)\1;?\s*\n?/);
76
- if (directiveMatch) {
77
- // Insert import after the directive
78
- const directive = directiveMatch[0];
79
- transformed = directive + sentryImport + transformed.slice(directive.length);
80
- } else {
81
- transformed = sentryImport + transformed;
82
- }
83
-
84
- return { code: transformed, map: null };
138
+ return { code: addSentryImport(fileTransformState.code), map: null };
85
139
  },
86
140
  };
87
141
  }
@@ -111,5 +165,28 @@ function arrayToObjectShorthand(contents) {
111
165
  return `{ ${uniqueItems.join(', ')} }`;
112
166
  }
113
167
 
114
- export { arrayToObjectShorthand, makeAutoInstrumentMiddlewarePlugin };
168
+ /**
169
+ * Adds the wrapMiddlewaresWithSentry import to the code.
170
+ * Handles 'use client' and 'use server' directives by inserting the import after them.
171
+ */
172
+ function addSentryImport(code) {
173
+ const sentryImport = "import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\n";
174
+
175
+ // Don't add the import if it already exists
176
+ if (code.includes(sentryImport.trimEnd())) {
177
+ return code;
178
+ }
179
+
180
+ // Check for 'use server' or 'use client' directives, these need to be before any imports
181
+ const directiveMatch = code.match(/^(['"])use (client|server)\1;?\s*\n?/);
182
+
183
+ if (!directiveMatch) {
184
+ return sentryImport + code;
185
+ }
186
+
187
+ const directive = directiveMatch[0];
188
+ return directive + sentryImport + code.slice(directive.length);
189
+ }
190
+
191
+ export { addSentryImport, arrayToObjectShorthand, makeAutoInstrumentMiddlewarePlugin, wrapGlobalMiddleware, wrapRouteMiddleware, wrapServerFnMiddleware };
115
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\n/**\n * A Vite plugin that automatically instruments TanStack Start middlewares\n * by wrapping `requestMiddleware` and `functionMiddleware` arrays in `createStart()`.\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 // Only wrap requestMiddleware and functionMiddleware in createStart()\n // createStart() should always be in a file named start.ts\n if (!id.includes('start') || !code.includes('createStart(')) {\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 transformed = transformed.replace(\n /(requestMiddleware|functionMiddleware)\\s*:\\s*\\[([^\\]]*)\\]/g,\n (match: string, key: string, contents: string) => {\n const objContents = arrayToObjectShorthand(contents);\n if (objContents) {\n needsImport = 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 skippedMiddlewares.push(key);\n }\n return match;\n },\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 const sentryImport = \"import { wrapMiddlewaresWithSentry } from '@sentry/tanstackstart-react';\\n\";\n\n // Check for 'use server' or 'use client' directives, these need to be before any imports\n const directiveMatch = transformed.match(/^(['\"])use (client|server)\\1;?\\s*\\n?/);\n if (directiveMatch) {\n // Insert import after the directive\n const directive = directiveMatch[0];\n transformed = directive + sentryImport + transformed.slice(directive.length);\n } else {\n transformed = sentryImport + transformed;\n }\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"],"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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"}
@@ -3,9 +3,27 @@ type AutoInstrumentMiddlewareOptions = {
3
3
  enabled?: boolean;
4
4
  debug?: boolean;
5
5
  };
6
+ type WrapResult = {
7
+ code: string;
8
+ didWrap: boolean;
9
+ skipped: string[];
10
+ };
11
+ /**
12
+ * Wraps global middleware arrays (requestMiddleware, functionMiddleware) in createStart() files.
13
+ */
14
+ export declare function wrapGlobalMiddleware(code: string, id: string, debug: boolean): WrapResult;
15
+ /**
16
+ * Wraps route middleware arrays in createFileRoute() files.
17
+ */
18
+ export declare function wrapRouteMiddleware(code: string, id: string, debug: boolean): WrapResult;
6
19
  /**
7
- * A Vite plugin that automatically instruments TanStack Start middlewares
8
- * by wrapping `requestMiddleware` and `functionMiddleware` arrays in `createStart()`.
20
+ * Wraps middleware arrays in createServerFn().middleware([...]) calls.
21
+ */
22
+ export declare function wrapServerFnMiddleware(code: string, id: string, debug: boolean): WrapResult;
23
+ /**
24
+ * A Vite plugin that automatically instruments TanStack Start middlewares:
25
+ * - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`
26
+ * - `middleware` arrays in `createFileRoute()` route definitions
9
27
  */
10
28
  export declare function makeAutoInstrumentMiddlewarePlugin(options?: AutoInstrumentMiddlewareOptions): Plugin;
11
29
  /**
@@ -16,5 +34,10 @@ export declare function makeAutoInstrumentMiddlewarePlugin(options?: AutoInstrum
16
34
  * which cannot be converted to object shorthand.
17
35
  */
18
36
  export declare function arrayToObjectShorthand(contents: string): string | null;
37
+ /**
38
+ * Adds the wrapMiddlewaresWithSentry import to the code.
39
+ * Handles 'use client' and 'use server' directives by inserting the import after them.
40
+ */
41
+ export declare function addSentryImport(code: string): string;
19
42
  export {};
20
43
  //# sourceMappingURL=autoInstrumentMiddleware.d.ts.map
@@ -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;;;GAGG;AACH,wBAAgB,kCAAkC,CAAC,OAAO,GAAE,+BAAoC,GAAG,MAAM,CAkFxG;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBtE"}
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"}
@@ -3,9 +3,27 @@ type AutoInstrumentMiddlewareOptions = {
3
3
  enabled?: boolean;
4
4
  debug?: boolean;
5
5
  };
6
+ type WrapResult = {
7
+ code: string;
8
+ didWrap: boolean;
9
+ skipped: string[];
10
+ };
11
+ /**
12
+ * Wraps global middleware arrays (requestMiddleware, functionMiddleware) in createStart() files.
13
+ */
14
+ export declare function wrapGlobalMiddleware(code: string, id: string, debug: boolean): WrapResult;
15
+ /**
16
+ * Wraps route middleware arrays in createFileRoute() files.
17
+ */
18
+ export declare function wrapRouteMiddleware(code: string, id: string, debug: boolean): WrapResult;
6
19
  /**
7
- * A Vite plugin that automatically instruments TanStack Start middlewares
8
- * by wrapping `requestMiddleware` and `functionMiddleware` arrays in `createStart()`.
20
+ * Wraps middleware arrays in createServerFn().middleware([...]) calls.
21
+ */
22
+ export declare function wrapServerFnMiddleware(code: string, id: string, debug: boolean): WrapResult;
23
+ /**
24
+ * A Vite plugin that automatically instruments TanStack Start middlewares:
25
+ * - `requestMiddleware` and `functionMiddleware` arrays in `createStart()`
26
+ * - `middleware` arrays in `createFileRoute()` route definitions
9
27
  */
10
28
  export declare function makeAutoInstrumentMiddlewarePlugin(options?: AutoInstrumentMiddlewareOptions): Plugin;
11
29
  /**
@@ -16,5 +34,10 @@ export declare function makeAutoInstrumentMiddlewarePlugin(options?: AutoInstrum
16
34
  * which cannot be converted to object shorthand.
17
35
  */
18
36
  export declare function arrayToObjectShorthand(contents: string): string | null;
37
+ /**
38
+ * Adds the wrapMiddlewaresWithSentry import to the code.
39
+ * Handles 'use client' and 'use server' directives by inserting the import after them.
40
+ */
41
+ export declare function addSentryImport(code: string): string;
19
42
  export {};
20
43
  //# sourceMappingURL=autoInstrumentMiddleware.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/tanstackstart-react",
3
- "version": "10.37.0",
3
+ "version": "10.39.0-alpha.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,11 +52,11 @@
52
52
  "dependencies": {
53
53
  "@opentelemetry/api": "^1.9.0",
54
54
  "@opentelemetry/semantic-conventions": "^1.37.0",
55
- "@sentry-internal/browser-utils": "10.37.0",
56
- "@sentry/core": "10.37.0",
57
- "@sentry/node": "10.37.0",
58
- "@sentry/react": "10.37.0",
59
- "@sentry/vite-plugin": "^4.7.0"
55
+ "@sentry-internal/browser-utils": "10.39.0-alpha.0",
56
+ "@sentry/core": "10.39.0-alpha.0",
57
+ "@sentry/node": "10.39.0-alpha.0",
58
+ "@sentry/react": "10.39.0-alpha.0",
59
+ "@sentry/vite-plugin": "^4.8.0"
60
60
  },
61
61
  "devDependencies": {
62
62
  "vite": "^5.4.11"