@glasstrace/sdk 1.15.1 → 1.17.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 +118 -11
- package/dist/async-context/index.cjs +21 -2
- package/dist/async-context/index.cjs.map +1 -1
- package/dist/async-context/index.js +2 -2
- package/dist/{capture-error-03qDnC5v.d.cts → capture-error-B0txjNut.d.cts} +2 -2
- package/dist/{capture-error-CAfFUyIU.d.ts → capture-error-Dc01rYNR.d.ts} +2 -2
- package/dist/{chunk-ZIYT2Y4B.js → chunk-BJOZBAP7.js} +3 -3
- package/dist/{chunk-VMK2G6QR.js → chunk-CN5EP25B.js} +2 -2
- package/dist/{chunk-HMEHYSTS.js → chunk-EVX6D2TX.js} +2 -2
- package/dist/{chunk-T4ETJJSK.js → chunk-F2IPBTDJ.js} +133 -11
- package/dist/{chunk-T4ETJJSK.js.map → chunk-F2IPBTDJ.js.map} +1 -1
- package/dist/{chunk-XMD5OYD6.js → chunk-M3QGJUEI.js} +2 -2
- package/dist/{chunk-7LE2O4ZJ.js → chunk-MKT54VEH.js} +55 -6
- package/dist/{chunk-7LE2O4ZJ.js.map → chunk-MKT54VEH.js.map} +1 -1
- package/dist/{chunk-MP3QNDXQ.js → chunk-O7IJP2TQ.js} +2 -2
- package/dist/{chunk-F7A3QXCT.js → chunk-UOAG72NR.js} +2 -2
- package/dist/{chunk-6ST4QV7T.js → chunk-VEQX2YSQ.js} +3 -3
- package/dist/{chunk-LQZRGBN5.js → chunk-YKE6HJLW.js} +2 -2
- package/dist/cli/init.cjs +18 -5
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +7 -7
- package/dist/cli/mcp-add.cjs +15 -2
- 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 +14 -1
- package/dist/cli/validate.cjs.map +1 -1
- package/dist/cli/validate.js +2 -2
- package/dist/{correlation-id-YcfcqOru.d.ts → correlation-id-B9YYmoZw.d.ts} +1 -1
- package/dist/{correlation-id-CZ2bstzA.d.cts → correlation-id-CelUvw7j.d.cts} +1 -1
- package/dist/edge-entry.cjs +21 -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 +4 -4
- package/dist/import-graph-DBLGNjcI.d.cts +238 -0
- package/dist/import-graph-Dka_Fm7j.d.ts +238 -0
- package/dist/index.cjs +203 -12
- package/dist/index.cjs.map +1 -1
- package/dist/{index.d-BQIJ5Dvc.d.cts → index.d-3-cJoY8y.d.cts} +10 -2
- package/dist/{index.d-BQIJ5Dvc.d.ts → index.d-3-cJoY8y.d.ts} +10 -2
- package/dist/index.d.cts +102 -5
- package/dist/index.d.ts +102 -5
- package/dist/index.js +30 -5
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.cjs +21 -2
- package/dist/middleware/index.cjs.map +1 -1
- package/dist/middleware/index.js +2 -2
- package/dist/node-entry.cjs +28 -8
- 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 +27 -1
- package/dist/node-subpath.cjs.map +1 -1
- package/dist/node-subpath.d.cts +51 -235
- package/dist/node-subpath.d.ts +51 -235
- package/dist/node-subpath.js +16 -3
- package/dist/node-subpath.js.map +1 -1
- package/dist/{source-map-uploader-NUONOEJG.js → source-map-uploader-U7SLSKIZ.js} +3 -3
- package/dist/trpc/index.cjs +21 -2
- package/dist/trpc/index.cjs.map +1 -1
- package/dist/trpc/index.js +1 -1
- package/package.json +1 -1
- /package/dist/{chunk-ZIYT2Y4B.js.map → chunk-BJOZBAP7.js.map} +0 -0
- /package/dist/{chunk-VMK2G6QR.js.map → chunk-CN5EP25B.js.map} +0 -0
- /package/dist/{chunk-HMEHYSTS.js.map → chunk-EVX6D2TX.js.map} +0 -0
- /package/dist/{chunk-XMD5OYD6.js.map → chunk-M3QGJUEI.js.map} +0 -0
- /package/dist/{chunk-MP3QNDXQ.js.map → chunk-O7IJP2TQ.js.map} +0 -0
- /package/dist/{chunk-F7A3QXCT.js.map → chunk-UOAG72NR.js.map} +0 -0
- /package/dist/{chunk-6ST4QV7T.js.map → chunk-VEQX2YSQ.js.map} +0 -0
- /package/dist/{chunk-LQZRGBN5.js.map → chunk-YKE6HJLW.js.map} +0 -0
- /package/dist/{source-map-uploader-NUONOEJG.js.map → source-map-uploader-U7SLSKIZ.js.map} +0 -0
package/README.md
CHANGED
|
@@ -580,9 +580,9 @@ Values are bounded to identifier-shaped compact tokens, with
|
|
|
580
580
|
specialized BCP-47 validation for `locale` and IANA validation for
|
|
581
581
|
`timezone`.
|
|
582
582
|
|
|
583
|
-
**Open pattern** (
|
|
584
|
-
`^[a-z][A-Za-z0-9]*(Class|Count|Kind|Role)$` are admitted
|
|
585
|
-
the stable core. Value shapes are suffix-routed:
|
|
583
|
+
**Open pattern** (5 canonical suffixes): keys matching
|
|
584
|
+
`^[a-z][A-Za-z0-9]*(Class|Count|Kind|Role|Holds)$` are admitted
|
|
585
|
+
alongside the stable core. Value shapes are suffix-routed:
|
|
586
586
|
|
|
587
587
|
| Suffix | Value shape | Max length | Casing convention | Examples |
|
|
588
588
|
|---|---|---|---|---|
|
|
@@ -590,6 +590,7 @@ the stable core. Value shapes are suffix-routed:
|
|
|
590
590
|
| `*Count` | non-negative integer string | 16 | digits only (no `-`, `.`, or letters) | `participantCount="2"`, `attemptCount="3"` |
|
|
591
591
|
| `*Kind` | identifier-shaped compact token | 80 | lowerCamel or `UPPERCASE-CONST` | `notificationKind=transactional` |
|
|
592
592
|
| `*Role` | identifier-shaped compact token | 80 | lowercase-kebab | `actorRole=operator` |
|
|
593
|
+
| `*Holds` | boolean-literal string | 5 | `"true"` / `"false"` only | `timezonePreservedHolds="false"` (see [Boolean relations](#boolean-relations-holds)) |
|
|
593
594
|
|
|
594
595
|
Value casing is preserved verbatim; normalize at the call site so
|
|
595
596
|
cross-trace comparisons collapse to the same identity. Non-digit
|
|
@@ -670,6 +671,103 @@ ingestion service before persistence. This is intentional
|
|
|
670
671
|
defense-in-depth: the SDK is the first gate; the product receiver
|
|
671
672
|
is the second.
|
|
672
673
|
|
|
674
|
+
### Value-fidelity scalars
|
|
675
|
+
|
|
676
|
+
Beyond the categorical `fields` channel, `recordSideEffect()` accepts an
|
|
677
|
+
optional `scalars` map for type-aware magnitudes emitted on a separate
|
|
678
|
+
`glasstrace.side_effect.scalar.*` channel. The key suffix declares the
|
|
679
|
+
value type:
|
|
680
|
+
|
|
681
|
+
- `*Ms` / `*Amount` / `*Bytes` / `*Ratio` / `*Value` → a finite `number`
|
|
682
|
+
- `*Flag` → a `boolean`
|
|
683
|
+
- `*Id` → a pseudonymized `gthid_` string (see `hashId` below)
|
|
684
|
+
|
|
685
|
+
(`Count` stays on the categorical `fields` channel; free-form string
|
|
686
|
+
enums belong there too, not on the scalar channel.)
|
|
687
|
+
|
|
688
|
+
```ts
|
|
689
|
+
import { recordSideEffect } from "@glasstrace/sdk";
|
|
690
|
+
import { hashId } from "@glasstrace/sdk/node";
|
|
691
|
+
|
|
692
|
+
recordSideEffect({
|
|
693
|
+
kind: "external_api",
|
|
694
|
+
operation: "charge.create",
|
|
695
|
+
status: "succeeded",
|
|
696
|
+
scalars: {
|
|
697
|
+
latencyMs: 142, // bounded delta — not a wall-clock epoch
|
|
698
|
+
amountValue: 1999, // a magnitude
|
|
699
|
+
retriedFlag: false, // a boolean condition
|
|
700
|
+
// Identifiers must be pseudonymized; raw ids are rejected.
|
|
701
|
+
customerId: hashId(rawCustomerId, process.env.GLASSTRACE_ATTR_HMAC_KEY!),
|
|
702
|
+
},
|
|
703
|
+
});
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
Scalars are validated at emit time under a **fail-closed `strict`**
|
|
707
|
+
posture. (An account-level `captureFidelity` setting that can relax the
|
|
708
|
+
timestamp/identifier rejections is part of the wire contract but is **not
|
|
709
|
+
active in this release** — scalars are always validated as `strict`
|
|
710
|
+
here.) Under `strict` the SDK rejects values that would leak raw,
|
|
711
|
+
high-cardinality data before they reach the wire, recording only an
|
|
712
|
+
integer omission count:
|
|
713
|
+
|
|
714
|
+
| Rejected value | Omission reason |
|
|
715
|
+
|---|---|
|
|
716
|
+
| A `Date`, or a raw epoch on a `*Ms` key | `raw_timestamp` |
|
|
717
|
+
| A non-`gthid_` value on an `*Id` key | `unhashed_id` |
|
|
718
|
+
| `NaN` / `±Infinity` | `non_finite` |
|
|
719
|
+
| A value whose type doesn't match its key suffix (e.g. a string or boolean on `*Ms`) | `raw_payload` |
|
|
720
|
+
| A key not matching the scalar pattern | `unsupported_key` |
|
|
721
|
+
| More than 16 scalars in one call (the excess are dropped) | `value_too_long` |
|
|
722
|
+
|
|
723
|
+
Send **bounded deltas as numbers** (e.g. `latencyMs: 142`), not absolute
|
|
724
|
+
timestamps. Note that raw-epoch screening applies only to `*Ms` keys (the
|
|
725
|
+
time-typed suffix) — keep wall-clock values off other numeric suffixes.
|
|
726
|
+
Pseudonymize identifiers with **`hashId`** (HMAC-SHA256, fixed-shape
|
|
727
|
+
`gthid_<hex>`, fail-closed — returns `null` without a key), which ships on
|
|
728
|
+
the Node-only `@glasstrace/sdk/node` subpath because it uses
|
|
729
|
+
`node:crypto`. At most 16 scalars are recorded per operation.
|
|
730
|
+
|
|
731
|
+
### Boolean relations (`*Holds`)
|
|
732
|
+
|
|
733
|
+
When the decisive evidence is a *relationship* between values rather than
|
|
734
|
+
the values themselves, emit it as a boolean **relation** on the
|
|
735
|
+
categorical field channel. `recordSideEffect()` accepts a `relations` map
|
|
736
|
+
of `boolean`s keyed by camelCase names ending in `Holds`; values are
|
|
737
|
+
coerced to `"true"`/`"false"`:
|
|
738
|
+
|
|
739
|
+
> **Availability:** the SDK emits `*Holds` relations now, but the Glasstrace
|
|
740
|
+
> backend admits them only once a coordinated release lands; until then a
|
|
741
|
+
> `*Holds` field is dropped at ingestion (like any unrecognized key) and is
|
|
742
|
+
> not yet surfaced in traces. Capture is also gated by the account
|
|
743
|
+
> `sideEffectEvidence` flag.
|
|
744
|
+
|
|
745
|
+
```ts
|
|
746
|
+
import { recordSideEffect, invariant, isNullInvariant } from "@glasstrace/sdk";
|
|
747
|
+
|
|
748
|
+
recordSideEffect({
|
|
749
|
+
kind: "calendar_link",
|
|
750
|
+
operation: "invite.create",
|
|
751
|
+
relations: {
|
|
752
|
+
// Did the emitted duration match what was declared?
|
|
753
|
+
durationMatchesHolds: invariant(emittedMinutes, "eq", declaredMinutes),
|
|
754
|
+
// Was the timezone preserved (not silently dropped)?
|
|
755
|
+
timezonePreservedHolds: invariant(emittedTz, "eq", declaredTz),
|
|
756
|
+
recipientMissingHolds: isNullInvariant(recipient),
|
|
757
|
+
},
|
|
758
|
+
});
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
`invariant(left, op, right)` evaluates one of `eq` / `neq` / `lt` / `lte`
|
|
762
|
+
/ `gt` / `gte` and returns the boolean; `isNullInvariant(value)` is the
|
|
763
|
+
unary `null`/`undefined` check. Both are pure and edge-safe (root barrel).
|
|
764
|
+
|
|
765
|
+
A relation key not ending in `Holds`, a non-boolean value, or a key
|
|
766
|
+
already attached by `fields` (a same-channel collision — `fields` takes
|
|
767
|
+
precedence) is dropped and recorded only as an integer omission count.
|
|
768
|
+
Relations count against the same product-side per-operation field budget
|
|
769
|
+
as `fields` (enforced at projection).
|
|
770
|
+
|
|
673
771
|
## Source maps
|
|
674
772
|
|
|
675
773
|
Glasstrace uploads server-side source maps at build time and resolves
|
|
@@ -841,7 +939,7 @@ without a deprecation cycle. Rely on the static file.
|
|
|
841
939
|
|
|
842
940
|
## Subpath exports
|
|
843
941
|
|
|
844
|
-
`@glasstrace/sdk` ships
|
|
942
|
+
`@glasstrace/sdk` ships six public entries:
|
|
845
943
|
|
|
846
944
|
- **`@glasstrace/sdk`** — primary import site. Use from
|
|
847
945
|
`instrumentation.ts` (runtime instrumentation) and `next.config.ts`
|
|
@@ -853,14 +951,19 @@ without a deprecation cycle. Rely on the static file.
|
|
|
853
951
|
runtimes; workloads running strictly on workerd or Vercel Edge
|
|
854
952
|
should import from the internal edge-entry bundle — not currently
|
|
855
953
|
exposed as a public entry — or ask for a public `/edge` subpath.
|
|
856
|
-
- **`@glasstrace/sdk/node`** — Node-only build-time tooling
|
|
857
|
-
(source-map uploading, import-graph construction)
|
|
858
|
-
`
|
|
859
|
-
condition; non-Node runtimes (workerd,
|
|
860
|
-
module resolution rather than at
|
|
954
|
+
- **`@glasstrace/sdk/node`** — Node-only helpers: build-time tooling
|
|
955
|
+
(source-map uploading, import-graph construction) plus the request-time
|
|
956
|
+
`hashId` identifier-pseudonymization helper for value-fidelity scalars.
|
|
957
|
+
Resolves only under the Node condition; non-Node runtimes (workerd,
|
|
958
|
+
edge-light) fail cleanly at module resolution rather than at
|
|
959
|
+
evaluation.
|
|
861
960
|
- **`@glasstrace/sdk/drizzle`** — Drizzle ORM adapter.
|
|
862
961
|
- **`@glasstrace/sdk/trpc`** — tRPC middleware-chain instrumentation.
|
|
863
962
|
See "tRPC middleware instrumentation" below.
|
|
963
|
+
- **`@glasstrace/sdk/middleware`** — request-middleware tracing wrapper
|
|
964
|
+
(`tracedRequestMiddleware`).
|
|
965
|
+
- **`@glasstrace/sdk/async-context`** — async causality propagation
|
|
966
|
+
(`withAsyncCausality`).
|
|
864
967
|
|
|
865
968
|
The source-map and import-graph helpers previously reachable from the
|
|
866
969
|
`@glasstrace/sdk` root specifier have moved to `@glasstrace/sdk/node`
|
|
@@ -906,11 +1009,15 @@ and the recommended call site.
|
|
|
906
1009
|
| `discoverTestFiles` | function | `node:fs`, `node:path` | — (call from a build script / CI job) |
|
|
907
1010
|
| `extractImports` | function | — (pure string processing) | — (kept under `/node` for API cohesion with `buildImportGraph`) |
|
|
908
1011
|
| `buildImportGraph` | function | `node:fs`, `node:path`, `node:crypto` | — (call from a build script / CI job) |
|
|
1012
|
+
| `hashId` | function | `node:crypto` | — (call from the request handler that records the side effect) |
|
|
909
1013
|
|
|
910
1014
|
Type exports erase at runtime and are technically safe to import from
|
|
911
1015
|
edge code, but every runtime function that produces or consumes them is
|
|
912
|
-
Node-only, so the practical signal is the same: reach for
|
|
913
|
-
your build pipeline, not from a request
|
|
1016
|
+
Node-only, so the practical signal is the same: reach for the source-map
|
|
1017
|
+
and import-graph helpers from your build pipeline, not from a request
|
|
1018
|
+
handler. `hashId` is the exception — it is a request-time helper for
|
|
1019
|
+
pseudonymizing identifiers before `recordSideEffect()`, Node-only only
|
|
1020
|
+
because it uses `node:crypto`.
|
|
914
1021
|
|
|
915
1022
|
#### Why is X Node-only?
|
|
916
1023
|
|
|
@@ -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;
|