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