@posthog/browser-common 0.9.5 → 0.9.7

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.
Files changed (89) hide show
  1. package/dist/client.d.ts +6 -0
  2. package/dist/config.js +1 -1
  3. package/dist/config.mjs +1 -1
  4. package/dist/feature-flags.d.ts +1 -0
  5. package/dist/feature-flags.js +5 -0
  6. package/dist/feature-flags.mjs +5 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +58 -10
  9. package/dist/index.mjs +1 -0
  10. package/dist/survey-action-matcher.d.ts +27 -0
  11. package/dist/survey-action-matcher.js +169 -0
  12. package/dist/survey-action-matcher.mjs +131 -0
  13. package/dist/survey-constants.d.ts +86 -0
  14. package/dist/survey-constants.js +144 -0
  15. package/dist/survey-constants.mjs +76 -0
  16. package/dist/survey-event-host.d.ts +15 -0
  17. package/dist/survey-event-host.js +18 -0
  18. package/dist/survey-event-host.mjs +1 -0
  19. package/dist/survey-event-receiver-base.d.ts +180 -0
  20. package/dist/survey-event-receiver-base.js +354 -0
  21. package/dist/survey-event-receiver-base.mjs +316 -0
  22. package/dist/survey-event-receiver.d.ts +36 -0
  23. package/dist/survey-event-receiver.js +133 -0
  24. package/dist/survey-event-receiver.mjs +95 -0
  25. package/dist/survey-render-context.d.ts +13 -0
  26. package/dist/survey-render-context.js +45 -0
  27. package/dist/survey-render-context.mjs +7 -0
  28. package/dist/surveys/components/BottomSection.d.ts +12 -0
  29. package/dist/surveys/components/BottomSection.js +82 -0
  30. package/dist/surveys/components/BottomSection.mjs +44 -0
  31. package/dist/surveys/components/ConfirmationMessage.d.ts +10 -0
  32. package/dist/surveys/components/ConfirmationMessage.js +92 -0
  33. package/dist/surveys/components/ConfirmationMessage.mjs +54 -0
  34. package/dist/surveys/components/IntroScreen.d.ts +10 -0
  35. package/dist/surveys/components/IntroScreen.js +78 -0
  36. package/dist/surveys/components/IntroScreen.mjs +40 -0
  37. package/dist/surveys/components/PostHogLogo.d.ts +5 -0
  38. package/dist/surveys/components/PostHogLogo.js +54 -0
  39. package/dist/surveys/components/PostHogLogo.mjs +16 -0
  40. package/dist/surveys/components/QuestionHeader.d.ts +10 -0
  41. package/dist/surveys/components/QuestionHeader.js +82 -0
  42. package/dist/surveys/components/QuestionHeader.mjs +41 -0
  43. package/dist/surveys/components/QuestionTypes.d.ts +31 -0
  44. package/dist/surveys/components/QuestionTypes.js +519 -0
  45. package/dist/surveys/components/QuestionTypes.mjs +469 -0
  46. package/dist/surveys/icons.d.ts +12 -0
  47. package/dist/surveys/icons.js +212 -0
  48. package/dist/surveys/icons.mjs +147 -0
  49. package/dist/surveys/survey-branching.d.ts +12 -0
  50. package/dist/surveys/survey-branching.js +101 -0
  51. package/dist/surveys/survey-branching.mjs +60 -0
  52. package/dist/surveys/survey-styles.d.ts +1 -0
  53. package/dist/surveys/survey-styles.js +40 -0
  54. package/dist/surveys/survey-styles.mjs +2 -0
  55. package/dist/surveys/survey-translations.d.ts +22 -0
  56. package/dist/surveys/survey-translations.js +68 -0
  57. package/dist/surveys/survey-translations.mjs +27 -0
  58. package/dist/surveys/survey-url-prefill.d.ts +36 -0
  59. package/dist/surveys/survey-url-prefill.js +162 -0
  60. package/dist/surveys/survey-url-prefill.mjs +118 -0
  61. package/dist/surveys/surveys-extension-utils.d.ts +133 -0
  62. package/dist/surveys/surveys-extension-utils.js +739 -0
  63. package/dist/surveys/surveys-extension-utils.mjs +608 -0
  64. package/dist/surveys-config.d.ts +60 -0
  65. package/dist/surveys-config.js +68 -0
  66. package/dist/surveys-config.mjs +9 -0
  67. package/dist/surveys-renderer.d.ts +248 -0
  68. package/dist/surveys-renderer.js +1299 -0
  69. package/dist/surveys-renderer.mjs +1230 -0
  70. package/dist/surveys.d.ts +117 -0
  71. package/dist/surveys.js +566 -0
  72. package/dist/surveys.mjs +495 -0
  73. package/dist/types/surveys.d.ts +83 -86
  74. package/dist/types/surveys.js +1 -127
  75. package/dist/types/surveys.mjs +1 -76
  76. package/dist/utils/autocapture-utils.js +8 -9
  77. package/dist/utils/autocapture-utils.mjs +8 -9
  78. package/dist/utils/matcher-utils.d.ts +1 -1
  79. package/dist/utils/matcher-utils.js +13 -10
  80. package/dist/utils/matcher-utils.mjs +10 -7
  81. package/dist/utils/survey-utils.d.ts +16 -0
  82. package/dist/utils/survey-utils.js +121 -0
  83. package/dist/utils/survey-utils.mjs +38 -0
  84. package/dist/utils/url-targeting-utils.d.ts +3 -1
  85. package/dist/utils/url-targeting-utils.js +1 -2
  86. package/dist/utils/url-targeting-utils.mjs +1 -2
  87. package/dist/utils/uuidv7.js +4 -4
  88. package/dist/utils/uuidv7.mjs +4 -4
  89. package/package.json +96 -2
@@ -0,0 +1,354 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, getters, values)=>{
5
+ var define = (defs, kind)=>{
6
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
7
+ enumerable: true,
8
+ [kind]: defs[key]
9
+ });
10
+ };
11
+ define(getters, "get");
12
+ define(values, "value");
13
+ };
14
+ })();
15
+ (()=>{
16
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
17
+ })();
18
+ (()=>{
19
+ __webpack_require__.r = (exports1)=>{
20
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
21
+ value: 'Module'
22
+ });
23
+ Object.defineProperty(exports1, '__esModule', {
24
+ value: true
25
+ });
26
+ };
27
+ })();
28
+ var __webpack_exports__ = {};
29
+ __webpack_require__.r(__webpack_exports__);
30
+ __webpack_require__.d(__webpack_exports__, {
31
+ EventReceiver: ()=>EventReceiver
32
+ });
33
+ const external_survey_constants_js_namespaceObject = require("./survey-constants.js");
34
+ const external_survey_action_matcher_js_namespaceObject = require("./survey-action-matcher.js");
35
+ const surveys_namespaceObject = require("@posthog/core/surveys");
36
+ const core_namespaceObject = require("@posthog/core");
37
+ class EventReceiver {
38
+ constructor(host, _onActivationChanged){
39
+ this._onActivationChanged = _onActivationChanged;
40
+ this._pendingActivatedItems = [];
41
+ this._host = host;
42
+ this._eventToItems = new Map();
43
+ this._cancelEventToItems = new Map();
44
+ this._actionToItems = new Map();
45
+ }
46
+ _subscribeSession() {
47
+ this._sessionIdUnsubscribe = this._host.subscribeSession?.((sessionId)=>this._onSessionIdChanged(sessionId));
48
+ }
49
+ _shouldPersistArmedActivation(_itemId) {
50
+ return false;
51
+ }
52
+ _getActivationTimestampsKey() {
53
+ return null;
54
+ }
55
+ _writeActivationTimestamps(_timestamps) {}
56
+ _clearActivationTimestampsStore() {}
57
+ _doesEventMatchFilter(eventConfig, eventPayload) {
58
+ if (!eventConfig) return false;
59
+ return (0, surveys_namespaceObject.matchPropertyFilters)(eventConfig.propertyFilters, eventPayload?.properties);
60
+ }
61
+ _buildEventToItemMap(items, conditionField) {
62
+ const map = new Map();
63
+ items.forEach((item)=>{
64
+ item.conditions?.[conditionField]?.values?.forEach((event)=>{
65
+ if (event?.name) {
66
+ const existing = map.get(event.name) || [];
67
+ existing.push(item.id);
68
+ map.set(event.name, existing);
69
+ }
70
+ });
71
+ });
72
+ return map;
73
+ }
74
+ _getMatchingItems(eventName, eventPayload, conditionField) {
75
+ const itemIdMap = conditionField === external_survey_constants_js_namespaceObject.SurveyEventType.Activation ? this._eventToItems : this._cancelEventToItems;
76
+ const itemIds = itemIdMap.get(eventName);
77
+ let items = [];
78
+ this._getItems((allItems)=>{
79
+ items = allItems.filter((item)=>itemIds?.includes(item.id));
80
+ });
81
+ return items.filter((item)=>{
82
+ const eventConfig = item.conditions?.[conditionField]?.values?.find((e)=>e.name === eventName);
83
+ return this._doesEventMatchFilter(eventConfig, eventPayload);
84
+ });
85
+ }
86
+ register(items) {
87
+ this._register(items, false);
88
+ }
89
+ replace(items) {
90
+ this._register(items, true);
91
+ }
92
+ _register(items, replace) {
93
+ if ((0, core_namespaceObject.isUndefined)(this._host.subscribeCapture)) return;
94
+ this._setupEventBasedItems(items, replace);
95
+ this._setupActionBasedItems(items, replace);
96
+ }
97
+ _setupActionBasedItems(items, replace) {
98
+ const actionBasedItems = items.filter((item)=>item.conditions?.actions?.values?.length);
99
+ if (replace) this._actionToItems.clear();
100
+ if (0 === actionBasedItems.length) {
101
+ if (replace) this._actionMatcher?.replace([]);
102
+ return;
103
+ }
104
+ if (!this._actionMatcher) {
105
+ this._actionMatcher = new external_survey_action_matcher_js_namespaceObject.ActionMatcher(this._host);
106
+ this._actionMatcher.init();
107
+ this._actionMatcher._addActionHook((actionName)=>this.onAction(actionName));
108
+ }
109
+ const actions = [];
110
+ actionBasedItems.forEach((item)=>{
111
+ item.conditions?.actions?.values.forEach((action)=>{
112
+ actions.push(action);
113
+ if (action.name) {
114
+ const matchingItems = this._actionToItems.get(action.name) ?? [];
115
+ if (!matchingItems.includes(item.id)) matchingItems.push(item.id);
116
+ this._actionToItems.set(action.name, matchingItems);
117
+ }
118
+ });
119
+ });
120
+ if (replace) this._actionMatcher.replace(actions);
121
+ else this._actionMatcher.register(actions);
122
+ }
123
+ _mergeItemMaps(target, source) {
124
+ source.forEach((itemIds, eventName)=>{
125
+ const matchingItems = target.get(eventName) ?? [];
126
+ itemIds.forEach((itemId)=>{
127
+ if (!matchingItems.includes(itemId)) matchingItems.push(itemId);
128
+ });
129
+ target.set(eventName, matchingItems);
130
+ });
131
+ }
132
+ _setupEventBasedItems(items, replace) {
133
+ const eventBasedItems = items.filter((item)=>item.conditions?.events && item.conditions?.events?.values?.length > 0);
134
+ const itemsWithCancelEvents = items.filter((item)=>item.conditions?.cancelEvents && item.conditions?.cancelEvents?.values?.length > 0);
135
+ const eventToItems = this._buildEventToItemMap(items, external_survey_constants_js_namespaceObject.SurveyEventType.Activation);
136
+ const cancelEventToItems = this._buildEventToItemMap(items, external_survey_constants_js_namespaceObject.SurveyEventType.Cancellation);
137
+ if (replace) {
138
+ this._eventToItems = eventToItems;
139
+ this._cancelEventToItems = cancelEventToItems;
140
+ } else {
141
+ this._mergeItemMaps(this._eventToItems, eventToItems);
142
+ this._mergeItemMaps(this._cancelEventToItems, cancelEventToItems);
143
+ }
144
+ if (0 === eventBasedItems.length && 0 === itemsWithCancelEvents.length && !items.some((item)=>item.conditions?.actions?.values?.length)) return;
145
+ const matchEventToItem = (eventName, eventPayload)=>{
146
+ this.onEvent(eventName, eventPayload);
147
+ };
148
+ this._captureHookUnsubscribe ??= this._host.subscribeCapture?.(matchEventToItem);
149
+ }
150
+ onEvent(event, eventPayload) {
151
+ const logger = this._getLogger();
152
+ const itemId = eventPayload?.properties?.$survey_id || eventPayload?.properties?.$product_tour_id;
153
+ if (itemId && this.getActivatedIds().includes(itemId)) {
154
+ const outcome = this._activationOutcome(event, itemId, eventPayload);
155
+ if ('consume' === outcome) {
156
+ logger.info('event consumed activated item, removing it', {
157
+ event,
158
+ itemId
159
+ });
160
+ this._deactivateItems([
161
+ itemId
162
+ ]);
163
+ return;
164
+ }
165
+ if ('persist' === outcome) {
166
+ logger.info('shown item promoted to persisted activation', {
167
+ event,
168
+ itemId
169
+ });
170
+ this._persistActivation(itemId);
171
+ this._clearActivationTimestamps([
172
+ itemId
173
+ ]);
174
+ return;
175
+ }
176
+ }
177
+ if (this._cancelEventToItems.has(event)) {
178
+ const itemsToCancel = this._getMatchingItems(event, eventPayload, external_survey_constants_js_namespaceObject.SurveyEventType.Cancellation);
179
+ if (itemsToCancel.length > 0) {
180
+ logger.info('cancel event matched, cancelling items', {
181
+ event,
182
+ itemsToCancel: itemsToCancel.map((s)=>s.id)
183
+ });
184
+ this._deactivateItems(itemsToCancel.map((item)=>item.id));
185
+ itemsToCancel.forEach((item)=>this._cancelPendingItem(item.id));
186
+ }
187
+ }
188
+ if (!this._eventToItems.has(event)) return;
189
+ logger.info('event name matched', {
190
+ event,
191
+ eventPayload,
192
+ items: this._eventToItems.get(event)
193
+ });
194
+ const matchedItems = this._getMatchingItems(event, eventPayload, external_survey_constants_js_namespaceObject.SurveyEventType.Activation);
195
+ this._activateItems(matchedItems.map((item)=>item.id));
196
+ }
197
+ onAction(actionName) {
198
+ if (this._actionToItems.has(actionName)) this._activateItems(this._actionToItems.get(actionName) || []);
199
+ }
200
+ _activateItems(itemIds) {
201
+ if (0 === itemIds.length) return;
202
+ const canPersist = !!this._host.getSessionId();
203
+ const armedInMemory = [];
204
+ for (const itemId of itemIds)if (canPersist && this._shouldPersistArmedActivation(itemId)) {
205
+ if (this._persistActivation(itemId)) this._recordActivationTimestamp(itemId);
206
+ } else armedInMemory.push(itemId);
207
+ if (armedInMemory.length > 0) this._pendingActivatedItems = [
208
+ ...new Set([
209
+ ...this._pendingActivatedItems,
210
+ ...armedInMemory
211
+ ])
212
+ ];
213
+ this._getLogger().info('updating activated items', {
214
+ activatedItems: this.getActivatedIds()
215
+ });
216
+ this._notifyActivationChanged();
217
+ }
218
+ _persistActivation(itemId) {
219
+ this._pendingActivatedItems = this._pendingActivatedItems.filter((id)=>id !== itemId);
220
+ const persisted = this._getPersistedActivatedIds();
221
+ if (persisted.includes(itemId)) return false;
222
+ this._setActivatedItems([
223
+ ...persisted,
224
+ itemId
225
+ ]);
226
+ this._stampActivationSession();
227
+ return true;
228
+ }
229
+ _deactivateItems(itemIds) {
230
+ const remove = new Set(itemIds);
231
+ this._pendingActivatedItems = this._pendingActivatedItems.filter((id)=>!remove.has(id));
232
+ const persisted = this._getRawPersistedActivatedIds();
233
+ const nextPersisted = persisted.filter((id)=>!remove.has(id));
234
+ if (nextPersisted.length !== persisted.length) {
235
+ this._setActivatedItems(nextPersisted);
236
+ if (0 === nextPersisted.length) this._clearActivationSession();
237
+ }
238
+ this._clearActivationTimestamps(itemIds);
239
+ this._notifyActivationChanged();
240
+ }
241
+ _notifyActivationChanged() {
242
+ try {
243
+ this._onActivationChanged?.();
244
+ } catch (error) {
245
+ this._getLogger().error('Error while handling activated items change', error);
246
+ }
247
+ }
248
+ _getRawActivationTimestamps() {
249
+ const key = this._getActivationTimestampsKey();
250
+ if (!key) return {};
251
+ const stored = this._host.getProperty(key);
252
+ return stored && 'object' == typeof stored ? stored : {};
253
+ }
254
+ _recordActivationTimestamp(itemId) {
255
+ const key = this._getActivationTimestampsKey();
256
+ if (!key) return;
257
+ const timestamps = this._getRawActivationTimestamps();
258
+ this._writeActivationTimestamps({
259
+ ...timestamps,
260
+ [itemId]: Date.now()
261
+ });
262
+ }
263
+ _clearActivationTimestamps(itemIds) {
264
+ const key = this._getActivationTimestampsKey();
265
+ if (!key) return;
266
+ const timestamps = this._getRawActivationTimestamps();
267
+ const next = {};
268
+ let changed = false;
269
+ for (const [id, ts] of Object.entries(timestamps))if (itemIds.includes(id)) changed = true;
270
+ else next[id] = ts;
271
+ if (!changed) return;
272
+ if ((0, core_namespaceObject.isEmptyObject)(next)) return void this._clearActivationTimestampsStore();
273
+ this._writeActivationTimestamps(next);
274
+ }
275
+ _clearAllActivationTimestamps() {
276
+ if (this._getActivationTimestampsKey()) this._clearActivationTimestampsStore();
277
+ }
278
+ getActivationTimestamp(itemId) {
279
+ if (!this._getPersistedActivatedIds().includes(itemId)) return;
280
+ const ts = this._getRawActivationTimestamps()[itemId];
281
+ return (0, core_namespaceObject.isNumber)(ts) ? ts : void 0;
282
+ }
283
+ _getRawPersistedActivatedIds() {
284
+ const activatedKey = this._getActivatedKey();
285
+ const existingActivatedItems = this._host.getProperty(activatedKey);
286
+ return existingActivatedItems ? existingActivatedItems : [];
287
+ }
288
+ _getPersistedActivatedIds() {
289
+ const ids = this._getRawPersistedActivatedIds();
290
+ if (0 === ids.length) return [];
291
+ const stampedSessionId = this._host.getProperty(this._getActivatedSessionKey());
292
+ const currentSessionId = this._host.getSessionId();
293
+ if (!currentSessionId || stampedSessionId !== currentSessionId) return [];
294
+ return ids;
295
+ }
296
+ _stampActivationSession() {
297
+ const currentSessionId = this._host.getSessionId();
298
+ if (currentSessionId) this._setActivatedSession(currentSessionId);
299
+ }
300
+ _clearActivationSession() {
301
+ this._clearActivatedSession();
302
+ }
303
+ _onSessionIdChanged(sessionId) {
304
+ const stampedSessionId = this._host.getProperty(this._getActivatedSessionKey());
305
+ if (stampedSessionId && stampedSessionId !== sessionId) {
306
+ const activatedItemIds = this._getRawPersistedActivatedIds();
307
+ const activationTimestamps = this._getRawActivationTimestamps();
308
+ if (activatedItemIds.length > 0) {
309
+ this._setActivatedItems([]);
310
+ activatedItemIds.filter((itemId)=>(0, core_namespaceObject.isNumber)(activationTimestamps[itemId])).forEach((itemId)=>this._cancelPendingItem(itemId));
311
+ }
312
+ this._clearActivationSession();
313
+ this._clearAllActivationTimestamps();
314
+ if (activatedItemIds.length > 0) this._notifyActivationChanged();
315
+ }
316
+ }
317
+ getActivatedIds() {
318
+ const all = [
319
+ ...new Set([
320
+ ...this._getPersistedActivatedIds(),
321
+ ...this._pendingActivatedItems
322
+ ])
323
+ ];
324
+ return all.filter((itemId)=>!this._isItemPermanentlyIneligible(itemId));
325
+ }
326
+ dispose() {
327
+ this._sessionIdUnsubscribe?.();
328
+ this._sessionIdUnsubscribe = void 0;
329
+ this._captureHookUnsubscribe?.();
330
+ this._captureHookUnsubscribe = void 0;
331
+ this._actionMatcher?.dispose();
332
+ this._actionMatcher = void 0;
333
+ }
334
+ reset() {
335
+ this._pendingActivatedItems = [];
336
+ if (this._getRawPersistedActivatedIds().length > 0) this._setActivatedItems([]);
337
+ this._clearActivationSession();
338
+ this._clearAllActivationTimestamps();
339
+ this._notifyActivationChanged();
340
+ }
341
+ getEventToItemsMap() {
342
+ return this._eventToItems;
343
+ }
344
+ _getActionMatcher() {
345
+ return this._actionMatcher;
346
+ }
347
+ }
348
+ exports.EventReceiver = __webpack_exports__.EventReceiver;
349
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
350
+ "EventReceiver"
351
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
352
+ Object.defineProperty(exports, '__esModule', {
353
+ value: true
354
+ });
@@ -0,0 +1,316 @@
1
+ import { SurveyEventType } from "./survey-constants.mjs";
2
+ import { ActionMatcher } from "./survey-action-matcher.mjs";
3
+ import { matchPropertyFilters } from "@posthog/core/surveys";
4
+ import { isEmptyObject, isNumber, isUndefined } from "@posthog/core";
5
+ class EventReceiver {
6
+ constructor(host, _onActivationChanged){
7
+ this._onActivationChanged = _onActivationChanged;
8
+ this._pendingActivatedItems = [];
9
+ this._host = host;
10
+ this._eventToItems = new Map();
11
+ this._cancelEventToItems = new Map();
12
+ this._actionToItems = new Map();
13
+ }
14
+ _subscribeSession() {
15
+ this._sessionIdUnsubscribe = this._host.subscribeSession?.((sessionId)=>this._onSessionIdChanged(sessionId));
16
+ }
17
+ _shouldPersistArmedActivation(_itemId) {
18
+ return false;
19
+ }
20
+ _getActivationTimestampsKey() {
21
+ return null;
22
+ }
23
+ _writeActivationTimestamps(_timestamps) {}
24
+ _clearActivationTimestampsStore() {}
25
+ _doesEventMatchFilter(eventConfig, eventPayload) {
26
+ if (!eventConfig) return false;
27
+ return matchPropertyFilters(eventConfig.propertyFilters, eventPayload?.properties);
28
+ }
29
+ _buildEventToItemMap(items, conditionField) {
30
+ const map = new Map();
31
+ items.forEach((item)=>{
32
+ item.conditions?.[conditionField]?.values?.forEach((event)=>{
33
+ if (event?.name) {
34
+ const existing = map.get(event.name) || [];
35
+ existing.push(item.id);
36
+ map.set(event.name, existing);
37
+ }
38
+ });
39
+ });
40
+ return map;
41
+ }
42
+ _getMatchingItems(eventName, eventPayload, conditionField) {
43
+ const itemIdMap = conditionField === SurveyEventType.Activation ? this._eventToItems : this._cancelEventToItems;
44
+ const itemIds = itemIdMap.get(eventName);
45
+ let items = [];
46
+ this._getItems((allItems)=>{
47
+ items = allItems.filter((item)=>itemIds?.includes(item.id));
48
+ });
49
+ return items.filter((item)=>{
50
+ const eventConfig = item.conditions?.[conditionField]?.values?.find((e)=>e.name === eventName);
51
+ return this._doesEventMatchFilter(eventConfig, eventPayload);
52
+ });
53
+ }
54
+ register(items) {
55
+ this._register(items, false);
56
+ }
57
+ replace(items) {
58
+ this._register(items, true);
59
+ }
60
+ _register(items, replace) {
61
+ if (isUndefined(this._host.subscribeCapture)) return;
62
+ this._setupEventBasedItems(items, replace);
63
+ this._setupActionBasedItems(items, replace);
64
+ }
65
+ _setupActionBasedItems(items, replace) {
66
+ const actionBasedItems = items.filter((item)=>item.conditions?.actions?.values?.length);
67
+ if (replace) this._actionToItems.clear();
68
+ if (0 === actionBasedItems.length) {
69
+ if (replace) this._actionMatcher?.replace([]);
70
+ return;
71
+ }
72
+ if (!this._actionMatcher) {
73
+ this._actionMatcher = new ActionMatcher(this._host);
74
+ this._actionMatcher.init();
75
+ this._actionMatcher._addActionHook((actionName)=>this.onAction(actionName));
76
+ }
77
+ const actions = [];
78
+ actionBasedItems.forEach((item)=>{
79
+ item.conditions?.actions?.values.forEach((action)=>{
80
+ actions.push(action);
81
+ if (action.name) {
82
+ const matchingItems = this._actionToItems.get(action.name) ?? [];
83
+ if (!matchingItems.includes(item.id)) matchingItems.push(item.id);
84
+ this._actionToItems.set(action.name, matchingItems);
85
+ }
86
+ });
87
+ });
88
+ if (replace) this._actionMatcher.replace(actions);
89
+ else this._actionMatcher.register(actions);
90
+ }
91
+ _mergeItemMaps(target, source) {
92
+ source.forEach((itemIds, eventName)=>{
93
+ const matchingItems = target.get(eventName) ?? [];
94
+ itemIds.forEach((itemId)=>{
95
+ if (!matchingItems.includes(itemId)) matchingItems.push(itemId);
96
+ });
97
+ target.set(eventName, matchingItems);
98
+ });
99
+ }
100
+ _setupEventBasedItems(items, replace) {
101
+ const eventBasedItems = items.filter((item)=>item.conditions?.events && item.conditions?.events?.values?.length > 0);
102
+ const itemsWithCancelEvents = items.filter((item)=>item.conditions?.cancelEvents && item.conditions?.cancelEvents?.values?.length > 0);
103
+ const eventToItems = this._buildEventToItemMap(items, SurveyEventType.Activation);
104
+ const cancelEventToItems = this._buildEventToItemMap(items, SurveyEventType.Cancellation);
105
+ if (replace) {
106
+ this._eventToItems = eventToItems;
107
+ this._cancelEventToItems = cancelEventToItems;
108
+ } else {
109
+ this._mergeItemMaps(this._eventToItems, eventToItems);
110
+ this._mergeItemMaps(this._cancelEventToItems, cancelEventToItems);
111
+ }
112
+ if (0 === eventBasedItems.length && 0 === itemsWithCancelEvents.length && !items.some((item)=>item.conditions?.actions?.values?.length)) return;
113
+ const matchEventToItem = (eventName, eventPayload)=>{
114
+ this.onEvent(eventName, eventPayload);
115
+ };
116
+ this._captureHookUnsubscribe ??= this._host.subscribeCapture?.(matchEventToItem);
117
+ }
118
+ onEvent(event, eventPayload) {
119
+ const logger = this._getLogger();
120
+ const itemId = eventPayload?.properties?.$survey_id || eventPayload?.properties?.$product_tour_id;
121
+ if (itemId && this.getActivatedIds().includes(itemId)) {
122
+ const outcome = this._activationOutcome(event, itemId, eventPayload);
123
+ if ('consume' === outcome) {
124
+ logger.info('event consumed activated item, removing it', {
125
+ event,
126
+ itemId
127
+ });
128
+ this._deactivateItems([
129
+ itemId
130
+ ]);
131
+ return;
132
+ }
133
+ if ('persist' === outcome) {
134
+ logger.info('shown item promoted to persisted activation', {
135
+ event,
136
+ itemId
137
+ });
138
+ this._persistActivation(itemId);
139
+ this._clearActivationTimestamps([
140
+ itemId
141
+ ]);
142
+ return;
143
+ }
144
+ }
145
+ if (this._cancelEventToItems.has(event)) {
146
+ const itemsToCancel = this._getMatchingItems(event, eventPayload, SurveyEventType.Cancellation);
147
+ if (itemsToCancel.length > 0) {
148
+ logger.info('cancel event matched, cancelling items', {
149
+ event,
150
+ itemsToCancel: itemsToCancel.map((s)=>s.id)
151
+ });
152
+ this._deactivateItems(itemsToCancel.map((item)=>item.id));
153
+ itemsToCancel.forEach((item)=>this._cancelPendingItem(item.id));
154
+ }
155
+ }
156
+ if (!this._eventToItems.has(event)) return;
157
+ logger.info('event name matched', {
158
+ event,
159
+ eventPayload,
160
+ items: this._eventToItems.get(event)
161
+ });
162
+ const matchedItems = this._getMatchingItems(event, eventPayload, SurveyEventType.Activation);
163
+ this._activateItems(matchedItems.map((item)=>item.id));
164
+ }
165
+ onAction(actionName) {
166
+ if (this._actionToItems.has(actionName)) this._activateItems(this._actionToItems.get(actionName) || []);
167
+ }
168
+ _activateItems(itemIds) {
169
+ if (0 === itemIds.length) return;
170
+ const canPersist = !!this._host.getSessionId();
171
+ const armedInMemory = [];
172
+ for (const itemId of itemIds)if (canPersist && this._shouldPersistArmedActivation(itemId)) {
173
+ if (this._persistActivation(itemId)) this._recordActivationTimestamp(itemId);
174
+ } else armedInMemory.push(itemId);
175
+ if (armedInMemory.length > 0) this._pendingActivatedItems = [
176
+ ...new Set([
177
+ ...this._pendingActivatedItems,
178
+ ...armedInMemory
179
+ ])
180
+ ];
181
+ this._getLogger().info('updating activated items', {
182
+ activatedItems: this.getActivatedIds()
183
+ });
184
+ this._notifyActivationChanged();
185
+ }
186
+ _persistActivation(itemId) {
187
+ this._pendingActivatedItems = this._pendingActivatedItems.filter((id)=>id !== itemId);
188
+ const persisted = this._getPersistedActivatedIds();
189
+ if (persisted.includes(itemId)) return false;
190
+ this._setActivatedItems([
191
+ ...persisted,
192
+ itemId
193
+ ]);
194
+ this._stampActivationSession();
195
+ return true;
196
+ }
197
+ _deactivateItems(itemIds) {
198
+ const remove = new Set(itemIds);
199
+ this._pendingActivatedItems = this._pendingActivatedItems.filter((id)=>!remove.has(id));
200
+ const persisted = this._getRawPersistedActivatedIds();
201
+ const nextPersisted = persisted.filter((id)=>!remove.has(id));
202
+ if (nextPersisted.length !== persisted.length) {
203
+ this._setActivatedItems(nextPersisted);
204
+ if (0 === nextPersisted.length) this._clearActivationSession();
205
+ }
206
+ this._clearActivationTimestamps(itemIds);
207
+ this._notifyActivationChanged();
208
+ }
209
+ _notifyActivationChanged() {
210
+ try {
211
+ this._onActivationChanged?.();
212
+ } catch (error) {
213
+ this._getLogger().error('Error while handling activated items change', error);
214
+ }
215
+ }
216
+ _getRawActivationTimestamps() {
217
+ const key = this._getActivationTimestampsKey();
218
+ if (!key) return {};
219
+ const stored = this._host.getProperty(key);
220
+ return stored && 'object' == typeof stored ? stored : {};
221
+ }
222
+ _recordActivationTimestamp(itemId) {
223
+ const key = this._getActivationTimestampsKey();
224
+ if (!key) return;
225
+ const timestamps = this._getRawActivationTimestamps();
226
+ this._writeActivationTimestamps({
227
+ ...timestamps,
228
+ [itemId]: Date.now()
229
+ });
230
+ }
231
+ _clearActivationTimestamps(itemIds) {
232
+ const key = this._getActivationTimestampsKey();
233
+ if (!key) return;
234
+ const timestamps = this._getRawActivationTimestamps();
235
+ const next = {};
236
+ let changed = false;
237
+ for (const [id, ts] of Object.entries(timestamps))if (itemIds.includes(id)) changed = true;
238
+ else next[id] = ts;
239
+ if (!changed) return;
240
+ if (isEmptyObject(next)) return void this._clearActivationTimestampsStore();
241
+ this._writeActivationTimestamps(next);
242
+ }
243
+ _clearAllActivationTimestamps() {
244
+ if (this._getActivationTimestampsKey()) this._clearActivationTimestampsStore();
245
+ }
246
+ getActivationTimestamp(itemId) {
247
+ if (!this._getPersistedActivatedIds().includes(itemId)) return;
248
+ const ts = this._getRawActivationTimestamps()[itemId];
249
+ return isNumber(ts) ? ts : void 0;
250
+ }
251
+ _getRawPersistedActivatedIds() {
252
+ const activatedKey = this._getActivatedKey();
253
+ const existingActivatedItems = this._host.getProperty(activatedKey);
254
+ return existingActivatedItems ? existingActivatedItems : [];
255
+ }
256
+ _getPersistedActivatedIds() {
257
+ const ids = this._getRawPersistedActivatedIds();
258
+ if (0 === ids.length) return [];
259
+ const stampedSessionId = this._host.getProperty(this._getActivatedSessionKey());
260
+ const currentSessionId = this._host.getSessionId();
261
+ if (!currentSessionId || stampedSessionId !== currentSessionId) return [];
262
+ return ids;
263
+ }
264
+ _stampActivationSession() {
265
+ const currentSessionId = this._host.getSessionId();
266
+ if (currentSessionId) this._setActivatedSession(currentSessionId);
267
+ }
268
+ _clearActivationSession() {
269
+ this._clearActivatedSession();
270
+ }
271
+ _onSessionIdChanged(sessionId) {
272
+ const stampedSessionId = this._host.getProperty(this._getActivatedSessionKey());
273
+ if (stampedSessionId && stampedSessionId !== sessionId) {
274
+ const activatedItemIds = this._getRawPersistedActivatedIds();
275
+ const activationTimestamps = this._getRawActivationTimestamps();
276
+ if (activatedItemIds.length > 0) {
277
+ this._setActivatedItems([]);
278
+ activatedItemIds.filter((itemId)=>isNumber(activationTimestamps[itemId])).forEach((itemId)=>this._cancelPendingItem(itemId));
279
+ }
280
+ this._clearActivationSession();
281
+ this._clearAllActivationTimestamps();
282
+ if (activatedItemIds.length > 0) this._notifyActivationChanged();
283
+ }
284
+ }
285
+ getActivatedIds() {
286
+ const all = [
287
+ ...new Set([
288
+ ...this._getPersistedActivatedIds(),
289
+ ...this._pendingActivatedItems
290
+ ])
291
+ ];
292
+ return all.filter((itemId)=>!this._isItemPermanentlyIneligible(itemId));
293
+ }
294
+ dispose() {
295
+ this._sessionIdUnsubscribe?.();
296
+ this._sessionIdUnsubscribe = void 0;
297
+ this._captureHookUnsubscribe?.();
298
+ this._captureHookUnsubscribe = void 0;
299
+ this._actionMatcher?.dispose();
300
+ this._actionMatcher = void 0;
301
+ }
302
+ reset() {
303
+ this._pendingActivatedItems = [];
304
+ if (this._getRawPersistedActivatedIds().length > 0) this._setActivatedItems([]);
305
+ this._clearActivationSession();
306
+ this._clearAllActivationTimestamps();
307
+ this._notifyActivationChanged();
308
+ }
309
+ getEventToItemsMap() {
310
+ return this._eventToItems;
311
+ }
312
+ _getActionMatcher() {
313
+ return this._actionMatcher;
314
+ }
315
+ }
316
+ export { EventReceiver };