@glasstrace/sdk 1.3.9 → 1.5.0
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 +124 -0
- package/dist/capture-error-BmQz7xF6.d.cts +455 -0
- package/dist/capture-error-CTgSYxek.d.ts +455 -0
- package/dist/{chunk-XS5W3SPL.js → chunk-4WI7B5FQ.js} +91 -5
- package/dist/chunk-4WI7B5FQ.js.map +1 -0
- package/dist/{chunk-JZ475QRH.js → chunk-D3QXU2VM.js} +22 -191
- package/dist/chunk-D3QXU2VM.js.map +1 -0
- package/dist/{chunk-GYTCZSAV.js → chunk-MFYOQOD7.js} +2 -2
- package/dist/{chunk-4WUHMLMM.js → chunk-MMKFFF2L.js} +2 -2
- package/dist/{chunk-JH7EGRC5.js → chunk-N3XIVM2U.js} +158 -12
- package/dist/chunk-N3XIVM2U.js.map +1 -0
- package/dist/{chunk-FKBCEOJ5.js → chunk-Q42BY5BA.js} +2 -2
- package/dist/{chunk-DBKG6SRI.js → chunk-QU26IKIJ.js} +2 -2
- package/dist/{chunk-ADUD4PEK.js → chunk-TANUWTFO.js} +3 -3
- package/dist/{chunk-LJMZXJ45.js → chunk-YLY7AGLC.js} +9 -6
- package/dist/chunk-YLY7AGLC.js.map +1 -0
- package/dist/chunk-ZBQQXVHD.js +208 -0
- package/dist/chunk-ZBQQXVHD.js.map +1 -0
- package/dist/cli/init.cjs +218 -35
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +69 -12
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs +57 -26
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +12 -9
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/status.cjs +33 -3
- package/dist/cli/status.cjs.map +1 -1
- package/dist/cli/status.js +12 -3
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/uninit.cjs +27 -3
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.d.cts +10 -2
- package/dist/cli/uninit.d.ts +10 -2
- package/dist/cli/uninit.js +4 -3
- package/dist/cli/upgrade-instructions.cjs +440 -0
- package/dist/cli/upgrade-instructions.cjs.map +1 -0
- package/dist/cli/upgrade-instructions.d.cts +48 -0
- package/dist/cli/upgrade-instructions.d.ts +48 -0
- package/dist/cli/upgrade-instructions.js +80 -0
- package/dist/cli/upgrade-instructions.js.map +1 -0
- package/dist/cli/validate.cjs +12 -1
- package/dist/cli/validate.cjs.map +1 -1
- package/dist/cli/validate.js +2 -2
- package/dist/{edge-entry-BSKA1l_0.d.ts → edge-entry-AWO70gje.d.ts} +1 -1
- package/dist/{edge-entry-DyMWa6JK.d.cts → edge-entry-DaeG7D7S.d.cts} +1 -1
- package/dist/edge-entry.cjs +43 -2
- package/dist/edge-entry.cjs.map +1 -1
- package/dist/edge-entry.d.cts +2 -2
- package/dist/edge-entry.d.ts +2 -2
- package/dist/edge-entry.js +2 -2
- package/dist/index.cjs +594 -64
- package/dist/index.cjs.map +1 -1
- package/dist/{index.d-Bo_Rxund.d.cts → index.d-Dq33YwFT.d.cts} +91 -1
- package/dist/{index.d-Bo_Rxund.d.ts → index.d-Dq33YwFT.d.ts} +91 -1
- package/dist/index.d.cts +91 -431
- package/dist/index.d.ts +91 -431
- package/dist/index.js +291 -6
- package/dist/index.js.map +1 -1
- package/dist/node-entry.cjs +282 -71
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.d.cts +3 -3
- package/dist/node-entry.d.ts +3 -3
- package/dist/node-entry.js +8 -7
- package/dist/node-subpath.cjs +12 -1
- package/dist/node-subpath.cjs.map +1 -1
- package/dist/node-subpath.d.cts +1 -1
- package/dist/node-subpath.d.ts +1 -1
- package/dist/node-subpath.js +3 -3
- package/dist/{source-map-uploader-FSTHCYDR.js → source-map-uploader-PB3M4PPP.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-JH7EGRC5.js.map +0 -1
- package/dist/chunk-JZ475QRH.js.map +0 -1
- package/dist/chunk-LJMZXJ45.js.map +0 -1
- package/dist/chunk-XS5W3SPL.js.map +0 -1
- /package/dist/{chunk-GYTCZSAV.js.map → chunk-MFYOQOD7.js.map} +0 -0
- /package/dist/{chunk-4WUHMLMM.js.map → chunk-MMKFFF2L.js.map} +0 -0
- /package/dist/{chunk-FKBCEOJ5.js.map → chunk-Q42BY5BA.js.map} +0 -0
- /package/dist/{chunk-DBKG6SRI.js.map → chunk-QU26IKIJ.js.map} +0 -0
- /package/dist/{chunk-ADUD4PEK.js.map → chunk-TANUWTFO.js.map} +0 -0
- /package/dist/{source-map-uploader-FSTHCYDR.js.map → source-map-uploader-PB3M4PPP.js.map} +0 -0
package/README.md
CHANGED
|
@@ -98,6 +98,62 @@ total cap). HTTP 4xx/5xx and malformed responses are surfaced
|
|
|
98
98
|
immediately. Set `GLASSTRACE_SKIP_INIT_VERIFY=1` to skip verification
|
|
99
99
|
for offline installs.
|
|
100
100
|
|
|
101
|
+
## Refreshing agent instruction guidance
|
|
102
|
+
|
|
103
|
+
`glasstrace init` and `glasstrace mcp add` write a managed Glasstrace
|
|
104
|
+
MCP section into your project's agent instruction file (CLAUDE.md /
|
|
105
|
+
codex.md / .cursorrules). The section opens with a cost-aware
|
|
106
|
+
cross-tool decision paragraph telling your AI agent **when** Glasstrace
|
|
107
|
+
MCP is worth calling and **which** tool is the cheapest first call for
|
|
108
|
+
each symptom class.
|
|
109
|
+
|
|
110
|
+
The managed section's start marker carries an SDK version stamp, e.g.
|
|
111
|
+
`<!-- glasstrace:mcp:start v=1.5.0 -->`. When you upgrade
|
|
112
|
+
`@glasstrace/sdk`, run:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npx glasstrace upgrade-instructions
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The command refreshes every detected agent instruction file in one
|
|
119
|
+
run. Files outside the markers are untouched; files without a
|
|
120
|
+
Glasstrace managed section are left alone. The command is idempotent
|
|
121
|
+
— re-running produces byte-for-byte identical output.
|
|
122
|
+
|
|
123
|
+
`npx glasstrace mcp add` performs the same managed-section refresh
|
|
124
|
+
when run with `--force` (or against a project whose marker file has
|
|
125
|
+
shifted credentials), so either command is a valid upgrade path.
|
|
126
|
+
|
|
127
|
+
### Stale-section warning at SDK init
|
|
128
|
+
|
|
129
|
+
When the running SDK detects that an agent instruction file's stamp
|
|
130
|
+
is strictly older than the running version, it writes a single
|
|
131
|
+
stderr line at `registerGlasstrace()` time pointing at the upgrade
|
|
132
|
+
command. Constraints:
|
|
133
|
+
|
|
134
|
+
- Stderr only, never stdout. Tracing behaviour is unaffected.
|
|
135
|
+
- At most one warning per process boot, even when multiple
|
|
136
|
+
`registerGlasstrace()` calls happen (test runners, hot reload).
|
|
137
|
+
- Node-only — no-op on Edge / browser runtimes. Never throws.
|
|
138
|
+
- Does not mutate any file at runtime; the user opts in by running
|
|
139
|
+
the upgrade command.
|
|
140
|
+
- Suppressed by setting one of:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
GLASSTRACE_DISABLE_UPGRADE_NOTICE=1
|
|
144
|
+
GLASSTRACE_DISABLE_UPGRADE_NOTICE=true
|
|
145
|
+
GLASSTRACE_DISABLE_UPGRADE_NOTICE=yes
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
(case-insensitive). Any other value, including unset, leaves the
|
|
149
|
+
warning enabled.
|
|
150
|
+
|
|
151
|
+
Legacy unstamped managed sections (written by `@glasstrace/sdk`
|
|
152
|
+
versions before 1.5.0) trigger no warning — those projects receive
|
|
153
|
+
the refreshed text on their next `mcp add` or
|
|
154
|
+
`upgrade-instructions` run, and the upgrade replaces the legacy
|
|
155
|
+
block in place rather than appending a duplicate.
|
|
156
|
+
|
|
101
157
|
## Server Action detection (Next.js)
|
|
102
158
|
|
|
103
159
|
Next.js does not emit a dedicated OTel span for Server Actions. The SDK
|
|
@@ -293,6 +349,74 @@ body data. If your account enables the flag but a span never carries
|
|
|
293
349
|
the internal attribute (no adapter set it), the public attribute is
|
|
294
350
|
still absent. The default is "off, twice".
|
|
295
351
|
|
|
352
|
+
## Capturing side-effect evidence
|
|
353
|
+
|
|
354
|
+
When debugging a bug whose root cause is which side-effect operation
|
|
355
|
+
ran with which non-sensitive semantic value — "the cancellation email
|
|
356
|
+
used the wrong locale", "the wrong invite role was sent" — the agent
|
|
357
|
+
needs to know template key, role, locale, timezone, status, and phase,
|
|
358
|
+
but never the recipient, the rendered subject or body, the calendar
|
|
359
|
+
link, or any token that flowed through the operation. The SDK can
|
|
360
|
+
record allowlisted side-effect evidence on the active trace via
|
|
361
|
+
`recordSideEffect()`, gated by the `sideEffectEvidence` capture-config
|
|
362
|
+
flag.
|
|
363
|
+
|
|
364
|
+
What the SDK captures: a compact, normalized operation label, the
|
|
365
|
+
operation kind (`email`, `calendar_link`, `webhook`, `external_api`,
|
|
366
|
+
`queue`, `after_callback`), an optional lifecycle status
|
|
367
|
+
(`scheduled`, `started`, `succeeded`, `failed`, `unknown`), an
|
|
368
|
+
optional execution phase (`request`, `post_response`, `background`,
|
|
369
|
+
`unknown`), and a small set of allowlisted semantic fields:
|
|
370
|
+
`templateKey`, `providerOperation`, `role`, `locale`, `timezone`,
|
|
371
|
+
`status`, `phase`. Each value is bounded to compact tokens — IANA
|
|
372
|
+
timezones, BCP-47 locales, identifier-shaped enum tokens. The
|
|
373
|
+
per-trace operation budget is five.
|
|
374
|
+
|
|
375
|
+
What the SDK does not capture: recipient email addresses, sender or
|
|
376
|
+
recipient names, rendered email subjects or bodies, calendar links,
|
|
377
|
+
invite links, any URL with a query string or fragment, any
|
|
378
|
+
`Authorization`/`Cookie`/bearer-shaped value, any
|
|
379
|
+
password/token/api_key key-value pair, any UUID, any Glasstrace API
|
|
380
|
+
key, any free-form prose, and any structured payload. Values matching
|
|
381
|
+
those shapes are silently dropped and replaced with an integer count
|
|
382
|
+
under the matching omission attribute. The dropped value never
|
|
383
|
+
appears on the span, in any log line, or in any export.
|
|
384
|
+
|
|
385
|
+
Behavior-neutrality: `recordSideEffect()` is an observer. It does
|
|
386
|
+
not send, retry, duplicate, schedule, or delay any side effect. It
|
|
387
|
+
never throws. If no recording span is active, the call is a silent
|
|
388
|
+
no-op.
|
|
389
|
+
|
|
390
|
+
Account opt-in: the capture is gated on the `sideEffectEvidence` flag
|
|
391
|
+
in your account's capture configuration, which the SDK fetches at
|
|
392
|
+
init time. The flag defaults to `false`, so no side-effect attribute
|
|
393
|
+
is ever attached unless your account has explicitly enabled it.
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
import { recordSideEffect } from "@glasstrace/sdk";
|
|
397
|
+
|
|
398
|
+
await mailer.send({ to: recipient, template: "EventCanceledEmail" });
|
|
399
|
+
recordSideEffect({
|
|
400
|
+
kind: "email",
|
|
401
|
+
operation: "email.send",
|
|
402
|
+
status: "succeeded",
|
|
403
|
+
phase: "request",
|
|
404
|
+
fields: {
|
|
405
|
+
templateKey: "EventCanceledEmail",
|
|
406
|
+
role: "invitee",
|
|
407
|
+
locale: "en-US",
|
|
408
|
+
timezone: "Europe/Paris",
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
The SDK guard protects only callers of `recordSideEffect()`; user
|
|
414
|
+
code that bypasses the SDK and writes directly to the OTel span will
|
|
415
|
+
still hit the wire as-is and is filtered by the glasstrace-product
|
|
416
|
+
ingestion service before persistence. This is intentional
|
|
417
|
+
defense-in-depth: the SDK is the first gate; the product receiver
|
|
418
|
+
is the second.
|
|
419
|
+
|
|
296
420
|
## Source maps
|
|
297
421
|
|
|
298
422
|
Glasstrace uploads server-side source maps at build time and resolves
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import { G as GlasstraceEnvVars, f as GlasstraceOptions, A as AnonApiKey, g as SdkInitResponse, C as CaptureConfig, h as SdkHealthReport, I as ImportGraphPayload, i as SdkDiagnosticCode } from './index.d-Dq33YwFT.cjs';
|
|
2
|
+
import { ReadableSpan } from './export/ReadableSpan';
|
|
3
|
+
import { SpanExporter } from './export/SpanExporter';
|
|
4
|
+
import { ExportResult } from './ExportResult';
|
|
5
|
+
import { a as SessionManager } from './edge-entry-DaeG7D7S.cjs';
|
|
6
|
+
import { SpanProcessor } from './SpanProcessor';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolved configuration after merging explicit options with environment variables.
|
|
10
|
+
*/
|
|
11
|
+
interface ResolvedConfig {
|
|
12
|
+
apiKey: string | undefined;
|
|
13
|
+
endpoint: string;
|
|
14
|
+
forceEnable: boolean;
|
|
15
|
+
verbose: boolean;
|
|
16
|
+
environment: string | undefined;
|
|
17
|
+
coverageMapEnabled: boolean;
|
|
18
|
+
nodeEnv: string | undefined;
|
|
19
|
+
vercelEnv: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reads all recognized Glasstrace environment variables from process.env.
|
|
23
|
+
* Returns undefined for any variable not set. Never throws.
|
|
24
|
+
*/
|
|
25
|
+
declare function readEnvVars(): GlasstraceEnvVars;
|
|
26
|
+
/**
|
|
27
|
+
* Merges explicit GlasstraceOptions with environment variables.
|
|
28
|
+
* Explicit options take precedence over environment variables.
|
|
29
|
+
*/
|
|
30
|
+
declare function resolveConfig(options?: GlasstraceOptions): ResolvedConfig;
|
|
31
|
+
/**
|
|
32
|
+
* Returns true when the SDK should be inactive (production detected without force-enable).
|
|
33
|
+
* Logic order:
|
|
34
|
+
* 1. forceEnable === true → return false (override)
|
|
35
|
+
* 2. NODE_ENV === 'production' → return true
|
|
36
|
+
* 3. VERCEL_ENV === 'production' → return true
|
|
37
|
+
* 4. Otherwise → return false
|
|
38
|
+
*/
|
|
39
|
+
declare function isProductionDisabled(config: ResolvedConfig): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Returns true when no API key is configured (anonymous mode).
|
|
42
|
+
* Treats undefined, empty string, whitespace-only, and gt_anon_* keys as anonymous.
|
|
43
|
+
*/
|
|
44
|
+
declare function isAnonymousMode(config: ResolvedConfig): boolean;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The set of recognized fetch target categories.
|
|
48
|
+
*/
|
|
49
|
+
type FetchTarget = "supabase" | "stripe" | "internal" | "unknown";
|
|
50
|
+
/**
|
|
51
|
+
* Classifies an outbound fetch target URL into a known category.
|
|
52
|
+
* Classification is case-insensitive and based on the URL hostname.
|
|
53
|
+
* Uses dot-boundary matching to avoid false positives (e.g. evilstripe.com).
|
|
54
|
+
*
|
|
55
|
+
* Returns one of: 'supabase', 'stripe', 'internal', or 'unknown'.
|
|
56
|
+
*/
|
|
57
|
+
declare function classifyFetchTarget(url: string): FetchTarget;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Reads an existing anonymous key from the filesystem.
|
|
61
|
+
* Returns the key if valid, or null if:
|
|
62
|
+
* - The file does not exist
|
|
63
|
+
* - The file content is invalid
|
|
64
|
+
* - An I/O error occurs
|
|
65
|
+
* - `node:fs` is unavailable (non-Node environment)
|
|
66
|
+
*/
|
|
67
|
+
declare function readAnonKey(projectRoot?: string): Promise<AnonApiKey | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Gets an existing anonymous key from the filesystem, or creates a new one.
|
|
70
|
+
*
|
|
71
|
+
* - If file exists and contains a valid key, returns it
|
|
72
|
+
* - If file does not exist or content is invalid, generates a new key via createAnonApiKey()
|
|
73
|
+
* - Writes the new key to `.glasstrace/anon_key`, creating the directory if needed
|
|
74
|
+
* - On file write failure: logs a warning, caches an ephemeral in-memory key so
|
|
75
|
+
* repeated calls in the same process return the same key
|
|
76
|
+
* - In non-Node environments: returns an ephemeral in-memory key
|
|
77
|
+
*/
|
|
78
|
+
declare function getOrCreateAnonKey(projectRoot?: string): Promise<AnonApiKey>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Reads and validates a cached config file from `.glasstrace/config`.
|
|
82
|
+
* Returns the parsed `SdkInitResponse` or `null` on any failure,
|
|
83
|
+
* including when `node:fs` is unavailable (non-Node environments).
|
|
84
|
+
*/
|
|
85
|
+
declare function loadCachedConfig(projectRoot?: string): SdkInitResponse | null;
|
|
86
|
+
/**
|
|
87
|
+
* Persists the init response to `.glasstrace/config` using the SDK 2.0
|
|
88
|
+
* atomic-write protocol (`tmp + fsync(tmp) + rename + fsync(parent)`).
|
|
89
|
+
* Silently skipped when `node:fs` is unavailable (non-Node environments).
|
|
90
|
+
* On I/O failure, logs a warning.
|
|
91
|
+
*
|
|
92
|
+
* Atomicity: the payload is written to `.glasstrace/config.tmp`, fsynced
|
|
93
|
+
* to durable storage, then renamed into place; the parent directory is
|
|
94
|
+
* fsynced last so the rename survives an immediate crash. `rename` is
|
|
95
|
+
* atomic on POSIX filesystems, so readers either see the previous valid
|
|
96
|
+
* config or the new valid config — never a truncated or partially-written
|
|
97
|
+
* file (DISC-1247 Scenario 5). If any step fails, the temp file is
|
|
98
|
+
* cleaned up on a best-effort basis.
|
|
99
|
+
*/
|
|
100
|
+
declare function saveCachedConfig(response: SdkInitResponse, projectRoot?: string): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Sends a POST request to `/v1/sdk/init`.
|
|
103
|
+
* Validates the response against `SdkInitResponseSchema`.
|
|
104
|
+
*
|
|
105
|
+
* Uses `node:https` via {@link httpsPostJson} rather than the global
|
|
106
|
+
* `fetch` because Next.js 16 patches `fetch` for caching/revalidation
|
|
107
|
+
* and can cause the init request to silently hang (DISC-493 Issue 3).
|
|
108
|
+
* Retries transport-level failures (DNS, TCP, TLS) twice with 500ms +
|
|
109
|
+
* 1500ms backoff, capped at a 20-second total deadline. Server responses
|
|
110
|
+
* (HTTP 4xx/5xx) are never retried and are surfaced immediately.
|
|
111
|
+
*/
|
|
112
|
+
declare function sendInitRequest(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string, importGraph?: ImportGraphPayload, healthReport?: SdkHealthReport, diagnostics?: Array<{
|
|
113
|
+
code: SdkDiagnosticCode;
|
|
114
|
+
message: string;
|
|
115
|
+
timestamp: number;
|
|
116
|
+
}>, signal?: AbortSignal): Promise<SdkInitResponse>;
|
|
117
|
+
/**
|
|
118
|
+
* Result returned by {@link performInit} when the backend reports an
|
|
119
|
+
* account claim transition. `null` means no claim was present.
|
|
120
|
+
*/
|
|
121
|
+
interface InitClaimResult {
|
|
122
|
+
claimResult: NonNullable<SdkInitResponse["claimResult"]>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Orchestrates the full init flow: send request, update config, cache result.
|
|
126
|
+
* This function MUST NOT throw.
|
|
127
|
+
*
|
|
128
|
+
* Returns the claim result when the backend reports an account claim
|
|
129
|
+
* transition, or `null` when no claim result is available (including
|
|
130
|
+
* when init is skipped due to rate-limit backoff, missing API key,
|
|
131
|
+
* or request failure). Callers that do not need claim information
|
|
132
|
+
* can safely ignore the return value.
|
|
133
|
+
*/
|
|
134
|
+
declare function performInit(config: ResolvedConfig, anonKey: AnonApiKey | null, sdkVersion: string, healthReport?: SdkHealthReport | null): Promise<InitClaimResult | null>;
|
|
135
|
+
/**
|
|
136
|
+
* Returns the current capture config from the three-tier fallback chain:
|
|
137
|
+
* 1. In-memory config from latest init response
|
|
138
|
+
* 2. File cache (read at most once per process lifetime)
|
|
139
|
+
* 3. DEFAULT_CAPTURE_CONFIG
|
|
140
|
+
*
|
|
141
|
+
* The disk read is cached via `configCacheChecked` to avoid repeated
|
|
142
|
+
* synchronous I/O on the hot path (called by GlasstraceExporter on
|
|
143
|
+
* every span export batch).
|
|
144
|
+
*/
|
|
145
|
+
declare function getActiveConfig(): CaptureConfig;
|
|
146
|
+
/**
|
|
147
|
+
* Returns the `linkedAccountId` from the current in-memory init response,
|
|
148
|
+
* or `undefined` if no init response is available or no account is linked.
|
|
149
|
+
*
|
|
150
|
+
* Used by the discovery endpoint to determine whether `claimed: true`
|
|
151
|
+
* should be included in the response.
|
|
152
|
+
*/
|
|
153
|
+
declare function getLinkedAccountId(): string | undefined;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Options for constructing a {@link GlasstraceExporter}.
|
|
157
|
+
*/
|
|
158
|
+
interface GlasstraceExporterOptions {
|
|
159
|
+
getApiKey: () => string;
|
|
160
|
+
sessionManager: SessionManager;
|
|
161
|
+
getConfig: () => CaptureConfig;
|
|
162
|
+
environment: string | undefined;
|
|
163
|
+
endpointUrl: string;
|
|
164
|
+
createDelegate: ((url: string, headers: Record<string, string>) => SpanExporter) | null;
|
|
165
|
+
/** When true, logs diagnostic details about enrichment decisions via sdkLog. */
|
|
166
|
+
verbose?: boolean;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* A SpanExporter that enriches spans with glasstrace.* attributes at export
|
|
170
|
+
* time, then delegates to a real OTLP exporter.
|
|
171
|
+
*
|
|
172
|
+
* This design resolves three issues:
|
|
173
|
+
* - Spans emitted before the API key resolves are buffered (not dropped)
|
|
174
|
+
* and flushed once the key is available.
|
|
175
|
+
* - Enrichment happens in the exporter (not onEnding), so it works
|
|
176
|
+
* on Vercel where CompositeSpanProcessor does not forward onEnding().
|
|
177
|
+
* - Session ID is computed at export time using the resolved API key,
|
|
178
|
+
* not the "pending" placeholder.
|
|
179
|
+
*/
|
|
180
|
+
declare class GlasstraceExporter implements SpanExporter {
|
|
181
|
+
private readonly getApiKey;
|
|
182
|
+
private readonly sessionManager;
|
|
183
|
+
private readonly getConfig;
|
|
184
|
+
private readonly environment;
|
|
185
|
+
private readonly endpointUrl;
|
|
186
|
+
private readonly createDelegateFn;
|
|
187
|
+
private readonly verbose;
|
|
188
|
+
private delegate;
|
|
189
|
+
private delegateKey;
|
|
190
|
+
private pendingBatches;
|
|
191
|
+
private pendingSpanCount;
|
|
192
|
+
private overflowLogged;
|
|
193
|
+
constructor(options: GlasstraceExporterOptions);
|
|
194
|
+
export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void;
|
|
195
|
+
/**
|
|
196
|
+
* Called when the API key transitions from "pending" to a resolved value.
|
|
197
|
+
* Creates the delegate exporter and flushes all buffered spans.
|
|
198
|
+
*/
|
|
199
|
+
notifyKeyResolved(): void;
|
|
200
|
+
shutdown(): Promise<void>;
|
|
201
|
+
/**
|
|
202
|
+
* Flushes any pending buffered spans (if the API key has resolved) and
|
|
203
|
+
* delegates to the underlying exporter's forceFlush to drain its queue.
|
|
204
|
+
*/
|
|
205
|
+
forceFlush(): Promise<void>;
|
|
206
|
+
/**
|
|
207
|
+
* Enriches a ReadableSpan with all glasstrace.* attributes.
|
|
208
|
+
* Returns a new ReadableSpan wrapper; the original span is not mutated.
|
|
209
|
+
*
|
|
210
|
+
* Only {@link SessionManager.getSessionId} is individually guarded because
|
|
211
|
+
* it calls into crypto and schema validation — a session ID failure should
|
|
212
|
+
* not prevent the rest of enrichment. The other helper calls
|
|
213
|
+
* ({@link deriveErrorCategory}, {@link deriveOrmProvider},
|
|
214
|
+
* {@link classifyFetchTarget}) are pure functions on typed string inputs
|
|
215
|
+
* and rely on the outer catch for any unexpected failure.
|
|
216
|
+
*
|
|
217
|
+
* On total failure, returns the original span unchanged.
|
|
218
|
+
*/
|
|
219
|
+
private enrichSpan;
|
|
220
|
+
/**
|
|
221
|
+
* Lazily creates the delegate OTLP exporter once the API key is resolved.
|
|
222
|
+
* Recreates the delegate if the key has changed (e.g., after key rotation)
|
|
223
|
+
* so the Authorization header stays current.
|
|
224
|
+
*/
|
|
225
|
+
private ensureDelegate;
|
|
226
|
+
/**
|
|
227
|
+
* Buffers raw (unenriched) spans while the API key is pending.
|
|
228
|
+
* Evicts oldest batches if the buffer exceeds MAX_PENDING_SPANS.
|
|
229
|
+
* Re-checks the key after buffering to close the race window where
|
|
230
|
+
* the key resolves between the caller's check and this buffer call.
|
|
231
|
+
*/
|
|
232
|
+
private bufferSpans;
|
|
233
|
+
/**
|
|
234
|
+
* Flushes all buffered spans through the delegate exporter.
|
|
235
|
+
* Enriches spans at flush time (not buffer time) so that session IDs
|
|
236
|
+
* are computed with the resolved API key instead of the "pending" sentinel.
|
|
237
|
+
*/
|
|
238
|
+
private flushPending;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* The primary SDK entry point called by developers in their `instrumentation.ts`.
|
|
243
|
+
* Orchestrates OTel setup, span processor, init client, anon key, and discovery endpoint.
|
|
244
|
+
*
|
|
245
|
+
* This function is synchronous and MUST NOT throw. The developer's server is never blocked.
|
|
246
|
+
* Background work (key resolution, init call) happens via fire-and-forget promises.
|
|
247
|
+
*
|
|
248
|
+
* @param options - Optional SDK configuration. Environment variables are used as fallbacks.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* // instrumentation.ts
|
|
253
|
+
* import { registerGlasstrace } from "@glasstrace/sdk";
|
|
254
|
+
* registerGlasstrace(); // uses env vars
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
declare function registerGlasstrace(options?: GlasstraceOptions): void;
|
|
258
|
+
/**
|
|
259
|
+
* Returns the registered discovery handler, or null if not registered.
|
|
260
|
+
*/
|
|
261
|
+
declare function getDiscoveryHandler(): ((request: Request) => Promise<Response | null>) | null;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Structural view of Next.js's `NextConfig`. The SDK does not import Next's
|
|
265
|
+
* type directly because Next is not a peer dependency — this wrapper must
|
|
266
|
+
* type-check regardless of which Next.js version the consumer has installed.
|
|
267
|
+
*
|
|
268
|
+
* The constraint is `object` rather than `Record<string, unknown>` because
|
|
269
|
+
* Next's actual `NextConfig` is an interface *without* a string index
|
|
270
|
+
* signature. Requiring `[key: string]: unknown` would fail the assignability
|
|
271
|
+
* check that caused DISC-1256, reported by Next 16 consumers as:
|
|
272
|
+
* > Argument of type 'NextConfig' is not assignable to parameter of type
|
|
273
|
+
* > 'NextConfig'. Index signature for type 'string' is missing in type
|
|
274
|
+
* > 'NextConfig'.
|
|
275
|
+
*
|
|
276
|
+
* `object` accepts every non-primitive value, which is what the wrapper
|
|
277
|
+
* actually handles at runtime (it shallow-copies the input and reads a few
|
|
278
|
+
* known properties defensively). Combined with the generic signature on
|
|
279
|
+
* `withGlasstraceConfig`, callers preserve their exact config subtype.
|
|
280
|
+
*/
|
|
281
|
+
type NextConfig = object;
|
|
282
|
+
/**
|
|
283
|
+
* Wraps the developer's Next.js config to enable source map generation
|
|
284
|
+
* and upload .map files to the ingestion API at build time.
|
|
285
|
+
*
|
|
286
|
+
* The build NEVER fails because of Glasstrace — all errors are caught
|
|
287
|
+
* and logged as warnings.
|
|
288
|
+
*
|
|
289
|
+
* ## What the wrapper configures for you
|
|
290
|
+
*
|
|
291
|
+
* - `experimental.serverSourceMaps: true` — enables server-side source maps
|
|
292
|
+
* so Glasstrace can resolve stack traces back to your source.
|
|
293
|
+
* - `serverExternalPackages: ["@glasstrace/sdk"]` — tells Next to load the
|
|
294
|
+
* SDK via Node's `require()` at runtime instead of bundling it through
|
|
295
|
+
* webpack or Turbopack on the RSC / Route Handler paths. This is the same
|
|
296
|
+
* pattern Prisma, `@vercel/otel`, Sentry, `sharp`, and `bcrypt` ship with.
|
|
297
|
+
* - A webpack `externals` entry that marks every Node.js built-in import
|
|
298
|
+
* (both `node:*` and bare forms like `zlib` or `stream`) as a runtime
|
|
299
|
+
* `commonjs` require. `serverExternalPackages` does not apply to the
|
|
300
|
+
* instrumentation path under `next dev --webpack`
|
|
301
|
+
* (vercel/next.js#58003, #28774), so any bundled SDK chunk that imports
|
|
302
|
+
* `node:child_process` or the bare `zlib` specifier used by
|
|
303
|
+
* `@opentelemetry/otlp-exporter-base` would otherwise crash with
|
|
304
|
+
* `UnhandledSchemeError` or `Can't resolve 'zlib'`. This entry is the
|
|
305
|
+
* actual DISC-1257 fix for the dev-webpack path. Turbopack is
|
|
306
|
+
* unaffected — it ignores `config.webpack` and resolves Node built-ins
|
|
307
|
+
* natively.
|
|
308
|
+
* - An empty `turbopack: {}` when none is set, so Next 16 does not reject
|
|
309
|
+
* the config for setting `webpack` without a companion `turbopack` key
|
|
310
|
+
* (DISC-1256).
|
|
311
|
+
* - A `webpack` hook that collects and uploads `.map` files on client-side
|
|
312
|
+
* production builds.
|
|
313
|
+
*
|
|
314
|
+
* ## Turbopack
|
|
315
|
+
*
|
|
316
|
+
* Next.js 16 made Turbopack the default bundler for `next build`, and Next
|
|
317
|
+
* rejects configs that set `webpack` without also setting `turbopack`. This
|
|
318
|
+
* wrapper therefore seeds an empty `turbopack: {}` when the user has not set
|
|
319
|
+
* one themselves, preserving existing behaviour for explicit Turbopack configs.
|
|
320
|
+
*
|
|
321
|
+
* **Source-map upload is currently webpack-only.** Under Turbopack the build
|
|
322
|
+
* succeeds, but the afterEmit hook that collects and uploads `.map` files does
|
|
323
|
+
* not fire. Run `next build --webpack` to get source-map uploads, or wait for
|
|
324
|
+
* a follow-up release that ports the plugin to Turbopack.
|
|
325
|
+
*
|
|
326
|
+
* @param nextConfig - The developer's existing Next.js configuration object.
|
|
327
|
+
* @returns A new config object with source map generation and upload enabled.
|
|
328
|
+
* The return type mirrors the input type so that caller-side config
|
|
329
|
+
* properties are preserved. The `object` constraint (rather than
|
|
330
|
+
* `Record<string, unknown>`) is what makes the wrapper accept Next's
|
|
331
|
+
* real `NextConfig` interface (DISC-1256).
|
|
332
|
+
*/
|
|
333
|
+
declare function withGlasstraceConfig<T extends NextConfig>(nextConfig: T): T;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Returns true when the SDK is in ACTIVE or ACTIVE_DEGRADED state.
|
|
337
|
+
*/
|
|
338
|
+
declare function isReady(): boolean;
|
|
339
|
+
/**
|
|
340
|
+
* Resolves when the SDK reaches ACTIVE or ACTIVE_DEGRADED.
|
|
341
|
+
* Rejects on PRODUCTION_DISABLED, REGISTRATION_FAILED, or timeout.
|
|
342
|
+
*
|
|
343
|
+
* Checks current state synchronously first — resolves/rejects immediately
|
|
344
|
+
* if the SDK has already reached a terminal or ready state.
|
|
345
|
+
*/
|
|
346
|
+
declare function waitForReady(timeoutMs?: number): Promise<void>;
|
|
347
|
+
/**
|
|
348
|
+
* Simplified public state query for external consumers.
|
|
349
|
+
* Hides implementation details like coexistence scenarios.
|
|
350
|
+
*
|
|
351
|
+
* The returned `tracing` field is the canonical user-observable signal
|
|
352
|
+
* for OTel coexistence outcomes:
|
|
353
|
+
*
|
|
354
|
+
* - `"active"` — the SDK owns the OTel provider and is exporting spans.
|
|
355
|
+
* - `"coexistence"` — another OTel provider was detected and the SDK
|
|
356
|
+
* either auto-attached its span processor or found one already
|
|
357
|
+
* present. Spans are exported through the existing pipeline.
|
|
358
|
+
* - `"degraded"` — the SDK is exporting but the core lifecycle entered
|
|
359
|
+
* `ACTIVE_DEGRADED` (e.g., a non-fatal export failure).
|
|
360
|
+
* - `"not-configured"` — the SDK could not configure tracing. Covers
|
|
361
|
+
* `OtelState.UNCONFIGURED`, `OtelState.CONFIGURING`, and
|
|
362
|
+
* `OtelState.COEXISTENCE_FAILED` (the DISC-1556 Next 16 production
|
|
363
|
+
* "auto-attach returned null" path). When the value is
|
|
364
|
+
* `"not-configured"` after `registerGlasstrace()` has resolved,
|
|
365
|
+
* spans are NOT reaching the Glasstrace exporter and the manual
|
|
366
|
+
* `createGlasstraceSpanProcessor()` workaround should be applied.
|
|
367
|
+
* See `runtime-state.json`'s `lastError` field for the structured
|
|
368
|
+
* failure record.
|
|
369
|
+
*/
|
|
370
|
+
declare function getStatus(): {
|
|
371
|
+
ready: boolean;
|
|
372
|
+
mode: "anonymous" | "authenticated" | "claiming" | "disabled";
|
|
373
|
+
tracing: "active" | "degraded" | "not-configured" | "coexistence";
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* OTel Coexistence Public API
|
|
378
|
+
*
|
|
379
|
+
* Provides createGlasstraceSpanProcessor() for developers who want to
|
|
380
|
+
* manually integrate Glasstrace with their existing OTel provider
|
|
381
|
+
* (e.g., Sentry's openTelemetrySpanProcessors config option).
|
|
382
|
+
*
|
|
383
|
+
* Also provides the auto-attach path (tryAutoAttachGlasstraceProcessor)
|
|
384
|
+
* that configureOtel() uses when it detects a pre-registered provider
|
|
385
|
+
* at runtime (Next.js 16 production, Sentry, Datadog, New Relic). Both
|
|
386
|
+
* entry points reuse the same span-processor factory so the manual and
|
|
387
|
+
* automatic paths stay in lockstep.
|
|
388
|
+
*
|
|
389
|
+
* Design: sdk-otel-coexistence.md Sections 3, 4, 5, 6
|
|
390
|
+
*/
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Creates a Glasstrace span processor for manual integration with an
|
|
394
|
+
* existing OTel provider.
|
|
395
|
+
*
|
|
396
|
+
* Use this when another tool (e.g., Sentry) owns the OTel provider and
|
|
397
|
+
* you want to add Glasstrace to their processor list:
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* ```ts
|
|
401
|
+
* import * as Sentry from "@sentry/nextjs";
|
|
402
|
+
* import { createGlasstraceSpanProcessor } from "@glasstrace/sdk";
|
|
403
|
+
*
|
|
404
|
+
* Sentry.init({
|
|
405
|
+
* dsn: "...",
|
|
406
|
+
* openTelemetrySpanProcessors: [createGlasstraceSpanProcessor()],
|
|
407
|
+
* });
|
|
408
|
+
* ```
|
|
409
|
+
*
|
|
410
|
+
* **Important:** `registerGlasstrace()` is still required even when using
|
|
411
|
+
* this function. The processor handles span transport (enrichment and
|
|
412
|
+
* export). `registerGlasstrace()` handles everything else: init calls,
|
|
413
|
+
* config sync, session management, anonymous key generation, discovery
|
|
414
|
+
* endpoint, and health reporting.
|
|
415
|
+
*
|
|
416
|
+
* @param options - Optional SDK configuration. If omitted, uses the same
|
|
417
|
+
* config as registerGlasstrace() (environment variables).
|
|
418
|
+
* @returns A BatchSpanProcessor wrapping a GlasstraceExporter with the
|
|
419
|
+
* branded Symbol.for('glasstrace.exporter') for coexistence detection.
|
|
420
|
+
*/
|
|
421
|
+
declare function createGlasstraceSpanProcessor(options?: GlasstraceOptions): SpanProcessor;
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Manual error capture API.
|
|
425
|
+
*
|
|
426
|
+
* Provides a simple function for developers to manually record errors
|
|
427
|
+
* as span events, independent of the `consoleErrors` config flag.
|
|
428
|
+
*/
|
|
429
|
+
/**
|
|
430
|
+
* Records an error as a span event on the currently active OTel span.
|
|
431
|
+
*
|
|
432
|
+
* Works regardless of the `consoleErrors` configuration — this is an
|
|
433
|
+
* explicit, opt-in API for manual error reporting. If no span is active
|
|
434
|
+
* or OTel is not available, the call is silently ignored.
|
|
435
|
+
*
|
|
436
|
+
* On the first captured error, may display a one-time diagnostic nudge
|
|
437
|
+
* to stderr if the MCP connection marker is absent (dev environments only).
|
|
438
|
+
*
|
|
439
|
+
* @param error - The error to capture. Accepts `Error` objects, strings, or any value.
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```ts
|
|
443
|
+
* import { captureError } from "@glasstrace/sdk";
|
|
444
|
+
*
|
|
445
|
+
* try {
|
|
446
|
+
* await riskyOperation();
|
|
447
|
+
* } catch (err) {
|
|
448
|
+
* captureError(err);
|
|
449
|
+
* // handle error normally...
|
|
450
|
+
* }
|
|
451
|
+
* ```
|
|
452
|
+
*/
|
|
453
|
+
declare function captureError(error: unknown): void;
|
|
454
|
+
|
|
455
|
+
export { type FetchTarget as F, GlasstraceExporter as G, type InitClaimResult as I, type ResolvedConfig as R, type GlasstraceExporterOptions as a, classifyFetchTarget as b, captureError as c, createGlasstraceSpanProcessor as d, getDiscoveryHandler as e, getLinkedAccountId as f, getActiveConfig as g, getOrCreateAnonKey as h, getStatus as i, isAnonymousMode as j, isProductionDisabled as k, isReady as l, loadCachedConfig as m, readEnvVars as n, registerGlasstrace as o, performInit as p, resolveConfig as q, readAnonKey as r, saveCachedConfig as s, sendInitRequest as t, withGlasstraceConfig as u, waitForReady as w };
|