@glasstrace/sdk 1.16.0 → 1.18.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 +44 -3
- package/dist/async-context/index.cjs.map +1 -1
- package/dist/async-context/index.js +2 -2
- package/dist/{capture-error-B0txjNut.d.cts → capture-error-B8qiXFeC.d.cts} +2 -2
- package/dist/{capture-error-Dc01rYNR.d.ts → capture-error-BTI6mCH2.d.ts} +2 -2
- package/dist/{chunk-WOYJAG7H.js → chunk-BJOZBAP7.js} +3 -3
- package/dist/{chunk-AFTCLH77.js → chunk-CN5EP25B.js} +2 -2
- package/dist/{chunk-KM4UNN3Q.js → chunk-EVX6D2TX.js} +2 -2
- package/dist/{chunk-BGJKEFBN.js → chunk-M3QGJUEI.js} +2 -2
- package/dist/{chunk-GBVMPMVV.js → chunk-MKT54VEH.js} +2 -2
- package/dist/{chunk-GBVMPMVV.js.map → chunk-MKT54VEH.js.map} +1 -1
- package/dist/{chunk-OHSX224U.js → chunk-O7IJP2TQ.js} +2 -2
- package/dist/{chunk-T7B752NF.js → chunk-SONZOTBP.js} +11 -3
- package/dist/{chunk-T7B752NF.js.map → chunk-SONZOTBP.js.map} +1 -1
- package/dist/{chunk-774XIOZG.js → chunk-UOAG72NR.js} +2 -2
- package/dist/{chunk-DW3CZDS6.js → chunk-YKE6HJLW.js} +2 -2
- package/dist/{chunk-EWW3TZ52.js → chunk-Z2DSC3YI.js} +61 -11
- package/dist/{chunk-EWW3TZ52.js.map → chunk-Z2DSC3YI.js.map} +1 -1
- package/dist/cli/init.cjs +4 -4
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +7 -7
- package/dist/cli/mcp-add.cjs +1 -1
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +3 -3
- package/dist/cli/uninit.js +3 -3
- package/dist/cli/upgrade-instructions.cjs +1 -1
- package/dist/cli/upgrade-instructions.js +3 -3
- package/dist/cli/validate.cjs.map +1 -1
- package/dist/cli/validate.js +2 -2
- package/dist/{correlation-id-CelUvw7j.d.cts → correlation-id-CClOq8Wn.d.cts} +1 -1
- package/dist/{correlation-id-B9YYmoZw.d.ts → correlation-id-Ct86Ug4s.d.ts} +1 -1
- 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 +4 -4
- package/dist/{import-graph-Dka_Fm7j.d.ts → import-graph-DZjTJdJ5.d.ts} +1 -1
- package/dist/{import-graph-DBLGNjcI.d.cts → import-graph-DyQfZU2f.d.cts} +1 -1
- package/dist/index.cjs +202 -7
- package/dist/index.cjs.map +1 -1
- package/dist/{index.d-3-cJoY8y.d.cts → index.d-DhatN7mq.d.cts} +1 -1
- package/dist/{index.d-3-cJoY8y.d.ts → index.d-DhatN7mq.d.ts} +1 -1
- package/dist/index.d.cts +243 -5
- package/dist/index.d.ts +243 -5
- package/dist/index.js +151 -6
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.cjs.map +1 -1
- package/dist/middleware/index.js +2 -2
- package/dist/node-entry.cjs +5 -5
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.d.cts +4 -4
- package/dist/node-entry.d.ts +4 -4
- package/dist/node-entry.js +7 -7
- package/dist/node-subpath.cjs.map +1 -1
- package/dist/node-subpath.d.cts +2 -2
- package/dist/node-subpath.d.ts +2 -2
- package/dist/node-subpath.js +3 -3
- package/dist/{source-map-uploader-UJPZCUFN.js → source-map-uploader-U7SLSKIZ.js} +3 -3
- package/dist/trpc/index.cjs.map +1 -1
- package/dist/trpc/index.js +1 -1
- package/package.json +1 -1
- /package/dist/{chunk-WOYJAG7H.js.map → chunk-BJOZBAP7.js.map} +0 -0
- /package/dist/{chunk-AFTCLH77.js.map → chunk-CN5EP25B.js.map} +0 -0
- /package/dist/{chunk-KM4UNN3Q.js.map → chunk-EVX6D2TX.js.map} +0 -0
- /package/dist/{chunk-BGJKEFBN.js.map → chunk-M3QGJUEI.js.map} +0 -0
- /package/dist/{chunk-OHSX224U.js.map → chunk-O7IJP2TQ.js.map} +0 -0
- /package/dist/{chunk-774XIOZG.js.map → chunk-UOAG72NR.js.map} +0 -0
- /package/dist/{chunk-DW3CZDS6.js.map → chunk-YKE6HJLW.js.map} +0 -0
- /package/dist/{source-map-uploader-UJPZCUFN.js.map → source-map-uploader-U7SLSKIZ.js.map} +0 -0
|
@@ -324,4 +324,4 @@ declare const SIDE_EFFECT_OPERATION_PHASES: readonly ["request", "post_response"
|
|
|
324
324
|
*/
|
|
325
325
|
type SideEffectOperationPhase = (typeof SIDE_EFFECT_OPERATION_PHASES)[number];
|
|
326
326
|
|
|
327
|
-
export { type AnonApiKey as A, type CaptureConfig as C, type GlasstraceEnvVars as G, type ImportGraphPayload as I, type
|
|
327
|
+
export { type AnonApiKey as A, type CaptureConfig as C, type GlasstraceEnvVars as G, type ImportGraphPayload as I, type SourceMapUploadResponse as S, type SourceMapManifestResponse as a, type SideEffectOperationKind as b, type SideEffectOperationStatus as c, deriveSessionId as d, type SideEffectOperationPhase as e, type SideEffectSemanticFieldKey as f, type SideEffectOmissionReason as g, type SideEffectSemanticFieldStableCoreKey as h, isSideEffectSemanticFieldKey as i, type SdkDiagnosticCode as j, type SessionId as k, type GlasstraceOptions as l, type SdkInitResponse as m, type SdkHealthReport as n };
|
|
@@ -324,4 +324,4 @@ declare const SIDE_EFFECT_OPERATION_PHASES: readonly ["request", "post_response"
|
|
|
324
324
|
*/
|
|
325
325
|
type SideEffectOperationPhase = (typeof SIDE_EFFECT_OPERATION_PHASES)[number];
|
|
326
326
|
|
|
327
|
-
export { type AnonApiKey as A, type CaptureConfig as C, type GlasstraceEnvVars as G, type ImportGraphPayload as I, type
|
|
327
|
+
export { type AnonApiKey as A, type CaptureConfig as C, type GlasstraceEnvVars as G, type ImportGraphPayload as I, type SourceMapUploadResponse as S, type SourceMapManifestResponse as a, type SideEffectOperationKind as b, type SideEffectOperationStatus as c, deriveSessionId as d, type SideEffectOperationPhase as e, type SideEffectSemanticFieldKey as f, type SideEffectOmissionReason as g, type SideEffectSemanticFieldStableCoreKey as h, isSideEffectSemanticFieldKey as i, type SdkDiagnosticCode as j, type SessionId as k, type GlasstraceOptions as l, type SdkInitResponse as m, type SdkHealthReport as n };
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { C as CorrelationIdRequest, G as GlasstraceSpanProcessor, S as SdkError, a as SessionManager, c as captureCorrelationId, g as getDateString, b as getOrigin } from './correlation-id-
|
|
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-
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
1
|
+
export { C as CorrelationIdRequest, G as GlasstraceSpanProcessor, S as SdkError, a as SessionManager, c as captureCorrelationId, g as getDateString, b as getOrigin } from './correlation-id-CClOq8Wn.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-B8qiXFeC.cjs';
|
|
3
|
+
import { b as SideEffectOperationKind, c as SideEffectOperationStatus, e as SideEffectOperationPhase, f as SideEffectSemanticFieldKey } from './index.d-DhatN7mq.cjs';
|
|
4
|
+
export { g as SideEffectOmissionReason, h as SideEffectSemanticFieldStableCoreKey, d as deriveSessionId, i as isSideEffectSemanticFieldKey } from './index.d-DhatN7mq.cjs';
|
|
5
|
+
import { Span } from './trace/span';
|
|
5
6
|
export { RequestMiddlewareFunction, TracedRequestMiddlewareOptions } from './middleware/index.cjs';
|
|
6
7
|
export { WithAsyncCausalityOptions } from './async-context/index.cjs';
|
|
7
8
|
import './export/ReadableSpan';
|
|
@@ -90,6 +91,20 @@ interface RecordSideEffectInput {
|
|
|
90
91
|
* prefix), so a categorical and a scalar facet can share a name.
|
|
91
92
|
*/
|
|
92
93
|
scalars?: Record<string, unknown>;
|
|
94
|
+
/**
|
|
95
|
+
* Optional producer-asserted boolean relations (invariants) emitted on
|
|
96
|
+
* the categorical field channel. Keys must be camelCase ending in
|
|
97
|
+
* `Holds` (e.g. `timezonePreservedHolds`); values are real `boolean`s,
|
|
98
|
+
* coerced to `"true"`/`"false"` on the wire. A non-`Holds` key, a
|
|
99
|
+
* non-boolean value, or a key already attached by `fields` (a
|
|
100
|
+
* same-channel collision — `fields` wins) is dropped with the matching
|
|
101
|
+
* omission counter. Relations count against the same product-side
|
|
102
|
+
* per-operation field budget as `fields` (enforced at projection).
|
|
103
|
+
*
|
|
104
|
+
* Use {@link invariant} / {@link isNullInvariant} to compute the
|
|
105
|
+
* boolean from a comparison.
|
|
106
|
+
*/
|
|
107
|
+
relations?: Record<string, boolean>;
|
|
93
108
|
}
|
|
94
109
|
/**
|
|
95
110
|
* Record allowlisted side-effect evidence on the current active OTel
|
|
@@ -143,4 +158,227 @@ interface RecordSideEffectInput {
|
|
|
143
158
|
*/
|
|
144
159
|
declare function recordSideEffect(input: RecordSideEffectInput): void;
|
|
145
160
|
|
|
146
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Public value-capture primitive (L1 passive capture).
|
|
163
|
+
*
|
|
164
|
+
* {@link capture} emits a single allowlisted value-fidelity scalar onto a
|
|
165
|
+
* caller-**owned** OTel span. It is the counterpart to {@link
|
|
166
|
+
* recordSideEffect} for the case where the emitter owns the target span
|
|
167
|
+
* itself (e.g. a passive database adapter that opens a `db.<Model>.<op>`
|
|
168
|
+
* span) rather than attaching to the ambient active span.
|
|
169
|
+
*
|
|
170
|
+
* Why this exists: {@link recordSideEffect} is ambient-only — it resolves
|
|
171
|
+
* the active span via `getActiveSpan()`. A passive adapter cannot use it,
|
|
172
|
+
* because at its capture point the ambient span is the database client's
|
|
173
|
+
* own operation span, which has already ended and is non-recording. So the
|
|
174
|
+
* adapter must own a fresh recording span and emit onto it explicitly.
|
|
175
|
+
*
|
|
176
|
+
* The behavior contract mirrors {@link recordSideEffect}: observational
|
|
177
|
+
* only. `capture` never executes a side effect, never reads or mutates the
|
|
178
|
+
* captured value's source, and **never throws**. Every failure mode
|
|
179
|
+
* (capture-config disabled, ended / `NonRecordingSpan` target, allowlist
|
|
180
|
+
* rejection, OTel attribute-slot exhaustion) routes to a silent no-op or to
|
|
181
|
+
* an omission-counter increment that carries no rejected input.
|
|
182
|
+
*
|
|
183
|
+
* Capture is **strict-mode only**: timestamp-shaped and unhashed-identifier
|
|
184
|
+
* values are rejected at emit so they never reach the wire. The `full`
|
|
185
|
+
* fidelity relaxation is not reachable through this primitive.
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
/** Options for {@link capture}. */
|
|
189
|
+
interface CaptureOptions {
|
|
190
|
+
/**
|
|
191
|
+
* The caller-owned, recording span to attach the scalar to. `capture`
|
|
192
|
+
* writes only to this span; it never resolves or touches the ambient
|
|
193
|
+
* active span. The caller is responsible for `end()`-ing it.
|
|
194
|
+
*/
|
|
195
|
+
span: Span;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Emit a single allowlisted value-fidelity scalar onto a caller-owned span.
|
|
199
|
+
*
|
|
200
|
+
* The scalar `name` must match the value-fidelity scalar key pattern
|
|
201
|
+
* (`*Ms` / `*Amount` / `*Bytes` / `*Ratio` / `*Id` / `*Value` / `*Flag`)
|
|
202
|
+
* and its value must match the suffix type — e.g. a `*Flag` key requires a
|
|
203
|
+
* `boolean`. Mismatches, timestamp-shaped values, and unhashed `*Id`s are
|
|
204
|
+
* rejected under strict mode and recorded as an omission count on the
|
|
205
|
+
* supplied span (never the active span).
|
|
206
|
+
*
|
|
207
|
+
* Edge cases (all silent no-ops, never throws):
|
|
208
|
+
* - capture-config flag `sideEffectEvidence` is `false` ⇒ no-op, **no
|
|
209
|
+
* counter** (mirrors {@link recordSideEffect}: with capture disabled the
|
|
210
|
+
* SDK does no allowlist evaluation and writes nothing).
|
|
211
|
+
* - the supplied span has already ended or is a `NonRecordingSpan` ⇒
|
|
212
|
+
* no-op, **no counter** (its omission counter would itself be a dropped
|
|
213
|
+
* span write). The owning adapter passes a fresh recording span, so this
|
|
214
|
+
* is a caller-misuse guard.
|
|
215
|
+
* - the value fails strict allowlist validation ⇒ an omission count is
|
|
216
|
+
* recorded on the supplied span; the rejected value is never emitted.
|
|
217
|
+
* - OTel attribute-slot exhaustion ⇒ the attribute write is silently
|
|
218
|
+
* dropped.
|
|
219
|
+
*
|
|
220
|
+
* @example Project a boolean result field onto an owned database span
|
|
221
|
+
* ```ts
|
|
222
|
+
* import { capture } from "@glasstrace/sdk";
|
|
223
|
+
*
|
|
224
|
+
* const span = tracer.startSpan("db.Poll.findUnique");
|
|
225
|
+
* try {
|
|
226
|
+
* const row = await query(args);
|
|
227
|
+
* if (row) capture("mutedFlag", row.muted, { span });
|
|
228
|
+
* return row;
|
|
229
|
+
* } finally {
|
|
230
|
+
* span.end();
|
|
231
|
+
* }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
declare function capture(name: string, value: unknown, options: CaptureOptions): void;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Passive Prisma value-capture adapter (L1 capture).
|
|
238
|
+
*
|
|
239
|
+
* `prismaAdapter({ allow })` returns a Prisma client extension that, for
|
|
240
|
+
* each allowlisted `(model, column)`, projects a boolean result field onto
|
|
241
|
+
* a Glasstrace value-fidelity scalar so an agent can read it back from the
|
|
242
|
+
* trace. It is **passive and observational**: it never executes a query
|
|
243
|
+
* itself, never reads or mutates the result, and never changes query
|
|
244
|
+
* behavior or errors.
|
|
245
|
+
*
|
|
246
|
+
* Apply it like any Prisma extension:
|
|
247
|
+
*
|
|
248
|
+
* ```ts
|
|
249
|
+
* import { prismaAdapter } from "@glasstrace/sdk";
|
|
250
|
+
*
|
|
251
|
+
* const prisma = new PrismaClient().$extends(
|
|
252
|
+
* prismaAdapter({ allow: [{ model: "Poll", column: "muted" }] }),
|
|
253
|
+
* );
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* Design:
|
|
257
|
+
* - **OWN a span.** At the capture point the database client's own
|
|
258
|
+
* operation span has already ended, so the adapter opens its own
|
|
259
|
+
* recording `db.<Model>.<op>` span (parented under the active request
|
|
260
|
+
* span) and emits onto it via {@link capture}.
|
|
261
|
+
* - **Default-deny.** Nothing is captured unless an explicit `allow` entry
|
|
262
|
+
* matches AND the server-pushed `sideEffectEvidence` capture flag is on.
|
|
263
|
+
* An empty / unset `allow` captures nothing.
|
|
264
|
+
* - **Boolean only.** This adapter projects boolean columns (the strict,
|
|
265
|
+
* no-`captureFidelity:full` case). Non-boolean allowlisted columns route
|
|
266
|
+
* to a safe omission counter, never a captured value.
|
|
267
|
+
* - **Pure observer.** Capture work can never throw into the host query;
|
|
268
|
+
* the owned span is always ended; the original query error is re-thrown
|
|
269
|
+
* verbatim.
|
|
270
|
+
* - **Bounded.** `findMany` / list operations are disabled (no per-row
|
|
271
|
+
* capture). The adapter never widens the app's `select`.
|
|
272
|
+
*
|
|
273
|
+
* This module has **no dependency on `@prisma/client`** — it is typed
|
|
274
|
+
* structurally against Prisma's client-extension shape (mirroring the
|
|
275
|
+
* Drizzle adapter), so it adds no runtime dependency and ships on the edge-
|
|
276
|
+
* safe root barrel. On a runtime with no active request span (e.g. an edge
|
|
277
|
+
* runtime with no AsyncLocalStorage), it captures nothing.
|
|
278
|
+
*/
|
|
279
|
+
/** The arguments Prisma passes to a `$allOperations` query-extension callback. */
|
|
280
|
+
interface PrismaAllOperationsArgs {
|
|
281
|
+
/** The Prisma model name (PascalCase, e.g. `Poll`), or `undefined` for raw ops. */
|
|
282
|
+
model?: string;
|
|
283
|
+
/** The Prisma operation (e.g. `findUnique`, `findMany`, `update`). */
|
|
284
|
+
operation: string;
|
|
285
|
+
/** The operation arguments, forwarded unchanged to `query`. */
|
|
286
|
+
args: unknown;
|
|
287
|
+
/** Executes the underlying operation. Called exactly once. */
|
|
288
|
+
query: (args: unknown) => Promise<unknown>;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* A Prisma client extension — the object passed to `prisma.$extends(...)`.
|
|
292
|
+
* Structurally typed so the adapter needs no `@prisma/client` dependency.
|
|
293
|
+
*/
|
|
294
|
+
interface PrismaCaptureExtension {
|
|
295
|
+
name: string;
|
|
296
|
+
query: {
|
|
297
|
+
$allModels: {
|
|
298
|
+
$allOperations(args: PrismaAllOperationsArgs): Promise<unknown>;
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/** A single allowlisted column to project. */
|
|
303
|
+
interface PrismaCaptureColumn {
|
|
304
|
+
/** The Prisma model name, PascalCase, exactly as Prisma reports it (e.g. `Poll`). */
|
|
305
|
+
model: string;
|
|
306
|
+
/** The boolean result column to project (e.g. `muted`). */
|
|
307
|
+
column: string;
|
|
308
|
+
}
|
|
309
|
+
/** Options for {@link prismaAdapter}. */
|
|
310
|
+
interface PrismaAdapterOptions {
|
|
311
|
+
/**
|
|
312
|
+
* The default-deny allowlist. Only `(model, column)` pairs listed here are
|
|
313
|
+
* eligible for capture; an empty or unset list captures nothing. The
|
|
314
|
+
* server-side per-tenant allowlist re-enforces this independently at
|
|
315
|
+
* ingestion.
|
|
316
|
+
*/
|
|
317
|
+
allow?: ReadonlyArray<PrismaCaptureColumn>;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Build a passive Prisma value-capture extension. See the module doc for
|
|
321
|
+
* the full behavior contract.
|
|
322
|
+
*/
|
|
323
|
+
declare function prismaAdapter(options?: PrismaAdapterOptions): PrismaCaptureExtension;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Producer-sugar for computing boolean relations to emit as `*Holds`
|
|
327
|
+
* side-effect evidence.
|
|
328
|
+
*
|
|
329
|
+
* These helpers turn a comparison into the boolean a producer passes to
|
|
330
|
+
* `recordSideEffect({ relations: { …Holds: invariant(a, "eq", b) } })`.
|
|
331
|
+
* They are pure (no I/O, no Node built-ins) and edge-safe, so they live
|
|
332
|
+
* on the root barrel. The operator set is intentionally minimal and
|
|
333
|
+
* fixed — six binary comparisons plus a separate unary null check — and
|
|
334
|
+
* is not a general expression DSL.
|
|
335
|
+
*/
|
|
336
|
+
/**
|
|
337
|
+
* The six supported binary comparison operators. `isNull` is **not** an
|
|
338
|
+
* operator here — use {@link isNullInvariant} for the unary case.
|
|
339
|
+
*/
|
|
340
|
+
type InvariantOp = "eq" | "neq" | "lt" | "lte" | "gt" | "gte";
|
|
341
|
+
/**
|
|
342
|
+
* Evaluate a binary comparison invariant and return the boolean result.
|
|
343
|
+
*
|
|
344
|
+
* Both operands are constrained to the same primitive type. `eq`/`neq`
|
|
345
|
+
* use strict equality; the ordering operators (`lt`/`lte`/`gt`/`gte`)
|
|
346
|
+
* use the language relational operators (numeric for numbers/bigints,
|
|
347
|
+
* lexical for strings). Intended for producing a `*Holds` relation, e.g.
|
|
348
|
+
* `invariant(emittedDurationMinutes, "eq", declaredDurationMinutes)`.
|
|
349
|
+
*
|
|
350
|
+
* Operands should be comparable primitives. `NaN` follows IEEE-754
|
|
351
|
+
* (unequal to everything; all orderings `false`), so screen `NaN` before
|
|
352
|
+
* asserting a relation. Passing a non-primitive (e.g. a `Symbol`, or an
|
|
353
|
+
* object with a throwing `valueOf`) to an ordering operator throws per
|
|
354
|
+
* JS semantics — the type signature prevents this for typed callers.
|
|
355
|
+
*
|
|
356
|
+
* @param left - The left operand.
|
|
357
|
+
* @param op - One of the six {@link InvariantOp} comparisons.
|
|
358
|
+
* @param right - The right operand (same primitive type as `left`).
|
|
359
|
+
* @returns The boolean result of `left <op> right`.
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* recordSideEffect({
|
|
363
|
+
* kind: "calendar_link",
|
|
364
|
+
* operation: "invite.create",
|
|
365
|
+
* relations: {
|
|
366
|
+
* durationMatchesHolds: invariant(emittedMinutes, "eq", declaredMinutes),
|
|
367
|
+
* },
|
|
368
|
+
* });
|
|
369
|
+
*/
|
|
370
|
+
declare function invariant<T extends number | string | bigint | boolean>(left: T, op: InvariantOp, right: T): boolean;
|
|
371
|
+
/**
|
|
372
|
+
* Unary null/undefined invariant — `true` when `value` is `null` or
|
|
373
|
+
* `undefined`. Kept separate from {@link invariant} because nullishness
|
|
374
|
+
* is a unary predicate, not a binary comparison (there is no `isNull`
|
|
375
|
+
* operator). Use for a `*Holds` relation asserting a value's absence,
|
|
376
|
+
* e.g. `relations: { recipientMissingHolds: isNullInvariant(recipient) }`.
|
|
377
|
+
*
|
|
378
|
+
* @param value - The value to test.
|
|
379
|
+
* @returns `true` when `value` is `null` or `undefined`, else `false`
|
|
380
|
+
* (falsy-but-present values like `0`, `""`, `false`, `NaN` are `false`).
|
|
381
|
+
*/
|
|
382
|
+
declare function isNullInvariant(value: unknown): boolean;
|
|
383
|
+
|
|
384
|
+
export { type CaptureOptions, type InvariantOp, type PrismaAdapterOptions, type PrismaCaptureColumn, type PrismaCaptureExtension, type RecordSideEffectInput, SideEffectOperationKind, SideEffectOperationPhase, SideEffectOperationStatus, SideEffectSemanticFieldKey, capture, invariant, isNullInvariant, prismaAdapter, recordSideEffect };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { C as CorrelationIdRequest, G as GlasstraceSpanProcessor, S as SdkError, a as SessionManager, c as captureCorrelationId, g as getDateString, b as getOrigin } from './correlation-id-
|
|
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-
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
1
|
+
export { C as CorrelationIdRequest, G as GlasstraceSpanProcessor, S as SdkError, a as SessionManager, c as captureCorrelationId, g as getDateString, b as getOrigin } from './correlation-id-Ct86Ug4s.js';
|
|
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-BTI6mCH2.js';
|
|
3
|
+
import { b as SideEffectOperationKind, c as SideEffectOperationStatus, e as SideEffectOperationPhase, f as SideEffectSemanticFieldKey } from './index.d-DhatN7mq.js';
|
|
4
|
+
export { g as SideEffectOmissionReason, h as SideEffectSemanticFieldStableCoreKey, d as deriveSessionId, i as isSideEffectSemanticFieldKey } from './index.d-DhatN7mq.js';
|
|
5
|
+
import { Span } from './trace/span';
|
|
5
6
|
export { RequestMiddlewareFunction, TracedRequestMiddlewareOptions } from './middleware/index.js';
|
|
6
7
|
export { WithAsyncCausalityOptions } from './async-context/index.js';
|
|
7
8
|
import './export/ReadableSpan';
|
|
@@ -90,6 +91,20 @@ interface RecordSideEffectInput {
|
|
|
90
91
|
* prefix), so a categorical and a scalar facet can share a name.
|
|
91
92
|
*/
|
|
92
93
|
scalars?: Record<string, unknown>;
|
|
94
|
+
/**
|
|
95
|
+
* Optional producer-asserted boolean relations (invariants) emitted on
|
|
96
|
+
* the categorical field channel. Keys must be camelCase ending in
|
|
97
|
+
* `Holds` (e.g. `timezonePreservedHolds`); values are real `boolean`s,
|
|
98
|
+
* coerced to `"true"`/`"false"` on the wire. A non-`Holds` key, a
|
|
99
|
+
* non-boolean value, or a key already attached by `fields` (a
|
|
100
|
+
* same-channel collision — `fields` wins) is dropped with the matching
|
|
101
|
+
* omission counter. Relations count against the same product-side
|
|
102
|
+
* per-operation field budget as `fields` (enforced at projection).
|
|
103
|
+
*
|
|
104
|
+
* Use {@link invariant} / {@link isNullInvariant} to compute the
|
|
105
|
+
* boolean from a comparison.
|
|
106
|
+
*/
|
|
107
|
+
relations?: Record<string, boolean>;
|
|
93
108
|
}
|
|
94
109
|
/**
|
|
95
110
|
* Record allowlisted side-effect evidence on the current active OTel
|
|
@@ -143,4 +158,227 @@ interface RecordSideEffectInput {
|
|
|
143
158
|
*/
|
|
144
159
|
declare function recordSideEffect(input: RecordSideEffectInput): void;
|
|
145
160
|
|
|
146
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Public value-capture primitive (L1 passive capture).
|
|
163
|
+
*
|
|
164
|
+
* {@link capture} emits a single allowlisted value-fidelity scalar onto a
|
|
165
|
+
* caller-**owned** OTel span. It is the counterpart to {@link
|
|
166
|
+
* recordSideEffect} for the case where the emitter owns the target span
|
|
167
|
+
* itself (e.g. a passive database adapter that opens a `db.<Model>.<op>`
|
|
168
|
+
* span) rather than attaching to the ambient active span.
|
|
169
|
+
*
|
|
170
|
+
* Why this exists: {@link recordSideEffect} is ambient-only — it resolves
|
|
171
|
+
* the active span via `getActiveSpan()`. A passive adapter cannot use it,
|
|
172
|
+
* because at its capture point the ambient span is the database client's
|
|
173
|
+
* own operation span, which has already ended and is non-recording. So the
|
|
174
|
+
* adapter must own a fresh recording span and emit onto it explicitly.
|
|
175
|
+
*
|
|
176
|
+
* The behavior contract mirrors {@link recordSideEffect}: observational
|
|
177
|
+
* only. `capture` never executes a side effect, never reads or mutates the
|
|
178
|
+
* captured value's source, and **never throws**. Every failure mode
|
|
179
|
+
* (capture-config disabled, ended / `NonRecordingSpan` target, allowlist
|
|
180
|
+
* rejection, OTel attribute-slot exhaustion) routes to a silent no-op or to
|
|
181
|
+
* an omission-counter increment that carries no rejected input.
|
|
182
|
+
*
|
|
183
|
+
* Capture is **strict-mode only**: timestamp-shaped and unhashed-identifier
|
|
184
|
+
* values are rejected at emit so they never reach the wire. The `full`
|
|
185
|
+
* fidelity relaxation is not reachable through this primitive.
|
|
186
|
+
*/
|
|
187
|
+
|
|
188
|
+
/** Options for {@link capture}. */
|
|
189
|
+
interface CaptureOptions {
|
|
190
|
+
/**
|
|
191
|
+
* The caller-owned, recording span to attach the scalar to. `capture`
|
|
192
|
+
* writes only to this span; it never resolves or touches the ambient
|
|
193
|
+
* active span. The caller is responsible for `end()`-ing it.
|
|
194
|
+
*/
|
|
195
|
+
span: Span;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Emit a single allowlisted value-fidelity scalar onto a caller-owned span.
|
|
199
|
+
*
|
|
200
|
+
* The scalar `name` must match the value-fidelity scalar key pattern
|
|
201
|
+
* (`*Ms` / `*Amount` / `*Bytes` / `*Ratio` / `*Id` / `*Value` / `*Flag`)
|
|
202
|
+
* and its value must match the suffix type — e.g. a `*Flag` key requires a
|
|
203
|
+
* `boolean`. Mismatches, timestamp-shaped values, and unhashed `*Id`s are
|
|
204
|
+
* rejected under strict mode and recorded as an omission count on the
|
|
205
|
+
* supplied span (never the active span).
|
|
206
|
+
*
|
|
207
|
+
* Edge cases (all silent no-ops, never throws):
|
|
208
|
+
* - capture-config flag `sideEffectEvidence` is `false` ⇒ no-op, **no
|
|
209
|
+
* counter** (mirrors {@link recordSideEffect}: with capture disabled the
|
|
210
|
+
* SDK does no allowlist evaluation and writes nothing).
|
|
211
|
+
* - the supplied span has already ended or is a `NonRecordingSpan` ⇒
|
|
212
|
+
* no-op, **no counter** (its omission counter would itself be a dropped
|
|
213
|
+
* span write). The owning adapter passes a fresh recording span, so this
|
|
214
|
+
* is a caller-misuse guard.
|
|
215
|
+
* - the value fails strict allowlist validation ⇒ an omission count is
|
|
216
|
+
* recorded on the supplied span; the rejected value is never emitted.
|
|
217
|
+
* - OTel attribute-slot exhaustion ⇒ the attribute write is silently
|
|
218
|
+
* dropped.
|
|
219
|
+
*
|
|
220
|
+
* @example Project a boolean result field onto an owned database span
|
|
221
|
+
* ```ts
|
|
222
|
+
* import { capture } from "@glasstrace/sdk";
|
|
223
|
+
*
|
|
224
|
+
* const span = tracer.startSpan("db.Poll.findUnique");
|
|
225
|
+
* try {
|
|
226
|
+
* const row = await query(args);
|
|
227
|
+
* if (row) capture("mutedFlag", row.muted, { span });
|
|
228
|
+
* return row;
|
|
229
|
+
* } finally {
|
|
230
|
+
* span.end();
|
|
231
|
+
* }
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
declare function capture(name: string, value: unknown, options: CaptureOptions): void;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Passive Prisma value-capture adapter (L1 capture).
|
|
238
|
+
*
|
|
239
|
+
* `prismaAdapter({ allow })` returns a Prisma client extension that, for
|
|
240
|
+
* each allowlisted `(model, column)`, projects a boolean result field onto
|
|
241
|
+
* a Glasstrace value-fidelity scalar so an agent can read it back from the
|
|
242
|
+
* trace. It is **passive and observational**: it never executes a query
|
|
243
|
+
* itself, never reads or mutates the result, and never changes query
|
|
244
|
+
* behavior or errors.
|
|
245
|
+
*
|
|
246
|
+
* Apply it like any Prisma extension:
|
|
247
|
+
*
|
|
248
|
+
* ```ts
|
|
249
|
+
* import { prismaAdapter } from "@glasstrace/sdk";
|
|
250
|
+
*
|
|
251
|
+
* const prisma = new PrismaClient().$extends(
|
|
252
|
+
* prismaAdapter({ allow: [{ model: "Poll", column: "muted" }] }),
|
|
253
|
+
* );
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* Design:
|
|
257
|
+
* - **OWN a span.** At the capture point the database client's own
|
|
258
|
+
* operation span has already ended, so the adapter opens its own
|
|
259
|
+
* recording `db.<Model>.<op>` span (parented under the active request
|
|
260
|
+
* span) and emits onto it via {@link capture}.
|
|
261
|
+
* - **Default-deny.** Nothing is captured unless an explicit `allow` entry
|
|
262
|
+
* matches AND the server-pushed `sideEffectEvidence` capture flag is on.
|
|
263
|
+
* An empty / unset `allow` captures nothing.
|
|
264
|
+
* - **Boolean only.** This adapter projects boolean columns (the strict,
|
|
265
|
+
* no-`captureFidelity:full` case). Non-boolean allowlisted columns route
|
|
266
|
+
* to a safe omission counter, never a captured value.
|
|
267
|
+
* - **Pure observer.** Capture work can never throw into the host query;
|
|
268
|
+
* the owned span is always ended; the original query error is re-thrown
|
|
269
|
+
* verbatim.
|
|
270
|
+
* - **Bounded.** `findMany` / list operations are disabled (no per-row
|
|
271
|
+
* capture). The adapter never widens the app's `select`.
|
|
272
|
+
*
|
|
273
|
+
* This module has **no dependency on `@prisma/client`** — it is typed
|
|
274
|
+
* structurally against Prisma's client-extension shape (mirroring the
|
|
275
|
+
* Drizzle adapter), so it adds no runtime dependency and ships on the edge-
|
|
276
|
+
* safe root barrel. On a runtime with no active request span (e.g. an edge
|
|
277
|
+
* runtime with no AsyncLocalStorage), it captures nothing.
|
|
278
|
+
*/
|
|
279
|
+
/** The arguments Prisma passes to a `$allOperations` query-extension callback. */
|
|
280
|
+
interface PrismaAllOperationsArgs {
|
|
281
|
+
/** The Prisma model name (PascalCase, e.g. `Poll`), or `undefined` for raw ops. */
|
|
282
|
+
model?: string;
|
|
283
|
+
/** The Prisma operation (e.g. `findUnique`, `findMany`, `update`). */
|
|
284
|
+
operation: string;
|
|
285
|
+
/** The operation arguments, forwarded unchanged to `query`. */
|
|
286
|
+
args: unknown;
|
|
287
|
+
/** Executes the underlying operation. Called exactly once. */
|
|
288
|
+
query: (args: unknown) => Promise<unknown>;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* A Prisma client extension — the object passed to `prisma.$extends(...)`.
|
|
292
|
+
* Structurally typed so the adapter needs no `@prisma/client` dependency.
|
|
293
|
+
*/
|
|
294
|
+
interface PrismaCaptureExtension {
|
|
295
|
+
name: string;
|
|
296
|
+
query: {
|
|
297
|
+
$allModels: {
|
|
298
|
+
$allOperations(args: PrismaAllOperationsArgs): Promise<unknown>;
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
/** A single allowlisted column to project. */
|
|
303
|
+
interface PrismaCaptureColumn {
|
|
304
|
+
/** The Prisma model name, PascalCase, exactly as Prisma reports it (e.g. `Poll`). */
|
|
305
|
+
model: string;
|
|
306
|
+
/** The boolean result column to project (e.g. `muted`). */
|
|
307
|
+
column: string;
|
|
308
|
+
}
|
|
309
|
+
/** Options for {@link prismaAdapter}. */
|
|
310
|
+
interface PrismaAdapterOptions {
|
|
311
|
+
/**
|
|
312
|
+
* The default-deny allowlist. Only `(model, column)` pairs listed here are
|
|
313
|
+
* eligible for capture; an empty or unset list captures nothing. The
|
|
314
|
+
* server-side per-tenant allowlist re-enforces this independently at
|
|
315
|
+
* ingestion.
|
|
316
|
+
*/
|
|
317
|
+
allow?: ReadonlyArray<PrismaCaptureColumn>;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Build a passive Prisma value-capture extension. See the module doc for
|
|
321
|
+
* the full behavior contract.
|
|
322
|
+
*/
|
|
323
|
+
declare function prismaAdapter(options?: PrismaAdapterOptions): PrismaCaptureExtension;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Producer-sugar for computing boolean relations to emit as `*Holds`
|
|
327
|
+
* side-effect evidence.
|
|
328
|
+
*
|
|
329
|
+
* These helpers turn a comparison into the boolean a producer passes to
|
|
330
|
+
* `recordSideEffect({ relations: { …Holds: invariant(a, "eq", b) } })`.
|
|
331
|
+
* They are pure (no I/O, no Node built-ins) and edge-safe, so they live
|
|
332
|
+
* on the root barrel. The operator set is intentionally minimal and
|
|
333
|
+
* fixed — six binary comparisons plus a separate unary null check — and
|
|
334
|
+
* is not a general expression DSL.
|
|
335
|
+
*/
|
|
336
|
+
/**
|
|
337
|
+
* The six supported binary comparison operators. `isNull` is **not** an
|
|
338
|
+
* operator here — use {@link isNullInvariant} for the unary case.
|
|
339
|
+
*/
|
|
340
|
+
type InvariantOp = "eq" | "neq" | "lt" | "lte" | "gt" | "gte";
|
|
341
|
+
/**
|
|
342
|
+
* Evaluate a binary comparison invariant and return the boolean result.
|
|
343
|
+
*
|
|
344
|
+
* Both operands are constrained to the same primitive type. `eq`/`neq`
|
|
345
|
+
* use strict equality; the ordering operators (`lt`/`lte`/`gt`/`gte`)
|
|
346
|
+
* use the language relational operators (numeric for numbers/bigints,
|
|
347
|
+
* lexical for strings). Intended for producing a `*Holds` relation, e.g.
|
|
348
|
+
* `invariant(emittedDurationMinutes, "eq", declaredDurationMinutes)`.
|
|
349
|
+
*
|
|
350
|
+
* Operands should be comparable primitives. `NaN` follows IEEE-754
|
|
351
|
+
* (unequal to everything; all orderings `false`), so screen `NaN` before
|
|
352
|
+
* asserting a relation. Passing a non-primitive (e.g. a `Symbol`, or an
|
|
353
|
+
* object with a throwing `valueOf`) to an ordering operator throws per
|
|
354
|
+
* JS semantics — the type signature prevents this for typed callers.
|
|
355
|
+
*
|
|
356
|
+
* @param left - The left operand.
|
|
357
|
+
* @param op - One of the six {@link InvariantOp} comparisons.
|
|
358
|
+
* @param right - The right operand (same primitive type as `left`).
|
|
359
|
+
* @returns The boolean result of `left <op> right`.
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* recordSideEffect({
|
|
363
|
+
* kind: "calendar_link",
|
|
364
|
+
* operation: "invite.create",
|
|
365
|
+
* relations: {
|
|
366
|
+
* durationMatchesHolds: invariant(emittedMinutes, "eq", declaredMinutes),
|
|
367
|
+
* },
|
|
368
|
+
* });
|
|
369
|
+
*/
|
|
370
|
+
declare function invariant<T extends number | string | bigint | boolean>(left: T, op: InvariantOp, right: T): boolean;
|
|
371
|
+
/**
|
|
372
|
+
* Unary null/undefined invariant — `true` when `value` is `null` or
|
|
373
|
+
* `undefined`. Kept separate from {@link invariant} because nullishness
|
|
374
|
+
* is a unary predicate, not a binary comparison (there is no `isNull`
|
|
375
|
+
* operator). Use for a `*Holds` relation asserting a value's absence,
|
|
376
|
+
* e.g. `relations: { recipientMissingHolds: isNullInvariant(recipient) }`.
|
|
377
|
+
*
|
|
378
|
+
* @param value - The value to test.
|
|
379
|
+
* @returns `true` when `value` is `null` or `undefined`, else `false`
|
|
380
|
+
* (falsy-but-present values like `0`, `""`, `false`, `NaN` are `false`).
|
|
381
|
+
*/
|
|
382
|
+
declare function isNullInvariant(value: unknown): boolean;
|
|
383
|
+
|
|
384
|
+
export { type CaptureOptions, type InvariantOp, type PrismaAdapterOptions, type PrismaCaptureColumn, type PrismaCaptureExtension, type RecordSideEffectInput, SideEffectOperationKind, SideEffectOperationPhase, SideEffectOperationStatus, SideEffectSemanticFieldKey, capture, invariant, isNullInvariant, prismaAdapter, recordSideEffect };
|