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 +101 -137
- package/dist/auto.js +1 -1
- package/dist/browser/context.d.ts +48 -0
- package/dist/browser/debug-headers.d.ts +16 -0
- package/dist/browser/error-reporting.d.ts +37 -0
- package/dist/browser/handlers.d.ts +19 -0
- package/dist/browser/index.d.ts +10 -0
- package/dist/browser/index.js +1 -1
- package/dist/browser/loaders.d.ts +36 -0
- package/dist/browser/metrics.d.ts +54 -0
- package/dist/browser/middleware.d.ts +47 -0
- package/dist/browser/middleware.js +1 -1
- package/dist/browser/server-functions.d.ts +19 -0
- package/dist/browser/testing.d.ts +45 -0
- package/dist/browser/types.d.ts +85 -0
- 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 +1 -1
- 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';
|
|
@@ -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';
|
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';
|
|
@@ -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-
|
|
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-
|
|
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
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"]}
|