autotel-tanstack 1.4.0 → 1.4.2
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 +101 -137
- package/dist/auto.js +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/middleware.js +1 -1
- package/dist/{chunk-4C7T5ZIM.js → chunk-A7WMQ2BC.js} +8 -3
- package/dist/chunk-A7WMQ2BC.js.map +1 -0
- package/dist/{chunk-OLBHLVLE.js → chunk-ETD6SGPH.js} +9 -3
- package/dist/chunk-ETD6SGPH.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/middleware.d.ts +48 -1
- package/dist/middleware.js +1 -1
- package/package.json +2 -2
- package/src/browser/index.ts +1 -0
- package/src/browser/middleware.ts +16 -0
- package/src/index.ts +1 -0
- package/src/middleware.ts +57 -0
- package/dist/chunk-4C7T5ZIM.js.map +0 -1
- package/dist/chunk-OLBHLVLE.js.map +0 -1
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
|
-
- **
|
|
8
|
-
- **
|
|
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
|
-
###
|
|
24
|
+
### TanStack-Native Setup (Recommended)
|
|
25
|
+
|
|
26
|
+
Configure global middleware in `start.ts` using TanStack's native patterns:
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
|
-
//
|
|
30
|
-
import '
|
|
31
|
-
import {
|
|
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
|
-
//
|
|
34
|
-
|
|
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
|
-
|
|
50
|
+
export const startInstance = createStart(() => ({
|
|
51
|
+
requestMiddleware: [requestTracingMiddleware],
|
|
52
|
+
functionMiddleware: [functionTracingMiddleware],
|
|
53
|
+
}));
|
|
54
|
+
```
|
|
38
55
|
|
|
39
56
|
```typescript
|
|
40
|
-
//
|
|
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:
|
|
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
|
-
|
|
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
|
-
//
|
|
61
|
-
import
|
|
62
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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
|
-
###
|
|
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
|
-
//
|
|
83
|
-
export const getUser = createServerFn({ method: 'GET' })
|
|
84
|
-
|
|
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
|
-
|
|
90
|
-
import { traceServerFn } from 'autotel-tanstack/server-functions';
|
|
104
|
+
### Per-Function Middleware (When Needed)
|
|
91
105
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|
121
|
+
export const sensitiveOperation = createServerFn({ method: 'POST' })
|
|
122
|
+
.middleware([customTracing])
|
|
123
|
+
.handler(async ({ data }) => {
|
|
124
|
+
// ...
|
|
125
|
+
});
|
|
99
126
|
```
|
|
100
127
|
|
|
101
|
-
###
|
|
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
|
-
###
|
|
150
|
+
### createTracingServerHandler Options
|
|
140
151
|
|
|
141
152
|
```typescript
|
|
142
|
-
import {
|
|
153
|
+
import { createTracingServerHandler } from 'autotel-tanstack/middleware';
|
|
143
154
|
|
|
144
|
-
const
|
|
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-
|
|
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';
|
package/dist/browser/index.js
CHANGED
|
@@ -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-
|
|
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';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { createTracingMiddleware, functionTracingMiddleware, tracingMiddleware } from '../chunk-
|
|
1
|
+
export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from '../chunk-A7WMQ2BC.js';
|
|
2
2
|
//# sourceMappingURL=middleware.js.map
|
|
3
3
|
//# sourceMappingURL=middleware.js.map
|
|
@@ -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-
|
|
20
|
-
//# sourceMappingURL=chunk-
|
|
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-
|
|
220
|
-
//# sourceMappingURL=chunk-
|
|
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-
|
|
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';
|
package/dist/middleware.d.ts
CHANGED
|
@@ -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 };
|
package/dist/middleware.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createTracingMiddleware, functionTracingMiddleware, tracingMiddleware } from './chunk-
|
|
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.
|
|
3
|
+
"version": "1.4.2",
|
|
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",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"license": "MIT",
|
|
118
118
|
"dependencies": {
|
|
119
119
|
"@opentelemetry/api": "^1.9.0",
|
|
120
|
-
"autotel": "2.
|
|
120
|
+
"autotel": "2.11.0"
|
|
121
121
|
},
|
|
122
122
|
"peerDependencies": {
|
|
123
123
|
"@tanstack/react-start": "^1.139.14",
|
package/src/browser/index.ts
CHANGED
|
@@ -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
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":"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","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"]}
|