@contentful/optimization-api-client 0.1.0-alpha8 → 0.1.0-alpha9

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 (79) hide show
  1. package/README.md +55 -24
  2. package/dist/199.mjs +2 -0
  3. package/dist/649.mjs +131 -0
  4. package/dist/649.mjs.map +1 -0
  5. package/dist/api-schemas.cjs +60 -0
  6. package/dist/api-schemas.cjs.map +1 -0
  7. package/dist/api-schemas.d.cts +4 -0
  8. package/dist/api-schemas.d.mts +4 -0
  9. package/dist/api-schemas.d.ts +4 -0
  10. package/dist/api-schemas.mjs +2 -0
  11. package/dist/index.cjs +588 -575
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +327 -68
  14. package/dist/index.d.mts +327 -68
  15. package/dist/index.d.ts +1649 -8
  16. package/dist/index.mjs +103 -136
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/logger.cjs +207 -0
  19. package/dist/logger.cjs.map +1 -0
  20. package/dist/logger.d.cts +287 -0
  21. package/dist/logger.d.mts +287 -0
  22. package/dist/logger.d.ts +287 -0
  23. package/dist/logger.mjs +1 -0
  24. package/package.json +24 -6
  25. package/dist/ApiClient.d.ts +0 -74
  26. package/dist/ApiClient.d.ts.map +0 -1
  27. package/dist/ApiClient.js +0 -61
  28. package/dist/ApiClient.js.map +0 -1
  29. package/dist/ApiClientBase.d.ts +0 -113
  30. package/dist/ApiClientBase.d.ts.map +0 -1
  31. package/dist/ApiClientBase.js +0 -94
  32. package/dist/ApiClientBase.js.map +0 -1
  33. package/dist/builders/EventBuilder.d.ts +0 -589
  34. package/dist/builders/EventBuilder.d.ts.map +0 -1
  35. package/dist/builders/EventBuilder.js +0 -349
  36. package/dist/builders/EventBuilder.js.map +0 -1
  37. package/dist/builders/index.d.ts +0 -3
  38. package/dist/builders/index.d.ts.map +0 -1
  39. package/dist/builders/index.js +0 -3
  40. package/dist/builders/index.js.map +0 -1
  41. package/dist/experience/ExperienceApiClient.d.ts +0 -267
  42. package/dist/experience/ExperienceApiClient.d.ts.map +0 -1
  43. package/dist/experience/ExperienceApiClient.js +0 -324
  44. package/dist/experience/ExperienceApiClient.js.map +0 -1
  45. package/dist/experience/index.d.ts +0 -4
  46. package/dist/experience/index.d.ts.map +0 -1
  47. package/dist/experience/index.js +0 -4
  48. package/dist/experience/index.js.map +0 -1
  49. package/dist/fetch/Fetch.d.ts +0 -96
  50. package/dist/fetch/Fetch.d.ts.map +0 -1
  51. package/dist/fetch/Fetch.js +0 -27
  52. package/dist/fetch/Fetch.js.map +0 -1
  53. package/dist/fetch/createProtectedFetchMethod.d.ts +0 -40
  54. package/dist/fetch/createProtectedFetchMethod.d.ts.map +0 -1
  55. package/dist/fetch/createProtectedFetchMethod.js +0 -53
  56. package/dist/fetch/createProtectedFetchMethod.js.map +0 -1
  57. package/dist/fetch/createRetryFetchMethod.d.ts +0 -60
  58. package/dist/fetch/createRetryFetchMethod.d.ts.map +0 -1
  59. package/dist/fetch/createRetryFetchMethod.js +0 -138
  60. package/dist/fetch/createRetryFetchMethod.js.map +0 -1
  61. package/dist/fetch/createTimeoutFetchMethod.d.ts +0 -51
  62. package/dist/fetch/createTimeoutFetchMethod.d.ts.map +0 -1
  63. package/dist/fetch/createTimeoutFetchMethod.js +0 -51
  64. package/dist/fetch/createTimeoutFetchMethod.js.map +0 -1
  65. package/dist/fetch/index.d.ts +0 -7
  66. package/dist/fetch/index.d.ts.map +0 -1
  67. package/dist/fetch/index.js +0 -7
  68. package/dist/fetch/index.js.map +0 -1
  69. package/dist/index.d.ts.map +0 -1
  70. package/dist/index.js +0 -8
  71. package/dist/index.js.map +0 -1
  72. package/dist/insights/InsightsApiClient.d.ts +0 -130
  73. package/dist/insights/InsightsApiClient.d.ts.map +0 -1
  74. package/dist/insights/InsightsApiClient.js +0 -143
  75. package/dist/insights/InsightsApiClient.js.map +0 -1
  76. package/dist/insights/index.d.ts +0 -4
  77. package/dist/insights/index.d.ts.map +0 -1
  78. package/dist/insights/index.js +0 -4
  79. package/dist/insights/index.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,564 +1,38 @@
1
1
  "use strict";
2
2
  var __webpack_modules__ = {
3
- "./src/ApiClient.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
3
+ "./src/lib/logger/LogSink.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4
4
  __webpack_require__.d(__webpack_exports__, {
5
- A: ()=>ApiClient
5
+ A: ()=>__rspack_default_export
6
6
  });
7
- var _experience__rspack_import_0 = __webpack_require__("./src/experience/index.ts");
8
- var _insights__rspack_import_1 = __webpack_require__("./src/insights/index.ts");
9
- class ApiClient {
10
- config;
11
- experience;
12
- insights;
13
- constructor(config){
14
- const { personalization, analytics, ...apiConfig } = config;
15
- this.config = apiConfig;
16
- this.experience = new _experience__rspack_import_0.A({
17
- ...apiConfig,
18
- ...personalization
19
- });
20
- this.insights = new _insights__rspack_import_1.A({
21
- ...apiConfig,
22
- ...analytics
23
- });
24
- }
7
+ class LogSink {
25
8
  }
9
+ const __rspack_default_export = LogSink;
26
10
  },
27
- "./src/ApiClientBase.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
11
+ "./src/lib/logger/logging.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
28
12
  __webpack_require__.d(__webpack_exports__, {
29
- A: ()=>src_ApiClientBase
13
+ A: ()=>logLevelSeverity
30
14
  });
31
- var dist = __webpack_require__("../../lib/logger/dist/index.mjs");
32
- const external_p_retry_namespaceObject = require("p-retry");
33
- var external_p_retry_default = /*#__PURE__*/ __webpack_require__.n(external_p_retry_namespaceObject);
34
- const logger = (0, dist.zP)('ApiClient:Retry');
35
- const DEFAULT_INTERVAL_TIMEOUT = 0;
36
- const DEFAULT_RETRY_COUNT = 1;
37
- const RETRY_RESPONSE_STATUS = 503;
38
- const HTTP_ERROR_RESPONSE_STATUS = 500;
39
- class HttpError extends Error {
40
- status;
41
- constructor(message, status = HTTP_ERROR_RESPONSE_STATUS){
42
- super(message);
43
- Object.setPrototypeOf(this, HttpError.prototype);
44
- this.status = status;
45
- }
46
- }
47
- function createRetryFetchCallback({ apiName = 'Optimization', controller, fetchMethod = fetch, init, url }) {
48
- return async ()=>{
49
- try {
50
- const response = await fetchMethod(url, init);
51
- if (response.status === RETRY_RESPONSE_STATUS) throw new HttpError(`${apiName} API request to "${url.toString()}" failed with status: "[${response.status}] ${response.statusText}".`, RETRY_RESPONSE_STATUS);
52
- if (!response.ok) {
53
- const httpError = new Error(`Request to "${url.toString()}" failed with status: [${response.status}] ${response.statusText} - traceparent: ${response.headers.get('traceparent')}`);
54
- logger.error('Request failed with non-OK status:', httpError);
55
- controller.abort();
56
- return;
57
- }
58
- logger.debug(`Response from "${url.toString()}":`, response);
59
- return response;
60
- } catch (error) {
61
- if (error instanceof HttpError && error.status === RETRY_RESPONSE_STATUS) throw error;
62
- logger.error(`Request to "${url.toString()}" failed:`, error);
63
- controller.abort();
64
- }
65
- };
66
- }
67
- function createRetryFetchMethod({ apiName = 'Optimization', fetchMethod = fetch, intervalTimeout = DEFAULT_INTERVAL_TIMEOUT, onFailedAttempt, retries = DEFAULT_RETRY_COUNT } = {}) {
68
- return async (url, init)=>{
69
- const controller = new AbortController();
70
- let retryResponse;
71
- try {
72
- retryResponse = await external_p_retry_default()(createRetryFetchCallback({
73
- apiName,
74
- controller,
75
- fetchMethod,
76
- init,
77
- url
78
- }), {
79
- minTimeout: intervalTimeout,
80
- onFailedAttempt: (options)=>onFailedAttempt?.({
81
- ...options,
82
- apiName
83
- }),
84
- retries,
85
- signal: controller.signal
86
- });
87
- } catch (error) {
88
- if (!(error instanceof Error) || 'AbortError' !== error.name) throw error;
89
- }
90
- if (!retryResponse) throw new Error(`${apiName} API request to "${url.toString()}" may not be retried.`);
91
- return retryResponse;
92
- };
93
- }
94
- const createTimeoutFetchMethod_logger = (0, dist.zP)('ApiClient:Timeout');
95
- const DEFAULT_REQUEST_TIMEOUT = 3000;
96
- function createTimeoutFetchMethod({ apiName = 'Optimization', fetchMethod = fetch, onRequestTimeout, requestTimeout = DEFAULT_REQUEST_TIMEOUT } = {}) {
97
- return async (url, init)=>{
98
- const controller = new AbortController();
99
- const id = setTimeout(()=>{
100
- if ('function' == typeof onRequestTimeout) onRequestTimeout({
101
- apiName
102
- });
103
- else createTimeoutFetchMethod_logger.error(`Request to "${url.toString()}" timed out`, new Error('Request timeout'));
104
- controller.abort();
105
- }, requestTimeout);
106
- const response = await fetchMethod(url, {
107
- ...init,
108
- signal: controller.signal
109
- });
110
- clearTimeout(id);
111
- return response;
112
- };
113
- }
114
- const createProtectedFetchMethod_logger = (0, dist.zP)('ApiClient:Fetch');
115
- function createProtectedFetchMethod(options) {
116
- try {
117
- const timeoutFetchMethod = createTimeoutFetchMethod(options);
118
- const retryFetchMethod = createRetryFetchMethod({
119
- ...options,
120
- fetchMethod: timeoutFetchMethod
121
- });
122
- return retryFetchMethod;
123
- } catch (error) {
124
- if (error instanceof Error) if ('AbortError' === error.name) createProtectedFetchMethod_logger.warn('Request aborted due to network issues. This request may not be retried.');
125
- else createProtectedFetchMethod_logger.error('Request failed:', error);
126
- throw error;
127
- }
128
- }
129
- const Fetch = {
130
- create: createProtectedFetchMethod
15
+ const logLevelSeverity = {
16
+ fatal: 60,
17
+ error: 50,
18
+ warn: 40,
19
+ info: 30,
20
+ debug: 20,
21
+ log: 10
131
22
  };
132
- const fetch_Fetch = Fetch;
133
- const src_fetch = fetch_Fetch;
134
- const ApiClientBase_logger = (0, dist.zP)('ApiClient');
135
- const DEFAULT_ENVIRONMENT = 'main';
136
- class ApiClientBase {
137
- name;
138
- clientId;
139
- environment;
140
- fetch;
141
- constructor(name, { fetchOptions, clientId, environment }){
142
- this.clientId = clientId;
143
- this.environment = environment ?? DEFAULT_ENVIRONMENT;
144
- this.name = name;
145
- this.fetch = src_fetch.create({
146
- ...fetchOptions ?? {},
147
- apiName: name
148
- });
149
- }
150
- logRequestError(error, { requestName }) {
151
- if (error instanceof Error) if ('AbortError' === error.name) ApiClientBase_logger.warn(`[${this.name}] "${requestName}" request aborted due to network issues. This request may not be retried.`);
152
- else ApiClientBase_logger.error(`[${this.name}] "${requestName}" request failed:`, error);
153
- }
154
- }
155
- const src_ApiClientBase = ApiClientBase;
156
- },
157
- "./src/builders/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
158
- __webpack_require__.d(__webpack_exports__, {
159
- c: ()=>DEFAULT_PAGE_PROPERTIES,
160
- e: ()=>builders_EventBuilder
161
- });
162
- var optimization_api_schemas_ = __webpack_require__("@contentful/optimization-api-schemas");
163
- const external_es_toolkit_namespaceObject = require("es-toolkit");
164
- const mini_namespaceObject = require("zod/mini");
165
- const UniversalEventBuilderArgs = mini_namespaceObject.object({
166
- campaign: mini_namespaceObject.optional(optimization_api_schemas_.Campaign),
167
- locale: mini_namespaceObject.optional(mini_namespaceObject.string()),
168
- location: mini_namespaceObject.optional(optimization_api_schemas_.GeoLocation),
169
- page: mini_namespaceObject.optional(optimization_api_schemas_.Page),
170
- screen: mini_namespaceObject.optional(optimization_api_schemas_.Screen),
171
- userAgent: mini_namespaceObject.optional(mini_namespaceObject.string())
172
- });
173
- const ComponentViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
174
- componentId: mini_namespaceObject.string(),
175
- experienceId: mini_namespaceObject.optional(mini_namespaceObject.string()),
176
- variantIndex: mini_namespaceObject.optional(mini_namespaceObject.number()),
177
- sticky: mini_namespaceObject.optional(mini_namespaceObject.boolean())
178
- });
179
- const IdentifyBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
180
- traits: mini_namespaceObject.optional(optimization_api_schemas_.Traits),
181
- userId: mini_namespaceObject.string()
182
- });
183
- const PageViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
184
- properties: mini_namespaceObject.optional(mini_namespaceObject.partial(optimization_api_schemas_.Page))
185
- });
186
- const ScreenViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
187
- name: mini_namespaceObject.string(),
188
- properties: optimization_api_schemas_.Properties
189
- });
190
- const TrackBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
191
- event: mini_namespaceObject.string(),
192
- properties: mini_namespaceObject.optional(mini_namespaceObject.prefault(optimization_api_schemas_.Properties, {}))
193
- });
194
- const DEFAULT_PAGE_PROPERTIES = {
195
- path: '',
196
- query: {},
197
- referrer: '',
198
- search: '',
199
- title: '',
200
- url: ''
201
- };
202
- class EventBuilder {
203
- app;
204
- channel;
205
- library;
206
- getLocale;
207
- getPageProperties;
208
- getUserAgent;
209
- constructor(config){
210
- const { app, channel, library, getLocale, getPageProperties, getUserAgent } = config;
211
- this.app = app;
212
- this.channel = channel;
213
- this.library = library;
214
- this.getLocale = getLocale ?? (()=>'en-US');
215
- this.getPageProperties = getPageProperties ?? (()=>DEFAULT_PAGE_PROPERTIES);
216
- this.getUserAgent = getUserAgent ?? (()=>void 0);
217
- }
218
- buildUniversalEventProperties({ campaign = {}, locale, location, page, screen, userAgent }) {
219
- const timestamp = new Date().toISOString();
220
- return {
221
- channel: this.channel,
222
- context: {
223
- app: this.app,
224
- campaign,
225
- gdpr: {
226
- isConsentGiven: true
227
- },
228
- library: this.library,
229
- locale: locale ?? this.getLocale() ?? 'en-US',
230
- location,
231
- page: page ?? this.getPageProperties(),
232
- screen,
233
- userAgent: userAgent ?? this.getUserAgent()
234
- },
235
- messageId: crypto.randomUUID(),
236
- originalTimestamp: timestamp,
237
- sentAt: timestamp,
238
- timestamp
239
- };
240
- }
241
- buildComponentView(args) {
242
- const { componentId, experienceId, variantIndex, ...universal } = ComponentViewBuilderArgs.parse(args);
243
- return {
244
- ...this.buildUniversalEventProperties(universal),
245
- type: 'component',
246
- componentType: 'Entry',
247
- componentId,
248
- experienceId,
249
- variantIndex: variantIndex ?? 0
250
- };
251
- }
252
- buildFlagView(args) {
253
- return {
254
- ...this.buildComponentView(args),
255
- componentType: 'Variable'
256
- };
257
- }
258
- buildIdentify(args) {
259
- const { traits = {}, userId, ...universal } = IdentifyBuilderArgs.parse(args);
260
- return {
261
- ...this.buildUniversalEventProperties(universal),
262
- type: 'identify',
263
- traits,
264
- userId
265
- };
266
- }
267
- buildPageView(args = {}) {
268
- const { properties = {}, ...universal } = PageViewBuilderArgs.parse(args);
269
- const pageProperties = this.getPageProperties();
270
- const merged = (0, external_es_toolkit_namespaceObject.merge)({
271
- ...pageProperties,
272
- title: pageProperties.title ?? DEFAULT_PAGE_PROPERTIES.title
273
- }, properties);
274
- const { context: { screen: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
275
- const context = optimization_api_schemas_.PageEventContext.parse(universalContext);
276
- return {
277
- ...universalProperties,
278
- context,
279
- type: 'page',
280
- properties: merged
281
- };
282
- }
283
- buildScreenView(args) {
284
- const { name, properties, ...universal } = ScreenViewBuilderArgs.parse(args);
285
- const { context: { page: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
286
- const context = optimization_api_schemas_.ScreenEventContext.parse(universalContext);
287
- return {
288
- ...universalProperties,
289
- context,
290
- type: 'screen',
291
- name,
292
- properties
293
- };
294
- }
295
- buildTrack(args) {
296
- const { event, properties = {}, ...universal } = TrackBuilderArgs.parse(args);
297
- return {
298
- ...this.buildUniversalEventProperties(universal),
299
- type: 'track',
300
- event,
301
- properties
302
- };
303
- }
304
- }
305
- const builders_EventBuilder = EventBuilder;
306
23
  },
307
- "./src/experience/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
24
+ "./src/logger.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
308
25
  __webpack_require__.d(__webpack_exports__, {
309
- n: ()=>EXPERIENCE_BASE_URL,
310
- A: ()=>experience
26
+ createScopedLogger: ()=>createScopedLogger
311
27
  });
312
- var optimization_api_schemas_ = __webpack_require__("@contentful/optimization-api-schemas");
313
- var dist = __webpack_require__("../../lib/logger/dist/index.mjs");
314
- var ApiClientBase = __webpack_require__("./src/ApiClientBase.ts");
315
- const logger = (0, dist.zP)('ApiClient:Experience');
316
- const EXPERIENCE_BASE_URL = 'https://experience.ninetailed.co/';
317
- class ExperienceApiClient extends ApiClientBase.A {
318
- baseUrl;
319
- enabledFeatures;
320
- ip;
321
- locale;
322
- plainText;
323
- preflight;
324
- constructor(config){
325
- super('Experience', config);
326
- const { baseUrl, enabledFeatures, ip, locale, plainText, preflight } = config;
327
- this.baseUrl = baseUrl || EXPERIENCE_BASE_URL;
328
- this.enabledFeatures = enabledFeatures;
329
- this.ip = ip;
330
- this.locale = locale;
331
- this.plainText = plainText;
332
- this.preflight = preflight;
333
- }
334
- async getProfile(id, options = {}) {
335
- if (!id) throw new Error('Valid profile ID required.');
336
- const requestName = 'Get Profile';
337
- logger.info(`Sending "${requestName}" request`);
338
- try {
339
- const response = await this.fetch(this.constructUrl(`v2/organizations/${this.clientId}/environments/${this.environment}/profiles/${id}`, options), {
340
- method: 'GET'
341
- });
342
- const { data: { changes, experiences, profile } } = optimization_api_schemas_.ExperienceResponse.parse(await response.json());
343
- const data = {
344
- changes,
345
- personalizations: experiences,
346
- profile
347
- };
348
- logger.debug(`"${requestName}" request successfully completed`);
349
- return data;
350
- } catch (error) {
351
- this.logRequestError(error, {
352
- requestName
353
- });
354
- throw error;
355
- }
356
- }
357
- async makeProfileMutationRequest({ url, body, options }) {
358
- return await this.fetch(this.constructUrl(url, options), {
359
- method: 'POST',
360
- headers: this.constructHeaders(options),
361
- body: JSON.stringify(body),
362
- keepalive: true
363
- });
364
- }
365
- async createProfile({ events }, options = {}) {
366
- const requestName = 'Create Profile';
367
- logger.info(`Sending "${requestName}" request`);
368
- const body = {
369
- events: optimization_api_schemas_.ExperienceEventArray.parse(events),
370
- options: this.constructBodyOptions(options)
371
- };
372
- logger.debug(`"${requestName}" request body:`, body);
373
- try {
374
- const response = await this.makeProfileMutationRequest({
375
- url: `v2/organizations/${this.clientId}/environments/${this.environment}/profiles`,
376
- body,
377
- options
378
- });
379
- const { data: { changes, experiences, profile } } = optimization_api_schemas_.ExperienceResponse.parse(await response.json());
380
- const data = {
381
- changes,
382
- personalizations: experiences,
383
- profile
384
- };
385
- logger.debug(`"${requestName}" request successfully completed`);
386
- return data;
387
- } catch (error) {
388
- this.logRequestError(error, {
389
- requestName
390
- });
391
- throw error;
392
- }
393
- }
394
- async updateProfile({ profileId, events }, options = {}) {
395
- if (!profileId) throw new Error('Valid profile ID required.');
396
- const requestName = 'Update Profile';
397
- logger.info(`Sending "${requestName}" request`);
398
- const body = {
399
- events: optimization_api_schemas_.ExperienceEventArray.parse(events),
400
- options: this.constructBodyOptions(options)
401
- };
402
- logger.debug(`"${requestName}" request body:`, body);
403
- try {
404
- const response = await this.makeProfileMutationRequest({
405
- url: `v2/organizations/${this.clientId}/environments/${this.environment}/profiles/${profileId}`,
406
- body,
407
- options
408
- });
409
- const { data: { changes, experiences, profile } } = optimization_api_schemas_.ExperienceResponse.parse(await response.json());
410
- const data = {
411
- changes,
412
- personalizations: experiences,
413
- profile
414
- };
415
- logger.debug(`"${requestName}" request successfully completed`);
416
- return data;
417
- } catch (error) {
418
- this.logRequestError(error, {
419
- requestName
420
- });
421
- throw error;
422
- }
423
- }
424
- async upsertProfile({ profileId, events }, options) {
425
- if (!profileId) return await this.createProfile({
426
- events
427
- }, options);
428
- return await this.updateProfile({
429
- profileId,
430
- events
431
- }, options);
432
- }
433
- async upsertManyProfiles({ events }, options = {}) {
434
- const requestName = 'Upsert Many Profiles';
435
- logger.info(`Sending "${requestName}" request`);
436
- const body = {
437
- events: optimization_api_schemas_.ExperienceEventArray.parse(events),
438
- options: this.constructBodyOptions(options)
439
- };
440
- logger.debug(`"${requestName}" request body:`, body);
441
- try {
442
- const response = await this.makeProfileMutationRequest({
443
- url: `v2/organizations/${this.clientId}/environments/${this.environment}/events`,
444
- body,
445
- options: {
446
- plainText: false,
447
- ...options
448
- }
449
- });
450
- const { data: { profiles } } = optimization_api_schemas_.BatchExperienceResponse.parse(await response.json());
451
- logger.debug(`"${requestName}" request successfully completed`);
452
- return profiles;
453
- } catch (error) {
454
- this.logRequestError(error, {
455
- requestName
456
- });
457
- throw error;
458
- }
459
- }
460
- constructUrl(path, options) {
461
- const url = new URL(path, this.baseUrl);
462
- const locale = options.locale ?? this.locale;
463
- const preflight = options.preflight ?? this.preflight;
464
- if (locale) url.searchParams.set('locale', locale);
465
- if (preflight) url.searchParams.set('type', 'preflight');
466
- return url.toString();
467
- }
468
- constructHeaders({ ip = this.ip, plainText = this.plainText }) {
469
- const headers = new Map();
470
- if (ip) headers.set('X-Force-IP', ip);
471
- if (plainText ?? this.plainText ?? true) headers.set('Content-Type', 'text/plain');
472
- else headers.set('Content-Type', 'application/json');
473
- return Object.fromEntries(headers);
474
- }
475
- constructBodyOptions = ({ enabledFeatures = this.enabledFeatures })=>{
476
- const bodyOptions = {};
477
- if (enabledFeatures && Array.isArray(enabledFeatures) && enabledFeatures.length > 0) bodyOptions.features = enabledFeatures;
478
- else bodyOptions.features = [
479
- 'ip-enrichment',
480
- 'location'
481
- ];
482
- return bodyOptions;
483
- };
484
- }
485
- const experience = ExperienceApiClient;
486
- },
487
- "./src/insights/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
488
- __webpack_require__.d(__webpack_exports__, {
489
- Q: ()=>INSIGHTS_BASE_URL,
490
- A: ()=>insights
491
- });
492
- var optimization_api_schemas_ = __webpack_require__("@contentful/optimization-api-schemas");
493
- var dist = __webpack_require__("../../lib/logger/dist/index.mjs");
494
- var ApiClientBase = __webpack_require__("./src/ApiClientBase.ts");
495
- const logger = (0, dist.zP)('ApiClient:Insights');
496
- const INSIGHTS_BASE_URL = 'https://ingest.insights.ninetailed.co/';
497
- class InsightsApiClient extends ApiClientBase.A {
498
- baseUrl;
499
- beaconHandler;
500
- constructor(config){
501
- super('Insights', config);
502
- const { baseUrl, beaconHandler } = config;
503
- this.baseUrl = baseUrl || INSIGHTS_BASE_URL;
504
- this.beaconHandler = beaconHandler;
505
- }
506
- async sendBatchEvents(batches, options = {}) {
507
- const { beaconHandler = this.beaconHandler } = options;
508
- const url = new URL(`v1/organizations/${this.clientId}/environments/${this.environment}/events`, this.baseUrl);
509
- const body = optimization_api_schemas_.BatchInsightsEventArray.parse(batches);
510
- if ('function' == typeof beaconHandler) {
511
- logger.debug('Queueing events via beaconHandler');
512
- const beaconSuccessfullyQueued = beaconHandler(url, body);
513
- if (beaconSuccessfullyQueued) return true;
514
- logger.warn('beaconHandler failed to queue events; events will be emitted immediately via fetch');
515
- }
516
- const requestName = 'Event Batches';
517
- logger.info(`Sending "${requestName}" request`);
518
- logger.debug(`"${requestName}" request body:`, body);
519
- try {
520
- await this.fetch(url, {
521
- method: 'POST',
522
- headers: {
523
- 'Content-Type': 'application/json'
524
- },
525
- body: JSON.stringify(body),
526
- keepalive: true
527
- });
528
- logger.debug(`"${requestName}" request successfully completed`);
529
- return true;
530
- } catch (error) {
531
- this.logRequestError(error, {
532
- requestName
533
- });
534
- return false;
535
- }
536
- }
537
- }
538
- const insights = InsightsApiClient;
539
- },
540
- "@contentful/optimization-api-schemas" (module) {
541
- module.exports = require("@contentful/optimization-api-schemas");
542
- },
543
- "../../lib/logger/dist/index.mjs" (__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
544
- __webpack_require__.d(__webpack_exports__, {
545
- zP: ()=>createScopedLogger
546
- });
547
- const external_diary_namespaceObject = require("diary");
548
- require("diary/utils");
549
- class Logger {
28
+ class Logger_Logger {
550
29
  name = '@contentful/optimization';
551
30
  PREFIX_PARTS = [
552
31
  'Ctfl',
553
32
  'O10n'
554
33
  ];
555
34
  DELIMITER = ':';
556
- diary;
557
35
  sinks = [];
558
- constructor(){
559
- this.diary = (0, external_diary_namespaceObject.diary)(this.name, this.onLogEvent.bind(this));
560
- (0, external_diary_namespaceObject.enable)(this.name);
561
- }
562
36
  assembleLocationPrefix(logLocation) {
563
37
  return `[${[
564
38
  ...this.PREFIX_PARTS,
@@ -578,22 +52,32 @@ var __webpack_modules__ = {
578
52
  this.sinks = [];
579
53
  }
580
54
  debug(logLocation, message, ...args) {
581
- this.diary.debug(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
55
+ this.emit('debug', logLocation, message, ...args);
582
56
  }
583
57
  info(logLocation, message, ...args) {
584
- this.diary.info(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
58
+ this.emit('info', logLocation, message, ...args);
585
59
  }
586
60
  log(logLocation, message, ...args) {
587
- this.diary.log(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
61
+ this.emit('log', logLocation, message, ...args);
588
62
  }
589
63
  warn(logLocation, message, ...args) {
590
- this.diary.warn(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
64
+ this.emit('warn', logLocation, message, ...args);
591
65
  }
592
66
  error(logLocation, message, ...args) {
593
- this.diary.error(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
67
+ this.emit('error', logLocation, message, ...args);
594
68
  }
595
69
  fatal(logLocation, message, ...args) {
596
- this.diary.fatal(`${this.assembleLocationPrefix(logLocation)} ${message}`, ...args);
70
+ this.emit('fatal', logLocation, message, ...args);
71
+ }
72
+ emit(level, logLocation, message, ...args) {
73
+ this.onLogEvent({
74
+ name: this.name,
75
+ level,
76
+ messages: [
77
+ `${this.assembleLocationPrefix(logLocation)} ${String(message)}`,
78
+ ...args
79
+ ]
80
+ });
597
81
  }
598
82
  onLogEvent(event) {
599
83
  this.sinks.forEach((sink)=>{
@@ -601,7 +85,7 @@ var __webpack_modules__ = {
601
85
  });
602
86
  }
603
87
  }
604
- const logger = new Logger();
88
+ const logger = new Logger_Logger();
605
89
  function createScopedLogger(location) {
606
90
  return {
607
91
  debug: (message, ...args)=>{
@@ -624,6 +108,9 @@ var __webpack_modules__ = {
624
108
  }
625
109
  };
626
110
  }
111
+ __webpack_require__("./src/lib/logger/logging.ts");
112
+ var LogSink = __webpack_require__("./src/lib/logger/LogSink.ts");
113
+ LogSink.A;
627
114
  }
628
115
  };
629
116
  var __webpack_module_cache__ = {};
@@ -636,15 +123,6 @@ function __webpack_require__(moduleId) {
636
123
  __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
637
124
  return module.exports;
638
125
  }
639
- (()=>{
640
- __webpack_require__.n = (module)=>{
641
- var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
642
- __webpack_require__.d(getter, {
643
- a: getter
644
- });
645
- return getter;
646
- };
647
- })();
648
126
  (()=>{
649
127
  __webpack_require__.d = (exports1, definition)=>{
650
128
  for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
@@ -670,24 +148,559 @@ var __webpack_exports__ = {};
670
148
  (()=>{
671
149
  __webpack_require__.r(__webpack_exports__);
672
150
  __webpack_require__.d(__webpack_exports__, {
673
- ApiClient: ()=>_ApiClient__rspack_import_0.A,
674
- DEFAULT_PAGE_PROPERTIES: ()=>_builders__rspack_import_3.c,
675
- EXPERIENCE_BASE_URL: ()=>_experience__rspack_import_4.n,
676
- EventBuilder: ()=>_builders__rspack_import_3.e,
677
- INSIGHTS_BASE_URL: ()=>_insights__rspack_import_5.Q
151
+ EXPERIENCE_BASE_URL: ()=>EXPERIENCE_BASE_URL,
152
+ ApiClient: ()=>ApiClient,
153
+ INSIGHTS_BASE_URL: ()=>INSIGHTS_BASE_URL,
154
+ DEFAULT_PAGE_PROPERTIES: ()=>DEFAULT_PAGE_PROPERTIES,
155
+ EventBuilder: ()=>builders_EventBuilder
156
+ });
157
+ const optimization_api_schemas_namespaceObject = require("@contentful/optimization-api-schemas");
158
+ var logger = __webpack_require__("./src/logger.ts");
159
+ const createRetryFetchMethod_logger = (0, logger.createScopedLogger)('ApiClient:Retry');
160
+ const DEFAULT_INTERVAL_TIMEOUT = 0;
161
+ const DEFAULT_RETRY_COUNT = 1;
162
+ const RETRY_RESPONSE_STATUS = 503;
163
+ const HTTP_ERROR_RESPONSE_STATUS = 500;
164
+ class HttpError extends Error {
165
+ status;
166
+ constructor(message, status = HTTP_ERROR_RESPONSE_STATUS){
167
+ super(message);
168
+ Object.setPrototypeOf(this, HttpError.prototype);
169
+ this.status = status;
170
+ }
171
+ }
172
+ function createRetryFetchCallback({ apiName = 'Optimization', controller, fetchMethod = fetch, init, url }) {
173
+ return async ()=>{
174
+ try {
175
+ const response = await fetchMethod(url, init);
176
+ if (response.status === RETRY_RESPONSE_STATUS) throw new HttpError(`${apiName} API request to "${url.toString()}" failed with status: "[${response.status}] ${response.statusText}".`, RETRY_RESPONSE_STATUS);
177
+ if (!response.ok) {
178
+ const httpError = new Error(`Request to "${url.toString()}" failed with status: [${response.status}] ${response.statusText} - traceparent: ${response.headers.get('traceparent')}`);
179
+ createRetryFetchMethod_logger.error('Request failed with non-OK status:', httpError);
180
+ controller.abort();
181
+ return;
182
+ }
183
+ createRetryFetchMethod_logger.debug(`Response from "${url.toString()}":`, response);
184
+ return response;
185
+ } catch (error) {
186
+ if (error instanceof HttpError && error.status === RETRY_RESPONSE_STATUS) throw error;
187
+ createRetryFetchMethod_logger.error(`Request to "${url.toString()}" failed:`, error);
188
+ controller.abort();
189
+ }
190
+ };
191
+ }
192
+ async function delayRetry(intervalTimeout) {
193
+ if (intervalTimeout <= 0) return;
194
+ const { promise, resolve } = Promise.withResolvers();
195
+ setTimeout(()=>{
196
+ resolve(void 0);
197
+ }, intervalTimeout);
198
+ await promise;
199
+ }
200
+ function createRetryFetchMethod({ apiName = 'Optimization', fetchMethod = fetch, intervalTimeout = DEFAULT_INTERVAL_TIMEOUT, onFailedAttempt, retries = DEFAULT_RETRY_COUNT } = {}) {
201
+ return async (url, init)=>{
202
+ const controller = new AbortController();
203
+ const maxAttempts = retries + 1;
204
+ const attemptFetch = createRetryFetchCallback({
205
+ apiName,
206
+ controller,
207
+ fetchMethod,
208
+ init,
209
+ url
210
+ });
211
+ for(let attemptNumber = 1; attemptNumber <= maxAttempts; attemptNumber++)try {
212
+ const response = await attemptFetch();
213
+ if (response) return response;
214
+ break;
215
+ } catch (error) {
216
+ if (!(error instanceof HttpError) || error.status !== RETRY_RESPONSE_STATUS) throw error;
217
+ const retriesLeft = maxAttempts - attemptNumber;
218
+ onFailedAttempt?.({
219
+ apiName,
220
+ error,
221
+ attemptNumber,
222
+ retriesLeft
223
+ });
224
+ if (0 === retriesLeft) throw error;
225
+ await delayRetry(intervalTimeout);
226
+ }
227
+ throw new Error(`${apiName} API request to "${url.toString()}" may not be retried.`);
228
+ };
229
+ }
230
+ const createTimeoutFetchMethod_logger = (0, logger.createScopedLogger)('ApiClient:Timeout');
231
+ const DEFAULT_REQUEST_TIMEOUT = 3000;
232
+ function createTimeoutFetchMethod({ apiName = 'Optimization', fetchMethod = fetch, onRequestTimeout, requestTimeout = DEFAULT_REQUEST_TIMEOUT } = {}) {
233
+ return async (url, init)=>{
234
+ const controller = new AbortController();
235
+ const id = setTimeout(()=>{
236
+ if ('function' == typeof onRequestTimeout) onRequestTimeout({
237
+ apiName
238
+ });
239
+ else createTimeoutFetchMethod_logger.error(`Request to "${url.toString()}" timed out`, new Error('Request timeout'));
240
+ controller.abort();
241
+ }, requestTimeout);
242
+ const response = await fetchMethod(url, {
243
+ ...init,
244
+ signal: controller.signal
245
+ });
246
+ clearTimeout(id);
247
+ return response;
248
+ };
249
+ }
250
+ const createProtectedFetchMethod_logger = (0, logger.createScopedLogger)('ApiClient:Fetch');
251
+ function createProtectedFetchMethod(options) {
252
+ try {
253
+ const timeoutFetchMethod = createTimeoutFetchMethod(options);
254
+ const retryFetchMethod = createRetryFetchMethod({
255
+ ...options,
256
+ fetchMethod: timeoutFetchMethod
257
+ });
258
+ return retryFetchMethod;
259
+ } catch (error) {
260
+ if (error instanceof Error) if ('AbortError' === error.name) createProtectedFetchMethod_logger.warn('Request aborted due to network issues. This request may not be retried.');
261
+ else createProtectedFetchMethod_logger.error('Request failed:', error);
262
+ throw error;
263
+ }
264
+ }
265
+ const Fetch = {
266
+ create: createProtectedFetchMethod
267
+ };
268
+ const fetch_Fetch = Fetch;
269
+ const src_fetch = fetch_Fetch;
270
+ const ApiClientBase_logger = (0, logger.createScopedLogger)('ApiClient');
271
+ const DEFAULT_ENVIRONMENT = 'main';
272
+ class ApiClientBase {
273
+ name;
274
+ clientId;
275
+ environment;
276
+ fetch;
277
+ constructor(name, { fetchOptions, clientId, environment }){
278
+ this.clientId = clientId;
279
+ this.environment = environment ?? DEFAULT_ENVIRONMENT;
280
+ this.name = name;
281
+ this.fetch = src_fetch.create({
282
+ ...fetchOptions ?? {},
283
+ apiName: name
284
+ });
285
+ }
286
+ logRequestError(error, { requestName }) {
287
+ if (error instanceof Error) if ('AbortError' === error.name) ApiClientBase_logger.warn(`[${this.name}] "${requestName}" request aborted due to network issues. This request may not be retried.`);
288
+ else ApiClientBase_logger.error(`[${this.name}] "${requestName}" request failed:`, error);
289
+ }
290
+ }
291
+ const src_ApiClientBase = ApiClientBase;
292
+ const ExperienceApiClient_logger = (0, logger.createScopedLogger)('ApiClient:Experience');
293
+ const EXPERIENCE_BASE_URL = 'https://experience.ninetailed.co/';
294
+ class ExperienceApiClient extends src_ApiClientBase {
295
+ baseUrl;
296
+ enabledFeatures;
297
+ ip;
298
+ locale;
299
+ plainText;
300
+ preflight;
301
+ constructor(config){
302
+ super('Experience', config);
303
+ const { baseUrl, enabledFeatures, ip, locale, plainText, preflight } = config;
304
+ this.baseUrl = baseUrl || EXPERIENCE_BASE_URL;
305
+ this.enabledFeatures = enabledFeatures;
306
+ this.ip = ip;
307
+ this.locale = locale;
308
+ this.plainText = plainText;
309
+ this.preflight = preflight;
310
+ }
311
+ async getProfile(id, options = {}) {
312
+ if (!id) throw new Error('Valid profile ID required.');
313
+ const requestName = 'Get Profile';
314
+ ExperienceApiClient_logger.info(`Sending "${requestName}" request`);
315
+ try {
316
+ const response = await this.fetch(this.constructUrl(`v2/organizations/${this.clientId}/environments/${this.environment}/profiles/${id}`, options), {
317
+ method: 'GET'
318
+ });
319
+ const { data: { changes, experiences, profile } } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ExperienceResponse, await response.json());
320
+ const data = {
321
+ changes,
322
+ personalizations: experiences,
323
+ profile
324
+ };
325
+ ExperienceApiClient_logger.debug(`"${requestName}" request successfully completed`);
326
+ return data;
327
+ } catch (error) {
328
+ this.logRequestError(error, {
329
+ requestName
330
+ });
331
+ throw error;
332
+ }
333
+ }
334
+ async makeProfileMutationRequest({ url, body, options }) {
335
+ return await this.fetch(this.constructUrl(url, options), {
336
+ method: 'POST',
337
+ headers: this.constructHeaders(options),
338
+ body: JSON.stringify(body),
339
+ keepalive: true
340
+ });
341
+ }
342
+ async createProfile({ events }, options = {}) {
343
+ const requestName = 'Create Profile';
344
+ ExperienceApiClient_logger.info(`Sending "${requestName}" request`);
345
+ const body = this.constructExperienceRequestBody(events, options);
346
+ ExperienceApiClient_logger.debug(`"${requestName}" request body:`, body);
347
+ try {
348
+ const response = await this.makeProfileMutationRequest({
349
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/profiles`,
350
+ body,
351
+ options
352
+ });
353
+ const { data: { changes, experiences, profile } } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ExperienceResponse, await response.json());
354
+ const data = {
355
+ changes,
356
+ personalizations: experiences,
357
+ profile
358
+ };
359
+ ExperienceApiClient_logger.debug(`"${requestName}" request successfully completed`);
360
+ return data;
361
+ } catch (error) {
362
+ this.logRequestError(error, {
363
+ requestName
364
+ });
365
+ throw error;
366
+ }
367
+ }
368
+ async updateProfile({ profileId, events }, options = {}) {
369
+ if (!profileId) throw new Error('Valid profile ID required.');
370
+ const requestName = 'Update Profile';
371
+ ExperienceApiClient_logger.info(`Sending "${requestName}" request`);
372
+ const body = this.constructExperienceRequestBody(events, options);
373
+ ExperienceApiClient_logger.debug(`"${requestName}" request body:`, body);
374
+ try {
375
+ const response = await this.makeProfileMutationRequest({
376
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/profiles/${profileId}`,
377
+ body,
378
+ options
379
+ });
380
+ const { data: { changes, experiences, profile } } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ExperienceResponse, await response.json());
381
+ const data = {
382
+ changes,
383
+ personalizations: experiences,
384
+ profile
385
+ };
386
+ ExperienceApiClient_logger.debug(`"${requestName}" request successfully completed`);
387
+ return data;
388
+ } catch (error) {
389
+ this.logRequestError(error, {
390
+ requestName
391
+ });
392
+ throw error;
393
+ }
394
+ }
395
+ async upsertProfile({ profileId, events }, options) {
396
+ if (!profileId) return await this.createProfile({
397
+ events
398
+ }, options);
399
+ return await this.updateProfile({
400
+ profileId,
401
+ events
402
+ }, options);
403
+ }
404
+ async upsertManyProfiles({ events }, options = {}) {
405
+ const requestName = 'Upsert Many Profiles';
406
+ ExperienceApiClient_logger.info(`Sending "${requestName}" request`);
407
+ const body = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.BatchExperienceRequestData, {
408
+ events,
409
+ options: this.constructBodyOptions(options)
410
+ });
411
+ ExperienceApiClient_logger.debug(`"${requestName}" request body:`, body);
412
+ try {
413
+ const response = await this.makeProfileMutationRequest({
414
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/events`,
415
+ body,
416
+ options: {
417
+ plainText: false,
418
+ ...options
419
+ }
420
+ });
421
+ const { data: { profiles } } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.BatchExperienceResponse, await response.json());
422
+ ExperienceApiClient_logger.debug(`"${requestName}" request successfully completed`);
423
+ return profiles;
424
+ } catch (error) {
425
+ this.logRequestError(error, {
426
+ requestName
427
+ });
428
+ throw error;
429
+ }
430
+ }
431
+ constructUrl(path, options) {
432
+ const url = new URL(path, this.baseUrl);
433
+ const locale = options.locale ?? this.locale;
434
+ const preflight = options.preflight ?? this.preflight;
435
+ if (locale) url.searchParams.set('locale', locale);
436
+ if (preflight) url.searchParams.set('type', 'preflight');
437
+ return url.toString();
438
+ }
439
+ constructHeaders({ ip = this.ip, plainText = this.plainText }) {
440
+ const headers = new Map();
441
+ if (ip) headers.set('X-Force-IP', ip);
442
+ if (plainText ?? this.plainText ?? true) headers.set('Content-Type', 'text/plain');
443
+ else headers.set('Content-Type', 'application/json');
444
+ return Object.fromEntries(headers);
445
+ }
446
+ constructBodyOptions = ({ enabledFeatures = this.enabledFeatures })=>{
447
+ const bodyOptions = {};
448
+ if (enabledFeatures && Array.isArray(enabledFeatures) && enabledFeatures.length > 0) bodyOptions.features = enabledFeatures;
449
+ else bodyOptions.features = [
450
+ 'ip-enrichment',
451
+ 'location'
452
+ ];
453
+ return bodyOptions;
454
+ };
455
+ constructExperienceRequestBody(events, options) {
456
+ return optimization_api_schemas_namespaceObject.ExperienceRequestData.parse({
457
+ events: (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ExperienceEventArray, events),
458
+ options: this.constructBodyOptions(options)
459
+ });
460
+ }
461
+ }
462
+ const experience = ExperienceApiClient;
463
+ const InsightsApiClient_logger = (0, logger.createScopedLogger)('ApiClient:Insights');
464
+ const INSIGHTS_BASE_URL = 'https://ingest.insights.ninetailed.co/';
465
+ class InsightsApiClient extends src_ApiClientBase {
466
+ baseUrl;
467
+ beaconHandler;
468
+ constructor(config){
469
+ super('Insights', config);
470
+ const { baseUrl, beaconHandler } = config;
471
+ this.baseUrl = baseUrl || INSIGHTS_BASE_URL;
472
+ this.beaconHandler = beaconHandler;
473
+ }
474
+ async sendBatchEvents(batches, options = {}) {
475
+ const { beaconHandler = this.beaconHandler } = options;
476
+ const url = new URL(`v1/organizations/${this.clientId}/environments/${this.environment}/events`, this.baseUrl);
477
+ const body = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.BatchInsightsEventArray, batches);
478
+ if ('function' == typeof beaconHandler) {
479
+ InsightsApiClient_logger.debug('Queueing events via beaconHandler');
480
+ const beaconSuccessfullyQueued = beaconHandler(url, body);
481
+ if (beaconSuccessfullyQueued) return true;
482
+ InsightsApiClient_logger.warn('beaconHandler failed to queue events; events will be emitted immediately via fetch');
483
+ }
484
+ const requestName = 'Event Batches';
485
+ InsightsApiClient_logger.info(`Sending "${requestName}" request`);
486
+ InsightsApiClient_logger.debug(`"${requestName}" request body:`, body);
487
+ try {
488
+ await this.fetch(url, {
489
+ method: 'POST',
490
+ headers: {
491
+ 'Content-Type': 'application/json'
492
+ },
493
+ body: JSON.stringify(body),
494
+ keepalive: true
495
+ });
496
+ InsightsApiClient_logger.debug(`"${requestName}" request successfully completed`);
497
+ return true;
498
+ } catch (error) {
499
+ this.logRequestError(error, {
500
+ requestName
501
+ });
502
+ return false;
503
+ }
504
+ }
505
+ }
506
+ const insights = InsightsApiClient;
507
+ class ApiClient {
508
+ config;
509
+ experience;
510
+ insights;
511
+ constructor(config){
512
+ const { personalization, analytics, clientId, environment, fetchOptions } = config;
513
+ const apiConfig = {
514
+ clientId,
515
+ environment,
516
+ fetchOptions
517
+ };
518
+ this.config = apiConfig;
519
+ this.experience = new experience({
520
+ ...apiConfig,
521
+ ...personalization
522
+ });
523
+ this.insights = new insights({
524
+ ...apiConfig,
525
+ ...analytics
526
+ });
527
+ }
528
+ }
529
+ const object_namespaceObject = require("es-toolkit/object");
530
+ const mini_namespaceObject = require("zod/mini");
531
+ const UniversalEventBuilderArgs = mini_namespaceObject.object({
532
+ campaign: mini_namespaceObject.optional(optimization_api_schemas_namespaceObject.Campaign),
533
+ locale: mini_namespaceObject.optional(mini_namespaceObject.string()),
534
+ location: mini_namespaceObject.optional(optimization_api_schemas_namespaceObject.GeoLocation),
535
+ page: mini_namespaceObject.optional(optimization_api_schemas_namespaceObject.Page),
536
+ screen: mini_namespaceObject.optional(optimization_api_schemas_namespaceObject.Screen),
537
+ userAgent: mini_namespaceObject.optional(mini_namespaceObject.string())
538
+ });
539
+ const ComponentInteractionBuilderArgsBase = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
540
+ componentId: mini_namespaceObject.string(),
541
+ experienceId: mini_namespaceObject.optional(mini_namespaceObject.string()),
542
+ variantIndex: mini_namespaceObject.optional(mini_namespaceObject.number())
678
543
  });
679
- var _ApiClient__rspack_import_0 = __webpack_require__("./src/ApiClient.ts");
680
- var _contentful_optimization_api_schemas__rspack_import_1 = __webpack_require__("@contentful/optimization-api-schemas");
681
- var __rspack_reexport = {};
682
- for(const __rspack_import_key in _contentful_optimization_api_schemas__rspack_import_1)if ([
683
- "default",
684
- "ApiClient"
685
- ].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] = ()=>_contentful_optimization_api_schemas__rspack_import_1[__rspack_import_key];
686
- __webpack_require__.d(__webpack_exports__, __rspack_reexport);
687
- __webpack_require__("./src/ApiClientBase.ts");
688
- var _builders__rspack_import_3 = __webpack_require__("./src/builders/index.ts");
689
- var _experience__rspack_import_4 = __webpack_require__("./src/experience/index.ts");
690
- var _insights__rspack_import_5 = __webpack_require__("./src/insights/index.ts");
544
+ const ComponentViewBuilderArgs = mini_namespaceObject.extend(ComponentInteractionBuilderArgsBase, {
545
+ sticky: mini_namespaceObject.optional(mini_namespaceObject.boolean()),
546
+ componentViewId: mini_namespaceObject.string(),
547
+ viewDurationMs: mini_namespaceObject.number()
548
+ });
549
+ const ComponentClickBuilderArgs = ComponentInteractionBuilderArgsBase;
550
+ const ComponentHoverBuilderArgs = mini_namespaceObject.extend(ComponentInteractionBuilderArgsBase, {
551
+ componentHoverId: mini_namespaceObject.string(),
552
+ hoverDurationMs: mini_namespaceObject.number()
553
+ });
554
+ const IdentifyBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
555
+ traits: mini_namespaceObject.optional(optimization_api_schemas_namespaceObject.Traits),
556
+ userId: mini_namespaceObject.string()
557
+ });
558
+ const PageViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
559
+ properties: mini_namespaceObject.optional(mini_namespaceObject.partial(optimization_api_schemas_namespaceObject.Page))
560
+ });
561
+ const ScreenViewBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
562
+ name: mini_namespaceObject.string(),
563
+ properties: optimization_api_schemas_namespaceObject.Properties
564
+ });
565
+ const TrackBuilderArgs = mini_namespaceObject.extend(UniversalEventBuilderArgs, {
566
+ event: mini_namespaceObject.string(),
567
+ properties: mini_namespaceObject.optional(mini_namespaceObject.prefault(optimization_api_schemas_namespaceObject.Properties, {}))
568
+ });
569
+ const DEFAULT_PAGE_PROPERTIES = {
570
+ path: '',
571
+ query: {},
572
+ referrer: '',
573
+ search: '',
574
+ title: '',
575
+ url: ''
576
+ };
577
+ class EventBuilder {
578
+ app;
579
+ channel;
580
+ library;
581
+ getLocale;
582
+ getPageProperties;
583
+ getUserAgent;
584
+ constructor(config){
585
+ const { app, channel, library, getLocale, getPageProperties, getUserAgent } = config;
586
+ this.app = app;
587
+ this.channel = channel;
588
+ this.library = library;
589
+ this.getLocale = getLocale ?? (()=>'en-US');
590
+ this.getPageProperties = getPageProperties ?? (()=>DEFAULT_PAGE_PROPERTIES);
591
+ this.getUserAgent = getUserAgent ?? (()=>void 0);
592
+ }
593
+ buildUniversalEventProperties({ campaign = {}, locale, location, page, screen, userAgent }) {
594
+ const timestamp = new Date().toISOString();
595
+ return {
596
+ channel: this.channel,
597
+ context: {
598
+ app: this.app,
599
+ campaign,
600
+ gdpr: {
601
+ isConsentGiven: true
602
+ },
603
+ library: this.library,
604
+ locale: locale ?? this.getLocale() ?? 'en-US',
605
+ location,
606
+ page: page ?? this.getPageProperties(),
607
+ screen,
608
+ userAgent: userAgent ?? this.getUserAgent()
609
+ },
610
+ messageId: crypto.randomUUID(),
611
+ originalTimestamp: timestamp,
612
+ sentAt: timestamp,
613
+ timestamp
614
+ };
615
+ }
616
+ buildEntryComponentBase(universal, componentId, experienceId, variantIndex) {
617
+ return {
618
+ ...this.buildUniversalEventProperties(universal),
619
+ componentType: 'Entry',
620
+ componentId,
621
+ experienceId,
622
+ variantIndex: variantIndex ?? 0
623
+ };
624
+ }
625
+ buildComponentView(args) {
626
+ const { componentId, componentViewId, experienceId, variantIndex, viewDurationMs, ...universal } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(ComponentViewBuilderArgs, args);
627
+ return {
628
+ ...this.buildEntryComponentBase(universal, componentId, experienceId, variantIndex),
629
+ type: 'component',
630
+ componentViewId,
631
+ viewDurationMs
632
+ };
633
+ }
634
+ buildComponentClick(args) {
635
+ const { componentId, experienceId, variantIndex, ...universal } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(ComponentClickBuilderArgs, args);
636
+ return {
637
+ ...this.buildEntryComponentBase(universal, componentId, experienceId, variantIndex),
638
+ type: 'component_click'
639
+ };
640
+ }
641
+ buildComponentHover(args) {
642
+ const { componentHoverId, componentId, experienceId, hoverDurationMs, variantIndex, ...universal } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(ComponentHoverBuilderArgs, args);
643
+ return {
644
+ ...this.buildEntryComponentBase(universal, componentId, experienceId, variantIndex),
645
+ type: 'component_hover',
646
+ componentHoverId,
647
+ hoverDurationMs
648
+ };
649
+ }
650
+ buildFlagView(args) {
651
+ return {
652
+ ...this.buildComponentView(args),
653
+ componentType: 'Variable'
654
+ };
655
+ }
656
+ buildIdentify(args) {
657
+ const { traits = {}, userId, ...universal } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(IdentifyBuilderArgs, args);
658
+ return {
659
+ ...this.buildUniversalEventProperties(universal),
660
+ type: 'identify',
661
+ traits,
662
+ userId
663
+ };
664
+ }
665
+ buildPageView(args = {}) {
666
+ const { properties = {}, ...universal } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(PageViewBuilderArgs, args);
667
+ const pageProperties = this.getPageProperties();
668
+ const merged = (0, object_namespaceObject.merge)({
669
+ ...pageProperties,
670
+ title: pageProperties.title ?? DEFAULT_PAGE_PROPERTIES.title
671
+ }, properties);
672
+ const { context: { screen: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
673
+ const context = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.PageEventContext, universalContext);
674
+ return {
675
+ ...universalProperties,
676
+ context,
677
+ type: 'page',
678
+ properties: merged
679
+ };
680
+ }
681
+ buildScreenView(args) {
682
+ const { name, properties, ...universal } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(ScreenViewBuilderArgs, args);
683
+ const { context: { page: _, ...universalContext }, ...universalProperties } = this.buildUniversalEventProperties(universal);
684
+ const context = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ScreenEventContext, universalContext);
685
+ return {
686
+ ...universalProperties,
687
+ context,
688
+ type: 'screen',
689
+ name,
690
+ properties
691
+ };
692
+ }
693
+ buildTrack(args) {
694
+ const { event, properties = {}, ...universal } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(TrackBuilderArgs, args);
695
+ return {
696
+ ...this.buildUniversalEventProperties(universal),
697
+ type: 'track',
698
+ event,
699
+ properties
700
+ };
701
+ }
702
+ }
703
+ const builders_EventBuilder = EventBuilder;
691
704
  })();
692
705
  exports.ApiClient = __webpack_exports__.ApiClient;
693
706
  exports.DEFAULT_PAGE_PROPERTIES = __webpack_exports__.DEFAULT_PAGE_PROPERTIES;