@cross-deck/node 1.13.0 → 1.14.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 CHANGED
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.14.0] — 2026-07-27
10
+
11
+ - **`campaignLink()` — stamp an outbound email link so its click binds to the recipient's identity on landing.** You know the recipient's email at send time; pass it with the link's destination and Crossdeck returns the same URL carrying a one-time arrival ticket (`cd_ref`). Put the returned URL in the email (Resend, HubSpot, your own SMTP — any tool). When the recipient clicks and lands on a page running `@cross-deck/web`, the SDK reads the ticket automatically (v1.10.0+) and binds that session to the person, so the post-click journey joins their identity. Server-side only — it mints an identity bind, so it requires a secret key. Degrades honestly: without the web SDK on the landing page the deep session stitch softens, but the server-side email funnel still lands by identity. Wraps `POST /v1/campaign/email-link`.
12
+
9
13
  ## [1.13.0] — 2026-07-26
10
14
 
11
15
  - **Crossdeck Trust — the gate now carries the browser's human-proof token.** `GateInput` gains an optional `token`: pass the attestation minted by the Crossdeck Trust panel in the browser (`Crossdeck.trust.panel(...)` / `<CrossdeckTrust>` in `@cross-deck/web`) and `gate()` forwards it as `challengeToken` to `/v1/trust/gate`, completing the SDK-native round trip. A real browser carries one; a server-to-server bot has none — that absence is scored, and in strict mode (`requireHumanProof`) a tokenless + suspicious attempt is the confident block. Optional and fail-open: omitting it never blocks on its own, and `gate()` remains fail-open by contract (a glitch returns `{ action: "allow", degraded: true }`, never a throw or a false block).
@@ -1,4 +1,4 @@
1
- import { x as CrossdeckServer } from '../crossdeck-server-CjnIok-o.mjs';
1
+ import { z as CrossdeckServer } from '../crossdeck-server-NL1p6hlR.mjs';
2
2
  import 'node:events';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { x as CrossdeckServer } from '../crossdeck-server-CjnIok-o.js';
1
+ import { z as CrossdeckServer } from '../crossdeck-server-NL1p6hlR.js';
2
2
  import 'node:events';
3
3
 
4
4
  /**
@@ -654,6 +654,25 @@ interface AliasResult {
654
654
  mergePending: boolean;
655
655
  env: Environment;
656
656
  }
657
+ /** Input to `campaignLink` — stamp an outbound email link with an identity-bind ticket. */
658
+ interface CampaignLinkInput {
659
+ /** The recipient's email address. The person is resolved from it once, at stamp time.
660
+ * Rides the request body only — never a URL/query (it is PII). */
661
+ email: string;
662
+ /** The absolute http(s) destination the recipient should land on. */
663
+ url: string;
664
+ /** Optional provenance for later enrichment (e.g. "resend", "hubspot"). Never required. */
665
+ rail?: string;
666
+ }
667
+ /** Result of `campaignLink` — the same destination with the arrival ticket appended. */
668
+ interface CampaignLinkResult {
669
+ object: "campaign_link";
670
+ /** The stamped URL to put in the email. Carries only an opaque `cd_ref` ticket. */
671
+ url: string;
672
+ /** How long the ticket stays live (a campaign's useful life). */
673
+ expiresInDays: number;
674
+ env: Environment;
675
+ }
657
676
  interface IngestResponse {
658
677
  object: "list";
659
678
  received: number;
@@ -1578,6 +1597,21 @@ declare class CrossdeckServer extends EventEmitter {
1578
1597
  identify(userId: string, anonymousId: string, options?: IdentifyOptions & RequestOptions): Promise<AliasResult>;
1579
1598
  aliasIdentity(input: AliasIdentityInput, options?: RequestOptions): Promise<AliasResult>;
1580
1599
  forget(hints: IdentityHints, options?: RequestOptions): Promise<ForgetResult>;
1600
+ /**
1601
+ * Stamp an outbound email link so its click binds to the recipient on landing.
1602
+ *
1603
+ * You know the recipient's email at send time; pass it with the link's destination
1604
+ * and Crossdeck returns the same URL carrying a one-time arrival ticket (`cd_ref`).
1605
+ * Put the returned URL in the email. When the recipient clicks and lands on a page
1606
+ * running `@cross-deck/web`, the SDK reads the ticket automatically and binds that
1607
+ * session to the person — the post-click journey then joins their identity.
1608
+ *
1609
+ * Rail-agnostic: works for Resend, HubSpot, your own SMTP, anything. Server-side
1610
+ * only (it mints an identity bind, so a secret key is required). If the landing page
1611
+ * has no Crossdeck web SDK, the deep session stitch softens but the server-side
1612
+ * email funnel (via the rail adapter) still lands by identity.
1613
+ */
1614
+ campaignLink(input: CampaignLinkInput, options?: RequestOptions): Promise<CampaignLinkResult>;
1581
1615
  /**
1582
1616
  * Fetch a customer's entitlements from Crossdeck and warm the cache.
1583
1617
  *
@@ -2128,4 +2162,4 @@ declare class CrossdeckServer extends EventEmitter {
2128
2162
  private normalizeIngestEvent;
2129
2163
  }
2130
2164
 
2131
- 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 };
2165
+ export { type IdentifyOptions as $, type AliasIdentityInput as A, type BlockVerdict as B, CROSSDECK_API_VERSION as C, type CrossdeckServerOptions as D, CrossdeckValidationError as E, DEFAULT_BASE_URL as F, DEFAULT_TIMEOUT_MS as G, type Diagnostics as H, type EntitlementCacheOptions as I, type EntitlementMutationResult as J, type EntitlementStore as K, type EntitlementsListResponse as L, type EntitlementsListener as M, type Environment as N, type ErrorCaptureConfig as O, type ErrorLevel as P, type EventProperties as Q, type ForgetResult as R, type GateInput as S, type GateVerdict as T, type GrantDuration as U, type GrantEntitlementInput as V, type GroupMembership as W, type HeartbeatResponse as X, type HttpRequestInfo as Y, type HttpResponseInfo as Z, type HttpRetriesConfig as _, type AliasResult as a, type IdentityHints as a0, type IngestOptions as a1, type IngestResponse as a2, type OwnerStatusInput as a3, type PublicEntitlement as a4, type PurchaseResult as a5, type RequestOptions as a6, type ResolveInput as a7, type ResolveResult as a8, type RevokeEntitlementInput as a9, type RuntimeHost as aa, type RuntimeInfo as ab, type ServerEvent as ac, type StackFrame as ad, type StoredEntitlements as ae, type SyncPurchaseInput as af, makeCrossdeckError as ag, type AuditDecision as b, type AuditEntry as c, type Breadcrumb as d, type BreadcrumbCategory as e, type BreadcrumbLevel as f, type CampaignLinkInput as g, type CampaignLinkResult as h, type CapturedError as i, type Contract as j, type ContractAppliesTo as k, type ContractFailureInput as l, type ContractPillar as m, type ContractStatus as n, type ContractTestRef as o, CrossdeckAuthenticationError as p, CrossdeckConfigurationError as q, CrossdeckContracts as r, CrossdeckError as s, type CrossdeckErrorPayload as t, type CrossdeckErrorType as u, CrossdeckInternalError as v, CrossdeckNetworkError as w, CrossdeckPermissionError as x, CrossdeckRateLimitError as y, CrossdeckServer as z };
@@ -654,6 +654,25 @@ interface AliasResult {
654
654
  mergePending: boolean;
655
655
  env: Environment;
656
656
  }
657
+ /** Input to `campaignLink` — stamp an outbound email link with an identity-bind ticket. */
658
+ interface CampaignLinkInput {
659
+ /** The recipient's email address. The person is resolved from it once, at stamp time.
660
+ * Rides the request body only — never a URL/query (it is PII). */
661
+ email: string;
662
+ /** The absolute http(s) destination the recipient should land on. */
663
+ url: string;
664
+ /** Optional provenance for later enrichment (e.g. "resend", "hubspot"). Never required. */
665
+ rail?: string;
666
+ }
667
+ /** Result of `campaignLink` — the same destination with the arrival ticket appended. */
668
+ interface CampaignLinkResult {
669
+ object: "campaign_link";
670
+ /** The stamped URL to put in the email. Carries only an opaque `cd_ref` ticket. */
671
+ url: string;
672
+ /** How long the ticket stays live (a campaign's useful life). */
673
+ expiresInDays: number;
674
+ env: Environment;
675
+ }
657
676
  interface IngestResponse {
658
677
  object: "list";
659
678
  received: number;
@@ -1578,6 +1597,21 @@ declare class CrossdeckServer extends EventEmitter {
1578
1597
  identify(userId: string, anonymousId: string, options?: IdentifyOptions & RequestOptions): Promise<AliasResult>;
1579
1598
  aliasIdentity(input: AliasIdentityInput, options?: RequestOptions): Promise<AliasResult>;
1580
1599
  forget(hints: IdentityHints, options?: RequestOptions): Promise<ForgetResult>;
1600
+ /**
1601
+ * Stamp an outbound email link so its click binds to the recipient on landing.
1602
+ *
1603
+ * You know the recipient's email at send time; pass it with the link's destination
1604
+ * and Crossdeck returns the same URL carrying a one-time arrival ticket (`cd_ref`).
1605
+ * Put the returned URL in the email. When the recipient clicks and lands on a page
1606
+ * running `@cross-deck/web`, the SDK reads the ticket automatically and binds that
1607
+ * session to the person — the post-click journey then joins their identity.
1608
+ *
1609
+ * Rail-agnostic: works for Resend, HubSpot, your own SMTP, anything. Server-side
1610
+ * only (it mints an identity bind, so a secret key is required). If the landing page
1611
+ * has no Crossdeck web SDK, the deep session stitch softens but the server-side
1612
+ * email funnel (via the rail adapter) still lands by identity.
1613
+ */
1614
+ campaignLink(input: CampaignLinkInput, options?: RequestOptions): Promise<CampaignLinkResult>;
1581
1615
  /**
1582
1616
  * Fetch a customer's entitlements from Crossdeck and warm the cache.
1583
1617
  *
@@ -2128,4 +2162,4 @@ declare class CrossdeckServer extends EventEmitter {
2128
2162
  private normalizeIngestEvent;
2129
2163
  }
2130
2164
 
2131
- 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 };
2165
+ export { type IdentifyOptions as $, type AliasIdentityInput as A, type BlockVerdict as B, CROSSDECK_API_VERSION as C, type CrossdeckServerOptions as D, CrossdeckValidationError as E, DEFAULT_BASE_URL as F, DEFAULT_TIMEOUT_MS as G, type Diagnostics as H, type EntitlementCacheOptions as I, type EntitlementMutationResult as J, type EntitlementStore as K, type EntitlementsListResponse as L, type EntitlementsListener as M, type Environment as N, type ErrorCaptureConfig as O, type ErrorLevel as P, type EventProperties as Q, type ForgetResult as R, type GateInput as S, type GateVerdict as T, type GrantDuration as U, type GrantEntitlementInput as V, type GroupMembership as W, type HeartbeatResponse as X, type HttpRequestInfo as Y, type HttpResponseInfo as Z, type HttpRetriesConfig as _, type AliasResult as a, type IdentityHints as a0, type IngestOptions as a1, type IngestResponse as a2, type OwnerStatusInput as a3, type PublicEntitlement as a4, type PurchaseResult as a5, type RequestOptions as a6, type ResolveInput as a7, type ResolveResult as a8, type RevokeEntitlementInput as a9, type RuntimeHost as aa, type RuntimeInfo as ab, type ServerEvent as ac, type StackFrame as ad, type StoredEntitlements as ae, type SyncPurchaseInput as af, makeCrossdeckError as ag, type AuditDecision as b, type AuditEntry as c, type Breadcrumb as d, type BreadcrumbCategory as e, type BreadcrumbLevel as f, type CampaignLinkInput as g, type CampaignLinkResult as h, type CapturedError as i, type Contract as j, type ContractAppliesTo as k, type ContractFailureInput as l, type ContractPillar as m, type ContractStatus as n, type ContractTestRef as o, CrossdeckAuthenticationError as p, CrossdeckConfigurationError as q, CrossdeckContracts as r, CrossdeckError as s, type CrossdeckErrorPayload as t, type CrossdeckErrorType as u, CrossdeckInternalError as v, CrossdeckNetworkError as w, CrossdeckPermissionError as x, CrossdeckRateLimitError as y, CrossdeckServer 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.13.0";
390
+ var SDK_VERSION = "1.14.0";
391
391
  var SDK_NAME = "@cross-deck/node";
392
392
 
393
393
  // src/_diagnostic-telemetry.ts
@@ -3048,6 +3048,43 @@ var CrossdeckServer = class extends import_node_events.EventEmitter {
3048
3048
  timeoutMs: options?.timeoutMs
3049
3049
  });
3050
3050
  }
3051
+ /**
3052
+ * Stamp an outbound email link so its click binds to the recipient on landing.
3053
+ *
3054
+ * You know the recipient's email at send time; pass it with the link's destination
3055
+ * and Crossdeck returns the same URL carrying a one-time arrival ticket (`cd_ref`).
3056
+ * Put the returned URL in the email. When the recipient clicks and lands on a page
3057
+ * running `@cross-deck/web`, the SDK reads the ticket automatically and binds that
3058
+ * session to the person — the post-click journey then joins their identity.
3059
+ *
3060
+ * Rail-agnostic: works for Resend, HubSpot, your own SMTP, anything. Server-side
3061
+ * only (it mints an identity bind, so a secret key is required). If the landing page
3062
+ * has no Crossdeck web SDK, the deep session stitch softens but the server-side
3063
+ * email funnel (via the rail adapter) still lands by identity.
3064
+ */
3065
+ async campaignLink(input, options) {
3066
+ if (!input.email) {
3067
+ throw new CrossdeckError({
3068
+ type: "invalid_request_error",
3069
+ code: "missing_email",
3070
+ message: "campaignLink requires the recipient's email."
3071
+ });
3072
+ }
3073
+ if (!input.url) {
3074
+ throw new CrossdeckError({
3075
+ type: "invalid_request_error",
3076
+ code: "missing_url",
3077
+ message: "campaignLink requires the link's destination url."
3078
+ });
3079
+ }
3080
+ const body = { email: input.email, url: input.url };
3081
+ if (input.rail) body.rail = input.rail;
3082
+ return this.http.request("POST", "/campaign/email-link", {
3083
+ body,
3084
+ signal: options?.signal,
3085
+ timeoutMs: options?.timeoutMs
3086
+ });
3087
+ }
3051
3088
  // ============================================================
3052
3089
  // Entitlements — direct HTTP + TTL cache (v1.0.0+)
3053
3090
  //