import { C as CrossdeckClient } from './consent.entry-DiG-dItA.js'; export { B as Breadcrumb, a as BreadcrumbCategory, b as BreadcrumbLevel, c as CapturedError, d as ConsentGlobals, e as ConsentMechanism, f as ConsentModeHandle, g as ConsentModeOptions, h as ConsentOwner, i as Contract, j as ContractAppliesTo, k as ContractFailureInput, l as ContractPillar, m as ContractStatus, n as ContractTestRef, o as CrossdeckContracts, D as DetectExistingConsentOptions, E as ErrorLevel, p as ExistingConsentSource, S as StackFrame, V as VerificationStatus } from './consent.entry-DiG-dItA.js'; export { C as CrossdeckTrustNamespace, M as MountTrustPanelOptions, b as TRUST_PANEL_ORIGIN, c as TrustPanelHandle, d as TrustPanelInput, e as TrustResult, T as TrustToken, a as TrustTokenStatus, f as TrustUnavailable, m as mountTrustPanel } from './trust-sji5vuxH.js'; import { K as KeyValueStorage } from './types-DfdHJNUG.js'; export { A as AliasResult, a as AuditRail, b as AutoTrackOptions, c as ConsentBannerHandle, d as ConsentBannerMode, e as ConsentBannerOptions, f as ConsentBannerState, g as ConsentCategoriesConfig, h as ConsentCategoryConfig, i as ConsentMethod, j as ConsentRecord, k as ConsentState, l as CrossdeckConsentNamespace, C as CrossdeckOptions, D as Diagnostics, E as EntitlementsListResponse, m as Environment, n as EventProperties, G as GroupTraits, H as HeartbeatResponse, I as IdentifyOptions, P as Platform, o as PublicEntitlement, p as PurchaseResult } from './types-DfdHJNUG.js'; /** * The ONE Crossdeck singleton — shared across every entry point. * * Why this module exists (the biotree defect, CD-155): `@cross-deck/web` and * `@cross-deck/web/react` build as SEPARATE bundles. Each one inlined * `crossdeck.ts` — including a bare `export const Crossdeck = new * CrossdeckClient()` — so the shipped package contained TWO singletons: one in * `index.mjs`, a different object baked into `react.mjs`. A React app that did * `Crossdeck.init()` / `identify()` / `getEntitlements()` on the core import * warmed instance A, while `useEntitlement()` (react entry) read instance B, * which was never initialised — so a paying customer read `false` forever. No * error, no warning; a silent duplicate-singleton hazard. In source the import * is single; the split is purely a bundling artefact. * * The fix that CANNOT regress: back the instance with the cross-realm global * symbol registry. `Symbol.for(key)` returns the same symbol everywhere, so no * matter how many times a bundler duplicates this module, every copy resolves * to the SAME instance. This is the same guard PostHog, Segment, and * LaunchDarkly use for their React bindings, for this exact reason. */ /** * The default singleton — most consumers want one SDK instance per app. Every * entry point (`@cross-deck/web`, `@cross-deck/web/react`, `.../vue`) resolves * to THIS object. Creating extra instances is still fine for advanced use: * just `new CrossdeckClient()`. */ declare const Crossdeck: CrossdeckClient; /** * Stripe-style error wrapper for @cross-deck/web. * * Mirrors the wire shape returned by the v1 backend (see * backend/src/api/v1-errors.ts) so SDK consumers can `catch` * with consistent fields: * * try { * await crossdeck.identify("user_847"); * } catch (err) { * if (err instanceof CrossdeckError && err.code === "invalid_api_key") { * // ... * } * } */ type CrossdeckErrorType = "authentication_error" | "permission_error" | "invalid_request_error" | "rate_limit_error" | "version_error" | "internal_error" | "network_error" | "configuration_error"; interface CrossdeckErrorPayload { type: CrossdeckErrorType; code: string; message: string; /** Server-issued request ID. Echoed in support tickets. */ requestId?: string; /** HTTP status code if the error came from an API response. */ status?: number; /** * Server-suggested wait (in milliseconds) before retrying. Populated * from the `Retry-After` response header on 429 / 503. The header * spec allows either delta-seconds or an HTTP-date; the parser below * normalises both to milliseconds. Consumers MUST honour this — the * server is telling you the safe rate. */ retryAfterMs?: number; /** * Required SDK version floor — populated only on a `426 Upgrade Required` * / `sdk_version_unsupported` response. The queue surfaces it in the * "update to >= X" PARK message so the cure is exact. */ minVersion?: string; /** SDK surface the rejection applies to (web/node/swift/…), on a 426. */ surface?: string; } declare class CrossdeckError extends Error { readonly type: CrossdeckErrorType; readonly code: string; readonly requestId?: string; readonly status?: number; readonly retryAfterMs?: number; readonly minVersion?: string; readonly surface?: string; constructor(payload: CrossdeckErrorPayload); } /** * Storage adapters for SDK-persisted state. * * Three flavours: * - browser localStorage (default in browsers) * - 1st-party document.cookie (redundancy for cleared localStorage) * - in-memory (default in Node, or as an explicit fallback) * * Detection is at construction time, not at every call — picking the * adapter once means we don't hit `typeof window` checks on hot paths. * * ----- Bank-grade identity continuity ----- * * Plain localStorage is not enough. ITP, private browsing, "clear site * data" actions, and aggressive privacy extensions all wipe it. When * that happens, the SDK mints a fresh anonymousId on next page load * and the customer's analytics see one human as multiple "new * visitors" — a credibility hit on every dashboard chart that depends * on visitor uniqueness (new vs returning, retention, funnels). * * The fix is redundancy: we write the same identity to BOTH * localStorage AND a 1st-party cookie. On boot we read both; whichever * survived wins. On set, we write to both stores so a future clear of * either doesn't lose the user. * * Caveats (documented honestly): * 1. Safari ITP caps client-set 1st-party cookies at 7 days. Cookie * redundancy protects against localStorage clears WITHIN that * 7-day window, not beyond it. The full ITP-bypass story (server- * set cookies via a customer-CNAMEd subdomain) is a Phase 2 * follow-up that requires customer DNS configuration. * 2. We never write fingerprintable data — only the same anonymousId * already in localStorage. Privacy posture is unchanged from * single-store identity. * 3. `persistIdentity: false` disables BOTH stores so customers * running strict consent flows can defer cookie writes until the * user opts in. */ /** * In-memory storage. Cleared on process exit. Useful for Node runtimes * where you want session-scoped identity that doesn't persist to disk. */ declare class MemoryStorage implements KeyValueStorage { private store; getItem(key: string): string | null; setItem(key: string, value: string): void; removeItem(key: string): void; } /** * SDK version constant — generated by `scripts/sync-sdk-versions.mjs`. * * Single source of truth: the `version` field in this package's * package.json. The sync script writes this file so that * `SDK_VERSION` is a plain TypeScript literal at runtime — no * runtime JSON-import gotcha (Node ESM requires * `with { type: "json" }` to import JSON as ESM, and the published * dist file would otherwise fail to load). * * Drift protection: `node scripts/sync-sdk-versions.mjs --check` (the * CI gate) flags this file when it falls out of sync with package.json. * Bumping `package.json` without re-running the sync script fails CI. * * Do NOT edit by hand — `node scripts/sync-sdk-versions.mjs`. */ declare const SDK_VERSION = "1.14.2"; declare const SDK_NAME = "@cross-deck/web"; /** * HTTP transport for the SDK. Single fetch wrapper used by every endpoint * call. Adds the Bearer token and SDK version header, parses responses, * normalises errors to CrossdeckError. * * Uses platform-native fetch (browser + Node 18+). No axios, no isomorphic- * fetch shim, no transitive deps. */ declare const DEFAULT_BASE_URL = "https://api.cross-deck.com/v1"; /** * Machine-readable index of every error code the SDK can throw, with * a short description and a hint on what action to take. Published * verbatim as `crossdeck-error-codes.json` in the npm tarball so AI * integration assistants, error-aggregator dashboards (Sentry, * DataDog), and the Crossdeck dashboard can render human-friendly * messages without parsing freeform `message` strings. * * Stripe publishes the same surface at stripe.com/docs/error-codes; * developers love it because every code has a canonical "what does * this mean / what should I do" answer. * * Adding a new error code: * 1. Add the code string to the union in `errors.ts` (where used). * 2. Add an entry here. * 3. The next `npm run build` regenerates the JSON sidecar. * * Keep entries terse — the consumer surfaces this in tooltips and * automated tickets, not in long-form docs. */ interface ErrorCodeEntry { /** The string thrown as CrossdeckError.code. */ code: string; /** CrossdeckError.type — broad category. */ type: "authentication_error" | "permission_error" | "invalid_request_error" | "rate_limit_error" | "version_error" | "internal_error" | "network_error" | "configuration_error"; /** One-sentence description. Surfaced verbatim in dashboards. */ description: string; /** What the developer should do. Imperative phrasing. */ resolution: string; /** True for codes the SDK can auto-recover from (no developer action). */ retryable: boolean; } declare const CROSSDECK_ERROR_CODES: readonly ErrorCodeEntry[]; /** Lookup helper — returns the entry matching a CrossdeckError.code, or undefined. */ declare function getErrorCode(code: string): ErrorCodeEntry | undefined; /** * Device + environment enrichment. * * Auto-attached to every event the SDK emits when `autoTrack.deviceInfo` is * enabled (default). Caller-supplied event properties always override * auto-detected ones (so a developer can manually set `app.version` per * event if they want to A/B between builds). * * Privacy posture: * - No fingerprinting (no canvas hashes, no font enumeration). * - No precise geolocation (only timezone + locale, both of which the * browser exposes to every page anyway). * - No IP collection — the backend logs the request IP for rate-limit * purposes; it isn't stored on the event document. * - All fields are typed enums or short strings; we never echo back * full User-Agent strings to avoid surfacing fingerprintable detail * in dashboards. */ interface DeviceInfo { os?: string; osVersion?: string; browser?: string; browserVersion?: string; locale?: string; timezone?: string; screenWidth?: number; screenHeight?: number; viewportWidth?: number; viewportHeight?: number; devicePixelRatio?: number; /** Caller-supplied. Set via Crossdeck.start({ appVersion: "1.2.3" }). */ appVersion?: string; } export { CROSSDECK_ERROR_CODES, Crossdeck, CrossdeckClient, CrossdeckError, type CrossdeckErrorPayload, type CrossdeckErrorType, DEFAULT_BASE_URL, type DeviceInfo, type ErrorCodeEntry, KeyValueStorage, MemoryStorage, SDK_NAME, SDK_VERSION, getErrorCode };