@beworke/pixel 0.1.0-rc.7 → 0.1.0-rc.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +71 -56
- package/RELEASE_CANDIDATE.md +28 -62
- package/dist/Pixel-CCgGk43j.d.ts +797 -0
- package/dist/Pixel-CqbgC_72.d.mts +797 -0
- package/dist/{StorageFactory-DeMaZ8wk.d.ts → StorageFactory-BRBsnnH7.d.ts} +1 -1
- package/dist/{StorageFactory-Cq29vF32.d.mts → StorageFactory-Dp19Wecr.d.mts} +1 -1
- package/dist/browser/index.cjs.js +3 -0
- package/dist/browser/index.cjs.js.map +1 -0
- package/dist/browser/index.d.mts +55 -0
- package/dist/browser/index.d.ts +55 -0
- package/dist/browser/index.esm.js +3 -0
- package/dist/browser/index.esm.js.map +1 -0
- package/dist/browser/pixel.global.js +4 -0
- package/dist/browser/pixel.global.js.map +1 -0
- package/dist/config/index.cjs.js +1 -1
- package/dist/config/index.cjs.js.map +1 -1
- package/dist/config/index.d.mts +15 -5
- package/dist/config/index.d.ts +15 -5
- package/dist/config/index.esm.js +1 -1
- package/dist/config/index.esm.js.map +1 -1
- package/dist/examples/html-script/RELEASE_CANDIDATE.md +6 -8
- package/dist/examples/html-script/add-payment-info/example-add-payment-info-card-autocomplete.html +40 -47
- package/dist/examples/html-script/add-payment-info/example-add-payment-info-card-disabled.html +40 -47
- package/dist/examples/html-script/add-payment-info/example-add-payment-info-card-fields.html +40 -47
- package/dist/examples/html-script/add-payment-info/example-add-payment-info-data-track.html +40 -47
- package/dist/examples/html-script/add-payment-info/example-add-payment-info-dedupe.html +40 -47
- package/dist/examples/html-script/add-payment-info/example-add-payment-info-manual.html +40 -47
- package/dist/examples/html-script/add-payment-info/example-add-payment-info-rules-card.html +40 -47
- package/dist/examples/html-script/add-payment-info/example-add-payment-info-security.html +40 -47
- package/dist/examples/html-script/add-to-cart/example-add-to-cart-attribute.html +40 -47
- package/dist/examples/html-script/add-to-cart/example-add-to-cart-auto.html +40 -47
- package/dist/examples/html-script/add-to-cart/example-add-to-cart-click.html +40 -47
- package/dist/examples/html-script/add-to-cart/example-add-to-cart-dedupe.html +40 -47
- package/dist/examples/html-script/add-to-cart/example-add-to-cart-link.html +40 -47
- package/dist/examples/html-script/add-to-cart/example-add-to-cart-manual.html +40 -47
- package/dist/examples/html-script/add-to-cart/example-add-to-cart-order-bump.html +40 -47
- package/dist/examples/html-script/add-to-cart/example-add-to-cart-text.html +40 -47
- package/dist/examples/html-script/behavior/example-behavior-engagement.html +4 -4
- package/dist/examples/html-script/behavior/example-behavior-heartbeat.html +4 -4
- package/dist/examples/html-script/behavior/example-behavior-runtime-intelligence.html +4 -4
- package/dist/examples/html-script/behavior/example-behavior-viewport.html +4 -4
- package/dist/examples/html-script/buygoods/example-buygoods-checkout.html +83 -0
- package/dist/examples/html-script/example-checkout-commerce.html +31 -30
- package/dist/examples/html-script/example-conversion.html +41 -48
- package/dist/examples/html-script/example-global-factory-classic.html +45 -0
- package/dist/examples/html-script/example-global-factory.html +40 -0
- package/dist/examples/html-script/example-integration.html +39 -45
- package/dist/examples/html-script/example-landing-commerce.html +3 -8
- package/dist/examples/html-script/example-runtime-diagnostics.html +4 -4
- package/dist/examples/html-script/example-transport.html +59 -57
- package/dist/examples/html-script/full-funnel/checkout.html +3 -1
- package/dist/examples/html-script/full-funnel/downsell.html +3 -1
- package/dist/examples/html-script/full-funnel/landing.html +3 -1
- package/dist/examples/html-script/full-funnel/thank-you.html +3 -1
- package/dist/examples/html-script/full-funnel/upsell.html +3 -1
- package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-attribute.html +40 -47
- package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-auto.html +40 -47
- package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-click.html +40 -47
- package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-manual.html +40 -47
- package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-snapshot.html +40 -47
- package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-submit.html +40 -47
- package/dist/examples/html-script/initiate-checkout/example-initiate-checkout-text.html +40 -47
- package/dist/examples/html-script/lead/example-lead-trigger-attribute.html +40 -47
- package/dist/examples/html-script/lead/example-lead-trigger-auto.html +40 -47
- package/dist/examples/html-script/lead/example-lead-trigger-click.html +40 -47
- package/dist/examples/html-script/release-candidate.html +31 -30
- package/dist/examples/html-script/remove-from-cart/README.md +3 -3
- package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-attribute.html +40 -47
- package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-css.html +40 -47
- package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-dedupe.html +47 -54
- package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-manual.html +40 -47
- package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-multi.html +40 -47
- package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-state.html +40 -47
- package/dist/examples/html-script/remove-from-cart/example-remove-from-cart-text.html +40 -47
- package/dist/examples/html-script/search/example-search-attribute.html +40 -47
- package/dist/examples/html-script/search/example-search-button-sync.html +40 -47
- package/dist/examples/html-script/search/example-search-dedupe.html +40 -47
- package/dist/examples/html-script/search/example-search-input.html +40 -47
- package/dist/examples/html-script/search/example-search-manual.html +40 -47
- package/dist/examples/html-script/search/example-search-submit.html +40 -47
- package/dist/examples/html-script/search/example-search-text.html +40 -47
- package/dist/examples/html-script/url-context/example-url-context-allowed-domains.html +4 -4
- package/dist/examples/html-script/url-context/example-url-context-landing.html +4 -4
- package/dist/examples/html-script/url-context/example-url-context-upsell.html +4 -4
- package/dist/examples/html-script/url-context/example-url-context.html +4 -4
- package/dist/examples/html-script/view-content/example-view-content-attribute.html +40 -47
- package/dist/examples/html-script/view-content/example-view-content-css.html +40 -47
- package/dist/examples/html-script/view-content/example-view-content-dedupe.html +40 -47
- package/dist/examples/html-script/view-content/example-view-content-empty.html +40 -47
- package/dist/examples/html-script/view-content/example-view-content-manual.html +40 -47
- package/dist/examples/html-script/view-content/example-view-content-product-card.html +40 -47
- package/dist/examples/html-script/view-content/example-view-content-text.html +40 -47
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.mts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/{pixel-DMwpppf_.d.mts → pixel-C93c-0M2.d.mts} +109 -97
- package/dist/{pixel-2uL4LSyC.d.ts → pixel-DVy4rzj8.d.ts} +109 -97
- package/dist/pixel-default-config-BkAjriVH.d.mts +21 -0
- package/dist/pixel-default-config-Co69vDP3.d.ts +21 -0
- package/dist/pixel-settings-BhfJqA92.d.mts +40 -0
- package/dist/pixel-settings-C0qPFTii.d.ts +40 -0
- package/dist/runtime/index.cjs.js +1 -1
- package/dist/runtime/index.cjs.js.map +1 -1
- package/dist/runtime/index.d.mts +4 -4
- package/dist/runtime/index.d.ts +4 -4
- package/dist/runtime/index.esm.js +1 -1
- package/dist/runtime/index.esm.js.map +1 -1
- package/dist/services/index.cjs.js +1 -1
- package/dist/services/index.cjs.js.map +1 -1
- package/dist/services/index.d.mts +4 -4
- package/dist/services/index.d.ts +4 -4
- package/dist/services/index.esm.js +1 -1
- package/dist/services/index.esm.js.map +1 -1
- package/dist/{types-BqUEoZo0.d.ts → types-B2aUNHb3.d.ts} +2 -2
- package/dist/{types-6HF3UlsL.d.mts → types-C0J9KUQg.d.mts} +2 -2
- package/dist/{types-CgrabttM.d.mts → types-C2dsBog1.d.mts} +1 -1
- package/dist/{types-fFcQ1apy.d.ts → types-DcaBYgVI.d.ts} +1 -1
- package/dist/v2/global.global.js +1 -1
- package/dist/v2/global.global.js.map +1 -1
- package/dist/v2/index.cjs.js +1 -1
- package/dist/v2/index.cjs.js.map +1 -1
- package/dist/v2/index.d.mts +21 -787
- package/dist/v2/index.d.ts +21 -787
- package/dist/v2/index.esm.js +1 -1
- package/dist/v2/index.esm.js.map +1 -1
- package/docs/public/README.md +7 -4
- package/docs/public/api/exports.md +12 -8
- package/docs/public/api/pixel.md +27 -6
- package/docs/public/configuration/commerce.md +2 -2
- package/docs/public/configuration/modules.md +11 -14
- package/docs/public/configuration/overview.md +41 -25
- package/docs/public/configuration/transport.md +127 -0
- package/docs/public/events/catalog.md +3 -1
- package/docs/public/getting-started/installation.md +14 -12
- package/docs/public/getting-started/quick-start.md +95 -30
- package/docs/public/getting-started/react-nextjs.md +57 -34
- package/docs/public/getting-started/script-tag.md +55 -32
- package/docs/public/guides/funnel-checkout.md +1 -1
- package/docs/public/guides/funnel-landing.md +9 -7
- package/docs/public/limitations.md +5 -4
- package/docs/public/privacy/limitations.md +6 -6
- package/docs/public/release-candidate/validation.md +4 -4
- package/docs/public/troubleshooting.md +7 -6
- package/package.json +8 -3
- package/dist/pixel-default-config-BDPUVHse.d.ts +0 -5
- package/dist/pixel-default-config-C5uLt52W.d.mts +0 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/ModuleRegistry.ts","../../src/events/builder/BaseEventBuilder.ts","../../src/logger/ConsolePixelLogger.ts","../../src/services/attribution/types.ts","../../src/services/attribution/ClickIdParser.ts","../../src/services/attribution/CookieCollector.ts","../../src/services/attribution/AttributionCollector.ts","../../src/services/attribution/AttributionStore.ts","../../src/services/attribution/AttributionService.ts","../../src/services/browser-metadata/BrowserMetadataService.ts","../../src/services/dispatcher/DispatcherService.ts","../../src/services/fingerprint/FingerprintService.ts","../../src/services/storage/BrowserStorageAdapter.ts","../../src/services/storage/MemoryStorageAdapter.ts","../../src/services/storage/StorageService.ts","../../src/services/storage/StorageFactory.ts","../../src/services/commerce/ProductCatalog.ts","../../src/services/commerce/CommerceState.ts","../../src/services/commerce/OrderCalculator.ts","../../src/config/shared/commerce.ts","../../src/services/commerce/CommerceResolver.ts","../../src/services/commerce/CommerceService.ts","../../src/services/session/session-id.ts","../../src/services/session/SessionService.ts","../../src/services/visitor/visitor-id.ts","../../src/services/visitor/VisitorService.ts","../../src/modules/core/url-context/constants.ts","../../src/modules/core/url-context/utils.ts","../../src/modules/core/url-context/QueryParamCollector.ts","../../src/modules/core/url-context/ManagedParamResolver.ts","../../src/modules/core/url-context/ForwardParamResolver.ts","../../src/modules/core/url-context/LinkDecorator.ts","../../src/modules/core/url-context/UrlContextStore.ts","../../src/modules/core/url-context/resolve-config.ts","../../src/modules/core/url-context/UrlContextService.ts","../../src/runtime/PixelRuntime.ts"],"sourcesContent":["import type { PixelModule } from './types';\n\nexport class ModuleRegistry {\n private readonly modules: PixelModule[] = [];\n\n register(module: PixelModule): void {\n if (this.modules.some(existing => existing.name === module.name)) {\n throw new Error(`[Pixel] Module \"${module.name}\" is already registered`);\n }\n\n this.modules.push(module);\n }\n\n getAll(): readonly PixelModule[] {\n return this.modules;\n }\n\n size(): number {\n return this.modules.length;\n }\n}\n","import type { AttributionService } from '@/services/attribution/types';\nimport type { BrowserMetadataService } from '@/services/browser-metadata';\nimport type { UrlContextService } from '@/modules/core/url-context';\n\nimport type { BasePixelEvent } from '../base';\n\nexport class BaseEventBuilder {\n private readonly metadataService: BrowserMetadataService;\n\n private readonly attribution: AttributionService | null;\n\n private readonly urlContext: UrlContextService | null;\n\n constructor(\n metadataService: BrowserMetadataService,\n attribution?: AttributionService | null,\n urlContext?: UrlContextService | null\n ) {\n this.metadataService = metadataService;\n this.attribution = attribution ?? null;\n this.urlContext = urlContext ?? null;\n }\n\n build<T extends { type: string }>(event: T): T & BasePixelEvent {\n const metadata = this.metadataService.getMetadata();\n const identifiers = this.attribution?.getSnapshot();\n const hasIdentifiers =\n identifiers !== undefined &&\n Object.keys(identifiers).some(key => {\n const value = identifiers[key as keyof typeof identifiers];\n return value !== undefined && value !== null && value !== '';\n });\n\n const urlSnapshot = this.urlContext?.isEnabled()\n ? this.urlContext.getSnapshot()\n : null;\n\n const hasQueryParams =\n urlSnapshot !== null && Object.keys(urlSnapshot.queryParams).length > 0;\n const hasUrlContext =\n urlSnapshot !== null &&\n ((urlSnapshot.urlContext.managed &&\n Object.keys(urlSnapshot.urlContext.managed).length > 0) ||\n (urlSnapshot.urlContext.forwarded &&\n Object.keys(urlSnapshot.urlContext.forwarded).length > 0) ||\n (urlSnapshot.urlContext.source &&\n Object.keys(urlSnapshot.urlContext.source).length > 0));\n\n return {\n ...event,\n timestamp: Date.now(),\n path: metadata.path,\n url: metadata.url,\n hostname: metadata.hostname,\n language: metadata.language,\n timezone: metadata.timezone,\n ...(hasIdentifiers ? { identifiers } : {}),\n ...(hasQueryParams\n ? { queryParams: { ...urlSnapshot!.queryParams } }\n : {}),\n ...(hasUrlContext\n ? {\n urlContext: {\n ...(urlSnapshot!.urlContext.managed\n ? { managed: { ...urlSnapshot!.urlContext.managed } }\n : {}),\n ...(urlSnapshot!.urlContext.forwarded\n ? { forwarded: { ...urlSnapshot!.urlContext.forwarded } }\n : {}),\n ...(urlSnapshot!.urlContext.source\n ? { source: { ...urlSnapshot!.urlContext.source } }\n : {}),\n },\n }\n : {}),\n };\n }\n}\n","import type { PixelLogger } from './PixelLogger';\n\nexport class ConsolePixelLogger implements PixelLogger {\n constructor(private readonly debugEnabled: boolean) {}\n\n debug(...args: unknown[]): void {\n if (!this.debugEnabled) return;\n if (typeof console === 'undefined') return;\n console.debug(...args);\n }\n\n info(...args: unknown[]): void {\n if (typeof console === 'undefined') return;\n console.info(...args);\n }\n\n warn(...args: unknown[]): void {\n if (typeof console === 'undefined') return;\n console.warn(...args);\n }\n\n error(...args: unknown[]): void {\n if (typeof console === 'undefined') return;\n console.error(...args);\n }\n}\n","export type AttributionIdentifiers = {\n readonly fbclid?: string;\n readonly fbp?: string;\n readonly fbc?: string;\n\n readonly gclid?: string;\n readonly gbraid?: string;\n readonly wbraid?: string;\n readonly ga?: string;\n readonly gid?: string;\n readonly gclAu?: string;\n\n readonly ttclid?: string;\n readonly ttp?: string;\n\n readonly msclkid?: string;\n readonly liFatId?: string;\n readonly epik?: string;\n\n readonly customClickIds?: Readonly<Record<string, string>>;\n\n readonly firstCollectedAt?: number;\n readonly lastCollectedAt?: number;\n readonly landingUrl?: string;\n readonly referrer?: string;\n};\n\nexport type AttributionConfig = {\n readonly enabled: boolean;\n readonly ttlDays?: number;\n readonly persist?: boolean;\n readonly captureUrlParams?: boolean;\n readonly captureCookies?: boolean;\n readonly customClickIdParams?: string[];\n};\n\nexport const DEFAULT_ATTRIBUTION_CONFIG: AttributionConfig = {\n enabled: true,\n ttlDays: 90,\n persist: true,\n captureUrlParams: true,\n captureCookies: true,\n customClickIdParams: [],\n};\n\nexport const ATTRIBUTION_STORAGE_KEY = 'attribution';\n\nexport interface AttributionService {\n init(): void;\n destroy(): void;\n collect(): AttributionIdentifiers;\n getSnapshot(): AttributionIdentifiers;\n update(partial: Partial<AttributionIdentifiers>): AttributionIdentifiers;\n clear(): void;\n}\n","import type { AttributionIdentifiers } from './types';\n\nconst BUILTIN_CLICK_PARAMS = [\n 'fbclid',\n 'gclid',\n 'gbraid',\n 'wbraid',\n 'ttclid',\n 'msclkid',\n 'epik',\n 'li_fat_id',\n] as const;\n\n/**\n * Parses click IDs from URL search params and maps to AttributionIdentifiers fields.\n */\nexport class ClickIdParser {\n parse(customParams: readonly string[] = []): Partial<AttributionIdentifiers> {\n if (typeof window === 'undefined' || !window.location?.search) {\n return {};\n }\n\n try {\n const params = new URLSearchParams(window.location.search);\n const result: Record<string, unknown> = {};\n const customClickIds: Record<string, string> = {};\n\n for (const key of BUILTIN_CLICK_PARAMS) {\n const value = params.get(key);\n if (!value) continue;\n\n if (key === 'li_fat_id') {\n result.liFatId = value;\n } else {\n result[key] = value;\n }\n }\n\n for (const key of customParams) {\n const value = params.get(key);\n if (value) customClickIds[key] = value;\n }\n\n if (Object.keys(customClickIds).length > 0) {\n result.customClickIds = customClickIds;\n }\n\n return result as Partial<AttributionIdentifiers>;\n } catch {\n return {};\n }\n }\n\n /**\n * Meta convention: when fbclid is present and _fbc cookie is missing,\n * synthesize fbc = fb.1.<timestamp_ms>.<fbclid>\n */\n synthesizeFbc(fbclid: string, existingFbc?: string): string | undefined {\n if (existingFbc) return existingFbc;\n if (!fbclid) return undefined;\n return `fb.1.${Date.now()}.${fbclid}`;\n }\n}\n","/**\n * SSR-safe cookie reader for attribution identifiers.\n */\nexport class CookieCollector {\n collectKnown(): Readonly<Record<string, string>> {\n if (typeof document === 'undefined') return {};\n\n const cookies = this.parseCookies();\n const result: Record<string, string> = {};\n\n const map: Record<string, string> = {\n _fbp: 'fbp',\n _fbc: 'fbc',\n _ga: 'ga',\n _gid: 'gid',\n _gcl_au: 'gclAu',\n _ttp: 'ttp',\n li_fat_id: 'liFatId',\n epik: 'epik',\n };\n\n for (const [cookieName, field] of Object.entries(map)) {\n const value = cookies[cookieName];\n if (value) result[field] = value;\n }\n\n return result;\n }\n\n private parseCookies(): Record<string, string> {\n if (typeof document === 'undefined') return {};\n\n try {\n return document.cookie.split(';').reduce(\n (acc, part) => {\n const [rawKey, ...rest] = part.trim().split('=');\n if (!rawKey) return acc;\n acc[rawKey] = decodeURIComponent(rest.join('=') || '');\n return acc;\n },\n {} as Record<string, string>\n );\n } catch {\n return {};\n }\n }\n}\n","import type { AttributionIdentifiers } from './types';\nimport { ClickIdParser } from './ClickIdParser';\nimport { CookieCollector } from './CookieCollector';\n\n/**\n * Collects attribution signals from URL + cookies and merges them.\n */\nexport class AttributionCollector {\n private readonly clickIdParser = new ClickIdParser();\n\n private readonly cookieCollector = new CookieCollector();\n\n private readonly customParams: readonly string[];\n\n private readonly captureUrlParams: boolean;\n\n private readonly captureCookies: boolean;\n\n constructor(\n options: {\n customParams?: readonly string[];\n captureUrlParams?: boolean;\n captureCookies?: boolean;\n } = {}\n ) {\n this.customParams = options.customParams ?? [];\n this.captureUrlParams = options.captureUrlParams !== false;\n this.captureCookies = options.captureCookies !== false;\n }\n\n collectFresh(): Partial<AttributionIdentifiers> {\n const fromUrl = this.captureUrlParams\n ? this.clickIdParser.parse(this.customParams)\n : {};\n const fromCookies = this.captureCookies\n ? this.cookieCollector.collectKnown()\n : {};\n\n const merged: Record<string, unknown> = {\n ...fromCookies,\n ...fromUrl,\n };\n\n const customClickIds = {\n ...((fromCookies as AttributionIdentifiers).customClickIds ?? {}),\n ...(fromUrl.customClickIds ?? {}),\n };\n if (Object.keys(customClickIds).length > 0) {\n merged.customClickIds = customClickIds;\n }\n\n if (typeof merged.fbclid === 'string' && merged.fbclid) {\n const fbc = this.clickIdParser.synthesizeFbc(\n merged.fbclid,\n typeof merged.fbc === 'string' ? merged.fbc : undefined\n );\n if (fbc) merged.fbc = fbc;\n }\n\n if (typeof window !== 'undefined') {\n try {\n merged.landingUrl = window.location.href;\n } catch {\n // ignore\n }\n }\n\n if (typeof document !== 'undefined') {\n try {\n if (document.referrer) merged.referrer = document.referrer;\n } catch {\n // ignore\n }\n }\n\n return merged as Partial<AttributionIdentifiers>;\n }\n\n /**\n * Merge: never overwrite existing defined values with undefined.\n */\n merge(\n existing: AttributionIdentifiers,\n incoming: Partial<AttributionIdentifiers>\n ): AttributionIdentifiers {\n const next: Record<string, unknown> = { ...existing };\n\n for (const [key, value] of Object.entries(incoming)) {\n if (value === undefined || value === null || value === '') continue;\n\n if (key === 'customClickIds' && typeof value === 'object') {\n next.customClickIds = {\n ...((existing.customClickIds as Record<string, string>) ?? {}),\n ...(value as Record<string, string>),\n };\n continue;\n }\n\n next[key] = value;\n }\n\n const now = Date.now();\n if (!existing.firstCollectedAt) {\n next.firstCollectedAt = now;\n }\n next.lastCollectedAt = now;\n\n return next as AttributionIdentifiers;\n }\n}\n","import type { StorageService } from '@/services/storage/types';\n\nimport { ATTRIBUTION_STORAGE_KEY, type AttributionIdentifiers } from './types';\n\n/**\n * Persists AttributionIdentifiers via StorageService only (no direct localStorage).\n */\nexport class AttributionStore {\n private readonly storage: StorageService;\n\n private readonly persist: boolean;\n\n private readonly ttlMs: number;\n\n private readonly storageKey: string;\n\n constructor(\n storage: StorageService,\n options: { persist: boolean; ttlDays: number; storageKey?: string }\n ) {\n this.storage = storage;\n this.persist = options.persist;\n this.ttlMs = options.ttlDays * 24 * 60 * 60 * 1000;\n this.storageKey = options.storageKey ?? ATTRIBUTION_STORAGE_KEY;\n }\n\n load(): AttributionIdentifiers | null {\n if (!this.persist) return null;\n\n try {\n const snapshot = this.storage.get<AttributionIdentifiers>(\n this.storageKey\n );\n if (!snapshot) return null;\n\n if (this.isExpired(snapshot)) {\n this.clear();\n return null;\n }\n\n return snapshot;\n } catch {\n return null;\n }\n }\n\n save(snapshot: AttributionIdentifiers): void {\n if (!this.persist) return;\n\n try {\n this.storage.set(this.storageKey, snapshot);\n } catch {\n // quota / SSR — keep in-memory only\n }\n }\n\n clear(): void {\n try {\n this.storage.remove(this.storageKey);\n } catch {\n // ignore\n }\n }\n\n private isExpired(snapshot: AttributionIdentifiers): boolean {\n const anchor = snapshot.lastCollectedAt ?? snapshot.firstCollectedAt;\n if (!anchor) return false;\n return Date.now() - anchor > this.ttlMs;\n }\n}\n","import type { StorageService } from '@/services/storage/types';\n\nimport { AttributionCollector } from './AttributionCollector';\nimport { AttributionStore } from './AttributionStore';\nimport {\n DEFAULT_ATTRIBUTION_CONFIG,\n type AttributionConfig,\n type AttributionIdentifiers,\n type AttributionService,\n} from './types';\n\nexport class AttributionServiceImpl implements AttributionService {\n private readonly store: AttributionStore;\n\n private readonly collector: AttributionCollector;\n\n private readonly enabled: boolean;\n\n private snapshot: AttributionIdentifiers = {};\n\n private active = false;\n\n constructor(\n storage: StorageService,\n config: AttributionConfig = DEFAULT_ATTRIBUTION_CONFIG\n ) {\n this.enabled = config.enabled !== false;\n this.store = new AttributionStore(storage, {\n persist: config.persist !== false,\n ttlDays: config.ttlDays ?? 90,\n });\n this.collector = new AttributionCollector({\n customParams: config.customClickIdParams ?? [],\n captureUrlParams: config.captureUrlParams !== false,\n captureCookies: config.captureCookies !== false,\n });\n }\n\n init(): void {\n if (this.active) return;\n this.active = true;\n\n if (!this.enabled) return;\n\n const stored = this.store.load();\n if (stored) {\n this.snapshot = stored;\n }\n\n this.collect();\n }\n\n destroy(): void {\n if (!this.active) return;\n this.active = false;\n }\n\n collect(): AttributionIdentifiers {\n if (!this.enabled) return this.snapshot;\n\n const fresh = this.collector.collectFresh();\n this.snapshot = this.collector.merge(this.snapshot, fresh);\n this.store.save(this.snapshot);\n return this.snapshot;\n }\n\n getSnapshot(): AttributionIdentifiers {\n return { ...this.snapshot };\n }\n\n update(partial: Partial<AttributionIdentifiers>): AttributionIdentifiers {\n this.snapshot = this.collector.merge(this.snapshot, partial);\n this.store.save(this.snapshot);\n return this.getSnapshot();\n }\n\n clear(): void {\n this.snapshot = {};\n this.store.clear();\n }\n}\n","import type { BrowserMetadata, BrowserMetadataService } from './types';\n\nexport class BrowserMetadataServiceImpl implements BrowserMetadataService {\n getMetadata(): BrowserMetadata {\n if (typeof window === 'undefined') {\n return {};\n }\n\n const timezone = (() => {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone;\n } catch {\n return undefined;\n }\n })();\n\n return {\n url: location.href,\n path: location.pathname,\n hostname: location.hostname,\n origin: location.origin,\n title: typeof document !== 'undefined' ? document.title : undefined,\n referrer: typeof document !== 'undefined' ? document.referrer : undefined,\n language: navigator.language,\n timezone,\n userAgent: navigator.userAgent,\n platform: navigator.platform,\n screenWidth: screen.width,\n screenHeight: screen.height,\n colorDepth: screen.colorDepth,\n };\n }\n}\n","import type { PixelEvent } from '@/events';\nimport type { PixelLogger } from '@/logger/PixelLogger';\n\nimport type { DispatcherService } from './types';\n\ntype EventListener = (event: PixelEvent) => void;\n\nconst MAX_ERROR_MESSAGE_LENGTH = 200;\n\n/**\n * Hardening 18.1 — falha de um listener não interrompe os demais nem propaga\n * para o produtor (trackers/engines). Log sanitizado, sem payload/PII.\n */\nexport class DispatcherServiceImpl implements DispatcherService {\n private readonly listeners = new Set<EventListener>();\n\n private lastEvent: PixelEvent | null = null;\n\n private readonly logger: Pick<PixelLogger, 'warn'> | undefined;\n\n constructor(logger?: Pick<PixelLogger, 'warn'>) {\n this.logger = logger;\n }\n\n dispatch(event: PixelEvent): void {\n this.lastEvent = event;\n\n // Snapshot: permite unsubscribe durante dispatch sem pular listeners.\n const snapshot = [...this.listeners];\n\n for (let index = 0; index < snapshot.length; index += 1) {\n const listener = snapshot[index];\n if (!listener) continue;\n\n try {\n listener(event);\n } catch (error) {\n this.logger?.warn(sanitizeDispatcherError(error, event.type, index));\n }\n }\n }\n\n subscribe(listener: (event: PixelEvent) => void): () => void {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n clear(): void {\n this.listeners.clear();\n this.lastEvent = null;\n }\n\n getListenerCount(): number {\n return this.listeners.size;\n }\n\n getLastEvent(): PixelEvent | null {\n return this.lastEvent;\n }\n}\n\nexport function sanitizeDispatcherError(\n error: unknown,\n eventType: string,\n listenerIndex: number\n): Record<string, unknown> {\n const name =\n error instanceof Error\n ? error.name\n : typeof error === 'object' && error !== null && 'name' in error\n ? String((error as { name: unknown }).name)\n : 'Error';\n\n let message =\n error instanceof Error\n ? error.message\n : typeof error === 'string'\n ? error\n : 'unknown';\n\n message = message\n .replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g, '[redacted]')\n .replace(/\\+?\\d[\\d\\s().-]{7,}\\d/g, '[redacted]');\n\n if (message.length > MAX_ERROR_MESSAGE_LENGTH) {\n message = `${message.slice(0, MAX_ERROR_MESSAGE_LENGTH)}…`;\n }\n\n return {\n code: 'DISPATCHER_LISTENER_FAILED',\n eventType,\n listenerIndex,\n errorName: name,\n message,\n timestamp: Date.now(),\n };\n}\n","import type { PixelConfig } from '@/config';\nimport type { BrowserMetadataService } from '@/services/browser-metadata';\nimport type { StorageService } from '@/services/storage';\n\nimport type { FingerprintService } from './types';\n\nconst DEFAULT_FINGERPRINT_KEY = 'fingerprint';\n\nfunction hashFingerprintInput(input: string): string {\n let hash = 0;\n\n for (let index = 0; index < input.length; index++) {\n hash = (hash << 5) - hash + input.charCodeAt(index);\n hash |= 0;\n }\n\n const positiveHash = Math.abs(hash).toString(16).padStart(8, '0');\n let secondaryHash = 0;\n\n for (let index = input.length - 1; index >= 0; index--) {\n secondaryHash =\n (secondaryHash << 5) - secondaryHash + input.charCodeAt(index);\n secondaryHash |= 0;\n }\n\n return `fp_${positiveHash}${Math.abs(secondaryHash).toString(16).padStart(8, '0')}`;\n}\n\nfunction computeLightFingerprint(\n metadataService: BrowserMetadataService\n): string {\n const metadata = metadataService.getMetadata();\n\n const components = [\n metadata.userAgent ?? '',\n metadata.language ?? '',\n metadata.platform ?? '',\n String(metadata.screenWidth ?? ''),\n String(metadata.screenHeight ?? ''),\n String(metadata.colorDepth ?? ''),\n metadata.timezone ?? '',\n ];\n\n return hashFingerprintInput(components.join('|'));\n}\n\nexport class FingerprintServiceImpl implements FingerprintService {\n private readonly storage: StorageService;\n\n private readonly storageKey: string;\n\n private readonly metadataService: BrowserMetadataService;\n\n constructor(\n storage: StorageService,\n config: PixelConfig,\n metadataService: BrowserMetadataService\n ) {\n this.storage = storage;\n this.storageKey =\n config.storage.keys?.fingerprint ?? DEFAULT_FINGERPRINT_KEY;\n this.metadataService = metadataService;\n }\n\n getFingerprint(): string | null {\n return this.storage.get<string>(this.storageKey);\n }\n\n ensureFingerprint(): string {\n const existing = this.getFingerprint();\n if (existing) return existing;\n\n const fingerprint = computeLightFingerprint(this.metadataService);\n this.storage.set(this.storageKey, fingerprint);\n return fingerprint;\n }\n}\n","import type { StorageAdapter } from './types';\n\nexport class BrowserStorageAdapter implements StorageAdapter {\n private readonly storage: Storage | null;\n\n private readonly memoryFallback = new Map<string, string>();\n\n constructor(storage: Storage) {\n this.storage = typeof window === 'undefined' ? null : storage;\n }\n\n get(key: string): string | null {\n if (this.storage) {\n return this.storage.getItem(key);\n }\n\n return this.memoryFallback.get(key) ?? null;\n }\n\n set(key: string, value: string): void {\n if (this.storage) {\n this.storage.setItem(key, value);\n return;\n }\n\n this.memoryFallback.set(key, value);\n }\n\n remove(key: string): void {\n if (this.storage) {\n this.storage.removeItem(key);\n return;\n }\n\n this.memoryFallback.delete(key);\n }\n\n clear(): void {\n // Never clear entire browser storage — namespace removal uses removeKeysMatching.\n if (!this.storage) {\n this.memoryFallback.clear();\n }\n }\n\n removeKeysMatching(predicate: (key: string) => boolean): void {\n if (this.storage) {\n const keysToRemove: string[] = [];\n\n for (let index = 0; index < this.storage.length; index++) {\n const key = this.storage.key(index);\n if (key && predicate(key)) {\n keysToRemove.push(key);\n }\n }\n\n for (const key of keysToRemove) {\n this.storage.removeItem(key);\n }\n\n return;\n }\n\n for (const key of this.memoryFallback.keys()) {\n if (predicate(key)) {\n this.memoryFallback.delete(key);\n }\n }\n }\n}\n","import type { StorageAdapter } from './types';\n\nexport class MemoryStorageAdapter implements StorageAdapter {\n private readonly store = new Map<string, string>();\n\n get(key: string): string | null {\n return this.store.get(key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(key, value);\n }\n\n remove(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n removeKeysMatching(predicate: (key: string) => boolean): void {\n for (const key of this.store.keys()) {\n if (predicate(key)) {\n this.store.delete(key);\n }\n }\n }\n}\n","import type { StorageAdapter, StorageService } from './types';\n\ntype NamespaceClearableAdapter = StorageAdapter & {\n removeKeysMatching(predicate: (key: string) => boolean): void;\n};\n\nfunction supportsNamespaceClear(\n adapter: StorageAdapter\n): adapter is NamespaceClearableAdapter {\n return (\n 'removeKeysMatching' in adapter &&\n typeof adapter.removeKeysMatching === 'function'\n );\n}\n\nexport class StorageServiceImpl implements StorageService {\n private readonly adapter: StorageAdapter;\n\n private readonly namespace: string;\n\n private readonly prefix?: string;\n\n constructor(adapter: StorageAdapter, namespace: string, prefix?: string) {\n this.adapter = adapter;\n this.namespace = namespace;\n this.prefix = prefix;\n }\n\n get<T>(key: string): T | null {\n const raw = this.adapter.get(this.createKey(key));\n if (raw === null) return null;\n\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n }\n\n set<T>(key: string, value: T): void {\n this.adapter.set(this.createKey(key), JSON.stringify(value));\n }\n\n remove(key: string): void {\n this.adapter.remove(this.createKey(key));\n }\n\n has(key: string): boolean {\n return this.adapter.get(this.createKey(key)) !== null;\n }\n\n clear(): void {\n const namespaceKeyPrefix = this.getNamespaceKeyPrefix();\n\n if (supportsNamespaceClear(this.adapter)) {\n this.adapter.removeKeysMatching(key =>\n key.startsWith(namespaceKeyPrefix)\n );\n return;\n }\n\n this.adapter.clear();\n }\n\n createKey(key: string): string {\n if (this.prefix) {\n return `${this.prefix}:${this.namespace}:${key}`;\n }\n\n return `${this.namespace}:${key}`;\n }\n\n private getNamespaceKeyPrefix(): string {\n if (this.prefix) {\n return `${this.prefix}:${this.namespace}:`;\n }\n\n return `${this.namespace}:`;\n }\n}\n","import type {\n AttributionStoragePersistence,\n QueueStoragePersistence,\n SessionStoragePersistence,\n VisitorStoragePersistence,\n} from '@/config/shared/persistence';\n\nimport { BrowserStorageAdapter } from './BrowserStorageAdapter';\nimport { MemoryStorageAdapter } from './MemoryStorageAdapter';\nimport type { StorageAdapter } from './types';\n\nexport type StoragePersistence =\n | VisitorStoragePersistence\n | SessionStoragePersistence\n | AttributionStoragePersistence\n | QueueStoragePersistence;\n\nexport function createStorageAdapter(\n persistence?: StoragePersistence\n): StorageAdapter {\n const mode = persistence ?? 'memory';\n\n if (typeof window === 'undefined') {\n return new MemoryStorageAdapter();\n }\n\n switch (mode) {\n case 'memory':\n return new MemoryStorageAdapter();\n case 'localStorage':\n return new BrowserStorageAdapter(window.localStorage);\n case 'sessionStorage':\n return new BrowserStorageAdapter(window.sessionStorage);\n case 'cookie_localStorage':\n // TODO: implementar cookie fallback.\n return new BrowserStorageAdapter(window.localStorage);\n case 'cookie':\n return new MemoryStorageAdapter();\n case 'indexedDB':\n return new MemoryStorageAdapter();\n default:\n return new MemoryStorageAdapter();\n }\n}\n\nexport function resolveStorageAdapterName(\n persistence?: StoragePersistence\n): string {\n const mode = persistence ?? 'memory';\n\n switch (mode) {\n case 'localStorage':\n case 'sessionStorage':\n case 'cookie_localStorage':\n return 'BrowserStorageAdapter';\n default:\n return 'MemoryStorageAdapter';\n }\n}\n","import type { CommerceProduct } from '@/config/shared/commerce';\n\nexport type ProductCatalogOptions = {\n readonly defaultCurrency?: string;\n};\n\nexport type ProductCatalogSnapshot = {\n readonly products: CommerceProduct[];\n readonly count: number;\n};\n\n/**\n * Catálogo de produtos configurados em `config.commerce.catalog`.\n * Isolado por instância — sem estado global / module-level.\n * Não acessa DOM, Transport nem altera payloads de eventos.\n */\nexport class ProductCatalog {\n private readonly productsById = new Map<string, CommerceProduct>();\n\n private readonly productsBySku = new Map<string, CommerceProduct>();\n\n private readonly orderedIds: string[] = [];\n\n constructor(\n products: readonly CommerceProduct[] | undefined = [],\n options: ProductCatalogOptions = {}\n ) {\n this.indexProducts(products ?? [], options.defaultCurrency);\n }\n\n list(): CommerceProduct[] {\n return this.orderedIds.map(id =>\n this.cloneProduct(this.productsById.get(id)!)\n );\n }\n\n getById(id: string): CommerceProduct | null {\n if (!id) return null;\n const product = this.productsById.get(id);\n return product ? this.cloneProduct(product) : null;\n }\n\n getBySku(sku: string): CommerceProduct | null {\n if (!sku) return null;\n const product = this.productsBySku.get(sku);\n return product ? this.cloneProduct(product) : null;\n }\n\n hasProduct(id: string): boolean {\n return Boolean(id) && this.productsById.has(id);\n }\n\n getSnapshot(): ProductCatalogSnapshot {\n const products = this.list();\n return { products, count: products.length };\n }\n\n private indexProducts(\n products: readonly CommerceProduct[],\n defaultCurrency?: string\n ): void {\n for (const raw of products) {\n if (!raw || typeof raw !== 'object') continue;\n\n const id = typeof raw.id === 'string' ? raw.id.trim() : '';\n if (!id) continue;\n\n // Duplicado por id: mantém o primeiro (determinístico).\n if (this.productsById.has(id)) continue;\n\n const product = this.normalizeProduct(raw, id, defaultCurrency);\n this.productsById.set(id, product);\n this.orderedIds.push(id);\n\n const sku = typeof product.sku === 'string' ? product.sku.trim() : '';\n if (sku && !this.productsBySku.has(sku)) {\n this.productsBySku.set(sku, product);\n }\n }\n }\n\n private normalizeProduct(\n raw: CommerceProduct,\n id: string,\n defaultCurrency?: string\n ): CommerceProduct {\n const sku =\n typeof raw.sku === 'string' && raw.sku.trim()\n ? raw.sku.trim()\n : undefined;\n\n const currency =\n typeof raw.currency === 'string' && raw.currency.trim()\n ? raw.currency.trim()\n : defaultCurrency;\n\n const quantity =\n typeof raw.quantity === 'number' && Number.isFinite(raw.quantity)\n ? raw.quantity\n : undefined;\n\n return {\n ...raw,\n id,\n ...(sku !== undefined ? { sku } : {}),\n ...(currency !== undefined ? { currency } : {}),\n ...(quantity !== undefined ? { quantity } : {}),\n ...(raw.metadata ? { metadata: { ...raw.metadata } } : {}),\n };\n }\n\n private cloneProduct(product: CommerceProduct): CommerceProduct {\n return {\n ...product,\n ...(product.metadata ? { metadata: { ...product.metadata } } : {}),\n };\n }\n}\n","import type { CommerceCartItem } from '@/config/shared/commerce';\n\nexport type CommerceStateOptions = {\n /**\n * Quando `false`, `upsertItem` só atualiza itens já presentes\n * (não adiciona novos productIds). Default: `true`.\n */\n readonly allowDynamicItems?: boolean;\n};\n\nexport type CommerceStateSnapshot = {\n /**\n * Estado vivo do carrinho (runtime).\n * Não confundir com `commerce.cart.initialItems` da config.\n */\n readonly selectedItems: CommerceCartItem[];\n readonly count: number;\n};\n\n/**\n * Estado em memória do cart da instância.\n * Inicializado com `config.commerce.cart.initialItems`.\n * Não persiste, não acessa DOM/Transport e não dispara eventos.\n */\nexport class CommerceState {\n private readonly itemsByProductId = new Map<string, CommerceCartItem>();\n\n private readonly allowDynamicItems: boolean;\n\n constructor(\n initialItems: readonly CommerceCartItem[] | undefined = [],\n options: CommerceStateOptions = {}\n ) {\n this.allowDynamicItems = options.allowDynamicItems !== false;\n this.seed(initialItems ?? []);\n }\n\n getSelectedItems(): CommerceCartItem[] {\n return Array.from(this.itemsByProductId.values()).map(item =>\n this.cloneItem(item)\n );\n }\n\n hasItem(productId: string): boolean {\n return Boolean(productId) && this.itemsByProductId.has(productId);\n }\n\n getItem(productId: string): CommerceCartItem | null {\n if (!productId) return null;\n const item = this.itemsByProductId.get(productId);\n return item ? this.cloneItem(item) : null;\n }\n\n /**\n * Insere ou atualiza item.\n * - Sem `productId` → no-op\n * - `selected === false` → remove se existir / não adiciona\n * - `quantity <= 0` → remove\n * - `allowDynamicItems === false` e item novo → no-op\n */\n upsertItem(item: CommerceCartItem): void {\n if (!item || typeof item !== 'object') return;\n\n const productId =\n typeof item.productId === 'string' ? item.productId.trim() : '';\n if (!productId) return;\n\n if (item.selected === false) {\n this.itemsByProductId.delete(productId);\n return;\n }\n\n const quantity = this.normalizeQuantity(item.quantity);\n if (quantity <= 0) {\n this.itemsByProductId.delete(productId);\n return;\n }\n\n const exists = this.itemsByProductId.has(productId);\n if (!exists && !this.allowDynamicItems) return;\n\n const previous = this.itemsByProductId.get(productId);\n const metadata = item.metadata\n ? { ...item.metadata }\n : previous?.metadata\n ? { ...previous.metadata }\n : undefined;\n\n const next: CommerceCartItem = {\n ...previous,\n ...item,\n productId,\n quantity,\n selected: true,\n ...(metadata ? { metadata } : {}),\n };\n\n this.itemsByProductId.set(productId, next);\n }\n\n removeItem(productId: string): void {\n if (!productId) return;\n this.itemsByProductId.delete(productId);\n }\n\n /**\n * Atualiza quantidade. `quantity <= 0` remove o item.\n */\n updateQuantity(productId: string, quantity: number): void {\n if (!productId || !this.itemsByProductId.has(productId)) return;\n\n const normalized = this.normalizeQuantity(quantity);\n if (normalized <= 0) {\n this.itemsByProductId.delete(productId);\n return;\n }\n\n const current = this.itemsByProductId.get(productId)!;\n this.itemsByProductId.set(productId, {\n ...current,\n quantity: normalized,\n });\n }\n\n clear(): void {\n this.itemsByProductId.clear();\n }\n\n getSnapshot(): CommerceStateSnapshot {\n const selectedItems = this.getSelectedItems();\n return { selectedItems, count: selectedItems.length };\n }\n\n private seed(initialItems: readonly CommerceCartItem[]): void {\n for (const item of initialItems) {\n // Seed ignora allowDynamicItems — itens da config sempre entram\n // (exceto selected:false / inválidos / quantity<=0).\n this.seedItem(item);\n }\n }\n\n private seedItem(item: CommerceCartItem): void {\n if (!item || typeof item !== 'object') return;\n\n const productId =\n typeof item.productId === 'string' ? item.productId.trim() : '';\n if (!productId) return;\n if (item.selected === false) return;\n\n const quantity = this.normalizeQuantity(item.quantity);\n if (quantity <= 0) return;\n\n // Duplicado por productId no seed: mantém o primeiro.\n if (this.itemsByProductId.has(productId)) return;\n\n this.itemsByProductId.set(productId, {\n ...item,\n productId,\n quantity,\n selected: true,\n ...(item.metadata ? { metadata: { ...item.metadata } } : {}),\n });\n }\n\n private normalizeQuantity(quantity: number | undefined): number {\n if (quantity === undefined || quantity === null) return 1;\n if (typeof quantity !== 'number' || !Number.isFinite(quantity)) return 1;\n return quantity;\n }\n\n private cloneItem(item: CommerceCartItem): CommerceCartItem {\n return {\n ...item,\n ...(item.metadata ? { metadata: { ...item.metadata } } : {}),\n };\n }\n}\n","/**\n * Calcula value/currency a partir de items resolvidos.\n * Não conhece DOM, detectors, Transport nem Dispatcher.\n * Não muta o input.\n */\n\nexport type ResolvedCommerceItem = {\n productId?: string;\n sku?: string;\n productName?: string;\n price?: number;\n quantity?: number;\n currency?: string;\n category?: string;\n variant?: string;\n brand?: string;\n type?: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type OrderCalculationInput = {\n items?: ResolvedCommerceItem[];\n value?: number;\n currency?: string;\n defaultCurrency?: string;\n};\n\nexport type OrderCalculationResult = {\n items: ResolvedCommerceItem[];\n value?: number;\n currency?: string;\n};\n\nexport class OrderCalculator {\n calculate(input: OrderCalculationInput): OrderCalculationResult {\n const sourceItems = Array.isArray(input.items) ? input.items : [];\n const items = sourceItems.map(item => this.cloneItem(item));\n\n for (const item of items) {\n if (item.quantity == null || !Number.isFinite(item.quantity)) {\n item.quantity = 1;\n }\n }\n\n const value =\n typeof input.value === 'number' && Number.isFinite(input.value)\n ? input.value\n : this.sumValue(items);\n\n const currency = this.resolveCurrency(input, items);\n\n return {\n items,\n ...(value !== undefined ? { value } : {}),\n ...(currency !== undefined ? { currency } : {}),\n };\n }\n\n private sumValue(items: ResolvedCommerceItem[]): number | undefined {\n let total = 0;\n let hasPriced = false;\n\n for (const item of items) {\n if (typeof item.price !== 'number' || !Number.isFinite(item.price)) {\n continue;\n }\n const qty =\n typeof item.quantity === 'number' && Number.isFinite(item.quantity)\n ? item.quantity\n : 1;\n total += item.price * qty;\n hasPriced = true;\n }\n\n return hasPriced ? total : undefined;\n }\n\n /**\n * Ordem: currency manual → primeiro item com currency → defaultCurrency.\n * Multi-currency: determinístico — usa o primeiro item com currency\n * (não normaliza conversão entre moedas nesta etapa).\n */\n private resolveCurrency(\n input: OrderCalculationInput,\n items: ResolvedCommerceItem[]\n ): string | undefined {\n if (typeof input.currency === 'string' && input.currency.trim()) {\n return input.currency.trim();\n }\n\n for (const item of items) {\n if (typeof item.currency === 'string' && item.currency.trim()) {\n return item.currency.trim();\n }\n }\n\n if (\n typeof input.defaultCurrency === 'string' &&\n input.defaultCurrency.trim()\n ) {\n return input.defaultCurrency.trim();\n }\n\n return undefined;\n }\n\n private cloneItem(item: ResolvedCommerceItem): ResolvedCommerceItem {\n return {\n ...item,\n ...(item.metadata ? { metadata: { ...item.metadata } } : {}),\n };\n }\n}\n","/**\n * Contratos globais de commerce (root `PixelConfig.commerce`).\n * Não pertencem a conversion — representam o contexto comercial da página/fluxo.\n */\n\nexport type ProductType =\n | 'main'\n | 'order_bump'\n | 'upsell'\n | 'downsell'\n | 'cross_sell'\n | 'addon'\n | 'subscription'\n | 'custom'\n | 'other';\n\nexport type CommerceProduct = {\n id: string;\n name?: string;\n sku?: string;\n type?: ProductType;\n price?: number;\n currency?: string;\n quantity?: number;\n category?: string;\n variant?: string;\n brand?: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type CommerceCartItem = {\n productId: string;\n quantity?: number;\n price?: number;\n currency?: string;\n selected?: boolean;\n metadata?: Record<string, unknown>;\n};\n\nexport type CommerceCartMode =\n | 'landing_page'\n | 'single_product'\n | 'multi_product'\n | 'checkout'\n | 'upsell'\n | 'custom'\n | 'cart'\n | 'funnel';\n\nexport type CommerceCalculateValueFrom =\n | 'cart'\n | 'event'\n | 'manual'\n | 'catalog';\n\nexport type CommerceEnrichmentSource =\n | 'cart'\n | 'event'\n | 'event_or_cart'\n | 'catalog';\n\nexport type CommerceEventEnrichmentConfig = {\n enabled: boolean;\n source?: CommerceEnrichmentSource;\n};\n\nexport type CommerceEnrichmentConfig = {\n pageView?: CommerceEventEnrichmentConfig;\n viewContent?: CommerceEventEnrichmentConfig;\n lead?: CommerceEventEnrichmentConfig;\n addToCart?: CommerceEventEnrichmentConfig;\n removeFromCart?: CommerceEventEnrichmentConfig;\n initiateCheckout?: CommerceEventEnrichmentConfig;\n addPaymentInfo?: CommerceEventEnrichmentConfig;\n purchase?: CommerceEventEnrichmentConfig;\n};\n\nexport type ProductCatalogConfig = {\n products?: CommerceProduct[];\n};\n\nexport type CommerceCartConfig = {\n mode?: CommerceCartMode;\n /** Seed inicial do carrinho — não é estado vivo. */\n initialItems?: CommerceCartItem[];\n allowDynamicItems?: boolean;\n calculateValueFrom?: CommerceCalculateValueFrom;\n metadata?: Record<string, unknown>;\n};\n\nexport type CommerceMappingsConfig = {\n attributes?: Record<string, string[]>;\n fields?: Record<string, string[]>;\n};\n\nexport type CommerceConfig = {\n enabled?: boolean;\n currency?: string;\n catalog?: ProductCatalogConfig;\n cart?: CommerceCartConfig;\n mappings?: CommerceMappingsConfig;\n enrichment?: CommerceEnrichmentConfig;\n};\n\nexport const DEFAULT_COMMERCE_ENRICHMENT: Required<CommerceEnrichmentConfig> = {\n pageView: { enabled: false, source: 'cart' },\n viewContent: { enabled: true, source: 'event_or_cart' },\n lead: { enabled: false, source: 'event_or_cart' },\n addToCart: { enabled: true, source: 'event_or_cart' },\n removeFromCart: { enabled: true, source: 'event_or_cart' },\n initiateCheckout: { enabled: true, source: 'cart' },\n addPaymentInfo: { enabled: true, source: 'cart' },\n purchase: { enabled: true, source: 'cart' },\n};\n\n/** Default seguro: commerce off, sem produtos, sem itens. */\nexport const DEFAULT_COMMERCE_CONFIG: CommerceConfig = {\n enabled: false,\n currency: 'BRL',\n catalog: {\n products: [],\n },\n cart: {\n mode: 'custom',\n initialItems: [],\n allowDynamicItems: true,\n calculateValueFrom: 'cart',\n },\n mappings: {\n attributes: {},\n fields: {},\n },\n enrichment: { ...DEFAULT_COMMERCE_ENRICHMENT },\n};\n\n/** Normaliza calculateValueFrom (inclui aliases legado em runtime). */\nexport function normalizeCalculateValueFrom(\n value: CommerceCalculateValueFrom | string | undefined\n): 'cart' | 'event' | 'manual' | 'catalog' {\n switch (value) {\n case 'event':\n case 'event_items':\n return 'event';\n case 'manual':\n return 'manual';\n case 'catalog':\n return 'catalog';\n case 'cart':\n case 'selected_items':\n default:\n return 'cart';\n }\n}\n","import type { CommerceCalculateValueFrom } from '@/config/shared/commerce';\nimport { normalizeCalculateValueFrom } from '@/config/shared/commerce';\nimport type { PixelItem } from '@/events/conversion';\n\nimport type { CommerceState } from './CommerceState';\nimport type { ProductCatalog } from './ProductCatalog';\nimport type { OrderCalculator, ResolvedCommerceItem } from './OrderCalculator';\n\nexport type CommerceEventType =\n | 'ADD_TO_CART'\n | 'REMOVE_FROM_CART'\n | 'INITIATE_CHECKOUT'\n | 'PURCHASE'\n | 'VIEW_CONTENT'\n | 'ADD_PAYMENT_INFO';\n\nexport type ExtractedProductInput = {\n productId?: string;\n productName?: string;\n price?: number;\n quantity?: number;\n currency?: string;\n sku?: string;\n};\n\nexport type CommerceResolverInput = {\n eventType: CommerceEventType;\n payload?: Record<string, unknown>;\n extractedProduct?: ExtractedProductInput;\n enrichmentSource?: import('@/config/shared/commerce').CommerceEnrichmentSource;\n items?: Array<{\n productId?: string;\n id?: string;\n sku?: string;\n name?: string;\n productName?: string;\n price?: number;\n quantity?: number;\n currency?: string;\n category?: string;\n }>;\n};\n\nexport type CommerceResolverResult = {\n data: Record<string, unknown>;\n items?: ResolvedCommerceItem[];\n value?: number;\n currency?: string;\n};\n\nexport type CommerceResolverOptions = {\n catalog: ProductCatalog;\n state: CommerceState;\n calculator: OrderCalculator;\n defaultCurrency?: string;\n calculateValueFrom?: CommerceCalculateValueFrom;\n};\n\n/**\n * Combina payload + extracted + state + catalog + defaults.\n * Não dispara eventos, não escreve em CommerceState, não conhece DOM/Transport.\n *\n * Prioridade de merge por campo:\n * manual payload > extractedProduct > commerce state > catalog > defaults\n */\nexport class CommerceResolver {\n private readonly catalog: ProductCatalog;\n\n private readonly state: CommerceState;\n\n private readonly calculator: OrderCalculator;\n\n private readonly defaultCurrency?: string;\n\n private readonly calculateValueFrom: ReturnType<\n typeof normalizeCalculateValueFrom\n >;\n\n constructor(options: CommerceResolverOptions) {\n this.catalog = options.catalog;\n this.state = options.state;\n this.calculator = options.calculator;\n this.defaultCurrency = trim(options.defaultCurrency);\n this.calculateValueFrom = normalizeCalculateValueFrom(\n options.calculateValueFrom\n );\n }\n\n resolve(input: CommerceResolverInput): CommerceResolverResult {\n const source = input.enrichmentSource;\n\n // source: 'event' — não completa via cart/catalog\n if (source === 'event') {\n return { data: { ...(input.payload ?? {}) } };\n }\n\n switch (input.eventType) {\n case 'ADD_TO_CART':\n return this.resolveAddToCart(input);\n case 'REMOVE_FROM_CART':\n return this.resolveRemoveFromCart(input);\n case 'INITIATE_CHECKOUT':\n return this.resolveCheckoutLike(input, false);\n case 'PURCHASE':\n return this.resolveCheckoutLike(input, true);\n case 'VIEW_CONTENT':\n return this.resolveViewContent(input);\n case 'ADD_PAYMENT_INFO':\n return this.resolveCheckoutLike(input, false);\n default:\n return { data: { ...(input.payload ?? {}) } };\n }\n }\n\n private resolveAddToCart(\n input: CommerceResolverInput\n ): CommerceResolverResult {\n const payload = input.payload ?? {};\n const extracted = input.extractedProduct ?? {};\n const source = input.enrichmentSource ?? 'event_or_cart';\n const useCart = source === 'cart' || source === 'event_or_cart';\n const useCatalog =\n source === 'catalog' || source === 'cart' || source === 'event_or_cart';\n\n let productId =\n asString(payload.priceId) ??\n asString(payload.productId) ??\n asString(extracted.productId) ??\n (useCatalog\n ? this.lookupIdBySku(asString(payload.sku) ?? asString(extracted.sku))\n : undefined);\n\n // Fallback: sem productId/sku no evento → item principal do cart\n const cartFallback =\n !productId && useCart ? this.resolvePrimaryCartItem() : null;\n if (!productId && cartFallback) {\n productId = cartFallback.productId;\n }\n\n const catalogProduct =\n useCatalog && productId\n ? this.catalog.getById(productId)\n : useCatalog\n ? this.lookupProductBySku(\n asString(payload.sku) ?? asString(extracted.sku)\n )\n : null;\n\n const resolvedId = productId ?? catalogProduct?.id;\n const stateItem =\n useCart && resolvedId\n ? (this.state.getItem(resolvedId) ?? cartFallback)\n : null;\n\n // source: 'catalog' sem productId/sku → não injeta cart\n if (source === 'catalog' && !resolvedId && !catalogProduct) {\n return { data: { ...payload } };\n }\n\n const productName =\n asString(payload.productName) ??\n asString(extracted.productName) ??\n catalogProduct?.name;\n\n const price =\n asNumber(payload.price) ??\n asNumber(extracted.price) ??\n (useCart ? asNumber(stateItem?.price) : undefined) ??\n catalogProduct?.price;\n\n const quantity =\n asNumber(payload.quantity) ??\n asNumber(extracted.quantity) ??\n (useCart ? asNumber(stateItem?.quantity) : undefined) ??\n catalogProduct?.quantity ??\n 1;\n\n const currency =\n asString(payload.currency) ??\n asString(extracted.currency) ??\n (useCart ? asString(stateItem?.currency) : undefined) ??\n catalogProduct?.currency ??\n this.defaultCurrency;\n\n const identity = resolveCatalogItemIdentity(catalogProduct, {\n priceId: asString(payload.priceId),\n productId: resolvedId,\n offerId: asString(payload.offerId),\n id: asString(payload.id),\n });\n\n const data: Record<string, unknown> = {};\n if (identity.id) data.id = identity.id;\n if (identity.priceId) data.priceId = identity.priceId;\n if (identity.productId) data.productId = identity.productId;\n if (identity.offerId) data.offerId = identity.offerId;\n if (productName) data.productName = productName;\n if (price !== undefined) data.price = price;\n if (currency) data.currency = currency;\n if (quantity !== undefined) data.quantity = quantity;\n\n // Preserva campos extras do payload (sem sobrescrever resolvidos).\n for (const [key, value] of Object.entries(payload)) {\n if (value === undefined) continue;\n if (!(key in data)) data[key] = value;\n }\n\n return { data };\n }\n\n /**\n * Escolhe o item principal do cart runtime:\n * 1. único item → esse\n * 2. múltiplos → preferir catalog.type === 'main'\n * 3. senão → primeiro do cart\n * 4. cart vazio → null\n */\n private resolvePrimaryCartItem(): {\n productId: string;\n quantity?: number;\n price?: number;\n currency?: string;\n } | null {\n const items = this.state.getSelectedItems();\n if (items.length === 0) return null;\n if (items.length === 1) return items[0] ?? null;\n\n const main = items.find(item => {\n const product = this.catalog.getById(item.productId);\n return product?.type === 'main';\n });\n return main ?? items[0] ?? null;\n }\n\n private resolveRemoveFromCart(\n input: CommerceResolverInput\n ): CommerceResolverResult {\n const payload = input.payload ?? {};\n const extracted = input.extractedProduct ?? {};\n\n const productId =\n asString(payload.productId) ??\n asString(extracted.productId) ??\n this.lookupIdBySku(asString(payload.sku) ?? asString(extracted.sku));\n\n const catalogProduct = productId ? this.catalog.getById(productId) : null;\n\n const resolvedId = productId ?? catalogProduct?.id;\n const stateItem = resolvedId ? this.state.getItem(resolvedId) : null;\n\n const quantity =\n asNumber(payload.quantity) ??\n asNumber(extracted.quantity) ??\n asNumber(stateItem?.quantity) ??\n 1;\n\n const data: Record<string, unknown> = {};\n if (resolvedId) data.productId = resolvedId;\n if (quantity !== undefined) data.quantity = quantity;\n\n for (const [key, value] of Object.entries(payload)) {\n if (value === undefined) continue;\n if (!(key in data)) data[key] = value;\n }\n\n return { data };\n }\n\n private resolveCheckoutLike(\n input: CommerceResolverInput,\n isPurchase: boolean\n ): CommerceResolverResult {\n const payload = { ...(input.payload ?? {}) };\n const manualValue = asNumber(payload.value);\n const manualCurrency = asString(payload.currency);\n const manualItems = this.readPayloadItems(input);\n const source = input.enrichmentSource;\n\n const resolvedItems = this.resolveItemsSource(manualItems, source);\n const pixelItems = resolvedItems.map(item => this.toPixelItem(item));\n\n const allowCalculatedValue =\n source !== 'catalog' && this.calculateValueFrom !== 'manual';\n\n const shouldCalculateValue =\n manualValue === undefined && allowCalculatedValue;\n\n const calc = this.calculator.calculate({\n items: resolvedItems,\n value: shouldCalculateValue ? undefined : manualValue,\n currency: manualCurrency,\n defaultCurrency: this.defaultCurrency,\n });\n\n const value =\n manualValue !== undefined\n ? manualValue\n : allowCalculatedValue\n ? calc.value\n : undefined;\n\n const currency = manualCurrency ?? calc.currency ?? this.defaultCurrency;\n\n const data: Record<string, unknown> = { ...payload };\n\n if (pixelItems.length > 0) {\n data.items = pixelItems;\n } else if (manualItems === null) {\n delete data.items;\n }\n\n if (value !== undefined) {\n data.value = value;\n } else {\n delete data.value;\n }\n\n if (currency) {\n data.currency = currency;\n }\n\n if (isPurchase) {\n // orderId e demais campos do payload já estão em data via spread.\n }\n\n return {\n data,\n items: calc.items,\n ...(value !== undefined ? { value } : {}),\n ...(currency ? { currency } : {}),\n };\n }\n\n private resolveViewContent(\n input: CommerceResolverInput\n ): CommerceResolverResult {\n const payload = { ...(input.payload ?? {}) };\n const source = input.enrichmentSource ?? 'event_or_cart';\n\n // Tenta completar productId/name/price a partir de payload + cart/catalog\n if (source === 'cart' || source === 'event_or_cart') {\n const atc = this.resolveAddToCart({\n ...input,\n eventType: 'ADD_TO_CART',\n enrichmentSource: source,\n });\n\n const checkout = this.resolveCheckoutLike(\n { ...input, eventType: 'INITIATE_CHECKOUT', enrichmentSource: source },\n false\n );\n\n const data: Record<string, unknown> = { ...payload };\n\n const contentId =\n asString(payload.contentId) ??\n asString(atc.data.productId as string | undefined) ??\n (Array.isArray(checkout.data.items) &&\n checkout.data.items[0] &&\n typeof (checkout.data.items[0] as { id?: unknown }).id === 'string'\n ? (checkout.data.items[0] as { id: string }).id\n : undefined);\n\n const contentName =\n asString(payload.contentName) ??\n asString(atc.data.productName as string | undefined) ??\n (Array.isArray(checkout.data.items) &&\n checkout.data.items[0] &&\n typeof (checkout.data.items[0] as { name?: unknown }).name === 'string'\n ? (checkout.data.items[0] as { name: string }).name\n : undefined);\n\n if (contentId) data.contentId = contentId;\n if (contentName) data.contentName = contentName;\n\n if (\n asNumber(payload.value) === undefined &&\n checkout.value !== undefined\n ) {\n data.value = checkout.value;\n }\n if (!asString(payload.currency) && checkout.currency) {\n data.currency = checkout.currency;\n }\n if (payload.items === undefined && Array.isArray(checkout.data.items)) {\n data.items = checkout.data.items;\n }\n\n return {\n data,\n ...(checkout.value !== undefined ? { value: checkout.value } : {}),\n ...(checkout.currency ? { currency: checkout.currency } : {}),\n items: checkout.items,\n };\n }\n\n if (source === 'catalog') {\n const atc = this.resolveAddToCart({\n ...input,\n eventType: 'ADD_TO_CART',\n enrichmentSource: 'catalog',\n });\n const data: Record<string, unknown> = { ...payload };\n if (atc.data.productId && !asString(payload.contentId)) {\n data.contentId = atc.data.productId;\n }\n if (atc.data.productName && !asString(payload.contentName)) {\n data.contentName = atc.data.productName;\n }\n if (\n atc.data.price !== undefined &&\n asNumber(payload.value) === undefined\n ) {\n data.value = atc.data.price;\n }\n if (atc.data.currency && !asString(payload.currency)) {\n data.currency = atc.data.currency;\n }\n return { data };\n }\n\n return { data: payload };\n }\n\n /**\n * null = payload não trouxe items (usar state conforme calculateValueFrom)\n * [] = payload trouxe items vazios\n */\n private readPayloadItems(\n input: CommerceResolverInput\n ): ResolvedCommerceItem[] | null {\n if (input.items) {\n return input.items.map(item => this.normalizeLooseItem(item));\n }\n\n const raw = input.payload?.items;\n if (raw === undefined) return null;\n if (!Array.isArray(raw)) return null;\n return raw.map(item =>\n this.normalizeLooseItem(\n (item && typeof item === 'object' ? item : {}) as Record<\n string,\n unknown\n >\n )\n );\n }\n\n private resolveItemsSource(\n manualItems: ResolvedCommerceItem[] | null,\n enrichmentSource?: import('@/config/shared/commerce').CommerceEnrichmentSource\n ): ResolvedCommerceItem[] {\n // Items manuais sempre vencem state.\n if (manualItems !== null) {\n return manualItems.map(item => this.enrichItem(item));\n }\n\n // source: 'catalog' — não injeta cart inteiro\n if (enrichmentSource === 'catalog') {\n return [];\n }\n\n // source: 'cart' força fallback do carrinho (independente de calculateValueFrom),\n // exceto quando calculateValueFrom === 'manual' (value/items só do payload).\n if (\n enrichmentSource === 'cart' &&\n this.calculateValueFrom !== 'manual' &&\n this.calculateValueFrom !== 'event'\n ) {\n return this.state.getSelectedItems().map(stateItem =>\n this.enrichItem({\n productId: stateItem.productId,\n price: stateItem.price,\n quantity: stateItem.quantity,\n currency: stateItem.currency,\n })\n );\n }\n\n if (this.calculateValueFrom === 'cart') {\n return this.state.getSelectedItems().map(stateItem =>\n this.enrichItem({\n productId: stateItem.productId,\n price: stateItem.price,\n quantity: stateItem.quantity,\n currency: stateItem.currency,\n })\n );\n }\n\n if (this.calculateValueFrom === 'catalog') {\n const fromState = this.state.getSelectedItems();\n if (fromState.length > 0) {\n return fromState.map(stateItem =>\n this.enrichItem({\n productId: stateItem.productId,\n price: stateItem.price,\n quantity: stateItem.quantity,\n currency: stateItem.currency,\n })\n );\n }\n return this.catalog.list().map(product =>\n this.enrichItem({\n productId: product.id,\n price: product.price,\n quantity: product.quantity ?? 1,\n currency: product.currency,\n productName: product.name,\n sku: product.sku,\n category: product.category,\n })\n );\n }\n\n // event / manual sem items no payload → sem items\n return [];\n }\n\n private enrichItem(item: ResolvedCommerceItem): ResolvedCommerceItem {\n const productId =\n item.productId ?? this.lookupIdBySku(item.sku) ?? undefined;\n const catalog = productId\n ? this.catalog.getById(productId)\n : this.lookupProductBySku(item.sku);\n\n const resolvedId = productId ?? catalog?.id;\n\n return {\n ...item,\n ...(resolvedId ? { productId: resolvedId } : {}),\n productName: item.productName ?? catalog?.name,\n sku: item.sku ?? catalog?.sku,\n price: item.price ?? catalog?.price,\n quantity: item.quantity ?? catalog?.quantity ?? 1,\n currency: item.currency ?? catalog?.currency ?? this.defaultCurrency,\n category: item.category ?? catalog?.category,\n variant: item.variant ?? catalog?.variant,\n brand: item.brand ?? catalog?.brand,\n type: item.type ?? catalog?.type,\n metadata: item.metadata ?? catalog?.metadata,\n };\n }\n\n private toPixelItem(item: ResolvedCommerceItem): PixelItem {\n const pixel: PixelItem = {\n ...(item.productId ? { id: item.productId } : {}),\n ...(item.productName ? { name: item.productName } : {}),\n ...(item.category ? { category: item.category } : {}),\n ...(item.price !== undefined ? { price: item.price } : {}),\n ...(item.quantity !== undefined ? { quantity: item.quantity } : {}),\n };\n return pixel;\n }\n\n private normalizeLooseItem(\n item:\n | Record<string, unknown>\n | {\n productId?: string;\n id?: string;\n sku?: string;\n name?: string;\n productName?: string;\n price?: number;\n quantity?: number;\n currency?: string;\n category?: string;\n }\n ): ResolvedCommerceItem {\n return {\n productId:\n asString((item as { productId?: unknown }).productId) ??\n asString((item as { id?: unknown }).id),\n sku: asString((item as { sku?: unknown }).sku),\n productName:\n asString((item as { productName?: unknown }).productName) ??\n asString((item as { name?: unknown }).name),\n price: asNumber((item as { price?: unknown }).price),\n quantity: asNumber((item as { quantity?: unknown }).quantity),\n currency: asString((item as { currency?: unknown }).currency),\n category: asString((item as { category?: unknown }).category),\n };\n }\n\n private lookupIdBySku(sku: string | undefined): string | undefined {\n if (!sku) return undefined;\n return this.catalog.getBySku(sku)?.id;\n }\n\n private lookupProductBySku(sku: string | undefined) {\n if (!sku) return null;\n return this.catalog.getBySku(sku);\n }\n}\n\nfunction resolveCatalogItemIdentity(\n catalogProduct: import('@/config/shared/commerce').CommerceProduct | null,\n incoming: {\n id?: string;\n priceId?: string;\n productId?: string;\n offerId?: string;\n }\n): {\n id?: string;\n priceId?: string;\n productId?: string;\n offerId?: string;\n} {\n const meta = catalogProduct?.metadata ?? {};\n const metaPriceId = asString(meta.priceId);\n const metaProductId = asString(meta.productId);\n const metaOfferId = asString(meta.offerId);\n\n // Identidade Bemony (id/priceId/offerId) só quando priceId explícito ou metadata.\n // Catálogo genérico do Core continua só com productId.\n const priceId = incoming.priceId ?? metaPriceId;\n if (!priceId) {\n const productId = incoming.productId ?? catalogProduct?.id;\n return {\n ...(incoming.id ? { id: incoming.id } : {}),\n ...(productId ? { productId } : {}),\n ...(incoming.offerId ? { offerId: incoming.offerId } : {}),\n };\n }\n\n return {\n id: incoming.id ?? priceId,\n priceId,\n productId: metaProductId ?? incoming.productId ?? priceId,\n offerId: metaOfferId ?? incoming.offerId ?? priceId,\n };\n}\n\nfunction asString(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;\n return value;\n}\n\nfunction trim(value: string | undefined): string | undefined {\n if (typeof value !== 'string') return undefined;\n const t = value.trim();\n return t.length > 0 ? t : undefined;\n}\n","import type {\n CommerceConfig,\n CommerceEnrichmentSource,\n CommerceEventEnrichmentConfig,\n} from '@/config/shared/commerce';\nimport {\n DEFAULT_COMMERCE_CONFIG,\n DEFAULT_COMMERCE_ENRICHMENT,\n normalizeCalculateValueFrom,\n} from '@/config/shared/commerce';\nimport type { PixelItem } from '@/events/conversion';\n\nimport { CommerceResolver } from './CommerceResolver';\nimport { CommerceState } from './CommerceState';\nimport { OrderCalculator } from './OrderCalculator';\nimport { ProductCatalog } from './ProductCatalog';\n\nexport type CommerceEnrichmentEvent =\n | 'pageView'\n | 'viewContent'\n | 'lead'\n | 'addToCart'\n | 'removeFromCart'\n | 'initiateCheckout'\n | 'addPaymentInfo'\n | 'purchase';\n\nexport type PageViewCommercePayload = {\n readonly value?: number;\n readonly currency?: string;\n readonly items?: PixelItem[];\n readonly contentId?: string;\n readonly contentName?: string;\n};\n\n/**\n * Serviço compartilhado de commerce (root config).\n * Usado por Core (PAGE_VIEW) e Conversion sem dependência circular\n * entre os módulos.\n */\nexport class CommerceService {\n readonly enabled: boolean;\n\n readonly config: CommerceConfig;\n\n readonly catalog: ProductCatalog;\n\n readonly state: CommerceState;\n\n private readonly resolver: CommerceResolver;\n\n constructor(config: CommerceConfig | undefined) {\n this.config = {\n ...DEFAULT_COMMERCE_CONFIG,\n ...config,\n catalog: {\n products: config?.catalog?.products ?? [],\n },\n cart: {\n ...DEFAULT_COMMERCE_CONFIG.cart,\n ...config?.cart,\n initialItems: config?.cart?.initialItems\n ? config.cart.initialItems.map(item => ({ ...item }))\n : [],\n },\n mappings: {\n attributes: { ...(config?.mappings?.attributes ?? {}) },\n fields: { ...(config?.mappings?.fields ?? {}) },\n },\n enrichment: {\n ...DEFAULT_COMMERCE_ENRICHMENT,\n ...config?.enrichment,\n },\n };\n\n this.enabled = this.config.enabled === true;\n\n this.catalog = new ProductCatalog(this.config.catalog?.products, {\n defaultCurrency: this.config.currency,\n });\n\n this.state = new CommerceState(this.config.cart?.initialItems, {\n allowDynamicItems: this.config.cart?.allowDynamicItems !== false,\n });\n\n this.resolver = new CommerceResolver({\n catalog: this.catalog,\n state: this.state,\n calculator: new OrderCalculator(),\n defaultCurrency: this.config.currency,\n calculateValueFrom: normalizeCalculateValueFrom(\n this.config.cart?.calculateValueFrom\n ),\n });\n }\n\n getEnrichment(event: CommerceEnrichmentEvent): CommerceEventEnrichmentConfig {\n const fromConfig = this.config.enrichment?.[event];\n const fallback = DEFAULT_COMMERCE_ENRICHMENT[event];\n return {\n enabled: fromConfig?.enabled ?? fallback.enabled,\n source: fromConfig?.source ?? fallback.source,\n };\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n isEnrichmentEnabled(event: CommerceEnrichmentEvent): boolean {\n return this.enabled && this.getEnrichment(event).enabled === true;\n }\n\n getEnrichmentSource(\n event: CommerceEnrichmentEvent\n ): CommerceEnrichmentSource {\n return this.getEnrichment(event).source ?? 'event_or_cart';\n }\n\n /**\n * Resolve payload de commerce para um evento conversion.\n * Retorna null quando enrichment está desabilitado (caller usa payload original).\n */\n resolveForEvent(\n event: CommerceEnrichmentEvent,\n eventType:\n | 'ADD_TO_CART'\n | 'REMOVE_FROM_CART'\n | 'INITIATE_CHECKOUT'\n | 'PURCHASE'\n | 'VIEW_CONTENT'\n | 'ADD_PAYMENT_INFO',\n payload: Record<string, unknown> = {}\n ): Record<string, unknown> | null {\n if (!this.isEnrichmentEnabled(event)) return null;\n\n const result = this.resolver.resolve({\n eventType,\n payload,\n enrichmentSource: this.getEnrichmentSource(event),\n });\n\n return result.data;\n }\n\n /**\n * Payload de commerce para PAGE_VIEW quando enrichment.pageView.enabled.\n * Não depende de ConversionEngine.\n */\n resolvePageViewEnrichment(): PageViewCommercePayload | null {\n if (!this.isEnrichmentEnabled('pageView')) return null;\n\n const source = this.getEnrichment('pageView').source ?? 'cart';\n if (source === 'event') return null;\n\n const resolved = this.resolver.resolve({\n eventType: 'INITIATE_CHECKOUT',\n payload: {},\n });\n\n const items = (resolved.data.items as PixelItem[] | undefined) ?? [];\n const first = items[0];\n const contentId =\n first && typeof first.id === 'string' ? first.id : undefined;\n const contentName =\n first && typeof first.name === 'string' ? first.name : undefined;\n\n if (\n resolved.value === undefined &&\n !resolved.currency &&\n items.length === 0\n ) {\n return null;\n }\n\n return {\n ...(resolved.value !== undefined ? { value: resolved.value } : {}),\n ...(resolved.currency ? { currency: resolved.currency } : {}),\n ...(items.length > 0 ? { items } : {}),\n ...(contentId ? { contentId } : {}),\n ...(contentName ? { contentName } : {}),\n };\n }\n\n getResolver(): CommerceResolver {\n return this.resolver;\n }\n\n getCalculateValueFrom(): ReturnType<typeof normalizeCalculateValueFrom> {\n return normalizeCalculateValueFrom(this.config.cart?.calculateValueFrom);\n }\n\n getMappings() {\n return this.config.mappings;\n }\n}\n","function createRandomSuffix(): string {\n if (\n typeof crypto !== 'undefined' &&\n typeof crypto.randomUUID === 'function'\n ) {\n return crypto.randomUUID().replace(/-/g, '');\n }\n\n return `${Date.now()}${Math.random().toString(36).slice(2)}`;\n}\n\nexport function generateSessionId(): string {\n return `ses_${createRandomSuffix()}`;\n}\n","import type { PixelConfig } from '@/config';\nimport type { StorageService } from '@/services/storage';\n\nimport type { EnsureSessionResult, SessionData, SessionService } from './types';\nimport { generateSessionId } from './session-id';\n\nconst DEFAULT_SESSION_KEY = 'session';\n\nexport class SessionServiceImpl implements SessionService {\n private readonly storage: StorageService;\n\n private readonly storageKey: string;\n\n constructor(storage: StorageService, config: PixelConfig) {\n this.storage = storage;\n this.storageKey = config.storage.keys?.session ?? DEFAULT_SESSION_KEY;\n }\n\n getSessionId(): string | null {\n return this.getSessionData()?.sessionId ?? null;\n }\n\n getSessionData(): SessionData | null {\n const raw = this.storage.get<SessionData | string>(this.storageKey);\n if (!raw) return null;\n\n if (typeof raw === 'string') {\n const now = Date.now();\n return {\n sessionId: raw,\n lastActivityAt: now,\n createdAt: now,\n };\n }\n\n return raw;\n }\n\n getLastActivityAt(): number | null {\n return this.getSessionData()?.lastActivityAt ?? null;\n }\n\n isExpired(ttlMs: number): boolean {\n const data = this.getSessionData();\n if (!data) return true;\n\n return Date.now() - data.lastActivityAt > ttlMs;\n }\n\n ensureSession(ttlMs: number): EnsureSessionResult {\n const data = this.getSessionData();\n const now = Date.now();\n\n if (!data) {\n const sessionId = generateSessionId();\n this.writeSessionData({\n sessionId,\n lastActivityAt: now,\n createdAt: now,\n });\n\n return {\n sessionId,\n expired: false,\n created: true,\n };\n }\n\n if (now - data.lastActivityAt > ttlMs) {\n const previousSessionId = data.sessionId;\n const sessionId = generateSessionId();\n\n this.writeSessionData({\n sessionId,\n lastActivityAt: now,\n createdAt: now,\n });\n\n return {\n sessionId,\n expired: true,\n previousSessionId,\n created: false,\n };\n }\n\n return {\n sessionId: data.sessionId,\n expired: false,\n created: false,\n };\n }\n\n ensureSessionId(): string {\n return this.ensureSession(Number.MAX_SAFE_INTEGER).sessionId;\n }\n\n touchActivity(): void {\n const data = this.getSessionData();\n if (!data) return;\n\n this.writeSessionData({\n ...data,\n lastActivityAt: Date.now(),\n });\n }\n\n renew(): string {\n const now = Date.now();\n const sessionId = generateSessionId();\n\n this.writeSessionData({\n sessionId,\n lastActivityAt: now,\n createdAt: now,\n });\n\n return sessionId;\n }\n\n clear(): void {\n this.storage.remove(this.storageKey);\n }\n\n private writeSessionData(data: SessionData): void {\n this.storage.set(this.storageKey, data);\n }\n}\n","function createRandomSuffix(): string {\n if (\n typeof crypto !== 'undefined' &&\n typeof crypto.randomUUID === 'function'\n ) {\n return crypto.randomUUID().replace(/-/g, '');\n }\n\n return `${Date.now()}${Math.random().toString(36).slice(2)}`;\n}\n\nexport function generateVisitorId(): string {\n return `vst_${createRandomSuffix()}`;\n}\n","import type { PixelConfig } from '@/config';\nimport type { StorageService } from '@/services/storage';\n\nimport type { VisitorService } from './types';\nimport { generateVisitorId } from './visitor-id';\n\nconst DEFAULT_VISITOR_KEY = 'visitor';\n\nexport class VisitorServiceImpl implements VisitorService {\n private readonly storage: StorageService;\n\n private readonly storageKey: string;\n\n constructor(storage: StorageService, config: PixelConfig) {\n this.storage = storage;\n this.storageKey = config.storage.keys?.visitor ?? DEFAULT_VISITOR_KEY;\n }\n\n getVisitorId(): string | null {\n return this.storage.get<string>(this.storageKey);\n }\n\n ensureVisitorId(): string {\n const existing = this.getVisitorId();\n if (existing) return existing;\n\n const visitorId = generateVisitorId();\n this.storage.set(this.storageKey, visitorId);\n return visitorId;\n }\n\n clearVisitorId(): void {\n this.storage.remove(this.storageKey);\n }\n}\n","/** Constantes default de UrlContext — denylist, domínios e selectors. */\n\nexport const DEFAULT_URL_CONTEXT_DENYLIST: readonly string[] = [\n 'token',\n 'access_token',\n 'refresh_token',\n 'id_token',\n 'password',\n 'pass',\n 'pwd',\n 'email',\n 'phone',\n 'cpf',\n 'cnpj',\n 'document',\n 'card',\n 'cc',\n 'credit_card',\n 'cvv',\n 'cvc',\n 'auth',\n 'code',\n 'sessionId',\n 'internalSessionId',\n 'pixelSessionId',\n];\n\nexport const DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS: readonly string[] = [\n 'facebook.com',\n 'google.com',\n 'youtube.com',\n 'instagram.com',\n 'wa.me',\n 'whatsapp.com',\n 't.me',\n 'telegram.me',\n];\n\nexport const DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS: readonly string[] = [\n '[data-no-url-context]',\n '[download]',\n];\n\nexport const SID_EXCLUDE_SELECTOR = '[data-no-sid]';\n\nexport const DEFAULT_URL_CONTEXT_SID_MAX_AGE_MS = 1000 * 60 * 60 * 24 * 30;\n","import {\n DEFAULT_URL_CONTEXT_DENYLIST,\n DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS,\n DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS,\n SID_EXCLUDE_SELECTOR,\n} from './constants';\n\nexport function normalizeParamKey(key: string): string {\n return key.trim().toLowerCase();\n}\n\n/** decodeURIComponent seguro — URI malformada não quebra o collector. */\nexport function safeDecodeURIComponent(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nexport function buildDenylistSet(\n userDenylist: readonly string[] | undefined,\n mergeDefault: boolean | undefined\n): Set<string> {\n const set = new Set<string>();\n if (mergeDefault !== false) {\n for (const key of DEFAULT_URL_CONTEXT_DENYLIST) {\n set.add(normalizeParamKey(key));\n }\n }\n for (const key of userDenylist ?? []) {\n if (typeof key === 'string' && key.trim()) {\n set.add(normalizeParamKey(key));\n }\n }\n return set;\n}\n\nexport function buildExcludedDomains(\n userExcluded: readonly string[] | undefined,\n mergeDefault: boolean | undefined\n): string[] {\n const list: string[] = [];\n if (mergeDefault !== false) {\n list.push(...DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS);\n }\n for (const domain of userExcluded ?? []) {\n if (typeof domain === 'string' && domain.trim()) {\n list.push(domain.trim().toLowerCase());\n }\n }\n return Array.from(new Set(list.map(d => d.toLowerCase())));\n}\n\nexport function buildExcludeSelectors(\n userSelectors: readonly string[] | undefined,\n mergeDefault: boolean | undefined,\n includeSidSelector: boolean\n): string[] {\n const list: string[] = [];\n if (mergeDefault !== false) {\n list.push(...DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS);\n }\n if (includeSidSelector) {\n list.push(SID_EXCLUDE_SELECTOR);\n }\n for (const sel of userSelectors ?? []) {\n if (typeof sel === 'string' && sel.trim()) {\n list.push(sel.trim());\n }\n }\n return Array.from(new Set(list));\n}\n\nexport function isDeniedKey(key: string, denylist: Set<string>): boolean {\n return denylist.has(normalizeParamKey(key));\n}\n\nexport function hostMatchesDomain(hostname: string, domain: string): boolean {\n const host = hostname.toLowerCase().replace(/\\.$/, '');\n // remove porta se vier colada por engano\n const hostNoPort = host.replace(/:\\d+$/, '');\n const target = domain.toLowerCase().replace(/^\\./, '').replace(/:\\d+$/, '');\n return hostNoPort === target || hostNoPort.endsWith(`.${target}`);\n}\n\nexport function isDomainAllowed(\n hostname: string,\n allowedDomains: '*' | string[] | undefined,\n excludedDomains: readonly string[]\n): boolean {\n /**\n * Hostname vazio (ex.: `file://` + link relativo / same-origin local).\n * Permitido apenas com sentinel `local` ou allow-all `*`.\n */\n if (!hostname) {\n if (allowedDomains === undefined || allowedDomains === '*') return true;\n return allowedDomains.some(\n domain => domain.trim().toLowerCase() === 'local'\n );\n }\n\n for (const excluded of excludedDomains) {\n if (hostMatchesDomain(hostname, excluded)) return false;\n }\n\n if (allowedDomains === undefined || allowedDomains === '*') return true;\n\n return allowedDomains.some(domain => {\n const normalized = domain.trim().toLowerCase();\n // Sentinel `local` não é hostname real\n if (normalized === 'local') return false;\n return hostMatchesDomain(hostname, domain);\n });\n}\n\n/** Gera ID público: `sid_<ts_base36>_<random>` — sem PII / session / visitor. */\nexport function generatePublicId(prefix = 'sid'): string {\n const safePrefix = (prefix || 'sid').replace(/[^a-zA-Z0-9_-]/g, '') || 'sid';\n const ts = Date.now().toString(36);\n const random = Math.random().toString(36).slice(2, 10);\n return `${safePrefix}_${ts}_${random}`;\n}\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * replaceState silencioso — usa History.prototype para não disparar\n * NavigationObserver / SPA PAGE_VIEW do Core.\n */\nexport function silentReplaceState(url: string): void {\n if (!isBrowser()) return;\n try {\n History.prototype.replaceState.call(\n history,\n history.state,\n document.title,\n url\n );\n } catch {\n // ignore — SSR / environments sem History\n }\n}\n\n/**\n * Parse de query string.\n * - duplicados: último valor vence (payload simples / idempotente)\n * - encoding malformado: não lança\n * - `+` → espaço\n */\nexport function parseSearchParams(search: string): Record<string, string> {\n const result: Record<string, string> = {};\n if (!search || search === '?') return result;\n\n const raw = search.startsWith('?') ? search.slice(1) : search;\n if (!raw) return result;\n\n for (const part of raw.split('&')) {\n if (!part) continue;\n const eq = part.indexOf('=');\n const key = safeDecodeURIComponent(\n (eq >= 0 ? part.slice(0, eq) : part).replace(/\\+/g, ' ')\n ).trim();\n if (!key) continue;\n const value =\n eq >= 0\n ? safeDecodeURIComponent(part.slice(eq + 1).replace(/\\+/g, ' '))\n : '';\n result[key] = value;\n }\n\n return result;\n}\n\nexport function buildSearchString(params: Record<string, string>): string {\n const pairs: string[] = [];\n for (const [key, value] of Object.entries(params)) {\n if (!key) continue;\n pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value ?? '')}`);\n }\n return pairs.length > 0 ? `?${pairs.join('&')}` : '';\n}\n\n/** Cópia rasa congelada — evita mutação externa do snapshot. */\nexport function freezeRecord(\n record: Record<string, string>\n): Readonly<Record<string, string>> {\n return Object.freeze({ ...record });\n}\n\n/**\n * Reformata href decorado preservando forma relativa quando possível.\n * Garante `path?query#hash` (nunca `path#hash?query`).\n */\nexport function formatDecoratedHref(originalHref: string, url: URL): string {\n const trimmed = originalHref.trim();\n const search = url.search || '';\n const hash = url.hash || '';\n\n if (trimmed.startsWith('//')) {\n return `//${url.host}${url.pathname}${search}${hash}`;\n }\n\n if (/^[a-zA-Z][a-zA-Z\\d+\\-.]*:/.test(trimmed)) {\n // absolute com scheme (http, https, ...)\n return url.toString();\n }\n\n if (trimmed.startsWith('/')) {\n return `${url.pathname}${search}${hash}`;\n }\n\n if (trimmed.startsWith('#')) {\n return `${search}${hash}`;\n }\n\n // relativo: checkout, ./checkout, ../checkout\n const pathPart = trimmed.split(/[?#]/)[0] ?? trimmed;\n return `${pathPart}${search}${hash}`;\n}\n","import type { UrlQueryParamsConfig } from '@/config/shared/url-context';\n\nimport {\n buildDenylistSet,\n isBrowser,\n isDeniedKey,\n normalizeParamKey,\n parseSearchParams,\n} from './utils';\n\n/**\n * Lê `window.location.search`, aplica allow/deny e retorna snapshot sanitizado.\n */\nexport class QueryParamCollector {\n collect(config: UrlQueryParamsConfig | undefined): Record<string, string> {\n if (!config || config.enabled === false) return {};\n if (!isBrowser()) return {};\n\n const raw = parseSearchParams(window.location.search);\n const denylist = buildDenylistSet(\n config.denylist,\n config.mergeDefaultDenylist\n );\n const mode = config.mode ?? 'all_except';\n const allowlist = new Set(\n (config.allowlist ?? []).map(normalizeParamKey).filter(Boolean)\n );\n\n const result: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(raw)) {\n if (isDeniedKey(key, denylist)) continue;\n if (mode === 'allowlist' && !allowlist.has(normalizeParamKey(key))) {\n continue;\n }\n // valores vazios: omitir (mantém payload limpo)\n if (value === '') continue;\n result[key] = value;\n }\n\n return result;\n }\n}\n","import type {\n UrlContextSource,\n UrlManagedParamConfig,\n} from '@/config/shared/url-context';\n\nimport type { UrlContextStore } from './UrlContextStore';\nimport {\n buildSearchString,\n generatePublicId,\n isBrowser,\n parseSearchParams,\n silentReplaceState,\n} from './utils';\n\nexport type ManagedParamResolution = {\n values: Record<string, string>;\n sources: Record<string, UrlContextSource>;\n decorateParams: Record<string, string>;\n};\n\n/**\n * Resolve managed params: URL → cookie → storage → generated.\n * Persiste e opcionalmente escreve na URL via replaceState silencioso.\n */\nexport class ManagedParamResolver {\n private readonly store: UrlContextStore;\n\n constructor(store: UrlContextStore) {\n this.store = store;\n }\n\n resolve(configs: readonly UrlManagedParamConfig[]): ManagedParamResolution {\n const values: Record<string, string> = {};\n const sources: Record<string, UrlContextSource> = {};\n const decorateParams: Record<string, string> = {};\n const urlWrites: Record<string, string> = {};\n\n const currentParams = isBrowser()\n ? parseSearchParams(window.location.search)\n : {};\n\n for (const config of configs) {\n const param = config.param?.trim();\n if (!param) continue;\n\n const mode = config.mode ?? 'read_write';\n const canRead = mode === 'read_only' || mode === 'read_write';\n const canWrite = mode === 'write_only' || mode === 'read_write';\n\n let value: string | null = null;\n let source: UrlContextSource | null = null;\n\n if (canRead) {\n const fromUrl = currentParams[param];\n if (fromUrl && fromUrl.length > 0) {\n value = fromUrl;\n source = 'url';\n }\n }\n\n if (!value && canRead && config.persistence?.enabled !== false) {\n const cookieName = config.persistence?.cookie?.name?.trim() || param;\n if (config.persistence?.cookie?.enabled !== false) {\n const fromCookie = this.store.getCookie(cookieName);\n if (fromCookie) {\n value = fromCookie;\n source = 'cookie';\n }\n }\n }\n\n if (!value && canRead && config.persistence?.enabled !== false) {\n const storageKey = config.persistence?.storageKey?.trim() || param;\n const fromStorage = this.store.getStorage(storageKey);\n if (fromStorage) {\n value = fromStorage;\n source = 'storage';\n }\n }\n\n if (!value && canWrite && config.generator?.type === 'public_id') {\n value = generatePublicId(config.generator.prefix ?? param);\n source = 'generated';\n }\n\n if (!value || !source) continue;\n\n values[param] = value;\n sources[param] = source;\n\n if (config.decorateLinks !== false) {\n decorateParams[param] = value;\n }\n\n // Persist always when we have a value and persistence enabled\n if (config.persistence?.enabled !== false) {\n this.persist(config, value);\n }\n\n // Write to URL if strategy allows and value missing/different on URL\n if (\n canWrite &&\n (config.writeStrategy ?? 'replaceState') === 'replaceState' &&\n isBrowser()\n ) {\n const existing = currentParams[param];\n if (existing !== value) {\n urlWrites[param] = value;\n }\n }\n }\n\n if (Object.keys(urlWrites).length > 0 && isBrowser()) {\n this.writeToUrl(urlWrites);\n }\n\n return { values, sources, decorateParams };\n }\n\n /**\n * Aplica valor externo após o resolve inicial (sem generator).\n * Persiste e opcionalmente escreve na URL.\n */\n applyExternalValue(config: UrlManagedParamConfig, value: string): void {\n const trimmed = value.trim();\n if (!trimmed) return;\n\n if (config.persistence?.enabled !== false) {\n this.persist(config, trimmed);\n }\n\n if (\n (config.writeStrategy ?? 'replaceState') === 'replaceState' &&\n isBrowser()\n ) {\n this.writeToUrl({ [config.param]: trimmed });\n }\n }\n\n private persist(config: UrlManagedParamConfig, value: string): void {\n const strategy = config.persistence?.strategy ?? 'localStorage_cookie';\n const storageKey = config.persistence?.storageKey?.trim() || config.param;\n const cookieCfg = config.persistence?.cookie;\n const cookieName = cookieCfg?.name?.trim() || config.param;\n\n if (strategy === 'storage' || strategy === 'localStorage_cookie') {\n this.store.setStorage(storageKey, value);\n }\n\n if (\n (strategy === 'cookie' || strategy === 'localStorage_cookie') &&\n cookieCfg?.enabled !== false\n ) {\n this.store.setCookie({\n name: cookieName,\n value,\n path: cookieCfg?.path ?? '/',\n domain: cookieCfg?.domain ?? 'auto',\n sameSite: cookieCfg?.sameSite ?? 'Lax',\n secure: cookieCfg?.secure ?? true,\n maxAgeMs: cookieCfg?.maxAgeMs,\n });\n }\n }\n\n private writeToUrl(writes: Record<string, string>): void {\n const current = parseSearchParams(window.location.search);\n const next = { ...current, ...writes };\n const search = buildSearchString(next);\n const hash = window.location.hash ?? '';\n const path = window.location.pathname + search + hash;\n silentReplaceState(path);\n }\n}\n","import type { UrlForwardParamsConfig } from '@/config/shared/url-context';\n\nimport { buildDenylistSet, isDeniedKey, normalizeParamKey } from './utils';\n\n/**\n * Decide quais params (não gerenciados) propagar em links.\n * Não gera nem persiste — só filtra.\n */\nexport class ForwardParamResolver {\n resolve(input: {\n queryParams: Record<string, string>;\n managedValues: Record<string, string>;\n config: UrlForwardParamsConfig | undefined;\n }): Record<string, string> {\n const { queryParams, managedValues, config } = input;\n if (!config || config.enabled === false) return {};\n\n const denylist = buildDenylistSet(\n config.denylist,\n config.mergeDefaultDenylist\n );\n const mode = config.mode ?? 'all_except';\n const allowlist = new Set(\n (config.allowlist ?? []).map(normalizeParamKey).filter(Boolean)\n );\n\n const result: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(queryParams)) {\n if (!value) continue;\n if (isDeniedKey(key, denylist)) continue;\n if (key in managedValues) continue; // managed tem prioridade\n if (mode === 'allowlist' && !allowlist.has(normalizeParamKey(key))) {\n continue;\n }\n result[key] = value;\n }\n\n return result;\n }\n}\n","import type { UrlLinkDecorationConfig } from '@/config/shared/url-context';\n\nimport {\n buildExcludeSelectors,\n buildExcludedDomains,\n buildSearchString,\n formatDecoratedHref,\n isBrowser,\n isDomainAllowed,\n parseSearchParams,\n} from './utils';\n\nconst BLOCKED_PROTOCOLS = [\n 'mailto:',\n 'tel:',\n 'javascript:',\n 'data:',\n 'blob:',\n] as const;\n\nexport type LinkDecoratorOptions = {\n forwardedParams?: Readonly<Record<string, string>>;\n managedParams?: Readonly<Record<string, string>>;\n config: UrlLinkDecorationConfig;\n /**\n * Quando true, inclui `[data-no-sid]` nos exclude selectors.\n * Semântica legada: exclusão remove toda a decoração do link.\n */\n includeSidExclude?: boolean;\n};\n\n/**\n * Decora links com forwarded + managed params (grupos separados).\n *\n * Ordem:\n * 1. query existente do link\n * 2. forwarded (respeita preserveExisting / overwriteExisting)\n * 3. managed (sempre autoritativo)\n * 4. dedupe / remontagem\n *\n * Strategies: on_click | on_init | both.\n */\nexport class LinkDecorator {\n private readonly forwardedParams: Readonly<Record<string, string>>;\n\n private managedParams: Readonly<Record<string, string>>;\n\n private readonly config: UrlLinkDecorationConfig;\n\n private readonly excludedDomains: readonly string[];\n\n private readonly excludeSelectors: readonly string[];\n\n private clickHandler: ((event: MouseEvent) => void) | null = null;\n\n private started = false;\n\n constructor(\n paramsOrOptions: Record<string, string> | LinkDecoratorOptions,\n config?: UrlLinkDecorationConfig,\n includeSidExclude?: boolean\n ) {\n if (isLinkDecoratorOptions(paramsOrOptions)) {\n this.forwardedParams = Object.freeze({\n ...(paramsOrOptions.forwardedParams ?? {}),\n });\n this.managedParams = Object.freeze({\n ...(paramsOrOptions.managedParams ?? {}),\n });\n this.config = paramsOrOptions.config;\n this.excludedDomains = buildExcludedDomains(\n paramsOrOptions.config.excludedDomains,\n paramsOrOptions.config.mergeDefaultExcludedDomains\n );\n this.excludeSelectors = buildExcludeSelectors(\n paramsOrOptions.config.excludeSelectors,\n paramsOrOptions.config.mergeDefaultExcludeSelectors,\n paramsOrOptions.includeSidExclude === true\n );\n return;\n }\n\n // Legado: params flat tratados como managed (autoritativos).\n const flat = paramsOrOptions;\n const resolvedConfig = config!;\n this.forwardedParams = Object.freeze({});\n this.managedParams = Object.freeze({ ...flat });\n this.config = resolvedConfig;\n this.excludedDomains = buildExcludedDomains(\n resolvedConfig.excludedDomains,\n resolvedConfig.mergeDefaultExcludedDomains\n );\n this.excludeSelectors = buildExcludeSelectors(\n resolvedConfig.excludeSelectors,\n resolvedConfig.mergeDefaultExcludeSelectors,\n includeSidExclude === true\n );\n }\n\n /**\n * Atualiza managed params após o start (ex.: `oid` registrado no checkout).\n * Reaplica decoração on_init/both nos links já presentes.\n */\n updateManagedParams(managedParams: Readonly<Record<string, string>>): void {\n this.managedParams = Object.freeze({ ...managedParams });\n if (!this.started || !isBrowser()) return;\n if (this.config.enabled === false) return;\n const strategy = this.config.strategy ?? 'on_click';\n if (strategy === 'on_init' || strategy === 'both') {\n this.decorateMatchingLinks();\n }\n }\n\n start(): void {\n if (this.started || !isBrowser()) return;\n if (this.config.enabled === false) return;\n if (\n Object.keys(this.forwardedParams).length === 0 &&\n Object.keys(this.managedParams).length === 0\n ) {\n return;\n }\n\n this.started = true;\n const strategy = this.config.strategy ?? 'on_click';\n\n if (strategy === 'on_init' || strategy === 'both') {\n this.decorateMatchingLinks();\n }\n\n if (strategy === 'on_click' || strategy === 'both') {\n this.clickHandler = (event: MouseEvent) => {\n const anchor = findAnchor(event.target);\n if (!anchor) return;\n if (this.isExcludedAnchor(anchor)) return;\n this.decorateAnchor(anchor);\n };\n document.addEventListener('click', this.clickHandler, true);\n }\n }\n\n destroy(): void {\n if (!this.started) return;\n if (this.clickHandler && typeof document !== 'undefined') {\n document.removeEventListener('click', this.clickHandler, true);\n }\n this.clickHandler = null;\n this.started = false;\n }\n\n /** Expõe para testes e uso interno. */\n decorateHref(href: string, baseHostname?: string): string | null {\n if (!href || href.trim() === '') return null;\n\n const trimmed = href.trim();\n const lower = trimmed.toLowerCase();\n\n for (const proto of BLOCKED_PROTOCOLS) {\n if (!lower.startsWith(proto)) continue;\n if (proto === 'mailto:' && this.config.decorateMailto === true) {\n return null;\n }\n if (proto === 'tel:' && this.config.decorateTel === true) {\n return null;\n }\n return null;\n }\n\n if (trimmed.startsWith('#') && this.config.decorateHashLinks !== true) {\n return null;\n }\n\n let url: URL;\n try {\n const base = isBrowser()\n ? window.location.href\n : `https://${baseHostname ?? 'example.com'}/`;\n url = new URL(trimmed, base);\n } catch {\n return null;\n }\n\n if (\n !isDomainAllowed(\n url.hostname,\n this.config.allowedDomains,\n this.excludedDomains\n )\n ) {\n return null;\n }\n\n const existing = parseSearchParams(url.search);\n const preserve = this.config.preserveExisting !== false;\n const overwrite = this.config.overwriteExisting === true;\n const next: Record<string, string> = { ...existing };\n let changed = false;\n\n // 1) Forwarded — respeitam preserveExisting / overwriteExisting\n for (const [key, value] of Object.entries(this.forwardedParams)) {\n if (key in next && preserve && !overwrite) {\n continue;\n }\n if (next[key] !== value) changed = true;\n next[key] = value;\n }\n\n // 2) Managed — sempre autoritativos\n for (const [key, value] of Object.entries(this.managedParams)) {\n if (next[key] !== value) changed = true;\n next[key] = value;\n }\n\n const originalParsed = parseSearchParams(\n trimmed.includes('?')\n ? (trimmed.slice(trimmed.indexOf('?')).split('#')[0] ?? '')\n : ''\n );\n const hadDuplicateKeys =\n countQueryKeys(trimmed) > Object.keys(originalParsed).length;\n\n if (!changed && !hadDuplicateKeys) {\n return trimmed;\n }\n\n const search = buildSearchString(next);\n url.search = search.startsWith('?') ? search.slice(1) : search;\n return formatDecoratedHref(trimmed, url);\n }\n\n private decorateMatchingLinks(): void {\n // Sem selector: todas as âncoras; filtro real é allowedDomains em decorateHref\n const selector = this.config.selector ?? 'a[href]';\n let nodes: NodeListOf<Element>;\n try {\n nodes = document.querySelectorAll(selector);\n } catch {\n return;\n }\n for (const node of nodes) {\n if (!(node instanceof HTMLAnchorElement)) continue;\n if (this.isExcludedAnchor(node)) continue;\n this.decorateAnchor(node);\n }\n }\n\n private isExcludedAnchor(anchor: HTMLAnchorElement): boolean {\n if (anchor.hasAttribute('download')) return true;\n\n for (const sel of this.excludeSelectors) {\n try {\n if (anchor.matches(sel)) return true;\n } catch {\n // selector inválido — ignorar\n }\n }\n\n return false;\n }\n\n private decorateAnchor(anchor: HTMLAnchorElement): void {\n const href = anchor.getAttribute('href');\n if (!href) return;\n const next = this.decorateHref(href);\n if (next != null && next !== href) {\n anchor.setAttribute('href', next);\n }\n }\n}\n\nfunction isLinkDecoratorOptions(\n value: Record<string, string> | LinkDecoratorOptions\n): value is LinkDecoratorOptions {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'config' in value &&\n typeof (value as LinkDecoratorOptions).config === 'object' &&\n (value as LinkDecoratorOptions).config !== null\n );\n}\n\nfunction findAnchor(target: EventTarget | null): HTMLAnchorElement | null {\n if (!(target instanceof Element)) return null;\n return target.closest('a[href]');\n}\n\n/** Conta chaves brutas na query (inclui duplicadas). */\nfunction countQueryKeys(href: string): number {\n const qIndex = href.indexOf('?');\n if (qIndex < 0) return 0;\n const hashIndex = href.indexOf('#', qIndex);\n const raw =\n hashIndex >= 0 ? href.slice(qIndex + 1, hashIndex) : href.slice(qIndex + 1);\n if (!raw) return 0;\n return raw.split('&').filter(Boolean).length;\n}\n","import type { StorageService } from '@/services/storage/types';\n\nimport { isBrowser, safeDecodeURIComponent } from './utils';\n\nexport type CookieWriteOptions = {\n name: string;\n value: string;\n path?: string;\n domain?: 'auto' | string;\n sameSite?: 'Lax' | 'Strict' | 'None';\n secure?: boolean;\n maxAgeMs?: number;\n};\n\n/**\n * Persistência de managed params — storage + cookie SSR-safe.\n * Não acessa DOM/localStorage em import time.\n */\nexport class UrlContextStore {\n private readonly storage: StorageService | null;\n\n constructor(storage?: StorageService | null) {\n this.storage = storage ?? null;\n }\n\n getStorage(key: string): string | null {\n if (!this.storage) return null;\n try {\n const value = this.storage.get<string>(key);\n return typeof value === 'string' && value.length > 0 ? value : null;\n } catch {\n return null;\n }\n }\n\n setStorage(key: string, value: string): void {\n if (!this.storage) return;\n try {\n this.storage.set(key, value);\n } catch {\n // quota / private mode\n }\n }\n\n getCookie(name: string): string | null {\n if (!isBrowser()) return null;\n try {\n const cookies = document.cookie ? document.cookie.split(';') : [];\n for (const part of cookies) {\n const idx = part.indexOf('=');\n const key = (idx >= 0 ? part.slice(0, idx) : part).trim();\n if (key !== name) continue;\n const raw = idx >= 0 ? part.slice(idx + 1).trim() : '';\n return safeDecodeURIComponent(raw);\n }\n } catch {\n return null;\n }\n return null;\n }\n\n setCookie(options: CookieWriteOptions): void {\n if (!isBrowser()) return;\n\n const parts = [\n `${encodeURIComponent(options.name)}=${encodeURIComponent(options.value)}`,\n ];\n\n parts.push(`path=${options.path ?? '/'}`);\n\n const domain = resolveCookieDomain(options.domain);\n if (domain) {\n parts.push(`domain=${domain}`);\n }\n\n if (\n typeof options.maxAgeMs === 'number' &&\n Number.isFinite(options.maxAgeMs)\n ) {\n parts.push(`max-age=${Math.max(0, Math.floor(options.maxAgeMs / 1000))}`);\n }\n\n const sameSite = options.sameSite ?? 'Lax';\n parts.push(`SameSite=${sameSite}`);\n\n const secure =\n options.secure === true ||\n (typeof location !== 'undefined' && location.protocol === 'https:');\n if (secure) {\n parts.push('Secure');\n }\n\n try {\n document.cookie = parts.join('; ');\n } catch {\n // ignore\n }\n }\n}\n\nfunction resolveCookieDomain(\n domain: 'auto' | string | undefined\n): string | null {\n if (!domain || domain === 'auto') {\n if (!isBrowser()) return null;\n const host = location.hostname;\n // localhost / IPs: não forçar domain\n if (\n host === 'localhost' ||\n host === '127.0.0.1' ||\n /^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n !host.includes('.')\n ) {\n return null;\n }\n return host;\n }\n return domain;\n}\n","import type {\n UrlContextConfig,\n UrlForwardParamsConfig,\n UrlLinkDecorationConfig,\n UrlManagedParamConfig,\n UrlQueryParamsConfig,\n} from '@/config/shared/url-context';\n\nimport { DEFAULT_URL_CONTEXT_SID_MAX_AGE_MS } from './constants';\n\nexport const DEFAULT_SID_MANAGED_PARAM: UrlManagedParamConfig = {\n key: 'public_session',\n param: 'sid',\n mode: 'read_write',\n writeStrategy: 'replaceState',\n generator: {\n type: 'public_id',\n prefix: 'sid',\n },\n persistence: {\n enabled: true,\n strategy: 'localStorage_cookie',\n storageKey: 'sid',\n cookie: {\n enabled: true,\n name: 'sid',\n domain: 'auto',\n path: '/',\n sameSite: 'Lax',\n secure: true,\n maxAgeMs: DEFAULT_URL_CONTEXT_SID_MAX_AGE_MS,\n },\n },\n decorateLinks: true,\n};\n\nexport const DEFAULT_QUERY_PARAMS_WHEN_ENABLED: Required<\n Pick<UrlQueryParamsConfig, 'enabled' | 'mode' | 'mergeDefaultDenylist'>\n> &\n UrlQueryParamsConfig = {\n enabled: true,\n mode: 'all_except',\n mergeDefaultDenylist: true,\n};\n\nexport const DEFAULT_FORWARD_PARAMS_WHEN_ENABLED: Required<\n Pick<UrlForwardParamsConfig, 'enabled' | 'mode' | 'mergeDefaultDenylist'>\n> &\n UrlForwardParamsConfig = {\n enabled: true,\n mode: 'all_except',\n mergeDefaultDenylist: true,\n};\n\nexport const DEFAULT_LINK_DECORATION_WHEN_ENABLED: UrlLinkDecorationConfig = {\n enabled: true,\n strategy: 'on_click',\n selector: 'a[href]',\n allowedDomains: '*',\n mergeDefaultExcludedDomains: true,\n mergeDefaultExcludeSelectors: true,\n preserveExisting: true,\n overwriteExisting: false,\n decorateHashLinks: false,\n decorateMailto: false,\n decorateTel: false,\n};\n\n/**\n * Resolve config parcial → efetiva.\n * - `enabled: false` → feature off\n * - `enabled: true` sem nested → aplica defaults úteis (inclui sid)\n * - `managedParams: []` → não cria sid\n */\nexport function resolveUrlContextConfig(\n raw: UrlContextConfig | undefined\n): Required<Pick<UrlContextConfig, 'enabled'>> & {\n queryParams: UrlQueryParamsConfig;\n managedParams: UrlManagedParamConfig[];\n forwardParams: UrlForwardParamsConfig;\n linkDecoration: UrlLinkDecorationConfig;\n} {\n if (!raw || raw.enabled !== true) {\n return {\n enabled: false,\n queryParams: { enabled: false },\n managedParams: [],\n forwardParams: { enabled: false },\n linkDecoration: { enabled: false },\n };\n }\n\n const managedParams =\n raw.managedParams !== undefined\n ? raw.managedParams.map(cloneManagedParam)\n : [cloneManagedParam(DEFAULT_SID_MANAGED_PARAM)];\n\n return {\n enabled: true,\n queryParams: {\n ...DEFAULT_QUERY_PARAMS_WHEN_ENABLED,\n ...raw.queryParams,\n ...(raw.queryParams?.allowlist\n ? { allowlist: [...raw.queryParams.allowlist] }\n : {}),\n ...(raw.queryParams?.denylist\n ? { denylist: [...raw.queryParams.denylist] }\n : {}),\n },\n managedParams,\n forwardParams: {\n ...DEFAULT_FORWARD_PARAMS_WHEN_ENABLED,\n ...raw.forwardParams,\n ...(raw.forwardParams?.allowlist\n ? { allowlist: [...raw.forwardParams.allowlist] }\n : {}),\n ...(raw.forwardParams?.denylist\n ? { denylist: [...raw.forwardParams.denylist] }\n : {}),\n },\n linkDecoration: {\n ...DEFAULT_LINK_DECORATION_WHEN_ENABLED,\n ...raw.linkDecoration,\n ...(raw.linkDecoration?.allowedDomains &&\n raw.linkDecoration.allowedDomains !== '*'\n ? { allowedDomains: [...raw.linkDecoration.allowedDomains] }\n : {}),\n ...(raw.linkDecoration?.excludedDomains\n ? { excludedDomains: [...raw.linkDecoration.excludedDomains] }\n : {}),\n ...(raw.linkDecoration?.excludeSelectors\n ? { excludeSelectors: [...raw.linkDecoration.excludeSelectors] }\n : {}),\n },\n };\n}\n\nfunction cloneManagedParam(\n param: UrlManagedParamConfig\n): UrlManagedParamConfig {\n return {\n ...param,\n ...(param.generator ? { generator: { ...param.generator } } : {}),\n ...(param.persistence\n ? {\n persistence: {\n ...param.persistence,\n ...(param.persistence.cookie\n ? { cookie: { ...param.persistence.cookie } }\n : {}),\n },\n }\n : {}),\n };\n}\n","import type {\n UrlContextConfig,\n UrlContextPayload,\n UrlContextSnapshot,\n UrlContextSource,\n UrlManagedParamConfig,\n} from '@/config/shared/url-context';\nimport type { StorageService } from '@/services/storage/types';\n\nimport { ForwardParamResolver } from './ForwardParamResolver';\nimport { LinkDecorator } from './LinkDecorator';\nimport { ManagedParamResolver } from './ManagedParamResolver';\nimport { QueryParamCollector } from './QueryParamCollector';\nimport { resolveUrlContextConfig } from './resolve-config';\nimport { UrlContextStore } from './UrlContextStore';\nimport { freezeRecord } from './utils';\n/**\n * Orquestra UrlContext: collect → manage → forward → decorate → snapshot.\n * SSR-safe; init/destroy idempotentes.\n */\nexport class UrlContextService {\n private readonly storage: StorageService | null;\n\n private readonly rawConfig: UrlContextConfig | undefined;\n\n private readonly collector = new QueryParamCollector();\n\n private readonly forwardResolver = new ForwardParamResolver();\n\n private store: UrlContextStore | null = null;\n\n private managedResolver: ManagedParamResolver | null = null;\n\n private decorator: LinkDecorator | null = null;\n\n private snapshot: UrlContextSnapshot = emptySnapshot();\n\n private managedConfigs: readonly UrlManagedParamConfig[] = [];\n\n private decorateManaged: Record<string, string> = {};\n\n private initialized = false;\n\n private enabled = false;\n\n constructor(\n config: UrlContextConfig | undefined,\n storage?: StorageService | null\n ) {\n this.rawConfig = config;\n this.storage = storage ?? null;\n }\n\n init(): void {\n if (this.initialized) return;\n this.initialized = true;\n\n const resolved = resolveUrlContextConfig(this.rawConfig);\n this.enabled = resolved.enabled;\n this.managedConfigs = resolved.managedParams;\n\n if (!resolved.enabled) {\n this.snapshot = emptySnapshot();\n return;\n }\n\n this.store = new UrlContextStore(this.storage);\n this.managedResolver = new ManagedParamResolver(this.store);\n\n const queryParams = this.collector.collect(resolved.queryParams);\n const managed = this.managedResolver.resolve(resolved.managedParams);\n\n // Após replaceState, query params podem já incluir sid — re-coleta leve\n const queryAfter =\n Object.keys(managed.values).length > 0\n ? this.collector.collect(resolved.queryParams)\n : queryParams;\n\n const forwarded = this.forwardResolver.resolve({\n queryParams: queryAfter,\n managedValues: managed.values,\n config: resolved.forwardParams,\n });\n\n const source: Record<string, UrlContextSource> = {\n ...managed.sources,\n };\n for (const key of Object.keys(forwarded)) {\n if (!source[key]) {\n source[key] = 'url';\n }\n }\n\n const urlContext: UrlContextPayload = {\n ...(Object.keys(managed.values).length > 0\n ? { managed: freezeRecord(managed.values) }\n : {}),\n ...(Object.keys(forwarded).length > 0\n ? { forwarded: freezeRecord(forwarded) }\n : {}),\n ...(Object.keys(source).length > 0\n ? { source: Object.freeze({ ...source }) }\n : {}),\n };\n this.snapshot = {\n queryParams: freezeRecord(queryAfter),\n urlContext: Object.freeze(urlContext),\n };\n\n const decorateForwarded = freezeRecord(forwarded);\n this.decorateManaged = { ...managed.decorateParams };\n\n const hasSid = resolved.managedParams.some(\n p => p.param === 'sid' && p.decorateLinks !== false\n );\n\n this.decorator = new LinkDecorator({\n forwardedParams: decorateForwarded,\n managedParams: freezeRecord(this.decorateManaged),\n config: resolved.linkDecoration,\n includeSidExclude: hasSid,\n });\n this.decorator.start();\n }\n\n /**\n * Define ou substitui um managed param após o init (ex.: `oid` no checkout).\n * Idempotente para o mesmo valor. Persistência e decoração seguem a config do param.\n *\n * @returns false se UrlContext desabilitado, não inicializado ou param não configurado.\n */\n setManagedParam(param: string, value: string): boolean {\n if (!this.initialized || !this.enabled || !this.managedResolver) {\n return false;\n }\n\n const key = param.trim();\n const trimmed = value.trim();\n if (!key || !trimmed) {\n return false;\n }\n\n const config = this.managedConfigs.find(c => c.param === key);\n if (!config) {\n return false;\n }\n\n const current = this.snapshot.urlContext.managed?.[key];\n if (current === trimmed) {\n return true;\n }\n\n this.managedResolver.applyExternalValue(config, trimmed);\n\n const managed = {\n ...(this.snapshot.urlContext.managed ?? {}),\n [key]: trimmed,\n };\n const source = {\n ...(this.snapshot.urlContext.source ?? {}),\n [key]: 'manual' as const,\n };\n\n // Re-coleta query após possível replaceState\n const resolved = resolveUrlContextConfig(this.rawConfig);\n const queryAfter = this.collector.collect(resolved.queryParams);\n\n this.snapshot = {\n queryParams: freezeRecord(queryAfter),\n urlContext: Object.freeze({\n managed: freezeRecord(managed),\n ...(this.snapshot.urlContext.forwarded\n ? { forwarded: freezeRecord(this.snapshot.urlContext.forwarded) }\n : {}),\n source: Object.freeze({ ...source }),\n }),\n };\n\n if (config.decorateLinks !== false) {\n this.decorateManaged = { ...this.decorateManaged, [key]: trimmed };\n this.decorator?.updateManagedParams(this.decorateManaged);\n // Se decorator ainda não startou (sem params no init), cria agora\n if (!this.decorator && resolved.enabled) {\n const hasSid = this.managedConfigs.some(\n p => p.param === 'sid' && p.decorateLinks !== false\n );\n this.decorator = new LinkDecorator({\n forwardedParams: freezeRecord(\n this.snapshot.urlContext.forwarded ?? {}\n ),\n managedParams: freezeRecord(this.decorateManaged),\n config: resolved.linkDecoration,\n includeSidExclude: hasSid,\n });\n this.decorator.start();\n }\n }\n\n return true;\n }\n\n destroy(): void {\n this.decorator?.destroy();\n this.decorator = null;\n this.managedResolver = null;\n this.store = null;\n this.managedConfigs = [];\n this.decorateManaged = {};\n this.initialized = false;\n this.enabled = false;\n this.snapshot = emptySnapshot();\n }\n\n /** Alias de destroy — cleanup completo sem listeners/refs. */\n dispose(): void {\n this.destroy();\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n getSnapshot(): UrlContextSnapshot {\n return {\n queryParams: freezeRecord(this.snapshot.queryParams),\n urlContext: {\n ...(this.snapshot.urlContext.managed\n ? { managed: freezeRecord(this.snapshot.urlContext.managed) }\n : {}),\n ...(this.snapshot.urlContext.forwarded\n ? { forwarded: freezeRecord(this.snapshot.urlContext.forwarded) }\n : {}),\n ...(this.snapshot.urlContext.source\n ? {\n source: Object.freeze({\n ...this.snapshot.urlContext.source,\n }),\n }\n : {}),\n },\n };\n }\n getQueryParams(): Record<string, string> {\n return { ...this.snapshot.queryParams };\n }\n\n getUrlContext(): UrlContextPayload {\n return this.getSnapshot().urlContext;\n }\n}\n\nfunction emptySnapshot(): UrlContextSnapshot {\n return {\n queryParams: freezeRecord({}),\n urlContext: Object.freeze({}),\n };\n}\n","import type { PixelConfig } from '@/config';\nimport { BaseEventBuilder } from '@/events/builder';\nimport { ConsolePixelLogger, type PixelLogger } from '@/logger';\nimport {\n AttributionServiceImpl,\n DEFAULT_ATTRIBUTION_CONFIG,\n} from '@/services/attribution';\nimport { BrowserMetadataServiceImpl } from '@/services/browser-metadata/BrowserMetadataService';\nimport { DispatcherServiceImpl } from '@/services/dispatcher/DispatcherService';\nimport { FingerprintServiceImpl } from '@/services/fingerprint/FingerprintService';\nimport { createStorageAdapter, StorageServiceImpl } from '@/services/storage';\nimport type { StoragePersistence } from '@/services/storage/StorageFactory';\nimport { CommerceService } from '@/services/commerce';\nimport { SessionServiceImpl } from '@/services/session/SessionService';\nimport type { PixelRuntimeServices } from '@/services/types';\nimport { VisitorServiceImpl } from '@/services/visitor/VisitorService';\nimport { UrlContextService } from '@/modules/core/url-context';\n\nimport { ModuleRegistry } from './ModuleRegistry';\nimport type { PixelRuntimeContext } from './PixelRuntimeContext';\nimport type { ModuleName } from './shared/module';\nimport type { PixelModule } from './types';\n\nexport class PixelRuntime {\n private initialized = false;\n\n private readonly initializedModules: PixelModule[] = [];\n\n private readonly registry: ModuleRegistry;\n\n private readonly config: PixelConfig;\n\n private readonly fallbackLogger: ConsolePixelLogger;\n\n private context: PixelRuntimeContext | null = null;\n\n constructor(config: PixelConfig) {\n this.config = config;\n this.registry = new ModuleRegistry();\n this.fallbackLogger = new ConsolePixelLogger(config.app.debug === true);\n }\n\n register(module: PixelModule): void {\n this.registry.register(module);\n }\n\n async init(): Promise<void> {\n if (this.initialized) {\n this.getLogger().debug('[PixelRuntime] Runtime already initialized');\n return;\n }\n\n this.fallbackLogger.debug('[PixelRuntime] Initializing runtime');\n\n this.context = this.createContext();\n this.context.services.attribution.init();\n\n for (const module of this.registry.getAll()) {\n if (!this.isModuleEnabled(module)) {\n this.fallbackLogger.debug(\n `[PixelRuntime] Skipping disabled module: ${module.name}`\n );\n continue;\n }\n\n this.fallbackLogger.debug(\n `[PixelRuntime] Initializing module: ${module.name}`\n );\n\n try {\n await module.init(this.context);\n this.initializedModules.push(module);\n } catch (error) {\n this.fallbackLogger.error(\n `[Pixel] Failed to initialize module \"${module.name}\"`,\n error\n );\n }\n }\n\n this.initialized = true;\n }\n\n async destroy(): Promise<void> {\n if (!this.initialized) return;\n\n const logger = this.getLogger();\n\n for (let index = this.initializedModules.length - 1; index >= 0; index--) {\n const module = this.initializedModules[index];\n\n logger.debug(`[PixelRuntime] Destroying module: ${module.name}`);\n\n try {\n await module.destroy?.();\n } catch (error) {\n logger.error(\n `[Pixel] Failed to destroy module \"${module.name}\"`,\n error\n );\n }\n }\n\n this.context?.services.attribution.destroy();\n this.context?.services.dispatcher.clear();\n\n this.initialized = false;\n this.initializedModules.length = 0;\n this.context = null;\n\n this.fallbackLogger.debug('[PixelRuntime] Runtime destroyed');\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /** @internal For playground and development only. Not part of the stable public API. */\n getDebugServices(): PixelRuntimeServices | null {\n return this.context?.services ?? null;\n }\n\n /** @internal Read-only diagnostics — names of modules that completed init. */\n getInitializedModuleNames(): readonly string[] {\n return this.initializedModules.map(m => m.name);\n }\n\n /** @internal Registered module names (all registered, regardless of enabled). */\n getRegisteredModuleNames(): readonly string[] {\n return this.registry.getAll().map(m => m.name);\n }\n\n private createServices(logger: PixelLogger): PixelRuntimeServices {\n const { namespace, prefix, persistence } = this.config.storage;\n\n const visitorStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.visitor\n );\n const sessionStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.session\n );\n const fingerprintStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.attribution\n );\n const attributionStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.attribution ?? 'localStorage'\n );\n const storage = this.createStorageService(namespace, prefix, 'memory');\n const browserMetadata = new BrowserMetadataServiceImpl();\n\n const attribution = new AttributionServiceImpl(\n attributionStorage,\n this.config.attribution ?? DEFAULT_ATTRIBUTION_CONFIG\n );\n\n const urlContextStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.attribution ?? 'localStorage'\n );\n const urlContext = new UrlContextService(\n this.config.modules.core.urlContext,\n urlContextStorage\n );\n\n const eventBuilder = new BaseEventBuilder(\n browserMetadata,\n attribution,\n urlContext\n );\n\n const visitor = new VisitorServiceImpl(visitorStorage, this.config);\n const session = new SessionServiceImpl(sessionStorage, this.config);\n const fingerprint = new FingerprintServiceImpl(\n fingerprintStorage,\n this.config,\n browserMetadata\n );\n const dispatcher = new DispatcherServiceImpl(logger);\n const commerce = new CommerceService(this.config.commerce);\n\n return {\n storage,\n visitor,\n session,\n fingerprint,\n dispatcher,\n browserMetadata,\n eventBuilder,\n attribution,\n commerce,\n urlContext,\n };\n }\n\n private createStorageService(\n namespace: string,\n prefix: string | undefined,\n persistence: StoragePersistence | undefined\n ): StorageServiceImpl {\n return new StorageServiceImpl(\n createStorageAdapter(persistence),\n namespace,\n prefix\n );\n }\n\n private createContext(): PixelRuntimeContext {\n return {\n config: this.config,\n logger: this.fallbackLogger,\n services: this.createServices(this.fallbackLogger),\n };\n }\n\n private getLogger(): PixelLogger {\n return this.context?.logger ?? this.fallbackLogger;\n }\n\n private isModuleEnabled(module: PixelModule): boolean {\n if (module.name === 'diagnostics') return true;\n\n const enabledModules: Record<\n Exclude<ModuleName, 'diagnostics'>,\n boolean\n > = {\n privacy: this.config.modules.privacy.enabled,\n core: this.config.modules.core.enabled,\n behavior: this.config.modules.behavior.enabled,\n conversion: this.config.modules.conversion.enabled,\n transport: this.config.modules.transport.enabled,\n integrations: this.config.modules.integrations.enabled,\n };\n\n return enabledModules[module.name];\n }\n}\n"],"mappings":"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","names":["ModuleRegistry","module","existing","BaseEventBuilder","metadataService","attribution","urlContext","event","metadata","identifiers","hasIdentifiers","key","value","urlSnapshot","hasQueryParams","hasUrlContext","ConsolePixelLogger","debugEnabled","args","DEFAULT_ATTRIBUTION_CONFIG","ATTRIBUTION_STORAGE_KEY","BUILTIN_CLICK_PARAMS","ClickIdParser","customParams","params","result","customClickIds","key","value","fbclid","existingFbc","CookieCollector","cookies","result","map","cookieName","field","value","acc","part","rawKey","rest","AttributionCollector","options","ClickIdParser","CookieCollector","fromUrl","fromCookies","merged","customClickIds","fbc","existing","incoming","next","key","value","now","AttributionStore","storage","options","ATTRIBUTION_STORAGE_KEY","snapshot","anchor","AttributionServiceImpl","storage","config","DEFAULT_ATTRIBUTION_CONFIG","AttributionStore","AttributionCollector","stored","fresh","partial","BrowserMetadataServiceImpl","timezone","DispatcherServiceImpl","logger","event","snapshot","index","listener","error","sanitizeDispatcherError","eventType","listenerIndex","name","message","DEFAULT_FINGERPRINT_KEY","hashFingerprintInput","input","hash","index","positiveHash","secondaryHash","computeLightFingerprint","metadataService","metadata","components","FingerprintServiceImpl","storage","config","existing","fingerprint","BrowserStorageAdapter","storage","key","value","predicate","keysToRemove","index","MemoryStorageAdapter","key","value","predicate","supportsNamespaceClear","adapter","StorageServiceImpl","namespace","prefix","key","raw","value","namespaceKeyPrefix","createStorageAdapter","persistence","mode","MemoryStorageAdapter","BrowserStorageAdapter","ProductCatalog","products","options","id","product","sku","defaultCurrency","raw","currency","quantity","CommerceState","initialItems","options","item","productId","quantity","previous","metadata","next","normalized","current","selectedItems","OrderCalculator","input","items","item","value","currency","total","hasPriced","qty","DEFAULT_COMMERCE_ENRICHMENT","DEFAULT_COMMERCE_CONFIG","normalizeCalculateValueFrom","value","CommerceResolver","options","trim","normalizeCalculateValueFrom","input","payload","extracted","source","useCart","useCatalog","productId","asString","cartFallback","catalogProduct","resolvedId","stateItem","productName","price","asNumber","quantity","currency","identity","resolveCatalogItemIdentity","data","key","value","items","item","isPurchase","manualValue","manualCurrency","manualItems","resolvedItems","pixelItems","allowCalculatedValue","shouldCalculateValue","calc","atc","checkout","contentId","contentName","raw","enrichmentSource","fromState","product","catalog","sku","incoming","meta","metaPriceId","metaProductId","metaOfferId","priceId","trimmed","t","CommerceService","config","DEFAULT_COMMERCE_CONFIG","item","DEFAULT_COMMERCE_ENRICHMENT","ProductCatalog","CommerceState","CommerceResolver","OrderCalculator","normalizeCalculateValueFrom","event","fromConfig","fallback","eventType","payload","resolved","items","first","contentId","contentName","createRandomSuffix","generateSessionId","DEFAULT_SESSION_KEY","SessionServiceImpl","storage","config","raw","now","ttlMs","data","sessionId","generateSessionId","previousSessionId","createRandomSuffix","generateVisitorId","DEFAULT_VISITOR_KEY","VisitorServiceImpl","storage","config","existing","visitorId","generateVisitorId","DEFAULT_URL_CONTEXT_DENYLIST","DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS","DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS","SID_EXCLUDE_SELECTOR","normalizeParamKey","key","safeDecodeURIComponent","value","buildDenylistSet","userDenylist","mergeDefault","set","DEFAULT_URL_CONTEXT_DENYLIST","buildExcludedDomains","userExcluded","list","DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS","domain","d","buildExcludeSelectors","userSelectors","includeSidSelector","DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS","SID_EXCLUDE_SELECTOR","sel","isDeniedKey","denylist","hostMatchesDomain","hostname","hostNoPort","target","isDomainAllowed","allowedDomains","excludedDomains","excluded","generatePublicId","prefix","safePrefix","ts","random","isBrowser","silentReplaceState","url","parseSearchParams","search","result","raw","part","eq","buildSearchString","params","pairs","freezeRecord","record","formatDecoratedHref","originalHref","trimmed","hash","QueryParamCollector","config","isBrowser","raw","parseSearchParams","denylist","buildDenylistSet","mode","allowlist","normalizeParamKey","result","key","value","isDeniedKey","ManagedParamResolver","store","configs","values","sources","decorateParams","urlWrites","currentParams","isBrowser","parseSearchParams","config","param","mode","canRead","canWrite","value","source","fromUrl","cookieName","fromCookie","storageKey","fromStorage","generatePublicId","trimmed","strategy","cookieCfg","writes","next","search","buildSearchString","hash","path","silentReplaceState","ForwardParamResolver","input","queryParams","managedValues","config","denylist","buildDenylistSet","mode","allowlist","normalizeParamKey","result","key","value","isDeniedKey","BLOCKED_PROTOCOLS","LinkDecorator","paramsOrOptions","config","includeSidExclude","isLinkDecoratorOptions","buildExcludedDomains","buildExcludeSelectors","flat","resolvedConfig","managedParams","isBrowser","strategy","event","anchor","findAnchor","href","baseHostname","trimmed","lower","proto","url","base","isDomainAllowed","existing","parseSearchParams","preserve","overwrite","next","changed","key","value","originalParsed","hadDuplicateKeys","countQueryKeys","search","buildSearchString","formatDecoratedHref","selector","nodes","node","sel","target","qIndex","hashIndex","raw","UrlContextStore","storage","key","value","name","isBrowser","cookies","part","idx","raw","safeDecodeURIComponent","options","parts","domain","resolveCookieDomain","sameSite","host","DEFAULT_SID_MANAGED_PARAM","DEFAULT_QUERY_PARAMS_WHEN_ENABLED","DEFAULT_FORWARD_PARAMS_WHEN_ENABLED","DEFAULT_LINK_DECORATION_WHEN_ENABLED","resolveUrlContextConfig","raw","managedParams","cloneManagedParam","param","UrlContextService","config","storage","QueryParamCollector","ForwardParamResolver","emptySnapshot","resolved","resolveUrlContextConfig","UrlContextStore","ManagedParamResolver","queryParams","managed","queryAfter","forwarded","source","key","urlContext","freezeRecord","decorateForwarded","hasSid","p","LinkDecorator","param","value","trimmed","c","PixelRuntime","config","ModuleRegistry","ConsolePixelLogger","module","error","logger","index","m","namespace","prefix","persistence","visitorStorage","sessionStorage","fingerprintStorage","attributionStorage","storage","browserMetadata","BrowserMetadataServiceImpl","attribution","AttributionServiceImpl","DEFAULT_ATTRIBUTION_CONFIG","urlContextStorage","urlContext","UrlContextService","eventBuilder","BaseEventBuilder","visitor","VisitorServiceImpl","session","SessionServiceImpl","fingerprint","FingerprintServiceImpl","dispatcher","DispatcherServiceImpl","commerce","CommerceService","StorageServiceImpl","createStorageAdapter"]}
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/ModuleRegistry.ts","../../src/events/builder/BaseEventBuilder.ts","../../src/logger/ConsolePixelLogger.ts","../../src/services/attribution/types.ts","../../src/services/attribution/ClickIdParser.ts","../../src/services/attribution/CookieCollector.ts","../../src/services/attribution/AttributionCollector.ts","../../src/services/attribution/AttributionStore.ts","../../src/services/attribution/AttributionService.ts","../../src/services/browser-metadata/BrowserMetadataService.ts","../../src/services/dispatcher/DispatcherService.ts","../../src/services/fingerprint/FingerprintService.ts","../../src/services/storage/BrowserStorageAdapter.ts","../../src/services/storage/MemoryStorageAdapter.ts","../../src/services/storage/StorageService.ts","../../src/services/storage/StorageFactory.ts","../../src/services/commerce/ProductCatalog.ts","../../src/services/commerce/CommerceState.ts","../../src/services/commerce/OrderCalculator.ts","../../src/config/shared/commerce.ts","../../src/services/commerce/CommerceResolver.ts","../../src/services/commerce/CommerceService.ts","../../src/services/session/session-id.ts","../../src/services/session/SessionService.ts","../../src/services/visitor/visitor-id.ts","../../src/services/visitor/VisitorService.ts","../../src/modules/core/url-context/constants.ts","../../src/modules/core/url-context/utils.ts","../../src/modules/core/url-context/QueryParamCollector.ts","../../src/modules/core/url-context/ManagedParamResolver.ts","../../src/modules/core/url-context/ForwardParamResolver.ts","../../src/modules/core/url-context/LinkDecorator.ts","../../src/modules/core/url-context/UrlContextStore.ts","../../src/modules/core/url-context/resolve-config.ts","../../src/modules/core/url-context/UrlContextService.ts","../../src/runtime/PixelRuntime.ts"],"sourcesContent":["import type { PixelModule } from './types';\n\nexport class ModuleRegistry {\n private readonly modules: PixelModule[] = [];\n\n register(module: PixelModule): void {\n if (this.modules.some(existing => existing.name === module.name)) {\n throw new Error(`[Pixel] Module \"${module.name}\" is already registered`);\n }\n\n this.modules.push(module);\n }\n\n getAll(): readonly PixelModule[] {\n return this.modules;\n }\n\n size(): number {\n return this.modules.length;\n }\n}\n","import type { AttributionService } from '@/services/attribution/types';\nimport type { BrowserMetadataService } from '@/services/browser-metadata';\nimport type { UrlContextService } from '@/modules/core/url-context';\n\nimport type { BasePixelEvent } from '../base';\n\nexport class BaseEventBuilder {\n private readonly metadataService: BrowserMetadataService;\n\n private readonly attribution: AttributionService | null;\n\n private readonly urlContext: UrlContextService | null;\n\n constructor(\n metadataService: BrowserMetadataService,\n attribution?: AttributionService | null,\n urlContext?: UrlContextService | null\n ) {\n this.metadataService = metadataService;\n this.attribution = attribution ?? null;\n this.urlContext = urlContext ?? null;\n }\n\n build<T extends { type: string }>(event: T): T & BasePixelEvent {\n const metadata = this.metadataService.getMetadata();\n const identifiers = this.attribution?.getSnapshot();\n const hasIdentifiers =\n identifiers !== undefined &&\n Object.keys(identifiers).some(key => {\n const value = identifiers[key as keyof typeof identifiers];\n return value !== undefined && value !== null && value !== '';\n });\n\n const urlSnapshot = this.urlContext?.isEnabled()\n ? this.urlContext.getSnapshot()\n : null;\n\n const hasQueryParams =\n urlSnapshot !== null && Object.keys(urlSnapshot.queryParams).length > 0;\n const hasUrlContext =\n urlSnapshot !== null &&\n ((urlSnapshot.urlContext.managed &&\n Object.keys(urlSnapshot.urlContext.managed).length > 0) ||\n (urlSnapshot.urlContext.forwarded &&\n Object.keys(urlSnapshot.urlContext.forwarded).length > 0) ||\n (urlSnapshot.urlContext.source &&\n Object.keys(urlSnapshot.urlContext.source).length > 0));\n\n return {\n ...event,\n timestamp: Date.now(),\n path: metadata.path,\n url: metadata.url,\n hostname: metadata.hostname,\n language: metadata.language,\n timezone: metadata.timezone,\n ...(hasIdentifiers ? { identifiers } : {}),\n ...(hasQueryParams\n ? { queryParams: { ...urlSnapshot!.queryParams } }\n : {}),\n ...(hasUrlContext\n ? {\n urlContext: {\n ...(urlSnapshot!.urlContext.managed\n ? { managed: { ...urlSnapshot!.urlContext.managed } }\n : {}),\n ...(urlSnapshot!.urlContext.forwarded\n ? { forwarded: { ...urlSnapshot!.urlContext.forwarded } }\n : {}),\n ...(urlSnapshot!.urlContext.source\n ? { source: { ...urlSnapshot!.urlContext.source } }\n : {}),\n },\n }\n : {}),\n };\n }\n}\n","import type { PixelLogger } from './PixelLogger';\n\nexport class ConsolePixelLogger implements PixelLogger {\n constructor(private readonly debugEnabled: boolean) {}\n\n debug(...args: unknown[]): void {\n if (!this.debugEnabled) return;\n if (typeof console === 'undefined') return;\n console.debug(...args);\n }\n\n info(...args: unknown[]): void {\n if (typeof console === 'undefined') return;\n console.info(...args);\n }\n\n warn(...args: unknown[]): void {\n if (typeof console === 'undefined') return;\n console.warn(...args);\n }\n\n error(...args: unknown[]): void {\n if (typeof console === 'undefined') return;\n console.error(...args);\n }\n}\n","export type AttributionIdentifiers = {\n readonly fbclid?: string;\n readonly fbp?: string;\n readonly fbc?: string;\n\n readonly gclid?: string;\n readonly gbraid?: string;\n readonly wbraid?: string;\n readonly ga?: string;\n readonly gid?: string;\n readonly gclAu?: string;\n\n readonly ttclid?: string;\n readonly ttp?: string;\n\n readonly msclkid?: string;\n readonly liFatId?: string;\n readonly epik?: string;\n\n readonly customClickIds?: Readonly<Record<string, string>>;\n\n readonly firstCollectedAt?: number;\n readonly lastCollectedAt?: number;\n readonly landingUrl?: string;\n readonly referrer?: string;\n};\n\nexport type AttributionConfig = {\n readonly enabled: boolean;\n readonly ttlDays?: number;\n readonly persist?: boolean;\n readonly captureUrlParams?: boolean;\n readonly captureCookies?: boolean;\n readonly customClickIdParams?: string[];\n};\n\nexport const DEFAULT_ATTRIBUTION_CONFIG: AttributionConfig = {\n enabled: true,\n ttlDays: 90,\n persist: true,\n captureUrlParams: true,\n captureCookies: true,\n customClickIdParams: [],\n};\n\nexport const ATTRIBUTION_STORAGE_KEY = 'attribution';\n\nexport interface AttributionService {\n init(): void;\n destroy(): void;\n collect(): AttributionIdentifiers;\n getSnapshot(): AttributionIdentifiers;\n update(partial: Partial<AttributionIdentifiers>): AttributionIdentifiers;\n clear(): void;\n}\n","import type { AttributionIdentifiers } from './types';\n\nconst BUILTIN_CLICK_PARAMS = [\n 'fbclid',\n 'gclid',\n 'gbraid',\n 'wbraid',\n 'ttclid',\n 'msclkid',\n 'epik',\n 'li_fat_id',\n] as const;\n\n/**\n * Parses click IDs from URL search params and maps to AttributionIdentifiers fields.\n */\nexport class ClickIdParser {\n parse(customParams: readonly string[] = []): Partial<AttributionIdentifiers> {\n if (typeof window === 'undefined' || !window.location?.search) {\n return {};\n }\n\n try {\n const params = new URLSearchParams(window.location.search);\n const result: Record<string, unknown> = {};\n const customClickIds: Record<string, string> = {};\n\n for (const key of BUILTIN_CLICK_PARAMS) {\n const value = params.get(key);\n if (!value) continue;\n\n if (key === 'li_fat_id') {\n result.liFatId = value;\n } else {\n result[key] = value;\n }\n }\n\n for (const key of customParams) {\n const value = params.get(key);\n if (value) customClickIds[key] = value;\n }\n\n if (Object.keys(customClickIds).length > 0) {\n result.customClickIds = customClickIds;\n }\n\n return result as Partial<AttributionIdentifiers>;\n } catch {\n return {};\n }\n }\n\n /**\n * Meta convention: when fbclid is present and _fbc cookie is missing,\n * synthesize fbc = fb.1.<timestamp_ms>.<fbclid>\n */\n synthesizeFbc(fbclid: string, existingFbc?: string): string | undefined {\n if (existingFbc) return existingFbc;\n if (!fbclid) return undefined;\n return `fb.1.${Date.now()}.${fbclid}`;\n }\n}\n","/**\n * SSR-safe cookie reader for attribution identifiers.\n */\nexport class CookieCollector {\n collectKnown(): Readonly<Record<string, string>> {\n if (typeof document === 'undefined') return {};\n\n const cookies = this.parseCookies();\n const result: Record<string, string> = {};\n\n const map: Record<string, string> = {\n _fbp: 'fbp',\n _fbc: 'fbc',\n _ga: 'ga',\n _gid: 'gid',\n _gcl_au: 'gclAu',\n _ttp: 'ttp',\n li_fat_id: 'liFatId',\n epik: 'epik',\n };\n\n for (const [cookieName, field] of Object.entries(map)) {\n const value = cookies[cookieName];\n if (value) result[field] = value;\n }\n\n return result;\n }\n\n private parseCookies(): Record<string, string> {\n if (typeof document === 'undefined') return {};\n\n try {\n return document.cookie.split(';').reduce(\n (acc, part) => {\n const [rawKey, ...rest] = part.trim().split('=');\n if (!rawKey) return acc;\n acc[rawKey] = decodeURIComponent(rest.join('=') || '');\n return acc;\n },\n {} as Record<string, string>\n );\n } catch {\n return {};\n }\n }\n}\n","import type { AttributionIdentifiers } from './types';\nimport { ClickIdParser } from './ClickIdParser';\nimport { CookieCollector } from './CookieCollector';\n\n/**\n * Collects attribution signals from URL + cookies and merges them.\n */\nexport class AttributionCollector {\n private readonly clickIdParser = new ClickIdParser();\n\n private readonly cookieCollector = new CookieCollector();\n\n private readonly customParams: readonly string[];\n\n private readonly captureUrlParams: boolean;\n\n private readonly captureCookies: boolean;\n\n constructor(\n options: {\n customParams?: readonly string[];\n captureUrlParams?: boolean;\n captureCookies?: boolean;\n } = {}\n ) {\n this.customParams = options.customParams ?? [];\n this.captureUrlParams = options.captureUrlParams !== false;\n this.captureCookies = options.captureCookies !== false;\n }\n\n collectFresh(): Partial<AttributionIdentifiers> {\n const fromUrl = this.captureUrlParams\n ? this.clickIdParser.parse(this.customParams)\n : {};\n const fromCookies = this.captureCookies\n ? this.cookieCollector.collectKnown()\n : {};\n\n const merged: Record<string, unknown> = {\n ...fromCookies,\n ...fromUrl,\n };\n\n const customClickIds = {\n ...((fromCookies as AttributionIdentifiers).customClickIds ?? {}),\n ...(fromUrl.customClickIds ?? {}),\n };\n if (Object.keys(customClickIds).length > 0) {\n merged.customClickIds = customClickIds;\n }\n\n if (typeof merged.fbclid === 'string' && merged.fbclid) {\n const fbc = this.clickIdParser.synthesizeFbc(\n merged.fbclid,\n typeof merged.fbc === 'string' ? merged.fbc : undefined\n );\n if (fbc) merged.fbc = fbc;\n }\n\n if (typeof window !== 'undefined') {\n try {\n merged.landingUrl = window.location.href;\n } catch {\n // ignore\n }\n }\n\n if (typeof document !== 'undefined') {\n try {\n if (document.referrer) merged.referrer = document.referrer;\n } catch {\n // ignore\n }\n }\n\n return merged as Partial<AttributionIdentifiers>;\n }\n\n /**\n * Merge: never overwrite existing defined values with undefined.\n */\n merge(\n existing: AttributionIdentifiers,\n incoming: Partial<AttributionIdentifiers>\n ): AttributionIdentifiers {\n const next: Record<string, unknown> = { ...existing };\n\n for (const [key, value] of Object.entries(incoming)) {\n if (value === undefined || value === null || value === '') continue;\n\n if (key === 'customClickIds' && typeof value === 'object') {\n next.customClickIds = {\n ...((existing.customClickIds as Record<string, string>) ?? {}),\n ...(value as Record<string, string>),\n };\n continue;\n }\n\n next[key] = value;\n }\n\n const now = Date.now();\n if (!existing.firstCollectedAt) {\n next.firstCollectedAt = now;\n }\n next.lastCollectedAt = now;\n\n return next as AttributionIdentifiers;\n }\n}\n","import type { StorageService } from '@/services/storage/types';\n\nimport { ATTRIBUTION_STORAGE_KEY, type AttributionIdentifiers } from './types';\n\n/**\n * Persists AttributionIdentifiers via StorageService only (no direct localStorage).\n */\nexport class AttributionStore {\n private readonly storage: StorageService;\n\n private readonly persist: boolean;\n\n private readonly ttlMs: number;\n\n private readonly storageKey: string;\n\n constructor(\n storage: StorageService,\n options: { persist: boolean; ttlDays: number; storageKey?: string }\n ) {\n this.storage = storage;\n this.persist = options.persist;\n this.ttlMs = options.ttlDays * 24 * 60 * 60 * 1000;\n this.storageKey = options.storageKey ?? ATTRIBUTION_STORAGE_KEY;\n }\n\n load(): AttributionIdentifiers | null {\n if (!this.persist) return null;\n\n try {\n const snapshot = this.storage.get<AttributionIdentifiers>(\n this.storageKey\n );\n if (!snapshot) return null;\n\n if (this.isExpired(snapshot)) {\n this.clear();\n return null;\n }\n\n return snapshot;\n } catch {\n return null;\n }\n }\n\n save(snapshot: AttributionIdentifiers): void {\n if (!this.persist) return;\n\n try {\n this.storage.set(this.storageKey, snapshot);\n } catch {\n // quota / SSR — keep in-memory only\n }\n }\n\n clear(): void {\n try {\n this.storage.remove(this.storageKey);\n } catch {\n // ignore\n }\n }\n\n private isExpired(snapshot: AttributionIdentifiers): boolean {\n const anchor = snapshot.lastCollectedAt ?? snapshot.firstCollectedAt;\n if (!anchor) return false;\n return Date.now() - anchor > this.ttlMs;\n }\n}\n","import type { StorageService } from '@/services/storage/types';\n\nimport { AttributionCollector } from './AttributionCollector';\nimport { AttributionStore } from './AttributionStore';\nimport {\n DEFAULT_ATTRIBUTION_CONFIG,\n type AttributionConfig,\n type AttributionIdentifiers,\n type AttributionService,\n} from './types';\n\nexport class AttributionServiceImpl implements AttributionService {\n private readonly store: AttributionStore;\n\n private readonly collector: AttributionCollector;\n\n private readonly enabled: boolean;\n\n private snapshot: AttributionIdentifiers = {};\n\n private active = false;\n\n constructor(\n storage: StorageService,\n config: AttributionConfig = DEFAULT_ATTRIBUTION_CONFIG\n ) {\n this.enabled = config.enabled !== false;\n this.store = new AttributionStore(storage, {\n persist: config.persist !== false,\n ttlDays: config.ttlDays ?? 90,\n });\n this.collector = new AttributionCollector({\n customParams: config.customClickIdParams ?? [],\n captureUrlParams: config.captureUrlParams !== false,\n captureCookies: config.captureCookies !== false,\n });\n }\n\n init(): void {\n if (this.active) return;\n this.active = true;\n\n if (!this.enabled) return;\n\n const stored = this.store.load();\n if (stored) {\n this.snapshot = stored;\n }\n\n this.collect();\n }\n\n destroy(): void {\n if (!this.active) return;\n this.active = false;\n }\n\n collect(): AttributionIdentifiers {\n if (!this.enabled) return this.snapshot;\n\n const fresh = this.collector.collectFresh();\n this.snapshot = this.collector.merge(this.snapshot, fresh);\n this.store.save(this.snapshot);\n return this.snapshot;\n }\n\n getSnapshot(): AttributionIdentifiers {\n return { ...this.snapshot };\n }\n\n update(partial: Partial<AttributionIdentifiers>): AttributionIdentifiers {\n this.snapshot = this.collector.merge(this.snapshot, partial);\n this.store.save(this.snapshot);\n return this.getSnapshot();\n }\n\n clear(): void {\n this.snapshot = {};\n this.store.clear();\n }\n}\n","import type { BrowserMetadata, BrowserMetadataService } from './types';\n\nexport class BrowserMetadataServiceImpl implements BrowserMetadataService {\n getMetadata(): BrowserMetadata {\n if (typeof window === 'undefined') {\n return {};\n }\n\n const timezone = (() => {\n try {\n return Intl.DateTimeFormat().resolvedOptions().timeZone;\n } catch {\n return undefined;\n }\n })();\n\n return {\n url: location.href,\n path: location.pathname,\n hostname: location.hostname,\n origin: location.origin,\n title: typeof document !== 'undefined' ? document.title : undefined,\n referrer: typeof document !== 'undefined' ? document.referrer : undefined,\n language: navigator.language,\n timezone,\n userAgent: navigator.userAgent,\n platform: navigator.platform,\n screenWidth: screen.width,\n screenHeight: screen.height,\n colorDepth: screen.colorDepth,\n };\n }\n}\n","import type { PixelEvent } from '@/events';\nimport type { PixelLogger } from '@/logger/PixelLogger';\n\nimport type { DispatcherService } from './types';\n\ntype EventListener = (event: PixelEvent) => void;\n\nconst MAX_ERROR_MESSAGE_LENGTH = 200;\n\n/**\n * Hardening 18.1 — falha de um listener não interrompe os demais nem propaga\n * para o produtor (trackers/engines). Log sanitizado, sem payload/PII.\n */\nexport class DispatcherServiceImpl implements DispatcherService {\n private readonly listeners = new Set<EventListener>();\n\n private lastEvent: PixelEvent | null = null;\n\n private readonly logger: Pick<PixelLogger, 'warn'> | undefined;\n\n constructor(logger?: Pick<PixelLogger, 'warn'>) {\n this.logger = logger;\n }\n\n dispatch(event: PixelEvent): void {\n this.lastEvent = event;\n\n // Snapshot: permite unsubscribe durante dispatch sem pular listeners.\n const snapshot = [...this.listeners];\n\n for (let index = 0; index < snapshot.length; index += 1) {\n const listener = snapshot[index];\n if (!listener) continue;\n\n try {\n listener(event);\n } catch (error) {\n this.logger?.warn(sanitizeDispatcherError(error, event.type, index));\n }\n }\n }\n\n subscribe(listener: (event: PixelEvent) => void): () => void {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n clear(): void {\n this.listeners.clear();\n this.lastEvent = null;\n }\n\n getListenerCount(): number {\n return this.listeners.size;\n }\n\n getLastEvent(): PixelEvent | null {\n return this.lastEvent;\n }\n}\n\nexport function sanitizeDispatcherError(\n error: unknown,\n eventType: string,\n listenerIndex: number\n): Record<string, unknown> {\n const name =\n error instanceof Error\n ? error.name\n : typeof error === 'object' && error !== null && 'name' in error\n ? String((error as { name: unknown }).name)\n : 'Error';\n\n let message =\n error instanceof Error\n ? error.message\n : typeof error === 'string'\n ? error\n : 'unknown';\n\n message = message\n .replace(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g, '[redacted]')\n .replace(/\\+?\\d[\\d\\s().-]{7,}\\d/g, '[redacted]');\n\n if (message.length > MAX_ERROR_MESSAGE_LENGTH) {\n message = `${message.slice(0, MAX_ERROR_MESSAGE_LENGTH)}…`;\n }\n\n return {\n code: 'DISPATCHER_LISTENER_FAILED',\n eventType,\n listenerIndex,\n errorName: name,\n message,\n timestamp: Date.now(),\n };\n}\n","import type { PixelConfig } from '@/config';\nimport type { BrowserMetadataService } from '@/services/browser-metadata';\nimport type { StorageService } from '@/services/storage';\n\nimport type { FingerprintService } from './types';\n\nconst DEFAULT_FINGERPRINT_KEY = 'fingerprint';\n\nfunction hashFingerprintInput(input: string): string {\n let hash = 0;\n\n for (let index = 0; index < input.length; index++) {\n hash = (hash << 5) - hash + input.charCodeAt(index);\n hash |= 0;\n }\n\n const positiveHash = Math.abs(hash).toString(16).padStart(8, '0');\n let secondaryHash = 0;\n\n for (let index = input.length - 1; index >= 0; index--) {\n secondaryHash =\n (secondaryHash << 5) - secondaryHash + input.charCodeAt(index);\n secondaryHash |= 0;\n }\n\n return `fp_${positiveHash}${Math.abs(secondaryHash).toString(16).padStart(8, '0')}`;\n}\n\nfunction computeLightFingerprint(\n metadataService: BrowserMetadataService\n): string {\n const metadata = metadataService.getMetadata();\n\n const components = [\n metadata.userAgent ?? '',\n metadata.language ?? '',\n metadata.platform ?? '',\n String(metadata.screenWidth ?? ''),\n String(metadata.screenHeight ?? ''),\n String(metadata.colorDepth ?? ''),\n metadata.timezone ?? '',\n ];\n\n return hashFingerprintInput(components.join('|'));\n}\n\nexport class FingerprintServiceImpl implements FingerprintService {\n private readonly storage: StorageService;\n\n private readonly storageKey: string;\n\n private readonly metadataService: BrowserMetadataService;\n\n constructor(\n storage: StorageService,\n config: PixelConfig,\n metadataService: BrowserMetadataService\n ) {\n this.storage = storage;\n this.storageKey =\n config.storage.keys?.fingerprint ?? DEFAULT_FINGERPRINT_KEY;\n this.metadataService = metadataService;\n }\n\n getFingerprint(): string | null {\n return this.storage.get<string>(this.storageKey);\n }\n\n ensureFingerprint(): string {\n const existing = this.getFingerprint();\n if (existing) return existing;\n\n const fingerprint = computeLightFingerprint(this.metadataService);\n this.storage.set(this.storageKey, fingerprint);\n return fingerprint;\n }\n}\n","import type { StorageAdapter } from './types';\n\nexport class BrowserStorageAdapter implements StorageAdapter {\n private readonly storage: Storage | null;\n\n private readonly memoryFallback = new Map<string, string>();\n\n constructor(storage: Storage) {\n this.storage = typeof window === 'undefined' ? null : storage;\n }\n\n get(key: string): string | null {\n if (this.storage) {\n return this.storage.getItem(key);\n }\n\n return this.memoryFallback.get(key) ?? null;\n }\n\n set(key: string, value: string): void {\n if (this.storage) {\n this.storage.setItem(key, value);\n return;\n }\n\n this.memoryFallback.set(key, value);\n }\n\n remove(key: string): void {\n if (this.storage) {\n this.storage.removeItem(key);\n return;\n }\n\n this.memoryFallback.delete(key);\n }\n\n clear(): void {\n // Never clear entire browser storage — namespace removal uses removeKeysMatching.\n if (!this.storage) {\n this.memoryFallback.clear();\n }\n }\n\n removeKeysMatching(predicate: (key: string) => boolean): void {\n if (this.storage) {\n const keysToRemove: string[] = [];\n\n for (let index = 0; index < this.storage.length; index++) {\n const key = this.storage.key(index);\n if (key && predicate(key)) {\n keysToRemove.push(key);\n }\n }\n\n for (const key of keysToRemove) {\n this.storage.removeItem(key);\n }\n\n return;\n }\n\n for (const key of this.memoryFallback.keys()) {\n if (predicate(key)) {\n this.memoryFallback.delete(key);\n }\n }\n }\n}\n","import type { StorageAdapter } from './types';\n\nexport class MemoryStorageAdapter implements StorageAdapter {\n private readonly store = new Map<string, string>();\n\n get(key: string): string | null {\n return this.store.get(key) ?? null;\n }\n\n set(key: string, value: string): void {\n this.store.set(key, value);\n }\n\n remove(key: string): void {\n this.store.delete(key);\n }\n\n clear(): void {\n this.store.clear();\n }\n\n removeKeysMatching(predicate: (key: string) => boolean): void {\n for (const key of this.store.keys()) {\n if (predicate(key)) {\n this.store.delete(key);\n }\n }\n }\n}\n","import type { StorageAdapter, StorageService } from './types';\n\ntype NamespaceClearableAdapter = StorageAdapter & {\n removeKeysMatching(predicate: (key: string) => boolean): void;\n};\n\nfunction supportsNamespaceClear(\n adapter: StorageAdapter\n): adapter is NamespaceClearableAdapter {\n return (\n 'removeKeysMatching' in adapter &&\n typeof adapter.removeKeysMatching === 'function'\n );\n}\n\nexport class StorageServiceImpl implements StorageService {\n private readonly adapter: StorageAdapter;\n\n private readonly namespace: string;\n\n private readonly prefix?: string;\n\n constructor(adapter: StorageAdapter, namespace: string, prefix?: string) {\n this.adapter = adapter;\n this.namespace = namespace;\n this.prefix = prefix;\n }\n\n get<T>(key: string): T | null {\n const raw = this.adapter.get(this.createKey(key));\n if (raw === null) return null;\n\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n }\n\n set<T>(key: string, value: T): void {\n this.adapter.set(this.createKey(key), JSON.stringify(value));\n }\n\n remove(key: string): void {\n this.adapter.remove(this.createKey(key));\n }\n\n has(key: string): boolean {\n return this.adapter.get(this.createKey(key)) !== null;\n }\n\n clear(): void {\n const namespaceKeyPrefix = this.getNamespaceKeyPrefix();\n\n if (supportsNamespaceClear(this.adapter)) {\n this.adapter.removeKeysMatching(key =>\n key.startsWith(namespaceKeyPrefix)\n );\n return;\n }\n\n this.adapter.clear();\n }\n\n createKey(key: string): string {\n if (this.prefix) {\n return `${this.prefix}:${this.namespace}:${key}`;\n }\n\n return `${this.namespace}:${key}`;\n }\n\n private getNamespaceKeyPrefix(): string {\n if (this.prefix) {\n return `${this.prefix}:${this.namespace}:`;\n }\n\n return `${this.namespace}:`;\n }\n}\n","import type {\n AttributionStoragePersistence,\n QueueStoragePersistence,\n SessionStoragePersistence,\n VisitorStoragePersistence,\n} from '@/config/shared/persistence';\n\nimport { BrowserStorageAdapter } from './BrowserStorageAdapter';\nimport { MemoryStorageAdapter } from './MemoryStorageAdapter';\nimport type { StorageAdapter } from './types';\n\nexport type StoragePersistence =\n | VisitorStoragePersistence\n | SessionStoragePersistence\n | AttributionStoragePersistence\n | QueueStoragePersistence;\n\nexport function createStorageAdapter(\n persistence?: StoragePersistence\n): StorageAdapter {\n const mode = persistence ?? 'memory';\n\n if (typeof window === 'undefined') {\n return new MemoryStorageAdapter();\n }\n\n switch (mode) {\n case 'memory':\n return new MemoryStorageAdapter();\n case 'localStorage':\n return new BrowserStorageAdapter(window.localStorage);\n case 'sessionStorage':\n return new BrowserStorageAdapter(window.sessionStorage);\n case 'cookie_localStorage':\n // TODO: implementar cookie fallback.\n return new BrowserStorageAdapter(window.localStorage);\n case 'cookie':\n return new MemoryStorageAdapter();\n case 'indexedDB':\n return new MemoryStorageAdapter();\n default:\n return new MemoryStorageAdapter();\n }\n}\n\nexport function resolveStorageAdapterName(\n persistence?: StoragePersistence\n): string {\n const mode = persistence ?? 'memory';\n\n switch (mode) {\n case 'localStorage':\n case 'sessionStorage':\n case 'cookie_localStorage':\n return 'BrowserStorageAdapter';\n default:\n return 'MemoryStorageAdapter';\n }\n}\n","import type { CommerceProduct } from '@/config/shared/commerce';\n\nexport type ProductCatalogOptions = {\n readonly defaultCurrency?: string;\n};\n\nexport type ProductCatalogSnapshot = {\n readonly products: CommerceProduct[];\n readonly count: number;\n};\n\n/**\n * Catálogo de produtos configurados em `config.commerce.catalog`.\n * Isolado por instância — sem estado global / module-level.\n * Não acessa DOM, Transport nem altera payloads de eventos.\n */\nexport class ProductCatalog {\n private readonly productsById = new Map<string, CommerceProduct>();\n\n private readonly productsBySku = new Map<string, CommerceProduct>();\n\n private readonly orderedIds: string[] = [];\n\n constructor(\n products: readonly CommerceProduct[] | undefined = [],\n options: ProductCatalogOptions = {}\n ) {\n this.indexProducts(products ?? [], options.defaultCurrency);\n }\n\n list(): CommerceProduct[] {\n return this.orderedIds.map(id =>\n this.cloneProduct(this.productsById.get(id)!)\n );\n }\n\n getById(id: string): CommerceProduct | null {\n if (!id) return null;\n const product = this.productsById.get(id);\n return product ? this.cloneProduct(product) : null;\n }\n\n getBySku(sku: string): CommerceProduct | null {\n if (!sku) return null;\n const product = this.productsBySku.get(sku);\n return product ? this.cloneProduct(product) : null;\n }\n\n hasProduct(id: string): boolean {\n return Boolean(id) && this.productsById.has(id);\n }\n\n getSnapshot(): ProductCatalogSnapshot {\n const products = this.list();\n return { products, count: products.length };\n }\n\n private indexProducts(\n products: readonly CommerceProduct[],\n defaultCurrency?: string\n ): void {\n for (const raw of products) {\n if (!raw || typeof raw !== 'object') continue;\n\n const id = typeof raw.id === 'string' ? raw.id.trim() : '';\n if (!id) continue;\n\n // Duplicado por id: mantém o primeiro (determinístico).\n if (this.productsById.has(id)) continue;\n\n const product = this.normalizeProduct(raw, id, defaultCurrency);\n this.productsById.set(id, product);\n this.orderedIds.push(id);\n\n const sku = typeof product.sku === 'string' ? product.sku.trim() : '';\n if (sku && !this.productsBySku.has(sku)) {\n this.productsBySku.set(sku, product);\n }\n }\n }\n\n private normalizeProduct(\n raw: CommerceProduct,\n id: string,\n defaultCurrency?: string\n ): CommerceProduct {\n const sku =\n typeof raw.sku === 'string' && raw.sku.trim()\n ? raw.sku.trim()\n : undefined;\n\n const currency =\n typeof raw.currency === 'string' && raw.currency.trim()\n ? raw.currency.trim()\n : defaultCurrency;\n\n const quantity =\n typeof raw.quantity === 'number' && Number.isFinite(raw.quantity)\n ? raw.quantity\n : undefined;\n\n return {\n ...raw,\n id,\n ...(sku !== undefined ? { sku } : {}),\n ...(currency !== undefined ? { currency } : {}),\n ...(quantity !== undefined ? { quantity } : {}),\n ...(raw.metadata ? { metadata: { ...raw.metadata } } : {}),\n };\n }\n\n private cloneProduct(product: CommerceProduct): CommerceProduct {\n return {\n ...product,\n ...(product.metadata ? { metadata: { ...product.metadata } } : {}),\n };\n }\n}\n","import type { CommerceCartItem } from '@/config/shared/commerce';\n\nexport type CommerceStateOptions = {\n /**\n * Quando `false`, `upsertItem` só atualiza itens já presentes\n * (não adiciona novos productIds). Default: `true`.\n */\n readonly allowDynamicItems?: boolean;\n};\n\nexport type CommerceStateSnapshot = {\n /**\n * Estado vivo do carrinho (runtime).\n * Não confundir com `commerce.cart.initialItems` da config.\n */\n readonly selectedItems: CommerceCartItem[];\n readonly count: number;\n};\n\n/**\n * Estado em memória do cart da instância.\n * Inicializado com `config.commerce.cart.initialItems`.\n * Não persiste, não acessa DOM/Transport e não dispara eventos.\n */\nexport class CommerceState {\n private readonly itemsByProductId = new Map<string, CommerceCartItem>();\n\n private readonly allowDynamicItems: boolean;\n\n constructor(\n initialItems: readonly CommerceCartItem[] | undefined = [],\n options: CommerceStateOptions = {}\n ) {\n this.allowDynamicItems = options.allowDynamicItems !== false;\n this.seed(initialItems ?? []);\n }\n\n getSelectedItems(): CommerceCartItem[] {\n return Array.from(this.itemsByProductId.values()).map(item =>\n this.cloneItem(item)\n );\n }\n\n hasItem(productId: string): boolean {\n return Boolean(productId) && this.itemsByProductId.has(productId);\n }\n\n getItem(productId: string): CommerceCartItem | null {\n if (!productId) return null;\n const item = this.itemsByProductId.get(productId);\n return item ? this.cloneItem(item) : null;\n }\n\n /**\n * Insere ou atualiza item.\n * - Sem `productId` → no-op\n * - `selected === false` → remove se existir / não adiciona\n * - `quantity <= 0` → remove\n * - `allowDynamicItems === false` e item novo → no-op\n */\n upsertItem(item: CommerceCartItem): void {\n if (!item || typeof item !== 'object') return;\n\n const productId =\n typeof item.productId === 'string' ? item.productId.trim() : '';\n if (!productId) return;\n\n if (item.selected === false) {\n this.itemsByProductId.delete(productId);\n return;\n }\n\n const quantity = this.normalizeQuantity(item.quantity);\n if (quantity <= 0) {\n this.itemsByProductId.delete(productId);\n return;\n }\n\n const exists = this.itemsByProductId.has(productId);\n if (!exists && !this.allowDynamicItems) return;\n\n const previous = this.itemsByProductId.get(productId);\n const metadata = item.metadata\n ? { ...item.metadata }\n : previous?.metadata\n ? { ...previous.metadata }\n : undefined;\n\n const next: CommerceCartItem = {\n ...previous,\n ...item,\n productId,\n quantity,\n selected: true,\n ...(metadata ? { metadata } : {}),\n };\n\n this.itemsByProductId.set(productId, next);\n }\n\n removeItem(productId: string): void {\n if (!productId) return;\n this.itemsByProductId.delete(productId);\n }\n\n /**\n * Atualiza quantidade. `quantity <= 0` remove o item.\n */\n updateQuantity(productId: string, quantity: number): void {\n if (!productId || !this.itemsByProductId.has(productId)) return;\n\n const normalized = this.normalizeQuantity(quantity);\n if (normalized <= 0) {\n this.itemsByProductId.delete(productId);\n return;\n }\n\n const current = this.itemsByProductId.get(productId)!;\n this.itemsByProductId.set(productId, {\n ...current,\n quantity: normalized,\n });\n }\n\n clear(): void {\n this.itemsByProductId.clear();\n }\n\n getSnapshot(): CommerceStateSnapshot {\n const selectedItems = this.getSelectedItems();\n return { selectedItems, count: selectedItems.length };\n }\n\n private seed(initialItems: readonly CommerceCartItem[]): void {\n for (const item of initialItems) {\n // Seed ignora allowDynamicItems — itens da config sempre entram\n // (exceto selected:false / inválidos / quantity<=0).\n this.seedItem(item);\n }\n }\n\n private seedItem(item: CommerceCartItem): void {\n if (!item || typeof item !== 'object') return;\n\n const productId =\n typeof item.productId === 'string' ? item.productId.trim() : '';\n if (!productId) return;\n if (item.selected === false) return;\n\n const quantity = this.normalizeQuantity(item.quantity);\n if (quantity <= 0) return;\n\n // Duplicado por productId no seed: mantém o primeiro.\n if (this.itemsByProductId.has(productId)) return;\n\n this.itemsByProductId.set(productId, {\n ...item,\n productId,\n quantity,\n selected: true,\n ...(item.metadata ? { metadata: { ...item.metadata } } : {}),\n });\n }\n\n private normalizeQuantity(quantity: number | undefined): number {\n if (quantity === undefined || quantity === null) return 1;\n if (typeof quantity !== 'number' || !Number.isFinite(quantity)) return 1;\n return quantity;\n }\n\n private cloneItem(item: CommerceCartItem): CommerceCartItem {\n return {\n ...item,\n ...(item.metadata ? { metadata: { ...item.metadata } } : {}),\n };\n }\n}\n","/**\n * Calcula value/currency a partir de items resolvidos.\n * Não conhece DOM, detectors, Transport nem Dispatcher.\n * Não muta o input.\n */\n\nexport type ResolvedCommerceItem = {\n productId?: string;\n sku?: string;\n productName?: string;\n price?: number;\n quantity?: number;\n currency?: string;\n category?: string;\n variant?: string;\n brand?: string;\n type?: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type OrderCalculationInput = {\n items?: ResolvedCommerceItem[];\n value?: number;\n currency?: string;\n defaultCurrency?: string;\n};\n\nexport type OrderCalculationResult = {\n items: ResolvedCommerceItem[];\n value?: number;\n currency?: string;\n};\n\nexport class OrderCalculator {\n calculate(input: OrderCalculationInput): OrderCalculationResult {\n const sourceItems = Array.isArray(input.items) ? input.items : [];\n const items = sourceItems.map(item => this.cloneItem(item));\n\n for (const item of items) {\n if (item.quantity == null || !Number.isFinite(item.quantity)) {\n item.quantity = 1;\n }\n }\n\n const value =\n typeof input.value === 'number' && Number.isFinite(input.value)\n ? input.value\n : this.sumValue(items);\n\n const currency = this.resolveCurrency(input, items);\n\n return {\n items,\n ...(value !== undefined ? { value } : {}),\n ...(currency !== undefined ? { currency } : {}),\n };\n }\n\n private sumValue(items: ResolvedCommerceItem[]): number | undefined {\n let total = 0;\n let hasPriced = false;\n\n for (const item of items) {\n if (typeof item.price !== 'number' || !Number.isFinite(item.price)) {\n continue;\n }\n const qty =\n typeof item.quantity === 'number' && Number.isFinite(item.quantity)\n ? item.quantity\n : 1;\n total += item.price * qty;\n hasPriced = true;\n }\n\n return hasPriced ? total : undefined;\n }\n\n /**\n * Ordem: currency manual → primeiro item com currency → defaultCurrency.\n * Multi-currency: determinístico — usa o primeiro item com currency\n * (não normaliza conversão entre moedas nesta etapa).\n */\n private resolveCurrency(\n input: OrderCalculationInput,\n items: ResolvedCommerceItem[]\n ): string | undefined {\n if (typeof input.currency === 'string' && input.currency.trim()) {\n return input.currency.trim();\n }\n\n for (const item of items) {\n if (typeof item.currency === 'string' && item.currency.trim()) {\n return item.currency.trim();\n }\n }\n\n if (\n typeof input.defaultCurrency === 'string' &&\n input.defaultCurrency.trim()\n ) {\n return input.defaultCurrency.trim();\n }\n\n return undefined;\n }\n\n private cloneItem(item: ResolvedCommerceItem): ResolvedCommerceItem {\n return {\n ...item,\n ...(item.metadata ? { metadata: { ...item.metadata } } : {}),\n };\n }\n}\n","/**\n * Contratos globais de commerce (root `PixelConfig.commerce`).\n * Não pertencem a conversion — representam o contexto comercial da página/fluxo.\n */\n\nexport type ProductType =\n | 'main'\n | 'order_bump'\n | 'upsell'\n | 'downsell'\n | 'cross_sell'\n | 'addon'\n | 'subscription'\n | 'custom'\n | 'other';\n\nexport type CommerceProduct = {\n id: string;\n name?: string;\n sku?: string;\n type?: ProductType;\n price?: number;\n currency?: string;\n quantity?: number;\n category?: string;\n variant?: string;\n brand?: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type CommerceCartItem = {\n productId: string;\n quantity?: number;\n price?: number;\n currency?: string;\n selected?: boolean;\n metadata?: Record<string, unknown>;\n};\n\nexport type CommerceCartMode =\n | 'landing_page'\n | 'single_product'\n | 'multi_product'\n | 'checkout'\n | 'upsell'\n | 'custom'\n | 'cart'\n | 'funnel';\n\nexport type CommerceCalculateValueFrom =\n | 'cart'\n | 'event'\n | 'manual'\n | 'catalog';\n\nexport type CommerceEnrichmentSource =\n | 'cart'\n | 'event'\n | 'event_or_cart'\n | 'catalog';\n\nexport type CommerceEventEnrichmentConfig = {\n enabled: boolean;\n source?: CommerceEnrichmentSource;\n};\n\nexport type CommerceEnrichmentConfig = {\n pageView?: CommerceEventEnrichmentConfig;\n viewContent?: CommerceEventEnrichmentConfig;\n lead?: CommerceEventEnrichmentConfig;\n addToCart?: CommerceEventEnrichmentConfig;\n removeFromCart?: CommerceEventEnrichmentConfig;\n initiateCheckout?: CommerceEventEnrichmentConfig;\n addPaymentInfo?: CommerceEventEnrichmentConfig;\n purchase?: CommerceEventEnrichmentConfig;\n};\n\nexport type ProductCatalogConfig = {\n products?: CommerceProduct[];\n};\n\nexport type CommerceCartConfig = {\n mode?: CommerceCartMode;\n /** Seed inicial do carrinho — não é estado vivo. */\n initialItems?: CommerceCartItem[];\n allowDynamicItems?: boolean;\n calculateValueFrom?: CommerceCalculateValueFrom;\n metadata?: Record<string, unknown>;\n};\n\nexport type CommerceMappingsConfig = {\n attributes?: Record<string, string[]>;\n fields?: Record<string, string[]>;\n};\n\nexport type CommerceConfig = {\n enabled?: boolean;\n currency?: string;\n catalog?: ProductCatalogConfig;\n cart?: CommerceCartConfig;\n mappings?: CommerceMappingsConfig;\n enrichment?: CommerceEnrichmentConfig;\n};\n\nexport const DEFAULT_COMMERCE_ENRICHMENT: Required<CommerceEnrichmentConfig> = {\n pageView: { enabled: true, source: 'cart' },\n viewContent: { enabled: true, source: 'event_or_cart' },\n lead: { enabled: false, source: 'event_or_cart' },\n addToCart: { enabled: true, source: 'event_or_cart' },\n removeFromCart: { enabled: true, source: 'event_or_cart' },\n initiateCheckout: { enabled: true, source: 'cart' },\n addPaymentInfo: { enabled: true, source: 'cart' },\n purchase: { enabled: true, source: 'cart' },\n};\n\n/**\n * Commerce on by default so catalog/cart enrichment runs when products exist.\n * Empty catalog / empty cart is a no-op.\n */\nexport const DEFAULT_COMMERCE_CONFIG: CommerceConfig = {\n enabled: true,\n currency: 'BRL',\n catalog: {\n products: [],\n },\n cart: {\n mode: 'custom',\n initialItems: [],\n allowDynamicItems: true,\n calculateValueFrom: 'cart',\n },\n mappings: {\n attributes: {},\n fields: {},\n },\n enrichment: { ...DEFAULT_COMMERCE_ENRICHMENT },\n};\n\n/** Normaliza calculateValueFrom (inclui aliases legado em runtime). */\nexport function normalizeCalculateValueFrom(\n value: CommerceCalculateValueFrom | string | undefined\n): 'cart' | 'event' | 'manual' | 'catalog' {\n switch (value) {\n case 'event':\n case 'event_items':\n return 'event';\n case 'manual':\n return 'manual';\n case 'catalog':\n return 'catalog';\n case 'cart':\n case 'selected_items':\n default:\n return 'cart';\n }\n}\n","import type { CommerceCalculateValueFrom } from '@/config/shared/commerce';\nimport { normalizeCalculateValueFrom } from '@/config/shared/commerce';\nimport type { PixelItem } from '@/events/conversion';\n\nimport type { CommerceState } from './CommerceState';\nimport type { ProductCatalog } from './ProductCatalog';\nimport type { OrderCalculator, ResolvedCommerceItem } from './OrderCalculator';\n\nexport type CommerceEventType =\n | 'ADD_TO_CART'\n | 'REMOVE_FROM_CART'\n | 'INITIATE_CHECKOUT'\n | 'PURCHASE'\n | 'VIEW_CONTENT'\n | 'ADD_PAYMENT_INFO';\n\nexport type ExtractedProductInput = {\n productId?: string;\n productName?: string;\n price?: number;\n quantity?: number;\n currency?: string;\n sku?: string;\n};\n\nexport type CommerceResolverInput = {\n eventType: CommerceEventType;\n payload?: Record<string, unknown>;\n extractedProduct?: ExtractedProductInput;\n enrichmentSource?: import('@/config/shared/commerce').CommerceEnrichmentSource;\n items?: Array<{\n productId?: string;\n id?: string;\n sku?: string;\n name?: string;\n productName?: string;\n price?: number;\n quantity?: number;\n currency?: string;\n category?: string;\n }>;\n};\n\nexport type CommerceResolverResult = {\n data: Record<string, unknown>;\n items?: ResolvedCommerceItem[];\n value?: number;\n currency?: string;\n};\n\nexport type CommerceResolverOptions = {\n catalog: ProductCatalog;\n state: CommerceState;\n calculator: OrderCalculator;\n defaultCurrency?: string;\n calculateValueFrom?: CommerceCalculateValueFrom;\n};\n\n/**\n * Combina payload + extracted + state + catalog + defaults.\n * Não dispara eventos, não escreve em CommerceState, não conhece DOM/Transport.\n *\n * Prioridade de merge por campo:\n * manual payload > extractedProduct > commerce state > catalog > defaults\n */\nexport class CommerceResolver {\n private readonly catalog: ProductCatalog;\n\n private readonly state: CommerceState;\n\n private readonly calculator: OrderCalculator;\n\n private readonly defaultCurrency?: string;\n\n private readonly calculateValueFrom: ReturnType<\n typeof normalizeCalculateValueFrom\n >;\n\n constructor(options: CommerceResolverOptions) {\n this.catalog = options.catalog;\n this.state = options.state;\n this.calculator = options.calculator;\n this.defaultCurrency = trim(options.defaultCurrency);\n this.calculateValueFrom = normalizeCalculateValueFrom(\n options.calculateValueFrom\n );\n }\n\n resolve(input: CommerceResolverInput): CommerceResolverResult {\n const source = input.enrichmentSource;\n\n // source: 'event' — não completa via cart/catalog\n if (source === 'event') {\n return { data: { ...(input.payload ?? {}) } };\n }\n\n switch (input.eventType) {\n case 'ADD_TO_CART':\n return this.resolveAddToCart(input);\n case 'REMOVE_FROM_CART':\n return this.resolveRemoveFromCart(input);\n case 'INITIATE_CHECKOUT':\n return this.resolveCheckoutLike(input, false);\n case 'PURCHASE':\n return this.resolveCheckoutLike(input, true);\n case 'VIEW_CONTENT':\n return this.resolveViewContent(input);\n case 'ADD_PAYMENT_INFO':\n return this.resolveCheckoutLike(input, false);\n default:\n return { data: { ...(input.payload ?? {}) } };\n }\n }\n\n private resolveAddToCart(\n input: CommerceResolverInput\n ): CommerceResolverResult {\n const payload = input.payload ?? {};\n const extracted = input.extractedProduct ?? {};\n const source = input.enrichmentSource ?? 'event_or_cart';\n const useCart = source === 'cart' || source === 'event_or_cart';\n const useCatalog =\n source === 'catalog' || source === 'cart' || source === 'event_or_cart';\n\n let productId =\n asString(payload.priceId) ??\n asString(payload.productId) ??\n asString(extracted.productId) ??\n (useCatalog\n ? this.lookupIdBySku(asString(payload.sku) ?? asString(extracted.sku))\n : undefined);\n\n // Fallback: sem productId/sku no evento → item principal do cart\n const cartFallback =\n !productId && useCart ? this.resolvePrimaryCartItem() : null;\n if (!productId && cartFallback) {\n productId = cartFallback.productId;\n }\n\n const catalogProduct =\n useCatalog && productId\n ? this.catalog.getById(productId)\n : useCatalog\n ? this.lookupProductBySku(\n asString(payload.sku) ?? asString(extracted.sku)\n )\n : null;\n\n const resolvedId = productId ?? catalogProduct?.id;\n const stateItem =\n useCart && resolvedId\n ? (this.state.getItem(resolvedId) ?? cartFallback)\n : null;\n\n // source: 'catalog' sem productId/sku → não injeta cart\n if (source === 'catalog' && !resolvedId && !catalogProduct) {\n return { data: { ...payload } };\n }\n\n const productName =\n asString(payload.productName) ??\n asString(extracted.productName) ??\n catalogProduct?.name;\n\n const price =\n asNumber(payload.price) ??\n asNumber(extracted.price) ??\n (useCart ? asNumber(stateItem?.price) : undefined) ??\n catalogProduct?.price;\n\n const quantity =\n asNumber(payload.quantity) ??\n asNumber(extracted.quantity) ??\n (useCart ? asNumber(stateItem?.quantity) : undefined) ??\n catalogProduct?.quantity ??\n 1;\n\n const currency =\n asString(payload.currency) ??\n asString(extracted.currency) ??\n (useCart ? asString(stateItem?.currency) : undefined) ??\n catalogProduct?.currency ??\n this.defaultCurrency;\n\n const identity = resolveCatalogItemIdentity(catalogProduct, {\n priceId: asString(payload.priceId),\n productId: resolvedId,\n offerId: asString(payload.offerId),\n id: asString(payload.id),\n });\n\n const data: Record<string, unknown> = {};\n if (identity.id) data.id = identity.id;\n if (identity.priceId) data.priceId = identity.priceId;\n if (identity.productId) data.productId = identity.productId;\n if (identity.offerId) data.offerId = identity.offerId;\n if (productName) data.productName = productName;\n if (price !== undefined) data.price = price;\n if (currency) data.currency = currency;\n if (quantity !== undefined) data.quantity = quantity;\n\n // Preserva campos extras do payload (sem sobrescrever resolvidos).\n for (const [key, value] of Object.entries(payload)) {\n if (value === undefined) continue;\n if (!(key in data)) data[key] = value;\n }\n\n return { data };\n }\n\n /**\n * Escolhe o item principal do cart runtime:\n * 1. único item → esse\n * 2. múltiplos → preferir catalog.type === 'main'\n * 3. senão → primeiro do cart\n * 4. cart vazio → null\n */\n private resolvePrimaryCartItem(): {\n productId: string;\n quantity?: number;\n price?: number;\n currency?: string;\n } | null {\n const items = this.state.getSelectedItems();\n if (items.length === 0) return null;\n if (items.length === 1) return items[0] ?? null;\n\n const main = items.find(item => {\n const product = this.catalog.getById(item.productId);\n return product?.type === 'main';\n });\n return main ?? items[0] ?? null;\n }\n\n private resolveRemoveFromCart(\n input: CommerceResolverInput\n ): CommerceResolverResult {\n const payload = input.payload ?? {};\n const extracted = input.extractedProduct ?? {};\n\n const productId =\n asString(payload.productId) ??\n asString(extracted.productId) ??\n this.lookupIdBySku(asString(payload.sku) ?? asString(extracted.sku));\n\n const catalogProduct = productId ? this.catalog.getById(productId) : null;\n\n const resolvedId = productId ?? catalogProduct?.id;\n const stateItem = resolvedId ? this.state.getItem(resolvedId) : null;\n\n const quantity =\n asNumber(payload.quantity) ??\n asNumber(extracted.quantity) ??\n asNumber(stateItem?.quantity) ??\n 1;\n\n const data: Record<string, unknown> = {};\n if (resolvedId) data.productId = resolvedId;\n if (quantity !== undefined) data.quantity = quantity;\n\n for (const [key, value] of Object.entries(payload)) {\n if (value === undefined) continue;\n if (!(key in data)) data[key] = value;\n }\n\n return { data };\n }\n\n private resolveCheckoutLike(\n input: CommerceResolverInput,\n isPurchase: boolean\n ): CommerceResolverResult {\n const payload = { ...(input.payload ?? {}) };\n const manualValue = asNumber(payload.value);\n const manualCurrency = asString(payload.currency);\n const manualItems = this.readPayloadItems(input);\n const source = input.enrichmentSource;\n\n const resolvedItems = this.resolveItemsSource(manualItems, source);\n const pixelItems = resolvedItems.map(item => this.toPixelItem(item));\n\n const allowCalculatedValue =\n source !== 'catalog' && this.calculateValueFrom !== 'manual';\n\n const shouldCalculateValue =\n manualValue === undefined && allowCalculatedValue;\n\n const calc = this.calculator.calculate({\n items: resolvedItems,\n value: shouldCalculateValue ? undefined : manualValue,\n currency: manualCurrency,\n defaultCurrency: this.defaultCurrency,\n });\n\n const value =\n manualValue !== undefined\n ? manualValue\n : allowCalculatedValue\n ? calc.value\n : undefined;\n\n const currency = manualCurrency ?? calc.currency ?? this.defaultCurrency;\n\n const data: Record<string, unknown> = { ...payload };\n\n if (pixelItems.length > 0) {\n data.items = pixelItems;\n } else if (manualItems === null) {\n delete data.items;\n }\n\n if (value !== undefined) {\n data.value = value;\n } else {\n delete data.value;\n }\n\n if (currency) {\n data.currency = currency;\n }\n\n if (isPurchase) {\n // orderId e demais campos do payload já estão em data via spread.\n }\n\n return {\n data,\n items: calc.items,\n ...(value !== undefined ? { value } : {}),\n ...(currency ? { currency } : {}),\n };\n }\n\n private resolveViewContent(\n input: CommerceResolverInput\n ): CommerceResolverResult {\n const payload = { ...(input.payload ?? {}) };\n const source = input.enrichmentSource ?? 'event_or_cart';\n\n // Tenta completar productId/name/price a partir de payload + cart/catalog\n if (source === 'cart' || source === 'event_or_cart') {\n const atc = this.resolveAddToCart({\n ...input,\n eventType: 'ADD_TO_CART',\n enrichmentSource: source,\n });\n\n const checkout = this.resolveCheckoutLike(\n { ...input, eventType: 'INITIATE_CHECKOUT', enrichmentSource: source },\n false\n );\n\n const data: Record<string, unknown> = { ...payload };\n\n const contentId =\n asString(payload.contentId) ??\n asString(atc.data.productId as string | undefined) ??\n (Array.isArray(checkout.data.items) &&\n checkout.data.items[0] &&\n typeof (checkout.data.items[0] as { id?: unknown }).id === 'string'\n ? (checkout.data.items[0] as { id: string }).id\n : undefined);\n\n const contentName =\n asString(payload.contentName) ??\n asString(atc.data.productName as string | undefined) ??\n (Array.isArray(checkout.data.items) &&\n checkout.data.items[0] &&\n typeof (checkout.data.items[0] as { name?: unknown }).name === 'string'\n ? (checkout.data.items[0] as { name: string }).name\n : undefined);\n\n if (contentId) data.contentId = contentId;\n if (contentName) data.contentName = contentName;\n\n if (\n asNumber(payload.value) === undefined &&\n checkout.value !== undefined\n ) {\n data.value = checkout.value;\n }\n if (!asString(payload.currency) && checkout.currency) {\n data.currency = checkout.currency;\n }\n if (payload.items === undefined && Array.isArray(checkout.data.items)) {\n data.items = checkout.data.items;\n }\n\n return {\n data,\n ...(checkout.value !== undefined ? { value: checkout.value } : {}),\n ...(checkout.currency ? { currency: checkout.currency } : {}),\n items: checkout.items,\n };\n }\n\n if (source === 'catalog') {\n const atc = this.resolveAddToCart({\n ...input,\n eventType: 'ADD_TO_CART',\n enrichmentSource: 'catalog',\n });\n const data: Record<string, unknown> = { ...payload };\n if (atc.data.productId && !asString(payload.contentId)) {\n data.contentId = atc.data.productId;\n }\n if (atc.data.productName && !asString(payload.contentName)) {\n data.contentName = atc.data.productName;\n }\n if (\n atc.data.price !== undefined &&\n asNumber(payload.value) === undefined\n ) {\n data.value = atc.data.price;\n }\n if (atc.data.currency && !asString(payload.currency)) {\n data.currency = atc.data.currency;\n }\n return { data };\n }\n\n return { data: payload };\n }\n\n /**\n * null = payload não trouxe items (usar state conforme calculateValueFrom)\n * [] = payload trouxe items vazios\n */\n private readPayloadItems(\n input: CommerceResolverInput\n ): ResolvedCommerceItem[] | null {\n if (input.items) {\n return input.items.map(item => this.normalizeLooseItem(item));\n }\n\n const raw = input.payload?.items;\n if (raw === undefined) return null;\n if (!Array.isArray(raw)) return null;\n return raw.map(item =>\n this.normalizeLooseItem(\n (item && typeof item === 'object' ? item : {}) as Record<\n string,\n unknown\n >\n )\n );\n }\n\n private resolveItemsSource(\n manualItems: ResolvedCommerceItem[] | null,\n enrichmentSource?: import('@/config/shared/commerce').CommerceEnrichmentSource\n ): ResolvedCommerceItem[] {\n // Items manuais sempre vencem state.\n if (manualItems !== null) {\n return manualItems.map(item => this.enrichItem(item));\n }\n\n // source: 'catalog' — não injeta cart inteiro\n if (enrichmentSource === 'catalog') {\n return [];\n }\n\n // source: 'cart' força fallback do carrinho (independente de calculateValueFrom),\n // exceto quando calculateValueFrom === 'manual' (value/items só do payload).\n if (\n enrichmentSource === 'cart' &&\n this.calculateValueFrom !== 'manual' &&\n this.calculateValueFrom !== 'event'\n ) {\n return this.state.getSelectedItems().map(stateItem =>\n this.enrichItem({\n productId: stateItem.productId,\n price: stateItem.price,\n quantity: stateItem.quantity,\n currency: stateItem.currency,\n })\n );\n }\n\n if (this.calculateValueFrom === 'cart') {\n return this.state.getSelectedItems().map(stateItem =>\n this.enrichItem({\n productId: stateItem.productId,\n price: stateItem.price,\n quantity: stateItem.quantity,\n currency: stateItem.currency,\n })\n );\n }\n\n if (this.calculateValueFrom === 'catalog') {\n const fromState = this.state.getSelectedItems();\n if (fromState.length > 0) {\n return fromState.map(stateItem =>\n this.enrichItem({\n productId: stateItem.productId,\n price: stateItem.price,\n quantity: stateItem.quantity,\n currency: stateItem.currency,\n })\n );\n }\n return this.catalog.list().map(product =>\n this.enrichItem({\n productId: product.id,\n price: product.price,\n quantity: product.quantity ?? 1,\n currency: product.currency,\n productName: product.name,\n sku: product.sku,\n category: product.category,\n })\n );\n }\n\n // event / manual sem items no payload → sem items\n return [];\n }\n\n private enrichItem(item: ResolvedCommerceItem): ResolvedCommerceItem {\n const productId =\n item.productId ?? this.lookupIdBySku(item.sku) ?? undefined;\n const catalog = productId\n ? this.catalog.getById(productId)\n : this.lookupProductBySku(item.sku);\n\n const resolvedId = productId ?? catalog?.id;\n\n return {\n ...item,\n ...(resolvedId ? { productId: resolvedId } : {}),\n productName: item.productName ?? catalog?.name,\n sku: item.sku ?? catalog?.sku,\n price: item.price ?? catalog?.price,\n quantity: item.quantity ?? catalog?.quantity ?? 1,\n currency: item.currency ?? catalog?.currency ?? this.defaultCurrency,\n category: item.category ?? catalog?.category,\n variant: item.variant ?? catalog?.variant,\n brand: item.brand ?? catalog?.brand,\n type: item.type ?? catalog?.type,\n metadata: item.metadata ?? catalog?.metadata,\n };\n }\n\n private toPixelItem(item: ResolvedCommerceItem): PixelItem {\n const pixel: PixelItem = {\n ...(item.productId ? { id: item.productId } : {}),\n ...(item.productName ? { name: item.productName } : {}),\n ...(item.category ? { category: item.category } : {}),\n ...(item.price !== undefined ? { price: item.price } : {}),\n ...(item.quantity !== undefined ? { quantity: item.quantity } : {}),\n };\n return pixel;\n }\n\n private normalizeLooseItem(\n item:\n | Record<string, unknown>\n | {\n productId?: string;\n id?: string;\n sku?: string;\n name?: string;\n productName?: string;\n price?: number;\n quantity?: number;\n currency?: string;\n category?: string;\n }\n ): ResolvedCommerceItem {\n return {\n productId:\n asString((item as { productId?: unknown }).productId) ??\n asString((item as { id?: unknown }).id),\n sku: asString((item as { sku?: unknown }).sku),\n productName:\n asString((item as { productName?: unknown }).productName) ??\n asString((item as { name?: unknown }).name),\n price: asNumber((item as { price?: unknown }).price),\n quantity: asNumber((item as { quantity?: unknown }).quantity),\n currency: asString((item as { currency?: unknown }).currency),\n category: asString((item as { category?: unknown }).category),\n };\n }\n\n private lookupIdBySku(sku: string | undefined): string | undefined {\n if (!sku) return undefined;\n return this.catalog.getBySku(sku)?.id;\n }\n\n private lookupProductBySku(sku: string | undefined) {\n if (!sku) return null;\n return this.catalog.getBySku(sku);\n }\n}\n\nfunction resolveCatalogItemIdentity(\n catalogProduct: import('@/config/shared/commerce').CommerceProduct | null,\n incoming: {\n id?: string;\n priceId?: string;\n productId?: string;\n offerId?: string;\n }\n): {\n id?: string;\n priceId?: string;\n productId?: string;\n offerId?: string;\n} {\n const meta = catalogProduct?.metadata ?? {};\n const metaPriceId = asString(meta.priceId);\n const metaProductId = asString(meta.productId);\n const metaOfferId = asString(meta.offerId);\n\n // Identidade Bemony (id/priceId/offerId) só quando priceId explícito ou metadata.\n // Catálogo genérico do Core continua só com productId.\n const priceId = incoming.priceId ?? metaPriceId;\n if (!priceId) {\n const productId = incoming.productId ?? catalogProduct?.id;\n return {\n ...(incoming.id ? { id: incoming.id } : {}),\n ...(productId ? { productId } : {}),\n ...(incoming.offerId ? { offerId: incoming.offerId } : {}),\n };\n }\n\n return {\n id: incoming.id ?? priceId,\n priceId,\n productId: metaProductId ?? incoming.productId ?? priceId,\n offerId: metaOfferId ?? incoming.offerId ?? priceId,\n };\n}\n\nfunction asString(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value)) return undefined;\n return value;\n}\n\nfunction trim(value: string | undefined): string | undefined {\n if (typeof value !== 'string') return undefined;\n const t = value.trim();\n return t.length > 0 ? t : undefined;\n}\n","import type {\n CommerceConfig,\n CommerceEnrichmentSource,\n CommerceEventEnrichmentConfig,\n} from '@/config/shared/commerce';\nimport {\n DEFAULT_COMMERCE_CONFIG,\n DEFAULT_COMMERCE_ENRICHMENT,\n normalizeCalculateValueFrom,\n} from '@/config/shared/commerce';\nimport type { PixelItem } from '@/events/conversion';\n\nimport { CommerceResolver } from './CommerceResolver';\nimport { CommerceState } from './CommerceState';\nimport { OrderCalculator } from './OrderCalculator';\nimport { ProductCatalog } from './ProductCatalog';\n\nexport type CommerceEnrichmentEvent =\n | 'pageView'\n | 'viewContent'\n | 'lead'\n | 'addToCart'\n | 'removeFromCart'\n | 'initiateCheckout'\n | 'addPaymentInfo'\n | 'purchase';\n\nexport type PageViewCommercePayload = {\n readonly value?: number;\n readonly currency?: string;\n readonly items?: PixelItem[];\n readonly contentId?: string;\n readonly contentName?: string;\n};\n\n/**\n * Serviço compartilhado de commerce (root config).\n * Usado por Core (PAGE_VIEW) e Conversion sem dependência circular\n * entre os módulos.\n */\nexport class CommerceService {\n readonly enabled: boolean;\n\n readonly config: CommerceConfig;\n\n readonly catalog: ProductCatalog;\n\n readonly state: CommerceState;\n\n private readonly resolver: CommerceResolver;\n\n constructor(config: CommerceConfig | undefined) {\n this.config = {\n ...DEFAULT_COMMERCE_CONFIG,\n ...config,\n catalog: {\n products: config?.catalog?.products ?? [],\n },\n cart: {\n ...DEFAULT_COMMERCE_CONFIG.cart,\n ...config?.cart,\n initialItems: config?.cart?.initialItems\n ? config.cart.initialItems.map(item => ({ ...item }))\n : [],\n },\n mappings: {\n attributes: { ...(config?.mappings?.attributes ?? {}) },\n fields: { ...(config?.mappings?.fields ?? {}) },\n },\n enrichment: {\n ...DEFAULT_COMMERCE_ENRICHMENT,\n ...config?.enrichment,\n },\n };\n\n this.enabled = this.config.enabled === true;\n\n this.catalog = new ProductCatalog(this.config.catalog?.products, {\n defaultCurrency: this.config.currency,\n });\n\n this.state = new CommerceState(this.config.cart?.initialItems, {\n allowDynamicItems: this.config.cart?.allowDynamicItems !== false,\n });\n\n this.resolver = new CommerceResolver({\n catalog: this.catalog,\n state: this.state,\n calculator: new OrderCalculator(),\n defaultCurrency: this.config.currency,\n calculateValueFrom: normalizeCalculateValueFrom(\n this.config.cart?.calculateValueFrom\n ),\n });\n }\n\n getEnrichment(event: CommerceEnrichmentEvent): CommerceEventEnrichmentConfig {\n const fromConfig = this.config.enrichment?.[event];\n const fallback = DEFAULT_COMMERCE_ENRICHMENT[event];\n return {\n enabled: fromConfig?.enabled ?? fallback.enabled,\n source: fromConfig?.source ?? fallback.source,\n };\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n isEnrichmentEnabled(event: CommerceEnrichmentEvent): boolean {\n return this.enabled && this.getEnrichment(event).enabled === true;\n }\n\n getEnrichmentSource(\n event: CommerceEnrichmentEvent\n ): CommerceEnrichmentSource {\n return this.getEnrichment(event).source ?? 'event_or_cart';\n }\n\n /**\n * Resolve payload de commerce para um evento conversion.\n * Retorna null quando enrichment está desabilitado (caller usa payload original).\n */\n resolveForEvent(\n event: CommerceEnrichmentEvent,\n eventType:\n | 'ADD_TO_CART'\n | 'REMOVE_FROM_CART'\n | 'INITIATE_CHECKOUT'\n | 'PURCHASE'\n | 'VIEW_CONTENT'\n | 'ADD_PAYMENT_INFO',\n payload: Record<string, unknown> = {}\n ): Record<string, unknown> | null {\n if (!this.isEnrichmentEnabled(event)) return null;\n\n const result = this.resolver.resolve({\n eventType,\n payload,\n enrichmentSource: this.getEnrichmentSource(event),\n });\n\n return result.data;\n }\n\n /**\n * Payload de commerce para PAGE_VIEW quando enrichment.pageView.enabled.\n * Não depende de ConversionEngine.\n */\n resolvePageViewEnrichment(): PageViewCommercePayload | null {\n if (!this.isEnrichmentEnabled('pageView')) return null;\n\n const source = this.getEnrichment('pageView').source ?? 'cart';\n if (source === 'event') return null;\n\n const resolved = this.resolver.resolve({\n eventType: 'INITIATE_CHECKOUT',\n payload: {},\n });\n\n const items = (resolved.data.items as PixelItem[] | undefined) ?? [];\n const first = items[0];\n const contentId =\n first && typeof first.id === 'string' ? first.id : undefined;\n const contentName =\n first && typeof first.name === 'string' ? first.name : undefined;\n\n if (\n resolved.value === undefined &&\n !resolved.currency &&\n items.length === 0\n ) {\n return null;\n }\n\n return {\n ...(resolved.value !== undefined ? { value: resolved.value } : {}),\n ...(resolved.currency ? { currency: resolved.currency } : {}),\n ...(items.length > 0 ? { items } : {}),\n ...(contentId ? { contentId } : {}),\n ...(contentName ? { contentName } : {}),\n };\n }\n\n getResolver(): CommerceResolver {\n return this.resolver;\n }\n\n getCalculateValueFrom(): ReturnType<typeof normalizeCalculateValueFrom> {\n return normalizeCalculateValueFrom(this.config.cart?.calculateValueFrom);\n }\n\n getMappings() {\n return this.config.mappings;\n }\n}\n","function createRandomSuffix(): string {\n if (\n typeof crypto !== 'undefined' &&\n typeof crypto.randomUUID === 'function'\n ) {\n return crypto.randomUUID().replace(/-/g, '');\n }\n\n return `${Date.now()}${Math.random().toString(36).slice(2)}`;\n}\n\nexport function generateSessionId(): string {\n return `ses_${createRandomSuffix()}`;\n}\n","import type { PixelConfig } from '@/config';\nimport type { StorageService } from '@/services/storage';\n\nimport type { EnsureSessionResult, SessionData, SessionService } from './types';\nimport { generateSessionId } from './session-id';\n\nconst DEFAULT_SESSION_KEY = 'session';\n\nexport class SessionServiceImpl implements SessionService {\n private readonly storage: StorageService;\n\n private readonly storageKey: string;\n\n constructor(storage: StorageService, config: PixelConfig) {\n this.storage = storage;\n this.storageKey = config.storage.keys?.session ?? DEFAULT_SESSION_KEY;\n }\n\n getSessionId(): string | null {\n return this.getSessionData()?.sessionId ?? null;\n }\n\n getSessionData(): SessionData | null {\n const raw = this.storage.get<SessionData | string>(this.storageKey);\n if (!raw) return null;\n\n if (typeof raw === 'string') {\n const now = Date.now();\n return {\n sessionId: raw,\n lastActivityAt: now,\n createdAt: now,\n };\n }\n\n return raw;\n }\n\n getLastActivityAt(): number | null {\n return this.getSessionData()?.lastActivityAt ?? null;\n }\n\n isExpired(ttlMs: number): boolean {\n const data = this.getSessionData();\n if (!data) return true;\n\n return Date.now() - data.lastActivityAt > ttlMs;\n }\n\n ensureSession(ttlMs: number): EnsureSessionResult {\n const data = this.getSessionData();\n const now = Date.now();\n\n if (!data) {\n const sessionId = generateSessionId();\n this.writeSessionData({\n sessionId,\n lastActivityAt: now,\n createdAt: now,\n });\n\n return {\n sessionId,\n expired: false,\n created: true,\n };\n }\n\n if (now - data.lastActivityAt > ttlMs) {\n const previousSessionId = data.sessionId;\n const sessionId = generateSessionId();\n\n this.writeSessionData({\n sessionId,\n lastActivityAt: now,\n createdAt: now,\n });\n\n return {\n sessionId,\n expired: true,\n previousSessionId,\n created: false,\n };\n }\n\n return {\n sessionId: data.sessionId,\n expired: false,\n created: false,\n };\n }\n\n ensureSessionId(): string {\n return this.ensureSession(Number.MAX_SAFE_INTEGER).sessionId;\n }\n\n touchActivity(): void {\n const data = this.getSessionData();\n if (!data) return;\n\n this.writeSessionData({\n ...data,\n lastActivityAt: Date.now(),\n });\n }\n\n renew(): string {\n const now = Date.now();\n const sessionId = generateSessionId();\n\n this.writeSessionData({\n sessionId,\n lastActivityAt: now,\n createdAt: now,\n });\n\n return sessionId;\n }\n\n clear(): void {\n this.storage.remove(this.storageKey);\n }\n\n private writeSessionData(data: SessionData): void {\n this.storage.set(this.storageKey, data);\n }\n}\n","function createRandomSuffix(): string {\n if (\n typeof crypto !== 'undefined' &&\n typeof crypto.randomUUID === 'function'\n ) {\n return crypto.randomUUID().replace(/-/g, '');\n }\n\n return `${Date.now()}${Math.random().toString(36).slice(2)}`;\n}\n\nexport function generateVisitorId(): string {\n return `vst_${createRandomSuffix()}`;\n}\n","import type { PixelConfig } from '@/config';\nimport type { StorageService } from '@/services/storage';\n\nimport type { VisitorService } from './types';\nimport { generateVisitorId } from './visitor-id';\n\nconst DEFAULT_VISITOR_KEY = 'visitor';\n\nexport class VisitorServiceImpl implements VisitorService {\n private readonly storage: StorageService;\n\n private readonly storageKey: string;\n\n constructor(storage: StorageService, config: PixelConfig) {\n this.storage = storage;\n this.storageKey = config.storage.keys?.visitor ?? DEFAULT_VISITOR_KEY;\n }\n\n getVisitorId(): string | null {\n return this.storage.get<string>(this.storageKey);\n }\n\n ensureVisitorId(): string {\n const existing = this.getVisitorId();\n if (existing) return existing;\n\n const visitorId = generateVisitorId();\n this.storage.set(this.storageKey, visitorId);\n return visitorId;\n }\n\n clearVisitorId(): void {\n this.storage.remove(this.storageKey);\n }\n}\n","/** Constantes default de UrlContext — denylist, domínios e selectors. */\n\nexport const DEFAULT_URL_CONTEXT_DENYLIST: readonly string[] = [\n 'token',\n 'access_token',\n 'refresh_token',\n 'id_token',\n 'password',\n 'pass',\n 'pwd',\n 'email',\n 'phone',\n 'cpf',\n 'cnpj',\n 'document',\n 'card',\n 'cc',\n 'credit_card',\n 'cvv',\n 'cvc',\n 'auth',\n 'code',\n 'sessionId',\n 'internalSessionId',\n 'pixelSessionId',\n];\n\nexport const DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS: readonly string[] = [\n 'facebook.com',\n 'google.com',\n 'youtube.com',\n 'instagram.com',\n 'wa.me',\n 'whatsapp.com',\n 't.me',\n 'telegram.me',\n];\n\nexport const DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS: readonly string[] = [\n '[data-no-url-context]',\n '[download]',\n];\n\nexport const SID_EXCLUDE_SELECTOR = '[data-no-sid]';\n\nexport const DEFAULT_URL_CONTEXT_SID_MAX_AGE_MS = 1000 * 60 * 60 * 24 * 30;\n","import {\n DEFAULT_URL_CONTEXT_DENYLIST,\n DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS,\n DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS,\n SID_EXCLUDE_SELECTOR,\n} from './constants';\n\nexport function normalizeParamKey(key: string): string {\n return key.trim().toLowerCase();\n}\n\n/** decodeURIComponent seguro — URI malformada não quebra o collector. */\nexport function safeDecodeURIComponent(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nexport function buildDenylistSet(\n userDenylist: readonly string[] | undefined,\n mergeDefault: boolean | undefined\n): Set<string> {\n const set = new Set<string>();\n if (mergeDefault !== false) {\n for (const key of DEFAULT_URL_CONTEXT_DENYLIST) {\n set.add(normalizeParamKey(key));\n }\n }\n for (const key of userDenylist ?? []) {\n if (typeof key === 'string' && key.trim()) {\n set.add(normalizeParamKey(key));\n }\n }\n return set;\n}\n\nexport function buildExcludedDomains(\n userExcluded: readonly string[] | undefined,\n mergeDefault: boolean | undefined\n): string[] {\n const list: string[] = [];\n if (mergeDefault !== false) {\n list.push(...DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS);\n }\n for (const domain of userExcluded ?? []) {\n if (typeof domain === 'string' && domain.trim()) {\n list.push(domain.trim().toLowerCase());\n }\n }\n return Array.from(new Set(list.map(d => d.toLowerCase())));\n}\n\nexport function buildExcludeSelectors(\n userSelectors: readonly string[] | undefined,\n mergeDefault: boolean | undefined,\n includeSidSelector: boolean\n): string[] {\n const list: string[] = [];\n if (mergeDefault !== false) {\n list.push(...DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS);\n }\n if (includeSidSelector) {\n list.push(SID_EXCLUDE_SELECTOR);\n }\n for (const sel of userSelectors ?? []) {\n if (typeof sel === 'string' && sel.trim()) {\n list.push(sel.trim());\n }\n }\n return Array.from(new Set(list));\n}\n\nexport function isDeniedKey(key: string, denylist: Set<string>): boolean {\n return denylist.has(normalizeParamKey(key));\n}\n\nexport function hostMatchesDomain(hostname: string, domain: string): boolean {\n const host = hostname.toLowerCase().replace(/\\.$/, '');\n // remove porta se vier colada por engano\n const hostNoPort = host.replace(/:\\d+$/, '');\n const target = domain.toLowerCase().replace(/^\\./, '').replace(/:\\d+$/, '');\n return hostNoPort === target || hostNoPort.endsWith(`.${target}`);\n}\n\nexport function isDomainAllowed(\n hostname: string,\n allowedDomains: '*' | string[] | undefined,\n excludedDomains: readonly string[]\n): boolean {\n /**\n * Hostname vazio (ex.: `file://` + link relativo / same-origin local).\n * Permitido apenas com sentinel `local` ou allow-all `*`.\n */\n if (!hostname) {\n if (allowedDomains === undefined || allowedDomains === '*') return true;\n return allowedDomains.some(\n domain => domain.trim().toLowerCase() === 'local'\n );\n }\n\n for (const excluded of excludedDomains) {\n if (hostMatchesDomain(hostname, excluded)) return false;\n }\n\n if (allowedDomains === undefined || allowedDomains === '*') return true;\n\n return allowedDomains.some(domain => {\n const normalized = domain.trim().toLowerCase();\n // Sentinel `local` não é hostname real\n if (normalized === 'local') return false;\n return hostMatchesDomain(hostname, domain);\n });\n}\n\n/** Gera ID público: `sid_<ts_base36>_<random>` — sem PII / session / visitor. */\nexport function generatePublicId(prefix = 'sid'): string {\n const safePrefix = (prefix || 'sid').replace(/[^a-zA-Z0-9_-]/g, '') || 'sid';\n const ts = Date.now().toString(36);\n const random = Math.random().toString(36).slice(2, 10);\n return `${safePrefix}_${ts}_${random}`;\n}\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * replaceState silencioso — usa History.prototype para não disparar\n * NavigationObserver / SPA PAGE_VIEW do Core.\n */\nexport function silentReplaceState(url: string): void {\n if (!isBrowser()) return;\n try {\n History.prototype.replaceState.call(\n history,\n history.state,\n document.title,\n url\n );\n } catch {\n // ignore — SSR / environments sem History\n }\n}\n\n/**\n * Parse de query string.\n * - duplicados: último valor vence (payload simples / idempotente)\n * - encoding malformado: não lança\n * - `+` → espaço\n */\nexport function parseSearchParams(search: string): Record<string, string> {\n const result: Record<string, string> = {};\n if (!search || search === '?') return result;\n\n const raw = search.startsWith('?') ? search.slice(1) : search;\n if (!raw) return result;\n\n for (const part of raw.split('&')) {\n if (!part) continue;\n const eq = part.indexOf('=');\n const key = safeDecodeURIComponent(\n (eq >= 0 ? part.slice(0, eq) : part).replace(/\\+/g, ' ')\n ).trim();\n if (!key) continue;\n const value =\n eq >= 0\n ? safeDecodeURIComponent(part.slice(eq + 1).replace(/\\+/g, ' '))\n : '';\n result[key] = value;\n }\n\n return result;\n}\n\nexport function buildSearchString(params: Record<string, string>): string {\n const pairs: string[] = [];\n for (const [key, value] of Object.entries(params)) {\n if (!key) continue;\n pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value ?? '')}`);\n }\n return pairs.length > 0 ? `?${pairs.join('&')}` : '';\n}\n\n/** Cópia rasa congelada — evita mutação externa do snapshot. */\nexport function freezeRecord(\n record: Record<string, string>\n): Readonly<Record<string, string>> {\n return Object.freeze({ ...record });\n}\n\n/**\n * Reformata href decorado preservando forma relativa quando possível.\n * Garante `path?query#hash` (nunca `path#hash?query`).\n */\nexport function formatDecoratedHref(originalHref: string, url: URL): string {\n const trimmed = originalHref.trim();\n const search = url.search || '';\n const hash = url.hash || '';\n\n if (trimmed.startsWith('//')) {\n return `//${url.host}${url.pathname}${search}${hash}`;\n }\n\n if (/^[a-zA-Z][a-zA-Z\\d+\\-.]*:/.test(trimmed)) {\n // absolute com scheme (http, https, ...)\n return url.toString();\n }\n\n if (trimmed.startsWith('/')) {\n return `${url.pathname}${search}${hash}`;\n }\n\n if (trimmed.startsWith('#')) {\n return `${search}${hash}`;\n }\n\n // relativo: checkout, ./checkout, ../checkout\n const pathPart = trimmed.split(/[?#]/)[0] ?? trimmed;\n return `${pathPart}${search}${hash}`;\n}\n","import type { UrlQueryParamsConfig } from '@/config/shared/url-context';\n\nimport {\n buildDenylistSet,\n isBrowser,\n isDeniedKey,\n normalizeParamKey,\n parseSearchParams,\n} from './utils';\n\n/**\n * Lê `window.location.search`, aplica allow/deny e retorna snapshot sanitizado.\n */\nexport class QueryParamCollector {\n collect(config: UrlQueryParamsConfig | undefined): Record<string, string> {\n if (!config || config.enabled === false) return {};\n if (!isBrowser()) return {};\n\n const raw = parseSearchParams(window.location.search);\n const denylist = buildDenylistSet(\n config.denylist,\n config.mergeDefaultDenylist\n );\n const mode = config.mode ?? 'all_except';\n const allowlist = new Set(\n (config.allowlist ?? []).map(normalizeParamKey).filter(Boolean)\n );\n\n const result: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(raw)) {\n if (isDeniedKey(key, denylist)) continue;\n if (mode === 'allowlist' && !allowlist.has(normalizeParamKey(key))) {\n continue;\n }\n // valores vazios: omitir (mantém payload limpo)\n if (value === '') continue;\n result[key] = value;\n }\n\n return result;\n }\n}\n","import type {\n UrlContextSource,\n UrlManagedParamConfig,\n} from '@/config/shared/url-context';\n\nimport type { UrlContextStore } from './UrlContextStore';\nimport {\n buildSearchString,\n generatePublicId,\n isBrowser,\n parseSearchParams,\n silentReplaceState,\n} from './utils';\n\nexport type ManagedParamResolution = {\n values: Record<string, string>;\n sources: Record<string, UrlContextSource>;\n decorateParams: Record<string, string>;\n};\n\n/**\n * Resolve managed params: URL → cookie → storage → generated.\n * Persiste e opcionalmente escreve na URL via replaceState silencioso.\n */\nexport class ManagedParamResolver {\n private readonly store: UrlContextStore;\n\n constructor(store: UrlContextStore) {\n this.store = store;\n }\n\n resolve(configs: readonly UrlManagedParamConfig[]): ManagedParamResolution {\n const values: Record<string, string> = {};\n const sources: Record<string, UrlContextSource> = {};\n const decorateParams: Record<string, string> = {};\n const urlWrites: Record<string, string> = {};\n\n const currentParams = isBrowser()\n ? parseSearchParams(window.location.search)\n : {};\n\n for (const config of configs) {\n const param = config.param?.trim();\n if (!param) continue;\n\n const mode = config.mode ?? 'read_write';\n const canRead = mode === 'read_only' || mode === 'read_write';\n const canWrite = mode === 'write_only' || mode === 'read_write';\n\n let value: string | null = null;\n let source: UrlContextSource | null = null;\n\n if (canRead) {\n const fromUrl = currentParams[param];\n if (fromUrl && fromUrl.length > 0) {\n value = fromUrl;\n source = 'url';\n }\n }\n\n if (!value && canRead && config.persistence?.enabled !== false) {\n const cookieName = config.persistence?.cookie?.name?.trim() || param;\n if (config.persistence?.cookie?.enabled !== false) {\n const fromCookie = this.store.getCookie(cookieName);\n if (fromCookie) {\n value = fromCookie;\n source = 'cookie';\n }\n }\n }\n\n if (!value && canRead && config.persistence?.enabled !== false) {\n const storageKey = config.persistence?.storageKey?.trim() || param;\n const fromStorage = this.store.getStorage(storageKey);\n if (fromStorage) {\n value = fromStorage;\n source = 'storage';\n }\n }\n\n if (!value && canWrite && config.generator?.type === 'public_id') {\n value = generatePublicId(config.generator.prefix ?? param);\n source = 'generated';\n }\n\n if (!value || !source) continue;\n\n values[param] = value;\n sources[param] = source;\n\n if (config.decorateLinks !== false) {\n decorateParams[param] = value;\n }\n\n // Persist always when we have a value and persistence enabled\n if (config.persistence?.enabled !== false) {\n this.persist(config, value);\n }\n\n // Write to URL if strategy allows and value missing/different on URL\n if (\n canWrite &&\n (config.writeStrategy ?? 'replaceState') === 'replaceState' &&\n isBrowser()\n ) {\n const existing = currentParams[param];\n if (existing !== value) {\n urlWrites[param] = value;\n }\n }\n }\n\n if (Object.keys(urlWrites).length > 0 && isBrowser()) {\n this.writeToUrl(urlWrites);\n }\n\n return { values, sources, decorateParams };\n }\n\n /**\n * Aplica valor externo após o resolve inicial (sem generator).\n * Persiste e opcionalmente escreve na URL.\n */\n applyExternalValue(config: UrlManagedParamConfig, value: string): void {\n const trimmed = value.trim();\n if (!trimmed) return;\n\n if (config.persistence?.enabled !== false) {\n this.persist(config, trimmed);\n }\n\n if (\n (config.writeStrategy ?? 'replaceState') === 'replaceState' &&\n isBrowser()\n ) {\n this.writeToUrl({ [config.param]: trimmed });\n }\n }\n\n private persist(config: UrlManagedParamConfig, value: string): void {\n const strategy = config.persistence?.strategy ?? 'localStorage_cookie';\n const storageKey = config.persistence?.storageKey?.trim() || config.param;\n const cookieCfg = config.persistence?.cookie;\n const cookieName = cookieCfg?.name?.trim() || config.param;\n\n if (strategy === 'storage' || strategy === 'localStorage_cookie') {\n this.store.setStorage(storageKey, value);\n }\n\n if (\n (strategy === 'cookie' || strategy === 'localStorage_cookie') &&\n cookieCfg?.enabled !== false\n ) {\n this.store.setCookie({\n name: cookieName,\n value,\n path: cookieCfg?.path ?? '/',\n domain: cookieCfg?.domain ?? 'auto',\n sameSite: cookieCfg?.sameSite ?? 'Lax',\n secure: cookieCfg?.secure ?? true,\n maxAgeMs: cookieCfg?.maxAgeMs,\n });\n }\n }\n\n private writeToUrl(writes: Record<string, string>): void {\n const current = parseSearchParams(window.location.search);\n const next = { ...current, ...writes };\n const search = buildSearchString(next);\n const hash = window.location.hash ?? '';\n const path = window.location.pathname + search + hash;\n silentReplaceState(path);\n }\n}\n","import type { UrlForwardParamsConfig } from '@/config/shared/url-context';\n\nimport { buildDenylistSet, isDeniedKey, normalizeParamKey } from './utils';\n\n/**\n * Decide quais params (não gerenciados) propagar em links.\n * Não gera nem persiste — só filtra.\n */\nexport class ForwardParamResolver {\n resolve(input: {\n queryParams: Record<string, string>;\n managedValues: Record<string, string>;\n config: UrlForwardParamsConfig | undefined;\n }): Record<string, string> {\n const { queryParams, managedValues, config } = input;\n if (!config || config.enabled === false) return {};\n\n const denylist = buildDenylistSet(\n config.denylist,\n config.mergeDefaultDenylist\n );\n const mode = config.mode ?? 'all_except';\n const allowlist = new Set(\n (config.allowlist ?? []).map(normalizeParamKey).filter(Boolean)\n );\n\n const result: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(queryParams)) {\n if (!value) continue;\n if (isDeniedKey(key, denylist)) continue;\n if (key in managedValues) continue; // managed tem prioridade\n if (mode === 'allowlist' && !allowlist.has(normalizeParamKey(key))) {\n continue;\n }\n result[key] = value;\n }\n\n return result;\n }\n}\n","import type { UrlLinkDecorationConfig } from '@/config/shared/url-context';\n\nimport {\n buildExcludeSelectors,\n buildExcludedDomains,\n buildSearchString,\n formatDecoratedHref,\n isBrowser,\n isDomainAllowed,\n parseSearchParams,\n} from './utils';\n\nconst BLOCKED_PROTOCOLS = [\n 'mailto:',\n 'tel:',\n 'javascript:',\n 'data:',\n 'blob:',\n] as const;\n\nexport type LinkDecoratorOptions = {\n forwardedParams?: Readonly<Record<string, string>>;\n managedParams?: Readonly<Record<string, string>>;\n config: UrlLinkDecorationConfig;\n /**\n * Quando true, inclui `[data-no-sid]` nos exclude selectors.\n * Semântica legada: exclusão remove toda a decoração do link.\n */\n includeSidExclude?: boolean;\n};\n\n/**\n * Decora links com forwarded + managed params (grupos separados).\n *\n * Ordem:\n * 1. query existente do link\n * 2. forwarded (respeita preserveExisting / overwriteExisting)\n * 3. managed (sempre autoritativo)\n * 4. dedupe / remontagem\n *\n * Strategies: on_click | on_init | both.\n */\nexport class LinkDecorator {\n private readonly forwardedParams: Readonly<Record<string, string>>;\n\n private managedParams: Readonly<Record<string, string>>;\n\n private readonly config: UrlLinkDecorationConfig;\n\n private readonly excludedDomains: readonly string[];\n\n private readonly excludeSelectors: readonly string[];\n\n private clickHandler: ((event: MouseEvent) => void) | null = null;\n\n private started = false;\n\n constructor(\n paramsOrOptions: Record<string, string> | LinkDecoratorOptions,\n config?: UrlLinkDecorationConfig,\n includeSidExclude?: boolean\n ) {\n if (isLinkDecoratorOptions(paramsOrOptions)) {\n this.forwardedParams = Object.freeze({\n ...(paramsOrOptions.forwardedParams ?? {}),\n });\n this.managedParams = Object.freeze({\n ...(paramsOrOptions.managedParams ?? {}),\n });\n this.config = paramsOrOptions.config;\n this.excludedDomains = buildExcludedDomains(\n paramsOrOptions.config.excludedDomains,\n paramsOrOptions.config.mergeDefaultExcludedDomains\n );\n this.excludeSelectors = buildExcludeSelectors(\n paramsOrOptions.config.excludeSelectors,\n paramsOrOptions.config.mergeDefaultExcludeSelectors,\n paramsOrOptions.includeSidExclude === true\n );\n return;\n }\n\n // Legado: params flat tratados como managed (autoritativos).\n const flat = paramsOrOptions;\n const resolvedConfig = config!;\n this.forwardedParams = Object.freeze({});\n this.managedParams = Object.freeze({ ...flat });\n this.config = resolvedConfig;\n this.excludedDomains = buildExcludedDomains(\n resolvedConfig.excludedDomains,\n resolvedConfig.mergeDefaultExcludedDomains\n );\n this.excludeSelectors = buildExcludeSelectors(\n resolvedConfig.excludeSelectors,\n resolvedConfig.mergeDefaultExcludeSelectors,\n includeSidExclude === true\n );\n }\n\n /**\n * Atualiza managed params após o start (ex.: `oid` registrado no checkout).\n * Reaplica decoração on_init/both nos links já presentes.\n */\n updateManagedParams(managedParams: Readonly<Record<string, string>>): void {\n this.managedParams = Object.freeze({ ...managedParams });\n if (!this.started || !isBrowser()) return;\n if (this.config.enabled === false) return;\n const strategy = this.config.strategy ?? 'on_click';\n if (strategy === 'on_init' || strategy === 'both') {\n this.decorateMatchingLinks();\n }\n }\n\n start(): void {\n if (this.started || !isBrowser()) return;\n if (this.config.enabled === false) return;\n if (\n Object.keys(this.forwardedParams).length === 0 &&\n Object.keys(this.managedParams).length === 0\n ) {\n return;\n }\n\n this.started = true;\n const strategy = this.config.strategy ?? 'on_click';\n\n if (strategy === 'on_init' || strategy === 'both') {\n this.decorateMatchingLinks();\n }\n\n if (strategy === 'on_click' || strategy === 'both') {\n this.clickHandler = (event: MouseEvent) => {\n const anchor = findAnchor(event.target);\n if (!anchor) return;\n if (this.isExcludedAnchor(anchor)) return;\n this.decorateAnchor(anchor);\n };\n document.addEventListener('click', this.clickHandler, true);\n }\n }\n\n destroy(): void {\n if (!this.started) return;\n if (this.clickHandler && typeof document !== 'undefined') {\n document.removeEventListener('click', this.clickHandler, true);\n }\n this.clickHandler = null;\n this.started = false;\n }\n\n /** Expõe para testes e uso interno. */\n decorateHref(href: string, baseHostname?: string): string | null {\n if (!href || href.trim() === '') return null;\n\n const trimmed = href.trim();\n const lower = trimmed.toLowerCase();\n\n for (const proto of BLOCKED_PROTOCOLS) {\n if (!lower.startsWith(proto)) continue;\n if (proto === 'mailto:' && this.config.decorateMailto === true) {\n return null;\n }\n if (proto === 'tel:' && this.config.decorateTel === true) {\n return null;\n }\n return null;\n }\n\n if (trimmed.startsWith('#') && this.config.decorateHashLinks !== true) {\n return null;\n }\n\n let url: URL;\n try {\n const base = isBrowser()\n ? window.location.href\n : `https://${baseHostname ?? 'example.com'}/`;\n url = new URL(trimmed, base);\n } catch {\n return null;\n }\n\n if (\n !isDomainAllowed(\n url.hostname,\n this.config.allowedDomains,\n this.excludedDomains\n )\n ) {\n return null;\n }\n\n const existing = parseSearchParams(url.search);\n const preserve = this.config.preserveExisting !== false;\n const overwrite = this.config.overwriteExisting === true;\n const next: Record<string, string> = { ...existing };\n let changed = false;\n\n // 1) Forwarded — respeitam preserveExisting / overwriteExisting\n for (const [key, value] of Object.entries(this.forwardedParams)) {\n if (key in next && preserve && !overwrite) {\n continue;\n }\n if (next[key] !== value) changed = true;\n next[key] = value;\n }\n\n // 2) Managed — sempre autoritativos\n for (const [key, value] of Object.entries(this.managedParams)) {\n if (next[key] !== value) changed = true;\n next[key] = value;\n }\n\n const originalParsed = parseSearchParams(\n trimmed.includes('?')\n ? (trimmed.slice(trimmed.indexOf('?')).split('#')[0] ?? '')\n : ''\n );\n const hadDuplicateKeys =\n countQueryKeys(trimmed) > Object.keys(originalParsed).length;\n\n if (!changed && !hadDuplicateKeys) {\n return trimmed;\n }\n\n const search = buildSearchString(next);\n url.search = search.startsWith('?') ? search.slice(1) : search;\n return formatDecoratedHref(trimmed, url);\n }\n\n private decorateMatchingLinks(): void {\n // Sem selector: todas as âncoras; filtro real é allowedDomains em decorateHref\n const selector = this.config.selector ?? 'a[href]';\n let nodes: NodeListOf<Element>;\n try {\n nodes = document.querySelectorAll(selector);\n } catch {\n return;\n }\n for (const node of nodes) {\n if (!(node instanceof HTMLAnchorElement)) continue;\n if (this.isExcludedAnchor(node)) continue;\n this.decorateAnchor(node);\n }\n }\n\n private isExcludedAnchor(anchor: HTMLAnchorElement): boolean {\n if (anchor.hasAttribute('download')) return true;\n\n for (const sel of this.excludeSelectors) {\n try {\n if (anchor.matches(sel)) return true;\n } catch {\n // selector inválido — ignorar\n }\n }\n\n return false;\n }\n\n private decorateAnchor(anchor: HTMLAnchorElement): void {\n const href = anchor.getAttribute('href');\n if (!href) return;\n const next = this.decorateHref(href);\n if (next != null && next !== href) {\n anchor.setAttribute('href', next);\n }\n }\n}\n\nfunction isLinkDecoratorOptions(\n value: Record<string, string> | LinkDecoratorOptions\n): value is LinkDecoratorOptions {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'config' in value &&\n typeof (value as LinkDecoratorOptions).config === 'object' &&\n (value as LinkDecoratorOptions).config !== null\n );\n}\n\nfunction findAnchor(target: EventTarget | null): HTMLAnchorElement | null {\n if (!(target instanceof Element)) return null;\n return target.closest('a[href]');\n}\n\n/** Conta chaves brutas na query (inclui duplicadas). */\nfunction countQueryKeys(href: string): number {\n const qIndex = href.indexOf('?');\n if (qIndex < 0) return 0;\n const hashIndex = href.indexOf('#', qIndex);\n const raw =\n hashIndex >= 0 ? href.slice(qIndex + 1, hashIndex) : href.slice(qIndex + 1);\n if (!raw) return 0;\n return raw.split('&').filter(Boolean).length;\n}\n","import type { StorageService } from '@/services/storage/types';\n\nimport { isBrowser, safeDecodeURIComponent } from './utils';\n\nexport type CookieWriteOptions = {\n name: string;\n value: string;\n path?: string;\n domain?: 'auto' | string;\n sameSite?: 'Lax' | 'Strict' | 'None';\n secure?: boolean;\n maxAgeMs?: number;\n};\n\n/**\n * Persistência de managed params — storage + cookie SSR-safe.\n * Não acessa DOM/localStorage em import time.\n */\nexport class UrlContextStore {\n private readonly storage: StorageService | null;\n\n constructor(storage?: StorageService | null) {\n this.storage = storage ?? null;\n }\n\n getStorage(key: string): string | null {\n if (!this.storage) return null;\n try {\n const value = this.storage.get<string>(key);\n return typeof value === 'string' && value.length > 0 ? value : null;\n } catch {\n return null;\n }\n }\n\n setStorage(key: string, value: string): void {\n if (!this.storage) return;\n try {\n this.storage.set(key, value);\n } catch {\n // quota / private mode\n }\n }\n\n getCookie(name: string): string | null {\n if (!isBrowser()) return null;\n try {\n const cookies = document.cookie ? document.cookie.split(';') : [];\n for (const part of cookies) {\n const idx = part.indexOf('=');\n const key = (idx >= 0 ? part.slice(0, idx) : part).trim();\n if (key !== name) continue;\n const raw = idx >= 0 ? part.slice(idx + 1).trim() : '';\n return safeDecodeURIComponent(raw);\n }\n } catch {\n return null;\n }\n return null;\n }\n\n setCookie(options: CookieWriteOptions): void {\n if (!isBrowser()) return;\n\n const parts = [\n `${encodeURIComponent(options.name)}=${encodeURIComponent(options.value)}`,\n ];\n\n parts.push(`path=${options.path ?? '/'}`);\n\n const domain = resolveCookieDomain(options.domain);\n if (domain) {\n parts.push(`domain=${domain}`);\n }\n\n if (\n typeof options.maxAgeMs === 'number' &&\n Number.isFinite(options.maxAgeMs)\n ) {\n parts.push(`max-age=${Math.max(0, Math.floor(options.maxAgeMs / 1000))}`);\n }\n\n const sameSite = options.sameSite ?? 'Lax';\n parts.push(`SameSite=${sameSite}`);\n\n const secure =\n options.secure === true ||\n (typeof location !== 'undefined' && location.protocol === 'https:');\n if (secure) {\n parts.push('Secure');\n }\n\n try {\n document.cookie = parts.join('; ');\n } catch {\n // ignore\n }\n }\n}\n\nfunction resolveCookieDomain(\n domain: 'auto' | string | undefined\n): string | null {\n if (!domain || domain === 'auto') {\n if (!isBrowser()) return null;\n const host = location.hostname;\n // localhost / IPs: não forçar domain\n if (\n host === 'localhost' ||\n host === '127.0.0.1' ||\n /^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(host) ||\n !host.includes('.')\n ) {\n return null;\n }\n return host;\n }\n return domain;\n}\n","import type {\n UrlContextConfig,\n UrlForwardParamsConfig,\n UrlLinkDecorationConfig,\n UrlManagedParamConfig,\n UrlQueryParamsConfig,\n} from '@/config/shared/url-context';\n\nimport { DEFAULT_URL_CONTEXT_SID_MAX_AGE_MS } from './constants';\n\nexport const DEFAULT_SID_MANAGED_PARAM: UrlManagedParamConfig = {\n key: 'public_session',\n param: 'sid',\n mode: 'read_write',\n writeStrategy: 'replaceState',\n generator: {\n type: 'public_id',\n prefix: 'sid',\n },\n persistence: {\n enabled: true,\n strategy: 'localStorage_cookie',\n storageKey: 'sid',\n cookie: {\n enabled: true,\n name: 'sid',\n domain: 'auto',\n path: '/',\n sameSite: 'Lax',\n secure: true,\n maxAgeMs: DEFAULT_URL_CONTEXT_SID_MAX_AGE_MS,\n },\n },\n decorateLinks: true,\n};\n\nexport const DEFAULT_QUERY_PARAMS_WHEN_ENABLED: Required<\n Pick<UrlQueryParamsConfig, 'enabled' | 'mode' | 'mergeDefaultDenylist'>\n> &\n UrlQueryParamsConfig = {\n enabled: true,\n mode: 'all_except',\n mergeDefaultDenylist: true,\n};\n\nexport const DEFAULT_FORWARD_PARAMS_WHEN_ENABLED: Required<\n Pick<UrlForwardParamsConfig, 'enabled' | 'mode' | 'mergeDefaultDenylist'>\n> &\n UrlForwardParamsConfig = {\n enabled: true,\n mode: 'all_except',\n mergeDefaultDenylist: true,\n};\n\nexport const DEFAULT_LINK_DECORATION_WHEN_ENABLED: UrlLinkDecorationConfig = {\n enabled: true,\n strategy: 'on_click',\n selector: 'a[href]',\n allowedDomains: '*',\n mergeDefaultExcludedDomains: true,\n mergeDefaultExcludeSelectors: true,\n preserveExisting: true,\n overwriteExisting: false,\n decorateHashLinks: false,\n decorateMailto: false,\n decorateTel: false,\n};\n\n/**\n * Resolve config parcial → efetiva.\n * - `enabled: false` → feature off\n * - `enabled: true` sem nested → aplica defaults úteis (inclui sid)\n * - `managedParams: []` → não cria sid\n */\nexport function resolveUrlContextConfig(\n raw: UrlContextConfig | undefined\n): Required<Pick<UrlContextConfig, 'enabled'>> & {\n queryParams: UrlQueryParamsConfig;\n managedParams: UrlManagedParamConfig[];\n forwardParams: UrlForwardParamsConfig;\n linkDecoration: UrlLinkDecorationConfig;\n} {\n if (!raw || raw.enabled !== true) {\n return {\n enabled: false,\n queryParams: { enabled: false },\n managedParams: [],\n forwardParams: { enabled: false },\n linkDecoration: { enabled: false },\n };\n }\n\n const managedParams =\n raw.managedParams !== undefined\n ? raw.managedParams.map(cloneManagedParam)\n : [cloneManagedParam(DEFAULT_SID_MANAGED_PARAM)];\n\n return {\n enabled: true,\n queryParams: {\n ...DEFAULT_QUERY_PARAMS_WHEN_ENABLED,\n ...raw.queryParams,\n ...(raw.queryParams?.allowlist\n ? { allowlist: [...raw.queryParams.allowlist] }\n : {}),\n ...(raw.queryParams?.denylist\n ? { denylist: [...raw.queryParams.denylist] }\n : {}),\n },\n managedParams,\n forwardParams: {\n ...DEFAULT_FORWARD_PARAMS_WHEN_ENABLED,\n ...raw.forwardParams,\n ...(raw.forwardParams?.allowlist\n ? { allowlist: [...raw.forwardParams.allowlist] }\n : {}),\n ...(raw.forwardParams?.denylist\n ? { denylist: [...raw.forwardParams.denylist] }\n : {}),\n },\n linkDecoration: {\n ...DEFAULT_LINK_DECORATION_WHEN_ENABLED,\n ...raw.linkDecoration,\n ...(raw.linkDecoration?.allowedDomains &&\n raw.linkDecoration.allowedDomains !== '*'\n ? { allowedDomains: [...raw.linkDecoration.allowedDomains] }\n : {}),\n ...(raw.linkDecoration?.excludedDomains\n ? { excludedDomains: [...raw.linkDecoration.excludedDomains] }\n : {}),\n ...(raw.linkDecoration?.excludeSelectors\n ? { excludeSelectors: [...raw.linkDecoration.excludeSelectors] }\n : {}),\n },\n };\n}\n\nfunction cloneManagedParam(\n param: UrlManagedParamConfig\n): UrlManagedParamConfig {\n return {\n ...param,\n ...(param.generator ? { generator: { ...param.generator } } : {}),\n ...(param.persistence\n ? {\n persistence: {\n ...param.persistence,\n ...(param.persistence.cookie\n ? { cookie: { ...param.persistence.cookie } }\n : {}),\n },\n }\n : {}),\n };\n}\n","import type {\n UrlContextConfig,\n UrlContextPayload,\n UrlContextSnapshot,\n UrlContextSource,\n UrlManagedParamConfig,\n} from '@/config/shared/url-context';\nimport type { StorageService } from '@/services/storage/types';\n\nimport { ForwardParamResolver } from './ForwardParamResolver';\nimport { LinkDecorator } from './LinkDecorator';\nimport { ManagedParamResolver } from './ManagedParamResolver';\nimport { QueryParamCollector } from './QueryParamCollector';\nimport { resolveUrlContextConfig } from './resolve-config';\nimport { UrlContextStore } from './UrlContextStore';\nimport { freezeRecord } from './utils';\n/**\n * Orquestra UrlContext: collect → manage → forward → decorate → snapshot.\n * SSR-safe; init/destroy idempotentes.\n */\nexport class UrlContextService {\n private readonly storage: StorageService | null;\n\n private readonly rawConfig: UrlContextConfig | undefined;\n\n private readonly collector = new QueryParamCollector();\n\n private readonly forwardResolver = new ForwardParamResolver();\n\n private store: UrlContextStore | null = null;\n\n private managedResolver: ManagedParamResolver | null = null;\n\n private decorator: LinkDecorator | null = null;\n\n private snapshot: UrlContextSnapshot = emptySnapshot();\n\n private managedConfigs: readonly UrlManagedParamConfig[] = [];\n\n private decorateManaged: Record<string, string> = {};\n\n private initialized = false;\n\n private enabled = false;\n\n constructor(\n config: UrlContextConfig | undefined,\n storage?: StorageService | null\n ) {\n this.rawConfig = config;\n this.storage = storage ?? null;\n }\n\n init(): void {\n if (this.initialized) return;\n this.initialized = true;\n\n const resolved = resolveUrlContextConfig(this.rawConfig);\n this.enabled = resolved.enabled;\n this.managedConfigs = resolved.managedParams;\n\n if (!resolved.enabled) {\n this.snapshot = emptySnapshot();\n return;\n }\n\n this.store = new UrlContextStore(this.storage);\n this.managedResolver = new ManagedParamResolver(this.store);\n\n const queryParams = this.collector.collect(resolved.queryParams);\n const managed = this.managedResolver.resolve(resolved.managedParams);\n\n // Após replaceState, query params podem já incluir sid — re-coleta leve\n const queryAfter =\n Object.keys(managed.values).length > 0\n ? this.collector.collect(resolved.queryParams)\n : queryParams;\n\n const forwarded = this.forwardResolver.resolve({\n queryParams: queryAfter,\n managedValues: managed.values,\n config: resolved.forwardParams,\n });\n\n const source: Record<string, UrlContextSource> = {\n ...managed.sources,\n };\n for (const key of Object.keys(forwarded)) {\n if (!source[key]) {\n source[key] = 'url';\n }\n }\n\n const urlContext: UrlContextPayload = {\n ...(Object.keys(managed.values).length > 0\n ? { managed: freezeRecord(managed.values) }\n : {}),\n ...(Object.keys(forwarded).length > 0\n ? { forwarded: freezeRecord(forwarded) }\n : {}),\n ...(Object.keys(source).length > 0\n ? { source: Object.freeze({ ...source }) }\n : {}),\n };\n this.snapshot = {\n queryParams: freezeRecord(queryAfter),\n urlContext: Object.freeze(urlContext),\n };\n\n const decorateForwarded = freezeRecord(forwarded);\n this.decorateManaged = { ...managed.decorateParams };\n\n const hasSid = resolved.managedParams.some(\n p => p.param === 'sid' && p.decorateLinks !== false\n );\n\n this.decorator = new LinkDecorator({\n forwardedParams: decorateForwarded,\n managedParams: freezeRecord(this.decorateManaged),\n config: resolved.linkDecoration,\n includeSidExclude: hasSid,\n });\n this.decorator.start();\n }\n\n /**\n * Define ou substitui um managed param após o init (ex.: `oid` no checkout).\n * Idempotente para o mesmo valor. Persistência e decoração seguem a config do param.\n *\n * @returns false se UrlContext desabilitado, não inicializado ou param não configurado.\n */\n setManagedParam(param: string, value: string): boolean {\n if (!this.initialized || !this.enabled || !this.managedResolver) {\n return false;\n }\n\n const key = param.trim();\n const trimmed = value.trim();\n if (!key || !trimmed) {\n return false;\n }\n\n const config = this.managedConfigs.find(c => c.param === key);\n if (!config) {\n return false;\n }\n\n const current = this.snapshot.urlContext.managed?.[key];\n if (current === trimmed) {\n return true;\n }\n\n this.managedResolver.applyExternalValue(config, trimmed);\n\n const managed = {\n ...(this.snapshot.urlContext.managed ?? {}),\n [key]: trimmed,\n };\n const source = {\n ...(this.snapshot.urlContext.source ?? {}),\n [key]: 'manual' as const,\n };\n\n // Re-coleta query após possível replaceState\n const resolved = resolveUrlContextConfig(this.rawConfig);\n const queryAfter = this.collector.collect(resolved.queryParams);\n\n this.snapshot = {\n queryParams: freezeRecord(queryAfter),\n urlContext: Object.freeze({\n managed: freezeRecord(managed),\n ...(this.snapshot.urlContext.forwarded\n ? { forwarded: freezeRecord(this.snapshot.urlContext.forwarded) }\n : {}),\n source: Object.freeze({ ...source }),\n }),\n };\n\n if (config.decorateLinks !== false) {\n this.decorateManaged = { ...this.decorateManaged, [key]: trimmed };\n this.decorator?.updateManagedParams(this.decorateManaged);\n // Se decorator ainda não startou (sem params no init), cria agora\n if (!this.decorator && resolved.enabled) {\n const hasSid = this.managedConfigs.some(\n p => p.param === 'sid' && p.decorateLinks !== false\n );\n this.decorator = new LinkDecorator({\n forwardedParams: freezeRecord(\n this.snapshot.urlContext.forwarded ?? {}\n ),\n managedParams: freezeRecord(this.decorateManaged),\n config: resolved.linkDecoration,\n includeSidExclude: hasSid,\n });\n this.decorator.start();\n }\n }\n\n return true;\n }\n\n destroy(): void {\n this.decorator?.destroy();\n this.decorator = null;\n this.managedResolver = null;\n this.store = null;\n this.managedConfigs = [];\n this.decorateManaged = {};\n this.initialized = false;\n this.enabled = false;\n this.snapshot = emptySnapshot();\n }\n\n /** Alias de destroy — cleanup completo sem listeners/refs. */\n dispose(): void {\n this.destroy();\n }\n\n isEnabled(): boolean {\n return this.enabled;\n }\n\n getSnapshot(): UrlContextSnapshot {\n return {\n queryParams: freezeRecord(this.snapshot.queryParams),\n urlContext: {\n ...(this.snapshot.urlContext.managed\n ? { managed: freezeRecord(this.snapshot.urlContext.managed) }\n : {}),\n ...(this.snapshot.urlContext.forwarded\n ? { forwarded: freezeRecord(this.snapshot.urlContext.forwarded) }\n : {}),\n ...(this.snapshot.urlContext.source\n ? {\n source: Object.freeze({\n ...this.snapshot.urlContext.source,\n }),\n }\n : {}),\n },\n };\n }\n getQueryParams(): Record<string, string> {\n return { ...this.snapshot.queryParams };\n }\n\n getUrlContext(): UrlContextPayload {\n return this.getSnapshot().urlContext;\n }\n}\n\nfunction emptySnapshot(): UrlContextSnapshot {\n return {\n queryParams: freezeRecord({}),\n urlContext: Object.freeze({}),\n };\n}\n","import type { PixelConfig } from '@/config';\nimport { BaseEventBuilder } from '@/events/builder';\nimport { ConsolePixelLogger, type PixelLogger } from '@/logger';\nimport {\n AttributionServiceImpl,\n DEFAULT_ATTRIBUTION_CONFIG,\n} from '@/services/attribution';\nimport { BrowserMetadataServiceImpl } from '@/services/browser-metadata/BrowserMetadataService';\nimport { DispatcherServiceImpl } from '@/services/dispatcher/DispatcherService';\nimport { FingerprintServiceImpl } from '@/services/fingerprint/FingerprintService';\nimport { createStorageAdapter, StorageServiceImpl } from '@/services/storage';\nimport type { StoragePersistence } from '@/services/storage/StorageFactory';\nimport { CommerceService } from '@/services/commerce';\nimport { SessionServiceImpl } from '@/services/session/SessionService';\nimport type { PixelRuntimeServices } from '@/services/types';\nimport { VisitorServiceImpl } from '@/services/visitor/VisitorService';\nimport { UrlContextService } from '@/modules/core/url-context';\n\nimport { ModuleRegistry } from './ModuleRegistry';\nimport type { PixelRuntimeContext } from './PixelRuntimeContext';\nimport type { ModuleName } from './shared/module';\nimport type { PixelModule } from './types';\n\nexport class PixelRuntime {\n private initialized = false;\n\n private readonly initializedModules: PixelModule[] = [];\n\n private readonly registry: ModuleRegistry;\n\n private readonly config: PixelConfig;\n\n private readonly fallbackLogger: ConsolePixelLogger;\n\n private context: PixelRuntimeContext | null = null;\n\n constructor(config: PixelConfig) {\n this.config = config;\n this.registry = new ModuleRegistry();\n this.fallbackLogger = new ConsolePixelLogger(config.app.debug === true);\n }\n\n register(module: PixelModule): void {\n this.registry.register(module);\n }\n\n async init(): Promise<void> {\n if (this.initialized) {\n this.getLogger().debug('[PixelRuntime] Runtime already initialized');\n return;\n }\n\n this.fallbackLogger.debug('[PixelRuntime] Initializing runtime');\n\n this.context = this.createContext();\n this.context.services.attribution.init();\n\n for (const module of this.registry.getAll()) {\n if (!this.isModuleEnabled(module)) {\n this.fallbackLogger.debug(\n `[PixelRuntime] Skipping disabled module: ${module.name}`\n );\n continue;\n }\n\n this.fallbackLogger.debug(\n `[PixelRuntime] Initializing module: ${module.name}`\n );\n\n try {\n await module.init(this.context);\n this.initializedModules.push(module);\n } catch (error) {\n this.fallbackLogger.error(\n `[Pixel] Failed to initialize module \"${module.name}\"`,\n error\n );\n }\n }\n\n this.initialized = true;\n }\n\n async destroy(): Promise<void> {\n if (!this.initialized) return;\n\n const logger = this.getLogger();\n\n for (let index = this.initializedModules.length - 1; index >= 0; index--) {\n const module = this.initializedModules[index];\n\n logger.debug(`[PixelRuntime] Destroying module: ${module.name}`);\n\n try {\n await module.destroy?.();\n } catch (error) {\n logger.error(\n `[Pixel] Failed to destroy module \"${module.name}\"`,\n error\n );\n }\n }\n\n this.context?.services.attribution.destroy();\n this.context?.services.dispatcher.clear();\n\n this.initialized = false;\n this.initializedModules.length = 0;\n this.context = null;\n\n this.fallbackLogger.debug('[PixelRuntime] Runtime destroyed');\n }\n\n isInitialized(): boolean {\n return this.initialized;\n }\n\n /** @internal For playground and development only. Not part of the stable public API. */\n getDebugServices(): PixelRuntimeServices | null {\n return this.context?.services ?? null;\n }\n\n /** @internal Read-only diagnostics — names of modules that completed init. */\n getInitializedModuleNames(): readonly string[] {\n return this.initializedModules.map(m => m.name);\n }\n\n /** @internal Registered module names (all registered, regardless of enabled). */\n getRegisteredModuleNames(): readonly string[] {\n return this.registry.getAll().map(m => m.name);\n }\n\n private createServices(logger: PixelLogger): PixelRuntimeServices {\n const { namespace, prefix, persistence } = this.config.storage;\n\n const visitorStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.visitor\n );\n const sessionStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.session\n );\n const fingerprintStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.attribution\n );\n const attributionStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.attribution ?? 'localStorage'\n );\n const storage = this.createStorageService(namespace, prefix, 'memory');\n const browserMetadata = new BrowserMetadataServiceImpl();\n\n const attribution = new AttributionServiceImpl(\n attributionStorage,\n this.config.attribution ?? DEFAULT_ATTRIBUTION_CONFIG\n );\n\n const urlContextStorage = this.createStorageService(\n namespace,\n prefix,\n persistence?.attribution ?? 'localStorage'\n );\n const urlContext = new UrlContextService(\n this.config.modules.core.urlContext,\n urlContextStorage\n );\n\n const eventBuilder = new BaseEventBuilder(\n browserMetadata,\n attribution,\n urlContext\n );\n\n const visitor = new VisitorServiceImpl(visitorStorage, this.config);\n const session = new SessionServiceImpl(sessionStorage, this.config);\n const fingerprint = new FingerprintServiceImpl(\n fingerprintStorage,\n this.config,\n browserMetadata\n );\n const dispatcher = new DispatcherServiceImpl(logger);\n const commerce = new CommerceService(this.config.commerce);\n\n return {\n storage,\n visitor,\n session,\n fingerprint,\n dispatcher,\n browserMetadata,\n eventBuilder,\n attribution,\n commerce,\n urlContext,\n };\n }\n\n private createStorageService(\n namespace: string,\n prefix: string | undefined,\n persistence: StoragePersistence | undefined\n ): StorageServiceImpl {\n return new StorageServiceImpl(\n createStorageAdapter(persistence),\n namespace,\n prefix\n );\n }\n\n private createContext(): PixelRuntimeContext {\n return {\n config: this.config,\n logger: this.fallbackLogger,\n services: this.createServices(this.fallbackLogger),\n };\n }\n\n private getLogger(): PixelLogger {\n return this.context?.logger ?? this.fallbackLogger;\n }\n\n private isModuleEnabled(module: PixelModule): boolean {\n if (module.name === 'diagnostics') return true;\n\n const enabledModules: Record<\n Exclude<ModuleName, 'diagnostics'>,\n boolean\n > = {\n privacy: this.config.modules.privacy.enabled,\n core: this.config.modules.core.enabled,\n behavior: this.config.modules.behavior.enabled,\n conversion: this.config.modules.conversion.enabled,\n transport: this.config.transport.enabled,\n integrations: this.config.modules.integrations.enabled,\n };\n\n return enabledModules[module.name];\n }\n}\n"],"mappings":"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","names":["ModuleRegistry","module","existing","BaseEventBuilder","metadataService","attribution","urlContext","event","metadata","identifiers","hasIdentifiers","key","value","urlSnapshot","hasQueryParams","hasUrlContext","ConsolePixelLogger","debugEnabled","args","DEFAULT_ATTRIBUTION_CONFIG","ATTRIBUTION_STORAGE_KEY","BUILTIN_CLICK_PARAMS","ClickIdParser","customParams","params","result","customClickIds","key","value","fbclid","existingFbc","CookieCollector","cookies","result","map","cookieName","field","value","acc","part","rawKey","rest","AttributionCollector","options","ClickIdParser","CookieCollector","fromUrl","fromCookies","merged","customClickIds","fbc","existing","incoming","next","key","value","now","AttributionStore","storage","options","ATTRIBUTION_STORAGE_KEY","snapshot","anchor","AttributionServiceImpl","storage","config","DEFAULT_ATTRIBUTION_CONFIG","AttributionStore","AttributionCollector","stored","fresh","partial","BrowserMetadataServiceImpl","timezone","DispatcherServiceImpl","logger","event","snapshot","index","listener","error","sanitizeDispatcherError","eventType","listenerIndex","name","message","DEFAULT_FINGERPRINT_KEY","hashFingerprintInput","input","hash","index","positiveHash","secondaryHash","computeLightFingerprint","metadataService","metadata","components","FingerprintServiceImpl","storage","config","existing","fingerprint","BrowserStorageAdapter","storage","key","value","predicate","keysToRemove","index","MemoryStorageAdapter","key","value","predicate","supportsNamespaceClear","adapter","StorageServiceImpl","namespace","prefix","key","raw","value","namespaceKeyPrefix","createStorageAdapter","persistence","mode","MemoryStorageAdapter","BrowserStorageAdapter","ProductCatalog","products","options","id","product","sku","defaultCurrency","raw","currency","quantity","CommerceState","initialItems","options","item","productId","quantity","previous","metadata","next","normalized","current","selectedItems","OrderCalculator","input","items","item","value","currency","total","hasPriced","qty","DEFAULT_COMMERCE_ENRICHMENT","DEFAULT_COMMERCE_CONFIG","normalizeCalculateValueFrom","value","CommerceResolver","options","trim","normalizeCalculateValueFrom","input","payload","extracted","source","useCart","useCatalog","productId","asString","cartFallback","catalogProduct","resolvedId","stateItem","productName","price","asNumber","quantity","currency","identity","resolveCatalogItemIdentity","data","key","value","items","item","isPurchase","manualValue","manualCurrency","manualItems","resolvedItems","pixelItems","allowCalculatedValue","shouldCalculateValue","calc","atc","checkout","contentId","contentName","raw","enrichmentSource","fromState","product","catalog","sku","incoming","meta","metaPriceId","metaProductId","metaOfferId","priceId","trimmed","t","CommerceService","config","DEFAULT_COMMERCE_CONFIG","item","DEFAULT_COMMERCE_ENRICHMENT","ProductCatalog","CommerceState","CommerceResolver","OrderCalculator","normalizeCalculateValueFrom","event","fromConfig","fallback","eventType","payload","resolved","items","first","contentId","contentName","createRandomSuffix","generateSessionId","DEFAULT_SESSION_KEY","SessionServiceImpl","storage","config","raw","now","ttlMs","data","sessionId","generateSessionId","previousSessionId","createRandomSuffix","generateVisitorId","DEFAULT_VISITOR_KEY","VisitorServiceImpl","storage","config","existing","visitorId","generateVisitorId","DEFAULT_URL_CONTEXT_DENYLIST","DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS","DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS","SID_EXCLUDE_SELECTOR","normalizeParamKey","key","safeDecodeURIComponent","value","buildDenylistSet","userDenylist","mergeDefault","set","DEFAULT_URL_CONTEXT_DENYLIST","buildExcludedDomains","userExcluded","list","DEFAULT_URL_CONTEXT_EXCLUDED_DOMAINS","domain","d","buildExcludeSelectors","userSelectors","includeSidSelector","DEFAULT_URL_CONTEXT_EXCLUDE_SELECTORS","SID_EXCLUDE_SELECTOR","sel","isDeniedKey","denylist","hostMatchesDomain","hostname","hostNoPort","target","isDomainAllowed","allowedDomains","excludedDomains","excluded","generatePublicId","prefix","safePrefix","ts","random","isBrowser","silentReplaceState","url","parseSearchParams","search","result","raw","part","eq","buildSearchString","params","pairs","freezeRecord","record","formatDecoratedHref","originalHref","trimmed","hash","QueryParamCollector","config","isBrowser","raw","parseSearchParams","denylist","buildDenylistSet","mode","allowlist","normalizeParamKey","result","key","value","isDeniedKey","ManagedParamResolver","store","configs","values","sources","decorateParams","urlWrites","currentParams","isBrowser","parseSearchParams","config","param","mode","canRead","canWrite","value","source","fromUrl","cookieName","fromCookie","storageKey","fromStorage","generatePublicId","trimmed","strategy","cookieCfg","writes","next","search","buildSearchString","hash","path","silentReplaceState","ForwardParamResolver","input","queryParams","managedValues","config","denylist","buildDenylistSet","mode","allowlist","normalizeParamKey","result","key","value","isDeniedKey","BLOCKED_PROTOCOLS","LinkDecorator","paramsOrOptions","config","includeSidExclude","isLinkDecoratorOptions","buildExcludedDomains","buildExcludeSelectors","flat","resolvedConfig","managedParams","isBrowser","strategy","event","anchor","findAnchor","href","baseHostname","trimmed","lower","proto","url","base","isDomainAllowed","existing","parseSearchParams","preserve","overwrite","next","changed","key","value","originalParsed","hadDuplicateKeys","countQueryKeys","search","buildSearchString","formatDecoratedHref","selector","nodes","node","sel","target","qIndex","hashIndex","raw","UrlContextStore","storage","key","value","name","isBrowser","cookies","part","idx","raw","safeDecodeURIComponent","options","parts","domain","resolveCookieDomain","sameSite","host","DEFAULT_SID_MANAGED_PARAM","DEFAULT_QUERY_PARAMS_WHEN_ENABLED","DEFAULT_FORWARD_PARAMS_WHEN_ENABLED","DEFAULT_LINK_DECORATION_WHEN_ENABLED","resolveUrlContextConfig","raw","managedParams","cloneManagedParam","param","UrlContextService","config","storage","QueryParamCollector","ForwardParamResolver","emptySnapshot","resolved","resolveUrlContextConfig","UrlContextStore","ManagedParamResolver","queryParams","managed","queryAfter","forwarded","source","key","urlContext","freezeRecord","decorateForwarded","hasSid","p","LinkDecorator","param","value","trimmed","c","PixelRuntime","config","ModuleRegistry","ConsolePixelLogger","module","error","logger","index","m","namespace","prefix","persistence","visitorStorage","sessionStorage","fingerprintStorage","attributionStorage","storage","browserMetadata","BrowserMetadataServiceImpl","attribution","AttributionServiceImpl","DEFAULT_ATTRIBUTION_CONFIG","urlContextStorage","urlContext","UrlContextService","eventBuilder","BaseEventBuilder","visitor","VisitorServiceImpl","session","SessionServiceImpl","fingerprint","FingerprintServiceImpl","dispatcher","DispatcherServiceImpl","commerce","CommerceService","StorageServiceImpl","createStorageAdapter"]}
|