autotel-tanstack 1.13.29 → 1.13.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto.d.ts +8 -35
- package/dist/auto.d.ts.map +1 -0
- package/dist/auto.js +41 -22
- package/dist/auto.js.map +1 -1
- package/dist/browser/context.d.ts +50 -0
- package/dist/browser/context.d.ts.map +1 -0
- package/dist/browser/context.js +54 -2
- package/dist/browser/context.js.map +1 -1
- package/dist/browser/debug-headers.d.ts +10 -0
- package/dist/browser/debug-headers.d.ts.map +1 -0
- package/dist/browser/debug-headers.js +12 -2
- package/dist/browser/debug-headers.js.map +1 -1
- package/dist/browser/error-reporting.d.ts +39 -0
- package/dist/browser/error-reporting.d.ts.map +1 -0
- package/dist/browser/error-reporting.js +35 -2
- package/dist/browser/error-reporting.js.map +1 -1
- package/dist/browser/handlers.d.ts +14 -0
- package/dist/browser/handlers.d.ts.map +1 -0
- package/dist/browser/handlers.js +10 -2
- package/dist/browser/handlers.js.map +1 -1
- package/dist/browser/index.d.ts +11 -0
- package/dist/browser/index.js +12 -12
- package/dist/browser/loaders.d.ts +31 -0
- package/dist/browser/loaders.d.ts.map +1 -0
- package/dist/browser/loaders.js +29 -2
- package/dist/browser/loaders.js.map +1 -1
- package/dist/browser/metrics.d.ts +56 -0
- package/dist/browser/metrics.d.ts.map +1 -0
- package/dist/browser/metrics.js +48 -2
- package/dist/browser/metrics.js.map +1 -1
- package/dist/browser/middleware.d.ts +42 -0
- package/dist/browser/middleware.d.ts.map +1 -0
- package/dist/browser/middleware.js +36 -2
- package/dist/browser/middleware.js.map +1 -1
- package/dist/browser/server-functions.d.ts +14 -0
- package/dist/browser/server-functions.d.ts.map +1 -0
- package/dist/browser/server-functions.js +16 -2
- package/dist/browser/server-functions.js.map +1 -1
- package/dist/browser/testing.d.ts +85 -0
- package/dist/browser/testing.d.ts.map +1 -0
- package/dist/browser/testing.js +43 -2
- package/dist/browser/testing.js.map +1 -1
- package/dist/browser/types.d.ts +2 -0
- package/dist/browser/types.js +37 -2
- package/dist/browser/types.js.map +1 -1
- package/dist/context.d.ts +5 -3
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +112 -3
- package/dist/context.js.map +1 -1
- package/dist/debug-headers.d.ts +14 -14
- package/dist/debug-headers.d.ts.map +1 -0
- package/dist/debug-headers.js +62 -4
- package/dist/debug-headers.js.map +1 -1
- package/dist/env-BpFWNnpL.js +30 -0
- package/dist/env-BpFWNnpL.js.map +1 -0
- package/dist/error-reporting.d.ts +37 -37
- package/dist/error-reporting.d.ts.map +1 -0
- package/dist/error-reporting.js +154 -3
- package/dist/error-reporting.js.map +1 -1
- package/dist/handlers.d.ts +5 -4
- package/dist/handlers.d.ts.map +1 -0
- package/dist/handlers.js +192 -6
- package/dist/handlers.js.map +1 -1
- package/dist/index.d.ts +15 -16
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -16
- package/dist/instrument-DS7YCE1R.d.ts +10 -0
- package/dist/instrument-DS7YCE1R.d.ts.map +1 -0
- package/dist/instrument-DdLlMfRi.js +80 -0
- package/dist/instrument-DdLlMfRi.js.map +1 -0
- package/dist/loaders-DrVVY25K.d.ts +2402 -0
- package/dist/loaders-DrVVY25K.d.ts.map +1 -0
- package/dist/loaders.d.ts +2 -116
- package/dist/loaders.js +234 -5
- package/dist/loaders.js.map +1 -1
- package/dist/metrics.d.ts +39 -39
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +144 -3
- package/dist/metrics.js.map +1 -1
- package/dist/middleware.d.ts +16 -15
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +290 -7
- package/dist/middleware.js.map +1 -1
- package/dist/route-filter-dLg-j3jR.js +33 -0
- package/dist/route-filter-dLg-j3jR.js.map +1 -0
- package/dist/server-functions.d.ts +4 -3
- package/dist/server-functions.d.ts.map +1 -0
- package/dist/server-functions.js +133 -5
- package/dist/server-functions.js.map +1 -1
- package/dist/testing.d.ts +164 -65
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +212 -147
- package/dist/testing.js.map +1 -1
- package/dist/types-BJ7FyVoX.d.ts +87 -0
- package/dist/types-BJ7FyVoX.d.ts.map +1 -0
- package/dist/types-BrccP0yX.js +38 -0
- package/dist/types-BrccP0yX.js.map +1 -0
- package/dist/types-pQgmQa4j.d.ts +154 -0
- package/dist/types-pQgmQa4j.d.ts.map +1 -0
- package/package.json +7 -7
- package/dist/browser/index.js.map +0 -1
- package/dist/chunk-7OXOAS64.js +0 -41
- package/dist/chunk-7OXOAS64.js.map +0 -1
- package/dist/chunk-A7WMQ2BC.js +0 -25
- package/dist/chunk-A7WMQ2BC.js.map +0 -1
- package/dist/chunk-CCME55EK.js +0 -28
- package/dist/chunk-CCME55EK.js.map +0 -1
- package/dist/chunk-CSFIPJC2.js +0 -11
- package/dist/chunk-CSFIPJC2.js.map +0 -1
- package/dist/chunk-DTZCOB4W.js +0 -32
- package/dist/chunk-DTZCOB4W.js.map +0 -1
- package/dist/chunk-EFSKEYDJ.js +0 -20
- package/dist/chunk-EFSKEYDJ.js.map +0 -1
- package/dist/chunk-EGRHWZRV.js +0 -3
- package/dist/chunk-EGRHWZRV.js.map +0 -1
- package/dist/chunk-ESU66L3L.js +0 -92
- package/dist/chunk-ESU66L3L.js.map +0 -1
- package/dist/chunk-EUYFVNYE.js +0 -16
- package/dist/chunk-EUYFVNYE.js.map +0 -1
- package/dist/chunk-FFQ4FJKE.js +0 -185
- package/dist/chunk-FFQ4FJKE.js.map +0 -1
- package/dist/chunk-G526TOMY.js +0 -96
- package/dist/chunk-G526TOMY.js.map +0 -1
- package/dist/chunk-I4LX3LOG.js +0 -35
- package/dist/chunk-I4LX3LOG.js.map +0 -1
- package/dist/chunk-JXO7H6KO.js +0 -10
- package/dist/chunk-JXO7H6KO.js.map +0 -1
- package/dist/chunk-KPXGFKPU.js +0 -193
- package/dist/chunk-KPXGFKPU.js.map +0 -1
- package/dist/chunk-LRA2UVVS.js +0 -210
- package/dist/chunk-LRA2UVVS.js.map +0 -1
- package/dist/chunk-MFYOV2SF.js +0 -32
- package/dist/chunk-MFYOV2SF.js.map +0 -1
- package/dist/chunk-MNP65ZX7.js +0 -21
- package/dist/chunk-MNP65ZX7.js.map +0 -1
- package/dist/chunk-NTY64BKS.js +0 -38
- package/dist/chunk-NTY64BKS.js.map +0 -1
- package/dist/chunk-UMEJU65Q.js +0 -34
- package/dist/chunk-UMEJU65Q.js.map +0 -1
- package/dist/chunk-UTPW3QRT.js +0 -52
- package/dist/chunk-UTPW3QRT.js.map +0 -1
- package/dist/chunk-V3RO5N2M.js +0 -8
- package/dist/chunk-V3RO5N2M.js.map +0 -1
- package/dist/chunk-XXBHZR3M.js +0 -99
- package/dist/chunk-XXBHZR3M.js.map +0 -1
- package/dist/chunk-YQYYPJCK.js +0 -37
- package/dist/chunk-YQYYPJCK.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/instrument-DRR7VL63.d.ts +0 -46
- package/dist/types-m5OjZJ-4.d.ts +0 -152
package/dist/chunk-FFQ4FJKE.js
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { isExcludedPath } from './chunk-CCME55EK.js';
|
|
2
|
-
import { DEFAULT_CONFIG, SPAN_ATTRIBUTES } from './chunk-I4LX3LOG.js';
|
|
3
|
-
import { extractContextFromRequest } from './chunk-NTY64BKS.js';
|
|
4
|
-
import { context, SpanStatusCode } from '@opentelemetry/api';
|
|
5
|
-
import { init, trace } from 'autotel';
|
|
6
|
-
|
|
7
|
-
function wrapStartHandler(config = {}) {
|
|
8
|
-
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
9
|
-
const service = config.service || process.env.OTEL_SERVICE_NAME || "tanstack-start";
|
|
10
|
-
const endpoint = config.endpoint || process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
11
|
-
let headers = config.headers;
|
|
12
|
-
if (!headers && process.env.OTEL_EXPORTER_OTLP_HEADERS) {
|
|
13
|
-
headers = {};
|
|
14
|
-
const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(",");
|
|
15
|
-
for (const pair of pairs) {
|
|
16
|
-
const [key, value] = pair.split("=");
|
|
17
|
-
if (key && value) {
|
|
18
|
-
headers[key.trim()] = value.trim();
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
init({
|
|
23
|
-
service,
|
|
24
|
-
endpoint,
|
|
25
|
-
headers
|
|
26
|
-
});
|
|
27
|
-
return function wrapHandler(handler) {
|
|
28
|
-
return async function tracedHandler(request, opts) {
|
|
29
|
-
const url = new URL(request.url);
|
|
30
|
-
if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) {
|
|
31
|
-
return handler(request, opts);
|
|
32
|
-
}
|
|
33
|
-
const parentContext = extractContextFromRequest(request);
|
|
34
|
-
return context.with(parentContext, async () => {
|
|
35
|
-
const spanName = `${request.method} ${url.pathname}`;
|
|
36
|
-
return trace(spanName, async (ctx) => {
|
|
37
|
-
ctx.setAttributes({
|
|
38
|
-
[SPAN_ATTRIBUTES.HTTP_REQUEST_METHOD]: request.method,
|
|
39
|
-
[SPAN_ATTRIBUTES.URL_PATH]: url.pathname,
|
|
40
|
-
[SPAN_ATTRIBUTES.URL_FULL]: request.url,
|
|
41
|
-
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: "request"
|
|
42
|
-
});
|
|
43
|
-
if (url.search) {
|
|
44
|
-
ctx.setAttribute(SPAN_ATTRIBUTES.URL_QUERY, url.search);
|
|
45
|
-
}
|
|
46
|
-
if (mergedConfig.captureHeaders) {
|
|
47
|
-
for (const header of mergedConfig.captureHeaders) {
|
|
48
|
-
const value = request.headers.get(header);
|
|
49
|
-
if (value) {
|
|
50
|
-
ctx.setAttribute(
|
|
51
|
-
`http.request.header.${header.toLowerCase()}`,
|
|
52
|
-
value
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (config.customAttributes) {
|
|
58
|
-
const customAttrs = config.customAttributes({
|
|
59
|
-
type: "request",
|
|
60
|
-
name: spanName,
|
|
61
|
-
request
|
|
62
|
-
});
|
|
63
|
-
ctx.setAttributes(
|
|
64
|
-
customAttrs
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
const startTime = Date.now();
|
|
68
|
-
try {
|
|
69
|
-
const response = await handler(request, opts);
|
|
70
|
-
const duration = Date.now() - startTime;
|
|
71
|
-
ctx.setAttribute(
|
|
72
|
-
SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,
|
|
73
|
-
duration
|
|
74
|
-
);
|
|
75
|
-
ctx.setAttribute(
|
|
76
|
-
SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE,
|
|
77
|
-
response.status
|
|
78
|
-
);
|
|
79
|
-
if (response.status >= 400) {
|
|
80
|
-
ctx.setStatus({
|
|
81
|
-
code: SpanStatusCode.ERROR,
|
|
82
|
-
message: `HTTP ${response.status}`
|
|
83
|
-
});
|
|
84
|
-
} else {
|
|
85
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
86
|
-
}
|
|
87
|
-
return response;
|
|
88
|
-
} catch (error) {
|
|
89
|
-
const duration = Date.now() - startTime;
|
|
90
|
-
ctx.setAttribute(
|
|
91
|
-
SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,
|
|
92
|
-
duration
|
|
93
|
-
);
|
|
94
|
-
if (mergedConfig.captureErrors) {
|
|
95
|
-
ctx.recordError(error);
|
|
96
|
-
}
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
};
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
function createTracedHandler(config = {}) {
|
|
105
|
-
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
106
|
-
return function wrapHandler(handler) {
|
|
107
|
-
return async function tracedHandler(request, opts) {
|
|
108
|
-
const url = new URL(request.url);
|
|
109
|
-
if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) {
|
|
110
|
-
return handler(request, opts);
|
|
111
|
-
}
|
|
112
|
-
const parentContext = extractContextFromRequest(request);
|
|
113
|
-
return context.with(parentContext, async () => {
|
|
114
|
-
const spanName = `${request.method} ${url.pathname}`;
|
|
115
|
-
return trace(spanName, async (ctx) => {
|
|
116
|
-
ctx.setAttributes({
|
|
117
|
-
[SPAN_ATTRIBUTES.HTTP_REQUEST_METHOD]: request.method,
|
|
118
|
-
[SPAN_ATTRIBUTES.URL_PATH]: url.pathname,
|
|
119
|
-
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: "request"
|
|
120
|
-
});
|
|
121
|
-
if (url.search) {
|
|
122
|
-
ctx.setAttribute(SPAN_ATTRIBUTES.URL_QUERY, url.search);
|
|
123
|
-
}
|
|
124
|
-
if (mergedConfig.captureHeaders) {
|
|
125
|
-
for (const header of mergedConfig.captureHeaders) {
|
|
126
|
-
const value = request.headers.get(header);
|
|
127
|
-
if (value) {
|
|
128
|
-
ctx.setAttribute(
|
|
129
|
-
`http.request.header.${header.toLowerCase()}`,
|
|
130
|
-
value
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (config.customAttributes) {
|
|
136
|
-
const customAttrs = config.customAttributes({
|
|
137
|
-
type: "request",
|
|
138
|
-
name: spanName,
|
|
139
|
-
request
|
|
140
|
-
});
|
|
141
|
-
ctx.setAttributes(
|
|
142
|
-
customAttrs
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
const startTime = Date.now();
|
|
146
|
-
try {
|
|
147
|
-
const response = await handler(request, opts);
|
|
148
|
-
const duration = Date.now() - startTime;
|
|
149
|
-
ctx.setAttribute(
|
|
150
|
-
SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,
|
|
151
|
-
duration
|
|
152
|
-
);
|
|
153
|
-
ctx.setAttribute(
|
|
154
|
-
SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE,
|
|
155
|
-
response.status
|
|
156
|
-
);
|
|
157
|
-
if (response.status >= 400) {
|
|
158
|
-
ctx.setStatus({
|
|
159
|
-
code: SpanStatusCode.ERROR,
|
|
160
|
-
message: `HTTP ${response.status}`
|
|
161
|
-
});
|
|
162
|
-
} else {
|
|
163
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
164
|
-
}
|
|
165
|
-
return response;
|
|
166
|
-
} catch (error) {
|
|
167
|
-
const duration = Date.now() - startTime;
|
|
168
|
-
ctx.setAttribute(
|
|
169
|
-
SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,
|
|
170
|
-
duration
|
|
171
|
-
);
|
|
172
|
-
if (mergedConfig.captureErrors) {
|
|
173
|
-
ctx.recordError(error);
|
|
174
|
-
}
|
|
175
|
-
throw error;
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
};
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export { createTracedHandler, wrapStartHandler };
|
|
184
|
-
//# sourceMappingURL=chunk-FFQ4FJKE.js.map
|
|
185
|
-
//# sourceMappingURL=chunk-FFQ4FJKE.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/handlers.ts"],"names":[],"mappings":"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","file":"chunk-FFQ4FJKE.js","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"]}
|
package/dist/chunk-G526TOMY.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
// src/metrics.ts
|
|
2
|
-
var MetricsCollector = class {
|
|
3
|
-
metrics = /* @__PURE__ */ new Map();
|
|
4
|
-
maxSamples = 1e3;
|
|
5
|
-
// Limit memory usage
|
|
6
|
-
/**
|
|
7
|
-
* Record a timing measurement
|
|
8
|
-
*/
|
|
9
|
-
recordTiming(name, duration) {
|
|
10
|
-
if (!this.metrics.has(name)) {
|
|
11
|
-
this.metrics.set(name, []);
|
|
12
|
-
}
|
|
13
|
-
const timings = this.metrics.get(name);
|
|
14
|
-
timings.push(duration);
|
|
15
|
-
if (timings.length > this.maxSamples) {
|
|
16
|
-
timings.shift();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Get statistics for a metric
|
|
21
|
-
*/
|
|
22
|
-
getStats(name) {
|
|
23
|
-
const timings = this.metrics.get(name);
|
|
24
|
-
if (!timings || timings.length === 0) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
const sorted = [...timings].toSorted((a, b) => a - b);
|
|
28
|
-
const sum = timings.reduce((a, b) => a + b, 0);
|
|
29
|
-
return {
|
|
30
|
-
count: timings.length,
|
|
31
|
-
avg: sum / timings.length,
|
|
32
|
-
p50: sorted.at(Math.floor(sorted.length * 0.5)) ?? 0,
|
|
33
|
-
p95: sorted.at(Math.floor(sorted.length * 0.95)) ?? 0,
|
|
34
|
-
min: sorted[0] ?? 0,
|
|
35
|
-
max: sorted.at(-1) ?? 0
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Get all collected metrics
|
|
40
|
-
*/
|
|
41
|
-
getAllStats() {
|
|
42
|
-
const stats = {};
|
|
43
|
-
for (const [name] of this.metrics) {
|
|
44
|
-
const stat = this.getStats(name);
|
|
45
|
-
if (stat) {
|
|
46
|
-
stats[name] = stat;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return stats;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Reset all metrics
|
|
53
|
-
*/
|
|
54
|
-
reset() {
|
|
55
|
-
this.metrics.clear();
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Reset a specific metric
|
|
59
|
-
*/
|
|
60
|
-
resetMetric(name) {
|
|
61
|
-
this.metrics.delete(name);
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
var metricsCollector = new MetricsCollector();
|
|
65
|
-
function createMetricsHandler() {
|
|
66
|
-
return async () => {
|
|
67
|
-
const { json } = await import('@tanstack/react-start');
|
|
68
|
-
return json({
|
|
69
|
-
system: {
|
|
70
|
-
uptime: process.uptime(),
|
|
71
|
-
memory: process.memoryUsage(),
|
|
72
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
73
|
-
},
|
|
74
|
-
application: metricsCollector.getAllStats()
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function recordTiming(metricName, fn) {
|
|
79
|
-
return (async (...args) => {
|
|
80
|
-
const startTime = Date.now();
|
|
81
|
-
try {
|
|
82
|
-
const result = await fn(...args);
|
|
83
|
-
const duration = Date.now() - startTime;
|
|
84
|
-
metricsCollector.recordTiming(metricName, duration);
|
|
85
|
-
return result;
|
|
86
|
-
} catch (error) {
|
|
87
|
-
const duration = Date.now() - startTime;
|
|
88
|
-
metricsCollector.recordTiming(`${metricName}.error`, duration);
|
|
89
|
-
throw error;
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export { createMetricsHandler, metricsCollector, recordTiming };
|
|
95
|
-
//# sourceMappingURL=chunk-G526TOMY.js.map
|
|
96
|
-
//# sourceMappingURL=chunk-G526TOMY.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/metrics.ts"],"names":[],"mappings":"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","file":"chunk-G526TOMY.js","sourcesContent":["/**\n * Performance metrics collection for TanStack Start\n *\n * Provides utilities to collect and expose performance metrics\n * following the patterns from TanStack Start observability guide.\n */\n\n/**\n * Performance timing data\n */\nexport interface TimingStats {\n count: number;\n avg: number;\n p50: number;\n p95: number;\n min: number;\n max: number;\n}\n\n/**\n * Metrics collector for performance data\n *\n * Collects timing metrics and provides statistical analysis.\n * Thread-safe for concurrent access.\n *\n * @example\n * ```typescript\n * import { metricsCollector } from 'autotel-tanstack/metrics';\n *\n * // Record a timing\n * metricsCollector.recordTiming('serverFn.getUser', 150);\n *\n * // Get stats\n * const stats = metricsCollector.getStats('serverFn.getUser');\n * console.log(`Average: ${stats.avg}ms, P95: ${stats.p95}ms`);\n * ```\n */\nclass MetricsCollector {\n private metrics = new Map<string, number[]>();\n private readonly maxSamples = 1000; // Limit memory usage\n\n /**\n * Record a timing measurement\n */\n recordTiming(name: string, duration: number): void {\n if (!this.metrics.has(name)) {\n this.metrics.set(name, []);\n }\n\n const timings = this.metrics.get(name)!;\n timings.push(duration);\n\n // Limit samples to prevent memory issues\n if (timings.length > this.maxSamples) {\n timings.shift(); // Remove oldest\n }\n }\n\n /**\n * Get statistics for a metric\n */\n getStats(name: string): TimingStats | null {\n const timings = this.metrics.get(name);\n if (!timings || timings.length === 0) {\n return null;\n }\n\n const sorted = [...timings].toSorted((a, b) => a - b);\n const sum = timings.reduce((a, b) => a + b, 0);\n\n return {\n count: timings.length,\n avg: sum / timings.length,\n p50: sorted.at(Math.floor(sorted.length * 0.5)) ?? 0,\n p95: sorted.at(Math.floor(sorted.length * 0.95)) ?? 0,\n min: sorted[0] ?? 0,\n max: sorted.at(-1) ?? 0,\n };\n }\n\n /**\n * Get all collected metrics\n */\n getAllStats(): Record<string, TimingStats> {\n const stats: Record<string, TimingStats> = {};\n for (const [name] of this.metrics) {\n const stat = this.getStats(name);\n if (stat) {\n stats[name] = stat;\n }\n }\n return stats;\n }\n\n /**\n * Reset all metrics\n */\n reset(): void {\n this.metrics.clear();\n }\n\n /**\n * Reset a specific metric\n */\n resetMetric(name: string): void {\n this.metrics.delete(name);\n }\n}\n\n/**\n * Global metrics collector instance\n */\nexport const metricsCollector = new MetricsCollector();\n\n/**\n * Helper to create a metrics endpoint handler\n *\n * Returns a handler that exposes metrics in JSON format.\n * Use this to create a `/metrics` endpoint.\n *\n * @example\n * ```typescript\n * // routes/metrics.ts\n * import { createFileRoute } from '@tanstack/react-router';\n * import { json } from '@tanstack/react-start';\n * import { createMetricsHandler } from 'autotel-tanstack/metrics';\n *\n * export const Route = createFileRoute('/metrics')({\n * server: {\n * handlers: {\n * GET: createMetricsHandler(),\n * },\n * },\n * });\n * ```\n */\nexport function createMetricsHandler() {\n return async () => {\n const { json } = await import('@tanstack/react-start');\n\n return json({\n system: {\n uptime: process.uptime(),\n memory: process.memoryUsage(),\n timestamp: new Date().toISOString(),\n },\n application: metricsCollector.getAllStats(),\n });\n };\n}\n\n/**\n * Auto-record timing from a function execution\n *\n * Wraps a function to automatically record its execution time.\n *\n * @example\n * ```typescript\n * import { recordTiming } from 'autotel-tanstack/metrics';\n *\n * const getUser = createServerFn({ method: 'GET' })\n * .handler(recordTiming('serverFn.getUser', async ({ data: id }) => {\n * return await db.users.findUnique({ where: { id } });\n * }));\n * ```\n */\nexport function recordTiming<T extends (...args: any[]) => any>(\n metricName: string,\n fn: T,\n): T {\n return (async (...args: Parameters<T>) => {\n const startTime = Date.now();\n try {\n const result = await fn(...args);\n const duration = Date.now() - startTime;\n metricsCollector.recordTiming(metricName, duration);\n return result as ReturnType<T>;\n } catch (error) {\n const duration = Date.now() - startTime;\n metricsCollector.recordTiming(`${metricName}.error`, duration);\n throw error;\n }\n }) as T;\n}\n"]}
|
package/dist/chunk-I4LX3LOG.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
// src/types.ts
|
|
2
|
-
var DEFAULT_CONFIG = {
|
|
3
|
-
captureArgs: true,
|
|
4
|
-
captureResults: false,
|
|
5
|
-
captureErrors: true,
|
|
6
|
-
captureHeaders: ["x-request-id"],
|
|
7
|
-
excludePaths: [],
|
|
8
|
-
sampling: "adaptive"
|
|
9
|
-
};
|
|
10
|
-
var SPAN_ATTRIBUTES = {
|
|
11
|
-
// HTTP semantic conventions
|
|
12
|
-
HTTP_REQUEST_METHOD: "http.request.method",
|
|
13
|
-
HTTP_RESPONSE_STATUS_CODE: "http.response.status_code",
|
|
14
|
-
URL_PATH: "url.path",
|
|
15
|
-
URL_QUERY: "url.query",
|
|
16
|
-
URL_FULL: "url.full",
|
|
17
|
-
// RPC semantic conventions (for server functions)
|
|
18
|
-
RPC_SYSTEM: "rpc.system",
|
|
19
|
-
RPC_METHOD: "rpc.method",
|
|
20
|
-
// TanStack-specific attributes
|
|
21
|
-
TANSTACK_TYPE: "tanstack.type",
|
|
22
|
-
TANSTACK_SERVER_FN_NAME: "tanstack.server_function.name",
|
|
23
|
-
TANSTACK_SERVER_FN_METHOD: "tanstack.server_function.method",
|
|
24
|
-
TANSTACK_SERVER_FN_ARGS: "tanstack.server_function.args",
|
|
25
|
-
TANSTACK_SERVER_FN_RESULT: "tanstack.server_function.result",
|
|
26
|
-
TANSTACK_LOADER_ROUTE_ID: "tanstack.loader.route_id",
|
|
27
|
-
TANSTACK_LOADER_TYPE: "tanstack.loader.type",
|
|
28
|
-
TANSTACK_LOADER_PARAMS: "tanstack.loader.params",
|
|
29
|
-
TANSTACK_MIDDLEWARE_NAME: "tanstack.middleware.name",
|
|
30
|
-
TANSTACK_REQUEST_DURATION_MS: "tanstack.request.duration_ms"
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export { DEFAULT_CONFIG, SPAN_ATTRIBUTES };
|
|
34
|
-
//# sourceMappingURL=chunk-I4LX3LOG.js.map
|
|
35
|
-
//# sourceMappingURL=chunk-I4LX3LOG.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";AAgJO,IAAM,cAAA,GAET;AAAA,EACF,WAAA,EAAa,IAAA;AAAA,EACb,cAAA,EAAgB,KAAA;AAAA,EAChB,aAAA,EAAe,IAAA;AAAA,EACf,cAAA,EAAgB,CAAC,cAAc,CAAA;AAAA,EAC/B,cAAc,EAAC;AAAA,EACf,QAAA,EAAU;AACZ;AAKO,IAAM,eAAA,GAAkB;AAAA;AAAA,EAE7B,mBAAA,EAAqB,qBAAA;AAAA,EACrB,yBAAA,EAA2B,2BAAA;AAAA,EAC3B,QAAA,EAAU,UAAA;AAAA,EACV,SAAA,EAAW,WAAA;AAAA,EACX,QAAA,EAAU,UAAA;AAAA;AAAA,EAGV,UAAA,EAAY,YAAA;AAAA,EACZ,UAAA,EAAY,YAAA;AAAA;AAAA,EAGZ,aAAA,EAAe,eAAA;AAAA,EACf,uBAAA,EAAyB,+BAAA;AAAA,EACzB,yBAAA,EAA2B,iCAAA;AAAA,EAC3B,uBAAA,EAAyB,+BAAA;AAAA,EACzB,yBAAA,EAA2B,iCAAA;AAAA,EAC3B,wBAAA,EAA0B,0BAAA;AAAA,EAC1B,oBAAA,EAAsB,sBAAA;AAAA,EACtB,sBAAA,EAAwB,wBAAA;AAAA,EACxB,wBAAA,EAA0B,0BAAA;AAAA,EAC1B,4BAAA,EAA8B;AAChC","file":"chunk-I4LX3LOG.js","sourcesContent":["import type { Attributes } from '@opentelemetry/api';\n\n/**\n * Configuration options for TanStack Start instrumentation\n */\nexport interface TanStackInstrumentationConfig {\n /**\n * Service name for spans\n * @default process.env.OTEL_SERVICE_NAME || 'tanstack-start'\n */\n service?: string;\n\n /**\n * Whether to capture function arguments as span attributes\n * Warning: May contain PII, review before enabling in production\n * @default true\n */\n captureArgs?: boolean;\n\n /**\n * Whether to capture function results as span attributes\n * Warning: May contain PII, disable in production\n * @default false\n */\n captureResults?: boolean;\n\n /**\n * Whether to capture errors and record exceptions\n * @default true\n */\n captureErrors?: boolean;\n\n /**\n * HTTP headers to capture as span attributes\n * @default ['x-request-id']\n */\n captureHeaders?: string[];\n\n /**\n * URL paths to exclude from tracing (glob patterns)\n * @default []\n */\n excludePaths?: (string | RegExp)[];\n\n /**\n * Sampling strategy\n * - 'always': Sample all requests (100%)\n * - 'adaptive': Use autotel's adaptive sampling (errors + slow = 100%, baseline 10%)\n * - 'never': Disable sampling (for testing/debugging)\n * @default 'adaptive'\n */\n sampling?: 'always' | 'adaptive' | 'never';\n\n /**\n * Custom function to extract additional span attributes\n */\n customAttributes?: (context: {\n type: 'request' | 'serverFn' | 'loader' | 'beforeLoad' | 'middleware';\n name: string;\n request?: Request;\n args?: unknown;\n result?: unknown;\n }) => Attributes;\n}\n\n/**\n * Configuration specific to tracing middleware\n */\nexport interface TracingMiddlewareConfig extends TanStackInstrumentationConfig {\n /**\n * Type of middleware\n * - 'request': For global request middleware (routes, SSR)\n * - 'function': For server function middleware\n * @default 'request'\n */\n type?: 'request' | 'function';\n}\n\n/**\n * Configuration for server function tracing\n */\nexport interface TraceServerFnConfig {\n /**\n * Explicit name for the span\n * If not provided, will attempt to infer from function name\n */\n name?: string;\n\n /**\n * Whether to capture function arguments\n * @default true\n */\n captureArgs?: boolean;\n\n /**\n * Whether to capture function results\n * @default false\n */\n captureResults?: boolean;\n}\n\n/**\n * Configuration for loader tracing\n */\nexport interface TraceLoaderConfig {\n /**\n * Explicit name for the span\n * If not provided, will use route ID\n */\n name?: string;\n\n /**\n * Whether to capture route params\n * @default true\n */\n captureParams?: boolean;\n\n /**\n * Whether to capture loader result\n * @default false\n */\n captureResult?: boolean;\n}\n\n/**\n * Configuration for handler wrapper\n */\nexport interface WrapStartHandlerConfig extends TanStackInstrumentationConfig {\n /**\n * OTLP endpoint URL\n * @default process.env.OTEL_EXPORTER_OTLP_ENDPOINT\n */\n endpoint?: string;\n\n /**\n * OTLP headers (e.g., for authentication)\n * @default parsed from process.env.OTEL_EXPORTER_OTLP_HEADERS\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG: Required<\n Omit<TanStackInstrumentationConfig, 'customAttributes' | 'service'>\n> = {\n captureArgs: true,\n captureResults: false,\n captureErrors: true,\n captureHeaders: ['x-request-id'],\n excludePaths: [],\n sampling: 'adaptive',\n};\n\n/**\n * Span attribute keys following OpenTelemetry semantic conventions\n */\nexport const SPAN_ATTRIBUTES = {\n // HTTP semantic conventions\n HTTP_REQUEST_METHOD: 'http.request.method',\n HTTP_RESPONSE_STATUS_CODE: 'http.response.status_code',\n URL_PATH: 'url.path',\n URL_QUERY: 'url.query',\n URL_FULL: 'url.full',\n\n // RPC semantic conventions (for server functions)\n RPC_SYSTEM: 'rpc.system',\n RPC_METHOD: 'rpc.method',\n\n // TanStack-specific attributes\n TANSTACK_TYPE: 'tanstack.type',\n TANSTACK_SERVER_FN_NAME: 'tanstack.server_function.name',\n TANSTACK_SERVER_FN_METHOD: 'tanstack.server_function.method',\n TANSTACK_SERVER_FN_ARGS: 'tanstack.server_function.args',\n TANSTACK_SERVER_FN_RESULT: 'tanstack.server_function.result',\n TANSTACK_LOADER_ROUTE_ID: 'tanstack.loader.route_id',\n TANSTACK_LOADER_TYPE: 'tanstack.loader.type',\n TANSTACK_LOADER_PARAMS: 'tanstack.loader.params',\n TANSTACK_MIDDLEWARE_NAME: 'tanstack.middleware.name',\n TANSTACK_REQUEST_DURATION_MS: 'tanstack.request.duration_ms',\n} as const;\n"]}
|
package/dist/chunk-JXO7H6KO.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// src/browser/debug-headers.ts
|
|
2
|
-
function debugHeadersMiddleware() {
|
|
3
|
-
return async function noopMiddleware(opts) {
|
|
4
|
-
return opts.next();
|
|
5
|
-
};
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export { debugHeadersMiddleware };
|
|
9
|
-
//# sourceMappingURL=chunk-JXO7H6KO.js.map
|
|
10
|
-
//# sourceMappingURL=chunk-JXO7H6KO.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/browser/debug-headers.ts"],"names":[],"mappings":";AAYO,SAAS,sBAAA,GAEiB;AAC/B,EAAA,OAAO,eAAe,eAAe,IAAA,EAAM;AACzC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA;AACF","file":"chunk-JXO7H6KO.js","sourcesContent":["/**\n * Browser stub for debug-headers module\n *\n * Debug headers are server-side only.\n * In browser, this returns pass-through middleware.\n */\n\nimport type { MiddlewareHandler } from './middleware';\n\n/**\n * Browser stub: Returns pass-through middleware\n */\nexport function debugHeadersMiddleware<\n TContext = unknown,\n>(): MiddlewareHandler<TContext> {\n return async function noopMiddleware(opts) {\n return opts.next();\n };\n}\n"]}
|
package/dist/chunk-KPXGFKPU.js
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { isServerSide } from './chunk-EUYFVNYE.js';
|
|
2
|
-
import { SPAN_ATTRIBUTES } from './chunk-I4LX3LOG.js';
|
|
3
|
-
import { SpanStatusCode } from '@opentelemetry/api';
|
|
4
|
-
import { trace } from 'autotel';
|
|
5
|
-
|
|
6
|
-
function traceLoader(loaderFn, config = {}) {
|
|
7
|
-
const captureParams = config.captureParams ?? true;
|
|
8
|
-
const captureResult = config.captureResult ?? false;
|
|
9
|
-
const wrapped = (context) => {
|
|
10
|
-
if (!isServerSide()) {
|
|
11
|
-
return loaderFn(context);
|
|
12
|
-
}
|
|
13
|
-
const routeId = context?.route?.id || "unknown";
|
|
14
|
-
const spanName = config.name || `tanstack.loader.${routeId}`;
|
|
15
|
-
const result = loaderFn(context);
|
|
16
|
-
const isPromise = result instanceof Promise;
|
|
17
|
-
if (!isPromise) {
|
|
18
|
-
return trace(spanName, (ctx) => {
|
|
19
|
-
ctx.setAttributes({
|
|
20
|
-
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: "loader",
|
|
21
|
-
[SPAN_ATTRIBUTES.TANSTACK_LOADER_ROUTE_ID]: routeId,
|
|
22
|
-
[SPAN_ATTRIBUTES.TANSTACK_LOADER_TYPE]: "loader"
|
|
23
|
-
});
|
|
24
|
-
if (captureParams && context?.params) {
|
|
25
|
-
try {
|
|
26
|
-
ctx.setAttribute(
|
|
27
|
-
SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,
|
|
28
|
-
JSON.stringify(context.params)
|
|
29
|
-
);
|
|
30
|
-
} catch {
|
|
31
|
-
ctx.setAttribute(
|
|
32
|
-
SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,
|
|
33
|
-
"[non-serializable]"
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if (captureResult && result !== void 0) {
|
|
38
|
-
try {
|
|
39
|
-
ctx.setAttribute("tanstack.loader.result", JSON.stringify(result));
|
|
40
|
-
} catch {
|
|
41
|
-
ctx.setAttribute("tanstack.loader.result", "[non-serializable]");
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
45
|
-
return result;
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
return trace(spanName, async (ctx) => {
|
|
49
|
-
ctx.setAttributes({
|
|
50
|
-
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: "loader",
|
|
51
|
-
[SPAN_ATTRIBUTES.TANSTACK_LOADER_ROUTE_ID]: routeId,
|
|
52
|
-
[SPAN_ATTRIBUTES.TANSTACK_LOADER_TYPE]: "loader"
|
|
53
|
-
});
|
|
54
|
-
if (captureParams && context?.params) {
|
|
55
|
-
try {
|
|
56
|
-
ctx.setAttribute(
|
|
57
|
-
SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,
|
|
58
|
-
JSON.stringify(context.params)
|
|
59
|
-
);
|
|
60
|
-
} catch {
|
|
61
|
-
ctx.setAttribute(
|
|
62
|
-
SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,
|
|
63
|
-
"[non-serializable]"
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
const asyncResult = await result;
|
|
69
|
-
if (captureResult && asyncResult !== void 0) {
|
|
70
|
-
try {
|
|
71
|
-
ctx.setAttribute(
|
|
72
|
-
"tanstack.loader.result",
|
|
73
|
-
JSON.stringify(asyncResult)
|
|
74
|
-
);
|
|
75
|
-
} catch {
|
|
76
|
-
ctx.setAttribute("tanstack.loader.result", "[non-serializable]");
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
80
|
-
return asyncResult;
|
|
81
|
-
} catch (error) {
|
|
82
|
-
if ("recordError" in ctx && typeof ctx.recordError === "function") {
|
|
83
|
-
ctx.recordError(error);
|
|
84
|
-
} else if ("recordException" in ctx && typeof ctx.recordException === "function") {
|
|
85
|
-
ctx.recordException(error);
|
|
86
|
-
}
|
|
87
|
-
throw error;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
return wrapped;
|
|
92
|
-
}
|
|
93
|
-
function traceBeforeLoad(beforeLoadFn, config = {}) {
|
|
94
|
-
const captureParams = config.captureParams ?? true;
|
|
95
|
-
const wrapped = (input) => {
|
|
96
|
-
if (!isServerSide()) {
|
|
97
|
-
return beforeLoadFn(input);
|
|
98
|
-
}
|
|
99
|
-
const routeId = input?.route?.id || "unknown";
|
|
100
|
-
const spanName = config.name || `tanstack.beforeLoad.${routeId}`;
|
|
101
|
-
const result = beforeLoadFn(input);
|
|
102
|
-
const isPromise = result instanceof Promise;
|
|
103
|
-
if (!isPromise) {
|
|
104
|
-
return trace(spanName, (ctx) => {
|
|
105
|
-
ctx.setAttributes({
|
|
106
|
-
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: "beforeLoad",
|
|
107
|
-
[SPAN_ATTRIBUTES.TANSTACK_LOADER_ROUTE_ID]: routeId,
|
|
108
|
-
[SPAN_ATTRIBUTES.TANSTACK_LOADER_TYPE]: "beforeLoad"
|
|
109
|
-
});
|
|
110
|
-
if (captureParams && input?.params) {
|
|
111
|
-
try {
|
|
112
|
-
ctx.setAttribute(
|
|
113
|
-
SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,
|
|
114
|
-
JSON.stringify(input.params)
|
|
115
|
-
);
|
|
116
|
-
} catch {
|
|
117
|
-
ctx.setAttribute(
|
|
118
|
-
SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,
|
|
119
|
-
"[non-serializable]"
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
124
|
-
return result;
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
return trace(spanName, async (ctx) => {
|
|
128
|
-
ctx.setAttributes({
|
|
129
|
-
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: "beforeLoad",
|
|
130
|
-
[SPAN_ATTRIBUTES.TANSTACK_LOADER_ROUTE_ID]: routeId,
|
|
131
|
-
[SPAN_ATTRIBUTES.TANSTACK_LOADER_TYPE]: "beforeLoad"
|
|
132
|
-
});
|
|
133
|
-
if (captureParams && input?.params) {
|
|
134
|
-
try {
|
|
135
|
-
ctx.setAttribute(
|
|
136
|
-
SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,
|
|
137
|
-
JSON.stringify(input.params)
|
|
138
|
-
);
|
|
139
|
-
} catch {
|
|
140
|
-
ctx.setAttribute(
|
|
141
|
-
SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,
|
|
142
|
-
"[non-serializable]"
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
try {
|
|
147
|
-
const asyncResult = await result;
|
|
148
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
149
|
-
return asyncResult;
|
|
150
|
-
} catch (error) {
|
|
151
|
-
const errorName = error.name;
|
|
152
|
-
if (errorName === "RedirectError" || errorName === "NotFoundError") {
|
|
153
|
-
ctx.setAttribute("tanstack.beforeLoad.redirect", true);
|
|
154
|
-
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
155
|
-
} else {
|
|
156
|
-
if ("recordError" in ctx && typeof ctx.recordError === "function") {
|
|
157
|
-
ctx.recordError(error);
|
|
158
|
-
} else if ("recordException" in ctx && typeof ctx.recordException === "function") {
|
|
159
|
-
ctx.recordException(error);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
throw error;
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
return wrapped;
|
|
167
|
-
}
|
|
168
|
-
function createTracedRoute(routeId, config = {}) {
|
|
169
|
-
return {
|
|
170
|
-
/**
|
|
171
|
-
* Wrap a loader function with tracing
|
|
172
|
-
*/
|
|
173
|
-
loader(loaderFn) {
|
|
174
|
-
return traceLoader(loaderFn, {
|
|
175
|
-
...config,
|
|
176
|
-
name: `tanstack.loader.${routeId}`
|
|
177
|
-
});
|
|
178
|
-
},
|
|
179
|
-
/**
|
|
180
|
-
* Wrap a beforeLoad function with tracing
|
|
181
|
-
*/
|
|
182
|
-
beforeLoad(beforeLoadFn) {
|
|
183
|
-
return traceBeforeLoad(beforeLoadFn, {
|
|
184
|
-
...config,
|
|
185
|
-
name: `tanstack.beforeLoad.${routeId}`
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export { createTracedRoute, traceBeforeLoad, traceLoader };
|
|
192
|
-
//# sourceMappingURL=chunk-KPXGFKPU.js.map
|
|
193
|
-
//# sourceMappingURL=chunk-KPXGFKPU.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/loaders.ts"],"names":[],"mappings":"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","file":"chunk-KPXGFKPU.js","sourcesContent":["import { SpanStatusCode } from '@opentelemetry/api';\nimport { trace, type TraceContext } from 'autotel';\nimport { isServerSide } from './env';\nimport { type TraceLoaderConfig, SPAN_ATTRIBUTES } from './types';\n\n// Re-export types from @tanstack/react-router for consumers who need them\nexport type { LoaderFnContext } from '@tanstack/react-router';\n\n/**\n * Internal type for extracting route info from TanStack context.\n * This is a minimal interface used only for instrumentation - the actual\n * TanStack types flow through the generic parameter.\n */\ninterface TanStackContextInternal {\n route?: { id?: string };\n params?: Record<string, string>;\n}\n\n/**\n * Wrap a TanStack route loader with OpenTelemetry tracing\n *\n * This function wraps a loader function to automatically create spans\n * for each invocation. It captures route ID, params (optionally),\n * and errors.\n *\n * The generic type TLoaderFn preserves the full TanStack Router type inference,\n * including typed params, context, and return types.\n *\n * @param loaderFn - The loader function to wrap\n * @param config - Configuration options\n * @returns Wrapped loader function with tracing (preserves original types)\n *\n * @example\n * ```typescript\n * import { createFileRoute } from '@tanstack/react-router';\n * import { traceLoader } from 'autotel-tanstack/loaders';\n *\n * export const Route = createFileRoute('/users/$userId')({\n * // Types are fully preserved - params.userId is typed as string\n * loader: traceLoader(async ({ params }) => {\n * return await db.users.findUnique({ where: { id: params.userId } });\n * }),\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Sync loaders are also supported\n * export const Route = createFileRoute('/static')({\n * loader: traceLoader(({ context }) => ({\n * message: `Welcome, ${context.userId}!`,\n * })),\n * });\n * ```\n */\nexport function traceLoader<TLoaderFn extends (ctx: any) => any>(\n loaderFn: TLoaderFn,\n config: TraceLoaderConfig = {},\n): TLoaderFn {\n const captureParams = config.captureParams ?? true;\n const captureResult = config.captureResult ?? false;\n\n const wrapped = (context: TanStackContextInternal) => {\n // If we're in the browser, just call the loader without tracing\n // This prevents autotel (which uses Node.js APIs) from being executed in the browser\n if (!isServerSide()) {\n return loaderFn(context);\n }\n\n const routeId = context?.route?.id || 'unknown';\n const spanName = config.name || `tanstack.loader.${routeId}`;\n\n // Handle both sync and async loaders\n const result = loaderFn(context);\n const isPromise = result instanceof Promise;\n\n if (!isPromise) {\n // Sync loader - wrap in trace synchronously\n return trace(spanName, (ctx: TraceContext) => {\n ctx.setAttributes({\n [SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'loader',\n [SPAN_ATTRIBUTES.TANSTACK_LOADER_ROUTE_ID]: routeId,\n [SPAN_ATTRIBUTES.TANSTACK_LOADER_TYPE]: 'loader',\n });\n\n if (captureParams && context?.params) {\n try {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,\n JSON.stringify(context.params),\n );\n } catch {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,\n '[non-serializable]',\n );\n }\n }\n\n if (captureResult && result !== undefined) {\n try {\n ctx.setAttribute('tanstack.loader.result', JSON.stringify(result));\n } catch {\n ctx.setAttribute('tanstack.loader.result', '[non-serializable]');\n }\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n return result;\n });\n }\n\n // Async loader\n return trace(spanName, async (ctx: TraceContext) => {\n ctx.setAttributes({\n [SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'loader',\n [SPAN_ATTRIBUTES.TANSTACK_LOADER_ROUTE_ID]: routeId,\n [SPAN_ATTRIBUTES.TANSTACK_LOADER_TYPE]: 'loader',\n });\n\n if (captureParams && context?.params) {\n try {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,\n JSON.stringify(context.params),\n );\n } catch {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,\n '[non-serializable]',\n );\n }\n }\n\n try {\n const asyncResult = await result;\n\n if (captureResult && asyncResult !== undefined) {\n try {\n ctx.setAttribute(\n 'tanstack.loader.result',\n JSON.stringify(asyncResult),\n );\n } catch {\n ctx.setAttribute('tanstack.loader.result', '[non-serializable]');\n }\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n return asyncResult;\n } catch (error) {\n if ('recordError' in ctx && typeof ctx.recordError === 'function') {\n ctx.recordError(error);\n } else if (\n 'recordException' in ctx &&\n typeof ctx.recordException === 'function'\n ) {\n ctx.recordException(error);\n }\n throw error;\n }\n });\n };\n\n return wrapped as TLoaderFn;\n}\n\n/**\n * Wrap a TanStack route beforeLoad function with OpenTelemetry tracing\n *\n * This function wraps a beforeLoad function to automatically create spans.\n * beforeLoad runs before the route component renders and is typically\n * used for auth checks, redirects, or data prefetching.\n *\n * The generic type TBeforeLoadFn preserves the full TanStack Router type inference,\n * including typed params, context, search, and return types.\n *\n * @param beforeLoadFn - The beforeLoad function to wrap\n * @param config - Configuration options\n * @returns Wrapped beforeLoad function with tracing (preserves original types)\n *\n * @example\n * ```typescript\n * import { createFileRoute, redirect } from '@tanstack/react-router';\n * import { traceBeforeLoad } from 'autotel-tanstack/loaders';\n *\n * export const Route = createFileRoute('/dashboard')({\n * // Types are fully preserved - context, params, search are all typed\n * beforeLoad: traceBeforeLoad(async ({ context, params }) => {\n * if (!context.auth.isAuthenticated) {\n * throw redirect({ to: '/login' });\n * }\n * return { userId: params.userId }; // Return type flows to loader context\n * }),\n * loader: ({ context }) => {\n * // context.userId is typed from beforeLoad return\n * return { user: context.userId };\n * },\n * });\n * ```\n */\nexport function traceBeforeLoad<TBeforeLoadFn extends (opts: any) => any>(\n beforeLoadFn: TBeforeLoadFn,\n config: TraceLoaderConfig = {},\n): TBeforeLoadFn {\n const captureParams = config.captureParams ?? true;\n\n const wrapped = (input: TanStackContextInternal) => {\n // Skip tracing in browser\n if (!isServerSide()) {\n return beforeLoadFn(input);\n }\n\n const routeId = input?.route?.id || 'unknown';\n const spanName = config.name || `tanstack.beforeLoad.${routeId}`;\n\n // Handle both sync and async beforeLoad\n const result = beforeLoadFn(input);\n const isPromise = result instanceof Promise;\n\n if (!isPromise) {\n // Sync beforeLoad\n return trace(spanName, (ctx: TraceContext) => {\n ctx.setAttributes({\n [SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'beforeLoad',\n [SPAN_ATTRIBUTES.TANSTACK_LOADER_ROUTE_ID]: routeId,\n [SPAN_ATTRIBUTES.TANSTACK_LOADER_TYPE]: 'beforeLoad',\n });\n\n if (captureParams && input?.params) {\n try {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,\n JSON.stringify(input.params),\n );\n } catch {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,\n '[non-serializable]',\n );\n }\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n return result;\n });\n }\n\n // Async beforeLoad\n return trace(spanName, async (ctx: TraceContext) => {\n ctx.setAttributes({\n [SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'beforeLoad',\n [SPAN_ATTRIBUTES.TANSTACK_LOADER_ROUTE_ID]: routeId,\n [SPAN_ATTRIBUTES.TANSTACK_LOADER_TYPE]: 'beforeLoad',\n });\n\n if (captureParams && input?.params) {\n try {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,\n JSON.stringify(input.params),\n );\n } catch {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_LOADER_PARAMS,\n '[non-serializable]',\n );\n }\n }\n\n try {\n const asyncResult = await result;\n ctx.setStatus({ code: SpanStatusCode.OK });\n return asyncResult;\n } catch (error) {\n // Check if this is a redirect or notFound (expected control flow)\n const errorName = (error as Error).name;\n if (errorName === 'RedirectError' || errorName === 'NotFoundError') {\n // Mark as OK since these are expected control flow\n ctx.setAttribute('tanstack.beforeLoad.redirect', true);\n ctx.setStatus({ code: SpanStatusCode.OK });\n } else {\n if ('recordError' in ctx && typeof ctx.recordError === 'function') {\n ctx.recordError(error);\n } else if (\n 'recordException' in ctx &&\n typeof ctx.recordException === 'function'\n ) {\n ctx.recordException(error);\n }\n }\n throw error;\n }\n });\n };\n\n return wrapped as TBeforeLoadFn;\n}\n\n/**\n * Create a traced route configuration helper\n *\n * This higher-order function helps create route configurations\n * with automatic tracing for both loader and beforeLoad.\n *\n * @param routeId - The route identifier\n * @param config - Tracing configuration\n * @returns Object with traced loader and beforeLoad wrappers\n *\n * @example\n * ```typescript\n * import { createFileRoute } from '@tanstack/react-router';\n * import { createTracedRoute } from 'autotel-tanstack/loaders';\n *\n * const traced = createTracedRoute('/users/$userId');\n *\n * export const Route = createFileRoute('/users/$userId')({\n * beforeLoad: traced.beforeLoad(async ({ context }) => {\n * // Auth check\n * }),\n * loader: traced.loader(async ({ params }) => {\n * return await getUser(params.userId);\n * }),\n * });\n * ```\n */\nexport function createTracedRoute(\n routeId: string,\n config: Omit<TraceLoaderConfig, 'name'> = {},\n) {\n return {\n /**\n * Wrap a loader function with tracing\n */\n loader<TLoaderFn extends (ctx: any) => any>(\n loaderFn: TLoaderFn,\n ): TLoaderFn {\n return traceLoader(loaderFn, {\n ...config,\n name: `tanstack.loader.${routeId}`,\n });\n },\n\n /**\n * Wrap a beforeLoad function with tracing\n */\n beforeLoad<TBeforeLoadFn extends (opts: any) => any>(\n beforeLoadFn: TBeforeLoadFn,\n ): TBeforeLoadFn {\n return traceBeforeLoad(beforeLoadFn, {\n ...config,\n name: `tanstack.beforeLoad.${routeId}`,\n });\n },\n };\n}\n"]}
|