bitsnap-react 1.9.0 → 1.11.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.
Files changed (116) hide show
  1. package/README.md +95 -7
  2. package/dist/CartProvider-ONIOELW5.mjs +2 -0
  3. package/dist/CartProvider-Q3CIVK5K.js +2 -0
  4. package/dist/CartProvider-Q3CIVK5K.js.map +1 -0
  5. package/dist/analytics.d.mts +22 -5
  6. package/dist/analytics.d.ts +22 -5
  7. package/dist/analytics.js +1 -1
  8. package/dist/analytics.js.map +1 -1
  9. package/dist/analytics.mjs +1 -1
  10. package/dist/catalog.d.mts +1 -1
  11. package/dist/catalog.d.ts +1 -1
  12. package/dist/catalog.js +1 -1
  13. package/dist/catalog.js.map +1 -1
  14. package/dist/catalog.mjs +1 -1
  15. package/dist/chunk-7RGH57QG.js +2 -0
  16. package/dist/chunk-7RGH57QG.js.map +1 -0
  17. package/dist/chunk-ADYVTMGH.mjs +2 -0
  18. package/dist/chunk-ADYVTMGH.mjs.map +1 -0
  19. package/dist/{chunk-FHDFLSPW.js → chunk-ASNUY3EU.js} +2 -2
  20. package/dist/chunk-ASNUY3EU.js.map +1 -0
  21. package/dist/{chunk-HKVMSMDF.mjs → chunk-C5Q7DGCD.mjs} +2 -2
  22. package/dist/{chunk-LJWS6ZRJ.mjs → chunk-C5RMHUOG.mjs} +2 -2
  23. package/dist/{chunk-KG6RU37U.js → chunk-CUQ2PNCJ.js} +3 -3
  24. package/dist/chunk-CUQ2PNCJ.js.map +1 -0
  25. package/dist/{chunk-VXB7LA4E.js → chunk-ELGNOAH4.js} +2 -2
  26. package/dist/chunk-ELGNOAH4.js.map +1 -0
  27. package/dist/chunk-EZWH6BB2.mjs +2 -0
  28. package/dist/chunk-EZWH6BB2.mjs.map +1 -0
  29. package/dist/{chunk-SLLBTQTW.mjs → chunk-GPNALARZ.mjs} +2 -2
  30. package/dist/chunk-GT3OH55Y.js +2 -0
  31. package/dist/chunk-GT3OH55Y.js.map +1 -0
  32. package/dist/{chunk-SZ256RCC.mjs → chunk-H3YP2QPV.mjs} +2 -2
  33. package/dist/chunk-HG4YOJWE.mjs +4 -0
  34. package/dist/chunk-HG4YOJWE.mjs.map +1 -0
  35. package/dist/chunk-JSDGZ4NY.js.map +1 -1
  36. package/dist/chunk-KOYBZORL.js.map +1 -1
  37. package/dist/{chunk-VM6JEJFZ.js → chunk-PUYK4YHE.js} +2 -2
  38. package/dist/chunk-PUYK4YHE.js.map +1 -0
  39. package/dist/chunk-T57337WD.mjs +2 -0
  40. package/dist/chunk-T57337WD.mjs.map +1 -0
  41. package/dist/{chunk-3IMJALBX.js → chunk-VQQBBSK2.js} +2 -2
  42. package/dist/chunk-VQQBBSK2.js.map +1 -0
  43. package/dist/chunk-XIHGWNTS.js +2 -0
  44. package/dist/chunk-XIHGWNTS.js.map +1 -0
  45. package/dist/{chunk-GN63ITLA.mjs → chunk-XQ43IC4M.mjs} +2 -2
  46. package/dist/{chunk-V4U2PTKN.js → chunk-YFETPEI6.js} +2 -2
  47. package/dist/chunk-YFETPEI6.js.map +1 -0
  48. package/dist/consent.d.mts +7 -0
  49. package/dist/consent.d.ts +7 -0
  50. package/dist/consent.js +29 -15
  51. package/dist/consent.js.map +1 -1
  52. package/dist/consent.mjs +29 -15
  53. package/dist/consent.mjs.map +1 -1
  54. package/dist/course.d.mts +2 -2
  55. package/dist/course.d.ts +2 -2
  56. package/dist/course.js +1 -1
  57. package/dist/course.js.map +1 -1
  58. package/dist/course.mjs +1 -1
  59. package/dist/course.mjs.map +1 -1
  60. package/dist/embed/analytics.js +1 -1
  61. package/dist/embed/consent.js +27 -13
  62. package/dist/errors.js.map +1 -1
  63. package/dist/index.d.mts +40 -8
  64. package/dist/index.d.ts +40 -8
  65. package/dist/index.js +1 -1
  66. package/dist/index.js.map +1 -1
  67. package/dist/index.mjs +1 -1
  68. package/dist/index.mjs.map +1 -1
  69. package/dist/{instrument-C_abZLHk.d.ts → instrument-CmxK7S4T.d.mts} +22 -5
  70. package/dist/{instrument-C_abZLHk.d.mts → instrument-CmxK7S4T.d.ts} +22 -5
  71. package/dist/internal.js.map +1 -1
  72. package/dist/methods-C5HWYPPN.mjs +2 -0
  73. package/dist/methods-CHNMFVFV.js +2 -0
  74. package/dist/methods-CHNMFVFV.js.map +1 -0
  75. package/dist/models.js.map +1 -1
  76. package/dist/returns.d.mts +1 -1
  77. package/dist/returns.d.ts +1 -1
  78. package/dist/returns.js +1 -1
  79. package/dist/returns.js.map +1 -1
  80. package/dist/returns.mjs +1 -1
  81. package/dist/{types-D_WnqwR_.d.mts → types-BnVWLcoB.d.mts} +1 -1
  82. package/dist/{types-BaqLJYuq.d.ts → types-i-IuN4Im.d.ts} +1 -1
  83. package/package.json +2 -2
  84. package/dist/CartProvider-XWTLBIZ5.js +0 -2
  85. package/dist/CartProvider-XWTLBIZ5.js.map +0 -1
  86. package/dist/CartProvider-ZURLJNBW.mjs +0 -2
  87. package/dist/chunk-3IMJALBX.js.map +0 -1
  88. package/dist/chunk-3UHPJ6NK.js +0 -2
  89. package/dist/chunk-3UHPJ6NK.js.map +0 -1
  90. package/dist/chunk-CO2P4FR5.js +0 -2
  91. package/dist/chunk-CO2P4FR5.js.map +0 -1
  92. package/dist/chunk-E6QVQEGZ.mjs +0 -2
  93. package/dist/chunk-E6QVQEGZ.mjs.map +0 -1
  94. package/dist/chunk-FHDFLSPW.js.map +0 -1
  95. package/dist/chunk-KG6RU37U.js.map +0 -1
  96. package/dist/chunk-LZE2E4TE.mjs +0 -4
  97. package/dist/chunk-LZE2E4TE.mjs.map +0 -1
  98. package/dist/chunk-QZJGNLCZ.js +0 -2
  99. package/dist/chunk-QZJGNLCZ.js.map +0 -1
  100. package/dist/chunk-RA452LXZ.mjs +0 -2
  101. package/dist/chunk-RA452LXZ.mjs.map +0 -1
  102. package/dist/chunk-V4U2PTKN.js.map +0 -1
  103. package/dist/chunk-VM6JEJFZ.js.map +0 -1
  104. package/dist/chunk-VXB7LA4E.js.map +0 -1
  105. package/dist/chunk-XVQKEGPO.mjs +0 -2
  106. package/dist/chunk-XVQKEGPO.mjs.map +0 -1
  107. package/dist/methods-CYARZTYL.mjs +0 -2
  108. package/dist/methods-DAPEWVI6.js +0 -2
  109. package/dist/methods-DAPEWVI6.js.map +0 -1
  110. /package/dist/{CartProvider-ZURLJNBW.mjs.map → CartProvider-ONIOELW5.mjs.map} +0 -0
  111. /package/dist/{chunk-HKVMSMDF.mjs.map → chunk-C5Q7DGCD.mjs.map} +0 -0
  112. /package/dist/{chunk-LJWS6ZRJ.mjs.map → chunk-C5RMHUOG.mjs.map} +0 -0
  113. /package/dist/{chunk-SLLBTQTW.mjs.map → chunk-GPNALARZ.mjs.map} +0 -0
  114. /package/dist/{chunk-SZ256RCC.mjs.map → chunk-H3YP2QPV.mjs.map} +0 -0
  115. /package/dist/{chunk-GN63ITLA.mjs.map → chunk-XQ43IC4M.mjs.map} +0 -0
  116. /package/dist/{methods-CYARZTYL.mjs.map → methods-C5HWYPPN.mjs.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/consent/react.tsx","../src/consent/core/types.ts","../src/consent/core/activate.ts","../src/consent/core/config.ts","../src/consent/core/cookie.ts","../src/consent/core/gcm.ts","../src/consent/core/texts.ts","../src/consent/core/contrast.ts","../src/consent/core/styles.ts","../src/consent/core/ui.ts","../src/consent/core/controller.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"../lib/isomorphic-layout-effect\";\nimport { createConsent } from \"./core/controller\";\nimport type {\n BitsnapConsentApi,\n ConsentChoices,\n ConsentConfig,\n ConsentOptions,\n ConsentState,\n} from \"./core/types\";\n\ndeclare global {\n interface Window {\n BitsnapConsent?: BitsnapConsentApi;\n }\n}\n\nexport type BitsnapConsentProps = {\n /** Public project key: loads the project's banner config and logs choices. */\n projectKey?: string;\n theme?: ConsentOptions[\"theme\"];\n locale?: ConsentOptions[\"locale\"];\n position?: ConsentOptions[\"position\"];\n privacyPolicyUrl?: string;\n /** `project` keeps the consent cookie per project key. */\n scope?: ConsentOptions[\"scope\"];\n apiHost?: string;\n collectHost?: string;\n /** Local config, merged over the project config. */\n config?: Partial<ConsentConfig>;\n reloadOnWithdraw?: boolean;\n /** Google Consent Mode v2: `auto` (default) is on when `gtag` or `dataLayer` already exist. */\n gcm?: ConsentOptions[\"gcm\"];\n /** Categories offered when no remote config is loaded. */\n categories?: ConsentOptions[\"categories\"];\n /** Dashboard preview: shows the banner from the local options only; touches no cookie. */\n preview?: boolean;\n /** Replaces the banner title. */\n title?: string;\n /** Replaces the banner description. */\n description?: string;\n};\n\n/** Mounts Bitsnap Consent on the page. Renders nothing itself (the banner lives in a Shadow DOM). */\nexport function BitsnapConsent(props: BitsnapConsentProps): null {\n const {\n projectKey, theme, locale, position, privacyPolicyUrl, scope, apiHost, collectHost, reloadOnWithdraw,\n gcm, preview, title, description,\n } = props;\n const configKey = JSON.stringify(props.config ?? null);\n const configRef = useRef(props.config);\n configRef.current = props.config;\n const categoriesKey = JSON.stringify(props.categories ?? null);\n const categoriesRef = useRef(props.categories);\n categoriesRef.current = props.categories;\n\n // A layout effect: the page's passive effects (first events, tracker) must find the API already there.\n useIsomorphicLayoutEffect(() => {\n // A banner from the script tag or another instance already runs on this page.\n if (window.BitsnapConsent) return;\n const api = createConsent({\n projectKey,\n theme,\n locale,\n position,\n privacyPolicyUrl,\n scope,\n apiHost,\n collectHost,\n reloadOnWithdraw,\n gcm,\n preview,\n title,\n description,\n categories: categoriesRef.current,\n config: configRef.current,\n });\n window.BitsnapConsent = api;\n return () => {\n api.destroy();\n if (window.BitsnapConsent === api) delete window.BitsnapConsent;\n };\n }, [\n projectKey, theme, locale, position, privacyPolicyUrl, scope, apiHost, collectHost, reloadOnWithdraw,\n gcm, preview, title, description, categoriesKey, configKey,\n ]);\n\n return null;\n}\n\nlet lastKey = \"null\";\nlet lastState: ConsentState | null = null;\n\nfunction getSnapshot(): ConsentState | null {\n const current = typeof window === \"undefined\" ? null : (window.BitsnapConsent?.get() ?? null);\n const key = JSON.stringify(current);\n if (key !== lastKey) {\n lastKey = key;\n lastState = current;\n }\n return lastState;\n}\n\nfunction subscribe(onChange: () => void): () => void {\n window.addEventListener(\"bitsnap:consent\", onChange);\n window.addEventListener(\"bitsnap:consent:ready\", onChange);\n return () => {\n window.removeEventListener(\"bitsnap:consent\", onChange);\n window.removeEventListener(\"bitsnap:consent:ready\", onChange);\n };\n}\n\nexport type UseConsent = {\n /** The stored choice, or `null` while there is none (or on the server). */\n consent: ConsentState | null;\n /** `true` once the visitor has made a choice that is still valid. */\n decided: boolean;\n open: () => void;\n accept: (categories?: Partial<ConsentChoices>) => void;\n acceptAll: () => void;\n rejectAll: () => void;\n reset: () => void;\n};\n\n/** Current consent state of the page, kept up to date as the visitor chooses. */\nexport function useConsent(): UseConsent {\n const consent = useSyncExternalStore(subscribe, getSnapshot, () => null);\n const open = useCallback(() => window.BitsnapConsent?.open(), []);\n const accept = useCallback((categories?: Partial<ConsentChoices>) => window.BitsnapConsent?.accept(categories), []);\n const acceptAll = useCallback(() => window.BitsnapConsent?.acceptAll(), []);\n const rejectAll = useCallback(() => window.BitsnapConsent?.rejectAll(), []);\n const reset = useCallback(() => window.BitsnapConsent?.reset(), []);\n return { consent, decided: consent !== null, open, accept, acceptAll, rejectAll, reset };\n}\n","export type ConsentCategory = \"analytics\" | \"marketing\" | \"preferences\";\n\nexport type ConsentChoices = Record<ConsentCategory, boolean>;\n\nexport type ConsentTheme = \"auto\" | \"light\" | \"dark\";\n\nexport type ConsentPosition = \"bottom\" | \"bottom-left\" | \"bottom-right\";\n\nexport type ConsentLocale = \"pl\" | \"en\";\n\nexport const CONSENT_CATEGORIES: readonly ConsentCategory[] = [\n \"analytics\",\n \"marketing\",\n \"preferences\",\n];\n\nexport const CONSENT_TEXT_KEYS = [\n \"title\",\n \"description\",\n \"acceptAll\",\n \"rejectAll\",\n \"settings\",\n \"save\",\n \"close\",\n \"necessaryTitle\",\n \"necessaryDescription\",\n \"analyticsTitle\",\n \"analyticsDescription\",\n \"marketingTitle\",\n \"marketingDescription\",\n \"preferencesTitle\",\n \"preferencesDescription\",\n \"poweredBy\",\n] as const;\n\nexport type ConsentTexts = Record<(typeof CONSENT_TEXT_KEYS)[number], string>;\n\nexport type ConsentService = {\n name: string;\n category: ConsentCategory;\n /** Cookies to delete (best effort) when the category is withdrawn. A trailing `*` matches a prefix. */\n cookies?: string[];\n};\n\nexport type ConsentConfig = {\n /** Banner version. A stored choice with a lower `bv` makes the banner ask again. */\n version: number;\n theme: ConsentTheme;\n accentColor?: string;\n position: ConsentPosition;\n privacyPolicyUrl?: string;\n categories: ConsentChoices;\n services: ConsentService[];\n texts?: Partial<Record<ConsentLocale, Partial<ConsentTexts>>>;\n poweredBy: true;\n};\n\n/** What the consent cookie holds, and what `get()` returns. */\nexport type ConsentState = {\n id: string;\n /** Unix seconds. */\n ts: number;\n /** Version of the banner the choice was made on. */\n bv: number;\n c: ConsentChoices;\n};\n\nexport type ConsentAction =\n | \"accept_all\"\n | \"reject_all\"\n | \"custom\"\n | \"withdraw\";\n\n/** `detail` of `bitsnap:consent` and the argument of `on('change')`. */\nexport type ConsentChangeDetail = ConsentState & {\n /** `reset` when the visitor's stored choice was cleared (`get()` is `null` then). */\n action: ConsentAction | \"reset\";\n};\n\nexport type ConsentOptions = {\n /** Public project key. Enables the remote config and the consent log. */\n projectKey?: string;\n theme?: ConsentTheme;\n locale?: \"auto\" | ConsentLocale;\n position?: ConsentPosition;\n privacyPolicyUrl?: string;\n /** `project` keeps one cookie per project key (`bitsnap_consent_<key>`). */\n scope?: \"global\" | \"project\";\n apiHost?: string;\n collectHost?: string;\n /** Google Consent Mode v2. `auto` is on when `gtag` or `dataLayer` already exist. */\n gcm?: \"auto\" | \"on\" | \"off\";\n /** Local overrides, merged over the defaults and the remote config. */\n config?: Partial<ConsentConfig>;\n /** Categories used when no remote config is loaded. */\n categories?: Partial<ConsentChoices>;\n reloadOnWithdraw?: boolean;\n /**\n * Dashboard preview: shows the banner at once from the local options, never\n * reads or writes the cookie, loads no remote config, sends no consent log,\n * and the buttons only close the banner.\n */\n preview?: boolean;\n /** Replaces the banner title (current locale, non-empty values only). */\n title?: string;\n /** Replaces the banner description (current locale, non-empty values only). */\n description?: string;\n};\n\nexport type BitsnapConsentApi = {\n get(): ConsentState | null;\n /**\n * `true` when the visitor refused `category`, also in a choice made on an older banner\n * version (which `get()` no longer returns) that they have not answered again yet.\n */\n denied(category: ConsentCategory): boolean;\n on(event: \"change\", fn: (detail: ConsentChangeDetail) => void): () => void;\n open(): void;\n close(): void;\n accept(categories?: Partial<ConsentChoices>): void;\n acceptAll(): void;\n rejectAll(): void;\n reset(): void;\n /** Resolves with the stored choice (or `null`) once config and stored choice are applied. */\n ready: Promise<ConsentState | null>;\n destroy(): void;\n};\n","import { CONSENT_CATEGORIES, type ConsentChoices } from \"./types\";\n\nconst SCRIPT_SELECTOR = 'script[type=\"text/plain\"][data-bitsnap-consent]:not([data-bitsnap-queued])';\nconst FRAME_SELECTOR = \"iframe[data-bitsnap-consent][data-src]\";\n\nconst allowed = (c: ConsentChoices, category: string | null): boolean =>\n (CONSENT_CATEGORIES as readonly string[]).includes(category ?? \"\") &&\n c[category as keyof ConsentChoices];\n\n/** Settles when the script has loaded or failed: a broken script must not block the ones after it. */\nfunction settled(script: HTMLScriptElement): Promise<void> {\n return new Promise((resolve) => {\n script.addEventListener(\"load\", () => resolve(), { once: true });\n script.addEventListener(\"error\", () => resolve(), { once: true });\n });\n}\n\n/** Swaps the placeholder for a live script; resolves once an external one has loaded. */\nfunction run(doc: Document, placeholder: HTMLScriptElement): Promise<void> | undefined {\n const script = doc.createElement(\"script\");\n for (const { name, value } of Array.from(placeholder.attributes)) {\n if (name === \"type\" || name === \"data-bitsnap-queued\") continue;\n if (name === \"data-type\") {\n // The embed writes the original `type=\"module\"` here, as `type` itself is `text/plain`.\n if (value === \"module\") script.setAttribute(\"type\", \"module\");\n } else if (name === \"data-src\") script.setAttribute(\"src\", value);\n else script.setAttribute(name, value);\n }\n if (placeholder.nonce) script.nonce = placeholder.nonce;\n const external = script.hasAttribute(\"src\");\n if (external) {\n // Dynamic scripts are async by default; keep the order of the page.\n if (!placeholder.hasAttribute(\"async\")) script.async = false;\n } else {\n script.text = placeholder.text;\n }\n const loaded = external ? settled(script) : undefined;\n placeholder.parentNode?.replaceChild(script, placeholder);\n return loaded;\n}\n\n/**\n * Turns the consented placeholders into live elements:\n * `<script type=\"text/plain\" data-bitsnap-consent=\"marketing\" [data-src] [data-type=\"module\"]>` becomes\n * a real script (attributes copied, `type` dropped or restored from `data-type`, `data-src` -> `src`),\n * and `<iframe data-src>` gets its `src`.\n * Placeholders run in document order: an inline script waits for the external scripts before it\n * (`<script src=lib.js>` then `<script>Lib.init()</script>`), external ones only follow each other.\n */\nexport function activateScripts(doc: Document, c: ConsentChoices): number {\n let activated = 0;\n try {\n /** Set once a placeholder had to wait: everything after it queues behind it. */\n let gate: Promise<void> | null = null;\n /** External scripts inserted since the last inline one. */\n let loading: Promise<void>[] = [];\n doc.querySelectorAll<HTMLScriptElement>(SCRIPT_SELECTOR).forEach((placeholder) => {\n if (!allowed(c, placeholder.getAttribute(\"data-bitsnap-consent\"))) return;\n activated++;\n const inline = !placeholder.hasAttribute(\"data-src\") && !placeholder.hasAttribute(\"src\");\n if (gate || (inline && loading.length > 0)) {\n // Marked so that another call (a later choice) does not queue it again.\n placeholder.setAttribute(\"data-bitsnap-queued\", \"\");\n gate = (gate ?? Promise.all(loading).then(() => {})).then(() => {\n try {\n return run(doc, placeholder);\n } catch {\n // never throw into the host page\n }\n });\n loading = [];\n return;\n }\n const loaded = run(doc, placeholder);\n if (loaded) loading.push(loaded);\n });\n doc.querySelectorAll<HTMLIFrameElement>(FRAME_SELECTOR).forEach((frame) => {\n if (!allowed(c, frame.getAttribute(\"data-bitsnap-consent\"))) return;\n const src = frame.getAttribute(\"data-src\");\n if (src && frame.getAttribute(\"src\") !== src) {\n frame.setAttribute(\"src\", src);\n frame.removeAttribute(\"data-src\");\n activated++;\n }\n });\n } catch {\n // never throw into the host page\n }\n return activated;\n}\n","import {\n CONSENT_CATEGORIES,\n type ConsentChoices,\n type ConsentConfig,\n type ConsentService,\n} from \"./types\";\n\nexport const DEFAULT_API_HOST = \"https://bitsnap.pl\";\nexport const DEFAULT_COLLECT_HOST = \"https://collect.bitsnap.pl\";\n\nexport function defaultConfig(): ConsentConfig {\n return {\n version: 1,\n theme: \"auto\",\n position: \"bottom\",\n categories: { analytics: true, marketing: true, preferences: false },\n services: [],\n poweredBy: true,\n };\n}\n\nconst THEMES = [\"auto\", \"light\", \"dark\"];\nconst POSITIONS = [\"bottom\", \"bottom-left\", \"bottom-right\"];\n\nconst HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;\n\nexport function safeColor(value: unknown): string | undefined {\n return typeof value === \"string\" && HEX_COLOR.test(value.trim())\n ? value.trim()\n : undefined;\n}\n\n/** Only http(s) and relative URLs may end up in the banner. */\nexport function safeUrl(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const url = value.trim();\n return /^(?:https?:\\/\\/|\\/(?!\\/)|#|\\?)/i.test(url) ? url : undefined;\n}\n\nfunction cleanServices(value: unknown): ConsentService[] {\n if (!Array.isArray(value)) return [];\n const services: ConsentService[] = [];\n for (const item of value) {\n if (\n item &&\n typeof item.name === \"string\" &&\n (CONSENT_CATEGORIES as readonly string[]).includes(item.category)\n ) {\n services.push({\n name: item.name,\n category: item.category,\n cookies: Array.isArray(item.cookies)\n ? item.cookies.filter((cookie: unknown) => typeof cookie === \"string\")\n : undefined,\n });\n }\n }\n return services;\n}\n\n/** Layers partial configs (later wins) over the defaults, dropping invalid values. */\nexport function mergeConfig(\n ...layers: (Partial<ConsentConfig> | null | undefined)[]\n): ConsentConfig {\n const result = defaultConfig();\n for (const layer of layers) {\n if (!layer || typeof layer !== \"object\") continue;\n if (typeof layer.version === \"number\" && layer.version >= 0) {\n result.version = Math.floor(layer.version);\n }\n if (THEMES.includes(layer.theme as string)) result.theme = layer.theme!;\n if (POSITIONS.includes(layer.position as string)) result.position = layer.position!;\n const accent = safeColor(layer.accentColor);\n if (accent) result.accentColor = accent;\n const privacy = safeUrl(layer.privacyPolicyUrl);\n if (privacy) result.privacyPolicyUrl = privacy;\n if (layer.categories && typeof layer.categories === \"object\") {\n for (const category of CONSENT_CATEGORIES) {\n if (typeof layer.categories[category] === \"boolean\") {\n result.categories[category] = layer.categories[category];\n }\n }\n }\n if (layer.services !== undefined) result.services = cleanServices(layer.services);\n if (layer.texts && typeof layer.texts === \"object\") result.texts = layer.texts;\n }\n return result;\n}\n\nexport function parseCategoryList(value: string | null | undefined): ConsentChoices {\n const wanted = (value ?? \"\").split(\",\").map((item) => item.trim());\n return {\n analytics: wanted.includes(\"analytics\"),\n marketing: wanted.includes(\"marketing\"),\n preferences: wanted.includes(\"preferences\"),\n };\n}\n\n/** What `GET /api/consent/config` answers: whether the banner is on, and its config. */\nexport type RemoteConsentConfig = {\n /** `false` when the project turned the banner off: nothing is shown, stored choices still apply. */\n enabled: boolean;\n config: Partial<ConsentConfig> | null;\n};\n\n/** Loads the project's banner config. Resolves to `null` on any failure or after the timeout. */\nexport async function fetchRemoteConfig(\n apiHost: string,\n key: string,\n timeoutMs = 3000,\n): Promise<RemoteConsentConfig | null> {\n if (typeof fetch !== \"function\") return null;\n const controller = typeof AbortController === \"function\" ? new AbortController() : undefined;\n const timer = setTimeout(() => controller?.abort(), timeoutMs);\n try {\n const response = await fetch(\n `${apiHost.replace(/\\/+$/, \"\")}/api/consent/config?key=${encodeURIComponent(key)}`,\n { signal: controller?.signal, credentials: \"omit\" },\n );\n if (!response.ok) return null;\n const body = await response.json();\n if (!body || typeof body !== \"object\") return null;\n const config = body.config && typeof body.config === \"object\" ? body.config : null;\n const enabled = body.enabled !== false;\n return config || !enabled ? { enabled, config } : null;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n","import type { ConsentChoices, ConsentService, ConsentState } from \"./types\";\n\nexport const COOKIE_NAME = \"bitsnap_consent\";\nexport const COOKIE_MAX_AGE = 31536000;\n\n/** `bitsnap_consent`, or `bitsnap_consent_<projectKey>` when the cookie is scoped to a project. */\nexport function cookieName(projectKey?: string, scope?: \"global\" | \"project\"): string {\n if (scope === \"project\" && projectKey) {\n return `${COOKIE_NAME}_${projectKey.replace(/[^A-Za-z0-9_-]/g, \"_\")}`;\n }\n return COOKIE_NAME;\n}\n\nfunction toBase64Url(text: string): string {\n return btoa(text).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction fromBase64Url(text: string): string {\n const padded = text.replace(/-/g, \"+\").replace(/_/g, \"/\");\n return atob(padded + \"=\".repeat((4 - (padded.length % 4)) % 4));\n}\n\nexport function encodeState(state: ConsentState): string {\n return toBase64Url(\n JSON.stringify({ v: 1, id: state.id, ts: state.ts, bv: state.bv, c: state.c }),\n );\n}\n\nexport function decodeState(value: string): ConsentState | null {\n try {\n const raw = JSON.parse(fromBase64Url(value));\n if (\n !raw ||\n raw.v !== 1 ||\n typeof raw.id !== \"string\" ||\n raw.id === \"\" ||\n typeof raw.ts !== \"number\" ||\n typeof raw.bv !== \"number\" ||\n !raw.c ||\n typeof raw.c.analytics !== \"boolean\" ||\n typeof raw.c.marketing !== \"boolean\" ||\n typeof raw.c.preferences !== \"boolean\"\n ) {\n return null;\n }\n return {\n id: raw.id,\n ts: raw.ts,\n bv: raw.bv,\n c: {\n analytics: raw.c.analytics,\n marketing: raw.c.marketing,\n preferences: raw.c.preferences,\n },\n };\n } catch {\n return null;\n }\n}\n\n/** The `Set-Cookie`-style string for `document.cookie`. */\nexport function serializeCookie(name: string, state: ConsentState, secure: boolean): string {\n return (\n `${name}=${encodeState(state)}; Max-Age=${COOKIE_MAX_AGE}; Path=/; SameSite=Lax` +\n (secure ? \"; Secure\" : \"\")\n );\n}\n\nexport function cookieNames(header: string): string[] {\n return header\n .split(\";\")\n .map((part) => part.split(\"=\")[0].trim())\n .filter(Boolean);\n}\n\n/** Reads the consent from a `document.cookie` header. */\nexport function parseCookie(header: string, name: string): ConsentState | null {\n for (const part of header.split(\";\")) {\n const index = part.indexOf(\"=\");\n if (index === -1) continue;\n if (part.slice(0, index).trim() === name) {\n return decodeState(part.slice(index + 1).trim());\n }\n }\n return null;\n}\n\nexport function newConsentId(): string {\n try {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n } catch {\n // fall through to the random fallback\n }\n let id = \"\";\n for (let i = 0; i < 32; i++) id += Math.floor(Math.random() * 16).toString(16);\n return id;\n}\n\nexport function readConsent(doc: Document, name: string): ConsentState | null {\n try {\n return parseCookie(doc.cookie, name);\n } catch {\n return null;\n }\n}\n\nexport function writeConsent(doc: Document, name: string, state: ConsentState): void {\n try {\n doc.cookie = serializeCookie(name, state, doc.location?.protocol === \"https:\");\n } catch {\n // cookies blocked (sandboxed frame)\n }\n}\n\nexport function clearConsent(doc: Document, name: string): void {\n try {\n doc.cookie = `${name}=; Max-Age=0; Path=/; SameSite=Lax`;\n } catch {\n // ignore\n }\n}\n\n/** `a.b.example.com` -> the host and every parent with at least two labels. */\nexport function domainCandidates(hostname: string): string[] {\n if (!hostname || /^[\\d.]+$/.test(hostname) || hostname.includes(\":\")) return [];\n const labels = hostname.split(\".\");\n const result: string[] = [];\n for (let i = 0; i <= labels.length - 2; i++) result.push(labels.slice(i).join(\".\"));\n return result;\n}\n\n/**\n * Best-effort deletion of cookies the withdrawn categories declared, on the\n * current host and its parent domains. A trailing `*` matches a name prefix.\n */\nexport function deleteServiceCookies(\n doc: Document,\n services: ConsentService[],\n categories: (keyof ConsentChoices)[],\n): void {\n try {\n const wanted = services\n .filter((service) => categories.includes(service.category))\n .flatMap((service) => service.cookies ?? []);\n if (wanted.length === 0) return;\n const present = cookieNames(doc.cookie);\n const names = new Set<string>();\n for (const pattern of wanted) {\n if (pattern.endsWith(\"*\")) {\n const prefix = pattern.slice(0, -1);\n for (const name of present) if (name.startsWith(prefix)) names.add(name);\n } else {\n names.add(pattern);\n }\n }\n const domains = domainCandidates(doc.location?.hostname ?? \"\");\n for (const name of names) {\n const base = `${encodeURIComponent(name)}=; Max-Age=0; Path=/`;\n doc.cookie = base;\n for (const domain of domains) {\n doc.cookie = `${base}; Domain=${domain}`;\n doc.cookie = `${base}; Domain=.${domain}`;\n }\n }\n } catch {\n // best effort\n }\n}\n","import type { ConsentChoices } from \"./types\";\n\ntype Gtag = (...args: unknown[]) => void;\n\ntype GcmWindow = Window & {\n gtag?: Gtag;\n dataLayer?: unknown[];\n};\n\nexport const GCM_DEFAULT = {\n ad_storage: \"denied\",\n ad_user_data: \"denied\",\n ad_personalization: \"denied\",\n analytics_storage: \"denied\",\n functionality_storage: \"denied\",\n personalization_storage: \"denied\",\n security_storage: \"granted\",\n wait_for_update: 500,\n} as const;\n\nconst grant = (value: boolean) => (value ? \"granted\" : \"denied\");\n\n/** analytics -> analytics_storage; marketing -> ad_*; preferences -> functionality/personalization. */\nexport function toConsentModeUpdate(c: ConsentChoices) {\n return {\n analytics_storage: grant(c.analytics),\n ad_storage: grant(c.marketing),\n ad_user_data: grant(c.marketing),\n ad_personalization: grant(c.marketing),\n functionality_storage: grant(c.preferences),\n personalization_storage: grant(c.preferences),\n };\n}\n\nexport function shouldUseConsentMode(win: GcmWindow, mode: \"auto\" | \"on\" | \"off\" | undefined): boolean {\n if (mode === \"off\") return false;\n return mode === \"on\" || typeof win.gtag === \"function\" || Array.isArray(win.dataLayer);\n}\n\n/** A `gtag` that works without gtag.js: it queues `arguments` objects, as gtag.js expects. */\nexport function ensureGtag(win: GcmWindow): Gtag {\n if (typeof win.gtag === \"function\") return win.gtag;\n const layer = (win.dataLayer = win.dataLayer || []);\n const gtag: Gtag = function () {\n // eslint-disable-next-line prefer-rest-params\n layer.push(arguments);\n };\n win.gtag = gtag;\n return gtag;\n}\n\nexport type ConsentMode = {\n setDefault(): void;\n update(c: ConsentChoices): void;\n};\n\nexport function createConsentMode(win: GcmWindow, mode: \"auto\" | \"on\" | \"off\" | undefined): ConsentMode | null {\n if (!shouldUseConsentMode(win, mode)) return null;\n const gtag = ensureGtag(win);\n return {\n setDefault: () => gtag(\"consent\", \"default\", { ...GCM_DEFAULT }),\n update: (c) => gtag(\"consent\", \"update\", toConsentModeUpdate(c)),\n };\n}\n","import type { ConsentLocale, ConsentTexts } from \"./types\";\n\nexport const DEFAULT_TEXTS: Record<ConsentLocale, ConsentTexts> = {\n pl: {\n title: \"Szanujemy Twoją prywatność\",\n description:\n \"Używamy plików cookie, aby strona działała poprawnie. Za Twoją zgodą wykorzystujemy je też do statystyk, personalizacji i reklam. Możesz zaakceptować wszystkie, odrzucić wszystkie albo wybrać, na co się zgadzasz.\",\n acceptAll: \"Akceptuj wszystkie\",\n rejectAll: \"Odrzuć wszystkie\",\n settings: \"Ustawienia\",\n save: \"Zapisz wybór\",\n close: \"Zamknij\",\n necessaryTitle: \"Niezbędne\",\n necessaryDescription:\n \"Potrzebne do działania strony: koszyk, zapamiętanie Twojego wyboru, bezpieczeństwo. Nie można ich wyłączyć.\",\n analyticsTitle: \"Statystyki\",\n analyticsDescription:\n \"Pomagają nam zrozumieć, jak odwiedzający korzystają ze strony, żebyśmy mogli ją ulepszać.\",\n marketingTitle: \"Marketing\",\n marketingDescription:\n \"Pozwalają mierzyć skuteczność reklam i pokazywać Ci oferty dopasowane do zainteresowań.\",\n preferencesTitle: \"Preferencje\",\n preferencesDescription:\n \"Zapamiętują Twoje ustawienia, na przykład język czy wygląd strony.\",\n poweredBy: \"Powered by\",\n },\n en: {\n title: \"We value your privacy\",\n description:\n \"We use cookies to make this site work. With your consent we also use them for statistics, personalization and ads. You can accept all, reject all, or choose what you agree to.\",\n acceptAll: \"Accept all\",\n rejectAll: \"Reject all\",\n settings: \"Settings\",\n save: \"Save choices\",\n close: \"Close\",\n necessaryTitle: \"Necessary\",\n necessaryDescription:\n \"Needed for the site to work: the cart, remembering your choice, security. They cannot be turned off.\",\n analyticsTitle: \"Analytics\",\n analyticsDescription:\n \"Help us understand how visitors use the site, so we can improve it.\",\n marketingTitle: \"Marketing\",\n marketingDescription:\n \"Measure how well ads work and show you offers that match your interests.\",\n preferencesTitle: \"Preferences\",\n preferencesDescription:\n \"Remember your settings, such as language or how the site looks.\",\n poweredBy: \"Powered by\",\n },\n};\n\n/** Fixed interface labels that are not part of the configurable texts. */\nexport const UI_LABELS: Record<\n ConsentLocale,\n { privacy: string; services: string; always: string }\n> = {\n pl: {\n privacy: \"Polityka prywatności\",\n services: \"Usługi\",\n always: \"Zawsze aktywne\",\n },\n en: { privacy: \"Privacy policy\", services: \"Services\", always: \"Always on\" },\n};\n\nexport function resolveLocale(\n preference: \"auto\" | ConsentLocale | undefined,\n navigatorLanguage?: string,\n): ConsentLocale {\n if (preference === \"pl\" || preference === \"en\") return preference;\n return /^pl\\b/i.test(navigatorLanguage ?? \"\") ? \"pl\" : \"en\";\n}\n\n/** Built-in texts for the locale, with the (non-empty) overrides of the config on top. */\nexport function mergeTexts(\n locale: ConsentLocale,\n overrides?: Partial<Record<ConsentLocale, Partial<ConsentTexts>>>,\n): ConsentTexts {\n const merged = { ...DEFAULT_TEXTS[locale] };\n const own = overrides?.[locale];\n if (own) {\n for (const key of Object.keys(merged) as (keyof ConsentTexts)[]) {\n const value = own[key];\n if (typeof value === \"string\" && value.trim() !== \"\") merged[key] = value;\n }\n }\n return merged;\n}\n","function parse(hex: string): [number, number, number] {\n let h = hex.replace(\"#\", \"\");\n if (h.length === 3) h = h.replace(/./g, \"$&$&\");\n const n = parseInt(h, 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nfunction luminance(hex: string): number {\n const [r, g, b] = parse(hex).map((v) => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG contrast ratio of two `#rgb` / `#rrggbb` colors. */\nexport function contrastRatio(a: string, b: string): number {\n const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/** Black or white text, whichever reads better on `background`. */\nexport function onColor(background: string): string {\n return contrastRatio(background, \"#ffffff\") >= contrastRatio(background, \"#111111\")\n ? \"#ffffff\"\n : \"#111111\";\n}\n","/** Colors of both themes. Every text/background pair is checked against WCAG AA in the tests. */\nexport const PALETTE = {\n light: {\n bg: \"#ffffff\",\n fg: \"#14171c\",\n muted: \"#495260\",\n border: \"#c9ced6\",\n off: \"#6b7280\",\n thumb: \"#ffffff\",\n accent: \"#1d4ed8\",\n onAccent: \"#ffffff\",\n link: \"#1d4ed8\",\n },\n dark: {\n bg: \"#171a20\",\n fg: \"#f1f3f6\",\n muted: \"#b7beca\",\n border: \"#3a404b\",\n off: \"#8b93a1\",\n thumb: \"#171a20\",\n accent: \"#8ab4ff\",\n onAccent: \"#0b1220\",\n link: \"#9dc0ff\",\n },\n} as const;\n\nconst vars = (p: (typeof PALETTE)[\"light\"]) =>\n `--bg:${p.bg};--fg:${p.fg};--muted:${p.muted};--border:${p.border};--off:${p.off};--thumb:${p.thumb};--accent:${p.accent};--on-accent:${p.onAccent};--link:${p.link};--focus:${p.accent}`;\n\nexport const STYLES = `\n:host{all:initial}\n*{box-sizing:border-box}\n[hidden]{display:none!important}\n.root{${vars(PALETTE.light)};position:fixed;inset:0;pointer-events:none;z-index:2147483000;font:14px/1.5 system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;color:var(--fg);-webkit-text-size-adjust:100%}\n.root[data-theme=dark]{${vars(PALETTE.dark)};color-scheme:dark}\nbutton,input{font:inherit;color:inherit}\n.banner,.overlay{pointer-events:auto}\n.banner{position:absolute;background:var(--bg);color:var(--fg);box-shadow:0 8px 32px rgba(0,0,0,.22);max-height:92vh;overflow:auto;outline:none;animation:in .22s ease-out}\n.bottom{left:0;right:0;bottom:0;border-top:1px solid var(--border);padding:16px 24px calc(16px + env(safe-area-inset-bottom,0px))}\n.bottom .inner{display:grid;grid-template-columns:1fr auto;grid-template-areas:\"text actions\" \"foot actions\";gap:4px 32px;align-items:center;max-width:1200px;margin:0 auto}\n.card{bottom:16px;width:min(400px,calc(100vw - 32px));border:1px solid var(--border);border-radius:14px;padding:20px}\n.bottom-left{left:16px}\n.bottom-right{right:16px}\n.card .inner{display:flex;flex-direction:column;gap:16px}\n.text{grid-area:text}\n.actions{grid-area:actions;display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}\n.card .actions{justify-content:stretch}\n.foot{grid-area:foot}\n.title{font-size:16px;font-weight:650;line-height:1.35;margin:0 0 4px}\n.desc{margin:0;color:var(--muted)}\n.desc a,.link-btn{color:var(--link)}\n.btn{min-height:44px;padding:0 20px;border:2px solid var(--accent);border-radius:10px;background:var(--accent);color:var(--on-accent);font-weight:600;cursor:pointer;flex:1 1 150px;white-space:nowrap}\n.btn:hover{filter:brightness(.94)}\n.link-btn{min-height:44px;padding:0 12px;border:0;background:none;font-weight:500;text-decoration:underline;text-underline-offset:3px;cursor:pointer}\n.card .link-btn{flex:1 1 100%}\nbutton:focus-visible,a:focus-visible,.dialog:focus-visible{outline:2px solid var(--focus);outline-offset:2px}\n.foot{font-size:12px;color:var(--muted);padding-top:4px}\n.foot a{color:var(--muted);text-decoration:none;display:inline-flex;align-items:center;gap:5px;vertical-align:middle}\n.foot a:hover{text-decoration:underline}\n.foot b{color:var(--fg);font-weight:700;letter-spacing:-.01em}\n.foot svg{display:block}\n.overlay{position:absolute;inset:0;background:rgba(10,12,16,.58);display:flex;align-items:center;justify-content:center;padding:16px;animation:fade .2s ease-out}\n.dialog{background:var(--bg);color:var(--fg);width:100%;max-width:560px;max-height:min(92vh,760px);display:flex;flex-direction:column;border-radius:16px;box-shadow:0 16px 48px rgba(0,0,0,.35);outline:none;animation:in .22s ease-out}\n.d-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 8px 8px 24px}\n.d-head .title{margin:0;font-size:18px}\n.x{width:44px;height:44px;border:0;border-radius:10px;background:none;cursor:pointer;display:flex;align-items:center;justify-content:center;flex:none}\n.x:hover{background:var(--border)}\n.d-body{overflow:auto;padding:0 24px 8px;flex:1}\n.cat{border-top:1px solid var(--border);padding:10px 0 14px}\n.row{display:flex;align-items:center;justify-content:space-between;gap:12px}\n.cat-title{font-weight:600;font-size:15px}\n.always{font-size:12px;color:var(--muted);margin-right:4px}\n.cat p{margin:0;color:var(--muted)}\n.cat .svc{margin-top:6px;font-size:13px}\n.cat .svc b{font-weight:600;color:var(--fg)}\n.switch{position:relative;width:52px;height:44px;display:flex;align-items:center;justify-content:flex-end;flex:none}\n.switch input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}\n.switch input:disabled{cursor:default}\n.track{width:44px;height:24px;border-radius:12px;background:var(--off);position:relative;transition:background .15s}\n.track::after{content:\"\";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:var(--thumb);transition:transform .15s}\ninput:checked+.track{background:var(--accent)}\ninput:checked+.track::after{transform:translateX(20px);background:var(--on-accent)}\ninput:disabled+.track{opacity:.6}\ninput:focus-visible+.track{outline:2px solid var(--focus);outline-offset:2px}\n.d-foot{display:flex;flex-direction:column;gap:8px;padding:12px 24px 16px;border-top:1px solid var(--border)}\n.d-foot .actions{justify-content:stretch}\n@keyframes in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}\n@keyframes fade{from{opacity:0}to{opacity:1}}\n@media(max-width:640px){\n.bottom{padding:16px 16px calc(16px + env(safe-area-inset-bottom,0px))}\n.bottom .inner{grid-template-columns:1fr;grid-template-areas:\"text\" \"actions\" \"foot\";gap:12px}\n.bottom .actions{justify-content:stretch}\n.bottom .link-btn{flex:1 1 100%}\n.card{left:8px;right:8px;bottom:8px;width:auto}\n.overlay{align-items:flex-end;padding:0}\n.dialog{max-width:none;border-radius:16px 16px 0 0;max-height:92vh}\n.d-head{padding-left:16px}\n.d-body{padding:0 16px 8px}\n.d-foot{padding:12px 16px calc(16px + env(safe-area-inset-bottom,0px))}\n.btn{flex-basis:130px;padding:0 12px}\n}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}\n`.replace(/\\n/g, \"\");\n","import { contrastRatio, onColor } from \"./contrast\";\nimport { UI_LABELS } from \"./texts\";\nimport { PALETTE, STYLES } from \"./styles\";\nimport {\n CONSENT_CATEGORIES,\n type ConsentCategory,\n type ConsentChoices,\n type ConsentConfig,\n type ConsentLocale,\n type ConsentTexts,\n} from \"./types\";\n\nexport type UIOptions = {\n doc: Document;\n config: ConsentConfig;\n texts: ConsentTexts;\n locale: ConsentLocale;\n /** Current choice, used to preset the toggles. */\n getChoices(): ConsentChoices | null;\n /** Whether a valid choice exists, i.e. closing the settings must not bring back the banner. */\n hasChoice(): boolean;\n onAcceptAll(): void;\n onRejectAll(): void;\n onSave(choices: ConsentChoices): void;\n};\n\nexport type ConsentUI = {\n /** `focus` moves keyboard focus into the banner; leave it off when the banner opens on page load. */\n showBanner(focus?: boolean): void;\n showSettings(): void;\n hide(): void;\n destroy(): void;\n};\n\nconst WORDMARK =\n '<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><rect width=\"16\" height=\"16\" rx=\"4\" fill=\"currentColor\" style=\"color:var(--fg)\"/><circle cx=\"8\" cy=\"8\" r=\"3\" fill=\"var(--bg)\"/></svg>';\n\nconst CLOSE_ICON =\n '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M3 3l10 10M13 3L3 13\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" fill=\"none\"/></svg>';\n\nconst FOCUSABLE = \"button:not([disabled]),input:not([disabled]),a[href]\";\n\nexport function createUI(options: UIOptions): ConsentUI {\n const { doc, config, texts, locale } = options;\n const labels = UI_LABELS[locale];\n let host: HTMLElement | null = null;\n let shadow: ShadowRoot | null = null;\n let root: HTMLElement;\n let banner: HTMLElement;\n let overlay: HTMLElement;\n let dialog: HTMLElement;\n let settingsButton: HTMLElement;\n let layer: \"none\" | \"banner\" | \"settings\" = \"none\";\n let opener: HTMLElement | null = null;\n let media: MediaQueryList | null = null;\n const toggles = new Map<ConsentCategory, HTMLInputElement>();\n\n function el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n props: Record<string, string> = {},\n ...children: (Node | string)[]\n ): HTMLElementTagNameMap[K] {\n const node = doc.createElement(tag);\n for (const key of Object.keys(props)) {\n if (key === \"class\") node.className = props[key];\n else node.setAttribute(key, props[key]);\n }\n for (const child of children) node.append(child);\n return node;\n }\n\n function button(cls: string, text: string, onClick: () => void) {\n const node = el(\"button\", { type: \"button\", class: cls }, text);\n node.addEventListener(\"click\", onClick);\n return node;\n }\n\n function powered(): HTMLElement {\n const link = el(\"a\", {\n href: `https://bitsnap.pl/?utm_source=consent_banner&utm_medium=referral&utm_content=${encodeURIComponent(doc.location?.hostname ?? \"\")}`,\n target: \"_blank\",\n rel: \"noopener\",\n });\n link.append(texts.poweredBy + \" \");\n link.insertAdjacentHTML(\"beforeend\", WORDMARK);\n link.append(el(\"b\", {}, \"bitsnap\"));\n return el(\"div\", { class: \"foot\" }, link);\n }\n\n function description(): HTMLElement {\n const node = el(\"p\", { class: \"desc\", id: \"d\" }, texts.description);\n if (config.privacyPolicyUrl) {\n node.append(\n \" \",\n el(\n \"a\",\n { href: config.privacyPolicyUrl, target: \"_blank\", rel: \"noopener\" },\n labels.privacy,\n ),\n );\n }\n return node;\n }\n\n function buildBanner() {\n settingsButton = button(\"link-btn\", texts.settings, () => showSettings());\n banner = el(\n \"div\",\n {\n class: `banner ${config.position === \"bottom\" ? \"bottom\" : `card ${config.position}`}`,\n // Not modal: the page stays usable, so it is a live region, not a dialog.\n role: \"region\",\n \"aria-live\": \"polite\",\n \"aria-labelledby\": \"t\",\n \"aria-describedby\": \"d\",\n tabindex: \"-1\",\n },\n el(\n \"div\",\n { class: \"inner\" },\n el(\"div\", { class: \"text\" }, el(\"div\", { class: \"title\", id: \"t\" }, texts.title), description()),\n el(\n \"div\",\n { class: \"actions\" },\n button(\"btn\", texts.acceptAll, options.onAcceptAll),\n button(\"btn\", texts.rejectAll, options.onRejectAll),\n settingsButton,\n ),\n powered(),\n ),\n );\n }\n\n function category(id: ConsentCategory | \"necessary\"): HTMLElement {\n const services = config.services.filter((service) => service.category === id);\n const input = el(\"input\", { type: \"checkbox\", role: \"switch\", \"aria-labelledby\": `l-${id}`, \"aria-describedby\": `p-${id}` });\n if (id === \"necessary\") {\n input.checked = true;\n input.disabled = true;\n } else {\n toggles.set(id, input);\n }\n const node = el(\n \"div\",\n { class: \"cat\" },\n el(\n \"div\",\n { class: \"row\" },\n el(\"span\", { class: \"cat-title\", id: `l-${id}` }, texts[`${id}Title` as keyof ConsentTexts]),\n el(\n \"span\",\n { style: \"display:flex;align-items:center\" },\n ...(id === \"necessary\" ? [el(\"span\", { class: \"always\" }, labels.always)] : []),\n el(\"label\", { class: \"switch\" }, input, el(\"span\", { class: \"track\" })),\n ),\n ),\n el(\"p\", { id: `p-${id}` }, texts[`${id}Description` as keyof ConsentTexts]),\n );\n if (services.length > 0) {\n node.append(\n el(\"p\", { class: \"svc\" }, el(\"b\", {}, `${labels.services}: `), services.map((s) => s.name).join(\", \")),\n );\n }\n return node;\n }\n\n function buildSettings() {\n const close = el(\"button\", { type: \"button\", class: \"x\", \"aria-label\": texts.close });\n close.insertAdjacentHTML(\"beforeend\", CLOSE_ICON);\n close.addEventListener(\"click\", () => closeSettings());\n const body = el(\"div\", { class: \"d-body\" }, category(\"necessary\"));\n for (const id of CONSENT_CATEGORIES) {\n if (config.categories[id]) body.append(category(id));\n }\n dialog = el(\n \"div\",\n { class: \"dialog\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": \"st\", tabindex: \"-1\" },\n el(\"div\", { class: \"d-head\" }, el(\"div\", { class: \"title\", id: \"st\" }, texts.settings), close),\n body,\n el(\n \"div\",\n { class: \"d-foot\" },\n el(\n \"div\",\n { class: \"actions\" },\n button(\"btn\", texts.save, () => options.onSave(readToggles())),\n button(\"btn\", texts.acceptAll, options.onAcceptAll),\n button(\"btn\", texts.rejectAll, options.onRejectAll),\n ),\n powered(),\n ),\n );\n overlay = el(\"div\", { class: \"overlay\" }, dialog);\n overlay.addEventListener(\"mousedown\", (event) => {\n if (event.target === overlay) closeSettings();\n });\n }\n\n function readToggles(): ConsentChoices {\n const choices = { analytics: false, marketing: false, preferences: false };\n toggles.forEach((input, key) => (choices[key] = input.checked));\n return choices;\n }\n\n function applyTheme() {\n const dark = config.theme === \"dark\" || (config.theme === \"auto\" && !!media?.matches);\n root.setAttribute(\"data-theme\", dark ? \"dark\" : \"light\");\n applyAccent(dark);\n }\n\n /** A custom accent that is too faint on the dark background gives way to the dark theme's own. */\n function applyAccent(dark: boolean) {\n const accent = config.accentColor;\n if (!accent) return;\n if (dark && contrastRatio(accent, PALETTE.dark.bg) < 3) {\n for (const name of [\"--accent\", \"--focus\", \"--on-accent\"]) root.style.removeProperty(name);\n return;\n }\n root.style.setProperty(\"--accent\", accent);\n root.style.setProperty(\"--focus\", accent);\n root.style.setProperty(\"--on-accent\", onColor(accent));\n }\n\n function ensure() {\n if (host) return;\n host = el(\"div\", { id: \"bitsnap-consent\", \"data-bitsnap-consent-host\": \"\" });\n shadow = host.attachShadow({ mode: \"open\" });\n shadow.append(el(\"style\", {}, STYLES));\n root = el(\"div\", { class: \"root\", lang: locale });\n buildBanner();\n buildSettings();\n banner.hidden = true;\n overlay.hidden = true;\n root.append(banner, overlay);\n shadow.append(root);\n if (typeof doc.defaultView?.matchMedia === \"function\") {\n media = doc.defaultView.matchMedia(\"(prefers-color-scheme: dark)\");\n media.addEventListener?.(\"change\", applyTheme);\n }\n applyTheme();\n doc.body.append(host);\n }\n\n function focusables(): HTMLElement[] {\n return Array.from(dialog.querySelectorAll<HTMLElement>(FOCUSABLE));\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (layer !== \"settings\") return;\n if (event.key === \"Escape\") {\n event.preventDefault();\n closeSettings();\n return;\n }\n if (event.key !== \"Tab\") return;\n const items = focusables();\n if (items.length === 0) return;\n const active = shadow?.activeElement as HTMLElement | null;\n const first = items[0];\n const last = items[items.length - 1];\n const outside = !active || !dialog.contains(active);\n if (event.shiftKey && (outside || active === first || active === dialog)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (outside || active === last)) {\n event.preventDefault();\n first.focus();\n }\n }\n\n function showBanner(focus = false) {\n try {\n ensure();\n layer = \"banner\";\n doc.removeEventListener(\"keydown\", onKeydown, true);\n overlay.hidden = true;\n banner.hidden = false;\n if (focus) banner.focus({ preventScroll: true });\n } catch {\n // never throw into the host page\n }\n }\n\n function showSettings() {\n try {\n ensure();\n if (layer !== \"settings\") {\n const active = doc.activeElement as HTMLElement | null;\n opener = active && active !== host && active !== doc.body ? active : null;\n }\n const current = options.getChoices();\n toggles.forEach((input, key) => (input.checked = !!current?.[key]));\n layer = \"settings\";\n banner.hidden = true;\n overlay.hidden = false;\n doc.addEventListener(\"keydown\", onKeydown, true);\n dialog.focus({ preventScroll: true });\n } catch {\n // never throw into the host page\n }\n }\n\n function closeSettings() {\n if (layer !== \"settings\") return;\n doc.removeEventListener(\"keydown\", onKeydown, true);\n overlay.hidden = true;\n if (options.hasChoice()) {\n layer = \"none\";\n opener?.focus?.({ preventScroll: true });\n } else {\n layer = \"banner\";\n banner.hidden = false;\n settingsButton.focus({ preventScroll: true });\n }\n }\n\n function hide() {\n if (!host) return;\n doc.removeEventListener(\"keydown\", onKeydown, true);\n const wasSettings = layer === \"settings\";\n layer = \"none\";\n banner.hidden = true;\n overlay.hidden = true;\n if (wasSettings) opener?.focus?.({ preventScroll: true });\n }\n\n function destroy() {\n doc.removeEventListener(\"keydown\", onKeydown, true);\n media?.removeEventListener?.(\"change\", applyTheme);\n host?.remove();\n host = null;\n shadow = null;\n layer = \"none\";\n }\n\n return { showBanner, showSettings, hide, destroy };\n}\n","import { normalizeProjectKey } from \"../../analytics/contract\";\nimport { activateScripts } from \"./activate\";\nimport {\n DEFAULT_API_HOST,\n DEFAULT_COLLECT_HOST,\n fetchRemoteConfig,\n mergeConfig,\n} from \"./config\";\nimport {\n clearConsent,\n cookieName,\n deleteServiceCookies,\n newConsentId,\n readConsent,\n writeConsent,\n} from \"./cookie\";\nimport { createConsentMode } from \"./gcm\";\nimport { mergeTexts, resolveLocale } from \"./texts\";\nimport { createUI, type ConsentUI } from \"./ui\";\nimport {\n CONSENT_CATEGORIES,\n type BitsnapConsentApi,\n type ConsentAction,\n type ConsentCategory,\n type ConsentChangeDetail,\n type ConsentChoices,\n type ConsentConfig,\n type ConsentOptions,\n type ConsentState,\n type ConsentTexts,\n} from \"./types\";\n\nconst none = (): ConsentChoices => ({ analytics: false, marketing: false, preferences: false });\n\nconst copy = (state: ConsentState | null): ConsentState | null =>\n state && { id: state.id, ts: state.ts, bv: state.bv, c: { ...state.c } };\n\n/** Sync `get()`-style API with no DOM until a layer is shown. Never throws into the page. */\nexport function createConsent(options: ConsentOptions = {}): BitsnapConsentApi {\n const win = typeof window !== \"undefined\" ? window : undefined;\n const doc = win?.document;\n const listeners = new Set<(detail: ConsentChangeDetail) => void>();\n const apiHost = options.apiHost || DEFAULT_API_HOST;\n const collectHost = options.collectHost || DEFAULT_COLLECT_HOST;\n // The contract uses the bare key (no `pk_`) for the cookie name, the config URL and the log.\n const projectKey = options.projectKey ? normalizeProjectKey(options.projectKey) : null;\n const name = cookieName(projectKey ?? undefined, options.scope);\n const preview = !!options.preview;\n\n let config: ConsentConfig = mergeConfig(localLayer());\n let state: ConsentState | null = null;\n /** A stored choice made on an older banner version: it asks again, but its id is reused. */\n let stale: ConsentState | null = null;\n let ui: ConsentUI | null = null;\n let loaded = false;\n let destroyed = false;\n let removeOpenListener: (() => void) | undefined;\n /** Choices made before `ready`: they run inside it, before anyone waiting on `ready` is released. */\n const pending: Array<() => void> = [];\n\n // Consent Mode default has to be set before anything else, config or not.\n // A preview touches nothing outside its own banner: no dataLayer, no cookie.\n const mode = win && !preview ? safe(() => createConsentMode(win, options.gcm), null) : null;\n safe(() => mode?.setDefault(), undefined);\n // The stored choice is read now but only applied once the config is known: it has to match\n // the banner version and the categories on offer. Until then Consent Mode stays denied.\n const initial = doc && !preview ? readConsent(doc, name) : null;\n\n function localLayer(extra?: Partial<ConsentConfig>): Partial<ConsentConfig> {\n const own: Partial<ConsentConfig> = { ...options.config };\n if (options.theme) own.theme = options.theme;\n if (options.position) own.position = options.position;\n if (options.privacyPolicyUrl) own.privacyPolicyUrl = options.privacyPolicyUrl;\n return { ...extra, ...own };\n }\n\n function safe<T>(fn: () => T, fallback: T): T {\n try {\n return fn();\n } catch {\n return fallback;\n }\n }\n\n function enabled(choices: Partial<ConsentChoices> | undefined): ConsentChoices {\n const result = none();\n for (const category of CONSENT_CATEGORIES) {\n result[category] = !!choices?.[category] && config.categories[category];\n }\n return result;\n }\n\n function emit(detail: ConsentChangeDetail) {\n listeners.forEach((fn) => safe(() => fn({ ...detail, c: { ...detail.c } }), undefined));\n safe(() => {\n win?.dispatchEvent(new win.CustomEvent(\"bitsnap:consent\", { detail: { ...detail, c: { ...detail.c } } }));\n }, undefined);\n }\n\n function log(action: ConsentAction, record: ConsentState) {\n if (preview || !projectKey || typeof fetch !== \"function\") return;\n safe(() => {\n const body = JSON.stringify({\n k: projectKey,\n consent_id: record.id,\n action,\n c: record.c,\n bv: record.bv,\n host: win?.location?.hostname ?? \"\",\n ts: record.ts,\n });\n fetch(`${collectHost.replace(/\\/+$/, \"\")}/consent`, {\n method: \"POST\",\n keepalive: true,\n credentials: \"omit\",\n body,\n }).catch(() => {});\n }, undefined);\n }\n\n /** Granted categories the current config still offers. */\n function granted(c: ConsentChoices): ConsentCategory[] {\n return CONSENT_CATEGORIES.filter((category) => c[category] && config.categories[category]);\n }\n\n function commit(choices: ConsentChoices, requested: ConsentAction) {\n if (!doc || destroyed) return;\n if (preview) {\n ui?.hide();\n return;\n }\n const previous = state ?? stale;\n const dropped = previous ? granted(previous.c).filter((category) => !choices[category]) : [];\n const action: ConsentAction = dropped.length > 0 ? \"withdraw\" : requested;\n const next: ConsentState = {\n id: previous?.id ?? newConsentId(),\n ts: Math.floor(Date.now() / 1000),\n bv: config.version,\n c: choices,\n };\n writeConsent(doc, name, next);\n state = next;\n stale = null;\n applyChoices(next.c);\n if (dropped.length > 0) deleteServiceCookies(doc, config.services, dropped);\n ui?.hide();\n emit({ ...next, action });\n log(action, next);\n if (dropped.length > 0 && options.reloadOnWithdraw) reload();\n }\n\n function applyChoices(c: ConsentChoices) {\n safe(() => mode?.update(c), undefined);\n if (doc) activateScripts(doc, c);\n }\n\n function reload() {\n setTimeout(() => safe(() => win?.location.reload(), undefined), 50);\n }\n\n function ensureUI(): ConsentUI | null {\n if (!doc || !loaded || destroyed) return null;\n if (!ui) {\n const locale = resolveLocale(options.locale, win?.navigator?.language);\n ui = createUI({\n doc,\n config,\n locale,\n texts: localTexts(mergeTexts(locale, config.texts)),\n getChoices: () => state?.c ?? null,\n hasChoice: () => state !== null,\n onAcceptAll: () => commit(enabled({ analytics: true, marketing: true, preferences: true }), \"accept_all\"),\n onRejectAll: () => commit(none(), \"reject_all\"),\n onSave: (choices) => commit(enabled(choices), \"custom\"),\n });\n }\n return ui;\n }\n\n /** `data-title` / `data-description` win over the remote and default texts. */\n function localTexts(texts: ConsentTexts): ConsentTexts {\n const title = options.title?.trim();\n const description = options.description?.trim();\n return { ...texts, ...(title && { title }), ...(description && { description }) };\n }\n\n function onClick(event: Event) {\n const target = event.target as Element | null;\n if (target?.closest?.(\"[data-bitsnap-consent-open]\")) {\n event.preventDefault();\n api.open();\n }\n }\n\n const ready: Promise<ConsentState | null> = (async () => {\n if (!doc || !win) return null;\n const remote = projectKey && !preview ? await fetchRemoteConfig(apiHost, projectKey) : null;\n if (destroyed) return null;\n const categories = remote?.config ? undefined : options.categories;\n config = mergeConfig(\n remote?.config,\n categories ? { categories: { ...none(), ...categories } } : undefined,\n localLayer(),\n );\n if (doc.readyState === \"loading\") {\n await new Promise<void>((resolve) => doc.addEventListener(\"DOMContentLoaded\", () => resolve(), { once: true }));\n }\n if (destroyed) return null;\n loaded = true;\n doc.addEventListener(\"click\", onClick);\n removeOpenListener = () => doc.removeEventListener(\"click\", onClick);\n\n // A project whose config could not be loaded has an unknown banner version: keep the\n // stored choice instead of asking again on every network failure.\n const versionKnown = !projectKey || remote?.config != null;\n const bannerOff = remote?.enabled === false;\n if (preview) {\n ensureUI()?.showBanner();\n } else if (initial && (bannerOff || !versionKnown || initial.bv === config.version)) {\n state = initial;\n applyChoices(enabled(state.c));\n } else {\n if (initial) stale = initial;\n // A disabled banner is never shown, but the API (open, accept, ...) keeps working.\n if (!bannerOff) ensureUI()?.showBanner();\n }\n // A tracker that waits on `ready` has to see the final state, rejection included.\n pending.splice(0).forEach((fn) => safe(fn, undefined));\n safe(() => win.dispatchEvent(new win.CustomEvent(\"bitsnap:consent:ready\")), undefined);\n return copy(state);\n })().catch(() => null);\n\n function afterReady(fn: () => void) {\n if (loaded) fn();\n else pending.push(fn);\n }\n\n const api: BitsnapConsentApi = {\n get: () => copy(state),\n // A choice made on an older banner version has no `get()`, but a refusal in it still holds.\n denied: (category) => (state ?? stale)?.c[category] === false,\n on(event, fn) {\n if (event !== \"change\" || typeof fn !== \"function\") return () => {};\n listeners.add(fn);\n return () => void listeners.delete(fn);\n },\n open() {\n if (loaded) ensureUI()?.showSettings();\n else void ready.then(() => ensureUI()?.showSettings());\n },\n close() {\n ui?.hide();\n },\n // Called before `ready`, a choice waits for the merged config so it is stored with the right\n // banner version and only for categories on offer.\n accept: (categories) => afterReady(() => commit(enabled(categories), \"custom\")),\n acceptAll: () =>\n afterReady(() => commit(enabled({ analytics: true, marketing: true, preferences: true }), \"accept_all\")),\n rejectAll: () => afterReady(() => commit(none(), \"reject_all\")),\n reset() {\n if (!doc || destroyed) return;\n if (preview) {\n ensureUI()?.showBanner();\n return;\n }\n const previous = state ?? stale;\n const was = previous ? granted(previous.c) : [];\n clearConsent(doc, name);\n state = null;\n stale = previous;\n safe(() => mode?.update(none()), undefined);\n if (was.length > 0) deleteServiceCookies(doc, config.services, was);\n emit({\n id: previous?.id ?? \"\",\n ts: Math.floor(Date.now() / 1000),\n bv: config.version,\n c: none(),\n action: \"reset\",\n });\n if (previous && was.length > 0) {\n log(\"withdraw\", { id: previous.id, ts: Math.floor(Date.now() / 1000), bv: config.version, c: none() });\n }\n ensureUI()?.showBanner(true);\n if (was.length > 0 && options.reloadOnWithdraw) reload();\n },\n ready,\n destroy() {\n destroyed = true;\n removeOpenListener?.();\n ui?.destroy();\n ui = null;\n listeners.clear();\n },\n };\n\n return wrapSafe(api);\n}\n\n/** Every method of the public API swallows its own errors. */\nfunction wrapSafe(api: BitsnapConsentApi): BitsnapConsentApi {\n const wrapped = { ...api } as Record<string, unknown>;\n for (const key of Object.keys(api) as (keyof BitsnapConsentApi)[]) {\n const original = api[key];\n if (typeof original === \"function\") {\n wrapped[key] = (...args: unknown[]) => {\n try {\n return (original as (...a: unknown[]) => unknown)(...args);\n } catch {\n return key === \"get\" ? null : key === \"on\" ? () => {} : undefined;\n }\n };\n }\n }\n return wrapped as BitsnapConsentApi;\n}\n"],"mappings":"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","names":["useCallback","useRef","useSyncExternalStore","CONSENT_CATEGORIES","SCRIPT_SELECTOR","FRAME_SELECTOR","allowed","c","category","CONSENT_CATEGORIES","settled","script","resolve","run","doc","placeholder","name","value","external","loaded","activateScripts","activated","gate","loading","inline","frame","src","DEFAULT_API_HOST","DEFAULT_COLLECT_HOST","defaultConfig","THEMES","POSITIONS","HEX_COLOR","safeColor","value","safeUrl","url","cleanServices","services","item","CONSENT_CATEGORIES","cookie","mergeConfig","layers","result","layer","accent","privacy","category","fetchRemoteConfig","apiHost","key","timeoutMs","controller","timer","response","body","config","enabled","COOKIE_NAME","cookieName","projectKey","scope","COOKIE_NAME","toBase64Url","text","fromBase64Url","padded","encodeState","state","decodeState","value","raw","serializeCookie","name","secure","cookieNames","header","part","parseCookie","index","newConsentId","id","i","readConsent","doc","writeConsent","clearConsent","domainCandidates","hostname","labels","result","deleteServiceCookies","services","categories","wanted","service","present","names","pattern","prefix","domains","base","domain","GCM_DEFAULT","grant","value","toConsentModeUpdate","c","shouldUseConsentMode","win","mode","ensureGtag","layer","gtag","createConsentMode","DEFAULT_TEXTS","UI_LABELS","resolveLocale","preference","navigatorLanguage","mergeTexts","locale","overrides","merged","own","key","value","parse","hex","h","luminance","r","g","b","v","contrastRatio","a","hi","lo","x","y","onColor","background","PALETTE","vars","p","STYLES","WORDMARK","CLOSE_ICON","FOCUSABLE","createUI","options","doc","config","texts","locale","labels","UI_LABELS","host","shadow","root","banner","overlay","dialog","settingsButton","layer","opener","media","toggles","el","tag","props","children","node","key","child","button","cls","text","onClick","powered","link","description","buildBanner","showSettings","category","id","services","service","input","s","buildSettings","close","closeSettings","body","CONSENT_CATEGORIES","readToggles","event","choices","applyTheme","dark","applyAccent","accent","contrastRatio","PALETTE","name","onColor","ensure","STYLES","focusables","onKeydown","items","active","first","last","outside","showBanner","focus","current","hide","wasSettings","destroy","none","copy","state","createConsent","options","win","doc","listeners","apiHost","DEFAULT_API_HOST","collectHost","DEFAULT_COLLECT_HOST","projectKey","normalizeProjectKey","name","cookieName","preview","config","mergeConfig","localLayer","stale","ui","loaded","destroyed","removeOpenListener","pending","mode","safe","createConsentMode","initial","readConsent","extra","own","fn","fallback","enabled","choices","result","category","CONSENT_CATEGORIES","emit","detail","log","action","record","body","granted","c","commit","requested","previous","dropped","next","newConsentId","writeConsent","applyChoices","deleteServiceCookies","reload","activateScripts","ensureUI","locale","resolveLocale","createUI","localTexts","mergeTexts","texts","title","description","onClick","event","api","ready","remote","fetchRemoteConfig","categories","resolve","versionKnown","bannerOff","afterReady","was","clearConsent","wrapSafe","wrapped","key","original","args","BitsnapConsent","props","projectKey","theme","locale","position","privacyPolicyUrl","scope","apiHost","collectHost","reloadOnWithdraw","gcm","preview","title","description","configKey","configRef","useRef","categoriesKey","categoriesRef","useIsomorphicLayoutEffect","api","createConsent","lastKey","lastState","getSnapshot","current","key","subscribe","onChange","useConsent","consent","useSyncExternalStore","open","useCallback","accept","categories","acceptAll","rejectAll","reset"]}
1
+ {"version":3,"sources":["../src/consent/react.tsx","../src/consent/core/types.ts","../src/consent/core/activate.ts","../src/consent/core/config.ts","../src/consent/core/gcm.ts","../src/consent/core/texts.ts","../src/consent/core/contrast.ts","../src/consent/core/styles.ts","../src/consent/core/ui.ts","../src/consent/core/controller.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"../lib/isomorphic-layout-effect\";\nimport { createConsent } from \"./core/controller\";\nimport type {\n BitsnapConsentApi,\n ConsentChoices,\n ConsentConfig,\n ConsentOptions,\n ConsentState,\n} from \"./core/types\";\n\ndeclare global {\n interface Window {\n BitsnapConsent?: BitsnapConsentApi;\n }\n}\n\nexport type BitsnapConsentProps = {\n /** Public project key: loads the project's banner config and logs choices. */\n projectKey?: string;\n theme?: ConsentOptions[\"theme\"];\n locale?: ConsentOptions[\"locale\"];\n position?: ConsentOptions[\"position\"];\n privacyPolicyUrl?: string;\n /** `project` keeps the consent cookie per project key. */\n scope?: ConsentOptions[\"scope\"];\n apiHost?: string;\n collectHost?: string;\n /** Local config, merged over the project config. */\n config?: Partial<ConsentConfig>;\n reloadOnWithdraw?: boolean;\n /** Google Consent Mode v2: `auto` (default) is on when `gtag` or `dataLayer` already exist. */\n gcm?: ConsentOptions[\"gcm\"];\n /** Categories offered when no remote config is loaded. */\n categories?: ConsentOptions[\"categories\"];\n /** Dashboard preview: shows the banner from the local options only; touches no cookie. */\n preview?: boolean;\n /** Replaces the banner title. */\n title?: string;\n /** Replaces the banner description. */\n description?: string;\n};\n\n/** Mounts Bitsnap Consent on the page. Renders nothing itself (the banner lives in a Shadow DOM). */\nexport function BitsnapConsent(props: BitsnapConsentProps): null {\n const {\n projectKey, theme, locale, position, privacyPolicyUrl, scope, apiHost, collectHost, reloadOnWithdraw,\n gcm, preview, title, description,\n } = props;\n const configKey = JSON.stringify(props.config ?? null);\n const configRef = useRef(props.config);\n configRef.current = props.config;\n const categoriesKey = JSON.stringify(props.categories ?? null);\n const categoriesRef = useRef(props.categories);\n categoriesRef.current = props.categories;\n\n // A layout effect: the page's passive effects (first events, tracker) must find the API already there.\n useIsomorphicLayoutEffect(() => {\n // A banner from the script tag or another instance already runs on this page.\n if (window.BitsnapConsent) return;\n const api = createConsent({\n projectKey,\n theme,\n locale,\n position,\n privacyPolicyUrl,\n scope,\n apiHost,\n collectHost,\n reloadOnWithdraw,\n gcm,\n preview,\n title,\n description,\n categories: categoriesRef.current,\n config: configRef.current,\n });\n window.BitsnapConsent = api;\n return () => {\n api.destroy();\n if (window.BitsnapConsent === api) delete window.BitsnapConsent;\n };\n }, [\n projectKey, theme, locale, position, privacyPolicyUrl, scope, apiHost, collectHost, reloadOnWithdraw,\n gcm, preview, title, description, categoriesKey, configKey,\n ]);\n\n return null;\n}\n\nlet lastKey = \"null\";\nlet lastState: ConsentState | null = null;\n\nfunction getSnapshot(): ConsentState | null {\n const current = typeof window === \"undefined\" ? null : (window.BitsnapConsent?.get() ?? null);\n const key = JSON.stringify(current);\n if (key !== lastKey) {\n lastKey = key;\n lastState = current;\n }\n return lastState;\n}\n\nfunction subscribe(onChange: () => void): () => void {\n window.addEventListener(\"bitsnap:consent\", onChange);\n window.addEventListener(\"bitsnap:consent:ready\", onChange);\n return () => {\n window.removeEventListener(\"bitsnap:consent\", onChange);\n window.removeEventListener(\"bitsnap:consent:ready\", onChange);\n };\n}\n\nexport type UseConsent = {\n /** The stored choice, or `null` while there is none (or on the server). */\n consent: ConsentState | null;\n /** `true` once the visitor has made a choice that is still valid. */\n decided: boolean;\n open: () => void;\n accept: (categories?: Partial<ConsentChoices>) => void;\n acceptAll: () => void;\n rejectAll: () => void;\n reset: () => void;\n};\n\n/** Current consent state of the page, kept up to date as the visitor chooses. */\nexport function useConsent(): UseConsent {\n const consent = useSyncExternalStore(subscribe, getSnapshot, () => null);\n const open = useCallback(() => window.BitsnapConsent?.open(), []);\n const accept = useCallback((categories?: Partial<ConsentChoices>) => window.BitsnapConsent?.accept(categories), []);\n const acceptAll = useCallback(() => window.BitsnapConsent?.acceptAll(), []);\n const rejectAll = useCallback(() => window.BitsnapConsent?.rejectAll(), []);\n const reset = useCallback(() => window.BitsnapConsent?.reset(), []);\n return { consent, decided: consent !== null, open, accept, acceptAll, rejectAll, reset };\n}\n","export type ConsentCategory = \"analytics\" | \"marketing\" | \"preferences\";\n\nexport type ConsentChoices = Record<ConsentCategory, boolean>;\n\nexport type ConsentTheme = \"auto\" | \"light\" | \"dark\";\n\nexport type ConsentPosition = \"bottom\" | \"bottom-left\" | \"bottom-right\";\n\nexport type ConsentLocale = \"pl\" | \"en\";\n\nexport const CONSENT_CATEGORIES: readonly ConsentCategory[] = [\n \"analytics\",\n \"marketing\",\n \"preferences\",\n];\n\nexport const CONSENT_TEXT_KEYS = [\n \"title\",\n \"description\",\n \"acceptAll\",\n \"rejectAll\",\n \"settings\",\n \"save\",\n \"close\",\n \"necessaryTitle\",\n \"necessaryDescription\",\n \"analyticsTitle\",\n \"analyticsDescription\",\n \"marketingTitle\",\n \"marketingDescription\",\n \"preferencesTitle\",\n \"preferencesDescription\",\n \"poweredBy\",\n] as const;\n\nexport type ConsentTexts = Record<(typeof CONSENT_TEXT_KEYS)[number], string>;\n\nexport type ConsentService = {\n name: string;\n category: ConsentCategory;\n /** Cookies to delete (best effort) when the category is withdrawn. A trailing `*` matches a prefix. */\n cookies?: string[];\n};\n\nexport type ConsentConfig = {\n /** Banner version. A stored choice with a lower `bv` makes the banner ask again. */\n version: number;\n theme: ConsentTheme;\n accentColor?: string;\n position: ConsentPosition;\n privacyPolicyUrl?: string;\n categories: ConsentChoices;\n services: ConsentService[];\n texts?: Partial<Record<ConsentLocale, Partial<ConsentTexts>>>;\n poweredBy: true;\n};\n\n/** What the consent cookie holds, and what `get()` returns. */\nexport type ConsentState = {\n id: string;\n /** Unix seconds. */\n ts: number;\n /** Version of the banner the choice was made on. */\n bv: number;\n c: ConsentChoices;\n};\n\nexport type ConsentAction =\n | \"accept_all\"\n | \"reject_all\"\n | \"custom\"\n | \"withdraw\";\n\n/** `detail` of `bitsnap:consent` and the argument of `on('change')`. */\nexport type ConsentChangeDetail = ConsentState & {\n /** `reset` when the visitor's stored choice was cleared (`get()` is `null` then). */\n action: ConsentAction | \"reset\";\n};\n\nexport type ConsentOptions = {\n /** Public project key. Enables the remote config and the consent log. */\n projectKey?: string;\n theme?: ConsentTheme;\n locale?: \"auto\" | ConsentLocale;\n position?: ConsentPosition;\n privacyPolicyUrl?: string;\n /** `project` keeps one cookie per project key (`bitsnap_consent_<key>`). */\n scope?: \"global\" | \"project\";\n apiHost?: string;\n collectHost?: string;\n /** Google Consent Mode v2. `auto` is on when `gtag` or `dataLayer` already exist. */\n gcm?: \"auto\" | \"on\" | \"off\";\n /** Local overrides, merged over the defaults and the remote config. */\n config?: Partial<ConsentConfig>;\n /** Categories used when no remote config is loaded. */\n categories?: Partial<ConsentChoices>;\n reloadOnWithdraw?: boolean;\n /**\n * Dashboard preview: shows the banner at once from the local options, never\n * reads or writes the cookie, loads no remote config, sends no consent log,\n * and the buttons only close the banner.\n */\n preview?: boolean;\n /** Replaces the banner title (current locale, non-empty values only). */\n title?: string;\n /** Replaces the banner description (current locale, non-empty values only). */\n description?: string;\n};\n\nexport type BitsnapConsentApi = {\n /**\n * Whose choice this banner holds: `project` keeps one cookie per project key\n * (`bitsnap_consent_<key>`), `global` the site-wide `bitsnap_consent`.\n */\n readonly scope: \"global\" | \"project\";\n /** The bare public project key the banner was started with, if any (`pk_` stripped). */\n readonly projectKey: string | null;\n get(): ConsentState | null;\n /**\n * `true` when the visitor refused `category`, also in a choice made on an older banner\n * version (which `get()` no longer returns) that they have not answered again yet.\n */\n denied(category: ConsentCategory): boolean;\n on(event: \"change\", fn: (detail: ConsentChangeDetail) => void): () => void;\n open(): void;\n close(): void;\n accept(categories?: Partial<ConsentChoices>): void;\n acceptAll(): void;\n rejectAll(): void;\n reset(): void;\n /** Resolves with the stored choice (or `null`) once config and stored choice are applied. */\n ready: Promise<ConsentState | null>;\n destroy(): void;\n};\n","import { CONSENT_CATEGORIES, type ConsentChoices } from \"./types\";\n\nconst SCRIPT_SELECTOR = 'script[type=\"text/plain\"][data-bitsnap-consent]:not([data-bitsnap-queued])';\nconst FRAME_SELECTOR = \"iframe[data-bitsnap-consent][data-src]\";\n\nconst allowed = (c: ConsentChoices, category: string | null): boolean =>\n (CONSENT_CATEGORIES as readonly string[]).includes(category ?? \"\") &&\n c[category as keyof ConsentChoices];\n\n/** Settles when the script has loaded or failed: a broken script must not block the ones after it. */\nfunction settled(script: HTMLScriptElement): Promise<void> {\n return new Promise((resolve) => {\n script.addEventListener(\"load\", () => resolve(), { once: true });\n script.addEventListener(\"error\", () => resolve(), { once: true });\n });\n}\n\n/** Swaps the placeholder for a live script; resolves once an external one has loaded. */\nfunction run(doc: Document, placeholder: HTMLScriptElement): Promise<void> | undefined {\n const script = doc.createElement(\"script\");\n for (const { name, value } of Array.from(placeholder.attributes)) {\n if (name === \"type\" || name === \"data-bitsnap-queued\") continue;\n if (name === \"data-type\") {\n // The embed writes the original `type=\"module\"` here, as `type` itself is `text/plain`.\n if (value === \"module\") script.setAttribute(\"type\", \"module\");\n } else if (name === \"data-src\") script.setAttribute(\"src\", value);\n else script.setAttribute(name, value);\n }\n if (placeholder.nonce) script.nonce = placeholder.nonce;\n const external = script.hasAttribute(\"src\");\n if (external) {\n // Dynamic scripts are async by default; keep the order of the page.\n if (!placeholder.hasAttribute(\"async\")) script.async = false;\n } else {\n script.text = placeholder.text;\n }\n const loaded = external ? settled(script) : undefined;\n placeholder.parentNode?.replaceChild(script, placeholder);\n return loaded;\n}\n\n/**\n * Turns the consented placeholders into live elements:\n * `<script type=\"text/plain\" data-bitsnap-consent=\"marketing\" [data-src] [data-type=\"module\"]>` becomes\n * a real script (attributes copied, `type` dropped or restored from `data-type`, `data-src` -> `src`),\n * and `<iframe data-src>` gets its `src`.\n * Placeholders run in document order: an inline script waits for the external scripts before it\n * (`<script src=lib.js>` then `<script>Lib.init()</script>`), external ones only follow each other.\n */\nexport function activateScripts(doc: Document, c: ConsentChoices): number {\n let activated = 0;\n try {\n /** Set once a placeholder had to wait: everything after it queues behind it. */\n let gate: Promise<void> | null = null;\n /** External scripts inserted since the last inline one. */\n let loading: Promise<void>[] = [];\n doc.querySelectorAll<HTMLScriptElement>(SCRIPT_SELECTOR).forEach((placeholder) => {\n if (!allowed(c, placeholder.getAttribute(\"data-bitsnap-consent\"))) return;\n activated++;\n const inline = !placeholder.hasAttribute(\"data-src\") && !placeholder.hasAttribute(\"src\");\n if (gate || (inline && loading.length > 0)) {\n // Marked so that another call (a later choice) does not queue it again.\n placeholder.setAttribute(\"data-bitsnap-queued\", \"\");\n gate = (gate ?? Promise.all(loading).then(() => {})).then(() => {\n try {\n return run(doc, placeholder);\n } catch {\n // never throw into the host page\n }\n });\n loading = [];\n return;\n }\n const loaded = run(doc, placeholder);\n if (loaded) loading.push(loaded);\n });\n doc.querySelectorAll<HTMLIFrameElement>(FRAME_SELECTOR).forEach((frame) => {\n if (!allowed(c, frame.getAttribute(\"data-bitsnap-consent\"))) return;\n const src = frame.getAttribute(\"data-src\");\n if (src && frame.getAttribute(\"src\") !== src) {\n frame.setAttribute(\"src\", src);\n frame.removeAttribute(\"data-src\");\n activated++;\n }\n });\n } catch {\n // never throw into the host page\n }\n return activated;\n}\n","import {\n CONSENT_CATEGORIES,\n type ConsentChoices,\n type ConsentConfig,\n type ConsentService,\n} from \"./types\";\n\nexport const DEFAULT_API_HOST = \"https://bitsnap.pl\";\nexport const DEFAULT_COLLECT_HOST = \"https://collect.bitsnap.pl\";\n\nexport function defaultConfig(): ConsentConfig {\n return {\n version: 1,\n theme: \"auto\",\n position: \"bottom\",\n categories: { analytics: true, marketing: true, preferences: false },\n services: [],\n poweredBy: true,\n };\n}\n\nconst THEMES = [\"auto\", \"light\", \"dark\"];\nconst POSITIONS = [\"bottom\", \"bottom-left\", \"bottom-right\"];\n\nconst HEX_COLOR = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;\n\nexport function safeColor(value: unknown): string | undefined {\n return typeof value === \"string\" && HEX_COLOR.test(value.trim())\n ? value.trim()\n : undefined;\n}\n\n/** Only http(s) and relative URLs may end up in the banner. */\nexport function safeUrl(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const url = value.trim();\n return /^(?:https?:\\/\\/|\\/(?!\\/)|#|\\?)/i.test(url) ? url : undefined;\n}\n\nfunction cleanServices(value: unknown): ConsentService[] {\n if (!Array.isArray(value)) return [];\n const services: ConsentService[] = [];\n for (const item of value) {\n if (\n item &&\n typeof item.name === \"string\" &&\n (CONSENT_CATEGORIES as readonly string[]).includes(item.category)\n ) {\n services.push({\n name: item.name,\n category: item.category,\n cookies: Array.isArray(item.cookies)\n ? item.cookies.filter((cookie: unknown) => typeof cookie === \"string\")\n : undefined,\n });\n }\n }\n return services;\n}\n\n/** Layers partial configs (later wins) over the defaults, dropping invalid values. */\nexport function mergeConfig(\n ...layers: (Partial<ConsentConfig> | null | undefined)[]\n): ConsentConfig {\n const result = defaultConfig();\n for (const layer of layers) {\n if (!layer || typeof layer !== \"object\") continue;\n if (typeof layer.version === \"number\" && layer.version >= 0) {\n result.version = Math.floor(layer.version);\n }\n if (THEMES.includes(layer.theme as string)) result.theme = layer.theme!;\n if (POSITIONS.includes(layer.position as string)) result.position = layer.position!;\n const accent = safeColor(layer.accentColor);\n if (accent) result.accentColor = accent;\n const privacy = safeUrl(layer.privacyPolicyUrl);\n if (privacy) result.privacyPolicyUrl = privacy;\n if (layer.categories && typeof layer.categories === \"object\") {\n for (const category of CONSENT_CATEGORIES) {\n if (typeof layer.categories[category] === \"boolean\") {\n result.categories[category] = layer.categories[category];\n }\n }\n }\n if (layer.services !== undefined) result.services = cleanServices(layer.services);\n if (layer.texts && typeof layer.texts === \"object\") result.texts = layer.texts;\n }\n return result;\n}\n\nexport function parseCategoryList(value: string | null | undefined): ConsentChoices {\n const wanted = (value ?? \"\").split(\",\").map((item) => item.trim());\n return {\n analytics: wanted.includes(\"analytics\"),\n marketing: wanted.includes(\"marketing\"),\n preferences: wanted.includes(\"preferences\"),\n };\n}\n\n/** What `GET /api/consent/config` answers: whether the banner is on, and its config. */\nexport type RemoteConsentConfig = {\n /** `false` when the project turned the banner off: nothing is shown, stored choices still apply. */\n enabled: boolean;\n config: Partial<ConsentConfig> | null;\n};\n\n/** Loads the project's banner config. Resolves to `null` on any failure or after the timeout. */\nexport async function fetchRemoteConfig(\n apiHost: string,\n key: string,\n timeoutMs = 3000,\n): Promise<RemoteConsentConfig | null> {\n if (typeof fetch !== \"function\") return null;\n const controller = typeof AbortController === \"function\" ? new AbortController() : undefined;\n const timer = setTimeout(() => controller?.abort(), timeoutMs);\n try {\n const response = await fetch(\n `${apiHost.replace(/\\/+$/, \"\")}/api/consent/config?key=${encodeURIComponent(key)}`,\n { signal: controller?.signal, credentials: \"omit\" },\n );\n if (!response.ok) return null;\n const body = await response.json();\n if (!body || typeof body !== \"object\") return null;\n const config = body.config && typeof body.config === \"object\" ? body.config : null;\n const enabled = body.enabled !== false;\n return config || !enabled ? { enabled, config } : null;\n } catch {\n return null;\n } finally {\n clearTimeout(timer);\n }\n}\n","import type { ConsentChoices } from \"./types\";\n\ntype Gtag = (...args: unknown[]) => void;\n\ntype GcmWindow = Window & {\n gtag?: Gtag;\n dataLayer?: unknown[];\n};\n\nexport const GCM_DEFAULT = {\n ad_storage: \"denied\",\n ad_user_data: \"denied\",\n ad_personalization: \"denied\",\n analytics_storage: \"denied\",\n functionality_storage: \"denied\",\n personalization_storage: \"denied\",\n security_storage: \"granted\",\n wait_for_update: 500,\n} as const;\n\nconst grant = (value: boolean) => (value ? \"granted\" : \"denied\");\n\n/** analytics -> analytics_storage; marketing -> ad_*; preferences -> functionality/personalization. */\nexport function toConsentModeUpdate(c: ConsentChoices) {\n return {\n analytics_storage: grant(c.analytics),\n ad_storage: grant(c.marketing),\n ad_user_data: grant(c.marketing),\n ad_personalization: grant(c.marketing),\n functionality_storage: grant(c.preferences),\n personalization_storage: grant(c.preferences),\n };\n}\n\nexport function shouldUseConsentMode(win: GcmWindow, mode: \"auto\" | \"on\" | \"off\" | undefined): boolean {\n if (mode === \"off\") return false;\n return mode === \"on\" || typeof win.gtag === \"function\" || Array.isArray(win.dataLayer);\n}\n\n/** A `gtag` that works without gtag.js: it queues `arguments` objects, as gtag.js expects. */\nexport function ensureGtag(win: GcmWindow): Gtag {\n if (typeof win.gtag === \"function\") return win.gtag;\n const layer = (win.dataLayer = win.dataLayer || []);\n const gtag: Gtag = function () {\n // eslint-disable-next-line prefer-rest-params\n layer.push(arguments);\n };\n win.gtag = gtag;\n return gtag;\n}\n\nexport type ConsentMode = {\n setDefault(): void;\n update(c: ConsentChoices): void;\n};\n\nexport function createConsentMode(win: GcmWindow, mode: \"auto\" | \"on\" | \"off\" | undefined): ConsentMode | null {\n if (!shouldUseConsentMode(win, mode)) return null;\n const gtag = ensureGtag(win);\n return {\n setDefault: () => gtag(\"consent\", \"default\", { ...GCM_DEFAULT }),\n update: (c) => gtag(\"consent\", \"update\", toConsentModeUpdate(c)),\n };\n}\n","import type { ConsentLocale, ConsentTexts } from \"./types\";\n\nexport const DEFAULT_TEXTS: Record<ConsentLocale, ConsentTexts> = {\n pl: {\n title: \"Szanujemy Twoją prywatność\",\n description:\n \"Używamy plików cookie, aby strona działała poprawnie. Za Twoją zgodą wykorzystujemy je też do statystyk, personalizacji i reklam. Możesz zaakceptować wszystkie, odrzucić wszystkie albo wybrać, na co się zgadzasz.\",\n acceptAll: \"Akceptuj wszystkie\",\n rejectAll: \"Odrzuć wszystkie\",\n settings: \"Ustawienia\",\n save: \"Zapisz wybór\",\n close: \"Zamknij\",\n necessaryTitle: \"Niezbędne\",\n necessaryDescription:\n \"Potrzebne do działania strony: koszyk, zapamiętanie Twojego wyboru, bezpieczeństwo. Nie można ich wyłączyć.\",\n analyticsTitle: \"Statystyki\",\n analyticsDescription:\n \"Pomagają nam zrozumieć, jak odwiedzający korzystają ze strony, żebyśmy mogli ją ulepszać.\",\n marketingTitle: \"Marketing\",\n marketingDescription:\n \"Pozwalają mierzyć skuteczność reklam i pokazywać Ci oferty dopasowane do zainteresowań.\",\n preferencesTitle: \"Preferencje\",\n preferencesDescription:\n \"Zapamiętują Twoje ustawienia, na przykład język czy wygląd strony.\",\n poweredBy: \"Powered by\",\n },\n en: {\n title: \"We value your privacy\",\n description:\n \"We use cookies to make this site work. With your consent we also use them for statistics, personalization and ads. You can accept all, reject all, or choose what you agree to.\",\n acceptAll: \"Accept all\",\n rejectAll: \"Reject all\",\n settings: \"Settings\",\n save: \"Save choices\",\n close: \"Close\",\n necessaryTitle: \"Necessary\",\n necessaryDescription:\n \"Needed for the site to work: the cart, remembering your choice, security. They cannot be turned off.\",\n analyticsTitle: \"Analytics\",\n analyticsDescription:\n \"Help us understand how visitors use the site, so we can improve it.\",\n marketingTitle: \"Marketing\",\n marketingDescription:\n \"Measure how well ads work and show you offers that match your interests.\",\n preferencesTitle: \"Preferences\",\n preferencesDescription:\n \"Remember your settings, such as language or how the site looks.\",\n poweredBy: \"Powered by\",\n },\n};\n\n/** Fixed interface labels that are not part of the configurable texts. */\nexport const UI_LABELS: Record<\n ConsentLocale,\n { privacy: string; services: string; always: string }\n> = {\n pl: {\n privacy: \"Polityka prywatności\",\n services: \"Usługi\",\n always: \"Zawsze aktywne\",\n },\n en: { privacy: \"Privacy policy\", services: \"Services\", always: \"Always on\" },\n};\n\nexport function resolveLocale(\n preference: \"auto\" | ConsentLocale | undefined,\n navigatorLanguage?: string,\n): ConsentLocale {\n if (preference === \"pl\" || preference === \"en\") return preference;\n return /^pl\\b/i.test(navigatorLanguage ?? \"\") ? \"pl\" : \"en\";\n}\n\n/** Built-in texts for the locale, with the (non-empty) overrides of the config on top. */\nexport function mergeTexts(\n locale: ConsentLocale,\n overrides?: Partial<Record<ConsentLocale, Partial<ConsentTexts>>>,\n): ConsentTexts {\n const merged = { ...DEFAULT_TEXTS[locale] };\n const own = overrides?.[locale];\n if (own) {\n for (const key of Object.keys(merged) as (keyof ConsentTexts)[]) {\n const value = own[key];\n if (typeof value === \"string\" && value.trim() !== \"\") merged[key] = value;\n }\n }\n return merged;\n}\n","function parse(hex: string): [number, number, number] {\n let h = hex.replace(\"#\", \"\");\n if (h.length === 3) h = h.replace(/./g, \"$&$&\");\n const n = parseInt(h, 16);\n return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n}\n\nfunction luminance(hex: string): number {\n const [r, g, b] = parse(hex).map((v) => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/** WCAG contrast ratio of two `#rgb` / `#rrggbb` colors. */\nexport function contrastRatio(a: string, b: string): number {\n const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/** Black or white text, whichever reads better on `background`. */\nexport function onColor(background: string): string {\n return contrastRatio(background, \"#ffffff\") >= contrastRatio(background, \"#111111\")\n ? \"#ffffff\"\n : \"#111111\";\n}\n","/** Colors of both themes. Every text/background pair is checked against WCAG AA in the tests. */\nexport const PALETTE = {\n light: {\n bg: \"#ffffff\",\n fg: \"#14171c\",\n muted: \"#495260\",\n border: \"#c9ced6\",\n off: \"#6b7280\",\n thumb: \"#ffffff\",\n accent: \"#1d4ed8\",\n onAccent: \"#ffffff\",\n link: \"#1d4ed8\",\n },\n dark: {\n bg: \"#171a20\",\n fg: \"#f1f3f6\",\n muted: \"#b7beca\",\n border: \"#3a404b\",\n off: \"#8b93a1\",\n thumb: \"#171a20\",\n accent: \"#8ab4ff\",\n onAccent: \"#0b1220\",\n link: \"#9dc0ff\",\n },\n} as const;\n\nconst vars = (p: (typeof PALETTE)[\"light\"]) =>\n `--bg:${p.bg};--fg:${p.fg};--muted:${p.muted};--border:${p.border};--off:${p.off};--thumb:${p.thumb};--accent:${p.accent};--on-accent:${p.onAccent};--link:${p.link};--focus:${p.accent}`;\n\nexport const STYLES = `\n:host{all:initial}\n*{box-sizing:border-box}\n[hidden]{display:none!important}\n.root{${vars(PALETTE.light)};position:fixed;inset:0;pointer-events:none;z-index:2147483000;font:14px/1.5 system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;color:var(--fg);-webkit-text-size-adjust:100%}\n.root[data-theme=dark]{${vars(PALETTE.dark)};color-scheme:dark}\nbutton,input{font:inherit;color:inherit}\n.banner,.overlay{pointer-events:auto}\n::selection{background:color-mix(in srgb,var(--accent) 24%,transparent)}\n.banner{position:absolute;background:var(--bg);color:var(--fg);max-height:92vh;overflow:auto;outline:none;animation:in .22s ease-out}\n.bottom{left:0;right:0;bottom:0;border-top:1px solid var(--border);box-shadow:0 -8px 28px rgba(15,23,42,.08);padding:20px 24px calc(20px + env(safe-area-inset-bottom,0px))}\n.root[data-theme=dark] .bottom{box-shadow:0 -8px 28px rgba(0,0,0,.4)}\n.bottom .inner{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"text actions\" \"foot actions\";gap:4px 40px;align-items:center;max-width:1120px;margin:0 auto}\n.bottom .text{max-width:68ch}\n.bottom .btn,.bottom .link-btn{flex:0 0 auto}\n.card{bottom:16px;width:min(400px,calc(100vw - 32px));border:1px solid var(--border);border-radius:14px;padding:20px;box-shadow:0 12px 32px rgba(15,23,42,.14)}\n.root[data-theme=dark] .card{box-shadow:0 12px 32px rgba(0,0,0,.45)}\n.bottom-left{left:16px}\n.bottom-right{right:16px}\n.card .inner{display:flex;flex-direction:column;gap:16px}\n.text{grid-area:text}\n.actions{grid-area:actions;display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}\n.card .actions{justify-content:stretch}\n.foot{grid-area:foot}\n.title{font-size:17px;font-weight:650;line-height:1.35;letter-spacing:-.01em;text-wrap:balance;margin:0 0 6px}\n.desc{margin:0;color:var(--muted);line-height:1.55;text-wrap:pretty}\n.desc a{color:var(--link);text-decoration:underline;text-underline-offset:3px}\n.btn,.link-btn{min-height:44px;padding:0 20px;border-radius:10px;font-weight:600;cursor:pointer;white-space:nowrap;transition:background-color .12s ease-out,filter .12s ease-out,border-color .12s ease-out}\n.btn{border:2px solid var(--accent);background:var(--accent);color:var(--on-accent);flex:1 1 150px}\n.btn:hover{filter:brightness(.93)}\n.btn:active{filter:brightness(.87)}\n.link-btn{border:1px solid var(--border);background:transparent;color:var(--fg);text-decoration:none}\n.link-btn:hover{background:color-mix(in srgb,var(--fg) 6%,transparent)}\n.link-btn:active{background:color-mix(in srgb,var(--fg) 10%,transparent)}\n.card .link-btn{flex:1 1 100%}\nbutton:focus-visible,a:focus-visible,.dialog:focus-visible{outline:2px solid var(--focus);outline-offset:2px}\n.foot{font-size:12px;color:var(--muted);padding-top:8px}\n.foot a{color:var(--muted);text-decoration:none;display:inline-flex;align-items:center;gap:5px;vertical-align:middle}\n.foot a:hover{text-decoration:underline}\n.foot b{color:var(--fg);font-weight:700;letter-spacing:-.01em}\n.foot svg{display:block}\n.overlay{position:absolute;inset:0;background:rgba(10,12,16,.58);display:flex;align-items:center;justify-content:center;padding:16px;animation:fade .2s ease-out}\n.dialog{background:var(--bg);color:var(--fg);width:100%;max-width:560px;max-height:min(92vh,760px);display:flex;flex-direction:column;border-radius:16px;box-shadow:0 16px 48px rgba(0,0,0,.35);outline:none;animation:in .22s ease-out}\n.d-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 8px 8px 24px}\n.d-head .title{margin:0;font-size:18px}\n.x{width:44px;height:44px;border:0;border-radius:10px;background:none;cursor:pointer;display:flex;align-items:center;justify-content:center;flex:none}\n.x:hover{background:var(--border)}\n.d-body{overflow:auto;padding:0 24px 8px;flex:1}\n.cat{border-top:1px solid var(--border);padding:10px 0 14px}\n.row{display:flex;align-items:center;justify-content:space-between;gap:12px}\n.cat-title{font-weight:600;font-size:15px}\n.always{font-size:12px;color:var(--muted);margin-right:4px}\n.cat p{margin:0;color:var(--muted)}\n.cat .svc{margin-top:6px;font-size:13px}\n.cat .svc b{font-weight:600;color:var(--fg)}\n.switch{position:relative;width:52px;height:44px;display:flex;align-items:center;justify-content:flex-end;flex:none}\n.switch input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}\n.switch input:disabled{cursor:default}\n.track{width:44px;height:24px;border-radius:12px;background:var(--off);position:relative;transition:background .15s}\n.track::after{content:\"\";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:var(--thumb);transition:transform .15s}\ninput:checked+.track{background:var(--accent)}\ninput:checked+.track::after{transform:translateX(20px);background:var(--on-accent)}\ninput:disabled+.track{opacity:.6}\ninput:focus-visible+.track{outline:2px solid var(--focus);outline-offset:2px}\n.d-foot{display:flex;flex-direction:column;gap:8px;padding:12px 24px 16px;border-top:1px solid var(--border)}\n.d-foot .actions{justify-content:stretch}\n@keyframes in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}\n@keyframes fade{from{opacity:0}to{opacity:1}}\n@media(max-width:960px){\n.bottom .inner{grid-template-columns:minmax(0,1fr);grid-template-areas:\"text\" \"actions\" \"foot\";gap:14px}\n.bottom .actions{justify-content:flex-start}\n}\n@media(max-width:640px){\n.bottom{padding:16px 16px calc(16px + env(safe-area-inset-bottom,0px))}\n.bottom .inner{grid-template-columns:1fr;grid-template-areas:\"text\" \"actions\" \"foot\";gap:12px}\n.bottom .actions{justify-content:stretch}\n.bottom .btn{flex:1 1 130px}\n.bottom .link-btn{flex:1 1 100%}\n.card{left:8px;right:8px;bottom:8px;width:auto}\n.overlay{align-items:flex-end;padding:0}\n.dialog{max-width:none;border-radius:16px 16px 0 0;max-height:92vh}\n.d-head{padding-left:16px}\n.d-body{padding:0 16px 8px}\n.d-foot{padding:12px 16px calc(16px + env(safe-area-inset-bottom,0px))}\n.btn{flex-basis:130px;padding:0 12px}\n}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}\n`.replace(/\\n/g, \"\");\n","import { contrastRatio, onColor } from \"./contrast\";\nimport { UI_LABELS } from \"./texts\";\nimport { PALETTE, STYLES } from \"./styles\";\nimport {\n CONSENT_CATEGORIES,\n type ConsentCategory,\n type ConsentChoices,\n type ConsentConfig,\n type ConsentLocale,\n type ConsentTexts,\n} from \"./types\";\n\nexport type UIOptions = {\n doc: Document;\n config: ConsentConfig;\n texts: ConsentTexts;\n locale: ConsentLocale;\n /** Current choice, used to preset the toggles. */\n getChoices(): ConsentChoices | null;\n /** Whether a valid choice exists, i.e. closing the settings must not bring back the banner. */\n hasChoice(): boolean;\n onAcceptAll(): void;\n onRejectAll(): void;\n onSave(choices: ConsentChoices): void;\n};\n\nexport type ConsentUI = {\n /** `focus` moves keyboard focus into the banner; leave it off when the banner opens on page load. */\n showBanner(focus?: boolean): void;\n showSettings(): void;\n hide(): void;\n destroy(): void;\n};\n\nconst WORDMARK =\n '<svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><rect width=\"16\" height=\"16\" rx=\"4\" fill=\"currentColor\" style=\"color:var(--fg)\"/><circle cx=\"8\" cy=\"8\" r=\"3\" fill=\"var(--bg)\"/></svg>';\n\nconst CLOSE_ICON =\n '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M3 3l10 10M13 3L3 13\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" fill=\"none\"/></svg>';\n\nconst FOCUSABLE = \"button:not([disabled]),input:not([disabled]),a[href]\";\n\nexport function createUI(options: UIOptions): ConsentUI {\n const { doc, config, texts, locale } = options;\n const labels = UI_LABELS[locale];\n let host: HTMLElement | null = null;\n let shadow: ShadowRoot | null = null;\n let root: HTMLElement;\n let banner: HTMLElement;\n let overlay: HTMLElement;\n let dialog: HTMLElement;\n let settingsButton: HTMLElement;\n let layer: \"none\" | \"banner\" | \"settings\" = \"none\";\n let opener: HTMLElement | null = null;\n let media: MediaQueryList | null = null;\n const toggles = new Map<ConsentCategory, HTMLInputElement>();\n\n function el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n props: Record<string, string> = {},\n ...children: (Node | string)[]\n ): HTMLElementTagNameMap[K] {\n const node = doc.createElement(tag);\n for (const key of Object.keys(props)) {\n if (key === \"class\") node.className = props[key];\n else node.setAttribute(key, props[key]);\n }\n for (const child of children) node.append(child);\n return node;\n }\n\n function button(cls: string, text: string, onClick: () => void) {\n const node = el(\"button\", { type: \"button\", class: cls }, text);\n node.addEventListener(\"click\", onClick);\n return node;\n }\n\n function powered(): HTMLElement {\n const link = el(\"a\", {\n href: `https://bitsnap.pl/?utm_source=consent_banner&utm_medium=referral&utm_content=${encodeURIComponent(doc.location?.hostname ?? \"\")}`,\n target: \"_blank\",\n rel: \"noopener\",\n });\n link.append(texts.poweredBy + \" \");\n link.insertAdjacentHTML(\"beforeend\", WORDMARK);\n link.append(el(\"b\", {}, \"bitsnap\"));\n return el(\"div\", { class: \"foot\" }, link);\n }\n\n function description(): HTMLElement {\n const node = el(\"p\", { class: \"desc\", id: \"d\" }, texts.description);\n if (config.privacyPolicyUrl) {\n node.append(\n \" \",\n el(\n \"a\",\n { href: config.privacyPolicyUrl, target: \"_blank\", rel: \"noopener\" },\n labels.privacy,\n ),\n );\n }\n return node;\n }\n\n function buildBanner() {\n settingsButton = button(\"link-btn\", texts.settings, () => showSettings());\n banner = el(\n \"div\",\n {\n class: `banner ${config.position === \"bottom\" ? \"bottom\" : `card ${config.position}`}`,\n // Not modal: the page stays usable, so it is a live region, not a dialog.\n role: \"region\",\n \"aria-live\": \"polite\",\n \"aria-labelledby\": \"t\",\n \"aria-describedby\": \"d\",\n tabindex: \"-1\",\n },\n el(\n \"div\",\n { class: \"inner\" },\n el(\"div\", { class: \"text\" }, el(\"div\", { class: \"title\", id: \"t\" }, texts.title), description()),\n el(\n \"div\",\n { class: \"actions\" },\n button(\"btn\", texts.acceptAll, options.onAcceptAll),\n button(\"btn\", texts.rejectAll, options.onRejectAll),\n settingsButton,\n ),\n powered(),\n ),\n );\n }\n\n function category(id: ConsentCategory | \"necessary\"): HTMLElement {\n const services = config.services.filter((service) => service.category === id);\n const input = el(\"input\", { type: \"checkbox\", role: \"switch\", \"aria-labelledby\": `l-${id}`, \"aria-describedby\": `p-${id}` });\n if (id === \"necessary\") {\n input.checked = true;\n input.disabled = true;\n } else {\n toggles.set(id, input);\n }\n const node = el(\n \"div\",\n { class: \"cat\" },\n el(\n \"div\",\n { class: \"row\" },\n el(\"span\", { class: \"cat-title\", id: `l-${id}` }, texts[`${id}Title` as keyof ConsentTexts]),\n el(\n \"span\",\n { style: \"display:flex;align-items:center\" },\n ...(id === \"necessary\" ? [el(\"span\", { class: \"always\" }, labels.always)] : []),\n el(\"label\", { class: \"switch\" }, input, el(\"span\", { class: \"track\" })),\n ),\n ),\n el(\"p\", { id: `p-${id}` }, texts[`${id}Description` as keyof ConsentTexts]),\n );\n if (services.length > 0) {\n node.append(\n el(\"p\", { class: \"svc\" }, el(\"b\", {}, `${labels.services}: `), services.map((s) => s.name).join(\", \")),\n );\n }\n return node;\n }\n\n function buildSettings() {\n const close = el(\"button\", { type: \"button\", class: \"x\", \"aria-label\": texts.close });\n close.insertAdjacentHTML(\"beforeend\", CLOSE_ICON);\n close.addEventListener(\"click\", () => closeSettings());\n const body = el(\"div\", { class: \"d-body\" }, category(\"necessary\"));\n for (const id of CONSENT_CATEGORIES) {\n if (config.categories[id]) body.append(category(id));\n }\n dialog = el(\n \"div\",\n { class: \"dialog\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": \"st\", tabindex: \"-1\" },\n el(\"div\", { class: \"d-head\" }, el(\"div\", { class: \"title\", id: \"st\" }, texts.settings), close),\n body,\n el(\n \"div\",\n { class: \"d-foot\" },\n el(\n \"div\",\n { class: \"actions\" },\n button(\"btn\", texts.save, () => options.onSave(readToggles())),\n button(\"btn\", texts.acceptAll, options.onAcceptAll),\n button(\"btn\", texts.rejectAll, options.onRejectAll),\n ),\n powered(),\n ),\n );\n overlay = el(\"div\", { class: \"overlay\" }, dialog);\n overlay.addEventListener(\"mousedown\", (event) => {\n if (event.target === overlay) closeSettings();\n });\n }\n\n function readToggles(): ConsentChoices {\n const choices = { analytics: false, marketing: false, preferences: false };\n toggles.forEach((input, key) => (choices[key] = input.checked));\n return choices;\n }\n\n function applyTheme() {\n const dark = config.theme === \"dark\" || (config.theme === \"auto\" && !!media?.matches);\n root.setAttribute(\"data-theme\", dark ? \"dark\" : \"light\");\n applyAccent(dark);\n }\n\n /** A custom accent that is too faint on the dark background gives way to the dark theme's own. */\n function applyAccent(dark: boolean) {\n const accent = config.accentColor;\n if (!accent) return;\n if (dark && contrastRatio(accent, PALETTE.dark.bg) < 3) {\n for (const name of [\"--accent\", \"--focus\", \"--on-accent\"]) root.style.removeProperty(name);\n return;\n }\n root.style.setProperty(\"--accent\", accent);\n root.style.setProperty(\"--focus\", accent);\n root.style.setProperty(\"--on-accent\", onColor(accent));\n }\n\n function ensure() {\n if (host) return;\n host = el(\"div\", { id: \"bitsnap-consent\", \"data-bitsnap-consent-host\": \"\" });\n shadow = host.attachShadow({ mode: \"open\" });\n shadow.append(el(\"style\", {}, STYLES));\n root = el(\"div\", { class: \"root\", lang: locale });\n buildBanner();\n buildSettings();\n banner.hidden = true;\n overlay.hidden = true;\n root.append(banner, overlay);\n shadow.append(root);\n if (typeof doc.defaultView?.matchMedia === \"function\") {\n media = doc.defaultView.matchMedia(\"(prefers-color-scheme: dark)\");\n media.addEventListener?.(\"change\", applyTheme);\n }\n applyTheme();\n doc.body.append(host);\n }\n\n function focusables(): HTMLElement[] {\n return Array.from(dialog.querySelectorAll<HTMLElement>(FOCUSABLE));\n }\n\n function onKeydown(event: KeyboardEvent) {\n if (layer !== \"settings\") return;\n if (event.key === \"Escape\") {\n event.preventDefault();\n closeSettings();\n return;\n }\n if (event.key !== \"Tab\") return;\n const items = focusables();\n if (items.length === 0) return;\n const active = shadow?.activeElement as HTMLElement | null;\n const first = items[0];\n const last = items[items.length - 1];\n const outside = !active || !dialog.contains(active);\n if (event.shiftKey && (outside || active === first || active === dialog)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (outside || active === last)) {\n event.preventDefault();\n first.focus();\n }\n }\n\n function showBanner(focus = false) {\n try {\n ensure();\n layer = \"banner\";\n doc.removeEventListener(\"keydown\", onKeydown, true);\n overlay.hidden = true;\n banner.hidden = false;\n if (focus) banner.focus({ preventScroll: true });\n } catch {\n // never throw into the host page\n }\n }\n\n function showSettings() {\n try {\n ensure();\n if (layer !== \"settings\") {\n const active = doc.activeElement as HTMLElement | null;\n opener = active && active !== host && active !== doc.body ? active : null;\n }\n const current = options.getChoices();\n toggles.forEach((input, key) => (input.checked = !!current?.[key]));\n layer = \"settings\";\n banner.hidden = true;\n overlay.hidden = false;\n doc.addEventListener(\"keydown\", onKeydown, true);\n dialog.focus({ preventScroll: true });\n } catch {\n // never throw into the host page\n }\n }\n\n function closeSettings() {\n if (layer !== \"settings\") return;\n doc.removeEventListener(\"keydown\", onKeydown, true);\n overlay.hidden = true;\n if (options.hasChoice()) {\n layer = \"none\";\n opener?.focus?.({ preventScroll: true });\n } else {\n layer = \"banner\";\n banner.hidden = false;\n settingsButton.focus({ preventScroll: true });\n }\n }\n\n function hide() {\n if (!host) return;\n doc.removeEventListener(\"keydown\", onKeydown, true);\n const wasSettings = layer === \"settings\";\n layer = \"none\";\n banner.hidden = true;\n overlay.hidden = true;\n if (wasSettings) opener?.focus?.({ preventScroll: true });\n }\n\n function destroy() {\n doc.removeEventListener(\"keydown\", onKeydown, true);\n media?.removeEventListener?.(\"change\", applyTheme);\n host?.remove();\n host = null;\n shadow = null;\n layer = \"none\";\n }\n\n return { showBanner, showSettings, hide, destroy };\n}\n","import { normalizeProjectKey } from \"../../analytics/contract\";\nimport { activateScripts } from \"./activate\";\nimport {\n DEFAULT_API_HOST,\n DEFAULT_COLLECT_HOST,\n fetchRemoteConfig,\n mergeConfig,\n} from \"./config\";\nimport {\n clearConsent,\n cookieName,\n deleteServiceCookies,\n newConsentId,\n readConsent,\n writeConsent,\n} from \"./cookie\";\nimport { createConsentMode } from \"./gcm\";\nimport { mergeTexts, resolveLocale } from \"./texts\";\nimport { createUI, type ConsentUI } from \"./ui\";\nimport {\n CONSENT_CATEGORIES,\n type BitsnapConsentApi,\n type ConsentAction,\n type ConsentCategory,\n type ConsentChangeDetail,\n type ConsentChoices,\n type ConsentConfig,\n type ConsentOptions,\n type ConsentState,\n type ConsentTexts,\n} from \"./types\";\n\nconst none = (): ConsentChoices => ({ analytics: false, marketing: false, preferences: false });\n\nconst copy = (state: ConsentState | null): ConsentState | null =>\n state && { id: state.id, ts: state.ts, bv: state.bv, c: { ...state.c } };\n\n/** Sync `get()`-style API with no DOM until a layer is shown. Never throws into the page. */\nexport function createConsent(options: ConsentOptions = {}): BitsnapConsentApi {\n const win = typeof window !== \"undefined\" ? window : undefined;\n const doc = win?.document;\n const listeners = new Set<(detail: ConsentChangeDetail) => void>();\n const apiHost = options.apiHost || DEFAULT_API_HOST;\n const collectHost = options.collectHost || DEFAULT_COLLECT_HOST;\n // The contract uses the bare key (no `pk_`) for the cookie name, the config URL and the log.\n const projectKey = options.projectKey ? normalizeProjectKey(options.projectKey) : null;\n const name = cookieName(projectKey ?? undefined, options.scope);\n const preview = !!options.preview;\n\n let config: ConsentConfig = mergeConfig(localLayer());\n let state: ConsentState | null = null;\n /** A stored choice made on an older banner version: it asks again, but its id is reused. */\n let stale: ConsentState | null = null;\n let ui: ConsentUI | null = null;\n let loaded = false;\n let destroyed = false;\n let removeOpenListener: (() => void) | undefined;\n /** Choices made before `ready`: they run inside it, before anyone waiting on `ready` is released. */\n const pending: Array<() => void> = [];\n\n // Consent Mode default has to be set before anything else, config or not.\n // A preview touches nothing outside its own banner: no dataLayer, no cookie.\n const mode = win && !preview ? safe(() => createConsentMode(win, options.gcm), null) : null;\n safe(() => mode?.setDefault(), undefined);\n // The stored choice is read now but only applied once the config is known: it has to match\n // the banner version and the categories on offer. Until then Consent Mode stays denied.\n const initial = doc && !preview ? readConsent(doc, name) : null;\n\n function localLayer(extra?: Partial<ConsentConfig>): Partial<ConsentConfig> {\n const own: Partial<ConsentConfig> = { ...options.config };\n if (options.theme) own.theme = options.theme;\n if (options.position) own.position = options.position;\n if (options.privacyPolicyUrl) own.privacyPolicyUrl = options.privacyPolicyUrl;\n return { ...extra, ...own };\n }\n\n function safe<T>(fn: () => T, fallback: T): T {\n try {\n return fn();\n } catch {\n return fallback;\n }\n }\n\n function enabled(choices: Partial<ConsentChoices> | undefined): ConsentChoices {\n const result = none();\n for (const category of CONSENT_CATEGORIES) {\n result[category] = !!choices?.[category] && config.categories[category];\n }\n return result;\n }\n\n function emit(detail: ConsentChangeDetail) {\n listeners.forEach((fn) => safe(() => fn({ ...detail, c: { ...detail.c } }), undefined));\n safe(() => {\n win?.dispatchEvent(new win.CustomEvent(\"bitsnap:consent\", { detail: { ...detail, c: { ...detail.c } } }));\n }, undefined);\n }\n\n function log(action: ConsentAction, record: ConsentState) {\n if (preview || !projectKey || typeof fetch !== \"function\") return;\n safe(() => {\n const body = JSON.stringify({\n k: projectKey,\n consent_id: record.id,\n action,\n c: record.c,\n bv: record.bv,\n host: win?.location?.hostname ?? \"\",\n ts: record.ts,\n });\n fetch(`${collectHost.replace(/\\/+$/, \"\")}/consent`, {\n method: \"POST\",\n keepalive: true,\n credentials: \"omit\",\n body,\n }).catch(() => {});\n }, undefined);\n }\n\n /** Granted categories the current config still offers. */\n function granted(c: ConsentChoices): ConsentCategory[] {\n return CONSENT_CATEGORIES.filter((category) => c[category] && config.categories[category]);\n }\n\n function commit(choices: ConsentChoices, requested: ConsentAction) {\n if (!doc || destroyed) return;\n if (preview) {\n ui?.hide();\n return;\n }\n const previous = state ?? stale;\n const dropped = previous ? granted(previous.c).filter((category) => !choices[category]) : [];\n const action: ConsentAction = dropped.length > 0 ? \"withdraw\" : requested;\n const next: ConsentState = {\n id: previous?.id ?? newConsentId(),\n ts: Math.floor(Date.now() / 1000),\n bv: config.version,\n c: choices,\n };\n writeConsent(doc, name, next);\n state = next;\n stale = null;\n applyChoices(next.c);\n if (dropped.length > 0) deleteServiceCookies(doc, config.services, dropped);\n ui?.hide();\n emit({ ...next, action });\n log(action, next);\n if (dropped.length > 0 && options.reloadOnWithdraw) reload();\n }\n\n function applyChoices(c: ConsentChoices) {\n safe(() => mode?.update(c), undefined);\n if (doc) activateScripts(doc, c);\n }\n\n function reload() {\n setTimeout(() => safe(() => win?.location.reload(), undefined), 50);\n }\n\n function ensureUI(): ConsentUI | null {\n if (!doc || !loaded || destroyed) return null;\n if (!ui) {\n const locale = resolveLocale(options.locale, win?.navigator?.language);\n ui = createUI({\n doc,\n config,\n locale,\n texts: localTexts(mergeTexts(locale, config.texts)),\n getChoices: () => state?.c ?? null,\n hasChoice: () => state !== null,\n onAcceptAll: () => commit(enabled({ analytics: true, marketing: true, preferences: true }), \"accept_all\"),\n onRejectAll: () => commit(none(), \"reject_all\"),\n onSave: (choices) => commit(enabled(choices), \"custom\"),\n });\n }\n return ui;\n }\n\n /** `data-title` / `data-description` win over the remote and default texts. */\n function localTexts(texts: ConsentTexts): ConsentTexts {\n const title = options.title?.trim();\n const description = options.description?.trim();\n return { ...texts, ...(title && { title }), ...(description && { description }) };\n }\n\n function onClick(event: Event) {\n const target = event.target as Element | null;\n if (target?.closest?.(\"[data-bitsnap-consent-open]\")) {\n event.preventDefault();\n api.open();\n }\n }\n\n const ready: Promise<ConsentState | null> = (async () => {\n if (!doc || !win) return null;\n const remote = projectKey && !preview ? await fetchRemoteConfig(apiHost, projectKey) : null;\n if (destroyed) return null;\n const categories = remote?.config ? undefined : options.categories;\n config = mergeConfig(\n remote?.config,\n categories ? { categories: { ...none(), ...categories } } : undefined,\n localLayer(),\n );\n if (doc.readyState === \"loading\") {\n await new Promise<void>((resolve) => doc.addEventListener(\"DOMContentLoaded\", () => resolve(), { once: true }));\n }\n if (destroyed) return null;\n loaded = true;\n doc.addEventListener(\"click\", onClick);\n removeOpenListener = () => doc.removeEventListener(\"click\", onClick);\n\n // A project whose config could not be loaded has an unknown banner version: keep the\n // stored choice instead of asking again on every network failure.\n const versionKnown = !projectKey || remote?.config != null;\n const bannerOff = remote?.enabled === false;\n if (preview) {\n ensureUI()?.showBanner();\n } else if (initial && (bannerOff || !versionKnown || initial.bv === config.version)) {\n state = initial;\n applyChoices(enabled(state.c));\n } else {\n if (initial) stale = initial;\n // A disabled banner is never shown, but the API (open, accept, ...) keeps working.\n if (!bannerOff) ensureUI()?.showBanner();\n }\n // A tracker that waits on `ready` has to see the final state, rejection included.\n pending.splice(0).forEach((fn) => safe(fn, undefined));\n safe(() => win.dispatchEvent(new win.CustomEvent(\"bitsnap:consent:ready\")), undefined);\n return copy(state);\n })().catch(() => null);\n\n function afterReady(fn: () => void) {\n if (loaded) fn();\n else pending.push(fn);\n }\n\n const api: BitsnapConsentApi = {\n // Same rule as `cookieName`: a project scope needs a valid key.\n scope: options.scope === \"project\" && projectKey ? \"project\" : \"global\",\n projectKey,\n get: () => copy(state),\n // A choice made on an older banner version has no `get()`, but a refusal in it still holds.\n denied: (category) => (state ?? stale)?.c[category] === false,\n on(event, fn) {\n if (event !== \"change\" || typeof fn !== \"function\") return () => {};\n listeners.add(fn);\n return () => void listeners.delete(fn);\n },\n open() {\n if (loaded) ensureUI()?.showSettings();\n else void ready.then(() => ensureUI()?.showSettings());\n },\n close() {\n ui?.hide();\n },\n // Called before `ready`, a choice waits for the merged config so it is stored with the right\n // banner version and only for categories on offer.\n accept: (categories) => afterReady(() => commit(enabled(categories), \"custom\")),\n acceptAll: () =>\n afterReady(() => commit(enabled({ analytics: true, marketing: true, preferences: true }), \"accept_all\")),\n rejectAll: () => afterReady(() => commit(none(), \"reject_all\")),\n reset() {\n if (!doc || destroyed) return;\n if (preview) {\n ensureUI()?.showBanner();\n return;\n }\n const previous = state ?? stale;\n const was = previous ? granted(previous.c) : [];\n clearConsent(doc, name);\n state = null;\n stale = previous;\n safe(() => mode?.update(none()), undefined);\n if (was.length > 0) deleteServiceCookies(doc, config.services, was);\n emit({\n id: previous?.id ?? \"\",\n ts: Math.floor(Date.now() / 1000),\n bv: config.version,\n c: none(),\n action: \"reset\",\n });\n if (previous && was.length > 0) {\n log(\"withdraw\", { id: previous.id, ts: Math.floor(Date.now() / 1000), bv: config.version, c: none() });\n }\n ensureUI()?.showBanner(true);\n if (was.length > 0 && options.reloadOnWithdraw) reload();\n },\n ready,\n destroy() {\n destroyed = true;\n removeOpenListener?.();\n ui?.destroy();\n ui = null;\n listeners.clear();\n },\n };\n\n return wrapSafe(api);\n}\n\n/** Every method of the public API swallows its own errors. */\nfunction wrapSafe(api: BitsnapConsentApi): BitsnapConsentApi {\n const wrapped = { ...api } as Record<string, unknown>;\n for (const key of Object.keys(api) as (keyof BitsnapConsentApi)[]) {\n const original = api[key];\n if (typeof original === \"function\") {\n wrapped[key] = (...args: unknown[]) => {\n try {\n return (original as (...a: unknown[]) => unknown)(...args);\n } catch {\n return key === \"get\" ? null : key === \"on\" ? () => {} : undefined;\n }\n };\n }\n }\n return wrapped as BitsnapConsentApi;\n}\n"],"mappings":"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","names":["useCallback","useRef","useSyncExternalStore","CONSENT_CATEGORIES","SCRIPT_SELECTOR","FRAME_SELECTOR","allowed","c","category","CONSENT_CATEGORIES","settled","script","resolve","run","doc","placeholder","name","value","external","loaded","activateScripts","activated","gate","loading","inline","frame","src","DEFAULT_API_HOST","DEFAULT_COLLECT_HOST","defaultConfig","THEMES","POSITIONS","HEX_COLOR","safeColor","value","safeUrl","url","cleanServices","services","item","CONSENT_CATEGORIES","cookie","mergeConfig","layers","result","layer","accent","privacy","category","fetchRemoteConfig","apiHost","key","timeoutMs","controller","timer","response","body","config","enabled","GCM_DEFAULT","grant","value","toConsentModeUpdate","c","shouldUseConsentMode","win","mode","ensureGtag","layer","gtag","createConsentMode","DEFAULT_TEXTS","UI_LABELS","resolveLocale","preference","navigatorLanguage","mergeTexts","locale","overrides","merged","own","key","value","parse","hex","h","n","luminance","r","g","b","v","contrastRatio","a","hi","lo","x","y","onColor","background","PALETTE","vars","p","STYLES","WORDMARK","CLOSE_ICON","FOCUSABLE","createUI","options","doc","config","texts","locale","labels","UI_LABELS","host","shadow","root","banner","overlay","dialog","settingsButton","layer","opener","media","toggles","el","tag","props","children","node","key","child","button","cls","text","onClick","powered","link","description","buildBanner","showSettings","category","id","services","service","input","s","buildSettings","close","closeSettings","body","CONSENT_CATEGORIES","readToggles","event","choices","applyTheme","dark","applyAccent","accent","contrastRatio","PALETTE","name","onColor","ensure","STYLES","focusables","onKeydown","items","active","first","last","outside","showBanner","focus","current","hide","wasSettings","destroy","none","copy","state","createConsent","options","win","doc","listeners","apiHost","DEFAULT_API_HOST","collectHost","DEFAULT_COLLECT_HOST","projectKey","normalizeProjectKey","name","cookieName","preview","config","mergeConfig","localLayer","stale","ui","loaded","destroyed","removeOpenListener","pending","mode","safe","createConsentMode","initial","readConsent","extra","own","fn","fallback","enabled","choices","result","category","CONSENT_CATEGORIES","emit","detail","log","action","record","body","granted","c","commit","requested","previous","dropped","next","newConsentId","writeConsent","applyChoices","deleteServiceCookies","reload","activateScripts","ensureUI","locale","resolveLocale","createUI","localTexts","mergeTexts","texts","title","description","onClick","event","api","ready","remote","fetchRemoteConfig","categories","resolve","versionKnown","bannerOff","afterReady","was","clearConsent","wrapSafe","wrapped","key","original","args","BitsnapConsent","props","projectKey","theme","locale","position","privacyPolicyUrl","scope","apiHost","collectHost","reloadOnWithdraw","gcm","preview","title","description","configKey","configRef","useRef","categoriesKey","categoriesRef","useIsomorphicLayoutEffect","api","createConsent","lastKey","lastState","getSnapshot","current","key","subscribe","onChange","useConsent","consent","useSyncExternalStore","open","useCallback","accept","categories","acceptAll","rejectAll","reset"]}
package/dist/course.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { A as AnalyticsOption } from './instrument-C_abZLHk.mjs';
3
- import { G as GetThemeOutput } from './types-D_WnqwR_.mjs';
2
+ import { A as AnalyticsOption } from './instrument-CmxK7S4T.mjs';
3
+ import { G as GetThemeOutput } from './types-BnVWLcoB.mjs';
4
4
  import { Client } from '@connectrpc/connect';
5
5
  import { GenService, GenMessage } from '@bufbuild/protobuf/codegenv2';
6
6
  import { Timestamp } from '@bufbuild/protobuf/wkt';
package/dist/course.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { A as AnalyticsOption } from './instrument-C_abZLHk.js';
3
- import { G as GetThemeOutput } from './types-BaqLJYuq.js';
2
+ import { A as AnalyticsOption } from './instrument-CmxK7S4T.js';
3
+ import { G as GetThemeOutput } from './types-i-IuN4Im.js';
4
4
  import { Client } from '@connectrpc/connect';
5
5
  import { GenService, GenMessage } from '@bufbuild/protobuf/codegenv2';
6
6
  import { Timestamp } from '@bufbuild/protobuf/wkt';