@glasstrace/sdk 0.20.0 → 0.20.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/dist/chunk-BT2OCXCG.js +178 -0
- package/dist/chunk-BT2OCXCG.js.map +1 -0
- package/dist/{chunk-F2TZRBEH.js → chunk-DO2YPMQ5.js} +9 -181
- package/dist/chunk-DO2YPMQ5.js.map +1 -0
- package/dist/{chunk-YPXW2TN3.js → chunk-IP4NMDJK.js} +2 -2
- package/dist/{chunk-VN3GZDV6.js → chunk-IQN6TRMQ.js} +2 -2
- package/dist/{chunk-6JRI4OGB.js → chunk-LU3PPAOQ.js} +5 -3
- package/dist/{chunk-6JRI4OGB.js.map → chunk-LU3PPAOQ.js.map} +1 -1
- package/dist/chunk-R4DAIPXD.js +4461 -0
- package/dist/chunk-R4DAIPXD.js.map +1 -0
- package/dist/{chunk-5N2IR4EO.js → chunk-TQ54WLCZ.js} +1 -1
- package/dist/{chunk-5N2IR4EO.js.map → chunk-TQ54WLCZ.js.map} +1 -1
- package/dist/chunk-Z2EGETTT.js +204 -0
- package/dist/chunk-Z2EGETTT.js.map +1 -0
- package/dist/cli/init.cjs +5 -3
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +8 -6
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +2 -2
- package/dist/cli/uninit.cjs +3 -1
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.js +2 -2
- package/dist/edge-entry-Ds2fNOeh.d.ts +157 -0
- package/dist/edge-entry-FJFKkeFF.d.cts +157 -0
- package/dist/edge-entry.cjs +14939 -0
- package/dist/edge-entry.cjs.map +1 -0
- package/dist/edge-entry.d.cts +6 -0
- package/dist/edge-entry.d.ts +6 -0
- package/dist/edge-entry.js +16 -0
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d-DgeH-pNJ.d.cts +191 -0
- package/dist/index.d-DgeH-pNJ.d.ts +191 -0
- package/dist/index.d.cts +9 -461
- package/dist/index.d.ts +9 -461
- package/dist/index.js +32 -4618
- package/dist/index.js.map +1 -1
- package/dist/node-entry.cjs +22492 -0
- package/dist/node-entry.cjs.map +1 -0
- package/dist/node-entry.d.cts +10 -0
- package/dist/node-entry.d.ts +10 -0
- package/dist/node-entry.js +101 -0
- package/dist/node-entry.js.map +1 -0
- package/dist/node-subpath.cjs +14506 -0
- package/dist/node-subpath.cjs.map +1 -0
- package/dist/node-subpath.d.cts +132 -0
- package/dist/node-subpath.d.ts +132 -0
- package/dist/node-subpath.js +30 -0
- package/dist/node-subpath.js.map +1 -0
- package/dist/{source-map-uploader-VPDZWWM2.js → source-map-uploader-YXWO6JLN.js} +3 -3
- package/dist/source-map-uploader-YXWO6JLN.js.map +1 -0
- package/package.json +4 -1
- package/dist/chunk-F2TZRBEH.js.map +0 -1
- /package/dist/{chunk-YPXW2TN3.js.map → chunk-IP4NMDJK.js.map} +0 -0
- /package/dist/{chunk-VN3GZDV6.js.map → chunk-IQN6TRMQ.js.map} +0 -0
- /package/dist/{source-map-uploader-VPDZWWM2.js.map → edge-entry.js.map} +0 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import {
|
|
2
|
+
trace
|
|
3
|
+
} from "./chunk-DQ25VOKK.js";
|
|
4
|
+
import {
|
|
5
|
+
GLASSTRACE_ATTRIBUTE_NAMES
|
|
6
|
+
} from "./chunk-TQ54WLCZ.js";
|
|
7
|
+
|
|
8
|
+
// src/errors.ts
|
|
9
|
+
var SdkError = class extends Error {
|
|
10
|
+
code;
|
|
11
|
+
constructor(code, message, cause) {
|
|
12
|
+
super(message, { cause });
|
|
13
|
+
this.name = "SdkError";
|
|
14
|
+
this.code = code;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/span-processor.ts
|
|
19
|
+
var GlasstraceSpanProcessor = class {
|
|
20
|
+
wrappedProcessor;
|
|
21
|
+
/* eslint-disable @typescript-eslint/no-unused-vars -- backward compat signature */
|
|
22
|
+
constructor(wrappedProcessor, _sessionManager, _apiKey, _getConfig, _environment) {
|
|
23
|
+
this.wrappedProcessor = wrappedProcessor;
|
|
24
|
+
}
|
|
25
|
+
onStart(span, parentContext) {
|
|
26
|
+
this.wrappedProcessor.onStart(span, parentContext);
|
|
27
|
+
}
|
|
28
|
+
onEnd(readableSpan) {
|
|
29
|
+
this.wrappedProcessor.onEnd(readableSpan);
|
|
30
|
+
}
|
|
31
|
+
async shutdown() {
|
|
32
|
+
return this.wrappedProcessor.shutdown();
|
|
33
|
+
}
|
|
34
|
+
async forceFlush() {
|
|
35
|
+
return this.wrappedProcessor.forceFlush();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/discovery-endpoint.ts
|
|
40
|
+
var runtimeHandlerDeprecationWarned = false;
|
|
41
|
+
function warnRuntimeHandlerDeprecatedOnce() {
|
|
42
|
+
if (runtimeHandlerDeprecationWarned) return;
|
|
43
|
+
runtimeHandlerDeprecationWarned = true;
|
|
44
|
+
console.warn(
|
|
45
|
+
"[glasstrace] createDiscoveryHandler is deprecated. Run `npx glasstrace init` to generate a static file at public/.well-known/glasstrace.json (or static/.well-known/glasstrace.json on SvelteKit). The runtime handler will be removed in v1.0.0."
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
function isAllowedOrigin(origin) {
|
|
49
|
+
if (origin === null) return true;
|
|
50
|
+
if (origin.startsWith("chrome-extension://")) return true;
|
|
51
|
+
if (origin.startsWith("moz-extension://")) return true;
|
|
52
|
+
if (origin.startsWith("safari-web-extension://")) return true;
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
function buildCorsHeaders(origin) {
|
|
56
|
+
const headers = {
|
|
57
|
+
"Content-Type": "application/json",
|
|
58
|
+
Vary: "Origin"
|
|
59
|
+
};
|
|
60
|
+
if (origin && isAllowedOrigin(origin)) {
|
|
61
|
+
headers["Access-Control-Allow-Origin"] = origin;
|
|
62
|
+
}
|
|
63
|
+
return headers;
|
|
64
|
+
}
|
|
65
|
+
function createDiscoveryHandler(getAnonKey, getSessionId, getClaimState) {
|
|
66
|
+
return async (request) => {
|
|
67
|
+
let url;
|
|
68
|
+
try {
|
|
69
|
+
url = new URL(request.url);
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
if (url.pathname !== "/__glasstrace/config") {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
warnRuntimeHandlerDeprecatedOnce();
|
|
77
|
+
const origin = request.headers.get("Origin");
|
|
78
|
+
const corsHeaders = buildCorsHeaders(origin);
|
|
79
|
+
if (request.method === "OPTIONS") {
|
|
80
|
+
return new Response(null, {
|
|
81
|
+
status: 204,
|
|
82
|
+
headers: {
|
|
83
|
+
...corsHeaders,
|
|
84
|
+
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
|
85
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (request.method !== "GET") {
|
|
90
|
+
return new Response(
|
|
91
|
+
JSON.stringify({ error: "method_not_allowed" }),
|
|
92
|
+
{
|
|
93
|
+
status: 405,
|
|
94
|
+
headers: corsHeaders
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const anonKey = await getAnonKey();
|
|
100
|
+
if (anonKey === null) {
|
|
101
|
+
return new Response(
|
|
102
|
+
JSON.stringify({ error: "not_ready" }),
|
|
103
|
+
{
|
|
104
|
+
status: 503,
|
|
105
|
+
headers: corsHeaders
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
const sessionId = getSessionId();
|
|
110
|
+
const responseBody = { key: anonKey, sessionId };
|
|
111
|
+
const claimState = getClaimState?.();
|
|
112
|
+
if (claimState?.claimed) {
|
|
113
|
+
responseBody.claimed = true;
|
|
114
|
+
if (claimState.accountHint) {
|
|
115
|
+
responseBody.accountHint = claimState.accountHint;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return new Response(
|
|
119
|
+
JSON.stringify(responseBody),
|
|
120
|
+
{
|
|
121
|
+
status: 200,
|
|
122
|
+
headers: corsHeaders
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
} catch {
|
|
126
|
+
return new Response(
|
|
127
|
+
JSON.stringify({ error: "internal_error" }),
|
|
128
|
+
{
|
|
129
|
+
status: 500,
|
|
130
|
+
headers: corsHeaders
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/correlation-id.ts
|
|
138
|
+
var ATTR = GLASSTRACE_ATTRIBUTE_NAMES;
|
|
139
|
+
var HEADER_NAME = "x-gt-cid";
|
|
140
|
+
var MAX_CID_LENGTH = 128;
|
|
141
|
+
function captureCorrelationId(req) {
|
|
142
|
+
try {
|
|
143
|
+
if (!req || !req.headers) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const value = readHeader(req.headers);
|
|
147
|
+
if (!value) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const span = trace.getActiveSpan();
|
|
151
|
+
if (!span) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
span.setAttribute(ATTR.CORRELATION_ID, value);
|
|
155
|
+
} catch {
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function readHeader(headers) {
|
|
159
|
+
const asFetch = headers;
|
|
160
|
+
if (typeof asFetch.get === "function") {
|
|
161
|
+
const raw = asFetch.get(HEADER_NAME);
|
|
162
|
+
return firstToken(raw);
|
|
163
|
+
}
|
|
164
|
+
const dict = headers;
|
|
165
|
+
const direct = dict[HEADER_NAME];
|
|
166
|
+
if (direct !== void 0) {
|
|
167
|
+
return firstValue(direct);
|
|
168
|
+
}
|
|
169
|
+
for (const key of Object.keys(dict)) {
|
|
170
|
+
if (key.toLowerCase() === HEADER_NAME) {
|
|
171
|
+
return firstValue(dict[key]);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return void 0;
|
|
175
|
+
}
|
|
176
|
+
function firstValue(value) {
|
|
177
|
+
if (Array.isArray(value)) {
|
|
178
|
+
for (const entry of value) {
|
|
179
|
+
const token = firstToken(entry);
|
|
180
|
+
if (token) return token;
|
|
181
|
+
}
|
|
182
|
+
return void 0;
|
|
183
|
+
}
|
|
184
|
+
return firstToken(value);
|
|
185
|
+
}
|
|
186
|
+
function firstToken(value) {
|
|
187
|
+
if (typeof value !== "string") return void 0;
|
|
188
|
+
const parts = value.split(",");
|
|
189
|
+
for (const part of parts) {
|
|
190
|
+
const trimmed = part.trim();
|
|
191
|
+
if (trimmed.length === 0) continue;
|
|
192
|
+
if (trimmed.length > MAX_CID_LENGTH) return void 0;
|
|
193
|
+
return trimmed;
|
|
194
|
+
}
|
|
195
|
+
return void 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export {
|
|
199
|
+
SdkError,
|
|
200
|
+
GlasstraceSpanProcessor,
|
|
201
|
+
createDiscoveryHandler,
|
|
202
|
+
captureCorrelationId
|
|
203
|
+
};
|
|
204
|
+
//# sourceMappingURL=chunk-Z2EGETTT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/span-processor.ts","../src/discovery-endpoint.ts","../src/correlation-id.ts"],"sourcesContent":["import type { SdkDiagnosticCode } from \"@glasstrace/protocol\";\n\n/**\n * Internal SDK error class with a typed diagnostic code.\n * Caught at the boundary and converted to a log message + diagnostic entry.\n * Never thrown to the developer.\n */\nexport class SdkError extends Error {\n readonly code: SdkDiagnosticCode;\n\n constructor(code: SdkDiagnosticCode, message: string, cause?: Error) {\n super(message, { cause });\n this.name = \"SdkError\";\n this.code = code;\n }\n}\n","import type { SpanProcessor, ReadableSpan } from \"@opentelemetry/sdk-trace-base\";\nimport type { Span } from \"@opentelemetry/sdk-trace-base\";\nimport type { CaptureConfig } from \"@glasstrace/protocol\";\nimport type { SessionManager } from \"./session.js\";\n\n/**\n * Lightweight SpanProcessor that delegates to a wrapped processor.\n *\n * All glasstrace.* attribute enrichment has been moved to {@link GlasstraceExporter}\n * (see enriching-exporter.ts), which enriches spans at export time. This resolves:\n * - Cold-start spans are buffered in the exporter, not dropped\n * - Vercel's CompositeSpanProcessor skips onEnding(); the exporter doesn't need it\n * - Session ID is computed at export time with the resolved API key\n *\n * This class is retained for backward compatibility. New code should use\n * GlasstraceExporter directly.\n *\n * @deprecated Use GlasstraceExporter for span enrichment. This processor is now a pass-through.\n */\nexport class GlasstraceSpanProcessor implements SpanProcessor {\n private readonly wrappedProcessor: SpanProcessor;\n\n /* eslint-disable @typescript-eslint/no-unused-vars -- backward compat signature */\n constructor(\n wrappedProcessor: SpanProcessor,\n _sessionManager?: SessionManager,\n _apiKey?: string | (() => string),\n _getConfig?: () => CaptureConfig,\n _environment?: string,\n ) {\n /* eslint-enable @typescript-eslint/no-unused-vars */\n this.wrappedProcessor = wrappedProcessor;\n }\n\n onStart(span: Span, parentContext: Parameters<SpanProcessor[\"onStart\"]>[1]): void {\n this.wrappedProcessor.onStart(span, parentContext);\n }\n\n onEnd(readableSpan: ReadableSpan): void {\n this.wrappedProcessor.onEnd(readableSpan);\n }\n\n async shutdown(): Promise<void> {\n return this.wrappedProcessor.shutdown();\n }\n\n async forceFlush(): Promise<void> {\n return this.wrappedProcessor.forceFlush();\n }\n}\n","import type { AnonApiKey, SessionId } from \"@glasstrace/protocol\";\n\n/**\n * Tracks whether the runtime-handler deprecation warning has already been\n * emitted for this process. The warning is noisy by design (we want users\n * to migrate) but should fire exactly once per process — repeated logs on\n * every request would drown out real warnings and spam CI output.\n */\nlet runtimeHandlerDeprecationWarned = false;\n\n/**\n * @internal Reset the deprecation-warning flag. Test-only.\n */\nexport function _resetDiscoveryDeprecationWarningForTesting(): void {\n runtimeHandlerDeprecationWarned = false;\n}\n\n/**\n * Emits a one-time `console.warn` explaining that the runtime discovery\n * handler has been superseded by the static file written by `sdk init`.\n *\n * Scheduled for removal in v1.0.0 per the deprecation timeline documented\n * in the \"SDK Discovery Endpoint / Static File\" design doc. Kept out of\n * the module top level so bundlers can tree-shake the warning path when\n * the handler itself is not imported.\n *\n * The `[glasstrace]` prefix matches the SDK-internal log convention so\n * console capture (see `console-capture.ts`) skips the warning rather\n * than recording it as a user-facing span event.\n */\nfunction warnRuntimeHandlerDeprecatedOnce(): void {\n if (runtimeHandlerDeprecationWarned) return;\n runtimeHandlerDeprecationWarned = true;\n console.warn(\n \"[glasstrace] createDiscoveryHandler is deprecated. \" +\n \"Run `npx glasstrace init` to generate a static file at \" +\n \"public/.well-known/glasstrace.json (or static/.well-known/glasstrace.json \" +\n \"on SvelteKit). The runtime handler will be removed in v1.0.0.\",\n );\n}\n\n/**\n * Checks whether the given Origin header is allowed for CORS access.\n *\n * Allowed origins:\n * - `chrome-extension://*` — any Chrome extension\n * - `moz-extension://*` — any Firefox extension\n * - `safari-web-extension://*` — any Safari extension\n * - Absent origin (same-origin / non-browser request)\n *\n * Replaced wildcard `*` to prevent arbitrary websites from\n * reading the anonymous API key from localhost.\n */\nfunction isAllowedOrigin(origin: string | null): boolean {\n if (origin === null) return true;\n if (origin.startsWith(\"chrome-extension://\")) return true;\n if (origin.startsWith(\"moz-extension://\")) return true;\n if (origin.startsWith(\"safari-web-extension://\")) return true;\n return false;\n}\n\n/**\n * Builds CORS headers for a given request origin.\n * Returns headers with `Access-Control-Allow-Origin` set to the origin\n * if allowed, otherwise omits that header entirely.\n */\nfunction buildCorsHeaders(origin: string | null): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Vary: \"Origin\",\n };\n\n if (origin && isAllowedOrigin(origin)) {\n headers[\"Access-Control-Allow-Origin\"] = origin;\n }\n\n return headers;\n}\n\n/**\n * Claim state returned by the `getClaimState` callback.\n *\n * - `claimed` — `true` when the anonymous key has been linked to an account.\n * - `accountHint` — optional masked identifier (e.g. `\"er***@example.com\"`)\n * for the browser extension to display to the user.\n */\nexport interface ClaimState {\n claimed: boolean;\n accountHint?: string;\n}\n\n/**\n * Creates a request handler for the `/__glasstrace/config` discovery endpoint.\n *\n * The returned handler checks if the request URL path is `/__glasstrace/config`.\n * If not, returns `null` (pass-through). If it matches, returns a `DiscoveryResponse`\n * with the anonymous key and current session ID.\n *\n * When `getClaimState` returns a non-null value with `claimed: true`, the\n * response includes `claimed` and (optionally) `accountHint` so the browser\n * extension can prompt the user to sign in.\n *\n * The triple guard (anonymous + dev + active) is enforced by the caller,\n * not by this module. If the handler is registered, it serves.\n */\nexport function createDiscoveryHandler(\n getAnonKey: () => Promise<AnonApiKey | null>,\n getSessionId: () => SessionId,\n getClaimState?: () => ClaimState | null,\n): (request: Request) => Promise<Response | null> {\n return async (request: Request): Promise<Response | null> => {\n // Check path match\n let url: URL;\n try {\n url = new URL(request.url);\n } catch {\n return null;\n }\n\n if (url.pathname !== \"/__glasstrace/config\") {\n return null;\n }\n\n // Fire the deprecation notice only when the handler actually serves a\n // Glasstrace-discovery request — non-matching paths pass through, so\n // warning there would spam users who never invoked the handler.\n warnRuntimeHandlerDeprecatedOnce();\n\n // Restrict CORS to known extension origins instead of wildcard\n const origin = request.headers.get(\"Origin\");\n const corsHeaders = buildCorsHeaders(origin);\n\n // Handle CORS preflight\n if (request.method === \"OPTIONS\") {\n return new Response(null, {\n status: 204,\n headers: {\n ...corsHeaders,\n \"Access-Control-Allow-Methods\": \"GET, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n },\n });\n }\n\n // Only allow GET requests\n if (request.method !== \"GET\") {\n return new Response(\n JSON.stringify({ error: \"method_not_allowed\" }),\n {\n status: 405,\n headers: corsHeaders,\n },\n );\n }\n\n try {\n // Get the anonymous key\n const anonKey = await getAnonKey();\n\n if (anonKey === null) {\n return new Response(\n JSON.stringify({ error: \"not_ready\" }),\n {\n status: 503,\n headers: corsHeaders,\n },\n );\n }\n\n // Get the current session ID\n const sessionId = getSessionId();\n\n // Build response body, conditionally including claim fields\n const responseBody: Record<string, unknown> = { key: anonKey, sessionId };\n const claimState = getClaimState?.();\n if (claimState?.claimed) {\n responseBody.claimed = true;\n if (claimState.accountHint) {\n responseBody.accountHint = claimState.accountHint;\n }\n }\n\n return new Response(\n JSON.stringify(responseBody),\n {\n status: 200,\n headers: corsHeaders,\n },\n );\n } catch {\n return new Response(\n JSON.stringify({ error: \"internal_error\" }),\n {\n status: 500,\n headers: corsHeaders,\n },\n );\n }\n };\n}\n\n// Exported for testing\nexport { isAllowedOrigin, buildCorsHeaders };\n","import { trace } from \"@opentelemetry/api\";\nimport { GLASSTRACE_ATTRIBUTE_NAMES } from \"@glasstrace/protocol\";\n\nconst ATTR = GLASSTRACE_ATTRIBUTE_NAMES;\nconst HEADER_NAME = \"x-gt-cid\";\n\n/**\n * Hard cap on the correlation ID length we accept from the wire. Our\n * own extension emits ULIDs (26 characters); 128 is a generous ceiling\n * that still prevents a hostile client from ballooning span payloads.\n */\nconst MAX_CID_LENGTH = 128;\n\n/**\n * Minimal Fetch-API `Headers`-like interface supporting case-insensitive\n * single-value lookup. Matches `Headers` from `undici` / the Web Fetch API.\n */\ninterface FetchHeadersLike {\n get(name: string): string | null;\n}\n\n/**\n * Minimal Node `IncomingMessage.headers`-like shape: a dictionary mapping\n * (typically lower-cased) header names to a value, a list of values, or\n * `undefined`.\n */\ntype NodeHeadersLike = Record<\n string,\n string | string[] | undefined\n>;\n\n/**\n * Accepted request shape for {@link captureCorrelationId}. Intentionally\n * loose so callers can pass either a Fetch `Request` (or `NextRequest`)\n * or a Node `IncomingMessage` without adapting the type.\n */\nexport interface CorrelationIdRequest {\n headers: FetchHeadersLike | NodeHeadersLike | undefined;\n}\n\n/**\n * Captures the Glasstrace correlation ID header (`x-gt-cid`) from an\n * incoming request and materializes it as the\n * `glasstrace.correlation.id` attribute on the currently active OTel span\n * (DISC-1253).\n *\n * The SDK does not own any HTTP instrumentation, so it cannot read this\n * header itself. Users opt in by calling this helper from a hook that\n * runs inside the request's OTel context — typically a Next.js\n * `middleware.ts` or a custom server request handler.\n *\n * The function is intentionally forgiving:\n * - No active span → no-op.\n * - Missing / empty header → no-op.\n * - Array header values (Node IncomingMessage) → the first non-empty\n * value is used; subsequent values are ignored because a correlation\n * ID is a single logical value.\n * - Malformed or unexpected `headers` shapes → caught and ignored; the\n * helper never throws.\n *\n * @example\n * ```ts\n * // Next.js middleware.ts\n * import { captureCorrelationId } from \"@glasstrace/sdk\";\n *\n * export function middleware(req: Request) {\n * captureCorrelationId(req);\n * return NextResponse.next();\n * }\n * ```\n */\nexport function captureCorrelationId(req: CorrelationIdRequest | null | undefined): void {\n try {\n if (!req || !req.headers) {\n return;\n }\n\n const value = readHeader(req.headers);\n if (!value) {\n return;\n }\n\n const span = trace.getActiveSpan();\n if (!span) {\n return;\n }\n\n span.setAttribute(ATTR.CORRELATION_ID, value);\n } catch {\n // Never throw from a request hook — correlation is a best-effort\n // enrichment and must not break the user's request pipeline.\n }\n}\n\n/**\n * Reads the `x-gt-cid` header from either a Fetch-API `Headers` object\n * or a Node-style dictionary. Returns a trimmed single value, or\n * `undefined` if the header is missing or empty.\n */\nfunction readHeader(\n headers: FetchHeadersLike | NodeHeadersLike,\n): string | undefined {\n // Fetch-API Headers: duck-type on `.get(name)` being a function.\n const asFetch = headers as FetchHeadersLike;\n if (typeof asFetch.get === \"function\") {\n const raw = asFetch.get(HEADER_NAME);\n return firstToken(raw);\n }\n\n // Node IncomingMessage headers: case-insensitive dictionary lookup.\n // Node normalizes to lower-case but some frameworks preserve case, so\n // scan keys defensively.\n const dict = headers as NodeHeadersLike;\n const direct = dict[HEADER_NAME];\n if (direct !== undefined) {\n return firstValue(direct);\n }\n\n for (const key of Object.keys(dict)) {\n if (key.toLowerCase() === HEADER_NAME) {\n return firstValue(dict[key]);\n }\n }\n\n return undefined;\n}\n\n/**\n * Picks the first value from a possibly-array header and trims it.\n * Correlation IDs are logically single-valued; when duplicated we keep\n * the first occurrence and drop the rest.\n *\n * Also handles the comma-joined form that intermediaries (and some\n * Node.js HTTP stacks) produce when the same header is sent multiple\n * times — `x-gt-cid: cid1, x-gt-cid: cid2` may surface as the single\n * string `\"cid1, cid2\"` via `Headers.get()` or `IncomingMessage.headers`.\n * Storing that raw merged value would both fail correlation and\n * silently suppress the DISC-1253 Server Action nudge (which only\n * checks attribute presence, not validity). We split on commas and\n * keep the first non-empty token.\n */\nfunction firstValue(value: string | string[] | undefined): string | undefined {\n if (Array.isArray(value)) {\n for (const entry of value) {\n const token = firstToken(entry);\n if (token) return token;\n }\n return undefined;\n }\n return firstToken(value);\n}\n\n/**\n * Extracts the first comma-separated token from a header-like string\n * and normalizes it. Returns undefined when no non-empty token exists\n * within the length bound.\n */\nfunction firstToken(value: string | null | undefined): string | undefined {\n if (typeof value !== \"string\") return undefined;\n // Split on commas (HTTP list-header separator). Trim each token and\n // return the first non-empty one that fits within MAX_CID_LENGTH.\n // A single un-merged header has no commas and this reduces to the\n // previous normalize() behavior.\n const parts = value.split(\",\");\n for (const part of parts) {\n const trimmed = part.trim();\n if (trimmed.length === 0) continue;\n if (trimmed.length > MAX_CID_LENGTH) return undefined;\n return trimmed;\n }\n return undefined;\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli/init.cjs
CHANGED
|
@@ -15985,7 +15985,8 @@ function isSvelteKitProject(projectRoot) {
|
|
|
15985
15985
|
return fs4.existsSync(svelteConfigJs) || fs4.existsSync(svelteConfigTs) || fs4.existsSync(appHtml);
|
|
15986
15986
|
}
|
|
15987
15987
|
function relativeDiscoveryPath(layout) {
|
|
15988
|
-
|
|
15988
|
+
const rootDir = layout === "static" ? "static" : "public";
|
|
15989
|
+
return `${rootDir}/${WELL_KNOWN_GLASSTRACE_PATH}`;
|
|
15989
15990
|
}
|
|
15990
15991
|
function readExistingDiscoveryFile(filePath) {
|
|
15991
15992
|
let raw;
|
|
@@ -16145,13 +16146,14 @@ function removeDiscoveryFile(projectRoot) {
|
|
|
16145
16146
|
directoryRemoved: chosen.directoryRemoved || anyDirectoryRemoved
|
|
16146
16147
|
};
|
|
16147
16148
|
}
|
|
16148
|
-
var fs4, path4, DISCOVERY_FILE_VERSION;
|
|
16149
|
+
var fs4, path4, WELL_KNOWN_GLASSTRACE_PATH, DISCOVERY_FILE_VERSION;
|
|
16149
16150
|
var init_discovery_file = __esm({
|
|
16150
16151
|
"src/cli/discovery-file.ts"() {
|
|
16151
16152
|
"use strict";
|
|
16152
16153
|
fs4 = __toESM(require("node:fs"), 1);
|
|
16153
16154
|
path4 = __toESM(require("node:path"), 1);
|
|
16154
16155
|
init_dist();
|
|
16156
|
+
WELL_KNOWN_GLASSTRACE_PATH = ".well-known/glasstrace.json";
|
|
16155
16157
|
DISCOVERY_FILE_VERSION = 1;
|
|
16156
16158
|
}
|
|
16157
16159
|
});
|
|
@@ -18490,7 +18492,7 @@ async function verifyAnonKeyRegistration(projectRoot) {
|
|
|
18490
18492
|
}
|
|
18491
18493
|
const baseConfig = resolveConfig({ apiKey: devKey });
|
|
18492
18494
|
const config2 = { ...baseConfig, apiKey: devKey };
|
|
18493
|
-
const sdkVersion = true ? "0.20.
|
|
18495
|
+
const sdkVersion = true ? "0.20.1" : "0.0.0-dev";
|
|
18494
18496
|
const result = await verifyInitReachable(config2, anonKey, sdkVersion);
|
|
18495
18497
|
if (result.ok) {
|
|
18496
18498
|
return { outcome: "verified" };
|