@contentful/optimization-core 0.1.0-alpha → 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.
Files changed (149) hide show
  1. package/README.md +329 -93
  2. package/dist/160.mjs +3 -0
  3. package/dist/260.mjs +14 -0
  4. package/dist/260.mjs.map +1 -0
  5. package/dist/499.mjs +4 -0
  6. package/dist/632.mjs +5 -0
  7. package/dist/632.mjs.map +1 -0
  8. package/dist/942.mjs +2 -0
  9. package/dist/api-client.cjs +60 -0
  10. package/dist/api-client.cjs.map +1 -0
  11. package/dist/api-client.d.cts +4 -0
  12. package/dist/api-client.d.mts +4 -0
  13. package/dist/api-client.d.ts +4 -0
  14. package/dist/api-client.mjs +2 -0
  15. package/dist/api-schemas.cjs +63 -0
  16. package/dist/api-schemas.cjs.map +1 -0
  17. package/dist/api-schemas.d.cts +4 -0
  18. package/dist/api-schemas.d.mts +4 -0
  19. package/dist/api-schemas.d.ts +4 -0
  20. package/dist/api-schemas.mjs +2 -0
  21. package/dist/constants.cjs +78 -0
  22. package/dist/constants.cjs.map +1 -0
  23. package/dist/constants.d.cts +88 -0
  24. package/dist/constants.d.mts +88 -0
  25. package/dist/constants.d.ts +88 -0
  26. package/dist/constants.mjs +1 -0
  27. package/dist/index.cjs +1509 -1715
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +2523 -0
  30. package/dist/index.d.mts +2523 -0
  31. package/dist/index.d.ts +2523 -15
  32. package/dist/index.mjs +1215 -1362
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/logger.cjs +67 -0
  35. package/dist/logger.cjs.map +1 -0
  36. package/dist/logger.d.cts +8 -0
  37. package/dist/logger.d.mts +8 -0
  38. package/dist/logger.d.ts +8 -0
  39. package/dist/logger.mjs +2 -0
  40. package/dist/symbols.cjs +42 -0
  41. package/dist/symbols.cjs.map +1 -0
  42. package/dist/symbols.d.cts +10 -0
  43. package/dist/symbols.d.mts +10 -0
  44. package/dist/symbols.d.ts +10 -0
  45. package/dist/symbols.mjs +1 -0
  46. package/package.json +78 -12
  47. package/dist/Consent.d.ts +0 -44
  48. package/dist/Consent.d.ts.map +0 -1
  49. package/dist/Consent.js +0 -2
  50. package/dist/Consent.js.map +0 -1
  51. package/dist/CoreBase.d.ts +0 -161
  52. package/dist/CoreBase.d.ts.map +0 -1
  53. package/dist/CoreBase.js +0 -151
  54. package/dist/CoreBase.js.map +0 -1
  55. package/dist/CoreStateful.d.ts +0 -142
  56. package/dist/CoreStateful.d.ts.map +0 -1
  57. package/dist/CoreStateful.js +0 -137
  58. package/dist/CoreStateful.js.map +0 -1
  59. package/dist/CoreStateless.d.ts +0 -53
  60. package/dist/CoreStateless.d.ts.map +0 -1
  61. package/dist/CoreStateless.js +0 -43
  62. package/dist/CoreStateless.js.map +0 -1
  63. package/dist/ProductBase.d.ts +0 -83
  64. package/dist/ProductBase.d.ts.map +0 -1
  65. package/dist/ProductBase.js +0 -50
  66. package/dist/ProductBase.js.map +0 -1
  67. package/dist/analytics/AnalyticsBase.d.ts +0 -35
  68. package/dist/analytics/AnalyticsBase.d.ts.map +0 -1
  69. package/dist/analytics/AnalyticsBase.js +0 -13
  70. package/dist/analytics/AnalyticsBase.js.map +0 -1
  71. package/dist/analytics/AnalyticsStateful.d.ts +0 -138
  72. package/dist/analytics/AnalyticsStateful.d.ts.map +0 -1
  73. package/dist/analytics/AnalyticsStateful.js +0 -179
  74. package/dist/analytics/AnalyticsStateful.js.map +0 -1
  75. package/dist/analytics/AnalyticsStateless.d.ts +0 -48
  76. package/dist/analytics/AnalyticsStateless.d.ts.map +0 -1
  77. package/dist/analytics/AnalyticsStateless.js +0 -61
  78. package/dist/analytics/AnalyticsStateless.js.map +0 -1
  79. package/dist/analytics/index.d.ts +0 -5
  80. package/dist/analytics/index.d.ts.map +0 -1
  81. package/dist/analytics/index.js +0 -5
  82. package/dist/analytics/index.js.map +0 -1
  83. package/dist/global-constants.d.ts +0 -18
  84. package/dist/global-constants.d.ts.map +0 -1
  85. package/dist/global-constants.js +0 -18
  86. package/dist/global-constants.js.map +0 -1
  87. package/dist/index.d.ts.map +0 -1
  88. package/dist/index.js +0 -15
  89. package/dist/index.js.map +0 -1
  90. package/dist/lib/decorators/guardedBy.d.ts +0 -113
  91. package/dist/lib/decorators/guardedBy.d.ts.map +0 -1
  92. package/dist/lib/decorators/guardedBy.js +0 -143
  93. package/dist/lib/decorators/guardedBy.js.map +0 -1
  94. package/dist/lib/decorators/index.d.ts +0 -2
  95. package/dist/lib/decorators/index.d.ts.map +0 -1
  96. package/dist/lib/decorators/index.js +0 -2
  97. package/dist/lib/decorators/index.js.map +0 -1
  98. package/dist/lib/interceptor/InterceptorManager.d.ts +0 -127
  99. package/dist/lib/interceptor/InterceptorManager.d.ts.map +0 -1
  100. package/dist/lib/interceptor/InterceptorManager.js +0 -125
  101. package/dist/lib/interceptor/InterceptorManager.js.map +0 -1
  102. package/dist/lib/interceptor/index.d.ts +0 -2
  103. package/dist/lib/interceptor/index.d.ts.map +0 -1
  104. package/dist/lib/interceptor/index.js +0 -2
  105. package/dist/lib/interceptor/index.js.map +0 -1
  106. package/dist/lib/value-presence/ValuePresence.d.ts +0 -123
  107. package/dist/lib/value-presence/ValuePresence.d.ts.map +0 -1
  108. package/dist/lib/value-presence/ValuePresence.js +0 -141
  109. package/dist/lib/value-presence/ValuePresence.js.map +0 -1
  110. package/dist/lib/value-presence/index.d.ts +0 -2
  111. package/dist/lib/value-presence/index.d.ts.map +0 -1
  112. package/dist/lib/value-presence/index.js +0 -2
  113. package/dist/lib/value-presence/index.js.map +0 -1
  114. package/dist/personalization/PersonalizationBase.d.ts +0 -184
  115. package/dist/personalization/PersonalizationBase.d.ts.map +0 -1
  116. package/dist/personalization/PersonalizationBase.js +0 -76
  117. package/dist/personalization/PersonalizationBase.js.map +0 -1
  118. package/dist/personalization/PersonalizationStateful.d.ts +0 -226
  119. package/dist/personalization/PersonalizationStateful.d.ts.map +0 -1
  120. package/dist/personalization/PersonalizationStateful.js +0 -297
  121. package/dist/personalization/PersonalizationStateful.js.map +0 -1
  122. package/dist/personalization/PersonalizationStateless.d.ts +0 -74
  123. package/dist/personalization/PersonalizationStateless.d.ts.map +0 -1
  124. package/dist/personalization/PersonalizationStateless.js +0 -98
  125. package/dist/personalization/PersonalizationStateless.js.map +0 -1
  126. package/dist/personalization/index.d.ts +0 -6
  127. package/dist/personalization/index.d.ts.map +0 -1
  128. package/dist/personalization/index.js +0 -6
  129. package/dist/personalization/index.js.map +0 -1
  130. package/dist/personalization/resolvers/FlagsResolver.d.ts +0 -35
  131. package/dist/personalization/resolvers/FlagsResolver.d.ts.map +0 -1
  132. package/dist/personalization/resolvers/FlagsResolver.js +0 -47
  133. package/dist/personalization/resolvers/FlagsResolver.js.map +0 -1
  134. package/dist/personalization/resolvers/MergeTagValueResolver.d.ts +0 -74
  135. package/dist/personalization/resolvers/MergeTagValueResolver.d.ts.map +0 -1
  136. package/dist/personalization/resolvers/MergeTagValueResolver.js +0 -109
  137. package/dist/personalization/resolvers/MergeTagValueResolver.js.map +0 -1
  138. package/dist/personalization/resolvers/PersonalizedEntryResolver.d.ts +0 -142
  139. package/dist/personalization/resolvers/PersonalizedEntryResolver.d.ts.map +0 -1
  140. package/dist/personalization/resolvers/PersonalizedEntryResolver.js +0 -196
  141. package/dist/personalization/resolvers/PersonalizedEntryResolver.js.map +0 -1
  142. package/dist/personalization/resolvers/index.d.ts +0 -7
  143. package/dist/personalization/resolvers/index.d.ts.map +0 -1
  144. package/dist/personalization/resolvers/index.js +0 -7
  145. package/dist/personalization/resolvers/index.js.map +0 -1
  146. package/dist/signals.d.ts +0 -35
  147. package/dist/signals.d.ts.map +0 -1
  148. package/dist/signals.js +0 -30
  149. package/dist/signals.js.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,824 +1,298 @@
1
- import * as __rspack_external__contentful_optimization_api_client_cba5a7ee from "@contentful/optimization-api-client";
2
- import { batch, computed, effect, signal } from "@preact/signals-core";
3
- import { get as compat_get } from "es-toolkit/compat";
4
- import { diary, enable } from "diary";
5
- import { compare } from "diary/utils";
6
- import { isEqual } from "es-toolkit";
7
- const FlagsResolver = {
8
- resolve (changes) {
9
- if (!changes) return {};
10
- return changes.reduce((acc, { key, value })=>{
11
- const actualValue = 'object' == typeof value && null !== value && 'value' in value && 'object' == typeof value.value ? value.value : value;
12
- acc[key] = actualValue;
13
- return acc;
14
- }, {});
15
- }
16
- };
17
- const resolvers_FlagsResolver = FlagsResolver;
18
- class Logger {
19
- name = '@contentful/optimization';
20
- PREFIX_PARTS = [
21
- 'Ctfl',
22
- 'O10n'
23
- ];
24
- DELIMITER = ':';
25
- diary;
26
- sinks = [];
27
- constructor(){
28
- this.diary = diary(this.name, this.onLogEvent.bind(this));
29
- enable(this.name);
30
- }
31
- assembleLocationPrefix(logLocation) {
32
- return `[${[
33
- ...this.PREFIX_PARTS,
34
- logLocation
35
- ].join(this.DELIMITER)}]`;
36
- }
37
- addSink(sink) {
38
- this.sinks = [
39
- ...this.sinks.filter((existingSink)=>existingSink.name !== sink.name),
40
- sink
41
- ];
42
- }
43
- removeSink(name) {
44
- this.sinks = this.sinks.filter((sink)=>sink.name !== name);
45
- }
46
- removeSinks() {
47
- this.sinks = [];
48
- }
49
- debug(logLocation, message, ...args) {
50
- this.diary.debug(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
51
- }
52
- info(logLocation, message, ...args) {
53
- this.diary.info(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
54
- }
55
- log(logLocation, message, ...args) {
56
- this.diary.log(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
57
- }
58
- warn(logLocation, message, ...args) {
59
- this.diary.warn(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
60
- }
61
- error(logLocation, message, ...args) {
62
- this.diary.error(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
63
- }
64
- fatal(logLocation, message, ...args) {
65
- this.diary.fatal(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
66
- }
67
- onLogEvent(event) {
68
- this.sinks.forEach((sink)=>{
69
- sink.ingest(event);
70
- });
71
- }
1
+ import { batch, computed, effect, signal, untracked } from "@preact/signals-core";
2
+ import { cloneDeep } from "es-toolkit";
3
+ import { merge } from "es-toolkit/object";
4
+ import { boolean as mini_boolean, extend, number, object, optional, partial, prefault, string } from "zod/mini";
5
+ import { isEqual as predicate_isEqual } from "es-toolkit/predicate";
6
+ import { __rspack_external__contentful_optimization_api_client_api_schemas_4192893e } from "./160.mjs";
7
+ import { __rspack_external__contentful_optimization_api_client_logger_f0d05f82 } from "./499.mjs";
8
+ import { __rspack_external__contentful_optimization_api_client_cba5a7ee } from "./942.mjs";
9
+ import { OPTIMIZATION_CORE_SDK_NAME, OPTIMIZATION_CORE_SDK_VERSION } from "./260.mjs";
10
+ import { PREVIEW_PANEL_SIGNALS_SYMBOL, PREVIEW_PANEL_SIGNAL_FNS_SYMBOL } from "./632.mjs";
11
+ function isNonNullish(value) {
12
+ return null != value;
72
13
  }
73
- const logger = new Logger();
74
- function createScopedLogger(location) {
14
+ function toError(value) {
15
+ if (value instanceof Error) return value;
16
+ return new Error(`Subscriber threw non-Error value: ${String(value)}`);
17
+ }
18
+ function toObservable(s) {
75
19
  return {
76
- debug: (message, ...args)=>{
77
- logger.debug(location, message, ...args);
78
- },
79
- info: (message, ...args)=>{
80
- logger.info(location, message, ...args);
81
- },
82
- log: (message, ...args)=>{
83
- logger.log(location, message, ...args);
84
- },
85
- warn: (message, ...args)=>{
86
- logger.warn(location, message, ...args);
87
- },
88
- error: (message, ...args)=>{
89
- logger.error(location, message, ...args);
20
+ get current () {
21
+ return cloneDeep(s.value);
90
22
  },
91
- fatal: (message, ...args)=>{
92
- logger.fatal(location, message, ...args);
93
- }
94
- };
95
- }
96
- class LogSink {
97
- }
98
- const src_LogSink = LogSink;
99
- const consoleMap = {
100
- debug: (...args)=>{
101
- console.debug(...args);
102
- },
103
- info: (...args)=>{
104
- console.info(...args);
105
- },
106
- log: (...args)=>{
107
- console.log(...args);
108
- },
109
- warn: (...args)=>{
110
- console.warn(...args);
111
- },
112
- error: (...args)=>{
113
- console.error(...args);
114
- },
115
- fatal: (...args)=>{
116
- console.error(...args);
117
- }
118
- };
119
- const COMPARISON_EQUALITY = 0;
120
- class ConsoleLogSink extends src_LogSink {
121
- name = 'ConsoleLogSink';
122
- verbosity;
123
- constructor(verbosity){
124
- super();
125
- this.verbosity = verbosity ?? 'error';
126
- }
127
- ingest(event) {
128
- if (compare(this.verbosity, event.level) > COMPARISON_EQUALITY) return;
129
- consoleMap[event.level](...event.messages);
130
- }
131
- }
132
- const MergeTagValueResolver_logger = createScopedLogger('Personalization');
133
- const RESOLUTION_WARNING_BASE = 'Could not resolve Merge Tag value:';
134
- const MergeTagValueResolver = {
135
- isMergeTagEntry (embeddedEntryNodeTarget) {
136
- return __rspack_external__contentful_optimization_api_client_cba5a7ee.MergeTagEntry.safeParse(embeddedEntryNodeTarget).success;
137
- },
138
- normalizeSelectors (id) {
139
- return id.split('_').map((_path, index, paths)=>{
140
- const dotPath = paths.slice(0, index).join('.');
141
- const underScorePath = paths.slice(index).join('_');
142
- return [
143
- dotPath,
144
- underScorePath
145
- ].filter((path)=>'' !== path).join('.');
146
- });
147
- },
148
- getValueFromProfile (id, profile) {
149
- const selectors = MergeTagValueResolver.normalizeSelectors(id);
150
- const matchingSelector = selectors.find((selector)=>compat_get(profile, selector));
151
- if (!matchingSelector) return;
152
- const value = compat_get(profile, matchingSelector);
153
- if (!value || 'string' != typeof value && 'number' != typeof value && 'boolean' != typeof value) return;
154
- return `${value}`;
155
- },
156
- resolve (mergeTagEntry, profile) {
157
- if (!MergeTagValueResolver.isMergeTagEntry(mergeTagEntry)) return void MergeTagValueResolver_logger.warn(`${RESOLUTION_WARNING_BASE} supplied entry is not a Merge Tag entry`);
158
- const { fields: { nt_fallback: fallback } } = mergeTagEntry;
159
- if (!__rspack_external__contentful_optimization_api_client_cba5a7ee.Profile.safeParse(profile).success) {
160
- MergeTagValueResolver_logger.warn(`${RESOLUTION_WARNING_BASE} no valid profile`);
161
- return fallback;
162
- }
163
- return MergeTagValueResolver.getValueFromProfile(mergeTagEntry.fields.nt_mergetag_id, profile) ?? fallback;
164
- }
165
- };
166
- const resolvers_MergeTagValueResolver = MergeTagValueResolver;
167
- const PersonalizedEntryResolver_logger = createScopedLogger('Personalization');
168
- const PersonalizedEntryResolver_RESOLUTION_WARNING_BASE = 'Could not resolve personalized entry variant:';
169
- const PersonalizedEntryResolver = {
170
- getPersonalizationEntry ({ personalizedEntry, selectedPersonalizations }, skipValidation = false) {
171
- if (!skipValidation && (!selectedPersonalizations.length || !(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isPersonalizedEntry)(personalizedEntry))) return;
172
- const personalizationEntry = personalizedEntry.fields.nt_experiences.filter((maybePersonalization)=>(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isPersonalizationEntry)(maybePersonalization)).find((personalizationEntry)=>selectedPersonalizations.some(({ experienceId })=>experienceId === personalizationEntry.fields.nt_experience_id));
173
- return personalizationEntry;
174
- },
175
- getSelectedPersonalization ({ personalizationEntry, selectedPersonalizations }, skipValidation = false) {
176
- if (!skipValidation && (!selectedPersonalizations.length || !(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isPersonalizationEntry)(personalizationEntry))) return;
177
- const selectedPersonalization = selectedPersonalizations.find(({ experienceId })=>experienceId === personalizationEntry.fields.nt_experience_id);
178
- return selectedPersonalization;
179
- },
180
- getSelectedVariant ({ personalizedEntry, personalizationEntry, selectedVariantIndex }, skipValidation = false) {
181
- if (!skipValidation && (!(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isPersonalizedEntry)(personalizedEntry) || !(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isPersonalizationEntry)(personalizationEntry))) return;
182
- const relevantVariants = personalizationEntry.fields.nt_config?.components?.filter((component)=>(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isEntryReplacementComponent)(component) && !component.baseline.hidden).find((component)=>component.baseline.id === personalizedEntry.sys.id)?.variants;
183
- if (!relevantVariants?.length) return;
184
- return relevantVariants.at(selectedVariantIndex - 1);
185
- },
186
- getSelectedVariantEntry ({ personalizationEntry, selectedVariant }, skipValidation = false) {
187
- if (!skipValidation && (!(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isPersonalizationEntry)(personalizationEntry) || !(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isEntryReplacementVariant)(selectedVariant))) return;
188
- const selectedVariantEntry = personalizationEntry.fields.nt_variants?.find((variant)=>variant.sys.id === selectedVariant.id);
189
- return (0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isEntry)(selectedVariantEntry) ? selectedVariantEntry : void 0;
190
- },
191
- resolve (entry, selectedPersonalizations) {
192
- PersonalizedEntryResolver_logger.debug(`Resolving personalized entry for baseline entry ${entry.sys.id}`);
193
- if (!selectedPersonalizations?.length) {
194
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} no selectedPersonalizations exist for the current profile`);
195
- return {
196
- entry
197
- };
198
- }
199
- if (!(0, __rspack_external__contentful_optimization_api_client_cba5a7ee.isPersonalizedEntry)(entry)) {
200
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} entry ${entry.sys.id} is not personalized`);
201
- return {
202
- entry
203
- };
204
- }
205
- const personalizationEntry = PersonalizedEntryResolver.getPersonalizationEntry({
206
- personalizedEntry: entry,
207
- selectedPersonalizations
208
- }, true);
209
- if (!personalizationEntry) {
210
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a personalization entry for ${entry.sys.id}`);
211
- return {
212
- entry
213
- };
214
- }
215
- const selectedPersonalization = PersonalizedEntryResolver.getSelectedPersonalization({
216
- personalizationEntry,
217
- selectedPersonalizations
218
- }, true);
219
- const selectedVariantIndex = selectedPersonalization?.variantIndex ?? 0;
220
- if (0 === selectedVariantIndex) {
221
- PersonalizedEntryResolver_logger.debug(`Resolved personalization entry for entry ${entry.sys.id} is baseline`);
23
+ subscribe (next) {
24
+ const dispose = effect(()=>{
25
+ next(cloneDeep(s.value));
26
+ });
222
27
  return {
223
- entry
28
+ unsubscribe: dispose
224
29
  };
225
- }
226
- const selectedVariant = PersonalizedEntryResolver.getSelectedVariant({
227
- personalizedEntry: entry,
228
- personalizationEntry,
229
- selectedVariantIndex
230
- }, true);
231
- if (!selectedVariant) {
232
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
233
- return {
234
- entry
30
+ },
31
+ subscribeOnce (next) {
32
+ let closed = false;
33
+ let isEffectActive = false;
34
+ let dispose = ()=>void 0;
35
+ const stop = ()=>{
36
+ if (closed) return;
37
+ closed = true;
38
+ if (isEffectActive) dispose();
235
39
  };
236
- }
237
- const selectedVariantEntry = PersonalizedEntryResolver.getSelectedVariantEntry({
238
- personalizationEntry,
239
- selectedVariant
240
- }, true);
241
- if (selectedVariantEntry) PersonalizedEntryResolver_logger.debug(`Entry ${entry.sys.id} has been resolved to variant entry ${selectedVariantEntry.sys.id}`);
242
- else {
243
- PersonalizedEntryResolver_logger.warn(`${PersonalizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
40
+ dispose = effect(()=>{
41
+ if (closed) return;
42
+ const { value } = s;
43
+ if (!isNonNullish(value)) return;
44
+ closed = true;
45
+ let callbackError = null;
46
+ try {
47
+ next(cloneDeep(value));
48
+ } catch (error) {
49
+ callbackError = toError(error);
50
+ }
51
+ if (isEffectActive) dispose();
52
+ else queueMicrotask(dispose);
53
+ if (callbackError) throw callbackError;
54
+ });
55
+ isEffectActive = true;
244
56
  return {
245
- entry
57
+ unsubscribe: stop
246
58
  };
247
59
  }
248
- return {
249
- entry: selectedVariantEntry,
250
- personalization: selectedPersonalization
251
- };
252
- }
253
- };
254
- const resolvers_PersonalizedEntryResolver = PersonalizedEntryResolver;
255
- const signals_changes = signal();
256
- const consent = signal();
257
- const signals_event = signal();
258
- const flags = computed(()=>resolvers_FlagsResolver.resolve(signals_changes.value ?? []));
259
- const online = signal(true);
260
- const signals_personalizations = signal();
261
- const signals_profile = signal();
262
- function toObservable(s) {
60
+ };
61
+ }
62
+ function toDistinctObservable(s, isEqual) {
63
+ const observable = toObservable(s);
263
64
  return {
65
+ get current () {
66
+ return observable.current;
67
+ },
264
68
  subscribe (next) {
265
- const dispose = effect(()=>{
266
- next(s.value);
69
+ let hasPrevious = false;
70
+ let previous = cloneDeep(observable.current);
71
+ return observable.subscribe((value)=>{
72
+ if (hasPrevious && isEqual(previous, value)) return;
73
+ hasPrevious = true;
74
+ previous = cloneDeep(value);
75
+ next(value);
267
76
  });
268
- return {
269
- unsubscribe: dispose
270
- };
77
+ },
78
+ subscribeOnce (next) {
79
+ return observable.subscribeOnce(next);
271
80
  }
272
81
  };
273
82
  }
83
+ const signals_changes = signal();
84
+ const blockedEvent = signal();
85
+ const consent = signal();
86
+ const signals_event = signal();
87
+ const online = signal(true);
88
+ const previewPanelAttached = signal(false);
89
+ const previewPanelOpen = signal(false);
90
+ const signals_selectedOptimizations = signal();
91
+ const canOptimize = computed(()=>void 0 !== signals_selectedOptimizations.value);
92
+ const signals_profile = signal();
274
93
  const signals = {
94
+ blockedEvent: blockedEvent,
275
95
  changes: signals_changes,
276
96
  consent: consent,
277
97
  event: signals_event,
278
- flags: flags,
279
98
  online: online,
280
- personalizations: signals_personalizations,
99
+ previewPanelAttached: previewPanelAttached,
100
+ previewPanelOpen: previewPanelOpen,
101
+ selectedOptimizations: signals_selectedOptimizations,
102
+ canOptimize: canOptimize,
281
103
  profile: signals_profile
282
104
  };
283
- const isFunction = (v)=>'function' == typeof v;
284
- const nameToString = (name)=>'string' == typeof name ? name : 'symbol' == typeof name ? name.description ?? String(name) : String(name);
285
- const isOnBlockedKey = (v)=>'string' == typeof v || 'symbol' == typeof v;
286
- const isAsyncFunction = (fn)=>'[object AsyncFunction]' === Object.prototype.toString.call(fn);
287
- function guardedBy(predicateName, opts) {
288
- return function(_value, context) {
289
- const decoratedName = nameToString(context.name);
290
- context.addInitializer(function() {
291
- const originalUnknown = Reflect.get(this, context.name);
292
- if (!isFunction(originalUnknown)) return;
293
- const original = originalUnknown;
294
- const originalIsAsync = isAsyncFunction(original);
295
- const resolvePredicate = (self)=>{
296
- const { [predicateName]: cand } = self;
297
- if (!isFunction(cand)) throw new TypeError(`@guardedBy expects predicate "${String(predicateName)}" to be a synchronous function.`);
298
- return cand;
299
- };
300
- const computeAllowed = (self, args)=>{
301
- const pred = resolvePredicate(self);
302
- const ok = Boolean(pred.call(self, decoratedName, args));
303
- return opts?.invert === true ? !ok : ok;
304
- };
305
- const runOnBlocked = (self, args)=>{
306
- const { onBlocked } = opts ?? {};
307
- if (void 0 === onBlocked) return;
308
- if (isFunction(onBlocked)) return void onBlocked.call(self, decoratedName, args);
309
- if (isOnBlockedKey(onBlocked)) {
310
- const { [onBlocked]: handlerCandidate } = self;
311
- if (isFunction(handlerCandidate)) handlerCandidate.call(self, decoratedName, args);
312
- }
313
- };
314
- const blockedReturn = ()=>originalIsAsync ? Promise.resolve(void 0) : void 0;
315
- const wrapped = function(...args) {
316
- if (!computeAllowed(this, args)) {
317
- runOnBlocked(this, args);
318
- return blockedReturn();
319
- }
320
- return original.call(this, ...args);
321
- };
322
- Reflect.set(this, context.name, wrapped);
323
- });
324
- };
325
- }
326
- class ValuePresence {
327
- #map;
328
- constructor(defaultMap){
329
- const map = new Map();
330
- if (defaultMap) Object.entries(defaultMap).map(([scope, values])=>map.set(scope.length ? scope : void 0, new Set(values)));
331
- this.#map = map;
332
- }
333
- isPresent(scope, value) {
334
- return this.#map.get(scope)?.has(value) ?? false;
335
- }
336
- addValue(scope, value) {
337
- const values = this.#map.get(scope);
338
- if (values) values.add(value);
339
- else this.#map.set(scope, new Set([
340
- value
341
- ]));
342
- }
343
- removeValue(scope, value) {
344
- this.#map.get(scope)?.delete(value);
345
- }
346
- reset(scope) {
347
- if (void 0 !== scope) this.#map.get(scope)?.clear();
348
- else this.#map.clear();
349
- }
350
- }
351
- const value_presence_ValuePresence = ValuePresence;
352
- const defaultAllowedEvents = [
353
- 'page',
354
- 'identify'
355
- ];
356
- class ProductBase {
357
- allowedEventTypes;
358
- builder;
359
- api;
360
- duplicationDetector;
361
- interceptors;
362
- constructor(options){
363
- const { api, builder, config, interceptors } = options;
364
- this.allowedEventTypes = config?.allowedEventTypes ?? defaultAllowedEvents;
365
- this.api = api;
366
- this.builder = builder;
367
- this.duplicationDetector = new value_presence_ValuePresence(config?.preventedComponentEvents);
368
- this.interceptors = interceptors;
369
- }
370
- }
371
- const src_ProductBase = ProductBase;
372
- class AnalyticsBase extends src_ProductBase {
373
- }
374
- const analytics_AnalyticsBase = AnalyticsBase;
375
- function applyDecs2203RFactory() {
376
- function createAddInitializerMethod(initializers, decoratorFinishedRef) {
377
- return function(initializer) {
378
- assertNotFinished(decoratorFinishedRef, "addInitializer");
379
- assertCallable(initializer, "An initializer");
380
- initializers.push(initializer);
105
+ const signalFns = {
106
+ batch: batch,
107
+ computed: computed,
108
+ effect: effect,
109
+ untracked: untracked
110
+ };
111
+ const UniversalEventBuilderArgs = object({
112
+ campaign: optional(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.Campaign),
113
+ locale: optional(string()),
114
+ location: optional(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.GeoLocation),
115
+ page: optional(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.Page),
116
+ screen: optional(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.Screen),
117
+ userAgent: optional(string())
118
+ });
119
+ const EntryInteractionBuilderArgsBase = extend(UniversalEventBuilderArgs, {
120
+ componentId: string(),
121
+ experienceId: optional(string()),
122
+ variantIndex: optional(number())
123
+ });
124
+ const ViewBuilderArgs = extend(EntryInteractionBuilderArgsBase, {
125
+ sticky: optional(mini_boolean()),
126
+ viewId: string(),
127
+ viewDurationMs: number()
128
+ });
129
+ const FlagViewBuilderArgs = extend(EntryInteractionBuilderArgsBase, {
130
+ viewId: optional(string()),
131
+ viewDurationMs: optional(number())
132
+ });
133
+ const ClickBuilderArgs = EntryInteractionBuilderArgsBase;
134
+ const HoverBuilderArgs = extend(EntryInteractionBuilderArgsBase, {
135
+ hoverId: string(),
136
+ hoverDurationMs: number()
137
+ });
138
+ const IdentifyBuilderArgs = extend(UniversalEventBuilderArgs, {
139
+ traits: optional(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.Traits),
140
+ userId: string()
141
+ });
142
+ const PageViewBuilderArgs = extend(UniversalEventBuilderArgs, {
143
+ properties: optional(partial(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.Page))
144
+ });
145
+ const ScreenViewBuilderArgs = extend(UniversalEventBuilderArgs, {
146
+ name: string(),
147
+ properties: __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.Properties
148
+ });
149
+ const TrackBuilderArgs = extend(UniversalEventBuilderArgs, {
150
+ event: string(),
151
+ properties: optional(prefault(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.Properties, {}))
152
+ });
153
+ const DEFAULT_PAGE_PROPERTIES = {
154
+ path: '',
155
+ query: {},
156
+ referrer: '',
157
+ search: '',
158
+ title: '',
159
+ url: ''
160
+ };
161
+ class EventBuilder {
162
+ app;
163
+ channel;
164
+ library;
165
+ getLocale;
166
+ getPageProperties;
167
+ getUserAgent;
168
+ constructor(config){
169
+ const { app, channel, library, getLocale, getPageProperties, getUserAgent } = config;
170
+ this.app = app;
171
+ this.channel = channel;
172
+ this.library = library;
173
+ this.getLocale = getLocale ?? (()=>'en-US');
174
+ this.getPageProperties = getPageProperties ?? (()=>DEFAULT_PAGE_PROPERTIES);
175
+ this.getUserAgent = getUserAgent ?? (()=>void 0);
176
+ }
177
+ buildUniversalEventProperties({ campaign = {}, locale, location, page, screen, userAgent }) {
178
+ const timestamp = new Date().toISOString();
179
+ return {
180
+ channel: this.channel,
181
+ context: {
182
+ app: this.app,
183
+ campaign,
184
+ gdpr: {
185
+ isConsentGiven: true
186
+ },
187
+ library: this.library,
188
+ locale: locale ?? this.getLocale() ?? 'en-US',
189
+ location,
190
+ page: page ?? this.getPageProperties(),
191
+ screen,
192
+ userAgent: userAgent ?? this.getUserAgent()
193
+ },
194
+ messageId: crypto.randomUUID(),
195
+ originalTimestamp: timestamp,
196
+ sentAt: timestamp,
197
+ timestamp
381
198
  };
382
199
  }
383
- function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
384
- var kindStr;
385
- switch(kind){
386
- case 1:
387
- kindStr = "accessor";
388
- break;
389
- case 2:
390
- kindStr = "method";
391
- break;
392
- case 3:
393
- kindStr = "getter";
394
- break;
395
- case 4:
396
- kindStr = "setter";
397
- break;
398
- default:
399
- kindStr = "field";
400
- }
401
- var ctx = {
402
- kind: kindStr,
403
- name: isPrivate ? "#" + name : name,
404
- static: isStatic,
405
- private: isPrivate,
406
- metadata: metadata
407
- };
408
- var decoratorFinishedRef = {
409
- v: false
410
- };
411
- ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
412
- var get, set;
413
- if (0 === kind) if (isPrivate) {
414
- get = desc.get;
415
- set = desc.set;
416
- } else {
417
- get = function() {
418
- return this[name];
419
- };
420
- set = function(v) {
421
- this[name] = v;
422
- };
423
- }
424
- else if (2 === kind) get = function() {
425
- return desc.value;
426
- };
427
- else {
428
- if (1 === kind || 3 === kind) get = function() {
429
- return desc.get.call(this);
430
- };
431
- if (1 === kind || 4 === kind) set = function(v) {
432
- desc.set.call(this, v);
433
- };
434
- }
435
- ctx.access = get && set ? {
436
- get: get,
437
- set: set
438
- } : get ? {
439
- get: get
440
- } : {
441
- set: set
200
+ buildEntryInteractionBase(universal, componentId, experienceId, variantIndex) {
201
+ return {
202
+ ...this.buildUniversalEventProperties(universal),
203
+ componentType: 'Entry',
204
+ componentId,
205
+ experienceId,
206
+ variantIndex: variantIndex ?? 0
442
207
  };
443
- try {
444
- return dec(value, ctx);
445
- } finally{
446
- decoratorFinishedRef.v = true;
447
- }
448
- }
449
- function assertNotFinished(decoratorFinishedRef, fnName) {
450
- if (decoratorFinishedRef.v) throw new Error("attempted to call " + fnName + " after decoration was finished");
451
- }
452
- function assertCallable(fn, hint) {
453
- if ("function" != typeof fn) throw new TypeError(hint + " must be a function");
454
- }
455
- function assertValidReturnValue(kind, value) {
456
- var type = typeof value;
457
- if (1 === kind) {
458
- if ("object" !== type || null === value) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
459
- if (void 0 !== value.get) assertCallable(value.get, "accessor.get");
460
- if (void 0 !== value.set) assertCallable(value.set, "accessor.set");
461
- if (void 0 !== value.init) assertCallable(value.init, "accessor.init");
462
- } else if ("function" !== type) {
463
- var hint;
464
- hint = 0 === kind ? "field" : 10 === kind ? "class" : "method";
465
- throw new TypeError(hint + " decorators must return a function or void 0");
466
- }
467
208
  }
468
- function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
469
- var decs = decInfo[0];
470
- var desc, init, value;
471
- if (isPrivate) desc = 0 === kind || 1 === kind ? {
472
- get: decInfo[3],
473
- set: decInfo[4]
474
- } : 3 === kind ? {
475
- get: decInfo[3]
476
- } : 4 === kind ? {
477
- set: decInfo[3]
478
- } : {
479
- value: decInfo[3]
480
- };
481
- else if (0 !== kind) desc = Object.getOwnPropertyDescriptor(base, name);
482
- if (1 === kind) value = {
483
- get: desc.get,
484
- set: desc.set
209
+ buildView(args) {
210
+ const { componentId, viewId, experienceId, variantIndex, viewDurationMs, ...universal } = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(ViewBuilderArgs, args);
211
+ return {
212
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
213
+ type: 'component',
214
+ viewId,
215
+ viewDurationMs
485
216
  };
486
- else if (2 === kind) value = desc.value;
487
- else if (3 === kind) value = desc.get;
488
- else if (4 === kind) value = desc.set;
489
- var newValue, get, set;
490
- if ("function" == typeof decs) {
491
- newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
492
- if (void 0 !== newValue) {
493
- assertValidReturnValue(kind, newValue);
494
- if (0 === kind) init = newValue;
495
- else if (1 === kind) {
496
- init = newValue.init;
497
- get = newValue.get || value.get;
498
- set = newValue.set || value.set;
499
- value = {
500
- get: get,
501
- set: set
502
- };
503
- } else value = newValue;
504
- }
505
- } else for(var i = decs.length - 1; i >= 0; i--){
506
- var dec = decs[i];
507
- newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
508
- if (void 0 !== newValue) {
509
- assertValidReturnValue(kind, newValue);
510
- var newInit;
511
- if (0 === kind) newInit = newValue;
512
- else if (1 === kind) {
513
- newInit = newValue.init;
514
- get = newValue.get || value.get;
515
- set = newValue.set || value.set;
516
- value = {
517
- get: get,
518
- set: set
519
- };
520
- } else value = newValue;
521
- if (void 0 !== newInit) if (void 0 === init) init = newInit;
522
- else if ("function" == typeof init) init = [
523
- init,
524
- newInit
525
- ];
526
- else init.push(newInit);
527
- }
528
- }
529
- if (0 === kind || 1 === kind) {
530
- if (void 0 === init) init = function(instance, init) {
531
- return init;
532
- };
533
- else if ("function" != typeof init) {
534
- var ownInitializers = init;
535
- init = function(instance, init) {
536
- var value = init;
537
- for(var i = 0; i < ownInitializers.length; i++)value = ownInitializers[i].call(instance, value);
538
- return value;
539
- };
540
- } else {
541
- var originalInitializer = init;
542
- init = function(instance, init) {
543
- return originalInitializer.call(instance, init);
544
- };
545
- }
546
- ret.push(init);
547
- }
548
- if (0 !== kind) {
549
- if (1 === kind) {
550
- desc.get = value.get;
551
- desc.set = value.set;
552
- } else if (2 === kind) desc.value = value;
553
- else if (3 === kind) desc.get = value;
554
- else if (4 === kind) desc.set = value;
555
- if (isPrivate) if (1 === kind) {
556
- ret.push(function(instance, args) {
557
- return value.get.call(instance, args);
558
- });
559
- ret.push(function(instance, args) {
560
- return value.set.call(instance, args);
561
- });
562
- } else if (2 === kind) ret.push(value);
563
- else ret.push(function(instance, args) {
564
- return value.call(instance, args);
565
- });
566
- else Object.defineProperty(base, name, desc);
567
- }
568
217
  }
569
- function applyMemberDecs(Class, decInfos, metadata) {
570
- var ret = [];
571
- var protoInitializers;
572
- var staticInitializers;
573
- var existingProtoNonFields = new Map();
574
- var existingStaticNonFields = new Map();
575
- for(var i = 0; i < decInfos.length; i++){
576
- var decInfo = decInfos[i];
577
- if (Array.isArray(decInfo)) {
578
- var kind = decInfo[1];
579
- var name = decInfo[2];
580
- var isPrivate = decInfo.length > 3;
581
- var isStatic = kind >= 5;
582
- var base;
583
- var initializers;
584
- if (isStatic) {
585
- base = Class;
586
- kind -= 5;
587
- staticInitializers = staticInitializers || [];
588
- initializers = staticInitializers;
589
- } else {
590
- base = Class.prototype;
591
- protoInitializers = protoInitializers || [];
592
- initializers = protoInitializers;
593
- }
594
- if (0 !== kind && !isPrivate) {
595
- var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
596
- var existingKind = existingNonFields.get(name) || 0;
597
- 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);
598
- if (!existingKind && kind > 2) existingNonFields.set(name, kind);
599
- else existingNonFields.set(name, true);
600
- }
601
- applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
602
- }
603
- }
604
- pushInitializers(ret, protoInitializers);
605
- pushInitializers(ret, staticInitializers);
606
- return ret;
607
- }
608
- function pushInitializers(ret, initializers) {
609
- if (initializers) ret.push(function(instance) {
610
- for(var i = 0; i < initializers.length; i++)initializers[i].call(instance);
611
- return instance;
612
- });
613
- }
614
- function applyClassDecs(targetClass, classDecs, metadata) {
615
- if (classDecs.length > 0) {
616
- var initializers = [];
617
- var newClass = targetClass;
618
- var name = targetClass.name;
619
- for(var i = classDecs.length - 1; i >= 0; i--){
620
- var decoratorFinishedRef = {
621
- v: false
622
- };
623
- try {
624
- var nextNewClass = classDecs[i](newClass, {
625
- kind: "class",
626
- name: name,
627
- addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
628
- metadata
629
- });
630
- } finally{
631
- decoratorFinishedRef.v = true;
632
- }
633
- if (void 0 !== nextNewClass) {
634
- assertValidReturnValue(10, nextNewClass);
635
- newClass = nextNewClass;
636
- }
637
- }
638
- return [
639
- defineMetadata(newClass, metadata),
640
- function() {
641
- for(var i = 0; i < initializers.length; i++)initializers[i].call(newClass);
642
- }
643
- ];
644
- }
645
- }
646
- function defineMetadata(Class, metadata) {
647
- return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
648
- configurable: true,
649
- enumerable: true,
650
- value: metadata
651
- });
652
- }
653
- return function(targetClass, memberDecs, classDecs, parentClass) {
654
- if (void 0 !== parentClass) var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
655
- var metadata = Object.create(void 0 === parentMetadata ? null : parentMetadata);
656
- var e = applyMemberDecs(targetClass, memberDecs, metadata);
657
- if (!classDecs.length) defineMetadata(targetClass, metadata);
218
+ buildClick(args) {
219
+ const { componentId, experienceId, variantIndex, ...universal } = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(ClickBuilderArgs, args);
658
220
  return {
659
- e: e,
660
- get c () {
661
- return applyClassDecs(targetClass, classDecs, metadata);
662
- }
221
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
222
+ type: 'component_click'
663
223
  };
664
- };
665
- }
666
- function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
667
- return (_apply_decs_2203_r = applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
668
- }
669
- var _dec, _dec1, _dec2, _dec3, _initProto;
670
- const AnalyticsStateful_logger = createScopedLogger('Analytics');
671
- const MAX_QUEUED_EVENTS = 25;
672
- _dec = guardedBy('isNotDuplicated', {
673
- onBlocked: 'onBlockedByDuplication'
674
- }), _dec1 = guardedBy('hasConsent', {
675
- onBlocked: 'onBlockedByConsent'
676
- }), _dec2 = guardedBy('isNotDuplicated', {
677
- onBlocked: 'onBlockedByDuplication'
678
- }), _dec3 = guardedBy('hasConsent', {
679
- onBlocked: 'onBlockedByConsent'
680
- });
681
- class AnalyticsStateful extends analytics_AnalyticsBase {
682
- static{
683
- ({ e: [_initProto] } = _apply_decs_2203_r(this, [
684
- [
685
- [
686
- _dec,
687
- _dec1
688
- ],
689
- 2,
690
- "trackComponentView"
691
- ],
692
- [
693
- [
694
- _dec2,
695
- _dec3
696
- ],
697
- 2,
698
- "trackFlagView"
699
- ]
700
- ], []));
701
- }
702
- queue = (_initProto(this), new Map());
703
- states = {
704
- eventStream: toObservable(signals_event),
705
- profile: toObservable(signals_profile)
706
- };
707
- constructor(options){
708
- const { api, builder, config, interceptors } = options;
709
- super({
710
- api,
711
- builder,
712
- config,
713
- interceptors
714
- });
715
- const { defaults } = config ?? {};
716
- if (defaults?.profile !== void 0) {
717
- const { profile: defaultProfile } = defaults;
718
- signals_profile.value = defaultProfile;
719
- }
720
- effect(()=>{
721
- const id = signals_profile.value?.id;
722
- AnalyticsStateful_logger.info(`Analytics ${consent.value ? 'will' : 'will not'} be collected due to consent (${consent.value})`);
723
- AnalyticsStateful_logger.debug(`Profile ${id && `with ID ${id}`} has been ${id ? 'set' : 'cleared'}`);
724
- });
725
- effect(()=>{
726
- if (online.value) this.flush();
727
- });
728
224
  }
729
- reset() {
730
- batch(()=>{
731
- signals_event.value = void 0;
732
- signals_profile.value = void 0;
733
- });
734
- }
735
- hasConsent(name) {
736
- return !!consent.value || (this.allowedEventTypes ?? []).includes('trackComponentView' === name || 'trackFlagView' === name ? 'component' : name);
737
- }
738
- onBlockedByConsent(name, payload) {
739
- AnalyticsStateful_logger.warn(`Event "${name}" was blocked due to lack of consent; payload: ${JSON.stringify(payload)}`);
740
- }
741
- isNotDuplicated(_name, payload) {
742
- const [{ componentId: value }, duplicationScope] = payload;
743
- const isDuplicated = this.duplicationDetector.isPresent(duplicationScope, value);
744
- if (!isDuplicated) this.duplicationDetector.addValue(duplicationScope, value);
745
- return !isDuplicated;
746
- }
747
- onBlockedByDuplication(name, payload) {
748
- const componentType = 'trackFlagView' === name ? 'flag' : 'component';
749
- AnalyticsStateful_logger.debug(`Duplicate "${componentType} view" event detected, skipping; payload: ${JSON.stringify(payload)}`);
750
- }
751
- async trackComponentView(payload, _duplicationScope = '') {
752
- AnalyticsStateful_logger.info(`Processing "component view" event for ${payload.componentId}`);
753
- await this.enqueueEvent(this.builder.buildComponentView(payload));
225
+ buildHover(args) {
226
+ const { hoverId, componentId, experienceId, hoverDurationMs, variantIndex, ...universal } = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(HoverBuilderArgs, args);
227
+ return {
228
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
229
+ type: 'component_hover',
230
+ hoverId,
231
+ hoverDurationMs
232
+ };
754
233
  }
755
- async trackFlagView(payload, _duplicationScope = '') {
756
- AnalyticsStateful_logger.debug(`Processing "flag view" event for ${payload.componentId}`);
757
- await this.enqueueEvent(this.builder.buildFlagView(payload));
234
+ buildFlagView(args) {
235
+ const { componentId, experienceId, variantIndex, viewId, viewDurationMs, ...universal } = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(FlagViewBuilderArgs, args);
236
+ return {
237
+ ...this.buildEntryInteractionBase(universal, componentId, experienceId, variantIndex),
238
+ ...void 0 === viewDurationMs ? {} : {
239
+ viewDurationMs
240
+ },
241
+ ...void 0 === viewId ? {} : {
242
+ viewId
243
+ },
244
+ type: 'component',
245
+ componentType: 'Variable'
246
+ };
758
247
  }
759
- async enqueueEvent(event) {
760
- const { value: profile } = signals_profile;
761
- if (!profile) return void AnalyticsStateful_logger.warn('Attempting to emit an event without an Optimization profile');
762
- const intercepted = await this.interceptors.event.run(event);
763
- const validEvent = __rspack_external__contentful_optimization_api_client_cba5a7ee.InsightsEvent.parse(intercepted);
764
- AnalyticsStateful_logger.debug(`Queueing ${validEvent.type} event for profile ${profile.id}`, validEvent);
765
- const profileEventQueue = this.queue.get(profile);
766
- signals_event.value = validEvent;
767
- if (profileEventQueue) profileEventQueue.push(validEvent);
768
- else this.queue.set(profile, [
769
- validEvent
770
- ]);
771
- await this.flushMaxEvents();
248
+ buildIdentify(args) {
249
+ const { traits = {}, userId, ...universal } = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(IdentifyBuilderArgs, args);
250
+ return {
251
+ ...this.buildUniversalEventProperties(universal),
252
+ type: 'identify',
253
+ traits,
254
+ userId
255
+ };
772
256
  }
773
- async flushMaxEvents() {
774
- if (this.queue.values().toArray().flat().length >= MAX_QUEUED_EVENTS) await this.flush();
257
+ buildPageView(args = {}) {
258
+ const { properties = {}, ...universal } = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(PageViewBuilderArgs, args);
259
+ const pageProperties = this.getPageProperties();
260
+ const merged = merge({
261
+ ...pageProperties,
262
+ title: pageProperties.title ?? DEFAULT_PAGE_PROPERTIES.title
263
+ }, properties);
264
+ const { context: { screen: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
265
+ const context = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.PageEventContext, universalContext);
266
+ return {
267
+ ...universalProperties,
268
+ context,
269
+ type: 'page',
270
+ properties: merged
271
+ };
775
272
  }
776
- async flush() {
777
- AnalyticsStateful_logger.debug('Flushing event queue');
778
- const batches = [];
779
- this.queue.forEach((events, profile)=>batches.push({
780
- profile,
781
- events
782
- }));
783
- if (!batches.length) return;
784
- const sendSuccess = await this.api.insights.sendBatchEvents(batches);
785
- if (sendSuccess) this.queue.clear();
273
+ buildScreenView(args) {
274
+ const { name, properties, ...universal } = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(ScreenViewBuilderArgs, args);
275
+ const { context: { page: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
276
+ const context = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.ScreenEventContext, universalContext);
277
+ return {
278
+ ...universalProperties,
279
+ context,
280
+ type: 'screen',
281
+ name,
282
+ properties
283
+ };
786
284
  }
787
- }
788
- const analytics_AnalyticsStateful = AnalyticsStateful;
789
- const AnalyticsStateless_logger = createScopedLogger('Analytics');
790
- class AnalyticsStateless extends analytics_AnalyticsBase {
791
- async trackComponentView(args) {
792
- AnalyticsStateless_logger.info('Processing "component view" event');
793
- const { profile, ...builderArgs } = args;
794
- const event = this.builder.buildComponentView(builderArgs);
795
- const intercepted = await this.interceptors.event.run(event);
796
- const parsed = __rspack_external__contentful_optimization_api_client_cba5a7ee.ComponentViewEvent.parse(intercepted);
797
- await this.sendBatchEvent(parsed, profile);
798
- }
799
- async trackFlagView(args) {
800
- AnalyticsStateless_logger.debug('Processing "flag view" event');
801
- const { profile, ...builderArgs } = args;
802
- const event = this.builder.buildFlagView(builderArgs);
803
- const intercepted = await this.interceptors.event.run(event);
804
- const parsed = __rspack_external__contentful_optimization_api_client_cba5a7ee.ComponentViewEvent.parse(intercepted);
805
- await this.sendBatchEvent(parsed, profile);
806
- }
807
- async sendBatchEvent(event, profile) {
808
- const batchEvent = __rspack_external__contentful_optimization_api_client_cba5a7ee.BatchInsightsEventArray.parse([
809
- {
810
- profile,
811
- events: [
812
- event
813
- ]
814
- }
815
- ]);
816
- await this.api.insights.sendBatchEvents(batchEvent);
285
+ buildTrack(args) {
286
+ const { event, properties = {}, ...universal } = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(TrackBuilderArgs, args);
287
+ return {
288
+ ...this.buildUniversalEventProperties(universal),
289
+ type: 'track',
290
+ event,
291
+ properties
292
+ };
817
293
  }
818
294
  }
819
- const analytics_AnalyticsStateless = AnalyticsStateless;
820
- const OPTIMIZATION_CORE_SDK_VERSION = "0.1.0-alpha";
821
- const ANONYMOUS_ID_COOKIE = 'ctfl-opt-aid';
295
+ const events_EventBuilder = EventBuilder;
822
296
  class InterceptorManager {
823
297
  interceptors = new Map();
824
298
  nextId = 0;
@@ -840,696 +314,1075 @@ class InterceptorManager {
840
314
  async run(input) {
841
315
  const fns = Array.from(this.interceptors.values());
842
316
  let acc = input;
843
- for (const fn of fns)acc = await fn(acc);
317
+ for (const fn of fns)acc = await fn(cloneDeep(acc));
844
318
  return acc;
845
319
  }
846
320
  }
321
+ const FlagsResolver = {
322
+ resolve (changes) {
323
+ if (!changes) return {};
324
+ return changes.reduce((acc, { key, value })=>{
325
+ const actualValue = 'object' == typeof value && null !== value && 'value' in value && 'object' == typeof value.value ? value.value : value;
326
+ acc[key] = actualValue;
327
+ return acc;
328
+ }, {});
329
+ }
330
+ };
331
+ const resolvers_FlagsResolver = FlagsResolver;
332
+ const logger = (0, __rspack_external__contentful_optimization_api_client_logger_f0d05f82.createScopedLogger)('Optimization');
333
+ const RESOLUTION_WARNING_BASE = 'Could not resolve Merge Tag value:';
334
+ const getAtPath = (value, path)=>{
335
+ if (!value || 'object' != typeof value) return;
336
+ if (!path) return value;
337
+ let current = value;
338
+ const segments = path.split('.').filter(Boolean);
339
+ for (const segment of segments){
340
+ if (!current || 'object' != typeof current && 'function' != typeof current) return;
341
+ current = Reflect.get(current, segment);
342
+ }
343
+ return current;
344
+ };
345
+ const MergeTagValueResolver = {
346
+ normalizeSelectors (id) {
347
+ return id.split('_').map((_path, index, paths)=>{
348
+ const dotPath = paths.slice(0, index).join('.');
349
+ const underScorePath = paths.slice(index).join('_');
350
+ return [
351
+ dotPath,
352
+ underScorePath
353
+ ].filter((path)=>'' !== path).join('.');
354
+ });
355
+ },
356
+ getValueFromProfile (id, profile) {
357
+ const selectors = MergeTagValueResolver.normalizeSelectors(id);
358
+ const matchingSelector = selectors.find((selector)=>getAtPath(profile, selector));
359
+ if (!matchingSelector) return;
360
+ const value = getAtPath(profile, matchingSelector);
361
+ if (!value || 'string' != typeof value && 'number' != typeof value && 'boolean' != typeof value) return;
362
+ return `${value}`;
363
+ },
364
+ resolve (mergeTagEntry, profile) {
365
+ if (!(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isMergeTagEntry)(mergeTagEntry)) return void logger.warn(`${RESOLUTION_WARNING_BASE} supplied entry is not a Merge Tag entry`);
366
+ const { fields: { nt_fallback: fallback } } = mergeTagEntry;
367
+ if (!__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.Profile.safeParse(profile).success) {
368
+ logger.warn(`${RESOLUTION_WARNING_BASE} no valid profile`);
369
+ return fallback;
370
+ }
371
+ return MergeTagValueResolver.getValueFromProfile(mergeTagEntry.fields.nt_mergetag_id, profile) ?? fallback;
372
+ }
373
+ };
374
+ const resolvers_MergeTagValueResolver = MergeTagValueResolver;
375
+ const OptimizedEntryResolver_logger = (0, __rspack_external__contentful_optimization_api_client_logger_f0d05f82.createScopedLogger)('Optimization');
376
+ const OptimizedEntryResolver_RESOLUTION_WARNING_BASE = 'Could not resolve optimized entry variant:';
377
+ function resolve(entry, selectedOptimizations) {
378
+ OptimizedEntryResolver_logger.debug(`Resolving optimized entry for baseline entry ${entry.sys.id}`);
379
+ if (!selectedOptimizations?.length) {
380
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} no selectedOptimizations exist for the current profile`);
381
+ return {
382
+ entry
383
+ };
384
+ }
385
+ if (!(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isOptimizedEntry)(entry)) {
386
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} entry ${entry.sys.id} is not optimized`);
387
+ return {
388
+ entry
389
+ };
390
+ }
391
+ const optimizationEntry = OptimizedEntryResolver.getOptimizationEntry({
392
+ optimizedEntry: entry,
393
+ selectedOptimizations
394
+ }, true);
395
+ if (!optimizationEntry) {
396
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find an optimization entry for ${entry.sys.id}`);
397
+ return {
398
+ entry
399
+ };
400
+ }
401
+ const selectedOptimization = OptimizedEntryResolver.getSelectedOptimization({
402
+ optimizationEntry,
403
+ selectedOptimizations
404
+ }, true);
405
+ const selectedVariantIndex = selectedOptimization?.variantIndex ?? 0;
406
+ if (0 === selectedVariantIndex) {
407
+ OptimizedEntryResolver_logger.debug(`Resolved optimization entry for entry ${entry.sys.id} is baseline`);
408
+ return {
409
+ entry
410
+ };
411
+ }
412
+ const selectedVariant = OptimizedEntryResolver.getSelectedVariant({
413
+ optimizedEntry: entry,
414
+ optimizationEntry,
415
+ selectedVariantIndex
416
+ }, true);
417
+ if (!selectedVariant) {
418
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
419
+ return {
420
+ entry
421
+ };
422
+ }
423
+ const selectedVariantEntry = OptimizedEntryResolver.getSelectedVariantEntry({
424
+ optimizationEntry,
425
+ selectedVariant
426
+ }, true);
427
+ if (selectedVariantEntry) OptimizedEntryResolver_logger.debug(`Entry ${entry.sys.id} has been resolved to variant entry ${selectedVariantEntry.sys.id}`);
428
+ else {
429
+ OptimizedEntryResolver_logger.warn(`${OptimizedEntryResolver_RESOLUTION_WARNING_BASE} could not find a valid replacement variant entry for ${entry.sys.id}`);
430
+ return {
431
+ entry
432
+ };
433
+ }
434
+ return {
435
+ entry: selectedVariantEntry,
436
+ selectedOptimization
437
+ };
438
+ }
439
+ const OptimizedEntryResolver = {
440
+ getOptimizationEntry ({ optimizedEntry, selectedOptimizations }, skipValidation = false) {
441
+ if (!skipValidation && (!selectedOptimizations.length || !(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isOptimizedEntry)(optimizedEntry))) return;
442
+ const optimizationEntry = optimizedEntry.fields.nt_experiences.filter((maybeOptimization)=>(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isOptimizationEntry)(maybeOptimization)).find((optimizationEntry)=>selectedOptimizations.some(({ experienceId })=>experienceId === optimizationEntry.fields.nt_experience_id));
443
+ return optimizationEntry;
444
+ },
445
+ getSelectedOptimization ({ optimizationEntry, selectedOptimizations }, skipValidation = false) {
446
+ if (!skipValidation && (!selectedOptimizations.length || !(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isOptimizationEntry)(optimizationEntry))) return;
447
+ const selectedOptimization = selectedOptimizations.find(({ experienceId })=>experienceId === optimizationEntry.fields.nt_experience_id);
448
+ return selectedOptimization;
449
+ },
450
+ getSelectedVariant ({ optimizedEntry, optimizationEntry, selectedVariantIndex }, skipValidation = false) {
451
+ if (!skipValidation && (!(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isOptimizedEntry)(optimizedEntry) || !(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isOptimizationEntry)(optimizationEntry))) return;
452
+ const relevantVariants = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.normalizeOptimizationConfig)(optimizationEntry.fields.nt_config).components.filter((component)=>(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isEntryReplacementComponent)(component) && !component.baseline.hidden).find((component)=>component.baseline.id === optimizedEntry.sys.id)?.variants;
453
+ if (!relevantVariants?.length) return;
454
+ return relevantVariants.at(selectedVariantIndex - 1);
455
+ },
456
+ getSelectedVariantEntry ({ optimizationEntry, selectedVariant }, skipValidation = false) {
457
+ if (!skipValidation && (!(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isOptimizationEntry)(optimizationEntry) || !(0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isEntryReplacementVariant)(selectedVariant))) return;
458
+ const selectedVariantEntry = optimizationEntry.fields.nt_variants?.find((variant)=>variant.sys.id === selectedVariant.id);
459
+ return (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.isEntry)(selectedVariantEntry) ? selectedVariantEntry : void 0;
460
+ },
461
+ resolve: resolve
462
+ };
463
+ const resolvers_OptimizedEntryResolver = OptimizedEntryResolver;
847
464
  class CoreBase {
848
465
  api;
849
466
  eventBuilder;
850
467
  config;
468
+ flagsResolver = resolvers_FlagsResolver;
469
+ mergeTagValueResolver = resolvers_MergeTagValueResolver;
470
+ optimizedEntryResolver = resolvers_OptimizedEntryResolver;
851
471
  interceptors = {
852
472
  event: new InterceptorManager(),
853
473
  state: new InterceptorManager()
854
474
  };
855
- constructor(config){
475
+ constructor(config, api = {}){
856
476
  this.config = config;
857
- const { analytics, personalization, eventBuilder, logLevel, environment, clientId } = config;
858
- logger.addSink(new ConsoleLogSink(logLevel));
477
+ const { eventBuilder, logLevel, environment, clientId, fetchOptions } = config;
478
+ __rspack_external__contentful_optimization_api_client_logger_f0d05f82.logger.addSink(new __rspack_external__contentful_optimization_api_client_logger_f0d05f82.ConsoleLogSink(logLevel));
859
479
  const apiConfig = {
860
- ...analytics,
861
- ...personalization,
862
480
  clientId,
863
- environment
481
+ environment,
482
+ fetchOptions,
483
+ experience: api.experience,
484
+ insights: api.insights
864
485
  };
865
486
  this.api = new __rspack_external__contentful_optimization_api_client_cba5a7ee.ApiClient(apiConfig);
866
- this.eventBuilder = new __rspack_external__contentful_optimization_api_client_cba5a7ee.EventBuilder(eventBuilder ?? {
487
+ this.eventBuilder = new events_EventBuilder(eventBuilder ?? {
867
488
  channel: 'server',
868
489
  library: {
869
- name: 'Optimization Core',
490
+ name: OPTIMIZATION_CORE_SDK_NAME,
870
491
  version: OPTIMIZATION_CORE_SDK_VERSION
871
492
  }
872
493
  });
873
494
  }
874
- getCustomFlag(name, changes) {
875
- return this.personalization.getCustomFlag(name, changes);
495
+ getFlag(name, changes) {
496
+ return this.flagsResolver.resolve(changes)[name];
876
497
  }
877
- personalizeEntry(entry, personalizations) {
878
- return this.personalization.personalizeEntry(entry, personalizations);
498
+ resolveOptimizedEntry(entry, selectedOptimizations) {
499
+ return this.optimizedEntryResolver.resolve(entry, selectedOptimizations);
879
500
  }
880
501
  getMergeTagValue(embeddedEntryNodeTarget, profile) {
881
- return this.personalization.getMergeTagValue(embeddedEntryNodeTarget, profile);
502
+ return this.mergeTagValueResolver.resolve(embeddedEntryNodeTarget, profile);
503
+ }
504
+ }
505
+ const src_CoreBase = CoreBase;
506
+ const coreLogger = (0, __rspack_external__contentful_optimization_api_client_logger_f0d05f82.createScopedLogger)('CoreStateful');
507
+ const CONSENT_EVENT_TYPE_MAP = {
508
+ trackView: 'component',
509
+ trackFlagView: 'component',
510
+ trackClick: 'component_click',
511
+ trackHover: 'component_hover'
512
+ };
513
+ class CoreStatefulEventEmitter extends src_CoreBase {
514
+ flagObservables = new Map();
515
+ getFlag(name, changes = signals_changes.value) {
516
+ const value = super.getFlag(name, changes);
517
+ const payload = this.buildFlagViewBuilderArgs(name, changes);
518
+ this.trackFlagView(payload).catch((error)=>{
519
+ __rspack_external__contentful_optimization_api_client_logger_f0d05f82.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
520
+ });
521
+ return value;
522
+ }
523
+ resolveOptimizedEntry(entry, selectedOptimizations = signals_selectedOptimizations.value) {
524
+ return super.resolveOptimizedEntry(entry, selectedOptimizations);
525
+ }
526
+ getMergeTagValue(embeddedEntryNodeTarget, profile = signals_profile.value) {
527
+ return super.getMergeTagValue(embeddedEntryNodeTarget, profile);
882
528
  }
883
529
  async identify(payload) {
884
- return await this.personalization.identify(payload);
530
+ const { profile, ...builderArgs } = payload;
531
+ return await this.sendExperienceEvent('identify', [
532
+ payload
533
+ ], this.eventBuilder.buildIdentify(builderArgs), profile);
534
+ }
535
+ async page(payload = {}) {
536
+ const { profile, ...builderArgs } = payload;
537
+ return await this.sendExperienceEvent('page', [
538
+ payload
539
+ ], this.eventBuilder.buildPageView(builderArgs), profile);
540
+ }
541
+ async screen(payload) {
542
+ const { profile, ...builderArgs } = payload;
543
+ return await this.sendExperienceEvent('screen', [
544
+ payload
545
+ ], this.eventBuilder.buildScreenView(builderArgs), profile);
546
+ }
547
+ async track(payload) {
548
+ const { profile, ...builderArgs } = payload;
549
+ return await this.sendExperienceEvent('track', [
550
+ payload
551
+ ], this.eventBuilder.buildTrack(builderArgs), profile);
552
+ }
553
+ async trackView(payload) {
554
+ const { profile, ...builderArgs } = payload;
555
+ let result;
556
+ if (payload.sticky) result = await this.sendExperienceEvent('trackView', [
557
+ payload
558
+ ], this.eventBuilder.buildView(builderArgs), profile);
559
+ await this.sendInsightsEvent('trackView', [
560
+ payload
561
+ ], this.eventBuilder.buildView(builderArgs), profile);
562
+ return result;
563
+ }
564
+ async trackClick(payload) {
565
+ await this.sendInsightsEvent('trackClick', [
566
+ payload
567
+ ], this.eventBuilder.buildClick(payload));
568
+ }
569
+ async trackHover(payload) {
570
+ await this.sendInsightsEvent('trackHover', [
571
+ payload
572
+ ], this.eventBuilder.buildHover(payload));
573
+ }
574
+ async trackFlagView(payload) {
575
+ await this.sendInsightsEvent('trackFlagView', [
576
+ payload
577
+ ], this.eventBuilder.buildFlagView(payload));
578
+ }
579
+ hasConsent(name) {
580
+ const { [name]: mappedEventType } = CONSENT_EVENT_TYPE_MAP;
581
+ const isAllowed = void 0 !== mappedEventType ? this.allowedEventTypes.includes(mappedEventType) : this.allowedEventTypes.some((eventType)=>eventType === name);
582
+ return !!consent.value || isAllowed;
583
+ }
584
+ onBlockedByConsent(name, args) {
585
+ coreLogger.warn(`Event "${name}" was blocked due to lack of consent; payload: ${JSON.stringify(args)}`);
586
+ this.reportBlockedEvent('consent', name, args);
587
+ }
588
+ async sendExperienceEvent(method, args, event, _profile) {
589
+ if (!this.hasConsent(method)) return void this.onBlockedByConsent(method, args);
590
+ return await this.experienceQueue.send(event);
591
+ }
592
+ async sendInsightsEvent(method, args, event, _profile) {
593
+ if (!this.hasConsent(method)) return void this.onBlockedByConsent(method, args);
594
+ await this.insightsQueue.send(event);
595
+ }
596
+ buildFlagViewBuilderArgs(name, changes = signals_changes.value) {
597
+ const change = changes?.find((candidate)=>candidate.key === name);
598
+ return {
599
+ componentId: name,
600
+ experienceId: change?.meta.experienceId,
601
+ variantIndex: change?.meta.variantIndex
602
+ };
885
603
  }
886
- async page(payload) {
887
- return await this.personalization.page(payload);
604
+ getFlagObservable(name) {
605
+ const existingObservable = this.flagObservables.get(name);
606
+ if (existingObservable) return existingObservable;
607
+ const trackFlagView = this.trackFlagView.bind(this);
608
+ const buildFlagViewBuilderArgs = this.buildFlagViewBuilderArgs.bind(this);
609
+ const valueSignal = signalFns.computed(()=>super.getFlag(name, signals_changes.value));
610
+ const distinctObservable = toDistinctObservable(valueSignal, predicate_isEqual);
611
+ const trackedObservable = {
612
+ get current () {
613
+ const { current: value } = distinctObservable;
614
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
615
+ trackFlagView(payload).catch((error)=>{
616
+ __rspack_external__contentful_optimization_api_client_logger_f0d05f82.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
617
+ });
618
+ return value;
619
+ },
620
+ subscribe: (next)=>distinctObservable.subscribe((value)=>{
621
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
622
+ trackFlagView(payload).catch((error)=>{
623
+ __rspack_external__contentful_optimization_api_client_logger_f0d05f82.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
624
+ });
625
+ next(value);
626
+ }),
627
+ subscribeOnce: (next)=>distinctObservable.subscribeOnce((value)=>{
628
+ const payload = buildFlagViewBuilderArgs(name, signals_changes.value);
629
+ trackFlagView(payload).catch((error)=>{
630
+ __rspack_external__contentful_optimization_api_client_logger_f0d05f82.logger.warn(`Failed to emit "flag view" event for "${name}"`, String(error));
631
+ });
632
+ next(value);
633
+ })
634
+ };
635
+ this.flagObservables.set(name, trackedObservable);
636
+ return trackedObservable;
637
+ }
638
+ reportBlockedEvent(reason, method, args) {
639
+ const event = {
640
+ reason,
641
+ method,
642
+ args
643
+ };
644
+ try {
645
+ this.onEventBlocked?.(event);
646
+ } catch (error) {
647
+ coreLogger.warn(`onEventBlocked callback failed for method "${method}"`, error);
648
+ }
649
+ blockedEvent.value = event;
650
+ }
651
+ }
652
+ const src_CoreStatefulEventEmitter = CoreStatefulEventEmitter;
653
+ const toPositiveInt = (value, fallback)=>{
654
+ if (!Number.isFinite(value) || void 0 === value || value < 1) return fallback;
655
+ return Math.floor(value);
656
+ };
657
+ const toRatio = (value, fallback)=>{
658
+ if (!Number.isFinite(value) || void 0 === value) return fallback;
659
+ return Math.min(1, Math.max(0, value));
660
+ };
661
+ const DEFAULT_QUEUE_FLUSH_POLICY = {
662
+ flushIntervalMs: 30000,
663
+ baseBackoffMs: 500,
664
+ maxBackoffMs: 30000,
665
+ jitterRatio: 0.2,
666
+ maxConsecutiveFailures: 8,
667
+ circuitOpenMs: 120000
668
+ };
669
+ const resolveQueueFlushPolicy = (policy, defaults = DEFAULT_QUEUE_FLUSH_POLICY)=>{
670
+ const configuredPolicy = policy ?? {};
671
+ const baseBackoffMs = toPositiveInt(configuredPolicy.baseBackoffMs, defaults.baseBackoffMs);
672
+ const maxBackoffMs = Math.max(baseBackoffMs, toPositiveInt(configuredPolicy.maxBackoffMs, defaults.maxBackoffMs));
673
+ return {
674
+ flushIntervalMs: toPositiveInt(configuredPolicy.flushIntervalMs, defaults.flushIntervalMs),
675
+ baseBackoffMs,
676
+ maxBackoffMs,
677
+ jitterRatio: toRatio(configuredPolicy.jitterRatio, defaults.jitterRatio),
678
+ maxConsecutiveFailures: toPositiveInt(configuredPolicy.maxConsecutiveFailures, defaults.maxConsecutiveFailures),
679
+ circuitOpenMs: toPositiveInt(configuredPolicy.circuitOpenMs, defaults.circuitOpenMs),
680
+ onCircuitOpen: configuredPolicy.onCircuitOpen,
681
+ onFlushFailure: configuredPolicy.onFlushFailure,
682
+ onFlushRecovered: configuredPolicy.onFlushRecovered
683
+ };
684
+ };
685
+ const computeQueueFlushRetryDelayMs = (options)=>{
686
+ const { consecutiveFailures, policy: { baseBackoffMs, jitterRatio, maxBackoffMs } } = options;
687
+ const exponential = baseBackoffMs * 2 ** Math.max(0, consecutiveFailures - 1);
688
+ const capped = Math.min(maxBackoffMs, exponential);
689
+ const jitter = capped * jitterRatio * Math.random();
690
+ return Math.round(capped + jitter);
691
+ };
692
+ const createQueueFlushFailureWindow = (options)=>{
693
+ const { consecutiveFailures, failureTimestamp, retryDelayMs, policy: { maxConsecutiveFailures, circuitOpenMs } } = options;
694
+ if (consecutiveFailures < maxConsecutiveFailures) return {
695
+ openedCircuit: false,
696
+ retryDelayMs,
697
+ nextFlushAllowedAt: failureTimestamp + retryDelayMs,
698
+ circuitOpenUntil: 0
699
+ };
700
+ const circuitOpenUntil = failureTimestamp + circuitOpenMs;
701
+ return {
702
+ openedCircuit: true,
703
+ retryDelayMs: circuitOpenMs,
704
+ nextFlushAllowedAt: circuitOpenUntil,
705
+ circuitOpenUntil
706
+ };
707
+ };
708
+ const STATEFUL_RUNTIME_LOCK_KEY = '__ctfl_optimization_stateful_runtime_lock__';
709
+ const getStatefulRuntimeLock = ()=>{
710
+ const singletonGlobal = globalThis;
711
+ singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY] ??= {
712
+ owner: void 0
713
+ };
714
+ return singletonGlobal[STATEFUL_RUNTIME_LOCK_KEY];
715
+ };
716
+ const acquireStatefulRuntimeSingleton = (owner)=>{
717
+ const lock = getStatefulRuntimeLock();
718
+ if (lock.owner) throw new Error(`Stateful Optimization SDK already initialized (${lock.owner}). Only one stateful instance is supported per runtime.`);
719
+ lock.owner = owner;
720
+ };
721
+ const releaseStatefulRuntimeSingleton = (owner)=>{
722
+ const lock = getStatefulRuntimeLock();
723
+ if (lock.owner === owner) lock.owner = void 0;
724
+ };
725
+ class QueueFlushRuntime {
726
+ circuitOpenUntil = 0;
727
+ flushFailureCount = 0;
728
+ flushInFlight = false;
729
+ nextFlushAllowedAt = 0;
730
+ onCallbackError;
731
+ onRetry;
732
+ policy;
733
+ retryTimer;
734
+ constructor(options){
735
+ const { onCallbackError, onRetry, policy } = options;
736
+ this.policy = policy;
737
+ this.onRetry = onRetry;
738
+ this.onCallbackError = onCallbackError;
888
739
  }
889
- async screen(payload) {
890
- return await this.personalization.screen(payload);
740
+ reset() {
741
+ this.clearScheduledRetry();
742
+ this.circuitOpenUntil = 0;
743
+ this.flushFailureCount = 0;
744
+ this.flushInFlight = false;
745
+ this.nextFlushAllowedAt = 0;
746
+ }
747
+ clearScheduledRetry() {
748
+ if (void 0 === this.retryTimer) return;
749
+ clearTimeout(this.retryTimer);
750
+ this.retryTimer = void 0;
751
+ }
752
+ shouldSkip(options) {
753
+ const { force, isOnline } = options;
754
+ if (this.flushInFlight) return true;
755
+ if (force) return false;
756
+ if (!isOnline) return true;
757
+ const now = Date.now();
758
+ if (this.nextFlushAllowedAt > now) return true;
759
+ if (this.circuitOpenUntil > now) return true;
760
+ return false;
761
+ }
762
+ markFlushStarted() {
763
+ this.flushInFlight = true;
764
+ }
765
+ markFlushFinished() {
766
+ this.flushInFlight = false;
767
+ }
768
+ handleFlushSuccess() {
769
+ const { flushFailureCount: previousConsecutiveFailures } = this;
770
+ this.clearScheduledRetry();
771
+ this.circuitOpenUntil = 0;
772
+ this.flushFailureCount = 0;
773
+ this.nextFlushAllowedAt = 0;
774
+ if (previousConsecutiveFailures <= 0) return;
775
+ this.safeInvoke('onFlushRecovered', {
776
+ consecutiveFailures: previousConsecutiveFailures
777
+ });
891
778
  }
892
- async track(payload) {
893
- return await this.personalization.track(payload);
779
+ handleFlushFailure(options) {
780
+ const { queuedBatches, queuedEvents } = options;
781
+ this.flushFailureCount += 1;
782
+ const retryDelayMs = computeQueueFlushRetryDelayMs({
783
+ consecutiveFailures: this.flushFailureCount,
784
+ policy: this.policy
785
+ });
786
+ const failureTimestamp = Date.now();
787
+ const failureContext = {
788
+ consecutiveFailures: this.flushFailureCount,
789
+ queuedBatches,
790
+ queuedEvents,
791
+ retryDelayMs
792
+ };
793
+ this.safeInvoke('onFlushFailure', failureContext);
794
+ const failureWindow = createQueueFlushFailureWindow({
795
+ consecutiveFailures: this.flushFailureCount,
796
+ failureTimestamp,
797
+ retryDelayMs,
798
+ policy: this.policy
799
+ });
800
+ const { circuitOpenUntil, nextFlushAllowedAt, openedCircuit, retryDelayMs: scheduledRetryDelayMs } = failureWindow;
801
+ this.nextFlushAllowedAt = nextFlushAllowedAt;
802
+ if (openedCircuit) {
803
+ this.circuitOpenUntil = circuitOpenUntil;
804
+ this.safeInvoke('onCircuitOpen', {
805
+ ...failureContext,
806
+ retryDelayMs: scheduledRetryDelayMs
807
+ });
808
+ }
809
+ this.scheduleRetry(scheduledRetryDelayMs);
894
810
  }
895
- async trackComponentView(payload, duplicationScope) {
896
- if (payload.sticky) return await this.personalization.trackComponentView(payload, duplicationScope);
897
- await this.analytics.trackComponentView(payload, duplicationScope);
811
+ scheduleRetry(delayMs) {
812
+ this.clearScheduledRetry();
813
+ this.retryTimer = setTimeout(()=>{
814
+ this.retryTimer = void 0;
815
+ this.onRetry();
816
+ }, delayMs);
898
817
  }
899
- async trackFlagView(payload, duplicationScope) {
900
- await this.analytics.trackFlagView(payload, duplicationScope);
818
+ safeInvoke(...args) {
819
+ const [callbackName, payload] = args;
820
+ try {
821
+ if ('onFlushRecovered' === callbackName) return void this.policy.onFlushRecovered?.(payload);
822
+ if ('onCircuitOpen' === callbackName) return void this.policy.onCircuitOpen?.(payload);
823
+ this.policy.onFlushFailure?.(payload);
824
+ } catch (error) {
825
+ this.onCallbackError?.(callbackName, error);
826
+ }
901
827
  }
902
828
  }
903
- const src_CoreBase = CoreBase;
904
- class PersonalizationBase extends src_ProductBase {
905
- flagsResolver = resolvers_FlagsResolver;
906
- mergeTagValueResolver = resolvers_MergeTagValueResolver;
907
- personalizedEntryResolver = resolvers_PersonalizedEntryResolver;
908
- getCustomFlag(name, changes) {
909
- return resolvers_FlagsResolver.resolve(changes)[name];
910
- }
911
- personalizeEntry(entry, personalizations) {
912
- return resolvers_PersonalizedEntryResolver.resolve(entry, personalizations);
913
- }
914
- getMergeTagValue(embeddedEntryNodeTarget, profile) {
915
- return resolvers_MergeTagValueResolver.resolve(embeddedEntryNodeTarget, profile);
829
+ const ExperienceQueue_coreLogger = (0, __rspack_external__contentful_optimization_api_client_logger_f0d05f82.createScopedLogger)('CoreStateful');
830
+ class ExperienceQueue {
831
+ experienceApi;
832
+ eventInterceptors;
833
+ flushRuntime;
834
+ getAnonymousId;
835
+ offlineMaxEvents;
836
+ onOfflineDrop;
837
+ queuedExperienceEvents = new Set();
838
+ stateInterceptors;
839
+ constructor(options){
840
+ const { experienceApi, eventInterceptors, flushPolicy, getAnonymousId, offlineMaxEvents, onOfflineDrop, stateInterceptors } = options;
841
+ this.experienceApi = experienceApi;
842
+ this.eventInterceptors = eventInterceptors;
843
+ this.getAnonymousId = getAnonymousId;
844
+ this.offlineMaxEvents = offlineMaxEvents;
845
+ this.onOfflineDrop = onOfflineDrop;
846
+ this.stateInterceptors = stateInterceptors;
847
+ this.flushRuntime = new QueueFlushRuntime({
848
+ policy: flushPolicy,
849
+ onRetry: ()=>{
850
+ this.flush();
851
+ },
852
+ onCallbackError: (callbackName, error)=>{
853
+ ExperienceQueue_coreLogger.warn(`Experience flush policy callback "${callbackName}" failed`, error);
854
+ }
855
+ });
916
856
  }
917
- }
918
- const personalization_PersonalizationBase = PersonalizationBase;
919
- function PersonalizationStateful_applyDecs2203RFactory() {
920
- function createAddInitializerMethod(initializers, decoratorFinishedRef) {
921
- return function(initializer) {
922
- assertNotFinished(decoratorFinishedRef, "addInitializer");
923
- assertCallable(initializer, "An initializer");
924
- initializers.push(initializer);
925
- };
857
+ clearScheduledRetry() {
858
+ this.flushRuntime.clearScheduledRetry();
926
859
  }
927
- function memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value) {
928
- var kindStr;
929
- switch(kind){
930
- case 1:
931
- kindStr = "accessor";
932
- break;
933
- case 2:
934
- kindStr = "method";
935
- break;
936
- case 3:
937
- kindStr = "getter";
938
- break;
939
- case 4:
940
- kindStr = "setter";
941
- break;
942
- default:
943
- kindStr = "field";
860
+ async send(event) {
861
+ const intercepted = await this.eventInterceptors.run(event);
862
+ const validEvent = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.ExperienceEvent, intercepted);
863
+ signals_event.value = validEvent;
864
+ if (online.value) return await this.upsertProfile([
865
+ validEvent
866
+ ]);
867
+ ExperienceQueue_coreLogger.debug(`Queueing ${validEvent.type} event`, validEvent);
868
+ this.enqueueEvent(validEvent);
869
+ }
870
+ async flush(options = {}) {
871
+ const { force = false } = options;
872
+ if (this.flushRuntime.shouldSkip({
873
+ force,
874
+ isOnline: !!online.value
875
+ })) return;
876
+ if (0 === this.queuedExperienceEvents.size) return void this.flushRuntime.clearScheduledRetry();
877
+ ExperienceQueue_coreLogger.debug('Flushing offline Experience event queue');
878
+ const queuedEvents = Array.from(this.queuedExperienceEvents);
879
+ this.flushRuntime.markFlushStarted();
880
+ try {
881
+ const sendSuccess = await this.tryUpsertQueuedEvents(queuedEvents);
882
+ if (sendSuccess) {
883
+ queuedEvents.forEach((queuedEvent)=>{
884
+ this.queuedExperienceEvents.delete(queuedEvent);
885
+ });
886
+ this.flushRuntime.handleFlushSuccess();
887
+ } else this.flushRuntime.handleFlushFailure({
888
+ queuedBatches: this.queuedExperienceEvents.size > 0 ? 1 : 0,
889
+ queuedEvents: this.queuedExperienceEvents.size
890
+ });
891
+ } finally{
892
+ this.flushRuntime.markFlushFinished();
944
893
  }
945
- var ctx = {
946
- kind: kindStr,
947
- name: isPrivate ? "#" + name : name,
948
- static: isStatic,
949
- private: isPrivate,
950
- metadata: metadata
951
- };
952
- var decoratorFinishedRef = {
953
- v: false
954
- };
955
- ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
956
- var get, set;
957
- if (0 === kind) if (isPrivate) {
958
- get = desc.get;
959
- set = desc.set;
960
- } else {
961
- get = function() {
962
- return this[name];
963
- };
964
- set = function(v) {
965
- this[name] = v;
966
- };
894
+ }
895
+ enqueueEvent(event) {
896
+ let droppedEvents = [];
897
+ if (this.queuedExperienceEvents.size >= this.offlineMaxEvents) {
898
+ const dropCount = this.queuedExperienceEvents.size - this.offlineMaxEvents + 1;
899
+ droppedEvents = this.dropOldestEvents(dropCount);
900
+ if (droppedEvents.length > 0) ExperienceQueue_coreLogger.warn(`Dropped ${droppedEvents.length} oldest offline event(s) due to queue limit (${this.offlineMaxEvents})`);
967
901
  }
968
- else if (2 === kind) get = function() {
969
- return desc.value;
970
- };
971
- else {
972
- if (1 === kind || 3 === kind) get = function() {
973
- return desc.get.call(this);
974
- };
975
- if (1 === kind || 4 === kind) set = function(v) {
976
- desc.set.call(this, v);
977
- };
902
+ this.queuedExperienceEvents.add(event);
903
+ if (droppedEvents.length > 0) this.invokeOfflineDropCallback({
904
+ droppedCount: droppedEvents.length,
905
+ droppedEvents,
906
+ maxEvents: this.offlineMaxEvents,
907
+ queuedEvents: this.queuedExperienceEvents.size
908
+ });
909
+ }
910
+ dropOldestEvents(count) {
911
+ const droppedEvents = [];
912
+ for(let index = 0; index < count; index += 1){
913
+ const oldestEvent = this.queuedExperienceEvents.values().next();
914
+ if (oldestEvent.done) break;
915
+ this.queuedExperienceEvents.delete(oldestEvent.value);
916
+ droppedEvents.push(oldestEvent.value);
978
917
  }
979
- ctx.access = get && set ? {
980
- get: get,
981
- set: set
982
- } : get ? {
983
- get: get
984
- } : {
985
- set: set
986
- };
918
+ return droppedEvents;
919
+ }
920
+ invokeOfflineDropCallback(context) {
987
921
  try {
988
- return dec(value, ctx);
989
- } finally{
990
- decoratorFinishedRef.v = true;
922
+ this.onOfflineDrop?.(context);
923
+ } catch (error) {
924
+ ExperienceQueue_coreLogger.warn('Offline queue drop callback failed', error);
991
925
  }
992
926
  }
993
- function assertNotFinished(decoratorFinishedRef, fnName) {
994
- if (decoratorFinishedRef.v) throw new Error("attempted to call " + fnName + " after decoration was finished");
995
- }
996
- function assertCallable(fn, hint) {
997
- if ("function" != typeof fn) throw new TypeError(hint + " must be a function");
998
- }
999
- function assertValidReturnValue(kind, value) {
1000
- var type = typeof value;
1001
- if (1 === kind) {
1002
- if ("object" !== type || null === value) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
1003
- if (void 0 !== value.get) assertCallable(value.get, "accessor.get");
1004
- if (void 0 !== value.set) assertCallable(value.set, "accessor.set");
1005
- if (void 0 !== value.init) assertCallable(value.init, "accessor.init");
1006
- } else if ("function" !== type) {
1007
- var hint;
1008
- hint = 0 === kind ? "field" : 10 === kind ? "class" : "method";
1009
- throw new TypeError(hint + " decorators must return a function or void 0");
927
+ async tryUpsertQueuedEvents(events) {
928
+ try {
929
+ await this.upsertProfile(events);
930
+ return true;
931
+ } catch (error) {
932
+ ExperienceQueue_coreLogger.warn('Experience queue flush request threw an error', error);
933
+ return false;
1010
934
  }
1011
935
  }
1012
- function applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata) {
1013
- var decs = decInfo[0];
1014
- var desc, init, value;
1015
- if (isPrivate) desc = 0 === kind || 1 === kind ? {
1016
- get: decInfo[3],
1017
- set: decInfo[4]
1018
- } : 3 === kind ? {
1019
- get: decInfo[3]
1020
- } : 4 === kind ? {
1021
- set: decInfo[3]
1022
- } : {
1023
- value: decInfo[3]
1024
- };
1025
- else if (0 !== kind) desc = Object.getOwnPropertyDescriptor(base, name);
1026
- if (1 === kind) value = {
1027
- get: desc.get,
1028
- set: desc.set
1029
- };
1030
- else if (2 === kind) value = desc.value;
1031
- else if (3 === kind) value = desc.get;
1032
- else if (4 === kind) value = desc.set;
1033
- var newValue, get, set;
1034
- if ("function" == typeof decs) {
1035
- newValue = memberDec(decs, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
1036
- if (void 0 !== newValue) {
1037
- assertValidReturnValue(kind, newValue);
1038
- if (0 === kind) init = newValue;
1039
- else if (1 === kind) {
1040
- init = newValue.init;
1041
- get = newValue.get || value.get;
1042
- set = newValue.set || value.set;
1043
- value = {
1044
- get: get,
1045
- set: set
1046
- };
1047
- } else value = newValue;
1048
- }
1049
- } else for(var i = decs.length - 1; i >= 0; i--){
1050
- var dec = decs[i];
1051
- newValue = memberDec(dec, name, desc, initializers, kind, isStatic, isPrivate, metadata, value);
1052
- if (void 0 !== newValue) {
1053
- assertValidReturnValue(kind, newValue);
1054
- var newInit;
1055
- if (0 === kind) newInit = newValue;
1056
- else if (1 === kind) {
1057
- newInit = newValue.init;
1058
- get = newValue.get || value.get;
1059
- set = newValue.set || value.set;
1060
- value = {
1061
- get: get,
1062
- set: set
1063
- };
1064
- } else value = newValue;
1065
- if (void 0 !== newInit) if (void 0 === init) init = newInit;
1066
- else if ("function" == typeof init) init = [
1067
- init,
1068
- newInit
1069
- ];
1070
- else init.push(newInit);
1071
- }
1072
- }
1073
- if (0 === kind || 1 === kind) {
1074
- if (void 0 === init) init = function(instance, init) {
1075
- return init;
1076
- };
1077
- else if ("function" != typeof init) {
1078
- var ownInitializers = init;
1079
- init = function(instance, init) {
1080
- var value = init;
1081
- for(var i = 0; i < ownInitializers.length; i++)value = ownInitializers[i].call(instance, value);
1082
- return value;
1083
- };
1084
- } else {
1085
- var originalInitializer = init;
1086
- init = function(instance, init) {
1087
- return originalInitializer.call(instance, init);
1088
- };
936
+ async upsertProfile(events) {
937
+ const anonymousId = this.getAnonymousId();
938
+ if (anonymousId) ExperienceQueue_coreLogger.debug(`Anonymous ID found: ${anonymousId}`);
939
+ const data = await this.experienceApi.upsertProfile({
940
+ profileId: anonymousId ?? signals_profile.value?.id,
941
+ events
942
+ });
943
+ await this.updateOutputSignals(data);
944
+ return data;
945
+ }
946
+ async updateOutputSignals(data) {
947
+ const intercepted = await this.stateInterceptors.run(data);
948
+ const { changes, profile, selectedOptimizations } = intercepted;
949
+ batch(()=>{
950
+ if (!predicate_isEqual(signals_changes.value, changes)) signals_changes.value = changes;
951
+ if (!predicate_isEqual(signals_profile.value, profile)) signals_profile.value = profile;
952
+ if (!predicate_isEqual(signals_selectedOptimizations.value, selectedOptimizations)) signals_selectedOptimizations.value = selectedOptimizations;
953
+ });
954
+ }
955
+ }
956
+ const InsightsQueue_coreLogger = (0, __rspack_external__contentful_optimization_api_client_logger_f0d05f82.createScopedLogger)('CoreStateful');
957
+ const MAX_QUEUED_INSIGHTS_EVENTS = 25;
958
+ class InsightsQueue {
959
+ eventInterceptors;
960
+ flushIntervalMs;
961
+ flushRuntime;
962
+ insightsApi;
963
+ queuedInsightsByProfile = new Map();
964
+ insightsPeriodicFlushTimer;
965
+ constructor(options){
966
+ const { eventInterceptors, flushPolicy, insightsApi } = options;
967
+ const { flushIntervalMs } = flushPolicy;
968
+ this.eventInterceptors = eventInterceptors;
969
+ this.flushIntervalMs = flushIntervalMs;
970
+ this.insightsApi = insightsApi;
971
+ this.flushRuntime = new QueueFlushRuntime({
972
+ policy: flushPolicy,
973
+ onRetry: ()=>{
974
+ this.flush();
975
+ },
976
+ onCallbackError: (callbackName, error)=>{
977
+ InsightsQueue_coreLogger.warn(`Insights flush policy callback "${callbackName}" failed`, error);
1089
978
  }
1090
- ret.push(init);
979
+ });
980
+ }
981
+ clearScheduledRetry() {
982
+ this.flushRuntime.clearScheduledRetry();
983
+ }
984
+ clearPeriodicFlushTimer() {
985
+ if (void 0 === this.insightsPeriodicFlushTimer) return;
986
+ clearInterval(this.insightsPeriodicFlushTimer);
987
+ this.insightsPeriodicFlushTimer = void 0;
988
+ }
989
+ async send(event) {
990
+ const { value: profile } = signals_profile;
991
+ if (!profile) return void InsightsQueue_coreLogger.warn('Attempting to emit an event without an Optimization profile');
992
+ const intercepted = await this.eventInterceptors.run(event);
993
+ const validEvent = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.InsightsEvent, intercepted);
994
+ InsightsQueue_coreLogger.debug(`Queueing ${validEvent.type} event for profile ${profile.id}`, validEvent);
995
+ const queuedProfileEvents = this.queuedInsightsByProfile.get(profile.id);
996
+ signals_event.value = validEvent;
997
+ if (queuedProfileEvents) {
998
+ queuedProfileEvents.profile = profile;
999
+ queuedProfileEvents.events.push(validEvent);
1000
+ } else this.queuedInsightsByProfile.set(profile.id, {
1001
+ profile,
1002
+ events: [
1003
+ validEvent
1004
+ ]
1005
+ });
1006
+ this.ensurePeriodicFlushTimer();
1007
+ if (this.getQueuedEventCount() >= MAX_QUEUED_INSIGHTS_EVENTS) await this.flush();
1008
+ this.reconcilePeriodicFlushTimer();
1009
+ }
1010
+ async flush(options = {}) {
1011
+ const { force = false } = options;
1012
+ if (this.flushRuntime.shouldSkip({
1013
+ force,
1014
+ isOnline: !!online.value
1015
+ })) return;
1016
+ InsightsQueue_coreLogger.debug('Flushing insights event queue');
1017
+ const batches = this.createBatches();
1018
+ if (!batches.length) {
1019
+ this.flushRuntime.clearScheduledRetry();
1020
+ this.reconcilePeriodicFlushTimer();
1021
+ return;
1091
1022
  }
1092
- if (0 !== kind) {
1093
- if (1 === kind) {
1094
- desc.get = value.get;
1095
- desc.set = value.set;
1096
- } else if (2 === kind) desc.value = value;
1097
- else if (3 === kind) desc.get = value;
1098
- else if (4 === kind) desc.set = value;
1099
- if (isPrivate) if (1 === kind) {
1100
- ret.push(function(instance, args) {
1101
- return value.get.call(instance, args);
1102
- });
1103
- ret.push(function(instance, args) {
1104
- return value.set.call(instance, args);
1105
- });
1106
- } else if (2 === kind) ret.push(value);
1107
- else ret.push(function(instance, args) {
1108
- return value.call(instance, args);
1023
+ this.flushRuntime.markFlushStarted();
1024
+ try {
1025
+ const sendSuccess = await this.trySendBatches(batches);
1026
+ if (sendSuccess) {
1027
+ this.queuedInsightsByProfile.clear();
1028
+ this.flushRuntime.handleFlushSuccess();
1029
+ } else this.flushRuntime.handleFlushFailure({
1030
+ queuedBatches: batches.length,
1031
+ queuedEvents: this.getQueuedEventCount()
1109
1032
  });
1110
- else Object.defineProperty(base, name, desc);
1033
+ } finally{
1034
+ this.flushRuntime.markFlushFinished();
1035
+ this.reconcilePeriodicFlushTimer();
1111
1036
  }
1112
1037
  }
1113
- function applyMemberDecs(Class, decInfos, metadata) {
1114
- var ret = [];
1115
- var protoInitializers;
1116
- var staticInitializers;
1117
- var existingProtoNonFields = new Map();
1118
- var existingStaticNonFields = new Map();
1119
- for(var i = 0; i < decInfos.length; i++){
1120
- var decInfo = decInfos[i];
1121
- if (Array.isArray(decInfo)) {
1122
- var kind = decInfo[1];
1123
- var name = decInfo[2];
1124
- var isPrivate = decInfo.length > 3;
1125
- var isStatic = kind >= 5;
1126
- var base;
1127
- var initializers;
1128
- if (isStatic) {
1129
- base = Class;
1130
- kind -= 5;
1131
- staticInitializers = staticInitializers || [];
1132
- initializers = staticInitializers;
1133
- } else {
1134
- base = Class.prototype;
1135
- protoInitializers = protoInitializers || [];
1136
- initializers = protoInitializers;
1137
- }
1138
- if (0 !== kind && !isPrivate) {
1139
- var existingNonFields = isStatic ? existingStaticNonFields : existingProtoNonFields;
1140
- var existingKind = existingNonFields.get(name) || 0;
1141
- 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);
1142
- if (!existingKind && kind > 2) existingNonFields.set(name, kind);
1143
- else existingNonFields.set(name, true);
1144
- }
1145
- applyMemberDec(ret, base, decInfo, name, kind, isStatic, isPrivate, initializers, metadata);
1146
- }
1147
- }
1148
- pushInitializers(ret, protoInitializers);
1149
- pushInitializers(ret, staticInitializers);
1150
- return ret;
1151
- }
1152
- function pushInitializers(ret, initializers) {
1153
- if (initializers) ret.push(function(instance) {
1154
- for(var i = 0; i < initializers.length; i++)initializers[i].call(instance);
1155
- return instance;
1038
+ createBatches() {
1039
+ const batches = [];
1040
+ this.queuedInsightsByProfile.forEach(({ profile, events })=>{
1041
+ batches.push({
1042
+ profile,
1043
+ events
1044
+ });
1156
1045
  });
1046
+ return batches;
1157
1047
  }
1158
- function applyClassDecs(targetClass, classDecs, metadata) {
1159
- if (classDecs.length > 0) {
1160
- var initializers = [];
1161
- var newClass = targetClass;
1162
- var name = targetClass.name;
1163
- for(var i = classDecs.length - 1; i >= 0; i--){
1164
- var decoratorFinishedRef = {
1165
- v: false
1166
- };
1167
- try {
1168
- var nextNewClass = classDecs[i](newClass, {
1169
- kind: "class",
1170
- name: name,
1171
- addInitializer: createAddInitializerMethod(initializers, decoratorFinishedRef),
1172
- metadata
1173
- });
1174
- } finally{
1175
- decoratorFinishedRef.v = true;
1176
- }
1177
- if (void 0 !== nextNewClass) {
1178
- assertValidReturnValue(10, nextNewClass);
1179
- newClass = nextNewClass;
1180
- }
1181
- }
1182
- return [
1183
- defineMetadata(newClass, metadata),
1184
- function() {
1185
- for(var i = 0; i < initializers.length; i++)initializers[i].call(newClass);
1186
- }
1187
- ];
1048
+ async trySendBatches(batches) {
1049
+ try {
1050
+ return await this.insightsApi.sendBatchEvents(batches);
1051
+ } catch (error) {
1052
+ InsightsQueue_coreLogger.warn('Insights queue flush request threw an error', error);
1053
+ return false;
1188
1054
  }
1189
1055
  }
1190
- function defineMetadata(Class, metadata) {
1191
- return Object.defineProperty(Class, Symbol.metadata || Symbol.for("Symbol.metadata"), {
1192
- configurable: true,
1193
- enumerable: true,
1194
- value: metadata
1056
+ getQueuedEventCount() {
1057
+ let queuedCount = 0;
1058
+ this.queuedInsightsByProfile.forEach(({ events })=>{
1059
+ queuedCount += events.length;
1195
1060
  });
1061
+ return queuedCount;
1196
1062
  }
1197
- return function(targetClass, memberDecs, classDecs, parentClass) {
1198
- if (void 0 !== parentClass) var parentMetadata = parentClass[Symbol.metadata || Symbol.for("Symbol.metadata")];
1199
- var metadata = Object.create(void 0 === parentMetadata ? null : parentMetadata);
1200
- var e = applyMemberDecs(targetClass, memberDecs, metadata);
1201
- if (!classDecs.length) defineMetadata(targetClass, metadata);
1202
- return {
1203
- e: e,
1204
- get c () {
1205
- return applyClassDecs(targetClass, classDecs, metadata);
1206
- }
1207
- };
1208
- };
1209
- }
1210
- function PersonalizationStateful_apply_decs_2203_r(targetClass, memberDecs, classDecs, parentClass) {
1211
- return (PersonalizationStateful_apply_decs_2203_r = PersonalizationStateful_applyDecs2203RFactory())(targetClass, memberDecs, classDecs, parentClass);
1212
- }
1213
- var PersonalizationStateful_dec, PersonalizationStateful_dec1, PersonalizationStateful_dec2, PersonalizationStateful_dec3, _dec4, _dec5, PersonalizationStateful_initProto;
1214
- const PersonalizationStateful_logger = createScopedLogger('Personalization');
1215
- PersonalizationStateful_dec = guardedBy('hasConsent', {
1216
- onBlocked: 'onBlockedByConsent'
1217
- }), PersonalizationStateful_dec1 = guardedBy('hasConsent', {
1218
- onBlocked: 'onBlockedByConsent'
1219
- }), PersonalizationStateful_dec2 = guardedBy('hasConsent', {
1220
- onBlocked: 'onBlockedByConsent'
1221
- }), PersonalizationStateful_dec3 = guardedBy('hasConsent', {
1222
- onBlocked: 'onBlockedByConsent'
1223
- }), _dec4 = guardedBy('isNotDuplicated', {
1224
- onBlocked: 'onBlockedByDuplication'
1225
- }), _dec5 = guardedBy('hasConsent', {
1226
- onBlocked: 'onBlockedByConsent'
1227
- });
1228
- class PersonalizationStateful extends personalization_PersonalizationBase {
1229
- static{
1230
- ({ e: [PersonalizationStateful_initProto] } = PersonalizationStateful_apply_decs_2203_r(this, [
1231
- [
1232
- PersonalizationStateful_dec,
1233
- 2,
1234
- "identify"
1235
- ],
1236
- [
1237
- PersonalizationStateful_dec1,
1238
- 2,
1239
- "page"
1240
- ],
1241
- [
1242
- PersonalizationStateful_dec2,
1243
- 2,
1244
- "screen"
1245
- ],
1246
- [
1247
- PersonalizationStateful_dec3,
1248
- 2,
1249
- "track"
1250
- ],
1251
- [
1252
- [
1253
- _dec4,
1254
- _dec5
1255
- ],
1256
- 2,
1257
- "trackComponentView"
1258
- ]
1259
- ], []));
1063
+ ensurePeriodicFlushTimer() {
1064
+ if (void 0 !== this.insightsPeriodicFlushTimer) return;
1065
+ if (0 === this.getQueuedEventCount()) return;
1066
+ this.insightsPeriodicFlushTimer = setInterval(()=>{
1067
+ this.flush();
1068
+ }, this.flushIntervalMs);
1260
1069
  }
1261
- offlineQueue = (PersonalizationStateful_initProto(this), new Set());
1070
+ reconcilePeriodicFlushTimer() {
1071
+ if (this.getQueuedEventCount() > 0) return void this.ensurePeriodicFlushTimer();
1072
+ this.clearPeriodicFlushTimer();
1073
+ }
1074
+ }
1075
+ const CoreStateful_coreLogger = (0, __rspack_external__contentful_optimization_api_client_logger_f0d05f82.createScopedLogger)('CoreStateful');
1076
+ const DEFAULT_ALLOWED_EVENT_TYPES = [
1077
+ 'identify',
1078
+ 'page',
1079
+ 'screen'
1080
+ ];
1081
+ const OFFLINE_QUEUE_MAX_EVENTS = 100;
1082
+ const hasDefinedValues = (record)=>Object.values(record).some((value)=>void 0 !== value);
1083
+ const createStatefulExperienceApiConfig = (api)=>{
1084
+ if (void 0 === api) return;
1085
+ const experienceConfig = {
1086
+ baseUrl: api.experienceBaseUrl,
1087
+ enabledFeatures: api.enabledFeatures,
1088
+ ip: api.ip,
1089
+ locale: api.locale,
1090
+ plainText: api.plainText,
1091
+ preflight: api.preflight
1092
+ };
1093
+ return hasDefinedValues(experienceConfig) ? experienceConfig : void 0;
1094
+ };
1095
+ const createStatefulInsightsApiConfig = (api)=>{
1096
+ if (void 0 === api) return;
1097
+ const insightsConfig = {
1098
+ baseUrl: api.insightsBaseUrl,
1099
+ beaconHandler: api.beaconHandler
1100
+ };
1101
+ return hasDefinedValues(insightsConfig) ? insightsConfig : void 0;
1102
+ };
1103
+ const resolveQueuePolicy = (policy)=>({
1104
+ flush: resolveQueueFlushPolicy(policy?.flush),
1105
+ offlineMaxEvents: toPositiveInt(policy?.offlineMaxEvents, OFFLINE_QUEUE_MAX_EVENTS),
1106
+ onOfflineDrop: policy?.onOfflineDrop
1107
+ });
1108
+ let statefulInstanceCounter = 0;
1109
+ class CoreStateful extends src_CoreStatefulEventEmitter {
1110
+ singletonOwner;
1111
+ destroyed = false;
1112
+ allowedEventTypes;
1113
+ experienceQueue;
1114
+ insightsQueue;
1115
+ onEventBlocked;
1262
1116
  states = {
1117
+ blockedEventStream: toObservable(blockedEvent),
1118
+ flag: (name)=>this.getFlagObservable(name),
1119
+ consent: toObservable(consent),
1263
1120
  eventStream: toObservable(signals_event),
1264
- flags: toObservable(flags),
1265
- profile: toObservable(signals_profile),
1266
- personalizations: toObservable(signals_personalizations)
1121
+ canOptimize: toObservable(canOptimize),
1122
+ selectedOptimizations: toObservable(signals_selectedOptimizations),
1123
+ previewPanelAttached: toObservable(previewPanelAttached),
1124
+ previewPanelOpen: toObservable(previewPanelOpen),
1125
+ profile: toObservable(signals_profile)
1267
1126
  };
1268
- getAnonymousId;
1269
- constructor(options){
1270
- const { api, builder, config, interceptors } = options;
1271
- super({
1272
- api,
1273
- builder,
1274
- config,
1275
- interceptors
1127
+ constructor(config){
1128
+ super(config, {
1129
+ experience: createStatefulExperienceApiConfig(config.api),
1130
+ insights: createStatefulInsightsApiConfig(config.api)
1276
1131
  });
1277
- const { defaults, getAnonymousId } = config ?? {};
1278
- if (defaults) {
1279
- const { changes: defaultChanges, personalizations: defaultPersonalizations, profile: defaultProfile } = defaults;
1132
+ this.singletonOwner = `CoreStateful#${++statefulInstanceCounter}`;
1133
+ acquireStatefulRuntimeSingleton(this.singletonOwner);
1134
+ try {
1135
+ const { allowedEventTypes, defaults, getAnonymousId, onEventBlocked, queuePolicy } = config;
1136
+ const { changes: defaultChanges, consent: defaultConsent, selectedOptimizations: defaultSelectedOptimizations, profile: defaultProfile } = defaults ?? {};
1137
+ const resolvedQueuePolicy = resolveQueuePolicy(queuePolicy);
1138
+ this.allowedEventTypes = allowedEventTypes ?? DEFAULT_ALLOWED_EVENT_TYPES;
1139
+ this.onEventBlocked = onEventBlocked;
1140
+ this.insightsQueue = new InsightsQueue({
1141
+ eventInterceptors: this.interceptors.event,
1142
+ flushPolicy: resolvedQueuePolicy.flush,
1143
+ insightsApi: this.api.insights
1144
+ });
1145
+ this.experienceQueue = new ExperienceQueue({
1146
+ experienceApi: this.api.experience,
1147
+ eventInterceptors: this.interceptors.event,
1148
+ flushPolicy: resolvedQueuePolicy.flush,
1149
+ getAnonymousId: getAnonymousId ?? (()=>void 0),
1150
+ offlineMaxEvents: resolvedQueuePolicy.offlineMaxEvents,
1151
+ onOfflineDrop: resolvedQueuePolicy.onOfflineDrop,
1152
+ stateInterceptors: this.interceptors.state
1153
+ });
1154
+ if (void 0 !== defaultConsent) consent.value = defaultConsent;
1280
1155
  batch(()=>{
1281
- signals_changes.value = defaultChanges;
1282
- signals_personalizations.value = defaultPersonalizations;
1283
- signals_profile.value = defaultProfile;
1156
+ if (void 0 !== defaultChanges) signals_changes.value = defaultChanges;
1157
+ if (void 0 !== defaultSelectedOptimizations) signals_selectedOptimizations.value = defaultSelectedOptimizations;
1158
+ if (void 0 !== defaultProfile) signals_profile.value = defaultProfile;
1284
1159
  });
1160
+ this.initializeEffects();
1161
+ } catch (error) {
1162
+ releaseStatefulRuntimeSingleton(this.singletonOwner);
1163
+ throw error;
1285
1164
  }
1286
- if (defaults?.consent !== void 0) {
1287
- const { consent: defaultConsent } = defaults;
1288
- consent.value = defaultConsent;
1289
- }
1290
- this.getAnonymousId = getAnonymousId ?? (()=>void 0);
1165
+ }
1166
+ initializeEffects() {
1291
1167
  effect(()=>{
1292
- PersonalizationStateful_logger.debug(`Profile ${signals_profile.value && `with ID ${signals_profile.value.id}`} has been ${signals_profile.value ? 'set' : 'cleared'}`);
1168
+ CoreStateful_coreLogger.debug(`Profile ${signals_profile.value && `with ID ${signals_profile.value.id}`} has been ${signals_profile.value ? 'set' : 'cleared'}`);
1293
1169
  });
1294
1170
  effect(()=>{
1295
- PersonalizationStateful_logger.debug(`Variants have been ${signals_personalizations.value?.length ? 'populated' : 'cleared'}`);
1171
+ CoreStateful_coreLogger.debug(`Variants have been ${signals_selectedOptimizations.value?.length ? 'populated' : 'cleared'}`);
1296
1172
  });
1297
1173
  effect(()=>{
1298
- PersonalizationStateful_logger.info(`Personalization ${consent.value ? 'will' : 'will not'} take effect due to consent (${consent.value})`);
1174
+ CoreStateful_coreLogger.info(`Core ${consent.value ? 'will' : 'will not'} emit gated events due to consent (${consent.value})`);
1299
1175
  });
1300
1176
  effect(()=>{
1301
- if (online.value) this.flush();
1177
+ if (!online.value) return;
1178
+ this.insightsQueue.clearScheduledRetry();
1179
+ this.experienceQueue.clearScheduledRetry();
1180
+ this.flushQueues({
1181
+ force: true
1182
+ });
1183
+ });
1184
+ }
1185
+ async flushQueues(options = {}) {
1186
+ await this.insightsQueue.flush(options);
1187
+ await this.experienceQueue.flush(options);
1188
+ }
1189
+ destroy() {
1190
+ if (this.destroyed) return;
1191
+ this.destroyed = true;
1192
+ this.insightsQueue.flush({
1193
+ force: true
1194
+ }).catch((error)=>{
1195
+ __rspack_external__contentful_optimization_api_client_logger_f0d05f82.logger.warn('Failed to flush insights queue during destroy()', String(error));
1196
+ });
1197
+ this.experienceQueue.flush({
1198
+ force: true
1199
+ }).catch((error)=>{
1200
+ __rspack_external__contentful_optimization_api_client_logger_f0d05f82.logger.warn('Failed to flush Experience queue during destroy()', String(error));
1302
1201
  });
1202
+ this.insightsQueue.clearPeriodicFlushTimer();
1203
+ releaseStatefulRuntimeSingleton(this.singletonOwner);
1303
1204
  }
1304
1205
  reset() {
1305
1206
  batch(()=>{
1306
- signals_changes.value = void 0;
1207
+ blockedEvent.value = void 0;
1307
1208
  signals_event.value = void 0;
1209
+ signals_changes.value = void 0;
1308
1210
  signals_profile.value = void 0;
1309
- signals_personalizations.value = void 0;
1211
+ signals_selectedOptimizations.value = void 0;
1310
1212
  });
1311
1213
  }
1312
- getCustomFlag(name, changes = signals_changes.value) {
1313
- return super.getCustomFlag(name, changes);
1314
- }
1315
- personalizeEntry(entry, personalizations = signals_personalizations.value) {
1316
- return super.personalizeEntry(entry, personalizations);
1214
+ async flush() {
1215
+ await this.flushQueues();
1317
1216
  }
1318
- getMergeTagValue(embeddedEntryNodeTarget, profile = signals_profile.value) {
1319
- return super.getMergeTagValue(embeddedEntryNodeTarget, profile);
1217
+ consent(accept) {
1218
+ consent.value = accept;
1320
1219
  }
1321
- hasConsent(name) {
1322
- return !!consent.value || (this.allowedEventTypes ?? []).includes('trackComponentView' === name || 'trackFlagView' === name ? 'component' : name);
1220
+ get online() {
1221
+ return online.value ?? false;
1323
1222
  }
1324
- onBlockedByConsent(name, payload) {
1325
- PersonalizationStateful_logger.warn(`Event "${name}" was blocked due to lack of consent; payload: ${JSON.stringify(payload)}`);
1223
+ set online(isOnline) {
1224
+ online.value = isOnline;
1326
1225
  }
1327
- isNotDuplicated(_name, payload) {
1328
- const [{ componentId: value }, duplicationScope] = payload;
1329
- const isDuplicated = this.duplicationDetector.isPresent(duplicationScope, value);
1330
- if (!isDuplicated) this.duplicationDetector.addValue(duplicationScope, value);
1331
- return !isDuplicated;
1226
+ registerPreviewPanel(previewPanel) {
1227
+ Reflect.set(previewPanel, PREVIEW_PANEL_SIGNALS_SYMBOL, signals);
1228
+ Reflect.set(previewPanel, PREVIEW_PANEL_SIGNAL_FNS_SYMBOL, signalFns);
1332
1229
  }
1333
- onBlockedByDuplication(_name, payload) {
1334
- PersonalizationStateful_logger.debug(`Duplicate "component view" event detected, skipping; payload: ${JSON.stringify(payload)}`);
1230
+ }
1231
+ const src_CoreStateful = CoreStateful;
1232
+ const TRACK_CLICK_PROFILE_ERROR = 'CoreStateless.forRequest().trackClick() requires `payload.profile.id` for Insights delivery.';
1233
+ const TRACK_HOVER_PROFILE_ERROR = 'CoreStateless.forRequest().trackHover() requires `payload.profile.id` for Insights delivery.';
1234
+ const TRACK_FLAG_VIEW_PROFILE_ERROR = 'CoreStateless.forRequest().trackFlagView() requires `payload.profile.id` for Insights delivery.';
1235
+ const NON_STICKY_TRACK_VIEW_PROFILE_ERROR = 'CoreStateless.forRequest().trackView() requires `payload.profile.id` when `payload.sticky` is not `true`.';
1236
+ 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.';
1237
+ const requireInsightsProfile = (profile, errorMessage)=>{
1238
+ if (void 0 !== profile) return profile;
1239
+ throw new Error(errorMessage);
1240
+ };
1241
+ class CoreStatelessRequestScope {
1242
+ core;
1243
+ options;
1244
+ constructor(core, options = {}){
1245
+ this.core = core;
1246
+ this.options = Object.freeze({
1247
+ ...options
1248
+ });
1335
1249
  }
1336
1250
  async identify(payload) {
1337
- PersonalizationStateful_logger.info('Sending "identify" event');
1338
- const event = this.builder.buildIdentify(payload);
1339
- return await this.sendOrEnqueueEvent(event);
1251
+ const { profile, ...builderArgs } = payload;
1252
+ return await this.sendExperienceEvent(this.core.eventBuilder.buildIdentify(builderArgs), profile);
1340
1253
  }
1341
- async page(payload) {
1342
- PersonalizationStateful_logger.info('Sending "page" event');
1343
- const event = this.builder.buildPageView(payload);
1344
- return await this.sendOrEnqueueEvent(event);
1254
+ async page(payload = {}) {
1255
+ const { profile, ...builderArgs } = payload;
1256
+ return await this.sendExperienceEvent(this.core.eventBuilder.buildPageView(builderArgs), profile);
1345
1257
  }
1346
1258
  async screen(payload) {
1347
- PersonalizationStateful_logger.info(`Sending "screen" event for "${payload.name}"`);
1348
- const event = this.builder.buildScreenView(payload);
1349
- return await this.sendOrEnqueueEvent(event);
1259
+ const { profile, ...builderArgs } = payload;
1260
+ return await this.sendExperienceEvent(this.core.eventBuilder.buildScreenView(builderArgs), profile);
1350
1261
  }
1351
1262
  async track(payload) {
1352
- PersonalizationStateful_logger.info(`Sending "track" event "${payload.event}"`);
1353
- const event = this.builder.buildTrack(payload);
1354
- return await this.sendOrEnqueueEvent(event);
1355
- }
1356
- async trackComponentView(payload, _duplicationScope = '') {
1357
- PersonalizationStateful_logger.info(`Sending "track personalization" event for ${payload.componentId}`);
1358
- const event = this.builder.buildComponentView(payload);
1359
- return await this.sendOrEnqueueEvent(event);
1360
- }
1361
- async sendOrEnqueueEvent(event) {
1362
- const intercepted = await this.interceptors.event.run(event);
1363
- const validEvent = __rspack_external__contentful_optimization_api_client_cba5a7ee.ExperienceEvent.parse(intercepted);
1364
- signals_event.value = validEvent;
1365
- if (online.value) return await this.upsertProfile([
1366
- validEvent
1367
- ]);
1368
- PersonalizationStateful_logger.debug(`Queueing ${validEvent.type} event`, validEvent);
1369
- this.offlineQueue.add(validEvent);
1370
- }
1371
- async flush() {
1372
- if (0 === this.offlineQueue.size) return;
1373
- PersonalizationStateful_logger.debug('Flushing offline event queue');
1374
- await this.upsertProfile(Array.from(this.offlineQueue));
1375
- this.offlineQueue.clear();
1376
- }
1377
- async upsertProfile(events) {
1378
- const anonymousId = this.getAnonymousId();
1379
- if (anonymousId) PersonalizationStateful_logger.debug(`Anonymous ID found: ${anonymousId}`);
1380
- const data = await this.api.experience.upsertProfile({
1381
- profileId: anonymousId ?? signals_profile.value?.id,
1382
- events
1383
- });
1384
- await this.updateOutputSignals(data);
1385
- return data;
1386
- }
1387
- async updateOutputSignals(data) {
1388
- const intercepted = await this.interceptors.state.run(data);
1389
- const { changes, personalizations, profile } = intercepted;
1390
- batch(()=>{
1391
- if (!isEqual(signals_changes.value, changes)) signals_changes.value = changes;
1392
- if (!isEqual(signals_profile.value, profile)) signals_profile.value = profile;
1393
- if (!isEqual(signals_personalizations.value, personalizations)) signals_personalizations.value = personalizations;
1394
- });
1395
- }
1396
- }
1397
- const personalization_PersonalizationStateful = PersonalizationStateful;
1398
- const PersonalizationStateless_logger = createScopedLogger('Personalization');
1399
- class PersonalizationStateless extends personalization_PersonalizationBase {
1400
- async identify(payload) {
1401
- PersonalizationStateless_logger.info('Sending "identify" event');
1402
1263
  const { profile, ...builderArgs } = payload;
1403
- const event = __rspack_external__contentful_optimization_api_client_cba5a7ee.IdentifyEvent.parse(this.builder.buildIdentify(builderArgs));
1404
- return await this.upsertProfile(event, profile);
1264
+ return await this.sendExperienceEvent(this.core.eventBuilder.buildTrack(builderArgs), profile);
1405
1265
  }
1406
- async page(payload) {
1407
- PersonalizationStateless_logger.info('Sending "page" event');
1266
+ async trackView(payload) {
1408
1267
  const { profile, ...builderArgs } = payload;
1409
- const event = __rspack_external__contentful_optimization_api_client_cba5a7ee.PageViewEvent.parse(this.builder.buildPageView(builderArgs));
1410
- return await this.upsertProfile(event, profile);
1268
+ let result;
1269
+ let insightsProfile = profile;
1270
+ if (payload.sticky) {
1271
+ result = await this.sendExperienceEvent(this.core.eventBuilder.buildView(builderArgs), profile);
1272
+ const { profile: responseProfile } = result;
1273
+ insightsProfile = responseProfile;
1274
+ }
1275
+ await this.sendInsightsEvent(this.core.eventBuilder.buildView(builderArgs), requireInsightsProfile(insightsProfile, payload.sticky ? STICKY_TRACK_VIEW_PROFILE_ERROR : NON_STICKY_TRACK_VIEW_PROFILE_ERROR));
1276
+ return result;
1411
1277
  }
1412
- async screen(payload) {
1413
- PersonalizationStateless_logger.info(`Sending "screen" event for "${payload.name}"`);
1278
+ async trackClick(payload) {
1414
1279
  const { profile, ...builderArgs } = payload;
1415
- const event = __rspack_external__contentful_optimization_api_client_cba5a7ee.ScreenViewEvent.parse(this.builder.buildScreenView(builderArgs));
1416
- return await this.upsertProfile(event, profile);
1280
+ await this.sendInsightsEvent(this.core.eventBuilder.buildClick(builderArgs), requireInsightsProfile(profile, TRACK_CLICK_PROFILE_ERROR));
1417
1281
  }
1418
- async track(payload) {
1419
- PersonalizationStateless_logger.info(`Sending "track" event "${payload.event}"`);
1282
+ async trackHover(payload) {
1420
1283
  const { profile, ...builderArgs } = payload;
1421
- const event = __rspack_external__contentful_optimization_api_client_cba5a7ee.TrackEvent.parse(this.builder.buildTrack(builderArgs));
1422
- return await this.upsertProfile(event, profile);
1284
+ await this.sendInsightsEvent(this.core.eventBuilder.buildHover(builderArgs), requireInsightsProfile(profile, TRACK_HOVER_PROFILE_ERROR));
1423
1285
  }
1424
- async trackComponentView(payload) {
1425
- PersonalizationStateless_logger.info('Sending "track personalization" event');
1286
+ async trackFlagView(payload) {
1426
1287
  const { profile, ...builderArgs } = payload;
1427
- const event = __rspack_external__contentful_optimization_api_client_cba5a7ee.ComponentViewEvent.parse(this.builder.buildComponentView(builderArgs));
1428
- return await this.upsertProfile(event, profile);
1288
+ await this.sendInsightsEvent(this.core.eventBuilder.buildFlagView(builderArgs), requireInsightsProfile(profile, TRACK_FLAG_VIEW_PROFILE_ERROR));
1429
1289
  }
1430
- async upsertProfile(event, profile) {
1431
- const intercepted = await this.interceptors.event.run(event);
1432
- const data = await this.api.experience.upsertProfile({
1290
+ async sendExperienceEvent(event, profile) {
1291
+ const intercepted = await this.core.interceptors.event.run(event);
1292
+ const validEvent = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.ExperienceEvent, intercepted);
1293
+ return await this.core.api.experience.upsertProfile({
1433
1294
  profileId: profile?.id,
1434
1295
  events: [
1435
- intercepted
1296
+ validEvent
1436
1297
  ]
1437
- });
1438
- return data;
1439
- }
1440
- }
1441
- const personalization_PersonalizationStateless = PersonalizationStateless;
1442
- class CoreStateful extends src_CoreBase {
1443
- analytics;
1444
- personalization;
1445
- constructor(config){
1446
- super(config);
1447
- const { allowedEventTypes, defaults, getAnonymousId, preventedComponentEvents } = config;
1448
- if (defaults?.consent !== void 0) {
1449
- const { consent: defaultConsent } = defaults;
1450
- consent.value = defaultConsent;
1451
- }
1452
- this.analytics = new analytics_AnalyticsStateful({
1453
- api: this.api,
1454
- builder: this.eventBuilder,
1455
- config: {
1456
- allowedEventTypes,
1457
- preventedComponentEvents,
1458
- defaults: {
1459
- consent: defaults?.consent,
1460
- profile: defaults?.profile
1461
- }
1462
- },
1463
- interceptors: this.interceptors
1464
- });
1465
- this.personalization = new personalization_PersonalizationStateful({
1466
- api: this.api,
1467
- builder: this.eventBuilder,
1468
- config: {
1469
- allowedEventTypes,
1470
- getAnonymousId,
1471
- preventedComponentEvents,
1472
- defaults: {
1473
- consent: defaults?.consent,
1474
- changes: defaults?.changes,
1475
- profile: defaults?.profile,
1476
- personalizations: defaults?.personalizations
1477
- }
1478
- },
1479
- interceptors: this.interceptors
1480
- });
1481
- }
1482
- get states() {
1483
- return {
1484
- consent: toObservable(consent),
1485
- eventStream: toObservable(signals_event),
1486
- flags: toObservable(flags),
1487
- personalizations: toObservable(signals_personalizations),
1488
- profile: toObservable(signals_profile)
1489
- };
1490
- }
1491
- reset() {
1492
- batch(()=>{
1493
- signals_event.value = void 0;
1494
- signals_changes.value = void 0;
1495
- signals_profile.value = void 0;
1496
- signals_personalizations.value = void 0;
1497
- });
1298
+ }, this.options);
1498
1299
  }
1499
- async flush() {
1500
- await this.analytics.flush();
1501
- await this.personalization.flush();
1502
- }
1503
- consent(accept) {
1504
- consent.value = accept;
1505
- }
1506
- online(isOnline) {
1507
- online.value = isOnline;
1508
- }
1509
- registerPreviewPanel(previewPanel) {
1510
- previewPanel.signals = signals;
1300
+ async sendInsightsEvent(event, profile) {
1301
+ const intercepted = await this.core.interceptors.event.run(event);
1302
+ const validEvent = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.InsightsEvent, intercepted);
1303
+ const batchEvent = (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.BatchInsightsEventArray, [
1304
+ {
1305
+ profile: (0, __rspack_external__contentful_optimization_api_client_api_schemas_4192893e.parseWithFriendlyError)(__rspack_external__contentful_optimization_api_client_api_schemas_4192893e.PartialProfile, profile),
1306
+ events: [
1307
+ validEvent
1308
+ ]
1309
+ }
1310
+ ]);
1311
+ await this.core.api.insights.sendBatchEvents(batchEvent);
1511
1312
  }
1512
1313
  }
1513
- const src_CoreStateful = CoreStateful;
1314
+ const CoreStateless_hasDefinedValues = (record)=>Object.values(record).some((value)=>void 0 !== value);
1315
+ const createStatelessExperienceApiConfig = (api)=>{
1316
+ if (void 0 === api) return;
1317
+ const experienceConfig = {
1318
+ baseUrl: api.experienceBaseUrl,
1319
+ enabledFeatures: api.enabledFeatures
1320
+ };
1321
+ return CoreStateless_hasDefinedValues(experienceConfig) ? experienceConfig : void 0;
1322
+ };
1323
+ const createStatelessInsightsApiConfig = (api)=>{
1324
+ if (api?.insightsBaseUrl === void 0) return;
1325
+ return {
1326
+ baseUrl: api.insightsBaseUrl
1327
+ };
1328
+ };
1514
1329
  class CoreStateless extends src_CoreBase {
1515
- analytics;
1516
- personalization;
1517
1330
  constructor(config){
1518
- super(config);
1519
- this.analytics = new analytics_AnalyticsStateless({
1520
- api: this.api,
1521
- builder: this.eventBuilder,
1522
- interceptors: this.interceptors
1523
- });
1524
- this.personalization = new personalization_PersonalizationStateless({
1525
- api: this.api,
1526
- builder: this.eventBuilder,
1527
- interceptors: this.interceptors
1331
+ super(config, {
1332
+ experience: createStatelessExperienceApiConfig(config.api),
1333
+ insights: createStatelessInsightsApiConfig(config.api)
1528
1334
  });
1529
1335
  }
1336
+ forRequest(options = {}) {
1337
+ return new CoreStatelessRequestScope(this, options);
1338
+ }
1530
1339
  }
1531
1340
  const src_CoreStateless = CoreStateless;
1532
- export * from "@contentful/optimization-api-client";
1533
- export { ANONYMOUS_ID_COOKIE, ConsoleLogSink, InterceptorManager, Logger, OPTIMIZATION_CORE_SDK_VERSION, analytics_AnalyticsStateful as AnalyticsStateful, analytics_AnalyticsStateless as AnalyticsStateless, batch, createScopedLogger, effect, guardedBy, logger, personalization_PersonalizationStateful as PersonalizationStateful, personalization_PersonalizationStateless as PersonalizationStateless, resolvers_FlagsResolver as FlagsResolver, resolvers_MergeTagValueResolver as MergeTagValueResolver, resolvers_PersonalizedEntryResolver as PersonalizedEntryResolver, signals, src_CoreStateful as CoreStateful, src_CoreStateless as CoreStateless, src_LogSink as LogSink, value_presence_ValuePresence as ValuePresence };
1341
+ const isFunction = (v)=>'function' == typeof v;
1342
+ const nameToString = (name)=>'string' == typeof name ? name : 'symbol' == typeof name ? name.description ?? String(name) : String(name);
1343
+ const isOnBlockedKey = (v)=>'string' == typeof v || 'symbol' == typeof v;
1344
+ const isAsyncFunction = (fn)=>'[object AsyncFunction]' === Object.prototype.toString.call(fn);
1345
+ function guardedBy(predicateName, opts) {
1346
+ return function(_value, context) {
1347
+ const decoratedName = nameToString(context.name);
1348
+ context.addInitializer(function() {
1349
+ const originalUnknown = Reflect.get(this, context.name);
1350
+ if (!isFunction(originalUnknown)) return;
1351
+ const original = originalUnknown;
1352
+ const originalIsAsync = isAsyncFunction(original);
1353
+ const resolvePredicate = (self)=>{
1354
+ const { [predicateName]: cand } = self;
1355
+ if (!isFunction(cand)) throw new TypeError(`@guardedBy expects predicate "${String(predicateName)}" to be a synchronous function.`);
1356
+ return cand;
1357
+ };
1358
+ const computeAllowed = (self, args)=>{
1359
+ const pred = resolvePredicate(self);
1360
+ const ok = Boolean(pred.call(self, decoratedName, args));
1361
+ return opts?.invert === true ? !ok : ok;
1362
+ };
1363
+ const runOnBlocked = (self, args)=>{
1364
+ const { onBlocked } = opts ?? {};
1365
+ if (void 0 === onBlocked) return;
1366
+ if (isFunction(onBlocked)) return void onBlocked.call(self, decoratedName, args);
1367
+ if (isOnBlockedKey(onBlocked)) {
1368
+ const { [onBlocked]: handlerCandidate } = self;
1369
+ if (isFunction(handlerCandidate)) handlerCandidate.call(self, decoratedName, args);
1370
+ }
1371
+ };
1372
+ const blockedReturn = ()=>originalIsAsync ? Promise.resolve(void 0) : void 0;
1373
+ const wrapped = function(...args) {
1374
+ if (!computeAllowed(this, args)) {
1375
+ runOnBlocked(this, args);
1376
+ return blockedReturn();
1377
+ }
1378
+ return original.call(this, ...args);
1379
+ };
1380
+ Reflect.set(this, context.name, wrapped);
1381
+ });
1382
+ };
1383
+ }
1384
+ export { ANONYMOUS_ID_COOKIE, ANONYMOUS_ID_COOKIE_LEGACY, ANONYMOUS_ID_KEY, ANONYMOUS_ID_KEY_LEGACY, CHANGES_CACHE_KEY, CONSENT_KEY, DEBUG_FLAG_KEY, OPTIMIZATION_CORE_SDK_NAME, OPTIMIZATION_CORE_SDK_VERSION, PROFILE_CACHE_KEY, SELECTED_OPTIMIZATIONS_CACHE_KEY } from "./260.mjs";
1385
+ export { PREVIEW_PANEL_SIGNALS_SYMBOL, PREVIEW_PANEL_SIGNAL_FNS_SYMBOL } from "./632.mjs";
1386
+ export { ClickBuilderArgs, CoreStatelessRequestScope, DEFAULT_PAGE_PROPERTIES, EntryInteractionBuilderArgsBase, FlagViewBuilderArgs, HoverBuilderArgs, IdentifyBuilderArgs, InterceptorManager, PageViewBuilderArgs, ScreenViewBuilderArgs, TrackBuilderArgs, UniversalEventBuilderArgs, ViewBuilderArgs, batch, effect, events_EventBuilder as EventBuilder, guardedBy, resolvers_FlagsResolver as FlagsResolver, resolvers_MergeTagValueResolver as MergeTagValueResolver, resolvers_OptimizedEntryResolver as OptimizedEntryResolver, signalFns, signals, src_CoreStateful as CoreStateful, src_CoreStateless as CoreStateless, toDistinctObservable, toObservable };
1534
1387
 
1535
1388
  //# sourceMappingURL=index.mjs.map