@active-reach/web-sdk 1.7.3 → 1.8.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.
@@ -48,6 +48,52 @@ export interface InAppCampaign {
48
48
  };
49
49
  assigned_variant_id?: string;
50
50
  }
51
+ /**
52
+ * Payload for `campaign-click` lifecycle event. CANCELLABLE — return `false`
53
+ * (or call `evt.preventDefault()`) from the handler to suppress the SDK's
54
+ * default `window.location.href` navigation, e.g. to route via a SPA router.
55
+ */
56
+ export interface CampaignClickEvent {
57
+ campaign: InAppCampaign;
58
+ /** Sanitized destination URL — already passed through `sanitizeUrl()`. */
59
+ action_url: string;
60
+ /** Best-effort button identifier — populated when the click came from a
61
+ * named button in a multi-button campaign (modals, alerts). `cta` for the
62
+ * primary CTA on single-button campaigns. */
63
+ button_id?: string;
64
+ /** Mutate via `evt.preventDefault()` to signal the SDK to skip its
65
+ * default hard-navigation. Identical semantics to DOM CustomEvent. */
66
+ preventDefault: () => void;
67
+ defaultPrevented: boolean;
68
+ }
69
+ /** Payload for `campaign-dismiss` lifecycle event. */
70
+ export interface CampaignDismissEvent {
71
+ campaign: InAppCampaign;
72
+ /** Source of dismissal — close button, swipe, ESC key, programmatic. */
73
+ source: 'close_button' | 'overlay' | 'esc' | 'auto_timeout' | 'programmatic';
74
+ }
75
+ /** Payload for `error` lifecycle event. Aggregates non-fatal SDK errors so
76
+ * host apps can wire them into Sentry / Datadog RUM / similar. */
77
+ export interface AegisErrorEvent {
78
+ message: string;
79
+ error: unknown;
80
+ /** Optional structured context — `{ event: 'campaign-click' }` for handler
81
+ * throws, `{ campaign_id, stage }` for render path failures, etc. */
82
+ context: Record<string, unknown>;
83
+ }
84
+ /**
85
+ * Map of lifecycle event name → handler signature. Used by the typed
86
+ * `on(event, handler)` overload below so TS correctly narrows the payload
87
+ * type per event without a discriminated union at the call site.
88
+ */
89
+ export interface InAppLifecycleEventMap {
90
+ 'campaigns-loaded': (campaigns: InAppCampaign[]) => void;
91
+ 'campaign-will-show': (campaign: InAppCampaign) => void | false;
92
+ 'campaign-shown': (campaign: InAppCampaign) => void;
93
+ 'campaign-click': (evt: CampaignClickEvent) => void | false;
94
+ 'campaign-dismiss': (evt: CampaignDismissEvent) => void;
95
+ 'error': (evt: AegisErrorEvent) => void;
96
+ }
51
97
  export interface AegisInAppConfig {
52
98
  writeKey: string;
53
99
  apiHost?: string;
@@ -84,6 +130,45 @@ export declare class AegisInAppManager {
84
130
  private reconnectAttempts;
85
131
  private maxReconnectAttempts;
86
132
  private static readonly CONVERSION_STORAGE_PREFIX;
133
+ private hooks;
134
+ private readyResolve;
135
+ readonly ready: Promise<void>;
136
+ private emit;
137
+ private emitError;
138
+ private register;
139
+ /**
140
+ * Subscribe to in-app message lifecycle events. Returns an unsubscribe
141
+ * function — call to remove the handler (matches React `useEffect` cleanup
142
+ * convention).
143
+ *
144
+ * Supported events: `campaigns-loaded`, `campaign-will-show` (cancellable),
145
+ * `campaign-shown`, `campaign-click` (cancellable), `campaign-dismiss`,
146
+ * `error`. Cancellable events: handler returns `false` to suppress the
147
+ * SDK's default behaviour (e.g., prevent the hard navigation on click,
148
+ * skip rendering on will-show).
149
+ */
150
+ on<E extends keyof InAppLifecycleEventMap>(event: E, handler: InAppLifecycleEventMap[E]): () => void;
151
+ /** Sugar: subscribe to `campaigns-loaded`. Fires after every successful
152
+ * `/v1/in-app/active` poll with the full active-campaign list. */
153
+ onCampaignsLoaded(handler: (campaigns: InAppCampaign[]) => void): () => void;
154
+ /** Sugar: subscribe to `campaign-will-show`. CANCELLABLE — return `false`
155
+ * to suppress rendering this campaign (host-side suppression rules,
156
+ * route-aware blocking, etc.). */
157
+ onCampaignWillShow(handler: (campaign: InAppCampaign) => void | false): () => void;
158
+ /** Sugar: subscribe to `campaign-shown`. Fires after the SDK has painted
159
+ * the campaign to the DOM (post-impression). */
160
+ onCampaignShown(handler: (campaign: InAppCampaign) => void): () => void;
161
+ /** Sugar: subscribe to `campaign-click`. CANCELLABLE — return `false` (or
162
+ * call `evt.preventDefault()`) to suppress the SDK's default
163
+ * `window.location.href` navigation, e.g. to route via a SPA router. */
164
+ onCampaignClick(handler: (evt: CampaignClickEvent) => void | false): () => void;
165
+ /** Sugar: subscribe to `campaign-dismiss`. Fires when user closes/swipes
166
+ * away the campaign before clicking through. */
167
+ onCampaignDismiss(handler: (evt: CampaignDismissEvent) => void): () => void;
168
+ /** Sugar: subscribe to `error`. Aggregates non-fatal SDK errors — fetch
169
+ * failures, render exceptions, host-handler throws. Wire this into your
170
+ * error monitoring (Sentry, Datadog RUM, etc.). */
171
+ onError(handler: (evt: AegisErrorEvent) => void): () => void;
87
172
  constructor(config: AegisInAppConfig);
88
173
  initialize(): Promise<void>;
89
174
  updateUserId(userId: string): void;
@@ -186,6 +271,25 @@ export declare class AegisInAppManager {
186
271
  private createOverlay;
187
272
  private createCTAButton;
188
273
  private addCloseButton;
274
+ /**
275
+ * Navigate to a campaign CTA URL.
276
+ *
277
+ * Dispatches a cancellable `aegis:campaign-click` CustomEvent so host
278
+ * apps (e.g., the storefront SPA) can intercept and route in-place via
279
+ * their client-side router, avoiding a full page reload that re-runs
280
+ * SSR + re-renders the location picker / banner / cart drawer state.
281
+ *
282
+ * The host calls `event.preventDefault()` to suppress the hard nav and
283
+ * handle the URL itself. If no listener calls preventDefault, the SDK
284
+ * falls through to `window.location.href` so plain HTML pages without a
285
+ * SPA still get the user to the destination.
286
+ *
287
+ * Industry parallel: CleverTap dispatches `clevertap-deeplink-click`,
288
+ * MoEngage dispatches `MoE_inappRedirect`. The pattern lets the same
289
+ * SDK serve both vanilla websites (full nav fallback) and SPAs
290
+ * (in-place state change) without per-host configuration.
291
+ */
292
+ private navigateToCampaignAction;
189
293
  private renderBanner;
190
294
  private renderModal;
191
295
  private renderFullScreen;
@@ -1 +1 @@
1
- {"version":3,"file":"AegisInAppManager.d.ts","sourceRoot":"","sources":["../../src/inapp/AegisInAppManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AegisInAppManager.d.ts","sourceRoot":"","sources":["../../src/inapp/AegisInAppManager.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  export { AegisInAppManager } from './AegisInAppManager';
2
- export type { InAppCampaign, AegisInAppConfig } from './AegisInAppManager';
2
+ export type { InAppCampaign, AegisInAppConfig, CampaignClickEvent, CampaignDismissEvent, AegisErrorEvent, InAppLifecycleEventMap, } from './AegisInAppManager';
3
3
  export { renderPreview } from './renderPreview';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inapp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/inapp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,sBAAsB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export type { AegisEvent, TrackEvent, IdentifyEvent, PageEvent, GroupEvent, Alia
7
7
  export type { Plugin, PluginRegistry } from './types/plugin';
8
8
  export { debounce, throttle } from './utils/debounce';
9
9
  export type { ConsentPreferences, ConsentCategory, ConsentStatus, } from './utils/consent';
10
- export type { InAppCampaign, AegisInAppConfig } from './inapp';
10
+ export type { InAppCampaign, AegisInAppConfig, CampaignClickEvent, CampaignDismissEvent, AegisErrorEvent, InAppLifecycleEventMap, } from './inapp';
11
11
  export { renderPreview } from './inapp';
12
12
  export { AegisPlacementManager } from './placements/AegisPlacementManager';
13
13
  export type { PlacementContent, PlacementSlot, AegisPlacementConfig, } from './placements/AegisPlacementManager';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,QAAA,MAAM,KAAK,OAAc,CAAC;AAE1B,eAAe,KAAK,CAAC;AAErB,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5E,YAAY,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,SAAS,EACT,UAAU,EACV,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,aAAa,GACd,MAAM,iBAAiB,CAAC;AAIzB,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,sBAAsB,GACvB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,oBAAoB,GACrB,MAAM,oCAAoC,CAAC;AAE5C,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,YAAY,EAAE,SAAS,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAIxG,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,YAAY,EACV,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,2BAA2B,EAC3B,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAOhF,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChD,YAAY,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,SAAS,EACT,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAE1E,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAK9D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC7E,YAAY,EAAE,mBAAmB,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAQvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -751,6 +751,10 @@ const _AegisInAppManager = class _AegisInAppManager {
751
751
  this.isInitialized = false;
752
752
  this.reconnectAttempts = 0;
753
753
  this.maxReconnectAttempts = 5;
754
+ this.hooks = /* @__PURE__ */ new Map();
755
+ this.ready = new Promise((resolve) => {
756
+ this.readyResolve = resolve;
757
+ });
754
758
  this.writeKey = config.writeKey;
755
759
  this.apiHost = config.apiHost || "https://api.aegis.ai";
756
760
  this.userId = config.userId ?? readAnonIdFromStorage$1();
@@ -761,6 +765,92 @@ const _AegisInAppManager = class _AegisInAppManager {
761
765
  this.enableSSE = config.enableSSE === true;
762
766
  this.onInteractiveCampaign = config.onInteractiveCampaign;
763
767
  }
768
+ emit(eventName, payload) {
769
+ const handlers = this.hooks.get(eventName);
770
+ if (!handlers || handlers.size === 0) return true;
771
+ let proceed = true;
772
+ for (const handler of handlers) {
773
+ try {
774
+ const result = handler(payload);
775
+ if (result === false) proceed = false;
776
+ } catch (err) {
777
+ this.emitError(err, { event: eventName });
778
+ }
779
+ }
780
+ return proceed;
781
+ }
782
+ emitError(err, context) {
783
+ const handlers = this.hooks.get("error");
784
+ if (!handlers || handlers.size === 0) {
785
+ this.log(`Aegis SDK error: ${err instanceof Error ? err.message : String(err)}`, "error");
786
+ return;
787
+ }
788
+ for (const handler of handlers) {
789
+ try {
790
+ handler({
791
+ message: err instanceof Error ? err.message : String(err),
792
+ error: err,
793
+ context: context ?? {}
794
+ });
795
+ } catch {
796
+ }
797
+ }
798
+ }
799
+ register(eventName, handler) {
800
+ if (!this.hooks.has(eventName)) this.hooks.set(eventName, /* @__PURE__ */ new Set());
801
+ this.hooks.get(eventName).add(handler);
802
+ return () => {
803
+ var _a;
804
+ (_a = this.hooks.get(eventName)) == null ? void 0 : _a.delete(handler);
805
+ };
806
+ }
807
+ /**
808
+ * Subscribe to in-app message lifecycle events. Returns an unsubscribe
809
+ * function — call to remove the handler (matches React `useEffect` cleanup
810
+ * convention).
811
+ *
812
+ * Supported events: `campaigns-loaded`, `campaign-will-show` (cancellable),
813
+ * `campaign-shown`, `campaign-click` (cancellable), `campaign-dismiss`,
814
+ * `error`. Cancellable events: handler returns `false` to suppress the
815
+ * SDK's default behaviour (e.g., prevent the hard navigation on click,
816
+ * skip rendering on will-show).
817
+ */
818
+ on(event, handler) {
819
+ return this.register(event, handler);
820
+ }
821
+ /** Sugar: subscribe to `campaigns-loaded`. Fires after every successful
822
+ * `/v1/in-app/active` poll with the full active-campaign list. */
823
+ onCampaignsLoaded(handler) {
824
+ return this.register("campaigns-loaded", handler);
825
+ }
826
+ /** Sugar: subscribe to `campaign-will-show`. CANCELLABLE — return `false`
827
+ * to suppress rendering this campaign (host-side suppression rules,
828
+ * route-aware blocking, etc.). */
829
+ onCampaignWillShow(handler) {
830
+ return this.register("campaign-will-show", handler);
831
+ }
832
+ /** Sugar: subscribe to `campaign-shown`. Fires after the SDK has painted
833
+ * the campaign to the DOM (post-impression). */
834
+ onCampaignShown(handler) {
835
+ return this.register("campaign-shown", handler);
836
+ }
837
+ /** Sugar: subscribe to `campaign-click`. CANCELLABLE — return `false` (or
838
+ * call `evt.preventDefault()`) to suppress the SDK's default
839
+ * `window.location.href` navigation, e.g. to route via a SPA router. */
840
+ onCampaignClick(handler) {
841
+ return this.register("campaign-click", handler);
842
+ }
843
+ /** Sugar: subscribe to `campaign-dismiss`. Fires when user closes/swipes
844
+ * away the campaign before clicking through. */
845
+ onCampaignDismiss(handler) {
846
+ return this.register("campaign-dismiss", handler);
847
+ }
848
+ /** Sugar: subscribe to `error`. Aggregates non-fatal SDK errors — fetch
849
+ * failures, render exceptions, host-handler throws. Wire this into your
850
+ * error monitoring (Sentry, Datadog RUM, etc.). */
851
+ onError(handler) {
852
+ return this.register("error", handler);
853
+ }
764
854
  async initialize() {
765
855
  if (this.isInitialized) {
766
856
  this.log("AegisInApp already initialized");
@@ -1006,8 +1096,11 @@ const _AegisInAppManager = class _AegisInAppManager {
1006
1096
  this.processABAssignments(this.campaigns);
1007
1097
  this.rehydrateSuppressionFromStorage();
1008
1098
  this.log(`Fetched ${this.campaigns.length} campaigns`);
1099
+ this.emit("campaigns-loaded", this.campaigns);
1100
+ this.readyResolve();
1009
1101
  this.tryDisplayNextCampaign();
1010
1102
  } catch (error) {
1103
+ this.emitError(error, { stage: "refresh-campaigns" });
1011
1104
  this.log(`Error refreshing campaigns: ${error}`, "error");
1012
1105
  }
1013
1106
  }
@@ -1103,6 +1196,11 @@ const _AegisInAppManager = class _AegisInAppManager {
1103
1196
  }
1104
1197
  }
1105
1198
  displayCampaign(campaign) {
1199
+ const proceed = this.emit("campaign-will-show", campaign);
1200
+ if (!proceed) {
1201
+ this.log(`campaign ${campaign.id} suppressed by campaign-will-show handler`);
1202
+ return;
1203
+ }
1106
1204
  this.displayedCampaigns.add(campaign.id);
1107
1205
  const interactiveSubTypes = /* @__PURE__ */ new Set([
1108
1206
  "spin_wheel",
@@ -1116,6 +1214,7 @@ const _AegisInAppManager = class _AegisInAppManager {
1116
1214
  if (campaign.sub_type && interactiveSubTypes.has(campaign.sub_type)) {
1117
1215
  this.renderInteractive(campaign);
1118
1216
  this.trackEvent(campaign.id, "impression");
1217
+ this.emit("campaign-shown", campaign);
1119
1218
  return;
1120
1219
  }
1121
1220
  switch (campaign.type) {
@@ -1146,24 +1245,30 @@ const _AegisInAppManager = class _AegisInAppManager {
1146
1245
  case "carousel_cards":
1147
1246
  renderCarouselCards(this.buildRenderContext(campaign));
1148
1247
  this.trackEvent(campaign.id, "impression");
1248
+ this.emit("campaign-shown", campaign);
1149
1249
  return;
1150
1250
  case "sticky_bar":
1151
1251
  renderStickyBar(this.buildRenderContext(campaign));
1152
1252
  this.trackEvent(campaign.id, "impression");
1253
+ this.emit("campaign-shown", campaign);
1153
1254
  return;
1154
1255
  case "progress_bar":
1155
1256
  renderProgressBar(this.buildRenderContext(campaign));
1156
1257
  this.trackEvent(campaign.id, "impression");
1258
+ this.emit("campaign-shown", campaign);
1157
1259
  return;
1158
1260
  case "coachmark_tour":
1159
1261
  renderCoachmarkTour(this.buildRenderContext(campaign));
1262
+ this.emit("campaign-shown", campaign);
1160
1263
  return;
1161
1264
  case "product_recommendation":
1162
1265
  renderProductRecommendation(this.buildRenderContext(campaign));
1163
1266
  this.trackEvent(campaign.id, "impression");
1267
+ this.emit("campaign-shown", campaign);
1164
1268
  return;
1165
1269
  }
1166
1270
  this.trackEvent(campaign.id, "impression");
1271
+ this.emit("campaign-shown", campaign);
1167
1272
  }
1168
1273
  /**
1169
1274
  * Build the shared context passed into the preload-first renderers.
@@ -1514,6 +1619,53 @@ const _AegisInAppManager = class _AegisInAppManager {
1514
1619
  });
1515
1620
  container.appendChild(close);
1516
1621
  }
1622
+ /**
1623
+ * Navigate to a campaign CTA URL.
1624
+ *
1625
+ * Dispatches a cancellable `aegis:campaign-click` CustomEvent so host
1626
+ * apps (e.g., the storefront SPA) can intercept and route in-place via
1627
+ * their client-side router, avoiding a full page reload that re-runs
1628
+ * SSR + re-renders the location picker / banner / cart drawer state.
1629
+ *
1630
+ * The host calls `event.preventDefault()` to suppress the hard nav and
1631
+ * handle the URL itself. If no listener calls preventDefault, the SDK
1632
+ * falls through to `window.location.href` so plain HTML pages without a
1633
+ * SPA still get the user to the destination.
1634
+ *
1635
+ * Industry parallel: CleverTap dispatches `clevertap-deeplink-click`,
1636
+ * MoEngage dispatches `MoE_inappRedirect`. The pattern lets the same
1637
+ * SDK serve both vanilla websites (full nav fallback) and SPAs
1638
+ * (in-place state change) without per-host configuration.
1639
+ */
1640
+ navigateToCampaignAction(campaign, safeUrl, buttonId = "cta") {
1641
+ if (typeof window === "undefined") return;
1642
+ let typedDefaultPrevented = false;
1643
+ const typedEvent = {
1644
+ campaign,
1645
+ action_url: safeUrl,
1646
+ button_id: buttonId,
1647
+ preventDefault: () => {
1648
+ typedDefaultPrevented = true;
1649
+ typedEvent.defaultPrevented = true;
1650
+ },
1651
+ defaultPrevented: false
1652
+ };
1653
+ const typedProceed = this.emit("campaign-click", typedEvent);
1654
+ const domEvent = new CustomEvent("aegis:campaign-click", {
1655
+ detail: {
1656
+ campaign_id: campaign.id,
1657
+ campaign_type: campaign.type,
1658
+ action_url: safeUrl,
1659
+ button_id: buttonId
1660
+ },
1661
+ cancelable: true
1662
+ });
1663
+ const domProceed = window.dispatchEvent(domEvent);
1664
+ const suppressed = !typedProceed || typedDefaultPrevented || !domProceed || domEvent.defaultPrevented;
1665
+ if (!suppressed) {
1666
+ window.location.href = safeUrl;
1667
+ }
1668
+ }
1517
1669
  renderBanner(campaign) {
1518
1670
  const banner = document.createElement("div");
1519
1671
  banner.className = "aegis-in-app-banner";
@@ -1577,7 +1729,7 @@ const _AegisInAppManager = class _AegisInAppManager {
1577
1729
  this.trackEvent(campaign.id, "clicked");
1578
1730
  const safeUrl = this.sanitizeUrl(campaign.action_url);
1579
1731
  if (safeUrl) {
1580
- window.location.href = safeUrl;
1732
+ this.navigateToCampaignAction(campaign, safeUrl);
1581
1733
  }
1582
1734
  this.removeBanner(banner);
1583
1735
  });
@@ -1679,7 +1831,7 @@ const _AegisInAppManager = class _AegisInAppManager {
1679
1831
  this.trackEvent(campaign.id, "clicked");
1680
1832
  const safeUrl = this.sanitizeUrl(campaign.action_url);
1681
1833
  if (safeUrl) {
1682
- window.location.href = safeUrl;
1834
+ this.navigateToCampaignAction(campaign, safeUrl);
1683
1835
  }
1684
1836
  this.removeModal(overlay);
1685
1837
  });
@@ -1768,7 +1920,7 @@ const _AegisInAppManager = class _AegisInAppManager {
1768
1920
  this.trackEvent(campaign.id, "clicked");
1769
1921
  const safeUrl = this.sanitizeUrl(campaign.action_url);
1770
1922
  if (safeUrl) {
1771
- window.location.href = safeUrl;
1923
+ this.navigateToCampaignAction(campaign, safeUrl);
1772
1924
  }
1773
1925
  this.removeModal(overlay);
1774
1926
  });
@@ -1871,7 +2023,7 @@ const _AegisInAppManager = class _AegisInAppManager {
1871
2023
  this.trackEvent(campaign.id, "clicked");
1872
2024
  const safeUrl = this.sanitizeUrl(campaign.action_url);
1873
2025
  if (safeUrl) {
1874
- window.location.href = safeUrl;
2026
+ this.navigateToCampaignAction(campaign, safeUrl);
1875
2027
  }
1876
2028
  this.removeModal(overlay);
1877
2029
  });
@@ -1968,7 +2120,7 @@ const _AegisInAppManager = class _AegisInAppManager {
1968
2120
  this.trackEvent(campaign.id, "clicked");
1969
2121
  const safeUrl = this.sanitizeUrl(campaign.action_url);
1970
2122
  if (safeUrl) {
1971
- window.location.href = safeUrl;
2123
+ this.navigateToCampaignAction(campaign, safeUrl);
1972
2124
  }
1973
2125
  this.removeModal(overlay);
1974
2126
  });
@@ -2320,6 +2472,15 @@ const _AegisInAppManager = class _AegisInAppManager {
2320
2472
  * in_app.dismissed → engagement.dismiss
2321
2473
  */
2322
2474
  async trackEvent(campaignId, eventType) {
2475
+ if (eventType === "dismissed") {
2476
+ const campaign = this.campaigns.find((c) => c.id === campaignId);
2477
+ if (campaign) {
2478
+ this.emit("campaign-dismiss", {
2479
+ campaign,
2480
+ source: "close_button"
2481
+ });
2482
+ }
2483
+ }
2323
2484
  try {
2324
2485
  const url = `${this.apiHost}/v1/in_app/events`;
2325
2486
  const externalEventId = `inapp_${campaignId}_${eventType}_${Date.now()}`;