@refraction-ui/react 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ZF3OHCGV.js → chunk-2Q6HHFAN.js} +1 -1
- package/dist/chunk-2Q6HHFAN.js.map +7 -0
- package/dist/{chunk-533MCMSU.js → chunk-3I3DYDHR.js} +2 -2
- package/dist/{chunk-H54FLNAF.js → chunk-63N4PZUJ.js} +2 -2
- package/dist/chunk-7P7EJ56S.js +7 -0
- package/dist/{chunk-Y2FNNAIL.js → chunk-EGVPAMQU.js} +2 -2
- package/dist/chunk-EGVPAMQU.js.map +1 -0
- package/dist/{chunk-WK2IIUFO.js → chunk-QDMLIDYN.js} +2 -2
- package/dist/{chunk-BOLFYVI6.js → chunk-QPCKJ2YR.js} +2 -2
- package/dist/{chunk-TOZBR4GL.js → chunk-RSWOLRIC.js} +4 -4
- package/dist/{chunk-TOZBR4GL.js.map → chunk-RSWOLRIC.js.map} +1 -1
- package/dist/{chunk-UNEM2TRI.js → chunk-SDAJVXD4.js} +2 -2
- package/dist/{chunk-VK3EQ34F.js → chunk-V24GDHUX.js} +2 -2
- package/dist/{chunk-XWP763SH.js → chunk-V727VZOE.js} +4 -2
- package/dist/{chunk-XWP763SH.js.map → chunk-V727VZOE.js.map} +2 -2
- package/dist/{chunk-AMK4VCBG.js → chunk-WYKPPK3W.js} +2 -2
- package/dist/{chunk-ONACRMG4.js → chunk-XMFNBOPO.js} +2 -2
- package/dist/{chunk-NKCWOPNX.js → chunk-Z5IHYNQD.js} +12 -8
- package/dist/chunk-Z5IHYNQD.js.map +7 -0
- package/dist/faro-engine-VIUXJAPH-FSARIABU.js +3 -0
- package/dist/{faro-engine-47HGRAQH-JKINJPMH.js.map → faro-engine-VIUXJAPH-FSARIABU.js.map} +1 -1
- package/dist/form.cjs.map +1 -1
- package/dist/form.js +1 -1
- package/dist/index.cjs +1305 -302
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/internal/action-list/index.d.ts +39 -0
- package/dist/internal/avatar/index.d.cts +4 -1
- package/dist/internal/avatar/index.d.ts +4 -1
- package/dist/internal/button/index.d.cts +2 -2
- package/dist/internal/button/index.d.ts +2 -2
- package/dist/internal/card/index.d.cts +5 -1
- package/dist/internal/card/index.d.ts +5 -1
- package/dist/internal/data-table/index.d.cts +48 -3
- package/dist/internal/data-table/index.d.ts +48 -3
- package/dist/internal/funnel-chart/index.d.ts +60 -0
- package/dist/internal/line-chart/index.d.ts +124 -0
- package/dist/internal/native-select/index.d.ts +21 -0
- package/dist/internal/page-header/index.d.ts +35 -0
- package/dist/internal/react-action-list/index.d.ts +28 -0
- package/dist/internal/react-avatar/index.d.cts +4 -2
- package/dist/internal/react-avatar/index.d.ts +4 -2
- package/dist/internal/react-card/index.d.cts +10 -4
- package/dist/internal/react-card/index.d.ts +10 -4
- package/dist/internal/react-command/index.d.cts +13 -2
- package/dist/internal/react-command/index.d.ts +13 -2
- package/dist/internal/react-data-table/index.d.cts +27 -9
- package/dist/internal/react-data-table/index.d.ts +27 -9
- package/dist/internal/react-dialog/index.d.cts +5 -0
- package/dist/internal/react-dialog/index.d.ts +5 -0
- package/dist/internal/react-dropdown-menu/index.d.cts +19 -1
- package/dist/internal/react-dropdown-menu/index.d.ts +19 -1
- package/dist/internal/react-funnel-chart/index.d.ts +28 -0
- package/dist/internal/react-line-chart/index.d.ts +38 -0
- package/dist/internal/react-native-select/index.d.ts +19 -0
- package/dist/internal/react-page-header/index.d.ts +23 -0
- package/dist/internal/react-select/index.d.cts +21 -3
- package/dist/internal/react-select/index.d.ts +21 -3
- package/dist/internal/react-stat-grid/index.d.ts +22 -11
- package/dist/internal/react-table/index.d.ts +39 -0
- package/dist/internal/select/index.d.cts +14 -1
- package/dist/internal/select/index.d.ts +14 -1
- package/dist/internal/shared/index.d.cts +6 -3
- package/dist/internal/shared/index.d.ts +6 -3
- package/dist/internal/stat-grid/index.d.ts +49 -7
- package/dist/internal/table/index.d.ts +46 -0
- package/dist/internal/tabs/index.d.cts +8 -1
- package/dist/internal/tabs/index.d.ts +8 -1
- package/dist/react-accordion.js +1 -1
- package/dist/react-action-list.js +74 -0
- package/dist/react-action-list.js.map +7 -0
- package/dist/react-ai.js +1 -1
- package/dist/react-analytics.js +16 -4
- package/dist/react-analytics.js.map +2 -2
- package/dist/react-animated-text.js +1 -1
- package/dist/react-app-shell.js +1 -1
- package/dist/react-audience-feature-card.js +1 -1
- package/dist/react-audio-room.js +1 -1
- package/dist/react-auth.js +1 -1
- package/dist/react-avatar-group.js +1 -1
- package/dist/react-avatar.js +13 -9
- package/dist/react-avatar.js.map +2 -2
- package/dist/react-badge.js +2 -2
- package/dist/react-badge.js.map +1 -1
- package/dist/react-bottom-nav.js +1 -1
- package/dist/react-brand-network-cell.js +1 -1
- package/dist/react-breadcrumbs.js +1 -1
- package/dist/react-browser-chrome-mock.js +1 -1
- package/dist/react-button.js +3 -3
- package/dist/react-calendar.js +1 -1
- package/dist/react-call-controls.js +1 -1
- package/dist/react-callout.js +8 -3
- package/dist/react-callout.js.map +2 -2
- package/dist/react-card-grid.js +1 -1
- package/dist/react-card.js +5 -5
- package/dist/react-card.js.map +2 -2
- package/dist/react-carousel.js +1 -1
- package/dist/react-charts.js +1 -1
- package/dist/react-checkbox.js +1 -1
- package/dist/react-checklist.js +1 -1
- package/dist/react-code-block.js +1 -1
- package/dist/react-code-editor.js +1 -1
- package/dist/react-collapsible.js +1 -1
- package/dist/react-combobox.js +1 -1
- package/dist/react-command-input.js +1 -1
- package/dist/react-command.js +115 -70
- package/dist/react-command.js.map +3 -3
- package/dist/react-composer.js +3 -3
- package/dist/react-content-protection.js +1 -1
- package/dist/react-conversation.js +5 -5
- package/dist/react-cookie-consent.js +1 -1
- package/dist/react-data-table.js +125 -114
- package/dist/react-data-table.js.map +2 -2
- package/dist/react-date-picker.js +1 -1
- package/dist/react-device-frame.js +1 -1
- package/dist/react-dialog.js +33 -9
- package/dist/react-dialog.js.map +2 -2
- package/dist/react-diff-viewer.js +1 -1
- package/dist/react-dropdown-menu.js +61 -8
- package/dist/react-dropdown-menu.js.map +3 -3
- package/dist/react-editor-status-bar.js +1 -1
- package/dist/react-editor-tabs.js +1 -1
- package/dist/react-emoji-picker.js +2 -2
- package/dist/react-empty-state.js +1 -1
- package/dist/react-feedback-dialog.js +2 -2
- package/dist/react-file-tree.js +1 -1
- package/dist/react-file-upload.js +1 -1
- package/dist/react-floating-reactions.js +1 -1
- package/dist/react-flow-editor.js +2 -2
- package/dist/react-footer.js +1 -1
- package/dist/react-funnel-chart.js +105 -0
- package/dist/react-funnel-chart.js.map +7 -0
- package/dist/react-graph-view.js +2 -2
- package/dist/react-infinite-canvas.js +2 -2
- package/dist/react-inline-editor.js +1 -1
- package/dist/react-input-group.js +1 -1
- package/dist/react-input.js +2 -2
- package/dist/react-install-prompt.js +1 -1
- package/dist/react-kanban-board.js +1 -1
- package/dist/react-keyboard-shortcut.js +2 -2
- package/dist/react-language-selector.js +1 -1
- package/dist/react-line-chart.js +280 -0
- package/dist/react-line-chart.js.map +7 -0
- package/dist/react-link-card.js +1 -1
- package/dist/react-live-captions.js +1 -1
- package/dist/react-live-cursors.js +1 -1
- package/dist/react-live-transcript.js +1 -1
- package/dist/react-location-selector.js +1 -1
- package/dist/react-logger.js +3 -3
- package/dist/react-markdown-renderer.js +2 -2
- package/dist/react-marquee-strip.js +1 -1
- package/dist/react-mascot.js +1 -1
- package/dist/react-mastery-bar.js +1 -1
- package/dist/react-mini-map.js +1 -1
- package/dist/react-mobile-nav.js +1 -1
- package/dist/react-native-select.js +52 -0
- package/dist/react-native-select.js.map +7 -0
- package/dist/react-navbar.js +1 -1
- package/dist/react-numbered-steps.js +1 -1
- package/dist/react-otp-input.js +1 -1
- package/dist/react-page-header.js +40 -0
- package/dist/react-page-header.js.map +7 -0
- package/dist/react-pagination.js +1 -1
- package/dist/react-password-input.js +2 -2
- package/dist/react-payment.js +1 -1
- package/dist/react-popover.js +1 -1
- package/dist/react-pre-call-lobby.js +1 -1
- package/dist/react-presence-indicator.js +1 -1
- package/dist/react-pricing-card.js +1 -1
- package/dist/react-progress-display.js +2 -2
- package/dist/react-progress-display.js.map +1 -1
- package/dist/react-radial-gauge.js +1 -1
- package/dist/react-radio.js +1 -1
- package/dist/react-rating-scale.js +1 -1
- package/dist/react-reaction-bar.js +1 -1
- package/dist/react-resizable-layout.js +1 -1
- package/dist/react-search-bar.js +1 -1
- package/dist/react-section-head.js +1 -1
- package/dist/react-segmented-control.js +1 -1
- package/dist/react-select.js +94 -20
- package/dist/react-select.js.map +3 -3
- package/dist/react-separator.js +1 -1
- package/dist/react-sheet.js +1 -1
- package/dist/react-sidebar.js +1 -1
- package/dist/react-skeleton.js +1 -1
- package/dist/react-skip-to-content.js +1 -1
- package/dist/react-slide-viewer.js +1 -1
- package/dist/react-slider.js +1 -1
- package/dist/react-slot-picker.js +1 -1
- package/dist/react-social-auth-button.js +3 -3
- package/dist/react-sortable-list.js +1 -1
- package/dist/react-stat-grid.js +91 -22
- package/dist/react-stat-grid.js.map +2 -2
- package/dist/react-status-indicator.js +1 -1
- package/dist/react-steps.js +1 -1
- package/dist/react-sticky-note.js +1 -1
- package/dist/react-switch.js +1 -1
- package/dist/react-table-of-contents.js +1 -1
- package/dist/react-table.js +148 -0
- package/dist/react-table.js.map +7 -0
- package/dist/react-tabs.js +84 -7
- package/dist/react-tabs.js.map +2 -2
- package/dist/react-terminal.js +1 -1
- package/dist/react-test-results.js +1 -1
- package/dist/react-textarea.js +3 -3
- package/dist/react-textarea.js.map +1 -1
- package/dist/react-thread-view.js +2 -2
- package/dist/react-timeline.js +1 -1
- package/dist/react-toast.js +1 -1
- package/dist/react-tooltip.js +1 -1
- package/dist/react-version-selector.js +1 -1
- package/dist/react-video-grid.js +2 -2
- package/dist/react-video-player.js +1 -1
- package/dist/react-video-tile.js +2 -2
- package/dist/react-voice-pill.js +1 -1
- package/dist/react-waveform.js +1 -1
- package/dist/react-wizard.js +1 -1
- package/dist/theme.js +1 -1
- package/package.json +7 -1
- package/dist/chunk-NKCWOPNX.js.map +0 -7
- package/dist/chunk-SDZ3LROZ.js +0 -7
- package/dist/chunk-Y2FNNAIL.js.map +0 -1
- package/dist/chunk-ZF3OHCGV.js.map +0 -7
- package/dist/faro-engine-47HGRAQH-JKINJPMH.js +0 -3
- /package/dist/{chunk-533MCMSU.js.map → chunk-3I3DYDHR.js.map} +0 -0
- /package/dist/{chunk-H54FLNAF.js.map → chunk-63N4PZUJ.js.map} +0 -0
- /package/dist/{chunk-SDZ3LROZ.js.map → chunk-7P7EJ56S.js.map} +0 -0
- /package/dist/{chunk-WK2IIUFO.js.map → chunk-QDMLIDYN.js.map} +0 -0
- /package/dist/{chunk-BOLFYVI6.js.map → chunk-QPCKJ2YR.js.map} +0 -0
- /package/dist/{chunk-UNEM2TRI.js.map → chunk-SDAJVXD4.js.map} +0 -0
- /package/dist/{chunk-VK3EQ34F.js.map → chunk-V24GDHUX.js.map} +0 -0
- /package/dist/{chunk-AMK4VCBG.js.map → chunk-WYKPPK3W.js.map} +0 -0
- /package/dist/{chunk-ONACRMG4.js.map → chunk-XMFNBOPO.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../analytics/src/types.ts", "../../analytics/src/uuid.ts", "../../analytics/src/storage.ts", "../../analytics/src/session.ts", "../../analytics/src/identity.ts", "../../analytics/src/consent.ts", "../../analytics/src/redaction.ts", "../../analytics/src/http-sink.ts", "../../analytics/src/console-sink.ts", "../../analytics/src/noop.ts", "../../analytics/src/analytics-manager.ts", "../../analytics/src/mock-sink.ts", "../../analytics-sink-ga4/src/mapping.ts", "../../analytics-sink-ga4/src/http-sink.ts", "../../analytics-sink-ga4/src/client-sdk-sink.ts", "../../analytics-sink-ga4/src/ga4-sink.ts", "../../analytics-sink-app-insights/src/mapping.ts", "../../analytics-sink-app-insights/src/app-insights-sink.ts", "../../analytics-sink-posthog/src/mapping.ts", "../../analytics-sink-posthog/src/http-sink.ts", "../../analytics-sink-posthog/src/client-sdk-sink.ts", "../../analytics-sink-posthog/src/sink.ts", "../../analytics-sink-posthog/src/replay.ts", "../../react-analytics/src/analytics-provider.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * @refraction-ui/analytics — type contracts.\n *\n * The library is a neutral Segment-spec collector/router. The app instruments\n * once via the canonical API; the router fans the canonical envelope out to\n * N pluggable sinks. There is NO privileged engine — every vendor is a sink.\n */\n\n/** Canonical Segment event types. */\nexport type AnalyticsEventType =\n | 'track'\n | 'identify'\n | 'page'\n | 'screen'\n | 'group'\n | 'alias'\n\n/** Schema version stamped onto every envelope and the wire contract path. */\nexport const SCHEMA_VERSION = 1\n\n/** Arbitrary, JSON-serialisable bag of values. */\nexport type AnalyticsProperties = Record<string, unknown>\n\n/**\n * The context block attached to every event. `library` identifies the\n * collector; `app`/`env` identify the product instance.\n */\nexport interface AnalyticsContext {\n app: string\n env: string\n page?: {\n path?: string\n url?: string\n referrer?: string\n title?: string\n search?: string\n }\n library: {\n name: string\n version: string\n }\n /** Free-form additions contributed by `with(context)` children. */\n [key: string]: unknown\n}\n\n/**\n * The canonical Segment envelope. Every sink receives events in exactly this\n * shape; the built-in HTTP sink ships it verbatim over the wire contract.\n */\nexport interface AnalyticsEvent {\n /** Segment call type. */\n type: AnalyticsEventType\n /** Event name (track/screen) or page name (page). */\n event?: string\n /** Idempotency key — backends MUST dedupe on this. */\n messageId: string\n /** Persistent, non-PII, resettable client id. */\n anonymousId: string\n /** Opaque app-supplied id (set after identify). */\n userId?: string\n /** Group id (group calls). */\n groupId?: string\n /** Previous id (alias calls). */\n previousId?: string\n /** Analytics session id (UUIDv4, minted at session start). */\n sessionId: string\n /** track/page/screen/group payload. */\n properties?: AnalyticsProperties\n /** identify/group trait payload. */\n traits?: AnalyticsProperties\n /** Collector + product context. */\n context: AnalyticsContext\n /** ISO-8601 client timestamp. */\n timestamp: string\n /** Envelope schema version. */\n schemaVersion: number\n}\n\n/**\n * Sink SPI — implemented by adapter packages (GA4, Azure, PostHog) and by the\n * built-in HTTP sink. A sink declares the consent categories it requires; the\n * router will not deliver to a sink whose categories are not all granted.\n */\nexport interface AnalyticsSink {\n /** Stable sink identifier. */\n name: string\n /** Consent categories this sink requires (e.g. ['analytics']). */\n consentCategories?: string[]\n /** Called once before the first delivery. */\n init?(ctx: SinkInitContext): void | Promise<void>\n /** Deliver a batch of canonical events. */\n deliver(batch: AnalyticsEvent[], ctx: SinkDeliverContext): void | Promise<void>\n /** Flush any buffered state (best-effort). */\n flush?(): void | Promise<void>\n /** Release resources on reset()/shutdown. */\n shutdown?(): void | Promise<void>\n}\n\n/** Context handed to `sink.init`. */\nexport interface SinkInitContext {\n app: string\n env: string\n endpoint?: string\n}\n\n/** Context handed to every `sink.deliver`. */\nexport interface SinkDeliverContext {\n /** True on the unload path — sinks should prefer sendBeacon. */\n unload: boolean\n}\n\n/** Cross-tab persistence SPI. Defaults pick localStorage/cookie/memory. */\nexport interface AnalyticsStorage {\n get(key: string): string | null\n set(key: string, value: string): void\n remove(key: string): void\n}\n\n/** Session engine configuration. */\nexport interface SessionConfig {\n /** Inactivity timeout in ms before a new session is minted. GA4 = 30min. */\n timeoutMs?: number\n /** Reset the session when a campaign/utm change is detected. */\n resetOnCampaign?: boolean\n /** Persistence backend; defaults to localStorage→cookie→memory. */\n storage?: AnalyticsStorage\n /** Storage key namespace. */\n storageKey?: string\n}\n\n/** Identity engine configuration. */\nexport interface IdentityConfig {\n /** Persistence backend; defaults to localStorage→cookie→memory. */\n storage?: AnalyticsStorage\n /** Storage key namespace. */\n storageKey?: string\n}\n\n/** Consent gate configuration. */\nexport interface ConsentConfig {\n /** Categories granted at boot. */\n granted?: string[]\n /**\n * If true, an event is dropped entirely when NO sink can receive it.\n * If false (default), events are still buffered until consent is granted.\n */\n strict?: boolean\n}\n\n/** Consent gate runtime API. */\nexport interface ConsentAPI {\n grant(...categories: string[]): void\n revoke(...categories: string[]): void\n granted(): string[]\n isGranted(category: string): boolean\n}\n\n/** Session runtime API. */\nexport interface SessionAPI {\n /** Current session id (mints one lazily if none active). */\n id(): string\n /** Force-start a new session, returning the new id. */\n start(): string\n /** End the current session. */\n end(): void\n /** Attach arbitrary session-scoped properties. */\n set(props: AnalyticsProperties): void\n}\n\n/** Built-in HTTP sink options (Segment HTTP Tracking API wire contract). */\nexport interface HttpSinkOptions {\n /** Base endpoint; events POST to `{endpoint}/v{schemaVersion}/batch`. */\n endpoint: string\n /** Write key — sent as `Authorization: Basic base64(writeKey:)`. */\n writeKey: string\n /** Max retries for 429/5xx (exponential backoff). Default 3. */\n maxRetries?: number\n /** Base backoff delay in ms. Default 500. */\n backoffBaseMs?: number\n /** Injected fetch (defaults to global fetch). */\n fetchImpl?: typeof fetch\n /** Injected sendBeacon (defaults to navigator.sendBeacon). */\n beaconImpl?: (url: string, body: string) => boolean\n /** Consent categories this sink requires. Default ['analytics']. */\n consentCategories?: string[]\n /** Soft per-batch byte cap (Segment ≈ 500KB). Default 500_000. */\n maxBatchBytes?: number\n /** Soft per-event byte cap (Segment ≈ 32KB). Default 32_000. */\n maxEventBytes?: number\n /** Clock for the batch `sentAt` stamp. Default: ambient `new Date()` — inject for deterministic tests. */\n now?: () => Date\n}\n\n/** `createAnalytics` configuration. */\nexport interface AnalyticsConfig {\n /** Product/app identifier (stamped into context.app). */\n app: string\n /** Environment, e.g. 'development' | 'production'. Drives presets. */\n env: string\n /** When set, a built-in HTTP sink is auto-registered to this endpoint. */\n endpoint?: string\n /** Write key for the auto-registered HTTP sink. */\n writeKey?: string\n /** Kill switch — when false, a tree-shakeable noop is returned. Default true. */\n enabled?: boolean\n /** 0..1 sampling rate applied per top-level call. Default 1. */\n sampleRate?: number\n /** Extra property/trait keys to redact (in addition to the PII deny-list). */\n redactKeys?: string[]\n /** Explicit sinks (in addition to / instead of the auto HTTP sink). */\n sinks?: AnalyticsSink[]\n /** Session engine config. */\n session?: SessionConfig\n /** Identity engine config. */\n identity?: IdentityConfig\n /** Consent gate config. */\n consent?: ConsentConfig\n /**\n * Force a preset. Defaults: env==='production' → 'prod', else 'dev'.\n * dev = sync + console; prod = batch + sample + beacon flush on unload.\n */\n preset?: 'dev' | 'prod'\n /** Batch size before an automatic flush (prod). Default 20. */\n batchSize?: number\n /** Auto-flush interval in ms (prod). Default 10_000. */\n flushIntervalMs?: number\n /** Clock for default event timestamps. Default: ambient `new Date()` — inject for deterministic tests/SSR. */\n now?: () => Date\n /** RNG for sample-rate decisions. Default: ambient `Math.random` — inject for deterministic tests. */\n random?: () => number\n}\n\n/** Options accepted by every top-level call. */\nexport interface CallOptions {\n /** Per-call timestamp override (ISO-8601). */\n timestamp?: string\n /** Per-call context overrides (shallow-merged). */\n context?: Partial<AnalyticsContext>\n}\n\n/** The public analytics surface returned by `createAnalytics`. */\nexport interface Analytics {\n track(event: string, properties?: AnalyticsProperties, opts?: CallOptions): void\n identify(userId: string, traits?: AnalyticsProperties, opts?: CallOptions): void\n page(name?: string, properties?: AnalyticsProperties, opts?: CallOptions): void\n screen(name?: string, properties?: AnalyticsProperties, opts?: CallOptions): void\n group(groupId: string, traits?: AnalyticsProperties, opts?: CallOptions): void\n alias(userId: string, previousId?: string, opts?: CallOptions): void\n\n /** Analytics-session API (NOT replay). */\n session: SessionAPI\n /** Consent gate API. */\n consent: ConsentAPI\n\n /** Persistent, non-PII anonymous id. */\n anonymousId(): string\n /** Current opaque user id (if identified). */\n userId(): string | undefined\n\n /** Derive a child that merges extra context into every event. */\n with(context: Partial<AnalyticsContext>): Analytics\n\n /** Register an additional sink at runtime. */\n addSink(sink: AnalyticsSink): void\n /** Remove a sink by name. */\n removeSink(name: string): void\n /** Registered sink names. */\n readonly sinks: string[]\n\n /** Flush all sinks (and the internal batch). */\n flush(): Promise<void>\n /**\n * Reset identity + session (privacy-safe logout). Mints a fresh\n * anonymousId and ends the session.\n */\n reset(): void\n /** Whether this is a live collector (false for the noop). */\n readonly enabled: boolean\n}\n", "/**\n * uuidv4 — RFC 4122 version 4 UUID.\n *\n * Prefers `crypto.randomUUID` / `crypto.getRandomValues` when available\n * (browser, modern Node) and degrades to `Math.random` only as a last\n * resort. No external dependency by design (this is the neutral router).\n */\nexport function uuidv4(): string {\n const c: Crypto | undefined =\n typeof globalThis !== 'undefined'\n ? (globalThis.crypto as Crypto | undefined)\n : undefined\n\n if (c && typeof c.randomUUID === 'function') {\n return c.randomUUID()\n }\n\n const bytes = new Uint8Array(16)\n if (c && typeof c.getRandomValues === 'function') {\n c.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n }\n\n // Per RFC 4122 §4.4: set version (4) and variant (10xx) bits.\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n\n const hex: string[] = []\n for (let i = 0; i < 256; i++) hex.push((i + 0x100).toString(16).slice(1))\n\n return (\n hex[bytes[0]] +\n hex[bytes[1]] +\n hex[bytes[2]] +\n hex[bytes[3]] +\n '-' +\n hex[bytes[4]] +\n hex[bytes[5]] +\n '-' +\n hex[bytes[6]] +\n hex[bytes[7]] +\n '-' +\n hex[bytes[8]] +\n hex[bytes[9]] +\n '-' +\n hex[bytes[10]] +\n hex[bytes[11]] +\n hex[bytes[12]] +\n hex[bytes[13]] +\n hex[bytes[14]] +\n hex[bytes[15]]\n )\n}\n\n/** RFC 4122 v4 shape matcher (case-insensitive). */\nexport const UUID_V4_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n\n/** True when `value` is a well-formed v4 UUID. */\nexport function isUuidV4(value: unknown): value is string {\n return typeof value === 'string' && UUID_V4_RE.test(value)\n}\n", "import type { AnalyticsStorage } from './types.js'\n\n/**\n * Storage adapters.\n *\n * Order of preference for the cross-tab default: localStorage → cookie →\n * in-memory. The package is environment-agnostic; consumers can inject any\n * `AnalyticsStorage` (e.g. an RN AsyncStorage shim) via config.\n */\n\n/** Volatile per-process store (SSR / Node / no-DOM fallback). */\nexport function createMemoryStorage(): AnalyticsStorage {\n const map = new Map<string, string>()\n return {\n get: (k) => (map.has(k) ? (map.get(k) as string) : null),\n set: (k, v) => {\n map.set(k, v)\n },\n remove: (k) => {\n map.delete(k)\n },\n }\n}\n\n/** `window.localStorage` adapter (cross-tab via the storage event). */\nexport function createLocalStorageAdapter(\n ls: Storage,\n): AnalyticsStorage {\n return {\n get: (k) => {\n try {\n return ls.getItem(k)\n } catch {\n return null\n }\n },\n set: (k, v) => {\n try {\n ls.setItem(k, v)\n } catch {\n /* quota / disabled — degrade silently */\n }\n },\n remove: (k) => {\n try {\n ls.removeItem(k)\n } catch {\n /* ignore */\n }\n },\n }\n}\n\ninterface CookieDoc {\n cookie: string\n}\n\n/** `document.cookie` adapter (cross-tab + cross-subdomain capable). */\nexport function createCookieAdapter(\n doc: CookieDoc,\n maxAgeSeconds = 60 * 60 * 24 * 365,\n): AnalyticsStorage {\n const read = (k: string): string | null => {\n const target = encodeURIComponent(k) + '='\n const parts = doc.cookie ? doc.cookie.split(';') : []\n for (const part of parts) {\n const c = part.trim()\n if (c.startsWith(target)) {\n return decodeURIComponent(c.slice(target.length))\n }\n }\n return null\n }\n return {\n get: read,\n set: (k, v) => {\n doc.cookie = `${encodeURIComponent(k)}=${encodeURIComponent(\n v,\n )}; path=/; max-age=${maxAgeSeconds}; SameSite=Lax`\n },\n remove: (k) => {\n doc.cookie = `${encodeURIComponent(k)}=; path=/; max-age=0; SameSite=Lax`\n },\n }\n}\n\n/**\n * Resolve the default storage for the current environment. A caller-supplied\n * storage always wins. Browser → localStorage (falls back to cookie if\n * localStorage throws), otherwise in-memory.\n */\nexport function resolveStorage(\n override?: AnalyticsStorage,\n): AnalyticsStorage {\n if (override) return override\n\n const g = globalThis as unknown as {\n localStorage?: Storage\n document?: CookieDoc\n }\n\n if (g.localStorage) {\n try {\n // Probe — Safari private mode throws on setItem.\n const probe = '__rfx_a_probe__'\n g.localStorage.setItem(probe, '1')\n g.localStorage.removeItem(probe)\n return createLocalStorageAdapter(g.localStorage)\n } catch {\n /* fall through to cookie */\n }\n }\n\n if (g.document && typeof g.document.cookie === 'string') {\n return createCookieAdapter(g.document)\n }\n\n return createMemoryStorage()\n}\n", "import type {\n AnalyticsProperties,\n AnalyticsStorage,\n SessionConfig,\n} from './types.js'\nimport { resolveStorage } from './storage.js'\nimport { uuidv4 } from './uuid.js'\n\n/** GA4 parity: 30 minutes of inactivity ends a session. */\nexport const DEFAULT_SESSION_TIMEOUT_MS = 30 * 60 * 1000\n\nconst DEFAULT_KEY = 'rfx:analytics:session'\n\ninterface PersistedSession {\n id: string\n /** Last activity epoch ms. */\n lastActivity: number\n /** Campaign fingerprint at session start (for campaign-reset). */\n campaign?: string\n /** Session-scoped properties (set via session.set). */\n props?: AnalyticsProperties\n}\n\n/** Recognised campaign params (UTM + common click ids). GA4 parity. */\nconst CAMPAIGN_PARAMS = [\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_term',\n 'utm_content',\n 'gclid',\n 'fbclid',\n 'msclkid',\n]\n\n/**\n * Derive a stable campaign fingerprint from a URL's query string. A change in\n * this fingerprint (a *new* campaign, not its absence) forces a new session,\n * matching GA4's \"campaign change resets the session\" behaviour.\n */\nexport function campaignFingerprint(search?: string): string | undefined {\n if (!search) return undefined\n let qs = search\n const q = qs.indexOf('?')\n if (q !== -1) qs = qs.slice(q + 1)\n let params: URLSearchParams\n try {\n params = new URLSearchParams(qs)\n } catch {\n return undefined\n }\n const pairs: string[] = []\n for (const p of CAMPAIGN_PARAMS) {\n const v = params.get(p)\n if (v) pairs.push(`${p}=${v}`)\n }\n return pairs.length ? pairs.join('&') : undefined\n}\n\n/**\n * Session engine.\n *\n * A session is a span of continuous activity. It ends after `timeoutMs` of\n * inactivity (GA4 parity, default 30 min) or when a *new* campaign is\n * detected. State is persisted cross-tab so multiple tabs share one session.\n */\nexport function createSession(\n config?: SessionConfig,\n now: () => number = () => Date.now(),\n) {\n const storage: AnalyticsStorage = resolveStorage(config?.storage)\n const key = config?.storageKey ?? DEFAULT_KEY\n const timeoutMs = config?.timeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS\n const resetOnCampaign = config?.resetOnCampaign ?? true\n\n function read(): PersistedSession | null {\n const raw = storage.get(key)\n if (!raw) return null\n try {\n const parsed = JSON.parse(raw) as PersistedSession\n if (parsed && typeof parsed.id === 'string') return parsed\n } catch {\n /* corrupt — treat as none */\n }\n return null\n }\n\n function write(s: PersistedSession): void {\n storage.set(key, JSON.stringify(s))\n }\n\n function mint(campaign?: string): PersistedSession {\n const s: PersistedSession = {\n id: uuidv4(),\n lastActivity: now(),\n campaign,\n }\n write(s)\n return s\n }\n\n /**\n * Return the live session, creating/rotating it as required by the\n * inactivity timeout and (optionally) a campaign change.\n */\n function ensure(campaign?: string): PersistedSession {\n const existing = read()\n const t = now()\n\n if (!existing) return mint(campaign)\n\n // Inactivity timeout.\n if (t - existing.lastActivity > timeoutMs) {\n return mint(campaign)\n }\n\n // Campaign reset — only when a *new* campaign appears.\n if (\n resetOnCampaign &&\n campaign !== undefined &&\n existing.campaign !== campaign\n ) {\n return mint(campaign)\n }\n\n return existing\n }\n\n return {\n /** Get the current session id, rotating if expired. */\n id(campaign?: string): string {\n return ensure(campaign).id\n },\n /** Force a brand-new session. */\n start(campaign?: string): string {\n return mint(campaign).id\n },\n /** End the current session (next id() mints a fresh one). */\n end(): void {\n storage.remove(key)\n },\n /** Touch activity so the inactivity window slides forward. */\n touch(campaign?: string): string {\n const s = ensure(campaign)\n s.lastActivity = now()\n write(s)\n return s.id\n },\n /** Attach/merge session-scoped properties. */\n set(props: AnalyticsProperties): void {\n const s = ensure()\n s.props = { ...(s.props ?? {}), ...props }\n write(s)\n },\n /** Read session-scoped properties (undefined when none). */\n props(): AnalyticsProperties | undefined {\n return read()?.props\n },\n }\n}\n\nexport type Session = ReturnType<typeof createSession>\n", "import type { AnalyticsStorage, IdentityConfig } from './types.js'\nimport { resolveStorage } from './storage.js'\nimport { uuidv4, isUuidV4 } from './uuid.js'\n\nconst DEFAULT_KEY = 'rfx:analytics:anon'\n\n/**\n * Identity engine.\n *\n * - `anonymousId`: persistent, non-PII, resettable UUIDv4 stored cross-tab.\n * - `userId`: opaque, app-supplied; never persisted by the library (the app\n * owns the user record) — kept only in memory for the active page.\n * - `alias`: records a previous→current stitch for the wire envelope.\n */\nexport function createIdentity(config?: IdentityConfig) {\n const storage: AnalyticsStorage = resolveStorage(config?.storage)\n const key = config?.storageKey ?? DEFAULT_KEY\n\n let userId: string | undefined\n\n function loadOrMintAnon(): string {\n const existing = storage.get(key)\n if (isUuidV4(existing)) return existing as string\n const fresh = uuidv4()\n storage.set(key, fresh)\n return fresh\n }\n\n let anonymousId = loadOrMintAnon()\n\n return {\n anonymousId(): string {\n return anonymousId\n },\n userId(): string | undefined {\n return userId\n },\n /** identify(): bind an opaque app user id (no validation, no persistence). */\n setUserId(id: string): void {\n userId = id\n },\n /**\n * alias(): returns the stitch pair for the envelope. `previousId`\n * defaults to the current user or anonymous id.\n */\n alias(nextUserId: string, previousId?: string): { userId: string; previousId: string } {\n const prev = previousId ?? userId ?? anonymousId\n userId = nextUserId\n return { userId: nextUserId, previousId: prev }\n },\n /**\n * reset(): privacy-safe logout. Drops the user binding and mints a brand\n * new anonymousId so the next visitor is not stitched to the old one.\n */\n reset(): string {\n userId = undefined\n anonymousId = uuidv4()\n storage.set(key, anonymousId)\n return anonymousId\n },\n }\n}\n\nexport type Identity = ReturnType<typeof createIdentity>\n", "import type { ConsentAPI, ConsentConfig } from './types.js'\n\n/**\n * Consent gate.\n *\n * Holds the set of granted consent categories. The router asks the gate, per\n * sink, whether *all* of that sink's required categories are granted before\n * delivering. A sink with no declared categories is always allowed (it is the\n * sink author's responsibility to declare what it needs).\n */\nexport function createConsent(config?: ConsentConfig): ConsentAPI & {\n /** True when every required category is granted (empty list ⇒ allowed). */\n allows(required?: string[]): boolean\n /** True when at least one sink could receive (used by strict mode). */\n strict: boolean\n} {\n const granted = new Set<string>(config?.granted ?? [])\n\n return {\n strict: config?.strict ?? false,\n grant(...categories: string[]): void {\n for (const c of categories) granted.add(c)\n },\n revoke(...categories: string[]): void {\n for (const c of categories) granted.delete(c)\n },\n granted(): string[] {\n return [...granted]\n },\n isGranted(category: string): boolean {\n return granted.has(category)\n },\n allows(required?: string[]): boolean {\n if (!required || required.length === 0) return true\n return required.every((c) => granted.has(c))\n },\n }\n}\n\nexport type Consent = ReturnType<typeof createConsent>\n", "import type { AnalyticsProperties } from './types.js'\n\n/**\n * PII redaction.\n *\n * A built-in deny-list of well-known PII key names (email/phone/name and\n * common variants) plus any caller-supplied `redactKeys`. Matching is\n * case-insensitive and substring-based so `userEmail`, `email_address`,\n * `phoneNumber`, `fullName`, etc. are all caught. Redaction recurses into\n * nested objects and arrays so PII cannot hide one level down.\n */\n\n/**\n * Built-in PII deny-list (substring, case-insensitive, separator-insensitive).\n * These match anywhere in a key, so `userEmail`, `email_address`,\n * `phoneNumber`, `firstName`, etc. are all caught.\n */\nexport const PII_DENY_LIST: readonly string[] = [\n 'email',\n 'phone',\n 'mobile',\n 'firstname',\n 'lastname',\n 'fullname',\n 'givenname',\n 'surname',\n 'password',\n 'passwd',\n 'ssn',\n 'creditcard',\n 'cardnumber',\n 'cvv',\n 'dob',\n 'dateofbirth',\n 'address',\n]\n\n/**\n * Keys that are PII only as an *exact* (normalised) match. `name` belongs\n * here so genuine name fields redact while `username`, `eventName`,\n * `fileName`, `firstName`-style compounds (handled by the deny-list) do not\n * over-redact every key that merely contains \"name\".\n */\nexport const PII_EXACT_KEYS: readonly string[] = ['name']\n\n/** Replacement token written in place of a redacted value. */\nexport const REDACTED = '[REDACTED]'\n\nfunction normalize(key: string): string {\n return key.toLowerCase().replace(/[_\\-\\s]/g, '')\n}\n\n/**\n * Build a key matcher from the deny-list + extra keys. `extra` entries match\n * exactly (case-insensitive, normalised); deny-list entries match as\n * substrings.\n */\nexport function createRedactor(extraKeys: string[] = []) {\n const exact = new Set([\n ...extraKeys.map(normalize),\n ...PII_EXACT_KEYS.map(normalize),\n ])\n const deny = PII_DENY_LIST.map(normalize)\n\n const shouldRedact = (key: string): boolean => {\n const n = normalize(key)\n if (exact.has(n)) return true\n return deny.some((d) => n.includes(d))\n }\n\n const walk = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(walk)\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = shouldRedact(k) ? REDACTED : walk(v)\n }\n return out\n }\n return value\n }\n\n return {\n shouldRedact,\n /** Redact a properties/traits bag (returns a new object). */\n redact(props?: AnalyticsProperties): AnalyticsProperties | undefined {\n if (!props) return props\n return walk(props) as AnalyticsProperties\n },\n }\n}\n\nexport type Redactor = ReturnType<typeof createRedactor>\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n HttpSinkOptions,\n SinkDeliverContext,\n} from './types.js'\nimport { SCHEMA_VERSION } from './types.js'\nimport { uuidv4 } from './uuid.js'\n\n/**\n * Built-in `http` sink — Segment HTTP Tracking API wire contract.\n *\n * Wire contract (adopt, do not invent — RudderStack/Jitsu/Segment conform):\n *\n * POST {endpoint}/v{schemaVersion}/batch\n * Content-Type: application/json\n * Authorization: Basic base64(writeKey:) (note the trailing colon)\n * Body: { batch: AnalyticsEvent[], sentAt, batchId }\n *\n * Each event carries `messageId` (idempotency — backends MUST dedupe),\n * `anonymousId`, `userId?`, `sessionId`, `type`, `event?`,\n * `properties`/`traits`, `context`, `timestamp`, `schemaVersion`.\n *\n * Response handling (accept-and-queue semantics):\n * 200 accepted (the backend has only queued it, not processed it)\n * 400 malformed → DROP, never retry\n * 401 bad write key → DROP, never retry\n * 413 payload too big → DROP (we also pre-split under the size caps)\n * 429 / 5xx transient → exponential backoff retry\n *\n * Clock skew: the backend corrects with\n * corrected = timestamp + (receivedAt − sentAt)\n * so we always stamp an honest client `sentAt`.\n *\n * sendBeacon caveat: the unload path (`pagehide`/`visibilitychange`) uses\n * `navigator.sendBeacon`, which cannot set an `Authorization` header. On that\n * path we fall back to `?writeKey=` in the query string with a\n * `text/plain` body (the wire contract requires the backend to accept this).\n */\n\nconst NO_RETRY = new Set([400, 401, 413])\n\nfunction base64(input: string): string {\n const g = globalThis as unknown as {\n btoa?: (s: string) => string\n Buffer?: { from(s: string, enc: string): { toString(enc: string): string } }\n }\n if (typeof g.btoa === 'function') {\n return g.btoa(input)\n }\n if (g.Buffer) {\n return g.Buffer.from(input, 'utf-8').toString('base64')\n }\n throw new Error('No base64 implementation available (btoa/Buffer)')\n}\n\nfunction byteLength(s: string): number {\n const g = globalThis as unknown as {\n TextEncoder?: new () => { encode(s: string): { length: number } }\n }\n if (g.TextEncoder) return new g.TextEncoder().encode(s).length\n // Conservative fallback (UTF-8 worst case is 4 bytes/char; use 3 as typical).\n return unescape(encodeURIComponent(s)).length\n}\n\nconst sleep = (ms: number) =>\n new Promise<void>((r) => setTimeout(r, ms))\n\n/**\n * Split a batch so neither the per-event nor per-batch byte caps are\n * exceeded. Over-sized single events are dropped (they can never be sent).\n */\nfunction splitBatch(\n batch: AnalyticsEvent[],\n maxBatchBytes: number,\n maxEventBytes: number,\n): { batches: AnalyticsEvent[][]; dropped: AnalyticsEvent[] } {\n const batches: AnalyticsEvent[][] = []\n const dropped: AnalyticsEvent[] = []\n let current: AnalyticsEvent[] = []\n let currentBytes = 2 // \"[]\"\n\n for (const ev of batch) {\n const evBytes = byteLength(JSON.stringify(ev))\n if (evBytes > maxEventBytes) {\n dropped.push(ev)\n continue\n }\n if (current.length && currentBytes + evBytes + 1 > maxBatchBytes) {\n batches.push(current)\n current = []\n currentBytes = 2\n }\n current.push(ev)\n currentBytes += evBytes + 1\n }\n if (current.length) batches.push(current)\n return { batches, dropped }\n}\n\n/** Create the built-in Segment-spec HTTP sink. */\nexport function createHttpSink(options: HttpSinkOptions): AnalyticsSink {\n const {\n endpoint,\n writeKey,\n maxRetries = 3,\n backoffBaseMs = 500,\n consentCategories = ['analytics'],\n maxBatchBytes = 500_000,\n maxEventBytes = 32_000,\n } = options\n\n const base = endpoint.replace(/\\/+$/, '')\n const url = `${base}/v${SCHEMA_VERSION}/batch`\n const authHeader = `Basic ${base64(`${writeKey}:`)}`\n // Injection boundary: `sentAt` defaults to ambient time; inject `now` for determinism.\n const now = options.now ?? (() => new Date())\n\n const resolveFetch = (): typeof fetch => {\n if (options.fetchImpl) return options.fetchImpl\n const f = (globalThis as unknown as { fetch?: typeof fetch }).fetch\n if (!f) throw new Error('No fetch implementation available')\n return f\n }\n\n const resolveBeacon = ():\n | ((u: string, body: string) => boolean)\n | undefined => {\n if (options.beaconImpl) return options.beaconImpl\n const nav = (globalThis as unknown as {\n navigator?: { sendBeacon?: (u: string, data: BodyInit) => boolean }\n }).navigator\n if (nav && typeof nav.sendBeacon === 'function') {\n return (u, body) => nav.sendBeacon!(u, body)\n }\n return undefined\n }\n\n function envelope(batch: AnalyticsEvent[]) {\n return {\n batch,\n sentAt: now().toISOString(),\n batchId: uuidv4(),\n }\n }\n\n /** Beacon path: writeKey via query string, text/plain body. */\n function sendViaBeacon(batch: AnalyticsEvent[]): boolean {\n const beacon = resolveBeacon()\n if (!beacon) return false\n const beaconUrl = `${url}?writeKey=${encodeURIComponent(writeKey)}`\n return beacon(beaconUrl, JSON.stringify(envelope(batch)))\n }\n\n /** Standard path: fetch + Authorization header, with backoff retries. */\n async function sendViaFetch(batch: AnalyticsEvent[]): Promise<void> {\n const doFetch = resolveFetch()\n const body = JSON.stringify(envelope(batch))\n\n for (let attempt = 0; ; attempt++) {\n let status: number\n try {\n const res = await doFetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: authHeader,\n },\n body,\n keepalive: true,\n })\n status = res.status\n } catch {\n // Network error — treat as transient.\n status = 0\n }\n\n if (status >= 200 && status < 300) return // accepted-and-queued\n if (NO_RETRY.has(status)) return // 400/401/413 — drop, never retry\n\n // 429 / 5xx / network (0) → backoff retry.\n if (attempt >= maxRetries) return\n const delay = backoffBaseMs * 2 ** attempt\n await sleep(delay)\n }\n }\n\n return {\n name: 'http',\n consentCategories,\n\n async deliver(\n batch: AnalyticsEvent[],\n ctx: SinkDeliverContext,\n ): Promise<void> {\n if (batch.length === 0) return\n const { batches, dropped } = splitBatch(\n batch,\n maxBatchBytes,\n maxEventBytes,\n )\n void dropped // oversized events are unsendable by contract — silently dropped\n\n for (const part of batches) {\n if (ctx.unload) {\n // Unload path: try beacon first; fall back to keepalive fetch.\n if (sendViaBeacon(part)) continue\n void sendViaFetch(part)\n } else {\n await sendViaFetch(part)\n }\n }\n },\n }\n}\n", "import type { AnalyticsEvent, AnalyticsSink } from './types.js'\n\nexport interface ConsoleSinkOptions {\n /** Injected logger (defaults to globalThis.console). */\n logger?: Pick<Console, 'log' | 'groupCollapsed' | 'groupEnd'>\n /** Consent categories this sink requires. Default: none (always allowed). */\n consentCategories?: string[]\n}\n\n/**\n * Built-in `console` sink — the dev preset's default. Prints each canonical\n * envelope so engineers can see exactly what would ship over the wire.\n */\nexport function createConsoleSink(\n options: ConsoleSinkOptions = {},\n): AnalyticsSink {\n const logger =\n options.logger ??\n (globalThis as unknown as { console: Console }).console\n\n return {\n name: 'console',\n consentCategories: options.consentCategories,\n deliver(batch: AnalyticsEvent[]): void {\n for (const ev of batch) {\n const label = `[analytics] ${ev.type}${ev.event ? ` ${ev.event}` : ''}`\n if (typeof logger.groupCollapsed === 'function') {\n logger.groupCollapsed(label)\n logger.log(ev)\n logger.groupEnd?.()\n } else {\n logger.log(label, ev)\n }\n }\n },\n }\n}\n", "import type { Analytics } from './types.js'\n\n/**\n * The noop collector returned when `enabled: false`.\n *\n * Every method is an empty function so calls are free and the surrounding\n * vendor/sink code can be tree-shaken out of a production bundle when\n * analytics is compiled off. Kept in its own module so bundlers can drop the\n * live collector entirely on the `enabled:false` path.\n */\nexport function createNoopAnalytics(): Analytics {\n const sessionId = '00000000-0000-4000-8000-000000000000'\n const noop = (): void => {}\n\n const api: Analytics = {\n track: noop,\n identify: noop,\n page: noop,\n screen: noop,\n group: noop,\n alias: noop,\n session: {\n id: () => sessionId,\n start: () => sessionId,\n end: noop,\n set: noop,\n },\n consent: {\n grant: noop,\n revoke: noop,\n granted: () => [],\n isGranted: () => false,\n },\n anonymousId: () => sessionId,\n userId: () => undefined,\n with: () => api,\n addSink: noop,\n removeSink: noop,\n get sinks() {\n return []\n },\n flush: async () => {},\n reset: noop,\n enabled: false,\n }\n\n return api\n}\n", "import type {\n Analytics,\n AnalyticsConfig,\n AnalyticsContext,\n AnalyticsEvent,\n AnalyticsEventType,\n AnalyticsSink,\n CallOptions,\n SinkDeliverContext,\n} from './types.js'\nimport { SCHEMA_VERSION } from './types.js'\nimport { uuidv4 } from './uuid.js'\nimport { createSession, campaignFingerprint } from './session.js'\nimport { createIdentity } from './identity.js'\nimport { createConsent } from './consent.js'\nimport { createRedactor } from './redaction.js'\nimport { createHttpSink } from './http-sink.js'\nimport { createConsoleSink } from './console-sink.js'\nimport { createNoopAnalytics } from './noop.js'\n\nconst LIBRARY = {\n name: '@refraction-ui/analytics',\n version: '0.1.0',\n}\n\n/** Read the current page block from the DOM, if any (browser-only). */\nfunction readPage(): AnalyticsContext['page'] | undefined {\n const g = globalThis as unknown as {\n location?: { pathname?: string; href?: string; search?: string }\n document?: { title?: string; referrer?: string }\n }\n if (!g.location && !g.document) return undefined\n return {\n path: g.location?.pathname,\n url: g.location?.href,\n search: g.location?.search,\n title: g.document?.title,\n referrer: g.document?.referrer,\n }\n}\n\n/**\n * createAnalytics — the neutral Segment-spec collector/router.\n *\n * Mirrors `createAI`: a single factory returns the entire public surface and\n * fans the canonical envelope out to registered sinks. There is NO privileged\n * engine — the built-in HTTP sink and every vendor adapter are equal sinks.\n *\n * Presets:\n * dev — synchronous delivery + a console sink (see exactly what ships).\n * prod — batching + sampling + beacon flush on pagehide/visibilitychange.\n *\n * When `enabled: false`, a tree-shakeable noop is returned and none of the\n * live collector / sink code is reachable.\n */\nexport function createAnalytics(config: AnalyticsConfig): Analytics {\n if (config.enabled === false) {\n return createNoopAnalytics()\n }\n\n const { app, env } = config\n const preset =\n config.preset ?? (env === 'production' ? 'prod' : 'dev')\n const sampleRate = config.sampleRate ?? 1\n const batchSize = config.batchSize ?? 20\n const flushIntervalMs = config.flushIntervalMs ?? 10_000\n // Injection boundary: ambient time/randomness default here; inject `now`/`random` for determinism.\n const now = config.now ?? (() => new Date())\n const random = config.random ?? (() => Math.random())\n\n const session = createSession(config.session)\n const identity = createIdentity(config.identity)\n const consent = createConsent(config.consent)\n const redactor = createRedactor(config.redactKeys)\n\n // --- Sink registry ------------------------------------------------------\n const sinks = new Map<string, AnalyticsSink>()\n const sinkOrder: string[] = []\n const initialized = new Set<string>()\n\n function registerSink(sink: AnalyticsSink): void {\n if (!sinks.has(sink.name)) sinkOrder.push(sink.name)\n sinks.set(sink.name, sink)\n }\n\n // Auto HTTP sink when an endpoint is supplied.\n if (config.endpoint) {\n registerSink(\n createHttpSink({\n endpoint: config.endpoint,\n writeKey: config.writeKey ?? '',\n // One clock for the whole manager: the auto sink stamps sentAt with it too.\n now,\n }),\n )\n }\n // dev preset → add a console sink for visibility.\n if (preset === 'dev') {\n registerSink(createConsoleSink())\n }\n // Explicit sinks (override same-named built-ins).\n for (const s of config.sinks ?? []) registerSink(s)\n\n /**\n * Initialise a sink at most once. Returns a promise only when the sink's\n * own `init` is async — synchronous sinks stay on the synchronous path so\n * the dev preset delivers without a microtask hop.\n */\n function ensureInit(sink: AnalyticsSink): void | Promise<void> {\n if (initialized.has(sink.name)) return\n initialized.add(sink.name)\n if (sink.init) {\n return sink.init({ app, env, endpoint: config.endpoint })\n }\n }\n\n // --- Batch buffer -------------------------------------------------------\n const buffer: AnalyticsEvent[] = []\n let timer: ReturnType<typeof setInterval> | undefined\n\n function startTimer(): void {\n if (preset !== 'prod' || timer) return\n timer = setInterval(() => {\n void flush(false)\n }, flushIntervalMs)\n // Do not keep a Node process alive purely for the flush timer.\n ;(timer as unknown as { unref?: () => void }).unref?.()\n }\n\n /**\n * Fan a batch out to every consented sink. Stays fully synchronous when all\n * sinks are synchronous (dev preset visibility); returns a promise only if a\n * sink's init/deliver is async.\n */\n function deliverToSinks(\n batch: AnalyticsEvent[],\n unload: boolean,\n ): void | Promise<void> {\n if (batch.length === 0) return\n const ctx: SinkDeliverContext = { unload }\n const pending: Array<Promise<unknown>> = []\n for (const name of sinkOrder) {\n const sink = sinks.get(name)\n if (!sink) continue\n if (!consent.allows(sink.consentCategories)) continue\n const inited = ensureInit(sink)\n if (inited && typeof (inited as Promise<void>).then === 'function') {\n pending.push(\n (inited as Promise<void>).then(() => sink.deliver(batch, ctx)),\n )\n } else {\n const r = sink.deliver(batch, ctx)\n if (r && typeof (r as Promise<void>).then === 'function') {\n pending.push(r as Promise<void>)\n }\n }\n }\n if (pending.length) return Promise.all(pending).then(() => undefined)\n }\n\n async function flush(unload = false): Promise<void> {\n const batch = buffer.splice(0, buffer.length)\n await deliverToSinks(batch, unload)\n for (const name of sinkOrder) {\n const sink = sinks.get(name)\n if (sink?.flush && consent.allows(sink.consentCategories)) {\n await sink.flush()\n }\n }\n }\n\n // --- Unload flush (prod) ------------------------------------------------\n function bindUnload(): void {\n if (preset !== 'prod') return\n const g = globalThis as unknown as {\n addEventListener?: (t: string, h: () => void) => void\n document?: { visibilityState?: string }\n }\n if (typeof g.addEventListener !== 'function') return\n const onUnload = (): void => {\n void deliverToSinks(buffer.splice(0, buffer.length), true)\n }\n g.addEventListener('pagehide', onUnload)\n g.addEventListener('visibilitychange', () => {\n if (g.document?.visibilityState === 'hidden') onUnload()\n })\n }\n\n startTimer()\n bindUnload()\n\n // --- Envelope construction ---------------------------------------------\n function buildContext(\n extra?: Partial<AnalyticsContext>,\n childCtx?: Partial<AnalyticsContext>,\n ): AnalyticsContext {\n const page = readPage()\n return {\n app,\n env,\n ...(page ? { page } : {}),\n ...childCtx,\n ...extra,\n library: LIBRARY,\n }\n }\n\n function sampled(): boolean {\n if (sampleRate >= 1) return true\n if (sampleRate <= 0) return false\n return random() < sampleRate\n }\n\n function enqueue(ev: AnalyticsEvent): void {\n if (preset === 'dev') {\n // Synchronous, unbatched — immediate visibility.\n void deliverToSinks([ev], false)\n return\n }\n buffer.push(ev)\n if (buffer.length >= batchSize) {\n void flush(false)\n }\n }\n\n function emit(\n type: AnalyticsEventType,\n fields: Partial<AnalyticsEvent>,\n childCtx: Partial<AnalyticsContext> | undefined,\n opts?: CallOptions,\n ): void {\n if (!sampled()) return\n\n const page = readPage()\n const campaign = campaignFingerprint(page?.search)\n const sessionId = session.touch(campaign)\n const sessionProps = session.props()\n\n const ev: AnalyticsEvent = {\n type,\n messageId: uuidv4(),\n anonymousId: identity.anonymousId(),\n userId: identity.userId(),\n sessionId,\n context: buildContext(opts?.context, childCtx),\n timestamp: opts?.timestamp ?? now().toISOString(),\n schemaVersion: SCHEMA_VERSION,\n ...fields,\n }\n\n // Merge session-scoped props beneath call props.\n if (sessionProps && (ev.properties || type === 'track' || type === 'page' || type === 'screen')) {\n ev.properties = { ...sessionProps, ...(ev.properties ?? {}) }\n }\n\n enqueue(ev)\n }\n\n function makeApi(childCtx?: Partial<AnalyticsContext>): Analytics {\n const api: Analytics = {\n track(event, properties, opts) {\n emit(\n 'track',\n { event, properties: redactor.redact(properties) },\n childCtx,\n opts,\n )\n },\n\n identify(userId, traits, opts) {\n identity.setUserId(userId)\n emit('identify', { traits: redactor.redact(traits) }, childCtx, opts)\n },\n\n page(name, properties, opts) {\n emit(\n 'page',\n { event: name, properties: redactor.redact(properties) },\n childCtx,\n opts,\n )\n },\n\n screen(name, properties, opts) {\n emit(\n 'screen',\n { event: name, properties: redactor.redact(properties) },\n childCtx,\n opts,\n )\n },\n\n group(groupId, traits, opts) {\n emit(\n 'group',\n { groupId, traits: redactor.redact(traits) },\n childCtx,\n opts,\n )\n },\n\n alias(userId, previousId, opts) {\n const stitch = identity.alias(userId, previousId)\n emit(\n 'alias',\n { userId: stitch.userId, previousId: stitch.previousId },\n childCtx,\n opts,\n )\n },\n\n session: {\n id: () => session.id(),\n start: () => session.start(),\n end: () => session.end(),\n set: (props) => session.set(props),\n },\n\n consent: {\n grant: (...c) => consent.grant(...c),\n revoke: (...c) => consent.revoke(...c),\n granted: () => consent.granted(),\n isGranted: (c) => consent.isGranted(c),\n },\n\n anonymousId: () => identity.anonymousId(),\n userId: () => identity.userId(),\n\n with(extra: Partial<AnalyticsContext>): Analytics {\n return makeApi({ ...childCtx, ...extra })\n },\n\n addSink(sink: AnalyticsSink): void {\n registerSink(sink)\n },\n\n removeSink(name: string): void {\n if (sinks.has(name)) {\n sinks.delete(name)\n const i = sinkOrder.indexOf(name)\n if (i !== -1) sinkOrder.splice(i, 1)\n initialized.delete(name)\n }\n },\n\n get sinks(): string[] {\n return [...sinkOrder]\n },\n\n async flush(): Promise<void> {\n await flush(false)\n },\n\n reset(): void {\n identity.reset()\n session.end()\n },\n\n enabled: true,\n }\n\n return api\n }\n\n return makeApi()\n}\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkDeliverContext,\n SinkInitContext,\n} from './types.js'\n\n/** A mock sink that records every call — used for testing the router. */\nexport interface MockSink extends AnalyticsSink {\n /** All events received across all deliver() calls (flattened). */\n events: AnalyticsEvent[]\n /** Each deliver() call's batch + context. */\n deliveries: Array<{ batch: AnalyticsEvent[]; ctx: SinkDeliverContext }>\n /** init() call contexts. */\n initCalls: SinkInitContext[]\n /** flush() invocation count. */\n flushCalls: number\n /** shutdown() invocation count. */\n shutdownCalls: number\n}\n\nexport interface CreateMockSinkOptions {\n name?: string\n consentCategories?: string[]\n}\n\n/**\n * createMockSink — an `AnalyticsSink` that captures everything for assertion.\n * Mirrors the testing ergonomics of `@refraction-ui/ai`'s mock providers.\n */\nexport function createMockSink(\n options: CreateMockSinkOptions = {},\n): MockSink {\n const sink: MockSink = {\n name: options.name ?? 'mock',\n consentCategories: options.consentCategories,\n events: [],\n deliveries: [],\n initCalls: [],\n flushCalls: 0,\n shutdownCalls: 0,\n\n init(ctx: SinkInitContext): void {\n sink.initCalls.push(ctx)\n },\n\n deliver(batch: AnalyticsEvent[], ctx: SinkDeliverContext): void {\n sink.deliveries.push({ batch, ctx })\n for (const ev of batch) sink.events.push(ev)\n },\n\n flush(): void {\n sink.flushCalls++\n },\n\n shutdown(): void {\n sink.shutdownCalls++\n },\n }\n\n return sink\n}\n", "/**\n * Canonical envelope → GA4 mapping.\n *\n * One mapper, two consumers: the `client-sdk` adapter feeds the result into\n * `gtag('event', name, params)` / `gtag('set', ...)`, and the `http` adapter\n * serialises it into a Measurement Protocol `/mp/collect` payload. Keeping the\n * mapping in one place guarantees the two modes stay behaviourally identical.\n *\n * Identity / param mapping (issue #216, epic #213):\n * anonymousId → client_id (GA4 device/browser id)\n * userId → user_id (GA4 User-ID, cross-device)\n * properties → event params (track/page/screen/group payload)\n * identify → user_properties (traits become GA4 user properties)\n * sessionId → session_id param (so GA4 sessionisation can align)\n *\n * GA4 event-name normalisation: GA4 recommends snake_case event names and\n * forbids spaces. `page` → `page_view`, `screen` → `screen_view` (GA4\n * Enhanced-Measurement parity); everything else is lower_snake_cased.\n */\n\nimport type { AnalyticsEvent, AnalyticsProperties } from '@refraction-ui/analytics'\n\n/** A GA4 event ready for gtag.js or the Measurement Protocol. */\nexport interface GA4Event {\n /** GA4 event name (snake_case, no spaces). */\n name: string\n /** Event params (GA4 caps these; we pass them through verbatim). */\n params: Record<string, unknown>\n}\n\n/** The fully-mapped result for a single canonical envelope. */\nexport interface GA4Mapped {\n /** GA4 client_id (from anonymousId). Always present. */\n clientId: string\n /** GA4 user_id (from userId). Present only after identify. */\n userId?: string\n /**\n * GA4 user_properties (from identify/group traits). Each value is wrapped\n * in `{ value }` as the Measurement Protocol requires; the gtag adapter\n * unwraps when it calls `gtag('set', 'user_properties', ...)`.\n */\n userProperties?: Record<string, { value: unknown }>\n /**\n * The GA4 event to send. `identify` calls carry no event (they only set\n * user_id / user_properties), so this is optional.\n */\n event?: GA4Event\n}\n\nconst GA4_RESERVED_PREFIXES = ['google_', 'ga_', 'firebase_']\n\n/** Lower_snake_case an arbitrary event/trait name for GA4. */\nexport function toGa4Name(name: string): string {\n const snake = name\n .trim()\n .replace(/['\"]/g, '')\n .replace(/[^a-zA-Z0-9]+/g, '_')\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/_+/g, '_')\n .replace(/^_+|_+$/g, '')\n .toLowerCase()\n // GA4 names must start with a letter and avoid reserved prefixes.\n const safe = /^[a-z]/.test(snake) ? snake : `e_${snake}`\n return GA4_RESERVED_PREFIXES.some((p) => safe.startsWith(p))\n ? `x_${safe}`\n : safe\n}\n\n/** Map a Segment call type + name to its GA4 event name. */\nexport function ga4EventName(ev: AnalyticsEvent): string | undefined {\n switch (ev.type) {\n case 'identify':\n // identify only sets identity/user_properties — no event is emitted.\n return undefined\n case 'page':\n return 'page_view'\n case 'screen':\n return 'screen_view'\n case 'group':\n return 'group'\n case 'alias':\n return 'alias'\n case 'track':\n return ev.event ? toGa4Name(ev.event) : 'track'\n default:\n return undefined\n }\n}\n\n/** Wrap traits as GA4 user_properties (`{ name: { value } }`). */\nfunction toUserProperties(\n traits: AnalyticsProperties | undefined,\n): Record<string, { value: unknown }> | undefined {\n if (!traits) return undefined\n const out: Record<string, { value: unknown }> = {}\n let any = false\n for (const [k, v] of Object.entries(traits)) {\n if (v === undefined) continue\n out[toGa4Name(k)] = { value: v }\n any = true\n }\n return any ? out : undefined\n}\n\n/** Build the GA4 event params from a canonical envelope. */\nfunction toParams(ev: AnalyticsEvent): Record<string, unknown> {\n const params: Record<string, unknown> = {}\n\n // Pass through the canonical payload as GA4 params.\n for (const [k, v] of Object.entries(ev.properties ?? {})) {\n if (v === undefined) continue\n params[toGa4Name(k)] = v\n }\n\n // Align GA4 sessionisation with our analytics session.\n params.session_id = ev.sessionId\n // Stable client-supplied de-dupe / debugging aid.\n params.engagement_time_msec = params.engagement_time_msec ?? 1\n\n // page/screen context → GA4 page_* params (Enhanced-Measurement parity).\n const page = ev.context.page\n if (ev.type === 'page' || ev.type === 'screen') {\n if (ev.event) {\n if (ev.type === 'screen') params.screen_name = ev.event\n else params.page_title = params.page_title ?? ev.event\n }\n if (page?.url && params.page_location === undefined) {\n params.page_location = page.url\n }\n if (page?.path && params.page_path === undefined) {\n params.page_path = page.path\n }\n if (page?.referrer && params.page_referrer === undefined) {\n params.page_referrer = page.referrer\n }\n if (page?.title && params.page_title === undefined) {\n params.page_title = page.title\n }\n }\n\n if (ev.type === 'group' && ev.groupId) {\n params.group_id = ev.groupId\n }\n if (ev.type === 'alias') {\n if (ev.userId) params.user_id = ev.userId\n if (ev.previousId) params.previous_id = ev.previousId\n }\n\n return params\n}\n\n/**\n * Map one canonical envelope to its GA4 representation. Pure — no transport,\n * no vendor lib; both the gtag and Measurement-Protocol adapters consume this.\n */\nexport function mapEvent(ev: AnalyticsEvent): GA4Mapped {\n const name = ga4EventName(ev)\n const mapped: GA4Mapped = {\n clientId: ev.anonymousId,\n }\n if (ev.userId) mapped.userId = ev.userId\n\n if (ev.type === 'identify' || ev.type === 'group') {\n const up = toUserProperties(ev.traits)\n if (up) mapped.userProperties = up\n }\n\n if (name) {\n mapped.event = { name, params: toParams(ev) }\n }\n return mapped\n}\n", "/**\n * GA4 `http` adapter — Measurement Protocol (`/mp/collect`).\n *\n * Server-relay friendly: this path NEVER loads gtag.js or any browser\n * library. It only POSTs JSON to the Measurement Protocol endpoint:\n *\n * POST {endpoint}/mp/collect?measurement_id={id}&api_secret={secret}\n * Content-Type: application/json\n * { client_id, user_id?, user_properties?, events: [{ name, params }] }\n *\n * GA4 Measurement Protocol constraints honoured here:\n * - up to 25 events per request → batches are chunked.\n * - `identify` envelopes carry no event; they still POST so user_id /\n * user_properties propagate (events array may be empty for a user-props\n * only ping, which GA4 accepts).\n * - 2xx (incl. 204) = accepted. The MP endpoint always returns 2xx for\n * well-formed requests; the `debug` endpoint returns validation messages.\n */\n\nimport type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkInitContext,\n} from '@refraction-ui/analytics'\nimport type { GA4HttpOptions } from './types.js'\nimport { mapEvent } from './mapping.js'\n\nconst DEFAULT_ENDPOINT = 'https://www.google-analytics.com'\nconst MAX_EVENTS_PER_REQUEST = 25\n\ninterface MPPayload {\n client_id: string\n user_id?: string\n user_properties?: Record<string, { value: unknown }>\n events: Array<{ name: string; params: Record<string, unknown> }>\n}\n\nfunction resolveFetch(opts: GA4HttpOptions): typeof fetch {\n if (opts.fetchImpl) return opts.fetchImpl\n const f = (globalThis as unknown as { fetch?: typeof fetch }).fetch\n if (!f) throw new Error('GA4 http sink: no fetch implementation available')\n return f\n}\n\n/**\n * Group consecutive envelopes by GA4 identity (client_id + user_id) so each\n * Measurement Protocol request carries a single identity, then chunk to the\n * 25-event limit.\n */\nfunction buildPayloads(batch: AnalyticsEvent[]): MPPayload[] {\n const payloads: MPPayload[] = []\n\n for (const ev of batch) {\n const m = mapEvent(ev)\n const last = payloads[payloads.length - 1]\n const sameIdentity =\n last &&\n last.client_id === m.clientId &&\n last.user_id === m.userId &&\n last.events.length < MAX_EVENTS_PER_REQUEST &&\n // user_properties must not silently differ within one request\n JSON.stringify(last.user_properties) ===\n JSON.stringify(m.userProperties)\n\n const target: MPPayload = sameIdentity\n ? last\n : (() => {\n const p: MPPayload = { client_id: m.clientId, events: [] }\n if (m.userId) p.user_id = m.userId\n if (m.userProperties) p.user_properties = m.userProperties\n payloads.push(p)\n return p\n })()\n\n if (m.event) {\n target.events.push(m.event)\n }\n }\n\n // Drop empty payloads that carry neither an event nor user identity\n // signal (nothing to send to GA4).\n return payloads.filter(\n (p) =>\n p.events.length > 0 ||\n p.user_id !== undefined ||\n p.user_properties !== undefined,\n )\n}\n\n/**\n * Create the GA4 Measurement-Protocol (`http`) sink.\n *\n * No vendor library is loaded on this path under any circumstance.\n */\nexport function createGA4HttpSink(options: GA4HttpOptions): AnalyticsSink {\n const {\n measurementId,\n apiSecret,\n consentCategories = ['analytics'],\n name = 'ga4',\n debug = false,\n } = options\n const base = (options.endpoint ?? DEFAULT_ENDPOINT).replace(/\\/+$/, '')\n const path = debug ? '/debug/mp/collect' : '/mp/collect'\n const url =\n `${base}${path}?measurement_id=${encodeURIComponent(measurementId)}` +\n `&api_secret=${encodeURIComponent(apiSecret)}`\n\n return {\n name,\n consentCategories,\n\n init(_ctx: SinkInitContext): void {\n // No-op: the Measurement Protocol is stateless and credential-driven.\n // Explicitly NO vendor script / SDK is loaded here.\n void _ctx\n },\n\n async deliver(batch: AnalyticsEvent[]): Promise<void> {\n if (batch.length === 0) return\n const payloads = buildPayloads(batch)\n if (payloads.length === 0) return\n const doFetch = resolveFetch(options)\n\n for (const payload of payloads) {\n try {\n await doFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n keepalive: true,\n })\n // GA4 MP returns 2xx (204) for well-formed requests and never\n // asks for client-side retries; transient failures are dropped.\n } catch {\n // Network failure — GA4 MP is fire-and-forget; drop silently.\n }\n }\n },\n }\n}\n", "/**\n * GA4 `client-sdk` adapter — lazy gtag.js.\n *\n * The vendor library is NEVER a hard dependency and is NEVER bundled. On the\n * first delivery the adapter:\n * 1. installs the gtag stub + dataLayer,\n * 2. pushes the Consent Mode default (if a bridge is configured),\n * 3. lazily injects `https://www.googletagmanager.com/gtag/js?id=<id>`\n * via a `<script>` tag (or an injected loader for tests/SSR),\n * 4. runs `gtag('js', Date)` + `gtag('config', <id>, { send_page_view:false })`.\n *\n * Subsequent deliveries map each canonical envelope through the shared mapper\n * and call `gtag('set', 'user_properties', …)` / `gtag('set', { user_id })` /\n * `gtag('event', name, params)`.\n *\n * Consent Mode bridge: `init` pushes `consent: default`; `deliver` is only\n * reached when the router's consent gate already allows this sink, at which\n * point `consent: update` is pushed for the mapped GA4 consent types.\n */\n\nimport type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkInitContext,\n} from '@refraction-ui/analytics'\nimport type { GA4ClientSdkOptions, GtagFn } from './types.js'\nimport { mapEvent } from './mapping.js'\n\nconst DEFAULT_SRC_BASE = 'https://www.googletagmanager.com/gtag/js'\n\ninterface GtagGlobal {\n dataLayer?: unknown[]\n gtag?: GtagFn\n document?: {\n createElement(tag: string): {\n async: boolean\n src: string\n onload: (() => void) | null\n onerror: (() => void) | null\n }\n head?: { appendChild(node: unknown): void }\n getElementsByTagName(tag: string): ArrayLike<{\n parentNode?: { insertBefore(a: unknown, b: unknown): void }\n }>\n }\n}\n\n/** DOM `<script>` injector (browser only). */\nfunction defaultScriptLoader(src: string): Promise<void> {\n const g = globalThis as unknown as GtagGlobal\n const doc = g.document\n if (!doc || typeof doc.createElement !== 'function') {\n return Promise.reject(\n new Error('GA4 client-sdk sink: no DOM to inject gtag.js'),\n )\n }\n return new Promise<void>((resolve, reject) => {\n const el = doc.createElement('script')\n el.async = true\n el.src = src\n el.onload = () => resolve()\n el.onerror = () => reject(new Error('GA4 client-sdk: gtag.js failed'))\n if (doc.head?.appendChild) {\n doc.head.appendChild(el)\n } else {\n const first = doc.getElementsByTagName('script')[0]\n first?.parentNode?.insertBefore(el, first)\n }\n })\n}\n\n/**\n * Create the GA4 gtag.js (`client-sdk`) sink. The vendor script is dynamically\n * loaded on first delivery only — there is no static import of any GA4/gtag\n * library, so `http`-mode consumers never pull this code path.\n */\nexport function createGA4ClientSdkSink(\n options: GA4ClientSdkOptions,\n): AnalyticsSink {\n const {\n measurementId,\n consentCategories = ['analytics'],\n name = 'ga4',\n consentMode,\n } = options\n\n const g = globalThis as unknown as GtagGlobal\n\n let gtag: GtagFn | undefined = options.gtag\n let loaded = false\n let loadPromise: Promise<void> | undefined\n\n function ensureGtagStub(): GtagFn {\n if (gtag) return gtag\n // Standard gtag bootstrap: dataLayer-backed shim available synchronously.\n g.dataLayer = g.dataLayer ?? []\n const dl = g.dataLayer\n const fn: GtagFn = (...args: unknown[]) => {\n dl.push(args)\n }\n g.gtag = g.gtag ?? fn\n gtag = g.gtag\n return gtag\n }\n\n function pushConsentDefault(): void {\n if (!consentMode?.default || !gtag) return\n gtag('consent', 'default', { ...consentMode.default })\n }\n\n function pushConsentUpdate(): void {\n if (!consentMode?.map || !gtag) return\n const update: Record<string, 'granted'> = {}\n // deliver() only runs when the router's consent gate already permits this\n // sink (all consentCategories granted) → reflect that to GA4.\n for (const cat of consentCategories) {\n for (const ga4Type of consentMode.map[cat] ?? []) {\n update[ga4Type] = 'granted'\n }\n }\n if (Object.keys(update).length > 0) {\n gtag('consent', 'update', update)\n }\n }\n\n function ensureLoaded(): Promise<void> {\n if (loaded) return Promise.resolve()\n if (loadPromise) return loadPromise\n\n ensureGtagStub()\n pushConsentDefault()\n\n // App/test supplied its own gtag → never inject a vendor script.\n if (options.gtag) {\n gtag!('js', new Date())\n gtag!('config', measurementId, { send_page_view: false })\n loaded = true\n return Promise.resolve()\n }\n\n const base = options.gtagSrcBase ?? DEFAULT_SRC_BASE\n const src = `${base}?id=${encodeURIComponent(measurementId)}`\n const load = options.scriptLoader ?? defaultScriptLoader\n\n loadPromise = load(src).then(() => {\n gtag!('js', new Date())\n gtag!('config', measurementId, { send_page_view: false })\n loaded = true\n })\n return loadPromise\n }\n\n return {\n name,\n consentCategories,\n\n init(_ctx: SinkInitContext): void {\n // Install the stub + Consent Mode default eagerly so a `consent:\n // default` is in dataLayer before the tag loads. The vendor script\n // itself is still deferred to the first delivery.\n ensureGtagStub()\n pushConsentDefault()\n void _ctx\n },\n\n async deliver(batch: AnalyticsEvent[]): Promise<void> {\n if (batch.length === 0) return\n await ensureLoaded()\n const send = gtag!\n pushConsentUpdate()\n\n for (const ev of batch) {\n const m = mapEvent(ev)\n\n if (m.userId) {\n send('set', { user_id: m.userId })\n }\n if (m.userProperties) {\n const flat: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(m.userProperties)) {\n flat[k] = v.value\n }\n send('set', 'user_properties', flat)\n }\n if (m.event) {\n send('event', m.event.name, m.event.params)\n }\n }\n },\n }\n}\n", "/**\n * `createGA4Sink` — the single entry point. Dispatches on `mode`:\n * - `mode: 'client-sdk'` → lazy gtag.js adapter\n * - `mode: 'http'` (default) → Measurement Protocol adapter, no vendor lib\n *\n * Default is `http` to honour the epic's \"default = protocol adapters (no\n * vendor libs in the browser)\" stance. GA4 is just a sink — register it via\n * `createAnalytics({ sinks: [createGA4Sink(...)] })` or `analytics.addSink`.\n *\n * Both factories are independent modules. The `http` factory has ZERO\n * references to gtag.js / DOM-script code, and the `client-sdk` factory only\n * touches the vendor script lazily (first delivery). Selecting one mode never\n * executes the other's load path; consumers that only ever construct an\n * `http` sink never run any vendor code.\n */\n\nimport type { AnalyticsSink } from '@refraction-ui/analytics'\nimport type { GA4SinkOptions } from './types.js'\nimport { createGA4HttpSink } from './http-sink.js'\nimport { createGA4ClientSdkSink } from './client-sdk-sink.js'\n\nexport function createGA4Sink(options: GA4SinkOptions): AnalyticsSink {\n if (options.mode === 'client-sdk') {\n return createGA4ClientSdkSink(options)\n }\n return createGA4HttpSink(options)\n}\n", "import type { AnalyticsEvent } from '@refraction-ui/analytics'\n\n/**\n * App Insights custom-event payload after mapping the canonical envelope.\n *\n * App Insights splits a custom event's bag into two dictionaries:\n * - `properties` — string-valued dimensions (everything non-numeric)\n * - `measurements`— numeric metrics (queryable/aggregatable in KQL)\n *\n * We additionally surface identity:\n * - `authenticatedUserId` — present iff the envelope has `userId`\n * - `anonymous` — `'true'` when no `userId`, else `'false'` (string for the\n * properties bag; App Insights properties are always strings)\n */\nexport interface AppInsightsEvent {\n /** App Insights custom-event name. */\n name: string\n /** String-valued custom dimensions. */\n properties: Record<string, string>\n /** Numeric custom metrics. */\n measurements: Record<string, number>\n}\n\n/** Track-call name fallback when the envelope omits `event`. */\nconst FALLBACK_TRACK_NAME = 'track'\n\n/**\n * Derive the App Insights custom-event name for a canonical event.\n *\n * - `page` → `Page View: <name|path>` (also routed to `trackPageView` in the\n * client-sdk mode; the name here is the http-mode/event fallback)\n * - `screen`→ `Screen: <name>`\n * - `identify` → `Identify`\n * - `group` → `Group`\n * - `alias` → `Alias`\n * - `track` → the event name (or `track` when absent)\n */\nexport function eventName(ev: AnalyticsEvent): string {\n switch (ev.type) {\n case 'page':\n return `Page View: ${ev.event ?? ev.context.page?.path ?? '(unknown)'}`\n case 'screen':\n return `Screen: ${ev.event ?? '(unknown)'}`\n case 'identify':\n return 'Identify'\n case 'group':\n return 'Group'\n case 'alias':\n return 'Alias'\n case 'track':\n default:\n return ev.event ?? FALLBACK_TRACK_NAME\n }\n}\n\n/** True for finite numbers (App Insights measurements must be finite). */\nfunction isMeasurement(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value)\n}\n\n/**\n * Stringify a non-numeric value for the App Insights `properties` bag, which\n * is string-only. Objects/arrays are JSON-encoded; everything else uses\n * `String()`. `undefined`/`null` keys are skipped by the caller.\n */\nfunction stringify(value: unknown): string {\n if (typeof value === 'string') return value\n if (typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value)\n }\n if (typeof value === 'number') return String(value)\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return String(value)\n }\n}\n\n/**\n * Split an arbitrary bag into App Insights `properties` (strings) and\n * `measurements` (finite numbers), recursively flattening nested objects with\n * dotted keys so KQL queries stay flat (App Insights does not index nested\n * JSON in custom dimensions).\n */\nfunction splitBag(\n bag: Record<string, unknown> | undefined,\n prefix: string,\n properties: Record<string, string>,\n measurements: Record<string, number>,\n): void {\n if (!bag) return\n for (const [key, value] of Object.entries(bag)) {\n if (value === undefined || value === null) continue\n const flatKey = prefix ? `${prefix}.${key}` : key\n if (isMeasurement(value)) {\n measurements[flatKey] = value\n continue\n }\n if (\n typeof value === 'object' &&\n !Array.isArray(value) &&\n value.constructor === Object\n ) {\n splitBag(\n value as Record<string, unknown>,\n flatKey,\n properties,\n measurements,\n )\n continue\n }\n properties[flatKey] = stringify(value)\n }\n}\n\n/**\n * Map a canonical {@link AnalyticsEvent} to an {@link AppInsightsEvent}.\n *\n * Properties bag composition:\n * - canonical context: `app`, `env`, library name/version, page fields\n * - envelope identity/routing: `messageId`, `anonymousId`, `sessionId`,\n * `type`, `groupId?`, `previousId?`, `timestamp`, `schemaVersion`\n * - identity surface: `authenticatedUserId` (iff `userId`), `anonymous`\n * - the event's `properties` and `traits`, numbers → `measurements`\n *\n * The split is stable and lossless: every scalar lands in exactly one of the\n * two dictionaries; nested objects are dot-flattened.\n */\nexport function mapEvent(ev: AnalyticsEvent): AppInsightsEvent {\n const properties: Record<string, string> = {}\n const measurements: Record<string, number> = {}\n\n // Identity → App Insights authenticated/anonymous surface.\n if (ev.userId !== undefined) {\n properties.authenticatedUserId = ev.userId\n properties.anonymous = 'false'\n } else {\n properties.anonymous = 'true'\n }\n\n // Routing / envelope metadata (kept as queryable dimensions).\n properties.messageId = ev.messageId\n properties.anonymousId = ev.anonymousId\n properties.sessionId = ev.sessionId\n properties.eventType = ev.type\n properties.timestamp = ev.timestamp\n measurements.schemaVersion = ev.schemaVersion\n if (ev.groupId !== undefined) properties.groupId = ev.groupId\n if (ev.previousId !== undefined) properties.previousId = ev.previousId\n if (ev.event !== undefined) properties.eventName = ev.event\n\n // Canonical context.\n properties.app = ev.context.app\n properties.env = ev.context.env\n properties.libraryName = ev.context.library.name\n properties.libraryVersion = ev.context.library.version\n if (ev.context.page) {\n splitBag(\n ev.context.page as Record<string, unknown>,\n 'page',\n properties,\n measurements,\n )\n }\n\n // Event payload + identify/group traits.\n splitBag(ev.properties, '', properties, measurements)\n splitBag(ev.traits, '', properties, measurements)\n\n return { name: eventName(ev), properties, measurements }\n}\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkDeliverContext,\n} from '@refraction-ui/analytics'\nimport { mapEvent, eventName } from './mapping.js'\n\n/**\n * Minimal structural shape of the bits of `@microsoft/applicationinsights-web`\n * we use. Declared locally so the vendor lib stays an OPTIONAL peer with NO\n * type-level hard dependency — it is only ever reached via dynamic import.\n */\nexport interface AppInsightsLike {\n loadAppInsights?: () => unknown\n trackEvent: (\n event: { name: string },\n customProperties?: Record<string, unknown>,\n ) => void\n trackPageView: (pageView?: {\n name?: string\n uri?: string\n properties?: Record<string, unknown>\n measurements?: Record<string, number>\n }) => void\n setAuthenticatedUserContext?: (\n authenticatedUserId: string,\n accountId?: string,\n storeInCookie?: boolean,\n ) => void\n clearAuthenticatedUserContext?: () => void\n flush?: (async?: boolean) => void\n}\n\n/** Fan-out mode for the App Insights sink. */\nexport type AppInsightsSinkMode = 'client-sdk' | 'http'\n\ninterface BaseOptions {\n /** Consent categories this sink requires. Default `['analytics']`. */\n consentCategories?: string[]\n /** Stable sink name. Default `'app-insights'`. */\n name?: string\n}\n\n/**\n * `client-sdk` mode — runs in the browser via `@microsoft/applicationinsights-web`.\n *\n * The vendor SDK is loaded **lazily via dynamic import** the first time a\n * batch is delivered, so it never enters the bundle unless this sink is used.\n * Callers may instead inject a ready instance (`appInsights`) or a custom\n * `loadSdk` factory (used by tests with a mock transport — no network).\n */\nexport interface ClientSdkOptions extends BaseOptions {\n mode: 'client-sdk'\n /** App Insights connection string (preferred) or instrumentation key. */\n connectionString?: string\n /** Legacy instrumentation key (used when `connectionString` is absent). */\n instrumentationKey?: string\n /**\n * Pre-constructed App Insights instance. When provided, no dynamic import\n * or `loadAppInsights()` happens — used for DI/testing.\n */\n appInsights?: AppInsightsLike\n /**\n * Custom async SDK factory. Overrides the built-in dynamic import of\n * `@microsoft/applicationinsights-web`. Receives the resolved config.\n */\n loadSdk?: (config: {\n connectionString?: string\n instrumentationKey?: string\n }) => Promise<AppInsightsLike>\n}\n\n/**\n * `http` mode — POSTs to the App Insights `/v2/track` ingestion endpoint.\n * No browser library is loaded; server-relay friendly.\n */\nexport interface HttpOptions extends BaseOptions {\n mode: 'http'\n /** Instrumentation key (iKey) for the ingestion envelope. Required. */\n instrumentationKey: string\n /**\n * Ingestion endpoint base. Default the public global endpoint\n * `https://dc.services.visualstudio.com`. Region endpoints are accepted.\n * Events POST to `{endpoint}/v2/track`.\n */\n endpoint?: string\n /** Injected fetch (defaults to global fetch). */\n fetchImpl?: typeof fetch\n /** Max retries for 429/5xx (exponential backoff). Default 3. */\n maxRetries?: number\n /** Base backoff delay in ms. Default 500. */\n backoffBaseMs?: number\n}\n\nexport type AppInsightsSinkOptions = ClientSdkOptions | HttpOptions\n\nconst DEFAULT_INGEST_ENDPOINT = 'https://dc.services.visualstudio.com'\nconst NO_RETRY = new Set([400, 401, 403, 413])\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms))\n\n// `@microsoft/applicationinsights-web` is an OPTIONAL peer — installed only by\n// consumers who opt into client-sdk mode. The specifier must stay\n// non-statically-analyzable: the meta packages (`@refraction-ui/astro`,\n// `@refraction-ui/react`) re-export this module from their entry, so a literal\n// `import('@microsoft/applicationinsights-web')` makes consumer bundlers\n// (vite/rollup) fail the whole build trying to resolve a package that is not\n// installed — long before tree-shaking can drop the module. Routing the\n// specifier through a const keeps the import runtime-only. (The previous\n// `/* @vite-ignore */` annotation did NOT suffice — vite still resolves\n// literal dynamic-import specifiers in SSR builds.)\nconst appInsightsWebSpecifier = '@microsoft/applicationinsights-web'\n\n/* ------------------------------------------------------------------ */\n/* client-sdk mode */\n/* ------------------------------------------------------------------ */\n\nfunction createClientSdkSink(opts: ClientSdkOptions): AnalyticsSink {\n const name = opts.name ?? 'app-insights'\n let instance: AppInsightsLike | undefined = opts.appInsights\n let loading: Promise<AppInsightsLike> | undefined\n\n async function resolveSdk(): Promise<AppInsightsLike> {\n if (instance) return instance\n if (loading) return loading\n loading = (async () => {\n if (opts.loadSdk) {\n instance = await opts.loadSdk({\n connectionString: opts.connectionString,\n instrumentationKey: opts.instrumentationKey,\n })\n return instance\n }\n // Lazy, dynamic, optional — never a static/hard dependency.\n const mod = (await import(appInsightsWebSpecifier)) as {\n ApplicationInsights: new (cfg: {\n config: {\n connectionString?: string\n instrumentationKey?: string\n }\n }) => AppInsightsLike\n }\n const ai = new mod.ApplicationInsights({\n config: {\n connectionString: opts.connectionString,\n instrumentationKey: opts.instrumentationKey,\n },\n })\n ai.loadAppInsights?.()\n instance = ai\n return ai\n })()\n return loading\n }\n\n let lastAuthUserId: string | undefined\n\n return {\n name,\n consentCategories: opts.consentCategories ?? ['analytics'],\n\n async deliver(batch: AnalyticsEvent[]): Promise<void> {\n if (batch.length === 0) return\n const ai = await resolveSdk()\n\n for (const ev of batch) {\n // Identity → App Insights authenticated-user context.\n if (ev.userId !== undefined && ev.userId !== lastAuthUserId) {\n ai.setAuthenticatedUserContext?.(ev.userId)\n lastAuthUserId = ev.userId\n }\n if (\n ev.type === 'identify' &&\n ev.userId === undefined &&\n lastAuthUserId !== undefined\n ) {\n ai.clearAuthenticatedUserContext?.()\n lastAuthUserId = undefined\n }\n\n const mapped = mapEvent(ev)\n const merged: Record<string, unknown> = {\n ...mapped.properties,\n ...mapped.measurements,\n }\n\n if (ev.type === 'page') {\n ai.trackPageView({\n name: ev.event ?? ev.context.page?.path,\n uri: ev.context.page?.url,\n properties: mapped.properties,\n measurements: mapped.measurements,\n })\n } else {\n ai.trackEvent({ name: mapped.name }, merged)\n }\n }\n },\n\n async flush(): Promise<void> {\n if (instance?.flush) instance.flush(false)\n },\n\n shutdown(): void {\n instance = undefined\n loading = undefined\n lastAuthUserId = undefined\n },\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* http mode — App Insights /v2/track ingestion */\n/* ------------------------------------------------------------------ */\n\ninterface IngestEnvelope {\n name: string\n time: string\n iKey: string\n tags: Record<string, string>\n data: {\n baseType: 'EventData' | 'PageViewData'\n baseData: {\n ver: 2\n name: string\n properties: Record<string, string>\n measurements: Record<string, number>\n }\n }\n}\n\n/**\n * Build an App Insights ingestion envelope (Breeze schema) for one canonical\n * event. `tags` carry session/user/operation correlation; `baseData` carries\n * the custom event with the properties/measurements split.\n */\nexport function buildIngestEnvelope(\n ev: AnalyticsEvent,\n iKey: string,\n): IngestEnvelope {\n const mapped = mapEvent(ev)\n const isPage = ev.type === 'page'\n const tags: Record<string, string> = {\n 'ai.session.id': ev.sessionId,\n 'ai.user.id': ev.anonymousId,\n 'ai.operation.id': ev.messageId,\n 'ai.internal.sdkVersion': `refraction-ui-analytics-app-insights:0.1.0`,\n 'ai.application.ver': ev.context.library.version,\n 'ai.cloud.role': ev.context.app,\n 'ai.cloud.roleInstance': ev.context.env,\n }\n if (ev.userId !== undefined) tags['ai.user.authUserId'] = ev.userId\n\n return {\n name: isPage\n ? 'Microsoft.ApplicationInsights.PageView'\n : 'Microsoft.ApplicationInsights.Event',\n time: ev.timestamp,\n iKey,\n tags,\n data: {\n baseType: isPage ? 'PageViewData' : 'EventData',\n baseData: {\n ver: 2,\n name: isPage ? eventName(ev) : mapped.name,\n properties: mapped.properties,\n measurements: mapped.measurements,\n },\n },\n }\n}\n\nfunction createHttpSink(opts: HttpOptions): AnalyticsSink {\n const name = opts.name ?? 'app-insights'\n const {\n instrumentationKey,\n maxRetries = 3,\n backoffBaseMs = 500,\n } = opts\n const base = (opts.endpoint ?? DEFAULT_INGEST_ENDPOINT).replace(/\\/+$/, '')\n const url = `${base}/v2/track`\n\n const resolveFetch = (): typeof fetch => {\n if (opts.fetchImpl) return opts.fetchImpl\n const f = (globalThis as unknown as { fetch?: typeof fetch }).fetch\n if (!f) throw new Error('No fetch implementation available')\n return f\n }\n\n async function send(body: string): Promise<void> {\n const doFetch = resolveFetch()\n for (let attempt = 0; ; attempt++) {\n let status: number\n try {\n const res = await doFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n keepalive: true,\n })\n status = res.status\n } catch {\n status = 0 // network error → transient\n }\n if (status >= 200 && status < 300) return\n if (NO_RETRY.has(status)) return\n if (attempt >= maxRetries) return\n await sleep(backoffBaseMs * 2 ** attempt)\n }\n }\n\n return {\n name,\n consentCategories: opts.consentCategories ?? ['analytics'],\n\n async deliver(\n batch: AnalyticsEvent[],\n _ctx: SinkDeliverContext,\n ): Promise<void> {\n if (batch.length === 0) return\n const envelopes = batch.map((ev) =>\n buildIngestEnvelope(ev, instrumentationKey),\n )\n // App Insights ingestion accepts a JSON array of envelopes (it also\n // accepts newline-delimited; the array form is the documented batch).\n await send(JSON.stringify(envelopes))\n },\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* factory */\n/* ------------------------------------------------------------------ */\n\n/**\n * Create an Azure Application Insights {@link AnalyticsSink}.\n *\n * Dual-mode:\n * - `client-sdk` — browser, lazy `@microsoft/applicationinsights-web`\n * (`trackEvent` / `trackPageView`); the vendor lib is an OPTIONAL peer\n * loaded only via dynamic import, never a hard/static dependency.\n * - `http` — App Insights `/v2/track` ingestion endpoint; no browser lib,\n * server-relay friendly.\n *\n * Both modes map the canonical envelope to App Insights custom events with a\n * properties/measurements split and surface identity as\n * `authenticatedUserId` / `anonymous`.\n */\nexport function createAppInsightsSink(\n options: AppInsightsSinkOptions,\n): AnalyticsSink {\n return options.mode === 'http'\n ? createHttpSink(options)\n : createClientSdkSink(options)\n}\n", "import type { AnalyticsEvent } from '@refraction-ui/analytics'\n\n/**\n * Canonical envelope → PostHog event mapping.\n *\n * This module is pure (no I/O, no transport) so the http sink and the\n * client-sdk sink share exactly one mapping definition and it can be unit\n * tested in isolation against a mock transport.\n *\n * PostHog identity model:\n * - `distinct_id` is the single id PostHog buckets a person under.\n * - Before `identify`, the anonymous visitor is keyed by `anonymousId`.\n * - `identify` upgrades the person to the opaque app `userId`, sending\n * `$set` traits and an `$anon_distinct_id` so PostHog stitches the\n * pre-identify anonymous history onto the identified person.\n * - `alias` emits PostHog's `$create_alias` linking `previousId` (alias)\n * to the canonical `userId`/`anonymousId` (distinct_id).\n * - `group` emits a `$groupidentify` event with `$group_set` traits.\n *\n * See https://posthog.com/docs/api/capture for the event shape.\n */\n\n/** A single PostHog capture event (the `/capture` and `/batch` item shape). */\nexport interface PostHogEvent {\n /** PostHog event name (Segment names map to `$pageview`/`$screen`/etc.). */\n event: string\n /** The person bucket id. */\n distinct_id: string\n /** Event + person/group properties. */\n properties: Record<string, unknown>\n /** ISO-8601 client timestamp (PostHog corrects for skew server-side). */\n timestamp: string\n /** Idempotency key — PostHog dedupes on this. Mirrors `messageId`. */\n uuid: string\n}\n\n/** Resolve the PostHog `distinct_id` for an envelope. */\nexport function distinctId(ev: AnalyticsEvent): string {\n return ev.userId ?? ev.anonymousId\n}\n\n/**\n * Properties that PostHog reads off `context` for every event so its UI\n * shows app/library/page/session metadata without the consumer wiring it.\n */\nfunction contextProperties(ev: AnalyticsEvent): Record<string, unknown> {\n const ctx = ev.context\n const props: Record<string, unknown> = {\n $lib: ctx.library?.name,\n $lib_version: ctx.library?.version,\n app: ctx.app,\n env: ctx.env,\n $session_id: ev.sessionId,\n // Keep the canonical anonymous id addressable in PostHog too.\n anonymousId: ev.anonymousId,\n }\n const page = ctx.page\n if (page) {\n if (page.url !== undefined) props.$current_url = page.url\n if (page.path !== undefined) props.$pathname = page.path\n if (page.referrer !== undefined) props.$referrer = page.referrer\n if (page.title !== undefined) props.title = page.title\n if (page.search !== undefined) props.$search = page.search\n }\n return props\n}\n\n/**\n * Map one canonical envelope to one PostHog event.\n *\n * `track` → the event name verbatim, `properties` passed through.\n * `page` → `$pageview` (PostHog's built-in pageview).\n * `screen` → `$screen` with `$screen_name`.\n * `identify` → `$identify` with `$set` traits + `$anon_distinct_id` stitch.\n * `group` → `$groupidentify` with `$group_set` traits.\n * `alias` → `$create_alias` linking `previousId` → distinct id.\n */\nexport function toPostHogEvent(ev: AnalyticsEvent): PostHogEvent {\n const base = {\n distinct_id: distinctId(ev),\n timestamp: ev.timestamp,\n uuid: ev.messageId,\n }\n const props = contextProperties(ev)\n\n switch (ev.type) {\n case 'identify': {\n return {\n ...base,\n event: '$identify',\n properties: {\n ...props,\n $set: { ...(ev.traits ?? {}) },\n // Stitch the pre-identify anonymous history onto this person.\n $anon_distinct_id: ev.anonymousId,\n },\n }\n }\n case 'group': {\n const groupType = (ev.properties?.groupType as string) ?? 'company'\n return {\n ...base,\n event: '$groupidentify',\n properties: {\n ...props,\n $group_type: groupType,\n $group_key: ev.groupId,\n $group_set: { ...(ev.traits ?? {}) },\n },\n }\n }\n case 'alias': {\n return {\n ...base,\n event: '$create_alias',\n properties: {\n ...props,\n // PostHog links `alias` to the current `distinct_id`.\n alias: ev.previousId,\n },\n }\n }\n case 'page': {\n return {\n ...base,\n event: '$pageview',\n properties: { ...props, ...(ev.properties ?? {}) },\n }\n }\n case 'screen': {\n return {\n ...base,\n event: '$screen',\n properties: {\n ...props,\n $screen_name: ev.event,\n ...(ev.properties ?? {}),\n },\n }\n }\n case 'track':\n default: {\n return {\n ...base,\n event: ev.event ?? 'track',\n properties: { ...props, ...(ev.properties ?? {}) },\n }\n }\n }\n}\n\n/** Map a batch of canonical envelopes to PostHog events. */\nexport function toPostHogBatch(batch: AnalyticsEvent[]): PostHogEvent[] {\n return batch.map(toPostHogEvent)\n}\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkDeliverContext,\n} from '@refraction-ui/analytics'\nimport { toPostHogBatch } from './mapping.js'\n\n/**\n * PostHog `http` sink — the DEFAULT mode.\n *\n * Talks to PostHog's ingestion API directly over `fetch`; it never loads\n * `posthog-js` or any browser library, so it is server-relay friendly and\n * ad-blocker-proof when fronted by your own endpoint.\n *\n * single event → POST {host}/capture/ { api_key, event, ... }\n * batch → POST {host}/batch/ { api_key, batch: [...] }\n *\n * PostHog accept-and-queue semantics mirror the canonical wire contract:\n * 2xx accepted (queued, not processed) → done\n * 400 malformed → DROP, never retry\n * 401 / 403 bad project key → DROP, never retry\n * 413 payload too big → DROP (we also pre-split under the size caps)\n * 429 / 5xx transient → exponential backoff retry\n * network — → treated as transient → retry\n *\n * No `Authorization` header is used: PostHog authenticates with the public\n * project API key carried in the JSON body, so the `sendBeacon` unload path\n * works without any header juggling.\n */\n\nconst NO_RETRY = new Set([400, 401, 403, 413])\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms))\n\nfunction byteLength(s: string): number {\n const g = globalThis as unknown as {\n TextEncoder?: new () => { encode(s: string): { length: number } }\n }\n if (g.TextEncoder) return new g.TextEncoder().encode(s).length\n return unescape(encodeURIComponent(s)).length\n}\n\nexport interface PostHogHttpSinkOptions {\n /** PostHog project API key (the public, write-only key). */\n apiKey: string\n /**\n * Ingestion host. Default `https://us.i.posthog.com`. Use\n * `https://eu.i.posthog.com`, a self-hosted host, or — recommended for\n * production — your own reverse-proxy/relay path.\n */\n host?: string\n /** Sink name. Default `posthog`. */\n name?: string\n /** Consent categories this sink requires. Default `['analytics']`. */\n consentCategories?: string[]\n /** Max retries for 429/5xx (exponential backoff). Default 3. */\n maxRetries?: number\n /** Base backoff delay in ms. Default 500. */\n backoffBaseMs?: number\n /** Injected fetch (defaults to global fetch). */\n fetchImpl?: typeof fetch\n /** Injected sendBeacon (defaults to navigator.sendBeacon). */\n beaconImpl?: (url: string, body: string) => boolean\n /** Soft per-batch byte cap. PostHog limit ≈ 20MB; default 1MB. */\n maxBatchBytes?: number\n /** Soft per-event byte cap. Default 32KB. */\n maxEventBytes?: number\n}\n\ntype PostHogBatchItem = ReturnType<typeof toPostHogBatch>[number]\n\n/** Split so neither per-event nor per-batch byte caps are exceeded. */\nfunction splitBatch(\n items: PostHogBatchItem[],\n maxBatchBytes: number,\n maxEventBytes: number,\n): PostHogBatchItem[][] {\n const batches: PostHogBatchItem[][] = []\n let current: PostHogBatchItem[] = []\n let currentBytes = 2\n\n for (const item of items) {\n const itemBytes = byteLength(JSON.stringify(item))\n // Oversized single events can never be sent — drop them.\n if (itemBytes > maxEventBytes) continue\n if (current.length && currentBytes + itemBytes + 1 > maxBatchBytes) {\n batches.push(current)\n current = []\n currentBytes = 2\n }\n current.push(item)\n currentBytes += itemBytes + 1\n }\n if (current.length) batches.push(current)\n return batches\n}\n\n/**\n * Create the PostHog `http`-mode sink (default). Pure protocol adapter —\n * no `posthog-js`, safe in Node and the browser.\n */\nexport function createPostHogHttpSink(\n options: PostHogHttpSinkOptions,\n): AnalyticsSink {\n const {\n apiKey,\n host = 'https://us.i.posthog.com',\n name = 'posthog',\n consentCategories = ['analytics'],\n maxRetries = 3,\n backoffBaseMs = 500,\n maxBatchBytes = 1_000_000,\n maxEventBytes = 32_000,\n } = options\n\n const base = host.replace(/\\/+$/, '')\n const captureUrl = `${base}/capture/`\n const batchUrl = `${base}/batch/`\n\n const resolveFetch = (): typeof fetch => {\n if (options.fetchImpl) return options.fetchImpl\n const f = (globalThis as unknown as { fetch?: typeof fetch }).fetch\n if (!f) throw new Error('No fetch implementation available')\n return f\n }\n\n const resolveBeacon = ():\n | ((u: string, body: string) => boolean)\n | undefined => {\n if (options.beaconImpl) return options.beaconImpl\n const nav = (\n globalThis as unknown as {\n navigator?: { sendBeacon?: (u: string, data: BodyInit) => boolean }\n }\n ).navigator\n if (nav && typeof nav.sendBeacon === 'function') {\n return (u, body) => nav.sendBeacon!(u, body)\n }\n return undefined\n }\n\n function payload(part: PostHogBatchItem[]): {\n url: string\n body: string\n } {\n if (part.length === 1) {\n return {\n url: captureUrl,\n body: JSON.stringify({ api_key: apiKey, ...part[0] }),\n }\n }\n return {\n url: batchUrl,\n body: JSON.stringify({ api_key: apiKey, batch: part }),\n }\n }\n\n async function sendViaFetch(part: PostHogBatchItem[]): Promise<void> {\n const doFetch = resolveFetch()\n const { url, body } = payload(part)\n\n for (let attempt = 0; ; attempt++) {\n let status: number\n try {\n const res = await doFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n keepalive: true,\n })\n status = res.status\n } catch {\n status = 0 // network error → transient\n }\n\n if (status >= 200 && status < 300) return\n if (NO_RETRY.has(status)) return\n\n if (attempt >= maxRetries) return\n await sleep(backoffBaseMs * 2 ** attempt)\n }\n }\n\n function sendViaBeacon(part: PostHogBatchItem[]): boolean {\n const beacon = resolveBeacon()\n if (!beacon) return false\n const { url, body } = payload(part)\n return beacon(url, body)\n }\n\n return {\n name,\n consentCategories,\n\n async deliver(\n batch: AnalyticsEvent[],\n ctx: SinkDeliverContext,\n ): Promise<void> {\n if (batch.length === 0) return\n const items = toPostHogBatch(batch)\n const parts = splitBatch(items, maxBatchBytes, maxEventBytes)\n\n for (const part of parts) {\n if (part.length === 0) continue\n if (ctx.unload) {\n if (sendViaBeacon(part)) continue\n void sendViaFetch(part)\n } else {\n await sendViaFetch(part)\n }\n }\n },\n }\n}\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkInitContext,\n} from '@refraction-ui/analytics'\nimport { distinctId } from './mapping.js'\n\n/**\n * PostHog `client-sdk` sink — OPTIONAL, opt-in mode.\n *\n * For client-exclusive PostHog features (autocapture, feature flags,\n * surveys, web experiments) that the protocol API alone cannot drive.\n * `posthog-js` is loaded **lazily via dynamic `import()`** the first time the\n * sink delivers, so a consumer who only uses the default `http` sink never\n * pays the browser-library cost and `posthog-js` stays a fully optional peer.\n *\n * Session replay is deliberately NOT touched here — it lives in the separate\n * `@refraction-ui/analytics-sink-posthog/replay` module so it is never on the\n * event path and tree-shakes out unless explicitly enabled.\n */\n\n/** Minimal structural type for the bits of `posthog-js` we use. */\ninterface PostHogJs {\n init(apiKey: string, options: Record<string, unknown>): void\n capture(event: string, properties?: Record<string, unknown>): void\n identify(distinctId: string, set?: Record<string, unknown>): void\n alias(alias: string, original?: string): void\n group(\n groupType: string,\n groupKey: string,\n properties?: Record<string, unknown>,\n ): void\n reset(): void\n}\n\nexport interface PostHogClientSdkSinkOptions {\n /** PostHog project API key. */\n apiKey: string\n /** PostHog API host. Default `https://us.i.posthog.com`. */\n host?: string\n /** Sink name. Default `posthog`. */\n name?: string\n /** Consent categories this sink requires. Default `['analytics']`. */\n consentCategories?: string[]\n /**\n * Extra `posthog-js` init options. `autocapture`, `capture_pageview`, and\n * `session_recording` default to OFF — the canonical router owns the event\n * path; replay is opt-in via the separate module.\n */\n posthogOptions?: Record<string, unknown>\n /**\n * Injected loader (testing / custom bundling). Defaults to a lazy\n * `import('posthog-js')`.\n */\n loadPostHog?: () => Promise<{ default: PostHogJs } | PostHogJs>\n}\n\n// `posthog-js` is an OPTIONAL peer — installed only by consumers who opt into\n// client-sdk mode. The specifier must stay non-statically-analyzable: the meta\n// packages (`@refraction-ui/astro`, `@refraction-ui/react`) re-export this\n// module from their entry, so a literal `import('posthog-js')` makes consumer\n// bundlers (vite/rollup) fail the whole build trying to resolve a package that\n// is not installed — long before tree-shaking can drop the module. Routing the\n// specifier through a const keeps the import runtime-only. (A `/* @vite-ignore */`\n// annotation does NOT suffice — vite still resolves literal dynamic-import\n// specifiers in SSR builds.)\nconst posthogJsSpecifier = 'posthog-js'\n\nasync function defaultLoad(): Promise<PostHogJs> {\n // Dynamic import keeps `posthog-js` out of the graph until first delivery.\n const mod = (await import(posthogJsSpecifier)) as unknown as\n | { default: PostHogJs }\n | PostHogJs\n return 'default' in mod ? mod.default : mod\n}\n\n/**\n * Create the OPTIONAL PostHog `client-sdk`-mode sink. `posthog-js` is\n * dynamically imported on first use, never at module load.\n */\nexport function createPostHogClientSdkSink(\n options: PostHogClientSdkSinkOptions,\n): AnalyticsSink {\n const {\n apiKey,\n host = 'https://us.i.posthog.com',\n name = 'posthog',\n consentCategories = ['analytics'],\n posthogOptions = {},\n } = options\n\n let ph: PostHogJs | undefined\n let loading: Promise<PostHogJs> | undefined\n\n async function ensure(): Promise<PostHogJs> {\n if (ph) return ph\n if (!loading) {\n const load = options.loadPostHog\n ? async () => {\n const m = await options.loadPostHog!()\n return ('default' in m ? m.default : m) as PostHogJs\n }\n : defaultLoad\n loading = load().then((instance) => {\n instance.init(apiKey, {\n api_host: host,\n // The canonical router owns the event path — disable PostHog's\n // own auto-capture and pageview, and never start replay here.\n autocapture: false,\n capture_pageview: false,\n disable_session_recording: true,\n ...posthogOptions,\n })\n ph = instance\n return instance\n })\n }\n return loading\n }\n\n return {\n name,\n consentCategories,\n\n async init(_ctx: SinkInitContext): Promise<void> {\n // Eagerly warm the SDK so the first event is not delayed. Still lazy\n // relative to module load — only runs once the sink is registered.\n await ensure()\n },\n\n async deliver(batch: AnalyticsEvent[]): Promise<void> {\n if (batch.length === 0) return\n const client = await ensure()\n for (const ev of batch) {\n const did = distinctId(ev)\n switch (ev.type) {\n case 'identify':\n client.identify(did, { ...(ev.traits ?? {}) })\n break\n case 'alias':\n if (ev.previousId) client.alias(ev.previousId, did)\n break\n case 'group':\n client.group(\n (ev.properties?.groupType as string) ?? 'company',\n ev.groupId ?? '',\n { ...(ev.traits ?? {}) },\n )\n break\n case 'page':\n client.capture('$pageview', { ...(ev.properties ?? {}) })\n break\n case 'screen':\n client.capture('$screen', {\n $screen_name: ev.event,\n ...(ev.properties ?? {}),\n })\n break\n case 'track':\n default:\n client.capture(ev.event ?? 'track', { ...(ev.properties ?? {}) })\n break\n }\n }\n },\n\n shutdown(): void {\n ph?.reset()\n },\n }\n}\n", "import type { AnalyticsSink } from '@refraction-ui/analytics'\nimport {\n createPostHogHttpSink,\n type PostHogHttpSinkOptions,\n} from './http-sink.js'\nimport {\n createPostHogClientSdkSink,\n type PostHogClientSdkSinkOptions,\n} from './client-sdk-sink.js'\n\n/** PostHog fan-out mode. `http` is the default (no browser library). */\nexport type PostHogSinkMode = 'http' | 'client-sdk'\n\nexport type PostHogSinkOptions =\n | ({ mode?: 'http' } & PostHogHttpSinkOptions)\n | ({ mode: 'client-sdk' } & PostHogClientSdkSinkOptions)\n\n/**\n * Create a PostHog `AnalyticsSink`.\n *\n * - `mode: 'http'` (DEFAULT) — pure protocol adapter against PostHog's\n * `/capture` + `/batch` API. No `posthog-js`. Server-relay friendly.\n * - `mode: 'client-sdk'` — OPTIONAL. Lazily dynamic-imports `posthog-js`\n * for client-exclusive features. Only loaded if this mode is selected.\n *\n * Session replay is NOT configurable here — import the separate\n * `@refraction-ui/analytics-sink-posthog/replay` module to opt in. It is\n * never on the event path and tree-shakes away when unused.\n */\nexport function createPostHogSink(\n options: PostHogSinkOptions,\n): AnalyticsSink {\n if (options.mode === 'client-sdk') {\n return createPostHogClientSdkSink(options)\n }\n return createPostHogHttpSink(options)\n}\n", "/**\n * @refraction-ui/analytics-sink-posthog/replay\n *\n * OPTIONAL, lazy session-replay (rrweb, via `posthog-js`).\n *\n * Hard guarantees this module exists to enforce:\n *\n * 1. **Off by default.** Nothing in the main `@refraction-ui/analytics-sink-posthog`\n * entry imports this file, so it (and `posthog-js`, and rrweb) are fully\n * tree-shaken out of any bundle that does not explicitly import it.\n * 2. **Never on the event path.** Replay is not an `AnalyticsSink`. It does\n * not see, transform, or block canonical envelopes. `track`/`identify`/…\n * keep flowing through the sink even if replay never starts or fails.\n * 3. **Privacy/consent gated.** `startSessionReplay` refuses to start unless\n * a consent predicate returns true, and re-checks it; `stop()` tears the\n * recorder down. Masking defaults are maximally private.\n * 4. **Lazy.** `posthog-js` is `import()`-ed only when `startSessionReplay`\n * is actually called.\n *\n * This is a thin controller around `posthog-js`'s built-in rrweb session\n * recording — we do not bundle rrweb ourselves.\n */\n\n/** Minimal structural view of the `posthog-js` replay surface. */\ninterface PostHogReplay {\n init(apiKey: string, options: Record<string, unknown>): void\n startSessionRecording(): void\n stopSessionRecording(): void\n sessionRecordingStarted?(): boolean\n}\n\nexport interface SessionReplayOptions {\n /** PostHog project API key. */\n apiKey: string\n /** PostHog API host. Default `https://us.i.posthog.com`. */\n host?: string\n /**\n * Consent predicate. Replay starts ONLY when this returns `true`, and is\n * re-checked by `enforceConsent()`. There is no default-allow: if omitted,\n * replay is treated as NOT consented and will not start.\n */\n hasConsent?: () => boolean\n /**\n * rrweb masking. Defaults are maximally private: all text + all inputs\n * masked. Override deliberately and document the privacy review.\n */\n maskAllText?: boolean\n maskAllInputs?: boolean\n /** Extra `posthog-js` session_recording options (advanced). */\n recordingOptions?: Record<string, unknown>\n /**\n * Injected loader (testing / custom bundling). Defaults to a lazy\n * `import('posthog-js')`.\n */\n loadPostHog?: () => Promise<{ default: PostHogReplay } | PostHogReplay>\n}\n\n/** Handle returned by {@link startSessionReplay}. */\nexport interface SessionReplayHandle {\n /** True if the rrweb recorder is currently running. */\n readonly recording: boolean\n /**\n * Re-evaluate the consent predicate. If consent was revoked, recording is\n * stopped. Call this from your consent-change handler.\n */\n enforceConsent(): void\n /** Stop recording and release the recorder. Idempotent. */\n stop(): void\n}\n\n// `posthog-js` is an OPTIONAL peer — installed only by consumers who opt into\n// session replay. The specifier must stay non-statically-analyzable: the meta\n// packages (`@refraction-ui/astro`, `@refraction-ui/react`) re-export this\n// module from their entry, so a literal `import('posthog-js')` makes consumer\n// bundlers (vite/rollup) fail the whole build trying to resolve a package that\n// is not installed — long before tree-shaking can drop the module. Routing the\n// specifier through a const keeps the import runtime-only.\nconst posthogJsSpecifier = 'posthog-js'\n\nasync function defaultLoad(): Promise<PostHogReplay> {\n const mod = (await import(posthogJsSpecifier)) as unknown as\n | { default: PostHogReplay }\n | PostHogReplay\n return 'default' in mod ? mod.default : mod\n}\n\n/**\n * Start PostHog/rrweb session replay. Resolves to a handle, or to a\n * non-recording handle if consent is not granted (it never throws on the\n * consent path — replay simply does not start).\n *\n * `posthog-js` is dynamically imported here and nowhere else.\n */\nexport async function startSessionReplay(\n options: SessionReplayOptions,\n): Promise<SessionReplayHandle> {\n const {\n apiKey,\n host = 'https://us.i.posthog.com',\n hasConsent,\n maskAllText = true,\n maskAllInputs = true,\n recordingOptions = {},\n } = options\n\n const consented = (): boolean =>\n typeof hasConsent === 'function' ? hasConsent() === true : false\n\n // Single-slot holder so the closure can observe the lazily-loaded\n // instance without an outer `let` rebind.\n const slot: { ph?: PostHogReplay } = {}\n let recording = false\n\n const stop = (): void => {\n if (slot.ph && recording) {\n slot.ph.stopSessionRecording()\n }\n recording = false\n }\n\n const handle: SessionReplayHandle = {\n get recording() {\n return recording\n },\n enforceConsent(): void {\n if (!consented()) stop()\n },\n stop,\n }\n\n // Privacy gate: do not even load posthog-js if consent is absent.\n if (!consented()) return handle\n\n const load = options.loadPostHog\n ? async () => {\n const m = await options.loadPostHog!()\n return ('default' in m ? m.default : m) as PostHogReplay\n }\n : defaultLoad\n\n slot.ph = await load()\n slot.ph.init(apiKey, {\n api_host: host,\n autocapture: false,\n capture_pageview: false,\n // Start with replay disabled, then opt in explicitly below.\n disable_session_recording: true,\n session_recording: {\n maskAllInputs,\n maskTextSelector: maskAllText ? '*' : undefined,\n ...recordingOptions,\n },\n })\n\n // Re-check consent after the (async) load in case it was revoked meanwhile.\n if (!consented()) return handle\n\n slot.ph.startSessionRecording()\n recording = slot.ph.sessionRecordingStarted?.() ?? true\n return handle\n}\n", "import * as React from 'react'\nimport { devWarn } from '@refraction-ui/shared'\nimport { createNoopAnalytics } from '@refraction-ui/analytics'\nimport type {\n Analytics,\n AnalyticsContext as AnalyticsEventContext,\n AnalyticsProperties,\n CallOptions,\n} from '@refraction-ui/analytics'\n\nconst AnalyticsContext = React.createContext<Analytics | null>(null)\n\n/**\n * Shared no-op Analytics used when a hook is called outside an\n * <AnalyticsProvider>. Lazily created once and reused so the reference stays\n * stable. The hooks degrade gracefully (silent no-op) instead of throwing —\n * components instrumented with useAnalytics/useTrackEvent render fine without\n * a provider (tests, standalone); analytics activates when one is mounted.\n */\nlet noopAnalytics: Analytics | null = null\nfunction getNoopAnalytics(): Analytics {\n return (noopAnalytics ??= createNoopAnalytics())\n}\n\nexport interface AnalyticsProviderProps {\n children: React.ReactNode\n /**\n * The `Analytics` instance to expose. Construct it once with\n * `createAnalytics(...)` from `@refraction-ui/analytics`.\n */\n value: Analytics\n}\n\n/**\n * AnalyticsProvider — wraps your app with analytics context.\n *\n * ```tsx\n * <AnalyticsProvider value={createAnalytics({ app: 'my-app', env: 'production' })}>\n * <App />\n * </AnalyticsProvider>\n * ```\n */\nexport function AnalyticsProvider({ children, value }: AnalyticsProviderProps) {\n const analyticsRef = React.useRef<Analytics | null>(null)\n\n if (!analyticsRef.current) {\n analyticsRef.current = value\n }\n\n return React.createElement(\n AnalyticsContext.Provider,\n { value: analyticsRef.current },\n children,\n )\n}\n\nexport interface UseAnalyticsOptions {\n /** When set, returns a `with({ ...scope })` child bound to the context. */\n scope?: Partial<AnalyticsEventContext>\n}\n\n/**\n * useAnalytics — access the `Analytics` instance from context.\n *\n * Pass `{ scope }` to receive a `with(...)` child whose context is merged\n * into every event. If called outside an `<AnalyticsProvider>` it does NOT\n * throw: it returns a shared no-op `Analytics` (a dev-only warn-once hint is\n * emitted). Instrumenting a component with analytics must never crash the\n * host (incl. in tests).\n */\nexport function useAnalytics(options?: UseAnalyticsOptions): Analytics {\n const ctx = React.useContext(AnalyticsContext)\n let base = ctx\n if (!base) {\n devWarn(\n 'react-analytics/use-analytics-outside-provider',\n 'useAnalytics() (or useTrackEvent()) was called outside an <AnalyticsProvider>. Analytics is a no-op here; wrap your app (or the consuming subtree) in <AnalyticsProvider> to enable it.',\n )\n base = getNoopAnalytics()\n }\n const scope = options?.scope\n return React.useMemo<Analytics>(\n () => (scope ? base.with(scope) : base),\n [base, scope],\n )\n}\n\n/**\n * useTrackEvent — a stable, bound `track` for the current context.\n *\n * ```tsx\n * const track = useTrackEvent()\n * track('Signup Clicked', { plan: 'pro' })\n * ```\n */\nexport function useTrackEvent(\n options?: UseAnalyticsOptions,\n): (event: string, properties?: AnalyticsProperties, opts?: CallOptions) => void {\n const analytics = useAnalytics(options)\n return React.useCallback(\n (event: string, properties?: AnalyticsProperties, opts?: CallOptions) =>\n analytics.track(event, properties, opts),\n [analytics],\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * @refraction-ui/analytics — type contracts.\n *\n * The library is a neutral Segment-spec collector/router. The app instruments\n * once via the canonical API; the router fans the canonical envelope out to\n * N pluggable sinks. There is NO privileged engine — every vendor is a sink.\n */\n\n/** Canonical Segment event types. */\nexport type AnalyticsEventType =\n | 'track'\n | 'identify'\n | 'page'\n | 'screen'\n | 'group'\n | 'alias'\n\n/** Schema version stamped onto every envelope and the wire contract path. */\nexport const SCHEMA_VERSION = 1\n\n/** Arbitrary, JSON-serialisable bag of values. */\nexport type AnalyticsProperties = Record<string, unknown>\n\n/**\n * The context block attached to every event. `library` identifies the\n * collector; `app`/`env` identify the product instance.\n */\nexport interface AnalyticsContext {\n app: string\n env: string\n page?: {\n path?: string\n url?: string\n referrer?: string\n title?: string\n search?: string\n }\n library: {\n name: string\n version: string\n }\n /** Free-form additions contributed by `with(context)` children. */\n [key: string]: unknown\n}\n\n/**\n * The canonical Segment envelope. Every sink receives events in exactly this\n * shape; the built-in HTTP sink ships it verbatim over the wire contract.\n */\nexport interface AnalyticsEvent {\n /** Segment call type. */\n type: AnalyticsEventType\n /** Event name (track/screen) or page name (page). */\n event?: string\n /** Idempotency key — backends MUST dedupe on this. */\n messageId: string\n /** Persistent, non-PII, resettable client id. */\n anonymousId: string\n /** Opaque app-supplied id (set after identify). */\n userId?: string\n /** Group id (group calls). */\n groupId?: string\n /** Previous id (alias calls). */\n previousId?: string\n /** Analytics session id (UUIDv4, minted at session start). */\n sessionId: string\n /** track/page/screen/group payload. */\n properties?: AnalyticsProperties\n /** identify/group trait payload. */\n traits?: AnalyticsProperties\n /** Collector + product context. */\n context: AnalyticsContext\n /** ISO-8601 client timestamp. */\n timestamp: string\n /** Envelope schema version. */\n schemaVersion: number\n}\n\n/**\n * Sink SPI — implemented by adapter packages (GA4, Azure, PostHog) and by the\n * built-in HTTP sink. A sink declares the consent categories it requires; the\n * router will not deliver to a sink whose categories are not all granted.\n */\nexport interface AnalyticsSink {\n /** Stable sink identifier. */\n name: string\n /** Consent categories this sink requires (e.g. ['analytics']). */\n consentCategories?: string[]\n /** Called once before the first delivery. */\n init?(ctx: SinkInitContext): void | Promise<void>\n /** Deliver a batch of canonical events. */\n deliver(batch: AnalyticsEvent[], ctx: SinkDeliverContext): void | Promise<void>\n /** Flush any buffered state (best-effort). */\n flush?(): void | Promise<void>\n /** Release resources on reset()/shutdown. */\n shutdown?(): void | Promise<void>\n}\n\n/** Context handed to `sink.init`. */\nexport interface SinkInitContext {\n app: string\n env: string\n endpoint?: string\n}\n\n/** Context handed to every `sink.deliver`. */\nexport interface SinkDeliverContext {\n /** True on the unload path — sinks should prefer sendBeacon. */\n unload: boolean\n}\n\n/** Cross-tab persistence SPI. Defaults pick localStorage/cookie/memory. */\nexport interface AnalyticsStorage {\n get(key: string): string | null\n set(key: string, value: string): void\n remove(key: string): void\n}\n\n/** Session engine configuration. */\nexport interface SessionConfig {\n /** Inactivity timeout in ms before a new session is minted. GA4 = 30min. */\n timeoutMs?: number\n /** Reset the session when a campaign/utm change is detected. */\n resetOnCampaign?: boolean\n /** Persistence backend; defaults to localStorage→cookie→memory. */\n storage?: AnalyticsStorage\n /** Storage key namespace. */\n storageKey?: string\n}\n\n/** Identity engine configuration. */\nexport interface IdentityConfig {\n /** Persistence backend; defaults to localStorage→cookie→memory. */\n storage?: AnalyticsStorage\n /** Storage key namespace. */\n storageKey?: string\n}\n\n/** Consent gate configuration. */\nexport interface ConsentConfig {\n /** Categories granted at boot. */\n granted?: string[]\n /**\n * If true, an event is dropped entirely when NO sink can receive it.\n * If false (default), events are still buffered until consent is granted.\n */\n strict?: boolean\n}\n\n/** Consent gate runtime API. */\nexport interface ConsentAPI {\n grant(...categories: string[]): void\n revoke(...categories: string[]): void\n granted(): string[]\n isGranted(category: string): boolean\n}\n\n/** Session runtime API. */\nexport interface SessionAPI {\n /** Current session id (mints one lazily if none active). */\n id(): string\n /** Force-start a new session, returning the new id. */\n start(): string\n /** End the current session. */\n end(): void\n /** Attach arbitrary session-scoped properties. */\n set(props: AnalyticsProperties): void\n}\n\n/** Built-in HTTP sink options (Segment HTTP Tracking API wire contract). */\nexport interface HttpSinkOptions {\n /** Base endpoint; events POST to `{endpoint}/v{schemaVersion}/batch`. */\n endpoint: string\n /** Write key — sent as `Authorization: Basic base64(writeKey:)`. */\n writeKey: string\n /** Max retries for 429/5xx (exponential backoff). Default 3. */\n maxRetries?: number\n /** Base backoff delay in ms. Default 500. */\n backoffBaseMs?: number\n /** Injected fetch (defaults to global fetch). */\n fetchImpl?: typeof fetch\n /** Injected sendBeacon (defaults to navigator.sendBeacon). */\n beaconImpl?: (url: string, body: string) => boolean\n /** Consent categories this sink requires. Default ['analytics']. */\n consentCategories?: string[]\n /** Soft per-batch byte cap (Segment ≈ 500KB). Default 500_000. */\n maxBatchBytes?: number\n /** Soft per-event byte cap (Segment ≈ 32KB). Default 32_000. */\n maxEventBytes?: number\n /** Clock for the batch `sentAt` stamp. Default: ambient `new Date()` — inject for deterministic tests. */\n now?: () => Date\n}\n\n/** `createAnalytics` configuration. */\nexport interface AnalyticsConfig {\n /** Product/app identifier (stamped into context.app). */\n app: string\n /** Environment, e.g. 'development' | 'production'. Drives presets. */\n env: string\n /** When set, a built-in HTTP sink is auto-registered to this endpoint. */\n endpoint?: string\n /** Write key for the auto-registered HTTP sink. */\n writeKey?: string\n /** Kill switch — when false, a tree-shakeable noop is returned. Default true. */\n enabled?: boolean\n /** 0..1 sampling rate applied per top-level call. Default 1. */\n sampleRate?: number\n /** Extra property/trait keys to redact (in addition to the PII deny-list). */\n redactKeys?: string[]\n /** Explicit sinks (in addition to / instead of the auto HTTP sink). */\n sinks?: AnalyticsSink[]\n /** Session engine config. */\n session?: SessionConfig\n /** Identity engine config. */\n identity?: IdentityConfig\n /** Consent gate config. */\n consent?: ConsentConfig\n /**\n * Force a preset. Defaults: env==='production' → 'prod', else 'dev'.\n * dev = sync + console; prod = batch + sample + beacon flush on unload.\n */\n preset?: 'dev' | 'prod'\n /** Batch size before an automatic flush (prod). Default 20. */\n batchSize?: number\n /** Auto-flush interval in ms (prod). Default 10_000. */\n flushIntervalMs?: number\n /** Clock for default event timestamps. Default: ambient `new Date()` — inject for deterministic tests/SSR. */\n now?: () => Date\n /** RNG for sample-rate decisions. Default: ambient `Math.random` — inject for deterministic tests. */\n random?: () => number\n}\n\n/** Options accepted by every top-level call. */\nexport interface CallOptions {\n /** Per-call timestamp override (ISO-8601). */\n timestamp?: string\n /** Per-call context overrides (shallow-merged). */\n context?: Partial<AnalyticsContext>\n}\n\n/** The public analytics surface returned by `createAnalytics`. */\nexport interface Analytics {\n track(event: string, properties?: AnalyticsProperties, opts?: CallOptions): void\n identify(userId: string, traits?: AnalyticsProperties, opts?: CallOptions): void\n page(name?: string, properties?: AnalyticsProperties, opts?: CallOptions): void\n screen(name?: string, properties?: AnalyticsProperties, opts?: CallOptions): void\n group(groupId: string, traits?: AnalyticsProperties, opts?: CallOptions): void\n alias(userId: string, previousId?: string, opts?: CallOptions): void\n\n /** Analytics-session API (NOT replay). */\n session: SessionAPI\n /** Consent gate API. */\n consent: ConsentAPI\n\n /** Persistent, non-PII anonymous id. */\n anonymousId(): string\n /** Current opaque user id (if identified). */\n userId(): string | undefined\n\n /** Derive a child that merges extra context into every event. */\n with(context: Partial<AnalyticsContext>): Analytics\n\n /** Register an additional sink at runtime. */\n addSink(sink: AnalyticsSink): void\n /** Remove a sink by name. */\n removeSink(name: string): void\n /** Registered sink names. */\n readonly sinks: string[]\n\n /** Flush all sinks (and the internal batch). */\n flush(): Promise<void>\n /**\n * Reset identity + session (privacy-safe logout). Mints a fresh\n * anonymousId and ends the session.\n */\n reset(): void\n /** Whether this is a live collector (false for the noop). */\n readonly enabled: boolean\n}\n", "/**\n * uuidv4 — RFC 4122 version 4 UUID.\n *\n * Prefers `crypto.randomUUID` / `crypto.getRandomValues` when available\n * (browser, modern Node) and degrades to `Math.random` only as a last\n * resort. No external dependency by design (this is the neutral router).\n */\nexport function uuidv4(): string {\n const c: Crypto | undefined =\n typeof globalThis !== 'undefined'\n ? (globalThis.crypto as Crypto | undefined)\n : undefined\n\n if (c && typeof c.randomUUID === 'function') {\n return c.randomUUID()\n }\n\n const bytes = new Uint8Array(16)\n if (c && typeof c.getRandomValues === 'function') {\n c.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n }\n\n // Per RFC 4122 §4.4: set version (4) and variant (10xx) bits.\n bytes[6] = (bytes[6] & 0x0f) | 0x40\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n\n const hex: string[] = []\n for (let i = 0; i < 256; i++) hex.push((i + 0x100).toString(16).slice(1))\n\n return (\n hex[bytes[0]] +\n hex[bytes[1]] +\n hex[bytes[2]] +\n hex[bytes[3]] +\n '-' +\n hex[bytes[4]] +\n hex[bytes[5]] +\n '-' +\n hex[bytes[6]] +\n hex[bytes[7]] +\n '-' +\n hex[bytes[8]] +\n hex[bytes[9]] +\n '-' +\n hex[bytes[10]] +\n hex[bytes[11]] +\n hex[bytes[12]] +\n hex[bytes[13]] +\n hex[bytes[14]] +\n hex[bytes[15]]\n )\n}\n\n/** RFC 4122 v4 shape matcher (case-insensitive). */\nexport const UUID_V4_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n\n/** True when `value` is a well-formed v4 UUID. */\nexport function isUuidV4(value: unknown): value is string {\n return typeof value === 'string' && UUID_V4_RE.test(value)\n}\n", "import type { AnalyticsStorage } from './types.js'\n\n/**\n * Storage adapters.\n *\n * Order of preference for the cross-tab default: localStorage → cookie →\n * in-memory. The package is environment-agnostic; consumers can inject any\n * `AnalyticsStorage` (e.g. an RN AsyncStorage shim) via config.\n */\n\n/** Volatile per-process store (SSR / Node / no-DOM fallback). */\nexport function createMemoryStorage(): AnalyticsStorage {\n const map = new Map<string, string>()\n return {\n get: (k) => (map.has(k) ? (map.get(k) as string) : null),\n set: (k, v) => {\n map.set(k, v)\n },\n remove: (k) => {\n map.delete(k)\n },\n }\n}\n\n/** `window.localStorage` adapter (cross-tab via the storage event). */\nexport function createLocalStorageAdapter(\n ls: Storage,\n): AnalyticsStorage {\n return {\n get: (k) => {\n try {\n return ls.getItem(k)\n } catch {\n return null\n }\n },\n set: (k, v) => {\n try {\n ls.setItem(k, v)\n } catch {\n /* quota / disabled — degrade silently */\n }\n },\n remove: (k) => {\n try {\n ls.removeItem(k)\n } catch {\n /* ignore */\n }\n },\n }\n}\n\ninterface CookieDoc {\n cookie: string\n}\n\n/** `document.cookie` adapter (cross-tab + cross-subdomain capable). */\nexport function createCookieAdapter(\n doc: CookieDoc,\n maxAgeSeconds = 60 * 60 * 24 * 365,\n): AnalyticsStorage {\n const read = (k: string): string | null => {\n const target = encodeURIComponent(k) + '='\n const parts = doc.cookie ? doc.cookie.split(';') : []\n for (const part of parts) {\n const c = part.trim()\n if (c.startsWith(target)) {\n return decodeURIComponent(c.slice(target.length))\n }\n }\n return null\n }\n return {\n get: read,\n set: (k, v) => {\n doc.cookie = `${encodeURIComponent(k)}=${encodeURIComponent(\n v,\n )}; path=/; max-age=${maxAgeSeconds}; SameSite=Lax`\n },\n remove: (k) => {\n doc.cookie = `${encodeURIComponent(k)}=; path=/; max-age=0; SameSite=Lax`\n },\n }\n}\n\n/**\n * Resolve the default storage for the current environment. A caller-supplied\n * storage always wins. Browser → localStorage (falls back to cookie if\n * localStorage throws), otherwise in-memory.\n */\nexport function resolveStorage(\n override?: AnalyticsStorage,\n): AnalyticsStorage {\n if (override) return override\n\n const g = globalThis as unknown as {\n localStorage?: Storage\n document?: CookieDoc\n }\n\n if (g.localStorage) {\n try {\n // Probe — Safari private mode throws on setItem.\n const probe = '__rfx_a_probe__'\n g.localStorage.setItem(probe, '1')\n g.localStorage.removeItem(probe)\n return createLocalStorageAdapter(g.localStorage)\n } catch {\n /* fall through to cookie */\n }\n }\n\n if (g.document && typeof g.document.cookie === 'string') {\n return createCookieAdapter(g.document)\n }\n\n return createMemoryStorage()\n}\n", "import type {\n AnalyticsProperties,\n AnalyticsStorage,\n SessionConfig,\n} from './types.js'\nimport { resolveStorage } from './storage.js'\nimport { uuidv4 } from './uuid.js'\n\n/** GA4 parity: 30 minutes of inactivity ends a session. */\nexport const DEFAULT_SESSION_TIMEOUT_MS = 30 * 60 * 1000\n\nconst DEFAULT_KEY = 'rfx:analytics:session'\n\ninterface PersistedSession {\n id: string\n /** Last activity epoch ms. */\n lastActivity: number\n /** Campaign fingerprint at session start (for campaign-reset). */\n campaign?: string\n /** Session-scoped properties (set via session.set). */\n props?: AnalyticsProperties\n}\n\n/** Recognised campaign params (UTM + common click ids). GA4 parity. */\nconst CAMPAIGN_PARAMS = [\n 'utm_source',\n 'utm_medium',\n 'utm_campaign',\n 'utm_term',\n 'utm_content',\n 'gclid',\n 'fbclid',\n 'msclkid',\n]\n\n/**\n * Derive a stable campaign fingerprint from a URL's query string. A change in\n * this fingerprint (a *new* campaign, not its absence) forces a new session,\n * matching GA4's \"campaign change resets the session\" behaviour.\n */\nexport function campaignFingerprint(search?: string): string | undefined {\n if (!search) return undefined\n let qs = search\n const q = qs.indexOf('?')\n if (q !== -1) qs = qs.slice(q + 1)\n let params: URLSearchParams\n try {\n params = new URLSearchParams(qs)\n } catch {\n return undefined\n }\n const pairs: string[] = []\n for (const p of CAMPAIGN_PARAMS) {\n const v = params.get(p)\n if (v) pairs.push(`${p}=${v}`)\n }\n return pairs.length ? pairs.join('&') : undefined\n}\n\n/**\n * Session engine.\n *\n * A session is a span of continuous activity. It ends after `timeoutMs` of\n * inactivity (GA4 parity, default 30 min) or when a *new* campaign is\n * detected. State is persisted cross-tab so multiple tabs share one session.\n */\nexport function createSession(\n config?: SessionConfig,\n now: () => number = () => Date.now(),\n) {\n const storage: AnalyticsStorage = resolveStorage(config?.storage)\n const key = config?.storageKey ?? DEFAULT_KEY\n const timeoutMs = config?.timeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS\n const resetOnCampaign = config?.resetOnCampaign ?? true\n\n function read(): PersistedSession | null {\n const raw = storage.get(key)\n if (!raw) return null\n try {\n const parsed = JSON.parse(raw) as PersistedSession\n if (parsed && typeof parsed.id === 'string') return parsed\n } catch {\n /* corrupt — treat as none */\n }\n return null\n }\n\n function write(s: PersistedSession): void {\n storage.set(key, JSON.stringify(s))\n }\n\n function mint(campaign?: string): PersistedSession {\n const s: PersistedSession = {\n id: uuidv4(),\n lastActivity: now(),\n campaign,\n }\n write(s)\n return s\n }\n\n /**\n * Return the live session, creating/rotating it as required by the\n * inactivity timeout and (optionally) a campaign change.\n */\n function ensure(campaign?: string): PersistedSession {\n const existing = read()\n const t = now()\n\n if (!existing) return mint(campaign)\n\n // Inactivity timeout.\n if (t - existing.lastActivity > timeoutMs) {\n return mint(campaign)\n }\n\n // Campaign reset — only when a *new* campaign appears.\n if (\n resetOnCampaign &&\n campaign !== undefined &&\n existing.campaign !== campaign\n ) {\n return mint(campaign)\n }\n\n return existing\n }\n\n return {\n /** Get the current session id, rotating if expired. */\n id(campaign?: string): string {\n return ensure(campaign).id\n },\n /** Force a brand-new session. */\n start(campaign?: string): string {\n return mint(campaign).id\n },\n /** End the current session (next id() mints a fresh one). */\n end(): void {\n storage.remove(key)\n },\n /** Touch activity so the inactivity window slides forward. */\n touch(campaign?: string): string {\n const s = ensure(campaign)\n s.lastActivity = now()\n write(s)\n return s.id\n },\n /** Attach/merge session-scoped properties. */\n set(props: AnalyticsProperties): void {\n const s = ensure()\n s.props = { ...(s.props ?? {}), ...props }\n write(s)\n },\n /** Read session-scoped properties (undefined when none). */\n props(): AnalyticsProperties | undefined {\n return read()?.props\n },\n }\n}\n\nexport type Session = ReturnType<typeof createSession>\n", "import type { AnalyticsStorage, IdentityConfig } from './types.js'\nimport { resolveStorage } from './storage.js'\nimport { uuidv4, isUuidV4 } from './uuid.js'\n\nconst DEFAULT_KEY = 'rfx:analytics:anon'\n\n/**\n * Identity engine.\n *\n * - `anonymousId`: persistent, non-PII, resettable UUIDv4 stored cross-tab.\n * - `userId`: opaque, app-supplied; never persisted by the library (the app\n * owns the user record) — kept only in memory for the active page.\n * - `alias`: records a previous→current stitch for the wire envelope.\n */\nexport function createIdentity(config?: IdentityConfig) {\n const storage: AnalyticsStorage = resolveStorage(config?.storage)\n const key = config?.storageKey ?? DEFAULT_KEY\n\n let userId: string | undefined\n\n function loadOrMintAnon(): string {\n const existing = storage.get(key)\n if (isUuidV4(existing)) return existing as string\n const fresh = uuidv4()\n storage.set(key, fresh)\n return fresh\n }\n\n let anonymousId = loadOrMintAnon()\n\n return {\n anonymousId(): string {\n return anonymousId\n },\n userId(): string | undefined {\n return userId\n },\n /** identify(): bind an opaque app user id (no validation, no persistence). */\n setUserId(id: string): void {\n userId = id\n },\n /**\n * alias(): returns the stitch pair for the envelope. `previousId`\n * defaults to the current user or anonymous id.\n */\n alias(nextUserId: string, previousId?: string): { userId: string; previousId: string } {\n const prev = previousId ?? userId ?? anonymousId\n userId = nextUserId\n return { userId: nextUserId, previousId: prev }\n },\n /**\n * reset(): privacy-safe logout. Drops the user binding and mints a brand\n * new anonymousId so the next visitor is not stitched to the old one.\n */\n reset(): string {\n userId = undefined\n anonymousId = uuidv4()\n storage.set(key, anonymousId)\n return anonymousId\n },\n }\n}\n\nexport type Identity = ReturnType<typeof createIdentity>\n", "import type { ConsentAPI, ConsentConfig } from './types.js'\n\n/**\n * Consent gate.\n *\n * Holds the set of granted consent categories. The router asks the gate, per\n * sink, whether *all* of that sink's required categories are granted before\n * delivering. A sink with no declared categories is always allowed (it is the\n * sink author's responsibility to declare what it needs).\n */\nexport function createConsent(config?: ConsentConfig): ConsentAPI & {\n /** True when every required category is granted (empty list ⇒ allowed). */\n allows(required?: string[]): boolean\n /** True when at least one sink could receive (used by strict mode). */\n strict: boolean\n} {\n const granted = new Set<string>(config?.granted ?? [])\n\n return {\n strict: config?.strict ?? false,\n grant(...categories: string[]): void {\n for (const c of categories) granted.add(c)\n },\n revoke(...categories: string[]): void {\n for (const c of categories) granted.delete(c)\n },\n granted(): string[] {\n return [...granted]\n },\n isGranted(category: string): boolean {\n return granted.has(category)\n },\n allows(required?: string[]): boolean {\n if (!required || required.length === 0) return true\n return required.every((c) => granted.has(c))\n },\n }\n}\n\nexport type Consent = ReturnType<typeof createConsent>\n", "import type { AnalyticsProperties } from './types.js'\n\n/**\n * PII redaction.\n *\n * A built-in deny-list of well-known PII key names (email/phone/name and\n * common variants) plus any caller-supplied `redactKeys`. Matching is\n * case-insensitive and substring-based so `userEmail`, `email_address`,\n * `phoneNumber`, `fullName`, etc. are all caught. Redaction recurses into\n * nested objects and arrays so PII cannot hide one level down.\n */\n\n/**\n * Built-in PII deny-list (substring, case-insensitive, separator-insensitive).\n * These match anywhere in a key, so `userEmail`, `email_address`,\n * `phoneNumber`, `firstName`, etc. are all caught.\n */\nexport const PII_DENY_LIST: readonly string[] = [\n 'email',\n 'phone',\n 'mobile',\n 'firstname',\n 'lastname',\n 'fullname',\n 'givenname',\n 'surname',\n 'password',\n 'passwd',\n 'ssn',\n 'creditcard',\n 'cardnumber',\n 'cvv',\n 'dob',\n 'dateofbirth',\n 'address',\n]\n\n/**\n * Keys that are PII only as an *exact* (normalised) match. `name` belongs\n * here so genuine name fields redact while `username`, `eventName`,\n * `fileName`, `firstName`-style compounds (handled by the deny-list) do not\n * over-redact every key that merely contains \"name\".\n */\nexport const PII_EXACT_KEYS: readonly string[] = ['name']\n\n/** Replacement token written in place of a redacted value. */\nexport const REDACTED = '[REDACTED]'\n\nfunction normalize(key: string): string {\n return key.toLowerCase().replace(/[_\\-\\s]/g, '')\n}\n\n/**\n * Build a key matcher from the deny-list + extra keys. `extra` entries match\n * exactly (case-insensitive, normalised); deny-list entries match as\n * substrings.\n */\nexport function createRedactor(extraKeys: string[] = []) {\n const exact = new Set([\n ...extraKeys.map(normalize),\n ...PII_EXACT_KEYS.map(normalize),\n ])\n const deny = PII_DENY_LIST.map(normalize)\n\n const shouldRedact = (key: string): boolean => {\n const n = normalize(key)\n if (exact.has(n)) return true\n return deny.some((d) => n.includes(d))\n }\n\n const walk = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(walk)\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = shouldRedact(k) ? REDACTED : walk(v)\n }\n return out\n }\n return value\n }\n\n return {\n shouldRedact,\n /** Redact a properties/traits bag (returns a new object). */\n redact(props?: AnalyticsProperties): AnalyticsProperties | undefined {\n if (!props) return props\n return walk(props) as AnalyticsProperties\n },\n }\n}\n\nexport type Redactor = ReturnType<typeof createRedactor>\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n HttpSinkOptions,\n SinkDeliverContext,\n} from './types.js'\nimport { SCHEMA_VERSION } from './types.js'\nimport { uuidv4 } from './uuid.js'\n\n/**\n * Built-in `http` sink — Segment HTTP Tracking API wire contract.\n *\n * Wire contract (adopt, do not invent — RudderStack/Jitsu/Segment conform):\n *\n * POST {endpoint}/v{schemaVersion}/batch\n * Content-Type: application/json\n * Authorization: Basic base64(writeKey:) (note the trailing colon)\n * Body: { batch: AnalyticsEvent[], sentAt, batchId }\n *\n * Each event carries `messageId` (idempotency — backends MUST dedupe),\n * `anonymousId`, `userId?`, `sessionId`, `type`, `event?`,\n * `properties`/`traits`, `context`, `timestamp`, `schemaVersion`.\n *\n * Response handling (accept-and-queue semantics):\n * 200 accepted (the backend has only queued it, not processed it)\n * 400 malformed → DROP, never retry\n * 401 bad write key → DROP, never retry\n * 413 payload too big → DROP (we also pre-split under the size caps)\n * 429 / 5xx transient → exponential backoff retry\n *\n * Clock skew: the backend corrects with\n * corrected = timestamp + (receivedAt − sentAt)\n * so we always stamp an honest client `sentAt`.\n *\n * sendBeacon caveat: the unload path (`pagehide`/`visibilitychange`) uses\n * `navigator.sendBeacon`, which cannot set an `Authorization` header. On that\n * path we fall back to `?writeKey=` in the query string with a\n * `text/plain` body (the wire contract requires the backend to accept this).\n */\n\nconst NO_RETRY = new Set([400, 401, 413])\n\nfunction base64(input: string): string {\n const g = globalThis as unknown as {\n btoa?: (s: string) => string\n Buffer?: { from(s: string, enc: string): { toString(enc: string): string } }\n }\n if (typeof g.btoa === 'function') {\n return g.btoa(input)\n }\n if (g.Buffer) {\n return g.Buffer.from(input, 'utf-8').toString('base64')\n }\n throw new Error('No base64 implementation available (btoa/Buffer)')\n}\n\nfunction byteLength(s: string): number {\n const g = globalThis as unknown as {\n TextEncoder?: new () => { encode(s: string): { length: number } }\n }\n if (g.TextEncoder) return new g.TextEncoder().encode(s).length\n // Conservative fallback (UTF-8 worst case is 4 bytes/char; use 3 as typical).\n return unescape(encodeURIComponent(s)).length\n}\n\nconst sleep = (ms: number) =>\n new Promise<void>((r) => setTimeout(r, ms))\n\n/**\n * Split a batch so neither the per-event nor per-batch byte caps are\n * exceeded. Over-sized single events are dropped (they can never be sent).\n */\nfunction splitBatch(\n batch: AnalyticsEvent[],\n maxBatchBytes: number,\n maxEventBytes: number,\n): { batches: AnalyticsEvent[][]; dropped: AnalyticsEvent[] } {\n const batches: AnalyticsEvent[][] = []\n const dropped: AnalyticsEvent[] = []\n let current: AnalyticsEvent[] = []\n let currentBytes = 2 // \"[]\"\n\n for (const ev of batch) {\n const evBytes = byteLength(JSON.stringify(ev))\n if (evBytes > maxEventBytes) {\n dropped.push(ev)\n continue\n }\n if (current.length && currentBytes + evBytes + 1 > maxBatchBytes) {\n batches.push(current)\n current = []\n currentBytes = 2\n }\n current.push(ev)\n currentBytes += evBytes + 1\n }\n if (current.length) batches.push(current)\n return { batches, dropped }\n}\n\n/** Create the built-in Segment-spec HTTP sink. */\nexport function createHttpSink(options: HttpSinkOptions): AnalyticsSink {\n const {\n endpoint,\n writeKey,\n maxRetries = 3,\n backoffBaseMs = 500,\n consentCategories = ['analytics'],\n maxBatchBytes = 500_000,\n maxEventBytes = 32_000,\n } = options\n\n const base = endpoint.replace(/\\/+$/, '')\n const url = `${base}/v${SCHEMA_VERSION}/batch`\n const authHeader = `Basic ${base64(`${writeKey}:`)}`\n // Injection boundary: `sentAt` defaults to ambient time; inject `now` for determinism.\n const now = options.now ?? (() => new Date())\n\n const resolveFetch = (): typeof fetch => {\n if (options.fetchImpl) return options.fetchImpl\n const f = (globalThis as unknown as { fetch?: typeof fetch }).fetch\n if (!f) throw new Error('No fetch implementation available')\n return f\n }\n\n const resolveBeacon = ():\n | ((u: string, body: string) => boolean)\n | undefined => {\n if (options.beaconImpl) return options.beaconImpl\n const nav = (globalThis as unknown as {\n navigator?: { sendBeacon?: (u: string, data: BodyInit) => boolean }\n }).navigator\n if (nav && typeof nav.sendBeacon === 'function') {\n return (u, body) => nav.sendBeacon!(u, body)\n }\n return undefined\n }\n\n function envelope(batch: AnalyticsEvent[]) {\n return {\n batch,\n sentAt: now().toISOString(),\n batchId: uuidv4(),\n }\n }\n\n /** Beacon path: writeKey via query string, text/plain body. */\n function sendViaBeacon(batch: AnalyticsEvent[]): boolean {\n const beacon = resolveBeacon()\n if (!beacon) return false\n const beaconUrl = `${url}?writeKey=${encodeURIComponent(writeKey)}`\n return beacon(beaconUrl, JSON.stringify(envelope(batch)))\n }\n\n /** Standard path: fetch + Authorization header, with backoff retries. */\n async function sendViaFetch(batch: AnalyticsEvent[]): Promise<void> {\n const doFetch = resolveFetch()\n const body = JSON.stringify(envelope(batch))\n\n for (let attempt = 0; ; attempt++) {\n let status: number\n try {\n const res = await doFetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: authHeader,\n },\n body,\n keepalive: true,\n })\n status = res.status\n } catch {\n // Network error — treat as transient.\n status = 0\n }\n\n if (status >= 200 && status < 300) return // accepted-and-queued\n if (NO_RETRY.has(status)) return // 400/401/413 — drop, never retry\n\n // 429 / 5xx / network (0) → backoff retry.\n if (attempt >= maxRetries) return\n const delay = backoffBaseMs * 2 ** attempt\n await sleep(delay)\n }\n }\n\n return {\n name: 'http',\n consentCategories,\n\n async deliver(\n batch: AnalyticsEvent[],\n ctx: SinkDeliverContext,\n ): Promise<void> {\n if (batch.length === 0) return\n const { batches, dropped } = splitBatch(\n batch,\n maxBatchBytes,\n maxEventBytes,\n )\n void dropped // oversized events are unsendable by contract — silently dropped\n\n for (const part of batches) {\n if (ctx.unload) {\n // Unload path: try beacon first; fall back to keepalive fetch.\n if (sendViaBeacon(part)) continue\n void sendViaFetch(part)\n } else {\n await sendViaFetch(part)\n }\n }\n },\n }\n}\n", "import type { AnalyticsEvent, AnalyticsSink } from './types.js'\n\nexport interface ConsoleSinkOptions {\n /** Injected logger (defaults to globalThis.console). */\n logger?: Pick<Console, 'log' | 'groupCollapsed' | 'groupEnd'>\n /** Consent categories this sink requires. Default: none (always allowed). */\n consentCategories?: string[]\n}\n\n/**\n * Built-in `console` sink — the dev preset's default. Prints each canonical\n * envelope so engineers can see exactly what would ship over the wire.\n */\nexport function createConsoleSink(\n options: ConsoleSinkOptions = {},\n): AnalyticsSink {\n const logger =\n options.logger ??\n (globalThis as unknown as { console: Console }).console\n\n return {\n name: 'console',\n consentCategories: options.consentCategories,\n deliver(batch: AnalyticsEvent[]): void {\n for (const ev of batch) {\n const label = `[analytics] ${ev.type}${ev.event ? ` ${ev.event}` : ''}`\n if (typeof logger.groupCollapsed === 'function') {\n logger.groupCollapsed(label)\n logger.log(ev)\n logger.groupEnd?.()\n } else {\n logger.log(label, ev)\n }\n }\n },\n }\n}\n", "import type { Analytics } from './types.js'\n\n/**\n * The noop collector returned when `enabled: false`.\n *\n * Every method is an empty function so calls are free and the surrounding\n * vendor/sink code can be tree-shaken out of a production bundle when\n * analytics is compiled off. Kept in its own module so bundlers can drop the\n * live collector entirely on the `enabled:false` path.\n */\nexport function createNoopAnalytics(): Analytics {\n const sessionId = '00000000-0000-4000-8000-000000000000'\n const noop = (): void => {}\n\n const api: Analytics = {\n track: noop,\n identify: noop,\n page: noop,\n screen: noop,\n group: noop,\n alias: noop,\n session: {\n id: () => sessionId,\n start: () => sessionId,\n end: noop,\n set: noop,\n },\n consent: {\n grant: noop,\n revoke: noop,\n granted: () => [],\n isGranted: () => false,\n },\n anonymousId: () => sessionId,\n userId: () => undefined,\n with: () => api,\n addSink: noop,\n removeSink: noop,\n get sinks() {\n return []\n },\n flush: async () => {},\n reset: noop,\n enabled: false,\n }\n\n return api\n}\n", "import type {\n Analytics,\n AnalyticsConfig,\n AnalyticsContext,\n AnalyticsEvent,\n AnalyticsEventType,\n AnalyticsSink,\n CallOptions,\n SinkDeliverContext,\n} from './types.js'\nimport { SCHEMA_VERSION } from './types.js'\nimport { uuidv4 } from './uuid.js'\nimport { createSession, campaignFingerprint } from './session.js'\nimport { createIdentity } from './identity.js'\nimport { createConsent } from './consent.js'\nimport { createRedactor } from './redaction.js'\nimport { createHttpSink } from './http-sink.js'\nimport { createConsoleSink } from './console-sink.js'\nimport { createNoopAnalytics } from './noop.js'\n\nconst LIBRARY = {\n name: '@refraction-ui/analytics',\n version: '0.1.0',\n}\n\n/** Read the current page block from the DOM, if any (browser-only). */\nfunction readPage(): AnalyticsContext['page'] | undefined {\n const g = globalThis as unknown as {\n location?: { pathname?: string; href?: string; search?: string }\n document?: { title?: string; referrer?: string }\n }\n if (!g.location && !g.document) return undefined\n return {\n path: g.location?.pathname,\n url: g.location?.href,\n search: g.location?.search,\n title: g.document?.title,\n referrer: g.document?.referrer,\n }\n}\n\n/**\n * createAnalytics — the neutral Segment-spec collector/router.\n *\n * Mirrors `createAI`: a single factory returns the entire public surface and\n * fans the canonical envelope out to registered sinks. There is NO privileged\n * engine — the built-in HTTP sink and every vendor adapter are equal sinks.\n *\n * Presets:\n * dev — synchronous delivery + a console sink (see exactly what ships).\n * prod — batching + sampling + beacon flush on pagehide/visibilitychange.\n *\n * When `enabled: false`, a tree-shakeable noop is returned and none of the\n * live collector / sink code is reachable.\n */\nexport function createAnalytics(config: AnalyticsConfig): Analytics {\n if (config.enabled === false) {\n return createNoopAnalytics()\n }\n\n const { app, env } = config\n const preset =\n config.preset ?? (env === 'production' ? 'prod' : 'dev')\n const sampleRate = config.sampleRate ?? 1\n const batchSize = config.batchSize ?? 20\n const flushIntervalMs = config.flushIntervalMs ?? 10_000\n // Injection boundary: ambient time/randomness default here; inject `now`/`random` for determinism.\n const now = config.now ?? (() => new Date())\n const random = config.random ?? (() => Math.random())\n\n const session = createSession(config.session)\n const identity = createIdentity(config.identity)\n const consent = createConsent(config.consent)\n const redactor = createRedactor(config.redactKeys)\n\n // --- Sink registry ------------------------------------------------------\n const sinks = new Map<string, AnalyticsSink>()\n const sinkOrder: string[] = []\n const initialized = new Set<string>()\n\n function registerSink(sink: AnalyticsSink): void {\n if (!sinks.has(sink.name)) sinkOrder.push(sink.name)\n sinks.set(sink.name, sink)\n }\n\n // Auto HTTP sink when an endpoint is supplied.\n if (config.endpoint) {\n registerSink(\n createHttpSink({\n endpoint: config.endpoint,\n writeKey: config.writeKey ?? '',\n // One clock for the whole manager: the auto sink stamps sentAt with it too.\n now,\n }),\n )\n }\n // dev preset → add a console sink for visibility.\n if (preset === 'dev') {\n registerSink(createConsoleSink())\n }\n // Explicit sinks (override same-named built-ins).\n for (const s of config.sinks ?? []) registerSink(s)\n\n /**\n * Initialise a sink at most once. Returns a promise only when the sink's\n * own `init` is async — synchronous sinks stay on the synchronous path so\n * the dev preset delivers without a microtask hop.\n */\n function ensureInit(sink: AnalyticsSink): void | Promise<void> {\n if (initialized.has(sink.name)) return\n initialized.add(sink.name)\n if (sink.init) {\n return sink.init({ app, env, endpoint: config.endpoint })\n }\n }\n\n // --- Batch buffer -------------------------------------------------------\n const buffer: AnalyticsEvent[] = []\n let timer: ReturnType<typeof setInterval> | undefined\n\n function startTimer(): void {\n if (preset !== 'prod' || timer) return\n timer = setInterval(() => {\n void flush(false)\n }, flushIntervalMs)\n // Do not keep a Node process alive purely for the flush timer.\n ;(timer as unknown as { unref?: () => void }).unref?.()\n }\n\n /**\n * Fan a batch out to every consented sink. Stays fully synchronous when all\n * sinks are synchronous (dev preset visibility); returns a promise only if a\n * sink's init/deliver is async.\n */\n function deliverToSinks(\n batch: AnalyticsEvent[],\n unload: boolean,\n ): void | Promise<void> {\n if (batch.length === 0) return\n const ctx: SinkDeliverContext = { unload }\n const pending: Array<Promise<unknown>> = []\n for (const name of sinkOrder) {\n const sink = sinks.get(name)\n if (!sink) continue\n if (!consent.allows(sink.consentCategories)) continue\n const inited = ensureInit(sink)\n if (inited && typeof (inited as Promise<void>).then === 'function') {\n pending.push(\n (inited as Promise<void>).then(() => sink.deliver(batch, ctx)),\n )\n } else {\n const r = sink.deliver(batch, ctx)\n if (r && typeof (r as Promise<void>).then === 'function') {\n pending.push(r as Promise<void>)\n }\n }\n }\n if (pending.length) return Promise.all(pending).then(() => undefined)\n }\n\n async function flush(unload = false): Promise<void> {\n const batch = buffer.splice(0, buffer.length)\n await deliverToSinks(batch, unload)\n for (const name of sinkOrder) {\n const sink = sinks.get(name)\n if (sink?.flush && consent.allows(sink.consentCategories)) {\n await sink.flush()\n }\n }\n }\n\n // --- Unload flush (prod) ------------------------------------------------\n function bindUnload(): void {\n if (preset !== 'prod') return\n const g = globalThis as unknown as {\n addEventListener?: (t: string, h: () => void) => void\n document?: { visibilityState?: string }\n }\n if (typeof g.addEventListener !== 'function') return\n const onUnload = (): void => {\n void deliverToSinks(buffer.splice(0, buffer.length), true)\n }\n g.addEventListener('pagehide', onUnload)\n g.addEventListener('visibilitychange', () => {\n if (g.document?.visibilityState === 'hidden') onUnload()\n })\n }\n\n startTimer()\n bindUnload()\n\n // --- Envelope construction ---------------------------------------------\n function buildContext(\n extra?: Partial<AnalyticsContext>,\n childCtx?: Partial<AnalyticsContext>,\n ): AnalyticsContext {\n const page = readPage()\n return {\n app,\n env,\n ...(page ? { page } : {}),\n ...childCtx,\n ...extra,\n library: LIBRARY,\n }\n }\n\n function sampled(): boolean {\n if (sampleRate >= 1) return true\n if (sampleRate <= 0) return false\n return random() < sampleRate\n }\n\n function enqueue(ev: AnalyticsEvent): void {\n if (preset === 'dev') {\n // Synchronous, unbatched — immediate visibility.\n void deliverToSinks([ev], false)\n return\n }\n buffer.push(ev)\n if (buffer.length >= batchSize) {\n void flush(false)\n }\n }\n\n function emit(\n type: AnalyticsEventType,\n fields: Partial<AnalyticsEvent>,\n childCtx: Partial<AnalyticsContext> | undefined,\n opts?: CallOptions,\n ): void {\n if (!sampled()) return\n\n const page = readPage()\n const campaign = campaignFingerprint(page?.search)\n const sessionId = session.touch(campaign)\n const sessionProps = session.props()\n\n const ev: AnalyticsEvent = {\n type,\n messageId: uuidv4(),\n anonymousId: identity.anonymousId(),\n userId: identity.userId(),\n sessionId,\n context: buildContext(opts?.context, childCtx),\n timestamp: opts?.timestamp ?? now().toISOString(),\n schemaVersion: SCHEMA_VERSION,\n ...fields,\n }\n\n // Merge session-scoped props beneath call props.\n if (sessionProps && (ev.properties || type === 'track' || type === 'page' || type === 'screen')) {\n ev.properties = { ...sessionProps, ...(ev.properties ?? {}) }\n }\n\n enqueue(ev)\n }\n\n function makeApi(childCtx?: Partial<AnalyticsContext>): Analytics {\n const api: Analytics = {\n track(event, properties, opts) {\n emit(\n 'track',\n { event, properties: redactor.redact(properties) },\n childCtx,\n opts,\n )\n },\n\n identify(userId, traits, opts) {\n identity.setUserId(userId)\n emit('identify', { traits: redactor.redact(traits) }, childCtx, opts)\n },\n\n page(name, properties, opts) {\n emit(\n 'page',\n { event: name, properties: redactor.redact(properties) },\n childCtx,\n opts,\n )\n },\n\n screen(name, properties, opts) {\n emit(\n 'screen',\n { event: name, properties: redactor.redact(properties) },\n childCtx,\n opts,\n )\n },\n\n group(groupId, traits, opts) {\n emit(\n 'group',\n { groupId, traits: redactor.redact(traits) },\n childCtx,\n opts,\n )\n },\n\n alias(userId, previousId, opts) {\n const stitch = identity.alias(userId, previousId)\n emit(\n 'alias',\n { userId: stitch.userId, previousId: stitch.previousId },\n childCtx,\n opts,\n )\n },\n\n session: {\n id: () => session.id(),\n start: () => session.start(),\n end: () => session.end(),\n set: (props) => session.set(props),\n },\n\n consent: {\n grant: (...c) => consent.grant(...c),\n revoke: (...c) => consent.revoke(...c),\n granted: () => consent.granted(),\n isGranted: (c) => consent.isGranted(c),\n },\n\n anonymousId: () => identity.anonymousId(),\n userId: () => identity.userId(),\n\n with(extra: Partial<AnalyticsContext>): Analytics {\n return makeApi({ ...childCtx, ...extra })\n },\n\n addSink(sink: AnalyticsSink): void {\n registerSink(sink)\n },\n\n removeSink(name: string): void {\n if (sinks.has(name)) {\n sinks.delete(name)\n const i = sinkOrder.indexOf(name)\n if (i !== -1) sinkOrder.splice(i, 1)\n initialized.delete(name)\n }\n },\n\n get sinks(): string[] {\n return [...sinkOrder]\n },\n\n async flush(): Promise<void> {\n await flush(false)\n },\n\n reset(): void {\n identity.reset()\n session.end()\n },\n\n enabled: true,\n }\n\n return api\n }\n\n return makeApi()\n}\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkDeliverContext,\n SinkInitContext,\n} from './types.js'\n\n/** A mock sink that records every call — used for testing the router. */\nexport interface MockSink extends AnalyticsSink {\n /** All events received across all deliver() calls (flattened). */\n events: AnalyticsEvent[]\n /** Each deliver() call's batch + context. */\n deliveries: Array<{ batch: AnalyticsEvent[]; ctx: SinkDeliverContext }>\n /** init() call contexts. */\n initCalls: SinkInitContext[]\n /** flush() invocation count. */\n flushCalls: number\n /** shutdown() invocation count. */\n shutdownCalls: number\n}\n\nexport interface CreateMockSinkOptions {\n name?: string\n consentCategories?: string[]\n}\n\n/**\n * createMockSink — an `AnalyticsSink` that captures everything for assertion.\n * Mirrors the testing ergonomics of `@refraction-ui/ai`'s mock providers.\n */\nexport function createMockSink(\n options: CreateMockSinkOptions = {},\n): MockSink {\n const sink: MockSink = {\n name: options.name ?? 'mock',\n consentCategories: options.consentCategories,\n events: [],\n deliveries: [],\n initCalls: [],\n flushCalls: 0,\n shutdownCalls: 0,\n\n init(ctx: SinkInitContext): void {\n sink.initCalls.push(ctx)\n },\n\n deliver(batch: AnalyticsEvent[], ctx: SinkDeliverContext): void {\n sink.deliveries.push({ batch, ctx })\n for (const ev of batch) sink.events.push(ev)\n },\n\n flush(): void {\n sink.flushCalls++\n },\n\n shutdown(): void {\n sink.shutdownCalls++\n },\n }\n\n return sink\n}\n", "/**\n * Canonical envelope → GA4 mapping.\n *\n * One mapper, two consumers: the `client-sdk` adapter feeds the result into\n * `gtag('event', name, params)` / `gtag('set', ...)`, and the `http` adapter\n * serialises it into a Measurement Protocol `/mp/collect` payload. Keeping the\n * mapping in one place guarantees the two modes stay behaviourally identical.\n *\n * Identity / param mapping (issue #216, epic #213):\n * anonymousId → client_id (GA4 device/browser id)\n * userId → user_id (GA4 User-ID, cross-device)\n * properties → event params (track/page/screen/group payload)\n * identify → user_properties (traits become GA4 user properties)\n * sessionId → session_id param (so GA4 sessionisation can align)\n *\n * GA4 event-name normalisation: GA4 recommends snake_case event names and\n * forbids spaces. `page` → `page_view`, `screen` → `screen_view` (GA4\n * Enhanced-Measurement parity); everything else is lower_snake_cased.\n */\n\nimport type { AnalyticsEvent, AnalyticsProperties } from '@refraction-ui/analytics'\n\n/** A GA4 event ready for gtag.js or the Measurement Protocol. */\nexport interface GA4Event {\n /** GA4 event name (snake_case, no spaces). */\n name: string\n /** Event params (GA4 caps these; we pass them through verbatim). */\n params: Record<string, unknown>\n}\n\n/** The fully-mapped result for a single canonical envelope. */\nexport interface GA4Mapped {\n /** GA4 client_id (from anonymousId). Always present. */\n clientId: string\n /** GA4 user_id (from userId). Present only after identify. */\n userId?: string\n /**\n * GA4 user_properties (from identify/group traits). Each value is wrapped\n * in `{ value }` as the Measurement Protocol requires; the gtag adapter\n * unwraps when it calls `gtag('set', 'user_properties', ...)`.\n */\n userProperties?: Record<string, { value: unknown }>\n /**\n * The GA4 event to send. `identify` calls carry no event (they only set\n * user_id / user_properties), so this is optional.\n */\n event?: GA4Event\n}\n\nconst GA4_RESERVED_PREFIXES = ['google_', 'ga_', 'firebase_']\n\n/** Lower_snake_case an arbitrary event/trait name for GA4. */\nexport function toGa4Name(name: string): string {\n const snake = name\n .trim()\n .replace(/['\"]/g, '')\n .replace(/[^a-zA-Z0-9]+/g, '_')\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/_+/g, '_')\n .replace(/^_+|_+$/g, '')\n .toLowerCase()\n // GA4 names must start with a letter and avoid reserved prefixes.\n const safe = /^[a-z]/.test(snake) ? snake : `e_${snake}`\n return GA4_RESERVED_PREFIXES.some((p) => safe.startsWith(p))\n ? `x_${safe}`\n : safe\n}\n\n/** Map a Segment call type + name to its GA4 event name. */\nexport function ga4EventName(ev: AnalyticsEvent): string | undefined {\n switch (ev.type) {\n case 'identify':\n // identify only sets identity/user_properties — no event is emitted.\n return undefined\n case 'page':\n return 'page_view'\n case 'screen':\n return 'screen_view'\n case 'group':\n return 'group'\n case 'alias':\n return 'alias'\n case 'track':\n return ev.event ? toGa4Name(ev.event) : 'track'\n default:\n return undefined\n }\n}\n\n/** Wrap traits as GA4 user_properties (`{ name: { value } }`). */\nfunction toUserProperties(\n traits: AnalyticsProperties | undefined,\n): Record<string, { value: unknown }> | undefined {\n if (!traits) return undefined\n const out: Record<string, { value: unknown }> = {}\n let any = false\n for (const [k, v] of Object.entries(traits)) {\n if (v === undefined) continue\n out[toGa4Name(k)] = { value: v }\n any = true\n }\n return any ? out : undefined\n}\n\n/** Build the GA4 event params from a canonical envelope. */\nfunction toParams(ev: AnalyticsEvent): Record<string, unknown> {\n const params: Record<string, unknown> = {}\n\n // Pass through the canonical payload as GA4 params.\n for (const [k, v] of Object.entries(ev.properties ?? {})) {\n if (v === undefined) continue\n params[toGa4Name(k)] = v\n }\n\n // Align GA4 sessionisation with our analytics session.\n params.session_id = ev.sessionId\n // Stable client-supplied de-dupe / debugging aid.\n params.engagement_time_msec = params.engagement_time_msec ?? 1\n\n // page/screen context → GA4 page_* params (Enhanced-Measurement parity).\n const page = ev.context.page\n if (ev.type === 'page' || ev.type === 'screen') {\n if (ev.event) {\n if (ev.type === 'screen') params.screen_name = ev.event\n else params.page_title = params.page_title ?? ev.event\n }\n if (page?.url && params.page_location === undefined) {\n params.page_location = page.url\n }\n if (page?.path && params.page_path === undefined) {\n params.page_path = page.path\n }\n if (page?.referrer && params.page_referrer === undefined) {\n params.page_referrer = page.referrer\n }\n if (page?.title && params.page_title === undefined) {\n params.page_title = page.title\n }\n }\n\n if (ev.type === 'group' && ev.groupId) {\n params.group_id = ev.groupId\n }\n if (ev.type === 'alias') {\n if (ev.userId) params.user_id = ev.userId\n if (ev.previousId) params.previous_id = ev.previousId\n }\n\n return params\n}\n\n/**\n * Map one canonical envelope to its GA4 representation. Pure — no transport,\n * no vendor lib; both the gtag and Measurement-Protocol adapters consume this.\n */\nexport function mapEvent(ev: AnalyticsEvent): GA4Mapped {\n const name = ga4EventName(ev)\n const mapped: GA4Mapped = {\n clientId: ev.anonymousId,\n }\n if (ev.userId) mapped.userId = ev.userId\n\n if (ev.type === 'identify' || ev.type === 'group') {\n const up = toUserProperties(ev.traits)\n if (up) mapped.userProperties = up\n }\n\n if (name) {\n mapped.event = { name, params: toParams(ev) }\n }\n return mapped\n}\n", "/**\n * GA4 `http` adapter — Measurement Protocol (`/mp/collect`).\n *\n * Server-relay friendly: this path NEVER loads gtag.js or any browser\n * library. It only POSTs JSON to the Measurement Protocol endpoint:\n *\n * POST {endpoint}/mp/collect?measurement_id={id}&api_secret={secret}\n * Content-Type: application/json\n * { client_id, user_id?, user_properties?, events: [{ name, params }] }\n *\n * GA4 Measurement Protocol constraints honoured here:\n * - up to 25 events per request → batches are chunked.\n * - `identify` envelopes carry no event; they still POST so user_id /\n * user_properties propagate (events array may be empty for a user-props\n * only ping, which GA4 accepts).\n * - 2xx (incl. 204) = accepted. The MP endpoint always returns 2xx for\n * well-formed requests; the `debug` endpoint returns validation messages.\n */\n\nimport type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkInitContext,\n} from '@refraction-ui/analytics'\nimport type { GA4HttpOptions } from './types.js'\nimport { mapEvent } from './mapping.js'\n\nconst DEFAULT_ENDPOINT = 'https://www.google-analytics.com'\nconst MAX_EVENTS_PER_REQUEST = 25\n\ninterface MPPayload {\n client_id: string\n user_id?: string\n user_properties?: Record<string, { value: unknown }>\n events: Array<{ name: string; params: Record<string, unknown> }>\n}\n\nfunction resolveFetch(opts: GA4HttpOptions): typeof fetch {\n if (opts.fetchImpl) return opts.fetchImpl\n const f = (globalThis as unknown as { fetch?: typeof fetch }).fetch\n if (!f) throw new Error('GA4 http sink: no fetch implementation available')\n return f\n}\n\n/**\n * Group consecutive envelopes by GA4 identity (client_id + user_id) so each\n * Measurement Protocol request carries a single identity, then chunk to the\n * 25-event limit.\n */\nfunction buildPayloads(batch: AnalyticsEvent[]): MPPayload[] {\n const payloads: MPPayload[] = []\n\n for (const ev of batch) {\n const m = mapEvent(ev)\n const last = payloads[payloads.length - 1]\n const sameIdentity =\n last &&\n last.client_id === m.clientId &&\n last.user_id === m.userId &&\n last.events.length < MAX_EVENTS_PER_REQUEST &&\n // user_properties must not silently differ within one request\n JSON.stringify(last.user_properties) ===\n JSON.stringify(m.userProperties)\n\n const target: MPPayload = sameIdentity\n ? last\n : (() => {\n const p: MPPayload = { client_id: m.clientId, events: [] }\n if (m.userId) p.user_id = m.userId\n if (m.userProperties) p.user_properties = m.userProperties\n payloads.push(p)\n return p\n })()\n\n if (m.event) {\n target.events.push(m.event)\n }\n }\n\n // Drop empty payloads that carry neither an event nor user identity\n // signal (nothing to send to GA4).\n return payloads.filter(\n (p) =>\n p.events.length > 0 ||\n p.user_id !== undefined ||\n p.user_properties !== undefined,\n )\n}\n\n/**\n * Create the GA4 Measurement-Protocol (`http`) sink.\n *\n * No vendor library is loaded on this path under any circumstance.\n */\nexport function createGA4HttpSink(options: GA4HttpOptions): AnalyticsSink {\n const {\n measurementId,\n apiSecret,\n consentCategories = ['analytics'],\n name = 'ga4',\n debug = false,\n } = options\n const base = (options.endpoint ?? DEFAULT_ENDPOINT).replace(/\\/+$/, '')\n const path = debug ? '/debug/mp/collect' : '/mp/collect'\n const url =\n `${base}${path}?measurement_id=${encodeURIComponent(measurementId)}` +\n `&api_secret=${encodeURIComponent(apiSecret)}`\n\n return {\n name,\n consentCategories,\n\n init(_ctx: SinkInitContext): void {\n // No-op: the Measurement Protocol is stateless and credential-driven.\n // Explicitly NO vendor script / SDK is loaded here.\n void _ctx\n },\n\n async deliver(batch: AnalyticsEvent[]): Promise<void> {\n if (batch.length === 0) return\n const payloads = buildPayloads(batch)\n if (payloads.length === 0) return\n const doFetch = resolveFetch(options)\n\n for (const payload of payloads) {\n try {\n await doFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n keepalive: true,\n })\n // GA4 MP returns 2xx (204) for well-formed requests and never\n // asks for client-side retries; transient failures are dropped.\n } catch {\n // Network failure — GA4 MP is fire-and-forget; drop silently.\n }\n }\n },\n }\n}\n", "/**\n * GA4 `client-sdk` adapter — lazy gtag.js.\n *\n * The vendor library is NEVER a hard dependency and is NEVER bundled. On the\n * first delivery the adapter:\n * 1. installs the gtag stub + dataLayer,\n * 2. pushes the Consent Mode default (if a bridge is configured),\n * 3. lazily injects `https://www.googletagmanager.com/gtag/js?id=<id>`\n * via a `<script>` tag (or an injected loader for tests/SSR),\n * 4. runs `gtag('js', Date)` + `gtag('config', <id>, { send_page_view:false })`.\n *\n * Subsequent deliveries map each canonical envelope through the shared mapper\n * and call `gtag('set', 'user_properties', …)` / `gtag('set', { user_id })` /\n * `gtag('event', name, params)`.\n *\n * Consent Mode bridge: `init` pushes `consent: default`; `deliver` is only\n * reached when the router's consent gate already allows this sink, at which\n * point `consent: update` is pushed for the mapped GA4 consent types.\n */\n\nimport type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkInitContext,\n} from '@refraction-ui/analytics'\nimport type { GA4ClientSdkOptions, GtagFn } from './types.js'\nimport { mapEvent } from './mapping.js'\n\nconst DEFAULT_SRC_BASE = 'https://www.googletagmanager.com/gtag/js'\n\ninterface GtagGlobal {\n dataLayer?: unknown[]\n gtag?: GtagFn\n document?: {\n createElement(tag: string): {\n async: boolean\n src: string\n onload: (() => void) | null\n onerror: (() => void) | null\n }\n head?: { appendChild(node: unknown): void }\n getElementsByTagName(tag: string): ArrayLike<{\n parentNode?: { insertBefore(a: unknown, b: unknown): void }\n }>\n }\n}\n\n/** DOM `<script>` injector (browser only). */\nfunction defaultScriptLoader(src: string): Promise<void> {\n const g = globalThis as unknown as GtagGlobal\n const doc = g.document\n if (!doc || typeof doc.createElement !== 'function') {\n return Promise.reject(\n new Error('GA4 client-sdk sink: no DOM to inject gtag.js'),\n )\n }\n return new Promise<void>((resolve, reject) => {\n const el = doc.createElement('script')\n el.async = true\n el.src = src\n el.onload = () => resolve()\n el.onerror = () => reject(new Error('GA4 client-sdk: gtag.js failed'))\n if (doc.head?.appendChild) {\n doc.head.appendChild(el)\n } else {\n const first = doc.getElementsByTagName('script')[0]\n first?.parentNode?.insertBefore(el, first)\n }\n })\n}\n\n/**\n * Create the GA4 gtag.js (`client-sdk`) sink. The vendor script is dynamically\n * loaded on first delivery only — there is no static import of any GA4/gtag\n * library, so `http`-mode consumers never pull this code path.\n */\nexport function createGA4ClientSdkSink(\n options: GA4ClientSdkOptions,\n): AnalyticsSink {\n const {\n measurementId,\n consentCategories = ['analytics'],\n name = 'ga4',\n consentMode,\n } = options\n\n const g = globalThis as unknown as GtagGlobal\n\n let gtag: GtagFn | undefined = options.gtag\n let loaded = false\n let loadPromise: Promise<void> | undefined\n\n function ensureGtagStub(): GtagFn {\n if (gtag) return gtag\n // Standard gtag bootstrap: dataLayer-backed shim available synchronously.\n g.dataLayer = g.dataLayer ?? []\n const dl = g.dataLayer\n const fn: GtagFn = (...args: unknown[]) => {\n dl.push(args)\n }\n g.gtag = g.gtag ?? fn\n gtag = g.gtag\n return gtag\n }\n\n function pushConsentDefault(): void {\n if (!consentMode?.default || !gtag) return\n gtag('consent', 'default', { ...consentMode.default })\n }\n\n function pushConsentUpdate(): void {\n if (!consentMode?.map || !gtag) return\n const update: Record<string, 'granted'> = {}\n // deliver() only runs when the router's consent gate already permits this\n // sink (all consentCategories granted) → reflect that to GA4.\n for (const cat of consentCategories) {\n for (const ga4Type of consentMode.map[cat] ?? []) {\n update[ga4Type] = 'granted'\n }\n }\n if (Object.keys(update).length > 0) {\n gtag('consent', 'update', update)\n }\n }\n\n function ensureLoaded(): Promise<void> {\n if (loaded) return Promise.resolve()\n if (loadPromise) return loadPromise\n\n ensureGtagStub()\n pushConsentDefault()\n\n // App/test supplied its own gtag → never inject a vendor script.\n if (options.gtag) {\n gtag!('js', new Date())\n gtag!('config', measurementId, { send_page_view: false })\n loaded = true\n return Promise.resolve()\n }\n\n const base = options.gtagSrcBase ?? DEFAULT_SRC_BASE\n const src = `${base}?id=${encodeURIComponent(measurementId)}`\n const load = options.scriptLoader ?? defaultScriptLoader\n\n loadPromise = load(src).then(() => {\n gtag!('js', new Date())\n gtag!('config', measurementId, { send_page_view: false })\n loaded = true\n })\n return loadPromise\n }\n\n return {\n name,\n consentCategories,\n\n init(_ctx: SinkInitContext): void {\n // Install the stub + Consent Mode default eagerly so a `consent:\n // default` is in dataLayer before the tag loads. The vendor script\n // itself is still deferred to the first delivery.\n ensureGtagStub()\n pushConsentDefault()\n void _ctx\n },\n\n async deliver(batch: AnalyticsEvent[]): Promise<void> {\n if (batch.length === 0) return\n await ensureLoaded()\n const send = gtag!\n pushConsentUpdate()\n\n for (const ev of batch) {\n const m = mapEvent(ev)\n\n if (m.userId) {\n send('set', { user_id: m.userId })\n }\n if (m.userProperties) {\n const flat: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(m.userProperties)) {\n flat[k] = v.value\n }\n send('set', 'user_properties', flat)\n }\n if (m.event) {\n send('event', m.event.name, m.event.params)\n }\n }\n },\n }\n}\n", "/**\n * `createGA4Sink` — the single entry point. Dispatches on `mode`:\n * - `mode: 'client-sdk'` → lazy gtag.js adapter\n * - `mode: 'http'` (default) → Measurement Protocol adapter, no vendor lib\n *\n * Default is `http` to honour the epic's \"default = protocol adapters (no\n * vendor libs in the browser)\" stance. GA4 is just a sink — register it via\n * `createAnalytics({ sinks: [createGA4Sink(...)] })` or `analytics.addSink`.\n *\n * Both factories are independent modules. The `http` factory has ZERO\n * references to gtag.js / DOM-script code, and the `client-sdk` factory only\n * touches the vendor script lazily (first delivery). Selecting one mode never\n * executes the other's load path; consumers that only ever construct an\n * `http` sink never run any vendor code.\n */\n\nimport type { AnalyticsSink } from '@refraction-ui/analytics'\nimport type { GA4SinkOptions } from './types.js'\nimport { createGA4HttpSink } from './http-sink.js'\nimport { createGA4ClientSdkSink } from './client-sdk-sink.js'\n\nexport function createGA4Sink(options: GA4SinkOptions): AnalyticsSink {\n if (options.mode === 'client-sdk') {\n return createGA4ClientSdkSink(options)\n }\n return createGA4HttpSink(options)\n}\n", "import type { AnalyticsEvent } from '@refraction-ui/analytics'\n\n/**\n * App Insights custom-event payload after mapping the canonical envelope.\n *\n * App Insights splits a custom event's bag into two dictionaries:\n * - `properties` — string-valued dimensions (everything non-numeric)\n * - `measurements`— numeric metrics (queryable/aggregatable in KQL)\n *\n * We additionally surface identity:\n * - `authenticatedUserId` — present iff the envelope has `userId`\n * - `anonymous` — `'true'` when no `userId`, else `'false'` (string for the\n * properties bag; App Insights properties are always strings)\n */\nexport interface AppInsightsEvent {\n /** App Insights custom-event name. */\n name: string\n /** String-valued custom dimensions. */\n properties: Record<string, string>\n /** Numeric custom metrics. */\n measurements: Record<string, number>\n}\n\n/** Track-call name fallback when the envelope omits `event`. */\nconst FALLBACK_TRACK_NAME = 'track'\n\n/**\n * Derive the App Insights custom-event name for a canonical event.\n *\n * - `page` → `Page View: <name|path>` (also routed to `trackPageView` in the\n * client-sdk mode; the name here is the http-mode/event fallback)\n * - `screen`→ `Screen: <name>`\n * - `identify` → `Identify`\n * - `group` → `Group`\n * - `alias` → `Alias`\n * - `track` → the event name (or `track` when absent)\n */\nexport function eventName(ev: AnalyticsEvent): string {\n switch (ev.type) {\n case 'page':\n return `Page View: ${ev.event ?? ev.context.page?.path ?? '(unknown)'}`\n case 'screen':\n return `Screen: ${ev.event ?? '(unknown)'}`\n case 'identify':\n return 'Identify'\n case 'group':\n return 'Group'\n case 'alias':\n return 'Alias'\n case 'track':\n default:\n return ev.event ?? FALLBACK_TRACK_NAME\n }\n}\n\n/** True for finite numbers (App Insights measurements must be finite). */\nfunction isMeasurement(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value)\n}\n\n/**\n * Stringify a non-numeric value for the App Insights `properties` bag, which\n * is string-only. Objects/arrays are JSON-encoded; everything else uses\n * `String()`. `undefined`/`null` keys are skipped by the caller.\n */\nfunction stringify(value: unknown): string {\n if (typeof value === 'string') return value\n if (typeof value === 'boolean' || typeof value === 'bigint') {\n return String(value)\n }\n if (typeof value === 'number') return String(value)\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return String(value)\n }\n}\n\n/**\n * Split an arbitrary bag into App Insights `properties` (strings) and\n * `measurements` (finite numbers), recursively flattening nested objects with\n * dotted keys so KQL queries stay flat (App Insights does not index nested\n * JSON in custom dimensions).\n */\nfunction splitBag(\n bag: Record<string, unknown> | undefined,\n prefix: string,\n properties: Record<string, string>,\n measurements: Record<string, number>,\n): void {\n if (!bag) return\n for (const [key, value] of Object.entries(bag)) {\n if (value === undefined || value === null) continue\n const flatKey = prefix ? `${prefix}.${key}` : key\n if (isMeasurement(value)) {\n measurements[flatKey] = value\n continue\n }\n if (\n typeof value === 'object' &&\n !Array.isArray(value) &&\n value.constructor === Object\n ) {\n splitBag(\n value as Record<string, unknown>,\n flatKey,\n properties,\n measurements,\n )\n continue\n }\n properties[flatKey] = stringify(value)\n }\n}\n\n/**\n * Map a canonical {@link AnalyticsEvent} to an {@link AppInsightsEvent}.\n *\n * Properties bag composition:\n * - canonical context: `app`, `env`, library name/version, page fields\n * - envelope identity/routing: `messageId`, `anonymousId`, `sessionId`,\n * `type`, `groupId?`, `previousId?`, `timestamp`, `schemaVersion`\n * - identity surface: `authenticatedUserId` (iff `userId`), `anonymous`\n * - the event's `properties` and `traits`, numbers → `measurements`\n *\n * The split is stable and lossless: every scalar lands in exactly one of the\n * two dictionaries; nested objects are dot-flattened.\n */\nexport function mapEvent(ev: AnalyticsEvent): AppInsightsEvent {\n const properties: Record<string, string> = {}\n const measurements: Record<string, number> = {}\n\n // Identity → App Insights authenticated/anonymous surface.\n if (ev.userId !== undefined) {\n properties.authenticatedUserId = ev.userId\n properties.anonymous = 'false'\n } else {\n properties.anonymous = 'true'\n }\n\n // Routing / envelope metadata (kept as queryable dimensions).\n properties.messageId = ev.messageId\n properties.anonymousId = ev.anonymousId\n properties.sessionId = ev.sessionId\n properties.eventType = ev.type\n properties.timestamp = ev.timestamp\n measurements.schemaVersion = ev.schemaVersion\n if (ev.groupId !== undefined) properties.groupId = ev.groupId\n if (ev.previousId !== undefined) properties.previousId = ev.previousId\n if (ev.event !== undefined) properties.eventName = ev.event\n\n // Canonical context.\n properties.app = ev.context.app\n properties.env = ev.context.env\n properties.libraryName = ev.context.library.name\n properties.libraryVersion = ev.context.library.version\n if (ev.context.page) {\n splitBag(\n ev.context.page as Record<string, unknown>,\n 'page',\n properties,\n measurements,\n )\n }\n\n // Event payload + identify/group traits.\n splitBag(ev.properties, '', properties, measurements)\n splitBag(ev.traits, '', properties, measurements)\n\n return { name: eventName(ev), properties, measurements }\n}\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkDeliverContext,\n} from '@refraction-ui/analytics'\nimport { mapEvent, eventName } from './mapping.js'\n\n/**\n * Minimal structural shape of the bits of `@microsoft/applicationinsights-web`\n * we use. Declared locally so the vendor lib stays an OPTIONAL peer with NO\n * type-level hard dependency — it is only ever reached via dynamic import.\n */\nexport interface AppInsightsLike {\n loadAppInsights?: () => unknown\n trackEvent: (\n event: { name: string },\n customProperties?: Record<string, unknown>,\n ) => void\n trackPageView: (pageView?: {\n name?: string\n uri?: string\n properties?: Record<string, unknown>\n measurements?: Record<string, number>\n }) => void\n setAuthenticatedUserContext?: (\n authenticatedUserId: string,\n accountId?: string,\n storeInCookie?: boolean,\n ) => void\n clearAuthenticatedUserContext?: () => void\n flush?: (async?: boolean) => void\n}\n\n/** Fan-out mode for the App Insights sink. */\nexport type AppInsightsSinkMode = 'client-sdk' | 'http'\n\ninterface BaseOptions {\n /** Consent categories this sink requires. Default `['analytics']`. */\n consentCategories?: string[]\n /** Stable sink name. Default `'app-insights'`. */\n name?: string\n}\n\n/**\n * `client-sdk` mode — runs in the browser via `@microsoft/applicationinsights-web`.\n *\n * The vendor SDK is loaded **lazily via dynamic import** the first time a\n * batch is delivered, so it never enters the bundle unless this sink is used.\n * Callers may instead inject a ready instance (`appInsights`) or a custom\n * `loadSdk` factory (used by tests with a mock transport — no network).\n */\nexport interface ClientSdkOptions extends BaseOptions {\n mode: 'client-sdk'\n /** App Insights connection string (preferred) or instrumentation key. */\n connectionString?: string\n /** Legacy instrumentation key (used when `connectionString` is absent). */\n instrumentationKey?: string\n /**\n * Pre-constructed App Insights instance. When provided, no dynamic import\n * or `loadAppInsights()` happens — used for DI/testing.\n */\n appInsights?: AppInsightsLike\n /**\n * Custom async SDK factory. Overrides the built-in dynamic import of\n * `@microsoft/applicationinsights-web`. Receives the resolved config.\n */\n loadSdk?: (config: {\n connectionString?: string\n instrumentationKey?: string\n }) => Promise<AppInsightsLike>\n}\n\n/**\n * `http` mode — POSTs to the App Insights `/v2/track` ingestion endpoint.\n * No browser library is loaded; server-relay friendly.\n */\nexport interface HttpOptions extends BaseOptions {\n mode: 'http'\n /** Instrumentation key (iKey) for the ingestion envelope. Required. */\n instrumentationKey: string\n /**\n * Ingestion endpoint base. Default the public global endpoint\n * `https://dc.services.visualstudio.com`. Region endpoints are accepted.\n * Events POST to `{endpoint}/v2/track`.\n */\n endpoint?: string\n /** Injected fetch (defaults to global fetch). */\n fetchImpl?: typeof fetch\n /** Max retries for 429/5xx (exponential backoff). Default 3. */\n maxRetries?: number\n /** Base backoff delay in ms. Default 500. */\n backoffBaseMs?: number\n}\n\nexport type AppInsightsSinkOptions = ClientSdkOptions | HttpOptions\n\nconst DEFAULT_INGEST_ENDPOINT = 'https://dc.services.visualstudio.com'\nconst NO_RETRY = new Set([400, 401, 403, 413])\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms))\n\n// `@microsoft/applicationinsights-web` is an OPTIONAL peer — installed only by\n// consumers who opt into client-sdk mode. The specifier must stay\n// non-statically-analyzable: the meta packages (`@refraction-ui/astro`,\n// `@refraction-ui/react`) re-export this module from their entry, so a literal\n// `import('@microsoft/applicationinsights-web')` makes consumer bundlers\n// (vite/rollup) fail the whole build trying to resolve a package that is not\n// installed — long before tree-shaking can drop the module. Routing the\n// specifier through a const keeps the import runtime-only. (The previous\n// `/* @vite-ignore */` annotation did NOT suffice — vite still resolves\n// literal dynamic-import specifiers in SSR builds.)\nconst appInsightsWebSpecifier = '@microsoft/applicationinsights-web'\n\n/* ------------------------------------------------------------------ */\n/* client-sdk mode */\n/* ------------------------------------------------------------------ */\n\nfunction createClientSdkSink(opts: ClientSdkOptions): AnalyticsSink {\n const name = opts.name ?? 'app-insights'\n let instance: AppInsightsLike | undefined = opts.appInsights\n let loading: Promise<AppInsightsLike> | undefined\n\n async function resolveSdk(): Promise<AppInsightsLike> {\n if (instance) return instance\n if (loading) return loading\n loading = (async () => {\n if (opts.loadSdk) {\n instance = await opts.loadSdk({\n connectionString: opts.connectionString,\n instrumentationKey: opts.instrumentationKey,\n })\n return instance\n }\n // Lazy, dynamic, optional — never a static/hard dependency.\n const mod = (await import(/* webpackIgnore: true */ /* @vite-ignore */ appInsightsWebSpecifier)) as {\n ApplicationInsights: new (cfg: {\n config: {\n connectionString?: string\n instrumentationKey?: string\n }\n }) => AppInsightsLike\n }\n const ai = new mod.ApplicationInsights({\n config: {\n connectionString: opts.connectionString,\n instrumentationKey: opts.instrumentationKey,\n },\n })\n ai.loadAppInsights?.()\n instance = ai\n return ai\n })()\n return loading\n }\n\n let lastAuthUserId: string | undefined\n\n return {\n name,\n consentCategories: opts.consentCategories ?? ['analytics'],\n\n async deliver(batch: AnalyticsEvent[]): Promise<void> {\n if (batch.length === 0) return\n const ai = await resolveSdk()\n\n for (const ev of batch) {\n // Identity → App Insights authenticated-user context.\n if (ev.userId !== undefined && ev.userId !== lastAuthUserId) {\n ai.setAuthenticatedUserContext?.(ev.userId)\n lastAuthUserId = ev.userId\n }\n if (\n ev.type === 'identify' &&\n ev.userId === undefined &&\n lastAuthUserId !== undefined\n ) {\n ai.clearAuthenticatedUserContext?.()\n lastAuthUserId = undefined\n }\n\n const mapped = mapEvent(ev)\n const merged: Record<string, unknown> = {\n ...mapped.properties,\n ...mapped.measurements,\n }\n\n if (ev.type === 'page') {\n ai.trackPageView({\n name: ev.event ?? ev.context.page?.path,\n uri: ev.context.page?.url,\n properties: mapped.properties,\n measurements: mapped.measurements,\n })\n } else {\n ai.trackEvent({ name: mapped.name }, merged)\n }\n }\n },\n\n async flush(): Promise<void> {\n if (instance?.flush) instance.flush(false)\n },\n\n shutdown(): void {\n instance = undefined\n loading = undefined\n lastAuthUserId = undefined\n },\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* http mode — App Insights /v2/track ingestion */\n/* ------------------------------------------------------------------ */\n\ninterface IngestEnvelope {\n name: string\n time: string\n iKey: string\n tags: Record<string, string>\n data: {\n baseType: 'EventData' | 'PageViewData'\n baseData: {\n ver: 2\n name: string\n properties: Record<string, string>\n measurements: Record<string, number>\n }\n }\n}\n\n/**\n * Build an App Insights ingestion envelope (Breeze schema) for one canonical\n * event. `tags` carry session/user/operation correlation; `baseData` carries\n * the custom event with the properties/measurements split.\n */\nexport function buildIngestEnvelope(\n ev: AnalyticsEvent,\n iKey: string,\n): IngestEnvelope {\n const mapped = mapEvent(ev)\n const isPage = ev.type === 'page'\n const tags: Record<string, string> = {\n 'ai.session.id': ev.sessionId,\n 'ai.user.id': ev.anonymousId,\n 'ai.operation.id': ev.messageId,\n 'ai.internal.sdkVersion': `refraction-ui-analytics-app-insights:0.1.0`,\n 'ai.application.ver': ev.context.library.version,\n 'ai.cloud.role': ev.context.app,\n 'ai.cloud.roleInstance': ev.context.env,\n }\n if (ev.userId !== undefined) tags['ai.user.authUserId'] = ev.userId\n\n return {\n name: isPage\n ? 'Microsoft.ApplicationInsights.PageView'\n : 'Microsoft.ApplicationInsights.Event',\n time: ev.timestamp,\n iKey,\n tags,\n data: {\n baseType: isPage ? 'PageViewData' : 'EventData',\n baseData: {\n ver: 2,\n name: isPage ? eventName(ev) : mapped.name,\n properties: mapped.properties,\n measurements: mapped.measurements,\n },\n },\n }\n}\n\nfunction createHttpSink(opts: HttpOptions): AnalyticsSink {\n const name = opts.name ?? 'app-insights'\n const {\n instrumentationKey,\n maxRetries = 3,\n backoffBaseMs = 500,\n } = opts\n const base = (opts.endpoint ?? DEFAULT_INGEST_ENDPOINT).replace(/\\/+$/, '')\n const url = `${base}/v2/track`\n\n const resolveFetch = (): typeof fetch => {\n if (opts.fetchImpl) return opts.fetchImpl\n const f = (globalThis as unknown as { fetch?: typeof fetch }).fetch\n if (!f) throw new Error('No fetch implementation available')\n return f\n }\n\n async function send(body: string): Promise<void> {\n const doFetch = resolveFetch()\n for (let attempt = 0; ; attempt++) {\n let status: number\n try {\n const res = await doFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n keepalive: true,\n })\n status = res.status\n } catch {\n status = 0 // network error → transient\n }\n if (status >= 200 && status < 300) return\n if (NO_RETRY.has(status)) return\n if (attempt >= maxRetries) return\n await sleep(backoffBaseMs * 2 ** attempt)\n }\n }\n\n return {\n name,\n consentCategories: opts.consentCategories ?? ['analytics'],\n\n async deliver(\n batch: AnalyticsEvent[],\n _ctx: SinkDeliverContext,\n ): Promise<void> {\n if (batch.length === 0) return\n const envelopes = batch.map((ev) =>\n buildIngestEnvelope(ev, instrumentationKey),\n )\n // App Insights ingestion accepts a JSON array of envelopes (it also\n // accepts newline-delimited; the array form is the documented batch).\n await send(JSON.stringify(envelopes))\n },\n }\n}\n\n/* ------------------------------------------------------------------ */\n/* factory */\n/* ------------------------------------------------------------------ */\n\n/**\n * Create an Azure Application Insights {@link AnalyticsSink}.\n *\n * Dual-mode:\n * - `client-sdk` — browser, lazy `@microsoft/applicationinsights-web`\n * (`trackEvent` / `trackPageView`); the vendor lib is an OPTIONAL peer\n * loaded only via dynamic import, never a hard/static dependency.\n * - `http` — App Insights `/v2/track` ingestion endpoint; no browser lib,\n * server-relay friendly.\n *\n * Both modes map the canonical envelope to App Insights custom events with a\n * properties/measurements split and surface identity as\n * `authenticatedUserId` / `anonymous`.\n */\nexport function createAppInsightsSink(\n options: AppInsightsSinkOptions,\n): AnalyticsSink {\n return options.mode === 'http'\n ? createHttpSink(options)\n : createClientSdkSink(options)\n}\n", "import type { AnalyticsEvent } from '@refraction-ui/analytics'\n\n/**\n * Canonical envelope → PostHog event mapping.\n *\n * This module is pure (no I/O, no transport) so the http sink and the\n * client-sdk sink share exactly one mapping definition and it can be unit\n * tested in isolation against a mock transport.\n *\n * PostHog identity model:\n * - `distinct_id` is the single id PostHog buckets a person under.\n * - Before `identify`, the anonymous visitor is keyed by `anonymousId`.\n * - `identify` upgrades the person to the opaque app `userId`, sending\n * `$set` traits and an `$anon_distinct_id` so PostHog stitches the\n * pre-identify anonymous history onto the identified person.\n * - `alias` emits PostHog's `$create_alias` linking `previousId` (alias)\n * to the canonical `userId`/`anonymousId` (distinct_id).\n * - `group` emits a `$groupidentify` event with `$group_set` traits.\n *\n * See https://posthog.com/docs/api/capture for the event shape.\n */\n\n/** A single PostHog capture event (the `/capture` and `/batch` item shape). */\nexport interface PostHogEvent {\n /** PostHog event name (Segment names map to `$pageview`/`$screen`/etc.). */\n event: string\n /** The person bucket id. */\n distinct_id: string\n /** Event + person/group properties. */\n properties: Record<string, unknown>\n /** ISO-8601 client timestamp (PostHog corrects for skew server-side). */\n timestamp: string\n /** Idempotency key — PostHog dedupes on this. Mirrors `messageId`. */\n uuid: string\n}\n\n/** Resolve the PostHog `distinct_id` for an envelope. */\nexport function distinctId(ev: AnalyticsEvent): string {\n return ev.userId ?? ev.anonymousId\n}\n\n/**\n * Properties that PostHog reads off `context` for every event so its UI\n * shows app/library/page/session metadata without the consumer wiring it.\n */\nfunction contextProperties(ev: AnalyticsEvent): Record<string, unknown> {\n const ctx = ev.context\n const props: Record<string, unknown> = {\n $lib: ctx.library?.name,\n $lib_version: ctx.library?.version,\n app: ctx.app,\n env: ctx.env,\n $session_id: ev.sessionId,\n // Keep the canonical anonymous id addressable in PostHog too.\n anonymousId: ev.anonymousId,\n }\n const page = ctx.page\n if (page) {\n if (page.url !== undefined) props.$current_url = page.url\n if (page.path !== undefined) props.$pathname = page.path\n if (page.referrer !== undefined) props.$referrer = page.referrer\n if (page.title !== undefined) props.title = page.title\n if (page.search !== undefined) props.$search = page.search\n }\n return props\n}\n\n/**\n * Map one canonical envelope to one PostHog event.\n *\n * `track` → the event name verbatim, `properties` passed through.\n * `page` → `$pageview` (PostHog's built-in pageview).\n * `screen` → `$screen` with `$screen_name`.\n * `identify` → `$identify` with `$set` traits + `$anon_distinct_id` stitch.\n * `group` → `$groupidentify` with `$group_set` traits.\n * `alias` → `$create_alias` linking `previousId` → distinct id.\n */\nexport function toPostHogEvent(ev: AnalyticsEvent): PostHogEvent {\n const base = {\n distinct_id: distinctId(ev),\n timestamp: ev.timestamp,\n uuid: ev.messageId,\n }\n const props = contextProperties(ev)\n\n switch (ev.type) {\n case 'identify': {\n return {\n ...base,\n event: '$identify',\n properties: {\n ...props,\n $set: { ...(ev.traits ?? {}) },\n // Stitch the pre-identify anonymous history onto this person.\n $anon_distinct_id: ev.anonymousId,\n },\n }\n }\n case 'group': {\n const groupType = (ev.properties?.groupType as string) ?? 'company'\n return {\n ...base,\n event: '$groupidentify',\n properties: {\n ...props,\n $group_type: groupType,\n $group_key: ev.groupId,\n $group_set: { ...(ev.traits ?? {}) },\n },\n }\n }\n case 'alias': {\n return {\n ...base,\n event: '$create_alias',\n properties: {\n ...props,\n // PostHog links `alias` to the current `distinct_id`.\n alias: ev.previousId,\n },\n }\n }\n case 'page': {\n return {\n ...base,\n event: '$pageview',\n properties: { ...props, ...(ev.properties ?? {}) },\n }\n }\n case 'screen': {\n return {\n ...base,\n event: '$screen',\n properties: {\n ...props,\n $screen_name: ev.event,\n ...(ev.properties ?? {}),\n },\n }\n }\n case 'track':\n default: {\n return {\n ...base,\n event: ev.event ?? 'track',\n properties: { ...props, ...(ev.properties ?? {}) },\n }\n }\n }\n}\n\n/** Map a batch of canonical envelopes to PostHog events. */\nexport function toPostHogBatch(batch: AnalyticsEvent[]): PostHogEvent[] {\n return batch.map(toPostHogEvent)\n}\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkDeliverContext,\n} from '@refraction-ui/analytics'\nimport { toPostHogBatch } from './mapping.js'\n\n/**\n * PostHog `http` sink — the DEFAULT mode.\n *\n * Talks to PostHog's ingestion API directly over `fetch`; it never loads\n * `posthog-js` or any browser library, so it is server-relay friendly and\n * ad-blocker-proof when fronted by your own endpoint.\n *\n * single event → POST {host}/capture/ { api_key, event, ... }\n * batch → POST {host}/batch/ { api_key, batch: [...] }\n *\n * PostHog accept-and-queue semantics mirror the canonical wire contract:\n * 2xx accepted (queued, not processed) → done\n * 400 malformed → DROP, never retry\n * 401 / 403 bad project key → DROP, never retry\n * 413 payload too big → DROP (we also pre-split under the size caps)\n * 429 / 5xx transient → exponential backoff retry\n * network — → treated as transient → retry\n *\n * No `Authorization` header is used: PostHog authenticates with the public\n * project API key carried in the JSON body, so the `sendBeacon` unload path\n * works without any header juggling.\n */\n\nconst NO_RETRY = new Set([400, 401, 403, 413])\n\nconst sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms))\n\nfunction byteLength(s: string): number {\n const g = globalThis as unknown as {\n TextEncoder?: new () => { encode(s: string): { length: number } }\n }\n if (g.TextEncoder) return new g.TextEncoder().encode(s).length\n return unescape(encodeURIComponent(s)).length\n}\n\nexport interface PostHogHttpSinkOptions {\n /** PostHog project API key (the public, write-only key). */\n apiKey: string\n /**\n * Ingestion host. Default `https://us.i.posthog.com`. Use\n * `https://eu.i.posthog.com`, a self-hosted host, or — recommended for\n * production — your own reverse-proxy/relay path.\n */\n host?: string\n /** Sink name. Default `posthog`. */\n name?: string\n /** Consent categories this sink requires. Default `['analytics']`. */\n consentCategories?: string[]\n /** Max retries for 429/5xx (exponential backoff). Default 3. */\n maxRetries?: number\n /** Base backoff delay in ms. Default 500. */\n backoffBaseMs?: number\n /** Injected fetch (defaults to global fetch). */\n fetchImpl?: typeof fetch\n /** Injected sendBeacon (defaults to navigator.sendBeacon). */\n beaconImpl?: (url: string, body: string) => boolean\n /** Soft per-batch byte cap. PostHog limit ≈ 20MB; default 1MB. */\n maxBatchBytes?: number\n /** Soft per-event byte cap. Default 32KB. */\n maxEventBytes?: number\n}\n\ntype PostHogBatchItem = ReturnType<typeof toPostHogBatch>[number]\n\n/** Split so neither per-event nor per-batch byte caps are exceeded. */\nfunction splitBatch(\n items: PostHogBatchItem[],\n maxBatchBytes: number,\n maxEventBytes: number,\n): PostHogBatchItem[][] {\n const batches: PostHogBatchItem[][] = []\n let current: PostHogBatchItem[] = []\n let currentBytes = 2\n\n for (const item of items) {\n const itemBytes = byteLength(JSON.stringify(item))\n // Oversized single events can never be sent — drop them.\n if (itemBytes > maxEventBytes) continue\n if (current.length && currentBytes + itemBytes + 1 > maxBatchBytes) {\n batches.push(current)\n current = []\n currentBytes = 2\n }\n current.push(item)\n currentBytes += itemBytes + 1\n }\n if (current.length) batches.push(current)\n return batches\n}\n\n/**\n * Create the PostHog `http`-mode sink (default). Pure protocol adapter —\n * no `posthog-js`, safe in Node and the browser.\n */\nexport function createPostHogHttpSink(\n options: PostHogHttpSinkOptions,\n): AnalyticsSink {\n const {\n apiKey,\n host = 'https://us.i.posthog.com',\n name = 'posthog',\n consentCategories = ['analytics'],\n maxRetries = 3,\n backoffBaseMs = 500,\n maxBatchBytes = 1_000_000,\n maxEventBytes = 32_000,\n } = options\n\n const base = host.replace(/\\/+$/, '')\n const captureUrl = `${base}/capture/`\n const batchUrl = `${base}/batch/`\n\n const resolveFetch = (): typeof fetch => {\n if (options.fetchImpl) return options.fetchImpl\n const f = (globalThis as unknown as { fetch?: typeof fetch }).fetch\n if (!f) throw new Error('No fetch implementation available')\n return f\n }\n\n const resolveBeacon = ():\n | ((u: string, body: string) => boolean)\n | undefined => {\n if (options.beaconImpl) return options.beaconImpl\n const nav = (\n globalThis as unknown as {\n navigator?: { sendBeacon?: (u: string, data: BodyInit) => boolean }\n }\n ).navigator\n if (nav && typeof nav.sendBeacon === 'function') {\n return (u, body) => nav.sendBeacon!(u, body)\n }\n return undefined\n }\n\n function payload(part: PostHogBatchItem[]): {\n url: string\n body: string\n } {\n if (part.length === 1) {\n return {\n url: captureUrl,\n body: JSON.stringify({ api_key: apiKey, ...part[0] }),\n }\n }\n return {\n url: batchUrl,\n body: JSON.stringify({ api_key: apiKey, batch: part }),\n }\n }\n\n async function sendViaFetch(part: PostHogBatchItem[]): Promise<void> {\n const doFetch = resolveFetch()\n const { url, body } = payload(part)\n\n for (let attempt = 0; ; attempt++) {\n let status: number\n try {\n const res = await doFetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n keepalive: true,\n })\n status = res.status\n } catch {\n status = 0 // network error → transient\n }\n\n if (status >= 200 && status < 300) return\n if (NO_RETRY.has(status)) return\n\n if (attempt >= maxRetries) return\n await sleep(backoffBaseMs * 2 ** attempt)\n }\n }\n\n function sendViaBeacon(part: PostHogBatchItem[]): boolean {\n const beacon = resolveBeacon()\n if (!beacon) return false\n const { url, body } = payload(part)\n return beacon(url, body)\n }\n\n return {\n name,\n consentCategories,\n\n async deliver(\n batch: AnalyticsEvent[],\n ctx: SinkDeliverContext,\n ): Promise<void> {\n if (batch.length === 0) return\n const items = toPostHogBatch(batch)\n const parts = splitBatch(items, maxBatchBytes, maxEventBytes)\n\n for (const part of parts) {\n if (part.length === 0) continue\n if (ctx.unload) {\n if (sendViaBeacon(part)) continue\n void sendViaFetch(part)\n } else {\n await sendViaFetch(part)\n }\n }\n },\n }\n}\n", "import type {\n AnalyticsEvent,\n AnalyticsSink,\n SinkInitContext,\n} from '@refraction-ui/analytics'\nimport { distinctId } from './mapping.js'\n\n/**\n * PostHog `client-sdk` sink — OPTIONAL, opt-in mode.\n *\n * For client-exclusive PostHog features (autocapture, feature flags,\n * surveys, web experiments) that the protocol API alone cannot drive.\n * `posthog-js` is loaded **lazily via dynamic `import()`** the first time the\n * sink delivers, so a consumer who only uses the default `http` sink never\n * pays the browser-library cost and `posthog-js` stays a fully optional peer.\n *\n * Session replay is deliberately NOT touched here — it lives in the separate\n * `@refraction-ui/analytics-sink-posthog/replay` module so it is never on the\n * event path and tree-shakes out unless explicitly enabled.\n */\n\n/** Minimal structural type for the bits of `posthog-js` we use. */\ninterface PostHogJs {\n init(apiKey: string, options: Record<string, unknown>): void\n capture(event: string, properties?: Record<string, unknown>): void\n identify(distinctId: string, set?: Record<string, unknown>): void\n alias(alias: string, original?: string): void\n group(\n groupType: string,\n groupKey: string,\n properties?: Record<string, unknown>,\n ): void\n reset(): void\n}\n\nexport interface PostHogClientSdkSinkOptions {\n /** PostHog project API key. */\n apiKey: string\n /** PostHog API host. Default `https://us.i.posthog.com`. */\n host?: string\n /** Sink name. Default `posthog`. */\n name?: string\n /** Consent categories this sink requires. Default `['analytics']`. */\n consentCategories?: string[]\n /**\n * Extra `posthog-js` init options. `autocapture`, `capture_pageview`, and\n * `session_recording` default to OFF — the canonical router owns the event\n * path; replay is opt-in via the separate module.\n */\n posthogOptions?: Record<string, unknown>\n /**\n * Injected loader (testing / custom bundling). Defaults to a lazy\n * `import('posthog-js')`.\n */\n loadPostHog?: () => Promise<{ default: PostHogJs } | PostHogJs>\n}\n\n// `posthog-js` is an OPTIONAL peer — installed only by consumers who opt into\n// client-sdk mode. The specifier must stay non-statically-analyzable: the meta\n// packages (`@refraction-ui/astro`, `@refraction-ui/react`) re-export this\n// module from their entry, so a literal `import('posthog-js')` makes consumer\n// bundlers (vite/rollup) fail the whole build trying to resolve a package that\n// is not installed — long before tree-shaking can drop the module. Routing the\n// specifier through a const keeps the import runtime-only. (A `/* @vite-ignore */`\n// annotation does NOT suffice — vite still resolves literal dynamic-import\n// specifiers in SSR builds.)\nconst posthogJsSpecifier = 'posthog-js'\n\nasync function defaultLoad(): Promise<PostHogJs> {\n // Dynamic import keeps `posthog-js` out of the graph until first delivery.\n const mod = (await import(/* webpackIgnore: true */ /* @vite-ignore */ posthogJsSpecifier)) as unknown as\n | { default: PostHogJs }\n | PostHogJs\n return 'default' in mod ? mod.default : mod\n}\n\n/**\n * Create the OPTIONAL PostHog `client-sdk`-mode sink. `posthog-js` is\n * dynamically imported on first use, never at module load.\n */\nexport function createPostHogClientSdkSink(\n options: PostHogClientSdkSinkOptions,\n): AnalyticsSink {\n const {\n apiKey,\n host = 'https://us.i.posthog.com',\n name = 'posthog',\n consentCategories = ['analytics'],\n posthogOptions = {},\n } = options\n\n let ph: PostHogJs | undefined\n let loading: Promise<PostHogJs> | undefined\n\n async function ensure(): Promise<PostHogJs> {\n if (ph) return ph\n if (!loading) {\n const load = options.loadPostHog\n ? async () => {\n const m = await options.loadPostHog!()\n return ('default' in m ? m.default : m) as PostHogJs\n }\n : defaultLoad\n loading = load().then((instance) => {\n instance.init(apiKey, {\n api_host: host,\n // The canonical router owns the event path — disable PostHog's\n // own auto-capture and pageview, and never start replay here.\n autocapture: false,\n capture_pageview: false,\n disable_session_recording: true,\n ...posthogOptions,\n })\n ph = instance\n return instance\n })\n }\n return loading\n }\n\n return {\n name,\n consentCategories,\n\n async init(_ctx: SinkInitContext): Promise<void> {\n // Eagerly warm the SDK so the first event is not delayed. Still lazy\n // relative to module load — only runs once the sink is registered.\n await ensure()\n },\n\n async deliver(batch: AnalyticsEvent[]): Promise<void> {\n if (batch.length === 0) return\n const client = await ensure()\n for (const ev of batch) {\n const did = distinctId(ev)\n switch (ev.type) {\n case 'identify':\n client.identify(did, { ...(ev.traits ?? {}) })\n break\n case 'alias':\n if (ev.previousId) client.alias(ev.previousId, did)\n break\n case 'group':\n client.group(\n (ev.properties?.groupType as string) ?? 'company',\n ev.groupId ?? '',\n { ...(ev.traits ?? {}) },\n )\n break\n case 'page':\n client.capture('$pageview', { ...(ev.properties ?? {}) })\n break\n case 'screen':\n client.capture('$screen', {\n $screen_name: ev.event,\n ...(ev.properties ?? {}),\n })\n break\n case 'track':\n default:\n client.capture(ev.event ?? 'track', { ...(ev.properties ?? {}) })\n break\n }\n }\n },\n\n shutdown(): void {\n ph?.reset()\n },\n }\n}\n", "import type { AnalyticsSink } from '@refraction-ui/analytics'\nimport {\n createPostHogHttpSink,\n type PostHogHttpSinkOptions,\n} from './http-sink.js'\nimport {\n createPostHogClientSdkSink,\n type PostHogClientSdkSinkOptions,\n} from './client-sdk-sink.js'\n\n/** PostHog fan-out mode. `http` is the default (no browser library). */\nexport type PostHogSinkMode = 'http' | 'client-sdk'\n\nexport type PostHogSinkOptions =\n | ({ mode?: 'http' } & PostHogHttpSinkOptions)\n | ({ mode: 'client-sdk' } & PostHogClientSdkSinkOptions)\n\n/**\n * Create a PostHog `AnalyticsSink`.\n *\n * - `mode: 'http'` (DEFAULT) — pure protocol adapter against PostHog's\n * `/capture` + `/batch` API. No `posthog-js`. Server-relay friendly.\n * - `mode: 'client-sdk'` — OPTIONAL. Lazily dynamic-imports `posthog-js`\n * for client-exclusive features. Only loaded if this mode is selected.\n *\n * Session replay is NOT configurable here — import the separate\n * `@refraction-ui/analytics-sink-posthog/replay` module to opt in. It is\n * never on the event path and tree-shakes away when unused.\n */\nexport function createPostHogSink(\n options: PostHogSinkOptions,\n): AnalyticsSink {\n if (options.mode === 'client-sdk') {\n return createPostHogClientSdkSink(options)\n }\n return createPostHogHttpSink(options)\n}\n", "/**\n * @refraction-ui/analytics-sink-posthog/replay\n *\n * OPTIONAL, lazy session-replay (rrweb, via `posthog-js`).\n *\n * Hard guarantees this module exists to enforce:\n *\n * 1. **Off by default.** Nothing in the main `@refraction-ui/analytics-sink-posthog`\n * entry imports this file, so it (and `posthog-js`, and rrweb) are fully\n * tree-shaken out of any bundle that does not explicitly import it.\n * 2. **Never on the event path.** Replay is not an `AnalyticsSink`. It does\n * not see, transform, or block canonical envelopes. `track`/`identify`/…\n * keep flowing through the sink even if replay never starts or fails.\n * 3. **Privacy/consent gated.** `startSessionReplay` refuses to start unless\n * a consent predicate returns true, and re-checks it; `stop()` tears the\n * recorder down. Masking defaults are maximally private.\n * 4. **Lazy.** `posthog-js` is `import()`-ed only when `startSessionReplay`\n * is actually called.\n *\n * This is a thin controller around `posthog-js`'s built-in rrweb session\n * recording — we do not bundle rrweb ourselves.\n */\n\n/** Minimal structural view of the `posthog-js` replay surface. */\ninterface PostHogReplay {\n init(apiKey: string, options: Record<string, unknown>): void\n startSessionRecording(): void\n stopSessionRecording(): void\n sessionRecordingStarted?(): boolean\n}\n\nexport interface SessionReplayOptions {\n /** PostHog project API key. */\n apiKey: string\n /** PostHog API host. Default `https://us.i.posthog.com`. */\n host?: string\n /**\n * Consent predicate. Replay starts ONLY when this returns `true`, and is\n * re-checked by `enforceConsent()`. There is no default-allow: if omitted,\n * replay is treated as NOT consented and will not start.\n */\n hasConsent?: () => boolean\n /**\n * rrweb masking. Defaults are maximally private: all text + all inputs\n * masked. Override deliberately and document the privacy review.\n */\n maskAllText?: boolean\n maskAllInputs?: boolean\n /** Extra `posthog-js` session_recording options (advanced). */\n recordingOptions?: Record<string, unknown>\n /**\n * Injected loader (testing / custom bundling). Defaults to a lazy\n * `import('posthog-js')`.\n */\n loadPostHog?: () => Promise<{ default: PostHogReplay } | PostHogReplay>\n}\n\n/** Handle returned by {@link startSessionReplay}. */\nexport interface SessionReplayHandle {\n /** True if the rrweb recorder is currently running. */\n readonly recording: boolean\n /**\n * Re-evaluate the consent predicate. If consent was revoked, recording is\n * stopped. Call this from your consent-change handler.\n */\n enforceConsent(): void\n /** Stop recording and release the recorder. Idempotent. */\n stop(): void\n}\n\n// `posthog-js` is an OPTIONAL peer — installed only by consumers who opt into\n// session replay. The specifier must stay non-statically-analyzable: the meta\n// packages (`@refraction-ui/astro`, `@refraction-ui/react`) re-export this\n// module from their entry, so a literal `import('posthog-js')` makes consumer\n// bundlers (vite/rollup) fail the whole build trying to resolve a package that\n// is not installed — long before tree-shaking can drop the module. Routing the\n// specifier through a const keeps the import runtime-only.\nconst posthogJsSpecifier = 'posthog-js'\n\nasync function defaultLoad(): Promise<PostHogReplay> {\n const mod = (await import(/* webpackIgnore: true */ /* @vite-ignore */ posthogJsSpecifier)) as unknown as\n | { default: PostHogReplay }\n | PostHogReplay\n return 'default' in mod ? mod.default : mod\n}\n\n/**\n * Start PostHog/rrweb session replay. Resolves to a handle, or to a\n * non-recording handle if consent is not granted (it never throws on the\n * consent path — replay simply does not start).\n *\n * `posthog-js` is dynamically imported here and nowhere else.\n */\nexport async function startSessionReplay(\n options: SessionReplayOptions,\n): Promise<SessionReplayHandle> {\n const {\n apiKey,\n host = 'https://us.i.posthog.com',\n hasConsent,\n maskAllText = true,\n maskAllInputs = true,\n recordingOptions = {},\n } = options\n\n const consented = (): boolean =>\n typeof hasConsent === 'function' ? hasConsent() === true : false\n\n // Single-slot holder so the closure can observe the lazily-loaded\n // instance without an outer `let` rebind.\n const slot: { ph?: PostHogReplay } = {}\n let recording = false\n\n const stop = (): void => {\n if (slot.ph && recording) {\n slot.ph.stopSessionRecording()\n }\n recording = false\n }\n\n const handle: SessionReplayHandle = {\n get recording() {\n return recording\n },\n enforceConsent(): void {\n if (!consented()) stop()\n },\n stop,\n }\n\n // Privacy gate: do not even load posthog-js if consent is absent.\n if (!consented()) return handle\n\n const load = options.loadPostHog\n ? async () => {\n const m = await options.loadPostHog!()\n return ('default' in m ? m.default : m) as PostHogReplay\n }\n : defaultLoad\n\n slot.ph = await load()\n slot.ph.init(apiKey, {\n api_host: host,\n autocapture: false,\n capture_pageview: false,\n // Start with replay disabled, then opt in explicitly below.\n disable_session_recording: true,\n session_recording: {\n maskAllInputs,\n maskTextSelector: maskAllText ? '*' : undefined,\n ...recordingOptions,\n },\n })\n\n // Re-check consent after the (async) load in case it was revoked meanwhile.\n if (!consented()) return handle\n\n slot.ph.startSessionRecording()\n recording = slot.ph.sessionRecordingStarted?.() ?? true\n return handle\n}\n", "import * as React from 'react'\nimport { devWarn } from '@refraction-ui/shared'\nimport { createNoopAnalytics } from '@refraction-ui/analytics'\nimport type {\n Analytics,\n AnalyticsContext as AnalyticsEventContext,\n AnalyticsProperties,\n CallOptions,\n} from '@refraction-ui/analytics'\n\nconst AnalyticsContext = React.createContext<Analytics | null>(null)\n\n/**\n * Shared no-op Analytics used when a hook is called outside an\n * <AnalyticsProvider>. Lazily created once and reused so the reference stays\n * stable. The hooks degrade gracefully (silent no-op) instead of throwing —\n * components instrumented with useAnalytics/useTrackEvent render fine without\n * a provider (tests, standalone); analytics activates when one is mounted.\n */\nlet noopAnalytics: Analytics | null = null\nfunction getNoopAnalytics(): Analytics {\n return (noopAnalytics ??= createNoopAnalytics())\n}\n\nexport interface AnalyticsProviderProps {\n children: React.ReactNode\n /**\n * The `Analytics` instance to expose. Construct it once with\n * `createAnalytics(...)` from `@refraction-ui/analytics`.\n */\n value: Analytics\n}\n\n/**\n * AnalyticsProvider — wraps your app with analytics context.\n *\n * ```tsx\n * <AnalyticsProvider value={createAnalytics({ app: 'my-app', env: 'production' })}>\n * <App />\n * </AnalyticsProvider>\n * ```\n */\nexport function AnalyticsProvider({ children, value }: AnalyticsProviderProps) {\n const analyticsRef = React.useRef<Analytics | null>(null)\n\n if (!analyticsRef.current) {\n analyticsRef.current = value\n }\n\n return React.createElement(\n AnalyticsContext.Provider,\n { value: analyticsRef.current },\n children,\n )\n}\n\nexport interface UseAnalyticsOptions {\n /** When set, returns a `with({ ...scope })` child bound to the context. */\n scope?: Partial<AnalyticsEventContext>\n}\n\n/**\n * useAnalytics — access the `Analytics` instance from context.\n *\n * Pass `{ scope }` to receive a `with(...)` child whose context is merged\n * into every event. If called outside an `<AnalyticsProvider>` it does NOT\n * throw: it returns a shared no-op `Analytics` (a dev-only warn-once hint is\n * emitted). Instrumenting a component with analytics must never crash the\n * host (incl. in tests).\n */\nexport function useAnalytics(options?: UseAnalyticsOptions): Analytics {\n const ctx = React.useContext(AnalyticsContext)\n let base = ctx\n if (!base) {\n devWarn(\n 'react-analytics/use-analytics-outside-provider',\n 'useAnalytics() (or useTrackEvent()) was called outside an <AnalyticsProvider>. Analytics is a no-op here; wrap your app (or the consuming subtree) in <AnalyticsProvider> to enable it.',\n )\n base = getNoopAnalytics()\n }\n const scope = options?.scope\n return React.useMemo<Analytics>(\n () => (scope ? base.with(scope) : base),\n [base, scope],\n )\n}\n\n/**\n * useTrackEvent — a stable, bound `track` for the current context.\n *\n * ```tsx\n * const track = useTrackEvent()\n * track('Signup Clicked', { plan: 'pro' })\n * ```\n */\nexport function useTrackEvent(\n options?: UseAnalyticsOptions,\n): (event: string, properties?: AnalyticsProperties, opts?: CallOptions) => void {\n const analytics = useAnalytics(options)\n return React.useCallback(\n (event: string, properties?: AnalyticsProperties, opts?: CallOptions) =>\n analytics.track(event, properties, opts),\n [analytics],\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["DEFAULT_KEY", "resolveFetch", "mapEvent", "NO_RETRY", "sleep", "createHttpSink", "resolveFetch", "NO_RETRY", "sleep", "byteLength", "splitBatch", "resolveFetch", "posthogJsSpecifier", "defaultLoad"]
|
|
7
7
|
}
|