@cross-deck/node 1.7.0 → 1.8.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/CHANGELOG.md +25 -0
- package/README.md +11 -3
- package/dist/auto-events/index.d.mts +1 -1
- package/dist/auto-events/index.d.ts +1 -1
- package/dist/{crossdeck-server-DYawt4eT.d.mts → crossdeck-server-D9RvKxgA.d.mts} +10 -2
- package/dist/{crossdeck-server-DYawt4eT.d.ts → crossdeck-server-D9RvKxgA.d.ts} +10 -2
- package/dist/index.cjs +92 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +92 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,31 @@ All notable changes to `@cross-deck/node` will be documented here. The
|
|
|
4
4
|
format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [1.8.0] — 2026-06-21
|
|
10
|
+
|
|
11
|
+
**Self-defends against re-instantiation (Next.js / serverless).** Constructing
|
|
12
|
+
`new CrossdeckServer()` at module top-level is the documented pattern, but
|
|
13
|
+
frameworks like Next.js re-evaluate module scope (HMR, per-route isolation, chunk
|
|
14
|
+
splitting), so it could run many times in one process — each time firing another
|
|
15
|
+
boot heartbeat, starting another flush timer, stacking another set of process
|
|
16
|
+
listeners (`beforeExit` / `SIGTERM` / `uncaughtException` / `unhandledRejection`),
|
|
17
|
+
and re-wrapping global `fetch`. That produced a storm of duplicate phone-homes and
|
|
18
|
+
an `EventEmitter` max-listeners warning. The SDK now guards against it — minor,
|
|
19
|
+
backwards-compatible.
|
|
20
|
+
|
|
21
|
+
**Fixed:**
|
|
22
|
+
|
|
23
|
+
- **Singleton guard.** The constructor now returns the EXISTING instance for the
|
|
24
|
+
same credentials (secretKey + appId + baseUrl) instead of building a second one,
|
|
25
|
+
so re-evaluation never re-boots. Same defence Prisma / Firebase Admin ship for
|
|
26
|
+
the same reason. New `CrossdeckServer.clearSingletonCache()` static for tests /
|
|
27
|
+
bespoke hot-reload teardown.
|
|
28
|
+
- **Idempotent `fetch` wrap.** The error-capture fetch wrapper tags itself and
|
|
29
|
+
skips wrapping an already-wrapped `fetch`, so a double-install can't
|
|
30
|
+
double-capture every request.
|
|
31
|
+
|
|
7
32
|
## [1.7.0] — 2026-06-11
|
|
8
33
|
|
|
9
34
|
**PARK on version-rejection — events are held, never dropped.** A third
|
package/README.md
CHANGED
|
@@ -42,6 +42,8 @@ if (crossdeck.isEntitled({ userId: "user_847" }, "pro")) {
|
|
|
42
42
|
}
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
Construct the client **once** at module scope and import it where you need it. This is safe even under frameworks that re-evaluate modules (Next.js HMR, per-route isolation, React Server Components): for a given secret key the SDK returns the same instance every time, so you never get a duplicate client. _(Single-instance guard added in 1.8.0.)_
|
|
46
|
+
|
|
45
47
|
## Three USPs, one SDK
|
|
46
48
|
|
|
47
49
|
### USP 1 — Errors
|
|
@@ -368,7 +370,7 @@ try {
|
|
|
368
370
|
}
|
|
369
371
|
```
|
|
370
372
|
|
|
371
|
-
Subclasses: `CrossdeckAuthenticationError`, `CrossdeckPermissionError`, `CrossdeckValidationError`, `CrossdeckRateLimitError`, `CrossdeckNetworkError`, `CrossdeckInternalError`, `CrossdeckConfigurationError`. All extend `CrossdeckError`. Constructed automatically by the SDK — you never need to instantiate them yourself.
|
|
373
|
+
Subclasses: `CrossdeckAuthenticationError`, `CrossdeckPermissionError`, `CrossdeckValidationError`, `CrossdeckRateLimitError`, `CrossdeckNetworkError`, `CrossdeckInternalError`, `CrossdeckConfigurationError`. All extend `CrossdeckError`. The `version_error` type (code `sdk_version_unsupported`, HTTP 426) carries `minVersion`/`surface` and routes to PARK — see "Outdated-version PARK" above. Constructed automatically by the SDK — you never need to instantiate them yourself.
|
|
372
374
|
|
|
373
375
|
`CrossdeckErrorCode` is the literal union of every documented code in `CROSSDECK_ERROR_CODES`. Use `isCrossdeckErrorCode` to narrow `string` to the union for type-safe comparisons (catches misspelled codes at compile time).
|
|
374
376
|
|
|
@@ -397,6 +399,12 @@ new CrossdeckServer({
|
|
|
397
399
|
|
|
398
400
|
POST methods (`track`/`ingest`/`syncPurchases`/`grantEntitlement`/`revokeEntitlement`) DO NOT auto-retry at the HTTP layer. Retries happen via the event queue with per-batch `Idempotency-Key` reuse — the server can dedupe replays.
|
|
399
401
|
|
|
402
|
+
### Outdated-version PARK (v1.7.0)
|
|
403
|
+
|
|
404
|
+
If the server ever stops accepting this SDK version's event format, the rejection is machine-distinguishable — HTTP `426` with code `sdk_version_unsupported` — and the queue treats it as its own outcome, distinct from retry (transient) and drop (invalid): the events are **parked**. The queue holds them (FIFO-capped at 1,000), stops flushing a known-too-old payload, warns once on the console naming the exact version to update to, and fires the `onParked` callback + a typed `sdk.parked` debug event.
|
|
405
|
+
|
|
406
|
+
**Honest bound:** the Node queue is in-memory, so a process restart *before* you upgrade clears the held events — an opt-in disk-backed queue is on the roadmap. After you deploy the upgraded SDK, held events deliver on the next flush. Web/RN/Swift hold theirs durably across restarts. Full story: [the durability contract](https://cross-deck.com/docs/sdk-event-durability/).
|
|
407
|
+
|
|
400
408
|
**v1.4.0 — `syncPurchases` deterministic key.** The Idempotency-Key
|
|
401
409
|
on `syncPurchases` is derived from the request body (UUID-shaped
|
|
402
410
|
SHA-256 of `crossdeck:purchases/sync:<rail>:<jws|token>`). Two retries
|
|
@@ -584,8 +592,8 @@ CrossdeckContracts.byId("idempotency-key-deterministic");
|
|
|
584
592
|
CrossdeckContracts.byPillar("revenue");
|
|
585
593
|
CrossdeckContracts.withStatus("proposed");
|
|
586
594
|
CrossdeckContracts.findByTestName("rail namespacing prevents cross-rail collisions");
|
|
587
|
-
CrossdeckContracts.sdkVersion; // "1.
|
|
588
|
-
CrossdeckContracts.bundledIn; // "@cross-deck/node@1.
|
|
595
|
+
CrossdeckContracts.sdkVersion; // "1.7.0"
|
|
596
|
+
CrossdeckContracts.bundledIn; // "@cross-deck/node@1.7.0"
|
|
589
597
|
```
|
|
590
598
|
|
|
591
599
|
The `Contract` type is exported alongside; the binary-stability promise is documented in [`contracts/README.md`](https://github.com/VistaApps-za/crossdeck/blob/main/contracts/README.md).
|
|
@@ -183,8 +183,8 @@ declare const CrossdeckContracts: {
|
|
|
183
183
|
readonly byId: (id: string) => Contract | undefined;
|
|
184
184
|
readonly byPillar: (pillar: ContractPillar) => readonly Contract[];
|
|
185
185
|
readonly withStatus: (status: ContractStatus) => readonly Contract[];
|
|
186
|
-
readonly sdkVersion: "1.
|
|
187
|
-
readonly bundledIn: "@cross-deck/node@1.
|
|
186
|
+
readonly sdkVersion: "1.8.0";
|
|
187
|
+
readonly bundledIn: "@cross-deck/node@1.8.0";
|
|
188
188
|
/**
|
|
189
189
|
* Resolve a failing test back to the contract it exercises.
|
|
190
190
|
* Used by test-framework hooks to find the contract id of a
|
|
@@ -1385,6 +1385,14 @@ declare class CrossdeckServer extends EventEmitter {
|
|
|
1385
1385
|
*/
|
|
1386
1386
|
private didEmitShutdown;
|
|
1387
1387
|
constructor(options: CrossdeckServerOptions);
|
|
1388
|
+
/**
|
|
1389
|
+
* Clear the process-wide singleton cache. The SDK hands back the SAME instance
|
|
1390
|
+
* for the same credentials (the Next.js / serverless re-instantiation guard in
|
|
1391
|
+
* the constructor); this resets that so the next `new CrossdeckServer()` builds a
|
|
1392
|
+
* fresh instance. For TESTS (per-test isolation) and bespoke hot-reload teardown
|
|
1393
|
+
* only — production code never needs it.
|
|
1394
|
+
*/
|
|
1395
|
+
static clearSingletonCache(): void;
|
|
1388
1396
|
/**
|
|
1389
1397
|
* Emit the honest "no cold-start durability" warning when the runtime
|
|
1390
1398
|
* is serverless AND no `entitlementStore` is wired. Local-only debug
|
|
@@ -183,8 +183,8 @@ declare const CrossdeckContracts: {
|
|
|
183
183
|
readonly byId: (id: string) => Contract | undefined;
|
|
184
184
|
readonly byPillar: (pillar: ContractPillar) => readonly Contract[];
|
|
185
185
|
readonly withStatus: (status: ContractStatus) => readonly Contract[];
|
|
186
|
-
readonly sdkVersion: "1.
|
|
187
|
-
readonly bundledIn: "@cross-deck/node@1.
|
|
186
|
+
readonly sdkVersion: "1.8.0";
|
|
187
|
+
readonly bundledIn: "@cross-deck/node@1.8.0";
|
|
188
188
|
/**
|
|
189
189
|
* Resolve a failing test back to the contract it exercises.
|
|
190
190
|
* Used by test-framework hooks to find the contract id of a
|
|
@@ -1385,6 +1385,14 @@ declare class CrossdeckServer extends EventEmitter {
|
|
|
1385
1385
|
*/
|
|
1386
1386
|
private didEmitShutdown;
|
|
1387
1387
|
constructor(options: CrossdeckServerOptions);
|
|
1388
|
+
/**
|
|
1389
|
+
* Clear the process-wide singleton cache. The SDK hands back the SAME instance
|
|
1390
|
+
* for the same credentials (the Next.js / serverless re-instantiation guard in
|
|
1391
|
+
* the constructor); this resets that so the next `new CrossdeckServer()` builds a
|
|
1392
|
+
* fresh instance. For TESTS (per-test isolation) and bespoke hot-reload teardown
|
|
1393
|
+
* only — production code never needs it.
|
|
1394
|
+
*/
|
|
1395
|
+
static clearSingletonCache(): void;
|
|
1388
1396
|
/**
|
|
1389
1397
|
* Emit the honest "no cold-start durability" warning when the runtime
|
|
1390
1398
|
* is serverless AND no `entitlementStore` is wired. Local-only debug
|
package/dist/index.cjs
CHANGED
|
@@ -387,7 +387,7 @@ function byteLength(s) {
|
|
|
387
387
|
var https = __toESM(require("https"));
|
|
388
388
|
|
|
389
389
|
// src/_version.ts
|
|
390
|
-
var SDK_VERSION = "1.
|
|
390
|
+
var SDK_VERSION = "1.8.0";
|
|
391
391
|
var SDK_NAME = "@cross-deck/node";
|
|
392
392
|
|
|
393
393
|
// src/_diagnostic-telemetry.ts
|
|
@@ -1433,6 +1433,7 @@ var ErrorTracker = class {
|
|
|
1433
1433
|
installFetchWrap() {
|
|
1434
1434
|
const origFetch = globalThis.fetch;
|
|
1435
1435
|
if (typeof origFetch !== "function") return;
|
|
1436
|
+
if (origFetch.__crossdeckWrapped__) return;
|
|
1436
1437
|
const tracker = this;
|
|
1437
1438
|
const wrapped = async (...args) => {
|
|
1438
1439
|
const input = args[0];
|
|
@@ -1473,6 +1474,7 @@ var ErrorTracker = class {
|
|
|
1473
1474
|
throw err;
|
|
1474
1475
|
}
|
|
1475
1476
|
};
|
|
1477
|
+
wrapped.__crossdeckWrapped__ = true;
|
|
1476
1478
|
globalThis.fetch = wrapped;
|
|
1477
1479
|
this.cleanups.push(() => {
|
|
1478
1480
|
if (globalThis.fetch === wrapped) globalThis.fetch = origFetch;
|
|
@@ -2678,6 +2680,9 @@ function safeJson(obj) {
|
|
|
2678
2680
|
|
|
2679
2681
|
// src/crossdeck-server.ts
|
|
2680
2682
|
var CrossdeckServer = class extends import_node_events.EventEmitter {
|
|
2683
|
+
// `!` (definite assignment): these are assigned on the real construction path,
|
|
2684
|
+
// but the singleton guard in the constructor can `return` an existing instance
|
|
2685
|
+
// before reaching them — that early return is the only path that skips them.
|
|
2681
2686
|
http;
|
|
2682
2687
|
sdkVersion;
|
|
2683
2688
|
baseUrl;
|
|
@@ -2773,6 +2778,13 @@ var CrossdeckServer = class extends import_node_events.EventEmitter {
|
|
|
2773
2778
|
this.appId = options.appId;
|
|
2774
2779
|
this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
|
|
2775
2780
|
this.env = inferEnvFromKey(options.secretKey);
|
|
2781
|
+
const _store = globalThis;
|
|
2782
|
+
const _singletonKey = `${options.secretKey}|${this.appId ?? ""}|${this.baseUrl}`;
|
|
2783
|
+
_store.__crossdeckServers__ ??= /* @__PURE__ */ new Map();
|
|
2784
|
+
const _existing = _store.__crossdeckServers__.get(_singletonKey);
|
|
2785
|
+
if (_existing) {
|
|
2786
|
+
return _existing;
|
|
2787
|
+
}
|
|
2776
2788
|
this.secretKeyPrefix = maskSecretKey(options.secretKey);
|
|
2777
2789
|
this.scrubPii = options.scrubPii !== false;
|
|
2778
2790
|
this.http = new HttpClient({
|
|
@@ -2914,6 +2926,17 @@ var CrossdeckServer = class extends import_node_events.EventEmitter {
|
|
|
2914
2926
|
this.emitBootTelemetryEvent();
|
|
2915
2927
|
});
|
|
2916
2928
|
}
|
|
2929
|
+
_store.__crossdeckServers__.set(_singletonKey, this);
|
|
2930
|
+
}
|
|
2931
|
+
/**
|
|
2932
|
+
* Clear the process-wide singleton cache. The SDK hands back the SAME instance
|
|
2933
|
+
* for the same credentials (the Next.js / serverless re-instantiation guard in
|
|
2934
|
+
* the constructor); this resets that so the next `new CrossdeckServer()` builds a
|
|
2935
|
+
* fresh instance. For TESTS (per-test isolation) and bespoke hot-reload teardown
|
|
2936
|
+
* only — production code never needs it.
|
|
2937
|
+
*/
|
|
2938
|
+
static clearSingletonCache() {
|
|
2939
|
+
globalThis.__crossdeckServers__?.clear();
|
|
2917
2940
|
}
|
|
2918
2941
|
/**
|
|
2919
2942
|
* Emit the honest "no cold-start durability" warning when the runtime
|
|
@@ -4573,8 +4596,8 @@ function normaliseSecrets(input) {
|
|
|
4573
4596
|
}
|
|
4574
4597
|
|
|
4575
4598
|
// src/_contracts-bundled.ts
|
|
4576
|
-
var BUNDLED_IN = "@cross-deck/node@1.
|
|
4577
|
-
var SDK_VERSION2 = "1.
|
|
4599
|
+
var BUNDLED_IN = "@cross-deck/node@1.8.0";
|
|
4600
|
+
var SDK_VERSION2 = "1.8.0";
|
|
4578
4601
|
var BUNDLED_CONTRACTS = Object.freeze([
|
|
4579
4602
|
{
|
|
4580
4603
|
"id": "contract-failed-payload-schema-lock",
|
|
@@ -4696,7 +4719,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4696
4719
|
"legal/security/index.html#diagnostic",
|
|
4697
4720
|
"legal/sdk-data/index.html#b-diagnostic"
|
|
4698
4721
|
],
|
|
4699
|
-
"bundledIn": "@cross-deck/node@1.
|
|
4722
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
4700
4723
|
},
|
|
4701
4724
|
{
|
|
4702
4725
|
"id": "documentation-honesty",
|
|
@@ -4728,7 +4751,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4728
4751
|
],
|
|
4729
4752
|
"registeredAt": "2026-05-26",
|
|
4730
4753
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 7.1",
|
|
4731
|
-
"bundledIn": "@cross-deck/node@1.
|
|
4754
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
4732
4755
|
},
|
|
4733
4756
|
{
|
|
4734
4757
|
"id": "error-envelope-shape",
|
|
@@ -4767,7 +4790,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4767
4790
|
],
|
|
4768
4791
|
"registeredAt": "2026-05-26",
|
|
4769
4792
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 8 (codifies existing contract)",
|
|
4770
|
-
"bundledIn": "@cross-deck/node@1.
|
|
4793
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
4771
4794
|
},
|
|
4772
4795
|
{
|
|
4773
4796
|
"id": "flush-interval-parity",
|
|
@@ -4812,7 +4835,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4812
4835
|
],
|
|
4813
4836
|
"registeredAt": "2026-05-26",
|
|
4814
4837
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 3.3",
|
|
4815
|
-
"bundledIn": "@cross-deck/node@1.
|
|
4838
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
4816
4839
|
},
|
|
4817
4840
|
{
|
|
4818
4841
|
"id": "idempotency-key-deterministic",
|
|
@@ -4917,7 +4940,63 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4917
4940
|
],
|
|
4918
4941
|
"registeredAt": "2026-05-26",
|
|
4919
4942
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 2.2.a + 2.2.b + 2.2.c",
|
|
4920
|
-
"bundledIn": "@cross-deck/node@1.
|
|
4943
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
4944
|
+
},
|
|
4945
|
+
{
|
|
4946
|
+
"id": "invalid-input-rejected-natively",
|
|
4947
|
+
"pillar": "errors",
|
|
4948
|
+
"status": "enforced",
|
|
4949
|
+
"claim": "No public SDK API ever crashes the host app, and invalid input never reaches the wire. Invalid input (empty event name, empty userId, out-of-range config such as a non-positive breadcrumb capacity, NaN/Infinity/oversize/cyclic property values) is rejected at the call site WITHOUT a fatal trap. The signalling IDIOM is per-language and intentionally NOT uniform: Web, Node, and React Native THROW a typed CrossdeckError synchronously (code missing_event_name / missing_user_id / invalid_request_error) \u2014 a normal, catchable JavaScript convention where an uncaught throw logs and the app continues; Swift DROPS with a debug-log signal (track_dropped / identify_dropped) to match its non-throwing fire-and-forget surface, and exposes the throwing equivalent only via identifyAndWait(userId:). What is UNIFORM is the invariant, not the mechanism: every SDK rejects the same inputs, no public fire-and-forget API contains a fatalError / assertionFailure / precondition reachable from customer input, and no rejected input is enqueued or transmitted. Swift additionally proves this in BOTH debug and release configuration, because precondition fires under -O while assertionFailure does not. The bug class this contract closes was never the per-language difference \u2014 it was the UNDECLARED difference: each SDK's public API documentation must state its own semantics explicitly (TS docs: 'throws on empty name'; Swift docs: 'drops and logs').",
|
|
4950
|
+
"appliesTo": [
|
|
4951
|
+
"web",
|
|
4952
|
+
"node",
|
|
4953
|
+
"react-native",
|
|
4954
|
+
"swift"
|
|
4955
|
+
],
|
|
4956
|
+
"codeRef": [
|
|
4957
|
+
"sdks/web/src/crossdeck.ts",
|
|
4958
|
+
"sdks/node/src/crossdeck-server.ts",
|
|
4959
|
+
"sdks/react-native/src/crossdeck.ts",
|
|
4960
|
+
"sdks/swift/Sources/Crossdeck/Crossdeck.swift",
|
|
4961
|
+
"sdks/swift/Sources/Crossdeck/Breadcrumbs.swift"
|
|
4962
|
+
],
|
|
4963
|
+
"testRef": [
|
|
4964
|
+
{
|
|
4965
|
+
"file": "sdks/web/tests/crossdeck.test.ts",
|
|
4966
|
+
"name": "track with empty name throws synchronously"
|
|
4967
|
+
},
|
|
4968
|
+
{
|
|
4969
|
+
"file": "sdks/web/tests/crossdeck.test.ts",
|
|
4970
|
+
"name": "rejects empty userId"
|
|
4971
|
+
},
|
|
4972
|
+
{
|
|
4973
|
+
"file": "sdks/node/tests/crossdeck-server.test.ts",
|
|
4974
|
+
"name": "track() throws CrossdeckError with code 'missing_event_name' when event name is empty"
|
|
4975
|
+
},
|
|
4976
|
+
{
|
|
4977
|
+
"file": "sdks/react-native/tests/crossdeck.test.ts",
|
|
4978
|
+
"name": "track('') throws CrossdeckError(missing_event_name) synchronously"
|
|
4979
|
+
},
|
|
4980
|
+
{
|
|
4981
|
+
"file": "sdks/react-native/tests/crossdeck.test.ts",
|
|
4982
|
+
"name": "identify('') rejects with CrossdeckError(missing_user_id)"
|
|
4983
|
+
},
|
|
4984
|
+
{
|
|
4985
|
+
"file": "sdks/swift/Tests/CrossdeckTests/CrossdeckPublicAPITests.swift",
|
|
4986
|
+
"name": "test_track_dropsEmptyName"
|
|
4987
|
+
},
|
|
4988
|
+
{
|
|
4989
|
+
"file": "sdks/swift/Tests/CrossdeckTests/CrossdeckPublicAPITests.swift",
|
|
4990
|
+
"name": "test_identifyAndWait_rejectsEmptyId"
|
|
4991
|
+
},
|
|
4992
|
+
{
|
|
4993
|
+
"file": "sdks/swift/Tests/CrossdeckTests/PublicAPIInputSafetyTests.swift",
|
|
4994
|
+
"name": "test_start_withZeroBreadcrumbCapacity_doesNotTrap"
|
|
4995
|
+
}
|
|
4996
|
+
],
|
|
4997
|
+
"registeredAt": "2026-06-11",
|
|
4998
|
+
"firstRegisteredIn": "swift trap-on-input class fix \u2014 first machine-tested Swift release",
|
|
4999
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
4921
5000
|
},
|
|
4922
5001
|
{
|
|
4923
5002
|
"id": "node-pii-scrubber",
|
|
@@ -4956,7 +5035,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4956
5035
|
],
|
|
4957
5036
|
"registeredAt": "2026-05-26",
|
|
4958
5037
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 3.1",
|
|
4959
|
-
"bundledIn": "@cross-deck/node@1.
|
|
5038
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
4960
5039
|
},
|
|
4961
5040
|
{
|
|
4962
5041
|
"id": "node-shutdown-awaits-flush",
|
|
@@ -4989,7 +5068,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4989
5068
|
],
|
|
4990
5069
|
"registeredAt": "2026-05-26",
|
|
4991
5070
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 5.4",
|
|
4992
|
-
"bundledIn": "@cross-deck/node@1.
|
|
5071
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
4993
5072
|
},
|
|
4994
5073
|
{
|
|
4995
5074
|
"id": "sdk-error-codes-catalogue",
|
|
@@ -5034,7 +5113,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5034
5113
|
],
|
|
5035
5114
|
"registeredAt": "2026-05-26",
|
|
5036
5115
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 6.2",
|
|
5037
|
-
"bundledIn": "@cross-deck/node@1.
|
|
5116
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
5038
5117
|
},
|
|
5039
5118
|
{
|
|
5040
5119
|
"id": "sync-purchases-funnel-parity",
|
|
@@ -5067,7 +5146,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5067
5146
|
],
|
|
5068
5147
|
"registeredAt": "2026-05-26",
|
|
5069
5148
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 3.5",
|
|
5070
|
-
"bundledIn": "@cross-deck/node@1.
|
|
5149
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
5071
5150
|
},
|
|
5072
5151
|
{
|
|
5073
5152
|
"id": "verifier-timestamp-mandatory",
|
|
@@ -5121,7 +5200,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5121
5200
|
],
|
|
5122
5201
|
"registeredAt": "2026-05-26",
|
|
5123
5202
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 7.2",
|
|
5124
|
-
"bundledIn": "@cross-deck/node@1.
|
|
5203
|
+
"bundledIn": "@cross-deck/node@1.8.0"
|
|
5125
5204
|
}
|
|
5126
5205
|
]);
|
|
5127
5206
|
|