bitsnap-react 1.7.1 → 1.9.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 (112) hide show
  1. package/README.md +130 -0
  2. package/dist/CartProvider-XWTLBIZ5.js +2 -0
  3. package/dist/CartProvider-XWTLBIZ5.js.map +1 -0
  4. package/dist/CartProvider-ZURLJNBW.mjs +2 -0
  5. package/dist/analytics.d.mts +28 -0
  6. package/dist/analytics.d.ts +28 -0
  7. package/dist/analytics.js +2 -0
  8. package/dist/analytics.js.map +1 -0
  9. package/dist/analytics.mjs +2 -0
  10. package/dist/catalog.d.mts +14 -1
  11. package/dist/catalog.d.ts +14 -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-3IMJALBX.js +2 -0
  16. package/dist/chunk-3IMJALBX.js.map +1 -0
  17. package/dist/chunk-3UHPJ6NK.js +2 -0
  18. package/dist/chunk-3UHPJ6NK.js.map +1 -0
  19. package/dist/chunk-CO2P4FR5.js +2 -0
  20. package/dist/chunk-CO2P4FR5.js.map +1 -0
  21. package/dist/chunk-E6QVQEGZ.mjs +2 -0
  22. package/dist/chunk-E6QVQEGZ.mjs.map +1 -0
  23. package/dist/chunk-FHDFLSPW.js +2 -0
  24. package/dist/chunk-FHDFLSPW.js.map +1 -0
  25. package/dist/{chunk-6KQBDN7M.mjs → chunk-GN63ITLA.mjs} +2 -2
  26. package/dist/chunk-HKVMSMDF.mjs +2 -0
  27. package/dist/chunk-HKVMSMDF.mjs.map +1 -0
  28. package/dist/chunk-JSDGZ4NY.js +2 -0
  29. package/dist/chunk-JSDGZ4NY.js.map +1 -0
  30. package/dist/chunk-KG6RU37U.js +4 -0
  31. package/dist/chunk-KG6RU37U.js.map +1 -0
  32. package/dist/chunk-KOVKUJAW.mjs +2 -0
  33. package/dist/chunk-KOVKUJAW.mjs.map +1 -0
  34. package/dist/chunk-KOYBZORL.js +2 -0
  35. package/dist/chunk-KOYBZORL.js.map +1 -0
  36. package/dist/chunk-LJWS6ZRJ.mjs +2 -0
  37. package/dist/chunk-LJWS6ZRJ.mjs.map +1 -0
  38. package/dist/chunk-LZE2E4TE.mjs +4 -0
  39. package/dist/chunk-LZE2E4TE.mjs.map +1 -0
  40. package/dist/chunk-QZJGNLCZ.js +2 -0
  41. package/dist/chunk-QZJGNLCZ.js.map +1 -0
  42. package/dist/chunk-RA452LXZ.mjs +2 -0
  43. package/dist/chunk-RA452LXZ.mjs.map +1 -0
  44. package/dist/chunk-SLLBTQTW.mjs +2 -0
  45. package/dist/chunk-SLLBTQTW.mjs.map +1 -0
  46. package/dist/chunk-SZ256RCC.mjs +2 -0
  47. package/dist/chunk-SZ256RCC.mjs.map +1 -0
  48. package/dist/chunk-V4U2PTKN.js +2 -0
  49. package/dist/chunk-V4U2PTKN.js.map +1 -0
  50. package/dist/chunk-VM6JEJFZ.js +2 -0
  51. package/dist/chunk-VM6JEJFZ.js.map +1 -0
  52. package/dist/chunk-VXB7LA4E.js +2 -0
  53. package/dist/chunk-VXB7LA4E.js.map +1 -0
  54. package/dist/chunk-XVQKEGPO.mjs +2 -0
  55. package/dist/chunk-XVQKEGPO.mjs.map +1 -0
  56. package/dist/consent.d.mts +158 -0
  57. package/dist/consent.d.ts +158 -0
  58. package/dist/consent.js +75 -0
  59. package/dist/consent.js.map +1 -0
  60. package/dist/consent.mjs +75 -0
  61. package/dist/consent.mjs.map +1 -0
  62. package/dist/course.d.mts +1882 -0
  63. package/dist/course.d.ts +1882 -0
  64. package/dist/course.js +2 -0
  65. package/dist/course.js.map +1 -0
  66. package/dist/course.mjs +2 -0
  67. package/dist/course.mjs.map +1 -0
  68. package/dist/embed/analytics.js +1 -0
  69. package/dist/embed/consent.js +74 -0
  70. package/dist/errors.js +1 -1
  71. package/dist/errors.js.map +1 -1
  72. package/dist/index.css +1 -1
  73. package/dist/index.css.map +1 -1
  74. package/dist/index.d.mts +56 -40
  75. package/dist/index.d.ts +56 -40
  76. package/dist/index.js +1 -3
  77. package/dist/index.js.map +1 -1
  78. package/dist/index.mjs +1 -1
  79. package/dist/index.mjs.map +1 -1
  80. package/dist/instrument-C_abZLHk.d.mts +912 -0
  81. package/dist/instrument-C_abZLHk.d.ts +912 -0
  82. package/dist/internal.js +1 -1
  83. package/dist/internal.js.map +1 -1
  84. package/dist/methods-CYARZTYL.mjs +2 -0
  85. package/dist/methods-CYARZTYL.mjs.map +1 -0
  86. package/dist/methods-DAPEWVI6.js +2 -0
  87. package/dist/methods-DAPEWVI6.js.map +1 -0
  88. package/dist/models.js +1 -1
  89. package/dist/models.js.map +1 -1
  90. package/dist/returns.d.mts +14 -196
  91. package/dist/returns.d.ts +14 -196
  92. package/dist/returns.js +1 -1
  93. package/dist/returns.js.map +1 -1
  94. package/dist/returns.mjs +1 -1
  95. package/dist/texts-CIEFbJTN.d.ts +196 -0
  96. package/dist/texts-tQtAGJCT.d.mts +196 -0
  97. package/dist/types-BaqLJYuq.d.ts +53 -0
  98. package/dist/types-D_WnqwR_.d.mts +53 -0
  99. package/package.json +41 -5
  100. package/dist/CartProvider-F2VH7WFO.mjs +0 -2
  101. package/dist/chunk-3TENJTY4.mjs +0 -2
  102. package/dist/chunk-3TENJTY4.mjs.map +0 -1
  103. package/dist/chunk-4HOZFM6V.mjs +0 -2
  104. package/dist/chunk-4HOZFM6V.mjs.map +0 -1
  105. package/dist/chunk-FTYJTO6O.mjs +0 -2
  106. package/dist/chunk-FTYJTO6O.mjs.map +0 -1
  107. package/dist/chunk-RATFYRKZ.mjs +0 -4
  108. package/dist/chunk-RATFYRKZ.mjs.map +0 -1
  109. package/dist/methods-PFZSMZFU.mjs +0 -2
  110. /package/dist/{CartProvider-F2VH7WFO.mjs.map → CartProvider-ZURLJNBW.mjs.map} +0 -0
  111. /package/dist/{methods-PFZSMZFU.mjs.map → analytics.mjs.map} +0 -0
  112. /package/dist/{chunk-6KQBDN7M.mjs.map → chunk-GN63ITLA.mjs.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts","../src/analytics/core.ts","../src/analytics/react.tsx","../src/analytics/instrument.ts"],"sourcesContent":["// Generated by scripts/write-version.mjs from package.json. Do not edit.\nexport const SDK_VERSION = \"1.9.0\";\n","import {\n LIMITS,\n PAGE_TYPES,\n SCHEMA_VERSION,\n normalizeProjectKey,\n parseUrl,\n referrerHost,\n sanitizeProps,\n sanitizePath,\n validateEnvelope,\n type AppEventName,\n type Channel,\n type ClientEvent,\n type Env,\n type EventProps,\n type PageType,\n type Source,\n type StorefrontEventName,\n} from \"./contract\";\nimport { SDK_VERSION } from \"../version\";\n\n/** Events a browser may send. `consent_updated` is written by the consent log only. */\nexport type BrowserEventName = Exclude<StorefrontEventName, \"consent_updated\"> | AppEventName;\n\nexport type TrackerOptions = {\n /** Public project key (the hashed project id). `pk_` prefix is accepted. */\n projectKey: string;\n /** Defaults to `live`, or `test` when the page URL has the `?test=` test-mode parameter. */\n env?: Env;\n /** Collector origin. Default `https://collect.bitsnap.pl`. */\n endpoint?: string;\n /** `false` turns tracking off. Default `true`. */\n enabled?: boolean;\n /** Default `embed`. */\n channel?: Channel;\n /** Default `sdk_react`. */\n source?: Source;\n /** Only honoured by the collector for `source: \"dashboard\"` (hashed user id). */\n visitorId?: string;\n /** Receives every valid envelope before it is queued, e.g. to forward it to the merchant's own tools. */\n onEvent?: (event: ClientEvent) => void;\n /** `console.warn` dropped events. */\n debug?: boolean;\n};\n\n/** Envelope fields a call site may set per event. */\nexport type TrackExtra = {\n page_type?: PageType | null;\n product_id?: string | null;\n variant_id?: string | null;\n order_ref?: string | null;\n /** Route template for pages whose URL path is not the path to report (the dashboard). */\n path?: string;\n /**\n * Deterministic UUIDv7 for events another system reports too (e.g. hosted\n * `payment_returned`), so the collector dedupes them. An invalid value is\n * ignored and a fresh id is used.\n */\n event_id?: string;\n};\n\nexport interface Tracker {\n track<E extends BrowserEventName>(event: E, props: EventProps<E>, extra?: TrackExtra): void;\n /** Sends `page_view` and makes `pageType` the page type of the following events. */\n page(pageType?: PageType | null, extra?: TrackExtra): void;\n /** Sends the queue now. */\n flush(): void;\n setEnabled(enabled: boolean): void;\n /** Returns an unsubscribe function. */\n onEvent(fn: (event: ClientEvent) => void): () => void;\n /** Updates `env` and `endpoint` of a running tracker. Other options are fixed at creation. */\n configure(patch: { env?: Env; endpoint?: string }): void;\n /** Removes the page listeners and drops the queue. */\n destroy(): void;\n}\n\n/** The part of `window.BitsnapConsent` (`bitsnap-react/consent`) the tracker reads. */\ntype ConsentLike = {\n get(): { c: { analytics?: boolean } } | null;\n /** Also true for a refusal made on an older banner version, which `get()` no longer returns. */\n denied?(category: \"analytics\"): boolean;\n ready?: Promise<unknown>;\n};\n\nexport const DEFAULT_ENDPOINT = \"https://collect.bitsnap.pl\";\n\nconst FLUSH_INTERVAL_MS = 5000;\nconst FLUSH_AT = 20;\n// Half the collector's 64 KB body limit, measured in UTF-8 bytes of the whole body.\nconst MAX_BODY_BYTES = 32 * 1024;\n// Browsers share ~64 KB of in-flight keepalive requests; stay under it on pagehide.\nconst KEEPALIVE_BUDGET_BYTES = 60 * 1024;\nconst EVENT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n\nfunction byteLength(text: string): number {\n if (typeof TextEncoder === \"function\") return new TextEncoder().encode(text).length;\n return unescape(encodeURIComponent(text)).length;\n}\n\nexport const noopTracker: Tracker = {\n track() {},\n page() {},\n flush() {},\n setEnabled() {},\n onEvent: () => () => {},\n configure() {},\n destroy() {},\n};\n\nfunction randomBytes(n: number): Uint8Array {\n const bytes = new Uint8Array(n);\n const c = typeof crypto !== \"undefined\" ? crypto : undefined;\n if (c && typeof c.getRandomValues === \"function\") c.getRandomValues(bytes);\n else for (let i = 0; i < n; i++) bytes[i] = Math.floor(Math.random() * 256);\n return bytes;\n}\n\n/** UUIDv7: 48-bit unix ms, version 7, variant 10, 74 random bits. */\nexport function uuidv7(now = Date.now()): string {\n const b = randomBytes(16);\n let t = now;\n for (let i = 5; i >= 0; i--) {\n b[i] = t % 256;\n t = Math.floor(t / 256);\n }\n b[6] = (b[6] & 0x0f) | 0x70;\n b[8] = (b[8] & 0x3f) | 0x80;\n const hex = Array.from(b, (x) => x.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nconst PAGE_ID_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n\nfunction newPageId(): string {\n return Array.from(randomBytes(16), (x) => PAGE_ID_ALPHABET[x % PAGE_ID_ALPHABET.length]).join(\"\");\n}\n\nexport function isPageType(value: unknown): value is PageType {\n return typeof value === \"string\" && (PAGE_TYPES as readonly string[]).includes(value);\n}\n\nexport type PackedBody = { body: string; bytes: number; count: number };\n\n/**\n * Splits events into `POST /e` bodies of at most `MAX_BODY_BYTES` UTF-8 bytes\n * (wrapper included) and `maxBatchEvents` events. With `leaving` (pagehide)\n * only the newest bodies that fit the shared keepalive quota are kept.\n */\nexport function packEvents(projectKey: string, events: ClientEvent[], leaving = false): PackedBody[] {\n const wrapper = byteLength(JSON.stringify({ k: projectKey, events: [] }));\n let bodies: PackedBody[] = [];\n let batch: ClientEvent[] = [];\n let size = wrapper;\n const close = () => {\n if (batch.length > 0) bodies.push({ body: JSON.stringify({ k: projectKey, events: batch }), bytes: size, count: batch.length });\n batch = [];\n size = wrapper;\n };\n for (const event of events) {\n const own = byteLength(JSON.stringify(event));\n if (wrapper + own > MAX_BODY_BYTES) continue; // a single event that can never fit\n // +1 for the comma that joins it to the previous event.\n if (batch.length >= LIMITS.maxBatchEvents || size + own + (batch.length > 0 ? 1 : 0) > MAX_BODY_BYTES) close();\n size += own + (batch.length > 0 ? 1 : 0);\n batch.push(event);\n }\n close();\n if (leaving) {\n let total = 0;\n let keep = bodies.length;\n while (keep > 0 && total + bodies[keep - 1].bytes <= KEEPALIVE_BUDGET_BYTES) {\n total += bodies[keep - 1].bytes;\n keep--;\n }\n bodies = bodies.slice(keep);\n }\n return bodies;\n}\n\n/**\n * Cookieless, in-memory event tracker. It never throws into the host page and\n * never touches cookies or Web Storage. On the server it returns a no-op.\n */\nexport function createTracker(options: TrackerOptions): Tracker {\n try {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") return noopTracker;\n return build(options, window);\n } catch {\n return noopTracker;\n }\n}\n\nfunction build(options: TrackerOptions, win: Window & typeof globalThis): Tracker {\n const projectKey = normalizeProjectKey(options.projectKey ?? \"\");\n const debug = !!options.debug;\n const warn = (...args: unknown[]) => {\n if (debug) console.warn(\"[bitsnap analytics]\", ...args);\n };\n if (!projectKey) {\n warn(\"invalid projectKey, tracking is off\");\n return noopTracker;\n }\n const key: string = projectKey;\n\n const endpointUrl = (endpoint: string | undefined) => `${(endpoint || DEFAULT_ENDPOINT).replace(/\\/+$/, \"\")}/e`;\n let url = endpointUrl(options.endpoint);\n const source = options.source ?? \"sdk_react\";\n const channel = options.channel ?? \"embed\";\n const sdk = `bitsnap-react@${SDK_VERSION}`;\n const pageId = newPageId();\n const landing = parseUrl(win.location.href);\n let env: Env = options.env ?? \"live\";\n if (!options.env) {\n try {\n if (new URLSearchParams(win.location.search).has(\"test\")) env = \"test\";\n } catch {}\n }\n const refHost = referrerHost(document.referrer);\n\n let enabled = options.enabled !== false;\n let pageType: PageType | null = null;\n let pageViews = 0;\n let queue: ClientEvent[] = [];\n let timer: ReturnType<typeof setTimeout> | null = null;\n const listeners = new Set<(event: ClientEvent) => void>();\n if (options.onEvent) listeners.add(options.onEvent);\n /** Events the listeners have not seen yet because consent was still loading. */\n let held: ClientEvent[] = [];\n\n // -- consent: respect a rejection, wait for the stored choice to load -----\n\n let attached: ConsentLike | undefined;\n let consentReady = true;\n\n function attachConsent() {\n const api = (win as unknown as { BitsnapConsent?: ConsentLike }).BitsnapConsent;\n if (!api || api === attached) return;\n attached = api;\n consentReady = !api.ready;\n api.ready?.then(\n () => {\n if (attached !== api) return;\n consentReady = true;\n afterConsentChange();\n },\n () => {\n if (attached === api) consentReady = true;\n },\n );\n }\n\n function consentDenied(): boolean {\n attachConsent();\n try {\n if (!attached) return false;\n const state = attached.get();\n return (!!attached.denied && attached.denied(\"analytics\")) || (!!state && state.c.analytics === false);\n } catch {\n return false;\n }\n }\n\n function notify(event: ClientEvent) {\n listeners.forEach((fn) => {\n try {\n fn(event);\n } catch {}\n });\n }\n\n function afterConsentChange() {\n if (consentDenied()) {\n queue = [];\n held = [];\n clearTimer();\n } else {\n if (consentReady && held.length > 0) {\n const release = held;\n held = [];\n release.forEach(notify);\n }\n if (queue.length > 0) flush();\n }\n }\n\n // -- state ----------------------------------------------------------------\n\n function active(): boolean {\n if (!enabled) return false;\n const nav = win.navigator;\n if (nav && ((nav as { globalPrivacyControl?: boolean }).globalPrivacyControl === true || nav.webdriver === true)) {\n return false;\n }\n return !consentDenied();\n }\n\n function clearTimer() {\n if (timer !== null) clearTimeout(timer);\n timer = null;\n }\n\n function schedule() {\n if (timer !== null) return;\n timer = setTimeout(() => {\n timer = null;\n flush();\n }, FLUSH_INTERVAL_MS);\n (timer as { unref?: () => void }).unref?.();\n }\n\n // -- sending --------------------------------------------------------------\n\n function send(body: string) {\n // fetch keepalive first (no size cap below the shared quota); sendBeacon only as a fallback.\n try {\n if (typeof fetch === \"function\") {\n fetch(url, {\n method: \"POST\",\n body,\n keepalive: true,\n credentials: \"omit\",\n headers: { \"Content-Type\": \"text/plain\" },\n }).catch(() => {});\n return;\n }\n } catch {}\n try {\n const nav = win.navigator;\n if (nav && typeof nav.sendBeacon === \"function\") {\n nav.sendBeacon(url, new Blob([body], { type: \"text/plain\" }));\n }\n } catch {}\n }\n\n function flush(leaving = false) {\n try {\n clearTimer();\n if (queue.length === 0) return;\n if (!active()) {\n queue = [];\n return;\n }\n // Hold events until Bitsnap Consent has loaded the stored choice.\n if (!consentReady) return;\n const pending = queue;\n queue = [];\n packEvents(key, pending, leaving).forEach((entry) => send(entry.body));\n } catch {}\n }\n\n // -- building -------------------------------------------------------------\n\n function emit(name: string, props: unknown, extra: TrackExtra | undefined) {\n if (!active()) return;\n const cleaned = sanitizeProps(name, props);\n if (!cleaned.ok) {\n warn(\"dropped\", name, cleaned.reason);\n return;\n }\n const here = parseUrl(win.location.href);\n const event: Record<string, unknown> = {\n event_id: extra?.event_id && EVENT_ID_RE.test(extra.event_id) ? extra.event_id : uuidv7(),\n event: name,\n ts: Date.now(),\n schema_version: SCHEMA_VERSION,\n env,\n source,\n channel,\n sdk,\n page_id: pageId,\n page_type: extra?.page_type !== undefined ? extra.page_type : pageType,\n host: here?.host ?? null,\n path: extra?.path ? sanitizePath(extra.path.split(/[?#]/)[0]) : (here?.path ?? null),\n referrer_host: refHost,\n utm_source: landing?.utm_source ?? null,\n utm_medium: landing?.utm_medium ?? null,\n utm_campaign: landing?.utm_campaign ?? null,\n utm_content: landing?.utm_content ?? null,\n utm_term: landing?.utm_term ?? null,\n ref_code: landing?.ref_code ?? null,\n product_id: extra?.product_id ?? null,\n variant_id: extra?.variant_id ?? null,\n order_ref: extra?.order_ref ?? null,\n props: cleaned.props,\n };\n if (extra?.event_id && !EVENT_ID_RE.test(extra.event_id)) warn(\"ignored invalid event_id\", name);\n if (source === \"dashboard\" && options.visitorId) event.visitor_id = options.visitorId;\n\n const verdict = validateEnvelope(event);\n if (!verdict.ok) {\n warn(\"dropped\", name, verdict.reason);\n return;\n }\n const valid = event as unknown as ClientEvent;\n // Listeners (the merchant's own tools) only see events once consent is known and not denied.\n if (consentReady) notify(valid);\n else held.push(valid);\n queue.push(valid);\n if (queue.length >= FLUSH_AT) flush();\n else schedule();\n }\n\n // -- page lifecycle -------------------------------------------------------\n\n const onHide = () => flush(true);\n const onVisibility = () => {\n if (document.visibilityState === \"hidden\") flush(true);\n };\n const onConsent = () => afterConsentChange();\n win.addEventListener(\"pagehide\", onHide);\n document.addEventListener(\"visibilitychange\", onVisibility);\n win.addEventListener(\"bitsnap:consent\", onConsent);\n win.addEventListener(\"bitsnap:consent:ready\", onConsent);\n attachConsent();\n\n return {\n track(event, props, extra) {\n try {\n emit(event, props, extra);\n } catch {}\n },\n page(type, extra) {\n try {\n if (type !== undefined) pageType = type;\n emit(\"page_view\", { landing: pageViews++ === 0 }, extra);\n } catch {}\n },\n flush: () => flush(),\n setEnabled(value) {\n enabled = !!value;\n if (!enabled) {\n queue = [];\n held = [];\n clearTimer();\n }\n },\n configure(patch) {\n try {\n if (patch.env === \"live\" || patch.env === \"test\") env = patch.env;\n if (typeof patch.endpoint === \"string\" && patch.endpoint) url = endpointUrl(patch.endpoint);\n } catch {}\n },\n onEvent(fn) {\n listeners.add(fn);\n return () => void listeners.delete(fn);\n },\n destroy() {\n queue = [];\n held = [];\n clearTimer();\n listeners.clear();\n win.removeEventListener(\"pagehide\", onHide);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n win.removeEventListener(\"bitsnap:consent\", onConsent);\n win.removeEventListener(\"bitsnap:consent:ready\", onConsent);\n },\n };\n}\n\n// -- singleton ----------------------------------------------------------------\n\nlet instance: Tracker | undefined;\nlet instanceKey: string | null = null;\n\n/**\n * Creates the page's tracker on the first call and returns that same tracker\n * afterwards. A later call with another `projectKey` is ignored (warns in\n * debug mode); a later call with `env`, `endpoint` or `enabled` updates the\n * running tracker. A malformed key is not remembered, so a later valid call still works.\n */\nexport function initTracker(options: TrackerOptions): Tracker {\n if (!instance) {\n const created = createTracker(options);\n if (created === noopTracker) return created;\n instance = created;\n instanceKey = normalizeProjectKey(options.projectKey ?? \"\");\n return created;\n }\n try {\n const key = normalizeProjectKey(options.projectKey ?? \"\");\n if (key !== instanceKey && options.debug) {\n console.warn(\"[bitsnap analytics]\", \"tracker already started for another projectKey, ignoring\", options.projectKey);\n }\n if (key === instanceKey) {\n if (options.env || options.endpoint) instance.configure({ env: options.env, endpoint: options.endpoint });\n if (options.enabled != null) instance.setEnabled(options.enabled);\n }\n } catch {}\n return instance;\n}\n\n/** The tracker made by `initTracker`, if any. */\nexport function getTracker(): Tracker | undefined {\n return instance;\n}\n\n/** Destroys the singleton so that `initTracker` can build a fresh one (tests, hot reload). */\nexport function resetTracker() {\n instance?.destroy();\n instance = undefined;\n instanceKey = null;\n}\n","import { createContext, createElement, useContext, useMemo, useRef, type ReactNode } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"../lib/isomorphic-layout-effect\";\nimport { initTracker, noopTracker, type Tracker, type TrackerOptions } from \"./core\";\nimport type { ClientEvent } from \"./contract\";\n\nexport type AnalyticsApi = Pick<Tracker, \"track\" | \"page\">;\n\nconst noop: AnalyticsApi = { track: noopTracker.track, page: noopTracker.page };\n\nconst AnalyticsContext = createContext<AnalyticsApi>(noop);\n\nexport type BitsnapAnalyticsProviderProps = {\n /** Public project key (the `projectID` the rest of the SDK uses). */\n projectKey: string;\n env?: TrackerOptions[\"env\"];\n /** `false` turns tracking off. */\n enabled?: boolean;\n endpoint?: string;\n /** Called with every event before it is sent, e.g. to forward it to the merchant's own tools. */\n onEvent?: (event: ClientEvent) => void;\n children?: ReactNode;\n};\n\n/**\n * Starts the page's tracker and hands `track` and `page` to `useAnalytics()`.\n * The tracker is a per-page singleton: the first valid `projectKey` wins, but\n * `env`, `endpoint` and `enabled` of any provider update the running tracker.\n * Nothing is tracked on the server, and nothing is stored on the visitor's device.\n */\nexport function BitsnapAnalyticsProvider({\n projectKey,\n env,\n enabled,\n endpoint,\n onEvent,\n children,\n}: BitsnapAnalyticsProviderProps) {\n const tracker = useMemo(\n () => initTracker({ projectKey, env, endpoint, enabled }),\n // The tracker is a per-page singleton; `initTracker` applies env/endpoint/enabled changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [projectKey, env, endpoint],\n );\n const onEventRef = useRef(onEvent);\n onEventRef.current = onEvent;\n\n // Before the passive effects of the children, whose first events must already respect it.\n useIsomorphicLayoutEffect(() => {\n tracker.setEnabled(enabled !== false);\n }, [tracker, enabled]);\n\n // Layout effects run before the passive effects of the children, whose\n // first events (list viewed, cart opened) would otherwise be missed.\n useIsomorphicLayoutEffect(() => tracker.onEvent((event) => onEventRef.current?.(event)), [tracker]);\n\n const api = useMemo<AnalyticsApi>(\n () => ({ track: tracker.track.bind(tracker), page: tracker.page.bind(tracker) }),\n [tracker],\n );\n return createElement(AnalyticsContext.Provider, { value: api }, children);\n}\n\n/** `track` and `page`; no-ops outside a `<BitsnapAnalyticsProvider>`. */\nexport function useAnalytics(): AnalyticsApi {\n return useContext(AnalyticsContext);\n}\n","import { createContext, createElement, useContext, useEffect, useLayoutEffect, useMemo, useRef, type ReactNode } from \"react\";\nimport type { ClientEvent, Env, EventProps, PageType } from \"./contract\";\nimport { getTracker, initTracker, noopTracker, type BrowserEventName, type TrackExtra } from \"./core\";\nimport { useAnalytics, type AnalyticsApi } from \"./react\";\n\n/**\n * The `analytics` prop of every instrumented bitsnap-react component.\n * `true` (the default) tracks, `false` opts out, an object tracks and can\n * forward each event to the merchant's own tools.\n */\nexport type AnalyticsOption =\n | boolean\n | {\n /** Called with every event this component emits, after Bitsnap Consent allows analytics. */\n onEvent?: (event: ClientEvent) => void;\n /** `test` events are stored but never reach the merchant's stats. */\n env?: Env;\n };\n\n/** What the components call. It never throws and does nothing on the server. */\nexport interface Instrument {\n track<E extends BrowserEventName>(event: E, props: EventProps<E>, extra?: TrackExtra): void;\n}\n\nexport const noopInstrument: Instrument = { track() {} };\n\ntype Latest = {\n projectKey: string | null | undefined;\n analytics: AnalyticsOption | undefined;\n pageType: PageType | undefined;\n provided: AnalyticsApi | null;\n};\n\n/** The instrument whose `track` call is running; lets `onEvent` listeners tell their own events apart. */\nlet emitting: symbol | null = null;\n\nfunction createInstrument(read: () => Latest) {\n const id = Symbol(\"bitsnap-instrument\");\n\n function target(): Pick<AnalyticsApi, \"track\"> | null {\n if (typeof window === \"undefined\") return null;\n const { projectKey, analytics, provided } = read();\n if (analytics === false) return null;\n // A <BitsnapAnalyticsProvider> owns the tracker.\n if (provided) return provided;\n if (!projectKey) return null;\n return initTracker({\n projectKey,\n source: \"sdk_react\",\n channel: \"embed\",\n env: typeof analytics === \"object\" ? analytics.env : undefined,\n });\n }\n\n const instrument: Instrument = {\n track(event, props, extra) {\n try {\n const tracker = target();\n if (!tracker) return;\n const { analytics, pageType } = read();\n const withPage = pageType && extra?.page_type === undefined ? { ...extra, page_type: pageType } : extra;\n emitting = typeof analytics === \"object\" && analytics.onEvent ? id : null;\n tracker.track(event, props, withPage);\n } catch {\n // Analytics never breaks the host page.\n } finally {\n emitting = null;\n }\n },\n };\n\n /** Starts the tracker on mount and wires `onEvent`. Returns the cleanup. */\n function attach(): () => void {\n try {\n if (!target()) return () => {};\n const tracker = getTracker();\n if (!tracker) return () => {};\n return tracker.onEvent((event) => {\n if (emitting !== id) return;\n try {\n const { analytics } = read();\n if (typeof analytics === \"object\") analytics.onEvent?.(event);\n } catch {}\n });\n } catch {\n return () => {};\n }\n }\n\n return { instrument, attach };\n}\n\nconst InstrumentContext = createContext<Instrument | null>(null);\n\n/** Hands the instrument of a top-level component to the parts below it. */\nexport function InstrumentProvider({ value, children }: { value: Instrument; children?: ReactNode }) {\n return createElement(InstrumentContext.Provider, { value }, children);\n}\n\n/** The instrument of the closest instrumented ancestor, or a no-op. */\nexport function useInstrumentContext(): Instrument {\n return useContext(InstrumentContext) ?? noopInstrument;\n}\n\n/**\n * The instrument of a top-level component. `projectKey` is the public\n * project id the component already has. When `analytics` is not given and an\n * ancestor is instrumented, the ancestor's instrument is reused.\n */\nexport function useInstrument(\n projectKey: string | null | undefined,\n analytics?: AnalyticsOption,\n pageType?: PageType,\n): Instrument {\n const parent = useContext(InstrumentContext);\n const api = useAnalytics();\n const provided = api.track === noopTracker.track ? null : api;\n const latest = useRef<Latest>({ projectKey, analytics, pageType, provided });\n latest.current = { projectKey, analytics, pageType, provided };\n\n const own = useMemo(() => createInstrument(() => latest.current), []);\n const inherit = analytics === undefined && parent !== null;\n const hasListener = typeof analytics === \"object\" && !!analytics.onEvent;\n\n // A layout effect runs before the passive effects of the children, whose\n // first events (list viewed, cart opened) `onEvent` must not miss.\n useLayoutEffect(() => {\n if (inherit) return;\n return own.attach();\n }, [own, inherit, hasListener, projectKey]);\n\n return inherit ? parent : own.instrument;\n}\n\n// -- cart sink ---------------------------------------------------------------\n\nlet cartInstrument: Instrument = noopInstrument;\n\n/**\n * The instrument used for cart changes made outside of a component (the\n * `Bitsnap.addProductToCart` helper). `<BitsnapCheckout>` registers its own.\n */\nexport function setCartInstrument(instrument: Instrument | null) {\n cartInstrument = instrument ?? noopInstrument;\n}\n\nlet cartMuted = 0;\n\nexport function getCartInstrument(): Instrument {\n return cartMuted > 0 ? noopInstrument : cartInstrument;\n}\n\n/**\n * Runs `fn` with the cart sink muted, so a cart change made inside it (a custom\n * `onAddToCart` calling `Bitsnap.addProductToCart`) is not reported a second\n * time by the caller that reports it itself. Await the cart call inside `fn`.\n */\nexport async function withCartAnalyticsMuted<T>(fn: () => T | Promise<T>): Promise<T> {\n cartMuted++;\n try {\n return await fn();\n } finally {\n cartMuted--;\n }\n}\n\n/** Registers the instrument as the cart sink while the calling component is mounted. */\nexport function useCartInstrument(instrument: Instrument) {\n useEffect(() => {\n setCartInstrument(instrument);\n return () => {\n if (cartInstrument === instrument) setCartInstrument(null);\n };\n }, [instrument]);\n}\n\n// -- shared helpers ----------------------------------------------------------\n\n/** Score (0..100) → the contract's bucket. */\nexport function scoreBucket(percent: number): \"0-24\" | \"25-49\" | \"50-74\" | \"75-99\" | \"100\" {\n const value = Number.isFinite(percent) ? Math.max(0, Math.min(100, percent)) : 0;\n if (value >= 100) return \"100\";\n if (value >= 75) return \"75-99\";\n if (value >= 50) return \"50-74\";\n if (value >= 25) return \"25-49\";\n return \"0-24\";\n}\n\n/** Milestones (25/50/75/100) reached by `percent` that are not in `seen` yet. Adds them to `seen`. */\nexport function newMilestones(percent: number, seen: Set<number>): number[] {\n const reached: number[] = [];\n for (const milestone of [25, 50, 75, 100]) {\n if (percent >= milestone && !seen.has(milestone)) {\n seen.add(milestone);\n reached.push(milestone);\n }\n }\n return reached;\n}\n"],"mappings":"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","names":["SDK_VERSION","DEFAULT_ENDPOINT","FLUSH_INTERVAL_MS","FLUSH_AT","MAX_BODY_BYTES","KEEPALIVE_BUDGET_BYTES","EVENT_ID_RE","byteLength","text","noopTracker","randomBytes","n","bytes","c","i","uuidv7","now","b","t","hex","x","PAGE_ID_ALPHABET","newPageId","packEvents","projectKey","events","leaving","wrapper","byteLength","bodies","batch","size","close","event","own","MAX_BODY_BYTES","LIMITS","total","keep","KEEPALIVE_BUDGET_BYTES","createTracker","options","noopTracker","build","win","normalizeProjectKey","debug","warn","args","key","endpointUrl","endpoint","DEFAULT_ENDPOINT","url","source","channel","sdk","SDK_VERSION","pageId","newPageId","landing","parseUrl","env","refHost","referrerHost","enabled","pageType","pageViews","queue","timer","listeners","held","attached","consentReady","attachConsent","api","afterConsentChange","consentDenied","state","notify","fn","clearTimer","release","flush","active","nav","schedule","FLUSH_INTERVAL_MS","send","body","pending","entry","emit","name","props","extra","cleaned","sanitizeProps","here","EVENT_ID_RE","uuidv7","sanitizePath","verdict","validateEnvelope","valid","FLUSH_AT","onHide","onVisibility","onConsent","type","value","patch","instance","instanceKey","initTracker","created","getTracker","resetTracker","createContext","createElement","useContext","useMemo","useRef","noop","noopTracker","AnalyticsContext","createContext","BitsnapAnalyticsProvider","projectKey","env","enabled","endpoint","onEvent","children","tracker","useMemo","initTracker","onEventRef","useRef","useIsomorphicLayoutEffect","event","api","createElement","useAnalytics","useContext","createContext","createElement","useContext","useEffect","useLayoutEffect","useMemo","useRef","noopInstrument","emitting","createInstrument","read","id","target","projectKey","analytics","provided","initTracker","instrument","event","props","extra","tracker","pageType","withPage","attach","getTracker","InstrumentContext","createContext","InstrumentProvider","value","children","createElement","useInstrumentContext","useContext","useInstrument","parent","api","useAnalytics","noopTracker","latest","useRef","own","useMemo","inherit","hasListener","useLayoutEffect","cartInstrument","setCartInstrument","cartMuted","getCartInstrument","withCartAnalyticsMuted","fn","useCartInstrument","useEffect","scoreBucket","percent","newMilestones","seen","reached","milestone"]}
@@ -0,0 +1,158 @@
1
+ type ConsentCategory = "analytics" | "marketing" | "preferences";
2
+ type ConsentChoices = Record<ConsentCategory, boolean>;
3
+ type ConsentTheme = "auto" | "light" | "dark";
4
+ type ConsentPosition = "bottom" | "bottom-left" | "bottom-right";
5
+ type ConsentLocale = "pl" | "en";
6
+ declare const CONSENT_CATEGORIES: readonly ConsentCategory[];
7
+ declare const CONSENT_TEXT_KEYS: readonly ["title", "description", "acceptAll", "rejectAll", "settings", "save", "close", "necessaryTitle", "necessaryDescription", "analyticsTitle", "analyticsDescription", "marketingTitle", "marketingDescription", "preferencesTitle", "preferencesDescription", "poweredBy"];
8
+ type ConsentTexts = Record<(typeof CONSENT_TEXT_KEYS)[number], string>;
9
+ type ConsentService = {
10
+ name: string;
11
+ category: ConsentCategory;
12
+ /** Cookies to delete (best effort) when the category is withdrawn. A trailing `*` matches a prefix. */
13
+ cookies?: string[];
14
+ };
15
+ type ConsentConfig = {
16
+ /** Banner version. A stored choice with a lower `bv` makes the banner ask again. */
17
+ version: number;
18
+ theme: ConsentTheme;
19
+ accentColor?: string;
20
+ position: ConsentPosition;
21
+ privacyPolicyUrl?: string;
22
+ categories: ConsentChoices;
23
+ services: ConsentService[];
24
+ texts?: Partial<Record<ConsentLocale, Partial<ConsentTexts>>>;
25
+ poweredBy: true;
26
+ };
27
+ /** What the consent cookie holds, and what `get()` returns. */
28
+ type ConsentState = {
29
+ id: string;
30
+ /** Unix seconds. */
31
+ ts: number;
32
+ /** Version of the banner the choice was made on. */
33
+ bv: number;
34
+ c: ConsentChoices;
35
+ };
36
+ type ConsentAction = "accept_all" | "reject_all" | "custom" | "withdraw";
37
+ /** `detail` of `bitsnap:consent` and the argument of `on('change')`. */
38
+ type ConsentChangeDetail = ConsentState & {
39
+ /** `reset` when the visitor's stored choice was cleared (`get()` is `null` then). */
40
+ action: ConsentAction | "reset";
41
+ };
42
+ type ConsentOptions = {
43
+ /** Public project key. Enables the remote config and the consent log. */
44
+ projectKey?: string;
45
+ theme?: ConsentTheme;
46
+ locale?: "auto" | ConsentLocale;
47
+ position?: ConsentPosition;
48
+ privacyPolicyUrl?: string;
49
+ /** `project` keeps one cookie per project key (`bitsnap_consent_<key>`). */
50
+ scope?: "global" | "project";
51
+ apiHost?: string;
52
+ collectHost?: string;
53
+ /** Google Consent Mode v2. `auto` is on when `gtag` or `dataLayer` already exist. */
54
+ gcm?: "auto" | "on" | "off";
55
+ /** Local overrides, merged over the defaults and the remote config. */
56
+ config?: Partial<ConsentConfig>;
57
+ /** Categories used when no remote config is loaded. */
58
+ categories?: Partial<ConsentChoices>;
59
+ reloadOnWithdraw?: boolean;
60
+ /**
61
+ * Dashboard preview: shows the banner at once from the local options, never
62
+ * reads or writes the cookie, loads no remote config, sends no consent log,
63
+ * and the buttons only close the banner.
64
+ */
65
+ preview?: boolean;
66
+ /** Replaces the banner title (current locale, non-empty values only). */
67
+ title?: string;
68
+ /** Replaces the banner description (current locale, non-empty values only). */
69
+ description?: string;
70
+ };
71
+ type BitsnapConsentApi = {
72
+ get(): ConsentState | null;
73
+ /**
74
+ * `true` when the visitor refused `category`, also in a choice made on an older banner
75
+ * version (which `get()` no longer returns) that they have not answered again yet.
76
+ */
77
+ denied(category: ConsentCategory): boolean;
78
+ on(event: "change", fn: (detail: ConsentChangeDetail) => void): () => void;
79
+ open(): void;
80
+ close(): void;
81
+ accept(categories?: Partial<ConsentChoices>): void;
82
+ acceptAll(): void;
83
+ rejectAll(): void;
84
+ reset(): void;
85
+ /** Resolves with the stored choice (or `null`) once config and stored choice are applied. */
86
+ ready: Promise<ConsentState | null>;
87
+ destroy(): void;
88
+ };
89
+
90
+ declare global {
91
+ interface Window {
92
+ BitsnapConsent?: BitsnapConsentApi;
93
+ }
94
+ }
95
+ type BitsnapConsentProps = {
96
+ /** Public project key: loads the project's banner config and logs choices. */
97
+ projectKey?: string;
98
+ theme?: ConsentOptions["theme"];
99
+ locale?: ConsentOptions["locale"];
100
+ position?: ConsentOptions["position"];
101
+ privacyPolicyUrl?: string;
102
+ /** `project` keeps the consent cookie per project key. */
103
+ scope?: ConsentOptions["scope"];
104
+ apiHost?: string;
105
+ collectHost?: string;
106
+ /** Local config, merged over the project config. */
107
+ config?: Partial<ConsentConfig>;
108
+ reloadOnWithdraw?: boolean;
109
+ /** Google Consent Mode v2: `auto` (default) is on when `gtag` or `dataLayer` already exist. */
110
+ gcm?: ConsentOptions["gcm"];
111
+ /** Categories offered when no remote config is loaded. */
112
+ categories?: ConsentOptions["categories"];
113
+ /** Dashboard preview: shows the banner from the local options only; touches no cookie. */
114
+ preview?: boolean;
115
+ /** Replaces the banner title. */
116
+ title?: string;
117
+ /** Replaces the banner description. */
118
+ description?: string;
119
+ };
120
+ /** Mounts Bitsnap Consent on the page. Renders nothing itself (the banner lives in a Shadow DOM). */
121
+ declare function BitsnapConsent(props: BitsnapConsentProps): null;
122
+ type UseConsent = {
123
+ /** The stored choice, or `null` while there is none (or on the server). */
124
+ consent: ConsentState | null;
125
+ /** `true` once the visitor has made a choice that is still valid. */
126
+ decided: boolean;
127
+ open: () => void;
128
+ accept: (categories?: Partial<ConsentChoices>) => void;
129
+ acceptAll: () => void;
130
+ rejectAll: () => void;
131
+ reset: () => void;
132
+ };
133
+ /** Current consent state of the page, kept up to date as the visitor chooses. */
134
+ declare function useConsent(): UseConsent;
135
+
136
+ /** Sync `get()`-style API with no DOM until a layer is shown. Never throws into the page. */
137
+ declare function createConsent(options?: ConsentOptions): BitsnapConsentApi;
138
+
139
+ declare function defaultConfig(): ConsentConfig;
140
+ /** Layers partial configs (later wins) over the defaults, dropping invalid values. */
141
+ declare function mergeConfig(...layers: (Partial<ConsentConfig> | null | undefined)[]): ConsentConfig;
142
+
143
+ declare const DEFAULT_TEXTS: Record<ConsentLocale, ConsentTexts>;
144
+ declare function resolveLocale(preference: "auto" | ConsentLocale | undefined, navigatorLanguage?: string): ConsentLocale;
145
+ /** Built-in texts for the locale, with the (non-empty) overrides of the config on top. */
146
+ declare function mergeTexts(locale: ConsentLocale, overrides?: Partial<Record<ConsentLocale, Partial<ConsentTexts>>>): ConsentTexts;
147
+
148
+ /** analytics -> analytics_storage; marketing -> ad_*; preferences -> functionality/personalization. */
149
+ declare function toConsentModeUpdate(c: ConsentChoices): {
150
+ analytics_storage: string;
151
+ ad_storage: string;
152
+ ad_user_data: string;
153
+ ad_personalization: string;
154
+ functionality_storage: string;
155
+ personalization_storage: string;
156
+ };
157
+
158
+ export { BitsnapConsent, type BitsnapConsentApi, type BitsnapConsentProps, CONSENT_CATEGORIES, CONSENT_TEXT_KEYS, type ConsentAction, type ConsentCategory, type ConsentChangeDetail, type ConsentChoices, type ConsentConfig, type ConsentLocale, type ConsentOptions, type ConsentPosition, type ConsentService, type ConsentState, type ConsentTexts, type ConsentTheme, DEFAULT_TEXTS, type UseConsent, createConsent, defaultConfig, mergeConfig, mergeTexts, resolveLocale, toConsentModeUpdate, useConsent };
@@ -0,0 +1,158 @@
1
+ type ConsentCategory = "analytics" | "marketing" | "preferences";
2
+ type ConsentChoices = Record<ConsentCategory, boolean>;
3
+ type ConsentTheme = "auto" | "light" | "dark";
4
+ type ConsentPosition = "bottom" | "bottom-left" | "bottom-right";
5
+ type ConsentLocale = "pl" | "en";
6
+ declare const CONSENT_CATEGORIES: readonly ConsentCategory[];
7
+ declare const CONSENT_TEXT_KEYS: readonly ["title", "description", "acceptAll", "rejectAll", "settings", "save", "close", "necessaryTitle", "necessaryDescription", "analyticsTitle", "analyticsDescription", "marketingTitle", "marketingDescription", "preferencesTitle", "preferencesDescription", "poweredBy"];
8
+ type ConsentTexts = Record<(typeof CONSENT_TEXT_KEYS)[number], string>;
9
+ type ConsentService = {
10
+ name: string;
11
+ category: ConsentCategory;
12
+ /** Cookies to delete (best effort) when the category is withdrawn. A trailing `*` matches a prefix. */
13
+ cookies?: string[];
14
+ };
15
+ type ConsentConfig = {
16
+ /** Banner version. A stored choice with a lower `bv` makes the banner ask again. */
17
+ version: number;
18
+ theme: ConsentTheme;
19
+ accentColor?: string;
20
+ position: ConsentPosition;
21
+ privacyPolicyUrl?: string;
22
+ categories: ConsentChoices;
23
+ services: ConsentService[];
24
+ texts?: Partial<Record<ConsentLocale, Partial<ConsentTexts>>>;
25
+ poweredBy: true;
26
+ };
27
+ /** What the consent cookie holds, and what `get()` returns. */
28
+ type ConsentState = {
29
+ id: string;
30
+ /** Unix seconds. */
31
+ ts: number;
32
+ /** Version of the banner the choice was made on. */
33
+ bv: number;
34
+ c: ConsentChoices;
35
+ };
36
+ type ConsentAction = "accept_all" | "reject_all" | "custom" | "withdraw";
37
+ /** `detail` of `bitsnap:consent` and the argument of `on('change')`. */
38
+ type ConsentChangeDetail = ConsentState & {
39
+ /** `reset` when the visitor's stored choice was cleared (`get()` is `null` then). */
40
+ action: ConsentAction | "reset";
41
+ };
42
+ type ConsentOptions = {
43
+ /** Public project key. Enables the remote config and the consent log. */
44
+ projectKey?: string;
45
+ theme?: ConsentTheme;
46
+ locale?: "auto" | ConsentLocale;
47
+ position?: ConsentPosition;
48
+ privacyPolicyUrl?: string;
49
+ /** `project` keeps one cookie per project key (`bitsnap_consent_<key>`). */
50
+ scope?: "global" | "project";
51
+ apiHost?: string;
52
+ collectHost?: string;
53
+ /** Google Consent Mode v2. `auto` is on when `gtag` or `dataLayer` already exist. */
54
+ gcm?: "auto" | "on" | "off";
55
+ /** Local overrides, merged over the defaults and the remote config. */
56
+ config?: Partial<ConsentConfig>;
57
+ /** Categories used when no remote config is loaded. */
58
+ categories?: Partial<ConsentChoices>;
59
+ reloadOnWithdraw?: boolean;
60
+ /**
61
+ * Dashboard preview: shows the banner at once from the local options, never
62
+ * reads or writes the cookie, loads no remote config, sends no consent log,
63
+ * and the buttons only close the banner.
64
+ */
65
+ preview?: boolean;
66
+ /** Replaces the banner title (current locale, non-empty values only). */
67
+ title?: string;
68
+ /** Replaces the banner description (current locale, non-empty values only). */
69
+ description?: string;
70
+ };
71
+ type BitsnapConsentApi = {
72
+ get(): ConsentState | null;
73
+ /**
74
+ * `true` when the visitor refused `category`, also in a choice made on an older banner
75
+ * version (which `get()` no longer returns) that they have not answered again yet.
76
+ */
77
+ denied(category: ConsentCategory): boolean;
78
+ on(event: "change", fn: (detail: ConsentChangeDetail) => void): () => void;
79
+ open(): void;
80
+ close(): void;
81
+ accept(categories?: Partial<ConsentChoices>): void;
82
+ acceptAll(): void;
83
+ rejectAll(): void;
84
+ reset(): void;
85
+ /** Resolves with the stored choice (or `null`) once config and stored choice are applied. */
86
+ ready: Promise<ConsentState | null>;
87
+ destroy(): void;
88
+ };
89
+
90
+ declare global {
91
+ interface Window {
92
+ BitsnapConsent?: BitsnapConsentApi;
93
+ }
94
+ }
95
+ type BitsnapConsentProps = {
96
+ /** Public project key: loads the project's banner config and logs choices. */
97
+ projectKey?: string;
98
+ theme?: ConsentOptions["theme"];
99
+ locale?: ConsentOptions["locale"];
100
+ position?: ConsentOptions["position"];
101
+ privacyPolicyUrl?: string;
102
+ /** `project` keeps the consent cookie per project key. */
103
+ scope?: ConsentOptions["scope"];
104
+ apiHost?: string;
105
+ collectHost?: string;
106
+ /** Local config, merged over the project config. */
107
+ config?: Partial<ConsentConfig>;
108
+ reloadOnWithdraw?: boolean;
109
+ /** Google Consent Mode v2: `auto` (default) is on when `gtag` or `dataLayer` already exist. */
110
+ gcm?: ConsentOptions["gcm"];
111
+ /** Categories offered when no remote config is loaded. */
112
+ categories?: ConsentOptions["categories"];
113
+ /** Dashboard preview: shows the banner from the local options only; touches no cookie. */
114
+ preview?: boolean;
115
+ /** Replaces the banner title. */
116
+ title?: string;
117
+ /** Replaces the banner description. */
118
+ description?: string;
119
+ };
120
+ /** Mounts Bitsnap Consent on the page. Renders nothing itself (the banner lives in a Shadow DOM). */
121
+ declare function BitsnapConsent(props: BitsnapConsentProps): null;
122
+ type UseConsent = {
123
+ /** The stored choice, or `null` while there is none (or on the server). */
124
+ consent: ConsentState | null;
125
+ /** `true` once the visitor has made a choice that is still valid. */
126
+ decided: boolean;
127
+ open: () => void;
128
+ accept: (categories?: Partial<ConsentChoices>) => void;
129
+ acceptAll: () => void;
130
+ rejectAll: () => void;
131
+ reset: () => void;
132
+ };
133
+ /** Current consent state of the page, kept up to date as the visitor chooses. */
134
+ declare function useConsent(): UseConsent;
135
+
136
+ /** Sync `get()`-style API with no DOM until a layer is shown. Never throws into the page. */
137
+ declare function createConsent(options?: ConsentOptions): BitsnapConsentApi;
138
+
139
+ declare function defaultConfig(): ConsentConfig;
140
+ /** Layers partial configs (later wins) over the defaults, dropping invalid values. */
141
+ declare function mergeConfig(...layers: (Partial<ConsentConfig> | null | undefined)[]): ConsentConfig;
142
+
143
+ declare const DEFAULT_TEXTS: Record<ConsentLocale, ConsentTexts>;
144
+ declare function resolveLocale(preference: "auto" | ConsentLocale | undefined, navigatorLanguage?: string): ConsentLocale;
145
+ /** Built-in texts for the locale, with the (non-empty) overrides of the config on top. */
146
+ declare function mergeTexts(locale: ConsentLocale, overrides?: Partial<Record<ConsentLocale, Partial<ConsentTexts>>>): ConsentTexts;
147
+
148
+ /** analytics -> analytics_storage; marketing -> ad_*; preferences -> functionality/personalization. */
149
+ declare function toConsentModeUpdate(c: ConsentChoices): {
150
+ analytics_storage: string;
151
+ ad_storage: string;
152
+ ad_user_data: string;
153
+ ad_personalization: string;
154
+ functionality_storage: string;
155
+ personalization_storage: string;
156
+ };
157
+
158
+ export { BitsnapConsent, type BitsnapConsentApi, type BitsnapConsentProps, CONSENT_CATEGORIES, CONSENT_TEXT_KEYS, type ConsentAction, type ConsentCategory, type ConsentChangeDetail, type ConsentChoices, type ConsentConfig, type ConsentLocale, type ConsentOptions, type ConsentPosition, type ConsentService, type ConsentState, type ConsentTexts, type ConsentTheme, DEFAULT_TEXTS, type UseConsent, createConsent, defaultConfig, mergeConfig, mergeTexts, resolveLocale, toConsentModeUpdate, useConsent };
@@ -0,0 +1,75 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _chunk3UHPJ6NKjs = require('./chunk-3UHPJ6NK.js');require('./chunk-JSDGZ4NY.js');var _react = require('react');var A=["analytics","marketing","preferences"];var Ae='script[type="text/plain"][data-bitsnap-consent]:not([data-bitsnap-queued])',Ee="iframe[data-bitsnap-consent][data-src]",oe=(e,t)=>A.includes(_nullishCoalesce(t, () => ("")))&&e[t];function Le(e){return new Promise(t=>{e.addEventListener("load",()=>t(),{once:!0}),e.addEventListener("error",()=>t(),{once:!0})})}function ie(e,t){let n=e.createElement("script");for(let{name:s,value:l}of Array.from(t.attributes))s==="type"||s==="data-bitsnap-queued"||(s==="data-type"?l==="module"&&n.setAttribute("type","module"):s==="data-src"?n.setAttribute("src",l):n.setAttribute(s,l));t.nonce&&(n.nonce=t.nonce);let i=n.hasAttribute("src");i?t.hasAttribute("async")||(n.async=!1):n.text=t.text;let p=i?Le(n):void 0;return _optionalChain([t, 'access', _2 => _2.parentNode, 'optionalAccess', _3 => _3.replaceChild, 'call', _4 => _4(n,t)]),p}function re(e,t){let n=0;try{let i=null,p=[];e.querySelectorAll(Ae).forEach(s=>{if(!oe(t,s.getAttribute("data-bitsnap-consent")))return;n++;let l=!s.hasAttribute("data-src")&&!s.hasAttribute("src");if(i||l&&p.length>0){s.setAttribute("data-bitsnap-queued",""),i=(_nullishCoalesce(i, () => (Promise.all(p).then(()=>{})))).then(()=>{try{return ie(e,s)}catch (e2){}}),p=[];return}let u=ie(e,s);u&&p.push(u)}),e.querySelectorAll(Ee).forEach(s=>{if(!oe(t,s.getAttribute("data-bitsnap-consent")))return;let l=s.getAttribute("data-src");l&&s.getAttribute("src")!==l&&(s.setAttribute("src",l),s.removeAttribute("data-src"),n++)})}catch (e3){}return n}var se="https://bitsnap.pl",ae="https://collect.bitsnap.pl";function Z(){return{version:1,theme:"auto",position:"bottom",categories:{analytics:!0,marketing:!0,preferences:!1},services:[],poweredBy:!0}}var je=["auto","light","dark"],Pe=["bottom","bottom-left","bottom-right"],_e=/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;function Oe(e){return typeof e=="string"&&_e.test(e.trim())?e.trim():void 0}function Me(e){if(typeof e!="string")return;let t=e.trim();return/^(?:https?:\/\/|\/(?!\/)|#|\?)/i.test(t)?t:void 0}function ze(e){if(!Array.isArray(e))return[];let t=[];for(let n of e)n&&typeof n.name=="string"&&A.includes(n.category)&&t.push({name:n.name,category:n.category,cookies:Array.isArray(n.cookies)?n.cookies.filter(i=>typeof i=="string"):void 0});return t}function $(...e){let t=Z();for(let n of e){if(!n||typeof n!="object")continue;typeof n.version=="number"&&n.version>=0&&(t.version=Math.floor(n.version)),je.includes(n.theme)&&(t.theme=n.theme),Pe.includes(n.position)&&(t.position=n.position);let i=Oe(n.accentColor);i&&(t.accentColor=i);let p=Me(n.privacyPolicyUrl);if(p&&(t.privacyPolicyUrl=p),n.categories&&typeof n.categories=="object")for(let s of A)typeof n.categories[s]=="boolean"&&(t.categories[s]=n.categories[s]);n.services!==void 0&&(t.services=ze(n.services)),n.texts&&typeof n.texts=="object"&&(t.texts=n.texts)}return t}async function ce(e,t,n=3e3){if(typeof fetch!="function")return null;let i=typeof AbortController=="function"?new AbortController:void 0,p=setTimeout(()=>_optionalChain([i, 'optionalAccess', _5 => _5.abort, 'call', _6 => _6()]),n);try{let s=await fetch(`${e.replace(/\/+$/,"")}/api/consent/config?key=${encodeURIComponent(t)}`,{signal:_optionalChain([i, 'optionalAccess', _7 => _7.signal]),credentials:"omit"});if(!s.ok)return null;let l=await s.json();if(!l||typeof l!="object")return null;let u=l.config&&typeof l.config=="object"?l.config:null,g=l.enabled!==!1;return u||!g?{enabled:g,config:u}:null}catch (e4){return null}finally{clearTimeout(p)}}var le="bitsnap_consent";function de(e,t){return t==="project"&&e?`${le}_${e.replace(/[^A-Za-z0-9_-]/g,"_")}`:le}function Ue(e){return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function De(e){let t=e.replace(/-/g,"+").replace(/_/g,"/");return atob(t+"=".repeat((4-t.length%4)%4))}function Be(e){return Ue(JSON.stringify({v:1,id:e.id,ts:e.ts,bv:e.bv,c:e.c}))}function $e(e){try{let t=JSON.parse(De(e));return!t||t.v!==1||typeof t.id!="string"||t.id===""||typeof t.ts!="number"||typeof t.bv!="number"||!t.c||typeof t.c.analytics!="boolean"||typeof t.c.marketing!="boolean"||typeof t.c.preferences!="boolean"?null:{id:t.id,ts:t.ts,bv:t.bv,c:{analytics:t.c.analytics,marketing:t.c.marketing,preferences:t.c.preferences}}}catch (e5){return null}}function He(e,t,n){return`${e}=${Be(t)}; Max-Age=31536000; Path=/; SameSite=Lax`+(n?"; Secure":"")}function Re(e){return e.split(";").map(t=>t.split("=")[0].trim()).filter(Boolean)}function Ie(e,t){for(let n of e.split(";")){let i=n.indexOf("=");if(i!==-1&&n.slice(0,i).trim()===t)return $e(n.slice(i+1).trim())}return null}function pe(){try{if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID()}catch (e6){}let e="";for(let t=0;t<32;t++)e+=Math.floor(Math.random()*16).toString(16);return e}function fe(e,t){try{return Ie(e.cookie,t)}catch (e7){return null}}function ue(e,t,n){try{e.cookie=He(t,n,_optionalChain([e, 'access', _8 => _8.location, 'optionalAccess', _9 => _9.protocol])==="https:")}catch (e8){}}function ge(e,t){try{e.cookie=`${t}=; Max-Age=0; Path=/; SameSite=Lax`}catch (e9){}}function Ne(e){if(!e||/^[\d.]+$/.test(e)||e.includes(":"))return[];let t=e.split("."),n=[];for(let i=0;i<=t.length-2;i++)n.push(t.slice(i).join("."));return n}function V(e,t,n){try{let i=t.filter(u=>n.includes(u.category)).flatMap(u=>_nullishCoalesce(u.cookies, () => ([])));if(i.length===0)return;let p=Re(e.cookie),s=new Set;for(let u of i)if(u.endsWith("*")){let g=u.slice(0,-1);for(let f of p)f.startsWith(g)&&s.add(f)}else s.add(u);let l=Ne(_nullishCoalesce(_optionalChain([e, 'access', _10 => _10.location, 'optionalAccess', _11 => _11.hostname]), () => ("")));for(let u of s){let g=`${encodeURIComponent(u)}=; Max-Age=0; Path=/`;e.cookie=g;for(let f of l)e.cookie=`${g}; Domain=${f}`,e.cookie=`${g}; Domain=.${f}`}}catch (e10){}}var Ke={ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"granted",wait_for_update:500},M=e=>e?"granted":"denied";function Q(e){return{analytics_storage:M(e.analytics),ad_storage:M(e.marketing),ad_user_data:M(e.marketing),ad_personalization:M(e.marketing),functionality_storage:M(e.preferences),personalization_storage:M(e.preferences)}}function Ge(e,t){return t==="off"?!1:t==="on"||typeof e.gtag=="function"||Array.isArray(e.dataLayer)}function We(e){if(typeof e.gtag=="function")return e.gtag;let t=e.dataLayer=e.dataLayer||[],n=function(){t.push(arguments)};return e.gtag=n,n}function ye(e,t){if(!Ge(e,t))return null;let n=We(e);return{setDefault:()=>n("consent","default",{...Ke}),update:i=>n("consent","update",Q(i))}}var ee={pl:{title:"Szanujemy Twoj\u0105 prywatno\u015B\u0107",description:"U\u017Cywamy plik\xF3w cookie, aby strona dzia\u0142a\u0142a poprawnie. Za Twoj\u0105 zgod\u0105 wykorzystujemy je te\u017C do statystyk, personalizacji i reklam. Mo\u017Cesz zaakceptowa\u0107 wszystkie, odrzuci\u0107 wszystkie albo wybra\u0107, na co si\u0119 zgadzasz.",acceptAll:"Akceptuj wszystkie",rejectAll:"Odrzu\u0107 wszystkie",settings:"Ustawienia",save:"Zapisz wyb\xF3r",close:"Zamknij",necessaryTitle:"Niezb\u0119dne",necessaryDescription:"Potrzebne do dzia\u0142ania strony: koszyk, zapami\u0119tanie Twojego wyboru, bezpiecze\u0144stwo. Nie mo\u017Cna ich wy\u0142\u0105czy\u0107.",analyticsTitle:"Statystyki",analyticsDescription:"Pomagaj\u0105 nam zrozumie\u0107, jak odwiedzaj\u0105cy korzystaj\u0105 ze strony, \u017Ceby\u015Bmy mogli j\u0105 ulepsza\u0107.",marketingTitle:"Marketing",marketingDescription:"Pozwalaj\u0105 mierzy\u0107 skuteczno\u015B\u0107 reklam i pokazywa\u0107 Ci oferty dopasowane do zainteresowa\u0144.",preferencesTitle:"Preferencje",preferencesDescription:"Zapami\u0119tuj\u0105 Twoje ustawienia, na przyk\u0142ad j\u0119zyk czy wygl\u0105d strony.",poweredBy:"Powered by"},en:{title:"We value your privacy",description:"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.",acceptAll:"Accept all",rejectAll:"Reject all",settings:"Settings",save:"Save choices",close:"Close",necessaryTitle:"Necessary",necessaryDescription:"Needed for the site to work: the cart, remembering your choice, security. They cannot be turned off.",analyticsTitle:"Analytics",analyticsDescription:"Help us understand how visitors use the site, so we can improve it.",marketingTitle:"Marketing",marketingDescription:"Measure how well ads work and show you offers that match your interests.",preferencesTitle:"Preferences",preferencesDescription:"Remember your settings, such as language or how the site looks.",poweredBy:"Powered by"}},me={pl:{privacy:"Polityka prywatno\u015Bci",services:"Us\u0142ugi",always:"Zawsze aktywne"},en:{privacy:"Privacy policy",services:"Services",always:"Always on"}};function F(e,t){return e==="pl"||e==="en"?e:/^pl\b/i.test(_nullishCoalesce(t, () => ("")))?"pl":"en"}function X(e,t){let n={...ee[e]},i=_optionalChain([t, 'optionalAccess', _12 => _12[e]]);if(i)for(let p of Object.keys(n)){let s=i[p];typeof s=="string"&&s.trim()!==""&&(n[p]=s)}return n}function Fe(e){let t=e.replace("#","");t.length===3&&(t=t.replace(/./g,"$&$&"));let n=parseInt(t,16);return[n>>16&255,n>>8&255,n&255]}function Ce(e){let[t,n,i]=Fe(e).map(p=>{let s=p/255;return s<=.03928?s/12.92:Math.pow((s+.055)/1.055,2.4)});return .2126*t+.7152*n+.0722*i}function q(e,t){let[n,i]=[Ce(e),Ce(t)].sort((p,s)=>s-p);return(n+.05)/(i+.05)}function he(e){return q(e,"#ffffff")>=q(e,"#111111")?"#ffffff":"#111111"}var J={light:{bg:"#ffffff",fg:"#14171c",muted:"#495260",border:"#c9ced6",off:"#6b7280",thumb:"#ffffff",accent:"#1d4ed8",onAccent:"#ffffff",link:"#1d4ed8"},dark:{bg:"#171a20",fg:"#f1f3f6",muted:"#b7beca",border:"#3a404b",off:"#8b93a1",thumb:"#171a20",accent:"#8ab4ff",onAccent:"#0b1220",link:"#9dc0ff"}},be=e=>`--bg:${e.bg};--fg:${e.fg};--muted:${e.muted};--border:${e.border};--off:${e.off};--thumb:${e.thumb};--accent:${e.accent};--on-accent:${e.onAccent};--link:${e.link};--focus:${e.accent}`,xe=`
2
+ :host{all:initial}
3
+ *{box-sizing:border-box}
4
+ [hidden]{display:none!important}
5
+ .root{${be(J.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%}
6
+ .root[data-theme=dark]{${be(J.dark)};color-scheme:dark}
7
+ button,input{font:inherit;color:inherit}
8
+ .banner,.overlay{pointer-events:auto}
9
+ .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}
10
+ .bottom{left:0;right:0;bottom:0;border-top:1px solid var(--border);padding:16px 24px calc(16px + env(safe-area-inset-bottom,0px))}
11
+ .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}
12
+ .card{bottom:16px;width:min(400px,calc(100vw - 32px));border:1px solid var(--border);border-radius:14px;padding:20px}
13
+ .bottom-left{left:16px}
14
+ .bottom-right{right:16px}
15
+ .card .inner{display:flex;flex-direction:column;gap:16px}
16
+ .text{grid-area:text}
17
+ .actions{grid-area:actions;display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end}
18
+ .card .actions{justify-content:stretch}
19
+ .foot{grid-area:foot}
20
+ .title{font-size:16px;font-weight:650;line-height:1.35;margin:0 0 4px}
21
+ .desc{margin:0;color:var(--muted)}
22
+ .desc a,.link-btn{color:var(--link)}
23
+ .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}
24
+ .btn:hover{filter:brightness(.94)}
25
+ .link-btn{min-height:44px;padding:0 12px;border:0;background:none;font-weight:500;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
26
+ .card .link-btn{flex:1 1 100%}
27
+ button:focus-visible,a:focus-visible,.dialog:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
28
+ .foot{font-size:12px;color:var(--muted);padding-top:4px}
29
+ .foot a{color:var(--muted);text-decoration:none;display:inline-flex;align-items:center;gap:5px;vertical-align:middle}
30
+ .foot a:hover{text-decoration:underline}
31
+ .foot b{color:var(--fg);font-weight:700;letter-spacing:-.01em}
32
+ .foot svg{display:block}
33
+ .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}
34
+ .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}
35
+ .d-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 8px 8px 24px}
36
+ .d-head .title{margin:0;font-size:18px}
37
+ .x{width:44px;height:44px;border:0;border-radius:10px;background:none;cursor:pointer;display:flex;align-items:center;justify-content:center;flex:none}
38
+ .x:hover{background:var(--border)}
39
+ .d-body{overflow:auto;padding:0 24px 8px;flex:1}
40
+ .cat{border-top:1px solid var(--border);padding:10px 0 14px}
41
+ .row{display:flex;align-items:center;justify-content:space-between;gap:12px}
42
+ .cat-title{font-weight:600;font-size:15px}
43
+ .always{font-size:12px;color:var(--muted);margin-right:4px}
44
+ .cat p{margin:0;color:var(--muted)}
45
+ .cat .svc{margin-top:6px;font-size:13px}
46
+ .cat .svc b{font-weight:600;color:var(--fg)}
47
+ .switch{position:relative;width:52px;height:44px;display:flex;align-items:center;justify-content:flex-end;flex:none}
48
+ .switch input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}
49
+ .switch input:disabled{cursor:default}
50
+ .track{width:44px;height:24px;border-radius:12px;background:var(--off);position:relative;transition:background .15s}
51
+ .track::after{content:"";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:var(--thumb);transition:transform .15s}
52
+ input:checked+.track{background:var(--accent)}
53
+ input:checked+.track::after{transform:translateX(20px);background:var(--on-accent)}
54
+ input:disabled+.track{opacity:.6}
55
+ input:focus-visible+.track{outline:2px solid var(--focus);outline-offset:2px}
56
+ .d-foot{display:flex;flex-direction:column;gap:8px;padding:12px 24px 16px;border-top:1px solid var(--border)}
57
+ .d-foot .actions{justify-content:stretch}
58
+ @keyframes in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
59
+ @keyframes fade{from{opacity:0}to{opacity:1}}
60
+ @media(max-width:640px){
61
+ .bottom{padding:16px 16px calc(16px + env(safe-area-inset-bottom,0px))}
62
+ .bottom .inner{grid-template-columns:1fr;grid-template-areas:"text" "actions" "foot";gap:12px}
63
+ .bottom .actions{justify-content:stretch}
64
+ .bottom .link-btn{flex:1 1 100%}
65
+ .card{left:8px;right:8px;bottom:8px;width:auto}
66
+ .overlay{align-items:flex-end;padding:0}
67
+ .dialog{max-width:none;border-radius:16px 16px 0 0;max-height:92vh}
68
+ .d-head{padding-left:16px}
69
+ .d-body{padding:0 16px 8px}
70
+ .d-foot{padding:12px 16px calc(16px + env(safe-area-inset-bottom,0px))}
71
+ .btn{flex-basis:130px;padding:0 12px}
72
+ }
73
+ @media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}
74
+ `.replace(/\n/g,"");var Xe='<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>',qe='<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>',Je="button:not([disabled]),input:not([disabled]),a[href]";function ve(e){let{doc:t,config:n,texts:i,locale:p}=e,s=me[p],l=null,u=null,g,f,y,b,v,h="none",w=null,T=null,E=new Map;function c(o,a={},...d){let m=t.createElement(o);for(let C of Object.keys(a))C==="class"?m.className=a[C]:m.setAttribute(C,a[C]);for(let C of d)m.append(C);return m}function x(o,a,d){let m=c("button",{type:"button",class:o},a);return m.addEventListener("click",d),m}function z(){let o=c("a",{href:`https://bitsnap.pl/?utm_source=consent_banner&utm_medium=referral&utm_content=${encodeURIComponent(_nullishCoalesce(_optionalChain([t, 'access', _13 => _13.location, 'optionalAccess', _14 => _14.hostname]), () => ("")))}`,target:"_blank",rel:"noopener"});return o.append(i.poweredBy+" "),o.insertAdjacentHTML("beforeend",Xe),o.append(c("b",{},"bitsnap")),c("div",{class:"foot"},o)}function k(){let o=c("p",{class:"desc",id:"d"},i.description);return n.privacyPolicyUrl&&o.append(" ",c("a",{href:n.privacyPolicyUrl,target:"_blank",rel:"noopener"},s.privacy)),o}function j(){v=x("link-btn",i.settings,()=>B()),f=c("div",{class:`banner ${n.position==="bottom"?"bottom":`card ${n.position}`}`,role:"region","aria-live":"polite","aria-labelledby":"t","aria-describedby":"d",tabindex:"-1"},c("div",{class:"inner"},c("div",{class:"text"},c("div",{class:"title",id:"t"},i.title),k()),c("div",{class:"actions"},x("btn",i.acceptAll,e.onAcceptAll),x("btn",i.rejectAll,e.onRejectAll),v),z()))}function U(o){let a=n.services.filter(C=>C.category===o),d=c("input",{type:"checkbox",role:"switch","aria-labelledby":`l-${o}`,"aria-describedby":`p-${o}`});o==="necessary"?(d.checked=!0,d.disabled=!0):E.set(o,d);let m=c("div",{class:"cat"},c("div",{class:"row"},c("span",{class:"cat-title",id:`l-${o}`},i[`${o}Title`]),c("span",{style:"display:flex;align-items:center"},...o==="necessary"?[c("span",{class:"always"},s.always)]:[],c("label",{class:"switch"},d,c("span",{class:"track"})))),c("p",{id:`p-${o}`},i[`${o}Description`]));return a.length>0&&m.append(c("p",{class:"svc"},c("b",{},`${s.services}: `),a.map(C=>C.name).join(", "))),m}function R(){let o=c("button",{type:"button",class:"x","aria-label":i.close});o.insertAdjacentHTML("beforeend",qe),o.addEventListener("click",()=>_());let a=c("div",{class:"d-body"},U("necessary"));for(let d of A)n.categories[d]&&a.append(U(d));b=c("div",{class:"dialog",role:"dialog","aria-modal":"true","aria-labelledby":"st",tabindex:"-1"},c("div",{class:"d-head"},c("div",{class:"title",id:"st"},i.settings),o),a,c("div",{class:"d-foot"},c("div",{class:"actions"},x("btn",i.save,()=>e.onSave(I())),x("btn",i.acceptAll,e.onAcceptAll),x("btn",i.rejectAll,e.onRejectAll)),z())),y=c("div",{class:"overlay"},b),y.addEventListener("mousedown",d=>{d.target===y&&_()})}function I(){let o={analytics:!1,marketing:!1,preferences:!1};return E.forEach((a,d)=>o[d]=a.checked),o}function S(){let o=n.theme==="dark"||n.theme==="auto"&&!!_optionalChain([T, 'optionalAccess', _15 => _15.matches]);g.setAttribute("data-theme",o?"dark":"light"),N(o)}function N(o){let a=n.accentColor;if(a){if(o&&q(a,J.dark.bg)<3){for(let d of["--accent","--focus","--on-accent"])g.style.removeProperty(d);return}g.style.setProperty("--accent",a),g.style.setProperty("--focus",a),g.style.setProperty("--on-accent",he(a))}}function D(){l||(l=c("div",{id:"bitsnap-consent","data-bitsnap-consent-host":""}),u=l.attachShadow({mode:"open"}),u.append(c("style",{},xe)),g=c("div",{class:"root",lang:p}),j(),R(),f.hidden=!0,y.hidden=!0,g.append(f,y),u.append(g),typeof _optionalChain([t, 'access', _16 => _16.defaultView, 'optionalAccess', _17 => _17.matchMedia])=="function"&&(T=t.defaultView.matchMedia("(prefers-color-scheme: dark)"),_optionalChain([T, 'access', _18 => _18.addEventListener, 'optionalCall', _19 => _19("change",S)])),S(),t.body.append(l))}function L(){return Array.from(b.querySelectorAll(Je))}function P(o){if(h!=="settings")return;if(o.key==="Escape"){o.preventDefault(),_();return}if(o.key!=="Tab")return;let a=L();if(a.length===0)return;let d=_optionalChain([u, 'optionalAccess', _20 => _20.activeElement]),m=a[0],C=a[a.length-1],W=!d||!b.contains(d);o.shiftKey&&(W||d===m||d===b)?(o.preventDefault(),C.focus()):!o.shiftKey&&(W||d===C)&&(o.preventDefault(),m.focus())}function K(o=!1){try{D(),h="banner",t.removeEventListener("keydown",P,!0),y.hidden=!0,f.hidden=!1,o&&f.focus({preventScroll:!0})}catch (e11){}}function B(){try{if(D(),h!=="settings"){let a=t.activeElement;w=a&&a!==l&&a!==t.body?a:null}let o=e.getChoices();E.forEach((a,d)=>a.checked=!!_optionalChain([o, 'optionalAccess', _21 => _21[d]])),h="settings",f.hidden=!0,y.hidden=!1,t.addEventListener("keydown",P,!0),b.focus({preventScroll:!0})}catch (e12){}}function _(){h==="settings"&&(t.removeEventListener("keydown",P,!0),y.hidden=!0,e.hasChoice()?(h="none",_optionalChain([w, 'optionalAccess', _22 => _22.focus, 'optionalCall', _23 => _23({preventScroll:!0})])):(h="banner",f.hidden=!1,v.focus({preventScroll:!0})))}function G(){if(!l)return;t.removeEventListener("keydown",P,!0);let o=h==="settings";h="none",f.hidden=!0,y.hidden=!0,o&&_optionalChain([w, 'optionalAccess', _24 => _24.focus, 'optionalCall', _25 => _25({preventScroll:!0})])}function r(){t.removeEventListener("keydown",P,!0),_optionalChain([T, 'optionalAccess', _26 => _26.removeEventListener, 'optionalCall', _27 => _27("change",S)]),_optionalChain([l, 'optionalAccess', _28 => _28.remove, 'call', _29 => _29()]),l=null,u=null,h="none"}return{showBanner:K,showSettings:B,hide:G,destroy:r}}var O=()=>({analytics:!1,marketing:!1,preferences:!1}),we=e=>e&&{id:e.id,ts:e.ts,bv:e.bv,c:{...e.c}};function Y(e={}){let t=typeof window<"u"?window:void 0,n=_optionalChain([t, 'optionalAccess', _30 => _30.document]),i=new Set,p=e.apiHost||se,s=e.collectHost||ae,l=e.projectKey?_chunk3UHPJ6NKjs.b.call(void 0, e.projectKey):null,u=de(_nullishCoalesce(l, () => (void 0)),e.scope),g=!!e.preview,f=$(z()),y=null,b=null,v=null,h=!1,w=!1,T,E=[],c=t&&!g?k(()=>ye(t,e.gcm),null):null;k(()=>_optionalChain([c, 'optionalAccess', _31 => _31.setDefault, 'call', _32 => _32()]),void 0);let x=n&&!g?fe(n,u):null;function z(r){let o={...e.config};return e.theme&&(o.theme=e.theme),e.position&&(o.position=e.position),e.privacyPolicyUrl&&(o.privacyPolicyUrl=e.privacyPolicyUrl),{...r,...o}}function k(r,o){try{return r()}catch (e13){return o}}function j(r){let o=O();for(let a of A)o[a]=!!_optionalChain([r, 'optionalAccess', _33 => _33[a]])&&f.categories[a];return o}function U(r){i.forEach(o=>k(()=>o({...r,c:{...r.c}}),void 0)),k(()=>{_optionalChain([t, 'optionalAccess', _34 => _34.dispatchEvent, 'call', _35 => _35(new t.CustomEvent("bitsnap:consent",{detail:{...r,c:{...r.c}}}))])},void 0)}function R(r,o){g||!l||typeof fetch!="function"||k(()=>{let a=JSON.stringify({k:l,consent_id:o.id,action:r,c:o.c,bv:o.bv,host:_nullishCoalesce(_optionalChain([t, 'optionalAccess', _36 => _36.location, 'optionalAccess', _37 => _37.hostname]), () => ("")),ts:o.ts});fetch(`${s.replace(/\/+$/,"")}/consent`,{method:"POST",keepalive:!0,credentials:"omit",body:a}).catch(()=>{})},void 0)}function I(r){return A.filter(o=>r[o]&&f.categories[o])}function S(r,o){if(!n||w)return;if(g){_optionalChain([v, 'optionalAccess', _38 => _38.hide, 'call', _39 => _39()]);return}let a=_nullishCoalesce(y, () => (b)),d=a?I(a.c).filter(W=>!r[W]):[],m=d.length>0?"withdraw":o,C={id:_nullishCoalesce(_optionalChain([a, 'optionalAccess', _40 => _40.id]), () => (pe())),ts:Math.floor(Date.now()/1e3),bv:f.version,c:r};ue(n,u,C),y=C,b=null,N(C.c),d.length>0&&V(n,f.services,d),_optionalChain([v, 'optionalAccess', _41 => _41.hide, 'call', _42 => _42()]),U({...C,action:m}),R(m,C),d.length>0&&e.reloadOnWithdraw&&D()}function N(r){k(()=>_optionalChain([c, 'optionalAccess', _43 => _43.update, 'call', _44 => _44(r)]),void 0),n&&re(n,r)}function D(){setTimeout(()=>k(()=>_optionalChain([t, 'optionalAccess', _45 => _45.location, 'access', _46 => _46.reload, 'call', _47 => _47()]),void 0),50)}function L(){if(!n||!h||w)return null;if(!v){let r=F(e.locale,_optionalChain([t, 'optionalAccess', _48 => _48.navigator, 'optionalAccess', _49 => _49.language]));v=ve({doc:n,config:f,locale:r,texts:P(X(r,f.texts)),getChoices:()=>_nullishCoalesce(_optionalChain([y, 'optionalAccess', _50 => _50.c]), () => (null)),hasChoice:()=>y!==null,onAcceptAll:()=>S(j({analytics:!0,marketing:!0,preferences:!0}),"accept_all"),onRejectAll:()=>S(O(),"reject_all"),onSave:o=>S(j(o),"custom")})}return v}function P(r){let o=_optionalChain([e, 'access', _51 => _51.title, 'optionalAccess', _52 => _52.trim, 'call', _53 => _53()]),a=_optionalChain([e, 'access', _54 => _54.description, 'optionalAccess', _55 => _55.trim, 'call', _56 => _56()]);return{...r,...o&&{title:o},...a&&{description:a}}}function K(r){_optionalChain([r, 'access', _57 => _57.target, 'optionalAccess', _58 => _58.closest, 'optionalCall', _59 => _59("[data-bitsnap-consent-open]")])&&(r.preventDefault(),G.open())}let B=(async()=>{if(!n||!t)return null;let r=l&&!g?await ce(p,l):null;if(w)return null;let o=_optionalChain([r, 'optionalAccess', _60 => _60.config])?void 0:e.categories;if(f=$(_optionalChain([r, 'optionalAccess', _61 => _61.config]),o?{categories:{...O(),...o}}:void 0,z()),n.readyState==="loading"&&await new Promise(m=>n.addEventListener("DOMContentLoaded",()=>m(),{once:!0})),w)return null;h=!0,n.addEventListener("click",K),T=()=>n.removeEventListener("click",K);let a=!l||_optionalChain([r, 'optionalAccess', _62 => _62.config])!=null,d=_optionalChain([r, 'optionalAccess', _63 => _63.enabled])===!1;return g?_optionalChain([L, 'call', _64 => _64(), 'optionalAccess', _65 => _65.showBanner, 'call', _66 => _66()]):x&&(d||!a||x.bv===f.version)?(y=x,N(j(y.c))):(x&&(b=x),d||_optionalChain([L, 'call', _67 => _67(), 'optionalAccess', _68 => _68.showBanner, 'call', _69 => _69()])),E.splice(0).forEach(m=>k(m,void 0)),k(()=>t.dispatchEvent(new t.CustomEvent("bitsnap:consent:ready")),void 0),we(y)})().catch(()=>null);function _(r){h?r():E.push(r)}let G={get:()=>we(y),denied:r=>_optionalChain([(_nullishCoalesce(y, () => (b))), 'optionalAccess', _70 => _70.c, 'access', _71 => _71[r]])===!1,on(r,o){return r!=="change"||typeof o!="function"?()=>{}:(i.add(o),()=>void i.delete(o))},open(){h?_optionalChain([L, 'call', _72 => _72(), 'optionalAccess', _73 => _73.showSettings, 'call', _74 => _74()]):B.then(()=>_optionalChain([L, 'call', _75 => _75(), 'optionalAccess', _76 => _76.showSettings, 'call', _77 => _77()]))},close(){_optionalChain([v, 'optionalAccess', _78 => _78.hide, 'call', _79 => _79()])},accept:r=>_(()=>S(j(r),"custom")),acceptAll:()=>_(()=>S(j({analytics:!0,marketing:!0,preferences:!0}),"accept_all")),rejectAll:()=>_(()=>S(O(),"reject_all")),reset(){if(!n||w)return;if(g){_optionalChain([L, 'call', _80 => _80(), 'optionalAccess', _81 => _81.showBanner, 'call', _82 => _82()]);return}let r=_nullishCoalesce(y, () => (b)),o=r?I(r.c):[];ge(n,u),y=null,b=r,k(()=>_optionalChain([c, 'optionalAccess', _83 => _83.update, 'call', _84 => _84(O())]),void 0),o.length>0&&V(n,f.services,o),U({id:_nullishCoalesce(_optionalChain([r, 'optionalAccess', _85 => _85.id]), () => ("")),ts:Math.floor(Date.now()/1e3),bv:f.version,c:O(),action:"reset"}),r&&o.length>0&&R("withdraw",{id:r.id,ts:Math.floor(Date.now()/1e3),bv:f.version,c:O()}),_optionalChain([L, 'call', _86 => _86(), 'optionalAccess', _87 => _87.showBanner, 'call', _88 => _88(!0)]),o.length>0&&e.reloadOnWithdraw&&D()},ready:B,destroy(){w=!0,_optionalChain([T, 'optionalCall', _89 => _89()]),_optionalChain([v, 'optionalAccess', _90 => _90.destroy, 'call', _91 => _91()]),v=null,i.clear()}};return Ye(G)}function Ye(e){let t={...e};for(let n of Object.keys(e)){let i=e[n];typeof i=="function"&&(t[n]=(...p)=>{try{return i(...p)}catch (e14){return n==="get"?null:n==="on"?()=>{}:void 0}})}return t}function Ve(e){let{projectKey:t,theme:n,locale:i,position:p,privacyPolicyUrl:s,scope:l,apiHost:u,collectHost:g,reloadOnWithdraw:f,gcm:y,preview:b,title:v,description:h}=e,w=JSON.stringify(_nullishCoalesce(e.config, () => (null))),T=_react.useRef.call(void 0, e.config);T.current=e.config;let E=JSON.stringify(_nullishCoalesce(e.categories, () => (null))),c=_react.useRef.call(void 0, e.categories);return c.current=e.categories,_chunk3UHPJ6NKjs.h.call(void 0, ()=>{if(window.BitsnapConsent)return;let x=Y({projectKey:t,theme:n,locale:i,position:p,privacyPolicyUrl:s,scope:l,apiHost:u,collectHost:g,reloadOnWithdraw:f,gcm:y,preview:b,title:v,description:h,categories:c.current,config:T.current});return window.BitsnapConsent=x,()=>{x.destroy(),window.BitsnapConsent===x&&delete window.BitsnapConsent}},[t,n,i,p,s,l,u,g,f,y,b,v,h,E,w]),null}var Te="null",Se=null;function Qe(){let e=typeof window>"u"?null:_nullishCoalesce(_optionalChain([window, 'access', _92 => _92.BitsnapConsent, 'optionalAccess', _93 => _93.get, 'call', _94 => _94()]), () => (null)),t=JSON.stringify(e);return t!==Te&&(Te=t,Se=e),Se}function et(e){return window.addEventListener("bitsnap:consent",e),window.addEventListener("bitsnap:consent:ready",e),()=>{window.removeEventListener("bitsnap:consent",e),window.removeEventListener("bitsnap:consent:ready",e)}}function tt(){let e=_react.useSyncExternalStore.call(void 0, et,Qe,()=>null),t=_react.useCallback.call(void 0, ()=>_optionalChain([window, 'access', _95 => _95.BitsnapConsent, 'optionalAccess', _96 => _96.open, 'call', _97 => _97()]),[]),n=_react.useCallback.call(void 0, l=>_optionalChain([window, 'access', _98 => _98.BitsnapConsent, 'optionalAccess', _99 => _99.accept, 'call', _100 => _100(l)]),[]),i=_react.useCallback.call(void 0, ()=>_optionalChain([window, 'access', _101 => _101.BitsnapConsent, 'optionalAccess', _102 => _102.acceptAll, 'call', _103 => _103()]),[]),p=_react.useCallback.call(void 0, ()=>_optionalChain([window, 'access', _104 => _104.BitsnapConsent, 'optionalAccess', _105 => _105.rejectAll, 'call', _106 => _106()]),[]),s=_react.useCallback.call(void 0, ()=>_optionalChain([window, 'access', _107 => _107.BitsnapConsent, 'optionalAccess', _108 => _108.reset, 'call', _109 => _109()]),[]);return{consent:e,decided:e!==null,open:t,accept:n,acceptAll:i,rejectAll:p,reset:s}}exports.BitsnapConsent = Ve; exports.DEFAULT_TEXTS = ee; exports.createConsent = Y; exports.defaultConfig = Z; exports.mergeConfig = $; exports.mergeTexts = X; exports.resolveLocale = F; exports.toConsentModeUpdate = Q; exports.useConsent = tt;
75
+ //# sourceMappingURL=consent.js.map