@active-reach/web-sdk 1.41.0 → 1.43.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/package.json +1 -1
- package/dist/aegis-push.min.js +0 -2
- package/dist/aegis-push.min.js.map +0 -1
- package/dist/aegis-sw.js +0 -1
- package/dist/aegis.min.js +0 -2
- package/dist/aegis.min.js.map +0 -1
- package/dist/analytics-C-Go3Pm5.mjs +0 -3509
- package/dist/analytics-C-Go3Pm5.mjs.map +0 -1
- package/dist/cdn.d.ts +0 -26
- package/dist/cdn.d.ts.map +0 -1
- package/dist/chat/AegisChat.d.ts +0 -169
- package/dist/chat/AegisChat.d.ts.map +0 -1
- package/dist/chat/index.d.ts +0 -3
- package/dist/chat/index.d.ts.map +0 -1
- package/dist/core/analytics.d.ts +0 -320
- package/dist/core/analytics.d.ts.map +0 -1
- package/dist/core/bootstrap.d.ts +0 -96
- package/dist/core/bootstrap.d.ts.map +0 -1
- package/dist/core/prefetch-bundle-client.d.ts +0 -175
- package/dist/core/prefetch-bundle-client.d.ts.map +0 -1
- package/dist/core/queue.d.ts +0 -35
- package/dist/core/queue.d.ts.map +0 -1
- package/dist/core/rate-limiter.d.ts +0 -45
- package/dist/core/rate-limiter.d.ts.map +0 -1
- package/dist/core/sdk-config-poller.d.ts +0 -59
- package/dist/core/sdk-config-poller.d.ts.map +0 -1
- package/dist/core/session.d.ts +0 -52
- package/dist/core/session.d.ts.map +0 -1
- package/dist/core/transport.d.ts +0 -50
- package/dist/core/transport.d.ts.map +0 -1
- package/dist/core/user-namespace.d.ts +0 -48
- package/dist/core/user-namespace.d.ts.map +0 -1
- package/dist/ecommerce/index.d.ts +0 -94
- package/dist/ecommerce/index.d.ts.map +0 -1
- package/dist/ecommerce/types.d.ts +0 -81
- package/dist/ecommerce/types.d.ts.map +0 -1
- package/dist/governance/bloom-filter.d.ts +0 -47
- package/dist/governance/bloom-filter.d.ts.map +0 -1
- package/dist/governance/index.d.ts +0 -8
- package/dist/governance/index.d.ts.map +0 -1
- package/dist/governance/murmur3.d.ts +0 -43
- package/dist/governance/murmur3.d.ts.map +0 -1
- package/dist/governance/name-governor.d.ts +0 -98
- package/dist/governance/name-governor.d.ts.map +0 -1
- package/dist/governance/trait-governor.d.ts +0 -63
- package/dist/governance/trait-governor.d.ts.map +0 -1
- package/dist/inapp/AegisInAppManager.d.ts +0 -877
- package/dist/inapp/AegisInAppManager.d.ts.map +0 -1
- package/dist/inapp/actions.d.ts +0 -91
- package/dist/inapp/actions.d.ts.map +0 -1
- package/dist/inapp/devicePairing.d.ts +0 -70
- package/dist/inapp/devicePairing.d.ts.map +0 -1
- package/dist/inapp/eval-throttle.d.ts +0 -33
- package/dist/inapp/eval-throttle.d.ts.map +0 -1
- package/dist/inapp/font.d.ts +0 -16
- package/dist/inapp/font.d.ts.map +0 -1
- package/dist/inapp/index.d.ts +0 -8
- package/dist/inapp/index.d.ts.map +0 -1
- package/dist/inapp/lucide-svg.d.ts +0 -46
- package/dist/inapp/lucide-svg.d.ts.map +0 -1
- package/dist/inapp/renderPreview.d.ts +0 -40
- package/dist/inapp/renderPreview.d.ts.map +0 -1
- package/dist/inapp/renderers/active-web-chat.d.ts +0 -45
- package/dist/inapp/renderers/active-web-chat.d.ts.map +0 -1
- package/dist/inapp/renderers/card-style.d.ts +0 -31
- package/dist/inapp/renderers/card-style.d.ts.map +0 -1
- package/dist/inapp/renderers/card-template.d.ts +0 -233
- package/dist/inapp/renderers/card-template.d.ts.map +0 -1
- package/dist/inapp/renderers/carousel-cards.d.ts +0 -15
- package/dist/inapp/renderers/carousel-cards.d.ts.map +0 -1
- package/dist/inapp/renderers/coachmark-tour.d.ts +0 -24
- package/dist/inapp/renderers/coachmark-tour.d.ts.map +0 -1
- package/dist/inapp/renderers/games.d.ts +0 -27
- package/dist/inapp/renderers/games.d.ts.map +0 -1
- package/dist/inapp/renderers/hero.d.ts +0 -23
- package/dist/inapp/renderers/hero.d.ts.map +0 -1
- package/dist/inapp/renderers/index.d.ts +0 -22
- package/dist/inapp/renderers/index.d.ts.map +0 -1
- package/dist/inapp/renderers/interactive-contract.d.ts +0 -48
- package/dist/inapp/renderers/interactive-contract.d.ts.map +0 -1
- package/dist/inapp/renderers/product-recommendation.d.ts +0 -37
- package/dist/inapp/renderers/product-recommendation.d.ts.map +0 -1
- package/dist/inapp/renderers/progress-bar.d.ts +0 -38
- package/dist/inapp/renderers/progress-bar.d.ts.map +0 -1
- package/dist/inapp/renderers/progress-core.d.ts +0 -80
- package/dist/inapp/renderers/progress-core.d.ts.map +0 -1
- package/dist/inapp/renderers/reviews.d.ts +0 -38
- package/dist/inapp/renderers/reviews.d.ts.map +0 -1
- package/dist/inapp/renderers/sticky-bar.d.ts +0 -14
- package/dist/inapp/renderers/sticky-bar.d.ts.map +0 -1
- package/dist/inapp/renderers/stories.d.ts +0 -31
- package/dist/inapp/renderers/stories.d.ts.map +0 -1
- package/dist/inapp/renderers/types.d.ts +0 -147
- package/dist/inapp/renderers/types.d.ts.map +0 -1
- package/dist/inapp/renderers/video.d.ts +0 -20
- package/dist/inapp/renderers/video.d.ts.map +0 -1
- package/dist/inbox/AegisInbox.d.ts +0 -106
- package/dist/inbox/AegisInbox.d.ts.map +0 -1
- package/dist/inbox/index.d.ts +0 -3
- package/dist/inbox/index.d.ts.map +0 -1
- package/dist/index.d.ts +0 -40
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -15127
- package/dist/index.js.map +0 -1
- package/dist/integrations/react.d.ts +0 -19
- package/dist/integrations/react.d.ts.map +0 -1
- package/dist/loyalty/AegisLoyaltyManager.d.ts +0 -120
- package/dist/loyalty/AegisLoyaltyManager.d.ts.map +0 -1
- package/dist/loyalty/index.d.ts +0 -3
- package/dist/loyalty/index.d.ts.map +0 -1
- package/dist/plugins/registry.d.ts +0 -13
- package/dist/plugins/registry.d.ts.map +0 -1
- package/dist/push/AegisWebPush.d.ts +0 -199
- package/dist/push/AegisWebPush.d.ts.map +0 -1
- package/dist/push/AegisWebPush.js +0 -542
- package/dist/push/AegisWebPush.js.map +0 -1
- package/dist/push/cdn-push.d.ts +0 -21
- package/dist/push/cdn-push.d.ts.map +0 -1
- package/dist/react.js +0 -70
- package/dist/react.js.map +0 -1
- package/dist/runtime/AegisMessageRuntime.d.ts +0 -274
- package/dist/runtime/AegisMessageRuntime.d.ts.map +0 -1
- package/dist/runtime/index.d.ts +0 -3
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/snippet.min.js +0 -1
- package/dist/state/intent_ledger.d.ts +0 -136
- package/dist/state/intent_ledger.d.ts.map +0 -1
- package/dist/triggers/ContactScoresFetcher.d.ts +0 -113
- package/dist/triggers/ContactScoresFetcher.d.ts.map +0 -1
- package/dist/triggers/IntentRuleEvaluator.d.ts +0 -213
- package/dist/triggers/IntentRuleEvaluator.d.ts.map +0 -1
- package/dist/triggers/IntentSnapshotCollector.d.ts +0 -83
- package/dist/triggers/IntentSnapshotCollector.d.ts.map +0 -1
- package/dist/triggers/SelectorBinder.d.ts +0 -118
- package/dist/triggers/SelectorBinder.d.ts.map +0 -1
- package/dist/triggers/TriggerEngine.d.ts +0 -296
- package/dist/triggers/TriggerEngine.d.ts.map +0 -1
- package/dist/triggers/behaviouralTriggers.d.ts +0 -41
- package/dist/triggers/behaviouralTriggers.d.ts.map +0 -1
- package/dist/triggers/index.d.ts +0 -11
- package/dist/triggers/index.d.ts.map +0 -1
- package/dist/types/config.d.ts +0 -77
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/events.d.ts +0 -147
- package/dist/types/events.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -5
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/plugin.d.ts +0 -21
- package/dist/types/plugin.d.ts.map +0 -1
- package/dist/types/type-safe-events.d.ts +0 -14
- package/dist/types/type-safe-events.d.ts.map +0 -1
- package/dist/utils/canonical-identity.d.ts +0 -29
- package/dist/utils/canonical-identity.d.ts.map +0 -1
- package/dist/utils/consent.d.ts +0 -40
- package/dist/utils/consent.d.ts.map +0 -1
- package/dist/utils/debounce.d.ts +0 -3
- package/dist/utils/debounce.d.ts.map +0 -1
- package/dist/utils/device.d.ts +0 -6
- package/dist/utils/device.d.ts.map +0 -1
- package/dist/utils/identity.d.ts +0 -27
- package/dist/utils/identity.d.ts.map +0 -1
- package/dist/utils/index.d.ts +0 -7
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/logger.d.ts +0 -15
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/meta-cookies.d.ts +0 -65
- package/dist/utils/meta-cookies.d.ts.map +0 -1
- package/dist/utils/redact-url.d.ts +0 -56
- package/dist/utils/redact-url.d.ts.map +0 -1
- package/dist/utils/storage.d.ts +0 -20
- package/dist/utils/storage.d.ts.map +0 -1
- package/dist/utils/url-parser.d.ts +0 -61
- package/dist/utils/url-parser.d.ts.map +0 -1
- package/dist/utils/uuid.d.ts +0 -4
- package/dist/utils/uuid.d.ts.map +0 -1
- package/dist/utils/visitor.d.ts +0 -43
- package/dist/utils/visitor.d.ts.map +0 -1
- package/dist/widgets/AegisWidgetManager.d.ts +0 -209
- package/dist/widgets/AegisWidgetManager.d.ts.map +0 -1
- package/dist/widgets/index.d.ts +0 -3
- package/dist/widgets/index.d.ts.map +0 -1
|
@@ -1,877 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AegisInAppManager - Web SDK In-App Messaging Module
|
|
3
|
-
*
|
|
4
|
-
* HTTP polling architecture with client-side evaluation.
|
|
5
|
-
*
|
|
6
|
-
* Security:
|
|
7
|
-
* - XSS Protection: Uses DOM APIs (createElement, textContent) instead of innerHTML
|
|
8
|
-
* - URL Validation: Prevents javascript: protocol injection
|
|
9
|
-
* - CSP Compatible: No inline styles in HTML strings
|
|
10
|
-
*
|
|
11
|
-
* Architecture (RFC 2026-04-16):
|
|
12
|
-
* - Polls /v1/in-app/active on initialize + on identity change
|
|
13
|
-
* - Caches campaigns locally in memory
|
|
14
|
-
* - Evaluates trigger rules client-side
|
|
15
|
-
* - Tracks events (impression, click, dismiss) asynchronously
|
|
16
|
-
*
|
|
17
|
-
* NOTE: Persistent SSE for downstream delivery is disabled by default
|
|
18
|
-
* (enableSSE=false). Tenant dashboards that need realtime (inbox, chat,
|
|
19
|
-
* live page) open SSE directly via Next.js API routes — not via this SDK.
|
|
20
|
-
* End-user storefronts use polling + Web Push for background delivery.
|
|
21
|
-
*/
|
|
22
|
-
import type { CartState } from './renderers';
|
|
23
|
-
import { type AegisAction } from './actions';
|
|
24
|
-
export interface InAppCampaign {
|
|
25
|
-
id: string;
|
|
26
|
-
type: 'modal' | 'banner' | 'tooltip' | 'full_screen' | 'half_interstitial' | 'alert' | 'pip' | 'video' | 'stories' | 'carousel_cards' | 'sticky_bar' | 'progress_bar' | 'coachmark_tour' | 'product_recommendation' | 'active_web_chat' | 'custom_html';
|
|
27
|
-
sub_type?: string;
|
|
28
|
-
title: string;
|
|
29
|
-
body: string;
|
|
30
|
-
image_url?: string;
|
|
31
|
-
video_url?: string;
|
|
32
|
-
action_url?: string;
|
|
33
|
-
button_text?: string;
|
|
34
|
-
background_color?: string;
|
|
35
|
-
text_color?: string;
|
|
36
|
-
priority: number;
|
|
37
|
-
expires_at?: string;
|
|
38
|
-
frequency?: {
|
|
39
|
-
max_impressions?: number;
|
|
40
|
-
max_impressions_per_day?: number;
|
|
41
|
-
cooldown_seconds?: number;
|
|
42
|
-
suppress_after_conversion_seconds?: number;
|
|
43
|
-
suppress_after_dismiss_seconds?: number;
|
|
44
|
-
scope?: 'session' | 'user' | 'user_sku';
|
|
45
|
-
};
|
|
46
|
-
interactive_config?: Record<string, unknown>;
|
|
47
|
-
client_trigger?: {
|
|
48
|
-
type: string;
|
|
49
|
-
config?: Record<string, unknown>;
|
|
50
|
-
};
|
|
51
|
-
assigned_variant_id?: string;
|
|
52
|
-
delivery_modes?: Array<'in_app_overlay' | 'embedded_card' | 'standalone_page'>;
|
|
53
|
-
widget_category?: 'feedback' | 'loyalty' | 'promo' | 'commerce' | 'support' | 'custom' | 'onboarding' | 'hero' | 'announcement' | 'reorder' | 'reviews';
|
|
54
|
-
page_key?: 'bill' | 'rewards' | 'feedback' | 'reviews' | 'members';
|
|
55
|
-
surface?: string[];
|
|
56
|
-
target_screens?: string[];
|
|
57
|
-
journey_step_execution_id?: string | null;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Payload for `campaign-click` lifecycle event. CANCELLABLE — return `false`
|
|
61
|
-
* (or call `evt.preventDefault()`) from the handler to suppress the SDK's
|
|
62
|
-
* default `window.location.href` navigation, e.g. to route via a SPA router.
|
|
63
|
-
*/
|
|
64
|
-
export interface CampaignClickEvent {
|
|
65
|
-
campaign: InAppCampaign;
|
|
66
|
-
/** Sanitized destination URL — already passed through `sanitizeUrl()`. */
|
|
67
|
-
action_url: string;
|
|
68
|
-
/** Best-effort button identifier — populated when the click came from a
|
|
69
|
-
* named button in a multi-button campaign (modals, alerts). `cta` for the
|
|
70
|
-
* primary CTA on single-button campaigns. */
|
|
71
|
-
button_id?: string;
|
|
72
|
-
/** Mutate via `evt.preventDefault()` to signal the SDK to skip its
|
|
73
|
-
* default hard-navigation. Identical semantics to DOM CustomEvent. */
|
|
74
|
-
preventDefault: () => void;
|
|
75
|
-
defaultPrevented: boolean;
|
|
76
|
-
}
|
|
77
|
-
/** Payload for `campaign-dismiss` lifecycle event. */
|
|
78
|
-
export interface CampaignDismissEvent {
|
|
79
|
-
campaign: InAppCampaign;
|
|
80
|
-
/** Source of dismissal — close button, swipe, ESC key, programmatic. */
|
|
81
|
-
source: 'close_button' | 'overlay' | 'esc' | 'auto_timeout' | 'programmatic';
|
|
82
|
-
}
|
|
83
|
-
/** Payload for `error` lifecycle event. Aggregates non-fatal SDK errors so
|
|
84
|
-
* host apps can wire them into Sentry / Datadog RUM / similar. */
|
|
85
|
-
export interface AegisErrorEvent {
|
|
86
|
-
message: string;
|
|
87
|
-
error: unknown;
|
|
88
|
-
/** Optional structured context — `{ event: 'campaign-click' }` for handler
|
|
89
|
-
* throws, `{ campaign_id, stage }` for render path failures, etc. */
|
|
90
|
-
context: Record<string, unknown>;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Map of lifecycle event name → handler signature. Used by the typed
|
|
94
|
-
* `on(event, handler)` overload below so TS correctly narrows the payload
|
|
95
|
-
* type per event without a discriminated union at the call site.
|
|
96
|
-
*/
|
|
97
|
-
export interface InAppLifecycleEventMap {
|
|
98
|
-
'campaigns-loaded': (campaigns: InAppCampaign[]) => void;
|
|
99
|
-
'campaign-will-show': (campaign: InAppCampaign) => void | false;
|
|
100
|
-
'campaign-shown': (campaign: InAppCampaign) => void;
|
|
101
|
-
'campaign-click': (evt: CampaignClickEvent) => void | false;
|
|
102
|
-
'campaign-dismiss': (evt: CampaignDismissEvent) => void;
|
|
103
|
-
'error': (evt: AegisErrorEvent) => void;
|
|
104
|
-
}
|
|
105
|
-
export interface AegisInAppConfig {
|
|
106
|
-
writeKey: string;
|
|
107
|
-
apiHost?: string;
|
|
108
|
-
userId?: string;
|
|
109
|
-
contactId?: string;
|
|
110
|
-
/** Server-minted proof of `contactId` (S/C1). Without it, in-app answers are
|
|
111
|
-
* kept as anonymous events and never written onto the contact's profile. */
|
|
112
|
-
contactToken?: string;
|
|
113
|
-
organizationId?: string;
|
|
114
|
-
propertyId?: string;
|
|
115
|
-
debugMode?: boolean;
|
|
116
|
-
enableSSE?: boolean;
|
|
117
|
-
/**
|
|
118
|
-
* Canonical CTA-action handler (CANONICAL_ACTION_MODEL_TRACKER.md). ONE host
|
|
119
|
-
* callback receives every CTA action (add_to_cart / open_product / open_cart /
|
|
120
|
-
* open_login / navigate / custom …) — the CEP-standard shape. Return `true`
|
|
121
|
-
* when handled; otherwise the SDK applies the canonical fallback (navigate to
|
|
122
|
-
* the product/cart page) so a CTA is never a dead no-op. Legacy `aegis:*` DOM
|
|
123
|
-
* events still fire alongside this during the migration.
|
|
124
|
-
*/
|
|
125
|
-
onAction?: (action: AegisAction) => boolean | void;
|
|
126
|
-
/**
|
|
127
|
-
* Platform-aware product-URL resolver (sku → PDP url). Lets a Shopify/Woo/
|
|
128
|
-
* Magento adapter map to `/products/{handle}` etc. instead of the canonical
|
|
129
|
-
* `/p/{sku}`. Defaults to `/p/{sku}` when unset.
|
|
130
|
-
*/
|
|
131
|
-
productUrl?: (sku: string) => string;
|
|
132
|
-
/**
|
|
133
|
-
* Workspace cascade reader. Set this from the host SDK as
|
|
134
|
-
* `getWorkspaceId: () => aegis.getEffectiveWorkspaceId()` so in-app
|
|
135
|
-
* impressions/clicks/dismisses carry the same workspace context the
|
|
136
|
-
* main analytics SDK sees (URL path slug, ?ws=, setWorkspace runtime).
|
|
137
|
-
* Without it, in-app engagement events arrive at event-ingress with
|
|
138
|
-
* no workspace_id stamped → cross-outlet attribution silently falls
|
|
139
|
-
* back to the org's primary workspace.
|
|
140
|
-
*/
|
|
141
|
-
getWorkspaceId?: () => string | undefined;
|
|
142
|
-
/**
|
|
143
|
-
* Live cart-state reader, set by the runtime from its imperative
|
|
144
|
-
* `setCartState(...)`. Threaded into the renderer `RenderContext` so the
|
|
145
|
-
* progress-bar renderer can read a first-party cart value instead of
|
|
146
|
-
* `window.*` cart globals. Undefined for embeds that never feed a cart.
|
|
147
|
-
*/
|
|
148
|
-
getCartState?: () => CartState | undefined;
|
|
149
|
-
}
|
|
150
|
-
export declare function productIdentitiesFor(campaign: unknown): string | undefined;
|
|
151
|
-
export declare class AegisInAppManager {
|
|
152
|
-
private writeKey;
|
|
153
|
-
private apiHost;
|
|
154
|
-
private userId?;
|
|
155
|
-
private contactId?;
|
|
156
|
-
private contactToken?;
|
|
157
|
-
private organizationId?;
|
|
158
|
-
private propertyId?;
|
|
159
|
-
private debugMode;
|
|
160
|
-
private enableSSE;
|
|
161
|
-
private onActionHandler?;
|
|
162
|
-
private productUrl;
|
|
163
|
-
private getWorkspaceId?;
|
|
164
|
-
private getCartState?;
|
|
165
|
-
private campaigns;
|
|
166
|
-
private displayedCampaigns;
|
|
167
|
-
private _displaySizeMul;
|
|
168
|
-
private suppressedUntil;
|
|
169
|
-
private eventSource?;
|
|
170
|
-
private isInitialized;
|
|
171
|
-
private reconnectAttempts;
|
|
172
|
-
private maxReconnectAttempts;
|
|
173
|
-
private static readonly CONVERSION_STORAGE_PREFIX;
|
|
174
|
-
private hooks;
|
|
175
|
-
private readyResolve;
|
|
176
|
-
readonly ready: Promise<void>;
|
|
177
|
-
private emit;
|
|
178
|
-
private emitError;
|
|
179
|
-
private register;
|
|
180
|
-
/**
|
|
181
|
-
* Subscribe to in-app message lifecycle events. Returns an unsubscribe
|
|
182
|
-
* function — call to remove the handler (matches React `useEffect` cleanup
|
|
183
|
-
* convention).
|
|
184
|
-
*
|
|
185
|
-
* Supported events: `campaigns-loaded`, `campaign-will-show` (cancellable),
|
|
186
|
-
* `campaign-shown`, `campaign-click` (cancellable), `campaign-dismiss`,
|
|
187
|
-
* `error`. Cancellable events: handler returns `false` to suppress the
|
|
188
|
-
* SDK's default behaviour (e.g., prevent the hard navigation on click,
|
|
189
|
-
* skip rendering on will-show).
|
|
190
|
-
*/
|
|
191
|
-
on<E extends keyof InAppLifecycleEventMap>(event: E, handler: InAppLifecycleEventMap[E]): () => void;
|
|
192
|
-
/** Sugar: subscribe to `campaigns-loaded`. Fires after every successful
|
|
193
|
-
* `/v1/in-app/active` poll with the full active-campaign list. */
|
|
194
|
-
onCampaignsLoaded(handler: (campaigns: InAppCampaign[]) => void): () => void;
|
|
195
|
-
/** Sugar: subscribe to `campaign-will-show`. CANCELLABLE — return `false`
|
|
196
|
-
* to suppress rendering this campaign (host-side suppression rules,
|
|
197
|
-
* route-aware blocking, etc.). */
|
|
198
|
-
onCampaignWillShow(handler: (campaign: InAppCampaign) => void | false): () => void;
|
|
199
|
-
/** Sugar: subscribe to `campaign-shown`. Fires after the SDK has painted
|
|
200
|
-
* the campaign to the DOM (post-impression). */
|
|
201
|
-
onCampaignShown(handler: (campaign: InAppCampaign) => void): () => void;
|
|
202
|
-
/** Sugar: subscribe to `campaign-click`. CANCELLABLE — return `false` (or
|
|
203
|
-
* call `evt.preventDefault()`) to suppress the SDK's default
|
|
204
|
-
* `window.location.href` navigation, e.g. to route via a SPA router. */
|
|
205
|
-
onCampaignClick(handler: (evt: CampaignClickEvent) => void | false): () => void;
|
|
206
|
-
/** Sugar: subscribe to `campaign-dismiss`. Fires when user closes/swipes
|
|
207
|
-
* away the campaign before clicking through. */
|
|
208
|
-
onCampaignDismiss(handler: (evt: CampaignDismissEvent) => void): () => void;
|
|
209
|
-
/** Sugar: subscribe to `error`. Aggregates non-fatal SDK errors — fetch
|
|
210
|
-
* failures, render exceptions, host-handler throws. Wire this into your
|
|
211
|
-
* error monitoring (Sentry, Datadog RUM, etc.). */
|
|
212
|
-
onError(handler: (evt: AegisErrorEvent) => void): () => void;
|
|
213
|
-
constructor(config: AegisInAppConfig);
|
|
214
|
-
initialize(): Promise<void>;
|
|
215
|
-
private _lastHealOutcome;
|
|
216
|
-
private _sendPushBootBeacon;
|
|
217
|
-
updateUserId(userId: string): void;
|
|
218
|
-
updateContactId(contactId: string, contactToken?: string): void;
|
|
219
|
-
private refreshDebounceTimer?;
|
|
220
|
-
private static readonly REFRESH_DEBOUNCE_MS;
|
|
221
|
-
private pendingPreInitRefresh;
|
|
222
|
-
private currentSurface;
|
|
223
|
-
private currentScreen;
|
|
224
|
-
private currentLocationId;
|
|
225
|
-
private static readonly KNOWN_SURFACES;
|
|
226
|
-
/**
|
|
227
|
-
* Qualifying-event refresh — schedule a debounced `refreshCampaigns()`
|
|
228
|
-
* call in response to a host-app SDK event (`aegis.page()`,
|
|
229
|
-
* `aegis.screen()`, `aegis.track(name)`). Matches CleverTap / MoEngage /
|
|
230
|
-
* WebEngage's "refresh on qualifying event" shape, translated to the
|
|
231
|
-
* browser session.
|
|
232
|
-
*
|
|
233
|
-
* Why: new server-side eligibility opens on these events (a `page` view
|
|
234
|
-
* arms route-targeted campaigns; a `track('product_viewed')` arms
|
|
235
|
-
* trigger-gated campaigns whose `client_trigger.config.event` matches).
|
|
236
|
-
* Pre-P1, the SDK only refreshed on `initialize()` + `updateContactId()`
|
|
237
|
-
* + the SSE update channel (which storefront has disabled by design),
|
|
238
|
-
* so newly armed campaigns were invisible until the next identity flip.
|
|
239
|
-
*
|
|
240
|
-
* Debounce: 300ms. Five `page()` calls inside the window coalesce to
|
|
241
|
-
* one fetch; a sixth call ≥300ms after the prior burst starts a new
|
|
242
|
-
* fetch. The trailing-edge schedule (re-arm on every call) is correct
|
|
243
|
-
* for storefront rage-clicks + SPA route bursts — we want the LATEST
|
|
244
|
-
* URL's eligibility, not the first.
|
|
245
|
-
*
|
|
246
|
-
* Safe to call on the server (no-op when `setTimeout` is unavailable
|
|
247
|
-
* — though that's vanishingly rare in any modern environment we ship to).
|
|
248
|
-
*
|
|
249
|
-
* Surface capture (In-App Surface Filter tracker P2): when `eventName`
|
|
250
|
-
* matches one of the 8 canonical surface keys, it is captured into
|
|
251
|
-
* `currentSurface` and threaded to `/v1/in-app/active?current_surface=<name>`
|
|
252
|
-
* on the next refresh — wiring the existing `aegis.page(name)` /
|
|
253
|
-
* `aegis.screen(name)` argument through to campaign targeting. Unknown names
|
|
254
|
-
* (e.g. `aegis.track('product_viewed')`) still trigger a refresh but do NOT
|
|
255
|
-
* change `currentSurface`, so arbitrary events never poison the surface gate.
|
|
256
|
-
*/
|
|
257
|
-
refreshOnEvent(eventName: string, isScreenDeclaration?: boolean): void;
|
|
258
|
-
/**
|
|
259
|
-
* Outlet context — declare the outlet the customer is actively viewing
|
|
260
|
-
* (storefront outlet switcher / location-code). The host calls this when the
|
|
261
|
-
* shopper picks an outlet (or on initial outlet-scoped page load) and again
|
|
262
|
-
* with the new id when they switch. Threaded to
|
|
263
|
-
* `/v1/in-app/active?location_id=<id>` so the server serves outlet-scoped
|
|
264
|
-
* campaigns for THIS outlet (preferred over the property's static outlet) —
|
|
265
|
-
* the fix that makes a SHARED multi-outlet storefront's switcher actually
|
|
266
|
-
* drive in-app targeting. Pass `null` to clear (back to property/brand-wide).
|
|
267
|
-
*
|
|
268
|
-
* No-ops when the value is unchanged; otherwise debounce-refreshes so the
|
|
269
|
-
* armed campaign set follows the switcher within ~300ms.
|
|
270
|
-
*/
|
|
271
|
-
setLocation(locationId: string | null): void;
|
|
272
|
-
/**
|
|
273
|
-
* Conversion-aware suppression. Call this when the host app observes a
|
|
274
|
-
* goal event (purchase, order_placed, checkout_completed, or any custom
|
|
275
|
-
* goal the workspace has configured per-campaign).
|
|
276
|
-
*
|
|
277
|
-
* For every armed campaign whose `frequency.suppress_after_conversion_seconds`
|
|
278
|
-
* is set, this:
|
|
279
|
-
* 1. Persists the conversion in sessionStorage (so subsequent page
|
|
280
|
-
* loads in the same tab retain silence).
|
|
281
|
-
* 2. Computes an expiry epoch_ms and stores it in `suppressedUntil`.
|
|
282
|
-
* 3. The two campaign-evaluation paths (`tryDisplayNextCampaign`
|
|
283
|
-
* and `onClientEvent`) skip campaigns whose `suppressedUntil`
|
|
284
|
-
* has not yet passed.
|
|
285
|
-
*
|
|
286
|
-
* Scope: only `session` is implemented in P0a. `user` and `user_sku`
|
|
287
|
-
* scopes degrade to session-only with a debug log; the schema accepts
|
|
288
|
-
* them so future expansion is non-breaking.
|
|
289
|
-
*
|
|
290
|
-
* Safe to call repeatedly for the same goal — each call refreshes the
|
|
291
|
-
* sessionStorage timestamp and re-applies suppression to any campaigns
|
|
292
|
-
* loaded since the last call.
|
|
293
|
-
*/
|
|
294
|
-
notifyConversion(goalName: string): void;
|
|
295
|
-
/**
|
|
296
|
-
* Compute and store `suppressedUntil` entries for every armed campaign
|
|
297
|
-
* whose `frequency.suppress_after_conversion_seconds` is set. Called by
|
|
298
|
-
* `notifyConversion()` and `refreshCampaigns()` (the latter rehydrates
|
|
299
|
-
* suppression for newly-loaded campaigns when a prior conversion event
|
|
300
|
-
* exists in sessionStorage).
|
|
301
|
-
*
|
|
302
|
-
* `convertedAt` is the epoch_ms of the conversion; pass `Date.now()`
|
|
303
|
-
* when called from `notifyConversion`, or the `ts` recovered from
|
|
304
|
-
* sessionStorage when rehydrating.
|
|
305
|
-
*/
|
|
306
|
-
private applySuppressionFromCampaigns;
|
|
307
|
-
/**
|
|
308
|
-
* Recover any prior conversion timestamps from sessionStorage and apply
|
|
309
|
-
* suppression to currently-loaded campaigns. Called from
|
|
310
|
-
* `refreshCampaigns()` after `this.campaigns` is populated. This is the
|
|
311
|
-
* mechanism that prevents a converted buyer from seeing a discount popup
|
|
312
|
-
* on the next page load within the same session.
|
|
313
|
-
*/
|
|
314
|
-
private rehydrateSuppressionFromStorage;
|
|
315
|
-
/**
|
|
316
|
-
* Returns true if the campaign is currently suppressed (Date.now() is
|
|
317
|
-
* before the stored expiry). Used by both display paths.
|
|
318
|
-
*/
|
|
319
|
-
private isSuppressed;
|
|
320
|
-
private connectSSE;
|
|
321
|
-
private disconnectSSE;
|
|
322
|
-
private attemptReconnect;
|
|
323
|
-
private refreshCampaigns;
|
|
324
|
-
private static readonly SERVED_DEDUP_PREFIX;
|
|
325
|
-
private emitServedEvents;
|
|
326
|
-
private detectDeviceType;
|
|
327
|
-
private getABAssignments;
|
|
328
|
-
private processABAssignments;
|
|
329
|
-
private getVariantId;
|
|
330
|
-
private tryDisplayNextCampaign;
|
|
331
|
-
private _lastDispatch;
|
|
332
|
-
/** Persistent launchers (active_web_chat) mount AMBIENTLY on every arm — a
|
|
333
|
-
* single always-on entry point, NOT an interruption, so they must not
|
|
334
|
-
* compete in the one-at-a-time overlay queue (tryDisplayNextCampaign).
|
|
335
|
-
* Idempotent: renderActiveWebChatLauncher no-ops once a launcher is live and
|
|
336
|
-
* displayedCampaigns guards re-display. Before this, the launcher only
|
|
337
|
-
* mounted when it happened to be the single campaign tryDisplayNextCampaign
|
|
338
|
-
* picked — so aegis.chat.open() / the mobile "Ask" tab silently did nothing
|
|
339
|
-
* whenever another non-triggered campaign was armed first. */
|
|
340
|
-
private mountPersistentLaunchers;
|
|
341
|
-
private filledSlots;
|
|
342
|
-
private slotSignatures;
|
|
343
|
-
private slotTimers;
|
|
344
|
-
private slotObserver;
|
|
345
|
-
private slotRenderScheduled;
|
|
346
|
-
private slotUnfilledBeaconed;
|
|
347
|
-
private slotUnfilledSweepTimer;
|
|
348
|
-
/**
|
|
349
|
-
* Scan the page for `[data-aegis-slot]` anchors and render any
|
|
350
|
-
* campaign whose `widget_category` matches the slot key AND whose
|
|
351
|
-
* `delivery_modes` includes `'embedded_card'`.
|
|
352
|
-
*
|
|
353
|
-
* Runs after every refresh-campaigns success — the WeakSet guard
|
|
354
|
-
* keeps it idempotent across re-fetches. The slot key is the campaign's
|
|
355
|
-
* `widget_category` (the wide grouping discriminator from F3), so a
|
|
356
|
-
* `<div data-aegis-slot="feedback">` will accept the first active
|
|
357
|
-
* campaign with `widget_category='feedback'` + embedded_card mode.
|
|
358
|
-
*/
|
|
359
|
-
/** Normalize a declared free-form screen name to a canonical surface key
|
|
360
|
-
* ('storefront.catalog' → 'storefront_catalog'), or null when it maps
|
|
361
|
-
* outside the enum (e.g. 'shopify.product'). Mirrors the server's
|
|
362
|
-
* `_canonical_surface_from_screen`. */
|
|
363
|
-
private canonicalSurfaceFromScreen;
|
|
364
|
-
/**
|
|
365
|
-
* Dynamic Screens P2 + substrate isolation — combined surface + free-form
|
|
366
|
-
* screen predicate, mirroring the server's `_screen_or_surface_matches`:
|
|
367
|
-
* - screen-only campaign matches strictly on `currentScreen`
|
|
368
|
-
* - a declared screen NORMALIZES into the canonical tier
|
|
369
|
-
* ('storefront.catalog' → storefront_catalog) so surface pins match
|
|
370
|
-
* - a declared screen that maps OUTSIDE the enum (e.g. 'shopify.product')
|
|
371
|
-
* does NOT fall through to the all-surfaces default for surface-pinned
|
|
372
|
-
* campaigns — actii.me-pinned campaigns never render on Shopify
|
|
373
|
-
* - hosts that declare nothing keep the legacy render-everything default
|
|
374
|
-
*/
|
|
375
|
-
private matchesCurrentScreenOrSurface;
|
|
376
|
-
private ensureSlotObserver;
|
|
377
|
-
private renderIntoSlots;
|
|
378
|
-
/**
|
|
379
|
-
* slot_unfilled telemetry (Surface/Slot Contract tracker P2).
|
|
380
|
-
*
|
|
381
|
-
* A served embedded_card campaign whose `widget_category` has NO
|
|
382
|
-
* `data-aegis-slot` anchor on the page is silently discarded by
|
|
383
|
-
* `renderIntoSlots` — the exact failure mode that made the storefront
|
|
384
|
-
* value bar dark for browse traffic while the dashboard reported the
|
|
385
|
-
* campaign "active". This sweep runs ~3s after a render attempt (late
|
|
386
|
-
* mounts / SPA hydration get time to appear; the MutationObserver re-fill
|
|
387
|
-
* handles anchors that arrive even later) and beacons one `slot_unfilled`
|
|
388
|
-
* per (campaign, path) per session so the dashboard can show
|
|
389
|
-
* "served but never rendered".
|
|
390
|
-
*/
|
|
391
|
-
private scheduleSlotUnfilledSweep;
|
|
392
|
-
private sweepUnfilledSlots;
|
|
393
|
-
/**
|
|
394
|
-
* Rotating slot — cycles eligible campaigns one at a time inside a single host
|
|
395
|
-
* slot (the storefront sticky-footer "value bar"). Each campaign is pre-rendered
|
|
396
|
-
* into its own hidden pane so a live `progress_bar` keeps tracking the cart even
|
|
397
|
-
* while off-screen; only the visibility toggles every `rotateMs`. The impression
|
|
398
|
-
* is deferred at render and fired per campaign on FIRST visibility, so hidden
|
|
399
|
-
* panes never over-count. One rendered pane → no rotation (just shows it).
|
|
400
|
-
*/
|
|
401
|
-
private renderRotatingSlot;
|
|
402
|
-
/**
|
|
403
|
-
* Surface-Canvas inline element anchoring (Plotline / WebEngage model).
|
|
404
|
-
*
|
|
405
|
-
* Render inline-format campaigns into a HOST element the operator picked via
|
|
406
|
-
* the element inspector — `interactive_config.anchor.element_selector` — instead
|
|
407
|
-
* of a host-declared `[data-aegis-slot]`. `position` controls placement:
|
|
408
|
-
* inside (default) — append into the element (e.g. the storefront footer card)
|
|
409
|
-
* replace — clear the element's host-default children, then render in
|
|
410
|
-
* before / after — render into a wrapper inserted as a sibling
|
|
411
|
-
*
|
|
412
|
-
* Reuses `renderCampaignIntoSlot` (same sub_type dispatch → `renderProgressBarInline`
|
|
413
|
-
* etc.) so inline render code is single-sourced with the slot path. Embedded-card
|
|
414
|
-
* gated (so an anchored campaign never ALSO renders as an overlay), surface-gated,
|
|
415
|
-
* and idempotent via `filledSlots` keyed on the resolved element. A selector that
|
|
416
|
-
* doesn't resolve emits `anchor_unresolved` (parity with tooltip anchoring).
|
|
417
|
-
*/
|
|
418
|
-
private renderIntoAnchors;
|
|
419
|
-
/**
|
|
420
|
-
* U7 — render server-injected token-bound campaigns.
|
|
421
|
-
*
|
|
422
|
-
* The standalone-page route at `apps/cashier-portal/src/app/s/[slug]/
|
|
423
|
-
* [workspace]/[page_key]/page.tsx` (and the `/c/[token]` Aegis-hosted
|
|
424
|
-
* fallback) verify the URL token server-side via the F16 internal
|
|
425
|
-
* endpoint, then embed the resolved campaign payload as JSON inside
|
|
426
|
-
* a `<div data-aegis-token-data="...">` anchor. This SDK method
|
|
427
|
-
* scans for those anchors, parses the payload, and dispatches to
|
|
428
|
-
* the SAME `renderCampaignIntoSlot` used by the [data-aegis-slot]
|
|
429
|
-
* path — so widget rendering code is single-sourced.
|
|
430
|
-
*
|
|
431
|
-
* Why server-injected (not client-fetched): keeps INTERNAL_API_SECRET
|
|
432
|
-
* server-side, avoids an extra browser round-trip for verify, gives
|
|
433
|
-
* Next.js SSR-friendly initial HTML for SEO/no-JS users (rendered
|
|
434
|
-
* via the page handler's React tree alongside the SDK anchor).
|
|
435
|
-
*
|
|
436
|
-
* Idempotency: filledSlots is the same WeakSet used by
|
|
437
|
-
* renderIntoSlots — re-running on SSE/poll refresh is a no-op for
|
|
438
|
-
* already-filled anchors.
|
|
439
|
-
*/
|
|
440
|
-
private renderTokenAnchors;
|
|
441
|
-
/**
|
|
442
|
-
* Slot-mode counterpart to `displayCampaign`. Reuses the existing
|
|
443
|
-
* lifecycle hooks (`campaign-will-show`, `displayedCampaigns`,
|
|
444
|
-
* `campaign-shown`, impression tracking) so analytics + frequency
|
|
445
|
-
* caps work the same way as overlay renders.
|
|
446
|
-
*
|
|
447
|
-
* Only the sub_types that make UX sense embedded are handled; the
|
|
448
|
-
* rest (modal, full_screen, half_interstitial, alert, pip) silently
|
|
449
|
-
* skip — those types only make sense as fullscreen overlays.
|
|
450
|
-
*/
|
|
451
|
-
private renderCampaignIntoSlot;
|
|
452
|
-
/** §7.13.H — generic embedded card: image / title / body / coupon chip / CTA.
|
|
453
|
-
* The catch-all for banner + nudge sub_types (birthday, referral, app-install,
|
|
454
|
-
* win-back, etc.) so EVERY gallery nudge renders on the bill (previously only
|
|
455
|
-
* star_rating / nps_survey / form were handled → nudges never appeared). */
|
|
456
|
-
/**
|
|
457
|
-
* Whether `interactive_config` carries a composed `card_template` (non-empty
|
|
458
|
-
* `elements[]`). The ONE detector shared by all three composed-card cutover
|
|
459
|
-
* gates — inline slot, chrome overlay, and the P6 survey-overlay cutover — so
|
|
460
|
-
* they can't drift (the inline gate previously omitted the non-empty check).
|
|
461
|
-
*/
|
|
462
|
-
private _hasComposedTemplate;
|
|
463
|
-
/**
|
|
464
|
-
* P6.full — flat survey → card_template adapter. A `nps_survey` / `star_rating`
|
|
465
|
-
* / `quick_poll` authored WITHOUT a card_template gets one synthesised in place
|
|
466
|
-
* (carrying its follow-up config), so the EXISTING composed-template gates route
|
|
467
|
-
* it through the ONE card-template engine + the shared element builders (with
|
|
468
|
-
* the ported reason-capture/thank-you flows) — overlay AND slot. Back-compat:
|
|
469
|
-
* the field names + follow-up defaults match the retired bespoke renderers.
|
|
470
|
-
* No-op when a template already exists or the type isn't a single-card survey.
|
|
471
|
-
*/
|
|
472
|
-
private _ensureSurveyTemplate;
|
|
473
|
-
/**
|
|
474
|
-
* Composed single card — renders a campaign's top-level `card_template`
|
|
475
|
-
* (frame + elements: icon/text/progress/image/cta/group/…) through the generic
|
|
476
|
-
* `renderCardFromTemplate` engine. The canonical path for the rich card editor:
|
|
477
|
-
* the storefront value bar, loyalty nudges, and any operator-composed card all
|
|
478
|
-
* render here from declarative JSON, on ACS / custom / third-party sites.
|
|
479
|
-
*/
|
|
480
|
-
private renderComposedCardSlot;
|
|
481
|
-
/**
|
|
482
|
-
* C2 — composed card body in an OVERLAY (modal / banner / full_screen /
|
|
483
|
-
* half_interstitial). The overlay counterpart to `renderComposedCardSlot`: it
|
|
484
|
-
* builds the same `TemplateCard` from the campaign's canonical fields and paints
|
|
485
|
-
* it with the generic `renderCardFromTemplate` engine, then wraps it in the
|
|
486
|
-
* standard overlay chrome (close button + size scaling) so a composed card looks
|
|
487
|
-
* identical whether overlaid or slotted. Only invoked when a `card_template` is
|
|
488
|
-
* present (see displayCampaign) — flat campaigns never reach here.
|
|
489
|
-
* See IN_APP_FORMAT_LOCK_AND_COMPOSABLE_CARDS_TRACKER.md (Part B / C2).
|
|
490
|
-
*/
|
|
491
|
-
private renderComposedCardOverlay;
|
|
492
|
-
private renderGenericCardSlot;
|
|
493
|
-
/**
|
|
494
|
-
* §7.13.I — embedded profile FORM. Renders one input per `form_fields` entry
|
|
495
|
-
* and, on submit, POSTs `{response_type:'form', payload:{fields:{key:value}}}`
|
|
496
|
-
* to `/in-app/responses` — the cell-plane enrichment writes the mapped answers
|
|
497
|
-
* back onto the contact. Keyed by each field's `key` so it matches the
|
|
498
|
-
* campaign's field→contact map.
|
|
499
|
-
*/
|
|
500
|
-
private renderFormSlot;
|
|
501
|
-
/** Shared form body — the input fields + submit. Used embedded (slot) today;
|
|
502
|
-
* the overlay form path reuses it too. */
|
|
503
|
-
private _buildFormBody;
|
|
504
|
-
/** POST a form response to /in-app/responses (gateway → cell-plane). The
|
|
505
|
-
* cell-plane enriches the contact from the campaign's field-map. Best-effort. */
|
|
506
|
-
private submitFormResponse;
|
|
507
|
-
/**
|
|
508
|
-
* Generic interactive response submit → POST /v1/in-app/responses. Returns the
|
|
509
|
-
* parsed server response (which for spin/scratch carries the server-picked
|
|
510
|
-
* `prize`) or null. Interactive Widgets Parity tracker — every embedded widget
|
|
511
|
-
* records a response so analytics + prize-from-segments work uniformly.
|
|
512
|
-
*/
|
|
513
|
-
private submitWidgetResponse;
|
|
514
|
-
/**
|
|
515
|
-
* Built-in embedded SPIN WHEEL (no AegisMessageRuntime callback dependency —
|
|
516
|
-
* works on the bill). Slices come from `interactive_config.segments`; on Spin
|
|
517
|
-
* it submits to /in-app/responses, the server picks the prize from the AUTHORED
|
|
518
|
-
* segments, and the wheel animates to that segment + reveals the prize/coupon.
|
|
519
|
-
*/
|
|
520
|
-
private renderSpinWheelSlot;
|
|
521
|
-
/**
|
|
522
|
-
* Built-in embedded IMAGE/VIDEO CAROUSEL — a swipeable horizontal strip of
|
|
523
|
-
* `interactive_config.cards` (image OR video + title + body + CTA), contained
|
|
524
|
-
* to the slot (the parent overflow:hidden + this strip's own scroll). Each card
|
|
525
|
-
* reuses the same shape as the In-App carousel editor authors.
|
|
526
|
-
*/
|
|
527
|
-
private renderCarouselCardsSlot;
|
|
528
|
-
/** Built-in embedded COUNTDOWN — live H:M:S digits that pulse red in the
|
|
529
|
-
* final stretch (<60s) to create urgency, plus the CTA. */
|
|
530
|
-
private renderCountdownSlot;
|
|
531
|
-
/** Foil palette — a brushed-metal gradient + a contrast "ink" (for the
|
|
532
|
-
* SCRATCH-HERE text, sparkle motif, and logo tint) derived from the operator's
|
|
533
|
-
* chosen foil colour (brand primary / custom hex). Unset / invalid → the
|
|
534
|
-
* default silver. Light foils get dark ink, dark foils get white ink, so the
|
|
535
|
-
* prompt stays legible on any colour. */
|
|
536
|
-
private _scratchFoilPalette;
|
|
537
|
-
/** Built-in embedded SCRATCH CARD — a canvas foil the customer scratches to
|
|
538
|
-
* reveal the server-picked prize, then submits (records + grants). Confetti
|
|
539
|
-
* on reveal. No AegisMessageRuntime callback dependency (works on the bill). */
|
|
540
|
-
private renderScratchCardSlot;
|
|
541
|
-
/** Extract a human prize label from a spin/scratch server response. */
|
|
542
|
-
private _extractPrizeLabel;
|
|
543
|
-
/** Extract a redeemable coupon code from a spin/scratch server response. */
|
|
544
|
-
private _extractCouponCode;
|
|
545
|
-
/**
|
|
546
|
-
* Slot styling — the operator's look-&-feel knobs (Style panel) applied to the
|
|
547
|
-
* EMBEDDED render, CLAMPED to boundary-safe ranges so an authored value can
|
|
548
|
-
* never break out of the dynamic block. Unauthored knobs are `undefined` so
|
|
549
|
-
* each renderer keeps its own compact default (no visual regression). Colors
|
|
550
|
-
* default to the current slot defaults. The slot card keeps `width:100%;
|
|
551
|
-
* overflow:hidden` regardless, so the boundary guarantee is independent of
|
|
552
|
-
* these values.
|
|
553
|
-
*/
|
|
554
|
-
private _slotStyle;
|
|
555
|
-
private _wrapInSlotCard;
|
|
556
|
-
/**
|
|
557
|
-
* Flush a rendered slot card into its host card — drop the per-campaign radius
|
|
558
|
-
* + shadow so it reads as one unit with the host wrapper (used for the
|
|
559
|
-
* storefront value bar via `data-aegis-slot-flush`). Targets every
|
|
560
|
-
* `[data-campaign-id]` card inside `container` (or the container itself).
|
|
561
|
-
*/
|
|
562
|
-
private _flattenSlotCard;
|
|
563
|
-
/**
|
|
564
|
-
* Evaluate the currently armed campaigns against a client-side event
|
|
565
|
-
* and render any that match their `client_trigger`.
|
|
566
|
-
*
|
|
567
|
-
* Called by the host app (e.g., the EcommerceTracker on product_viewed),
|
|
568
|
-
* or by future TriggerEngine bridges. Safe to call repeatedly for the
|
|
569
|
-
* same event — dedup happens via `displayedCampaigns`.
|
|
570
|
-
*
|
|
571
|
-
* Supported trigger types (align with the cell-plane server-side
|
|
572
|
-
* `display_rules.trigger_type`):
|
|
573
|
-
* - `custom_event` : fire when eventName matches config.event
|
|
574
|
-
* - `product_match` : fire on `product_viewed` when eventData.product_id
|
|
575
|
-
* matches config.product_id (string or string[])
|
|
576
|
-
* - `delay` : client-side setTimeout — evaluated at armeng
|
|
577
|
-
* time (kicked off from `displayCampaign`), not here.
|
|
578
|
-
* - `exit_intent` / `scroll_depth` / `time_on_page` / `inactivity` : the
|
|
579
|
-
* TriggerEngine event named by `behaviouralTriggerEvent`;
|
|
580
|
-
* AegisMessageRuntime arms the engine and forwards it.
|
|
581
|
-
*/
|
|
582
|
-
onClientEvent(eventName: string, eventData?: Record<string, unknown>): void;
|
|
583
|
-
private matchesClientTrigger;
|
|
584
|
-
private displayCampaign;
|
|
585
|
-
/** The single chat launcher on the page (Active Web Chat). Persistent — not
|
|
586
|
-
* re-mounted on SSE/poll refresh; torn down on manager teardown. */
|
|
587
|
-
private activeWebChat?;
|
|
588
|
-
/**
|
|
589
|
-
* Mount the Active Web Chat launcher. Idempotent: a repeat delivery of the
|
|
590
|
-
* same (or another) chat campaign is a no-op once one launcher is live — at
|
|
591
|
-
* most one bubble per page, and an open session is never yanked out from
|
|
592
|
-
* under the customer.
|
|
593
|
-
*/
|
|
594
|
-
private renderActiveWebChatLauncher;
|
|
595
|
-
/**
|
|
596
|
-
* Build the shared context passed into the preload-first renderers.
|
|
597
|
-
* Matches the interface in `./renderers/types.ts`. Kept as a private
|
|
598
|
-
* method (rather than inlined at each call-site) so future renderer
|
|
599
|
-
* additions stay consistent and easy to audit.
|
|
600
|
-
*/
|
|
601
|
-
private buildRenderContext;
|
|
602
|
-
/**
|
|
603
|
-
* Renders interactive sub-type campaigns (spin wheel, NPS, quiz, etc.)
|
|
604
|
-
* using DOM-safe rendering. These sub-types use the campaign's
|
|
605
|
-
* interactive_config payload for type-specific behavior.
|
|
606
|
-
*/
|
|
607
|
-
private renderInteractive;
|
|
608
|
-
/**
|
|
609
|
-
* Built-in overlay for spin_wheel / scratch_card when no host runtime is
|
|
610
|
-
* wired (dashboard preview, runtime-less hosts). Wraps the same interactive
|
|
611
|
-
* slot renderers (`renderSpinWheelSlot` / `renderScratchCardSlot`) in a modal
|
|
612
|
-
* so the gamified widget is fully playable — not a dead frame.
|
|
613
|
-
*/
|
|
614
|
-
/** Display-size multiplier — operator control over how big a bounded overlay
|
|
615
|
-
* renders (small 0.82 / medium 1 / large 1.18). Default medium = prior size.
|
|
616
|
-
* Read from interactive_config.display_size; mirrors the schema enum + the
|
|
617
|
-
* dashboard preview harness so the operator's choice is honored identically. */
|
|
618
|
-
private _sizeMul;
|
|
619
|
-
private renderGamificationOverlay;
|
|
620
|
-
/** A circular ✕ close button in the modal's top-right corner. */
|
|
621
|
-
private _addCornerClose;
|
|
622
|
-
/**
|
|
623
|
-
* Custom HTML type — render operator-authored HTML in a SANDBOXED iframe.
|
|
624
|
-
* The frame runs with `sandbox="allow-scripts"` and NO `allow-same-origin`, so
|
|
625
|
-
* it's an opaque/null origin: no access to the host DOM, cookies, localStorage,
|
|
626
|
-
* the SDK write-key, or same-origin creds. The only channel out is a validated
|
|
627
|
-
* `postMessage` bridge (close / track / cta / resize), exposed to authors as a
|
|
628
|
-
* tiny injected `aegis` shim. See IN_APP_CUSTOM_HTML_TRACKER.md (security model).
|
|
629
|
-
*/
|
|
630
|
-
private renderCustomHtml;
|
|
631
|
-
/** Build the sandboxed iframe + the validated message bridge. Reused by the
|
|
632
|
-
* overlay + embedded-slot custom-HTML renderers. */
|
|
633
|
-
private _buildCustomHtmlFrame;
|
|
634
|
-
/** Embedded-slot custom HTML (e.g. on the bill) — the same sandboxed frame in
|
|
635
|
-
* a slot card instead of an overlay. */
|
|
636
|
-
private renderCustomHtmlSlot;
|
|
637
|
-
private renderCountdownOffer;
|
|
638
|
-
/**
|
|
639
|
-
* Multi-step form (SDK Demo v4 W1b) — in-app render type matching the
|
|
640
|
-
* Plotline multi-step flow pattern: a progress bar + per-step question with
|
|
641
|
-
* options, Back/Next navigation, Submit on the last step. `ic.steps` is an
|
|
642
|
-
* array of `{ question, options[] }`. DOM-safe (no innerHTML).
|
|
643
|
-
*/
|
|
644
|
-
private renderMultiStepForm;
|
|
645
|
-
/**
|
|
646
|
-
* Push primer (SDK Demo v4 W3) — in-app render type that "soft-asks" before
|
|
647
|
-
* the OS hard-ask. The Enable CTA calls `Notification.requestPermission()`;
|
|
648
|
-
* we report `permission_granted` / `permission_denied` / `permission_default`
|
|
649
|
-
* so journeys can react. Degrades gracefully where Notification is absent.
|
|
650
|
-
*/
|
|
651
|
-
private renderPushPrimer;
|
|
652
|
-
private _pushOptInCache;
|
|
653
|
-
private _pushOptInLoading;
|
|
654
|
-
/** Synchronous "can the primer render RIGHT NOW" gate used by the overlay
|
|
655
|
-
* selection loop. Never tracks events — an ineligible primer is a
|
|
656
|
-
* non-event, not a dismissal. */
|
|
657
|
-
private _primerEligibleNow;
|
|
658
|
-
/**
|
|
659
|
-
* Fetch the property's push opt-in mode/trigger from /v1/sdk/config
|
|
660
|
-
* (browser HTTP cache + ETag make repeat calls cheap). Fail-open to
|
|
661
|
-
* 'standard'/'immediate' — a config blip must not silently kill the
|
|
662
|
-
* only web-push opt-in surface.
|
|
663
|
-
*/
|
|
664
|
-
private _fetchPushOptInConfig;
|
|
665
|
-
/**
|
|
666
|
-
* Prompt-timing gate for the standard primer.
|
|
667
|
-
* immediate → always
|
|
668
|
-
* second_page_view → from the 2nd page load on (localStorage counter,
|
|
669
|
-
* incremented once per manager init)
|
|
670
|
-
* after_first_order→ once `aegis_ordered` is set (host runtimes set it
|
|
671
|
-
* on purchase; storefront checkout does)
|
|
672
|
-
* manual → never auto-shows; host calls the primer explicitly
|
|
673
|
-
*/
|
|
674
|
-
private _promptTriggerSatisfied;
|
|
675
|
-
private _renderPushPrimerModal;
|
|
676
|
-
/**
|
|
677
|
-
* Push-primer Enable handler — runs the SAME end-to-end subscribe flow the
|
|
678
|
-
* (now-retired) ACS PushOptInBanner did, so the primer is a complete web-push
|
|
679
|
-
* opt-in on every surface (ACS / Shopify / 3rd-party site), not just an OS
|
|
680
|
-
* permission prompt. Steps: fetch VAPID public key → register SW → hard-ask →
|
|
681
|
-
* subscribe → POST /v1/web_push/subscriptions → stitch known contact.
|
|
682
|
-
*
|
|
683
|
-
* Push runtime resolution prefers the already-loaded `window.AegisWebPush`
|
|
684
|
-
* global (the Shopify embed lazy-loads it via /apps/active_reach/push.js, so
|
|
685
|
-
* we reuse that single instance instead of registering the SW twice), and
|
|
686
|
-
* only dynamic-imports the module as a fallback for hosts that didn't preload
|
|
687
|
-
* it (ACS / 3rd-party sites). Returns the resolved permission string for
|
|
688
|
-
* engagement reporting; falls back to a bare permission ask if push can't be
|
|
689
|
-
* wired (no propertyId, no VAPID).
|
|
690
|
-
*/
|
|
691
|
-
private _subscribeFromPushPrimer;
|
|
692
|
-
private renderQuiz;
|
|
693
|
-
/**
|
|
694
|
-
* Embedded quiz on a bill/page slot — same question-stepping flow as the
|
|
695
|
-
* overlay, rendered inline with no overlay/close (Open/Closed: both paths
|
|
696
|
-
* share `_runQuizFlow`, so a feature added once lights up both). Returns
|
|
697
|
-
* false when there are no questions so dispatch can fall back to a card.
|
|
698
|
-
*/
|
|
699
|
-
private renderQuizSlot;
|
|
700
|
-
/**
|
|
701
|
-
* Shared quiz engine — drives the question stepper, scoring (knowledge =
|
|
702
|
-
* correct_index/points, personality = outcome tally), result-band selection,
|
|
703
|
-
* CTA, reaction and the `quiz` response submit. Renders into the provided
|
|
704
|
-
* `body`. `overlay` is the dismiss target for the close button on the overlay
|
|
705
|
-
* path; pass null on the slot path (no close affordance inline).
|
|
706
|
-
*/
|
|
707
|
-
private _runQuizFlow;
|
|
708
|
-
private createOverlay;
|
|
709
|
-
/** Wrap a card in a display-size scaling container (no-op at medium/×1). Used
|
|
710
|
-
* by formats that build their overlay inline (renderModal) rather than via
|
|
711
|
-
* createOverlay, so size is honored identically. */
|
|
712
|
-
private _wrapScaled;
|
|
713
|
-
private createCTAButton;
|
|
714
|
-
private addCloseButton;
|
|
715
|
-
/**
|
|
716
|
-
* Navigate to a campaign CTA URL.
|
|
717
|
-
*
|
|
718
|
-
* Dispatches a cancellable `aegis:campaign-click` CustomEvent so host
|
|
719
|
-
* apps (e.g., the storefront SPA) can intercept and route in-place via
|
|
720
|
-
* their client-side router, avoiding a full page reload that re-runs
|
|
721
|
-
* SSR + re-renders the location picker / banner / cart drawer state.
|
|
722
|
-
*
|
|
723
|
-
* The host calls `event.preventDefault()` to suppress the hard nav and
|
|
724
|
-
* handle the URL itself. If no listener calls preventDefault, the SDK
|
|
725
|
-
* falls through to `window.location.href` so plain HTML pages without a
|
|
726
|
-
* SPA still get the user to the destination.
|
|
727
|
-
*
|
|
728
|
-
* Industry parallel: CleverTap dispatches `clevertap-deeplink-click`,
|
|
729
|
-
* MoEngage dispatches `MoE_inappRedirect`. The pattern lets the same
|
|
730
|
-
* SDK serve both vanilla websites (full nav fallback) and SPAs
|
|
731
|
-
* (in-place state change) without per-host configuration.
|
|
732
|
-
*/
|
|
733
|
-
private navigateToCampaignAction;
|
|
734
|
-
/** Register/replace the canonical CTA-action handler after construction (the
|
|
735
|
-
* config `onAction` is the construct-time equivalent). Idempotent. */
|
|
736
|
-
setOnAction(handler: (action: AegisAction) => boolean | void): void;
|
|
737
|
-
/**
|
|
738
|
-
* Canonical CTA-action dispatcher (CANONICAL_ACTION_MODEL_TRACKER.md). ONE path
|
|
739
|
-
* for every host-facing CTA action:
|
|
740
|
-
* 1. give the host's `onAction` handler first refusal (return `true` = handled);
|
|
741
|
-
* 2. ALSO fire the legacy `aegis:*` DOM event (cancelable) so existing
|
|
742
|
-
* listeners (ACS) keep working unchanged during the migration;
|
|
743
|
-
* 3. if STILL unhandled → canonical fallback (navigate to the product/cart
|
|
744
|
-
* page) so a CTA is never a dead no-op (the rail-"Add" 3rd-party gap).
|
|
745
|
-
* Both add-to-cart paths (card "Add" + the `aegis://cart-add` verb) funnel here,
|
|
746
|
-
* so they're one behaviour delivered to the host's single `onAction` handler.
|
|
747
|
-
* (Phase E.2 hard cutover — the legacy `aegis:*` DOM events were removed.)
|
|
748
|
-
*/
|
|
749
|
-
dispatchAction(action: AegisAction, _campaignId?: string): void;
|
|
750
|
-
/**
|
|
751
|
-
* Phase-2 CTA action verbs (`aegis://<verb>?<params>`). Performs an in-app
|
|
752
|
-
* behaviour instead of navigating. Verbs:
|
|
753
|
-
* dismiss — close the message (tracked as dismissed)
|
|
754
|
-
* request-push — prompt for web-push permission, then close
|
|
755
|
-
* cart-add?sku=X — canonical `add_to_cart` action via dispatchAction
|
|
756
|
-
* (cancelable + product-page fallback)
|
|
757
|
-
*/
|
|
758
|
-
private runCampaignActionVerb;
|
|
759
|
-
/** Remove a rendered campaign's element(s) from the DOM by campaign id. */
|
|
760
|
-
private removeCampaignEl;
|
|
761
|
-
/**
|
|
762
|
-
* Resolve the operator's colour + style choices into concrete CSS values.
|
|
763
|
-
* Mirrors the studio preview's styleFrom() 1:1 (apps/web/src/app/api/preview/
|
|
764
|
-
* in-app/route.tsx) — same keys, same defaults — so what the operator designs
|
|
765
|
-
* in the editor is what the live SDK renders. The container uses the
|
|
766
|
-
* campaign's background_color/text_color and the CTA button is the inverse
|
|
767
|
-
* (so it pops on the coloured surface), exactly like the preview. Earlier the
|
|
768
|
-
* card renderers hardcoded a white card + dark text and ignored the Style
|
|
769
|
-
* panel entirely, so the live message looked nothing like the preview.
|
|
770
|
-
*/
|
|
771
|
-
/** Pick a legible label colour (#fff or near-black) for a solid fill, by
|
|
772
|
-
* relative luminance — so a brand-accent button is always readable. */
|
|
773
|
-
private _contrastText;
|
|
774
|
-
/** Central surface palette — the ONE place the brand colour becomes either a
|
|
775
|
-
* surface fill or an accent, so every widget is consistent.
|
|
776
|
-
*
|
|
777
|
-
* `surface_style` (interactive_config), default `clean`:
|
|
778
|
-
* - `clean` → NEUTRAL surface (white) + dark text + the brand colour as the
|
|
779
|
-
* CTA ACCENT. The 60-30-10 / WCAG-safe default: legible copy and
|
|
780
|
-
* a CTA that actually pops (higher CTR than a flat colour card).
|
|
781
|
-
* - `branded`→ brand-colour SURFACE + contrasting text + inverse CTA. For
|
|
782
|
-
* high-impact, low-text moments (flash sale, celebration).
|
|
783
|
-
* `background_color` is the operator's brand colour in BOTH modes — surface
|
|
784
|
-
* fill when branded, CTA accent when clean. */
|
|
785
|
-
private _surfacePalette;
|
|
786
|
-
private inAppStyle;
|
|
787
|
-
private renderBanner;
|
|
788
|
-
private renderModal;
|
|
789
|
-
private _heroVideo;
|
|
790
|
-
private renderFullScreen;
|
|
791
|
-
private renderHalfInterstitial;
|
|
792
|
-
private renderAlert;
|
|
793
|
-
private _pipCornerCss;
|
|
794
|
-
private renderPIP;
|
|
795
|
-
private removeBanner;
|
|
796
|
-
private removeModal;
|
|
797
|
-
/**
|
|
798
|
-
* Spotlight backdrop colour → a dim of the chosen base at `dim` opacity.
|
|
799
|
-
* `dark` (slate, default) · `brand` (the campaign brand colour) · `black` ·
|
|
800
|
-
* `custom` (a picked hex). Encoded as 8-digit hex alpha; falls back to slate
|
|
801
|
-
* rgba when the base isn't a 6-digit hex (e.g. an rgb() brand colour).
|
|
802
|
-
*/
|
|
803
|
-
private _spotlightDimColor;
|
|
804
|
-
private renderTooltip;
|
|
805
|
-
/** Fire a short confetti burst from the top of an anchor element. Vanilla
|
|
806
|
-
* (no deps) — mirrors the cashier-portal confetti. Respects
|
|
807
|
-
* prefers-reduced-motion. Used on positive moments (high rating, won prize,
|
|
808
|
-
* form complete). */
|
|
809
|
-
private _fireConfetti;
|
|
810
|
-
/**
|
|
811
|
-
* Emotional reaction layer (CEP parity — CleverTap exposes configurable
|
|
812
|
-
* outcome animation; MoEngage sets distinct win/lose icons). Three CONTEXT-
|
|
813
|
-
* AWARE intents drive a premium Lottie animation (with an instant SVG
|
|
814
|
-
* placeholder + graceful fallback):
|
|
815
|
-
*
|
|
816
|
-
* - `celebrate` → a real WIN in a game (spin/scratch prize). Trophy Lottie,
|
|
817
|
-
* gold rings, confetti. The big, earned moment.
|
|
818
|
-
* - `affirm` → positive FEEDBACK (high rating, NPS promoter, quiz/form
|
|
819
|
-
* done). An animated success check — friendly, NOT a trophy
|
|
820
|
-
* (a survey isn't a contest).
|
|
821
|
-
* - `empathize` → a negative outcome (low rating, NPS detractor, no-prize /
|
|
822
|
-
* "Try again"). A soft breathing heart — supportive, NO
|
|
823
|
-
* confetti, NO rings.
|
|
824
|
-
*
|
|
825
|
-
* Honors prefers-reduced-motion (static badge, no motion).
|
|
826
|
-
*/
|
|
827
|
-
private _playReaction;
|
|
828
|
-
/** Hand-built, brand-neutral animated SVG badges for the reaction layer — a
|
|
829
|
-
* premium alternative to system emoji (consistent across browsers, no Lottie
|
|
830
|
-
* dependency). The check strokes itself in; the heart breathes gently. */
|
|
831
|
-
private _reactionSvg;
|
|
832
|
-
/** Resolve the base URL the SDK assets are served from (so Lottie JSON +
|
|
833
|
-
* player load from the same origin/path as the SDK bundle — works in the
|
|
834
|
-
* dashboard preview and same-origin installs; cross-origin CDN installs fall
|
|
835
|
-
* back to the inline SVG when the asset 404s). */
|
|
836
|
-
private _assetBase;
|
|
837
|
-
/** Lazy-load the Lottie player once (cached on window). Resolves to the
|
|
838
|
-
* global `lottie`, or rejects if it can't be fetched (→ SVG fallback). */
|
|
839
|
-
private _loadLottie;
|
|
840
|
-
private addAnimationStyles;
|
|
841
|
-
private sanitizeUrl;
|
|
842
|
-
private sanitizeColor;
|
|
843
|
-
/**
|
|
844
|
-
* Track in-app event via the standard Event Ingress pipeline.
|
|
845
|
-
*
|
|
846
|
-
* Events flow: SDK → Event Ingress → Kafka → Governance Consumer
|
|
847
|
-
* → Event Engine → ClickHouse (in_app_events + events_with_ttl)
|
|
848
|
-
*
|
|
849
|
-
* The event_type uses the canonical prefix `in_app.` so the event
|
|
850
|
-
* switchboard maps it to the correct canonical form:
|
|
851
|
-
* in_app.impression → engagement.view
|
|
852
|
-
* in_app.clicked → engagement.click
|
|
853
|
-
* in_app.dismissed → engagement.dismiss
|
|
854
|
-
*/
|
|
855
|
-
private trackEvent;
|
|
856
|
-
/** campaign id → journey_step_execution_id for queued items seen this page. */
|
|
857
|
-
private journeyStepByCampaign;
|
|
858
|
-
/** `${step}:${action}` acks sent (or in flight) this page — one per render. */
|
|
859
|
-
private journeyAcks;
|
|
860
|
-
private static readonly JOURNEY_ACK_RETRY_MS;
|
|
861
|
-
/**
|
|
862
|
-
* POST /v1/in-app/widgets/{step}/ack — the canonical writer of a queue row's
|
|
863
|
-
* seen-state (the same endpoint the Android and iOS SDKs call). Fail-soft by
|
|
864
|
-
* construction: it runs after the render, is never awaited by it, and never
|
|
865
|
-
* throws. A network error or 5xx is retried once; if that also fails the key
|
|
866
|
-
* is released, so the next render of the (still re-served) message tries
|
|
867
|
-
* again. A 4xx is the server's answer and is not retried. The server side is
|
|
868
|
-
* idempotent — a repeated action is answered `late_arrival` and writes
|
|
869
|
-
* nothing — so a duplicate ack is harmless.
|
|
870
|
-
*/
|
|
871
|
-
private ackJourneyQueueItem;
|
|
872
|
-
private log;
|
|
873
|
-
destroy(options?: {
|
|
874
|
-
clearABState?: boolean;
|
|
875
|
-
}): void;
|
|
876
|
-
}
|
|
877
|
-
//# sourceMappingURL=AegisInAppManager.d.ts.map
|