{"version":3,"sources":["../src/consent-mode.ts"],"sourcesContent":["/**\n * Crossdeck Consent Mode — the single on-switch for the marketplace / guest build\n * (Path B, CD-175/CD-185). A connector calls `startConsentMode(...)` INSTEAD of\n * `Crossdeck.start(...)`; this boots Crossdeck in the guest posture and wires the\n * branded consent widget + co-existence deferral together.\n *\n * The guest posture (why each is here — the Webflow findings):\n *   - `cookieDomain: \"none\"`   → identity is host-scoped, no broad-domain probing (#8)\n *   - `autoTrack.errors: false`→ no error capture ⇒ no fetch/XHR/history wrapping (#7)\n *   - `autoTrack.wrapHistory: false` → never monkey-patch history for SPA nav (#7)\n *   - `autoTrack.clicks: false` / `webVitals: false` → minimal capture (#5)\n *   - `autoTrack.stripUrlParams: true` → no query/fragment/referrer in analytics (#3)\n *   - consent DENIED + identityOptIn FALSE at boot → nothing sends until the visitor\n *     opts in via the widget (#4, #9); identity is explicit-opt-in only (#2)\n *   - the Trust iframe is simply never mounted (#6)\n *\n * The full-capability path (Path A / direct install) is unaffected — this is a\n * separate boot profile, not a change to the core SDK's defaults.\n */\nimport { Crossdeck as defaultClient } from \"./singleton\";\nimport type { CrossdeckClient } from \"./crossdeck\";\nimport type { ConsentState } from \"./consent\";\nimport type { Environment } from \"./types\";\nimport {\n  mountConsentBanner,\n  type ConsentBannerHandle,\n  type ConsentBannerState,\n} from \"./consent-banner\";\nimport {\n  detectExistingConsent,\n  subscribeToExternalConsent,\n} from \"./consent-coexistence\";\n\n/** Who owns the consent moment on this site. */\nexport type ConsentOwner = \"auto\" | \"crossdeck\" | \"external\";\n\nexport interface ConsentModeOptions {\n  /** Client-safe publishable key (`cd_pub_…`). Ingest-only — never a secret key. */\n  publicKey: string;\n  /** The Crossdeck app id the connector provisioned. */\n  appId: string;\n  /** Environment. Defaults to \"production\" (marketplace installs are live). */\n  environment?: Environment;\n  /**\n   * The SITE OWNER's privacy-policy URL. REQUIRED — the Crossdeck-managed banner\n   * will not render without it (it is the site owner's tool, reflecting their\n   * policy). Ignored when we defer to an existing CMP.\n   */\n  policyUrl: string;\n  /** Where the banner mounts (element or selector). Defaults to document.body. */\n  target?: HTMLElement | string;\n  /** Identity cookie scope. Defaults to \"none\" (host-only) for the guest build. */\n  cookieDomain?: string;\n  /**\n   * Who manages consent. \"auto\" (default) → render the Crossdeck banner only if\n   * no other CMP is detected. \"crossdeck\" → always render ours. \"external\" →\n   * always defer, never render ours.\n   */\n  consentOwner?: ConsentOwner;\n  /** Called whenever the visitor's choice changes. */\n  onChange?: (state: ConsentBannerState) => void;\n  /** The Crossdeck client to drive. Defaults to the singleton. */\n  client?: CrossdeckClient;\n}\n\nexport interface ConsentModeHandle {\n  /** The mounted banner, or null when we deferred to an existing CMP. */\n  banner: ConsentBannerHandle | null;\n  /** The consent mechanism we deferred to (its label), or null if we own it. */\n  deferredTo: string | null;\n}\n\n/**\n * Boot Crossdeck in consent-mode and wire the widget + co-existence. One call.\n */\nexport function startConsentMode(opts: ConsentModeOptions): ConsentModeHandle {\n  const client = opts.client ?? defaultClient;\n\n  // 1. Boot in the guest posture (see file header for the finding each maps to).\n  client.start({\n    publicKey: opts.publicKey,\n    appId: opts.appId,\n    environment: opts.environment ?? \"production\",\n    cookieDomain: opts.cookieDomain ?? \"none\",\n    respectDnt: true,\n    scrubPii: true,\n    autoTrack: {\n      clicks: false,\n      webVitals: false,\n      errors: false,\n      stripUrlParams: true,\n      wrapHistory: false,\n    },\n  });\n\n  // 2. Deny everything at boot — nothing leaves the SDK until the visitor grants.\n  client.consent({ analytics: false, marketing: false, errors: false });\n  client.setIdentityOptIn(false);\n\n  // The widget routes analytics/marketing through the public consent() method;\n  // onChange carries the identity opt-in (no ConsentManager dimension, by design).\n  const consentAdapter = {\n    set: (partial: Partial<ConsentState>): ConsentState => client.consent(partial),\n  };\n  const onWidgetChange = (state: ConsentBannerState): void => {\n    client.setIdentityOptIn(state.identityOptIn);\n    opts.onChange?.(state);\n  };\n\n  // 3. Co-existence — never a second banner. GPC + any detected CMP wins.\n  const owner: ConsentOwner = opts.consentOwner ?? \"auto\";\n  if (owner !== \"crossdeck\") {\n    const existing = detectExistingConsent();\n    if (existing) {\n      const read = existing.read();\n      client.consent({\n        analytics: read.analytics ?? false,\n        marketing: read.marketing ?? false,\n      });\n      if (existing.emitsChanges) {\n        subscribeToExternalConsent(existing, (partial) => {\n          client.consent(partial);\n        });\n      }\n      return { banner: null, deferredTo: existing.source };\n    }\n    if (owner === \"external\") {\n      // Owner runs their own tool but none was detected yet — stay denied,\n      // render nothing. (They wire their tool → client.consent themselves.)\n      return { banner: null, deferredTo: null };\n    }\n  }\n\n  // 4. We own the consent moment — render the Crossdeck banner (managed mode).\n  const banner = mountConsentBanner({\n    target: opts.target,\n    policyUrl: opts.policyUrl,\n    consent: consentAdapter,\n    onChange: onWidgetChange,\n  });\n  return { banner, deferredTo: null };\n}\n"],"mappings":";;;;;;;;;;;;;;AA2EO,SAAS,iBAAiB,MAA6C;AAC5E,QAAM,SAAS,KAAK,UAAU;AAG9B,SAAO,MAAM;AAAA,IACX,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,IACZ,aAAa,KAAK,eAAe;AAAA,IACjC,cAAc,KAAK,gBAAgB;AAAA,IACnC,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,MACT,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,aAAa;AAAA,IACf;AAAA,EACF,CAAC;AAGD,SAAO,QAAQ,EAAE,WAAW,OAAO,WAAW,OAAO,QAAQ,MAAM,CAAC;AACpE,SAAO,iBAAiB,KAAK;AAI7B,QAAM,iBAAiB;AAAA,IACrB,KAAK,CAAC,YAAiD,OAAO,QAAQ,OAAO;AAAA,EAC/E;AACA,QAAM,iBAAiB,CAAC,UAAoC;AAC1D,WAAO,iBAAiB,MAAM,aAAa;AAC3C,SAAK,WAAW,KAAK;AAAA,EACvB;AAGA,QAAM,QAAsB,KAAK,gBAAgB;AACjD,MAAI,UAAU,aAAa;AACzB,UAAM,WAAW,sBAAsB;AACvC,QAAI,UAAU;AACZ,YAAM,OAAO,SAAS,KAAK;AAC3B,aAAO,QAAQ;AAAA,QACb,WAAW,KAAK,aAAa;AAAA,QAC7B,WAAW,KAAK,aAAa;AAAA,MAC/B,CAAC;AACD,UAAI,SAAS,cAAc;AACzB,mCAA2B,UAAU,CAAC,YAAY;AAChD,iBAAO,QAAQ,OAAO;AAAA,QACxB,CAAC;AAAA,MACH;AACA,aAAO,EAAE,QAAQ,MAAM,YAAY,SAAS,OAAO;AAAA,IACrD;AACA,QAAI,UAAU,YAAY;AAGxB,aAAO,EAAE,QAAQ,MAAM,YAAY,KAAK;AAAA,IAC1C;AAAA,EACF;AAGA,QAAM,SAAS,mBAAmB;AAAA,IAChC,QAAQ,KAAK;AAAA,IACb,WAAW,KAAK;AAAA,IAChB,SAAS;AAAA,IACT,UAAU;AAAA,EACZ,CAAC;AACD,SAAO,EAAE,QAAQ,YAAY,KAAK;AACpC;","names":[]}