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

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-alpha11";
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,339 @@ 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,
127
+ CoreStatelessRequestScope: ()=>CoreStatelessRequestScope,
98
128
  PREVIEW_PANEL_SIGNALS_SYMBOL: ()=>symbols.PREVIEW_PANEL_SIGNALS_SYMBOL,
99
129
  guardedBy: ()=>guardedBy,
100
130
  CHANGES_CACHE_KEY: ()=>constants.CHANGES_CACHE_KEY,
101
- PersonalizationBase: ()=>personalization_PersonalizationBase
131
+ EventBuilder: ()=>events_EventBuilder
102
132
  });
103
133
  const signals_core_namespaceObject = require("@preact/signals-core");
134
+ const external_es_toolkit_namespaceObject = require("es-toolkit");
135
+ function isNonNullish(value) {
136
+ return null != value;
137
+ }
138
+ function toError(value) {
139
+ if (value instanceof Error) return value;
140
+ return new Error(`Subscriber threw non-Error value: ${String(value)}`);
141
+ }
142
+ function toObservable(s) {
143
+ return {
144
+ get current () {
145
+ return (0, external_es_toolkit_namespaceObject.cloneDeep)(s.value);
146
+ },
147
+ subscribe (next) {
148
+ const dispose = (0, signals_core_namespaceObject.effect)(()=>{
149
+ next((0, external_es_toolkit_namespaceObject.cloneDeep)(s.value));
150
+ });
151
+ return {
152
+ unsubscribe: dispose
153
+ };
154
+ },
155
+ subscribeOnce (next) {
156
+ let closed = false;
157
+ let isEffectActive = false;
158
+ let dispose = ()=>void 0;
159
+ const stop = ()=>{
160
+ if (closed) return;
161
+ closed = true;
162
+ if (isEffectActive) dispose();
163
+ };
164
+ dispose = (0, signals_core_namespaceObject.effect)(()=>{
165
+ if (closed) return;
166
+ const { value } = s;
167
+ if (!isNonNullish(value)) return;
168
+ closed = true;
169
+ let callbackError = null;
170
+ try {
171
+ next((0, external_es_toolkit_namespaceObject.cloneDeep)(value));
172
+ } catch (error) {
173
+ callbackError = toError(error);
174
+ }
175
+ if (isEffectActive) dispose();
176
+ else queueMicrotask(dispose);
177
+ if (callbackError) throw callbackError;
178
+ });
179
+ isEffectActive = true;
180
+ return {
181
+ unsubscribe: stop
182
+ };
183
+ }
184
+ };
185
+ }
186
+ function toDistinctObservable(s, isEqual) {
187
+ const observable = toObservable(s);
188
+ return {
189
+ get current () {
190
+ return observable.current;
191
+ },
192
+ subscribe (next) {
193
+ let hasPrevious = false;
194
+ let previous = (0, external_es_toolkit_namespaceObject.cloneDeep)(observable.current);
195
+ return observable.subscribe((value)=>{
196
+ if (hasPrevious && isEqual(previous, value)) return;
197
+ hasPrevious = true;
198
+ previous = (0, external_es_toolkit_namespaceObject.cloneDeep)(value);
199
+ next(value);
200
+ });
201
+ },
202
+ subscribeOnce (next) {
203
+ return observable.subscribeOnce(next);
204
+ }
205
+ };
206
+ }
207
+ const signals_changes = (0, signals_core_namespaceObject.signal)();
208
+ const blockedEvent = (0, signals_core_namespaceObject.signal)();
209
+ const consent = (0, signals_core_namespaceObject.signal)();
210
+ const signals_event = (0, signals_core_namespaceObject.signal)();
211
+ const online = (0, signals_core_namespaceObject.signal)(true);
212
+ const previewPanelAttached = (0, signals_core_namespaceObject.signal)(false);
213
+ const previewPanelOpen = (0, signals_core_namespaceObject.signal)(false);
214
+ const signals_selectedOptimizations = (0, signals_core_namespaceObject.signal)();
215
+ const canOptimize = (0, signals_core_namespaceObject.computed)(()=>void 0 !== signals_selectedOptimizations.value);
216
+ const signals_profile = (0, signals_core_namespaceObject.signal)();
217
+ const signals = {
218
+ blockedEvent,
219
+ changes: signals_changes,
220
+ consent,
221
+ event: signals_event,
222
+ online,
223
+ previewPanelAttached,
224
+ previewPanelOpen,
225
+ selectedOptimizations: signals_selectedOptimizations,
226
+ canOptimize,
227
+ profile: signals_profile
228
+ };
229
+ const signalFns = {
230
+ batch: signals_core_namespaceObject.batch,
231
+ computed: signals_core_namespaceObject.computed,
232
+ effect: signals_core_namespaceObject.effect,
233
+ untracked: signals_core_namespaceObject.untracked
234
+ };
235
+ var constants = __webpack_require__("./src/constants.ts");
236
+ const optimization_api_client_namespaceObject = require("@contentful/optimization-api-client");
237
+ const logger_namespaceObject = require("@contentful/optimization-api-client/logger");
238
+ var api_schemas_ = __webpack_require__("@contentful/optimization-api-client/api-schemas");
239
+ const object_namespaceObject = require("es-toolkit/object");
240
+ const mini_namespaceObject = require("zod/mini");
241
+ const UniversalEventBuilderArgs = mini_namespaceObject.object({
242
+ campaign: mini_namespaceObject.optional(api_schemas_.Campaign),
243
+ locale: mini_namespaceObject.optional(mini_namespaceObject.string()),
244
+ location: mini_namespaceObject.optional(api_schemas_.GeoLocation),
245
+ page: mini_namespaceObject.optional(api_schemas_.Page),
246
+ screen: mini_namespaceObject.optional(api_schemas_.Screen),
247
+ userAgent: mini_namespaceObject.optional(mini_namespaceObject.string())
248
+ });
249
+ const EntryInteractionBuilderArgsBase = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
250
+ componentId: mini_namespaceObject.string(),
251
+ experienceId: mini_namespaceObject.optional(mini_namespaceObject.string()),
252
+ variantIndex: mini_namespaceObject.optional(mini_namespaceObject.number())
253
+ });
254
+ const ViewBuilderArgs = mini_namespaceObject.extend(EntryInteractionBuilderArgsBase, {
255
+ sticky: mini_namespaceObject.optional(mini_namespaceObject.boolean()),
256
+ viewId: mini_namespaceObject.string(),
257
+ viewDurationMs: mini_namespaceObject.number()
258
+ });
259
+ const FlagViewBuilderArgs = mini_namespaceObject.extend(EntryInteractionBuilderArgsBase, {
260
+ viewId: mini_namespaceObject.optional(mini_namespaceObject.string()),
261
+ viewDurationMs: mini_namespaceObject.optional(mini_namespaceObject.number())
262
+ });
263
+ const ClickBuilderArgs = EntryInteractionBuilderArgsBase;
264
+ const HoverBuilderArgs = mini_namespaceObject.extend(EntryInteractionBuilderArgsBase, {
265
+ hoverId: mini_namespaceObject.string(),
266
+ hoverDurationMs: mini_namespaceObject.number()
267
+ });
268
+ const IdentifyBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
269
+ traits: mini_namespaceObject.optional(api_schemas_.Traits),
270
+ userId: mini_namespaceObject.string()
271
+ });
272
+ const PageViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
273
+ properties: mini_namespaceObject.optional(mini_namespaceObject.partial(api_schemas_.Page))
274
+ });
275
+ const ScreenViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
276
+ name: mini_namespaceObject.string(),
277
+ properties: api_schemas_.Properties
278
+ });
279
+ const TrackBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
280
+ event: mini_namespaceObject.string(),
281
+ properties: mini_namespaceObject.optional(mini_namespaceObject.prefault(api_schemas_.Properties, {}))
282
+ });
283
+ const DEFAULT_PAGE_PROPERTIES = {
284
+ path: '',
285
+ query: {},
286
+ referrer: '',
287
+ search: '',
288
+ title: '',
289
+ url: ''
290
+ };
291
+ class EventBuilder {
292
+ app;
293
+ channel;
294
+ library;
295
+ getLocale;
296
+ getPageProperties;
297
+ getUserAgent;
298
+ constructor(config){
299
+ const { app, channel, library, getLocale, getPageProperties, getUserAgent } = config;
300
+ this.app = app;
301
+ this.channel = channel;
302
+ this.library = library;
303
+ this.getLocale = getLocale ?? (()=>'en-US');
304
+ this.getPageProperties = getPageProperties ?? (()=>DEFAULT_PAGE_PROPERTIES);
305
+ this.getUserAgent = getUserAgent ?? (()=>void 0);
306
+ }
307
+ buildUniversalEventProperties({ campaign = {}, locale, location, page, screen, userAgent }) {
308
+ const timestamp = new Date().toISOString();
309
+ return {
310
+ channel: this.channel,
311
+ context: {
312
+ app: this.app,
313
+ campaign,
314
+ gdpr: {
315
+ isConsentGiven: true
316
+ },
317
+ library: this.library,
318
+ locale: locale ?? this.getLocale() ?? 'en-US',
319
+ location,
320
+ page: page ?? this.getPageProperties(),
321
+ screen,
322
+ userAgent: userAgent ?? this.getUserAgent()
323
+ },
324
+ messageId: crypto.randomUUID(),
325
+ originalTimestamp: timestamp,
326
+ sentAt: timestamp,
327
+ timestamp
328
+ };
329
+ }
330
+ buildEntryInteractionBase(universal, componentId, experienceId, variantIndex) {
331
+ return {
332
+ ...this.buildUniversalEventProperties(universal),
333
+ componentType: 'Entry',
334
+ componentId,
335
+ experienceId,
336
+ variantIndex: variantIndex ?? 0
337
+ };
338
+ }
339
+ buildView(args) {
340
+ const { componentId, viewId, experienceId, variantIndex, viewDurationMs, ...universal } = (0, api_schemas_.parseWithFriendlyError)(ViewBuilderArgs, args);
341
+ return {
342
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
343
+ type: 'component',
344
+ viewId,
345
+ viewDurationMs
346
+ };
347
+ }
348
+ buildClick(args) {
349
+ const { componentId, experienceId, variantIndex, ...universal } = (0, api_schemas_.parseWithFriendlyError)(ClickBuilderArgs, args);
350
+ return {
351
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
352
+ type: 'component_click'
353
+ };
354
+ }
355
+ buildHover(args) {
356
+ const { hoverId, componentId, experienceId, hoverDurationMs, variantIndex, ...universal } = (0, api_schemas_.parseWithFriendlyError)(HoverBuilderArgs, args);
357
+ return {
358
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
359
+ type: 'component_hover',
360
+ hoverId,
361
+ hoverDurationMs
362
+ };
363
+ }
364
+ buildFlagView(args) {
365
+ const { componentId, experienceId, variantIndex, viewId, viewDurationMs, ...universal } = (0, api_schemas_.parseWithFriendlyError)(FlagViewBuilderArgs, args);
366
+ return {
367
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
368
+ ...void 0 === viewDurationMs ? {} : {
369
+ viewDurationMs
370
+ },
371
+ ...void 0 === viewId ? {} : {
372
+ viewId
373
+ },
374
+ type: 'component',
375
+ componentType: 'Variable'
376
+ };
377
+ }
378
+ buildIdentify(args) {
379
+ const { traits = {}, userId, ...universal } = (0, api_schemas_.parseWithFriendlyError)(IdentifyBuilderArgs, args);
380
+ return {
381
+ ...this.buildUniversalEventProperties(universal),
382
+ type: 'identify',
383
+ traits,
384
+ userId
385
+ };
386
+ }
387
+ buildPageView(args = {}) {
388
+ const { properties = {}, ...universal } = (0, api_schemas_.parseWithFriendlyError)(PageViewBuilderArgs, args);
389
+ const pageProperties = this.getPageProperties();
390
+ const merged = (0, object_namespaceObject.merge)({
391
+ ...pageProperties,
392
+ title: pageProperties.title ?? DEFAULT_PAGE_PROPERTIES.title
393
+ }, properties);
394
+ const { context: { screen: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
395
+ const context = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.PageEventContext, universalContext);
396
+ return {
397
+ ...universalProperties,
398
+ context,
399
+ type: 'page',
400
+ properties: merged
401
+ };
402
+ }
403
+ buildScreenView(args) {
404
+ const { name, properties, ...universal } = (0, api_schemas_.parseWithFriendlyError)(ScreenViewBuilderArgs, args);
405
+ const { context: { page: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
406
+ const context = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.ScreenEventContext, universalContext);
407
+ return {
408
+ ...universalProperties,
409
+ context,
410
+ type: 'screen',
411
+ name,
412
+ properties
413
+ };
414
+ }
415
+ buildTrack(args) {
416
+ const { event, properties = {}, ...universal } = (0, api_schemas_.parseWithFriendlyError)(TrackBuilderArgs, args);
417
+ return {
418
+ ...this.buildUniversalEventProperties(universal),
419
+ type: 'track',
420
+ event,
421
+ properties
422
+ };
423
+ }
424
+ }
425
+ const events_EventBuilder = EventBuilder;
426
+ class InterceptorManager {
427
+ interceptors = new Map();
428
+ nextId = 0;
429
+ add(interceptor) {
430
+ const { nextId: id } = this;
431
+ this.nextId += 1;
432
+ this.interceptors.set(id, interceptor);
433
+ return id;
434
+ }
435
+ remove(id) {
436
+ return this.interceptors.delete(id);
437
+ }
438
+ clear() {
439
+ this.interceptors.clear();
440
+ }
441
+ count() {
442
+ return this.interceptors.size;
443
+ }
444
+ async run(input) {
445
+ const fns = Array.from(this.interceptors.values());
446
+ let acc = input;
447
+ for (const fn of fns)acc = await fn((0, external_es_toolkit_namespaceObject.cloneDeep)(acc));
448
+ return acc;
449
+ }
450
+ }
104
451
  const FlagsResolver = {
105
452
  resolve (changes) {
106
453
  if (!changes) return {};
@@ -112,9 +459,7 @@ var __webpack_exports__ = {};
112
459
  }
113
460
  };
114
461
  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');
462
+ const logger = (0, logger_namespaceObject.createScopedLogger)('Optimization');
118
463
  const RESOLUTION_WARNING_BASE = 'Could not resolve Merge Tag value:';
119
464
  const getAtPath = (value, path)=>{
120
465
  if (!value || 'object' != typeof value) return;
@@ -147,9 +492,9 @@ var __webpack_exports__ = {};
147
492
  return `${value}`;
148
493
  },
149
494
  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`);
495
+ if (!(0, api_schemas_.isMergeTagEntry)(mergeTagEntry)) return void logger.warn(`${RESOLUTION_WARNING_BASE} supplied entry is not a Merge Tag entry`);
151
496
  const { fields: { nt_fallback: fallback } } = mergeTagEntry;
152
- if (!api_schemas_namespaceObject.Profile.safeParse(profile).success) {
497
+ if (!api_schemas_.Profile.safeParse(profile).success) {
153
498
  logger.warn(`${RESOLUTION_WARNING_BASE} no valid profile`);
154
499
  return fallback;
155
500
  }
@@ -157,177 +502,285 @@ var __webpack_exports__ = {};
157
502
  }
158
503
  };
159
504
  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;
505
+ const OptimizedEntryResolver_logger = (0, logger_namespaceObject.createScopedLogger)('Optimization');
506
+ const OptimizedEntryResolver_RESOLUTION_WARNING_BASE = 'Could not resolve optimized entry variant:';
507
+ function resolve(entry, selectedOptimizations) {
508
+ OptimizedEntryResolver_logger.debug(`Resolving optimized entry for baseline entry ${entry.sys.id}`);
509
+ if (!selectedOptimizations?.length) {
510
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} no selectedOptimizations exist for the current profile`);
511
+ return {
512
+ entry
513
+ };
514
+ }
515
+ if (!(0, api_schemas_.isOptimizedEntry)(entry)) {
516
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} entry ${entry.sys.id} is not optimized`);
517
+ return {
518
+ entry
519
+ };
520
+ }
521
+ const optimizationEntry = OptimizedEntryResolver.getOptimizationEntry({
522
+ optimizedEntry: entry,
523
+ selectedOptimizations
524
+ }, true);
525
+ if (!optimizationEntry) {
526
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find an optimization entry for ${entry.sys.id}`);
527
+ return {
528
+ entry
529
+ };
530
+ }
531
+ const selectedOptimization = OptimizedEntryResolver.getSelectedOptimization({
532
+ optimizationEntry,
533
+ selectedOptimizations
534
+ }, true);
535
+ const selectedVariantIndex = selectedOptimization?.variantIndex ?? 0;
536
+ if (0 === selectedVariantIndex) {
537
+ OptimizedEntryResolver_logger.debug(`Resolved optimization entry for entry ${entry.sys.id} is baseline`);
538
+ return {
539
+ entry
540
+ };
541
+ }
542
+ const selectedVariant = OptimizedEntryResolver.getSelectedVariant({
543
+ optimizedEntry: entry,
544
+ optimizationEntry,
545
+ selectedVariantIndex
546
+ }, true);
547
+ if (!selectedVariant) {
548
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
549
+ return {
550
+ entry
551
+ };
552
+ }
553
+ const selectedVariantEntry = OptimizedEntryResolver.getSelectedVariantEntry({
554
+ optimizationEntry,
555
+ selectedVariant
556
+ }, true);
557
+ if (selectedVariantEntry) OptimizedEntryResolver_logger.debug(`Entry ${entry.sys.id} has been resolved to variant entry ${selectedVariantEntry.sys.id}`);
558
+ else {
559
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
560
+ return {
561
+ entry
562
+ };
563
+ }
564
+ return {
565
+ entry: selectedVariantEntry,
566
+ selectedOptimization
567
+ };
568
+ }
569
+ const OptimizedEntryResolver = {
570
+ getOptimizationEntry ({ optimizedEntry, selectedOptimizations }, skipValidation = false) {
571
+ if (!skipValidation && (!selectedOptimizations.length || !(0, api_schemas_.isOptimizedEntry)(optimizedEntry))) return;
572
+ const optimizationEntry = optimizedEntry.fields.nt_experiences.filter((maybeOptimization)=>(0, api_schemas_.isOptimizationEntry)(maybeOptimization)).find((optimizationEntry)=>selectedOptimizations.some(({ experienceId })=>experienceId === optimizationEntry.fields.nt_experience_id));
573
+ return optimizationEntry;
167
574
  },
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;
575
+ getSelectedOptimization ({ optimizationEntry, selectedOptimizations }, skipValidation = false) {
576
+ if (!skipValidation && (!selectedOptimizations.length || !(0, api_schemas_.isOptimizationEntry)(optimizationEntry))) return;
577
+ const selectedOptimization = selectedOptimizations.find(({ experienceId })=>experienceId === optimizationEntry.fields.nt_experience_id);
578
+ return selectedOptimization;
172
579
  },
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;
580
+ getSelectedVariant ({ optimizedEntry, optimizationEntry, selectedVariantIndex }, skipValidation = false) {
581
+ if (!skipValidation && (!(0, api_schemas_.isOptimizedEntry)(optimizedEntry) || !(0, api_schemas_.isOptimizationEntry)(optimizationEntry))) return;
582
+ 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
583
  if (!relevantVariants?.length) return;
177
584
  return relevantVariants.at(selectedVariantIndex - 1);
178
585
  },
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;
586
+ getSelectedVariantEntry ({ optimizationEntry, selectedVariant }, skipValidation = false) {
587
+ if (!skipValidation && (!(0, api_schemas_.isOptimizationEntry)(optimizationEntry) || !(0, api_schemas_.isEntryReplacementVariant)(selectedVariant))) return;
588
+ const selectedVariantEntry = optimizationEntry.fields.nt_variants?.find((variant)=>variant.sys.id === selectedVariant.id);
589
+ return (0, api_schemas_.isEntry)(selectedVariantEntry) ? selectedVariantEntry : void 0;
183
590
  },
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
- }
591
+ resolve
246
592
  };
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
- }
593
+ const resolvers_OptimizedEntryResolver = OptimizedEntryResolver;
594
+ class CoreBase {
595
+ api;
596
+ eventBuilder;
597
+ config;
598
+ flagsResolver = resolvers_FlagsResolver;
599
+ mergeTagValueResolver = resolvers_MergeTagValueResolver;
600
+ optimizedEntryResolver = resolvers_OptimizedEntryResolver;
601
+ interceptors = {
602
+ event: new InterceptorManager(),
603
+ state: new InterceptorManager()
268
604
  };
605
+ constructor(config, api = {}){
606
+ this.config = config;
607
+ const { eventBuilder, logLevel, environment, clientId, fetchOptions } = config;
608
+ logger_namespaceObject.logger.addSink(new logger_namespaceObject.ConsoleLogSink(logLevel));
609
+ const apiConfig = {
610
+ clientId,
611
+ environment,
612
+ fetchOptions,
613
+ experience: api.experience,
614
+ insights: api.insights
615
+ };
616
+ this.api = new optimization_api_client_namespaceObject.ApiClient(apiConfig);
617
+ this.eventBuilder = new events_EventBuilder(eventBuilder ?? {
618
+ channel: 'server',
619
+ library: {
620
+ name: constants.OPTIMIZATION_CORE_SDK_NAME,
621
+ version: constants.OPTIMIZATION_CORE_SDK_VERSION
622
+ }
623
+ });
624
+ }
625
+ getFlag(name, changes) {
626
+ return this.flagsResolver.resolve(changes)[name];
627
+ }
628
+ resolveOptimizedEntry(entry, selectedOptimizations) {
629
+ return this.optimizedEntryResolver.resolve(entry, selectedOptimizations);
630
+ }
631
+ getMergeTagValue(embeddedEntryNodeTarget, profile) {
632
+ return this.mergeTagValueResolver.resolve(embeddedEntryNodeTarget, profile);
633
+ }
269
634
  }
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
635
+ const src_CoreBase = CoreBase;
636
+ const predicate_namespaceObject = require("es-toolkit/predicate");
637
+ const coreLogger = (0, logger_namespaceObject.createScopedLogger)('CoreStateful');
638
+ const CONSENT_EVENT_TYPE_MAP = {
639
+ trackView: 'component',
640
+ trackFlagView: 'component',
641
+ trackClick: 'component_click',
642
+ trackHover: 'component_hover'
287
643
  };
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);
644
+ class CoreStatefulEventEmitter extends src_CoreBase {
645
+ flagObservables = new Map();
646
+ getFlag(name, changes = signals_changes.value) {
647
+ const value = super.getFlag(name, changes);
648
+ const payload = this.buildFlagViewBuilderArgs(name, changes);
649
+ this.trackFlagView(payload).catch((error)=>{
650
+ logger_namespaceObject.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
328
651
  });
329
- };
652
+ return value;
653
+ }
654
+ resolveOptimizedEntry(entry, selectedOptimizations = signals_selectedOptimizations.value) {
655
+ return super.resolveOptimizedEntry(entry, selectedOptimizations);
656
+ }
657
+ getMergeTagValue(embeddedEntryNodeTarget, profile = signals_profile.value) {
658
+ return super.getMergeTagValue(embeddedEntryNodeTarget, profile);
659
+ }
660
+ async identify(payload) {
661
+ const { profile, ...builderArgs } = payload;
662
+ return await this.sendExperienceEvent('identify', [
663
+ payload
664
+ ], this.eventBuilder.buildIdentify(builderArgs), profile);
665
+ }
666
+ async page(payload = {}) {
667
+ const { profile, ...builderArgs } = payload;
668
+ return await this.sendExperienceEvent('page', [
669
+ payload
670
+ ], this.eventBuilder.buildPageView(builderArgs), profile);
671
+ }
672
+ async screen(payload) {
673
+ const { profile, ...builderArgs } = payload;
674
+ return await this.sendExperienceEvent('screen', [
675
+ payload
676
+ ], this.eventBuilder.buildScreenView(builderArgs), profile);
677
+ }
678
+ async track(payload) {
679
+ const { profile, ...builderArgs } = payload;
680
+ return await this.sendExperienceEvent('track', [
681
+ payload
682
+ ], this.eventBuilder.buildTrack(builderArgs), profile);
683
+ }
684
+ async trackView(payload) {
685
+ const { profile, ...builderArgs } = payload;
686
+ let result;
687
+ if (payload.sticky) result = await this.sendExperienceEvent('trackView', [
688
+ payload
689
+ ], this.eventBuilder.buildView(builderArgs), profile);
690
+ await this.sendInsightsEvent('trackView', [
691
+ payload
692
+ ], this.eventBuilder.buildView(builderArgs), profile);
693
+ return result;
694
+ }
695
+ async trackClick(payload) {
696
+ await this.sendInsightsEvent('trackClick', [
697
+ payload
698
+ ], this.eventBuilder.buildClick(payload));
699
+ }
700
+ async trackHover(payload) {
701
+ await this.sendInsightsEvent('trackHover', [
702
+ payload
703
+ ], this.eventBuilder.buildHover(payload));
704
+ }
705
+ async trackFlagView(payload) {
706
+ await this.sendInsightsEvent('trackFlagView', [
707
+ payload
708
+ ], this.eventBuilder.buildFlagView(payload));
709
+ }
710
+ hasConsent(name) {
711
+ const { [name]: mappedEventType } = CONSENT_EVENT_TYPE_MAP;
712
+ const isAllowed = void 0 !== mappedEventType ? this.allowedEventTypes.includes(mappedEventType) : this.allowedEventTypes.some((eventType)=>eventType === name);
713
+ return !!consent.value || isAllowed;
714
+ }
715
+ onBlockedByConsent(name, args) {
716
+ coreLogger.warn(`Event "${name}" was blocked due to lack of consent; payload: ${JSON.stringify(args)}`);
717
+ this.reportBlockedEvent('consent', name, args);
718
+ }
719
+ async sendExperienceEvent(method, args, event, _profile) {
720
+ if (!this.hasConsent(method)) return void this.onBlockedByConsent(method, args);
721
+ return await this.experienceQueue.send(event);
722
+ }
723
+ async sendInsightsEvent(method, args, event, _profile) {
724
+ if (!this.hasConsent(method)) return void this.onBlockedByConsent(method, args);
725
+ await this.insightsQueue.send(event);
726
+ }
727
+ buildFlagViewBuilderArgs(name, changes = signals_changes.value) {
728
+ const change = changes?.find((candidate)=>candidate.key === name);
729
+ return {
730
+ componentId: name,
731
+ experienceId: change?.meta.experienceId,
732
+ variantIndex: change?.meta.variantIndex
733
+ };
734
+ }
735
+ getFlagObservable(name) {
736
+ const existingObservable = this.flagObservables.get(name);
737
+ if (existingObservable) return existingObservable;
738
+ const trackFlagView = this.trackFlagView.bind(this);
739
+ const buildFlagViewBuilderArgs = this.buildFlagViewBuilderArgs.bind(this);
740
+ const valueSignal = signalFns.computed(()=>super.getFlag(name, signals_changes.value));
741
+ const distinctObservable = toDistinctObservable(valueSignal, predicate_namespaceObject.isEqual);
742
+ const trackedObservable = {
743
+ get current () {
744
+ const { current: value } = distinctObservable;
745
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
746
+ trackFlagView(payload).catch((error)=>{
747
+ logger_namespaceObject.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
748
+ });
749
+ return value;
750
+ },
751
+ subscribe: (next)=>distinctObservable.subscribe((value)=>{
752
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
753
+ trackFlagView(payload).catch((error)=>{
754
+ logger_namespaceObject.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
755
+ });
756
+ next(value);
757
+ }),
758
+ subscribeOnce: (next)=>distinctObservable.subscribeOnce((value)=>{
759
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
760
+ trackFlagView(payload).catch((error)=>{
761
+ logger_namespaceObject.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
762
+ });
763
+ next(value);
764
+ })
765
+ };
766
+ this.flagObservables.set(name, trackedObservable);
767
+ return trackedObservable;
768
+ }
769
+ reportBlockedEvent(reason, method, args) {
770
+ const event = {
771
+ reason,
772
+ method,
773
+ args
774
+ };
775
+ try {
776
+ this.onEventBlocked?.(event);
777
+ } catch (error) {
778
+ coreLogger.warn(`onEventBlocked callback failed for method "${method}"`, error);
779
+ }
780
+ blockedEvent.value = event;
781
+ }
330
782
  }
783
+ const src_CoreStatefulEventEmitter = CoreStatefulEventEmitter;
331
784
  const toPositiveInt = (value, fallback)=>{
332
785
  if (!Number.isFinite(value) || void 0 === value || value < 1) return fallback;
333
786
  return Math.floor(value);
@@ -337,6 +790,7 @@ var __webpack_exports__ = {};
337
790
  return Math.min(1, Math.max(0, value));
338
791
  };
339
792
  const DEFAULT_QUEUE_FLUSH_POLICY = {
793
+ flushIntervalMs: 30000,
340
794
  baseBackoffMs: 500,
341
795
  maxBackoffMs: 30000,
342
796
  jitterRatio: 0.2,
@@ -344,17 +798,19 @@ var __webpack_exports__ = {};
344
798
  circuitOpenMs: 120000
345
799
  };
346
800
  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));
801
+ const configuredPolicy = policy ?? {};
802
+ const baseBackoffMs = toPositiveInt(configuredPolicy.baseBackoffMs, defaults.baseBackoffMs);
803
+ const maxBackoffMs = Math.max(baseBackoffMs, toPositiveInt(configuredPolicy.maxBackoffMs, defaults.maxBackoffMs));
349
804
  return {
805
+ flushIntervalMs: toPositiveInt(configuredPolicy.flushIntervalMs, defaults.flushIntervalMs),
350
806
  baseBackoffMs,
351
807
  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
808
+ jitterRatio: toRatio(configuredPolicy.jitterRatio, defaults.jitterRatio),
809
+ maxConsecutiveFailures: toPositiveInt(configuredPolicy.maxConsecutiveFailures, defaults.maxConsecutiveFailures),
810
+ circuitOpenMs: toPositiveInt(configuredPolicy.circuitOpenMs, defaults.circuitOpenMs),
811
+ onCircuitOpen: configuredPolicy.onCircuitOpen,
812
+ onFlushFailure: configuredPolicy.onFlushFailure,
813
+ onFlushRecovered: configuredPolicy.onFlushRecovered
358
814
  };
359
815
  };
360
816
  const computeQueueFlushRetryDelayMs = (options)=>{
@@ -380,6 +836,23 @@ var __webpack_exports__ = {};
380
836
  circuitOpenUntil
381
837
  };
382
838
  };
839
+ const STATEFUL_RUNTIME_LOCK_KEY = '__ctfl_optimization_stateful_runtime_lock__';
840
+ const getStatefulRuntimeLock = ()=>{
841
+ const singletonGlobal = globalThis;
842
+ singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY] ??= {
843
+ owner: void 0
844
+ };
845
+ return singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY];
846
+ };
847
+ const acquireStatefulRuntimeSingleton = (owner)=>{
848
+ const lock = getStatefulRuntimeLock();
849
+ if (lock.owner) throw new Error(`Stateful Optimization SDK already initialized (${lock.owner}). Only one stateful instance is supported per runtime.`);
850
+ lock.owner = owner;
851
+ };
852
+ const releaseStatefulRuntimeSingleton = (owner)=>{
853
+ const lock = getStatefulRuntimeLock();
854
+ if (lock.owner === owner) lock.owner = void 0;
855
+ };
383
856
  class QueueFlushRuntime {
384
857
  circuitOpenUntil = 0;
385
858
  flushFailureCount = 0;
@@ -484,463 +957,186 @@ var __webpack_exports__ = {};
484
957
  }
485
958
  }
486
959
  }
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;
960
+ const ExperienceQueue_coreLogger = (0, logger_namespaceObject.createScopedLogger)('CoreStateful');
961
+ class ExperienceQueue {
962
+ experienceApi;
963
+ eventInterceptors;
964
+ flushRuntime;
965
+ getAnonymousId;
966
+ offlineMaxEvents;
967
+ onOfflineDrop;
968
+ queuedExperienceEvents = new Set();
969
+ stateInterceptors;
499
970
  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;
971
+ const { experienceApi, eventInterceptors, flushPolicy, getAnonymousId, offlineMaxEvents, onOfflineDrop, stateInterceptors } = options;
972
+ this.experienceApi = experienceApi;
973
+ this.eventInterceptors = eventInterceptors;
974
+ this.getAnonymousId = getAnonymousId;
975
+ this.offlineMaxEvents = offlineMaxEvents;
976
+ this.onOfflineDrop = onOfflineDrop;
977
+ this.stateInterceptors = stateInterceptors;
978
+ this.flushRuntime = new QueueFlushRuntime({
979
+ policy: flushPolicy,
980
+ onRetry: ()=>{
981
+ this.flush();
982
+ },
983
+ onCallbackError: (callbackName, error)=>{
984
+ ExperienceQueue_coreLogger.warn(`Experience flush policy callback "${callbackName}" failed`, error);
985
+ }
986
+ });
520
987
  }
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
- };
988
+ clearScheduledRetry() {
989
+ this.flushRuntime.clearScheduledRetry();
533
990
  }
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
- };
991
+ async send(event) {
992
+ const intercepted = await this.eventInterceptors.run(event);
993
+ const validEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.ExperienceEvent, intercepted);
994
+ signals_event.value = validEvent;
995
+ if (online.value) return await this.upsertProfile([
996
+ validEvent
997
+ ]);
998
+ ExperienceQueue_coreLogger.debug(`Queueing ${validEvent.type} event`, validEvent);
999
+ this.enqueueEvent(validEvent);
1000
+ }
1001
+ async flush(options = {}) {
1002
+ const { force = false } = options;
1003
+ if (this.flushRuntime.shouldSkip({
1004
+ force,
1005
+ isOnline: !!online.value
1006
+ })) return;
1007
+ if (0 === this.queuedExperienceEvents.size) return void this.flushRuntime.clearScheduledRetry();
1008
+ ExperienceQueue_coreLogger.debug('Flushing offline Experience event queue');
1009
+ const queuedEvents = Array.from(this.queuedExperienceEvents);
1010
+ this.flushRuntime.markFlushStarted();
594
1011
  try {
595
- return dec(value, ctx);
1012
+ const sendSuccess = await this.tryUpsertQueuedEvents(queuedEvents);
1013
+ if (sendSuccess) {
1014
+ queuedEvents.forEach((queuedEvent)=>{
1015
+ this.queuedExperienceEvents.delete(queuedEvent);
1016
+ });
1017
+ this.flushRuntime.handleFlushSuccess();
1018
+ } else this.flushRuntime.handleFlushFailure({
1019
+ queuedBatches: this.queuedExperienceEvents.size > 0 ? 1 : 0,
1020
+ queuedEvents: this.queuedExperienceEvents.size
1021
+ });
596
1022
  } finally{
597
- decoratorFinishedRef.v = true;
1023
+ this.flushRuntime.markFlushFinished();
598
1024
  }
599
1025
  }
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");
1026
+ enqueueEvent(event) {
1027
+ let droppedEvents = [];
1028
+ if (this.queuedExperienceEvents.size >= this.offlineMaxEvents) {
1029
+ const dropCount = this.queuedExperienceEvents.size - this.offlineMaxEvents + 1;
1030
+ droppedEvents = this.dropOldestEvents(dropCount);
1031
+ if (droppedEvents.length > 0) ExperienceQueue_coreLogger.warn(`Dropped ${droppedEvents.length} oldest offline event(s) due to queue limit (${this.offlineMaxEvents})`);
617
1032
  }
1033
+ this.queuedExperienceEvents.add(event);
1034
+ if (droppedEvents.length > 0) this.invokeOfflineDropCallback({
1035
+ droppedCount: droppedEvents.length,
1036
+ droppedEvents,
1037
+ maxEvents: this.offlineMaxEvents,
1038
+ queuedEvents: this.queuedExperienceEvents.size
1039
+ });
618
1040
  }
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);
1041
+ dropOldestEvents(count) {
1042
+ const droppedEvents = [];
1043
+ for(let index = 0; index < count; index += 1){
1044
+ const oldestEvent = this.queuedExperienceEvents.values().next();
1045
+ if (oldestEvent.done) break;
1046
+ this.queuedExperienceEvents.delete(oldestEvent.value);
1047
+ droppedEvents.push(oldestEvent.value);
718
1048
  }
1049
+ return droppedEvents;
719
1050
  }
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
- }
1051
+ invokeOfflineDropCallback(context) {
1052
+ try {
1053
+ this.onOfflineDrop?.(context);
1054
+ } catch (error) {
1055
+ ExperienceQueue_coreLogger.warn('Offline queue drop callback failed', error);
754
1056
  }
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
1057
  }
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
- ];
1058
+ async tryUpsertQueuedEvents(events) {
1059
+ try {
1060
+ await this.upsertProfile(events);
1061
+ return true;
1062
+ } catch (error) {
1063
+ ExperienceQueue_coreLogger.warn('Experience queue flush request threw an error', error);
1064
+ return false;
795
1065
  }
796
1066
  }
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
1067
+ async upsertProfile(events) {
1068
+ const anonymousId = this.getAnonymousId();
1069
+ if (anonymousId) ExperienceQueue_coreLogger.debug(`Anonymous ID found: ${anonymousId}`);
1070
+ const data = await this.experienceApi.upsertProfile({
1071
+ profileId: anonymousId ?? signals_profile.value?.id,
1072
+ events
802
1073
  });
1074
+ await this.updateOutputSignals(data);
1075
+ return data;
803
1076
  }
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
- ], []));
1077
+ async updateOutputSignals(data) {
1078
+ const intercepted = await this.stateInterceptors.run(data);
1079
+ const { changes, profile, selectedOptimizations } = intercepted;
1080
+ (0, signals_core_namespaceObject.batch)(()=>{
1081
+ if (!(0, predicate_namespaceObject.isEqual)(signals_changes.value, changes)) signals_changes.value = changes;
1082
+ if (!(0, predicate_namespaceObject.isEqual)(signals_profile.value, profile)) signals_profile.value = profile;
1083
+ if (!(0, predicate_namespaceObject.isEqual)(signals_selectedOptimizations.value, selectedOptimizations)) signals_selectedOptimizations.value = selectedOptimizations;
1084
+ });
862
1085
  }
863
- queue = (_initProto(this), new Map());
1086
+ }
1087
+ const InsightsQueue_coreLogger = (0, logger_namespaceObject.createScopedLogger)('CoreStateful');
1088
+ const MAX_QUEUED_INSIGHTS_EVENTS = 25;
1089
+ class InsightsQueue {
1090
+ eventInterceptors;
1091
+ flushIntervalMs;
864
1092
  flushRuntime;
865
- states = {
866
- blockedEventStream: toObservable(blockedEvent),
867
- eventStream: toObservable(signals_event),
868
- profile: toObservable(signals_profile)
869
- };
1093
+ insightsApi;
1094
+ queuedInsightsByProfile = new Map();
1095
+ insightsPeriodicFlushTimer;
870
1096
  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);
1097
+ const { eventInterceptors, flushPolicy, insightsApi } = options;
1098
+ const { flushIntervalMs } = flushPolicy;
1099
+ this.eventInterceptors = eventInterceptors;
1100
+ this.flushIntervalMs = flushIntervalMs;
1101
+ this.insightsApi = insightsApi;
879
1102
  this.flushRuntime = new QueueFlushRuntime({
880
- policy: resolveQueueFlushPolicy(config?.queuePolicy),
1103
+ policy: flushPolicy,
881
1104
  onRetry: ()=>{
882
1105
  this.flush();
883
1106
  },
884
1107
  onCallbackError: (callbackName, error)=>{
885
- AnalyticsStateful_logger.warn(`Analytics flush policy callback "${callbackName}" failed`, error);
1108
+ InsightsQueue_coreLogger.warn(`Insights flush policy callback "${callbackName}" failed`, error);
886
1109
  }
887
1110
  });
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
1111
  }
914
- async trackComponentHover(payload) {
915
- AnalyticsStateful_logger.info(`Processing "component hover" event for ${payload.componentId}`);
916
- await this.enqueueEvent(this.builder.buildComponentHover(payload));
1112
+ clearScheduledRetry() {
1113
+ this.flushRuntime.clearScheduledRetry();
917
1114
  }
918
- async trackFlagView(payload) {
919
- AnalyticsStateful_logger.debug(`Processing "flag view" event for ${payload.componentId}`);
920
- await this.enqueueEvent(this.builder.buildFlagView(payload));
1115
+ clearPeriodicFlushTimer() {
1116
+ if (void 0 === this.insightsPeriodicFlushTimer) return;
1117
+ clearInterval(this.insightsPeriodicFlushTimer);
1118
+ this.insightsPeriodicFlushTimer = void 0;
921
1119
  }
922
- async enqueueEvent(event) {
1120
+ async send(event) {
923
1121
  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);
1122
+ if (!profile) return void InsightsQueue_coreLogger.warn('Attempting to emit an event without an Optimization profile');
1123
+ const intercepted = await this.eventInterceptors.run(event);
1124
+ const validEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.InsightsEvent, intercepted);
1125
+ InsightsQueue_coreLogger.debug(`Queueing ${validEvent.type} event for profile ${profile.id}`, validEvent);
1126
+ const queuedProfileEvents = this.queuedInsightsByProfile.get(profile.id);
930
1127
  signals_event.value = validEvent;
931
1128
  if (queuedProfileEvents) {
932
1129
  queuedProfileEvents.profile = profile;
933
1130
  queuedProfileEvents.events.push(validEvent);
934
- } else this.queue.set(profileId, {
1131
+ } else this.queuedInsightsByProfile.set(profile.id, {
935
1132
  profile,
936
1133
  events: [
937
1134
  validEvent
938
1135
  ]
939
1136
  });
940
- await this.flushMaxEvents();
941
- }
942
- async flushMaxEvents() {
943
- if (this.getQueuedEventCount() >= MAX_QUEUED_EVENTS) await this.flush();
1137
+ this.ensurePeriodicFlushTimer();
1138
+ if (this.getQueuedEventCount() >= MAX_QUEUED_INSIGHTS_EVENTS) await this.flush();
1139
+ this.reconcilePeriodicFlushTimer();
944
1140
  }
945
1141
  async flush(options = {}) {
946
1142
  const { force = false } = options;
@@ -948,14 +1144,18 @@ var __webpack_exports__ = {};
948
1144
  force,
949
1145
  isOnline: !!online.value
950
1146
  })) return;
951
- AnalyticsStateful_logger.debug('Flushing event queue');
1147
+ InsightsQueue_coreLogger.debug('Flushing insights event queue');
952
1148
  const batches = this.createBatches();
953
- if (!batches.length) return void this.flushRuntime.clearScheduledRetry();
1149
+ if (!batches.length) {
1150
+ this.flushRuntime.clearScheduledRetry();
1151
+ this.reconcilePeriodicFlushTimer();
1152
+ return;
1153
+ }
954
1154
  this.flushRuntime.markFlushStarted();
955
1155
  try {
956
1156
  const sendSuccess = await this.trySendBatches(batches);
957
1157
  if (sendSuccess) {
958
- this.queue.clear();
1158
+ this.queuedInsightsByProfile.clear();
959
1159
  this.flushRuntime.handleFlushSuccess();
960
1160
  } else this.flushRuntime.handleFlushFailure({
961
1161
  queuedBatches: batches.length,
@@ -963,30 +1163,12 @@ var __webpack_exports__ = {};
963
1163
  });
964
1164
  } finally{
965
1165
  this.flushRuntime.markFlushFinished();
1166
+ this.reconcilePeriodicFlushTimer();
966
1167
  }
967
1168
  }
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
1169
  createBatches() {
988
1170
  const batches = [];
989
- this.queue.forEach(({ profile, events })=>{
1171
+ this.queuedInsightsByProfile.forEach(({ profile, events })=>{
990
1172
  batches.push({
991
1173
  profile,
992
1174
  events
@@ -996,998 +1178,422 @@ var __webpack_exports__ = {};
996
1178
  }
997
1179
  async trySendBatches(batches) {
998
1180
  try {
999
- return await this.api.insights.sendBatchEvents(batches);
1181
+ return await this.insightsApi.sendBatchEvents(batches);
1000
1182
  } catch (error) {
1001
- AnalyticsStateful_logger.warn('Analytics queue flush request threw an error', error);
1183
+ InsightsQueue_coreLogger.warn('Insights queue flush request threw an error', error);
1002
1184
  return false;
1003
1185
  }
1004
1186
  }
1005
1187
  getQueuedEventCount() {
1006
1188
  let queuedCount = 0;
1007
- this.queue.forEach(({ events })=>{
1189
+ this.queuedInsightsByProfile.forEach(({ events })=>{
1008
1190
  queuedCount += events.length;
1009
1191
  });
1010
1192
  return queuedCount;
1011
1193
  }
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);
1194
+ ensurePeriodicFlushTimer() {
1195
+ if (void 0 !== this.insightsPeriodicFlushTimer) return;
1196
+ if (0 === this.getQueuedEventCount()) return;
1197
+ this.insightsPeriodicFlushTimer = setInterval(()=>{
1198
+ this.flush();
1199
+ }, this.flushIntervalMs);
1200
+ }
1201
+ reconcilePeriodicFlushTimer() {
1202
+ if (this.getQueuedEventCount() > 0) return void this.ensurePeriodicFlushTimer();
1203
+ this.clearPeriodicFlushTimer();
1052
1204
  }
1053
1205
  }
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
1206
+ var symbols = __webpack_require__("./src/symbols.ts");
1207
+ const CoreStateful_coreLogger = (0, logger_namespaceObject.createScopedLogger)('CoreStateful');
1208
+ const DEFAULT_ALLOWED_EVENT_TYPES = [
1209
+ 'identify',
1210
+ 'page',
1211
+ 'screen'
1212
+ ];
1213
+ const OFFLINE_QUEUE_MAX_EVENTS = 100;
1214
+ const hasDefinedValues = (record)=>Object.values(record).some((value)=>void 0 !== value);
1215
+ const createStatefulExperienceApiConfig = (api)=>{
1216
+ if (void 0 === api) return;
1217
+ const experienceConfig = {
1218
+ baseUrl: api.experienceBaseUrl,
1219
+ enabledFeatures: api.enabledFeatures,
1220
+ ip: api.ip,
1221
+ locale: api.locale,
1222
+ plainText: api.plainText,
1223
+ preflight: api.preflight
1163
1224
  };
1164
- return singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY];
1165
- };
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;
1225
+ return hasDefinedValues(experienceConfig) ? experienceConfig : void 0;
1174
1226
  };
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
- };
1227
+ const createStatefulInsightsApiConfig = (api)=>{
1228
+ if (void 0 === api) return;
1229
+ const insightsConfig = {
1230
+ baseUrl: api.insightsBaseUrl,
1231
+ beaconHandler: api.beaconHandler
1483
1232
  };
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)
1233
+ return hasDefinedValues(insightsConfig) ? insightsConfig : void 0;
1234
+ };
1235
+ const resolveQueuePolicy = (policy)=>({
1236
+ flush: resolveQueueFlushPolicy(policy?.flush),
1237
+ offlineMaxEvents: toPositiveInt(policy?.offlineMaxEvents, OFFLINE_QUEUE_MAX_EVENTS),
1238
+ onOfflineDrop: policy?.onOfflineDrop
1495
1239
  });
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;
1240
+ let statefulInstanceCounter = 0;
1241
+ class CoreStateful extends src_CoreStatefulEventEmitter {
1242
+ singletonOwner;
1243
+ destroyed = false;
1244
+ allowedEventTypes;
1245
+ experienceQueue;
1246
+ insightsQueue;
1247
+ onEventBlocked;
1540
1248
  states = {
1541
1249
  blockedEventStream: toObservable(blockedEvent),
1250
+ flag: (name)=>this.getFlagObservable(name),
1251
+ consent: toObservable(consent),
1542
1252
  eventStream: toObservable(signals_event),
1543
- flags: toObservable(flags),
1544
- profile: toObservable(signals_profile),
1545
- personalizations: toObservable(signals_personalizations)
1253
+ canOptimize: toObservable(canOptimize),
1254
+ selectedOptimizations: toObservable(signals_selectedOptimizations),
1255
+ previewPanelAttached: toObservable(previewPanelAttached),
1256
+ previewPanelOpen: toObservable(previewPanelOpen),
1257
+ profile: toObservable(signals_profile)
1546
1258
  };
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
- }
1259
+ constructor(config){
1260
+ super(config, {
1261
+ experience: createStatefulExperienceApiConfig(config.api),
1262
+ insights: createStatefulInsightsApiConfig(config.api)
1566
1263
  });
1567
- if (defaults) {
1568
- const { changes: defaultChanges, personalizations: defaultPersonalizations, profile: defaultProfile } = defaults;
1264
+ this.singletonOwner = `CoreStateful#${++statefulInstanceCounter}`;
1265
+ acquireStatefulRuntimeSingleton(this.singletonOwner);
1266
+ try {
1267
+ const { allowedEventTypes, defaults, getAnonymousId, onEventBlocked, queuePolicy } = config;
1268
+ const { changes: defaultChanges, consent: defaultConsent, selectedOptimizations: defaultSelectedOptimizations, profile: defaultProfile } = defaults ?? {};
1269
+ const resolvedQueuePolicy = resolveQueuePolicy(queuePolicy);
1270
+ this.allowedEventTypes = allowedEventTypes ?? DEFAULT_ALLOWED_EVENT_TYPES;
1271
+ this.onEventBlocked = onEventBlocked;
1272
+ this.insightsQueue = new InsightsQueue({
1273
+ eventInterceptors: this.interceptors.event,
1274
+ flushPolicy: resolvedQueuePolicy.flush,
1275
+ insightsApi: this.api.insights
1276
+ });
1277
+ this.experienceQueue = new ExperienceQueue({
1278
+ experienceApi: this.api.experience,
1279
+ eventInterceptors: this.interceptors.event,
1280
+ flushPolicy: resolvedQueuePolicy.flush,
1281
+ getAnonymousId: getAnonymousId ?? (()=>void 0),
1282
+ offlineMaxEvents: resolvedQueuePolicy.offlineMaxEvents,
1283
+ onOfflineDrop: resolvedQueuePolicy.onOfflineDrop,
1284
+ stateInterceptors: this.interceptors.state
1285
+ });
1286
+ if (void 0 !== defaultConsent) consent.value = defaultConsent;
1569
1287
  (0, signals_core_namespaceObject.batch)(()=>{
1570
- signals_changes.value = defaultChanges;
1571
- signals_personalizations.value = defaultPersonalizations;
1572
- signals_profile.value = defaultProfile;
1288
+ if (void 0 !== defaultChanges) signals_changes.value = defaultChanges;
1289
+ if (void 0 !== defaultSelectedOptimizations) signals_selectedOptimizations.value = defaultSelectedOptimizations;
1290
+ if (void 0 !== defaultProfile) signals_profile.value = defaultProfile;
1573
1291
  });
1292
+ this.initializeEffects();
1293
+ } catch (error) {
1294
+ releaseStatefulRuntimeSingleton(this.singletonOwner);
1295
+ throw error;
1574
1296
  }
1575
- if (defaults?.consent !== void 0) {
1576
- const { consent: defaultConsent } = defaults;
1577
- consent.value = defaultConsent;
1578
- }
1579
- this.getAnonymousId = getAnonymousId ?? (()=>void 0);
1297
+ }
1298
+ initializeEffects() {
1580
1299
  (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'}`);
1300
+ CoreStateful_coreLogger.debug(`Profile ${signals_profile.value && `with ID ${signals_profile.value.id}`} has been ${signals_profile.value ? 'set' : 'cleared'}`);
1582
1301
  });
1583
1302
  (0, signals_core_namespaceObject.effect)(()=>{
1584
- PersonalizationStateful_logger.debug(`Variants have been ${signals_personalizations.value?.length ? 'populated' : 'cleared'}`);
1303
+ CoreStateful_coreLogger.debug(`Variants have been ${signals_selectedOptimizations.value?.length ? 'populated' : 'cleared'}`);
1585
1304
  });
1586
1305
  (0, signals_core_namespaceObject.effect)(()=>{
1587
- PersonalizationStateful_logger.info(`Personalization ${consent.value ? 'will' : 'will not'} take effect due to consent (${consent.value})`);
1306
+ CoreStateful_coreLogger.info(`Core ${consent.value ? 'will' : 'will not'} emit gated events due to consent (${consent.value})`);
1588
1307
  });
1589
1308
  (0, signals_core_namespaceObject.effect)(()=>{
1590
1309
  if (!online.value) return;
1591
- this.flushRuntime.clearScheduledRetry();
1592
- this.flush({
1310
+ this.insightsQueue.clearScheduledRetry();
1311
+ this.experienceQueue.clearScheduledRetry();
1312
+ this.flushQueues({
1593
1313
  force: true
1594
1314
  });
1595
1315
  });
1596
1316
  }
1317
+ async flushQueues(options = {}) {
1318
+ await this.insightsQueue.flush(options);
1319
+ await this.experienceQueue.flush(options);
1320
+ }
1321
+ destroy() {
1322
+ if (this.destroyed) return;
1323
+ this.destroyed = true;
1324
+ this.insightsQueue.flush({
1325
+ force: true
1326
+ }).catch((error)=>{
1327
+ logger_namespaceObject.logger.warn('Failed to flush insights queue during destroy()', String(error));
1328
+ });
1329
+ this.experienceQueue.flush({
1330
+ force: true
1331
+ }).catch((error)=>{
1332
+ logger_namespaceObject.logger.warn('Failed to flush Experience queue during destroy()', String(error));
1333
+ });
1334
+ this.insightsQueue.clearPeriodicFlushTimer();
1335
+ releaseStatefulRuntimeSingleton(this.singletonOwner);
1336
+ }
1597
1337
  reset() {
1598
- this.flushRuntime.reset();
1599
1338
  (0, signals_core_namespaceObject.batch)(()=>{
1600
- signals_changes.value = void 0;
1601
1339
  blockedEvent.value = void 0;
1602
1340
  signals_event.value = void 0;
1341
+ signals_changes.value = void 0;
1603
1342
  signals_profile.value = void 0;
1604
- signals_personalizations.value = void 0;
1343
+ signals_selectedOptimizations.value = void 0;
1605
1344
  });
1606
1345
  }
1607
- getCustomFlag(name, changes = signals_changes.value) {
1608
- return super.getCustomFlag(name, changes);
1346
+ async flush() {
1347
+ await this.flushQueues();
1609
1348
  }
1610
- getCustomFlags(changes = signals_changes.value) {
1611
- return super.getCustomFlags(changes);
1349
+ consent(accept) {
1350
+ consent.value = accept;
1612
1351
  }
1613
- personalizeEntry(entry, personalizations = signals_personalizations.value) {
1614
- return super.personalizeEntry(entry, personalizations);
1352
+ get online() {
1353
+ return online.value ?? false;
1615
1354
  }
1616
- getMergeTagValue(embeddedEntryNodeTarget, profile = signals_profile.value) {
1617
- return super.getMergeTagValue(embeddedEntryNodeTarget, profile);
1355
+ set online(isOnline) {
1356
+ online.value = isOnline;
1618
1357
  }
1619
- hasConsent(name) {
1620
- return !!consent.value || (this.allowedEventTypes ?? []).includes('trackComponentView' === name || 'trackFlagView' === name ? 'component' : name);
1358
+ registerPreviewPanel(previewPanel) {
1359
+ Reflect.set(previewPanel, symbols.PREVIEW_PANEL_SIGNALS_SYMBOL, signals);
1360
+ Reflect.set(previewPanel, symbols.PREVIEW_PANEL_SIGNAL_FNS_SYMBOL, signalFns);
1621
1361
  }
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);
1362
+ }
1363
+ const src_CoreStateful = CoreStateful;
1364
+ var api_schemas = __webpack_require__("./src/api-schemas.ts");
1365
+ const TRACK_CLICK_PROFILE_ERROR = 'CoreStateless.forRequest().trackClick() requires `payload.profile.id` for Insights delivery.';
1366
+ const TRACK_HOVER_PROFILE_ERROR = 'CoreStateless.forRequest().trackHover() requires `payload.profile.id` for Insights delivery.';
1367
+ const TRACK_FLAG_VIEW_PROFILE_ERROR = 'CoreStateless.forRequest().trackFlagView() requires `payload.profile.id` for Insights delivery.';
1368
+ const NON_STICKY_TRACK_VIEW_PROFILE_ERROR = 'CoreStateless.forRequest().trackView() requires `payload.profile.id` when `payload.sticky` is not `true`.';
1369
+ const STICKY_TRACK_VIEW_PROFILE_ERROR = 'CoreStateless.forRequest().trackView() could not derive a profile from the sticky Experience response. Pass `payload.profile.id` explicitly if you need a fallback.';
1370
+ const requireInsightsProfile = (profile, errorMessage)=>{
1371
+ if (void 0 !== profile) return profile;
1372
+ throw new Error(errorMessage);
1373
+ };
1374
+ class CoreStatelessRequestScope {
1375
+ core;
1376
+ options;
1377
+ constructor(core, options = {}){
1378
+ this.core = core;
1379
+ this.options = Object.freeze({
1380
+ ...options
1381
+ });
1625
1382
  }
1626
1383
  async identify(payload) {
1627
- PersonalizationStateful_logger.info('Sending "identify" event');
1628
- const event = this.builder.buildIdentify(payload);
1629
- return await this.sendOrEnqueueEvent(event);
1384
+ const { profile, ...builderArgs } = payload;
1385
+ return await this.sendExperienceEvent(this.core.eventBuilder.buildIdentify(builderArgs), profile);
1630
1386
  }
1631
- async page(payload) {
1632
- PersonalizationStateful_logger.info('Sending "page" event');
1633
- const event = this.builder.buildPageView(payload);
1634
- return await this.sendOrEnqueueEvent(event);
1387
+ async page(payload = {}) {
1388
+ const { profile, ...builderArgs } = payload;
1389
+ return await this.sendExperienceEvent(this.core.eventBuilder.buildPageView(builderArgs), profile);
1635
1390
  }
1636
1391
  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);
1392
+ const { profile, ...builderArgs } = payload;
1393
+ return await this.sendExperienceEvent(this.core.eventBuilder.buildScreenView(builderArgs), profile);
1640
1394
  }
1641
1395
  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);
1645
- }
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);
1650
- }
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);
1660
- }
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
1674
- });
1675
- }
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
- }
1729
- }
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;
1739
- }
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
- });
1748
- }
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');
1755
1396
  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);
1397
+ return await this.sendExperienceEvent(this.core.eventBuilder.buildTrack(builderArgs), profile);
1758
1398
  }
1759
- async page(payload) {
1760
- PersonalizationStateless_logger.info('Sending "page" event');
1399
+ async trackView(payload) {
1761
1400
  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);
1401
+ let result;
1402
+ let insightsProfile = profile;
1403
+ if (payload.sticky) {
1404
+ result = await this.sendExperienceEvent(this.core.eventBuilder.buildView(builderArgs), profile);
1405
+ const { profile: responseProfile } = result;
1406
+ insightsProfile = responseProfile;
1407
+ }
1408
+ await this.sendInsightsEvent(this.core.eventBuilder.buildView(builderArgs), requireInsightsProfile(insightsProfile, payload.sticky ? STICKY_TRACK_VIEW_PROFILE_ERROR : NON_STICKY_TRACK_VIEW_PROFILE_ERROR));
1409
+ return result;
1764
1410
  }
1765
- async screen(payload) {
1766
- PersonalizationStateless_logger.info(`Sending "screen" event for "${payload.name}"`);
1411
+ async trackClick(payload) {
1767
1412
  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);
1413
+ await this.sendInsightsEvent(this.core.eventBuilder.buildClick(builderArgs), requireInsightsProfile(profile, TRACK_CLICK_PROFILE_ERROR));
1770
1414
  }
1771
- async track(payload) {
1772
- PersonalizationStateless_logger.info(`Sending "track" event "${payload.event}"`);
1415
+ async trackHover(payload) {
1773
1416
  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);
1417
+ await this.sendInsightsEvent(this.core.eventBuilder.buildHover(builderArgs), requireInsightsProfile(profile, TRACK_HOVER_PROFILE_ERROR));
1776
1418
  }
1777
- async trackComponentView(payload) {
1778
- PersonalizationStateless_logger.info('Sending "track personalization" event');
1419
+ async trackFlagView(payload) {
1779
1420
  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);
1421
+ await this.sendInsightsEvent(this.core.eventBuilder.buildFlagView(builderArgs), requireInsightsProfile(profile, TRACK_FLAG_VIEW_PROFILE_ERROR));
1782
1422
  }
1783
- async upsertProfile(event, profile) {
1784
- 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({
1423
+ async sendExperienceEvent(event, profile) {
1424
+ const intercepted = await this.core.interceptors.event.run(event);
1425
+ const validEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.ExperienceEvent, intercepted);
1426
+ return await this.core.api.experience.upsertProfile({
1787
1427
  profileId: profile?.id,
1788
1428
  events: [
1789
1429
  validEvent
1790
1430
  ]
1791
- });
1792
- return data;
1431
+ }, this.options);
1432
+ }
1433
+ async sendInsightsEvent(event, profile) {
1434
+ const intercepted = await this.core.interceptors.event.run(event);
1435
+ const validEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.InsightsEvent, intercepted);
1436
+ const batchEvent = (0, api_schemas_.parseWithFriendlyError)(api_schemas_.BatchInsightsEventArray, [
1437
+ {
1438
+ profile: (0, api_schemas_.parseWithFriendlyError)(api_schemas.PartialProfile, profile),
1439
+ events: [
1440
+ validEvent
1441
+ ]
1442
+ }
1443
+ ]);
1444
+ await this.core.api.insights.sendBatchEvents(batchEvent);
1793
1445
  }
1794
1446
  }
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
1447
+ const CoreStateless_hasDefinedValues = (record)=>Object.values(record).some((value)=>void 0 !== value);
1448
+ const createStatelessExperienceApiConfig = (api)=>{
1449
+ if (void 0 === api) return;
1450
+ const experienceConfig = {
1451
+ baseUrl: api.experienceBaseUrl,
1452
+ enabledFeatures: api.enabledFeatures
1801
1453
  };
1802
- const { queuePolicy, ...apiConfig } = config;
1803
- const resolvedApiConfig = Object.keys(apiConfig).length > 0 ? apiConfig : void 0;
1454
+ return CoreStateless_hasDefinedValues(experienceConfig) ? experienceConfig : void 0;
1455
+ };
1456
+ const createStatelessInsightsApiConfig = (api)=>{
1457
+ if (api?.insightsBaseUrl === void 0) return;
1804
1458
  return {
1805
- apiConfig: resolvedApiConfig,
1806
- queuePolicy
1459
+ baseUrl: api.insightsBaseUrl
1807
1460
  };
1808
1461
  };
1809
- let statefulInstanceCounter = 0;
1810
- class CoreStateful extends src_CoreBase {
1811
- singletonOwner;
1812
- destroyed = false;
1813
- _analytics;
1814
- _personalization;
1462
+ class CoreStateless extends src_CoreBase {
1815
1463
  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;
1831
- }
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;
1464
+ super(config, {
1465
+ experience: createStatelessExperienceApiConfig(config.api),
1466
+ insights: createStatelessInsightsApiConfig(config.api)
1892
1467
  });
1893
1468
  }
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);
1469
+ forRequest(options = {}) {
1470
+ return new CoreStatelessRequestScope(this, options);
1910
1471
  }
1911
1472
  }
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
1473
+ const src_CoreStateless = CoreStateless;
1474
+ const isFunction = (v)=>'function' == typeof v;
1475
+ const nameToString = (name)=>'string' == typeof name ? name : 'symbol' == typeof name ? name.description ?? String(name) : String(name);
1476
+ const isOnBlockedKey = (v)=>'string' == typeof v || 'symbol' == typeof v;
1477
+ const isAsyncFunction = (fn)=>'[object AsyncFunction]' === Object.prototype.toString.call(fn);
1478
+ function guardedBy(predicateName, opts) {
1479
+ return function(_value, context) {
1480
+ const decoratedName = nameToString(context.name);
1481
+ context.addInitializer(function() {
1482
+ const originalUnknown = Reflect.get(this, context.name);
1483
+ if (!isFunction(originalUnknown)) return;
1484
+ const original = originalUnknown;
1485
+ const originalIsAsync = isAsyncFunction(original);
1486
+ const resolvePredicate = (self)=>{
1487
+ const { [predicateName]: cand } = self;
1488
+ if (!isFunction(cand)) throw new TypeError(`@guardedBy expects predicate "${String(predicateName)}" to be a synchronous function.`);
1489
+ return cand;
1490
+ };
1491
+ const computeAllowed = (self, args)=>{
1492
+ const pred = resolvePredicate(self);
1493
+ const ok = Boolean(pred.call(self, decoratedName, args));
1494
+ return opts?.invert === true ? !ok : ok;
1495
+ };
1496
+ const runOnBlocked = (self, args)=>{
1497
+ const { onBlocked } = opts ?? {};
1498
+ if (void 0 === onBlocked) return;
1499
+ if (isFunction(onBlocked)) return void onBlocked.call(self, decoratedName, args);
1500
+ if (isOnBlockedKey(onBlocked)) {
1501
+ const { [onBlocked]: handlerCandidate } = self;
1502
+ if (isFunction(handlerCandidate)) handlerCandidate.call(self, decoratedName, args);
1503
+ }
1504
+ };
1505
+ const blockedReturn = ()=>originalIsAsync ? Promise.resolve(void 0) : void 0;
1506
+ const wrapped = function(...args) {
1507
+ if (!computeAllowed(this, args)) {
1508
+ runOnBlocked(this, args);
1509
+ return blockedReturn();
1510
+ }
1511
+ return original.call(this, ...args);
1512
+ };
1513
+ Reflect.set(this, context.name, wrapped);
1927
1514
  });
1928
- }
1515
+ };
1929
1516
  }
1930
- const src_CoreStateless = CoreStateless;
1931
1517
  })();
1932
1518
  exports.ANONYMOUS_ID_COOKIE = __webpack_exports__.ANONYMOUS_ID_COOKIE;
1933
1519
  exports.ANONYMOUS_ID_COOKIE_LEGACY = __webpack_exports__.ANONYMOUS_ID_COOKIE_LEGACY;
1934
1520
  exports.ANONYMOUS_ID_KEY = __webpack_exports__.ANONYMOUS_ID_KEY;
1935
1521
  exports.ANONYMOUS_ID_KEY_LEGACY = __webpack_exports__.ANONYMOUS_ID_KEY_LEGACY;
1936
- exports.AnalyticsStateful = __webpack_exports__.AnalyticsStateful;
1937
- exports.AnalyticsStateless = __webpack_exports__.AnalyticsStateless;
1938
1522
  exports.CHANGES_CACHE_KEY = __webpack_exports__.CHANGES_CACHE_KEY;
1939
1523
  exports.CONSENT_KEY = __webpack_exports__.CONSENT_KEY;
1524
+ exports.ClickBuilderArgs = __webpack_exports__.ClickBuilderArgs;
1940
1525
  exports.CoreStateful = __webpack_exports__.CoreStateful;
1941
1526
  exports.CoreStateless = __webpack_exports__.CoreStateless;
1527
+ exports.CoreStatelessRequestScope = __webpack_exports__.CoreStatelessRequestScope;
1942
1528
  exports.DEBUG_FLAG_KEY = __webpack_exports__.DEBUG_FLAG_KEY;
1529
+ exports.DEFAULT_PAGE_PROPERTIES = __webpack_exports__.DEFAULT_PAGE_PROPERTIES;
1530
+ exports.EntryInteractionBuilderArgsBase = __webpack_exports__.EntryInteractionBuilderArgsBase;
1531
+ exports.EventBuilder = __webpack_exports__.EventBuilder;
1532
+ exports.FlagViewBuilderArgs = __webpack_exports__.FlagViewBuilderArgs;
1943
1533
  exports.FlagsResolver = __webpack_exports__.FlagsResolver;
1534
+ exports.HoverBuilderArgs = __webpack_exports__.HoverBuilderArgs;
1535
+ exports.IdentifyBuilderArgs = __webpack_exports__.IdentifyBuilderArgs;
1944
1536
  exports.InterceptorManager = __webpack_exports__.InterceptorManager;
1945
1537
  exports.MergeTagValueResolver = __webpack_exports__.MergeTagValueResolver;
1946
1538
  exports.OPTIMIZATION_CORE_SDK_NAME = __webpack_exports__.OPTIMIZATION_CORE_SDK_NAME;
1947
1539
  exports.OPTIMIZATION_CORE_SDK_VERSION = __webpack_exports__.OPTIMIZATION_CORE_SDK_VERSION;
1948
- exports.PERSONALIZATIONS_CACHE_KEY = __webpack_exports__.PERSONALIZATIONS_CACHE_KEY;
1540
+ exports.OptimizedEntryResolver = __webpack_exports__.OptimizedEntryResolver;
1949
1541
  exports.PREVIEW_PANEL_SIGNALS_SYMBOL = __webpack_exports__.PREVIEW_PANEL_SIGNALS_SYMBOL;
1950
1542
  exports.PREVIEW_PANEL_SIGNAL_FNS_SYMBOL = __webpack_exports__.PREVIEW_PANEL_SIGNAL_FNS_SYMBOL;
1951
1543
  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;
1544
+ exports.PageViewBuilderArgs = __webpack_exports__.PageViewBuilderArgs;
1545
+ exports.SELECTED_OPTIMIZATIONS_CACHE_KEY = __webpack_exports__.SELECTED_OPTIMIZATIONS_CACHE_KEY;
1546
+ exports.ScreenViewBuilderArgs = __webpack_exports__.ScreenViewBuilderArgs;
1547
+ exports.TrackBuilderArgs = __webpack_exports__.TrackBuilderArgs;
1548
+ exports.UniversalEventBuilderArgs = __webpack_exports__.UniversalEventBuilderArgs;
1549
+ exports.ViewBuilderArgs = __webpack_exports__.ViewBuilderArgs;
1956
1550
  exports.batch = __webpack_exports__.batch;
1957
1551
  exports.effect = __webpack_exports__.effect;
1958
1552
  exports.guardedBy = __webpack_exports__.guardedBy;
1959
1553
  exports.signalFns = __webpack_exports__.signalFns;
1960
1554
  exports.signals = __webpack_exports__.signals;
1555
+ exports.toDistinctObservable = __webpack_exports__.toDistinctObservable;
1556
+ exports.toObservable = __webpack_exports__.toObservable;
1961
1557
  for(var __rspack_i in __webpack_exports__)if (-1 === [
1962
1558
  "ANONYMOUS_ID_COOKIE",
1963
1559
  "ANONYMOUS_ID_COOKIE_LEGACY",
1964
1560
  "ANONYMOUS_ID_KEY",
1965
1561
  "ANONYMOUS_ID_KEY_LEGACY",
1966
- "AnalyticsStateful",
1967
- "AnalyticsStateless",
1968
1562
  "CHANGES_CACHE_KEY",
1969
1563
  "CONSENT_KEY",
1564
+ "ClickBuilderArgs",
1970
1565
  "CoreStateful",
1971
1566
  "CoreStateless",
1567
+ "CoreStatelessRequestScope",
1972
1568
  "DEBUG_FLAG_KEY",
1569
+ "DEFAULT_PAGE_PROPERTIES",
1570
+ "EntryInteractionBuilderArgsBase",
1571
+ "EventBuilder",
1572
+ "FlagViewBuilderArgs",
1973
1573
  "FlagsResolver",
1574
+ "HoverBuilderArgs",
1575
+ "IdentifyBuilderArgs",
1974
1576
  "InterceptorManager",
1975
1577
  "MergeTagValueResolver",
1976
1578
  "OPTIMIZATION_CORE_SDK_NAME",
1977
1579
  "OPTIMIZATION_CORE_SDK_VERSION",
1978
- "PERSONALIZATIONS_CACHE_KEY",
1580
+ "OptimizedEntryResolver",
1979
1581
  "PREVIEW_PANEL_SIGNALS_SYMBOL",
1980
1582
  "PREVIEW_PANEL_SIGNAL_FNS_SYMBOL",
1981
1583
  "PROFILE_CACHE_KEY",
1982
- "PersonalizationBase",
1983
- "PersonalizationStateful",
1984
- "PersonalizationStateless",
1985
- "PersonalizedEntryResolver",
1584
+ "PageViewBuilderArgs",
1585
+ "SELECTED_OPTIMIZATIONS_CACHE_KEY",
1586
+ "ScreenViewBuilderArgs",
1587
+ "TrackBuilderArgs",
1588
+ "UniversalEventBuilderArgs",
1589
+ "ViewBuilderArgs",
1986
1590
  "batch",
1987
1591
  "effect",
1988
1592
  "guardedBy",
1989
1593
  "signalFns",
1990
- "signals"
1594
+ "signals",
1595
+ "toDistinctObservable",
1596
+ "toObservable"
1991
1597
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
1992
1598
  Object.defineProperty(exports, '__esModule', {
1993
1599
  value: true