autotel-tanstack 1.13.35 → 1.13.36
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/package.json +4 -5
- package/src/auto.test.ts +0 -114
- package/src/auto.ts +0 -60
- package/src/browser/context.ts +0 -88
- package/src/browser/debug-headers.ts +0 -19
- package/src/browser/error-reporting.ts +0 -64
- package/src/browser/handlers.ts +0 -23
- package/src/browser/index.ts +0 -66
- package/src/browser/loaders.ts +0 -62
- package/src/browser/metrics.ts +0 -86
- package/src/browser/middleware.ts +0 -77
- package/src/browser/server-functions.ts +0 -31
- package/src/browser/testing.ts +0 -130
- package/src/browser/types.ts +0 -100
- package/src/context.test.ts +0 -90
- package/src/context.ts +0 -145
- package/src/debug-headers.ts +0 -109
- package/src/env.ts +0 -56
- package/src/error-reporting.ts +0 -204
- package/src/handlers.ts +0 -306
- package/src/index.ts +0 -97
- package/src/instrument.test.ts +0 -131
- package/src/instrument.ts +0 -97
- package/src/loaders.test.ts +0 -123
- package/src/loaders.ts +0 -356
- package/src/metrics.ts +0 -184
- package/src/middleware.test.ts +0 -198
- package/src/middleware.ts +0 -435
- package/src/route-filter.test.ts +0 -28
- package/src/route-filter.ts +0 -40
- package/src/server-functions.test.ts +0 -86
- package/src/server-functions.ts +0 -188
- package/src/testing.test.ts +0 -205
- package/src/testing.ts +0 -430
- package/src/types.test.ts +0 -46
- package/src/types.ts +0 -182
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser stub for server-functions module
|
|
3
|
-
*
|
|
4
|
-
* In browser environments, these functions are no-ops that just return
|
|
5
|
-
* the original functions without any tracing overhead.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { TraceServerFnConfig } from './types';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Browser stub: Returns the server function unchanged
|
|
12
|
-
*/
|
|
13
|
-
export function traceServerFn<
|
|
14
|
-
T extends (...args: unknown[]) => Promise<unknown>,
|
|
15
|
-
>(serverFn: T, config?: TraceServerFnConfig): T {
|
|
16
|
-
void config;
|
|
17
|
-
return serverFn;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Browser stub: Returns the createServerFn unchanged
|
|
22
|
-
*/
|
|
23
|
-
export function createTracedServerFnFactory<
|
|
24
|
-
TCreateServerFn extends (...args: unknown[]) => unknown,
|
|
25
|
-
>(
|
|
26
|
-
createServerFnOriginal: TCreateServerFn,
|
|
27
|
-
defaultConfig?: Omit<TraceServerFnConfig, 'name'>,
|
|
28
|
-
): TCreateServerFn {
|
|
29
|
-
void defaultConfig;
|
|
30
|
-
return createServerFnOriginal;
|
|
31
|
-
}
|
package/src/browser/testing.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
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
|
-
/**
|
|
9
|
-
* Test span structure (stub)
|
|
10
|
-
*/
|
|
11
|
-
export interface TestSpan {
|
|
12
|
-
name: string;
|
|
13
|
-
attributes: Record<string, unknown>;
|
|
14
|
-
status: { code: number; message?: string };
|
|
15
|
-
events: Array<{ name: string; attributes?: Record<string, unknown> }>;
|
|
16
|
-
duration: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Test collector structure (stub)
|
|
21
|
-
*/
|
|
22
|
-
export interface TestCollector {
|
|
23
|
-
getSpans(): TestSpan[];
|
|
24
|
-
getSpansByName(name: string): TestSpan[];
|
|
25
|
-
clear(): void;
|
|
26
|
-
waitForSpans(count: number, timeout?: number): Promise<TestSpan[]>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Browser stub: Returns empty collector
|
|
31
|
-
*/
|
|
32
|
-
export function createTestCollector(): TestCollector {
|
|
33
|
-
return {
|
|
34
|
-
getSpans: () => [],
|
|
35
|
-
getSpansByName: () => [],
|
|
36
|
-
clear: () => {},
|
|
37
|
-
waitForSpans: async () => [],
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Browser stub: No-op
|
|
43
|
-
*/
|
|
44
|
-
export function assertSpanCreated(
|
|
45
|
-
collector: TestCollector,
|
|
46
|
-
name: string,
|
|
47
|
-
): void {
|
|
48
|
-
void collector;
|
|
49
|
-
void name;
|
|
50
|
-
// No-op in browser
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Browser stub: No-op
|
|
55
|
-
*/
|
|
56
|
-
export function assertSpanHasAttribute(
|
|
57
|
-
collector: TestCollector,
|
|
58
|
-
name: string,
|
|
59
|
-
key: string,
|
|
60
|
-
value?: unknown,
|
|
61
|
-
): void {
|
|
62
|
-
void collector;
|
|
63
|
-
void name;
|
|
64
|
-
void key;
|
|
65
|
-
void value;
|
|
66
|
-
// No-op in browser
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Serialized span type (browser stub - mirrors server SerializedSpan).
|
|
71
|
-
*
|
|
72
|
-
* Defined as a `type` (not `interface`) so it is assignable to
|
|
73
|
-
* `Record<string, unknown>` in TypeScript 6+ strict mode.
|
|
74
|
-
*/
|
|
75
|
-
export type SerializedSpan = {
|
|
76
|
-
name: string;
|
|
77
|
-
spanId: string;
|
|
78
|
-
traceId: string;
|
|
79
|
-
parentSpanId?: string;
|
|
80
|
-
attributes?: Record<string, unknown>;
|
|
81
|
-
status: { code: number; message?: string };
|
|
82
|
-
durationMs: number;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Accepts either a raw `Request` (legacy) or a TanStack Router context
|
|
87
|
-
* object containing `{ request: Request }` (Router 1.168+).
|
|
88
|
-
*/
|
|
89
|
-
type HandlerInput = Request | { request: Request };
|
|
90
|
-
|
|
91
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
-
type CreateFileRoute = (path: string) => (options: any) => any;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Browser stub: createTestSpansRoute is server-only.
|
|
96
|
-
*/
|
|
97
|
-
export function createTestSpansRoute(
|
|
98
|
-
createFileRoute: CreateFileRoute,
|
|
99
|
-
path?: string,
|
|
100
|
-
): unknown {
|
|
101
|
-
void createFileRoute;
|
|
102
|
-
void path;
|
|
103
|
-
throw new Error('createTestSpansRoute is server-only');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Browser stub: test-spans handlers are server-only.
|
|
108
|
-
* Returns no-op handlers that always return 404.
|
|
109
|
-
*/
|
|
110
|
-
export function createTestSpansHandlers(): {
|
|
111
|
-
GET: (input: HandlerInput) => Response;
|
|
112
|
-
DELETE: (input: HandlerInput) => Response;
|
|
113
|
-
} {
|
|
114
|
-
return {
|
|
115
|
-
GET(input: HandlerInput): Response {
|
|
116
|
-
void input;
|
|
117
|
-
return Response.json(
|
|
118
|
-
{ error: 'createTestSpansHandlers is server-only' },
|
|
119
|
-
{ status: 404 },
|
|
120
|
-
);
|
|
121
|
-
},
|
|
122
|
-
DELETE(input: HandlerInput): Response {
|
|
123
|
-
void input;
|
|
124
|
-
return Response.json(
|
|
125
|
-
{ error: 'createTestSpansHandlers is server-only' },
|
|
126
|
-
{ status: 404 },
|
|
127
|
-
);
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
}
|
package/src/browser/types.ts
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser stub for types module
|
|
3
|
-
*
|
|
4
|
-
* Provides type definitions without importing from @opentelemetry/api
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* OpenTelemetry-compatible Attributes type (browser stub)
|
|
9
|
-
*/
|
|
10
|
-
export type Attributes = Record<string, string | number | boolean | undefined>;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Configuration options for TanStack Start instrumentation
|
|
14
|
-
*/
|
|
15
|
-
export interface TanStackInstrumentationConfig {
|
|
16
|
-
service?: string;
|
|
17
|
-
captureArgs?: boolean;
|
|
18
|
-
captureResults?: boolean;
|
|
19
|
-
captureErrors?: boolean;
|
|
20
|
-
captureHeaders?: string[];
|
|
21
|
-
excludePaths?: (string | RegExp)[];
|
|
22
|
-
sampling?: 'always' | 'adaptive' | 'never';
|
|
23
|
-
customAttributes?: (context: {
|
|
24
|
-
type: 'request' | 'serverFn' | 'loader' | 'beforeLoad' | 'middleware';
|
|
25
|
-
name: string;
|
|
26
|
-
request?: Request;
|
|
27
|
-
args?: unknown;
|
|
28
|
-
result?: unknown;
|
|
29
|
-
}) => Attributes;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Configuration specific to tracing middleware
|
|
34
|
-
*/
|
|
35
|
-
export interface TracingMiddlewareConfig extends TanStackInstrumentationConfig {
|
|
36
|
-
type?: 'request' | 'function';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Configuration for server function tracing
|
|
41
|
-
*/
|
|
42
|
-
export interface TraceServerFnConfig {
|
|
43
|
-
name?: string;
|
|
44
|
-
captureArgs?: boolean;
|
|
45
|
-
captureResults?: boolean;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Configuration for loader tracing
|
|
50
|
-
*/
|
|
51
|
-
export interface TraceLoaderConfig {
|
|
52
|
-
name?: string;
|
|
53
|
-
captureParams?: boolean;
|
|
54
|
-
captureResult?: boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Configuration for handler wrapper
|
|
59
|
-
*/
|
|
60
|
-
export interface WrapStartHandlerConfig extends TanStackInstrumentationConfig {
|
|
61
|
-
endpoint?: string;
|
|
62
|
-
headers?: Record<string, string>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Default configuration values
|
|
67
|
-
*/
|
|
68
|
-
export const DEFAULT_CONFIG: Required<
|
|
69
|
-
Omit<TanStackInstrumentationConfig, 'customAttributes' | 'service'>
|
|
70
|
-
> = {
|
|
71
|
-
captureArgs: true,
|
|
72
|
-
captureResults: false,
|
|
73
|
-
captureErrors: true,
|
|
74
|
-
captureHeaders: ['x-request-id'],
|
|
75
|
-
excludePaths: [],
|
|
76
|
-
sampling: 'adaptive',
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Span attribute keys (stub - values are strings)
|
|
81
|
-
*/
|
|
82
|
-
export const SPAN_ATTRIBUTES = {
|
|
83
|
-
HTTP_REQUEST_METHOD: 'http.request.method',
|
|
84
|
-
HTTP_RESPONSE_STATUS_CODE: 'http.response.status_code',
|
|
85
|
-
URL_PATH: 'url.path',
|
|
86
|
-
URL_QUERY: 'url.query',
|
|
87
|
-
URL_FULL: 'url.full',
|
|
88
|
-
RPC_SYSTEM: 'rpc.system',
|
|
89
|
-
RPC_METHOD: 'rpc.method',
|
|
90
|
-
TANSTACK_TYPE: 'tanstack.type',
|
|
91
|
-
TANSTACK_SERVER_FN_NAME: 'tanstack.server_function.name',
|
|
92
|
-
TANSTACK_SERVER_FN_METHOD: 'tanstack.server_function.method',
|
|
93
|
-
TANSTACK_SERVER_FN_ARGS: 'tanstack.server_function.args',
|
|
94
|
-
TANSTACK_SERVER_FN_RESULT: 'tanstack.server_function.result',
|
|
95
|
-
TANSTACK_LOADER_ROUTE_ID: 'tanstack.loader.route_id',
|
|
96
|
-
TANSTACK_LOADER_TYPE: 'tanstack.loader.type',
|
|
97
|
-
TANSTACK_LOADER_PARAMS: 'tanstack.loader.params',
|
|
98
|
-
TANSTACK_MIDDLEWARE_NAME: 'tanstack.middleware.name',
|
|
99
|
-
TANSTACK_REQUEST_DURATION_MS: 'tanstack.request.duration_ms',
|
|
100
|
-
} as const;
|
package/src/context.test.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
extractContextFromRequest,
|
|
4
|
-
injectContextToHeaders,
|
|
5
|
-
createTracedHeaders,
|
|
6
|
-
} from './context';
|
|
7
|
-
|
|
8
|
-
describe('context', () => {
|
|
9
|
-
describe('extractContextFromRequest', () => {
|
|
10
|
-
it('should return context from request with traceparent header', () => {
|
|
11
|
-
const traceparent =
|
|
12
|
-
'00-12345678901234567890123456789012-1234567890123456-01';
|
|
13
|
-
const request = new Request('http://localhost/test', {
|
|
14
|
-
headers: { traceparent },
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const ctx = extractContextFromRequest(request);
|
|
18
|
-
expect(ctx).toBeDefined();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should handle request without trace headers', () => {
|
|
22
|
-
const request = new Request('http://localhost/test');
|
|
23
|
-
const ctx = extractContextFromRequest(request);
|
|
24
|
-
expect(ctx).toBeDefined(); // Should return ROOT_CONTEXT
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should extract tracestate if present', () => {
|
|
28
|
-
const request = new Request('http://localhost/test', {
|
|
29
|
-
headers: {
|
|
30
|
-
traceparent:
|
|
31
|
-
'00-12345678901234567890123456789012-1234567890123456-01',
|
|
32
|
-
tracestate: 'vendor=value',
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const ctx = extractContextFromRequest(request);
|
|
37
|
-
expect(ctx).toBeDefined();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should extract baggage if present', () => {
|
|
41
|
-
const request = new Request('http://localhost/test', {
|
|
42
|
-
headers: {
|
|
43
|
-
traceparent:
|
|
44
|
-
'00-12345678901234567890123456789012-1234567890123456-01',
|
|
45
|
-
baggage: 'userId=123,sessionId=abc',
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const ctx = extractContextFromRequest(request);
|
|
50
|
-
expect(ctx).toBeDefined();
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe('injectContextToHeaders', () => {
|
|
55
|
-
it('should inject context into headers', () => {
|
|
56
|
-
const headers = new Headers();
|
|
57
|
-
const result = injectContextToHeaders(headers);
|
|
58
|
-
expect(result).toBe(headers); // Returns same headers object
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should work with existing headers', () => {
|
|
62
|
-
const headers = new Headers({ 'Content-Type': 'application/json' });
|
|
63
|
-
injectContextToHeaders(headers);
|
|
64
|
-
expect(headers.get('Content-Type')).toBe('application/json');
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe('createTracedHeaders', () => {
|
|
69
|
-
it('should create headers with trace context', () => {
|
|
70
|
-
const headers = createTracedHeaders();
|
|
71
|
-
expect(headers).toBeInstanceOf(Headers);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('should include existing headers', () => {
|
|
75
|
-
const headers = createTracedHeaders({
|
|
76
|
-
'Content-Type': 'application/json',
|
|
77
|
-
});
|
|
78
|
-
expect(headers.get('Content-Type')).toBe('application/json');
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('should work with HeadersInit object', () => {
|
|
82
|
-
const headers = createTracedHeaders({
|
|
83
|
-
'Content-Type': 'application/json',
|
|
84
|
-
'X-Custom': 'value',
|
|
85
|
-
});
|
|
86
|
-
expect(headers.get('Content-Type')).toBe('application/json');
|
|
87
|
-
expect(headers.get('X-Custom')).toBe('value');
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
});
|
package/src/context.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
context,
|
|
3
|
-
propagation,
|
|
4
|
-
type Context,
|
|
5
|
-
ROOT_CONTEXT,
|
|
6
|
-
} from '@opentelemetry/api';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Type representing values that can be used to initialize Headers
|
|
10
|
-
* This is equivalent to the DOM's HeadersInit type but works in Node.js
|
|
11
|
-
*/
|
|
12
|
-
export type HeadersInitType =
|
|
13
|
-
| Headers
|
|
14
|
-
| Record<string, string>
|
|
15
|
-
| [string, string][];
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Extract OpenTelemetry context from HTTP request headers
|
|
19
|
-
*
|
|
20
|
-
* This function extracts W3C Trace Context (traceparent, tracestate)
|
|
21
|
-
* and Baggage from request headers to enable distributed tracing.
|
|
22
|
-
*
|
|
23
|
-
* @param request - The incoming HTTP request
|
|
24
|
-
* @returns OpenTelemetry context with extracted trace information
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```typescript
|
|
28
|
-
* const parentContext = extractContextFromRequest(request);
|
|
29
|
-
* context.with(parentContext, async () => {
|
|
30
|
-
* // Spans created here will be children of the extracted context
|
|
31
|
-
* await trace('my-operation', async (ctx) => { ... });
|
|
32
|
-
* });
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export function extractContextFromRequest(request: Request): Context {
|
|
36
|
-
const carrier: Record<string, string> = {};
|
|
37
|
-
|
|
38
|
-
// Extract W3C Trace Context headers
|
|
39
|
-
const traceparent = request.headers.get('traceparent');
|
|
40
|
-
const tracestate = request.headers.get('tracestate');
|
|
41
|
-
const baggage = request.headers.get('baggage');
|
|
42
|
-
|
|
43
|
-
if (traceparent) carrier.traceparent = traceparent;
|
|
44
|
-
if (tracestate) carrier.tracestate = tracestate;
|
|
45
|
-
if (baggage) carrier.baggage = baggage;
|
|
46
|
-
|
|
47
|
-
// Return ROOT_CONTEXT if no trace headers present
|
|
48
|
-
if (Object.keys(carrier).length === 0) {
|
|
49
|
-
return ROOT_CONTEXT;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return propagation.extract(context.active(), carrier);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Inject OpenTelemetry context into HTTP headers
|
|
57
|
-
*
|
|
58
|
-
* This function injects W3C Trace Context (traceparent, tracestate)
|
|
59
|
-
* and Baggage into headers for outgoing requests.
|
|
60
|
-
*
|
|
61
|
-
* @param headers - Headers object to inject context into
|
|
62
|
-
* @param ctx - Optional context to inject (defaults to active context)
|
|
63
|
-
* @returns The headers object with injected trace context
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* ```typescript
|
|
67
|
-
* const headers = new Headers();
|
|
68
|
-
* injectContextToHeaders(headers);
|
|
69
|
-
*
|
|
70
|
-
* // Now use headers in outgoing fetch
|
|
71
|
-
* await fetch('https://api.example.com', { headers });
|
|
72
|
-
* ```
|
|
73
|
-
*/
|
|
74
|
-
export function injectContextToHeaders(
|
|
75
|
-
headers: Headers,
|
|
76
|
-
ctx?: Context,
|
|
77
|
-
): Headers {
|
|
78
|
-
const carrier: Record<string, string> = {};
|
|
79
|
-
propagation.inject(ctx ?? context.active(), carrier);
|
|
80
|
-
|
|
81
|
-
for (const [key, value] of Object.entries(carrier)) {
|
|
82
|
-
headers.set(key, value);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return headers;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Create a new Headers object with injected trace context
|
|
90
|
-
*
|
|
91
|
-
* Convenience function that creates a new Headers object
|
|
92
|
-
* with the current trace context already injected.
|
|
93
|
-
*
|
|
94
|
-
* @param existingHeaders - Optional existing headers to include
|
|
95
|
-
* @param ctx - Optional context to inject (defaults to active context)
|
|
96
|
-
* @returns New Headers object with trace context
|
|
97
|
-
*
|
|
98
|
-
* @example
|
|
99
|
-
* ```typescript
|
|
100
|
-
* const headers = createTracedHeaders({ 'Content-Type': 'application/json' });
|
|
101
|
-
* await fetch('https://api.example.com', {
|
|
102
|
-
* method: 'POST',
|
|
103
|
-
* headers,
|
|
104
|
-
* body: JSON.stringify(data),
|
|
105
|
-
* });
|
|
106
|
-
* ```
|
|
107
|
-
*/
|
|
108
|
-
export function createTracedHeaders(
|
|
109
|
-
existingHeaders?: HeadersInitType,
|
|
110
|
-
ctx?: Context,
|
|
111
|
-
): Headers {
|
|
112
|
-
const headers = new Headers(existingHeaders);
|
|
113
|
-
return injectContextToHeaders(headers, ctx);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Run a function within a specific OpenTelemetry context
|
|
118
|
-
*
|
|
119
|
-
* This is a convenience wrapper around context.with() that
|
|
120
|
-
* provides better TypeScript inference.
|
|
121
|
-
*
|
|
122
|
-
* @param parentContext - The context to run within
|
|
123
|
-
* @param fn - The function to execute
|
|
124
|
-
* @returns The result of the function
|
|
125
|
-
*
|
|
126
|
-
* @example
|
|
127
|
-
* ```typescript
|
|
128
|
-
* const parentContext = extractContextFromRequest(request);
|
|
129
|
-
* const result = await runInContext(parentContext, async () => {
|
|
130
|
-
* return await processRequest();
|
|
131
|
-
* });
|
|
132
|
-
* ```
|
|
133
|
-
*/
|
|
134
|
-
export function runInContext<T>(parentContext: Context, fn: () => T): T {
|
|
135
|
-
return context.with(parentContext, fn);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Get the current active context
|
|
140
|
-
*
|
|
141
|
-
* @returns The current active OpenTelemetry context
|
|
142
|
-
*/
|
|
143
|
-
export function getActiveContext(): Context {
|
|
144
|
-
return context.active();
|
|
145
|
-
}
|
package/src/debug-headers.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { isServerSide } from './env';
|
|
2
|
-
import type { MiddlewareHandler } from './middleware';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Configuration for debug headers middleware
|
|
6
|
-
*/
|
|
7
|
-
export interface DebugHeadersConfig {
|
|
8
|
-
/**
|
|
9
|
-
* Whether to enable debug headers
|
|
10
|
-
* @default process.env.NODE_ENV === 'development'
|
|
11
|
-
*/
|
|
12
|
-
enabled?: boolean;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Custom headers to add
|
|
16
|
-
*/
|
|
17
|
-
customHeaders?: Record<string, string | (() => string)>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Create middleware that adds debug headers to responses in development
|
|
22
|
-
*
|
|
23
|
-
* Adds helpful debug information to response headers:
|
|
24
|
-
* - X-Debug-Timestamp: Request timestamp
|
|
25
|
-
* - X-Debug-Node-Version: Node.js version
|
|
26
|
-
* - X-Debug-Uptime: Process uptime in seconds
|
|
27
|
-
* - X-Debug-Trace-Id: Current trace ID (if available)
|
|
28
|
-
*
|
|
29
|
-
* @param config - Configuration options
|
|
30
|
-
* @returns Middleware handler
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* ```typescript
|
|
34
|
-
* import { createStart } from '@tanstack/react-start';
|
|
35
|
-
* import { debugHeadersMiddleware } from 'autotel-tanstack/debug-headers';
|
|
36
|
-
*
|
|
37
|
-
* export const startInstance = createStart(() => ({
|
|
38
|
-
* requestMiddleware: [debugHeadersMiddleware()],
|
|
39
|
-
* }));
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
export function debugHeadersMiddleware(
|
|
43
|
-
config: DebugHeadersConfig = {},
|
|
44
|
-
): MiddlewareHandler {
|
|
45
|
-
// If we're in the browser, return a no-op middleware
|
|
46
|
-
if (!isServerSide()) {
|
|
47
|
-
return async function debugHeadersHandler(opts) {
|
|
48
|
-
return opts.next();
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const enabled =
|
|
53
|
-
config.enabled ??
|
|
54
|
-
(typeof process !== 'undefined' && process.env.NODE_ENV === 'development');
|
|
55
|
-
|
|
56
|
-
return async function debugHeadersHandler(opts) {
|
|
57
|
-
const { next, request } = opts;
|
|
58
|
-
|
|
59
|
-
if (!enabled || !request) {
|
|
60
|
-
return next();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const result = await next();
|
|
64
|
-
|
|
65
|
-
// Check if result is a Response
|
|
66
|
-
if (!(result instanceof Response)) {
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const response = result;
|
|
71
|
-
|
|
72
|
-
// Clone response to add headers (responses are immutable)
|
|
73
|
-
const newHeaders = new Headers(response.headers);
|
|
74
|
-
|
|
75
|
-
// Add standard debug headers
|
|
76
|
-
newHeaders.set('X-Debug-Timestamp', new Date().toISOString());
|
|
77
|
-
newHeaders.set('X-Debug-Node-Version', process.version);
|
|
78
|
-
newHeaders.set('X-Debug-Uptime', Math.floor(process.uptime()).toString());
|
|
79
|
-
|
|
80
|
-
// Add trace ID if available
|
|
81
|
-
try {
|
|
82
|
-
const { trace } = await import('@opentelemetry/api');
|
|
83
|
-
const activeSpan = trace.getActiveSpan();
|
|
84
|
-
if (activeSpan) {
|
|
85
|
-
const spanContext = activeSpan.spanContext();
|
|
86
|
-
if (spanContext.traceId) {
|
|
87
|
-
newHeaders.set('X-Debug-Trace-Id', spanContext.traceId);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
} catch {
|
|
91
|
-
// OpenTelemetry not available, skip trace ID
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Add custom headers
|
|
95
|
-
if (config.customHeaders) {
|
|
96
|
-
for (const [key, value] of Object.entries(config.customHeaders)) {
|
|
97
|
-
const headerValue = typeof value === 'function' ? value() : value;
|
|
98
|
-
newHeaders.set(`X-Debug-${key}`, headerValue);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Return new response with debug headers
|
|
103
|
-
return new Response(response.body, {
|
|
104
|
-
status: response.status,
|
|
105
|
-
statusText: response.statusText,
|
|
106
|
-
headers: newHeaders,
|
|
107
|
-
});
|
|
108
|
-
};
|
|
109
|
-
}
|
package/src/env.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Environment detection utilities
|
|
3
|
-
* Prevents server-only code from running in the browser
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Check if we're running in a browser environment
|
|
8
|
-
* Uses typeof checks to avoid TypeScript DOM type requirements
|
|
9
|
-
*/
|
|
10
|
-
export function isBrowser(): boolean {
|
|
11
|
-
return (
|
|
12
|
-
typeof globalThis !== 'undefined' &&
|
|
13
|
-
// @ts-expect-error - window may not exist in Node.js, that's the point
|
|
14
|
-
typeof globalThis.window !== 'undefined' &&
|
|
15
|
-
// @ts-expect-error - document may not exist in Node.js, that's the point
|
|
16
|
-
typeof globalThis.document !== 'undefined'
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Check if we're running in a Node.js environment
|
|
22
|
-
*/
|
|
23
|
-
export function isNode(): boolean {
|
|
24
|
-
return (
|
|
25
|
-
typeof process !== 'undefined' &&
|
|
26
|
-
typeof process.versions !== 'undefined' &&
|
|
27
|
-
typeof process.versions.node !== 'undefined'
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Check if we're in a server-side context
|
|
33
|
-
* In TanStack Start, middleware runs on the server, but router config
|
|
34
|
-
* might be evaluated on both sides during SSR
|
|
35
|
-
*/
|
|
36
|
-
export function isServerSide(): boolean {
|
|
37
|
-
// In TanStack Start, if we're in a request handler context, we're on the server
|
|
38
|
-
// Check for Node.js environment (server) and not browser
|
|
39
|
-
return isNode() && !isBrowser();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Safely check if a module is available (for optional dependencies)
|
|
44
|
-
*/
|
|
45
|
-
export function isModuleAvailable(moduleName: string): boolean {
|
|
46
|
-
try {
|
|
47
|
-
// This will only work in Node.js, not browser
|
|
48
|
-
if (typeof require !== 'undefined') {
|
|
49
|
-
require.resolve(moduleName);
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
} catch {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|