@cross-deck/node 1.10.0 → 1.10.1
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 +16 -0
- package/README.md +45 -0
- package/dist/auto-events/index.d.mts +1 -1
- package/dist/auto-events/index.d.ts +1 -1
- package/dist/{crossdeck-server-C4nWPQzH.d.mts → crossdeck-server-BpBVFC4O.d.mts} +51 -3
- package/dist/{crossdeck-server-C4nWPQzH.d.ts → crossdeck-server-BpBVFC4O.d.ts} +51 -3
- package/dist/index.cjs +70 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +70 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.10.1] — 2026-06-30
|
|
10
|
+
|
|
11
|
+
**Fixed — the blocking surface now works for the documented paths (still v2 preview).**
|
|
12
|
+
|
|
13
|
+
- `resolve()` / `isBlocked()` now accept a **bare `userId`** — the server-trusted
|
|
14
|
+
recognition path the backend honours (rides the identity backbone, matches on the email
|
|
15
|
+
Crossdeck already holds). 1.10.0's guard rejected it and fail-opened *without calling the
|
|
16
|
+
API*, so a known-user block silently never fired.
|
|
17
|
+
- **Added `gate({ email, ip })`** — the brand-new-signup door (`POST /v1/trust/gate`), the
|
|
18
|
+
only path that catches a farm Crossdeck has never seen. Fail-open by contract. New
|
|
19
|
+
`GateInput` / `GateVerdict` types.
|
|
20
|
+
- README now documents the blocking surface (the three doors + the verify-locally pattern).
|
|
21
|
+
|
|
22
|
+
Still `@experimental` — Crossdeck Trust ships with Crossdeck v2.
|
|
23
|
+
|
|
24
|
+
|
|
9
25
|
## [1.10.0] — 2026-06-30
|
|
10
26
|
|
|
11
27
|
**Added — the blocking surface (Crossdeck Trust, v2 preview).** Blocking is
|
package/README.md
CHANGED
|
@@ -211,6 +211,51 @@ app.post("/crossdeck-webhook", express.raw({ type: "application/json" }), (req,
|
|
|
211
211
|
|
|
212
212
|
For test fixtures that need to mint signed webhooks against the same scheme, `signWebhookPayload(payload, secret, timestampSec)` is exported.
|
|
213
213
|
|
|
214
|
+
### Blocking (Crossdeck Trust) — <sup>v2 preview</sup>
|
|
215
|
+
|
|
216
|
+
> **Preview — not GA.** The blocking surface launches **end-to-end with Crossdeck v2.**
|
|
217
|
+
> The shape is stable and all methods are `@experimental`, so it's documented and usable
|
|
218
|
+
> now (dogfooding / early access) — but it is **not** a launched feature yet, and this is
|
|
219
|
+
> not a fourth shipped USP. Treat it as preview until the v2 launch.
|
|
220
|
+
|
|
221
|
+
Blocking is **entitlements, inverted**: `getEntitlements()` asks *"can this user access Pro?"*; these ask *"should this user be here at all?"* — the **same identity backbone**, read for `blocked`. Every method is **fail-open by contract**: it never throws and never returns blocked on uncertainty, so a glitch can never lock out a real user.
|
|
222
|
+
|
|
223
|
+
There are three doors. Pick by who's at it:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
// 1. A user you ALREADY KNOW — a bare userId rides the backbone (no token, no setup).
|
|
227
|
+
// Crossdeck matches on the email it already holds. The common case.
|
|
228
|
+
const { blocked, blockReason } = await crossdeck.resolve({ userId, ip: req.ip });
|
|
229
|
+
if (blocked) { await signOut(); return showSuspended(blockReason); }
|
|
230
|
+
// or just the boolean: if (await crossdeck.isBlocked({ userId })) …
|
|
231
|
+
|
|
232
|
+
// 2. A BRAND-NEW signup Crossdeck has never seen — block by the two strings you have
|
|
233
|
+
// at signup, their email + ip. Call it BEFORE you create the account.
|
|
234
|
+
const gate = await crossdeck.gate({ email, ip: req.ip });
|
|
235
|
+
if (gate.action === "block") return rejectSignup(gate.blockReason);
|
|
236
|
+
|
|
237
|
+
// 3. A PUBLIC PAGE — "is the owner of this page blocked?" (no session token). Poll on a
|
|
238
|
+
// short TTL to invalidate your cache; the ip is the owner's CREATION ip.
|
|
239
|
+
const owner = await crossdeck.getOwnerStatus({ userId: ownerId });
|
|
240
|
+
if (owner.blocked) await takePageOffline(ownerId);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Recommended server pattern (no issuer registration):** if your backend runs Firebase
|
|
244
|
+
Admin, verify the ID token **locally** for the authoritative uid, then send that as a bare
|
|
245
|
+
`userId` — you keep the cryptographic proof on your side and Crossdeck needs zero setup:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
const { uid } = await getAuth().verifyIdToken(idToken); // your Firebase Admin
|
|
249
|
+
const { blocked } = await crossdeck.resolve({ userId: uid, ip: req.ip });
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Send `userId` + `idToken` to Crossdeck instead only if you *can't* verify locally — that's
|
|
253
|
+
the verified Tier-3 path, and the only one that needs a one-time auth-issuer registration.
|
|
254
|
+
Setting *who* is blocked is a rule in your Crossdeck admin. Full integration guide
|
|
255
|
+
(suspension pages, public-content takedown, the backfill sweep): `CROSSDECK_BLOCKING_DEVELOPER_GUIDE.md`.
|
|
256
|
+
|
|
257
|
+
Types: `ResolveInput` / `ResolveResult`, `GateInput` / `GateVerdict`, `OwnerStatusInput` / `BlockVerdict`.
|
|
258
|
+
|
|
214
259
|
## Cross-cutting
|
|
215
260
|
|
|
216
261
|
### Read-cost cross-match (Buckets)
|
|
@@ -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.10.
|
|
187
|
-
readonly bundledIn: "@cross-deck/node@1.10.
|
|
186
|
+
readonly sdkVersion: "1.10.1";
|
|
187
|
+
readonly bundledIn: "@cross-deck/node@1.10.1";
|
|
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
|
|
@@ -514,6 +514,41 @@ interface OwnerStatusInput {
|
|
|
514
514
|
domain?: string;
|
|
515
515
|
ip?: string;
|
|
516
516
|
}
|
|
517
|
+
/**
|
|
518
|
+
* Input for {@link CrossdeckServer.gate} — the brand-new-signup door. Pass the two strings
|
|
519
|
+
* you have at signup: `email` and `ip`. (Optional `domain`/`fingerprint` sharpen the score.)
|
|
520
|
+
*
|
|
521
|
+
* @experimental Preview — see {@link ResolveInput}.
|
|
522
|
+
*/
|
|
523
|
+
interface GateInput {
|
|
524
|
+
/** The signing-up user's email. Matched against email + domain blocklist rules. */
|
|
525
|
+
email?: string;
|
|
526
|
+
/** The signing-up request's IP. Matched against ip rules + datacenter/velocity signals. */
|
|
527
|
+
ip?: string;
|
|
528
|
+
/** Optional explicit domain (defaults to the email's domain). */
|
|
529
|
+
domain?: string;
|
|
530
|
+
/** Optional device fingerprint — sharpens the composite signup score. */
|
|
531
|
+
fingerprint?: string;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* The signup-gate verdict from {@link CrossdeckServer.gate}. Fail-open: on any error these
|
|
535
|
+
* come back `{ action: "allow", allow: true, degraded: true }` — a glitch never rejects a
|
|
536
|
+
* real signup.
|
|
537
|
+
*
|
|
538
|
+
* @experimental Preview — see {@link ResolveInput}.
|
|
539
|
+
*/
|
|
540
|
+
interface GateVerdict {
|
|
541
|
+
/** `"allow"` | `"review"` | `"block"`. Reject the account only on `"block"`. */
|
|
542
|
+
action: "allow" | "review" | "block";
|
|
543
|
+
/** Convenience: `false` only when `action` is `"block"`. */
|
|
544
|
+
allow: boolean;
|
|
545
|
+
/** Why, when blocked: e.g. `"disposable_domain"` | `"blocklist:ip"` | `"blocklist:domain"`. */
|
|
546
|
+
blockReason: string | null;
|
|
547
|
+
/** The exact rule/key that fired, when blocked. */
|
|
548
|
+
blockedKey: string | null;
|
|
549
|
+
/** True when this is the fail-open default (Crossdeck unreachable). `allow` is `true`. */
|
|
550
|
+
degraded?: boolean;
|
|
551
|
+
}
|
|
517
552
|
/**
|
|
518
553
|
* Snapshot of one customer's last-known-good entitlements, as written
|
|
519
554
|
* to / read from a durable `EntitlementStore`. Versioned for forward-
|
|
@@ -1566,6 +1601,19 @@ declare class CrossdeckServer extends EventEmitter {
|
|
|
1566
1601
|
* @experimental Preview — see {@link resolve}.
|
|
1567
1602
|
*/
|
|
1568
1603
|
getOwnerStatus(input: OwnerStatusInput, options?: RequestOptions): Promise<BlockVerdict>;
|
|
1604
|
+
/**
|
|
1605
|
+
* The brand-new-signup door (§3 of the Blocking developer guide). Block a user Crossdeck
|
|
1606
|
+
* has **never seen** — at the instant they sign up — by the two strings you have then:
|
|
1607
|
+
* their `email` and `ip`. There's no identity to ride yet, so {@link resolve} can't catch
|
|
1608
|
+
* them; this matches `email` / domain / `ip` blocklist rules directly. Call it BEFORE you
|
|
1609
|
+
* create the account; on `action: "block"`, reject the signup.
|
|
1610
|
+
*
|
|
1611
|
+
* **Fail-open by contract** — never throws, never blocks on uncertainty: any error →
|
|
1612
|
+
* `{ action: "allow", allow: true, degraded: true }`, so a glitch can't reject a real signup.
|
|
1613
|
+
*
|
|
1614
|
+
* @experimental Preview — Crossdeck Trust ships with Crossdeck v2.
|
|
1615
|
+
*/
|
|
1616
|
+
gate(input: GateInput, options?: RequestOptions): Promise<GateVerdict>;
|
|
1569
1617
|
/**
|
|
1570
1618
|
* Synchronous entitlement check. Returns `true` iff the customer
|
|
1571
1619
|
* has the entitlement AND the cache entry is fresh (within
|
|
@@ -2045,4 +2093,4 @@ declare class CrossdeckServer extends EventEmitter {
|
|
|
2045
2093
|
private normalizeIngestEvent;
|
|
2046
2094
|
}
|
|
2047
2095
|
|
|
2048
|
-
export { type
|
|
2096
|
+
export { type IngestOptions as $, type AliasIdentityInput as A, type BlockVerdict as B, CROSSDECK_API_VERSION as C, DEFAULT_BASE_URL as D, DEFAULT_TIMEOUT_MS as E, type Diagnostics as F, type EntitlementCacheOptions as G, type EntitlementMutationResult as H, type EntitlementStore as I, type EntitlementsListResponse as J, type EntitlementsListener as K, type Environment as L, type ErrorCaptureConfig as M, type ErrorLevel as N, type EventProperties as O, type ForgetResult as P, type GateInput as Q, type GateVerdict as R, type GrantDuration as S, type GrantEntitlementInput as T, type GroupMembership as U, type HeartbeatResponse as V, type HttpRequestInfo as W, type HttpResponseInfo as X, type HttpRetriesConfig as Y, type IdentifyOptions as Z, type IdentityHints as _, type AliasResult as a, type IngestResponse as a0, type OwnerStatusInput as a1, type PublicEntitlement as a2, type PurchaseResult as a3, type RequestOptions as a4, type ResolveInput as a5, type ResolveResult as a6, type RevokeEntitlementInput as a7, type RuntimeHost as a8, type RuntimeInfo as a9, type ServerEvent as aa, type StackFrame as ab, type StoredEntitlements as ac, type SyncPurchaseInput as ad, makeCrossdeckError as ae, type AuditDecision as b, type AuditEntry as c, type Breadcrumb as d, type BreadcrumbCategory as e, type BreadcrumbLevel as f, type CapturedError as g, type Contract as h, type ContractAppliesTo as i, type ContractFailureInput as j, type ContractPillar as k, type ContractStatus as l, type ContractTestRef as m, CrossdeckAuthenticationError as n, CrossdeckConfigurationError as o, CrossdeckContracts as p, CrossdeckError as q, type CrossdeckErrorPayload as r, type CrossdeckErrorType as s, CrossdeckInternalError as t, CrossdeckNetworkError as u, CrossdeckPermissionError as v, CrossdeckRateLimitError as w, CrossdeckServer as x, type CrossdeckServerOptions as y, CrossdeckValidationError as z };
|
|
@@ -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.10.
|
|
187
|
-
readonly bundledIn: "@cross-deck/node@1.10.
|
|
186
|
+
readonly sdkVersion: "1.10.1";
|
|
187
|
+
readonly bundledIn: "@cross-deck/node@1.10.1";
|
|
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
|
|
@@ -514,6 +514,41 @@ interface OwnerStatusInput {
|
|
|
514
514
|
domain?: string;
|
|
515
515
|
ip?: string;
|
|
516
516
|
}
|
|
517
|
+
/**
|
|
518
|
+
* Input for {@link CrossdeckServer.gate} — the brand-new-signup door. Pass the two strings
|
|
519
|
+
* you have at signup: `email` and `ip`. (Optional `domain`/`fingerprint` sharpen the score.)
|
|
520
|
+
*
|
|
521
|
+
* @experimental Preview — see {@link ResolveInput}.
|
|
522
|
+
*/
|
|
523
|
+
interface GateInput {
|
|
524
|
+
/** The signing-up user's email. Matched against email + domain blocklist rules. */
|
|
525
|
+
email?: string;
|
|
526
|
+
/** The signing-up request's IP. Matched against ip rules + datacenter/velocity signals. */
|
|
527
|
+
ip?: string;
|
|
528
|
+
/** Optional explicit domain (defaults to the email's domain). */
|
|
529
|
+
domain?: string;
|
|
530
|
+
/** Optional device fingerprint — sharpens the composite signup score. */
|
|
531
|
+
fingerprint?: string;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* The signup-gate verdict from {@link CrossdeckServer.gate}. Fail-open: on any error these
|
|
535
|
+
* come back `{ action: "allow", allow: true, degraded: true }` — a glitch never rejects a
|
|
536
|
+
* real signup.
|
|
537
|
+
*
|
|
538
|
+
* @experimental Preview — see {@link ResolveInput}.
|
|
539
|
+
*/
|
|
540
|
+
interface GateVerdict {
|
|
541
|
+
/** `"allow"` | `"review"` | `"block"`. Reject the account only on `"block"`. */
|
|
542
|
+
action: "allow" | "review" | "block";
|
|
543
|
+
/** Convenience: `false` only when `action` is `"block"`. */
|
|
544
|
+
allow: boolean;
|
|
545
|
+
/** Why, when blocked: e.g. `"disposable_domain"` | `"blocklist:ip"` | `"blocklist:domain"`. */
|
|
546
|
+
blockReason: string | null;
|
|
547
|
+
/** The exact rule/key that fired, when blocked. */
|
|
548
|
+
blockedKey: string | null;
|
|
549
|
+
/** True when this is the fail-open default (Crossdeck unreachable). `allow` is `true`. */
|
|
550
|
+
degraded?: boolean;
|
|
551
|
+
}
|
|
517
552
|
/**
|
|
518
553
|
* Snapshot of one customer's last-known-good entitlements, as written
|
|
519
554
|
* to / read from a durable `EntitlementStore`. Versioned for forward-
|
|
@@ -1566,6 +1601,19 @@ declare class CrossdeckServer extends EventEmitter {
|
|
|
1566
1601
|
* @experimental Preview — see {@link resolve}.
|
|
1567
1602
|
*/
|
|
1568
1603
|
getOwnerStatus(input: OwnerStatusInput, options?: RequestOptions): Promise<BlockVerdict>;
|
|
1604
|
+
/**
|
|
1605
|
+
* The brand-new-signup door (§3 of the Blocking developer guide). Block a user Crossdeck
|
|
1606
|
+
* has **never seen** — at the instant they sign up — by the two strings you have then:
|
|
1607
|
+
* their `email` and `ip`. There's no identity to ride yet, so {@link resolve} can't catch
|
|
1608
|
+
* them; this matches `email` / domain / `ip` blocklist rules directly. Call it BEFORE you
|
|
1609
|
+
* create the account; on `action: "block"`, reject the signup.
|
|
1610
|
+
*
|
|
1611
|
+
* **Fail-open by contract** — never throws, never blocks on uncertainty: any error →
|
|
1612
|
+
* `{ action: "allow", allow: true, degraded: true }`, so a glitch can't reject a real signup.
|
|
1613
|
+
*
|
|
1614
|
+
* @experimental Preview — Crossdeck Trust ships with Crossdeck v2.
|
|
1615
|
+
*/
|
|
1616
|
+
gate(input: GateInput, options?: RequestOptions): Promise<GateVerdict>;
|
|
1569
1617
|
/**
|
|
1570
1618
|
* Synchronous entitlement check. Returns `true` iff the customer
|
|
1571
1619
|
* has the entitlement AND the cache entry is fresh (within
|
|
@@ -2045,4 +2093,4 @@ declare class CrossdeckServer extends EventEmitter {
|
|
|
2045
2093
|
private normalizeIngestEvent;
|
|
2046
2094
|
}
|
|
2047
2095
|
|
|
2048
|
-
export { type
|
|
2096
|
+
export { type IngestOptions as $, type AliasIdentityInput as A, type BlockVerdict as B, CROSSDECK_API_VERSION as C, DEFAULT_BASE_URL as D, DEFAULT_TIMEOUT_MS as E, type Diagnostics as F, type EntitlementCacheOptions as G, type EntitlementMutationResult as H, type EntitlementStore as I, type EntitlementsListResponse as J, type EntitlementsListener as K, type Environment as L, type ErrorCaptureConfig as M, type ErrorLevel as N, type EventProperties as O, type ForgetResult as P, type GateInput as Q, type GateVerdict as R, type GrantDuration as S, type GrantEntitlementInput as T, type GroupMembership as U, type HeartbeatResponse as V, type HttpRequestInfo as W, type HttpResponseInfo as X, type HttpRetriesConfig as Y, type IdentifyOptions as Z, type IdentityHints as _, type AliasResult as a, type IngestResponse as a0, type OwnerStatusInput as a1, type PublicEntitlement as a2, type PurchaseResult as a3, type RequestOptions as a4, type ResolveInput as a5, type ResolveResult as a6, type RevokeEntitlementInput as a7, type RuntimeHost as a8, type RuntimeInfo as a9, type ServerEvent as aa, type StackFrame as ab, type StoredEntitlements as ac, type SyncPurchaseInput as ad, makeCrossdeckError as ae, type AuditDecision as b, type AuditEntry as c, type Breadcrumb as d, type BreadcrumbCategory as e, type BreadcrumbLevel as f, type CapturedError as g, type Contract as h, type ContractAppliesTo as i, type ContractFailureInput as j, type ContractPillar as k, type ContractStatus as l, type ContractTestRef as m, CrossdeckAuthenticationError as n, CrossdeckConfigurationError as o, CrossdeckContracts as p, CrossdeckError as q, type CrossdeckErrorPayload as r, type CrossdeckErrorType as s, CrossdeckInternalError as t, CrossdeckNetworkError as u, CrossdeckPermissionError as v, CrossdeckRateLimitError as w, CrossdeckServer as x, type CrossdeckServerOptions as y, CrossdeckValidationError as z };
|
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.10.
|
|
390
|
+
var SDK_VERSION = "1.10.1";
|
|
391
391
|
var SDK_NAME = "@cross-deck/node";
|
|
392
392
|
|
|
393
393
|
// src/_diagnostic-telemetry.ts
|
|
@@ -3185,10 +3185,10 @@ var CrossdeckServer = class extends import_node_events.EventEmitter {
|
|
|
3185
3185
|
anonymousId: input?.anonymousId ?? null,
|
|
3186
3186
|
identityError: null
|
|
3187
3187
|
});
|
|
3188
|
-
if (!input || !input.anonymousId && !
|
|
3188
|
+
if (!input || !input.anonymousId && !input.userId) {
|
|
3189
3189
|
this.debug.emit(
|
|
3190
3190
|
"sdk.resolve_missing_identity",
|
|
3191
|
-
"resolve() needs anonymousId
|
|
3191
|
+
"resolve() needs an anonymousId or a userId; returning fail-open blocked:false."
|
|
3192
3192
|
);
|
|
3193
3193
|
return failOpen();
|
|
3194
3194
|
}
|
|
@@ -3273,6 +3273,60 @@ var CrossdeckServer = class extends import_node_events.EventEmitter {
|
|
|
3273
3273
|
return { blocked: false, blockReason: null, blockedKey: null, degraded: true };
|
|
3274
3274
|
}
|
|
3275
3275
|
}
|
|
3276
|
+
/**
|
|
3277
|
+
* The brand-new-signup door (§3 of the Blocking developer guide). Block a user Crossdeck
|
|
3278
|
+
* has **never seen** — at the instant they sign up — by the two strings you have then:
|
|
3279
|
+
* their `email` and `ip`. There's no identity to ride yet, so {@link resolve} can't catch
|
|
3280
|
+
* them; this matches `email` / domain / `ip` blocklist rules directly. Call it BEFORE you
|
|
3281
|
+
* create the account; on `action: "block"`, reject the signup.
|
|
3282
|
+
*
|
|
3283
|
+
* **Fail-open by contract** — never throws, never blocks on uncertainty: any error →
|
|
3284
|
+
* `{ action: "allow", allow: true, degraded: true }`, so a glitch can't reject a real signup.
|
|
3285
|
+
*
|
|
3286
|
+
* @experimental Preview — Crossdeck Trust ships with Crossdeck v2.
|
|
3287
|
+
*/
|
|
3288
|
+
async gate(input, options) {
|
|
3289
|
+
const failOpen = () => ({
|
|
3290
|
+
action: "allow",
|
|
3291
|
+
allow: true,
|
|
3292
|
+
blockReason: null,
|
|
3293
|
+
blockedKey: null,
|
|
3294
|
+
degraded: true
|
|
3295
|
+
});
|
|
3296
|
+
if (!input || !input.email && !input.ip && !input.domain) {
|
|
3297
|
+
this.debug.emit(
|
|
3298
|
+
"sdk.gate_missing_input",
|
|
3299
|
+
"gate() needs at least one of email / ip / domain; returning fail-open allow:true."
|
|
3300
|
+
);
|
|
3301
|
+
return failOpen();
|
|
3302
|
+
}
|
|
3303
|
+
try {
|
|
3304
|
+
const raw = await this.http.request("POST", "/trust/gate", {
|
|
3305
|
+
body: {
|
|
3306
|
+
...input.email ? { email: input.email } : {},
|
|
3307
|
+
...input.ip ? { ip: input.ip } : {},
|
|
3308
|
+
...input.domain ? { domain: input.domain } : {},
|
|
3309
|
+
...input.fingerprint ? { fingerprint: input.fingerprint } : {}
|
|
3310
|
+
},
|
|
3311
|
+
signal: options?.signal,
|
|
3312
|
+
timeoutMs: options?.timeoutMs
|
|
3313
|
+
});
|
|
3314
|
+
const action = raw.action === "block" || raw.action === "review" ? raw.action : "allow";
|
|
3315
|
+
return {
|
|
3316
|
+
action,
|
|
3317
|
+
allow: raw.allow !== false && action !== "block",
|
|
3318
|
+
blockReason: raw.blockReason ?? null,
|
|
3319
|
+
blockedKey: raw.blockedKey ?? null
|
|
3320
|
+
};
|
|
3321
|
+
} catch (err) {
|
|
3322
|
+
this.debug.emit(
|
|
3323
|
+
"sdk.gate_failed",
|
|
3324
|
+
`gate() failed \u2014 fail-open allow:true. ${err instanceof Error ? err.message : String(err)}`,
|
|
3325
|
+
{ error: err instanceof Error ? err.message : String(err) }
|
|
3326
|
+
);
|
|
3327
|
+
return failOpen();
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3276
3330
|
/**
|
|
3277
3331
|
* Synchronous entitlement check. Returns `true` iff the customer
|
|
3278
3332
|
* has the entitlement AND the cache entry is fresh (within
|
|
@@ -4720,8 +4774,8 @@ function normaliseSecrets(input) {
|
|
|
4720
4774
|
}
|
|
4721
4775
|
|
|
4722
4776
|
// src/_contracts-bundled.ts
|
|
4723
|
-
var BUNDLED_IN = "@cross-deck/node@1.10.
|
|
4724
|
-
var SDK_VERSION2 = "1.10.
|
|
4777
|
+
var BUNDLED_IN = "@cross-deck/node@1.10.1";
|
|
4778
|
+
var SDK_VERSION2 = "1.10.1";
|
|
4725
4779
|
var BUNDLED_CONTRACTS = Object.freeze([
|
|
4726
4780
|
{
|
|
4727
4781
|
"id": "contract-failed-payload-schema-lock",
|
|
@@ -4843,7 +4897,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4843
4897
|
"legal/security/index.html#diagnostic",
|
|
4844
4898
|
"legal/sdk-data/index.html#b-diagnostic"
|
|
4845
4899
|
],
|
|
4846
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
4900
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
4847
4901
|
},
|
|
4848
4902
|
{
|
|
4849
4903
|
"id": "documentation-honesty",
|
|
@@ -4875,7 +4929,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4875
4929
|
],
|
|
4876
4930
|
"registeredAt": "2026-05-26",
|
|
4877
4931
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 7.1",
|
|
4878
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
4932
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
4879
4933
|
},
|
|
4880
4934
|
{
|
|
4881
4935
|
"id": "error-envelope-shape",
|
|
@@ -4914,7 +4968,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4914
4968
|
],
|
|
4915
4969
|
"registeredAt": "2026-05-26",
|
|
4916
4970
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 8 (codifies existing contract)",
|
|
4917
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
4971
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
4918
4972
|
},
|
|
4919
4973
|
{
|
|
4920
4974
|
"id": "flush-interval-parity",
|
|
@@ -4959,7 +5013,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
4959
5013
|
],
|
|
4960
5014
|
"registeredAt": "2026-05-26",
|
|
4961
5015
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 3.3",
|
|
4962
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
5016
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
4963
5017
|
},
|
|
4964
5018
|
{
|
|
4965
5019
|
"id": "idempotency-key-deterministic",
|
|
@@ -5064,7 +5118,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5064
5118
|
],
|
|
5065
5119
|
"registeredAt": "2026-05-26",
|
|
5066
5120
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 2.2.a + 2.2.b + 2.2.c",
|
|
5067
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
5121
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
5068
5122
|
},
|
|
5069
5123
|
{
|
|
5070
5124
|
"id": "invalid-input-rejected-natively",
|
|
@@ -5120,7 +5174,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5120
5174
|
],
|
|
5121
5175
|
"registeredAt": "2026-06-11",
|
|
5122
5176
|
"firstRegisteredIn": "swift trap-on-input class fix \u2014 first machine-tested Swift release",
|
|
5123
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
5177
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
5124
5178
|
},
|
|
5125
5179
|
{
|
|
5126
5180
|
"id": "node-pii-scrubber",
|
|
@@ -5159,7 +5213,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5159
5213
|
],
|
|
5160
5214
|
"registeredAt": "2026-05-26",
|
|
5161
5215
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 3.1",
|
|
5162
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
5216
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
5163
5217
|
},
|
|
5164
5218
|
{
|
|
5165
5219
|
"id": "node-shutdown-awaits-flush",
|
|
@@ -5192,7 +5246,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5192
5246
|
],
|
|
5193
5247
|
"registeredAt": "2026-05-26",
|
|
5194
5248
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 5.4",
|
|
5195
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
5249
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
5196
5250
|
},
|
|
5197
5251
|
{
|
|
5198
5252
|
"id": "sdk-error-codes-catalogue",
|
|
@@ -5237,7 +5291,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5237
5291
|
],
|
|
5238
5292
|
"registeredAt": "2026-05-26",
|
|
5239
5293
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 6.2",
|
|
5240
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
5294
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
5241
5295
|
},
|
|
5242
5296
|
{
|
|
5243
5297
|
"id": "sync-purchases-funnel-parity",
|
|
@@ -5270,7 +5324,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5270
5324
|
],
|
|
5271
5325
|
"registeredAt": "2026-05-26",
|
|
5272
5326
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 3.5",
|
|
5273
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
5327
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
5274
5328
|
},
|
|
5275
5329
|
{
|
|
5276
5330
|
"id": "verifier-timestamp-mandatory",
|
|
@@ -5324,7 +5378,7 @@ var BUNDLED_CONTRACTS = Object.freeze([
|
|
|
5324
5378
|
],
|
|
5325
5379
|
"registeredAt": "2026-05-26",
|
|
5326
5380
|
"firstRegisteredIn": "bank-grade reconciliation v1.4.0 \u2014 phase 7.2",
|
|
5327
|
-
"bundledIn": "@cross-deck/node@1.10.
|
|
5381
|
+
"bundledIn": "@cross-deck/node@1.10.1"
|
|
5328
5382
|
}
|
|
5329
5383
|
]);
|
|
5330
5384
|
|