@active-reach/web-sdk 1.14.0 → 1.15.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.
@@ -58,7 +58,7 @@ class AegisWebPush {
58
58
  apiClient.post("/v1/push/engagement", body, headers)
59
59
  ).catch((err) => {
60
60
  if (typeof console !== "undefined" && console.warn) {
61
- console.warn("[AegisWebPush] engagement report failed:", err);
61
+ console.warn("[Active Reach WebPush] engagement report failed:", err);
62
62
  }
63
63
  });
64
64
  }
@@ -119,7 +119,7 @@ class AegisWebPush {
119
119
  const handlers = this.hooks.get("error");
120
120
  if (!handlers || handlers.size === 0) {
121
121
  console.warn(
122
- "[AegisWebPush] error:",
122
+ "[Active Reach WebPush] error:",
123
123
  err instanceof Error ? err.message : String(err),
124
124
  context ?? {}
125
125
  );
@@ -139,7 +139,7 @@ class AegisWebPush {
139
139
  async initialize() {
140
140
  if (this.initialized) return;
141
141
  if (!("serviceWorker" in navigator) || !("PushManager" in window)) {
142
- console.warn("[AegisWebPush] Push notifications not supported in this browser");
142
+ console.warn("[Active Reach WebPush] Push notifications not supported in this browser");
143
143
  return;
144
144
  }
145
145
  try {
@@ -154,14 +154,14 @@ class AegisWebPush {
154
154
  });
155
155
  if (typeof window !== "undefined" && Notification.permission === "granted") {
156
156
  this.subscribeToPush().catch((err) => {
157
- console.warn("[AegisWebPush] auto-resync subscribeToPush failed:", err);
157
+ console.warn("[Active Reach WebPush] auto-resync subscribeToPush failed:", err);
158
158
  });
159
159
  }
160
160
  if (this.config.autoPrompt) {
161
161
  setTimeout(() => this.requestPermission(), this.config.promptDelay);
162
162
  }
163
163
  } catch (err) {
164
- console.error("[AegisWebPush] Service worker registration failed:", err);
164
+ console.error("[Active Reach WebPush] Service worker registration failed:", err);
165
165
  }
166
166
  }
167
167
  async requestPermission() {
@@ -302,7 +302,7 @@ class AegisWebPush {
302
302
  return;
303
303
  } catch (err) {
304
304
  if (attempt === maxRetries) {
305
- console.error("[AegisWebPush] API call failed after retries:", err);
305
+ console.error("[Active Reach WebPush] API call failed after retries:", err);
306
306
  return;
307
307
  }
308
308
  const delay = 1e3 * Math.pow(2, attempt);
@@ -404,7 +404,7 @@ class AegisWebPush {
404
404
  );
405
405
  this.trackPushEvent("push.resubscribed", {});
406
406
  } catch (err) {
407
- console.warn("[AegisWebPush] persistResubscription failed:", err);
407
+ console.warn("[Active Reach WebPush] persistResubscription failed:", err);
408
408
  }
409
409
  }
410
410
  trackPushEvent(eventName, properties) {
@@ -1 +1 @@
1
- {"version":3,"file":"AegisWebPush.js","sources":["../../src/push/AegisWebPush.ts"],"sourcesContent":["export interface AegisAPIClient {\n post(\n endpoint: string,\n payload: Record<string, unknown>,\n headers?: Record<string, string>\n ): Promise<unknown>;\n}\n\nexport interface ContactIdentity {\n contactId?: string;\n shopifyCustomerId?: string;\n email?: string;\n}\n\nexport interface AegisWebPushConfig {\n vapidPublicKey: string;\n // SubscriptionProperty binding — supplied by the embedding host (e.g.\n // the storefront SSR via the `sdk.property_id` field on /store/{slug}).\n // Required: every subscribe call sends it back as `X-Property-Id` so\n // the backend pins the row to the right origin.\n propertyId: string;\n // Stable per-browser cookie id (e.g. aegis_fpc). Used as the\n // device-fingerprint salt so a fresh subscribe after VAPID rotation\n // upserts onto the same `web_push_subscriptions` row.\n firstPartyCookieId: string;\n autoPrompt?: boolean;\n promptDelay?: number;\n serviceWorkerPath?: string;\n serviceWorkerScope?: string;\n // Engagement-event reporting credentials. When BOTH `writeKey` and\n // `organizationId` are provided AND the caller does NOT pass an\n // explicit `eventTracker` to the constructor, AegisWebPush auto-wires\n // a built-in tracker that POSTs push lifecycle events\n // (push.delivered / push.dismissed / push.clicked) to\n // `/v1/push/engagement` — closing the long-standing gap where shown\n // + dismissed signals (only the device-side SDK can report them)\n // never reached `aegis.delivery_events`. See backend dual-route at\n // `apps/event-ingress/src/services/event-switchboard.ts`\n // (SDK_ENGAGEMENT_EVENT_TO_DELIVERY_MAPPING).\n //\n // Callers using `AegisMessageRuntime` should keep passing the\n // runtime's analytics adapter as `eventTracker` — these fields are\n // only the standalone-init fallback.\n writeKey?: string;\n organizationId?: string;\n}\n\nexport interface PushEventTracker {\n track(eventName: string, properties: Record<string, unknown>): void;\n}\n\n/**\n * Payload for the `push-tap` lifecycle event. CANCELLABLE — return `false`\n * (or call `evt.preventDefault()`) from a handler to suppress the SDK's\n * default `window.location.href` fallback navigation. Use this to dispatch\n * an in-place state change in a SPA host instead of a hard reload.\n *\n * `action_type` + `action_payload` are author-controlled fields baked into\n * the push template's `data` block:\n *\n * ```json\n * {\n * \"title\": \"Your cart is waiting\",\n * \"body\": \"...\",\n * \"action_url\": \"https://shop.actii.me/?step=cart\",\n * \"data\": {\n * \"action_type\": \"open_cart\",\n * \"action_payload\": { \"step\": \"cart\" }\n * }\n * }\n * ```\n */\nexport interface PushTapEvent {\n /** Author-controlled action discriminator (e.g. `open_cart`,\n * `open_payment_link`, `open_order`). When unset, the SDK runs its\n * default fallback navigation to `action_url`. */\n action_type?: string;\n /** Optional structured args the host SPA forwards to its handler. */\n action_payload?: Record<string, unknown>;\n /** Sanitized destination URL — used as the SDK's default fallback nav\n * target when no host handler cancels. */\n action_url: string;\n /** Action-button id when the user clicked a specific button on a\n * multi-button notification; `'default'` for body taps. */\n action: string;\n /** Source campaign id from the push payload — useful for SPA routing\n * (e.g. open_cart from a cart-recovery campaign vs from a generic\n * catch-all template). */\n campaign_id?: string;\n /** Mutate via `evt.preventDefault()` to signal the SDK to skip its\n * default hard-navigation. Identical semantics to DOM CustomEvent. */\n preventDefault: () => void;\n defaultPrevented: boolean;\n}\n\n/** Payload for `push-shown` — fires after `showNotification` resolves on\n * the SW side. The `degraded` flag is true when the SW had to fall back\n * to its minimal `{title, body}` retry path (broken icon URL etc.). */\nexport interface PushShownEvent {\n campaign_id?: string;\n degraded?: boolean;\n}\n\n/** Payload for `push-dismissed` — fires when the user closes the\n * notification without clicking. */\nexport interface PushDismissEvent {\n campaign_id?: string;\n}\n\n/** Payload for `error` — non-fatal SDK errors (subscribe failures,\n * resubscribe persist failures, host-handler throws). Wire into Sentry\n * / Datadog RUM. */\nexport interface PushErrorEvent {\n message: string;\n error: unknown;\n context: Record<string, unknown>;\n}\n\n/** Map of lifecycle event name → handler signature. Mirrors 1.8.0\n * in-app lifecycle for consistency. */\nexport interface WebPushLifecycleEventMap {\n 'push-tap': (evt: PushTapEvent) => void | false;\n 'push-shown': (evt: PushShownEvent) => void;\n 'push-dismissed': (evt: PushDismissEvent) => void;\n 'error': (evt: PushErrorEvent) => void;\n}\n\n/**\n * AegisWebPush — Web Push notification manager.\n *\n * Handles service worker registration, push subscription via VAPID,\n * token registration with the backend, and push event tracking.\n */\nexport class AegisWebPush {\n private apiClient: AegisAPIClient;\n private eventTracker: PushEventTracker | null;\n private swRegistration: ServiceWorkerRegistration | null = null;\n private config: AegisWebPushConfig;\n private initialized = false;\n\n // ── Lifecycle event bus (1.8.5) ────────────────────────────────────────\n // Typed handler registry, parity with AegisInAppManager (1.8.0).\n // Hosts register via the public `on*` methods below; calling the\n // returned unsubscribe fn removes the handler. Multiple subscribers per\n // event are supported. Cancellable events (`push-tap`) suppress the\n // SDK's default behaviour when a handler returns `false` or calls\n // `evt.preventDefault()`.\n //\n // Industry parity: matches CleverTap `notificationCallback`, OneSignal\n // `addEventListener('notificationOpened')`, MoEngage\n // `onSelfHandledClick`, WebEngage `notificationCallback`. The SW posts\n // a `push.clicked` message; this class translates that into a typed\n // PushTapEvent with cancellable default-nav behaviour.\n private hooks = new Map<string, Set<(...args: unknown[]) => void | false | undefined>>();\n\n constructor(\n apiClient: AegisAPIClient,\n config: AegisWebPushConfig,\n eventTracker?: PushEventTracker\n ) {\n this.apiClient = apiClient;\n this.config = {\n serviceWorkerPath: '/aegis-sw.js',\n serviceWorkerScope: '/',\n autoPrompt: false,\n promptDelay: 5000,\n ...config,\n };\n // Explicit eventTracker wins (typical AegisMessageRuntime flow).\n // Otherwise, if both `writeKey` and `organizationId` are configured,\n // wire the built-in tracker that POSTs to `/v1/push/engagement` so\n // standalone push installs don't silently drop lifecycle events.\n if (eventTracker) {\n this.eventTracker = eventTracker;\n } else if (this.config.writeKey && this.config.organizationId) {\n this.eventTracker = this.createBuiltinEventTracker(\n this.config.writeKey,\n this.config.organizationId,\n );\n } else {\n this.eventTracker = null;\n }\n }\n\n /** Built-in fallback that POSTs push lifecycle events to\n * `/v1/push/engagement`. The gateway forwards to event-ingress with\n * the canonical `push.<event>` event_type, which the\n * event-switchboard's SDK_ENGAGEMENT_EVENT_TO_DELIVERY_MAPPING\n * dual-routes onto `aegis.delivery_events` as\n * `channel='push', status='shown'|'dismissed'|...`. Best-effort —\n * failures are warned but never thrown (push SW callbacks shouldn't\n * reject because the analytics POST failed). */\n private createBuiltinEventTracker(\n writeKey: string,\n organizationId: string,\n ): PushEventTracker {\n const apiClient = this.apiClient;\n const propertyId = this.config.propertyId;\n const resolveContactId = () => this.resolveContactId();\n return {\n track(eventName: string, properties: Record<string, unknown>): void {\n const contactId =\n (properties.contact_id as string | undefined) ?? resolveContactId();\n const body = {\n campaign_id: (properties.campaign_id as string | undefined) || '',\n message_id: (properties.message_id as string | undefined) || '',\n event_type: eventName, // e.g. 'push.delivered' — gateway tolerates either form\n user_id: (properties.user_id as string | undefined) || contactId,\n contact_id: contactId,\n anonymous_id: (properties.anonymous_id as string | undefined) || '',\n platform: (properties.platform as string | undefined) || 'web',\n property_id: propertyId,\n metadata: (properties.metadata as Record<string, unknown> | undefined) ?? {},\n };\n const headers = {\n 'X-Aegis-Write-Key': writeKey,\n 'X-Organization-ID': organizationId,\n 'X-Property-Id': propertyId,\n };\n void Promise.resolve(\n apiClient.post('/v1/push/engagement', body, headers),\n ).catch((err) => {\n if (typeof console !== 'undefined' && console.warn) {\n console.warn('[AegisWebPush] engagement report failed:', err);\n }\n });\n },\n };\n }\n\n // ── Public lifecycle hook API ──────────────────────────────────────────\n\n /** Generic typed subscribe — useful when the host wants to dispatch\n * multiple events through one wrapper. For single-event subscriptions\n * prefer the `on*` sugar methods below. */\n on<E extends keyof WebPushLifecycleEventMap>(\n event: E,\n handler: WebPushLifecycleEventMap[E],\n ): () => void {\n return this.register(event, handler as never);\n }\n\n /** Subscribe to push notification taps. CANCELLABLE — return `false`\n * (or call `evt.preventDefault()`) to suppress the SDK's default\n * `window.location.href = action_url` fallback. Use this to wire a\n * SPA router into the typed `action_type` payload (e.g. open the\n * cart drawer in-place instead of a full reload). */\n onPushTap(\n handler: (evt: PushTapEvent) => void | false,\n ): () => void {\n return this.register('push-tap', handler);\n }\n\n /** Subscribe to push impressions — fires after the OS notification\n * has actually rendered. `degraded=true` when the SW fell back to\n * the minimal `{title, body}` path (broken icon, etc.). */\n onPushShown(\n handler: (evt: PushShownEvent) => void,\n ): () => void {\n return this.register('push-shown', handler);\n }\n\n /** Subscribe to push dismissals (notification closed without a tap). */\n onPushDismiss(\n handler: (evt: PushDismissEvent) => void,\n ): () => void {\n return this.register('push-dismissed', handler);\n }\n\n /** Subscribe to non-fatal SDK errors. Wire into Sentry / Datadog. */\n onError(\n handler: (evt: PushErrorEvent) => void,\n ): () => void {\n return this.register('error', handler);\n }\n\n private register<T>(\n eventName: string,\n handler: (payload: T) => void | false | undefined,\n ): () => void {\n if (!this.hooks.has(eventName)) this.hooks.set(eventName, new Set());\n this.hooks.get(eventName)!.add(handler as (...args: unknown[]) => void | false | undefined);\n return () => {\n this.hooks.get(eventName)?.delete(handler as (...args: unknown[]) => void | false | undefined);\n };\n }\n\n private emit<T>(eventName: string, payload: T): boolean {\n const handlers = this.hooks.get(eventName);\n if (!handlers || handlers.size === 0) return true;\n let proceed = true;\n for (const handler of handlers) {\n try {\n const result = (handler as (p: T) => void | false | undefined)(payload);\n if (result === false) proceed = false;\n } catch (err) {\n this.emitError(err, { event: eventName });\n }\n }\n return proceed;\n }\n\n private emitError(err: unknown, context?: Record<string, unknown>): void {\n const handlers = this.hooks.get('error');\n if (!handlers || handlers.size === 0) {\n console.warn(\n '[AegisWebPush] error:',\n err instanceof Error ? err.message : String(err),\n context ?? {}\n );\n return;\n }\n for (const handler of handlers) {\n try {\n (handler as (e: PushErrorEvent) => void)({\n message: err instanceof Error ? err.message : String(err),\n error: err,\n context: context ?? {},\n });\n } catch {\n // already in error path — don't loop\n }\n }\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n if (!('serviceWorker' in navigator) || !('PushManager' in window)) {\n console.warn('[AegisWebPush] Push notifications not supported in this browser');\n return;\n }\n\n try {\n this.swRegistration = await navigator.serviceWorker.register(\n this.config.serviceWorkerPath!,\n { scope: this.config.serviceWorkerScope }\n );\n await navigator.serviceWorker.ready;\n this.initialized = true;\n\n // Listen for messages from the service worker (click/dismiss tracking,\n // and pushsubscriptionchange relay — see handleSWMessage).\n navigator.serviceWorker.addEventListener('message', (event) => {\n this.handleSWMessage(event.data);\n });\n\n // Heal endpoint drift on every page load.\n //\n // Background: when the SW updates with skipWaiting+clients.claim\n // (added in 1.7.3), some browsers — Samsung Internet most\n // aggressively, occasionally Chrome too — silently regenerate the\n // push subscription mid-flight. The SW catches the\n // pushsubscriptionchange event and resubscribes locally, but\n // historically the new endpoint never made it back to the\n // backend. Cell-plane kept FCM-pushing to the dead endpoint;\n // FCM 201s on receipt regardless of whether the token is alive,\n // so the silent failure was invisible until users complained.\n //\n // Fix: whenever permission is already granted at init time,\n // re-run subscribeToPush. The pushManager.subscribe() call is\n // idempotent — it returns the existing subscription if the\n // endpoint is still valid, otherwise mints a new one — and we\n // POST the result to /v1/web_push/subscriptions which UPSERTs\n // on (property_id, device_fingerprint). One extra round-trip\n // per page load; cheap, deterministic, never need to debug\n // stale-endpoint mysteries again.\n if (typeof window !== 'undefined' && Notification.permission === 'granted') {\n this.subscribeToPush().catch((err) => {\n console.warn('[AegisWebPush] auto-resync subscribeToPush failed:', err);\n });\n }\n\n if (this.config.autoPrompt) {\n setTimeout(() => this.requestPermission(), this.config.promptDelay);\n }\n } catch (err) {\n console.error('[AegisWebPush] Service worker registration failed:', err);\n }\n }\n\n async requestPermission(): Promise<boolean> {\n const permission = await Notification.requestPermission();\n\n if (permission === 'granted') {\n await this.subscribeToPush();\n return true;\n }\n\n this.trackPushEvent('push.permission_denied', {});\n return false;\n }\n\n async identify(params: ContactIdentity): Promise<void> {\n // Persist the resolved contact_id so getStableFingerprint /\n // resolveContactId see it on the next subscribe call. Then re-run\n // the subscribe flow — the backend UPSERT on\n // (property_id, device_fingerprint) updates the existing row with\n // the new contact_id in place.\n try {\n if (params.contactId) {\n window.localStorage.setItem('aegis_contact_id', params.contactId);\n }\n } catch {\n // storage blocked — proceed anyway; subscribe() still works\n }\n\n const subscription = await this.swRegistration?.pushManager.getSubscription();\n if (!subscription) return;\n\n const subscriptionJSON = subscription.toJSON();\n const fingerprint = await this.getStableFingerprint();\n await this.retryApiCall(() =>\n this.apiClient.post(\n '/v1/web_push/subscriptions',\n {\n contact_id: params.contactId ?? this.resolveContactId(),\n endpoint: subscriptionJSON.endpoint!,\n p256dh: subscriptionJSON.keys!.p256dh!,\n auth: subscriptionJSON.keys!.auth!,\n device_fingerprint: fingerprint,\n user_agent: navigator.userAgent,\n },\n { 'X-Property-Id': this.config.propertyId }\n )\n );\n }\n\n async logout(): Promise<void> {\n const subscription = await this.swRegistration?.pushManager.getSubscription();\n if (!subscription) return;\n const subscriptionJSON = subscription.toJSON();\n const fingerprint = await this.getStableFingerprint();\n try {\n await this.apiClient.post(\n '/v1/web_push/unsubscribe',\n {\n contact_id: this.resolveContactId(),\n device_fingerprint: fingerprint,\n endpoint: subscriptionJSON.endpoint!,\n },\n { 'X-Property-Id': this.config.propertyId }\n );\n } finally {\n try {\n window.localStorage.removeItem('aegis_contact_id');\n } catch {\n // ignore\n }\n }\n }\n\n // ---------------------------------------------------------------\n // Private\n // ---------------------------------------------------------------\n\n private async subscribeToPush(): Promise<void> {\n if (!this.swRegistration) return;\n\n const subscription = await this.swRegistration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: this.urlBase64ToUint8Array(this.config.vapidPublicKey),\n });\n\n const subscriptionJSON = subscription.toJSON();\n const fingerprint = await this.getStableFingerprint();\n const contactId = this.resolveContactId();\n\n await this.retryApiCall(() =>\n this.apiClient.post(\n '/v1/web_push/subscriptions',\n {\n contact_id: contactId,\n endpoint: subscriptionJSON.endpoint!,\n p256dh: subscriptionJSON.keys!.p256dh!,\n auth: subscriptionJSON.keys!.auth!,\n device_fingerprint: fingerprint,\n user_agent: navigator.userAgent,\n },\n { 'X-Property-Id': this.config.propertyId }\n )\n );\n\n this.trackPushEvent('push.subscribed', {\n browser: this.getBrowserInfo(),\n property_id: this.config.propertyId,\n });\n }\n\n /**\n * Stable SHA-256 device fingerprint over (first_party_cookie_id + UA stable\n * parts). Used as the UPSERT key on `(property_id, device_fingerprint)` —\n * re-subscribes after VAPID rotation or permission reset update the same\n * row instead of leaving dangling duplicates.\n */\n private async getStableFingerprint(): Promise<string> {\n const cookieId = this.config.firstPartyCookieId;\n const ua = navigator.userAgent || '';\n const platform = navigator.platform || '';\n const language = navigator.language || '';\n const input = `${cookieId}|${ua}|${platform}|${language}`;\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const bytes = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n }\n // Fallback only reachable in environments without Web Crypto —\n // push-capable browsers all have it, so this is defensive.\n let h = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return `fnv-${h.toString(16)}`;\n }\n\n /**\n * Resolve the current contact_id. AegisWebPush doesn't own identity, so\n * we look in a few well-known localStorage keys that the identity layer\n * of the SDK writes. If no known contact is set, we use the first-party\n * cookie id — the backend upgrades the row when identify() is called.\n */\n private resolveContactId(): string {\n try {\n const fromStorage =\n window.localStorage.getItem('aegis_contact_id') ||\n window.localStorage.getItem('aegis_user_id');\n if (fromStorage) return fromStorage;\n } catch {\n // storage blocked — fall through\n }\n return this.config.firstPartyCookieId;\n }\n\n /**\n * Retry an API call with exponential backoff (max 3 retries: 1s, 2s, 4s).\n */\n private async retryApiCall(fn: () => Promise<unknown>, maxRetries = 3): Promise<void> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n await fn();\n return;\n } catch (err) {\n if (attempt === maxRetries) {\n console.error('[AegisWebPush] API call failed after retries:', err);\n return;\n }\n const delay = 1000 * Math.pow(2, attempt);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n }\n\n /**\n * Handle messages forwarded from the service worker (push click, dismiss).\n */\n private handleSWMessage(data: Record<string, unknown>): void {\n if (!data || typeof data.type !== 'string') return;\n\n switch (data.type) {\n case 'push.clicked': {\n this.trackPushEvent('push.clicked', {\n campaign_id: data.campaign_id,\n action_url: data.action_url,\n action_type: data.action_type,\n });\n this.dispatchPushTap(data);\n break;\n }\n case 'push.dismissed':\n this.trackPushEvent('push.dismissed', {\n campaign_id: data.campaign_id,\n });\n this.emit('push-dismissed', {\n campaign_id: data.campaign_id as string | undefined,\n });\n break;\n case 'push.delivered':\n this.trackPushEvent('push.delivered', {\n campaign_id: data.campaign_id,\n });\n this.emit('push-shown', {\n campaign_id: data.campaign_id as string | undefined,\n degraded: data.degraded === true ? true : undefined,\n });\n break;\n case 'push.resubscribed':\n // SW caught a pushsubscriptionchange event and minted a new\n // push subscription. The browser side now has a fresh\n // endpoint; cell-plane still has the old one. Push the\n // updated payload up so the UPSERT keeps the row alive.\n // Without this, FCM pushes go to a dead endpoint with no\n // visible failure (FCM 201s regardless of token validity).\n void this.persistResubscription(\n data.subscription as PushSubscriptionJSON | undefined\n );\n break;\n }\n }\n\n /**\n * Translate a SW `push.clicked` postMessage into a typed PushTapEvent,\n * dispatch through the lifecycle hook bus, and fall back to a hard\n * navigation if no host handler claimed it.\n *\n * The fallback path matters: if a tenant ships a push template with\n * an unknown `action_type` (no SPA handler registered) OR pushes the\n * SDK before the host wires up its `onPushTap` subscriber, we still\n * want the user to land somewhere — `action_url` is always set by the\n * SW's notificationclick handler (it falls back to '/').\n */\n private dispatchPushTap(data: Record<string, unknown>): void {\n if (typeof window === 'undefined') return;\n const actionUrl = (data.action_url as string) || '/';\n let defaultPrevented = false;\n const evt: PushTapEvent = {\n action_type: data.action_type as string | undefined,\n action_payload: data.action_payload as Record<string, unknown> | undefined,\n action_url: actionUrl,\n action: (data.action as string) || 'default',\n campaign_id: data.campaign_id as string | undefined,\n preventDefault: () => {\n defaultPrevented = true;\n evt.defaultPrevented = true;\n },\n defaultPrevented: false,\n };\n const proceed = this.emit('push-tap', evt);\n if (proceed && !defaultPrevented) {\n // No subscriber claimed this tap (or the subscriber returned\n // void / didn't preventDefault). Default to a hard nav so the\n // user always lands somewhere actionable. SPAs that want\n // in-place handling MUST return false from their handler.\n try {\n window.location.href = actionUrl;\n } catch {\n // navigation blocked (sandboxed iframe, etc.) — host can\n // still handle via the hook\n }\n }\n }\n\n private async persistResubscription(\n subscription: PushSubscriptionJSON | undefined\n ): Promise<void> {\n if (!subscription || !subscription.endpoint || !subscription.keys) return;\n try {\n const fingerprint = await this.getStableFingerprint();\n await this.retryApiCall(() =>\n this.apiClient.post(\n '/v1/web_push/subscriptions',\n {\n contact_id: this.resolveContactId(),\n endpoint: subscription.endpoint!,\n p256dh: subscription.keys!.p256dh!,\n auth: subscription.keys!.auth!,\n device_fingerprint: fingerprint,\n user_agent: navigator.userAgent,\n },\n { 'X-Property-Id': this.config.propertyId }\n )\n );\n this.trackPushEvent('push.resubscribed', {});\n } catch (err) {\n console.warn('[AegisWebPush] persistResubscription failed:', err);\n }\n }\n\n private trackPushEvent(eventName: string, properties: Record<string, unknown>): void {\n this.eventTracker?.track(eventName, {\n ...properties,\n platform: 'web',\n browser: this.getBrowserInfo(),\n });\n }\n\n private getBrowserInfo(): string {\n const ua = navigator.userAgent;\n if (ua.includes('Edg')) return 'edge';\n if (ua.includes('Chrome')) return 'chrome';\n if (ua.includes('Firefox')) return 'firefox';\n if (ua.includes('Safari')) return 'safari';\n return 'unknown';\n }\n\n private urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');\n const rawData = atob(base64);\n const arr = new Uint8Array(rawData.length);\n for (let i = 0; i < rawData.length; ++i) {\n arr[i] = rawData.charCodeAt(i);\n }\n return arr;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AegisWebPush.js","sources":["../../src/push/AegisWebPush.ts"],"sourcesContent":["export interface AegisAPIClient {\n post(\n endpoint: string,\n payload: Record<string, unknown>,\n headers?: Record<string, string>\n ): Promise<unknown>;\n}\n\nexport interface ContactIdentity {\n contactId?: string;\n shopifyCustomerId?: string;\n email?: string;\n}\n\nexport interface AegisWebPushConfig {\n vapidPublicKey: string;\n // SubscriptionProperty binding — supplied by the embedding host (e.g.\n // the storefront SSR via the `sdk.property_id` field on /store/{slug}).\n // Required: every subscribe call sends it back as `X-Property-Id` so\n // the backend pins the row to the right origin.\n propertyId: string;\n // Stable per-browser cookie id (e.g. aegis_fpc). Used as the\n // device-fingerprint salt so a fresh subscribe after VAPID rotation\n // upserts onto the same `web_push_subscriptions` row.\n firstPartyCookieId: string;\n autoPrompt?: boolean;\n promptDelay?: number;\n serviceWorkerPath?: string;\n serviceWorkerScope?: string;\n // Engagement-event reporting credentials. When BOTH `writeKey` and\n // `organizationId` are provided AND the caller does NOT pass an\n // explicit `eventTracker` to the constructor, AegisWebPush auto-wires\n // a built-in tracker that POSTs push lifecycle events\n // (push.delivered / push.dismissed / push.clicked) to\n // `/v1/push/engagement` — closing the long-standing gap where shown\n // + dismissed signals (only the device-side SDK can report them)\n // never reached `aegis.delivery_events`. See backend dual-route at\n // `apps/event-ingress/src/services/event-switchboard.ts`\n // (SDK_ENGAGEMENT_EVENT_TO_DELIVERY_MAPPING).\n //\n // Callers using `AegisMessageRuntime` should keep passing the\n // runtime's analytics adapter as `eventTracker` — these fields are\n // only the standalone-init fallback.\n writeKey?: string;\n organizationId?: string;\n}\n\nexport interface PushEventTracker {\n track(eventName: string, properties: Record<string, unknown>): void;\n}\n\n/**\n * Payload for the `push-tap` lifecycle event. CANCELLABLE — return `false`\n * (or call `evt.preventDefault()`) from a handler to suppress the SDK's\n * default `window.location.href` fallback navigation. Use this to dispatch\n * an in-place state change in a SPA host instead of a hard reload.\n *\n * `action_type` + `action_payload` are author-controlled fields baked into\n * the push template's `data` block:\n *\n * ```json\n * {\n * \"title\": \"Your cart is waiting\",\n * \"body\": \"...\",\n * \"action_url\": \"https://shop.actii.me/?step=cart\",\n * \"data\": {\n * \"action_type\": \"open_cart\",\n * \"action_payload\": { \"step\": \"cart\" }\n * }\n * }\n * ```\n */\nexport interface PushTapEvent {\n /** Author-controlled action discriminator (e.g. `open_cart`,\n * `open_payment_link`, `open_order`). When unset, the SDK runs its\n * default fallback navigation to `action_url`. */\n action_type?: string;\n /** Optional structured args the host SPA forwards to its handler. */\n action_payload?: Record<string, unknown>;\n /** Sanitized destination URL — used as the SDK's default fallback nav\n * target when no host handler cancels. */\n action_url: string;\n /** Action-button id when the user clicked a specific button on a\n * multi-button notification; `'default'` for body taps. */\n action: string;\n /** Source campaign id from the push payload — useful for SPA routing\n * (e.g. open_cart from a cart-recovery campaign vs from a generic\n * catch-all template). */\n campaign_id?: string;\n /** Mutate via `evt.preventDefault()` to signal the SDK to skip its\n * default hard-navigation. Identical semantics to DOM CustomEvent. */\n preventDefault: () => void;\n defaultPrevented: boolean;\n}\n\n/** Payload for `push-shown` — fires after `showNotification` resolves on\n * the SW side. The `degraded` flag is true when the SW had to fall back\n * to its minimal `{title, body}` retry path (broken icon URL etc.). */\nexport interface PushShownEvent {\n campaign_id?: string;\n degraded?: boolean;\n}\n\n/** Payload for `push-dismissed` — fires when the user closes the\n * notification without clicking. */\nexport interface PushDismissEvent {\n campaign_id?: string;\n}\n\n/** Payload for `error` — non-fatal SDK errors (subscribe failures,\n * resubscribe persist failures, host-handler throws). Wire into Sentry\n * / Datadog RUM. */\nexport interface PushErrorEvent {\n message: string;\n error: unknown;\n context: Record<string, unknown>;\n}\n\n/** Map of lifecycle event name → handler signature. Mirrors 1.8.0\n * in-app lifecycle for consistency. */\nexport interface WebPushLifecycleEventMap {\n 'push-tap': (evt: PushTapEvent) => void | false;\n 'push-shown': (evt: PushShownEvent) => void;\n 'push-dismissed': (evt: PushDismissEvent) => void;\n 'error': (evt: PushErrorEvent) => void;\n}\n\n/**\n * AegisWebPush — Web Push notification manager.\n *\n * Handles service worker registration, push subscription via VAPID,\n * token registration with the backend, and push event tracking.\n */\nexport class AegisWebPush {\n private apiClient: AegisAPIClient;\n private eventTracker: PushEventTracker | null;\n private swRegistration: ServiceWorkerRegistration | null = null;\n private config: AegisWebPushConfig;\n private initialized = false;\n\n // ── Lifecycle event bus (1.8.5) ────────────────────────────────────────\n // Typed handler registry, parity with AegisInAppManager (1.8.0).\n // Hosts register via the public `on*` methods below; calling the\n // returned unsubscribe fn removes the handler. Multiple subscribers per\n // event are supported. Cancellable events (`push-tap`) suppress the\n // SDK's default behaviour when a handler returns `false` or calls\n // `evt.preventDefault()`.\n //\n // Industry parity: matches CleverTap `notificationCallback`, OneSignal\n // `addEventListener('notificationOpened')`, MoEngage\n // `onSelfHandledClick`, WebEngage `notificationCallback`. The SW posts\n // a `push.clicked` message; this class translates that into a typed\n // PushTapEvent with cancellable default-nav behaviour.\n private hooks = new Map<string, Set<(...args: unknown[]) => void | false | undefined>>();\n\n constructor(\n apiClient: AegisAPIClient,\n config: AegisWebPushConfig,\n eventTracker?: PushEventTracker\n ) {\n this.apiClient = apiClient;\n this.config = {\n serviceWorkerPath: '/aegis-sw.js',\n serviceWorkerScope: '/',\n autoPrompt: false,\n promptDelay: 5000,\n ...config,\n };\n // Explicit eventTracker wins (typical AegisMessageRuntime flow).\n // Otherwise, if both `writeKey` and `organizationId` are configured,\n // wire the built-in tracker that POSTs to `/v1/push/engagement` so\n // standalone push installs don't silently drop lifecycle events.\n if (eventTracker) {\n this.eventTracker = eventTracker;\n } else if (this.config.writeKey && this.config.organizationId) {\n this.eventTracker = this.createBuiltinEventTracker(\n this.config.writeKey,\n this.config.organizationId,\n );\n } else {\n this.eventTracker = null;\n }\n }\n\n /** Built-in fallback that POSTs push lifecycle events to\n * `/v1/push/engagement`. The gateway forwards to event-ingress with\n * the canonical `push.<event>` event_type, which the\n * event-switchboard's SDK_ENGAGEMENT_EVENT_TO_DELIVERY_MAPPING\n * dual-routes onto `aegis.delivery_events` as\n * `channel='push', status='shown'|'dismissed'|...`. Best-effort —\n * failures are warned but never thrown (push SW callbacks shouldn't\n * reject because the analytics POST failed). */\n private createBuiltinEventTracker(\n writeKey: string,\n organizationId: string,\n ): PushEventTracker {\n const apiClient = this.apiClient;\n const propertyId = this.config.propertyId;\n const resolveContactId = () => this.resolveContactId();\n return {\n track(eventName: string, properties: Record<string, unknown>): void {\n const contactId =\n (properties.contact_id as string | undefined) ?? resolveContactId();\n const body = {\n campaign_id: (properties.campaign_id as string | undefined) || '',\n message_id: (properties.message_id as string | undefined) || '',\n event_type: eventName, // e.g. 'push.delivered' — gateway tolerates either form\n user_id: (properties.user_id as string | undefined) || contactId,\n contact_id: contactId,\n anonymous_id: (properties.anonymous_id as string | undefined) || '',\n platform: (properties.platform as string | undefined) || 'web',\n property_id: propertyId,\n metadata: (properties.metadata as Record<string, unknown> | undefined) ?? {},\n };\n const headers = {\n 'X-Aegis-Write-Key': writeKey,\n 'X-Organization-ID': organizationId,\n 'X-Property-Id': propertyId,\n };\n void Promise.resolve(\n apiClient.post('/v1/push/engagement', body, headers),\n ).catch((err) => {\n if (typeof console !== 'undefined' && console.warn) {\n console.warn('[Active Reach WebPush] engagement report failed:', err);\n }\n });\n },\n };\n }\n\n // ── Public lifecycle hook API ──────────────────────────────────────────\n\n /** Generic typed subscribe — useful when the host wants to dispatch\n * multiple events through one wrapper. For single-event subscriptions\n * prefer the `on*` sugar methods below. */\n on<E extends keyof WebPushLifecycleEventMap>(\n event: E,\n handler: WebPushLifecycleEventMap[E],\n ): () => void {\n return this.register(event, handler as never);\n }\n\n /** Subscribe to push notification taps. CANCELLABLE — return `false`\n * (or call `evt.preventDefault()`) to suppress the SDK's default\n * `window.location.href = action_url` fallback. Use this to wire a\n * SPA router into the typed `action_type` payload (e.g. open the\n * cart drawer in-place instead of a full reload). */\n onPushTap(\n handler: (evt: PushTapEvent) => void | false,\n ): () => void {\n return this.register('push-tap', handler);\n }\n\n /** Subscribe to push impressions — fires after the OS notification\n * has actually rendered. `degraded=true` when the SW fell back to\n * the minimal `{title, body}` path (broken icon, etc.). */\n onPushShown(\n handler: (evt: PushShownEvent) => void,\n ): () => void {\n return this.register('push-shown', handler);\n }\n\n /** Subscribe to push dismissals (notification closed without a tap). */\n onPushDismiss(\n handler: (evt: PushDismissEvent) => void,\n ): () => void {\n return this.register('push-dismissed', handler);\n }\n\n /** Subscribe to non-fatal SDK errors. Wire into Sentry / Datadog. */\n onError(\n handler: (evt: PushErrorEvent) => void,\n ): () => void {\n return this.register('error', handler);\n }\n\n private register<T>(\n eventName: string,\n handler: (payload: T) => void | false | undefined,\n ): () => void {\n if (!this.hooks.has(eventName)) this.hooks.set(eventName, new Set());\n this.hooks.get(eventName)!.add(handler as (...args: unknown[]) => void | false | undefined);\n return () => {\n this.hooks.get(eventName)?.delete(handler as (...args: unknown[]) => void | false | undefined);\n };\n }\n\n private emit<T>(eventName: string, payload: T): boolean {\n const handlers = this.hooks.get(eventName);\n if (!handlers || handlers.size === 0) return true;\n let proceed = true;\n for (const handler of handlers) {\n try {\n const result = (handler as (p: T) => void | false | undefined)(payload);\n if (result === false) proceed = false;\n } catch (err) {\n this.emitError(err, { event: eventName });\n }\n }\n return proceed;\n }\n\n private emitError(err: unknown, context?: Record<string, unknown>): void {\n const handlers = this.hooks.get('error');\n if (!handlers || handlers.size === 0) {\n console.warn(\n '[Active Reach WebPush] error:',\n err instanceof Error ? err.message : String(err),\n context ?? {}\n );\n return;\n }\n for (const handler of handlers) {\n try {\n (handler as (e: PushErrorEvent) => void)({\n message: err instanceof Error ? err.message : String(err),\n error: err,\n context: context ?? {},\n });\n } catch {\n // already in error path — don't loop\n }\n }\n }\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n if (!('serviceWorker' in navigator) || !('PushManager' in window)) {\n console.warn('[Active Reach WebPush] Push notifications not supported in this browser');\n return;\n }\n\n try {\n this.swRegistration = await navigator.serviceWorker.register(\n this.config.serviceWorkerPath!,\n { scope: this.config.serviceWorkerScope }\n );\n await navigator.serviceWorker.ready;\n this.initialized = true;\n\n // Listen for messages from the service worker (click/dismiss tracking,\n // and pushsubscriptionchange relay — see handleSWMessage).\n navigator.serviceWorker.addEventListener('message', (event) => {\n this.handleSWMessage(event.data);\n });\n\n // Heal endpoint drift on every page load.\n //\n // Background: when the SW updates with skipWaiting+clients.claim\n // (added in 1.7.3), some browsers — Samsung Internet most\n // aggressively, occasionally Chrome too — silently regenerate the\n // push subscription mid-flight. The SW catches the\n // pushsubscriptionchange event and resubscribes locally, but\n // historically the new endpoint never made it back to the\n // backend. Cell-plane kept FCM-pushing to the dead endpoint;\n // FCM 201s on receipt regardless of whether the token is alive,\n // so the silent failure was invisible until users complained.\n //\n // Fix: whenever permission is already granted at init time,\n // re-run subscribeToPush. The pushManager.subscribe() call is\n // idempotent — it returns the existing subscription if the\n // endpoint is still valid, otherwise mints a new one — and we\n // POST the result to /v1/web_push/subscriptions which UPSERTs\n // on (property_id, device_fingerprint). One extra round-trip\n // per page load; cheap, deterministic, never need to debug\n // stale-endpoint mysteries again.\n if (typeof window !== 'undefined' && Notification.permission === 'granted') {\n this.subscribeToPush().catch((err) => {\n console.warn('[Active Reach WebPush] auto-resync subscribeToPush failed:', err);\n });\n }\n\n if (this.config.autoPrompt) {\n setTimeout(() => this.requestPermission(), this.config.promptDelay);\n }\n } catch (err) {\n console.error('[Active Reach WebPush] Service worker registration failed:', err);\n }\n }\n\n async requestPermission(): Promise<boolean> {\n const permission = await Notification.requestPermission();\n\n if (permission === 'granted') {\n await this.subscribeToPush();\n return true;\n }\n\n this.trackPushEvent('push.permission_denied', {});\n return false;\n }\n\n async identify(params: ContactIdentity): Promise<void> {\n // Persist the resolved contact_id so getStableFingerprint /\n // resolveContactId see it on the next subscribe call. Then re-run\n // the subscribe flow — the backend UPSERT on\n // (property_id, device_fingerprint) updates the existing row with\n // the new contact_id in place.\n try {\n if (params.contactId) {\n window.localStorage.setItem('aegis_contact_id', params.contactId);\n }\n } catch {\n // storage blocked — proceed anyway; subscribe() still works\n }\n\n const subscription = await this.swRegistration?.pushManager.getSubscription();\n if (!subscription) return;\n\n const subscriptionJSON = subscription.toJSON();\n const fingerprint = await this.getStableFingerprint();\n await this.retryApiCall(() =>\n this.apiClient.post(\n '/v1/web_push/subscriptions',\n {\n contact_id: params.contactId ?? this.resolveContactId(),\n endpoint: subscriptionJSON.endpoint!,\n p256dh: subscriptionJSON.keys!.p256dh!,\n auth: subscriptionJSON.keys!.auth!,\n device_fingerprint: fingerprint,\n user_agent: navigator.userAgent,\n },\n { 'X-Property-Id': this.config.propertyId }\n )\n );\n }\n\n async logout(): Promise<void> {\n const subscription = await this.swRegistration?.pushManager.getSubscription();\n if (!subscription) return;\n const subscriptionJSON = subscription.toJSON();\n const fingerprint = await this.getStableFingerprint();\n try {\n await this.apiClient.post(\n '/v1/web_push/unsubscribe',\n {\n contact_id: this.resolveContactId(),\n device_fingerprint: fingerprint,\n endpoint: subscriptionJSON.endpoint!,\n },\n { 'X-Property-Id': this.config.propertyId }\n );\n } finally {\n try {\n window.localStorage.removeItem('aegis_contact_id');\n } catch {\n // ignore\n }\n }\n }\n\n // ---------------------------------------------------------------\n // Private\n // ---------------------------------------------------------------\n\n private async subscribeToPush(): Promise<void> {\n if (!this.swRegistration) return;\n\n const subscription = await this.swRegistration.pushManager.subscribe({\n userVisibleOnly: true,\n applicationServerKey: this.urlBase64ToUint8Array(this.config.vapidPublicKey),\n });\n\n const subscriptionJSON = subscription.toJSON();\n const fingerprint = await this.getStableFingerprint();\n const contactId = this.resolveContactId();\n\n await this.retryApiCall(() =>\n this.apiClient.post(\n '/v1/web_push/subscriptions',\n {\n contact_id: contactId,\n endpoint: subscriptionJSON.endpoint!,\n p256dh: subscriptionJSON.keys!.p256dh!,\n auth: subscriptionJSON.keys!.auth!,\n device_fingerprint: fingerprint,\n user_agent: navigator.userAgent,\n },\n { 'X-Property-Id': this.config.propertyId }\n )\n );\n\n this.trackPushEvent('push.subscribed', {\n browser: this.getBrowserInfo(),\n property_id: this.config.propertyId,\n });\n }\n\n /**\n * Stable SHA-256 device fingerprint over (first_party_cookie_id + UA stable\n * parts). Used as the UPSERT key on `(property_id, device_fingerprint)` —\n * re-subscribes after VAPID rotation or permission reset update the same\n * row instead of leaving dangling duplicates.\n */\n private async getStableFingerprint(): Promise<string> {\n const cookieId = this.config.firstPartyCookieId;\n const ua = navigator.userAgent || '';\n const platform = navigator.platform || '';\n const language = navigator.language || '';\n const input = `${cookieId}|${ua}|${platform}|${language}`;\n if (typeof crypto !== 'undefined' && crypto.subtle) {\n const bytes = new TextEncoder().encode(input);\n const hash = await crypto.subtle.digest('SHA-256', bytes);\n return Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n }\n // Fallback only reachable in environments without Web Crypto —\n // push-capable browsers all have it, so this is defensive.\n let h = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n h ^= input.charCodeAt(i);\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;\n }\n return `fnv-${h.toString(16)}`;\n }\n\n /**\n * Resolve the current contact_id. AegisWebPush doesn't own identity, so\n * we look in a few well-known localStorage keys that the identity layer\n * of the SDK writes. If no known contact is set, we use the first-party\n * cookie id — the backend upgrades the row when identify() is called.\n */\n private resolveContactId(): string {\n try {\n const fromStorage =\n window.localStorage.getItem('aegis_contact_id') ||\n window.localStorage.getItem('aegis_user_id');\n if (fromStorage) return fromStorage;\n } catch {\n // storage blocked — fall through\n }\n return this.config.firstPartyCookieId;\n }\n\n /**\n * Retry an API call with exponential backoff (max 3 retries: 1s, 2s, 4s).\n */\n private async retryApiCall(fn: () => Promise<unknown>, maxRetries = 3): Promise<void> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n await fn();\n return;\n } catch (err) {\n if (attempt === maxRetries) {\n console.error('[Active Reach WebPush] API call failed after retries:', err);\n return;\n }\n const delay = 1000 * Math.pow(2, attempt);\n await new Promise((r) => setTimeout(r, delay));\n }\n }\n }\n\n /**\n * Handle messages forwarded from the service worker (push click, dismiss).\n */\n private handleSWMessage(data: Record<string, unknown>): void {\n if (!data || typeof data.type !== 'string') return;\n\n switch (data.type) {\n case 'push.clicked': {\n this.trackPushEvent('push.clicked', {\n campaign_id: data.campaign_id,\n action_url: data.action_url,\n action_type: data.action_type,\n });\n this.dispatchPushTap(data);\n break;\n }\n case 'push.dismissed':\n this.trackPushEvent('push.dismissed', {\n campaign_id: data.campaign_id,\n });\n this.emit('push-dismissed', {\n campaign_id: data.campaign_id as string | undefined,\n });\n break;\n case 'push.delivered':\n this.trackPushEvent('push.delivered', {\n campaign_id: data.campaign_id,\n });\n this.emit('push-shown', {\n campaign_id: data.campaign_id as string | undefined,\n degraded: data.degraded === true ? true : undefined,\n });\n break;\n case 'push.resubscribed':\n // SW caught a pushsubscriptionchange event and minted a new\n // push subscription. The browser side now has a fresh\n // endpoint; cell-plane still has the old one. Push the\n // updated payload up so the UPSERT keeps the row alive.\n // Without this, FCM pushes go to a dead endpoint with no\n // visible failure (FCM 201s regardless of token validity).\n void this.persistResubscription(\n data.subscription as PushSubscriptionJSON | undefined\n );\n break;\n }\n }\n\n /**\n * Translate a SW `push.clicked` postMessage into a typed PushTapEvent,\n * dispatch through the lifecycle hook bus, and fall back to a hard\n * navigation if no host handler claimed it.\n *\n * The fallback path matters: if a tenant ships a push template with\n * an unknown `action_type` (no SPA handler registered) OR pushes the\n * SDK before the host wires up its `onPushTap` subscriber, we still\n * want the user to land somewhere — `action_url` is always set by the\n * SW's notificationclick handler (it falls back to '/').\n */\n private dispatchPushTap(data: Record<string, unknown>): void {\n if (typeof window === 'undefined') return;\n const actionUrl = (data.action_url as string) || '/';\n let defaultPrevented = false;\n const evt: PushTapEvent = {\n action_type: data.action_type as string | undefined,\n action_payload: data.action_payload as Record<string, unknown> | undefined,\n action_url: actionUrl,\n action: (data.action as string) || 'default',\n campaign_id: data.campaign_id as string | undefined,\n preventDefault: () => {\n defaultPrevented = true;\n evt.defaultPrevented = true;\n },\n defaultPrevented: false,\n };\n const proceed = this.emit('push-tap', evt);\n if (proceed && !defaultPrevented) {\n // No subscriber claimed this tap (or the subscriber returned\n // void / didn't preventDefault). Default to a hard nav so the\n // user always lands somewhere actionable. SPAs that want\n // in-place handling MUST return false from their handler.\n try {\n window.location.href = actionUrl;\n } catch {\n // navigation blocked (sandboxed iframe, etc.) — host can\n // still handle via the hook\n }\n }\n }\n\n private async persistResubscription(\n subscription: PushSubscriptionJSON | undefined\n ): Promise<void> {\n if (!subscription || !subscription.endpoint || !subscription.keys) return;\n try {\n const fingerprint = await this.getStableFingerprint();\n await this.retryApiCall(() =>\n this.apiClient.post(\n '/v1/web_push/subscriptions',\n {\n contact_id: this.resolveContactId(),\n endpoint: subscription.endpoint!,\n p256dh: subscription.keys!.p256dh!,\n auth: subscription.keys!.auth!,\n device_fingerprint: fingerprint,\n user_agent: navigator.userAgent,\n },\n { 'X-Property-Id': this.config.propertyId }\n )\n );\n this.trackPushEvent('push.resubscribed', {});\n } catch (err) {\n console.warn('[Active Reach WebPush] persistResubscription failed:', err);\n }\n }\n\n private trackPushEvent(eventName: string, properties: Record<string, unknown>): void {\n this.eventTracker?.track(eventName, {\n ...properties,\n platform: 'web',\n browser: this.getBrowserInfo(),\n });\n }\n\n private getBrowserInfo(): string {\n const ua = navigator.userAgent;\n if (ua.includes('Edg')) return 'edge';\n if (ua.includes('Chrome')) return 'chrome';\n if (ua.includes('Firefox')) return 'firefox';\n if (ua.includes('Safari')) return 'safari';\n return 'unknown';\n }\n\n private urlBase64ToUint8Array(base64String: string): Uint8Array {\n const padding = '='.repeat((4 - (base64String.length % 4)) % 4);\n const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');\n const rawData = atob(base64);\n const arr = new Uint8Array(rawData.length);\n for (let i = 0; i < rawData.length; ++i) {\n arr[i] = rawData.charCodeAt(i);\n }\n return arr;\n }\n}\n"],"names":[],"mappings":"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"}
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { createContext, useState, useEffect, useContext } from "react";
2
- import { A as Aegis } from "./analytics-DGt-CSgi.mjs";
2
+ import { A as Aegis } from "./analytics-CjLItVo2.mjs";
3
3
  const AegisContext = createContext({
4
4
  aegis: null,
5
5
  isReady: false
@@ -15,7 +15,7 @@ const AegisProvider = ({
15
15
  aegis.init(writeKey, config).then(() => {
16
16
  setIsReady(true);
17
17
  }).catch((error) => {
18
- console.error("[Aegis] Initialization failed:", error);
18
+ console.error("[Active Reach] Initialization failed:", error);
19
19
  });
20
20
  return () => {
21
21
  aegis.destroy();
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","sources":["../src/integrations/react.tsx"],"sourcesContent":["import React, { createContext, useContext, useEffect, useState } from 'react';\nimport { Aegis } from '../core/analytics';\nimport { AegisConfig } from '../types/config';\n\ninterface AegisContextValue {\n aegis: Aegis | null;\n isReady: boolean;\n}\n\nconst AegisContext = createContext<AegisContextValue>({\n aegis: null,\n isReady: false,\n});\n\nexport interface AegisProviderProps {\n writeKey: string;\n config?: Partial<AegisConfig>;\n children: React.ReactNode;\n}\n\nexport const AegisProvider: React.FC<AegisProviderProps> = ({\n writeKey,\n config,\n children,\n}) => {\n const [aegis] = useState(() => new Aegis());\n const [isReady, setIsReady] = useState(false);\n\n useEffect(() => {\n aegis\n .init(writeKey, config)\n .then(() => {\n setIsReady(true);\n })\n .catch((error) => {\n console.error('[Aegis] Initialization failed:', error);\n });\n\n return () => {\n aegis.destroy();\n };\n }, [aegis, writeKey, config]);\n\n return (\n <AegisContext.Provider value={{ aegis, isReady }}>\n {children}\n </AegisContext.Provider>\n );\n};\n\nexport const useAegis = (): AegisContextValue => {\n const context = useContext(AegisContext);\n\n if (!context) {\n throw new Error('useAegis must be used within AegisProvider');\n }\n\n return context;\n};\n\nexport const useTrackEvent = () => {\n const { aegis, isReady } = useAegis();\n\n return React.useCallback(\n (eventName: string, properties?: Record<string, any>) => {\n if (isReady && aegis) {\n aegis.track(eventName, properties);\n }\n },\n [aegis, isReady]\n );\n};\n\nexport const usePageView = (\n pageName?: string,\n properties?: Record<string, any>,\n dependencies: any[] = []\n) => {\n const { aegis, isReady } = useAegis();\n\n useEffect(() => {\n if (isReady && aegis) {\n aegis.page(pageName, properties);\n }\n }, [aegis, isReady, pageName, ...dependencies]);\n};\n\nexport const useIdentifyUser = () => {\n const { aegis, isReady } = useAegis();\n\n return React.useCallback(\n (userId: string, traits?: Record<string, any>) => {\n if (isReady && aegis) {\n aegis.identify(userId, traits);\n }\n },\n [aegis, isReady]\n );\n};\n"],"names":[],"mappings":";;AASA,MAAM,eAAe,cAAiC;AAAA,EACpD,OAAO;AAAA,EACP,SAAS;AACX,CAAC;AAQM,MAAM,gBAA8C,CAAC;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,KAAK,IAAI,SAAS,MAAM,IAAI,OAAO;AAC1C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,YAAU,MAAM;AACd,UACG,KAAK,UAAU,MAAM,EACrB,KAAK,MAAM;AACV,iBAAW,IAAI;AAAA,IACjB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,cAAQ,MAAM,kCAAkC,KAAK;AAAA,IACvD,CAAC;AAEH,WAAO,MAAM;AACX,YAAM,QAAA;AAAA,IACR;AAAA,EACF,GAAG,CAAC,OAAO,UAAU,MAAM,CAAC;AAE5B,SACE,sBAAA,cAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,OAAO,UAAQ,GAC5C,QACH;AAEJ;AAEO,MAAM,WAAW,MAAyB;AAC/C,QAAM,UAAU,WAAW,YAAY;AAEvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAEA,SAAO;AACT;AAEO,MAAM,gBAAgB,MAAM;AACjC,QAAM,EAAE,OAAO,QAAA,IAAY,SAAA;AAE3B,SAAO,MAAM;AAAA,IACX,CAAC,WAAmB,eAAqC;AACvD,UAAI,WAAW,OAAO;AACpB,cAAM,MAAM,WAAW,UAAU;AAAA,MACnC;AAAA,IACF;AAAA,IACA,CAAC,OAAO,OAAO;AAAA,EAAA;AAEnB;AAEO,MAAM,cAAc,CACzB,UACA,YACA,eAAsB,CAAA,MACnB;AACH,QAAM,EAAE,OAAO,QAAA,IAAY,SAAA;AAE3B,YAAU,MAAM;AACd,QAAI,WAAW,OAAO;AACpB,YAAM,KAAK,UAAU,UAAU;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,OAAO,SAAS,UAAU,GAAG,YAAY,CAAC;AAChD;AAEO,MAAM,kBAAkB,MAAM;AACnC,QAAM,EAAE,OAAO,QAAA,IAAY,SAAA;AAE3B,SAAO,MAAM;AAAA,IACX,CAAC,QAAgB,WAAiC;AAChD,UAAI,WAAW,OAAO;AACpB,cAAM,SAAS,QAAQ,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,IACA,CAAC,OAAO,OAAO;AAAA,EAAA;AAEnB;"}
1
+ {"version":3,"file":"react.js","sources":["../src/integrations/react.tsx"],"sourcesContent":["import React, { createContext, useContext, useEffect, useState } from 'react';\nimport { Aegis } from '../core/analytics';\nimport { AegisConfig } from '../types/config';\n\ninterface AegisContextValue {\n aegis: Aegis | null;\n isReady: boolean;\n}\n\nconst AegisContext = createContext<AegisContextValue>({\n aegis: null,\n isReady: false,\n});\n\nexport interface AegisProviderProps {\n writeKey: string;\n config?: Partial<AegisConfig>;\n children: React.ReactNode;\n}\n\nexport const AegisProvider: React.FC<AegisProviderProps> = ({\n writeKey,\n config,\n children,\n}) => {\n const [aegis] = useState(() => new Aegis());\n const [isReady, setIsReady] = useState(false);\n\n useEffect(() => {\n aegis\n .init(writeKey, config)\n .then(() => {\n setIsReady(true);\n })\n .catch((error) => {\n console.error('[Active Reach] Initialization failed:', error);\n });\n\n return () => {\n aegis.destroy();\n };\n }, [aegis, writeKey, config]);\n\n return (\n <AegisContext.Provider value={{ aegis, isReady }}>\n {children}\n </AegisContext.Provider>\n );\n};\n\nexport const useAegis = (): AegisContextValue => {\n const context = useContext(AegisContext);\n\n if (!context) {\n throw new Error('useAegis must be used within AegisProvider');\n }\n\n return context;\n};\n\nexport const useTrackEvent = () => {\n const { aegis, isReady } = useAegis();\n\n return React.useCallback(\n (eventName: string, properties?: Record<string, any>) => {\n if (isReady && aegis) {\n aegis.track(eventName, properties);\n }\n },\n [aegis, isReady]\n );\n};\n\nexport const usePageView = (\n pageName?: string,\n properties?: Record<string, any>,\n dependencies: any[] = []\n) => {\n const { aegis, isReady } = useAegis();\n\n useEffect(() => {\n if (isReady && aegis) {\n aegis.page(pageName, properties);\n }\n }, [aegis, isReady, pageName, ...dependencies]);\n};\n\nexport const useIdentifyUser = () => {\n const { aegis, isReady } = useAegis();\n\n return React.useCallback(\n (userId: string, traits?: Record<string, any>) => {\n if (isReady && aegis) {\n aegis.identify(userId, traits);\n }\n },\n [aegis, isReady]\n );\n};\n"],"names":[],"mappings":";;AASA,MAAM,eAAe,cAAiC;AAAA,EACpD,OAAO;AAAA,EACP,SAAS;AACX,CAAC;AAQM,MAAM,gBAA8C,CAAC;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,CAAC,KAAK,IAAI,SAAS,MAAM,IAAI,OAAO;AAC1C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,YAAU,MAAM;AACd,UACG,KAAK,UAAU,MAAM,EACrB,KAAK,MAAM;AACV,iBAAW,IAAI;AAAA,IACjB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,cAAQ,MAAM,yCAAyC,KAAK;AAAA,IAC9D,CAAC;AAEH,WAAO,MAAM;AACX,YAAM,QAAA;AAAA,IACR;AAAA,EACF,GAAG,CAAC,OAAO,UAAU,MAAM,CAAC;AAE5B,SACE,sBAAA,cAAC,aAAa,UAAb,EAAsB,OAAO,EAAE,OAAO,UAAQ,GAC5C,QACH;AAEJ;AAEO,MAAM,WAAW,MAAyB;AAC/C,QAAM,UAAU,WAAW,YAAY;AAEvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAEA,SAAO;AACT;AAEO,MAAM,gBAAgB,MAAM;AACjC,QAAM,EAAE,OAAO,QAAA,IAAY,SAAA;AAE3B,SAAO,MAAM;AAAA,IACX,CAAC,WAAmB,eAAqC;AACvD,UAAI,WAAW,OAAO;AACpB,cAAM,MAAM,WAAW,UAAU;AAAA,MACnC;AAAA,IACF;AAAA,IACA,CAAC,OAAO,OAAO;AAAA,EAAA;AAEnB;AAEO,MAAM,cAAc,CACzB,UACA,YACA,eAAsB,CAAA,MACnB;AACH,QAAM,EAAE,OAAO,QAAA,IAAY,SAAA;AAE3B,YAAU,MAAM;AACd,QAAI,WAAW,OAAO;AACpB,YAAM,KAAK,UAAU,UAAU;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,OAAO,SAAS,UAAU,GAAG,YAAY,CAAC;AAChD;AAEO,MAAM,kBAAkB,MAAM;AACnC,QAAM,EAAE,OAAO,QAAA,IAAY,SAAA;AAE3B,SAAO,MAAM;AAAA,IACX,CAAC,QAAgB,WAAiC;AAChD,UAAI,WAAW,OAAO;AACpB,cAAM,SAAS,QAAQ,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,IACA,CAAC,OAAO,OAAO;AAAA,EAAA;AAEnB;"}
@@ -24,6 +24,8 @@
24
24
  */
25
25
  import { AegisInAppManager, type AegisInAppConfig, type InAppCampaign } from '../inapp';
26
26
  import { AegisWidgetManager, type AegisWidgetConfig } from '../widgets';
27
+ import { IntentRuleEvaluator } from '../triggers/IntentRuleEvaluator';
28
+ import { ContactScoresFetcher } from '../triggers/ContactScoresFetcher';
27
29
  export interface AegisMessageRuntimeConfig extends AegisInAppConfig {
28
30
  /** If set, a `TriggerEngine` from the SDK is wired to the WidgetManager
29
31
  * for its exit-intent / scroll-velocity / inactivity handlers. Leave
@@ -45,6 +47,16 @@ export interface AegisMessageRuntimeConfig extends AegisInAppConfig {
45
47
  export declare class AegisMessageRuntime {
46
48
  readonly inApp: AegisInAppManager;
47
49
  readonly widgets: AegisWidgetManager;
50
+ /** Shared IntentRuleEvaluator for identified-contact micro-intent
51
+ * patterns. The ContactScoresFetcher writes Layer-1 signals into its
52
+ * snapshot; IntentSnapshotCollector (if wired by the consumer) writes
53
+ * Layer-2 signals. Exposed so apps that pre-existed P4a can swap in
54
+ * their own evaluator if they need to. */
55
+ readonly intentRuleEvaluator: IntentRuleEvaluator;
56
+ /** Bridges GET /v1/sdk/contact-scores into the evaluator snapshot.
57
+ * Triggered automatically on initialize() and updateContactId(). */
58
+ readonly contactScores: ContactScoresFetcher;
59
+ private contactId?;
48
60
  private initialized;
49
61
  constructor(config: AegisMessageRuntimeConfig);
50
62
  /**
@@ -69,6 +81,29 @@ export declare class AegisMessageRuntime {
69
81
  * channel already.
70
82
  */
71
83
  onClientEvent(eventName: string, eventData?: Record<string, unknown>): void;
84
+ /**
85
+ * Notify the in-app subsystem that a tracked event occurred. Schedules
86
+ * a debounced refresh of armed campaigns so newly eligible in-app
87
+ * messages (e.g., trigger-gated on `cart_item_added`) become visible
88
+ * within ~300ms — bursts coalesce. See
89
+ * `AegisInAppManager.refreshOnEvent` for debounce semantics and why
90
+ * this matters under storefront polling.
91
+ */
92
+ track(eventName: string): void;
93
+ /**
94
+ * Notify the in-app subsystem that a URL-bound page view occurred.
95
+ * Mirrors `aegis.page()` semantics — fires `'page_view'` as the
96
+ * qualifying event so the trailing debounce covers SPA route bursts
97
+ * (history.pushState rapid-fire) without spamming the endpoint.
98
+ */
99
+ page(name?: string): void;
100
+ /**
101
+ * Notify the in-app subsystem that a SPA-logical screen view occurred
102
+ * (cart drawer open, checkout step transition — anywhere `aegis.screen()`
103
+ * is called). Refresh-on-screen lets per-screen-targeted campaigns
104
+ * arm without a URL change.
105
+ */
106
+ screen(name: string): void;
72
107
  /**
73
108
  * Conversion-aware suppression — call when the host app observes a
74
109
  * goal event (purchase / order_completed / checkout_completed / custom).
@@ -1 +1 @@
1
- {"version":3,"file":"AegisMessageRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/AegisMessageRuntime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGxE,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE;;kEAE8D;IAC9D,aAAa,CAAC,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;IACnD;;sDAEkD;IAClD,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;0EACsE;IACtE,cAAc,CAAC,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;CACtD;AAED;;;;GAIG;AACH,qBAAa,mBAAmB;IAC9B,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,yBAAyB;IAwC7C;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC;;;;;;;OAOG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD;;;;;;OAMG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAI/E;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIxC;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAMf;;;;;OAKG;IACH,YAAY,IAAI,aAAa,EAAE;CAMhC"}
1
+ {"version":3,"file":"AegisMessageRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/AegisMessageRuntime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAExE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAExE,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE;;kEAE8D;IAC9D,aAAa,CAAC,EAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;IACnD;;sDAEkD;IAClD,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;0EACsE;IACtE,cAAc,CAAC,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,CAAC;CACtD;AAED;;;;GAIG;AACH,qBAAa,mBAAmB;IAC9B,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC;;;;+CAI2C;IAC3C,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;IAClD;yEACqE;IACrE,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC;IAC7C,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,yBAAyB;IAoD7C;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBjC;;;;;;;OAOG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUvD;;;;;;OAMG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAkB/E;;;;;;;OAOG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK9B;;;;;OAKG;IACH,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAIzB;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK1B;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIxC;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAMf;;;;;OAKG;IACH,YAAY,IAAI,aAAa,EAAE;CAMhC"}
@@ -1 +1 @@
1
- !function(){var e=window.aegis=window.aegis||[];if(!e.invoked){e.invoked=!0,e.methods=["init","track","identify","page","screen","group","alias","reset","flush","use","debug","setCell","getCellInfo","getAnonymousId","getUserId","getSessionId","setConsent","grantConsent","denyConsent","hasConsent","getConsentPreferences","onConsentChange","user.login","user.logout","user.setAttribute","user.setAttributes","user.setEmail","user.setPhone","user.setHashedEmail","user.setHashedPhone","user.setBirthDate","user.setOptIn","user.setSecureToken"],e.factory=function(t){return function(){var s=Array.prototype.slice.call(arguments);return s.unshift(t),e.push(s),e}};for(var t=0;t<e.methods.length;t++){var s=e.methods[t];if(-1===s.indexOf("."))e[s]=e.factory(s);else{for(var n=s.split("."),r=e,o=0;o<n.length-1;o++)r[n[o]]=r[n[o]]||{},r=r[n[o]];r[n[n.length-1]]=e.factory(s)}}e.load=function(t,s){var n=document.createElement("script");n.type="text/javascript",n.async=!0,n.src=s&&s.cdnUrl?s.cdnUrl:"https://cdn.activereach.ai/sdk/aegis.min.js",n.onerror=function(){window.console&&console.error("Aegis SDK failed to load")};var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(n,r),e._loadOptions={key:t,options:s}},e.SNIPPET_VERSION="1.1.0"}}();
1
+ !function(){var e=window.aegis=window.aegis||[];if(!e.invoked){e.invoked=!0,e.methods=["init","track","identify","page","screen","group","alias","reset","flush","use","debug","setCell","getCellInfo","getAnonymousId","getUserId","getSessionId","setConsent","grantConsent","denyConsent","hasConsent","getConsentPreferences","onConsentChange","user.login","user.logout","user.setAttribute","user.setAttributes","user.setEmail","user.setPhone","user.setHashedEmail","user.setHashedPhone","user.setBirthDate","user.setOptIn","user.setSecureToken"],e.factory=function(t){return function(){var n=Array.prototype.slice.call(arguments);return n.unshift(t),e.push(n),e}};for(var t=0;t<e.methods.length;t++){var n=e.methods[t];if(-1===n.indexOf("."))e[n]=e.factory(n);else{for(var s=n.split("."),r=e,o=0;o<s.length-1;o++)r[s[o]]=r[s[o]]||{},r=r[s[o]];r[s[s.length-1]]=e.factory(n)}}e.load=function(t,n){var s=document.createElement("script");s.type="text/javascript",s.async=!0,s.src=n&&n.cdnUrl?n.cdnUrl:"https://cdn.activereach.ai/sdk/aegis.min.js",s.onerror=function(){window.console&&console.error("Active Reach SDK failed to load")};var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(s,r),e._loadOptions={key:t,options:n}},e.SNIPPET_VERSION="1.1.0"}}();
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Micro-Intent Engine — contact-scores fetcher (P4a bridge).
3
+ *
4
+ * Bridges `GET /v1/sdk/contact-scores` into the SDK's
5
+ * `IntentRuleEvaluator` snapshot. Without this, identified-contact
6
+ * micro-intent patterns (VIP Whisper, Win-back At-Risk, Price-Sensitive
7
+ * Nudge, etc.) cannot fire because their AND-compound rules evaluate
8
+ * `rfm_segment` / `lifecycle_stage` / `churn_risk_tier` /
9
+ * `predicted_ltv_tier` / `price_sensitivity_score` against an empty
10
+ * snapshot and always return false.
11
+ *
12
+ * Lifecycle
13
+ * ---------
14
+ * AegisMessageRuntime.initialize() → fetch if contactId known
15
+ * AegisMessageRuntime.updateContactId → fetch for the new contact
16
+ *
17
+ * The fetcher is session-deduped: a second `fetchForContact(sameId)`
18
+ * call within `dedupWindowMs` is a no-op. This stops a hot navigation
19
+ * loop from hammering the endpoint when SPA route changes re-call
20
+ * identify() with the same id.
21
+ *
22
+ * Empty state
23
+ * -----------
24
+ * The endpoint returns 204 for unknown contacts AND for contacts whose
25
+ * `scoring_tier='none'`. Either way the fetcher leaves the snapshot
26
+ * unchanged — the evaluator's leaf eval treats absent Layer-1 keys as
27
+ * null, which fail-closes any AND clause involving them. Anonymous
28
+ * patterns continue to work normally.
29
+ *
30
+ * Privacy posture
31
+ * ---------------
32
+ * The endpoint's default response is the tiered form (`predicted_ltv_tier`).
33
+ * Tenants who opt into raw `predicted_ltv` via
34
+ * `organizations.settings.score_serving_raw_ltv = true` will see the
35
+ * float on the snapshot too. Both are valid IntentSignals; rule
36
+ * authors pick whichever matches their tenant config.
37
+ *
38
+ * Plan reference: docs/architecture/MICRO_INTENT_ENGINE.md §P4a.
39
+ */
40
+ import type { IntentRuleEvaluator, IntentSnapshot } from './IntentRuleEvaluator';
41
+ /** Shape of the Layer-1 score response from /v1/sdk/contact-scores. */
42
+ export interface ContactScoresResponse {
43
+ rfm_segment?: string;
44
+ lifecycle_stage?: string;
45
+ churn_risk_tier?: 'low' | 'medium' | 'high';
46
+ predicted_ltv_tier?: 'low' | 'medium' | 'high';
47
+ predicted_ltv?: number;
48
+ price_sensitivity_score?: number;
49
+ scoring_tier?: string;
50
+ scores_updated_at?: string | null;
51
+ }
52
+ export interface ContactScoresFetcherConfig {
53
+ apiHost: string;
54
+ writeKey: string;
55
+ organizationId?: string;
56
+ /** Optional. When provided, the fetcher pushes the response into the
57
+ * evaluator's snapshot automatically on every successful fetch. */
58
+ evaluator?: IntentRuleEvaluator;
59
+ /** Minimum time between repeat fetches for the same contactId.
60
+ * Default 60 seconds. */
61
+ dedupWindowMs?: number;
62
+ /** Override for tests / non-browser environments. */
63
+ fetchImpl?: typeof fetch;
64
+ /** Console.warn channel. */
65
+ onError?: (err: unknown, contactId: string) => void;
66
+ }
67
+ export declare class ContactScoresFetcher {
68
+ private readonly apiHost;
69
+ private readonly writeKey;
70
+ private organizationId?;
71
+ private readonly evaluator?;
72
+ private readonly dedupWindowMs;
73
+ private readonly fetchImpl;
74
+ private readonly onError?;
75
+ private lastFetchedContactId?;
76
+ private lastFetchedAt;
77
+ private latestSnapshot;
78
+ constructor(cfg: ContactScoresFetcherConfig);
79
+ /** Update the org so subsequent fetches scope correctly (e.g. when
80
+ * the SDK resolves an org id after init). */
81
+ updateOrganizationId(organizationId: string | undefined): void;
82
+ /** Most recent successful response. `null` when no fetch has succeeded
83
+ * yet, OR when the endpoint returned 204 (unscored). Consumers can
84
+ * poll this for diagnostic UIs; campaign evaluation does not need to
85
+ * read it directly because the evaluator (if configured) already has
86
+ * the snapshot applied. */
87
+ getSnapshot(): Readonly<ContactScoresResponse> | null;
88
+ /** Fetch scores for `contactId` and apply to the configured evaluator
89
+ * (if any). Returns the response on success, null on 204 / error.
90
+ *
91
+ * Session-dedup: repeat calls for the same contactId within
92
+ * `dedupWindowMs` are no-ops. Pass `force: true` to override. */
93
+ fetchForContact(contactId: string, opts?: {
94
+ force?: boolean;
95
+ }): Promise<ContactScoresResponse | null>;
96
+ }
97
+ /** Project the wire response onto the evaluator's IntentSnapshot shape.
98
+ * Strings (rfm_segment / lifecycle_stage / *_tier) map straight across;
99
+ * numerics (price_sensitivity_score / predicted_ltv) are passed through
100
+ * as numbers. Missing keys are omitted so the evaluator's leaf eval
101
+ * treats them as null (per IntentRuleEvaluator semantics).
102
+ *
103
+ * Exported for the smoke test — drift guard pins the mapping. */
104
+ export declare function toIntentSnapshot(r: ContactScoresResponse): IntentSnapshot;
105
+ //# sourceMappingURL=ContactScoresFetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContactScoresFetcher.d.ts","sourceRoot":"","sources":["../../src/triggers/ContactScoresFetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEjF,uEAAuE;AACvE,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC5C,kBAAkB,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;wEACoE;IACpE,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC;8BAC0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,4BAA4B;IAC5B,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA4C;IAErE,OAAO,CAAC,oBAAoB,CAAC,CAAS;IACtC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAsC;gBAEhD,GAAG,EAAE,0BAA0B;IAU3C;kDAC8C;IAC9C,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAI9D;;;;gCAI4B;IAC5B,WAAW,IAAI,QAAQ,CAAC,qBAAqB,CAAC,GAAG,IAAI;IAIrD;;;;sEAIkE;IAC5D,eAAe,CACnB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO,GAC7B,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;CAuDzC;AAED;;;;;;kEAMkE;AAClE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,qBAAqB,GAAG,cAAc,CAYzE"}
@@ -26,7 +26,7 @@
26
26
  *
27
27
  * Plan reference: docs/architecture/MICRO_INTENT_ENGINE.md §"Schemas"
28
28
  */
29
- export type IntentSignal = 'scroll_depth' | 'time_on_page' | 'exit_intent' | 'back_button' | 'scroll_velocity' | 'inactivity' | 'visibility_change' | 'rage_click' | 'price_hover_ms' | 'cta_hover_ms' | 'cum_dwell_sku' | 'session_count_sku' | 'cart_value' | 'converted_in_session' | 'rfm_segment' | 'rfm_score' | 'lifecycle_stage' | 'purchase_intent_score' | 'purchase_intent_tier' | 'churn_risk_score' | 'churn_risk_tier' | 'predicted_ltv' | 'uninstall_risk_tier' | 'engagement_level' | 'price_tier' | 'price_sensitivity_score' | 'top_category' | 'avg_cart_value' | 'scoring_tier';
29
+ export type IntentSignal = 'scroll_depth' | 'time_on_page' | 'exit_intent' | 'back_button' | 'scroll_velocity' | 'inactivity' | 'visibility_change' | 'rage_click' | 'price_hover_ms' | 'cta_hover_ms' | 'cum_dwell_sku' | 'session_count_sku' | 'cart_value' | 'converted_in_session' | 'rfm_segment' | 'rfm_score' | 'lifecycle_stage' | 'purchase_intent_score' | 'purchase_intent_tier' | 'churn_risk_score' | 'churn_risk_tier' | 'predicted_ltv' | 'predicted_ltv_tier' | 'uninstall_risk_tier' | 'engagement_level' | 'price_tier' | 'price_sensitivity_score' | 'top_category' | 'avg_cart_value' | 'scoring_tier';
30
30
  export type Comparator = 'gte' | 'lte' | 'gt' | 'lt' | 'eq' | 'neq' | 'in' | 'nin';
31
31
  export type IntentLeafValue = number | string | boolean | ReadonlyArray<number | string | boolean>;
32
32
  export interface IntentLeaf {
@@ -1 +1 @@
1
- {"version":3,"file":"IntentRuleEvaluator.d.ts","sourceRoot":"","sources":["../../src/triggers/IntentRuleEvaluator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"IntentRuleEvaluator.d.ts","sourceRoot":"","sources":["../../src/triggers/IntentRuleEvaluator.ts"],"names":[],"mappings":"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"}
@@ -6,4 +6,6 @@ export { SelectorBinder } from './SelectorBinder';
6
6
  export type { IntentElementName, IntentDomEventType, IntentDomEvent, IntentDomHandler, IntentSelectors, SelectorBinderConfig, } from './SelectorBinder';
7
7
  export { IntentSnapshotCollector } from './IntentSnapshotCollector';
8
8
  export type { IntentSnapshotCollectorConfig } from './IntentSnapshotCollector';
9
+ export { ContactScoresFetcher, toIntentSnapshot } from './ContactScoresFetcher';
10
+ export type { ContactScoresFetcherConfig, ContactScoresResponse } from './ContactScoresFetcher';
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/triggers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,YAAY,EACZ,UAAU,EACV,eAAe,EACf,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,aAAa,EACb,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,YAAY,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/triggers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,YAAY,EACZ,UAAU,EACV,eAAe,EACf,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,aAAa,EACb,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,YAAY,EAAE,6BAA6B,EAAE,MAAM,2BAA2B,CAAC;AAG/E,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAChF,YAAY,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -62,7 +62,27 @@ export interface BaseEvent {
62
62
  anonymousId: string;
63
63
  userId?: string;
64
64
  sessionId: string;
65
+ /**
66
+ * Brand-tenant identifier. Under the post-2026-05-26 hierarchy
67
+ * (workspace = brand-tenant, location = outlet), this is the BRAND
68
+ * dimension. Use `location_id` for the outlet (within-brand)
69
+ * dimension. The two are independent — both can be set on the
70
+ * same event.
71
+ */
65
72
  workspace_id?: string | null;
73
+ /**
74
+ * P15.1 — outlet identifier (location within a brand). Stamped by
75
+ * the SDK when the storefront has resolved an active outlet via
76
+ * `aegis.setLocation(location_id)` OR when the SDK detects the
77
+ * outlet code from the URL path segment (`{brand}.actii.me/{outlet}/...`)
78
+ * and the bootstrap response surfaces a `locationCodes` allowlist.
79
+ *
80
+ * Independent of workspace_id — both can be set simultaneously on
81
+ * the same event. Required for per-outlet attribution on events
82
+ * consumed by analytics, journey triggers, and the activation
83
+ * matrix UI.
84
+ */
85
+ location_id?: string | null;
66
86
  context: EventContext;
67
87
  integrations?: Record<string, boolean>;
68
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/types/events.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,cAAM,MAAM;IACV,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAAyB;IAEvC,MAAM,IAAI,IAAI;IAId,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,OAAO;IAIpB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAK5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAK3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAI3C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CAG7C;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,cAAM,MAAM;IACV,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAAgC;IAE9C,MAAM,IAAI,IAAI;IAId,OAAO,IAAI,IAAI;IAIf,SAAS,IAAI,OAAO;IAIpB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAK5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAK3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAI3C,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CAG7C;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@active-reach/web-sdk",
3
- "version": "1.14.0",
4
- "description": "Web SDK for Active Reach Intelligence event tracking, identity resolution, in-app messaging, web push, and placements",
3
+ "version": "1.15.0",
4
+ "description": "Web SDK for Active Reach Intelligence \u2014 event tracking, identity resolution, in-app messaging, web push, and placements",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
7
7
  "browser": "./dist/aegis.min.js",
@@ -56,11 +56,12 @@
56
56
  "devDependencies": {
57
57
  "@types/node": "^20.10.0",
58
58
  "@types/react": "^18.3.1",
59
+ "eslint": "^9.16.0",
60
+ "jsdom": "^25.0.1",
61
+ "terser": "^5.27.0",
59
62
  "typescript": "^5.6.2",
60
63
  "vite": "^6.4.2",
61
- "vitest": "^3.2.1",
62
- "eslint": "^9.16.0",
63
- "terser": "^5.27.0"
64
+ "vitest": "^3.2.1"
64
65
  },
65
66
  "peerDependencies": {
66
67
  "react": ">=18.0.0"