autotel-tanstack 1.13.30 → 1.13.32

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.
Files changed (150) hide show
  1. package/dist/auto.d.ts +8 -35
  2. package/dist/auto.d.ts.map +1 -0
  3. package/dist/auto.js +41 -22
  4. package/dist/auto.js.map +1 -1
  5. package/dist/browser/context.d.ts +50 -0
  6. package/dist/browser/context.d.ts.map +1 -0
  7. package/dist/browser/context.js +54 -2
  8. package/dist/browser/context.js.map +1 -1
  9. package/dist/browser/debug-headers.d.ts +10 -0
  10. package/dist/browser/debug-headers.d.ts.map +1 -0
  11. package/dist/browser/debug-headers.js +12 -2
  12. package/dist/browser/debug-headers.js.map +1 -1
  13. package/dist/browser/error-reporting.d.ts +39 -0
  14. package/dist/browser/error-reporting.d.ts.map +1 -0
  15. package/dist/browser/error-reporting.js +35 -2
  16. package/dist/browser/error-reporting.js.map +1 -1
  17. package/dist/browser/handlers.d.ts +14 -0
  18. package/dist/browser/handlers.d.ts.map +1 -0
  19. package/dist/browser/handlers.js +10 -2
  20. package/dist/browser/handlers.js.map +1 -1
  21. package/dist/browser/index.d.ts +11 -0
  22. package/dist/browser/index.js +12 -12
  23. package/dist/browser/loaders.d.ts +31 -0
  24. package/dist/browser/loaders.d.ts.map +1 -0
  25. package/dist/browser/loaders.js +29 -2
  26. package/dist/browser/loaders.js.map +1 -1
  27. package/dist/browser/metrics.d.ts +56 -0
  28. package/dist/browser/metrics.d.ts.map +1 -0
  29. package/dist/browser/metrics.js +48 -2
  30. package/dist/browser/metrics.js.map +1 -1
  31. package/dist/browser/middleware.d.ts +42 -0
  32. package/dist/browser/middleware.d.ts.map +1 -0
  33. package/dist/browser/middleware.js +36 -2
  34. package/dist/browser/middleware.js.map +1 -1
  35. package/dist/browser/server-functions.d.ts +14 -0
  36. package/dist/browser/server-functions.d.ts.map +1 -0
  37. package/dist/browser/server-functions.js +16 -2
  38. package/dist/browser/server-functions.js.map +1 -1
  39. package/dist/browser/testing.d.ts +85 -0
  40. package/dist/browser/testing.d.ts.map +1 -0
  41. package/dist/browser/testing.js +43 -2
  42. package/dist/browser/testing.js.map +1 -1
  43. package/dist/browser/types.d.ts +2 -0
  44. package/dist/browser/types.js +37 -2
  45. package/dist/browser/types.js.map +1 -1
  46. package/dist/context.d.ts +5 -3
  47. package/dist/context.d.ts.map +1 -0
  48. package/dist/context.js +112 -3
  49. package/dist/context.js.map +1 -1
  50. package/dist/debug-headers.d.ts +14 -14
  51. package/dist/debug-headers.d.ts.map +1 -0
  52. package/dist/debug-headers.js +62 -4
  53. package/dist/debug-headers.js.map +1 -1
  54. package/dist/env-BpFWNnpL.js +30 -0
  55. package/dist/env-BpFWNnpL.js.map +1 -0
  56. package/dist/error-reporting.d.ts +37 -37
  57. package/dist/error-reporting.d.ts.map +1 -0
  58. package/dist/error-reporting.js +154 -3
  59. package/dist/error-reporting.js.map +1 -1
  60. package/dist/handlers.d.ts +5 -4
  61. package/dist/handlers.d.ts.map +1 -0
  62. package/dist/handlers.js +192 -6
  63. package/dist/handlers.js.map +1 -1
  64. package/dist/index.d.ts +15 -16
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +14 -16
  67. package/dist/instrument-DS7YCE1R.d.ts +10 -0
  68. package/dist/instrument-DS7YCE1R.d.ts.map +1 -0
  69. package/dist/instrument-DdLlMfRi.js +80 -0
  70. package/dist/instrument-DdLlMfRi.js.map +1 -0
  71. package/dist/loaders-DrVVY25K.d.ts +2402 -0
  72. package/dist/loaders-DrVVY25K.d.ts.map +1 -0
  73. package/dist/loaders.d.ts +2 -116
  74. package/dist/loaders.js +234 -5
  75. package/dist/loaders.js.map +1 -1
  76. package/dist/metrics.d.ts +39 -39
  77. package/dist/metrics.d.ts.map +1 -0
  78. package/dist/metrics.js +144 -3
  79. package/dist/metrics.js.map +1 -1
  80. package/dist/middleware.d.ts +16 -15
  81. package/dist/middleware.d.ts.map +1 -0
  82. package/dist/middleware.js +290 -7
  83. package/dist/middleware.js.map +1 -1
  84. package/dist/route-filter-dLg-j3jR.js +33 -0
  85. package/dist/route-filter-dLg-j3jR.js.map +1 -0
  86. package/dist/server-functions.d.ts +4 -3
  87. package/dist/server-functions.d.ts.map +1 -0
  88. package/dist/server-functions.js +133 -5
  89. package/dist/server-functions.js.map +1 -1
  90. package/dist/testing.d.ts +164 -65
  91. package/dist/testing.d.ts.map +1 -0
  92. package/dist/testing.js +212 -147
  93. package/dist/testing.js.map +1 -1
  94. package/dist/types-BJ7FyVoX.d.ts +87 -0
  95. package/dist/types-BJ7FyVoX.d.ts.map +1 -0
  96. package/dist/types-BrccP0yX.js +38 -0
  97. package/dist/types-BrccP0yX.js.map +1 -0
  98. package/dist/types-pQgmQa4j.d.ts +154 -0
  99. package/dist/types-pQgmQa4j.d.ts.map +1 -0
  100. package/package.json +7 -7
  101. package/dist/browser/index.js.map +0 -1
  102. package/dist/chunk-7OXOAS64.js +0 -41
  103. package/dist/chunk-7OXOAS64.js.map +0 -1
  104. package/dist/chunk-A7WMQ2BC.js +0 -25
  105. package/dist/chunk-A7WMQ2BC.js.map +0 -1
  106. package/dist/chunk-CCME55EK.js +0 -28
  107. package/dist/chunk-CCME55EK.js.map +0 -1
  108. package/dist/chunk-CSFIPJC2.js +0 -11
  109. package/dist/chunk-CSFIPJC2.js.map +0 -1
  110. package/dist/chunk-DTZCOB4W.js +0 -32
  111. package/dist/chunk-DTZCOB4W.js.map +0 -1
  112. package/dist/chunk-EFSKEYDJ.js +0 -20
  113. package/dist/chunk-EFSKEYDJ.js.map +0 -1
  114. package/dist/chunk-EGRHWZRV.js +0 -3
  115. package/dist/chunk-EGRHWZRV.js.map +0 -1
  116. package/dist/chunk-ESU66L3L.js +0 -92
  117. package/dist/chunk-ESU66L3L.js.map +0 -1
  118. package/dist/chunk-EUYFVNYE.js +0 -16
  119. package/dist/chunk-EUYFVNYE.js.map +0 -1
  120. package/dist/chunk-FFQ4FJKE.js +0 -185
  121. package/dist/chunk-FFQ4FJKE.js.map +0 -1
  122. package/dist/chunk-G526TOMY.js +0 -96
  123. package/dist/chunk-G526TOMY.js.map +0 -1
  124. package/dist/chunk-I4LX3LOG.js +0 -35
  125. package/dist/chunk-I4LX3LOG.js.map +0 -1
  126. package/dist/chunk-JXO7H6KO.js +0 -10
  127. package/dist/chunk-JXO7H6KO.js.map +0 -1
  128. package/dist/chunk-KPXGFKPU.js +0 -193
  129. package/dist/chunk-KPXGFKPU.js.map +0 -1
  130. package/dist/chunk-LRA2UVVS.js +0 -210
  131. package/dist/chunk-LRA2UVVS.js.map +0 -1
  132. package/dist/chunk-MFYOV2SF.js +0 -32
  133. package/dist/chunk-MFYOV2SF.js.map +0 -1
  134. package/dist/chunk-MNP65ZX7.js +0 -21
  135. package/dist/chunk-MNP65ZX7.js.map +0 -1
  136. package/dist/chunk-NTY64BKS.js +0 -38
  137. package/dist/chunk-NTY64BKS.js.map +0 -1
  138. package/dist/chunk-UMEJU65Q.js +0 -34
  139. package/dist/chunk-UMEJU65Q.js.map +0 -1
  140. package/dist/chunk-UTPW3QRT.js +0 -52
  141. package/dist/chunk-UTPW3QRT.js.map +0 -1
  142. package/dist/chunk-V3RO5N2M.js +0 -8
  143. package/dist/chunk-V3RO5N2M.js.map +0 -1
  144. package/dist/chunk-XXBHZR3M.js +0 -99
  145. package/dist/chunk-XXBHZR3M.js.map +0 -1
  146. package/dist/chunk-YQYYPJCK.js +0 -37
  147. package/dist/chunk-YQYYPJCK.js.map +0 -1
  148. package/dist/index.js.map +0 -1
  149. package/dist/instrument-DRR7VL63.d.ts +0 -46
  150. package/dist/types-m5OjZJ-4.d.ts +0 -152
@@ -1,5 +1,63 @@
1
- export { debugHeadersMiddleware } from './chunk-UTPW3QRT.js';
2
- import './chunk-EUYFVNYE.js';
3
- import './chunk-EGRHWZRV.js';
4
- //# sourceMappingURL=debug-headers.js.map
1
+ import { r as isServerSide } from "./env-BpFWNnpL.js";
2
+
3
+ //#region src/debug-headers.ts
4
+ /**
5
+ * Create middleware that adds debug headers to responses in development
6
+ *
7
+ * Adds helpful debug information to response headers:
8
+ * - X-Debug-Timestamp: Request timestamp
9
+ * - X-Debug-Node-Version: Node.js version
10
+ * - X-Debug-Uptime: Process uptime in seconds
11
+ * - X-Debug-Trace-Id: Current trace ID (if available)
12
+ *
13
+ * @param config - Configuration options
14
+ * @returns Middleware handler
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { createStart } from '@tanstack/react-start';
19
+ * import { debugHeadersMiddleware } from 'autotel-tanstack/debug-headers';
20
+ *
21
+ * export const startInstance = createStart(() => ({
22
+ * requestMiddleware: [debugHeadersMiddleware()],
23
+ * }));
24
+ * ```
25
+ */
26
+ function debugHeadersMiddleware(config = {}) {
27
+ if (!isServerSide()) return async function debugHeadersHandler(opts) {
28
+ return opts.next();
29
+ };
30
+ const enabled = config.enabled ?? (typeof process !== "undefined" && process.env.NODE_ENV === "development");
31
+ return async function debugHeadersHandler(opts) {
32
+ const { next, request } = opts;
33
+ if (!enabled || !request) return next();
34
+ const result = await next();
35
+ if (!(result instanceof Response)) return result;
36
+ const response = result;
37
+ const newHeaders = new Headers(response.headers);
38
+ newHeaders.set("X-Debug-Timestamp", (/* @__PURE__ */ new Date()).toISOString());
39
+ newHeaders.set("X-Debug-Node-Version", process.version);
40
+ newHeaders.set("X-Debug-Uptime", Math.floor(process.uptime()).toString());
41
+ try {
42
+ const { trace } = await import("@opentelemetry/api");
43
+ const activeSpan = trace.getActiveSpan();
44
+ if (activeSpan) {
45
+ const spanContext = activeSpan.spanContext();
46
+ if (spanContext.traceId) newHeaders.set("X-Debug-Trace-Id", spanContext.traceId);
47
+ }
48
+ } catch {}
49
+ if (config.customHeaders) for (const [key, value] of Object.entries(config.customHeaders)) {
50
+ const headerValue = typeof value === "function" ? value() : value;
51
+ newHeaders.set(`X-Debug-${key}`, headerValue);
52
+ }
53
+ return new Response(response.body, {
54
+ status: response.status,
55
+ statusText: response.statusText,
56
+ headers: newHeaders
57
+ });
58
+ };
59
+ }
60
+
61
+ //#endregion
62
+ export { debugHeadersMiddleware };
5
63
  //# sourceMappingURL=debug-headers.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"debug-headers.js"}
1
+ {"version":3,"file":"debug-headers.js","names":[],"sources":["../src/debug-headers.ts"],"sourcesContent":["import { isServerSide } from './env';\nimport type { MiddlewareHandler } from './middleware';\n\n/**\n * Configuration for debug headers middleware\n */\nexport interface DebugHeadersConfig {\n /**\n * Whether to enable debug headers\n * @default process.env.NODE_ENV === 'development'\n */\n enabled?: boolean;\n\n /**\n * Custom headers to add\n */\n customHeaders?: Record<string, string | (() => string)>;\n}\n\n/**\n * Create middleware that adds debug headers to responses in development\n *\n * Adds helpful debug information to response headers:\n * - X-Debug-Timestamp: Request timestamp\n * - X-Debug-Node-Version: Node.js version\n * - X-Debug-Uptime: Process uptime in seconds\n * - X-Debug-Trace-Id: Current trace ID (if available)\n *\n * @param config - Configuration options\n * @returns Middleware handler\n *\n * @example\n * ```typescript\n * import { createStart } from '@tanstack/react-start';\n * import { debugHeadersMiddleware } from 'autotel-tanstack/debug-headers';\n *\n * export const startInstance = createStart(() => ({\n * requestMiddleware: [debugHeadersMiddleware()],\n * }));\n * ```\n */\nexport function debugHeadersMiddleware(\n config: DebugHeadersConfig = {},\n): MiddlewareHandler {\n // If we're in the browser, return a no-op middleware\n if (!isServerSide()) {\n return async function debugHeadersHandler(opts) {\n return opts.next();\n };\n }\n\n const enabled =\n config.enabled ??\n (typeof process !== 'undefined' && process.env.NODE_ENV === 'development');\n\n return async function debugHeadersHandler(opts) {\n const { next, request } = opts;\n\n if (!enabled || !request) {\n return next();\n }\n\n const result = await next();\n\n // Check if result is a Response\n if (!(result instanceof Response)) {\n return result;\n }\n\n const response = result;\n\n // Clone response to add headers (responses are immutable)\n const newHeaders = new Headers(response.headers);\n\n // Add standard debug headers\n newHeaders.set('X-Debug-Timestamp', new Date().toISOString());\n newHeaders.set('X-Debug-Node-Version', process.version);\n newHeaders.set('X-Debug-Uptime', Math.floor(process.uptime()).toString());\n\n // Add trace ID if available\n try {\n const { trace } = await import('@opentelemetry/api');\n const activeSpan = trace.getActiveSpan();\n if (activeSpan) {\n const spanContext = activeSpan.spanContext();\n if (spanContext.traceId) {\n newHeaders.set('X-Debug-Trace-Id', spanContext.traceId);\n }\n }\n } catch {\n // OpenTelemetry not available, skip trace ID\n }\n\n // Add custom headers\n if (config.customHeaders) {\n for (const [key, value] of Object.entries(config.customHeaders)) {\n const headerValue = typeof value === 'function' ? value() : value;\n newHeaders.set(`X-Debug-${key}`, headerValue);\n }\n }\n\n // Return new response with debug headers\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers: newHeaders,\n });\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,SAAgB,uBACd,SAA6B,CAAC,GACX;CAEnB,IAAI,CAAC,aAAa,GAChB,OAAO,eAAe,oBAAoB,MAAM;EAC9C,OAAO,KAAK,KAAK;CACnB;CAGF,MAAM,UACJ,OAAO,YACN,OAAO,YAAY,eAAe,QAAQ,IAAI,aAAa;CAE9D,OAAO,eAAe,oBAAoB,MAAM;EAC9C,MAAM,EAAE,MAAM,YAAY;EAE1B,IAAI,CAAC,WAAW,CAAC,SACf,OAAO,KAAK;EAGd,MAAM,SAAS,MAAM,KAAK;EAG1B,IAAI,EAAE,kBAAkB,WACtB,OAAO;EAGT,MAAM,WAAW;EAGjB,MAAM,aAAa,IAAI,QAAQ,SAAS,OAAO;EAG/C,WAAW,IAAI,sCAAqB,IAAI,KAAK,EAAC,CAAC,YAAY,CAAC;EAC5D,WAAW,IAAI,wBAAwB,QAAQ,OAAO;EACtD,WAAW,IAAI,kBAAkB,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;EAGxE,IAAI;GACF,MAAM,EAAE,UAAU,MAAM,OAAO;GAC/B,MAAM,aAAa,MAAM,cAAc;GACvC,IAAI,YAAY;IACd,MAAM,cAAc,WAAW,YAAY;IAC3C,IAAI,YAAY,SACd,WAAW,IAAI,oBAAoB,YAAY,OAAO;GAE1D;EACF,QAAQ,CAER;EAGA,IAAI,OAAO,eACT,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,aAAa,GAAG;GAC/D,MAAM,cAAc,OAAO,UAAU,aAAa,MAAM,IAAI;GAC5D,WAAW,IAAI,WAAW,OAAO,WAAW;EAC9C;EAIF,OAAO,IAAI,SAAS,SAAS,MAAM;GACjC,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB,SAAS;EACX,CAAC;CACH;AACF"}
@@ -0,0 +1,30 @@
1
+ //#region src/env.ts
2
+ /**
3
+ * Environment detection utilities
4
+ * Prevents server-only code from running in the browser
5
+ */
6
+ /**
7
+ * Check if we're running in a browser environment
8
+ * Uses typeof checks to avoid TypeScript DOM type requirements
9
+ */
10
+ function isBrowser() {
11
+ return typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined" && typeof globalThis.document !== "undefined";
12
+ }
13
+ /**
14
+ * Check if we're running in a Node.js environment
15
+ */
16
+ function isNode() {
17
+ return typeof process !== "undefined" && typeof process.versions !== "undefined" && typeof process.versions.node !== "undefined";
18
+ }
19
+ /**
20
+ * Check if we're in a server-side context
21
+ * In TanStack Start, middleware runs on the server, but router config
22
+ * might be evaluated on both sides during SSR
23
+ */
24
+ function isServerSide() {
25
+ return isNode() && !isBrowser();
26
+ }
27
+
28
+ //#endregion
29
+ export { isNode as n, isServerSide as r, isBrowser as t };
30
+ //# sourceMappingURL=env-BpFWNnpL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-BpFWNnpL.js","names":[],"sources":["../src/env.ts"],"sourcesContent":["/**\n * Environment detection utilities\n * Prevents server-only code from running in the browser\n */\n\n/**\n * Check if we're running in a browser environment\n * Uses typeof checks to avoid TypeScript DOM type requirements\n */\nexport function isBrowser(): boolean {\n return (\n typeof globalThis !== 'undefined' &&\n // @ts-expect-error - window may not exist in Node.js, that's the point\n typeof globalThis.window !== 'undefined' &&\n // @ts-expect-error - document may not exist in Node.js, that's the point\n typeof globalThis.document !== 'undefined'\n );\n}\n\n/**\n * Check if we're running in a Node.js environment\n */\nexport function isNode(): boolean {\n return (\n typeof process !== 'undefined' &&\n typeof process.versions !== 'undefined' &&\n typeof process.versions.node !== 'undefined'\n );\n}\n\n/**\n * Check if we're in a server-side context\n * In TanStack Start, middleware runs on the server, but router config\n * might be evaluated on both sides during SSR\n */\nexport function isServerSide(): boolean {\n // In TanStack Start, if we're in a request handler context, we're on the server\n // Check for Node.js environment (server) and not browser\n return isNode() && !isBrowser();\n}\n\n/**\n * Safely check if a module is available (for optional dependencies)\n */\nexport function isModuleAvailable(moduleName: string): boolean {\n try {\n // This will only work in Node.js, not browser\n if (typeof require !== 'undefined') {\n require.resolve(moduleName);\n return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;AASA,SAAgB,YAAqB;CACnC,OACE,OAAO,eAAe,eAEtB,OAAO,WAAW,WAAW,eAE7B,OAAO,WAAW,aAAa;AAEnC;;;;AAKA,SAAgB,SAAkB;CAChC,OACE,OAAO,YAAY,eACnB,OAAO,QAAQ,aAAa,eAC5B,OAAO,QAAQ,SAAS,SAAS;AAErC;;;;;;AAOA,SAAgB,eAAwB;CAGtC,OAAO,OAAO,KAAK,CAAC,UAAU;AAChC"}
@@ -1,5 +1,4 @@
1
- import * as _tanstack_react_start from '@tanstack/react-start';
2
-
1
+ //#region src/error-reporting.d.ts
3
2
  /**
4
3
  * Error reporting utilities for TanStack Start
5
4
  *
@@ -10,15 +9,15 @@ import * as _tanstack_react_start from '@tanstack/react-start';
10
9
  * Error report data structure
11
10
  */
12
11
  interface ErrorReport {
13
- id: string;
14
- count: number;
15
- lastSeen: Date;
16
- error: {
17
- name: string;
18
- message: string;
19
- stack?: string;
20
- context?: unknown;
21
- };
12
+ id: string;
13
+ count: number;
14
+ lastSeen: Date;
15
+ error: {
16
+ name: string;
17
+ message: string;
18
+ stack?: string;
19
+ context?: unknown;
20
+ };
22
21
  }
23
22
  /**
24
23
  * Error store for in-memory error tracking
@@ -27,28 +26,28 @@ interface ErrorReport {
27
26
  * Thread-safe for concurrent access.
28
27
  */
29
28
  declare class ErrorStore {
30
- private errors;
31
- private readonly maxErrors;
32
- /**
33
- * Report an error
34
- */
35
- reportError(error: Error, context?: unknown): string;
36
- /**
37
- * Get all error reports
38
- */
39
- getAllErrors(): ErrorReport[];
40
- /**
41
- * Get a specific error by ID
42
- */
43
- getError(id: string): ErrorReport | undefined;
44
- /**
45
- * Clear all errors
46
- */
47
- clear(): void;
48
- /**
49
- * Clear a specific error
50
- */
51
- clearError(id: string): void;
29
+ private errors;
30
+ private readonly maxErrors;
31
+ /**
32
+ * Report an error
33
+ */
34
+ reportError(error: Error, context?: unknown): string;
35
+ /**
36
+ * Get all error reports
37
+ */
38
+ getAllErrors(): ErrorReport[];
39
+ /**
40
+ * Get a specific error by ID
41
+ */
42
+ getError(id: string): ErrorReport | undefined;
43
+ /**
44
+ * Clear all errors
45
+ */
46
+ clear(): void;
47
+ /**
48
+ * Clear a specific error
49
+ */
50
+ clearError(id: string): void;
52
51
  }
53
52
  /**
54
53
  * Global error store instance
@@ -95,8 +94,8 @@ declare function reportError(error: Error, context?: unknown): string;
95
94
  * });
96
95
  * ```
97
96
  */
98
- declare function createErrorReportingHandler(): () => Promise<_tanstack_react_start.JsonResponse<{
99
- errors: ErrorReport[];
97
+ declare function createErrorReportingHandler(): () => Promise<import("@tanstack/react-start").JsonResponse<{
98
+ errors: ErrorReport[];
100
99
  }>>;
101
100
  /**
102
101
  * Wrap a function with automatic error reporting
@@ -114,5 +113,6 @@ declare function createErrorReportingHandler(): () => Promise<_tanstack_react_st
114
113
  * ```
115
114
  */
116
115
  declare function withErrorReporting<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>, context?: Record<string, unknown>): (...args: TArgs) => Promise<TReturn>;
117
-
118
- export { type ErrorReport, createErrorReportingHandler, errorStore, reportError, withErrorReporting };
116
+ //#endregion
117
+ export { ErrorReport, createErrorReportingHandler, errorStore, reportError, withErrorReporting };
118
+ //# sourceMappingURL=error-reporting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-reporting.d.ts","names":[],"sources":["../src/error-reporting.ts"],"mappings":";;AAUA;;;;;;;;UAAiB,WAAA;EACf,EAAA;EACA,KAAA;EACA,QAAA,EAAU,IAAI;EACd,KAAA;IACE,IAAA;IACA,OAAA;IACA,KAAA;IACA,OAAA;EAAA;AAAA;;;;;;;cAUE,UAAA;EAAA,QACI,MAAA;EAAA,iBACS,SAAA;EAKS;;;EAA1B,WAAA,CAAY,KAAA,EAAO,KAAA,EAAO,OAAA;EA+DjB;;;EAPT,YAAA,IAAgB,WAAA;EAqBL;;AAAU;EAdrB,QAAA,CAAS,EAAA,WAAa,WAAA;EAsBkB;;;EAfxC,KAAA;EAmCc;;;EA5Bd,UAAA,CAAW,EAAA;AAAA;;;;cAQA,UAAA,EAAU,UAAmB;AA8C1C;;;;;;;;;;AAyBA;;;;;;;;AAzBA,iBA1BgB,WAAA,CAAY,KAAA,EAAO,KAAK,EAAE,OAAA;;;;;;;;;;;;;;;;;;AAsDJ;;;;;iBA5BtB,2BAAA,UAA2B,OAAA,iCAAA,YAAA;UAAA,WAAA;AAAA;;;;;;;;;;;;;;;;iBAyB3B,kBAAA,mCACd,EAAA,MAAQ,IAAA,EAAM,KAAA,KAAU,OAAA,CAAQ,OAAA,GAChC,OAAA,GAAU,MAAA,wBACL,IAAA,EAAM,KAAA,KAAU,OAAA,CAAQ,OAAA"}
@@ -1,4 +1,155 @@
1
- export { createErrorReportingHandler, errorStore, reportError, withErrorReporting } from './chunk-XXBHZR3M.js';
2
- import './chunk-EGRHWZRV.js';
3
- //# sourceMappingURL=error-reporting.js.map
1
+ //#region src/error-reporting.ts
2
+ /**
3
+ * Error store for in-memory error tracking
4
+ *
5
+ * Stores error reports with deduplication by error name + message.
6
+ * Thread-safe for concurrent access.
7
+ */
8
+ var ErrorStore = class {
9
+ errors = /* @__PURE__ */ new Map();
10
+ maxErrors = 100;
11
+ /**
12
+ * Report an error
13
+ */
14
+ reportError(error, context) {
15
+ const key = `${error.name}:${error.message}`;
16
+ const existing = this.errors.get(key);
17
+ if (existing) {
18
+ existing.count++;
19
+ existing.lastSeen = /* @__PURE__ */ new Date();
20
+ if (context) existing.error.context = {
21
+ ...existing.error.context,
22
+ ...context
23
+ };
24
+ return key;
25
+ }
26
+ const report = {
27
+ id: key,
28
+ count: 1,
29
+ lastSeen: /* @__PURE__ */ new Date(),
30
+ error: {
31
+ name: error.name,
32
+ message: error.message,
33
+ stack: error.stack,
34
+ context
35
+ }
36
+ };
37
+ this.errors.set(key, report);
38
+ if (this.errors.size > this.maxErrors) {
39
+ const oldest = [...this.errors.entries()].toSorted((a, b) => a[1].lastSeen.getTime() - b[1].lastSeen.getTime())[0];
40
+ this.errors.delete(oldest[0]);
41
+ }
42
+ console.error("[ERROR REPORTED]:", {
43
+ error: error.message,
44
+ count: 1,
45
+ context
46
+ });
47
+ return key;
48
+ }
49
+ /**
50
+ * Get all error reports
51
+ */
52
+ getAllErrors() {
53
+ return [...this.errors.values()];
54
+ }
55
+ /**
56
+ * Get a specific error by ID
57
+ */
58
+ getError(id) {
59
+ return this.errors.get(id);
60
+ }
61
+ /**
62
+ * Clear all errors
63
+ */
64
+ clear() {
65
+ this.errors.clear();
66
+ }
67
+ /**
68
+ * Clear a specific error
69
+ */
70
+ clearError(id) {
71
+ this.errors.delete(id);
72
+ }
73
+ };
74
+ /**
75
+ * Global error store instance
76
+ */
77
+ const errorStore = new ErrorStore();
78
+ /**
79
+ * Report an error to the error store
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * import { reportError } from 'autotel-tanstack/error-reporting';
84
+ *
85
+ * try {
86
+ * await riskyOperation();
87
+ * } catch (error) {
88
+ * reportError(error as Error, {
89
+ * userId: context.userId,
90
+ * operation: 'riskyOperation',
91
+ * });
92
+ * throw error;
93
+ * }
94
+ * ```
95
+ */
96
+ function reportError(error, context) {
97
+ return errorStore.reportError(error, context);
98
+ }
99
+ /**
100
+ * Create an error reporting endpoint handler
101
+ *
102
+ * Returns a handler that exposes error reports in JSON format.
103
+ * Use this to create an `/admin/errors` endpoint.
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * // routes/admin/errors.ts
108
+ * import { createFileRoute } from '@tanstack/react-router';
109
+ * import { json } from '@tanstack/react-start';
110
+ * import { createErrorReportingHandler } from 'autotel-tanstack/error-reporting';
111
+ *
112
+ * export const Route = createFileRoute('/admin/errors')({
113
+ * server: {
114
+ * handlers: {
115
+ * GET: createErrorReportingHandler(),
116
+ * },
117
+ * },
118
+ * });
119
+ * ```
120
+ */
121
+ function createErrorReportingHandler() {
122
+ return async () => {
123
+ const { json } = await import("@tanstack/react-start");
124
+ return json({ errors: errorStore.getAllErrors() });
125
+ };
126
+ }
127
+ /**
128
+ * Wrap a function with automatic error reporting
129
+ *
130
+ * Automatically reports errors to the error store.
131
+ *
132
+ * @example
133
+ * ```typescript
134
+ * import { withErrorReporting } from 'autotel-tanstack/error-reporting';
135
+ *
136
+ * const riskyOperation = createServerFn()
137
+ * .handler(withErrorReporting(async () => {
138
+ * return await performOperation();
139
+ * }, { operation: 'riskyOperation' }));
140
+ * ```
141
+ */
142
+ function withErrorReporting(fn, context) {
143
+ return async (...args) => {
144
+ try {
145
+ return await fn(...args);
146
+ } catch (error) {
147
+ reportError(error, context);
148
+ throw error;
149
+ }
150
+ };
151
+ }
152
+
153
+ //#endregion
154
+ export { createErrorReportingHandler, errorStore, reportError, withErrorReporting };
4
155
  //# sourceMappingURL=error-reporting.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"error-reporting.js"}
1
+ {"version":3,"file":"error-reporting.js","names":[],"sources":["../src/error-reporting.ts"],"sourcesContent":["/**\n * Error reporting utilities for TanStack Start\n *\n * Provides basic error reporting without external dependencies,\n * following the patterns from TanStack Start observability guide.\n */\n\n/**\n * Error report data structure\n */\nexport interface ErrorReport {\n id: string;\n count: number;\n lastSeen: Date;\n error: {\n name: string;\n message: string;\n stack?: string;\n context?: unknown;\n };\n}\n\n/**\n * Error store for in-memory error tracking\n *\n * Stores error reports with deduplication by error name + message.\n * Thread-safe for concurrent access.\n */\nclass ErrorStore {\n private errors = new Map<string, ErrorReport>();\n private readonly maxErrors = 100; // Limit memory usage\n\n /**\n * Report an error\n */\n reportError(error: Error, context?: unknown): string {\n const key = `${error.name}:${error.message}`;\n const existing = this.errors.get(key);\n\n if (existing) {\n existing.count++;\n existing.lastSeen = new Date();\n if (context) {\n // Merge context\n existing.error.context = {\n ...(existing.error.context as Record<string, unknown>),\n ...(context as Record<string, unknown>),\n };\n }\n return key;\n }\n\n // Add new error\n const report: ErrorReport = {\n id: key,\n count: 1,\n lastSeen: new Date(),\n error: {\n name: error.name,\n message: error.message,\n stack: error.stack,\n context,\n },\n };\n\n this.errors.set(key, report);\n\n // Limit stored errors\n if (this.errors.size > this.maxErrors) {\n // Remove oldest error\n const entries = [...this.errors.entries()];\n const oldest = entries.toSorted(\n (a: [string, ErrorReport], b: [string, ErrorReport]) =>\n a[1].lastSeen.getTime() - b[1].lastSeen.getTime(),\n )[0];\n this.errors.delete(oldest[0]);\n }\n\n // Log immediately\n console.error('[ERROR REPORTED]:', {\n error: error.message,\n count: 1,\n context,\n });\n\n return key;\n }\n\n /**\n * Get all error reports\n */\n getAllErrors(): ErrorReport[] {\n return [...this.errors.values()];\n }\n\n /**\n * Get a specific error by ID\n */\n getError(id: string): ErrorReport | undefined {\n return this.errors.get(id);\n }\n\n /**\n * Clear all errors\n */\n clear(): void {\n this.errors.clear();\n }\n\n /**\n * Clear a specific error\n */\n clearError(id: string): void {\n this.errors.delete(id);\n }\n}\n\n/**\n * Global error store instance\n */\nexport const errorStore = new ErrorStore();\n\n/**\n * Report an error to the error store\n *\n * @example\n * ```typescript\n * import { reportError } from 'autotel-tanstack/error-reporting';\n *\n * try {\n * await riskyOperation();\n * } catch (error) {\n * reportError(error as Error, {\n * userId: context.userId,\n * operation: 'riskyOperation',\n * });\n * throw error;\n * }\n * ```\n */\nexport function reportError(error: Error, context?: unknown): string {\n return errorStore.reportError(error, context);\n}\n\n/**\n * Create an error reporting endpoint handler\n *\n * Returns a handler that exposes error reports in JSON format.\n * Use this to create an `/admin/errors` endpoint.\n *\n * @example\n * ```typescript\n * // routes/admin/errors.ts\n * import { createFileRoute } from '@tanstack/react-router';\n * import { json } from '@tanstack/react-start';\n * import { createErrorReportingHandler } from 'autotel-tanstack/error-reporting';\n *\n * export const Route = createFileRoute('/admin/errors')({\n * server: {\n * handlers: {\n * GET: createErrorReportingHandler(),\n * },\n * },\n * });\n * ```\n */\nexport function createErrorReportingHandler() {\n return async () => {\n const { json } = await import('@tanstack/react-start');\n\n return json({\n errors: errorStore.getAllErrors(),\n });\n };\n}\n\n/**\n * Wrap a function with automatic error reporting\n *\n * Automatically reports errors to the error store.\n *\n * @example\n * ```typescript\n * import { withErrorReporting } from 'autotel-tanstack/error-reporting';\n *\n * const riskyOperation = createServerFn()\n * .handler(withErrorReporting(async () => {\n * return await performOperation();\n * }, { operation: 'riskyOperation' }));\n * ```\n */\nexport function withErrorReporting<TArgs extends unknown[], TReturn>(\n fn: (...args: TArgs) => Promise<TReturn>,\n context?: Record<string, unknown>,\n): (...args: TArgs) => Promise<TReturn> {\n return async (...args: TArgs): Promise<TReturn> => {\n try {\n return await fn(...args);\n } catch (error) {\n reportError(error as Error, context);\n throw error;\n }\n };\n}\n"],"mappings":";;;;;;;AA4BA,IAAM,aAAN,MAAiB;CACf,AAAQ,yBAAS,IAAI,IAAyB;CAC9C,AAAiB,YAAY;;;;CAK7B,YAAY,OAAc,SAA2B;EACnD,MAAM,MAAM,GAAG,MAAM,KAAK,GAAG,MAAM;EACnC,MAAM,WAAW,KAAK,OAAO,IAAI,GAAG;EAEpC,IAAI,UAAU;GACZ,SAAS;GACT,SAAS,2BAAW,IAAI,KAAK;GAC7B,IAAI,SAEF,SAAS,MAAM,UAAU;IACvB,GAAI,SAAS,MAAM;IACnB,GAAI;GACN;GAEF,OAAO;EACT;EAGA,MAAM,SAAsB;GAC1B,IAAI;GACJ,OAAO;GACP,0BAAU,IAAI,KAAK;GACnB,OAAO;IACL,MAAM,MAAM;IACZ,SAAS,MAAM;IACf,OAAO,MAAM;IACb;GACF;EACF;EAEA,KAAK,OAAO,IAAI,KAAK,MAAM;EAG3B,IAAI,KAAK,OAAO,OAAO,KAAK,WAAW;GAGrC,MAAM,SAAS,CADE,GAAG,KAAK,OAAO,QAAQ,CACnB,CAAC,CAAC,UACpB,GAA0B,MACzB,EAAE,EAAE,CAAC,SAAS,QAAQ,IAAI,EAAE,EAAE,CAAC,SAAS,QAAQ,CACpD,CAAC,CAAC;GACF,KAAK,OAAO,OAAO,OAAO,EAAE;EAC9B;EAGA,QAAQ,MAAM,qBAAqB;GACjC,OAAO,MAAM;GACb,OAAO;GACP;EACF,CAAC;EAED,OAAO;CACT;;;;CAKA,eAA8B;EAC5B,OAAO,CAAC,GAAG,KAAK,OAAO,OAAO,CAAC;CACjC;;;;CAKA,SAAS,IAAqC;EAC5C,OAAO,KAAK,OAAO,IAAI,EAAE;CAC3B;;;;CAKA,QAAc;EACZ,KAAK,OAAO,MAAM;CACpB;;;;CAKA,WAAW,IAAkB;EAC3B,KAAK,OAAO,OAAO,EAAE;CACvB;AACF;;;;AAKA,MAAa,aAAa,IAAI,WAAW;;;;;;;;;;;;;;;;;;;AAoBzC,SAAgB,YAAY,OAAc,SAA2B;CACnE,OAAO,WAAW,YAAY,OAAO,OAAO;AAC9C;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,8BAA8B;CAC5C,OAAO,YAAY;EACjB,MAAM,EAAE,SAAS,MAAM,OAAO;EAE9B,OAAO,KAAK,EACV,QAAQ,WAAW,aAAa,EAClC,CAAC;CACH;AACF;;;;;;;;;;;;;;;;AAiBA,SAAgB,mBACd,IACA,SACsC;CACtC,OAAO,OAAO,GAAG,SAAkC;EACjD,IAAI;GACF,OAAO,MAAM,GAAG,GAAG,IAAI;EACzB,SAAS,OAAO;GACd,YAAY,OAAgB,OAAO;GACnC,MAAM;EACR;CACF;AACF"}
@@ -1,11 +1,11 @@
1
- import { W as WrapStartHandlerConfig } from './types-m5OjZJ-4.js';
2
- import '@opentelemetry/api';
1
+ import { s as WrapStartHandlerConfig } from "./types-pQgmQa4j.js";
3
2
 
3
+ //#region src/handlers.d.ts
4
4
  /**
5
5
  * Request handler type (compatible with TanStack Start handlers)
6
6
  */
7
7
  type RequestHandler = (request: Request, opts?: {
8
- context?: Record<string, unknown>;
8
+ context?: Record<string, unknown>;
9
9
  }) => Promise<Response> | Response;
10
10
  /**
11
11
  * Wrap a TanStack Start handler with OpenTelemetry tracing
@@ -66,5 +66,6 @@ declare function wrapStartHandler(config?: WrapStartHandlerConfig): (handler: Re
66
66
  * ```
67
67
  */
68
68
  declare function createTracedHandler(config?: Omit<WrapStartHandlerConfig, 'endpoint' | 'headers' | 'service'>): (handler: RequestHandler) => RequestHandler;
69
-
69
+ //#endregion
70
70
  export { createTracedHandler, wrapStartHandler };
71
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","names":[],"sources":["../src/handlers.ts"],"mappings":";;;;;AAQiB;KAKZ,cAAA,IACH,OAAA,EAAS,OAAA,EACT,IAAA;EAAS,OAAA,GAAU,MAAA;AAAA,MAChB,OAAA,CAAQ,QAAA,IAAY,QAAA;;;;;;;;;;;;;;;;AAAQ;AAgCjC;;;;;;;;;;;;;;iBAAgB,gBAAA,CACd,MAAA,GAAQ,sBAAA,IACN,OAAA,EAAS,cAAA,KAAmB,cAAA;AA6JhC;;;;;;;;;;;;;;;;AAE8C;;;;;;;;;;;AAF9C,iBAAgB,mBAAA,CACd,MAAA,GAAQ,IAAA,CAAK,sBAAA,yCACX,OAAA,EAAS,cAAA,KAAmB,cAAA"}
package/dist/handlers.js CHANGED
@@ -1,7 +1,193 @@
1
- export { createTracedHandler, wrapStartHandler } from './chunk-FFQ4FJKE.js';
2
- import './chunk-CCME55EK.js';
3
- import './chunk-I4LX3LOG.js';
4
- import './chunk-NTY64BKS.js';
5
- import './chunk-EGRHWZRV.js';
6
- //# sourceMappingURL=handlers.js.map
1
+ import { n as SPAN_ATTRIBUTES, t as DEFAULT_CONFIG } from "./types-BrccP0yX.js";
2
+ import { extractContextFromRequest } from "./context.js";
3
+ import { t as isExcludedPath } from "./route-filter-dLg-j3jR.js";
4
+ import { SpanStatusCode, context } from "@opentelemetry/api";
5
+ import { init, trace } from "autotel";
6
+
7
+ //#region src/handlers.ts
8
+ /**
9
+ * Wrap a TanStack Start handler with OpenTelemetry tracing
10
+ *
11
+ * This function wraps the entire request handler to automatically create
12
+ * spans for all incoming requests. It initializes OpenTelemetry and
13
+ * provides comprehensive request tracing.
14
+ *
15
+ * @param config - Configuration options including OTLP endpoint and headers
16
+ * @returns Function that wraps a request handler
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // server.ts
21
+ * import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server';
22
+ * import { wrapStartHandler } from 'autotel-tanstack/handlers';
23
+ *
24
+ * export default wrapStartHandler({
25
+ * service: 'my-app',
26
+ * endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
27
+ * headers: { 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY },
28
+ * })(createStartHandler(defaultStreamHandler));
29
+ * ```
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * // With env var configuration (recommended for production)
34
+ * // Set OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS
35
+ * export default wrapStartHandler()(createStartHandler(defaultStreamHandler));
36
+ * ```
37
+ */
38
+ function wrapStartHandler(config = {}) {
39
+ const mergedConfig = {
40
+ ...DEFAULT_CONFIG,
41
+ ...config
42
+ };
43
+ const service = config.service || process.env.OTEL_SERVICE_NAME || "tanstack-start";
44
+ const endpoint = config.endpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
45
+ let headers = config.headers;
46
+ if (!headers && process.env.OTEL_EXPORTER_OTLP_HEADERS) {
47
+ headers = {};
48
+ const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(",");
49
+ for (const pair of pairs) {
50
+ const [key, value] = pair.split("=");
51
+ if (key && value) headers[key.trim()] = value.trim();
52
+ }
53
+ }
54
+ init({
55
+ service,
56
+ endpoint,
57
+ headers
58
+ });
59
+ return function wrapHandler(handler) {
60
+ return async function tracedHandler(request, opts) {
61
+ const url = new URL(request.url);
62
+ if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) return handler(request, opts);
63
+ const parentContext = extractContextFromRequest(request);
64
+ return context.with(parentContext, async () => {
65
+ const spanName = `${request.method} ${url.pathname}`;
66
+ return trace(spanName, async (ctx) => {
67
+ ctx.setAttributes({
68
+ [SPAN_ATTRIBUTES.HTTP_REQUEST_METHOD]: request.method,
69
+ [SPAN_ATTRIBUTES.URL_PATH]: url.pathname,
70
+ [SPAN_ATTRIBUTES.URL_FULL]: request.url,
71
+ [SPAN_ATTRIBUTES.TANSTACK_TYPE]: "request"
72
+ });
73
+ if (url.search) ctx.setAttribute(SPAN_ATTRIBUTES.URL_QUERY, url.search);
74
+ if (mergedConfig.captureHeaders) for (const header of mergedConfig.captureHeaders) {
75
+ const value = request.headers.get(header);
76
+ if (value) ctx.setAttribute(`http.request.header.${header.toLowerCase()}`, value);
77
+ }
78
+ if (config.customAttributes) {
79
+ const customAttrs = config.customAttributes({
80
+ type: "request",
81
+ name: spanName,
82
+ request
83
+ });
84
+ ctx.setAttributes(customAttrs);
85
+ }
86
+ const startTime = Date.now();
87
+ try {
88
+ const response = await handler(request, opts);
89
+ const duration = Date.now() - startTime;
90
+ ctx.setAttribute(SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS, duration);
91
+ ctx.setAttribute(SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE, response.status);
92
+ if (response.status >= 400) ctx.setStatus({
93
+ code: SpanStatusCode.ERROR,
94
+ message: `HTTP ${response.status}`
95
+ });
96
+ else ctx.setStatus({ code: SpanStatusCode.OK });
97
+ return response;
98
+ } catch (error) {
99
+ const duration = Date.now() - startTime;
100
+ ctx.setAttribute(SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS, duration);
101
+ if (mergedConfig.captureErrors) ctx.recordError(error);
102
+ throw error;
103
+ }
104
+ });
105
+ });
106
+ };
107
+ };
108
+ }
109
+ /**
110
+ * Create a traced handler without auto-initialization
111
+ *
112
+ * Use this when you want to initialize autotel separately
113
+ * (e.g., with more advanced configuration).
114
+ *
115
+ * @param config - Configuration options (excluding endpoint/headers)
116
+ * @returns Function that wraps a request handler
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * import { init } from 'autotel';
121
+ * import { createTracedHandler } from 'autotel-tanstack/handlers';
122
+ *
123
+ * // Initialize autotel with custom configuration
124
+ * init({
125
+ * service: 'my-app',
126
+ * endpoint: 'https://api.honeycomb.io',
127
+ * instrumentations: [/* custom instrumentations *\/],
128
+ * });
129
+ *
130
+ * // Wrap handler without re-initializing
131
+ * export default createTracedHandler({
132
+ * captureHeaders: ['x-request-id'],
133
+ * })(createStartHandler(defaultStreamHandler));
134
+ * ```
135
+ */
136
+ function createTracedHandler(config = {}) {
137
+ const mergedConfig = {
138
+ ...DEFAULT_CONFIG,
139
+ ...config
140
+ };
141
+ return function wrapHandler(handler) {
142
+ return async function tracedHandler(request, opts) {
143
+ const url = new URL(request.url);
144
+ if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) return handler(request, opts);
145
+ const parentContext = extractContextFromRequest(request);
146
+ return context.with(parentContext, async () => {
147
+ const spanName = `${request.method} ${url.pathname}`;
148
+ return trace(spanName, async (ctx) => {
149
+ ctx.setAttributes({
150
+ [SPAN_ATTRIBUTES.HTTP_REQUEST_METHOD]: request.method,
151
+ [SPAN_ATTRIBUTES.URL_PATH]: url.pathname,
152
+ [SPAN_ATTRIBUTES.TANSTACK_TYPE]: "request"
153
+ });
154
+ if (url.search) ctx.setAttribute(SPAN_ATTRIBUTES.URL_QUERY, url.search);
155
+ if (mergedConfig.captureHeaders) for (const header of mergedConfig.captureHeaders) {
156
+ const value = request.headers.get(header);
157
+ if (value) ctx.setAttribute(`http.request.header.${header.toLowerCase()}`, value);
158
+ }
159
+ if (config.customAttributes) {
160
+ const customAttrs = config.customAttributes({
161
+ type: "request",
162
+ name: spanName,
163
+ request
164
+ });
165
+ ctx.setAttributes(customAttrs);
166
+ }
167
+ const startTime = Date.now();
168
+ try {
169
+ const response = await handler(request, opts);
170
+ const duration = Date.now() - startTime;
171
+ ctx.setAttribute(SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS, duration);
172
+ ctx.setAttribute(SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE, response.status);
173
+ if (response.status >= 400) ctx.setStatus({
174
+ code: SpanStatusCode.ERROR,
175
+ message: `HTTP ${response.status}`
176
+ });
177
+ else ctx.setStatus({ code: SpanStatusCode.OK });
178
+ return response;
179
+ } catch (error) {
180
+ const duration = Date.now() - startTime;
181
+ ctx.setAttribute(SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS, duration);
182
+ if (mergedConfig.captureErrors) ctx.recordError(error);
183
+ throw error;
184
+ }
185
+ });
186
+ });
187
+ };
188
+ };
189
+ }
190
+
191
+ //#endregion
192
+ export { createTracedHandler, wrapStartHandler };
7
193
  //# sourceMappingURL=handlers.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"handlers.js"}
1
+ {"version":3,"file":"handlers.js","names":[],"sources":["../src/handlers.ts"],"sourcesContent":["import { context, SpanStatusCode } from '@opentelemetry/api';\nimport { trace, init, type TraceContext } from 'autotel';\nimport { extractContextFromRequest } from './context';\nimport { isExcludedPath } from './route-filter';\nimport {\n type WrapStartHandlerConfig,\n DEFAULT_CONFIG,\n SPAN_ATTRIBUTES,\n} from './types';\n\n/**\n * Request handler type (compatible with TanStack Start handlers)\n */\ntype RequestHandler = (\n request: Request,\n opts?: { context?: Record<string, unknown> },\n) => Promise<Response> | Response;\n\n/**\n * Wrap a TanStack Start handler with OpenTelemetry tracing\n *\n * This function wraps the entire request handler to automatically create\n * spans for all incoming requests. It initializes OpenTelemetry and\n * provides comprehensive request tracing.\n *\n * @param config - Configuration options including OTLP endpoint and headers\n * @returns Function that wraps a request handler\n *\n * @example\n * ```typescript\n * // server.ts\n * import { createStartHandler, defaultStreamHandler } from '@tanstack/react-start/server';\n * import { wrapStartHandler } from 'autotel-tanstack/handlers';\n *\n * export default wrapStartHandler({\n * service: 'my-app',\n * endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,\n * headers: { 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY },\n * })(createStartHandler(defaultStreamHandler));\n * ```\n *\n * @example\n * ```typescript\n * // With env var configuration (recommended for production)\n * // Set OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS\n * export default wrapStartHandler()(createStartHandler(defaultStreamHandler));\n * ```\n */\nexport function wrapStartHandler(\n config: WrapStartHandlerConfig = {},\n): (handler: RequestHandler) => RequestHandler {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n\n // Initialize autotel with provided configuration\n const service =\n config.service || process.env.OTEL_SERVICE_NAME || 'tanstack-start';\n const endpoint = config.endpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n\n // Parse headers from env if not provided\n let headers = config.headers;\n if (!headers && process.env.OTEL_EXPORTER_OTLP_HEADERS) {\n headers = {};\n const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(',');\n for (const pair of pairs) {\n const [key, value] = pair.split('=');\n if (key && value) {\n headers[key.trim()] = value.trim();\n }\n }\n }\n\n // Initialize OpenTelemetry\n init({\n service,\n endpoint,\n headers,\n });\n\n return function wrapHandler(handler: RequestHandler): RequestHandler {\n return async function tracedHandler(\n request: Request,\n opts?: { context?: Record<string, unknown> },\n ): Promise<Response> {\n const url = new URL(request.url);\n\n // Check if path should be excluded\n if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) {\n return handler(request, opts);\n }\n\n // Extract parent context from request headers\n const parentContext = extractContextFromRequest(request);\n\n // Run within parent context\n return context.with(parentContext, async () => {\n const spanName = `${request.method} ${url.pathname}`;\n\n return trace(spanName, async (ctx: TraceContext) => {\n // Set HTTP semantic attributes\n ctx.setAttributes({\n [SPAN_ATTRIBUTES.HTTP_REQUEST_METHOD]: request.method,\n [SPAN_ATTRIBUTES.URL_PATH]: url.pathname,\n [SPAN_ATTRIBUTES.URL_FULL]: request.url,\n [SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'request',\n });\n\n if (url.search) {\n ctx.setAttribute(SPAN_ATTRIBUTES.URL_QUERY, url.search);\n }\n\n // Capture configured headers\n if (mergedConfig.captureHeaders) {\n for (const header of mergedConfig.captureHeaders) {\n const value = request.headers.get(header);\n if (value) {\n ctx.setAttribute(\n `http.request.header.${header.toLowerCase()}`,\n value,\n );\n }\n }\n }\n\n // Add custom attributes\n if (config.customAttributes) {\n const customAttrs = config.customAttributes({\n type: 'request',\n name: spanName,\n request,\n });\n ctx.setAttributes(\n customAttrs as Record<string, string | number | boolean>,\n );\n }\n\n const startTime = Date.now();\n\n try {\n const response = await handler(request, opts);\n const duration = Date.now() - startTime;\n\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,\n duration,\n );\n ctx.setAttribute(\n SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE,\n response.status,\n );\n\n // Set status based on HTTP status code\n if (response.status >= 400) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: `HTTP ${response.status}`,\n });\n } else {\n ctx.setStatus({ code: SpanStatusCode.OK });\n }\n\n return response;\n } catch (error) {\n const duration = Date.now() - startTime;\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,\n duration,\n );\n\n if (mergedConfig.captureErrors) {\n ctx.recordError(error);\n }\n\n throw error;\n }\n });\n });\n };\n };\n}\n\n/**\n * Create a traced handler without auto-initialization\n *\n * Use this when you want to initialize autotel separately\n * (e.g., with more advanced configuration).\n *\n * @param config - Configuration options (excluding endpoint/headers)\n * @returns Function that wraps a request handler\n *\n * @example\n * ```typescript\n * import { init } from 'autotel';\n * import { createTracedHandler } from 'autotel-tanstack/handlers';\n *\n * // Initialize autotel with custom configuration\n * init({\n * service: 'my-app',\n * endpoint: 'https://api.honeycomb.io',\n * instrumentations: [/* custom instrumentations *\\/],\n * });\n *\n * // Wrap handler without re-initializing\n * export default createTracedHandler({\n * captureHeaders: ['x-request-id'],\n * })(createStartHandler(defaultStreamHandler));\n * ```\n */\nexport function createTracedHandler(\n config: Omit<WrapStartHandlerConfig, 'endpoint' | 'headers' | 'service'> = {},\n): (handler: RequestHandler) => RequestHandler {\n const mergedConfig = { ...DEFAULT_CONFIG, ...config };\n\n return function wrapHandler(handler: RequestHandler): RequestHandler {\n return async function tracedHandler(\n request: Request,\n opts?: { context?: Record<string, unknown> },\n ): Promise<Response> {\n const url = new URL(request.url);\n\n // Check if path should be excluded\n if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) {\n return handler(request, opts);\n }\n\n const parentContext = extractContextFromRequest(request);\n\n return context.with(parentContext, async () => {\n const spanName = `${request.method} ${url.pathname}`;\n\n return trace(spanName, async (ctx: TraceContext) => {\n ctx.setAttributes({\n [SPAN_ATTRIBUTES.HTTP_REQUEST_METHOD]: request.method,\n [SPAN_ATTRIBUTES.URL_PATH]: url.pathname,\n [SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'request',\n });\n\n if (url.search) {\n ctx.setAttribute(SPAN_ATTRIBUTES.URL_QUERY, url.search);\n }\n\n if (mergedConfig.captureHeaders) {\n for (const header of mergedConfig.captureHeaders) {\n const value = request.headers.get(header);\n if (value) {\n ctx.setAttribute(\n `http.request.header.${header.toLowerCase()}`,\n value,\n );\n }\n }\n }\n\n if (config.customAttributes) {\n const customAttrs = config.customAttributes({\n type: 'request',\n name: spanName,\n request,\n });\n ctx.setAttributes(\n customAttrs as Record<string, string | number | boolean>,\n );\n }\n\n const startTime = Date.now();\n\n try {\n const response = await handler(request, opts);\n const duration = Date.now() - startTime;\n\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,\n duration,\n );\n ctx.setAttribute(\n SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE,\n response.status,\n );\n\n if (response.status >= 400) {\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: `HTTP ${response.status}`,\n });\n } else {\n ctx.setStatus({ code: SpanStatusCode.OK });\n }\n\n return response;\n } catch (error) {\n const duration = Date.now() - startTime;\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,\n duration,\n );\n\n if (mergedConfig.captureErrors) {\n ctx.recordError(error);\n }\n\n throw error;\n }\n });\n });\n };\n };\n}\n"],"mappings":"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"}