@contentful/optimization-core 0.1.0-alpha10 → 0.1.0-alpha12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,5 +1,13 @@
1
1
  "use strict";
2
2
  var __webpack_modules__ = {
3
+ "./src/api-schemas.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
+ var _contentful_optimization_api_client_api_schemas__rspack_import_0 = __webpack_require__("@contentful/optimization-api-client/api-schemas");
5
+ if (__webpack_require__.o(_contentful_optimization_api_client_api_schemas__rspack_import_0, "PartialProfile")) __webpack_require__.d(__webpack_exports__, {
6
+ PartialProfile: function() {
7
+ return _contentful_optimization_api_client_api_schemas__rspack_import_0.PartialProfile;
8
+ }
9
+ });
10
+ },
3
11
  "./src/constants.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
12
  __webpack_require__.d(__webpack_exports__, {
5
13
  ANONYMOUS_ID_COOKIE: ()=>ANONYMOUS_ID_COOKIE,
@@ -11,10 +19,10 @@ var __webpack_modules__ = {
11
19
  DEBUG_FLAG_KEY: ()=>DEBUG_FLAG_KEY,
12
20
  OPTIMIZATION_CORE_SDK_NAME: ()=>OPTIMIZATION_CORE_SDK_NAME,
13
21
  OPTIMIZATION_CORE_SDK_VERSION: ()=>OPTIMIZATION_CORE_SDK_VERSION,
14
- PERSONALIZATIONS_CACHE_KEY: ()=>PERSONALIZATIONS_CACHE_KEY,
15
- PROFILE_CACHE_KEY: ()=>PROFILE_CACHE_KEY
22
+ PROFILE_CACHE_KEY: ()=>PROFILE_CACHE_KEY,
23
+ SELECTED_OPTIMIZATIONS_CACHE_KEY: ()=>SELECTED_OPTIMIZATIONS_CACHE_KEY
16
24
  });
17
- const OPTIMIZATION_CORE_SDK_VERSION = "0.1.0-alpha10";
25
+ const OPTIMIZATION_CORE_SDK_VERSION = "0.1.0-alpha12";
18
26
  const OPTIMIZATION_CORE_SDK_NAME = "@contentful/optimization-core";
19
27
  const ANONYMOUS_ID_COOKIE = 'ctfl-opt-aid';
20
28
  const ANONYMOUS_ID_KEY = '__ctfl_opt_anonymous_id__';
@@ -22,7 +30,7 @@ var __webpack_modules__ = {
22
30
  const CHANGES_CACHE_KEY = '__ctfl_opt_changes__';
23
31
  const DEBUG_FLAG_KEY = '__ctfl_opt_debug__';
24
32
  const PROFILE_CACHE_KEY = '__ctfl_opt_profile__';
25
- const PERSONALIZATIONS_CACHE_KEY = '__ctfl_opt_personalizations__';
33
+ const SELECTED_OPTIMIZATIONS_CACHE_KEY = '__ctfl_opt_selected-optimizations__';
26
34
  const ANONYMOUS_ID_COOKIE_LEGACY = 'ntaid';
27
35
  const ANONYMOUS_ID_KEY_LEGACY = '__nt_anonymous_id__';
28
36
  },
@@ -33,6 +41,9 @@ var __webpack_modules__ = {
33
41
  });
34
42
  const PREVIEW_PANEL_SIGNALS_SYMBOL = Symbol.for('ctfl.optimization.preview.signals');
35
43
  const PREVIEW_PANEL_SIGNAL_FNS_SYMBOL = Symbol.for('ctfl.optimization.preview.signalFns');
44
+ },
45
+ "@contentful/optimization-api-client/api-schemas" (module) {
46
+ module.exports = require("@contentful/optimization-api-client/api-schemas");
36
47
  }
37
48
  };
38
49
  var __webpack_module_cache__ = {};
@@ -45,6 +56,15 @@ function __webpack_require__(moduleId) {
45
56
  __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
46
57
  return module.exports;
47
58
  }
59
+ (()=>{
60
+ __webpack_require__.n = (module)=>{
61
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
62
+ __webpack_require__.d(getter, {
63
+ a: getter
64
+ });
65
+ return getter;
66
+ };
67
+ })();
48
68
  (()=>{
49
69
  __webpack_require__.d = (exports1, definition)=>{
50
70
  for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
@@ -70,18 +90,24 @@ var __webpack_exports__ = {};
70
90
  (()=>{
71
91
  __webpack_require__.r(__webpack_exports__);
72
92
  __webpack_require__.d(__webpack_exports__, {
73
- OPTIMIZATION_CORE_SDK_NAME: ()=>constants.OPTIMIZATION_CORE_SDK_NAME,
93
+ HoverBuilderArgs: ()=>HoverBuilderArgs,
74
94
  ANONYMOUS_ID_KEY: ()=>constants.ANONYMOUS_ID_KEY,
95
+ OPTIMIZATION_CORE_SDK_NAME: ()=>constants.OPTIMIZATION_CORE_SDK_NAME,
75
96
  OPTIMIZATION_CORE_SDK_VERSION: ()=>constants.OPTIMIZATION_CORE_SDK_VERSION,
97
+ DEFAULT_PAGE_PROPERTIES: ()=>DEFAULT_PAGE_PROPERTIES,
76
98
  PROFILE_CACHE_KEY: ()=>constants.PROFILE_CACHE_KEY,
77
- PersonalizationStateful: ()=>personalization_PersonalizationStateful,
99
+ SELECTED_OPTIMIZATIONS_CACHE_KEY: ()=>constants.SELECTED_OPTIMIZATIONS_CACHE_KEY,
100
+ PageViewBuilderArgs: ()=>PageViewBuilderArgs,
101
+ ScreenViewBuilderArgs: ()=>ScreenViewBuilderArgs,
78
102
  batch: ()=>signals_core_namespaceObject.batch,
79
- AnalyticsStateless: ()=>analytics_AnalyticsStateless,
80
- PersonalizationStateless: ()=>personalization_PersonalizationStateless,
103
+ toObservable: ()=>toObservable,
81
104
  InterceptorManager: ()=>InterceptorManager,
82
- AnalyticsStateful: ()=>analytics_AnalyticsStateful,
83
105
  CONSENT_KEY: ()=>constants.CONSENT_KEY,
106
+ FlagViewBuilderArgs: ()=>FlagViewBuilderArgs,
84
107
  signals: ()=>signals,
108
+ TrackBuilderArgs: ()=>TrackBuilderArgs,
109
+ ViewBuilderArgs: ()=>ViewBuilderArgs,
110
+ toDistinctObservable: ()=>toDistinctObservable,
85
111
  ANONYMOUS_ID_KEY_LEGACY: ()=>constants.ANONYMOUS_ID_KEY_LEGACY,
86
112
  CoreStateless: ()=>src_CoreStateless,
87
113
  PREVIEW_PANEL_SIGNAL_FNS_SYMBOL: ()=>symbols.PREVIEW_PANEL_SIGNAL_FNS_SYMBOL,
@@ -89,18 +115,338 @@ var __webpack_exports__ = {};
89
115
  MergeTagValueResolver: ()=>resolvers_MergeTagValueResolver,
90
116
  signalFns: ()=>signalFns,
91
117
  DEBUG_FLAG_KEY: ()=>constants.DEBUG_FLAG_KEY,
118
+ IdentifyBuilderArgs: ()=>IdentifyBuilderArgs,
92
119
  FlagsResolver: ()=>resolvers_FlagsResolver,
93
120
  ANONYMOUS_ID_COOKIE_LEGACY: ()=>constants.ANONYMOUS_ID_COOKIE_LEGACY,
94
121
  ANONYMOUS_ID_COOKIE: ()=>constants.ANONYMOUS_ID_COOKIE,
95
- PERSONALIZATIONS_CACHE_KEY: ()=>constants.PERSONALIZATIONS_CACHE_KEY,
122
+ ClickBuilderArgs: ()=>ClickBuilderArgs,
123
+ OptimizedEntryResolver: ()=>resolvers_OptimizedEntryResolver,
124
+ UniversalEventBuilderArgs: ()=>UniversalEventBuilderArgs,
125
+ EntryInteractionBuilderArgsBase: ()=>EntryInteractionBuilderArgsBase,
96
126
  effect: ()=>signals_core_namespaceObject.effect,
97
- PersonalizedEntryResolver: ()=>resolvers_PersonalizedEntryResolver,
98
127
  PREVIEW_PANEL_SIGNALS_SYMBOL: ()=>symbols.PREVIEW_PANEL_SIGNALS_SYMBOL,
99
128
  guardedBy: ()=>guardedBy,
100
129
  CHANGES_CACHE_KEY: ()=>constants.CHANGES_CACHE_KEY,
101
- PersonalizationBase: ()=>personalization_PersonalizationBase
130
+ EventBuilder: ()=>events_EventBuilder
102
131
  });
103
132
  const signals_core_namespaceObject = require("@preact/signals-core");
133
+ const external_es_toolkit_namespaceObject = require("es-toolkit");
134
+ function isNonNullish(value) {
135
+ return null != value;
136
+ }
137
+ function toError(value) {
138
+ if (value instanceof Error) return value;
139
+ return new Error(`Subscriber threw non-Error value: ${String(value)}`);
140
+ }
141
+ function toObservable(s) {
142
+ return {
143
+ get current () {
144
+ return (0, external_es_toolkit_namespaceObject.cloneDeep)(s.value);
145
+ },
146
+ subscribe (next) {
147
+ const dispose = (0, signals_core_namespaceObject.effect)(()=>{
148
+ next((0, external_es_toolkit_namespaceObject.cloneDeep)(s.value));
149
+ });
150
+ return {
151
+ unsubscribe: dispose
152
+ };
153
+ },
154
+ subscribeOnce (next) {
155
+ let closed = false;
156
+ let isEffectActive = false;
157
+ let dispose = ()=>void 0;
158
+ const stop = ()=>{
159
+ if (closed) return;
160
+ closed = true;
161
+ if (isEffectActive) dispose();
162
+ };
163
+ dispose = (0, signals_core_namespaceObject.effect)(()=>{
164
+ if (closed) return;
165
+ const { value } = s;
166
+ if (!isNonNullish(value)) return;
167
+ closed = true;
168
+ let callbackError = null;
169
+ try {
170
+ next((0, external_es_toolkit_namespaceObject.cloneDeep)(value));
171
+ } catch (error) {
172
+ callbackError = toError(error);
173
+ }
174
+ if (isEffectActive) dispose();
175
+ else queueMicrotask(dispose);
176
+ if (callbackError) throw callbackError;
177
+ });
178
+ isEffectActive = true;
179
+ return {
180
+ unsubscribe: stop
181
+ };
182
+ }
183
+ };
184
+ }
185
+ function toDistinctObservable(s, isEqual) {
186
+ const observable = toObservable(s);
187
+ return {
188
+ get current () {
189
+ return observable.current;
190
+ },
191
+ subscribe (next) {
192
+ let hasPrevious = false;
193
+ let previous = (0, external_es_toolkit_namespaceObject.cloneDeep)(observable.current);
194
+ return observable.subscribe((value)=>{
195
+ if (hasPrevious && isEqual(previous, value)) return;
196
+ hasPrevious = true;
197
+ previous = (0, external_es_toolkit_namespaceObject.cloneDeep)(value);
198
+ next(value);
199
+ });
200
+ },
201
+ subscribeOnce (next) {
202
+ return observable.subscribeOnce(next);
203
+ }
204
+ };
205
+ }
206
+ const signals_changes = (0, signals_core_namespaceObject.signal)();
207
+ const blockedEvent = (0, signals_core_namespaceObject.signal)();
208
+ const consent = (0, signals_core_namespaceObject.signal)();
209
+ const signals_event = (0, signals_core_namespaceObject.signal)();
210
+ const online = (0, signals_core_namespaceObject.signal)(true);
211
+ const previewPanelAttached = (0, signals_core_namespaceObject.signal)(false);
212
+ const previewPanelOpen = (0, signals_core_namespaceObject.signal)(false);
213
+ const signals_selectedOptimizations = (0, signals_core_namespaceObject.signal)();
214
+ const canOptimize = (0, signals_core_namespaceObject.computed)(()=>void 0 !== signals_selectedOptimizations.value);
215
+ const signals_profile = (0, signals_core_namespaceObject.signal)();
216
+ const signals = {
217
+ blockedEvent,
218
+ changes: signals_changes,
219
+ consent,
220
+ event: signals_event,
221
+ online,
222
+ previewPanelAttached,
223
+ previewPanelOpen,
224
+ selectedOptimizations: signals_selectedOptimizations,
225
+ canOptimize,
226
+ profile: signals_profile
227
+ };
228
+ const signalFns = {
229
+ batch: signals_core_namespaceObject.batch,
230
+ computed: signals_core_namespaceObject.computed,
231
+ effect: signals_core_namespaceObject.effect,
232
+ untracked: signals_core_namespaceObject.untracked
233
+ };
234
+ var constants = __webpack_require__("./src/constants.ts");
235
+ const optimization_api_client_namespaceObject = require("@contentful/optimization-api-client");
236
+ const logger_namespaceObject = require("@contentful/optimization-api-client/logger");
237
+ var api_schemas_ = __webpack_require__("@contentful/optimization-api-client/api-schemas");
238
+ const object_namespaceObject = require("es-toolkit/object");
239
+ const mini_namespaceObject = require("zod/mini");
240
+ const UniversalEventBuilderArgs = mini_namespaceObject.object({
241
+ campaign: mini_namespaceObject.optional(api_schemas_.Campaign),
242
+ locale: mini_namespaceObject.optional(mini_namespaceObject.string()),
243
+ location: mini_namespaceObject.optional(api_schemas_.GeoLocation),
244
+ page: mini_namespaceObject.optional(api_schemas_.Page),
245
+ screen: mini_namespaceObject.optional(api_schemas_.Screen),
246
+ userAgent: mini_namespaceObject.optional(mini_namespaceObject.string())
247
+ });
248
+ const EntryInteractionBuilderArgsBase = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
249
+ componentId: mini_namespaceObject.string(),
250
+ experienceId: mini_namespaceObject.optional(mini_namespaceObject.string()),
251
+ variantIndex: mini_namespaceObject.optional(mini_namespaceObject.number())
252
+ });
253
+ const ViewBuilderArgs = mini_namespaceObject.extend(EntryInteractionBuilderArgsBase, {
254
+ sticky: mini_namespaceObject.optional(mini_namespaceObject.boolean()),
255
+ viewId: mini_namespaceObject.string(),
256
+ viewDurationMs: mini_namespaceObject.number()
257
+ });
258
+ const FlagViewBuilderArgs = mini_namespaceObject.extend(EntryInteractionBuilderArgsBase, {
259
+ viewId: mini_namespaceObject.optional(mini_namespaceObject.string()),
260
+ viewDurationMs: mini_namespaceObject.optional(mini_namespaceObject.number())
261
+ });
262
+ const ClickBuilderArgs = EntryInteractionBuilderArgsBase;
263
+ const HoverBuilderArgs = mini_namespaceObject.extend(EntryInteractionBuilderArgsBase, {
264
+ hoverId: mini_namespaceObject.string(),
265
+ hoverDurationMs: mini_namespaceObject.number()
266
+ });
267
+ const IdentifyBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
268
+ traits: mini_namespaceObject.optional(api_schemas_.Traits),
269
+ userId: mini_namespaceObject.string()
270
+ });
271
+ const PageViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
272
+ properties: mini_namespaceObject.optional(mini_namespaceObject.partial(api_schemas_.Page))
273
+ });
274
+ const ScreenViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
275
+ name: mini_namespaceObject.string(),
276
+ properties: api_schemas_.Properties
277
+ });
278
+ const TrackBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
279
+ event: mini_namespaceObject.string(),
280
+ properties: mini_namespaceObject.optional(mini_namespaceObject.prefault(api_schemas_.Properties, {}))
281
+ });
282
+ const DEFAULT_PAGE_PROPERTIES = {
283
+ path: '',
284
+ query: {},
285
+ referrer: '',
286
+ search: '',
287
+ title: '',
288
+ url: ''
289
+ };
290
+ class EventBuilder {
291
+ app;
292
+ channel;
293
+ library;
294
+ getLocale;
295
+ getPageProperties;
296
+ getUserAgent;
297
+ constructor(config){
298
+ const { app, channel, library, getLocale, getPageProperties, getUserAgent } = config;
299
+ this.app = app;
300
+ this.channel = channel;
301
+ this.library = library;
302
+ this.getLocale = getLocale ?? (()=>'en-US');
303
+ this.getPageProperties = getPageProperties ?? (()=>DEFAULT_PAGE_PROPERTIES);
304
+ this.getUserAgent = getUserAgent ?? (()=>void 0);
305
+ }
306
+ buildUniversalEventProperties({ campaign = {}, locale, location, page, screen, userAgent }) {
307
+ const timestamp = new Date().toISOString();
308
+ return {
309
+ channel: this.channel,
310
+ context: {
311
+ app: this.app,
312
+ campaign,
313
+ gdpr: {
314
+ isConsentGiven: true
315
+ },
316
+ library: this.library,
317
+ locale: locale ?? this.getLocale() ?? 'en-US',
318
+ location,
319
+ page: page ?? this.getPageProperties(),
320
+ screen,
321
+ userAgent: userAgent ?? this.getUserAgent()
322
+ },
323
+ messageId: crypto.randomUUID(),
324
+ originalTimestamp: timestamp,
325
+ sentAt: timestamp,
326
+ timestamp
327
+ };
328
+ }
329
+ buildEntryInteractionBase(universal, componentId, experienceId, variantIndex) {
330
+ return {
331
+ ...this.buildUniversalEventProperties(universal),
332
+ componentType: 'Entry',
333
+ componentId,
334
+ experienceId,
335
+ variantIndex: variantIndex ?? 0
336
+ };
337
+ }
338
+ buildView(args) {
339
+ const { componentId, viewId, experienceId, variantIndex, viewDurationMs, ...universal } = (0, api_schemas_.parseWithFriendlyError)(ViewBuilderArgs, args);
340
+ return {
341
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
342
+ type: 'component',
343
+ viewId,
344
+ viewDurationMs
345
+ };
346
+ }
347
+ buildClick(args) {
348
+ const { componentId, experienceId, variantIndex, ...universal } = (0, api_schemas_.parseWithFriendlyError)(ClickBuilderArgs, args);
349
+ return {
350
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
351
+ type: 'component_click'
352
+ };
353
+ }
354
+ buildHover(args) {
355
+ const { hoverId, componentId, experienceId, hoverDurationMs, variantIndex, ...universal } = (0, api_schemas_.parseWithFriendlyError)(HoverBuilderArgs, args);
356
+ return {
357
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
358
+ type: 'component_hover',
359
+ hoverId,
360
+ hoverDurationMs
361
+ };
362
+ }
363
+ buildFlagView(args) {
364
+ const { componentId, experienceId, variantIndex, viewId, viewDurationMs, ...universal } = (0, api_schemas_.parseWithFriendlyError)(FlagViewBuilderArgs, args);
365
+ return {
366
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
367
+ ...void 0 === viewDurationMs ? {} : {
368
+ viewDurationMs
369
+ },
370
+ ...void 0 === viewId ? {} : {
371
+ viewId
372
+ },
373
+ type: 'component',
374
+ componentType: 'Variable'
375
+ };
376
+ }
377
+ buildIdentify(args) {
378
+ const { traits = {}, userId, ...universal } = (0, api_schemas_.parseWithFriendlyError)(IdentifyBuilderArgs, args);
379
+ return {
380
+ ...this.buildUniversalEventProperties(universal),
381
+ type: 'identify',
382
+ traits,
383
+ userId
384
+ };
385
+ }
386
+ buildPageView(args = {}) {
387
+ const { properties = {}, ...universal } = (0, api_schemas_.parseWithFriendlyError)(PageViewBuilderArgs, args);
388
+ const pageProperties = this.getPageProperties();
389
+ const merged = (0, object_namespaceObject.merge)({
390
+ ...pageProperties,
391
+ title: pageProperties.title ?? DEFAULT_PAGE_PROPERTIES.title
392
+ }, properties);
393
+ const { context: { screen: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
394
+ const context = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.PageEventContext, universalContext);
395
+ return {
396
+ ...universalProperties,
397
+ context,
398
+ type: 'page',
399
+ properties: merged
400
+ };
401
+ }
402
+ buildScreenView(args) {
403
+ const { name, properties, ...universal } = (0, api_schemas_.parseWithFriendlyError)(ScreenViewBuilderArgs, args);
404
+ const { context: { page: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
405
+ const context = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.ScreenEventContext, universalContext);
406
+ return {
407
+ ...universalProperties,
408
+ context,
409
+ type: 'screen',
410
+ name,
411
+ properties
412
+ };
413
+ }
414
+ buildTrack(args) {
415
+ const { event, properties = {}, ...universal } = (0, api_schemas_.parseWithFriendlyError)(TrackBuilderArgs, args);
416
+ return {
417
+ ...this.buildUniversalEventProperties(universal),
418
+ type: 'track',
419
+ event,
420
+ properties
421
+ };
422
+ }
423
+ }
424
+ const events_EventBuilder = EventBuilder;
425
+ class InterceptorManager {
426
+ interceptors = new Map();
427
+ nextId = 0;
428
+ add(interceptor) {
429
+ const { nextId: id } = this;
430
+ this.nextId += 1;
431
+ this.interceptors.set(id, interceptor);
432
+ return id;
433
+ }
434
+ remove(id) {
435
+ return this.interceptors.delete(id);
436
+ }
437
+ clear() {
438
+ this.interceptors.clear();
439
+ }
440
+ count() {
441
+ return this.interceptors.size;
442
+ }
443
+ async run(input) {
444
+ const fns = Array.from(this.interceptors.values());
445
+ let acc = input;
446
+ for (const fn of fns)acc = await fn((0, external_es_toolkit_namespaceObject.cloneDeep)(acc));
447
+ return acc;
448
+ }
449
+ }
104
450
  const FlagsResolver = {
105
451
  resolve (changes) {
106
452
  if (!changes) return {};
@@ -112,9 +458,7 @@ var __webpack_exports__ = {};
112
458
  }
113
459
  };
114
460
  const resolvers_FlagsResolver = FlagsResolver;
115
- const api_schemas_namespaceObject = require("@contentful/optimization-api-client/api-schemas");
116
- const logger_namespaceObject = require("@contentful/optimization-api-client/logger");
117
- const logger = (0, logger_namespaceObject.createScopedLogger)('Personalization');
461
+ const logger = (0, logger_namespaceObject.createScopedLogger)('Optimization');
118
462
  const RESOLUTION_WARNING_BASE = 'Could not resolve Merge Tag value:';
119
463
  const getAtPath = (value, path)=>{
120
464
  if (!value || 'object' != typeof value) return;
@@ -147,9 +491,9 @@ var __webpack_exports__ = {};
147
491
  return `${value}`;
148
492
  },
149
493
  resolve (mergeTagEntry, profile) {
150
- if (!(0, api_schemas_namespaceObject.isMergeTagEntry)(mergeTagEntry)) return void logger.warn(`${RESOLUTION_WARNING_BASE} supplied entry is not a Merge Tag entry`);
494
+ if (!(0, api_schemas_.isMergeTagEntry)(mergeTagEntry)) return void logger.warn(`${RESOLUTION_WARNING_BASE} supplied entry is not a Merge Tag entry`);
151
495
  const { fields: { nt_fallback: fallback } } = mergeTagEntry;
152
- if (!api_schemas_namespaceObject.Profile.safeParse(profile).success) {
496
+ if (!api_schemas_.Profile.safeParse(profile).success) {
153
497
  logger.warn(`${RESOLUTION_WARNING_BASE} no valid profile`);
154
498
  return fallback;
155
499
  }
@@ -157,177 +501,285 @@ var __webpack_exports__ = {};
157
501
  }
158
502
  };
159
503
  const resolvers_MergeTagValueResolver = MergeTagValueResolver;
160
- const PersonalizedEntryResolver_logger = (0, logger_namespaceObject.createScopedLogger)('Personalization');
161
- const PersonalizedEntryResolver_RESOLUTION_WARNING_BASE = 'Could not resolve personalized entry variant:';
162
- const PersonalizedEntryResolver = {
163
- getPersonalizationEntry ({ personalizedEntry, selectedPersonalizations }, skipValidation = false) {
164
- if (!skipValidation && (!selectedPersonalizations.length || !(0, api_schemas_namespaceObject.isPersonalizedEntry)(personalizedEntry))) return;
165
- const personalizationEntry = personalizedEntry.fields.nt_experiences.filter((maybePersonalization)=>(0, api_schemas_namespaceObject.isPersonalizationEntry)(maybePersonalization)).find((personalizationEntry)=>selectedPersonalizations.some(({ experienceId })=>experienceId === personalizationEntry.fields.nt_experience_id));
166
- return personalizationEntry;
504
+ const OptimizedEntryResolver_logger = (0, logger_namespaceObject.createScopedLogger)('Optimization');
505
+ const OptimizedEntryResolver_RESOLUTION_WARNING_BASE = 'Could not resolve optimized entry variant:';
506
+ function resolve(entry, selectedOptimizations) {
507
+ OptimizedEntryResolver_logger.debug(`Resolving optimized entry for baseline entry ${entry.sys.id}`);
508
+ if (!selectedOptimizations?.length) {
509
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} no selectedOptimizations exist for the current profile`);
510
+ return {
511
+ entry
512
+ };
513
+ }
514
+ if (!(0, api_schemas_.isOptimizedEntry)(entry)) {
515
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} entry ${entry.sys.id} is not optimized`);
516
+ return {
517
+ entry
518
+ };
519
+ }
520
+ const optimizationEntry = OptimizedEntryResolver.getOptimizationEntry({
521
+ optimizedEntry: entry,
522
+ selectedOptimizations
523
+ }, true);
524
+ if (!optimizationEntry) {
525
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find an optimization entry for ${entry.sys.id}`);
526
+ return {
527
+ entry
528
+ };
529
+ }
530
+ const selectedOptimization = OptimizedEntryResolver.getSelectedOptimization({
531
+ optimizationEntry,
532
+ selectedOptimizations
533
+ }, true);
534
+ const selectedVariantIndex = selectedOptimization?.variantIndex ?? 0;
535
+ if (0 === selectedVariantIndex) {
536
+ OptimizedEntryResolver_logger.debug(`Resolved optimization entry for entry ${entry.sys.id} is baseline`);
537
+ return {
538
+ entry
539
+ };
540
+ }
541
+ const selectedVariant = OptimizedEntryResolver.getSelectedVariant({
542
+ optimizedEntry: entry,
543
+ optimizationEntry,
544
+ selectedVariantIndex
545
+ }, true);
546
+ if (!selectedVariant) {
547
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
548
+ return {
549
+ entry
550
+ };
551
+ }
552
+ const selectedVariantEntry = OptimizedEntryResolver.getSelectedVariantEntry({
553
+ optimizationEntry,
554
+ selectedVariant
555
+ }, true);
556
+ if (selectedVariantEntry) OptimizedEntryResolver_logger.debug(`Entry ${entry.sys.id} has been resolved to variant entry ${selectedVariantEntry.sys.id}`);
557
+ else {
558
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
559
+ return {
560
+ entry
561
+ };
562
+ }
563
+ return {
564
+ entry: selectedVariantEntry,
565
+ selectedOptimization
566
+ };
567
+ }
568
+ const OptimizedEntryResolver = {
569
+ getOptimizationEntry ({ optimizedEntry, selectedOptimizations }, skipValidation = false) {
570
+ if (!skipValidation && (!selectedOptimizations.length || !(0, api_schemas_.isOptimizedEntry)(optimizedEntry))) return;
571
+ const optimizationEntry = optimizedEntry.fields.nt_experiences.filter((maybeOptimization)=>(0, api_schemas_.isOptimizationEntry)(maybeOptimization)).find((optimizationEntry)=>selectedOptimizations.some(({ experienceId })=>experienceId === optimizationEntry.fields.nt_experience_id));
572
+ return optimizationEntry;
167
573
  },
168
- getSelectedPersonalization ({ personalizationEntry, selectedPersonalizations }, skipValidation = false) {
169
- if (!skipValidation && (!selectedPersonalizations.length || !(0, api_schemas_namespaceObject.isPersonalizationEntry)(personalizationEntry))) return;
170
- const selectedPersonalization = selectedPersonalizations.find(({ experienceId })=>experienceId === personalizationEntry.fields.nt_experience_id);
171
- return selectedPersonalization;
574
+ getSelectedOptimization ({ optimizationEntry, selectedOptimizations }, skipValidation = false) {
575
+ if (!skipValidation && (!selectedOptimizations.length || !(0, api_schemas_.isOptimizationEntry)(optimizationEntry))) return;
576
+ const selectedOptimization = selectedOptimizations.find(({ experienceId })=>experienceId === optimizationEntry.fields.nt_experience_id);
577
+ return selectedOptimization;
172
578
  },
173
- getSelectedVariant ({ personalizedEntry, personalizationEntry, selectedVariantIndex }, skipValidation = false) {
174
- if (!skipValidation && (!(0, api_schemas_namespaceObject.isPersonalizedEntry)(personalizedEntry) || !(0, api_schemas_namespaceObject.isPersonalizationEntry)(personalizationEntry))) return;
175
- const relevantVariants = personalizationEntry.fields.nt_config?.components?.filter((component)=>(0, api_schemas_namespaceObject.isEntryReplacementComponent)(component) && !component.baseline.hidden).find((component)=>component.baseline.id === personalizedEntry.sys.id)?.variants;
579
+ getSelectedVariant ({ optimizedEntry, optimizationEntry, selectedVariantIndex }, skipValidation = false) {
580
+ if (!skipValidation && (!(0, api_schemas_.isOptimizedEntry)(optimizedEntry) || !(0, api_schemas_.isOptimizationEntry)(optimizationEntry))) return;
581
+ const relevantVariants = (0, api_schemas_.normalizeOptimizationConfig)(optimizationEntry.fields.nt_config).components.filter((component)=>(0, api_schemas_.isEntryReplacementComponent)(component) && !component.baseline.hidden).find((component)=>component.baseline.id === optimizedEntry.sys.id)?.variants;
176
582
  if (!relevantVariants?.length) return;
177
583
  return relevantVariants.at(selectedVariantIndex - 1);
178
584
  },
179
- getSelectedVariantEntry ({ personalizationEntry, selectedVariant }, skipValidation = false) {
180
- if (!skipValidation && (!(0, api_schemas_namespaceObject.isPersonalizationEntry)(personalizationEntry) || !(0, api_schemas_namespaceObject.isEntryReplacementVariant)(selectedVariant))) return;
181
- const selectedVariantEntry = personalizationEntry.fields.nt_variants?.find((variant)=>variant.sys.id === selectedVariant.id);
182
- return (0, api_schemas_namespaceObject.isEntry)(selectedVariantEntry) ? selectedVariantEntry : void 0;
585
+ getSelectedVariantEntry ({ optimizationEntry, selectedVariant }, skipValidation = false) {
586
+ if (!skipValidation && (!(0, api_schemas_.isOptimizationEntry)(optimizationEntry) || !(0, api_schemas_.isEntryReplacementVariant)(selectedVariant))) return;
587
+ const selectedVariantEntry = optimizationEntry.fields.nt_variants?.find((variant)=>variant.sys.id === selectedVariant.id);
588
+ return (0, api_schemas_.isEntry)(selectedVariantEntry) ? selectedVariantEntry : void 0;
183
589
  },
184
- resolve (entry, selectedPersonalizations) {
185
- PersonalizedEntryResolver_logger.debug(`Resolving personalized entry for baseline entry ${entry.sys.id}`);
186
- if (!selectedPersonalizations?.length) {
187
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} no selectedPersonalizations exist for the current profile`);
188
- return {
189
- entry
190
- };
191
- }
192
- if (!(0, api_schemas_namespaceObject.isPersonalizedEntry)(entry)) {
193
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} entry ${entry.sys.id} is not personalized`);
194
- return {
195
- entry
196
- };
197
- }
198
- const personalizationEntry = PersonalizedEntryResolver.getPersonalizationEntry({
199
- personalizedEntry: entry,
200
- selectedPersonalizations
201
- }, true);
202
- if (!personalizationEntry) {
203
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a personalization entry for ${entry.sys.id}`);
204
- return {
205
- entry
206
- };
207
- }
208
- const selectedPersonalization = PersonalizedEntryResolver.getSelectedPersonalization({
209
- personalizationEntry,
210
- selectedPersonalizations
211
- }, true);
212
- const selectedVariantIndex = selectedPersonalization?.variantIndex ?? 0;
213
- if (0 === selectedVariantIndex) {
214
- PersonalizedEntryResolver_logger.debug(`Resolved personalization entry for entry ${entry.sys.id} is baseline`);
215
- return {
216
- entry
217
- };
218
- }
219
- const selectedVariant = PersonalizedEntryResolver.getSelectedVariant({
220
- personalizedEntry: entry,
221
- personalizationEntry,
222
- selectedVariantIndex
223
- }, true);
224
- if (!selectedVariant) {
225
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
226
- return {
227
- entry
228
- };
229
- }
230
- const selectedVariantEntry = PersonalizedEntryResolver.getSelectedVariantEntry({
231
- personalizationEntry,
232
- selectedVariant
233
- }, true);
234
- if (selectedVariantEntry) PersonalizedEntryResolver_logger.debug(`Entry ${entry.sys.id} has been resolved to variant entry ${selectedVariantEntry.sys.id}`);
235
- else {
236
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
237
- return {
238
- entry
239
- };
240
- }
241
- return {
242
- entry: selectedVariantEntry,
243
- personalization: selectedPersonalization
244
- };
245
- }
590
+ resolve
246
591
  };
247
- const resolvers_PersonalizedEntryResolver = PersonalizedEntryResolver;
248
- const signals_changes = (0, signals_core_namespaceObject.signal)();
249
- const blockedEvent = (0, signals_core_namespaceObject.signal)();
250
- const consent = (0, signals_core_namespaceObject.signal)();
251
- const signals_event = (0, signals_core_namespaceObject.signal)();
252
- const flags = (0, signals_core_namespaceObject.computed)(()=>resolvers_FlagsResolver.resolve(signals_changes.value ?? []));
253
- const online = (0, signals_core_namespaceObject.signal)(true);
254
- const previewPanelAttached = (0, signals_core_namespaceObject.signal)(false);
255
- const previewPanelOpen = (0, signals_core_namespaceObject.signal)(false);
256
- const signals_personalizations = (0, signals_core_namespaceObject.signal)();
257
- const signals_profile = (0, signals_core_namespaceObject.signal)();
258
- function toObservable(s) {
259
- return {
260
- subscribe (next) {
261
- const dispose = (0, signals_core_namespaceObject.effect)(()=>{
262
- next(s.value);
263
- });
264
- return {
265
- unsubscribe: dispose
266
- };
267
- }
592
+ const resolvers_OptimizedEntryResolver = OptimizedEntryResolver;
593
+ class CoreBase {
594
+ api;
595
+ eventBuilder;
596
+ config;
597
+ flagsResolver = resolvers_FlagsResolver;
598
+ mergeTagValueResolver = resolvers_MergeTagValueResolver;
599
+ optimizedEntryResolver = resolvers_OptimizedEntryResolver;
600
+ interceptors = {
601
+ event: new InterceptorManager(),
602
+ state: new InterceptorManager()
268
603
  };
604
+ constructor(config, api = {}){
605
+ this.config = config;
606
+ const { eventBuilder, logLevel, environment, clientId, fetchOptions } = config;
607
+ logger_namespaceObject.logger.addSink(new logger_namespaceObject.ConsoleLogSink(logLevel));
608
+ const apiConfig = {
609
+ clientId,
610
+ environment,
611
+ fetchOptions,
612
+ experience: api.experience,
613
+ insights: api.insights
614
+ };
615
+ this.api = new optimization_api_client_namespaceObject.ApiClient(apiConfig);
616
+ this.eventBuilder = new events_EventBuilder(eventBuilder ?? {
617
+ channel: 'server',
618
+ library: {
619
+ name: constants.OPTIMIZATION_CORE_SDK_NAME,
620
+ version: constants.OPTIMIZATION_CORE_SDK_VERSION
621
+ }
622
+ });
623
+ }
624
+ getFlag(name, changes) {
625
+ return this.flagsResolver.resolve(changes)[name];
626
+ }
627
+ resolveOptimizedEntry(entry, selectedOptimizations) {
628
+ return this.optimizedEntryResolver.resolve(entry, selectedOptimizations);
629
+ }
630
+ getMergeTagValue(embeddedEntryNodeTarget, profile) {
631
+ return this.mergeTagValueResolver.resolve(embeddedEntryNodeTarget, profile);
632
+ }
269
633
  }
270
- const signals = {
271
- blockedEvent,
272
- changes: signals_changes,
273
- consent,
274
- event: signals_event,
275
- flags,
276
- online,
277
- previewPanelAttached,
278
- previewPanelOpen,
279
- personalizations: signals_personalizations,
280
- profile: signals_profile
281
- };
282
- const signalFns = {
283
- batch: signals_core_namespaceObject.batch,
284
- computed: signals_core_namespaceObject.computed,
285
- effect: signals_core_namespaceObject.effect,
286
- untracked: signals_core_namespaceObject.untracked
634
+ const src_CoreBase = CoreBase;
635
+ const predicate_namespaceObject = require("es-toolkit/predicate");
636
+ const coreLogger = (0, logger_namespaceObject.createScopedLogger)('CoreStateful');
637
+ const CONSENT_EVENT_TYPE_MAP = {
638
+ trackView: 'component',
639
+ trackFlagView: 'component',
640
+ trackClick: 'component_click',
641
+ trackHover: 'component_hover'
287
642
  };
288
- const isFunction = (v)=>'function' == typeof v;
289
- const nameToString = (name)=>'string' == typeof name ? name : 'symbol' == typeof name ? name.description ?? String(name) : String(name);
290
- const isOnBlockedKey = (v)=>'string' == typeof v || 'symbol' == typeof v;
291
- const isAsyncFunction = (fn)=>'[object AsyncFunction]' === Object.prototype.toString.call(fn);
292
- function guardedBy(predicateName, opts) {
293
- return function(_value, context) {
294
- const decoratedName = nameToString(context.name);
295
- context.addInitializer(function() {
296
- const originalUnknown = Reflect.get(this, context.name);
297
- if (!isFunction(originalUnknown)) return;
298
- const original = originalUnknown;
299
- const originalIsAsync = isAsyncFunction(original);
300
- const resolvePredicate = (self)=>{
301
- const { [predicateName]: cand } = self;
302
- if (!isFunction(cand)) throw new TypeError(`@guardedBy expects predicate "${String(predicateName)}" to be a synchronous function.`);
303
- return cand;
304
- };
305
- const computeAllowed = (self, args)=>{
306
- const pred = resolvePredicate(self);
307
- const ok = Boolean(pred.call(self, decoratedName, args));
308
- return opts?.invert === true ? !ok : ok;
309
- };
310
- const runOnBlocked = (self, args)=>{
311
- const { onBlocked } = opts ?? {};
312
- if (void 0 === onBlocked) return;
313
- if (isFunction(onBlocked)) return void onBlocked.call(self, decoratedName, args);
314
- if (isOnBlockedKey(onBlocked)) {
315
- const { [onBlocked]: handlerCandidate } = self;
316
- if (isFunction(handlerCandidate)) handlerCandidate.call(self, decoratedName, args);
317
- }
318
- };
319
- const blockedReturn = ()=>originalIsAsync ? Promise.resolve(void 0) : void 0;
320
- const wrapped = function(...args) {
321
- if (!computeAllowed(this, args)) {
322
- runOnBlocked(this, args);
323
- return blockedReturn();
324
- }
325
- return original.call(this, ...args);
326
- };
327
- Reflect.set(this, context.name, wrapped);
643
+ class CoreStatefulEventEmitter extends src_CoreBase {
644
+ flagObservables = new Map();
645
+ getFlag(name, changes = signals_changes.value) {
646
+ const value = super.getFlag(name, changes);
647
+ const payload = this.buildFlagViewBuilderArgs(name, changes);
648
+ this.trackFlagView(payload).catch((error)=>{
649
+ logger_namespaceObject.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
328
650
  });
329
- };
651
+ return value;
652
+ }
653
+ resolveOptimizedEntry(entry, selectedOptimizations = signals_selectedOptimizations.value) {
654
+ return super.resolveOptimizedEntry(entry, selectedOptimizations);
655
+ }
656
+ getMergeTagValue(embeddedEntryNodeTarget, profile = signals_profile.value) {
657
+ return super.getMergeTagValue(embeddedEntryNodeTarget, profile);
658
+ }
659
+ async identify(payload) {
660
+ const { profile, ...builderArgs } = payload;
661
+ return await this.sendExperienceEvent('identify', [
662
+ payload
663
+ ], this.eventBuilder.buildIdentify(builderArgs), profile);
664
+ }
665
+ async page(payload = {}) {
666
+ const { profile, ...builderArgs } = payload;
667
+ return await this.sendExperienceEvent('page', [
668
+ payload
669
+ ], this.eventBuilder.buildPageView(builderArgs), profile);
670
+ }
671
+ async screen(payload) {
672
+ const { profile, ...builderArgs } = payload;
673
+ return await this.sendExperienceEvent('screen', [
674
+ payload
675
+ ], this.eventBuilder.buildScreenView(builderArgs), profile);
676
+ }
677
+ async track(payload) {
678
+ const { profile, ...builderArgs } = payload;
679
+ return await this.sendExperienceEvent('track', [
680
+ payload
681
+ ], this.eventBuilder.buildTrack(builderArgs), profile);
682
+ }
683
+ async trackView(payload) {
684
+ const { profile, ...builderArgs } = payload;
685
+ let result;
686
+ if (payload.sticky) result = await this.sendExperienceEvent('trackView', [
687
+ payload
688
+ ], this.eventBuilder.buildView(builderArgs), profile);
689
+ await this.sendInsightsEvent('trackView', [
690
+ payload
691
+ ], this.eventBuilder.buildView(builderArgs), profile);
692
+ return result;
693
+ }
694
+ async trackClick(payload) {
695
+ await this.sendInsightsEvent('trackClick', [
696
+ payload
697
+ ], this.eventBuilder.buildClick(payload));
698
+ }
699
+ async trackHover(payload) {
700
+ await this.sendInsightsEvent('trackHover', [
701
+ payload
702
+ ], this.eventBuilder.buildHover(payload));
703
+ }
704
+ async trackFlagView(payload) {
705
+ await this.sendInsightsEvent('trackFlagView', [
706
+ payload
707
+ ], this.eventBuilder.buildFlagView(payload));
708
+ }
709
+ hasConsent(name) {
710
+ const { [name]: mappedEventType } = CONSENT_EVENT_TYPE_MAP;
711
+ const isAllowed = void 0 !== mappedEventType ? this.allowedEventTypes.includes(mappedEventType) : this.allowedEventTypes.some((eventType)=>eventType === name);
712
+ return !!consent.value || isAllowed;
713
+ }
714
+ onBlockedByConsent(name, args) {
715
+ coreLogger.warn(`Event "${name}" was blocked due to lack of consent; payload: ${JSON.stringify(args)}`);
716
+ this.reportBlockedEvent('consent', name, args);
717
+ }
718
+ async sendExperienceEvent(method, args, event, _profile) {
719
+ if (!this.hasConsent(method)) return void this.onBlockedByConsent(method, args);
720
+ return await this.experienceQueue.send(event);
721
+ }
722
+ async sendInsightsEvent(method, args, event, _profile) {
723
+ if (!this.hasConsent(method)) return void this.onBlockedByConsent(method, args);
724
+ await this.insightsQueue.send(event);
725
+ }
726
+ buildFlagViewBuilderArgs(name, changes = signals_changes.value) {
727
+ const change = changes?.find((candidate)=>candidate.key === name);
728
+ return {
729
+ componentId: name,
730
+ experienceId: change?.meta.experienceId,
731
+ variantIndex: change?.meta.variantIndex
732
+ };
733
+ }
734
+ getFlagObservable(name) {
735
+ const existingObservable = this.flagObservables.get(name);
736
+ if (existingObservable) return existingObservable;
737
+ const trackFlagView = this.trackFlagView.bind(this);
738
+ const buildFlagViewBuilderArgs = this.buildFlagViewBuilderArgs.bind(this);
739
+ const valueSignal = signalFns.computed(()=>super.getFlag(name, signals_changes.value));
740
+ const distinctObservable = toDistinctObservable(valueSignal, predicate_namespaceObject.isEqual);
741
+ const trackedObservable = {
742
+ get current () {
743
+ const { current: value } = distinctObservable;
744
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
745
+ trackFlagView(payload).catch((error)=>{
746
+ logger_namespaceObject.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
747
+ });
748
+ return value;
749
+ },
750
+ subscribe: (next)=>distinctObservable.subscribe((value)=>{
751
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
752
+ trackFlagView(payload).catch((error)=>{
753
+ logger_namespaceObject.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
754
+ });
755
+ next(value);
756
+ }),
757
+ subscribeOnce: (next)=>distinctObservable.subscribeOnce((value)=>{
758
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
759
+ trackFlagView(payload).catch((error)=>{
760
+ logger_namespaceObject.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
761
+ });
762
+ next(value);
763
+ })
764
+ };
765
+ this.flagObservables.set(name, trackedObservable);
766
+ return trackedObservable;
767
+ }
768
+ reportBlockedEvent(reason, method, args) {
769
+ const event = {
770
+ reason,
771
+ method,
772
+ args
773
+ };
774
+ try {
775
+ this.onEventBlocked?.(event);
776
+ } catch (error) {
777
+ coreLogger.warn(`onEventBlocked callback failed for method "${method}"`, error);
778
+ }
779
+ blockedEvent.value = event;
780
+ }
330
781
  }
782
+ const src_CoreStatefulEventEmitter = CoreStatefulEventEmitter;
331
783
  const toPositiveInt = (value, fallback)=>{
332
784
  if (!Number.isFinite(value) || void 0 === value || value < 1) return fallback;
333
785
  return Math.floor(value);
@@ -337,6 +789,7 @@ var __webpack_exports__ = {};
337
789
  return Math.min(1, Math.max(0, value));
338
790
  };
339
791
  const DEFAULT_QUEUE_FLUSH_POLICY = {
792
+ flushIntervalMs: 30000,
340
793
  baseBackoffMs: 500,
341
794
  maxBackoffMs: 30000,
342
795
  jitterRatio: 0.2,
@@ -344,17 +797,19 @@ var __webpack_exports__ = {};
344
797
  circuitOpenMs: 120000
345
798
  };
346
799
  const resolveQueueFlushPolicy = (policy, defaults = DEFAULT_QUEUE_FLUSH_POLICY)=>{
347
- const baseBackoffMs = toPositiveInt(policy?.baseBackoffMs, defaults.baseBackoffMs);
348
- const maxBackoffMs = Math.max(baseBackoffMs, toPositiveInt(policy?.maxBackoffMs, defaults.maxBackoffMs));
800
+ const configuredPolicy = policy ?? {};
801
+ const baseBackoffMs = toPositiveInt(configuredPolicy.baseBackoffMs, defaults.baseBackoffMs);
802
+ const maxBackoffMs = Math.max(baseBackoffMs, toPositiveInt(configuredPolicy.maxBackoffMs, defaults.maxBackoffMs));
349
803
  return {
804
+ flushIntervalMs: toPositiveInt(configuredPolicy.flushIntervalMs, defaults.flushIntervalMs),
350
805
  baseBackoffMs,
351
806
  maxBackoffMs,
352
- jitterRatio: toRatio(policy?.jitterRatio, defaults.jitterRatio),
353
- maxConsecutiveFailures: toPositiveInt(policy?.maxConsecutiveFailures, defaults.maxConsecutiveFailures),
354
- circuitOpenMs: toPositiveInt(policy?.circuitOpenMs, defaults.circuitOpenMs),
355
- onCircuitOpen: policy?.onCircuitOpen,
356
- onFlushFailure: policy?.onFlushFailure,
357
- onFlushRecovered: policy?.onFlushRecovered
807
+ jitterRatio: toRatio(configuredPolicy.jitterRatio, defaults.jitterRatio),
808
+ maxConsecutiveFailures: toPositiveInt(configuredPolicy.maxConsecutiveFailures, defaults.maxConsecutiveFailures),
809
+ circuitOpenMs: toPositiveInt(configuredPolicy.circuitOpenMs, defaults.circuitOpenMs),
810
+ onCircuitOpen: configuredPolicy.onCircuitOpen,
811
+ onFlushFailure: configuredPolicy.onFlushFailure,
812
+ onFlushRecovered: configuredPolicy.onFlushRecovered
358
813
  };
359
814
  };
360
815
  const computeQueueFlushRetryDelayMs = (options)=>{
@@ -380,6 +835,23 @@ var __webpack_exports__ = {};
380
835
  circuitOpenUntil
381
836
  };
382
837
  };
838
+ const STATEFUL_RUNTIME_LOCK_KEY = '__ctfl_optimization_stateful_runtime_lock__';
839
+ const getStatefulRuntimeLock = ()=>{
840
+ const singletonGlobal = globalThis;
841
+ singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY] ??= {
842
+ owner: void 0
843
+ };
844
+ return singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY];
845
+ };
846
+ const acquireStatefulRuntimeSingleton = (owner)=>{
847
+ const lock = getStatefulRuntimeLock();
848
+ if (lock.owner) throw new Error(`Stateful Optimization SDK already initialized (${lock.owner}). Only one stateful instance is supported per runtime.`);
849
+ lock.owner = owner;
850
+ };
851
+ const releaseStatefulRuntimeSingleton = (owner)=>{
852
+ const lock = getStatefulRuntimeLock();
853
+ if (lock.owner === owner) lock.owner = void 0;
854
+ };
383
855
  class QueueFlushRuntime {
384
856
  circuitOpenUntil = 0;
385
857
  flushFailureCount = 0;
@@ -484,463 +956,186 @@ var __webpack_exports__ = {};
484
956
  }
485
957
  }
486
958
  }
487
- const ProductBase_logger = (0, logger_namespaceObject.createScopedLogger)('ProductBase');
488
- const defaultAllowedEvents = [
489
- 'identify',
490
- 'page',
491
- 'screen'
492
- ];
493
- class ProductBase {
494
- allowedEventTypes;
495
- builder;
496
- api;
497
- interceptors;
498
- onEventBlocked;
959
+ const ExperienceQueue_coreLogger = (0, logger_namespaceObject.createScopedLogger)('CoreStateful');
960
+ class ExperienceQueue {
961
+ experienceApi;
962
+ eventInterceptors;
963
+ flushRuntime;
964
+ getAnonymousId;
965
+ offlineMaxEvents;
966
+ onOfflineDrop;
967
+ queuedExperienceEvents = new Set();
968
+ stateInterceptors;
499
969
  constructor(options){
500
- const { api, builder, config, interceptors } = options;
501
- this.allowedEventTypes = config?.allowedEventTypes ?? defaultAllowedEvents;
502
- this.api = api;
503
- this.builder = builder;
504
- this.interceptors = interceptors;
505
- this.onEventBlocked = config?.onEventBlocked;
506
- }
507
- reportBlockedEvent(reason, product, method, args) {
508
- const event = {
509
- reason,
510
- product,
511
- method,
512
- args
513
- };
514
- try {
515
- this.onEventBlocked?.(event);
516
- } catch (error) {
517
- ProductBase_logger.warn(`onEventBlocked callback failed for method "${method}"`, error);
518
- }
519
- blockedEvent.value = event;
970
+ const { experienceApi, eventInterceptors, flushPolicy, getAnonymousId, offlineMaxEvents, onOfflineDrop, stateInterceptors } = options;
971
+ this.experienceApi = experienceApi;
972
+ this.eventInterceptors = eventInterceptors;
973
+ this.getAnonymousId = getAnonymousId;
974
+ this.offlineMaxEvents = offlineMaxEvents;
975
+ this.onOfflineDrop = onOfflineDrop;
976
+ this.stateInterceptors = stateInterceptors;
977
+ this.flushRuntime = new QueueFlushRuntime({
978
+ policy: flushPolicy,
979
+ onRetry: ()=>{
980
+ this.flush();
981
+ },
982
+ onCallbackError: (callbackName, error)=>{
983
+ ExperienceQueue_coreLogger.warn(`Experience flush policy callback "${callbackName}" failed`, error);
984
+ }
985
+ });
520
986
  }
521
- }
522
- const src_ProductBase = ProductBase;
523
- class AnalyticsBase extends src_ProductBase {
524
- }
525
- const analytics_AnalyticsBase = AnalyticsBase;
526
- function applyDecs2203RFactory() {
527
- function createAddInitializerMethod(initializers, decoratorFinishedRef) {
528
- return function(initializer) {
529
- assertNotFinished(decoratorFinishedRef, "addInitializer");
530
- assertCallable(initializer, "An initializer");
531
- initializers.push(initializer);
532
- };
987
+ clearScheduledRetry() {
988
+ this.flushRuntime.clearScheduledRetry();
533
989
  }
534
- function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
535
- var kindStr;
536
- switch(kind){
537
- case 1:
538
- kindStr = "accessor";
539
- break;
540
- case 2:
541
- kindStr = "method";
542
- break;
543
- case 3:
544
- kindStr = "getter";
545
- break;
546
- case 4:
547
- kindStr = "setter";
548
- break;
549
- default:
550
- kindStr = "field";
551
- }
552
- var ctx = {
553
- kind: kindStr,
554
- name: isPrivate ? "#" + name : name,
555
- static: isStatic,
556
- private: isPrivate,
557
- metadata: metadata
558
- };
559
- var decoratorFinishedRef = {
560
- v: false
561
- };
562
- ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
563
- var get, set;
564
- if (0 === kind) if (isPrivate) {
565
- get = desc.get;
566
- set = desc.set;
567
- } else {
568
- get = function() {
569
- return this[name];
570
- };
571
- set = function(v) {
572
- this[name] = v;
573
- };
574
- }
575
- else if (2 === kind) get = function() {
576
- return desc.value;
577
- };
578
- else {
579
- if (1 === kind || 3 === kind) get = function() {
580
- return desc.get.call(this);
581
- };
582
- if (1 === kind || 4 === kind) set = function(v) {
583
- desc.set.call(this, v);
584
- };
585
- }
586
- ctx.access = get && set ? {
587
- get: get,
588
- set: set
589
- } : get ? {
590
- get: get
591
- } : {
592
- set: set
593
- };
990
+ async send(event) {
991
+ const intercepted = await this.eventInterceptors.run(event);
992
+ const validEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.ExperienceEvent, intercepted);
993
+ signals_event.value = validEvent;
994
+ if (online.value) return await this.upsertProfile([
995
+ validEvent
996
+ ]);
997
+ ExperienceQueue_coreLogger.debug(`Queueing ${validEvent.type} event`, validEvent);
998
+ this.enqueueEvent(validEvent);
999
+ }
1000
+ async flush(options = {}) {
1001
+ const { force = false } = options;
1002
+ if (this.flushRuntime.shouldSkip({
1003
+ force,
1004
+ isOnline: !!online.value
1005
+ })) return;
1006
+ if (0 === this.queuedExperienceEvents.size) return void this.flushRuntime.clearScheduledRetry();
1007
+ ExperienceQueue_coreLogger.debug('Flushing offline Experience event queue');
1008
+ const queuedEvents = Array.from(this.queuedExperienceEvents);
1009
+ this.flushRuntime.markFlushStarted();
594
1010
  try {
595
- return dec(value, ctx);
1011
+ const sendSuccess = await this.tryUpsertQueuedEvents(queuedEvents);
1012
+ if (sendSuccess) {
1013
+ queuedEvents.forEach((queuedEvent)=>{
1014
+ this.queuedExperienceEvents.delete(queuedEvent);
1015
+ });
1016
+ this.flushRuntime.handleFlushSuccess();
1017
+ } else this.flushRuntime.handleFlushFailure({
1018
+ queuedBatches: this.queuedExperienceEvents.size > 0 ? 1 : 0,
1019
+ queuedEvents: this.queuedExperienceEvents.size
1020
+ });
596
1021
  } finally{
597
- decoratorFinishedRef.v = true;
1022
+ this.flushRuntime.markFlushFinished();
598
1023
  }
599
1024
  }
600
- function assertNotFinished(decoratorFinishedRef, fnName) {
601
- if (decoratorFinishedRef.v) throw new Error("attempted to call " + fnName + " after decoration was finished");
602
- }
603
- function assertCallable(fn, hint) {
604
- if ("function" != typeof fn) throw new TypeError(hint + " must be a function");
605
- }
606
- function assertValidReturnValue(kind, value) {
607
- var type = typeof value;
608
- if (1 === kind) {
609
- if ("object" !== type || null === value) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
610
- if (void 0 !== value.get) assertCallable(value.get, "accessor.get");
611
- if (void 0 !== value.set) assertCallable(value.set, "accessor.set");
612
- if (void 0 !== value.init) assertCallable(value.init, "accessor.init");
613
- } else if ("function" !== type) {
614
- var hint;
615
- hint = 0 === kind ? "field" : 10 === kind ? "class" : "method";
616
- throw new TypeError(hint + " decorators must return a function or void 0");
1025
+ enqueueEvent(event) {
1026
+ let droppedEvents = [];
1027
+ if (this.queuedExperienceEvents.size >= this.offlineMaxEvents) {
1028
+ const dropCount = this.queuedExperienceEvents.size - this.offlineMaxEvents + 1;
1029
+ droppedEvents = this.dropOldestEvents(dropCount);
1030
+ if (droppedEvents.length > 0) ExperienceQueue_coreLogger.warn(`Dropped ${droppedEvents.length} oldest offline event(s) due to queue limit (${this.offlineMaxEvents})`);
617
1031
  }
1032
+ this.queuedExperienceEvents.add(event);
1033
+ if (droppedEvents.length > 0) this.invokeOfflineDropCallback({
1034
+ droppedCount: droppedEvents.length,
1035
+ droppedEvents,
1036
+ maxEvents: this.offlineMaxEvents,
1037
+ queuedEvents: this.queuedExperienceEvents.size
1038
+ });
618
1039
  }
619
- function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
620
- var decs = decInfo[0];
621
- var desc, init, value;
622
- if (isPrivate) desc = 0 === kind || 1 === kind ? {
623
- get: decInfo[3],
624
- set: decInfo[4]
625
- } : 3 === kind ? {
626
- get: decInfo[3]
627
- } : 4 === kind ? {
628
- set: decInfo[3]
629
- } : {
630
- value: decInfo[3]
631
- };
632
- else if (0 !== kind) desc = Object.getOwnPropertyDescriptor(base, name);
633
- if (1 === kind) value = {
634
- get: desc.get,
635
- set: desc.set
636
- };
637
- else if (2 === kind) value = desc.value;
638
- else if (3 === kind) value = desc.get;
639
- else if (4 === kind) value = desc.set;
640
- var newValue, get, set;
641
- if ("function" == typeof decs) {
642
- newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
643
- if (void 0 !== newValue) {
644
- assertValidReturnValue(kind, newValue);
645
- if (0 === kind) init = newValue;
646
- else if (1 === kind) {
647
- init = newValue.init;
648
- get = newValue.get || value.get;
649
- set = newValue.set || value.set;
650
- value = {
651
- get: get,
652
- set: set
653
- };
654
- } else value = newValue;
655
- }
656
- } else for(var i = decs.length - 1; i >= 0; i--){
657
- var dec = decs[i];
658
- newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
659
- if (void 0 !== newValue) {
660
- assertValidReturnValue(kind, newValue);
661
- var newInit;
662
- if (0 === kind) newInit = newValue;
663
- else if (1 === kind) {
664
- newInit = newValue.init;
665
- get = newValue.get || value.get;
666
- set = newValue.set || value.set;
667
- value = {
668
- get: get,
669
- set: set
670
- };
671
- } else value = newValue;
672
- if (void 0 !== newInit) if (void 0 === init) init = newInit;
673
- else if ("function" == typeof init) init = [
674
- init,
675
- newInit
676
- ];
677
- else init.push(newInit);
678
- }
679
- }
680
- if (0 === kind || 1 === kind) {
681
- if (void 0 === init) init = function(instance, init) {
682
- return init;
683
- };
684
- else if ("function" != typeof init) {
685
- var ownInitializers = init;
686
- init = function(instance, init) {
687
- var value = init;
688
- for(var i = 0; i < ownInitializers.length; i++)value = ownInitializers[i].call(instance, value);
689
- return value;
690
- };
691
- } else {
692
- var originalInitializer = init;
693
- init = function(instance, init) {
694
- return originalInitializer.call(instance, init);
695
- };
696
- }
697
- ret.push(init);
698
- }
699
- if (0 !== kind) {
700
- if (1 === kind) {
701
- desc.get = value.get;
702
- desc.set = value.set;
703
- } else if (2 === kind) desc.value = value;
704
- else if (3 === kind) desc.get = value;
705
- else if (4 === kind) desc.set = value;
706
- if (isPrivate) if (1 === kind) {
707
- ret.push(function(instance, args) {
708
- return value.get.call(instance, args);
709
- });
710
- ret.push(function(instance, args) {
711
- return value.set.call(instance, args);
712
- });
713
- } else if (2 === kind) ret.push(value);
714
- else ret.push(function(instance, args) {
715
- return value.call(instance, args);
716
- });
717
- else Object.defineProperty(base, name, desc);
1040
+ dropOldestEvents(count) {
1041
+ const droppedEvents = [];
1042
+ for(let index = 0; index < count; index += 1){
1043
+ const oldestEvent = this.queuedExperienceEvents.values().next();
1044
+ if (oldestEvent.done) break;
1045
+ this.queuedExperienceEvents.delete(oldestEvent.value);
1046
+ droppedEvents.push(oldestEvent.value);
718
1047
  }
1048
+ return droppedEvents;
719
1049
  }
720
- function applyMemberDecs(Class, decInfos, metadata) {
721
- var ret = [];
722
- var protoInitializers;
723
- var staticInitializers;
724
- var existingProtoNonFields = new Map();
725
- var existingStaticNonFields = new Map();
726
- for(var i = 0; i < decInfos.length; i++){
727
- var decInfo = decInfos[i];
728
- if (Array.isArray(decInfo)) {
729
- var kind = decInfo[1];
730
- var name = decInfo[2];
731
- var isPrivate = decInfo.length > 3;
732
- var isStatic = kind >= 5;
733
- var base;
734
- var initializers;
735
- if (isStatic) {
736
- base = Class;
737
- kind -= 5;
738
- staticInitializers = staticInitializers || [];
739
- initializers = staticInitializers;
740
- } else {
741
- base = Class.prototype;
742
- protoInitializers = protoInitializers || [];
743
- initializers = protoInitializers;
744
- }
745
- if (0 !== kind && !isPrivate) {
746
- var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
747
- var existingKind = existingNonFields.get(name) || 0;
748
- if (true === existingKind || 3 === existingKind && 4 !== kind || 4 === existingKind && 3 !== kind) throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
749
- if (!existingKind && kind > 2) existingNonFields.set(name, kind);
750
- else existingNonFields.set(name, true);
751
- }
752
- applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
753
- }
1050
+ invokeOfflineDropCallback(context) {
1051
+ try {
1052
+ this.onOfflineDrop?.(context);
1053
+ } catch (error) {
1054
+ ExperienceQueue_coreLogger.warn('Offline queue drop callback failed', error);
754
1055
  }
755
- pushInitializers(ret, protoInitializers);
756
- pushInitializers(ret, staticInitializers);
757
- return ret;
758
- }
759
- function pushInitializers(ret, initializers) {
760
- if (initializers) ret.push(function(instance) {
761
- for(var i = 0; i < initializers.length; i++)initializers[i].call(instance);
762
- return instance;
763
- });
764
1056
  }
765
- function applyClassDecs(targetClass, classDecs, metadata) {
766
- if (classDecs.length > 0) {
767
- var initializers = [];
768
- var newClass = targetClass;
769
- var name = targetClass.name;
770
- for(var i = classDecs.length - 1; i >= 0; i--){
771
- var decoratorFinishedRef = {
772
- v: false
773
- };
774
- try {
775
- var nextNewClass = classDecs[i](newClass, {
776
- kind: "class",
777
- name: name,
778
- addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
779
- metadata
780
- });
781
- } finally{
782
- decoratorFinishedRef.v = true;
783
- }
784
- if (void 0 !== nextNewClass) {
785
- assertValidReturnValue(10, nextNewClass);
786
- newClass = nextNewClass;
787
- }
788
- }
789
- return [
790
- defineMetadata(newClass, metadata),
791
- function() {
792
- for(var i = 0; i < initializers.length; i++)initializers[i].call(newClass);
793
- }
794
- ];
1057
+ async tryUpsertQueuedEvents(events) {
1058
+ try {
1059
+ await this.upsertProfile(events);
1060
+ return true;
1061
+ } catch (error) {
1062
+ ExperienceQueue_coreLogger.warn('Experience queue flush request threw an error', error);
1063
+ return false;
795
1064
  }
796
1065
  }
797
- function defineMetadata(Class, metadata) {
798
- return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
799
- configurable: true,
800
- enumerable: true,
801
- value: metadata
1066
+ async upsertProfile(events) {
1067
+ const anonymousId = this.getAnonymousId();
1068
+ if (anonymousId) ExperienceQueue_coreLogger.debug(`Anonymous ID found: ${anonymousId}`);
1069
+ const data = await this.experienceApi.upsertProfile({
1070
+ profileId: anonymousId ?? signals_profile.value?.id,
1071
+ events
802
1072
  });
1073
+ await this.updateOutputSignals(data);
1074
+ return data;
803
1075
  }
804
- return function(targetClass, memberDecs, classDecs, parentClass) {
805
- if (void 0 !== parentClass) var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
806
- var metadata = Object.create(void 0 === parentMetadata ? null : parentMetadata);
807
- var e = applyMemberDecs(targetClass, memberDecs, metadata);
808
- if (!classDecs.length) defineMetadata(targetClass, metadata);
809
- return {
810
- e: e,
811
- get c () {
812
- return applyClassDecs(targetClass, classDecs, metadata);
813
- }
814
- };
815
- };
816
- }
817
- function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
818
- return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
819
- }
820
- var _dec, _dec1, _dec2, _dec3, _initProto;
821
- const AnalyticsStateful_logger = (0, logger_namespaceObject.createScopedLogger)('Analytics');
822
- const MAX_QUEUED_EVENTS = 25;
823
- const ANALYTICS_METHOD_EVENT_TYPE_MAP = {
824
- trackComponentView: 'component',
825
- trackFlagView: 'component',
826
- trackComponentClick: 'component_click',
827
- trackComponentHover: 'component_hover'
828
- };
829
- _dec = guardedBy('hasConsent', {
830
- onBlocked: 'onBlockedByConsent'
831
- }), _dec1 = guardedBy('hasConsent', {
832
- onBlocked: 'onBlockedByConsent'
833
- }), _dec2 = guardedBy('hasConsent', {
834
- onBlocked: 'onBlockedByConsent'
835
- }), _dec3 = guardedBy('hasConsent', {
836
- onBlocked: 'onBlockedByConsent'
837
- });
838
- class AnalyticsStateful extends analytics_AnalyticsBase {
839
- static{
840
- ({ e: [_initProto] } = _apply_decs_2203_r(this, [
841
- [
842
- _dec,
843
- 2,
844
- "trackComponentView"
845
- ],
846
- [
847
- _dec1,
848
- 2,
849
- "trackComponentClick"
850
- ],
851
- [
852
- _dec2,
853
- 2,
854
- "trackComponentHover"
855
- ],
856
- [
857
- _dec3,
858
- 2,
859
- "trackFlagView"
860
- ]
861
- ], []));
1076
+ async updateOutputSignals(data) {
1077
+ const intercepted = await this.stateInterceptors.run(data);
1078
+ const { changes, profile, selectedOptimizations } = intercepted;
1079
+ (0, signals_core_namespaceObject.batch)(()=>{
1080
+ if (!(0, predicate_namespaceObject.isEqual)(signals_changes.value, changes)) signals_changes.value = changes;
1081
+ if (!(0, predicate_namespaceObject.isEqual)(signals_profile.value, profile)) signals_profile.value = profile;
1082
+ if (!(0, predicate_namespaceObject.isEqual)(signals_selectedOptimizations.value, selectedOptimizations)) signals_selectedOptimizations.value = selectedOptimizations;
1083
+ });
862
1084
  }
863
- queue = (_initProto(this), new Map());
1085
+ }
1086
+ const InsightsQueue_coreLogger = (0, logger_namespaceObject.createScopedLogger)('CoreStateful');
1087
+ const MAX_QUEUED_INSIGHTS_EVENTS = 25;
1088
+ class InsightsQueue {
1089
+ eventInterceptors;
1090
+ flushIntervalMs;
864
1091
  flushRuntime;
865
- states = {
866
- blockedEventStream: toObservable(blockedEvent),
867
- eventStream: toObservable(signals_event),
868
- profile: toObservable(signals_profile)
869
- };
1092
+ insightsApi;
1093
+ queuedInsightsByProfile = new Map();
1094
+ insightsPeriodicFlushTimer;
870
1095
  constructor(options){
871
- const { api, builder, config, interceptors } = options;
872
- super({
873
- api,
874
- builder,
875
- config,
876
- interceptors
877
- });
878
- this.applyDefaults(config?.defaults);
1096
+ const { eventInterceptors, flushPolicy, insightsApi } = options;
1097
+ const { flushIntervalMs } = flushPolicy;
1098
+ this.eventInterceptors = eventInterceptors;
1099
+ this.flushIntervalMs = flushIntervalMs;
1100
+ this.insightsApi = insightsApi;
879
1101
  this.flushRuntime = new QueueFlushRuntime({
880
- policy: resolveQueueFlushPolicy(config?.queuePolicy),
1102
+ policy: flushPolicy,
881
1103
  onRetry: ()=>{
882
1104
  this.flush();
883
1105
  },
884
1106
  onCallbackError: (callbackName, error)=>{
885
- AnalyticsStateful_logger.warn(`Analytics flush policy callback "${callbackName}" failed`, error);
1107
+ InsightsQueue_coreLogger.warn(`Insights flush policy callback "${callbackName}" failed`, error);
886
1108
  }
887
1109
  });
888
- this.initializeEffects();
889
- }
890
- reset() {
891
- this.flushRuntime.reset();
892
- (0, signals_core_namespaceObject.batch)(()=>{
893
- blockedEvent.value = void 0;
894
- signals_event.value = void 0;
895
- signals_profile.value = void 0;
896
- });
897
- }
898
- hasConsent(name) {
899
- const mappedEventType = ANALYTICS_METHOD_EVENT_TYPE_MAP[name] ?? name;
900
- return !!consent.value || (this.allowedEventTypes ?? []).includes(mappedEventType);
901
- }
902
- onBlockedByConsent(name, payload) {
903
- AnalyticsStateful_logger.warn(`Event "${name}" was blocked due to lack of consent; payload: ${JSON.stringify(payload)}`);
904
- this.reportBlockedEvent('consent', 'analytics', name, payload);
905
- }
906
- async trackComponentView(payload) {
907
- AnalyticsStateful_logger.info(`Processing "component view" event for ${payload.componentId}`);
908
- await this.enqueueEvent(this.builder.buildComponentView(payload));
909
- }
910
- async trackComponentClick(payload) {
911
- AnalyticsStateful_logger.info(`Processing "component click" event for ${payload.componentId}`);
912
- await this.enqueueEvent(this.builder.buildComponentClick(payload));
913
1110
  }
914
- async trackComponentHover(payload) {
915
- AnalyticsStateful_logger.info(`Processing "component hover" event for ${payload.componentId}`);
916
- await this.enqueueEvent(this.builder.buildComponentHover(payload));
1111
+ clearScheduledRetry() {
1112
+ this.flushRuntime.clearScheduledRetry();
917
1113
  }
918
- async trackFlagView(payload) {
919
- AnalyticsStateful_logger.debug(`Processing "flag view" event for ${payload.componentId}`);
920
- await this.enqueueEvent(this.builder.buildFlagView(payload));
1114
+ clearPeriodicFlushTimer() {
1115
+ if (void 0 === this.insightsPeriodicFlushTimer) return;
1116
+ clearInterval(this.insightsPeriodicFlushTimer);
1117
+ this.insightsPeriodicFlushTimer = void 0;
921
1118
  }
922
- async enqueueEvent(event) {
1119
+ async send(event) {
923
1120
  const { value: profile } = signals_profile;
924
- if (!profile) return void AnalyticsStateful_logger.warn('Attempting to emit an event without an Optimization profile');
925
- const intercepted = await this.interceptors.event.run(event);
926
- const validEvent = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.InsightsEvent, intercepted);
927
- AnalyticsStateful_logger.debug(`Queueing ${validEvent.type} event for profile ${profile.id}`, validEvent);
928
- const { id: profileId } = profile;
929
- const queuedProfileEvents = this.queue.get(profileId);
1121
+ if (!profile) return void InsightsQueue_coreLogger.warn('Attempting to emit an event without an Optimization profile');
1122
+ const intercepted = await this.eventInterceptors.run(event);
1123
+ const validEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.InsightsEvent, intercepted);
1124
+ InsightsQueue_coreLogger.debug(`Queueing ${validEvent.type} event for profile ${profile.id}`, validEvent);
1125
+ const queuedProfileEvents = this.queuedInsightsByProfile.get(profile.id);
930
1126
  signals_event.value = validEvent;
931
1127
  if (queuedProfileEvents) {
932
1128
  queuedProfileEvents.profile = profile;
933
1129
  queuedProfileEvents.events.push(validEvent);
934
- } else this.queue.set(profileId, {
1130
+ } else this.queuedInsightsByProfile.set(profile.id, {
935
1131
  profile,
936
1132
  events: [
937
1133
  validEvent
938
1134
  ]
939
1135
  });
940
- await this.flushMaxEvents();
941
- }
942
- async flushMaxEvents() {
943
- if (this.getQueuedEventCount() >= MAX_QUEUED_EVENTS) await this.flush();
1136
+ this.ensurePeriodicFlushTimer();
1137
+ if (this.getQueuedEventCount() >= MAX_QUEUED_INSIGHTS_EVENTS) await this.flush();
1138
+ this.reconcilePeriodicFlushTimer();
944
1139
  }
945
1140
  async flush(options = {}) {
946
1141
  const { force = false } = options;
@@ -948,14 +1143,18 @@ var __webpack_exports__ = {};
948
1143
  force,
949
1144
  isOnline: !!online.value
950
1145
  })) return;
951
- AnalyticsStateful_logger.debug('Flushing event queue');
1146
+ InsightsQueue_coreLogger.debug('Flushing insights event queue');
952
1147
  const batches = this.createBatches();
953
- if (!batches.length) return void this.flushRuntime.clearScheduledRetry();
1148
+ if (!batches.length) {
1149
+ this.flushRuntime.clearScheduledRetry();
1150
+ this.reconcilePeriodicFlushTimer();
1151
+ return;
1152
+ }
954
1153
  this.flushRuntime.markFlushStarted();
955
1154
  try {
956
1155
  const sendSuccess = await this.trySendBatches(batches);
957
1156
  if (sendSuccess) {
958
- this.queue.clear();
1157
+ this.queuedInsightsByProfile.clear();
959
1158
  this.flushRuntime.handleFlushSuccess();
960
1159
  } else this.flushRuntime.handleFlushFailure({
961
1160
  queuedBatches: batches.length,
@@ -963,30 +1162,12 @@ var __webpack_exports__ = {};
963
1162
  });
964
1163
  } finally{
965
1164
  this.flushRuntime.markFlushFinished();
1165
+ this.reconcilePeriodicFlushTimer();
966
1166
  }
967
1167
  }
968
- applyDefaults(defaults) {
969
- if (defaults?.profile === void 0) return;
970
- const { profile: defaultProfile } = defaults;
971
- signals_profile.value = defaultProfile;
972
- }
973
- initializeEffects() {
974
- (0, signals_core_namespaceObject.effect)(()=>{
975
- const id = signals_profile.value?.id;
976
- AnalyticsStateful_logger.info(`Analytics ${consent.value ? 'will' : 'will not'} be collected due to consent (${consent.value})`);
977
- AnalyticsStateful_logger.debug(`Profile ${id && `with ID ${id}`} has been ${id ? 'set' : 'cleared'}`);
978
- });
979
- (0, signals_core_namespaceObject.effect)(()=>{
980
- if (!online.value) return;
981
- this.flushRuntime.clearScheduledRetry();
982
- this.flush({
983
- force: true
984
- });
985
- });
986
- }
987
1168
  createBatches() {
988
1169
  const batches = [];
989
- this.queue.forEach(({ profile, events })=>{
1170
+ this.queuedInsightsByProfile.forEach(({ profile, events })=>{
990
1171
  batches.push({
991
1172
  profile,
992
1173
  events
@@ -996,998 +1177,407 @@ var __webpack_exports__ = {};
996
1177
  }
997
1178
  async trySendBatches(batches) {
998
1179
  try {
999
- return await this.api.insights.sendBatchEvents(batches);
1180
+ return await this.insightsApi.sendBatchEvents(batches);
1000
1181
  } catch (error) {
1001
- AnalyticsStateful_logger.warn('Analytics queue flush request threw an error', error);
1182
+ InsightsQueue_coreLogger.warn('Insights queue flush request threw an error', error);
1002
1183
  return false;
1003
1184
  }
1004
1185
  }
1005
1186
  getQueuedEventCount() {
1006
1187
  let queuedCount = 0;
1007
- this.queue.forEach(({ events })=>{
1188
+ this.queuedInsightsByProfile.forEach(({ events })=>{
1008
1189
  queuedCount += events.length;
1009
1190
  });
1010
1191
  return queuedCount;
1011
1192
  }
1012
- }
1013
- const analytics_AnalyticsStateful = AnalyticsStateful;
1014
- const AnalyticsStateless_logger = (0, logger_namespaceObject.createScopedLogger)('Analytics');
1015
- class AnalyticsStateless extends analytics_AnalyticsBase {
1016
- async trackComponentView(args) {
1017
- AnalyticsStateless_logger.info('Processing "component view" event');
1018
- const { profile, ...builderArgs } = args;
1019
- const event = this.builder.buildComponentView(builderArgs);
1020
- await this.sendBatchEvent(event, profile);
1021
- }
1022
- async trackComponentClick(args) {
1023
- AnalyticsStateless_logger.info('Processing "component click" event');
1024
- const { profile, ...builderArgs } = args;
1025
- const event = this.builder.buildComponentClick(builderArgs);
1026
- await this.sendBatchEvent(event, profile);
1027
- }
1028
- async trackComponentHover(args) {
1029
- AnalyticsStateless_logger.info('Processing "component hover" event');
1030
- const { profile, ...builderArgs } = args;
1031
- const event = this.builder.buildComponentHover(builderArgs);
1032
- await this.sendBatchEvent(event, profile);
1033
- }
1034
- async trackFlagView(args) {
1035
- AnalyticsStateless_logger.debug('Processing "flag view" event');
1036
- const { profile, ...builderArgs } = args;
1037
- const event = this.builder.buildFlagView(builderArgs);
1038
- await this.sendBatchEvent(event, profile);
1039
- }
1040
- async sendBatchEvent(event, profile) {
1041
- const intercepted = await this.interceptors.event.run(event);
1042
- const parsed = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.InsightsEvent, intercepted);
1043
- const batchEvent = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.BatchInsightsEventArray, [
1044
- {
1045
- profile,
1046
- events: [
1047
- parsed
1048
- ]
1049
- }
1050
- ]);
1051
- await this.api.insights.sendBatchEvents(batchEvent);
1193
+ ensurePeriodicFlushTimer() {
1194
+ if (void 0 !== this.insightsPeriodicFlushTimer) return;
1195
+ if (0 === this.getQueuedEventCount()) return;
1196
+ this.insightsPeriodicFlushTimer = setInterval(()=>{
1197
+ this.flush();
1198
+ }, this.flushIntervalMs);
1199
+ }
1200
+ reconcilePeriodicFlushTimer() {
1201
+ if (this.getQueuedEventCount() > 0) return void this.ensurePeriodicFlushTimer();
1202
+ this.clearPeriodicFlushTimer();
1052
1203
  }
1053
1204
  }
1054
- const analytics_AnalyticsStateless = AnalyticsStateless;
1055
- var constants = __webpack_require__("./src/constants.ts");
1056
- const optimization_api_client_namespaceObject = require("@contentful/optimization-api-client");
1057
- class InterceptorManager {
1058
- interceptors = new Map();
1059
- nextId = 0;
1060
- add(interceptor) {
1061
- const { nextId: id } = this;
1062
- this.nextId += 1;
1063
- this.interceptors.set(id, interceptor);
1064
- return id;
1065
- }
1066
- remove(id) {
1067
- return this.interceptors.delete(id);
1068
- }
1069
- clear() {
1070
- this.interceptors.clear();
1071
- }
1072
- count() {
1073
- return this.interceptors.size;
1074
- }
1075
- async run(input) {
1076
- const fns = Array.from(this.interceptors.values());
1077
- let acc = input;
1078
- for (const fn of fns)acc = await fn(acc);
1079
- return acc;
1080
- }
1081
- }
1082
- class CoreBase {
1083
- api;
1084
- eventBuilder;
1085
- config;
1086
- interceptors = {
1087
- event: new InterceptorManager(),
1088
- state: new InterceptorManager()
1089
- };
1090
- constructor(config){
1091
- this.config = config;
1092
- const { analytics, personalization, eventBuilder, logLevel, environment, clientId, fetchOptions } = config;
1093
- logger_namespaceObject.logger.addSink(new logger_namespaceObject.ConsoleLogSink(logLevel));
1094
- const apiConfig = {
1095
- clientId,
1096
- environment,
1097
- fetchOptions,
1098
- analytics,
1099
- personalization
1100
- };
1101
- this.api = new optimization_api_client_namespaceObject.ApiClient(apiConfig);
1102
- this.eventBuilder = new optimization_api_client_namespaceObject.EventBuilder(eventBuilder ?? {
1103
- channel: 'server',
1104
- library: {
1105
- name: constants.OPTIMIZATION_CORE_SDK_NAME,
1106
- version: constants.OPTIMIZATION_CORE_SDK_VERSION
1107
- }
1108
- });
1109
- }
1110
- get flagsResolver() {
1111
- return this._personalization.flagsResolver;
1112
- }
1113
- get mergeTagValueResolver() {
1114
- return this._personalization.mergeTagValueResolver;
1115
- }
1116
- get personalizedEntryResolver() {
1117
- return this._personalization.personalizedEntryResolver;
1118
- }
1119
- getCustomFlag(name, changes) {
1120
- return this._personalization.getCustomFlag(name, changes);
1121
- }
1122
- getCustomFlags(changes) {
1123
- return this._personalization.getCustomFlags(changes);
1124
- }
1125
- personalizeEntry(entry, personalizations) {
1126
- return this._personalization.personalizeEntry(entry, personalizations);
1127
- }
1128
- getMergeTagValue(embeddedEntryNodeTarget, profile) {
1129
- return this._personalization.getMergeTagValue(embeddedEntryNodeTarget, profile);
1130
- }
1131
- async identify(payload) {
1132
- return await this._personalization.identify(payload);
1133
- }
1134
- async page(payload) {
1135
- return await this._personalization.page(payload);
1136
- }
1137
- async screen(payload) {
1138
- return await this._personalization.screen(payload);
1139
- }
1140
- async track(payload) {
1141
- return await this._personalization.track(payload);
1142
- }
1143
- async trackComponentView(payload) {
1144
- if (payload.sticky) return await this._personalization.trackComponentView(payload);
1145
- await this._analytics.trackComponentView(payload);
1146
- }
1147
- async trackComponentClick(payload) {
1148
- await this._analytics.trackComponentClick(payload);
1149
- }
1150
- async trackComponentHover(payload) {
1151
- await this._analytics.trackComponentHover(payload);
1152
- }
1153
- async trackFlagView(payload) {
1154
- await this._analytics.trackFlagView(payload);
1155
- }
1156
- }
1157
- const src_CoreBase = CoreBase;
1158
- const STATEFUL_RUNTIME_LOCK_KEY = '__ctfl_optimization_stateful_runtime_lock__';
1159
- const getStatefulRuntimeLock = ()=>{
1160
- const singletonGlobal = globalThis;
1161
- singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY] ??= {
1162
- owner: void 0
1205
+ var symbols = __webpack_require__("./src/symbols.ts");
1206
+ const CoreStateful_coreLogger = (0, logger_namespaceObject.createScopedLogger)('CoreStateful');
1207
+ const DEFAULT_ALLOWED_EVENT_TYPES = [
1208
+ 'identify',
1209
+ 'page',
1210
+ 'screen'
1211
+ ];
1212
+ const OFFLINE_QUEUE_MAX_EVENTS = 100;
1213
+ const hasDefinedValues = (record)=>Object.values(record).some((value)=>void 0 !== value);
1214
+ const createStatefulExperienceApiConfig = (api)=>{
1215
+ if (void 0 === api) return;
1216
+ const experienceConfig = {
1217
+ baseUrl: api.experienceBaseUrl,
1218
+ enabledFeatures: api.enabledFeatures,
1219
+ ip: api.ip,
1220
+ locale: api.locale,
1221
+ plainText: api.plainText,
1222
+ preflight: api.preflight
1163
1223
  };
1164
- return singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY];
1224
+ return hasDefinedValues(experienceConfig) ? experienceConfig : void 0;
1165
1225
  };
1166
- const acquireStatefulRuntimeSingleton = (owner)=>{
1167
- const lock = getStatefulRuntimeLock();
1168
- if (lock.owner) throw new Error(`Stateful Optimization SDK already initialized (${lock.owner}). Only one stateful instance is supported per runtime.`);
1169
- lock.owner = owner;
1170
- };
1171
- const releaseStatefulRuntimeSingleton = (owner)=>{
1172
- const lock = getStatefulRuntimeLock();
1173
- if (lock.owner === owner) lock.owner = void 0;
1174
- };
1175
- class PersonalizationBase extends src_ProductBase {
1176
- flagsResolver = resolvers_FlagsResolver;
1177
- mergeTagValueResolver = resolvers_MergeTagValueResolver;
1178
- personalizedEntryResolver = resolvers_PersonalizedEntryResolver;
1179
- getCustomFlag(name, changes) {
1180
- return this.getCustomFlags(changes)[name];
1181
- }
1182
- getCustomFlags(changes) {
1183
- return resolvers_FlagsResolver.resolve(changes);
1184
- }
1185
- personalizeEntry(entry, personalizations) {
1186
- return resolvers_PersonalizedEntryResolver.resolve(entry, personalizations);
1187
- }
1188
- getMergeTagValue(embeddedEntryNodeTarget, profile) {
1189
- return resolvers_MergeTagValueResolver.resolve(embeddedEntryNodeTarget, profile);
1190
- }
1191
- }
1192
- const personalization_PersonalizationBase = PersonalizationBase;
1193
- const predicate_namespaceObject = require("es-toolkit/predicate");
1194
- function PersonalizationStateful_applyDecs2203RFactory() {
1195
- function createAddInitializerMethod(initializers, decoratorFinishedRef) {
1196
- return function(initializer) {
1197
- assertNotFinished(decoratorFinishedRef, "addInitializer");
1198
- assertCallable(initializer, "An initializer");
1199
- initializers.push(initializer);
1200
- };
1201
- }
1202
- function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
1203
- var kindStr;
1204
- switch(kind){
1205
- case 1:
1206
- kindStr = "accessor";
1207
- break;
1208
- case 2:
1209
- kindStr = "method";
1210
- break;
1211
- case 3:
1212
- kindStr = "getter";
1213
- break;
1214
- case 4:
1215
- kindStr = "setter";
1216
- break;
1217
- default:
1218
- kindStr = "field";
1219
- }
1220
- var ctx = {
1221
- kind: kindStr,
1222
- name: isPrivate ? "#" + name : name,
1223
- static: isStatic,
1224
- private: isPrivate,
1225
- metadata: metadata
1226
- };
1227
- var decoratorFinishedRef = {
1228
- v: false
1229
- };
1230
- ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
1231
- var get, set;
1232
- if (0 === kind) if (isPrivate) {
1233
- get = desc.get;
1234
- set = desc.set;
1235
- } else {
1236
- get = function() {
1237
- return this[name];
1238
- };
1239
- set = function(v) {
1240
- this[name] = v;
1241
- };
1242
- }
1243
- else if (2 === kind) get = function() {
1244
- return desc.value;
1245
- };
1246
- else {
1247
- if (1 === kind || 3 === kind) get = function() {
1248
- return desc.get.call(this);
1249
- };
1250
- if (1 === kind || 4 === kind) set = function(v) {
1251
- desc.set.call(this, v);
1252
- };
1253
- }
1254
- ctx.access = get && set ? {
1255
- get: get,
1256
- set: set
1257
- } : get ? {
1258
- get: get
1259
- } : {
1260
- set: set
1261
- };
1262
- try {
1263
- return dec(value, ctx);
1264
- } finally{
1265
- decoratorFinishedRef.v = true;
1266
- }
1267
- }
1268
- function assertNotFinished(decoratorFinishedRef, fnName) {
1269
- if (decoratorFinishedRef.v) throw new Error("attempted to call " + fnName + " after decoration was finished");
1270
- }
1271
- function assertCallable(fn, hint) {
1272
- if ("function" != typeof fn) throw new TypeError(hint + " must be a function");
1273
- }
1274
- function assertValidReturnValue(kind, value) {
1275
- var type = typeof value;
1276
- if (1 === kind) {
1277
- if ("object" !== type || null === value) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
1278
- if (void 0 !== value.get) assertCallable(value.get, "accessor.get");
1279
- if (void 0 !== value.set) assertCallable(value.set, "accessor.set");
1280
- if (void 0 !== value.init) assertCallable(value.init, "accessor.init");
1281
- } else if ("function" !== type) {
1282
- var hint;
1283
- hint = 0 === kind ? "field" : 10 === kind ? "class" : "method";
1284
- throw new TypeError(hint + " decorators must return a function or void 0");
1285
- }
1286
- }
1287
- function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
1288
- var decs = decInfo[0];
1289
- var desc, init, value;
1290
- if (isPrivate) desc = 0 === kind || 1 === kind ? {
1291
- get: decInfo[3],
1292
- set: decInfo[4]
1293
- } : 3 === kind ? {
1294
- get: decInfo[3]
1295
- } : 4 === kind ? {
1296
- set: decInfo[3]
1297
- } : {
1298
- value: decInfo[3]
1299
- };
1300
- else if (0 !== kind) desc = Object.getOwnPropertyDescriptor(base, name);
1301
- if (1 === kind) value = {
1302
- get: desc.get,
1303
- set: desc.set
1304
- };
1305
- else if (2 === kind) value = desc.value;
1306
- else if (3 === kind) value = desc.get;
1307
- else if (4 === kind) value = desc.set;
1308
- var newValue, get, set;
1309
- if ("function" == typeof decs) {
1310
- newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
1311
- if (void 0 !== newValue) {
1312
- assertValidReturnValue(kind, newValue);
1313
- if (0 === kind) init = newValue;
1314
- else if (1 === kind) {
1315
- init = newValue.init;
1316
- get = newValue.get || value.get;
1317
- set = newValue.set || value.set;
1318
- value = {
1319
- get: get,
1320
- set: set
1321
- };
1322
- } else value = newValue;
1323
- }
1324
- } else for(var i = decs.length - 1; i >= 0; i--){
1325
- var dec = decs[i];
1326
- newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
1327
- if (void 0 !== newValue) {
1328
- assertValidReturnValue(kind, newValue);
1329
- var newInit;
1330
- if (0 === kind) newInit = newValue;
1331
- else if (1 === kind) {
1332
- newInit = newValue.init;
1333
- get = newValue.get || value.get;
1334
- set = newValue.set || value.set;
1335
- value = {
1336
- get: get,
1337
- set: set
1338
- };
1339
- } else value = newValue;
1340
- if (void 0 !== newInit) if (void 0 === init) init = newInit;
1341
- else if ("function" == typeof init) init = [
1342
- init,
1343
- newInit
1344
- ];
1345
- else init.push(newInit);
1346
- }
1347
- }
1348
- if (0 === kind || 1 === kind) {
1349
- if (void 0 === init) init = function(instance, init) {
1350
- return init;
1351
- };
1352
- else if ("function" != typeof init) {
1353
- var ownInitializers = init;
1354
- init = function(instance, init) {
1355
- var value = init;
1356
- for(var i = 0; i < ownInitializers.length; i++)value = ownInitializers[i].call(instance, value);
1357
- return value;
1358
- };
1359
- } else {
1360
- var originalInitializer = init;
1361
- init = function(instance, init) {
1362
- return originalInitializer.call(instance, init);
1363
- };
1364
- }
1365
- ret.push(init);
1366
- }
1367
- if (0 !== kind) {
1368
- if (1 === kind) {
1369
- desc.get = value.get;
1370
- desc.set = value.set;
1371
- } else if (2 === kind) desc.value = value;
1372
- else if (3 === kind) desc.get = value;
1373
- else if (4 === kind) desc.set = value;
1374
- if (isPrivate) if (1 === kind) {
1375
- ret.push(function(instance, args) {
1376
- return value.get.call(instance, args);
1377
- });
1378
- ret.push(function(instance, args) {
1379
- return value.set.call(instance, args);
1380
- });
1381
- } else if (2 === kind) ret.push(value);
1382
- else ret.push(function(instance, args) {
1383
- return value.call(instance, args);
1384
- });
1385
- else Object.defineProperty(base, name, desc);
1386
- }
1387
- }
1388
- function applyMemberDecs(Class, decInfos, metadata) {
1389
- var ret = [];
1390
- var protoInitializers;
1391
- var staticInitializers;
1392
- var existingProtoNonFields = new Map();
1393
- var existingStaticNonFields = new Map();
1394
- for(var i = 0; i < decInfos.length; i++){
1395
- var decInfo = decInfos[i];
1396
- if (Array.isArray(decInfo)) {
1397
- var kind = decInfo[1];
1398
- var name = decInfo[2];
1399
- var isPrivate = decInfo.length > 3;
1400
- var isStatic = kind >= 5;
1401
- var base;
1402
- var initializers;
1403
- if (isStatic) {
1404
- base = Class;
1405
- kind -= 5;
1406
- staticInitializers = staticInitializers || [];
1407
- initializers = staticInitializers;
1408
- } else {
1409
- base = Class.prototype;
1410
- protoInitializers = protoInitializers || [];
1411
- initializers = protoInitializers;
1412
- }
1413
- if (0 !== kind && !isPrivate) {
1414
- var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
1415
- var existingKind = existingNonFields.get(name) || 0;
1416
- if (true === existingKind || 3 === existingKind && 4 !== kind || 4 === existingKind && 3 !== kind) throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + name);
1417
- if (!existingKind && kind > 2) existingNonFields.set(name, kind);
1418
- else existingNonFields.set(name, true);
1419
- }
1420
- applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
1421
- }
1422
- }
1423
- pushInitializers(ret, protoInitializers);
1424
- pushInitializers(ret, staticInitializers);
1425
- return ret;
1426
- }
1427
- function pushInitializers(ret, initializers) {
1428
- if (initializers) ret.push(function(instance) {
1429
- for(var i = 0; i < initializers.length; i++)initializers[i].call(instance);
1430
- return instance;
1431
- });
1432
- }
1433
- function applyClassDecs(targetClass, classDecs, metadata) {
1434
- if (classDecs.length > 0) {
1435
- var initializers = [];
1436
- var newClass = targetClass;
1437
- var name = targetClass.name;
1438
- for(var i = classDecs.length - 1; i >= 0; i--){
1439
- var decoratorFinishedRef = {
1440
- v: false
1441
- };
1442
- try {
1443
- var nextNewClass = classDecs[i](newClass, {
1444
- kind: "class",
1445
- name: name,
1446
- addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
1447
- metadata
1448
- });
1449
- } finally{
1450
- decoratorFinishedRef.v = true;
1451
- }
1452
- if (void 0 !== nextNewClass) {
1453
- assertValidReturnValue(10, nextNewClass);
1454
- newClass = nextNewClass;
1455
- }
1456
- }
1457
- return [
1458
- defineMetadata(newClass, metadata),
1459
- function() {
1460
- for(var i = 0; i < initializers.length; i++)initializers[i].call(newClass);
1461
- }
1462
- ];
1463
- }
1464
- }
1465
- function defineMetadata(Class, metadata) {
1466
- return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
1467
- configurable: true,
1468
- enumerable: true,
1469
- value: metadata
1470
- });
1471
- }
1472
- return function(targetClass, memberDecs, classDecs, parentClass) {
1473
- if (void 0 !== parentClass) var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
1474
- var metadata = Object.create(void 0 === parentMetadata ? null : parentMetadata);
1475
- var e = applyMemberDecs(targetClass, memberDecs, metadata);
1476
- if (!classDecs.length) defineMetadata(targetClass, metadata);
1477
- return {
1478
- e: e,
1479
- get c () {
1480
- return applyClassDecs(targetClass, classDecs, metadata);
1481
- }
1482
- };
1226
+ const createStatefulInsightsApiConfig = (api)=>{
1227
+ if (void 0 === api) return;
1228
+ const insightsConfig = {
1229
+ baseUrl: api.insightsBaseUrl,
1230
+ beaconHandler: api.beaconHandler
1483
1231
  };
1484
- }
1485
- function PersonalizationStateful_apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
1486
- return (PersonalizationStateful_apply_decs_2203_r = PersonalizationStateful_applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
1487
- }
1488
- var PersonalizationStateful_dec, PersonalizationStateful_dec1, PersonalizationStateful_dec2, PersonalizationStateful_dec3, _dec4, PersonalizationStateful_initProto;
1489
- const PersonalizationStateful_logger = (0, logger_namespaceObject.createScopedLogger)('Personalization');
1490
- const OFFLINE_QUEUE_MAX_EVENTS = 100;
1491
- const resolvePersonalizationQueuePolicy = (policy)=>({
1492
- maxEvents: toPositiveInt(policy?.maxEvents, OFFLINE_QUEUE_MAX_EVENTS),
1493
- onDrop: policy?.onDrop,
1494
- flushPolicy: resolveQueueFlushPolicy(policy?.flushPolicy)
1232
+ return hasDefinedValues(insightsConfig) ? insightsConfig : void 0;
1233
+ };
1234
+ const resolveQueuePolicy = (policy)=>({
1235
+ flush: resolveQueueFlushPolicy(policy?.flush),
1236
+ offlineMaxEvents: toPositiveInt(policy?.offlineMaxEvents, OFFLINE_QUEUE_MAX_EVENTS),
1237
+ onOfflineDrop: policy?.onOfflineDrop
1495
1238
  });
1496
- PersonalizationStateful_dec = guardedBy('hasConsent', {
1497
- onBlocked: 'onBlockedByConsent'
1498
- }), PersonalizationStateful_dec1 = guardedBy('hasConsent', {
1499
- onBlocked: 'onBlockedByConsent'
1500
- }), PersonalizationStateful_dec2 = guardedBy('hasConsent', {
1501
- onBlocked: 'onBlockedByConsent'
1502
- }), PersonalizationStateful_dec3 = guardedBy('hasConsent', {
1503
- onBlocked: 'onBlockedByConsent'
1504
- }), _dec4 = guardedBy('hasConsent', {
1505
- onBlocked: 'onBlockedByConsent'
1506
- });
1507
- class PersonalizationStateful extends personalization_PersonalizationBase {
1508
- static{
1509
- ({ e: [PersonalizationStateful_initProto] } = PersonalizationStateful_apply_decs_2203_r(this, [
1510
- [
1511
- PersonalizationStateful_dec,
1512
- 2,
1513
- "identify"
1514
- ],
1515
- [
1516
- PersonalizationStateful_dec1,
1517
- 2,
1518
- "page"
1519
- ],
1520
- [
1521
- PersonalizationStateful_dec2,
1522
- 2,
1523
- "screen"
1524
- ],
1525
- [
1526
- PersonalizationStateful_dec3,
1527
- 2,
1528
- "track"
1529
- ],
1530
- [
1531
- _dec4,
1532
- 2,
1533
- "trackComponentView"
1534
- ]
1535
- ], []));
1536
- }
1537
- offlineQueue = (PersonalizationStateful_initProto(this), new Set());
1538
- queuePolicy;
1539
- flushRuntime;
1239
+ let statefulInstanceCounter = 0;
1240
+ class CoreStateful extends src_CoreStatefulEventEmitter {
1241
+ singletonOwner;
1242
+ destroyed = false;
1243
+ allowedEventTypes;
1244
+ experienceQueue;
1245
+ insightsQueue;
1246
+ onEventBlocked;
1540
1247
  states = {
1541
1248
  blockedEventStream: toObservable(blockedEvent),
1249
+ flag: (name)=>this.getFlagObservable(name),
1250
+ consent: toObservable(consent),
1542
1251
  eventStream: toObservable(signals_event),
1543
- flags: toObservable(flags),
1544
- profile: toObservable(signals_profile),
1545
- personalizations: toObservable(signals_personalizations)
1252
+ canOptimize: toObservable(canOptimize),
1253
+ selectedOptimizations: toObservable(signals_selectedOptimizations),
1254
+ previewPanelAttached: toObservable(previewPanelAttached),
1255
+ previewPanelOpen: toObservable(previewPanelOpen),
1256
+ profile: toObservable(signals_profile)
1546
1257
  };
1547
- getAnonymousId;
1548
- constructor(options){
1549
- const { api, builder, config, interceptors } = options;
1550
- super({
1551
- api,
1552
- builder,
1553
- config,
1554
- interceptors
1555
- });
1556
- const { defaults, getAnonymousId, queuePolicy } = config ?? {};
1557
- this.queuePolicy = resolvePersonalizationQueuePolicy(queuePolicy);
1558
- this.flushRuntime = new QueueFlushRuntime({
1559
- policy: this.queuePolicy.flushPolicy,
1560
- onRetry: ()=>{
1561
- this.flush();
1562
- },
1563
- onCallbackError: (callbackName, error)=>{
1564
- PersonalizationStateful_logger.warn(`Personalization flush policy callback "${callbackName}" failed`, error);
1565
- }
1258
+ constructor(config){
1259
+ super(config, {
1260
+ experience: createStatefulExperienceApiConfig(config.api),
1261
+ insights: createStatefulInsightsApiConfig(config.api)
1566
1262
  });
1567
- if (defaults) {
1568
- const { changes: defaultChanges, personalizations: defaultPersonalizations, profile: defaultProfile } = defaults;
1263
+ this.singletonOwner = `CoreStateful#${++statefulInstanceCounter}`;
1264
+ acquireStatefulRuntimeSingleton(this.singletonOwner);
1265
+ try {
1266
+ const { allowedEventTypes, defaults, getAnonymousId, onEventBlocked, queuePolicy } = config;
1267
+ const { changes: defaultChanges, consent: defaultConsent, selectedOptimizations: defaultSelectedOptimizations, profile: defaultProfile } = defaults ?? {};
1268
+ const resolvedQueuePolicy = resolveQueuePolicy(queuePolicy);
1269
+ this.allowedEventTypes = allowedEventTypes ?? DEFAULT_ALLOWED_EVENT_TYPES;
1270
+ this.onEventBlocked = onEventBlocked;
1271
+ this.insightsQueue = new InsightsQueue({
1272
+ eventInterceptors: this.interceptors.event,
1273
+ flushPolicy: resolvedQueuePolicy.flush,
1274
+ insightsApi: this.api.insights
1275
+ });
1276
+ this.experienceQueue = new ExperienceQueue({
1277
+ experienceApi: this.api.experience,
1278
+ eventInterceptors: this.interceptors.event,
1279
+ flushPolicy: resolvedQueuePolicy.flush,
1280
+ getAnonymousId: getAnonymousId ?? (()=>void 0),
1281
+ offlineMaxEvents: resolvedQueuePolicy.offlineMaxEvents,
1282
+ onOfflineDrop: resolvedQueuePolicy.onOfflineDrop,
1283
+ stateInterceptors: this.interceptors.state
1284
+ });
1285
+ if (void 0 !== defaultConsent) consent.value = defaultConsent;
1569
1286
  (0, signals_core_namespaceObject.batch)(()=>{
1570
- signals_changes.value = defaultChanges;
1571
- signals_personalizations.value = defaultPersonalizations;
1572
- signals_profile.value = defaultProfile;
1287
+ if (void 0 !== defaultChanges) signals_changes.value = defaultChanges;
1288
+ if (void 0 !== defaultSelectedOptimizations) signals_selectedOptimizations.value = defaultSelectedOptimizations;
1289
+ if (void 0 !== defaultProfile) signals_profile.value = defaultProfile;
1573
1290
  });
1291
+ this.initializeEffects();
1292
+ } catch (error) {
1293
+ releaseStatefulRuntimeSingleton(this.singletonOwner);
1294
+ throw error;
1574
1295
  }
1575
- if (defaults?.consent !== void 0) {
1576
- const { consent: defaultConsent } = defaults;
1577
- consent.value = defaultConsent;
1578
- }
1579
- this.getAnonymousId = getAnonymousId ?? (()=>void 0);
1296
+ }
1297
+ initializeEffects() {
1580
1298
  (0, signals_core_namespaceObject.effect)(()=>{
1581
- PersonalizationStateful_logger.debug(`Profile ${signals_profile.value && `with ID ${signals_profile.value.id}`} has been ${signals_profile.value ? 'set' : 'cleared'}`);
1299
+ CoreStateful_coreLogger.debug(`Profile ${signals_profile.value && `with ID ${signals_profile.value.id}`} has been ${signals_profile.value ? 'set' : 'cleared'}`);
1582
1300
  });
1583
1301
  (0, signals_core_namespaceObject.effect)(()=>{
1584
- PersonalizationStateful_logger.debug(`Variants have been ${signals_personalizations.value?.length ? 'populated' : 'cleared'}`);
1302
+ CoreStateful_coreLogger.debug(`Variants have been ${signals_selectedOptimizations.value?.length ? 'populated' : 'cleared'}`);
1585
1303
  });
1586
1304
  (0, signals_core_namespaceObject.effect)(()=>{
1587
- PersonalizationStateful_logger.info(`Personalization ${consent.value ? 'will' : 'will not'} take effect due to consent (${consent.value})`);
1305
+ CoreStateful_coreLogger.info(`Core ${consent.value ? 'will' : 'will not'} emit gated events due to consent (${consent.value})`);
1588
1306
  });
1589
1307
  (0, signals_core_namespaceObject.effect)(()=>{
1590
1308
  if (!online.value) return;
1591
- this.flushRuntime.clearScheduledRetry();
1592
- this.flush({
1309
+ this.insightsQueue.clearScheduledRetry();
1310
+ this.experienceQueue.clearScheduledRetry();
1311
+ this.flushQueues({
1593
1312
  force: true
1594
1313
  });
1595
1314
  });
1596
1315
  }
1316
+ async flushQueues(options = {}) {
1317
+ await this.insightsQueue.flush(options);
1318
+ await this.experienceQueue.flush(options);
1319
+ }
1320
+ destroy() {
1321
+ if (this.destroyed) return;
1322
+ this.destroyed = true;
1323
+ this.insightsQueue.flush({
1324
+ force: true
1325
+ }).catch((error)=>{
1326
+ logger_namespaceObject.logger.warn('Failed to flush insights queue during destroy()', String(error));
1327
+ });
1328
+ this.experienceQueue.flush({
1329
+ force: true
1330
+ }).catch((error)=>{
1331
+ logger_namespaceObject.logger.warn('Failed to flush Experience queue during destroy()', String(error));
1332
+ });
1333
+ this.insightsQueue.clearPeriodicFlushTimer();
1334
+ releaseStatefulRuntimeSingleton(this.singletonOwner);
1335
+ }
1597
1336
  reset() {
1598
- this.flushRuntime.reset();
1599
1337
  (0, signals_core_namespaceObject.batch)(()=>{
1600
- signals_changes.value = void 0;
1601
1338
  blockedEvent.value = void 0;
1602
1339
  signals_event.value = void 0;
1340
+ signals_changes.value = void 0;
1603
1341
  signals_profile.value = void 0;
1604
- signals_personalizations.value = void 0;
1342
+ signals_selectedOptimizations.value = void 0;
1605
1343
  });
1606
1344
  }
1607
- getCustomFlag(name, changes = signals_changes.value) {
1608
- return super.getCustomFlag(name, changes);
1609
- }
1610
- getCustomFlags(changes = signals_changes.value) {
1611
- return super.getCustomFlags(changes);
1612
- }
1613
- personalizeEntry(entry, personalizations = signals_personalizations.value) {
1614
- return super.personalizeEntry(entry, personalizations);
1615
- }
1616
- getMergeTagValue(embeddedEntryNodeTarget, profile = signals_profile.value) {
1617
- return super.getMergeTagValue(embeddedEntryNodeTarget, profile);
1618
- }
1619
- hasConsent(name) {
1620
- return !!consent.value || (this.allowedEventTypes ?? []).includes('trackComponentView' === name || 'trackFlagView' === name ? 'component' : name);
1621
- }
1622
- onBlockedByConsent(name, payload) {
1623
- PersonalizationStateful_logger.warn(`Event "${name}" was blocked due to lack of consent; payload: ${JSON.stringify(payload)}`);
1624
- this.reportBlockedEvent('consent', 'personalization', name, payload);
1625
- }
1626
- async identify(payload) {
1627
- PersonalizationStateful_logger.info('Sending "identify" event');
1628
- const event = this.builder.buildIdentify(payload);
1629
- return await this.sendOrEnqueueEvent(event);
1630
- }
1631
- async page(payload) {
1632
- PersonalizationStateful_logger.info('Sending "page" event');
1633
- const event = this.builder.buildPageView(payload);
1634
- return await this.sendOrEnqueueEvent(event);
1345
+ async flush() {
1346
+ await this.flushQueues();
1635
1347
  }
1636
- async screen(payload) {
1637
- PersonalizationStateful_logger.info(`Sending "screen" event for "${payload.name}"`);
1638
- const event = this.builder.buildScreenView(payload);
1639
- return await this.sendOrEnqueueEvent(event);
1348
+ consent(accept) {
1349
+ consent.value = accept;
1640
1350
  }
1641
- async track(payload) {
1642
- PersonalizationStateful_logger.info(`Sending "track" event "${payload.event}"`);
1643
- const event = this.builder.buildTrack(payload);
1644
- return await this.sendOrEnqueueEvent(event);
1351
+ get online() {
1352
+ return online.value ?? false;
1645
1353
  }
1646
- async trackComponentView(payload) {
1647
- PersonalizationStateful_logger.info(`Sending "track personalization" event for ${payload.componentId}`);
1648
- const event = this.builder.buildComponentView(payload);
1649
- return await this.sendOrEnqueueEvent(event);
1354
+ set online(isOnline) {
1355
+ online.value = isOnline;
1650
1356
  }
1651
- async sendOrEnqueueEvent(event) {
1652
- const intercepted = await this.interceptors.event.run(event);
1653
- const validEvent = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.ExperienceEvent, intercepted);
1654
- signals_event.value = validEvent;
1655
- if (online.value) return await this.upsertProfile([
1656
- validEvent
1657
- ]);
1658
- PersonalizationStateful_logger.debug(`Queueing ${validEvent.type} event`, validEvent);
1659
- this.enqueueOfflineEvent(validEvent);
1357
+ registerPreviewPanel(previewPanel) {
1358
+ Reflect.set(previewPanel, symbols.PREVIEW_PANEL_SIGNALS_SYMBOL, signals);
1359
+ Reflect.set(previewPanel, symbols.PREVIEW_PANEL_SIGNAL_FNS_SYMBOL, signalFns);
1660
1360
  }
1661
- enqueueOfflineEvent(event) {
1662
- let droppedEvents = [];
1663
- if (this.offlineQueue.size >= this.queuePolicy.maxEvents) {
1664
- const dropCount = this.offlineQueue.size - this.queuePolicy.maxEvents + 1;
1665
- droppedEvents = this.dropOldestOfflineEvents(dropCount);
1666
- if (droppedEvents.length > 0) PersonalizationStateful_logger.warn(`Dropped ${droppedEvents.length} oldest personalization offline event(s) due to queue limit (${this.queuePolicy.maxEvents})`);
1667
- }
1668
- this.offlineQueue.add(event);
1669
- if (droppedEvents.length > 0) this.invokeQueueDropCallback({
1670
- droppedCount: droppedEvents.length,
1671
- droppedEvents,
1672
- maxEvents: this.queuePolicy.maxEvents,
1673
- queuedEvents: this.offlineQueue.size
1361
+ }
1362
+ const src_CoreStateful = CoreStateful;
1363
+ var api_schemas = __webpack_require__("./src/api-schemas.ts");
1364
+ const TRACK_CLICK_PROFILE_ERROR = 'CoreStateless.trackClick() requires `payload.profile.id` for Insights delivery.';
1365
+ const TRACK_HOVER_PROFILE_ERROR = 'CoreStateless.trackHover() requires `payload.profile.id` for Insights delivery.';
1366
+ const TRACK_FLAG_VIEW_PROFILE_ERROR = 'CoreStateless.trackFlagView() requires `payload.profile.id` for Insights delivery.';
1367
+ const NON_STICKY_TRACK_VIEW_PROFILE_ERROR = 'CoreStateless.trackView() requires `payload.profile.id` when `payload.sticky` is not `true`.';
1368
+ const STICKY_TRACK_VIEW_PROFILE_ERROR = 'CoreStateless.trackView() could not derive a profile from the sticky Experience response. Pass `payload.profile.id` explicitly if you need a fallback.';
1369
+ const CoreStateless_hasDefinedValues = (record)=>Object.values(record).some((value)=>void 0 !== value);
1370
+ const requireInsightsProfile = (profile, errorMessage)=>{
1371
+ if (void 0 !== profile) return profile;
1372
+ throw new Error(errorMessage);
1373
+ };
1374
+ const createStatelessExperienceApiConfig = (api)=>{
1375
+ if (void 0 === api) return;
1376
+ const experienceConfig = {
1377
+ baseUrl: api.experienceBaseUrl,
1378
+ enabledFeatures: api.enabledFeatures
1379
+ };
1380
+ return CoreStateless_hasDefinedValues(experienceConfig) ? experienceConfig : void 0;
1381
+ };
1382
+ const createStatelessInsightsApiConfig = (api)=>{
1383
+ if (api?.insightsBaseUrl === void 0) return;
1384
+ return {
1385
+ baseUrl: api.insightsBaseUrl
1386
+ };
1387
+ };
1388
+ class CoreStateless extends src_CoreBase {
1389
+ constructor(config){
1390
+ super(config, {
1391
+ experience: createStatelessExperienceApiConfig(config.api),
1392
+ insights: createStatelessInsightsApiConfig(config.api)
1674
1393
  });
1675
1394
  }
1676
- dropOldestOfflineEvents(count) {
1677
- const droppedEvents = [];
1678
- for(let index = 0; index < count; index += 1){
1679
- const oldestEvent = this.offlineQueue.values().next();
1680
- if (oldestEvent.done) break;
1681
- this.offlineQueue.delete(oldestEvent.value);
1682
- droppedEvents.push(oldestEvent.value);
1683
- }
1684
- return droppedEvents;
1685
- }
1686
- invokeQueueDropCallback(context) {
1687
- try {
1688
- this.queuePolicy.onDrop?.(context);
1689
- } catch (error) {
1690
- PersonalizationStateful_logger.warn('Personalization offline queue drop callback failed', error);
1691
- }
1692
- }
1693
- async flush(options = {}) {
1694
- await this.flushOfflineQueue(options);
1695
- }
1696
- async flushOfflineQueue(options = {}) {
1697
- const { force = false } = options;
1698
- if (this.flushRuntime.shouldSkip({
1699
- force,
1700
- isOnline: !!online.value
1701
- })) return;
1702
- if (0 === this.offlineQueue.size) return void this.flushRuntime.clearScheduledRetry();
1703
- PersonalizationStateful_logger.debug('Flushing offline event queue');
1704
- const queuedEvents = Array.from(this.offlineQueue);
1705
- this.flushRuntime.markFlushStarted();
1706
- try {
1707
- const sendSuccess = await this.tryUpsertQueuedEvents(queuedEvents);
1708
- if (sendSuccess) {
1709
- queuedEvents.forEach((event)=>{
1710
- this.offlineQueue.delete(event);
1711
- });
1712
- this.flushRuntime.handleFlushSuccess();
1713
- } else this.flushRuntime.handleFlushFailure({
1714
- queuedBatches: this.offlineQueue.size > 0 ? 1 : 0,
1715
- queuedEvents: this.offlineQueue.size
1716
- });
1717
- } finally{
1718
- this.flushRuntime.markFlushFinished();
1719
- }
1720
- }
1721
- async tryUpsertQueuedEvents(events) {
1722
- try {
1723
- await this.upsertProfile(events);
1724
- return true;
1725
- } catch (error) {
1726
- PersonalizationStateful_logger.warn('Personalization offline queue flush request threw an error', error);
1727
- return false;
1728
- }
1395
+ async identify(payload, requestOptions) {
1396
+ const { profile, ...builderArgs } = payload;
1397
+ return await this.sendExperienceEvent(this.eventBuilder.buildIdentify(builderArgs), profile, requestOptions);
1729
1398
  }
1730
- async upsertProfile(events) {
1731
- const anonymousId = this.getAnonymousId();
1732
- if (anonymousId) PersonalizationStateful_logger.debug(`Anonymous ID found: ${anonymousId}`);
1733
- const data = await this.api.experience.upsertProfile({
1734
- profileId: anonymousId ?? signals_profile.value?.id,
1735
- events
1736
- });
1737
- await this.updateOutputSignals(data);
1738
- return data;
1399
+ async page(payload = {}, requestOptions) {
1400
+ const { profile, ...builderArgs } = payload;
1401
+ return await this.sendExperienceEvent(this.eventBuilder.buildPageView(builderArgs), profile, requestOptions);
1739
1402
  }
1740
- async updateOutputSignals(data) {
1741
- const intercepted = await this.interceptors.state.run(data);
1742
- const { changes, personalizations, profile } = intercepted;
1743
- (0, signals_core_namespaceObject.batch)(()=>{
1744
- if (!(0, predicate_namespaceObject.isEqual)(signals_changes.value, changes)) signals_changes.value = changes;
1745
- if (!(0, predicate_namespaceObject.isEqual)(signals_profile.value, profile)) signals_profile.value = profile;
1746
- if (!(0, predicate_namespaceObject.isEqual)(signals_personalizations.value, personalizations)) signals_personalizations.value = personalizations;
1747
- });
1403
+ async screen(payload, requestOptions) {
1404
+ const { profile, ...builderArgs } = payload;
1405
+ return await this.sendExperienceEvent(this.eventBuilder.buildScreenView(builderArgs), profile, requestOptions);
1748
1406
  }
1749
- }
1750
- const personalization_PersonalizationStateful = PersonalizationStateful;
1751
- const PersonalizationStateless_logger = (0, logger_namespaceObject.createScopedLogger)('Personalization');
1752
- class PersonalizationStateless extends personalization_PersonalizationBase {
1753
- async identify(payload) {
1754
- PersonalizationStateless_logger.info('Sending "identify" event');
1407
+ async track(payload, requestOptions) {
1755
1408
  const { profile, ...builderArgs } = payload;
1756
- const event = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.IdentifyEvent, this.builder.buildIdentify(builderArgs));
1757
- return await this.upsertProfile(event, profile);
1409
+ return await this.sendExperienceEvent(this.eventBuilder.buildTrack(builderArgs), profile, requestOptions);
1758
1410
  }
1759
- async page(payload) {
1760
- PersonalizationStateless_logger.info('Sending "page" event');
1411
+ async trackView(payload, requestOptions) {
1761
1412
  const { profile, ...builderArgs } = payload;
1762
- const event = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.PageViewEvent, this.builder.buildPageView(builderArgs));
1763
- return await this.upsertProfile(event, profile);
1413
+ let result;
1414
+ let insightsProfile = profile;
1415
+ if (payload.sticky) {
1416
+ result = await this.sendExperienceEvent(this.eventBuilder.buildView(builderArgs), profile, requestOptions);
1417
+ const { profile: responseProfile } = result;
1418
+ insightsProfile = responseProfile;
1419
+ }
1420
+ await this.sendInsightsEvent(this.eventBuilder.buildView(builderArgs), requireInsightsProfile(insightsProfile, payload.sticky ? STICKY_TRACK_VIEW_PROFILE_ERROR : NON_STICKY_TRACK_VIEW_PROFILE_ERROR));
1421
+ return result;
1764
1422
  }
1765
- async screen(payload) {
1766
- PersonalizationStateless_logger.info(`Sending "screen" event for "${payload.name}"`);
1423
+ async trackClick(payload, _requestOptions) {
1767
1424
  const { profile, ...builderArgs } = payload;
1768
- const event = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.ScreenViewEvent, this.builder.buildScreenView(builderArgs));
1769
- return await this.upsertProfile(event, profile);
1425
+ await this.sendInsightsEvent(this.eventBuilder.buildClick(builderArgs), requireInsightsProfile(profile, TRACK_CLICK_PROFILE_ERROR));
1770
1426
  }
1771
- async track(payload) {
1772
- PersonalizationStateless_logger.info(`Sending "track" event "${payload.event}"`);
1427
+ async trackHover(payload, _requestOptions) {
1773
1428
  const { profile, ...builderArgs } = payload;
1774
- const event = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.TrackEvent, this.builder.buildTrack(builderArgs));
1775
- return await this.upsertProfile(event, profile);
1429
+ await this.sendInsightsEvent(this.eventBuilder.buildHover(builderArgs), requireInsightsProfile(profile, TRACK_HOVER_PROFILE_ERROR));
1776
1430
  }
1777
- async trackComponentView(payload) {
1778
- PersonalizationStateless_logger.info('Sending "track personalization" event');
1431
+ async trackFlagView(payload, _requestOptions) {
1779
1432
  const { profile, ...builderArgs } = payload;
1780
- const event = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.ComponentViewEvent, this.builder.buildComponentView(builderArgs));
1781
- return await this.upsertProfile(event, profile);
1433
+ await this.sendInsightsEvent(this.eventBuilder.buildFlagView(builderArgs), requireInsightsProfile(profile, TRACK_FLAG_VIEW_PROFILE_ERROR));
1782
1434
  }
1783
- async upsertProfile(event, profile) {
1435
+ async sendExperienceEvent(event, profile, requestOptions) {
1784
1436
  const intercepted = await this.interceptors.event.run(event);
1785
- const validEvent = (0, api_schemas_namespaceObject.parseWithFriendlyError)(api_schemas_namespaceObject.ExperienceEvent, intercepted);
1786
- const data = await this.api.experience.upsertProfile({
1437
+ const validEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.ExperienceEvent, intercepted);
1438
+ return await this.api.experience.upsertProfile({
1787
1439
  profileId: profile?.id,
1788
1440
  events: [
1789
1441
  validEvent
1790
1442
  ]
1791
- });
1792
- return data;
1443
+ }, requestOptions);
1793
1444
  }
1794
- }
1795
- const personalization_PersonalizationStateless = PersonalizationStateless;
1796
- var symbols = __webpack_require__("./src/symbols.ts");
1797
- const splitScopedQueuePolicy = (config)=>{
1798
- if (void 0 === config) return {
1799
- apiConfig: void 0,
1800
- queuePolicy: void 0
1801
- };
1802
- const { queuePolicy, ...apiConfig } = config;
1803
- const resolvedApiConfig = Object.keys(apiConfig).length > 0 ? apiConfig : void 0;
1804
- return {
1805
- apiConfig: resolvedApiConfig,
1806
- queuePolicy
1807
- };
1808
- };
1809
- let statefulInstanceCounter = 0;
1810
- class CoreStateful extends src_CoreBase {
1811
- singletonOwner;
1812
- destroyed = false;
1813
- _analytics;
1814
- _personalization;
1815
- constructor(config){
1816
- const { apiConfig: analyticsApiConfig, queuePolicy: analyticsRuntimeQueuePolicy } = splitScopedQueuePolicy(config.analytics);
1817
- const { apiConfig: personalizationApiConfig, queuePolicy: personalizationRuntimeQueuePolicy } = splitScopedQueuePolicy(config.personalization);
1818
- const baseConfig = {
1819
- ...config,
1820
- analytics: analyticsApiConfig,
1821
- personalization: personalizationApiConfig
1822
- };
1823
- super(baseConfig);
1824
- this.singletonOwner = `CoreStateful#${++statefulInstanceCounter}`;
1825
- acquireStatefulRuntimeSingleton(this.singletonOwner);
1826
- try {
1827
- const { allowedEventTypes, defaults, getAnonymousId, onEventBlocked } = config;
1828
- if (defaults?.consent !== void 0) {
1829
- const { consent: defaultConsent } = defaults;
1830
- consent.value = defaultConsent;
1445
+ async sendInsightsEvent(event, profile) {
1446
+ const intercepted = await this.interceptors.event.run(event);
1447
+ const validEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.InsightsEvent, intercepted);
1448
+ const batchEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.BatchInsightsEventArray, [
1449
+ {
1450
+ profile: (0, api_schemas_.parseWithFriendlyError)(api_schemas.PartialProfile, profile),
1451
+ events: [
1452
+ validEvent
1453
+ ]
1831
1454
  }
1832
- this._analytics = new analytics_AnalyticsStateful({
1833
- api: this.api,
1834
- builder: this.eventBuilder,
1835
- config: {
1836
- allowedEventTypes,
1837
- queuePolicy: analyticsRuntimeQueuePolicy,
1838
- onEventBlocked,
1839
- defaults: {
1840
- consent: defaults?.consent,
1841
- profile: defaults?.profile
1842
- }
1843
- },
1844
- interceptors: this.interceptors
1845
- });
1846
- this._personalization = new personalization_PersonalizationStateful({
1847
- api: this.api,
1848
- builder: this.eventBuilder,
1849
- config: {
1850
- allowedEventTypes,
1851
- getAnonymousId,
1852
- queuePolicy: personalizationRuntimeQueuePolicy,
1853
- onEventBlocked,
1854
- defaults: {
1855
- consent: defaults?.consent,
1856
- changes: defaults?.changes,
1857
- profile: defaults?.profile,
1858
- personalizations: defaults?.personalizations
1859
- }
1860
- },
1861
- interceptors: this.interceptors
1862
- });
1863
- } catch (error) {
1864
- releaseStatefulRuntimeSingleton(this.singletonOwner);
1865
- throw error;
1866
- }
1867
- }
1868
- destroy() {
1869
- if (this.destroyed) return;
1870
- this.destroyed = true;
1871
- releaseStatefulRuntimeSingleton(this.singletonOwner);
1872
- }
1873
- get states() {
1874
- return {
1875
- blockedEventStream: toObservable(blockedEvent),
1876
- consent: toObservable(consent),
1877
- eventStream: toObservable(signals_event),
1878
- flags: toObservable(flags),
1879
- personalizations: toObservable(signals_personalizations),
1880
- previewPanelAttached: toObservable(previewPanelAttached),
1881
- previewPanelOpen: toObservable(previewPanelOpen),
1882
- profile: toObservable(signals_profile)
1883
- };
1884
- }
1885
- reset() {
1886
- (0, signals_core_namespaceObject.batch)(()=>{
1887
- blockedEvent.value = void 0;
1888
- signals_event.value = void 0;
1889
- signals_changes.value = void 0;
1890
- signals_profile.value = void 0;
1891
- signals_personalizations.value = void 0;
1892
- });
1893
- }
1894
- async flush() {
1895
- await this._analytics.flush();
1896
- await this._personalization.flush();
1897
- }
1898
- consent(accept) {
1899
- consent.value = accept;
1900
- }
1901
- get online() {
1902
- return online.value ?? false;
1903
- }
1904
- set online(isOnline) {
1905
- online.value = isOnline;
1906
- }
1907
- registerPreviewPanel(previewPanel) {
1908
- Reflect.set(previewPanel, symbols.PREVIEW_PANEL_SIGNALS_SYMBOL, signals);
1909
- Reflect.set(previewPanel, symbols.PREVIEW_PANEL_SIGNAL_FNS_SYMBOL, signalFns);
1455
+ ]);
1456
+ await this.api.insights.sendBatchEvents(batchEvent);
1910
1457
  }
1911
1458
  }
1912
- const src_CoreStateful = CoreStateful;
1913
- class CoreStateless extends src_CoreBase {
1914
- _analytics;
1915
- _personalization;
1916
- constructor(config){
1917
- super(config);
1918
- this._analytics = new analytics_AnalyticsStateless({
1919
- api: this.api,
1920
- builder: this.eventBuilder,
1921
- interceptors: this.interceptors
1922
- });
1923
- this._personalization = new personalization_PersonalizationStateless({
1924
- api: this.api,
1925
- builder: this.eventBuilder,
1926
- interceptors: this.interceptors
1459
+ const src_CoreStateless = CoreStateless;
1460
+ const isFunction = (v)=>'function' == typeof v;
1461
+ const nameToString = (name)=>'string' == typeof name ? name : 'symbol' == typeof name ? name.description ?? String(name) : String(name);
1462
+ const isOnBlockedKey = (v)=>'string' == typeof v || 'symbol' == typeof v;
1463
+ const isAsyncFunction = (fn)=>'[object AsyncFunction]' === Object.prototype.toString.call(fn);
1464
+ function guardedBy(predicateName, opts) {
1465
+ return function(_value, context) {
1466
+ const decoratedName = nameToString(context.name);
1467
+ context.addInitializer(function() {
1468
+ const originalUnknown = Reflect.get(this, context.name);
1469
+ if (!isFunction(originalUnknown)) return;
1470
+ const original = originalUnknown;
1471
+ const originalIsAsync = isAsyncFunction(original);
1472
+ const resolvePredicate = (self)=>{
1473
+ const { [predicateName]: cand } = self;
1474
+ if (!isFunction(cand)) throw new TypeError(`@guardedBy expects predicate "${String(predicateName)}" to be a synchronous function.`);
1475
+ return cand;
1476
+ };
1477
+ const computeAllowed = (self, args)=>{
1478
+ const pred = resolvePredicate(self);
1479
+ const ok = Boolean(pred.call(self, decoratedName, args));
1480
+ return opts?.invert === true ? !ok : ok;
1481
+ };
1482
+ const runOnBlocked = (self, args)=>{
1483
+ const { onBlocked } = opts ?? {};
1484
+ if (void 0 === onBlocked) return;
1485
+ if (isFunction(onBlocked)) return void onBlocked.call(self, decoratedName, args);
1486
+ if (isOnBlockedKey(onBlocked)) {
1487
+ const { [onBlocked]: handlerCandidate } = self;
1488
+ if (isFunction(handlerCandidate)) handlerCandidate.call(self, decoratedName, args);
1489
+ }
1490
+ };
1491
+ const blockedReturn = ()=>originalIsAsync ? Promise.resolve(void 0) : void 0;
1492
+ const wrapped = function(...args) {
1493
+ if (!computeAllowed(this, args)) {
1494
+ runOnBlocked(this, args);
1495
+ return blockedReturn();
1496
+ }
1497
+ return original.call(this, ...args);
1498
+ };
1499
+ Reflect.set(this, context.name, wrapped);
1927
1500
  });
1928
- }
1501
+ };
1929
1502
  }
1930
- const src_CoreStateless = CoreStateless;
1931
1503
  })();
1932
1504
  exports.ANONYMOUS_ID_COOKIE = __webpack_exports__.ANONYMOUS_ID_COOKIE;
1933
1505
  exports.ANONYMOUS_ID_COOKIE_LEGACY = __webpack_exports__.ANONYMOUS_ID_COOKIE_LEGACY;
1934
1506
  exports.ANONYMOUS_ID_KEY = __webpack_exports__.ANONYMOUS_ID_KEY;
1935
1507
  exports.ANONYMOUS_ID_KEY_LEGACY = __webpack_exports__.ANONYMOUS_ID_KEY_LEGACY;
1936
- exports.AnalyticsStateful = __webpack_exports__.AnalyticsStateful;
1937
- exports.AnalyticsStateless = __webpack_exports__.AnalyticsStateless;
1938
1508
  exports.CHANGES_CACHE_KEY = __webpack_exports__.CHANGES_CACHE_KEY;
1939
1509
  exports.CONSENT_KEY = __webpack_exports__.CONSENT_KEY;
1510
+ exports.ClickBuilderArgs = __webpack_exports__.ClickBuilderArgs;
1940
1511
  exports.CoreStateful = __webpack_exports__.CoreStateful;
1941
1512
  exports.CoreStateless = __webpack_exports__.CoreStateless;
1942
1513
  exports.DEBUG_FLAG_KEY = __webpack_exports__.DEBUG_FLAG_KEY;
1514
+ exports.DEFAULT_PAGE_PROPERTIES = __webpack_exports__.DEFAULT_PAGE_PROPERTIES;
1515
+ exports.EntryInteractionBuilderArgsBase = __webpack_exports__.EntryInteractionBuilderArgsBase;
1516
+ exports.EventBuilder = __webpack_exports__.EventBuilder;
1517
+ exports.FlagViewBuilderArgs = __webpack_exports__.FlagViewBuilderArgs;
1943
1518
  exports.FlagsResolver = __webpack_exports__.FlagsResolver;
1519
+ exports.HoverBuilderArgs = __webpack_exports__.HoverBuilderArgs;
1520
+ exports.IdentifyBuilderArgs = __webpack_exports__.IdentifyBuilderArgs;
1944
1521
  exports.InterceptorManager = __webpack_exports__.InterceptorManager;
1945
1522
  exports.MergeTagValueResolver = __webpack_exports__.MergeTagValueResolver;
1946
1523
  exports.OPTIMIZATION_CORE_SDK_NAME = __webpack_exports__.OPTIMIZATION_CORE_SDK_NAME;
1947
1524
  exports.OPTIMIZATION_CORE_SDK_VERSION = __webpack_exports__.OPTIMIZATION_CORE_SDK_VERSION;
1948
- exports.PERSONALIZATIONS_CACHE_KEY = __webpack_exports__.PERSONALIZATIONS_CACHE_KEY;
1525
+ exports.OptimizedEntryResolver = __webpack_exports__.OptimizedEntryResolver;
1949
1526
  exports.PREVIEW_PANEL_SIGNALS_SYMBOL = __webpack_exports__.PREVIEW_PANEL_SIGNALS_SYMBOL;
1950
1527
  exports.PREVIEW_PANEL_SIGNAL_FNS_SYMBOL = __webpack_exports__.PREVIEW_PANEL_SIGNAL_FNS_SYMBOL;
1951
1528
  exports.PROFILE_CACHE_KEY = __webpack_exports__.PROFILE_CACHE_KEY;
1952
- exports.PersonalizationBase = __webpack_exports__.PersonalizationBase;
1953
- exports.PersonalizationStateful = __webpack_exports__.PersonalizationStateful;
1954
- exports.PersonalizationStateless = __webpack_exports__.PersonalizationStateless;
1955
- exports.PersonalizedEntryResolver = __webpack_exports__.PersonalizedEntryResolver;
1529
+ exports.PageViewBuilderArgs = __webpack_exports__.PageViewBuilderArgs;
1530
+ exports.SELECTED_OPTIMIZATIONS_CACHE_KEY = __webpack_exports__.SELECTED_OPTIMIZATIONS_CACHE_KEY;
1531
+ exports.ScreenViewBuilderArgs = __webpack_exports__.ScreenViewBuilderArgs;
1532
+ exports.TrackBuilderArgs = __webpack_exports__.TrackBuilderArgs;
1533
+ exports.UniversalEventBuilderArgs = __webpack_exports__.UniversalEventBuilderArgs;
1534
+ exports.ViewBuilderArgs = __webpack_exports__.ViewBuilderArgs;
1956
1535
  exports.batch = __webpack_exports__.batch;
1957
1536
  exports.effect = __webpack_exports__.effect;
1958
1537
  exports.guardedBy = __webpack_exports__.guardedBy;
1959
1538
  exports.signalFns = __webpack_exports__.signalFns;
1960
1539
  exports.signals = __webpack_exports__.signals;
1540
+ exports.toDistinctObservable = __webpack_exports__.toDistinctObservable;
1541
+ exports.toObservable = __webpack_exports__.toObservable;
1961
1542
  for(var __rspack_i in __webpack_exports__)if (-1 === [
1962
1543
  "ANONYMOUS_ID_COOKIE",
1963
1544
  "ANONYMOUS_ID_COOKIE_LEGACY",
1964
1545
  "ANONYMOUS_ID_KEY",
1965
1546
  "ANONYMOUS_ID_KEY_LEGACY",
1966
- "AnalyticsStateful",
1967
- "AnalyticsStateless",
1968
1547
  "CHANGES_CACHE_KEY",
1969
1548
  "CONSENT_KEY",
1549
+ "ClickBuilderArgs",
1970
1550
  "CoreStateful",
1971
1551
  "CoreStateless",
1972
1552
  "DEBUG_FLAG_KEY",
1553
+ "DEFAULT_PAGE_PROPERTIES",
1554
+ "EntryInteractionBuilderArgsBase",
1555
+ "EventBuilder",
1556
+ "FlagViewBuilderArgs",
1973
1557
  "FlagsResolver",
1558
+ "HoverBuilderArgs",
1559
+ "IdentifyBuilderArgs",
1974
1560
  "InterceptorManager",
1975
1561
  "MergeTagValueResolver",
1976
1562
  "OPTIMIZATION_CORE_SDK_NAME",
1977
1563
  "OPTIMIZATION_CORE_SDK_VERSION",
1978
- "PERSONALIZATIONS_CACHE_KEY",
1564
+ "OptimizedEntryResolver",
1979
1565
  "PREVIEW_PANEL_SIGNALS_SYMBOL",
1980
1566
  "PREVIEW_PANEL_SIGNAL_FNS_SYMBOL",
1981
1567
  "PROFILE_CACHE_KEY",
1982
- "PersonalizationBase",
1983
- "PersonalizationStateful",
1984
- "PersonalizationStateless",
1985
- "PersonalizedEntryResolver",
1568
+ "PageViewBuilderArgs",
1569
+ "SELECTED_OPTIMIZATIONS_CACHE_KEY",
1570
+ "ScreenViewBuilderArgs",
1571
+ "TrackBuilderArgs",
1572
+ "UniversalEventBuilderArgs",
1573
+ "ViewBuilderArgs",
1986
1574
  "batch",
1987
1575
  "effect",
1988
1576
  "guardedBy",
1989
1577
  "signalFns",
1990
- "signals"
1578
+ "signals",
1579
+ "toDistinctObservable",
1580
+ "toObservable"
1991
1581
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
1992
1582
  Object.defineProperty(exports, '__esModule', {
1993
1583
  value: true