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

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 (80) hide show
  1. package/README.md +110 -218
  2. package/THIRD_PARTY_NOTICES.txt +2038 -0
  3. package/dist/199.mjs +2 -0
  4. package/dist/649.mjs +131 -0
  5. package/dist/649.mjs.map +1 -0
  6. package/dist/api-schemas.cjs +60 -0
  7. package/dist/api-schemas.cjs.map +1 -0
  8. package/dist/api-schemas.d.cts +4 -0
  9. package/dist/api-schemas.d.mts +4 -0
  10. package/dist/api-schemas.d.ts +4 -0
  11. package/dist/api-schemas.mjs +2 -0
  12. package/dist/index.cjs +452 -580
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +520 -1042
  15. package/dist/index.d.mts +520 -1042
  16. package/dist/index.d.ts +868 -8
  17. package/dist/index.mjs +115 -298
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/logger.cjs +207 -0
  20. package/dist/logger.cjs.map +1 -0
  21. package/dist/logger.d.cts +287 -0
  22. package/dist/logger.d.mts +287 -0
  23. package/dist/logger.d.ts +287 -0
  24. package/dist/logger.mjs +1 -0
  25. package/package.json +37 -7
  26. package/dist/ApiClient.d.ts +0 -74
  27. package/dist/ApiClient.d.ts.map +0 -1
  28. package/dist/ApiClient.js +0 -61
  29. package/dist/ApiClient.js.map +0 -1
  30. package/dist/ApiClientBase.d.ts +0 -113
  31. package/dist/ApiClientBase.d.ts.map +0 -1
  32. package/dist/ApiClientBase.js +0 -94
  33. package/dist/ApiClientBase.js.map +0 -1
  34. package/dist/builders/EventBuilder.d.ts +0 -589
  35. package/dist/builders/EventBuilder.d.ts.map +0 -1
  36. package/dist/builders/EventBuilder.js +0 -349
  37. package/dist/builders/EventBuilder.js.map +0 -1
  38. package/dist/builders/index.d.ts +0 -3
  39. package/dist/builders/index.d.ts.map +0 -1
  40. package/dist/builders/index.js +0 -3
  41. package/dist/builders/index.js.map +0 -1
  42. package/dist/experience/ExperienceApiClient.d.ts +0 -267
  43. package/dist/experience/ExperienceApiClient.d.ts.map +0 -1
  44. package/dist/experience/ExperienceApiClient.js +0 -324
  45. package/dist/experience/ExperienceApiClient.js.map +0 -1
  46. package/dist/experience/index.d.ts +0 -4
  47. package/dist/experience/index.d.ts.map +0 -1
  48. package/dist/experience/index.js +0 -4
  49. package/dist/experience/index.js.map +0 -1
  50. package/dist/fetch/Fetch.d.ts +0 -96
  51. package/dist/fetch/Fetch.d.ts.map +0 -1
  52. package/dist/fetch/Fetch.js +0 -27
  53. package/dist/fetch/Fetch.js.map +0 -1
  54. package/dist/fetch/createProtectedFetchMethod.d.ts +0 -40
  55. package/dist/fetch/createProtectedFetchMethod.d.ts.map +0 -1
  56. package/dist/fetch/createProtectedFetchMethod.js +0 -53
  57. package/dist/fetch/createProtectedFetchMethod.js.map +0 -1
  58. package/dist/fetch/createRetryFetchMethod.d.ts +0 -60
  59. package/dist/fetch/createRetryFetchMethod.d.ts.map +0 -1
  60. package/dist/fetch/createRetryFetchMethod.js +0 -138
  61. package/dist/fetch/createRetryFetchMethod.js.map +0 -1
  62. package/dist/fetch/createTimeoutFetchMethod.d.ts +0 -51
  63. package/dist/fetch/createTimeoutFetchMethod.d.ts.map +0 -1
  64. package/dist/fetch/createTimeoutFetchMethod.js +0 -51
  65. package/dist/fetch/createTimeoutFetchMethod.js.map +0 -1
  66. package/dist/fetch/index.d.ts +0 -7
  67. package/dist/fetch/index.d.ts.map +0 -1
  68. package/dist/fetch/index.js +0 -7
  69. package/dist/fetch/index.js.map +0 -1
  70. package/dist/index.d.ts.map +0 -1
  71. package/dist/index.js +0 -8
  72. package/dist/index.js.map +0 -1
  73. package/dist/insights/InsightsApiClient.d.ts +0 -130
  74. package/dist/insights/InsightsApiClient.d.ts.map +0 -1
  75. package/dist/insights/InsightsApiClient.js +0 -143
  76. package/dist/insights/InsightsApiClient.js.map +0 -1
  77. package/dist/insights/index.d.ts +0 -4
  78. package/dist/insights/index.d.ts.map +0 -1
  79. package/dist/insights/index.js +0 -4
  80. 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
- }
25
- }
26
- },
27
- "./src/ApiClientBase.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
28
- __webpack_require__.d(__webpack_exports__, {
29
- A: ()=>src_ApiClientBase
30
- });
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
- };
7
+ class LogSink {
113
8
  }
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
131
- };
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;
9
+ const __rspack_default_export = LogSink;
156
10
  },
157
- "./src/builders/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
11
+ "./src/lib/logger/logging.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
158
12
  __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())
13
+ A: ()=>logLevelSeverity
178
14
  });
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: ''
15
+ const logLevelSeverity = {
16
+ fatal: 60,
17
+ error: 50,
18
+ warn: 40,
19
+ info: 30,
20
+ debug: 20,
21
+ log: 10
201
22
  };
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
- },
307
- "./src/experience/index.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
308
- __webpack_require__.d(__webpack_exports__, {
309
- n: ()=>EXPERIENCE_BASE_URL,
310
- A: ()=>experience
311
- });
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
23
  },
543
- "../../lib/logger/dist/index.mjs" (__unused_rspack___webpack_module__, __webpack_exports__, __webpack_require__) {
24
+ "./src/logger.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
544
25
  __webpack_require__.d(__webpack_exports__, {
545
- zP: ()=>createScopedLogger
26
+ createScopedLogger: ()=>createScopedLogger
546
27
  });
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,36 +148,430 @@ 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
+ createTimeoutFetchMethod: ()=>createTimeoutFetchMethod,
152
+ ExperienceApiClient: ()=>ExperienceApiClient,
153
+ createProtectedFetchMethod: ()=>createProtectedFetchMethod,
154
+ EXPERIENCE_BASE_URL: ()=>EXPERIENCE_BASE_URL,
155
+ ApiClient: ()=>ApiClient,
156
+ INSIGHTS_BASE_URL: ()=>INSIGHTS_BASE_URL,
157
+ createRetryFetchMethod: ()=>createRetryFetchMethod,
158
+ InsightsApiClient: ()=>InsightsApiClient
678
159
  });
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");
160
+ const optimization_api_schemas_namespaceObject = require("@contentful/optimization-api-schemas");
161
+ var logger = __webpack_require__("./src/logger.ts");
162
+ const fetchInputToString = (input)=>{
163
+ if ('string' == typeof input) return input;
164
+ return input.url;
165
+ };
166
+ const MISSING_FETCH_METHOD_MESSAGE = 'No fetch implementation available. Provide a fetchMethod.';
167
+ function resolveFetchMethod(fetchMethod) {
168
+ if (fetchMethod) return fetchMethod;
169
+ if ('function' == typeof globalThis.fetch) return globalThis.fetch.bind(globalThis);
170
+ throw new Error(MISSING_FETCH_METHOD_MESSAGE);
171
+ }
172
+ const createRetryFetchMethod_logger = (0, logger.createScopedLogger)('ApiClient:Retry');
173
+ const DEFAULT_INTERVAL_TIMEOUT = 0;
174
+ const DEFAULT_RETRY_COUNT = 1;
175
+ const RETRY_RESPONSE_STATUS = 503;
176
+ const HTTP_ERROR_RESPONSE_STATUS = 500;
177
+ class HttpError extends Error {
178
+ status;
179
+ constructor(message, status = HTTP_ERROR_RESPONSE_STATUS){
180
+ super(message);
181
+ Object.setPrototypeOf(this, HttpError.prototype);
182
+ this.status = status;
183
+ }
184
+ }
185
+ function createRetryFetchCallback({ apiName = 'Optimization', controller, fetchMethod, init, url }) {
186
+ return async ()=>{
187
+ const urlLabel = fetchInputToString(url);
188
+ try {
189
+ const response = await fetchMethod(url, init);
190
+ if (response.status === RETRY_RESPONSE_STATUS) throw new HttpError(`${apiName} API request to "${urlLabel}" failed with status: "[${response.status}] ${response.statusText}".`, RETRY_RESPONSE_STATUS);
191
+ if (!response.ok) {
192
+ const httpError = new Error(`Request to "${urlLabel}" failed with status: [${response.status}] ${response.statusText} - traceparent: ${response.headers.get('traceparent')}`);
193
+ createRetryFetchMethod_logger.error('Request failed with non-OK status:', httpError);
194
+ controller.abort();
195
+ return;
196
+ }
197
+ createRetryFetchMethod_logger.debug(`Response from "${urlLabel}":`, response);
198
+ return response;
199
+ } catch (error) {
200
+ if (error instanceof HttpError && error.status === RETRY_RESPONSE_STATUS) throw error;
201
+ createRetryFetchMethod_logger.error(`Request to "${urlLabel}" failed:`, error);
202
+ controller.abort();
203
+ }
204
+ };
205
+ }
206
+ async function delayRetry(intervalTimeout) {
207
+ if (intervalTimeout <= 0) return;
208
+ const { promise, resolve } = Promise.withResolvers();
209
+ setTimeout(()=>{
210
+ resolve(void 0);
211
+ }, intervalTimeout);
212
+ await promise;
213
+ }
214
+ function createRetryFetchMethod({ apiName = 'Optimization', fetchMethod, intervalTimeout = DEFAULT_INTERVAL_TIMEOUT, onFailedAttempt, retries = DEFAULT_RETRY_COUNT } = {}) {
215
+ const resolvedFetchMethod = resolveFetchMethod(fetchMethod);
216
+ return async (url, init)=>{
217
+ const controller = new AbortController();
218
+ const maxAttempts = retries + 1;
219
+ const attemptFetch = createRetryFetchCallback({
220
+ apiName,
221
+ controller,
222
+ fetchMethod: resolvedFetchMethod,
223
+ init,
224
+ url
225
+ });
226
+ for(let attemptNumber = 1; attemptNumber <= maxAttempts; attemptNumber++)try {
227
+ const response = await attemptFetch();
228
+ if (response) return response;
229
+ break;
230
+ } catch (error) {
231
+ if (!(error instanceof HttpError) || error.status !== RETRY_RESPONSE_STATUS) throw error;
232
+ const retriesLeft = maxAttempts - attemptNumber;
233
+ onFailedAttempt?.({
234
+ apiName,
235
+ error,
236
+ attemptNumber,
237
+ retriesLeft
238
+ });
239
+ if (0 === retriesLeft) throw error;
240
+ await delayRetry(intervalTimeout);
241
+ }
242
+ throw new Error(`${apiName} API request to "${fetchInputToString(url)}" may not be retried.`);
243
+ };
244
+ }
245
+ const createTimeoutFetchMethod_logger = (0, logger.createScopedLogger)('ApiClient:Timeout');
246
+ const DEFAULT_REQUEST_TIMEOUT = 3000;
247
+ function isFetchAbortSignal(signal) {
248
+ return 'object' == typeof signal && null !== signal;
249
+ }
250
+ function createTimeoutFetchMethod({ apiName = 'Optimization', fetchMethod, onRequestTimeout, requestTimeout = DEFAULT_REQUEST_TIMEOUT } = {}) {
251
+ const resolvedFetchMethod = resolveFetchMethod(fetchMethod);
252
+ return async (url, init)=>{
253
+ const controller = new AbortController();
254
+ const id = setTimeout(()=>{
255
+ if ('function' == typeof onRequestTimeout) onRequestTimeout({
256
+ apiName
257
+ });
258
+ else createTimeoutFetchMethod_logger.error(`Request to "${fetchInputToString(url)}" timed out`, new Error('Request timeout'));
259
+ controller.abort();
260
+ }, requestTimeout);
261
+ const { signal } = controller;
262
+ if (!isFetchAbortSignal(signal)) throw new Error('AbortController signal is not compatible with fetch.');
263
+ const requestInit = {
264
+ ...init,
265
+ signal
266
+ };
267
+ const response = await resolvedFetchMethod(url, requestInit);
268
+ clearTimeout(id);
269
+ return response;
270
+ };
271
+ }
272
+ const createProtectedFetchMethod_logger = (0, logger.createScopedLogger)('ApiClient:Fetch');
273
+ function createProtectedFetchMethod(options) {
274
+ try {
275
+ const timeoutFetchMethod = createTimeoutFetchMethod(options);
276
+ const retryFetchMethod = createRetryFetchMethod({
277
+ ...options,
278
+ fetchMethod: timeoutFetchMethod
279
+ });
280
+ return retryFetchMethod;
281
+ } catch (error) {
282
+ if (error instanceof Error) if ('AbortError' === error.name) createProtectedFetchMethod_logger.warn('Request aborted due to network issues. This request may not be retried.');
283
+ else createProtectedFetchMethod_logger.error('Request failed:', error);
284
+ throw error;
285
+ }
286
+ }
287
+ const Fetch = {
288
+ create: createProtectedFetchMethod
289
+ };
290
+ const fetch_Fetch = Fetch;
291
+ const fetch = fetch_Fetch;
292
+ const ApiClientBase_logger = (0, logger.createScopedLogger)('ApiClient');
293
+ const DEFAULT_ENVIRONMENT = 'main';
294
+ class ApiClientBase {
295
+ name;
296
+ clientId;
297
+ environment;
298
+ fetch;
299
+ constructor(name, { fetchOptions, clientId, environment }){
300
+ this.clientId = clientId;
301
+ this.environment = environment ?? DEFAULT_ENVIRONMENT;
302
+ this.name = name;
303
+ this.fetch = fetch.create({
304
+ ...fetchOptions ?? {},
305
+ apiName: name
306
+ });
307
+ }
308
+ logRequestError(error, { requestName }) {
309
+ 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.`);
310
+ else ApiClientBase_logger.error(`[${this.name}] "${requestName}" request failed:`, error);
311
+ }
312
+ }
313
+ const src_ApiClientBase = ApiClientBase;
314
+ const ExperienceApiClient_logger = (0, logger.createScopedLogger)('ApiClient:Experience');
315
+ const EXPERIENCE_BASE_URL = 'https://experience.ninetailed.co/';
316
+ class ExperienceApiClient extends src_ApiClientBase {
317
+ baseUrl;
318
+ enabledFeatures;
319
+ ip;
320
+ locale;
321
+ plainText;
322
+ preflight;
323
+ constructor(config){
324
+ super('Experience', config);
325
+ const { baseUrl, enabledFeatures, ip, locale, plainText, preflight } = config;
326
+ this.baseUrl = baseUrl || EXPERIENCE_BASE_URL;
327
+ this.enabledFeatures = enabledFeatures;
328
+ this.ip = ip;
329
+ this.locale = locale;
330
+ this.plainText = plainText;
331
+ this.preflight = preflight;
332
+ }
333
+ setLocale(locale) {
334
+ this.locale = locale;
335
+ }
336
+ async getProfile(id, options = {}) {
337
+ if (!id) throw new Error('Valid profile ID required.');
338
+ const requestName = 'Get Profile';
339
+ ExperienceApiClient_logger.info(`Sending "${requestName}" request`);
340
+ try {
341
+ const response = await this.fetch(this.constructUrl(`v2/organizations/${this.clientId}/environments/${this.environment}/profiles/${id}`, options), {
342
+ method: 'GET'
343
+ });
344
+ const { data: { changes, experiences, profile } } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ExperienceResponse, await response.json());
345
+ const data = {
346
+ changes,
347
+ selectedOptimizations: experiences,
348
+ profile
349
+ };
350
+ ExperienceApiClient_logger.debug(`"${requestName}" request successfully completed`);
351
+ return data;
352
+ } catch (error) {
353
+ this.logRequestError(error, {
354
+ requestName
355
+ });
356
+ throw error;
357
+ }
358
+ }
359
+ async makeProfileMutationRequest({ url, body, options }) {
360
+ return await this.fetch(this.constructUrl(url, options), {
361
+ method: 'POST',
362
+ headers: this.constructHeaders(options),
363
+ body: JSON.stringify(body),
364
+ keepalive: true
365
+ });
366
+ }
367
+ async createProfile({ events }, options = {}) {
368
+ const requestName = 'Create Profile';
369
+ ExperienceApiClient_logger.info(`Sending "${requestName}" request`);
370
+ const body = this.constructExperienceRequestBody(events, options);
371
+ ExperienceApiClient_logger.debug(`"${requestName}" request body:`, body);
372
+ try {
373
+ const response = await this.makeProfileMutationRequest({
374
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/profiles`,
375
+ body,
376
+ options
377
+ });
378
+ const { data: { changes, experiences, profile } } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ExperienceResponse, await response.json());
379
+ const data = {
380
+ changes,
381
+ selectedOptimizations: experiences,
382
+ profile
383
+ };
384
+ ExperienceApiClient_logger.debug(`"${requestName}" request successfully completed`);
385
+ return data;
386
+ } catch (error) {
387
+ this.logRequestError(error, {
388
+ requestName
389
+ });
390
+ throw error;
391
+ }
392
+ }
393
+ async updateProfile({ profileId, events }, options = {}) {
394
+ if (!profileId) throw new Error('Valid profile ID required.');
395
+ const requestName = 'Update Profile';
396
+ ExperienceApiClient_logger.info(`Sending "${requestName}" request`);
397
+ const body = this.constructExperienceRequestBody(events, options);
398
+ ExperienceApiClient_logger.debug(`"${requestName}" request body:`, body);
399
+ try {
400
+ const response = await this.makeProfileMutationRequest({
401
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/profiles/${profileId}`,
402
+ body,
403
+ options
404
+ });
405
+ const { data: { changes, experiences, profile } } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ExperienceResponse, await response.json());
406
+ const data = {
407
+ changes,
408
+ selectedOptimizations: experiences,
409
+ profile
410
+ };
411
+ ExperienceApiClient_logger.debug(`"${requestName}" request successfully completed`);
412
+ return data;
413
+ } catch (error) {
414
+ this.logRequestError(error, {
415
+ requestName
416
+ });
417
+ throw error;
418
+ }
419
+ }
420
+ async upsertProfile({ profileId, events }, options) {
421
+ if (!profileId) return await this.createProfile({
422
+ events
423
+ }, options);
424
+ return await this.updateProfile({
425
+ profileId,
426
+ events
427
+ }, options);
428
+ }
429
+ async upsertManyProfiles({ events }, options = {}) {
430
+ const requestName = 'Upsert Many Profiles';
431
+ ExperienceApiClient_logger.info(`Sending "${requestName}" request`);
432
+ const body = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.BatchExperienceRequestData, {
433
+ events,
434
+ options: this.constructBodyOptions(options)
435
+ });
436
+ ExperienceApiClient_logger.debug(`"${requestName}" request body:`, body);
437
+ try {
438
+ const response = await this.makeProfileMutationRequest({
439
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/events`,
440
+ body,
441
+ options: {
442
+ plainText: false,
443
+ ...options
444
+ }
445
+ });
446
+ const { data: { profiles } } = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.BatchExperienceResponse, await response.json());
447
+ ExperienceApiClient_logger.debug(`"${requestName}" request successfully completed`);
448
+ return profiles;
449
+ } catch (error) {
450
+ this.logRequestError(error, {
451
+ requestName
452
+ });
453
+ throw error;
454
+ }
455
+ }
456
+ constructUrl(path, options) {
457
+ const url = new URL(path, this.baseUrl);
458
+ const locale = options.locale ?? this.locale;
459
+ const preflight = options.preflight ?? this.preflight;
460
+ if (locale) url.searchParams.set('locale', locale);
461
+ if (preflight) url.searchParams.set('type', 'preflight');
462
+ return url.toString();
463
+ }
464
+ constructHeaders({ ip = this.ip, plainText = this.plainText }) {
465
+ const headers = new Map();
466
+ if (ip) headers.set('X-Force-IP', ip);
467
+ if (plainText ?? this.plainText ?? true) headers.set('Content-Type', 'text/plain');
468
+ else headers.set('Content-Type', 'application/json');
469
+ return Object.fromEntries(headers);
470
+ }
471
+ constructBodyOptions = ({ enabledFeatures = this.enabledFeatures })=>{
472
+ const bodyOptions = {};
473
+ if (enabledFeatures && Array.isArray(enabledFeatures) && enabledFeatures.length > 0) bodyOptions.features = enabledFeatures;
474
+ else bodyOptions.features = [
475
+ 'ip-enrichment',
476
+ 'location'
477
+ ];
478
+ return bodyOptions;
479
+ };
480
+ constructExperienceRequestBody(events, options) {
481
+ return optimization_api_schemas_namespaceObject.ExperienceRequestData.parse({
482
+ events: (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.ExperienceEventArray, events),
483
+ options: this.constructBodyOptions(options)
484
+ });
485
+ }
486
+ }
487
+ const InsightsApiClient_logger = (0, logger.createScopedLogger)('ApiClient:Insights');
488
+ const BEACON_FALLBACK_MESSAGE = 'beacon failed; falling back to fetch';
489
+ const INSIGHTS_BASE_URL = 'https://ingest.insights.ninetailed.co/';
490
+ class InsightsApiClient extends src_ApiClientBase {
491
+ baseUrl;
492
+ constructor(config){
493
+ super('Insights', config);
494
+ const { baseUrl } = config;
495
+ this.baseUrl = baseUrl || INSIGHTS_BASE_URL;
496
+ }
497
+ async sendBatchEvents(batches, options = {}) {
498
+ const { beacon } = options;
499
+ const url = new URL(`v1/organizations/${this.clientId}/environments/${this.environment}/events`, this.baseUrl);
500
+ const urlString = url.toString();
501
+ const body = (0, optimization_api_schemas_namespaceObject.parseWithFriendlyError)(optimization_api_schemas_namespaceObject.BatchInsightsEventArray, batches);
502
+ const serializedBody = JSON.stringify(body);
503
+ if (beacon) {
504
+ InsightsApiClient_logger.debug('Queueing events via beacon');
505
+ try {
506
+ const beaconSuccessfullyQueued = beacon(urlString, serializedBody);
507
+ if (beaconSuccessfullyQueued) return true;
508
+ InsightsApiClient_logger.warn(BEACON_FALLBACK_MESSAGE);
509
+ } catch (error) {
510
+ InsightsApiClient_logger.warn(BEACON_FALLBACK_MESSAGE, error);
511
+ }
512
+ }
513
+ const requestName = 'Event Batches';
514
+ InsightsApiClient_logger.info(`Sending "${requestName}" request`);
515
+ InsightsApiClient_logger.debug(`"${requestName}" request body:`, body);
516
+ try {
517
+ await this.fetch(urlString, {
518
+ method: 'POST',
519
+ headers: {
520
+ 'Content-Type': 'application/json'
521
+ },
522
+ body: serializedBody,
523
+ keepalive: !!beacon
524
+ });
525
+ InsightsApiClient_logger.debug(`"${requestName}" request successfully completed`);
526
+ return true;
527
+ } catch (error) {
528
+ this.logRequestError(error, {
529
+ requestName
530
+ });
531
+ return false;
532
+ }
533
+ }
534
+ }
535
+ class ApiClient {
536
+ config;
537
+ experience;
538
+ insights;
539
+ constructor(config){
540
+ const { experience, insights, clientId, environment, fetchOptions } = config;
541
+ const apiConfig = {
542
+ clientId,
543
+ environment,
544
+ fetchOptions
545
+ };
546
+ this.config = apiConfig;
547
+ this.experience = new ExperienceApiClient({
548
+ ...apiConfig,
549
+ ...experience
550
+ });
551
+ this.insights = new InsightsApiClient({
552
+ ...apiConfig,
553
+ ...insights
554
+ });
555
+ }
556
+ }
691
557
  })();
692
558
  exports.ApiClient = __webpack_exports__.ApiClient;
693
- exports.DEFAULT_PAGE_PROPERTIES = __webpack_exports__.DEFAULT_PAGE_PROPERTIES;
694
559
  exports.EXPERIENCE_BASE_URL = __webpack_exports__.EXPERIENCE_BASE_URL;
695
- exports.EventBuilder = __webpack_exports__.EventBuilder;
560
+ exports.ExperienceApiClient = __webpack_exports__.ExperienceApiClient;
696
561
  exports.INSIGHTS_BASE_URL = __webpack_exports__.INSIGHTS_BASE_URL;
562
+ exports.InsightsApiClient = __webpack_exports__.InsightsApiClient;
563
+ exports.createProtectedFetchMethod = __webpack_exports__.createProtectedFetchMethod;
564
+ exports.createRetryFetchMethod = __webpack_exports__.createRetryFetchMethod;
565
+ exports.createTimeoutFetchMethod = __webpack_exports__.createTimeoutFetchMethod;
697
566
  for(var __rspack_i in __webpack_exports__)if (-1 === [
698
567
  "ApiClient",
699
- "DEFAULT_PAGE_PROPERTIES",
700
568
  "EXPERIENCE_BASE_URL",
701
- "EventBuilder",
702
- "INSIGHTS_BASE_URL"
569
+ "ExperienceApiClient",
570
+ "INSIGHTS_BASE_URL",
571
+ "InsightsApiClient",
572
+ "createProtectedFetchMethod",
573
+ "createRetryFetchMethod",
574
+ "createTimeoutFetchMethod"
703
575
  ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
704
576
  Object.defineProperty(exports, '__esModule', {
705
577
  value: true