@contentful/optimization-api-client 0.1.0-alpha

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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +282 -0
  3. package/dist/ApiClient.d.ts +74 -0
  4. package/dist/ApiClient.d.ts.map +1 -0
  5. package/dist/ApiClient.js +61 -0
  6. package/dist/ApiClient.js.map +1 -0
  7. package/dist/ApiClientBase.d.ts +113 -0
  8. package/dist/ApiClientBase.d.ts.map +1 -0
  9. package/dist/ApiClientBase.js +94 -0
  10. package/dist/ApiClientBase.js.map +1 -0
  11. package/dist/builders/EventBuilder.d.ts +589 -0
  12. package/dist/builders/EventBuilder.d.ts.map +1 -0
  13. package/dist/builders/EventBuilder.js +349 -0
  14. package/dist/builders/EventBuilder.js.map +1 -0
  15. package/dist/builders/index.d.ts +3 -0
  16. package/dist/builders/index.d.ts.map +1 -0
  17. package/dist/builders/index.js +3 -0
  18. package/dist/builders/index.js.map +1 -0
  19. package/dist/experience/ExperienceApiClient.d.ts +267 -0
  20. package/dist/experience/ExperienceApiClient.d.ts.map +1 -0
  21. package/dist/experience/ExperienceApiClient.js +324 -0
  22. package/dist/experience/ExperienceApiClient.js.map +1 -0
  23. package/dist/experience/index.d.ts +4 -0
  24. package/dist/experience/index.d.ts.map +1 -0
  25. package/dist/experience/index.js +4 -0
  26. package/dist/experience/index.js.map +1 -0
  27. package/dist/fetch/Fetch.d.ts +96 -0
  28. package/dist/fetch/Fetch.d.ts.map +1 -0
  29. package/dist/fetch/Fetch.js +27 -0
  30. package/dist/fetch/Fetch.js.map +1 -0
  31. package/dist/fetch/createProtectedFetchMethod.d.ts +40 -0
  32. package/dist/fetch/createProtectedFetchMethod.d.ts.map +1 -0
  33. package/dist/fetch/createProtectedFetchMethod.js +53 -0
  34. package/dist/fetch/createProtectedFetchMethod.js.map +1 -0
  35. package/dist/fetch/createRetryFetchMethod.d.ts +60 -0
  36. package/dist/fetch/createRetryFetchMethod.d.ts.map +1 -0
  37. package/dist/fetch/createRetryFetchMethod.js +138 -0
  38. package/dist/fetch/createRetryFetchMethod.js.map +1 -0
  39. package/dist/fetch/createTimeoutFetchMethod.d.ts +51 -0
  40. package/dist/fetch/createTimeoutFetchMethod.d.ts.map +1 -0
  41. package/dist/fetch/createTimeoutFetchMethod.js +51 -0
  42. package/dist/fetch/createTimeoutFetchMethod.js.map +1 -0
  43. package/dist/fetch/index.d.ts +7 -0
  44. package/dist/fetch/index.d.ts.map +1 -0
  45. package/dist/fetch/index.js +7 -0
  46. package/dist/fetch/index.js.map +1 -0
  47. package/dist/index.cjs +708 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.ts +8 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +8 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/index.mjs +583 -0
  54. package/dist/index.mjs.map +1 -0
  55. package/dist/insights/InsightsApiClient.d.ts +130 -0
  56. package/dist/insights/InsightsApiClient.d.ts.map +1 -0
  57. package/dist/insights/InsightsApiClient.js +142 -0
  58. package/dist/insights/InsightsApiClient.js.map +1 -0
  59. package/dist/insights/index.d.ts +4 -0
  60. package/dist/insights/index.d.ts.map +1 -0
  61. package/dist/insights/index.js +4 -0
  62. package/dist/insights/index.js.map +1 -0
  63. package/package.json +27 -0
@@ -0,0 +1,324 @@
1
+ import { BatchExperienceResponse, ExperienceEventArray, ExperienceResponse, } from '@contentful/optimization-api-schemas';
2
+ import { createScopedLogger } from 'logger';
3
+ import ApiClientBase from '../ApiClientBase';
4
+ const logger = createScopedLogger('ApiClient:Experience');
5
+ /**
6
+ * Default base URL for the Experience API.
7
+ *
8
+ * @public
9
+ */
10
+ export const EXPERIENCE_BASE_URL = 'https://experience.ninetailed.co/';
11
+ /**
12
+ * Client for interacting with the Experience API.
13
+ *
14
+ * @public
15
+ *
16
+ * @remarks
17
+ * This client is responsible for reading and mutating Ninetailed profiles
18
+ * using the Experience API.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const client = new ExperienceApiClient({
23
+ * clientId: 'org-id',
24
+ * environment: 'main',
25
+ * })
26
+ *
27
+ * const profile = await client.getProfile('profile-id')
28
+ * ```
29
+ */
30
+ export default class ExperienceApiClient extends ApiClientBase {
31
+ /**
32
+ * Base URL used for Experience API requests.
33
+ */
34
+ baseUrl;
35
+ enabledFeatures;
36
+ ip;
37
+ locale;
38
+ plainText;
39
+ preflight;
40
+ /**
41
+ * Creates a new {@link ExperienceApiClient} instance.
42
+ *
43
+ * @param config - Configuration for the Experience API client.
44
+ */
45
+ constructor(config) {
46
+ super('Experience', config);
47
+ const { baseUrl, enabledFeatures, ip, locale, plainText, preflight } = config;
48
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Set default for anything falsey
49
+ this.baseUrl = baseUrl || EXPERIENCE_BASE_URL;
50
+ this.enabledFeatures = enabledFeatures;
51
+ this.ip = ip;
52
+ this.locale = locale;
53
+ this.plainText = plainText;
54
+ this.preflight = preflight;
55
+ }
56
+ /**
57
+ * Retrieves a profile by ID.
58
+ *
59
+ * @param id - The profile ID to retrieve.
60
+ * @param options - Optional request options. `preflight` and `plainText` are not allowed here.
61
+ * @returns The current optimization data for the profile.
62
+ *
63
+ * @throws {@link Error}
64
+ * Thrown if `id` is missing or the underlying request fails.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * const profile = await client.getProfile('profile-id', {
69
+ * locale: 'en-US',
70
+ * })
71
+ * ```
72
+ */
73
+ async getProfile(id, options = {}) {
74
+ if (!id)
75
+ throw new Error('Valid profile ID required.');
76
+ const requestName = 'Get Profile';
77
+ logger.info(`Sending "${requestName}" request`);
78
+ try {
79
+ const response = await this.fetch(this.constructUrl(`v2/organizations/${this.clientId}/environments/${this.environment}/profiles/${id}`, options), {
80
+ method: 'GET',
81
+ });
82
+ const { data: { changes, experiences, profile }, } = ExperienceResponse.parse(await response.json());
83
+ const data = { changes, personalizations: experiences, profile };
84
+ logger.debug(`"${requestName}" request successfully completed`);
85
+ return data;
86
+ }
87
+ catch (error) {
88
+ this.logRequestError(error, { requestName });
89
+ throw error;
90
+ }
91
+ }
92
+ /**
93
+ * Sends a POST request to mutate a profile or profiles.
94
+ *
95
+ * @param request - Mutation request options including URL, body, and request options.
96
+ * @returns The raw {@link Response} from the underlying fetch.
97
+ *
98
+ * @internal
99
+ */
100
+ async makeProfileMutationRequest({ url, body, options, }) {
101
+ return await this.fetch(this.constructUrl(url, options), {
102
+ method: 'POST',
103
+ headers: this.constructHeaders(options),
104
+ body: JSON.stringify(body),
105
+ keepalive: true,
106
+ });
107
+ }
108
+ /**
109
+ * Creates a profile and returns the resulting optimization data.
110
+ *
111
+ * @param params - Parameters containing the events to aggregate into the profile.
112
+ * @param options - Optional request options.
113
+ * @returns The optimization data for the newly created profile.
114
+ *
115
+ * @remarks
116
+ * The returned profile ID can be used for subsequent update requests.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * const data = await client.createProfile({
121
+ * events: [{ type: 'identify', userId: 'user-123' }],
122
+ * })
123
+ * ```
124
+ */
125
+ async createProfile({ events }, options = {}) {
126
+ const requestName = 'Create Profile';
127
+ logger.info(`Sending "${requestName}" request`);
128
+ const body = {
129
+ events: ExperienceEventArray.parse(events),
130
+ options: this.constructBodyOptions(options),
131
+ };
132
+ logger.debug(`"${requestName}" request body:`, body);
133
+ try {
134
+ const response = await this.makeProfileMutationRequest({
135
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/profiles`,
136
+ body,
137
+ options,
138
+ });
139
+ const { data: { changes, experiences, profile }, } = ExperienceResponse.parse(await response.json());
140
+ const data = { changes, personalizations: experiences, profile };
141
+ logger.debug(`"${requestName}" request successfully completed`);
142
+ return data;
143
+ }
144
+ catch (error) {
145
+ this.logRequestError(error, { requestName });
146
+ throw error;
147
+ }
148
+ }
149
+ /**
150
+ * Updates an existing profile with the given profile ID.
151
+ *
152
+ * @param params - Parameters including the profile ID and events.
153
+ * @param options - Optional request options.
154
+ * @returns The updated optimization data for the profile.
155
+ *
156
+ * @throws {@link Error}
157
+ * Thrown if `profileId` is missing or the underlying request fails.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * const data = await client.updateProfile({
162
+ * profileId: 'profile-id',
163
+ * events: [{ type: 'track', event: 'viewed_video' }],
164
+ * })
165
+ * ```
166
+ */
167
+ async updateProfile({ profileId, events }, options = {}) {
168
+ if (!profileId)
169
+ throw new Error('Valid profile ID required.');
170
+ const requestName = 'Update Profile';
171
+ logger.info(`Sending "${requestName}" request`);
172
+ const body = {
173
+ events: ExperienceEventArray.parse(events),
174
+ options: this.constructBodyOptions(options),
175
+ };
176
+ logger.debug(`"${requestName}" request body:`, body);
177
+ try {
178
+ const response = await this.makeProfileMutationRequest({
179
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/profiles/${profileId}`,
180
+ body,
181
+ options,
182
+ });
183
+ const { data: { changes, experiences, profile }, } = ExperienceResponse.parse(await response.json());
184
+ const data = { changes, personalizations: experiences, profile };
185
+ logger.debug(`"${requestName}" request successfully completed`);
186
+ return data;
187
+ }
188
+ catch (error) {
189
+ this.logRequestError(error, { requestName });
190
+ throw error;
191
+ }
192
+ }
193
+ /**
194
+ * Creates or updates a profile depending on whether a `profileId` is provided.
195
+ *
196
+ * @param params - Parameters including optional profile ID and events.
197
+ * @param options - Optional request options.
198
+ * @returns The resulting optimization data.
199
+ *
200
+ * @example
201
+ * ```ts
202
+ * // Create
203
+ * await client.upsertProfile({ events })
204
+ *
205
+ * // Update
206
+ * await client.upsertProfile({ profileId: 'profile-id', events })
207
+ * ```
208
+ */
209
+ async upsertProfile({ profileId, events }, options) {
210
+ if (!profileId) {
211
+ return await this.createProfile({ events }, options);
212
+ }
213
+ else {
214
+ return await this.updateProfile({ profileId, events }, options);
215
+ }
216
+ }
217
+ /**
218
+ * Sends multiple events to the Ninetailed Experience API to upsert many profiles.
219
+ *
220
+ * @param params - Parameters containing the batch of events.
221
+ * @param options - Optional request options.
222
+ * @returns The list of profiles affected by the batch operation.
223
+ *
224
+ * @remarks
225
+ * Every event must contain an anonymous ID. Profiles will be created or
226
+ * updated according to the anonymous ID.
227
+ *
228
+ * This method is intended to be used from server environments.
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * const profiles = await client.upsertManyProfiles({
233
+ * events: [
234
+ * [{ type: 'identify', userId: 'user-1' }],
235
+ * [{ type: 'identify', userId: 'user-2' }],
236
+ * ],
237
+ * })
238
+ * ```
239
+ */
240
+ async upsertManyProfiles({ events }, options = {}) {
241
+ const requestName = 'Upsert Many Profiles';
242
+ logger.info(`Sending "${requestName}" request`);
243
+ const body = {
244
+ events: ExperienceEventArray.parse(events),
245
+ options: this.constructBodyOptions(options),
246
+ };
247
+ logger.debug(`"${requestName}" request body:`, body);
248
+ try {
249
+ const response = await this.makeProfileMutationRequest({
250
+ url: `v2/organizations/${this.clientId}/environments/${this.environment}/events`,
251
+ body,
252
+ options: { plainText: false, ...options },
253
+ });
254
+ const { data: { profiles }, } = BatchExperienceResponse.parse(await response.json());
255
+ logger.debug(`"${requestName}" request successfully completed`);
256
+ return profiles;
257
+ }
258
+ catch (error) {
259
+ this.logRequestError(error, { requestName });
260
+ throw error;
261
+ }
262
+ }
263
+ /**
264
+ * Constructs a request URL with query parameters derived from request options.
265
+ *
266
+ * @param path - Path relative to the Experience API base URL.
267
+ * @param options - Request options that may influence query parameters.
268
+ * @returns The fully constructed URL as a string.
269
+ *
270
+ * @internal
271
+ */
272
+ constructUrl(path, options) {
273
+ const url = new URL(path, this.baseUrl);
274
+ const locale = options.locale ?? this.locale;
275
+ const preflight = options.preflight ?? this.preflight;
276
+ if (locale) {
277
+ url.searchParams.set('locale', locale);
278
+ }
279
+ if (preflight) {
280
+ url.searchParams.set('type', 'preflight');
281
+ }
282
+ return url.toString();
283
+ }
284
+ /**
285
+ * Constructs request headers based on request options and default configuration.
286
+ *
287
+ * @param options - Request options that may influence headers.
288
+ * @returns A record of HTTP headers to send with the request.
289
+ *
290
+ * @internal
291
+ */
292
+ constructHeaders({ ip = this.ip, plainText = this.plainText, }) {
293
+ const headers = new Map();
294
+ if (ip) {
295
+ headers.set('X-Force-IP', ip);
296
+ }
297
+ if (plainText ?? this.plainText ?? true) {
298
+ headers.set('Content-Type', 'text/plain');
299
+ }
300
+ else {
301
+ headers.set('Content-Type', 'application/json');
302
+ }
303
+ return Object.fromEntries(headers);
304
+ }
305
+ /**
306
+ * Constructs the `options` section of the request body for profile mutations.
307
+ *
308
+ * @param options - Request options that may specify enabled features.
309
+ * @returns Experience API body options including feature flags.
310
+ *
311
+ * @internal
312
+ */
313
+ constructBodyOptions = ({ enabledFeatures = this.enabledFeatures, }) => {
314
+ const bodyOptions = {};
315
+ if (enabledFeatures && Array.isArray(enabledFeatures) && enabledFeatures.length > 0) {
316
+ bodyOptions.features = enabledFeatures;
317
+ }
318
+ else {
319
+ bodyOptions.features = ['ip-enrichment', 'location'];
320
+ }
321
+ return bodyOptions;
322
+ };
323
+ }
324
+ //# sourceMappingURL=ExperienceApiClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExperienceApiClient.js","sourceRoot":"","sources":["../../src/experience/ExperienceApiClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import ExperienceApiClient from './ExperienceApiClient';
2
+ export * from './ExperienceApiClient';
3
+ export default ExperienceApiClient;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/experience/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,uBAAuB,CAAA;AAEvD,cAAc,uBAAuB,CAAA;AAErC,eAAe,mBAAmB,CAAA"}
@@ -0,0 +1,4 @@
1
+ import ExperienceApiClient from './ExperienceApiClient';
2
+ export * from './ExperienceApiClient';
3
+ export default ExperienceApiClient;
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/experience/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,uBAAuB,CAAA;AAEvD,cAAc,uBAAuB,CAAA;AAErC,eAAe,mBAAmB,CAAA"}
@@ -0,0 +1,96 @@
1
+ import { createProtectedFetchMethod } from './createProtectedFetchMethod';
2
+ /**
3
+ * Signature of a fetch method used by the API clients.
4
+ *
5
+ * @param url - The request URL.
6
+ * @param init - Initialization options passed to `fetch`.
7
+ * @returns A promise that resolves with the {@link Response}.
8
+ *
9
+ * @public
10
+ *
11
+ * @remarks
12
+ * This abstraction allows the underlying implementation to be replaced,
13
+ * for example in tests or different runtime environments.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const method: FetchMethod = async (url, init) => {
18
+ * return fetch(url, init)
19
+ * }
20
+ * ```
21
+ */
22
+ export type FetchMethod = (url: string | URL, init: RequestInit) => Promise<Response>;
23
+ /**
24
+ * Base options shared across fetch method factories.
25
+ *
26
+ * @public
27
+ */
28
+ export interface BaseFetchMethodOptions {
29
+ /**
30
+ * Human-readable name of the API being called.
31
+ *
32
+ * @remarks
33
+ * Used primarily for logging and error messages.
34
+ */
35
+ apiName?: string;
36
+ /**
37
+ * Custom fetch implementation to use instead of the global `fetch`.
38
+ *
39
+ * @remarks
40
+ * This is useful for providing polyfills, mocks, or instrumented fetch
41
+ * implementations.
42
+ */
43
+ fetchMethod?: FetchMethod;
44
+ }
45
+ /**
46
+ * Options passed to callback functions invoked by fetch wrappers.
47
+ *
48
+ * @public
49
+ *
50
+ * @remarks
51
+ * Not all fields are guaranteed to be present in all callback scenarios.
52
+ */
53
+ export interface FetchMethodCallbackOptions {
54
+ /**
55
+ * Name of the API associated with the request.
56
+ */
57
+ apiName?: string;
58
+ /**
59
+ * Error that caused the callback to be invoked, if available.
60
+ */
61
+ error?: Error;
62
+ /**
63
+ * The current attempt number (for retry callbacks).
64
+ */
65
+ attemptNumber?: number;
66
+ /**
67
+ * Number of retry attempts remaining (for retry callbacks).
68
+ */
69
+ retriesLeft?: number;
70
+ }
71
+ /**
72
+ * Namespace-like object providing factory methods for protected fetch functions.
73
+ *
74
+ * @public
75
+ */
76
+ declare const Fetch: {
77
+ /**
78
+ * Creates a fully protected fetch method with timeout and retry behavior.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const fetchMethod = Fetch.create({
83
+ * apiName: 'Optimization',
84
+ * requestTimeout: 3000,
85
+ * retries: 2,
86
+ * })
87
+ *
88
+ * const response = await fetchMethod('https://example.com', { method: 'GET' })
89
+ * ```
90
+ *
91
+ * @see createProtectedFetchMethod
92
+ */
93
+ create: typeof createProtectedFetchMethod;
94
+ };
95
+ export default Fetch;
96
+ //# sourceMappingURL=Fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Fetch.d.ts","sourceRoot":"","sources":["../../src/fetch/Fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAA;AAEzE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAErF;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,0BAA0B;IACzC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAA;IAEb;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;GAIG;AACH,QAAA,MAAM,KAAK;IACT;;;;;;;;;;;;;;;OAeG;;CAEJ,CAAA;AAED,eAAe,KAAK,CAAA"}
@@ -0,0 +1,27 @@
1
+ import { createProtectedFetchMethod } from './createProtectedFetchMethod';
2
+ /**
3
+ * Namespace-like object providing factory methods for protected fetch functions.
4
+ *
5
+ * @public
6
+ */
7
+ const Fetch = {
8
+ /**
9
+ * Creates a fully protected fetch method with timeout and retry behavior.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const fetchMethod = Fetch.create({
14
+ * apiName: 'Optimization',
15
+ * requestTimeout: 3000,
16
+ * retries: 2,
17
+ * })
18
+ *
19
+ * const response = await fetchMethod('https://example.com', { method: 'GET' })
20
+ * ```
21
+ *
22
+ * @see createProtectedFetchMethod
23
+ */
24
+ create: createProtectedFetchMethod,
25
+ };
26
+ export default Fetch;
27
+ //# sourceMappingURL=Fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Fetch.js","sourceRoot":"","sources":["../../src/fetch/Fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAA;AA8EzE;;;;GAIG;AACH,MAAM,KAAK,GAAG;IACZ;;;;;;;;;;;;;;;OAeG;IACH,MAAM,EAAE,0BAA0B;CACnC,CAAA;AAED,eAAe,KAAK,CAAA"}
@@ -0,0 +1,40 @@
1
+ import { type RetryFetchMethodOptions } from './createRetryFetchMethod';
2
+ import { type TimeoutFetchMethodOptions } from './createTimeoutFetchMethod';
3
+ import type { FetchMethod } from './Fetch';
4
+ /**
5
+ * Options for {@link createProtectedFetchMethod}, combining timeout and retry behavior.
6
+ */
7
+ export interface ProtectedFetchMethodOptions extends RetryFetchMethodOptions, TimeoutFetchMethodOptions {
8
+ }
9
+ /**
10
+ * Creates a {@link FetchMethod} that combines timeout and retry protection.
11
+ *
12
+ * @param options - Configuration options for both timeout and retry behavior.
13
+ * @returns A {@link FetchMethod} that applies timeout and retry logic to requests.
14
+ *
15
+ * @remarks
16
+ * The resulting method first wraps the base fetch with a timeout (via
17
+ * {@link createTimeoutFetchMethod}), then applies retry behavior (via
18
+ * {@link createRetryFetchMethod}).
19
+ *
20
+ * If an error is thrown during configuration or request execution, it is logged
21
+ * using {@link logger}.
22
+ *
23
+ * @throws {@link Error}
24
+ * Rethrows the original error after logging, including abort errors.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const fetchProtected = createProtectedFetchMethod({
29
+ * apiName: 'Optimization',
30
+ * requestTimeout: 4000,
31
+ * retries: 2,
32
+ * })
33
+ *
34
+ * const response = await fetchProtected('https://example.com/experiences', {
35
+ * method: 'GET',
36
+ * })
37
+ * ```
38
+ */
39
+ export declare function createProtectedFetchMethod(options: ProtectedFetchMethodOptions): FetchMethod;
40
+ //# sourceMappingURL=createProtectedFetchMethod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createProtectedFetchMethod.d.ts","sourceRoot":"","sources":["../../src/fetch/createProtectedFetchMethod.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,KAAK,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAC/F,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,4BAA4B,CAAA;AACnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C;;GAEG;AACH,MAAM,WAAW,2BACf,SAAQ,uBAAuB,EAC7B,yBAAyB;CAAG;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,WAAW,CAgB5F"}
@@ -0,0 +1,53 @@
1
+ import { createScopedLogger } from 'logger';
2
+ import { createRetryFetchMethod } from './createRetryFetchMethod';
3
+ import { createTimeoutFetchMethod, } from './createTimeoutFetchMethod';
4
+ const logger = createScopedLogger('ApiClient:Fetch');
5
+ /**
6
+ * Creates a {@link FetchMethod} that combines timeout and retry protection.
7
+ *
8
+ * @param options - Configuration options for both timeout and retry behavior.
9
+ * @returns A {@link FetchMethod} that applies timeout and retry logic to requests.
10
+ *
11
+ * @remarks
12
+ * The resulting method first wraps the base fetch with a timeout (via
13
+ * {@link createTimeoutFetchMethod}), then applies retry behavior (via
14
+ * {@link createRetryFetchMethod}).
15
+ *
16
+ * If an error is thrown during configuration or request execution, it is logged
17
+ * using {@link logger}.
18
+ *
19
+ * @throws {@link Error}
20
+ * Rethrows the original error after logging, including abort errors.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const fetchProtected = createProtectedFetchMethod({
25
+ * apiName: 'Optimization',
26
+ * requestTimeout: 4000,
27
+ * retries: 2,
28
+ * })
29
+ *
30
+ * const response = await fetchProtected('https://example.com/experiences', {
31
+ * method: 'GET',
32
+ * })
33
+ * ```
34
+ */
35
+ export function createProtectedFetchMethod(options) {
36
+ try {
37
+ const timeoutFetchMethod = createTimeoutFetchMethod(options);
38
+ const retryFetchMethod = createRetryFetchMethod({ ...options, fetchMethod: timeoutFetchMethod });
39
+ return retryFetchMethod;
40
+ }
41
+ catch (error) {
42
+ if (error instanceof Error) {
43
+ if (error.name === 'AbortError') {
44
+ logger.warn('Request aborted due to network issues. This request may not be retried.');
45
+ }
46
+ else {
47
+ logger.error('Request failed:', error);
48
+ }
49
+ }
50
+ throw error;
51
+ }
52
+ }
53
+ //# sourceMappingURL=createProtectedFetchMethod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createProtectedFetchMethod.js","sourceRoot":"","sources":["../../src/fetch/createProtectedFetchMethod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA;AAC3C,OAAO,EAAE,sBAAsB,EAAgC,MAAM,0BAA0B,CAAA;AAC/F,OAAO,EACL,wBAAwB,GAEzB,MAAM,4BAA4B,CAAA;AAGnC,MAAM,MAAM,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;AASpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,0BAA0B,CAAC,OAAoC;IAC7E,IAAI,CAAC;QACH,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAA;QAC5D,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC,CAAA;QAEhG,OAAO,gBAAgB,CAAA;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAChC,MAAM,CAAC,IAAI,CAAC,yEAAyE,CAAC,CAAA;YACxF,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAA;YACxC,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ import type { BaseFetchMethodOptions, FetchMethod, FetchMethodCallbackOptions } from './Fetch';
2
+ /**
3
+ * Configuration options for {@link createRetryFetchMethod}.
4
+ */
5
+ export interface RetryFetchMethodOptions extends BaseFetchMethodOptions {
6
+ /**
7
+ * Delay (in milliseconds) between retry attempts.
8
+ *
9
+ * @remarks
10
+ * Defaults to {@link DEFAULT_INTERVAL_TIMEOUT}.
11
+ */
12
+ intervalTimeout?: number;
13
+ /**
14
+ * Callback invoked whenever a retry attempt fails.
15
+ *
16
+ * @param options - Information about the failed attempt.
17
+ *
18
+ * @remarks
19
+ * This callback is invoked with additional metadata such as the attempt
20
+ * number and the number of retries left.
21
+ */
22
+ onFailedAttempt?: (options: FetchMethodCallbackOptions) => void;
23
+ /**
24
+ * Maximum number of retry attempts.
25
+ *
26
+ * @remarks
27
+ * Defaults to {@link DEFAULT_RETRY_COUNT}.
28
+ */
29
+ retries?: number;
30
+ }
31
+ /**
32
+ * Creates a {@link FetchMethod} that retries failed requests according to the
33
+ * provided configuration.
34
+ *
35
+ * @param options - Configuration options that control retry behavior.
36
+ * @returns A {@link FetchMethod} that automatically retries qualifying failures.
37
+ *
38
+ * @remarks
39
+ * This wrapper integrates with `p-retry` and uses an {@link AbortController}
40
+ * to cancel pending requests when a non-retriable error occurs.
41
+ *
42
+ * @throws {@link Error}
43
+ * Thrown when the request cannot be retried and no successful response is obtained.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const fetchWithRetry = createRetryFetchMethod({
48
+ * apiName: 'Optimization',
49
+ * retries: 3,
50
+ * intervalTimeout: 200,
51
+ * onFailedAttempt: ({ attemptNumber, retriesLeft }) => {
52
+ * console.warn(`Attempt ${attemptNumber} failed. Retries left: ${retriesLeft}`)
53
+ * },
54
+ * })
55
+ *
56
+ * const response = await fetchWithRetry('https://example.com', { method: 'GET' })
57
+ * ```
58
+ */
59
+ export declare function createRetryFetchMethod({ apiName, fetchMethod, intervalTimeout, onFailedAttempt, retries, }?: RetryFetchMethodOptions): FetchMethod;
60
+ //# sourceMappingURL=createRetryFetchMethod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createRetryFetchMethod.d.ts","sourceRoot":"","sources":["../../src/fetch/createRetryFetchMethod.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AA2D9F;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,sBAAsB;IACrE;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,IAAI,CAAA;IAE/D;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AA4ED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,OAAwB,EACxB,WAAmB,EACnB,eAA0C,EAC1C,eAAe,EACf,OAA6B,GAC9B,GAAE,uBAA4B,GAAG,WAAW,CA8B5C"}