autotel-tanstack 1.13.30 → 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/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"middleware.js"}
|
|
1
|
+
{"version":3,"file":"middleware.js","names":[],"sources":["../src/middleware.ts"],"sourcesContent":["import { context, SpanStatusCode, type Attributes } from '@opentelemetry/api';\nimport { trace, type TraceContext } from 'autotel';\nimport { extractContextFromRequest } from './context';\nimport { isServerSide } from './env';\nimport { isExcludedPath } from './route-filter';\nimport {\n type TracingMiddlewareConfig,\n DEFAULT_CONFIG,\n SPAN_ATTRIBUTES,\n} from './types';\n\n/**\n * Build span attributes for HTTP requests\n */\nfunction buildRequestAttributes(\n request: Request,\n config: Required<\n Omit<TracingMiddlewareConfig, 'customAttributes' | 'service' | 'type'>\n >,\n): Attributes {\n const url = new URL(request.url);\n const attrs: Attributes = {\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 attrs[SPAN_ATTRIBUTES.URL_QUERY] = url.search;\n }\n\n // Capture configured headers\n if (config.captureHeaders) {\n for (const header of config.captureHeaders) {\n const value = request.headers.get(header);\n if (value) {\n attrs[`http.request.header.${header.toLowerCase()}`] = value;\n }\n }\n }\n\n return attrs;\n}\n\n/**\n * Build span attributes for server functions\n */\nfunction buildServerFnAttributes(\n functionName: string,\n method: string,\n args: unknown,\n config: Required<\n Omit<TracingMiddlewareConfig, 'customAttributes' | 'service' | 'type'>\n >,\n): Attributes {\n const attrs: Attributes = {\n [SPAN_ATTRIBUTES.RPC_SYSTEM]: 'tanstack-start',\n [SPAN_ATTRIBUTES.RPC_METHOD]: functionName,\n [SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'serverFn',\n [SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_NAME]: functionName,\n [SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_METHOD]: method,\n };\n\n if (config.captureArgs && args !== undefined) {\n try {\n attrs[SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_ARGS] = JSON.stringify(args);\n } catch {\n attrs[SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_ARGS] = '[non-serializable]';\n }\n }\n\n return attrs;\n}\n\n/**\n * Generic middleware handler type (compatible with TanStack's middleware pattern)\n *\n * This type represents the shape of TanStack middleware handlers.\n * We use a generic type to avoid direct dependency on TanStack packages.\n */\nexport interface MiddlewareHandler<TContext = unknown> {\n (opts: {\n next: (ctx?: Partial<TContext>) => Promise<TContext>;\n context: TContext;\n request?: Request;\n pathname?: string;\n data?: unknown;\n method?: string;\n filename?: string;\n functionId?: string;\n signal?: AbortSignal;\n }): Promise<TContext>;\n}\n\n/**\n * Create a TanStack-compatible tracing middleware\n *\n * This creates middleware that automatically traces all requests/server functions\n * with OpenTelemetry spans. Use with TanStack Start's middleware system.\n *\n * @param config - Configuration options\n * @returns Middleware handler compatible with TanStack Start\n *\n * @example\n * ```typescript\n * // Global request middleware in app/start.ts\n * import { createStart } from '@tanstack/react-start';\n * import { createTracingMiddleware } from 'autotel-tanstack/middleware';\n *\n * export const startInstance = createStart(() => ({\n * requestMiddleware: [\n * createTracingMiddleware({\n * captureHeaders: ['x-request-id', 'user-agent'],\n * excludePaths: ['/health', '/metrics'],\n * }),\n * ],\n * }));\n * ```\n *\n * @example\n * ```typescript\n * // Server function middleware\n * import { createServerFn } from '@tanstack/react-start';\n * import { createTracingMiddleware } from 'autotel-tanstack/middleware';\n *\n * export const getUser = createServerFn({ method: 'GET' })\n * .middleware([createTracingMiddleware({ type: 'function' })])\n * .handler(async ({ data: id }) => {\n * return await db.users.findUnique({ where: { id } });\n * });\n * ```\n */\nexport function createTracingMiddleware<TContext = unknown>(\n config?: TracingMiddlewareConfig,\n): MiddlewareHandler<TContext> {\n const mergedConfig = {\n ...DEFAULT_CONFIG,\n ...config,\n type: config?.type ?? 'request',\n };\n\n return async function tracingMiddleware(opts) {\n // If we're in the browser, return a no-op middleware\n // This prevents autotel (which uses Node.js APIs) from being bundled/executed in the browser\n if (!isServerSide()) {\n return opts.next();\n }\n const { next, request, pathname, data, functionId } = opts;\n\n // For function middleware\n if (mergedConfig.type === 'function') {\n const fnName = functionId || 'unknown';\n const method = (opts as { method?: string }).method || 'POST';\n\n return trace(`tanstack.serverFn.${fnName}`, async (ctx: TraceContext) => {\n const attrs = buildServerFnAttributes(\n fnName,\n method,\n data,\n mergedConfig,\n );\n ctx.setAttributes(attrs as Record<string, string | number | boolean>);\n\n // Add custom attributes if provided\n if (config?.customAttributes) {\n const customAttrs = config.customAttributes({\n type: 'serverFn',\n name: fnName,\n args: data,\n });\n ctx.setAttributes(\n customAttrs as Record<string, string | number | boolean>,\n );\n }\n\n try {\n const result = await next();\n\n // Capture result if configured\n if (mergedConfig.captureResults && result !== undefined) {\n try {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_RESULT,\n JSON.stringify(result),\n );\n } catch {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_RESULT,\n '[non-serializable]',\n );\n }\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n if (mergedConfig.captureErrors) {\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 // Report error to error store\n try {\n const { reportError } = await import('./error-reporting');\n reportError(error as Error, {\n type: 'serverFn',\n name: fnName,\n method,\n });\n } catch {\n // Error reporting not available, skip\n }\n }\n throw error;\n }\n }) as Promise<TContext>;\n }\n\n // For request middleware\n if (!request) {\n // No request available, just pass through\n return next();\n }\n\n const url = new URL(request.url);\n\n // Check if path should be excluded\n if (isExcludedPath(url.pathname, mergedConfig.excludePaths)) {\n return next();\n }\n\n // Extract parent context from request headers\n const parentContext = extractContextFromRequest(request);\n\n // Run within parent context for distributed tracing\n return context.with(parentContext, async () => {\n const spanName = `${request.method} ${pathname || url.pathname}`;\n\n return trace(spanName, async (ctx: TraceContext) => {\n const attrs = buildRequestAttributes(request, mergedConfig);\n ctx.setAttributes(attrs as Record<string, string | number | boolean>);\n\n // Add custom attributes if provided\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 result = await next();\n\n const duration = Date.now() - startTime;\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_REQUEST_DURATION_MS,\n duration,\n );\n\n // Record timing in metrics collector\n try {\n const { metricsCollector } = await import('./metrics');\n metricsCollector.recordTiming(spanName, duration);\n } catch {\n // Metrics not available, skip\n }\n\n // Try to get response status from result if it's a Response\n if (result && typeof result === 'object' && 'status' in result) {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.HTTP_RESPONSE_STATUS_CODE,\n (result as { status: number }).status,\n );\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n return result;\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 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 // Report error to error store\n try {\n const { reportError } = await import('./error-reporting');\n reportError(error as Error, {\n type: 'request',\n method: request.method,\n pathname: url.pathname,\n });\n } catch {\n // Error reporting not available, skip\n }\n }\n throw error;\n }\n }) as Promise<TContext>;\n });\n };\n}\n\n/**\n * Pre-configured tracing middleware with sensible defaults\n *\n * Convenience export for quick setup. Uses adaptive sampling,\n * captures x-request-id header, and excludes common health check paths.\n *\n * @param config - Optional configuration overrides\n * @returns Middleware handler\n *\n * @example\n * ```typescript\n * import { createStart } from '@tanstack/react-start';\n * import { tracingMiddleware } from 'autotel-tanstack/middleware';\n *\n * export const startInstance = createStart(() => ({\n * requestMiddleware: [tracingMiddleware()],\n * }));\n * ```\n */\nexport function tracingMiddleware<TContext = unknown>(\n config?: TracingMiddlewareConfig,\n): MiddlewareHandler<TContext> {\n return createTracingMiddleware({\n sampling: 'adaptive',\n captureHeaders: ['x-request-id', 'user-agent'],\n excludePaths: ['/health', '/healthz', '/ready', '/metrics', '/_ping'],\n ...config,\n });\n}\n\n/**\n * Create function-specific tracing middleware\n *\n * Convenience wrapper for server function middleware.\n *\n * @param config - Optional configuration\n * @returns Middleware handler for server functions\n *\n * @example\n * ```typescript\n * import { createServerFn } from '@tanstack/react-start';\n * import { functionTracingMiddleware } from 'autotel-tanstack/middleware';\n *\n * export const getUser = createServerFn({ method: 'GET' })\n * .middleware([functionTracingMiddleware()])\n * .handler(async ({ data: id }) => {\n * return await db.users.findUnique({ where: { id } });\n * });\n * ```\n */\nexport function functionTracingMiddleware<TContext = unknown>(\n config?: Omit<TracingMiddlewareConfig, 'type'>,\n): MiddlewareHandler<TContext> {\n return createTracingMiddleware({\n ...config,\n type: 'function',\n });\n}\n\n/**\n * Create a tracing handler for use with TanStack's native createMiddleware()\n *\n * This provides the raw tracing logic that you can pass to createMiddleware().server().\n * Use this when you want full control over the middleware builder pattern.\n *\n * The handler accepts TanStack's middleware signature `{ next, context, request }`\n * and internally adapts it to our more flexible MiddlewareHandler interface.\n *\n * @param config - Configuration options\n * @returns Server handler function compatible with createMiddleware().server()\n *\n * @example\n * ```typescript\n * import { createStart, createMiddleware } from '@tanstack/react-start';\n * import { createTracingServerHandler } from 'autotel-tanstack/middleware';\n *\n * // TanStack-native middleware creation\n * const requestTracingMiddleware = createMiddleware().server(\n * createTracingServerHandler({ captureHeaders: ['x-request-id'] })\n * );\n *\n * export const start = createStart(() => ({\n * requestMiddleware: [requestTracingMiddleware],\n * }));\n * ```\n *\n * @example\n * ```typescript\n * // For server functions - use createMiddleware({ type: 'function' })\n * import { createStart, createMiddleware } from '@tanstack/react-start';\n * import { createTracingServerHandler } from 'autotel-tanstack/middleware';\n *\n * const functionTracingMiddleware = createMiddleware({ type: 'function' }).server(\n * createTracingServerHandler({ type: 'function', captureArgs: true })\n * );\n *\n * export const start = createStart(() => ({\n * functionMiddleware: [functionTracingMiddleware],\n * }));\n * ```\n */\nexport function createTracingServerHandler<TContext = unknown>(\n config?: TracingMiddlewareConfig,\n): (opts: any) => any {\n const handler = createTracingMiddleware<TContext>(config);\n\n // Adapt TanStack's signature to our handler\n return async (opts: any) => {\n return handler(opts);\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { shouldInstrumentPath } from "autotel-edge";
|
|
2
|
+
|
|
3
|
+
//#region src/route-filter.ts
|
|
4
|
+
/**
|
|
5
|
+
* TanStack historically supported:
|
|
6
|
+
* - glob strings (`/api/internal/*`)
|
|
7
|
+
* - regex values
|
|
8
|
+
* - plain-string prefix matching (`/health` matches `/healthz`)
|
|
9
|
+
*
|
|
10
|
+
* This helper keeps those semantics while delegating glob matching to
|
|
11
|
+
* autotel-edge's shared middleware toolkit.
|
|
12
|
+
*/
|
|
13
|
+
function isExcludedPath(pathname, excludePaths) {
|
|
14
|
+
for (const pattern of excludePaths) {
|
|
15
|
+
if (pattern instanceof RegExp) {
|
|
16
|
+
if (pattern.test(pathname)) return true;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
20
|
+
if (!shouldInstrumentPath(pathname, {
|
|
21
|
+
include: void 0,
|
|
22
|
+
exclude: [pattern]
|
|
23
|
+
})) return true;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (pathname === pattern || pathname.startsWith(pattern)) return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { isExcludedPath as t };
|
|
33
|
+
//# sourceMappingURL=route-filter-dLg-j3jR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-filter-dLg-j3jR.js","names":[],"sources":["../src/route-filter.ts"],"sourcesContent":["import { shouldInstrumentPath } from 'autotel-edge';\n\n/**\n * TanStack historically supported:\n * - glob strings (`/api/internal/*`)\n * - regex values\n * - plain-string prefix matching (`/health` matches `/healthz`)\n *\n * This helper keeps those semantics while delegating glob matching to\n * autotel-edge's shared middleware toolkit.\n */\nexport function isExcludedPath(\n pathname: string,\n excludePaths: Array<string | RegExp>,\n): boolean {\n for (const pattern of excludePaths) {\n if (pattern instanceof RegExp) {\n if (pattern.test(pathname)) return true;\n continue;\n }\n\n if (pattern.includes('*') || pattern.includes('?')) {\n if (\n !shouldInstrumentPath(pathname, {\n include: undefined,\n exclude: [pattern],\n })\n ) {\n return true;\n }\n continue;\n }\n\n if (pathname === pattern || pathname.startsWith(pattern)) {\n return true;\n }\n }\n\n return false;\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,eACd,UACA,cACS;CACT,KAAK,MAAM,WAAW,cAAc;EAClC,IAAI,mBAAmB,QAAQ;GAC7B,IAAI,QAAQ,KAAK,QAAQ,GAAG,OAAO;GACnC;EACF;EAEA,IAAI,QAAQ,SAAS,GAAG,KAAK,QAAQ,SAAS,GAAG,GAAG;GAClD,IACE,CAAC,qBAAqB,UAAU;IAC9B,SAAS;IACT,SAAS,CAAC,OAAO;GACnB,CAAC,GAED,OAAO;GAET;EACF;EAEA,IAAI,aAAa,WAAW,SAAS,WAAW,OAAO,GACrD,OAAO;CAEX;CAEA,OAAO;AACT"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import '@opentelemetry/api';
|
|
1
|
+
import { a as TraceServerFnConfig } from "./types-pQgmQa4j.js";
|
|
3
2
|
|
|
3
|
+
//#region src/server-functions.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Wrap a TanStack server function with OpenTelemetry tracing
|
|
6
6
|
*
|
|
@@ -67,5 +67,6 @@ declare function traceServerFn<T extends (...args: any[]) => any>(serverFn: T, c
|
|
|
67
67
|
* ```
|
|
68
68
|
*/
|
|
69
69
|
declare function createTracedServerFnFactory<TCreateServerFn extends (...args: any[]) => any>(createServerFnOriginal: TCreateServerFn, defaultConfig?: Omit<TraceServerFnConfig, 'name'>): TCreateServerFn;
|
|
70
|
-
|
|
70
|
+
//#endregion
|
|
71
71
|
export { createTracedServerFnFactory, traceServerFn };
|
|
72
|
+
//# sourceMappingURL=server-functions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-functions.d.ts","names":[],"sources":["../src/server-functions.ts"],"mappings":";;;;;AA6CA;;;;;;;;;;;;;;;;AAGI;AAwGJ;;;;;;;;;;;;;;;;;;AAKkB;;;iBAhHF,aAAA,eAA4B,IAAA,iBAC1C,QAAA,EAAU,CAAA,EACV,MAAA,GAAQ,mBAAA,GACP,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;iBAwGa,2BAAA,6BACc,IAAA,iBAE5B,sBAAA,EAAwB,eAAA,EACxB,aAAA,GAAe,IAAA,CAAK,mBAAA,YACnB,eAAA"}
|
package/dist/server-functions.js
CHANGED
|
@@ -1,6 +1,134 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
1
|
+
import { n as SPAN_ATTRIBUTES } from "./types-BrccP0yX.js";
|
|
2
|
+
import { r as isServerSide } from "./env-BpFWNnpL.js";
|
|
3
|
+
import { SpanStatusCode } from "@opentelemetry/api";
|
|
4
|
+
import { trace } from "autotel";
|
|
5
|
+
|
|
6
|
+
//#region src/server-functions.ts
|
|
7
|
+
/**
|
|
8
|
+
* Wrap a TanStack server function with OpenTelemetry tracing
|
|
9
|
+
*
|
|
10
|
+
* This function wraps a server function to automatically create spans
|
|
11
|
+
* for each invocation. It captures function name, arguments (optionally),
|
|
12
|
+
* results (optionally), and errors.
|
|
13
|
+
*
|
|
14
|
+
* @param serverFn - The server function to wrap
|
|
15
|
+
* @param config - Configuration options
|
|
16
|
+
* @returns Wrapped server function with tracing
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { createServerFn } from '@tanstack/react-start';
|
|
21
|
+
* import { traceServerFn } from 'autotel-tanstack/server-functions';
|
|
22
|
+
*
|
|
23
|
+
* const getUserBase = createServerFn({ method: 'GET' })
|
|
24
|
+
* .handler(async ({ data: id }) => {
|
|
25
|
+
* return await db.users.findUnique({ where: { id } });
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* export const getUser = traceServerFn(getUserBase, { name: 'getUser' });
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // With argument and result capture (careful with PII!)
|
|
34
|
+
* export const createUser = traceServerFn(
|
|
35
|
+
* createServerFn({ method: 'POST' })
|
|
36
|
+
* .handler(async ({ data }) => {
|
|
37
|
+
* return await db.users.create({ data });
|
|
38
|
+
* }),
|
|
39
|
+
* {
|
|
40
|
+
* name: 'createUser',
|
|
41
|
+
* captureArgs: true,
|
|
42
|
+
* captureResults: false, // Don't capture for PII reasons
|
|
43
|
+
* }
|
|
44
|
+
* );
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function traceServerFn(serverFn, config = {}) {
|
|
48
|
+
const fnName = config.name || serverFn.name || "serverFn";
|
|
49
|
+
const captureArgs = config.captureArgs ?? true;
|
|
50
|
+
const captureResults = config.captureResults ?? false;
|
|
51
|
+
return new Proxy(serverFn, {
|
|
52
|
+
apply(target, thisArg, argArray) {
|
|
53
|
+
if (!isServerSide()) return target.apply(thisArg, argArray);
|
|
54
|
+
return trace(`tanstack.serverFn.${fnName}`, async (ctx) => {
|
|
55
|
+
ctx.setAttributes({
|
|
56
|
+
[SPAN_ATTRIBUTES.RPC_SYSTEM]: "tanstack-start",
|
|
57
|
+
[SPAN_ATTRIBUTES.RPC_METHOD]: fnName,
|
|
58
|
+
[SPAN_ATTRIBUTES.TANSTACK_TYPE]: "serverFn",
|
|
59
|
+
[SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_NAME]: fnName
|
|
60
|
+
});
|
|
61
|
+
if (captureArgs && argArray.length > 0) {
|
|
62
|
+
const args = argArray[0];
|
|
63
|
+
if (args !== void 0) try {
|
|
64
|
+
ctx.setAttribute(SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_ARGS, JSON.stringify(args));
|
|
65
|
+
} catch {
|
|
66
|
+
ctx.setAttribute(SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_ARGS, "[non-serializable]");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const result = await Reflect.apply(target, thisArg, argArray);
|
|
71
|
+
if (captureResults && result !== void 0) try {
|
|
72
|
+
ctx.setAttribute(SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_RESULT, JSON.stringify(result));
|
|
73
|
+
} catch {
|
|
74
|
+
ctx.setAttribute(SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_RESULT, "[non-serializable]");
|
|
75
|
+
}
|
|
76
|
+
ctx.setStatus({ code: SpanStatusCode.OK });
|
|
77
|
+
return result;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if ("recordError" in ctx && typeof ctx.recordError === "function") ctx.recordError(error);
|
|
80
|
+
else if ("recordException" in ctx && typeof ctx.recordException === "function") ctx.recordException(error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
get(target, prop, receiver) {
|
|
86
|
+
return Reflect.get(target, prop, receiver);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Create a traced version of createServerFn
|
|
92
|
+
*
|
|
93
|
+
* This higher-order function wraps TanStack's createServerFn to automatically
|
|
94
|
+
* add tracing to all created server functions.
|
|
95
|
+
*
|
|
96
|
+
* @param createServerFnOriginal - The original createServerFn from TanStack
|
|
97
|
+
* @param defaultConfig - Default configuration for all server functions
|
|
98
|
+
* @returns Wrapped createServerFn that produces traced server functions
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* import { createServerFn as originalCreateServerFn } from '@tanstack/react-start';
|
|
103
|
+
* import { createTracedServerFnFactory } from 'autotel-tanstack/server-functions';
|
|
104
|
+
*
|
|
105
|
+
* export const createServerFn = createTracedServerFnFactory(originalCreateServerFn);
|
|
106
|
+
*
|
|
107
|
+
* // Now all server functions created with createServerFn are automatically traced
|
|
108
|
+
* export const getUser = createServerFn({ method: 'GET' })
|
|
109
|
+
* .handler(async ({ data: id }) => {
|
|
110
|
+
* return await db.users.findUnique({ where: { id } });
|
|
111
|
+
* });
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
function createTracedServerFnFactory(createServerFnOriginal, defaultConfig = {}) {
|
|
115
|
+
return new Proxy(createServerFnOriginal, { apply(target, thisArg, argArray) {
|
|
116
|
+
const result = Reflect.apply(target, thisArg, argArray);
|
|
117
|
+
if (result && typeof result === "object" && "handler" in result && typeof result.handler === "function") {
|
|
118
|
+
const originalHandler = result.handler.bind(result);
|
|
119
|
+
result.handler = function tracedHandler(handlerFn) {
|
|
120
|
+
const wrappedHandler = originalHandler(handlerFn);
|
|
121
|
+
const fnName = handlerFn?.name || "serverFn";
|
|
122
|
+
return traceServerFn(wrappedHandler, {
|
|
123
|
+
...defaultConfig,
|
|
124
|
+
name: fnName
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
} });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
export { createTracedServerFnFactory, traceServerFn };
|
|
6
134
|
//# sourceMappingURL=server-functions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"server-functions.js","names":[],"sources":["../src/server-functions.ts"],"sourcesContent":["import { SpanStatusCode } from '@opentelemetry/api';\nimport { trace, type TraceContext } from 'autotel';\nimport { isServerSide } from './env';\nimport { type TraceServerFnConfig, SPAN_ATTRIBUTES } from './types';\n\n/**\n * Wrap a TanStack server function with OpenTelemetry tracing\n *\n * This function wraps a server function to automatically create spans\n * for each invocation. It captures function name, arguments (optionally),\n * results (optionally), and errors.\n *\n * @param serverFn - The server function to wrap\n * @param config - Configuration options\n * @returns Wrapped server function with tracing\n *\n * @example\n * ```typescript\n * import { createServerFn } from '@tanstack/react-start';\n * import { traceServerFn } from 'autotel-tanstack/server-functions';\n *\n * const getUserBase = createServerFn({ method: 'GET' })\n * .handler(async ({ data: id }) => {\n * return await db.users.findUnique({ where: { id } });\n * });\n *\n * export const getUser = traceServerFn(getUserBase, { name: 'getUser' });\n * ```\n *\n * @example\n * ```typescript\n * // With argument and result capture (careful with PII!)\n * export const createUser = traceServerFn(\n * createServerFn({ method: 'POST' })\n * .handler(async ({ data }) => {\n * return await db.users.create({ data });\n * }),\n * {\n * name: 'createUser',\n * captureArgs: true,\n * captureResults: false, // Don't capture for PII reasons\n * }\n * );\n * ```\n */\nexport function traceServerFn<T extends (...args: any[]) => any>(\n serverFn: T,\n config: TraceServerFnConfig = {},\n): T {\n const fnName = config.name || serverFn.name || 'serverFn';\n const captureArgs = config.captureArgs ?? true;\n const captureResults = config.captureResults ?? false;\n\n return new Proxy(serverFn, {\n apply(target, thisArg, argArray) {\n // If we're in the browser, just call the function without tracing\n // Server functions should never run in the browser, but this prevents\n // autotel (which uses Node.js APIs) from being executed if it somehow does\n if (!isServerSide()) {\n return target.apply(thisArg, argArray);\n }\n\n return trace(`tanstack.serverFn.${fnName}`, async (ctx: TraceContext) => {\n ctx.setAttributes({\n [SPAN_ATTRIBUTES.RPC_SYSTEM]: 'tanstack-start',\n [SPAN_ATTRIBUTES.RPC_METHOD]: fnName,\n [SPAN_ATTRIBUTES.TANSTACK_TYPE]: 'serverFn',\n [SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_NAME]: fnName,\n });\n\n // Capture arguments if configured\n if (captureArgs && argArray.length > 0) {\n const args = argArray[0];\n if (args !== undefined) {\n try {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_ARGS,\n JSON.stringify(args),\n );\n } catch {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_ARGS,\n '[non-serializable]',\n );\n }\n }\n }\n\n try {\n const result = await Reflect.apply(target, thisArg, argArray);\n\n // Capture result if configured\n if (captureResults && result !== undefined) {\n try {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_RESULT,\n JSON.stringify(result),\n );\n } catch {\n ctx.setAttribute(\n SPAN_ATTRIBUTES.TANSTACK_SERVER_FN_RESULT,\n '[non-serializable]',\n );\n }\n }\n\n ctx.setStatus({ code: SpanStatusCode.OK });\n return result;\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 get(target, prop, receiver) {\n return Reflect.get(target, prop, receiver);\n },\n }) as T;\n}\n\n/**\n * Create a traced version of createServerFn\n *\n * This higher-order function wraps TanStack's createServerFn to automatically\n * add tracing to all created server functions.\n *\n * @param createServerFnOriginal - The original createServerFn from TanStack\n * @param defaultConfig - Default configuration for all server functions\n * @returns Wrapped createServerFn that produces traced server functions\n *\n * @example\n * ```typescript\n * import { createServerFn as originalCreateServerFn } from '@tanstack/react-start';\n * import { createTracedServerFnFactory } from 'autotel-tanstack/server-functions';\n *\n * export const createServerFn = createTracedServerFnFactory(originalCreateServerFn);\n *\n * // Now all server functions created with createServerFn are automatically traced\n * export const getUser = createServerFn({ method: 'GET' })\n * .handler(async ({ data: id }) => {\n * return await db.users.findUnique({ where: { id } });\n * });\n * ```\n */\nexport function createTracedServerFnFactory<\n TCreateServerFn extends (...args: any[]) => any,\n>(\n createServerFnOriginal: TCreateServerFn,\n defaultConfig: Omit<TraceServerFnConfig, 'name'> = {},\n): TCreateServerFn {\n return new Proxy(createServerFnOriginal, {\n apply(target, thisArg, argArray) {\n const result = Reflect.apply(target, thisArg, argArray);\n\n // If the result has a .handler method, wrap it\n if (\n result &&\n typeof result === 'object' &&\n 'handler' in result &&\n typeof result.handler === 'function'\n ) {\n const originalHandler = result.handler.bind(result);\n\n result.handler = function tracedHandler(handlerFn: unknown) {\n const wrappedHandler = originalHandler(handlerFn as never);\n\n // Try to infer function name from the handler\n const fnName = (handlerFn as { name?: string })?.name || 'serverFn';\n\n return traceServerFn(wrappedHandler, {\n ...defaultConfig,\n name: fnName,\n });\n };\n }\n\n return result;\n },\n }) as TCreateServerFn;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,SAAgB,cACd,UACA,SAA8B,CAAC,GAC5B;CACH,MAAM,SAAS,OAAO,QAAQ,SAAS,QAAQ;CAC/C,MAAM,cAAc,OAAO,eAAe;CAC1C,MAAM,iBAAiB,OAAO,kBAAkB;CAEhD,OAAO,IAAI,MAAM,UAAU;EACzB,MAAM,QAAQ,SAAS,UAAU;GAI/B,IAAI,CAAC,aAAa,GAChB,OAAO,OAAO,MAAM,SAAS,QAAQ;GAGvC,OAAO,MAAM,qBAAqB,UAAU,OAAO,QAAsB;IACvE,IAAI,cAAc;MACf,gBAAgB,aAAa;MAC7B,gBAAgB,aAAa;MAC7B,gBAAgB,gBAAgB;MAChC,gBAAgB,0BAA0B;IAC7C,CAAC;IAGD,IAAI,eAAe,SAAS,SAAS,GAAG;KACtC,MAAM,OAAO,SAAS;KACtB,IAAI,SAAS,QACX,IAAI;MACF,IAAI,aACF,gBAAgB,yBAChB,KAAK,UAAU,IAAI,CACrB;KACF,QAAQ;MACN,IAAI,aACF,gBAAgB,yBAChB,oBACF;KACF;IAEJ;IAEA,IAAI;KACF,MAAM,SAAS,MAAM,QAAQ,MAAM,QAAQ,SAAS,QAAQ;KAG5D,IAAI,kBAAkB,WAAW,QAC/B,IAAI;MACF,IAAI,aACF,gBAAgB,2BAChB,KAAK,UAAU,MAAM,CACvB;KACF,QAAQ;MACN,IAAI,aACF,gBAAgB,2BAChB,oBACF;KACF;KAGF,IAAI,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;KACzC,OAAO;IACT,SAAS,OAAO;KACd,IAAI,iBAAiB,OAAO,OAAO,IAAI,gBAAgB,YACrD,IAAI,YAAY,KAAK;UAChB,IACL,qBAAqB,OACrB,OAAO,IAAI,oBAAoB,YAE/B,IAAI,gBAAgB,KAAK;KAE3B,MAAM;IACR;GACF,CAAC;EACH;EAEA,IAAI,QAAQ,MAAM,UAAU;GAC1B,OAAO,QAAQ,IAAI,QAAQ,MAAM,QAAQ;EAC3C;CACF,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,4BAGd,wBACA,gBAAmD,CAAC,GACnC;CACjB,OAAO,IAAI,MAAM,wBAAwB,EACvC,MAAM,QAAQ,SAAS,UAAU;EAC/B,MAAM,SAAS,QAAQ,MAAM,QAAQ,SAAS,QAAQ;EAGtD,IACE,UACA,OAAO,WAAW,YAClB,aAAa,UACb,OAAO,OAAO,YAAY,YAC1B;GACA,MAAM,kBAAkB,OAAO,QAAQ,KAAK,MAAM;GAElD,OAAO,UAAU,SAAS,cAAc,WAAoB;IAC1D,MAAM,iBAAiB,gBAAgB,SAAkB;IAGzD,MAAM,SAAU,WAAiC,QAAQ;IAEzD,OAAO,cAAc,gBAAgB;KACnC,GAAG;KACH,MAAM;IACR,CAAC;GACH;EACF;EAEA,OAAO;CACT,EACF,CAAC;AACH"}
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,5 +1,103 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AttributeValue, Attributes, Context, HrTime, Link, SpanContext, SpanKind, SpanStatus } from "@opentelemetry/api";
|
|
2
2
|
|
|
3
|
+
//#region ../../node_modules/.pnpm/@opentelemetry+resources@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/resources/build/src/types.d.ts
|
|
4
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
5
|
+
type RawResourceAttribute = [string, MaybePromise<AttributeValue | undefined>];
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region ../../node_modules/.pnpm/@opentelemetry+resources@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/resources/build/src/Resource.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* An interface that represents a resource. A Resource describes the entity for which signals (metrics or trace) are
|
|
10
|
+
* collected.
|
|
11
|
+
*
|
|
12
|
+
* This interface is NOT user-implementable. Valid ways to obtain a {@link Resource} are by using either of these functions
|
|
13
|
+
* - {@link resourceFromAttributes}
|
|
14
|
+
* - {@link emptyResource}
|
|
15
|
+
* - {@link defaultResource}
|
|
16
|
+
* - {@link detectResources}
|
|
17
|
+
*/
|
|
18
|
+
interface Resource {
|
|
19
|
+
/**
|
|
20
|
+
* Check if async attributes have resolved. This is useful to avoid awaiting
|
|
21
|
+
* waitForAsyncAttributes (which will introduce asynchronous behavior) when not necessary.
|
|
22
|
+
*
|
|
23
|
+
* @returns true if the resource "attributes" property is not yet settled to its final value
|
|
24
|
+
*/
|
|
25
|
+
readonly asyncAttributesPending?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* @returns the Resource's attributes.
|
|
28
|
+
*/
|
|
29
|
+
readonly attributes: Attributes;
|
|
30
|
+
/**
|
|
31
|
+
* @returns the Resource's schema URL or undefined if not set.
|
|
32
|
+
*/
|
|
33
|
+
readonly schemaUrl?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Returns a promise that will never be rejected. Resolves when all async attributes have finished being added to
|
|
36
|
+
* this Resource's attributes. This is useful in exporters to block until resource detection
|
|
37
|
+
* has finished.
|
|
38
|
+
*/
|
|
39
|
+
waitForAsyncAttributes?(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Returns a new, merged {@link Resource} by merging the current Resource
|
|
42
|
+
* with the other Resource. In case of a collision, other Resource takes
|
|
43
|
+
* precedence.
|
|
44
|
+
*
|
|
45
|
+
* @param other the Resource that will be merged with this.
|
|
46
|
+
* @returns the newly merged Resource.
|
|
47
|
+
*/
|
|
48
|
+
merge(other: Resource | null): Resource;
|
|
49
|
+
getRawAttributes(): RawResourceAttribute[];
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region ../../node_modules/.pnpm/@opentelemetry+core@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/core/build/src/common/types.d.ts
|
|
53
|
+
/**
|
|
54
|
+
* An instrumentation scope consists of the name and optional version
|
|
55
|
+
* used to obtain a tracer or meter from a provider. This metadata is made
|
|
56
|
+
* available on ReadableSpan and MetricRecord for use by the export pipeline.
|
|
57
|
+
*/
|
|
58
|
+
interface InstrumentationScope {
|
|
59
|
+
readonly name: string;
|
|
60
|
+
readonly version?: string;
|
|
61
|
+
readonly schemaUrl?: string;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region ../../node_modules/.pnpm/@opentelemetry+sdk-trace-base@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/TimedEvent.d.ts
|
|
65
|
+
/**
|
|
66
|
+
* Represents a timed event.
|
|
67
|
+
* A timed event is an event with a timestamp.
|
|
68
|
+
*/
|
|
69
|
+
interface TimedEvent {
|
|
70
|
+
time: HrTime;
|
|
71
|
+
/** The name of the event. */
|
|
72
|
+
name: string;
|
|
73
|
+
/** The attributes of the event. */
|
|
74
|
+
attributes?: Attributes;
|
|
75
|
+
/** Count of attributes of the event that were dropped due to collection limits */
|
|
76
|
+
droppedAttributesCount?: number;
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region ../../node_modules/.pnpm/@opentelemetry+sdk-trace-base@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/ReadableSpan.d.ts
|
|
80
|
+
interface ReadableSpan {
|
|
81
|
+
readonly name: string;
|
|
82
|
+
readonly kind: SpanKind;
|
|
83
|
+
readonly spanContext: () => SpanContext;
|
|
84
|
+
readonly parentSpanContext?: SpanContext;
|
|
85
|
+
readonly startTime: HrTime;
|
|
86
|
+
readonly endTime: HrTime;
|
|
87
|
+
readonly status: SpanStatus;
|
|
88
|
+
readonly attributes: Attributes;
|
|
89
|
+
readonly links: Link[];
|
|
90
|
+
readonly events: TimedEvent[];
|
|
91
|
+
readonly duration: HrTime;
|
|
92
|
+
readonly ended: boolean;
|
|
93
|
+
readonly resource: Resource;
|
|
94
|
+
readonly instrumentationScope: InstrumentationScope;
|
|
95
|
+
readonly droppedAttributesCount: number;
|
|
96
|
+
readonly droppedEventsCount: number;
|
|
97
|
+
readonly droppedLinksCount: number;
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/testing.d.ts
|
|
3
101
|
/**
|
|
4
102
|
* Test harness for TanStack instrumentation testing
|
|
5
103
|
*
|
|
@@ -7,53 +105,53 @@ import { ReadableSpan } from '@opentelemetry/sdk-trace-base';
|
|
|
7
105
|
* with autotel-tanstack instrumentation.
|
|
8
106
|
*/
|
|
9
107
|
interface TestHarness {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
reset(): void;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Get all finished spans
|
|
19
|
-
*/
|
|
20
|
-
getSpans(): ReadableSpan[];
|
|
21
|
-
/**
|
|
22
|
-
* Get spans by name (exact match or regex)
|
|
23
|
-
*/
|
|
24
|
-
getSpansByName(name: string | RegExp): ReadableSpan[];
|
|
25
|
-
/**
|
|
26
|
-
* Get spans by TanStack type
|
|
27
|
-
*/
|
|
28
|
-
getSpansByType(type: 'request' | 'serverFn' | 'loader' | 'beforeLoad'): ReadableSpan[];
|
|
29
|
-
/**
|
|
30
|
-
* Reset collected spans
|
|
31
|
-
*/
|
|
108
|
+
/**
|
|
109
|
+
* The in-memory span exporter
|
|
110
|
+
*/
|
|
111
|
+
exporter: {
|
|
112
|
+
getFinishedSpans(): ReadableSpan[];
|
|
32
113
|
reset(): void;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Get all finished spans
|
|
117
|
+
*/
|
|
118
|
+
getSpans(): ReadableSpan[];
|
|
119
|
+
/**
|
|
120
|
+
* Get spans by name (exact match or regex)
|
|
121
|
+
*/
|
|
122
|
+
getSpansByName(name: string | RegExp): ReadableSpan[];
|
|
123
|
+
/**
|
|
124
|
+
* Get spans by TanStack type
|
|
125
|
+
*/
|
|
126
|
+
getSpansByType(type: 'request' | 'serverFn' | 'loader' | 'beforeLoad'): ReadableSpan[];
|
|
127
|
+
/**
|
|
128
|
+
* Reset collected spans
|
|
129
|
+
*/
|
|
130
|
+
reset(): void;
|
|
131
|
+
/**
|
|
132
|
+
* Assert a span exists
|
|
133
|
+
*/
|
|
134
|
+
assertSpanExists(name: string | RegExp): void;
|
|
135
|
+
/**
|
|
136
|
+
* Assert a span has a specific attribute
|
|
137
|
+
*/
|
|
138
|
+
assertSpanHasAttribute(name: string | RegExp, attr: string, value?: unknown): void;
|
|
139
|
+
/**
|
|
140
|
+
* Assert a server function was traced
|
|
141
|
+
*/
|
|
142
|
+
assertServerFnTraced(name: string): void;
|
|
143
|
+
/**
|
|
144
|
+
* Assert a loader was traced
|
|
145
|
+
*/
|
|
146
|
+
assertLoaderTraced(routeId: string): void;
|
|
147
|
+
/**
|
|
148
|
+
* Assert a beforeLoad was traced
|
|
149
|
+
*/
|
|
150
|
+
assertBeforeLoadTraced(routeId: string): void;
|
|
151
|
+
/**
|
|
152
|
+
* Assert an HTTP request was traced
|
|
153
|
+
*/
|
|
154
|
+
assertRequestTraced(method: string, path: string): void;
|
|
57
155
|
}
|
|
58
156
|
/**
|
|
59
157
|
* Create a test harness for TanStack instrumentation testing
|
|
@@ -106,9 +204,9 @@ declare function createTestHarness(): TestHarness;
|
|
|
106
204
|
* ```
|
|
107
205
|
*/
|
|
108
206
|
declare function createMockRequest(method: string, path: string, options?: {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
207
|
+
headers?: Record<string, string>;
|
|
208
|
+
body?: string;
|
|
209
|
+
traceparent?: string;
|
|
112
210
|
}): Request;
|
|
113
211
|
/**
|
|
114
212
|
* Generate a valid W3C traceparent header for testing
|
|
@@ -132,23 +230,23 @@ declare function generateTraceparent(traceId?: string, spanId?: string): string;
|
|
|
132
230
|
* `Record<string, unknown>` in TypeScript 6+ strict mode.
|
|
133
231
|
*/
|
|
134
232
|
type SerializedSpan = {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
233
|
+
name: string;
|
|
234
|
+
spanId: string;
|
|
235
|
+
traceId: string;
|
|
236
|
+
parentSpanId?: string;
|
|
237
|
+
attributes?: Record<string, unknown>;
|
|
238
|
+
status: {
|
|
239
|
+
code: number;
|
|
240
|
+
message?: string;
|
|
241
|
+
};
|
|
242
|
+
durationMs: number;
|
|
145
243
|
};
|
|
146
244
|
/**
|
|
147
245
|
* Accepts either a raw `Request` (legacy) or a TanStack Router context
|
|
148
246
|
* object containing `{ request: Request }` (Router 1.168+).
|
|
149
247
|
*/
|
|
150
248
|
type HandlerInput = Request | {
|
|
151
|
-
|
|
249
|
+
request: Request;
|
|
152
250
|
};
|
|
153
251
|
type CreateFileRoute = (path: string) => (options: any) => any;
|
|
154
252
|
/**
|
|
@@ -192,8 +290,9 @@ type CreateFileRoute = (path: string) => (options: any) => any;
|
|
|
192
290
|
*/
|
|
193
291
|
declare function createTestSpansRoute(createFileRoute: CreateFileRoute, path?: string): any;
|
|
194
292
|
declare function createTestSpansHandlers(): {
|
|
195
|
-
|
|
196
|
-
|
|
293
|
+
GET: (input: HandlerInput) => Response;
|
|
294
|
+
DELETE: (input: HandlerInput) => Response;
|
|
197
295
|
};
|
|
198
|
-
|
|
199
|
-
export {
|
|
296
|
+
//#endregion
|
|
297
|
+
export { SerializedSpan, TestHarness, createMockRequest, createTestHarness, createTestSpansHandlers, createTestSpansRoute, generateTraceparent };
|
|
298
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","names":["detect","ResourceDetectionConfig","config","DetectedResource","attributes","DetectedResourceAttributes","MaybePromise","AttributeValue","Record","DetectedResourceAttributeValue","T","Promise","schemaUrl","asyncAttributesPending","attributes","Attributes","schemaUrl","waitForAsyncAttributes","Promise","merge","Resource","other","getRawAttributes","RawResourceAttribute","Function","__wrapped","__unwrap","__original","name","version","schemaUrl","Exception","ex","time","HrTime","name","attributes","Attributes","droppedAttributesCount","name","kind","SpanKind","spanContext","SpanContext","parentSpanContext","startTime","HrTime","endTime","status","SpanStatus","attributes","Attributes","links","Link","events","TimedEvent","duration","ended","resource","Resource","instrumentationScope","InstrumentationScope","droppedAttributesCount","droppedEventsCount","droppedLinksCount"],"sources":["../../../node_modules/.pnpm/@opentelemetry+resources@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/resources/build/src/types.d.ts","../../../node_modules/.pnpm/@opentelemetry+resources@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/resources/build/src/Resource.d.ts","../../../node_modules/.pnpm/@opentelemetry+core@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/core/build/src/common/types.d.ts","../../../node_modules/.pnpm/@opentelemetry+sdk-trace-base@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/TimedEvent.d.ts","../../../node_modules/.pnpm/@opentelemetry+sdk-trace-base@2.7.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/ReadableSpan.d.ts","../src/testing.ts"],"x_google_ignoreList":[0,1,2,3,4],"mappings":";;;KA+BY,YAAA,MAAkB,CAAA,GAAI,OAAA,CAAQ,CAAA;AAAA,KAC9B,oBAAA,YAER,YAAY,CAAC,cAAA;;;;AAHjB;;;;;;;;;UCnBiB,QAAA;EDmBiBW;;;AAAS;AAC3C;;EADkCA,SCZrBE,sBAAAA;EDeTP;AAA2B;;EAA3BA,SCXSQ,UAAAA,EAAY,UAAA;;AAXzB;;WAeaE,SAAAA;EAJY;;;;;EAUrBC,sBAAAA,KAA2B,OAAA;EAUa;;;;;;;;EADxCE,KAAAA,CAAME,KAAAA,EAAO,QAAA,UAAkB,QAAA;EAC/BC,gBAAAA,IAAoB,oBAAA;AAAA;;;;;;;;UC5BP,oBAAA;EAAA,SACJM,IAAAA;EAAAA,SACAC,OAAAA;EAAAA,SACAC,SAAAA;AAAAA;;;;;AFab;;UG1BiB,UAAA;EACbG,IAAAA,EAAM,MAAA;EHyBgC;EGvBtCE,IAAAA;EHuBqC;EGrBrCC,UAAAA,GAAa,UAAU;EHqBF1B;EGnBrB4B,sBAAAA;AAAAA;;;UCRa,YAAA;EAAA,SACJC,IAAAA;EAAAA,SACAC,IAAAA,EAAM,QAAA;EAAA,SACNE,WAAAA,QAAmB,WAAA;EAAA,SACnBE,iBAAAA,GAAoB,WAAA;EAAA,SACpBC,SAAAA,EAAW,MAAA;EAAA,SACXE,OAAAA,EAAS,MAAA;EAAA,SACTC,MAAAA,EAAQ,UAAA;EAAA,SACRE,UAAAA,EAAY,UAAA;EAAA,SACZE,KAAAA,EAAO,IAAA;EAAA,SACPE,MAAAA,EAAQ,UAAA;EAAA,SACRE,QAAAA,EAAU,MAAA;EAAA,SACVC,KAAAA;EAAAA,SACAC,QAAAA,EAAU,QAAA;EAAA,SACVE,oBAAAA,EAAsB,oBAAA;EAAA,SACtBE,sBAAAA;EAAAA,SACAC,kBAAAA;EAAAA,SACAC,iBAAAA;AAAAA;;;;;AJUb;;;;UKpBiB,WAAA;ELoBiB;;;EKhBhC,QAAA;IACE,gBAAA,IAAoB,YAAA;IACpB,KAAA;EAAA;ELcuC;AAAA;AAC3C;EKTE,QAAA,IAAY,YAAA;;;ALWiB;EKN7B,cAAA,CAAe,IAAA,WAAe,MAAA,GAAS,YAAA;;;AJhBzC;EIqBE,cAAA,CACE,IAAA,qDACC,YAAA;;;;EAKH,KAAA;EJEiC;;;EIGjC,gBAAA,CAAiB,IAAA,WAAe,MAAA;EJ1BrBnD;;;EI+BX,sBAAA,CACE,IAAA,WAAe,MAAA,EACf,IAAA,UACA,KAAA;EJpBAI;;;EI0BF,oBAAA,CAAqB,IAAA;EJjBbI;;;EIsBR,kBAAA,CAAmB,OAAA;EJrBuB;AAAA;;EI0B1C,sBAAA,CAAuB,OAAA;;AHtDzB;;EG2DE,mBAAA,CAAoB,MAAA,UAAgB,IAAA;AAAA;;;;;AHxDhB;;;;ACbtB;;;;;;;;;;;AAO0B;;;;ACR1B;;;;;;;;;;;;;;iBC8GgB,iBAAA,IAAqB,WAAW;;;;;;;;;;;;;iBA8GhC,iBAAA,CACd,MAAA,UACA,IAAA,UACA,OAAA;EACE,OAAA,GAAU,MAAA;EACV,IAAA;EACA,WAAA;AAAA,IAED,OAAO;;;;;;;;;;;;;;iBA2BM,mBAAA,CAAoB,OAAA,WAAkB,MAAe;;AD9OvC;;;;ACV9B;;KAiRY,cAAA;EACV,IAAA;EACA,MAAA;EACA,OAAA;EACA,YAAA;EACA,UAAA,GAAa,MAAM;EACnB,MAAA;IAAU,IAAA;IAAc,OAAA;EAAA;EACxB,UAAA;AAAA;;;;;KA6CG,YAAA,GAAe,OAAA;EAAY,OAAA,EAAS,OAAO;AAAA;AAAA,KAG3C,eAAA,IAAmB,IAAA,cAAkB,OAAY;;;;;;;;;;;;;;;;;;;;;;;AAzQJ;AAwClD;;;;AAAgD;AA8GhD;;;;;;;;;;;iBA4JgB,oBAAA,CACd,eAAA,EAAiB,eAAe,EAChC,IAAA;AAAA,iBAUc,uBAAA;EACd,GAAA,GAAM,KAAA,EAAO,YAAA,KAAiB,QAAA;EAC9B,MAAA,GAAS,KAAA,EAAO,YAAA,KAAiB,QAAA;AAAA"}
|