@glasstrace/sdk 1.15.0 → 1.16.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 (74) hide show
  1. package/README.md +117 -8
  2. package/dist/async-context/index.cjs +21 -2
  3. package/dist/async-context/index.cjs.map +1 -1
  4. package/dist/async-context/index.js +2 -2
  5. package/dist/{capture-error-03qDnC5v.d.cts → capture-error-B0txjNut.d.cts} +2 -2
  6. package/dist/{capture-error-CAfFUyIU.d.ts → capture-error-Dc01rYNR.d.ts} +2 -2
  7. package/dist/{chunk-F7A3QXCT.js → chunk-774XIOZG.js} +2 -2
  8. package/dist/{chunk-VMK2G6QR.js → chunk-AFTCLH77.js} +2 -2
  9. package/dist/{chunk-XMD5OYD6.js → chunk-BGJKEFBN.js} +2 -2
  10. package/dist/{chunk-LQZRGBN5.js → chunk-DW3CZDS6.js} +2 -2
  11. package/dist/{chunk-PSMSSLQY.js → chunk-EWW3TZ52.js} +123 -12
  12. package/dist/{chunk-PSMSSLQY.js.map → chunk-EWW3TZ52.js.map} +1 -1
  13. package/dist/{chunk-7LE2O4ZJ.js → chunk-GBVMPMVV.js} +54 -5
  14. package/dist/{chunk-7LE2O4ZJ.js.map → chunk-GBVMPMVV.js.map} +1 -1
  15. package/dist/{chunk-HMEHYSTS.js → chunk-KM4UNN3Q.js} +2 -2
  16. package/dist/{chunk-MP3QNDXQ.js → chunk-OHSX224U.js} +2 -2
  17. package/dist/{chunk-6ST4QV7T.js → chunk-T7B752NF.js} +3 -3
  18. package/dist/{chunk-ZIYT2Y4B.js → chunk-WOYJAG7H.js} +3 -3
  19. package/dist/cli/init.cjs +18 -5
  20. package/dist/cli/init.cjs.map +1 -1
  21. package/dist/cli/init.js +7 -7
  22. package/dist/cli/mcp-add.cjs +15 -2
  23. package/dist/cli/mcp-add.cjs.map +1 -1
  24. package/dist/cli/mcp-add.js +3 -3
  25. package/dist/cli/uninit.js +3 -3
  26. package/dist/cli/upgrade-instructions.cjs +1 -1
  27. package/dist/cli/upgrade-instructions.js +3 -3
  28. package/dist/cli/validate.cjs +14 -1
  29. package/dist/cli/validate.cjs.map +1 -1
  30. package/dist/cli/validate.js +2 -2
  31. package/dist/{correlation-id-YcfcqOru.d.ts → correlation-id-B9YYmoZw.d.ts} +1 -1
  32. package/dist/{correlation-id-CZ2bstzA.d.cts → correlation-id-CelUvw7j.d.cts} +1 -1
  33. package/dist/edge-entry.cjs +21 -2
  34. package/dist/edge-entry.cjs.map +1 -1
  35. package/dist/edge-entry.d.cts +2 -2
  36. package/dist/edge-entry.d.ts +2 -2
  37. package/dist/edge-entry.js +4 -4
  38. package/dist/import-graph-DBLGNjcI.d.cts +238 -0
  39. package/dist/import-graph-Dka_Fm7j.d.ts +238 -0
  40. package/dist/index.cjs +165 -12
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/{index.d-BQIJ5Dvc.d.cts → index.d-3-cJoY8y.d.cts} +10 -2
  43. package/dist/{index.d-BQIJ5Dvc.d.ts → index.d-3-cJoY8y.d.ts} +10 -2
  44. package/dist/index.d.cts +28 -4
  45. package/dist/index.d.ts +28 -4
  46. package/dist/index.js +5 -5
  47. package/dist/middleware/index.cjs +21 -2
  48. package/dist/middleware/index.cjs.map +1 -1
  49. package/dist/middleware/index.js +2 -2
  50. package/dist/node-entry.cjs +56 -9
  51. package/dist/node-entry.cjs.map +1 -1
  52. package/dist/node-entry.d.cts +4 -4
  53. package/dist/node-entry.d.ts +4 -4
  54. package/dist/node-entry.js +7 -7
  55. package/dist/node-subpath.cjs +27 -1
  56. package/dist/node-subpath.cjs.map +1 -1
  57. package/dist/node-subpath.d.cts +51 -235
  58. package/dist/node-subpath.d.ts +51 -235
  59. package/dist/node-subpath.js +16 -3
  60. package/dist/node-subpath.js.map +1 -1
  61. package/dist/{source-map-uploader-NUONOEJG.js → source-map-uploader-UJPZCUFN.js} +3 -3
  62. package/dist/trpc/index.cjs +21 -2
  63. package/dist/trpc/index.cjs.map +1 -1
  64. package/dist/trpc/index.js +1 -1
  65. package/package.json +1 -1
  66. /package/dist/{chunk-F7A3QXCT.js.map → chunk-774XIOZG.js.map} +0 -0
  67. /package/dist/{chunk-VMK2G6QR.js.map → chunk-AFTCLH77.js.map} +0 -0
  68. /package/dist/{chunk-XMD5OYD6.js.map → chunk-BGJKEFBN.js.map} +0 -0
  69. /package/dist/{chunk-LQZRGBN5.js.map → chunk-DW3CZDS6.js.map} +0 -0
  70. /package/dist/{chunk-HMEHYSTS.js.map → chunk-KM4UNN3Q.js.map} +0 -0
  71. /package/dist/{chunk-MP3QNDXQ.js.map → chunk-OHSX224U.js.map} +0 -0
  72. /package/dist/{chunk-6ST4QV7T.js.map → chunk-T7B752NF.js.map} +0 -0
  73. /package/dist/{chunk-ZIYT2Y4B.js.map → chunk-WOYJAG7H.js.map} +0 -0
  74. /package/dist/{source-map-uploader-NUONOEJG.js.map → source-map-uploader-UJPZCUFN.js.map} +0 -0
package/README.md CHANGED
@@ -363,6 +363,49 @@ A future SDK release may extend the auto-attach detection to recognize
363
363
  additional Next 16 provider shapes; until that ships, the manual path
364
364
  above is the production-supported integration.
365
365
 
366
+ ## Database query spans (Prisma)
367
+
368
+ When Glasstrace manages the OpenTelemetry provider — the default when
369
+ your app does not already run its own OpenTelemetry or Sentry setup — it
370
+ automatically instruments [Prisma](https://www.prisma.io/) queries.
371
+ Install
372
+ [`@prisma/instrumentation`](https://www.npmjs.com/package/@prisma/instrumentation)
373
+ (an optional peer dependency, Prisma 4–7) and query spans appear once the
374
+ package is reachable; no extra wiring is required.
375
+
376
+ If Glasstrace instead detects a provider you already registered (Sentry,
377
+ a custom OpenTelemetry SDK, and similar), it attaches its exporter to
378
+ that provider rather than taking over instrumentation — so it does not
379
+ add Prisma instrumentation itself, and the diagnostic below does not
380
+ apply. Register `@prisma/instrumentation` on your own provider;
381
+ Glasstrace exports the spans it produces.
382
+
383
+ Prisma ORM versions **4.2.0 through 6.1.0** additionally require enabling
384
+ the `tracing`
385
+ [preview feature](https://www.prisma.io/docs/orm/prisma-client/observability-and-logging/opentelemetry-tracing)
386
+ in your schema's `generator` block — `previewFeatures = ["tracing"]` —
387
+ before any tracing spans are emitted. Later Prisma versions need no flag.
388
+
389
+ **Missing Prisma query spans?** On Prisma 4.2.0–6.1.0, first confirm the
390
+ `tracing` preview feature above is enabled. Otherwise, the usual cause is
391
+ a package manager that does not expose transitive copies of optional
392
+ peers. Under pnpm's
393
+ strict, isolated `node_modules`, `@prisma/instrumentation` can sit in
394
+ the virtual store (pulled in by another dependency) without being
395
+ linked into your app's `node_modules/@prisma/` — so the SDK's optional
396
+ import resolves to nothing and Prisma spans are silently skipped. Add it
397
+ as a **direct dependency** of your app:
398
+
399
+ ```bash
400
+ npm install @prisma/instrumentation
401
+ # pnpm add @prisma/instrumentation
402
+ ```
403
+
404
+ To confirm whether it was loaded, enable verbose mode
405
+ (`registerGlasstrace({ verbose: true })`): when
406
+ `@prisma/instrumentation` cannot be loaded, the SDK logs a diagnostic
407
+ noting that Prisma query spans will not be captured.
408
+
366
409
  ## Capturing error response bodies
367
410
 
368
411
  When debugging a 4xx or 5xx, the response body is often the most useful
@@ -627,6 +670,63 @@ ingestion service before persistence. This is intentional
627
670
  defense-in-depth: the SDK is the first gate; the product receiver
628
671
  is the second.
629
672
 
673
+ ### Value-fidelity scalars
674
+
675
+ Beyond the categorical `fields` channel, `recordSideEffect()` accepts an
676
+ optional `scalars` map for type-aware magnitudes emitted on a separate
677
+ `glasstrace.side_effect.scalar.*` channel. The key suffix declares the
678
+ value type:
679
+
680
+ - `*Ms` / `*Amount` / `*Bytes` / `*Ratio` / `*Value` → a finite `number`
681
+ - `*Flag` → a `boolean`
682
+ - `*Id` → a pseudonymized `gthid_` string (see `hashId` below)
683
+
684
+ (`Count` stays on the categorical `fields` channel; free-form string
685
+ enums belong there too, not on the scalar channel.)
686
+
687
+ ```ts
688
+ import { recordSideEffect } from "@glasstrace/sdk";
689
+ import { hashId } from "@glasstrace/sdk/node";
690
+
691
+ recordSideEffect({
692
+ kind: "external_api",
693
+ operation: "charge.create",
694
+ status: "succeeded",
695
+ scalars: {
696
+ latencyMs: 142, // bounded delta — not a wall-clock epoch
697
+ amountValue: 1999, // a magnitude
698
+ retriedFlag: false, // a boolean condition
699
+ // Identifiers must be pseudonymized; raw ids are rejected.
700
+ customerId: hashId(rawCustomerId, process.env.GLASSTRACE_ATTR_HMAC_KEY!),
701
+ },
702
+ });
703
+ ```
704
+
705
+ Scalars are validated at emit time under a **fail-closed `strict`**
706
+ posture. (An account-level `captureFidelity` setting that can relax the
707
+ timestamp/identifier rejections is part of the wire contract but is **not
708
+ active in this release** — scalars are always validated as `strict`
709
+ here.) Under `strict` the SDK rejects values that would leak raw,
710
+ high-cardinality data before they reach the wire, recording only an
711
+ integer omission count:
712
+
713
+ | Rejected value | Omission reason |
714
+ |---|---|
715
+ | A `Date`, or a raw epoch on a `*Ms` key | `raw_timestamp` |
716
+ | A non-`gthid_` value on an `*Id` key | `unhashed_id` |
717
+ | `NaN` / `±Infinity` | `non_finite` |
718
+ | A value whose type doesn't match its key suffix (e.g. a string or boolean on `*Ms`) | `raw_payload` |
719
+ | A key not matching the scalar pattern | `unsupported_key` |
720
+ | More than 16 scalars in one call (the excess are dropped) | `value_too_long` |
721
+
722
+ Send **bounded deltas as numbers** (e.g. `latencyMs: 142`), not absolute
723
+ timestamps. Note that raw-epoch screening applies only to `*Ms` keys (the
724
+ time-typed suffix) — keep wall-clock values off other numeric suffixes.
725
+ Pseudonymize identifiers with **`hashId`** (HMAC-SHA256, fixed-shape
726
+ `gthid_<hex>`, fail-closed — returns `null` without a key), which ships on
727
+ the Node-only `@glasstrace/sdk/node` subpath because it uses
728
+ `node:crypto`. At most 16 scalars are recorded per operation.
729
+
630
730
  ## Source maps
631
731
 
632
732
  Glasstrace uploads server-side source maps at build time and resolves
@@ -798,7 +898,7 @@ without a deprecation cycle. Rely on the static file.
798
898
 
799
899
  ## Subpath exports
800
900
 
801
- `@glasstrace/sdk` ships four public entries:
901
+ `@glasstrace/sdk` ships six public entries:
802
902
 
803
903
  - **`@glasstrace/sdk`** — primary import site. Use from
804
904
  `instrumentation.ts` (runtime instrumentation) and `next.config.ts`
@@ -810,14 +910,19 @@ without a deprecation cycle. Rely on the static file.
810
910
  runtimes; workloads running strictly on workerd or Vercel Edge
811
911
  should import from the internal edge-entry bundle — not currently
812
912
  exposed as a public entry — or ask for a public `/edge` subpath.
813
- - **`@glasstrace/sdk/node`** — Node-only build-time tooling
814
- (source-map uploading, import-graph construction). Use from
815
- `next.config.ts` / build scripts. Resolves only under the Node
816
- condition; non-Node runtimes (workerd, edge-light) fail cleanly at
817
- module resolution rather than at evaluation.
913
+ - **`@glasstrace/sdk/node`** — Node-only helpers: build-time tooling
914
+ (source-map uploading, import-graph construction) plus the request-time
915
+ `hashId` identifier-pseudonymization helper for value-fidelity scalars.
916
+ Resolves only under the Node condition; non-Node runtimes (workerd,
917
+ edge-light) fail cleanly at module resolution rather than at
918
+ evaluation.
818
919
  - **`@glasstrace/sdk/drizzle`** — Drizzle ORM adapter.
819
920
  - **`@glasstrace/sdk/trpc`** — tRPC middleware-chain instrumentation.
820
921
  See "tRPC middleware instrumentation" below.
922
+ - **`@glasstrace/sdk/middleware`** — request-middleware tracing wrapper
923
+ (`tracedRequestMiddleware`).
924
+ - **`@glasstrace/sdk/async-context`** — async causality propagation
925
+ (`withAsyncCausality`).
821
926
 
822
927
  The source-map and import-graph helpers previously reachable from the
823
928
  `@glasstrace/sdk` root specifier have moved to `@glasstrace/sdk/node`
@@ -863,11 +968,15 @@ and the recommended call site.
863
968
  | `discoverTestFiles` | function | `node:fs`, `node:path` | — (call from a build script / CI job) |
864
969
  | `extractImports` | function | — (pure string processing) | — (kept under `/node` for API cohesion with `buildImportGraph`) |
865
970
  | `buildImportGraph` | function | `node:fs`, `node:path`, `node:crypto` | — (call from a build script / CI job) |
971
+ | `hashId` | function | `node:crypto` | — (call from the request handler that records the side effect) |
866
972
 
867
973
  Type exports erase at runtime and are technically safe to import from
868
974
  edge code, but every runtime function that produces or consumes them is
869
- Node-only, so the practical signal is the same: reach for these from
870
- your build pipeline, not from a request handler.
975
+ Node-only, so the practical signal is the same: reach for the source-map
976
+ and import-graph helpers from your build pipeline, not from a request
977
+ handler. `hashId` is the exception — it is a request-time helper for
978
+ pseudonymizing identifiers before `recordSideEffect()`, Node-only only
979
+ because it uses `node:crypto`.
871
980
 
872
981
  #### Why is X Node-only?
873
982
 
@@ -15297,7 +15297,20 @@ var CaptureConfigSchema = external_exports.object({
15297
15297
  * client-side allowlist enforcement layered with the product's
15298
15298
  * storage-time filter as defense-in-depth.
15299
15299
  */
15300
- sideEffectEvidence: external_exports.boolean().optional().default(false)
15300
+ sideEffectEvidence: external_exports.boolean().optional().default(false),
15301
+ /**
15302
+ * Per-account value-fidelity capture posture (server-pushed).
15303
+ *
15304
+ * `strict` (default) is fail-closed: the SDK rejects raw wall-clock
15305
+ * timestamps and unhashed identifiers from the `scalar.*` channel at
15306
+ * emit time. `full` relaxes those rejections so raw magnitudes can be
15307
+ * surfaced — but only in conjunction with an explicit producer opt-in
15308
+ * (so a `full`-configured account still emits strict-shaped scalars
15309
+ * unless the producer also opts in). The operator owns this flag; it
15310
+ * is never derived from producer or request input. Absent on the wire
15311
+ * ⇒ `strict`.
15312
+ */
15313
+ captureFidelity: external_exports.enum(["strict", "full"]).optional().default("strict")
15301
15314
  });
15302
15315
  var SdkCachedConfigSchema = external_exports.object({
15303
15316
  response: external_exports.record(external_exports.string(), external_exports.unknown()),
@@ -15488,7 +15501,13 @@ var GLASSTRACE_ATTRIBUTE_NAMES = {
15488
15501
  SIDE_EFFECT_OMITTED_UNSUPPORTED_KEY: "glasstrace.side_effect.omitted.unsupported_key",
15489
15502
  SIDE_EFFECT_OMITTED_VALUE_TOO_LONG: "glasstrace.side_effect.omitted.value_too_long",
15490
15503
  SIDE_EFFECT_OMITTED_NOT_EMITTED: "glasstrace.side_effect.omitted.not_emitted",
15491
- SIDE_EFFECT_OMITTED_CAPTURE_DISABLED: "glasstrace.side_effect.omitted.capture_disabled"
15504
+ SIDE_EFFECT_OMITTED_CAPTURE_DISABLED: "glasstrace.side_effect.omitted.capture_disabled",
15505
+ // Value-fidelity scalar-channel omission reasons. Counts only; the
15506
+ // rejected raw value (timestamp, unhashed id, non-finite number) is
15507
+ // never echoed. Mirror the product omission enum verbatim.
15508
+ SIDE_EFFECT_OMITTED_RAW_TIMESTAMP: "glasstrace.side_effect.omitted.raw_timestamp",
15509
+ SIDE_EFFECT_OMITTED_UNHASHED_ID: "glasstrace.side_effect.omitted.unhashed_id",
15510
+ SIDE_EFFECT_OMITTED_NON_FINITE: "glasstrace.side_effect.omitted.non_finite"
15492
15511
  };
15493
15512
  var MAX_SOURCE_MAP_FILE_PATH_LENGTH = 512;
15494
15513
  var MAX_SOURCE_MAP_FILE_SIZE = 50 * 1024 * 1024;