autotel-tanstack 1.4.0 → 1.4.1

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/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # autotel-tanstack
2
2
 
3
- OpenTelemetry instrumentation for TanStack Start applications. Automatic tracing for server functions, middleware, and route loaders.
3
+ OpenTelemetry instrumentation for TanStack Start applications. Automatic tracing for server functions, middleware, and route loaders using TanStack's native patterns.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Zero-Config Option** - Just import `autotel-tanstack/auto` and you're done
8
- - **Framework-Aligned API** - Uses TanStack's middleware patterns
7
+ - **TanStack-Native** - Uses `createMiddleware().server()` builder pattern
8
+ - **Zero Boilerplate** - Global middleware traces all server functions automatically
9
9
  - **Full Coverage** - Server functions, loaders, beforeLoad, HTTP requests
10
10
  - **Tree-Shakeable** - Only bundle what you use
11
11
  - **Type-Safe** - Full TypeScript support
@@ -17,91 +17,120 @@ OpenTelemetry instrumentation for TanStack Start applications. Automatic tracing
17
17
  npm install autotel-tanstack autotel
18
18
  # or
19
19
  pnpm add autotel-tanstack autotel
20
- # or
21
- yarn add autotel-tanstack autotel
22
20
  ```
23
21
 
24
22
  ## Quick Start
25
23
 
26
- ### Option 1: Zero-Config (Recommended)
24
+ ### TanStack-Native Setup (Recommended)
25
+
26
+ Configure global middleware in `start.ts` using TanStack's native patterns:
27
27
 
28
28
  ```typescript
29
- // app/start.ts (React) or app/start.ts (Solid)
30
- import 'autotel-tanstack/auto';
31
- import { createStart } from '@tanstack/react-start';
29
+ // src/start.ts
30
+ import { createStart, createMiddleware } from '@tanstack/react-start';
31
+ import { createTracingServerHandler } from 'autotel-tanstack/middleware';
32
+ import './instrumentation'; // Initialize autotel
33
+
34
+ // Global request tracing middleware
35
+ const requestTracingMiddleware = createMiddleware().server(
36
+ createTracingServerHandler({
37
+ captureHeaders: ['x-request-id', 'user-agent'],
38
+ excludePaths: ['/health', '/metrics'],
39
+ }),
40
+ );
32
41
 
33
- // Set env vars: OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT
34
- export const startInstance = createStart(() => ({}));
35
- ```
42
+ // Global server function tracing middleware
43
+ const functionTracingMiddleware = createMiddleware({ type: 'function' }).server(
44
+ createTracingServerHandler({
45
+ type: 'function',
46
+ captureArgs: true,
47
+ }),
48
+ );
36
49
 
37
- ### Option 2: Middleware-Based
50
+ export const startInstance = createStart(() => ({
51
+ requestMiddleware: [requestTracingMiddleware],
52
+ functionMiddleware: [functionTracingMiddleware],
53
+ }));
54
+ ```
38
55
 
39
56
  ```typescript
40
- // app/start.ts
41
- import { createStart } from '@tanstack/react-start';
42
- import { tracingMiddleware } from 'autotel-tanstack/middleware';
57
+ // src/instrumentation.ts
43
58
  import { init } from 'autotel';
44
59
 
45
- // Initialize autotel
46
60
  init({
47
61
  service: 'my-app',
48
- endpoint: 'https://api.honeycomb.io',
49
- headers: { 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY },
62
+ endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
50
63
  });
51
-
52
- export const startInstance = createStart(() => ({
53
- requestMiddleware: [tracingMiddleware()],
54
- }));
55
64
  ```
56
65
 
57
- ### Option 3: Handler Wrapper (Full Control)
66
+ That's it! All server functions and requests are now automatically traced.
67
+
68
+ ### Zero-Config Alternative
69
+
70
+ For quick setup using environment variables:
58
71
 
59
72
  ```typescript
60
- // server.ts
61
- import {
62
- createStartHandler,
63
- defaultStreamHandler,
64
- } from '@tanstack/react-start/server';
65
- import { wrapStartHandler } from 'autotel-tanstack/handlers';
73
+ // src/start.ts
74
+ import 'autotel-tanstack/auto';
75
+ import { createStart } from '@tanstack/react-start';
66
76
 
67
- export default wrapStartHandler({
68
- service: 'my-app',
69
- endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
70
- headers: { 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY },
71
- })(createStartHandler(defaultStreamHandler));
77
+ // Set env vars: OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT
78
+ export const startInstance = createStart(() => ({}));
72
79
  ```
73
80
 
74
81
  ## Usage
75
82
 
76
- ### Tracing Server Functions
83
+ ### Server Functions (Auto-Traced)
84
+
85
+ With global `functionMiddleware` configured in `start.ts`, server functions are automatically traced:
77
86
 
78
87
  ```typescript
79
88
  import { createServerFn } from '@tanstack/react-start';
80
- import { functionTracingMiddleware } from 'autotel-tanstack/middleware';
81
89
 
82
- // Using middleware (recommended)
83
- export const getUser = createServerFn({ method: 'GET' })
84
- .middleware([functionTracingMiddleware()])
85
- .handler(async ({ data: id }) => {
90
+ // Automatically traced - no middleware needed per-function!
91
+ export const getUser = createServerFn({ method: 'GET' }).handler(
92
+ async ({ data: id }) => {
86
93
  return await db.users.findUnique({ where: { id } });
94
+ },
95
+ );
96
+
97
+ export const createUser = createServerFn({ method: 'POST' })
98
+ .inputValidator((d: UserInput) => d)
99
+ .handler(async ({ data }) => {
100
+ return await db.users.create({ data });
87
101
  });
102
+ ```
88
103
 
89
- // Or using explicit wrapper
90
- import { traceServerFn } from 'autotel-tanstack/server-functions';
104
+ ### Per-Function Middleware (When Needed)
91
105
 
92
- const getUserBase = createServerFn({ method: 'GET' }).handler(
93
- async ({ data: id }) => {
94
- return await db.users.findUnique({ where: { id } });
95
- },
106
+ For function-specific middleware, use TanStack's `.middleware()` chaining:
107
+
108
+ ```typescript
109
+ import { createServerFn, createMiddleware } from '@tanstack/react-start';
110
+ import { createTracingServerHandler } from 'autotel-tanstack/middleware';
111
+
112
+ // Custom middleware for this function only
113
+ const customTracing = createMiddleware({ type: 'function' }).server(
114
+ createTracingServerHandler({
115
+ type: 'function',
116
+ captureArgs: true,
117
+ captureResults: true, // Capture results for this specific function
118
+ }),
96
119
  );
97
120
 
98
- export const getUser = traceServerFn(getUserBase, { name: 'getUser' });
121
+ export const sensitiveOperation = createServerFn({ method: 'POST' })
122
+ .middleware([customTracing])
123
+ .handler(async ({ data }) => {
124
+ // ...
125
+ });
99
126
  ```
100
127
 
101
- ### Tracing Route Loaders
128
+ ### Route Loaders
129
+
130
+ Use `traceLoader` and `traceBeforeLoad` for route-level tracing:
102
131
 
103
132
  ```typescript
104
- import { createFileRoute } from '@tanstack/react-router';
133
+ import { createFileRoute, redirect } from '@tanstack/react-router';
105
134
  import { traceLoader, traceBeforeLoad } from 'autotel-tanstack/loaders';
106
135
 
107
136
  export const Route = createFileRoute('/users/$userId')({
@@ -116,32 +145,14 @@ export const Route = createFileRoute('/users/$userId')({
116
145
  });
117
146
  ```
118
147
 
119
- ### Using createTracedRoute Helper
120
-
121
- ```typescript
122
- import { createFileRoute } from '@tanstack/react-router';
123
- import { createTracedRoute } from 'autotel-tanstack/loaders';
124
-
125
- const traced = createTracedRoute('/users/$userId');
126
-
127
- export const Route = createFileRoute('/users/$userId')({
128
- beforeLoad: traced.beforeLoad(async ({ context }) => {
129
- // Auth check
130
- }),
131
- loader: traced.loader(async ({ params }) => {
132
- return await getUser(params.userId);
133
- }),
134
- });
135
- ```
136
-
137
148
  ## Configuration
138
149
 
139
- ### Middleware Configuration
150
+ ### createTracingServerHandler Options
140
151
 
141
152
  ```typescript
142
- import { createTracingMiddleware } from 'autotel-tanstack/middleware';
153
+ import { createTracingServerHandler } from 'autotel-tanstack/middleware';
143
154
 
144
- const middleware = createTracingMiddleware({
155
+ const handler = createTracingServerHandler({
145
156
  // Type: 'request' for global middleware, 'function' for server functions
146
157
  type: 'request',
147
158
 
@@ -167,27 +178,6 @@ const middleware = createTracingMiddleware({
167
178
  });
168
179
  ```
169
180
 
170
- ### Handler Configuration
171
-
172
- ```typescript
173
- import { wrapStartHandler } from 'autotel-tanstack/handlers';
174
-
175
- const handler = wrapStartHandler({
176
- // Service name (default: OTEL_SERVICE_NAME or 'tanstack-start')
177
- service: 'my-app',
178
-
179
- // OTLP endpoint (default: OTEL_EXPORTER_OTLP_ENDPOINT)
180
- endpoint: 'https://api.honeycomb.io',
181
-
182
- // OTLP headers (default: parsed from OTEL_EXPORTER_OTLP_HEADERS)
183
- headers: { 'x-honeycomb-team': 'YOUR_API_KEY' },
184
-
185
- // All middleware config options also available
186
- captureHeaders: ['x-request-id'],
187
- excludePaths: ['/health'],
188
- });
189
- ```
190
-
191
181
  ## Environment Variables
192
182
 
193
183
  | Variable | Description | Example |
@@ -221,51 +211,6 @@ const handler = wrapStartHandler({
221
211
  - `tanstack.loader.type` - "loader" or "beforeLoad"
222
212
  - `tanstack.loader.params` - Route params (if enabled)
223
213
 
224
- ## Testing
225
-
226
- ```typescript
227
- import { describe, it, beforeEach, afterEach } from 'vitest';
228
- import { createTestHarness } from 'autotel-tanstack/testing';
229
-
230
- describe('MyServerFunction', () => {
231
- let harness: ReturnType<typeof createTestHarness>;
232
-
233
- beforeEach(() => {
234
- harness = createTestHarness();
235
- });
236
-
237
- afterEach(() => {
238
- harness.reset();
239
- });
240
-
241
- it('should trace the server function', async () => {
242
- await myServerFunction({ id: '123' });
243
-
244
- harness.assertServerFnTraced('myServerFunction');
245
- harness.assertSpanHasAttribute(
246
- /tanstack\.serverFn/,
247
- 'tanstack.server_function.name',
248
- 'myServerFunction',
249
- );
250
- });
251
- });
252
- ```
253
-
254
- ### Mock Utilities
255
-
256
- ```typescript
257
- import {
258
- createMockRequest,
259
- generateTraceparent,
260
- } from 'autotel-tanstack/testing';
261
-
262
- // Create mock request
263
- const request = createMockRequest('GET', '/api/users', {
264
- headers: { 'x-request-id': 'test-123' },
265
- traceparent: generateTraceparent(),
266
- });
267
- ```
268
-
269
214
  ## Context Propagation
270
215
 
271
216
  For distributed tracing across services:
@@ -284,6 +229,25 @@ await fetch('https://api.example.com', { headers, method: 'POST', body });
284
229
  const parentContext = extractContextFromRequest(request);
285
230
  ```
286
231
 
232
+ ## Testing
233
+
234
+ ```typescript
235
+ import { describe, it, expect } from 'vitest';
236
+ import { createTestCollector } from 'autotel-tanstack/testing';
237
+
238
+ describe('MyServerFunction', () => {
239
+ it('should trace the server function', async () => {
240
+ const collector = createTestCollector();
241
+
242
+ await myServerFunction({ id: '123' });
243
+
244
+ const spans = collector.getSpans();
245
+ expect(spans).toHaveLength(1);
246
+ expect(spans[0].name).toContain('myServerFunction');
247
+ });
248
+ });
249
+ ```
250
+
287
251
  ## Supported Frameworks
288
252
 
289
253
  - **@tanstack/react-start** ^1.139.14
package/dist/auto.js CHANGED
@@ -1,4 +1,4 @@
1
- export { functionTracingMiddleware, tracingMiddleware } from './chunk-OLBHLVLE.js';
1
+ export { functionTracingMiddleware, tracingMiddleware } from './chunk-ETD6SGPH.js';
2
2
  export { traceServerFn } from './chunk-TNOQTZ3N.js';
3
3
  export { traceBeforeLoad, traceLoader } from './chunk-HKM7LMO6.js';
4
4
  import './chunk-EUYFVNYE.js';
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Browser stub for context module
3
+ *
4
+ * In browser environments, context propagation is not needed.
5
+ * These functions return empty/default values.
6
+ */
7
+ /**
8
+ * Type representing values that can be used to initialize Headers
9
+ */
10
+ type HeadersInitType = Headers | Record<string, string> | [string, string][];
11
+ /**
12
+ * Browser stub: Returns root context (no parent)
13
+ */
14
+ declare function extractContextFromRequest(_request: Request): unknown;
15
+ /**
16
+ * Browser stub: Returns headers unchanged
17
+ */
18
+ declare function injectContextToHeaders(headers: Headers, ctx?: unknown): Headers;
19
+ /**
20
+ * Browser stub: Create headers with optional initial values
21
+ */
22
+ declare function createTracedHeaders(existingHeaders?: HeadersInitType, ctx?: unknown): Headers;
23
+ /**
24
+ * Browser stub: Run function and return result
25
+ */
26
+ declare function runInContext<T>(parentContext: unknown, fn: () => T): T;
27
+ /**
28
+ * Browser stub: Returns empty context object
29
+ */
30
+ declare function getActiveContext(): unknown;
31
+ /**
32
+ * Browser stub: Returns empty string
33
+ */
34
+ declare function getTraceParent(): string;
35
+ /**
36
+ * Browser stub: Returns empty string
37
+ */
38
+ declare function getTraceState(): string;
39
+ /**
40
+ * Browser stub: Returns undefined
41
+ */
42
+ declare function getCurrentTraceId(): string | undefined;
43
+ /**
44
+ * Browser stub: Returns undefined
45
+ */
46
+ declare function getCurrentSpanId(): string | undefined;
47
+
48
+ export { type HeadersInitType, createTracedHeaders, extractContextFromRequest, getActiveContext, getCurrentSpanId, getCurrentTraceId, getTraceParent, getTraceState, injectContextToHeaders, runInContext };
@@ -0,0 +1,16 @@
1
+ import { MiddlewareHandler } from './middleware.js';
2
+ import './types.js';
3
+
4
+ /**
5
+ * Browser stub for debug-headers module
6
+ *
7
+ * Debug headers are server-side only.
8
+ * In browser, this returns pass-through middleware.
9
+ */
10
+
11
+ /**
12
+ * Browser stub: Returns pass-through middleware
13
+ */
14
+ declare function debugHeadersMiddleware<TContext = unknown>(): MiddlewareHandler<TContext>;
15
+
16
+ export { debugHeadersMiddleware };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Browser stub for error-reporting module
3
+ *
4
+ * Error reporting/collection only happens on the server.
5
+ * In browser, these are no-op functions.
6
+ */
7
+ /**
8
+ * Error entry structure (stub)
9
+ */
10
+ interface ErrorEntry {
11
+ timestamp: string;
12
+ message: string;
13
+ stack?: string;
14
+ context?: Record<string, unknown>;
15
+ }
16
+ /**
17
+ * Browser stub: No-op
18
+ */
19
+ declare function reportError(error: Error, context?: Record<string, unknown>): void;
20
+ /**
21
+ * Browser stub: Returns empty array
22
+ */
23
+ declare function getRecentErrors(limit?: number): ErrorEntry[];
24
+ /**
25
+ * Browser stub: No-op
26
+ */
27
+ declare function clearErrors(): void;
28
+ /**
29
+ * Browser stub: Returns JSON Response with empty errors
30
+ */
31
+ declare function createErrorReportingHandler(): () => Response;
32
+ /**
33
+ * Browser stub: Returns function unchanged
34
+ */
35
+ declare function withErrorReporting<T extends (...args: unknown[]) => unknown>(fn: T, context?: Record<string, unknown>): T;
36
+
37
+ export { type ErrorEntry, clearErrors, createErrorReportingHandler, getRecentErrors, reportError, withErrorReporting };
@@ -0,0 +1,19 @@
1
+ import { WrapStartHandlerConfig } from './types.js';
2
+
3
+ /**
4
+ * Browser stub for handlers module
5
+ *
6
+ * Handler wrapping only applies on the server side.
7
+ * In browser, we just return the handler unchanged.
8
+ */
9
+
10
+ /**
11
+ * Handler type
12
+ */
13
+ type StartHandler<T = unknown> = (request: Request) => Promise<T>;
14
+ /**
15
+ * Browser stub: Returns the handler unchanged
16
+ */
17
+ declare function wrapStartHandler<T>(config?: WrapStartHandlerConfig): (handler: StartHandler<T>) => StartHandler<T>;
18
+
19
+ export { type StartHandler, wrapStartHandler };
@@ -0,0 +1,10 @@
1
+ export { Attributes, DEFAULT_CONFIG, SPAN_ATTRIBUTES, TanStackInstrumentationConfig, TraceLoaderConfig, TraceServerFnConfig, TracingMiddlewareConfig, WrapStartHandlerConfig } from './types.js';
2
+ export { createTracedRoute, traceBeforeLoad, traceLoader } from './loaders.js';
3
+ export { createTracedServerFnFactory, traceServerFn } from './server-functions.js';
4
+ export { MiddlewareHandler, createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from './middleware.js';
5
+ export { HeadersInitType, createTracedHeaders, extractContextFromRequest, getActiveContext, getCurrentSpanId, getCurrentTraceId, getTraceParent, getTraceState, injectContextToHeaders, runInContext } from './context.js';
6
+ export { StartHandler, wrapStartHandler } from './handlers.js';
7
+ export { MetricsData, createMetricsHandler, getMetrics, metricsCollector, recordError, recordTiming, resetMetrics } from './metrics.js';
8
+ export { ErrorEntry, clearErrors, createErrorReportingHandler, getRecentErrors, reportError, withErrorReporting } from './error-reporting.js';
9
+ export { debugHeadersMiddleware } from './debug-headers.js';
10
+ export { TestCollector, TestSpan, assertSpanCreated, assertSpanHasAttribute, createTestCollector } from './testing.js';
@@ -1,7 +1,7 @@
1
1
  export { createMetricsHandler, getMetrics, metricsCollector, recordError, recordTiming, resetMetrics } from '../chunk-UMEJU65Q.js';
2
2
  export { clearErrors, createErrorReportingHandler, getRecentErrors, reportError, withErrorReporting } from '../chunk-HIQYW2HB.js';
3
3
  export { DEFAULT_CONFIG, SPAN_ATTRIBUTES } from '../chunk-MFYOV2SF.js';
4
- export { createTracingMiddleware, functionTracingMiddleware, tracingMiddleware } from '../chunk-4C7T5ZIM.js';
4
+ export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from '../chunk-A7WMQ2BC.js';
5
5
  export { createTracedServerFnFactory, traceServerFn } from '../chunk-CSFIPJC2.js';
6
6
  export { createTracedRoute, traceBeforeLoad, traceLoader } from '../chunk-MNP65ZX7.js';
7
7
  export { createTracedHeaders, extractContextFromRequest, getActiveContext, getCurrentSpanId, getCurrentTraceId, getTraceParent, getTraceState, injectContextToHeaders, runInContext } from '../chunk-DTZCOB4W.js';
@@ -0,0 +1,36 @@
1
+ import { TraceLoaderConfig } from './types.js';
2
+
3
+ /**
4
+ * Browser stub for loaders module
5
+ *
6
+ * In browser environments, these functions are no-ops that just call the
7
+ * original functions without any tracing overhead.
8
+ */
9
+
10
+ /**
11
+ * Loader context type (compatible with TanStack router loader context)
12
+ */
13
+ interface LoaderContext {
14
+ params?: Record<string, string>;
15
+ route?: {
16
+ id?: string;
17
+ };
18
+ [key: string]: unknown;
19
+ }
20
+ /**
21
+ * Browser stub: Returns the loader function unchanged
22
+ */
23
+ declare function traceLoader<T extends (context: LoaderContext) => Promise<unknown>>(loaderFn: T, config?: TraceLoaderConfig): T;
24
+ /**
25
+ * Browser stub: Returns the beforeLoad function unchanged
26
+ */
27
+ declare function traceBeforeLoad<T extends (context: LoaderContext) => Promise<unknown>>(beforeLoadFn: T, config?: TraceLoaderConfig): T;
28
+ /**
29
+ * Browser stub: Returns object with pass-through wrappers
30
+ */
31
+ declare function createTracedRoute(routeId: string, config?: Omit<TraceLoaderConfig, 'name'>): {
32
+ loader<T extends (context: LoaderContext) => Promise<unknown>>(loaderFn: T): T;
33
+ beforeLoad<T extends (context: LoaderContext) => Promise<unknown>>(beforeLoadFn: T): T;
34
+ };
35
+
36
+ export { createTracedRoute, traceBeforeLoad, traceLoader };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Browser stub for metrics module
3
+ *
4
+ * Metrics collection only happens on the server.
5
+ * In browser, these are no-op functions.
6
+ */
7
+ /**
8
+ * Metrics data structure (stub)
9
+ */
10
+ interface MetricsData {
11
+ requestCount: number;
12
+ errorCount: number;
13
+ avgLatency: number;
14
+ p50Latency: number;
15
+ p95Latency: number;
16
+ p99Latency: number;
17
+ requestsPerSecond: number;
18
+ endpoints: Record<string, {
19
+ count: number;
20
+ errors: number;
21
+ avgLatency: number;
22
+ }>;
23
+ }
24
+ /**
25
+ * Browser stub: Returns empty metrics
26
+ */
27
+ declare function getMetrics(): MetricsData;
28
+ /**
29
+ * Browser stub: No-op
30
+ */
31
+ declare function recordTiming(name: string, durationMs: number): void;
32
+ /**
33
+ * Browser stub: No-op
34
+ */
35
+ declare function recordError(name: string): void;
36
+ /**
37
+ * Browser stub: No-op
38
+ */
39
+ declare function resetMetrics(): void;
40
+ /**
41
+ * Browser stub: No-op metrics collector
42
+ */
43
+ declare const metricsCollector: {
44
+ recordTiming: typeof recordTiming;
45
+ recordError: typeof recordError;
46
+ getMetrics: typeof getMetrics;
47
+ reset: typeof resetMetrics;
48
+ };
49
+ /**
50
+ * Browser stub: Returns JSON Response with empty metrics
51
+ */
52
+ declare function createMetricsHandler(): () => Response;
53
+
54
+ export { type MetricsData, createMetricsHandler, getMetrics, metricsCollector, recordError, recordTiming, resetMetrics };
@@ -0,0 +1,47 @@
1
+ import { TracingMiddlewareConfig } from './types.js';
2
+
3
+ /**
4
+ * Browser stub for middleware module
5
+ *
6
+ * In browser environments, these functions return pass-through middleware
7
+ * that just calls next() without any tracing overhead.
8
+ */
9
+
10
+ /**
11
+ * Generic middleware handler type
12
+ */
13
+ interface MiddlewareHandler<TContext = unknown> {
14
+ (opts: {
15
+ next: (ctx?: Partial<TContext>) => Promise<TContext>;
16
+ context: TContext;
17
+ request?: Request;
18
+ pathname?: string;
19
+ data?: unknown;
20
+ method?: string;
21
+ filename?: string;
22
+ functionId?: string;
23
+ signal?: AbortSignal;
24
+ }): Promise<TContext>;
25
+ }
26
+ /**
27
+ * Browser stub: Returns pass-through middleware
28
+ */
29
+ declare function createTracingMiddleware<TContext = unknown>(config?: TracingMiddlewareConfig): MiddlewareHandler<TContext>;
30
+ /**
31
+ * Browser stub: Returns pass-through middleware
32
+ */
33
+ declare function tracingMiddleware<TContext = unknown>(config?: TracingMiddlewareConfig): MiddlewareHandler<TContext>;
34
+ /**
35
+ * Browser stub: Returns pass-through middleware
36
+ */
37
+ declare function functionTracingMiddleware<TContext = unknown>(config?: Omit<TracingMiddlewareConfig, 'type'>): MiddlewareHandler<TContext>;
38
+ /**
39
+ * Browser stub: Returns pass-through handler for createMiddleware().server()
40
+ */
41
+ declare function createTracingServerHandler<TContext = unknown>(config?: TracingMiddlewareConfig): (opts: {
42
+ next: (ctx?: Partial<TContext>) => Promise<TContext>;
43
+ context: TContext;
44
+ request?: Request;
45
+ }) => Promise<TContext>;
46
+
47
+ export { type MiddlewareHandler, createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware };
@@ -1,3 +1,3 @@
1
- export { createTracingMiddleware, functionTracingMiddleware, tracingMiddleware } from '../chunk-4C7T5ZIM.js';
1
+ export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from '../chunk-A7WMQ2BC.js';
2
2
  //# sourceMappingURL=middleware.js.map
3
3
  //# sourceMappingURL=middleware.js.map
@@ -0,0 +1,19 @@
1
+ import { TraceServerFnConfig } from './types.js';
2
+
3
+ /**
4
+ * Browser stub for server-functions module
5
+ *
6
+ * In browser environments, these functions are no-ops that just return
7
+ * the original functions without any tracing overhead.
8
+ */
9
+
10
+ /**
11
+ * Browser stub: Returns the server function unchanged
12
+ */
13
+ declare function traceServerFn<T extends (...args: unknown[]) => Promise<unknown>>(serverFn: T, config?: TraceServerFnConfig): T;
14
+ /**
15
+ * Browser stub: Returns the createServerFn unchanged
16
+ */
17
+ declare function createTracedServerFnFactory<TCreateServerFn extends (...args: unknown[]) => unknown>(createServerFnOriginal: TCreateServerFn, defaultConfig?: Omit<TraceServerFnConfig, 'name'>): TCreateServerFn;
18
+
19
+ export { createTracedServerFnFactory, traceServerFn };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Browser stub for testing module
3
+ *
4
+ * Testing utilities are server-side only.
5
+ * In browser, these return no-op implementations.
6
+ */
7
+ /**
8
+ * Test span structure (stub)
9
+ */
10
+ interface TestSpan {
11
+ name: string;
12
+ attributes: Record<string, unknown>;
13
+ status: {
14
+ code: number;
15
+ message?: string;
16
+ };
17
+ events: Array<{
18
+ name: string;
19
+ attributes?: Record<string, unknown>;
20
+ }>;
21
+ duration: number;
22
+ }
23
+ /**
24
+ * Test collector structure (stub)
25
+ */
26
+ interface TestCollector {
27
+ getSpans(): TestSpan[];
28
+ getSpansByName(name: string): TestSpan[];
29
+ clear(): void;
30
+ waitForSpans(count: number, timeout?: number): Promise<TestSpan[]>;
31
+ }
32
+ /**
33
+ * Browser stub: Returns empty collector
34
+ */
35
+ declare function createTestCollector(): TestCollector;
36
+ /**
37
+ * Browser stub: No-op
38
+ */
39
+ declare function assertSpanCreated(collector: TestCollector, name: string): void;
40
+ /**
41
+ * Browser stub: No-op
42
+ */
43
+ declare function assertSpanHasAttribute(collector: TestCollector, name: string, key: string, value?: unknown): void;
44
+
45
+ export { type TestCollector, type TestSpan, assertSpanCreated, assertSpanHasAttribute, createTestCollector };
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Browser stub for types module
3
+ *
4
+ * Provides type definitions without importing from @opentelemetry/api
5
+ */
6
+ /**
7
+ * OpenTelemetry-compatible Attributes type (browser stub)
8
+ */
9
+ type Attributes = Record<string, string | number | boolean | undefined>;
10
+ /**
11
+ * Configuration options for TanStack Start instrumentation
12
+ */
13
+ interface TanStackInstrumentationConfig {
14
+ service?: string;
15
+ captureArgs?: boolean;
16
+ captureResults?: boolean;
17
+ captureErrors?: boolean;
18
+ captureHeaders?: string[];
19
+ excludePaths?: (string | RegExp)[];
20
+ sampling?: 'always' | 'adaptive' | 'never';
21
+ customAttributes?: (context: {
22
+ type: 'request' | 'serverFn' | 'loader' | 'beforeLoad' | 'middleware';
23
+ name: string;
24
+ request?: Request;
25
+ args?: unknown;
26
+ result?: unknown;
27
+ }) => Attributes;
28
+ }
29
+ /**
30
+ * Configuration specific to tracing middleware
31
+ */
32
+ interface TracingMiddlewareConfig extends TanStackInstrumentationConfig {
33
+ type?: 'request' | 'function';
34
+ }
35
+ /**
36
+ * Configuration for server function tracing
37
+ */
38
+ interface TraceServerFnConfig {
39
+ name?: string;
40
+ captureArgs?: boolean;
41
+ captureResults?: boolean;
42
+ }
43
+ /**
44
+ * Configuration for loader tracing
45
+ */
46
+ interface TraceLoaderConfig {
47
+ name?: string;
48
+ captureParams?: boolean;
49
+ captureResult?: boolean;
50
+ }
51
+ /**
52
+ * Configuration for handler wrapper
53
+ */
54
+ interface WrapStartHandlerConfig extends TanStackInstrumentationConfig {
55
+ endpoint?: string;
56
+ headers?: Record<string, string>;
57
+ }
58
+ /**
59
+ * Default configuration values
60
+ */
61
+ declare const DEFAULT_CONFIG: Required<Omit<TanStackInstrumentationConfig, 'customAttributes' | 'service'>>;
62
+ /**
63
+ * Span attribute keys (stub - values are strings)
64
+ */
65
+ declare const SPAN_ATTRIBUTES: {
66
+ readonly HTTP_REQUEST_METHOD: "http.request.method";
67
+ readonly HTTP_RESPONSE_STATUS_CODE: "http.response.status_code";
68
+ readonly URL_PATH: "url.path";
69
+ readonly URL_QUERY: "url.query";
70
+ readonly URL_FULL: "url.full";
71
+ readonly RPC_SYSTEM: "rpc.system";
72
+ readonly RPC_METHOD: "rpc.method";
73
+ readonly TANSTACK_TYPE: "tanstack.type";
74
+ readonly TANSTACK_SERVER_FN_NAME: "tanstack.server_function.name";
75
+ readonly TANSTACK_SERVER_FN_METHOD: "tanstack.server_function.method";
76
+ readonly TANSTACK_SERVER_FN_ARGS: "tanstack.server_function.args";
77
+ readonly TANSTACK_SERVER_FN_RESULT: "tanstack.server_function.result";
78
+ readonly TANSTACK_LOADER_ROUTE_ID: "tanstack.loader.route_id";
79
+ readonly TANSTACK_LOADER_TYPE: "tanstack.loader.type";
80
+ readonly TANSTACK_LOADER_PARAMS: "tanstack.loader.params";
81
+ readonly TANSTACK_MIDDLEWARE_NAME: "tanstack.middleware.name";
82
+ readonly TANSTACK_REQUEST_DURATION_MS: "tanstack.request.duration_ms";
83
+ };
84
+
85
+ export { type Attributes, DEFAULT_CONFIG, SPAN_ATTRIBUTES, type TanStackInstrumentationConfig, type TraceLoaderConfig, type TraceServerFnConfig, type TracingMiddlewareConfig, type WrapStartHandlerConfig };
@@ -14,7 +14,12 @@ function functionTracingMiddleware(config) {
14
14
  return opts.next();
15
15
  };
16
16
  }
17
+ function createTracingServerHandler(config) {
18
+ return async function noopHandler(opts) {
19
+ return opts.next();
20
+ };
21
+ }
17
22
 
18
- export { createTracingMiddleware, functionTracingMiddleware, tracingMiddleware };
19
- //# sourceMappingURL=chunk-4C7T5ZIM.js.map
20
- //# sourceMappingURL=chunk-4C7T5ZIM.js.map
23
+ export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware };
24
+ //# sourceMappingURL=chunk-A7WMQ2BC.js.map
25
+ //# sourceMappingURL=chunk-A7WMQ2BC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/browser/middleware.ts"],"names":[],"mappings":";AA6BO,SAAS,wBACd,MAAA,EAC6B;AAE7B,EAAA,OAAO,eAAe,eAAe,IAAA,EAAM;AACzC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA;AACF;AAKO,SAAS,kBACd,MAAA,EAC6B;AAE7B,EAAA,OAAO,eAAe,eAAe,IAAA,EAAM;AACzC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA;AACF;AAKO,SAAS,0BACd,MAAA,EAC6B;AAE7B,EAAA,OAAO,eAAe,eAAe,IAAA,EAAM;AACzC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA;AACF;AAKO,SAAS,2BACd,MAAA,EAKsB;AAEtB,EAAA,OAAO,eAAe,YAAY,IAAA,EAAM;AACtC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA;AACF","file":"chunk-A7WMQ2BC.js","sourcesContent":["/**\n * Browser stub for middleware module\n *\n * In browser environments, these functions return pass-through middleware\n * that just calls next() without any tracing overhead.\n */\n\nimport type { TracingMiddlewareConfig } from './types';\n\n/**\n * Generic middleware handler type\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 * Browser stub: Returns pass-through middleware\n */\nexport function createTracingMiddleware<TContext = unknown>(\n config?: TracingMiddlewareConfig,\n): MiddlewareHandler<TContext> {\n void config;\n return async function noopMiddleware(opts) {\n return opts.next();\n };\n}\n\n/**\n * Browser stub: Returns pass-through middleware\n */\nexport function tracingMiddleware<TContext = unknown>(\n config?: TracingMiddlewareConfig,\n): MiddlewareHandler<TContext> {\n void config;\n return async function noopMiddleware(opts) {\n return opts.next();\n };\n}\n\n/**\n * Browser stub: Returns pass-through middleware\n */\nexport function functionTracingMiddleware<TContext = unknown>(\n config?: Omit<TracingMiddlewareConfig, 'type'>,\n): MiddlewareHandler<TContext> {\n void config;\n return async function noopMiddleware(opts) {\n return opts.next();\n };\n}\n\n/**\n * Browser stub: Returns pass-through handler for createMiddleware().server()\n */\nexport function createTracingServerHandler<TContext = unknown>(\n config?: TracingMiddlewareConfig,\n): (opts: {\n next: (ctx?: Partial<TContext>) => Promise<TContext>;\n context: TContext;\n request?: Request;\n}) => Promise<TContext> {\n void config;\n return async function noopHandler(opts) {\n return opts.next();\n };\n}\n"]}
@@ -214,7 +214,13 @@ function functionTracingMiddleware(config) {
214
214
  type: "function"
215
215
  });
216
216
  }
217
+ function createTracingServerHandler(config) {
218
+ const handler = createTracingMiddleware(config);
219
+ return async (opts) => {
220
+ return handler(opts);
221
+ };
222
+ }
217
223
 
218
- export { createTracingMiddleware, functionTracingMiddleware, tracingMiddleware };
219
- //# sourceMappingURL=chunk-OLBHLVLE.js.map
220
- //# sourceMappingURL=chunk-OLBHLVLE.js.map
224
+ export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware };
225
+ //# sourceMappingURL=chunk-ETD6SGPH.js.map
226
+ //# sourceMappingURL=chunk-ETD6SGPH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/middleware.ts"],"names":["tracingMiddleware"],"mappings":"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","file":"chunk-ETD6SGPH.js","sourcesContent":["import { context, SpanStatusCode, type Attributes } from '@opentelemetry/api';\nimport { trace, type TraceContext } from 'autotel';\nimport { extractContextFromRequest } from './context';\nimport { isServerSide } from './env';\nimport {\n type TracingMiddlewareConfig,\n DEFAULT_CONFIG,\n SPAN_ATTRIBUTES,\n} from './types';\n\n/**\n * Check if a path should be excluded from tracing\n */\nfunction shouldExcludePath(\n pathname: string,\n excludePaths: (string | RegExp)[],\n): boolean {\n for (const pattern of excludePaths) {\n if (typeof pattern === 'string') {\n // Simple glob matching\n if (pattern.includes('*')) {\n const regex = new RegExp(\n '^' + pattern.replaceAll('*', '.*').replaceAll('?', '.') + '$',\n );\n if (regex.test(pathname)) return true;\n } else {\n if (pathname === pattern || pathname.startsWith(pattern)) return true;\n }\n } else {\n if (pattern.test(pathname)) return true;\n }\n }\n return false;\n}\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 ctx.recordException(error as Error);\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\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 (shouldExcludePath(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 ctx.recordException(error as Error);\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\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: {\n next: (ctx?: Partial<TContext>) => Promise<TContext>;\n context: TContext;\n request?: Request;\n}) => Promise<TContext> {\n const handler = createTracingMiddleware<TContext>(config);\n\n // Adapt TanStack's signature to our handler\n return async (opts) => {\n return handler(opts);\n };\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { D as DEFAULT_CONFIG, S as SPAN_ATTRIBUTES, T as TanStackInstrumentationConfig, c as TraceLoaderConfig, b as TraceServerFnConfig, a as TracingMiddlewareConfig, W as WrapStartHandlerConfig } from './types-C37KSxMN.js';
2
- export { MiddlewareHandler, createTracingMiddleware, functionTracingMiddleware, tracingMiddleware } from './middleware.js';
2
+ export { MiddlewareHandler, createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from './middleware.js';
3
3
  export { createTracedServerFnFactory, traceServerFn } from './server-functions.js';
4
4
  export { createTracedRoute, traceBeforeLoad, traceLoader } from './loaders.js';
5
5
  export { createTracedHandler, wrapStartHandler } from './handlers.js';
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { debugHeadersMiddleware } from './chunk-UTPW3QRT.js';
2
2
  export { createMetricsHandler, metricsCollector, recordTiming } from './chunk-JSI6QG7M.js';
3
3
  export { createErrorReportingHandler, errorStore, reportError, withErrorReporting } from './chunk-XXBHZR3M.js';
4
- export { createTracingMiddleware, functionTracingMiddleware, tracingMiddleware } from './chunk-OLBHLVLE.js';
4
+ export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from './chunk-ETD6SGPH.js';
5
5
  export { createTracedServerFnFactory, traceServerFn } from './chunk-TNOQTZ3N.js';
6
6
  export { createTracedRoute, traceBeforeLoad, traceLoader } from './chunk-HKM7LMO6.js';
7
7
  export { isBrowser, isNode, isServerSide } from './chunk-EUYFVNYE.js';
@@ -100,5 +100,52 @@ declare function tracingMiddleware<TContext = unknown>(config?: TracingMiddlewar
100
100
  * ```
101
101
  */
102
102
  declare function functionTracingMiddleware<TContext = unknown>(config?: Omit<TracingMiddlewareConfig, 'type'>): MiddlewareHandler<TContext>;
103
+ /**
104
+ * Create a tracing handler for use with TanStack's native createMiddleware()
105
+ *
106
+ * This provides the raw tracing logic that you can pass to createMiddleware().server().
107
+ * Use this when you want full control over the middleware builder pattern.
108
+ *
109
+ * The handler accepts TanStack's middleware signature `{ next, context, request }`
110
+ * and internally adapts it to our more flexible MiddlewareHandler interface.
111
+ *
112
+ * @param config - Configuration options
113
+ * @returns Server handler function compatible with createMiddleware().server()
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * import { createStart, createMiddleware } from '@tanstack/react-start';
118
+ * import { createTracingServerHandler } from 'autotel-tanstack/middleware';
119
+ *
120
+ * // TanStack-native middleware creation
121
+ * const requestTracingMiddleware = createMiddleware().server(
122
+ * createTracingServerHandler({ captureHeaders: ['x-request-id'] })
123
+ * );
124
+ *
125
+ * export const start = createStart(() => ({
126
+ * requestMiddleware: [requestTracingMiddleware],
127
+ * }));
128
+ * ```
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // For server functions - use createMiddleware({ type: 'function' })
133
+ * import { createStart, createMiddleware } from '@tanstack/react-start';
134
+ * import { createTracingServerHandler } from 'autotel-tanstack/middleware';
135
+ *
136
+ * const functionTracingMiddleware = createMiddleware({ type: 'function' }).server(
137
+ * createTracingServerHandler({ type: 'function', captureArgs: true })
138
+ * );
139
+ *
140
+ * export const start = createStart(() => ({
141
+ * functionMiddleware: [functionTracingMiddleware],
142
+ * }));
143
+ * ```
144
+ */
145
+ declare function createTracingServerHandler<TContext = unknown>(config?: TracingMiddlewareConfig): (opts: {
146
+ next: (ctx?: Partial<TContext>) => Promise<TContext>;
147
+ context: TContext;
148
+ request?: Request;
149
+ }) => Promise<TContext>;
103
150
 
104
- export { type MiddlewareHandler, createTracingMiddleware, functionTracingMiddleware, tracingMiddleware };
151
+ export { type MiddlewareHandler, createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware };
@@ -1,4 +1,4 @@
1
- export { createTracingMiddleware, functionTracingMiddleware, tracingMiddleware } from './chunk-OLBHLVLE.js';
1
+ export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from './chunk-ETD6SGPH.js';
2
2
  import './chunk-EUYFVNYE.js';
3
3
  import './chunk-I4LX3LOG.js';
4
4
  import './chunk-NTY64BKS.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-tanstack",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "OpenTelemetry instrumentation for TanStack Start - automatic tracing for server functions, middleware, and route loaders",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -23,6 +23,7 @@ export {
23
23
  createTracingMiddleware,
24
24
  tracingMiddleware,
25
25
  functionTracingMiddleware,
26
+ createTracingServerHandler,
26
27
  type MiddlewareHandler,
27
28
  } from './middleware';
28
29
  export {
@@ -59,3 +59,19 @@ export function functionTracingMiddleware<TContext = unknown>(
59
59
  return opts.next();
60
60
  };
61
61
  }
62
+
63
+ /**
64
+ * Browser stub: Returns pass-through handler for createMiddleware().server()
65
+ */
66
+ export function createTracingServerHandler<TContext = unknown>(
67
+ config?: TracingMiddlewareConfig,
68
+ ): (opts: {
69
+ next: (ctx?: Partial<TContext>) => Promise<TContext>;
70
+ context: TContext;
71
+ request?: Request;
72
+ }) => Promise<TContext> {
73
+ void config;
74
+ return async function noopHandler(opts) {
75
+ return opts.next();
76
+ };
77
+ }
package/src/index.ts CHANGED
@@ -39,6 +39,7 @@ export {
39
39
  createTracingMiddleware,
40
40
  tracingMiddleware,
41
41
  functionTracingMiddleware,
42
+ createTracingServerHandler,
42
43
  type MiddlewareHandler,
43
44
  } from './middleware';
44
45
 
package/src/middleware.ts CHANGED
@@ -398,3 +398,60 @@ export function functionTracingMiddleware<TContext = unknown>(
398
398
  type: 'function',
399
399
  });
400
400
  }
401
+
402
+ /**
403
+ * Create a tracing handler for use with TanStack's native createMiddleware()
404
+ *
405
+ * This provides the raw tracing logic that you can pass to createMiddleware().server().
406
+ * Use this when you want full control over the middleware builder pattern.
407
+ *
408
+ * The handler accepts TanStack's middleware signature `{ next, context, request }`
409
+ * and internally adapts it to our more flexible MiddlewareHandler interface.
410
+ *
411
+ * @param config - Configuration options
412
+ * @returns Server handler function compatible with createMiddleware().server()
413
+ *
414
+ * @example
415
+ * ```typescript
416
+ * import { createStart, createMiddleware } from '@tanstack/react-start';
417
+ * import { createTracingServerHandler } from 'autotel-tanstack/middleware';
418
+ *
419
+ * // TanStack-native middleware creation
420
+ * const requestTracingMiddleware = createMiddleware().server(
421
+ * createTracingServerHandler({ captureHeaders: ['x-request-id'] })
422
+ * );
423
+ *
424
+ * export const start = createStart(() => ({
425
+ * requestMiddleware: [requestTracingMiddleware],
426
+ * }));
427
+ * ```
428
+ *
429
+ * @example
430
+ * ```typescript
431
+ * // For server functions - use createMiddleware({ type: 'function' })
432
+ * import { createStart, createMiddleware } from '@tanstack/react-start';
433
+ * import { createTracingServerHandler } from 'autotel-tanstack/middleware';
434
+ *
435
+ * const functionTracingMiddleware = createMiddleware({ type: 'function' }).server(
436
+ * createTracingServerHandler({ type: 'function', captureArgs: true })
437
+ * );
438
+ *
439
+ * export const start = createStart(() => ({
440
+ * functionMiddleware: [functionTracingMiddleware],
441
+ * }));
442
+ * ```
443
+ */
444
+ export function createTracingServerHandler<TContext = unknown>(
445
+ config?: TracingMiddlewareConfig,
446
+ ): (opts: {
447
+ next: (ctx?: Partial<TContext>) => Promise<TContext>;
448
+ context: TContext;
449
+ request?: Request;
450
+ }) => Promise<TContext> {
451
+ const handler = createTracingMiddleware<TContext>(config);
452
+
453
+ // Adapt TanStack's signature to our handler
454
+ return async (opts) => {
455
+ return handler(opts);
456
+ };
457
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/browser/middleware.ts"],"names":[],"mappings":";AA6BO,SAAS,wBACd,MAAA,EAC6B;AAE7B,EAAA,OAAO,eAAe,eAAe,IAAA,EAAM;AACzC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA;AACF;AAKO,SAAS,kBACd,MAAA,EAC6B;AAE7B,EAAA,OAAO,eAAe,eAAe,IAAA,EAAM;AACzC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA;AACF;AAKO,SAAS,0BACd,MAAA,EAC6B;AAE7B,EAAA,OAAO,eAAe,eAAe,IAAA,EAAM;AACzC,IAAA,OAAO,KAAK,IAAA,EAAK;AAAA,EACnB,CAAA;AACF","file":"chunk-4C7T5ZIM.js","sourcesContent":["/**\n * Browser stub for middleware module\n *\n * In browser environments, these functions return pass-through middleware\n * that just calls next() without any tracing overhead.\n */\n\nimport type { TracingMiddlewareConfig } from './types';\n\n/**\n * Generic middleware handler type\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 * Browser stub: Returns pass-through middleware\n */\nexport function createTracingMiddleware<TContext = unknown>(\n config?: TracingMiddlewareConfig,\n): MiddlewareHandler<TContext> {\n void config;\n return async function noopMiddleware(opts) {\n return opts.next();\n };\n}\n\n/**\n * Browser stub: Returns pass-through middleware\n */\nexport function tracingMiddleware<TContext = unknown>(\n config?: TracingMiddlewareConfig,\n): MiddlewareHandler<TContext> {\n void config;\n return async function noopMiddleware(opts) {\n return opts.next();\n };\n}\n\n/**\n * Browser stub: Returns pass-through middleware\n */\nexport function functionTracingMiddleware<TContext = unknown>(\n config?: Omit<TracingMiddlewareConfig, 'type'>,\n): MiddlewareHandler<TContext> {\n void config;\n return async function noopMiddleware(opts) {\n return opts.next();\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/middleware.ts"],"names":["tracingMiddleware"],"mappings":";;;;;;AAaA,SAAS,iBAAA,CACP,UACA,YAAA,EACS;AACT,EAAA,KAAA,MAAW,WAAW,YAAA,EAAc;AAClC,IAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAE/B,MAAA,IAAI,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG;AACzB,QAAA,MAAM,QAAQ,IAAI,MAAA;AAAA,UAChB,GAAA,GAAM,QAAQ,UAAA,CAAW,GAAA,EAAK,IAAI,CAAA,CAAE,UAAA,CAAW,GAAA,EAAK,GAAG,CAAA,GAAI;AAAA,SAC7D;AACA,QAAA,IAAI,KAAA,CAAM,IAAA,CAAK,QAAQ,CAAA,EAAG,OAAO,IAAA;AAAA,MACnC,CAAA,MAAO;AACL,QAAA,IAAI,aAAa,OAAA,IAAW,QAAA,CAAS,UAAA,CAAW,OAAO,GAAG,OAAO,IAAA;AAAA,MACnE;AAAA,IACF,CAAA,MAAO;AACL,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,EAAG,OAAO,IAAA;AAAA,IACrC;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAKA,SAAS,sBAAA,CACP,SACA,MAAA,EAGY;AACZ,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,EAAA,MAAM,KAAA,GAAoB;AAAA,IACxB,CAAC,eAAA,CAAgB,mBAAmB,GAAG,OAAA,CAAQ,MAAA;AAAA,IAC/C,CAAC,eAAA,CAAgB,QAAQ,GAAG,GAAA,CAAI,QAAA;AAAA,IAChC,CAAC,eAAA,CAAgB,aAAa,GAAG;AAAA,GACnC;AAEA,EAAA,IAAI,IAAI,MAAA,EAAQ;AACd,IAAA,KAAA,CAAM,eAAA,CAAgB,SAAS,CAAA,GAAI,GAAA,CAAI,MAAA;AAAA,EACzC;AAGA,EAAA,IAAI,OAAO,cAAA,EAAgB;AACzB,IAAA,KAAA,MAAW,MAAA,IAAU,OAAO,cAAA,EAAgB;AAC1C,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA;AACxC,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,KAAA,CAAM,CAAA,oBAAA,EAAuB,MAAA,CAAO,WAAA,EAAa,EAAE,CAAA,GAAI,KAAA;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAKA,SAAS,uBAAA,CACP,YAAA,EACA,MAAA,EACA,IAAA,EACA,MAAA,EAGY;AACZ,EAAA,MAAM,KAAA,GAAoB;AAAA,IACxB,CAAC,eAAA,CAAgB,UAAU,GAAG,gBAAA;AAAA,IAC9B,CAAC,eAAA,CAAgB,UAAU,GAAG,YAAA;AAAA,IAC9B,CAAC,eAAA,CAAgB,aAAa,GAAG,UAAA;AAAA,IACjC,CAAC,eAAA,CAAgB,uBAAuB,GAAG,YAAA;AAAA,IAC3C,CAAC,eAAA,CAAgB,yBAAyB,GAAG;AAAA,GAC/C;AAEA,EAAA,IAAI,MAAA,CAAO,WAAA,IAAe,IAAA,KAAS,MAAA,EAAW;AAC5C,IAAA,IAAI;AACF,MAAA,KAAA,CAAM,eAAA,CAAgB,uBAAuB,CAAA,GAAI,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,IACtE,CAAA,CAAA,MAAQ;AACN,MAAA,KAAA,CAAM,eAAA,CAAgB,uBAAuB,CAAA,GAAI,oBAAA;AAAA,IACnD;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AA4DO,SAAS,wBACd,MAAA,EAC6B;AAC7B,EAAA,MAAM,YAAA,GAAe;AAAA,IACnB,GAAG,cAAA;AAAA,IACH,GAAG,MAAA;AAAA,IACH,IAAA,EAAM,QAAQ,IAAA,IAAQ;AAAA,GACxB;AAEA,EAAA,OAAO,eAAeA,mBAAkB,IAAA,EAAM;AAG5C,IAAA,IAAI,CAAC,cAAa,EAAG;AACnB,MAAA,OAAO,KAAK,IAAA,EAAK;AAAA,IACnB;AACA,IAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAS,QAAA,EAAU,IAAA,EAAM,YAAW,GAAI,IAAA;AAGtD,IAAA,IAAI,YAAA,CAAa,SAAS,UAAA,EAAY;AACpC,MAAA,MAAM,SAAS,UAAA,IAAc,SAAA;AAC7B,MAAA,MAAM,MAAA,GAAU,KAA6B,MAAA,IAAU,MAAA;AAEvD,MAAA,OAAO,KAAA,CAAM,CAAA,kBAAA,EAAqB,MAAM,CAAA,CAAA,EAAI,OAAO,GAAA,KAAsB;AACvE,QAAA,MAAM,KAAA,GAAQ,uBAAA;AAAA,UACZ,MAAA;AAAA,UACA,MAAA;AAAA,UACA,IAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,GAAA,CAAI,cAAc,KAAkD,CAAA;AAGpE,QAAA,IAAI,QAAQ,gBAAA,EAAkB;AAC5B,UAAA,MAAM,WAAA,GAAc,OAAO,gBAAA,CAAiB;AAAA,YAC1C,IAAA,EAAM,UAAA;AAAA,YACN,IAAA,EAAM,MAAA;AAAA,YACN,IAAA,EAAM;AAAA,WACP,CAAA;AACD,UAAA,GAAA,CAAI,aAAA;AAAA,YACF;AAAA,WACF;AAAA,QACF;AAEA,QAAA,IAAI;AACF,UAAA,MAAM,MAAA,GAAS,MAAM,IAAA,EAAK;AAG1B,UAAA,IAAI,YAAA,CAAa,cAAA,IAAkB,MAAA,KAAW,KAAA,CAAA,EAAW;AACvD,YAAA,IAAI;AACF,cAAA,GAAA,CAAI,YAAA;AAAA,gBACF,eAAA,CAAgB,yBAAA;AAAA,gBAChB,IAAA,CAAK,UAAU,MAAM;AAAA,eACvB;AAAA,YACF,CAAA,CAAA,MAAQ;AACN,cAAA,GAAA,CAAI,YAAA;AAAA,gBACF,eAAA,CAAgB,yBAAA;AAAA,gBAChB;AAAA,eACF;AAAA,YACF;AAAA,UACF;AAEA,UAAA,GAAA,CAAI,SAAA,CAAU,EAAE,IAAA,EAAM,cAAA,CAAe,IAAI,CAAA;AACzC,UAAA,OAAO,MAAA;AAAA,QACT,SAAS,KAAA,EAAO;AACd,UAAA,IAAI,aAAa,aAAA,EAAe;AAC9B,YAAA,GAAA,CAAI,gBAAgB,KAAc,CAAA;AAClC,YAAA,GAAA,CAAI,SAAA,CAAU;AAAA,cACZ,MAAM,cAAA,CAAe,KAAA;AAAA,cACrB,SAAU,KAAA,CAAgB;AAAA,aAC3B,CAAA;AAGD,YAAA,IAAI;AACF,cAAA,MAAM,EAAE,WAAA,EAAY,GAAI,MAAM,OAAO,sBAAmB,CAAA;AACxD,cAAA,WAAA,CAAY,KAAA,EAAgB;AAAA,gBAC1B,IAAA,EAAM,UAAA;AAAA,gBACN,IAAA,EAAM,MAAA;AAAA,gBACN;AAAA,eACD,CAAA;AAAA,YACH,CAAA,CAAA,MAAQ;AAAA,YAER;AAAA,UACF;AACA,UAAA,MAAM,KAAA;AAAA,QACR;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAGA,IAAA,IAAI,CAAC,OAAA,EAAS;AAEZ,MAAA,OAAO,IAAA,EAAK;AAAA,IACd;AAEA,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAG/B,IAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,QAAA,EAAU,YAAA,CAAa,YAAY,CAAA,EAAG;AAC9D,MAAA,OAAO,IAAA,EAAK;AAAA,IACd;AAGA,IAAA,MAAM,aAAA,GAAgB,0BAA0B,OAAO,CAAA;AAGvD,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,aAAA,EAAe,YAAY;AAC7C,MAAA,MAAM,WAAW,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,QAAA,IAAY,IAAI,QAAQ,CAAA,CAAA;AAE9D,MAAA,OAAO,KAAA,CAAM,QAAA,EAAU,OAAO,GAAA,KAAsB;AAClD,QAAA,MAAM,KAAA,GAAQ,sBAAA,CAAuB,OAAA,EAAS,YAAY,CAAA;AAC1D,QAAA,GAAA,CAAI,cAAc,KAAkD,CAAA;AAGpE,QAAA,IAAI,QAAQ,gBAAA,EAAkB;AAC5B,UAAA,MAAM,WAAA,GAAc,OAAO,gBAAA,CAAiB;AAAA,YAC1C,IAAA,EAAM,SAAA;AAAA,YACN,IAAA,EAAM,QAAA;AAAA,YACN;AAAA,WACD,CAAA;AACD,UAAA,GAAA,CAAI,aAAA;AAAA,YACF;AAAA,WACF;AAAA,QACF;AAEA,QAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,QAAA,IAAI;AACF,UAAA,MAAM,MAAA,GAAS,MAAM,IAAA,EAAK;AAE1B,UAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAC9B,UAAA,GAAA,CAAI,YAAA;AAAA,YACF,eAAA,CAAgB,4BAAA;AAAA,YAChB;AAAA,WACF;AAGA,UAAA,IAAI;AACF,YAAA,MAAM,EAAE,gBAAA,EAAiB,GAAI,MAAM,OAAO,cAAW,CAAA;AACrD,YAAA,gBAAA,CAAiB,YAAA,CAAa,UAAU,QAAQ,CAAA;AAAA,UAClD,CAAA,CAAA,MAAQ;AAAA,UAER;AAGA,UAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,YAAY,MAAA,EAAQ;AAC9D,YAAA,GAAA,CAAI,YAAA;AAAA,cACF,eAAA,CAAgB,yBAAA;AAAA,cACf,MAAA,CAA8B;AAAA,aACjC;AAAA,UACF;AAEA,UAAA,GAAA,CAAI,SAAA,CAAU,EAAE,IAAA,EAAM,cAAA,CAAe,IAAI,CAAA;AACzC,UAAA,OAAO,MAAA;AAAA,QACT,SAAS,KAAA,EAAO;AACd,UAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAC9B,UAAA,GAAA,CAAI,YAAA;AAAA,YACF,eAAA,CAAgB,4BAAA;AAAA,YAChB;AAAA,WACF;AAEA,UAAA,IAAI,aAAa,aAAA,EAAe;AAC9B,YAAA,GAAA,CAAI,gBAAgB,KAAc,CAAA;AAClC,YAAA,GAAA,CAAI,SAAA,CAAU;AAAA,cACZ,MAAM,cAAA,CAAe,KAAA;AAAA,cACrB,SAAU,KAAA,CAAgB;AAAA,aAC3B,CAAA;AAGD,YAAA,IAAI;AACF,cAAA,MAAM,EAAE,WAAA,EAAY,GAAI,MAAM,OAAO,sBAAmB,CAAA;AACxD,cAAA,WAAA,CAAY,KAAA,EAAgB;AAAA,gBAC1B,IAAA,EAAM,SAAA;AAAA,gBACN,QAAQ,OAAA,CAAQ,MAAA;AAAA,gBAChB,UAAU,GAAA,CAAI;AAAA,eACf,CAAA;AAAA,YACH,CAAA,CAAA,MAAQ;AAAA,YAER;AAAA,UACF;AACA,UAAA,MAAM,KAAA;AAAA,QACR;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH,CAAA;AACF;AAqBO,SAAS,kBACd,MAAA,EAC6B;AAC7B,EAAA,OAAO,uBAAA,CAAwB;AAAA,IAC7B,QAAA,EAAU,UAAA;AAAA,IACV,cAAA,EAAgB,CAAC,cAAA,EAAgB,YAAY,CAAA;AAAA,IAC7C,cAAc,CAAC,SAAA,EAAW,UAAA,EAAY,QAAA,EAAU,YAAY,QAAQ,CAAA;AAAA,IACpE,GAAG;AAAA,GACJ,CAAA;AACH;AAsBO,SAAS,0BACd,MAAA,EAC6B;AAC7B,EAAA,OAAO,uBAAA,CAAwB;AAAA,IAC7B,GAAG,MAAA;AAAA,IACH,IAAA,EAAM;AAAA,GACP,CAAA;AACH","file":"chunk-OLBHLVLE.js","sourcesContent":["import { context, SpanStatusCode, type Attributes } from '@opentelemetry/api';\nimport { trace, type TraceContext } from 'autotel';\nimport { extractContextFromRequest } from './context';\nimport { isServerSide } from './env';\nimport {\n type TracingMiddlewareConfig,\n DEFAULT_CONFIG,\n SPAN_ATTRIBUTES,\n} from './types';\n\n/**\n * Check if a path should be excluded from tracing\n */\nfunction shouldExcludePath(\n pathname: string,\n excludePaths: (string | RegExp)[],\n): boolean {\n for (const pattern of excludePaths) {\n if (typeof pattern === 'string') {\n // Simple glob matching\n if (pattern.includes('*')) {\n const regex = new RegExp(\n '^' + pattern.replaceAll('*', '.*').replaceAll('?', '.') + '$',\n );\n if (regex.test(pathname)) return true;\n } else {\n if (pathname === pattern || pathname.startsWith(pattern)) return true;\n }\n } else {\n if (pattern.test(pathname)) return true;\n }\n }\n return false;\n}\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 ctx.recordException(error as Error);\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\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 (shouldExcludePath(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 ctx.recordException(error as Error);\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\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"]}