apimo.js 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +173 -191
- package/dist/core/api.d.ts +155 -131
- package/dist/core/api.js +69 -4
- package/dist/errors/index.d.ts +176 -0
- package/dist/errors/index.js +234 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/schemas/agency.d.ts +50 -359
- package/dist/schemas/common.d.ts +18 -111
- package/dist/schemas/internal.d.ts +2 -2
- package/dist/schemas/internal.js +4 -4
- package/dist/schemas/property.d.ts +250 -1373
- package/package.json +11 -8
package/dist/core/api.d.ts
CHANGED
|
@@ -26,6 +26,27 @@ export interface AdditionalConfig {
|
|
|
26
26
|
transformFn?: CatalogTransformer;
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
|
+
retry: {
|
|
30
|
+
/**
|
|
31
|
+
* Maximum total number of attempts (1 = no retries, 2 = one retry, etc.).
|
|
32
|
+
* @default 3
|
|
33
|
+
*/
|
|
34
|
+
attempts: number;
|
|
35
|
+
/**
|
|
36
|
+
* Delay in milliseconds before the first retry.
|
|
37
|
+
* Subsequent delays are calculated according to the `backoff` strategy.
|
|
38
|
+
* @default 200
|
|
39
|
+
*/
|
|
40
|
+
initialDelayMs: number;
|
|
41
|
+
/**
|
|
42
|
+
* Back-off strategy applied between attempts.
|
|
43
|
+
* - `exponential` — delay doubles on every retry (200 → 400 → 800 …)
|
|
44
|
+
* - `linear` — delay increases by `initialDelayMs` each time (200 → 400 → 600 …)
|
|
45
|
+
* - `fixed` — the same delay is used for every retry
|
|
46
|
+
* @default 'exponential'
|
|
47
|
+
*/
|
|
48
|
+
backoff: 'exponential' | 'linear' | 'fixed';
|
|
49
|
+
};
|
|
29
50
|
}
|
|
30
51
|
export declare const DEFAULT_BASE_URL = "https://api.apimo.pro";
|
|
31
52
|
export declare const DEFAULT_ADDITIONAL_CONFIG: AdditionalConfig;
|
|
@@ -47,31 +68,42 @@ export declare class Apimo {
|
|
|
47
68
|
getCatalogEntries(catalogName: CatalogName, options?: Pick<ApiSearchParams, 'culture'>): Promise<CatalogEntry[]>;
|
|
48
69
|
fetchCatalog(catalogName: CatalogName, options?: Pick<ApiSearchParams, 'culture'>): Promise<CatalogEntry[]>;
|
|
49
70
|
fetchAgencies(options?: Pick<ApiSearchParams, 'culture' | 'limit' | 'offset'>): Promise<{
|
|
50
|
-
|
|
71
|
+
total_items: number;
|
|
51
72
|
agencies: {
|
|
52
73
|
id: number;
|
|
53
|
-
|
|
74
|
+
reference: number;
|
|
54
75
|
active: boolean;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
name: string;
|
|
77
|
+
company: {
|
|
78
|
+
id: number;
|
|
79
|
+
name: string;
|
|
80
|
+
};
|
|
81
|
+
brand: unknown;
|
|
82
|
+
networks: unknown[];
|
|
83
|
+
address: string;
|
|
84
|
+
address_more: string | null;
|
|
60
85
|
city: {
|
|
61
86
|
id: number;
|
|
62
87
|
name: string;
|
|
63
88
|
zipcode: string;
|
|
64
89
|
};
|
|
90
|
+
district: unknown;
|
|
91
|
+
country: string;
|
|
92
|
+
region: string;
|
|
93
|
+
latitude: number;
|
|
94
|
+
longitude: number;
|
|
95
|
+
email: string;
|
|
96
|
+
phone: string;
|
|
97
|
+
fax: string | null;
|
|
98
|
+
url: string;
|
|
99
|
+
logo: string;
|
|
100
|
+
logo_svg: string | null;
|
|
65
101
|
picture: string;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
amount: number;
|
|
72
|
-
currency: string;
|
|
73
|
-
}[];
|
|
74
|
-
stories: unknown[];
|
|
102
|
+
currency: string;
|
|
103
|
+
timetable: string;
|
|
104
|
+
created_at: Date;
|
|
105
|
+
updated_at: Date;
|
|
106
|
+
providers: string;
|
|
75
107
|
rates: {
|
|
76
108
|
id: number;
|
|
77
109
|
category: string | CatalogEntryName | null;
|
|
@@ -82,24 +114,15 @@ export declare class Apimo {
|
|
|
82
114
|
comment: string;
|
|
83
115
|
url: string | null;
|
|
84
116
|
}[];
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
address_more: string | null;
|
|
95
|
-
country: string;
|
|
96
|
-
region: string;
|
|
97
|
-
latitude: number;
|
|
98
|
-
longitude: number;
|
|
99
|
-
logo: string;
|
|
100
|
-
logo_svg: string | null;
|
|
101
|
-
timetable: string;
|
|
102
|
-
providers: string;
|
|
117
|
+
partners: {
|
|
118
|
+
type: number;
|
|
119
|
+
partner: number | null;
|
|
120
|
+
name: string | null;
|
|
121
|
+
reference: string;
|
|
122
|
+
amount: number;
|
|
123
|
+
currency: string;
|
|
124
|
+
}[];
|
|
125
|
+
stories: unknown[];
|
|
103
126
|
users: {
|
|
104
127
|
id: number;
|
|
105
128
|
agency: number;
|
|
@@ -117,6 +140,7 @@ export declare class Apimo {
|
|
|
117
140
|
birthday_at: Date;
|
|
118
141
|
timezone: string | null;
|
|
119
142
|
picture: string | null;
|
|
143
|
+
rates: unknown;
|
|
120
144
|
username?: string | undefined;
|
|
121
145
|
password?: string | undefined;
|
|
122
146
|
spoken_languages?: string[] | undefined;
|
|
@@ -126,75 +150,22 @@ export declare class Apimo {
|
|
|
126
150
|
} | null | undefined;
|
|
127
151
|
partners?: unknown[] | undefined;
|
|
128
152
|
stories?: unknown[] | undefined;
|
|
129
|
-
rates?: unknown;
|
|
130
153
|
}[];
|
|
131
154
|
sectors: unknown[];
|
|
132
155
|
parameters: string;
|
|
133
156
|
subscription: string;
|
|
134
|
-
brand?: unknown;
|
|
135
|
-
district?: unknown;
|
|
136
157
|
}[];
|
|
137
|
-
|
|
158
|
+
timestamp: number;
|
|
138
159
|
}>;
|
|
139
160
|
fetchProperties(agencyId: number, options?: Pick<ApiSearchParams, 'culture' | 'limit' | 'offset' | 'timestamp' | 'step' | 'status' | 'group'>): Promise<{
|
|
140
|
-
timestamp: number;
|
|
141
161
|
total_items: number;
|
|
162
|
+
timestamp: number;
|
|
142
163
|
properties: {
|
|
143
|
-
tags: (string | CatalogEntryName | null)[];
|
|
144
164
|
id: number;
|
|
145
|
-
name: string | null;
|
|
146
|
-
options: unknown[];
|
|
147
|
-
type: string | CatalogEntryName | null;
|
|
148
|
-
length: number | null;
|
|
149
|
-
status: string | CatalogEntryName | null;
|
|
150
|
-
agency: number;
|
|
151
|
-
created_at: Date;
|
|
152
|
-
updated_at: Date;
|
|
153
|
-
city: {
|
|
154
|
-
id: number;
|
|
155
|
-
name: string;
|
|
156
|
-
zipcode: string;
|
|
157
|
-
};
|
|
158
|
-
rates: unknown[];
|
|
159
|
-
step: string | CatalogEntryName | null;
|
|
160
|
-
category: string | CatalogEntryName | null;
|
|
161
|
-
url: string | null;
|
|
162
165
|
reference: number;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
id: number;
|
|
167
|
-
name: string;
|
|
168
|
-
} | null;
|
|
169
|
-
country: string;
|
|
170
|
-
region: {
|
|
171
|
-
id: number;
|
|
172
|
-
name: string;
|
|
173
|
-
};
|
|
174
|
-
latitude: number;
|
|
175
|
-
longitude: number;
|
|
176
|
-
height: number | null;
|
|
177
|
-
comments: {
|
|
178
|
-
language: string;
|
|
179
|
-
comment: string;
|
|
180
|
-
title?: string | null | undefined;
|
|
181
|
-
subtitle?: string | null | undefined;
|
|
182
|
-
hook?: unknown;
|
|
183
|
-
comment_full?: string | null | undefined;
|
|
184
|
-
}[];
|
|
185
|
-
area: {
|
|
186
|
-
value: number;
|
|
187
|
-
unit: string | CatalogEntryName | null;
|
|
188
|
-
total: number;
|
|
189
|
-
weighted: number;
|
|
190
|
-
};
|
|
191
|
-
floor: {
|
|
192
|
-
value: number;
|
|
193
|
-
type: string | CatalogEntryName | null;
|
|
194
|
-
levels: number;
|
|
195
|
-
floors: number;
|
|
196
|
-
};
|
|
197
|
-
orientations: (string | CatalogEntryName | null)[];
|
|
166
|
+
agency: number;
|
|
167
|
+
brand: unknown;
|
|
168
|
+
sector: unknown;
|
|
198
169
|
user: {
|
|
199
170
|
id: number;
|
|
200
171
|
agency: number;
|
|
@@ -212,6 +183,7 @@ export declare class Apimo {
|
|
|
212
183
|
birthday_at: Date;
|
|
213
184
|
timezone: string | null;
|
|
214
185
|
picture: string | null;
|
|
186
|
+
rates: unknown;
|
|
215
187
|
username?: string | undefined;
|
|
216
188
|
password?: string | undefined;
|
|
217
189
|
spoken_languages?: string[] | undefined;
|
|
@@ -221,9 +193,14 @@ export declare class Apimo {
|
|
|
221
193
|
} | null | undefined;
|
|
222
194
|
partners?: unknown[] | undefined;
|
|
223
195
|
stories?: unknown[] | undefined;
|
|
224
|
-
rates?: unknown;
|
|
225
196
|
};
|
|
197
|
+
step: string | CatalogEntryName | null;
|
|
198
|
+
status: string | CatalogEntryName | null;
|
|
226
199
|
parent: number | null;
|
|
200
|
+
ranking: unknown;
|
|
201
|
+
category: string | CatalogEntryName | null;
|
|
202
|
+
name: string | null;
|
|
203
|
+
type: string | CatalogEntryName | null;
|
|
227
204
|
subtype: string | CatalogEntryName | null;
|
|
228
205
|
agreement: {
|
|
229
206
|
type: string | CatalogEntryName | null;
|
|
@@ -235,9 +212,38 @@ export declare class Apimo {
|
|
|
235
212
|
lot_reference: string | null;
|
|
236
213
|
cadastre_reference: string | null;
|
|
237
214
|
stairs_reference: string | null;
|
|
215
|
+
address: string | null;
|
|
216
|
+
address_more: string | null;
|
|
238
217
|
publish_address: boolean;
|
|
218
|
+
country: string;
|
|
219
|
+
region: {
|
|
220
|
+
id: number;
|
|
221
|
+
name: string;
|
|
222
|
+
};
|
|
223
|
+
city: {
|
|
224
|
+
id: number;
|
|
225
|
+
name: string;
|
|
226
|
+
zipcode: string;
|
|
227
|
+
};
|
|
228
|
+
original_city: unknown;
|
|
229
|
+
district: {
|
|
230
|
+
id: number;
|
|
231
|
+
name: string;
|
|
232
|
+
} | null;
|
|
233
|
+
original_district: unknown;
|
|
234
|
+
location: unknown;
|
|
235
|
+
longitude: number;
|
|
236
|
+
latitude: number;
|
|
239
237
|
radius: number;
|
|
240
238
|
altitude: number;
|
|
239
|
+
referral: unknown;
|
|
240
|
+
subreferral: unknown;
|
|
241
|
+
area: {
|
|
242
|
+
unit: string | CatalogEntryName | null;
|
|
243
|
+
value: number;
|
|
244
|
+
total: number;
|
|
245
|
+
weighted: number;
|
|
246
|
+
};
|
|
241
247
|
plot: {
|
|
242
248
|
net_floor: number;
|
|
243
249
|
land_type: string | CatalogEntryName | null;
|
|
@@ -249,26 +255,29 @@ export declare class Apimo {
|
|
|
249
255
|
bedrooms: number;
|
|
250
256
|
sleeps: number;
|
|
251
257
|
price: {
|
|
252
|
-
fees: number;
|
|
253
258
|
value: number;
|
|
254
|
-
currency: string;
|
|
255
259
|
max: number;
|
|
260
|
+
fees: number;
|
|
261
|
+
unit: unknown;
|
|
256
262
|
period: string | CatalogEntryName | null;
|
|
257
263
|
hide: boolean;
|
|
258
264
|
inventory: number | null;
|
|
259
265
|
deposit: number | null;
|
|
266
|
+
currency: string;
|
|
260
267
|
commission: number | null;
|
|
268
|
+
transfer_tax: unknown;
|
|
269
|
+
contribution: unknown;
|
|
270
|
+
pension: unknown;
|
|
261
271
|
tenant: number | null;
|
|
262
272
|
vat: boolean | null;
|
|
263
|
-
unit?: unknown;
|
|
264
|
-
transfer_tax?: unknown;
|
|
265
|
-
contribution?: unknown;
|
|
266
|
-
pension?: unknown;
|
|
267
273
|
};
|
|
274
|
+
rates: unknown[];
|
|
275
|
+
owner: unknown;
|
|
276
|
+
visit: unknown;
|
|
268
277
|
residence: {
|
|
269
|
-
fees: number;
|
|
270
278
|
id: number;
|
|
271
279
|
type: string | CatalogEntryName | null;
|
|
280
|
+
fees: number;
|
|
272
281
|
period: string | CatalogEntryName | null;
|
|
273
282
|
lots: number;
|
|
274
283
|
} | null;
|
|
@@ -277,17 +286,23 @@ export declare class Apimo {
|
|
|
277
286
|
landscape: (string | CatalogEntryName | null)[];
|
|
278
287
|
} | null;
|
|
279
288
|
construction: {
|
|
280
|
-
construction_step: string | CatalogEntryName | null;
|
|
281
289
|
construction_year: number;
|
|
282
290
|
renovation_year: number;
|
|
283
291
|
renovation_cost: number;
|
|
292
|
+
construction_step: string | CatalogEntryName | null;
|
|
284
293
|
type?: (string | CatalogEntryName | null)[] | undefined;
|
|
285
294
|
};
|
|
286
|
-
|
|
295
|
+
floor: {
|
|
287
296
|
type: string | CatalogEntryName | null;
|
|
297
|
+
value: number;
|
|
298
|
+
levels: number;
|
|
299
|
+
floors: number;
|
|
300
|
+
};
|
|
301
|
+
heating: {
|
|
288
302
|
device: string | CatalogEntryName | null;
|
|
289
303
|
devices: (string | CatalogEntryName | null)[] | null;
|
|
290
304
|
access: string | CatalogEntryName | null;
|
|
305
|
+
type: string | CatalogEntryName | null;
|
|
291
306
|
types: (string | CatalogEntryName | null)[] | null;
|
|
292
307
|
};
|
|
293
308
|
water: {
|
|
@@ -302,22 +317,29 @@ export declare class Apimo {
|
|
|
302
317
|
};
|
|
303
318
|
twinned: number | null;
|
|
304
319
|
facades: number;
|
|
320
|
+
length: number | null;
|
|
321
|
+
height: number | null;
|
|
322
|
+
url: string | null;
|
|
305
323
|
availability: string | CatalogEntryName | null;
|
|
324
|
+
available_at: unknown;
|
|
306
325
|
delivered_at: Date | null;
|
|
307
326
|
activities: (string | CatalogEntryName | null)[];
|
|
327
|
+
orientations: (string | CatalogEntryName | null)[];
|
|
308
328
|
services: (string | CatalogEntryName | null)[];
|
|
309
329
|
proximities: (string | CatalogEntryName | null)[];
|
|
330
|
+
tags: (string | CatalogEntryName | null)[];
|
|
310
331
|
tags_customized: unknown[];
|
|
311
332
|
pictures: {
|
|
312
333
|
id: number;
|
|
313
|
-
url: string;
|
|
314
334
|
rank: number;
|
|
335
|
+
url: string;
|
|
315
336
|
width_max: number;
|
|
316
337
|
height_max: number;
|
|
317
338
|
internet: boolean;
|
|
318
339
|
print: boolean;
|
|
319
340
|
panorama: boolean;
|
|
320
341
|
child: number;
|
|
342
|
+
reference: unknown;
|
|
321
343
|
comments: {
|
|
322
344
|
language: string;
|
|
323
345
|
comment: string;
|
|
@@ -326,13 +348,28 @@ export declare class Apimo {
|
|
|
326
348
|
hook?: unknown;
|
|
327
349
|
comment_full?: string | null | undefined;
|
|
328
350
|
}[];
|
|
329
|
-
reference?: unknown;
|
|
330
351
|
}[];
|
|
331
352
|
medias: unknown[];
|
|
332
353
|
documents: unknown[];
|
|
354
|
+
comments: {
|
|
355
|
+
language: string;
|
|
356
|
+
comment: string;
|
|
357
|
+
title?: string | null | undefined;
|
|
358
|
+
subtitle?: string | null | undefined;
|
|
359
|
+
hook?: unknown;
|
|
360
|
+
comment_full?: string | null | undefined;
|
|
361
|
+
}[];
|
|
333
362
|
areas: {
|
|
334
|
-
number: number;
|
|
335
363
|
type: string | CatalogEntryName | null;
|
|
364
|
+
number: number;
|
|
365
|
+
area: number;
|
|
366
|
+
flooring: string | CatalogEntryName | null;
|
|
367
|
+
ceiling_height: number | null;
|
|
368
|
+
floor: {
|
|
369
|
+
type: string | CatalogEntryName | null;
|
|
370
|
+
value: number;
|
|
371
|
+
};
|
|
372
|
+
orientations: (string | CatalogEntryName | null)[];
|
|
336
373
|
comments: {
|
|
337
374
|
language: string;
|
|
338
375
|
comment: string;
|
|
@@ -341,49 +378,36 @@ export declare class Apimo {
|
|
|
341
378
|
hook?: unknown;
|
|
342
379
|
comment_full?: string | null | undefined;
|
|
343
380
|
}[];
|
|
344
|
-
area: number;
|
|
345
|
-
flooring: string | CatalogEntryName | null;
|
|
346
|
-
ceiling_height: number | null;
|
|
347
|
-
floor: {
|
|
348
|
-
value: number;
|
|
349
|
-
type: string | CatalogEntryName | null;
|
|
350
|
-
};
|
|
351
|
-
orientations: (string | CatalogEntryName | null)[];
|
|
352
381
|
lot: {
|
|
382
|
+
type: unknown;
|
|
383
|
+
rank: unknown;
|
|
353
384
|
name: unknown[];
|
|
354
|
-
type?: unknown;
|
|
355
|
-
rank?: unknown;
|
|
356
385
|
};
|
|
357
386
|
}[];
|
|
358
387
|
regulations: {
|
|
359
|
-
value: number[];
|
|
360
388
|
type: string | CatalogEntryName | null;
|
|
389
|
+
value: number[];
|
|
361
390
|
date: Date | null;
|
|
362
391
|
graph: string | null;
|
|
363
392
|
}[];
|
|
364
393
|
financial: unknown[];
|
|
365
394
|
exchanges: unknown[];
|
|
395
|
+
options: unknown[];
|
|
396
|
+
filling_rate: unknown;
|
|
397
|
+
private_comment: unknown;
|
|
398
|
+
interagency_comment: unknown;
|
|
399
|
+
status_comment: unknown;
|
|
366
400
|
logs: unknown[];
|
|
367
401
|
referrals: unknown[];
|
|
402
|
+
created_at: Date;
|
|
403
|
+
updated_at: Date;
|
|
368
404
|
created_by: number;
|
|
369
405
|
updated_by: number;
|
|
370
|
-
referral?: unknown;
|
|
371
|
-
brand?: unknown;
|
|
372
|
-
sector?: unknown;
|
|
373
|
-
ranking?: unknown;
|
|
374
|
-
original_city?: unknown;
|
|
375
|
-
original_district?: unknown;
|
|
376
|
-
location?: unknown;
|
|
377
|
-
subreferral?: unknown;
|
|
378
|
-
owner?: unknown;
|
|
379
|
-
visit?: unknown;
|
|
380
|
-
available_at?: unknown;
|
|
381
|
-
filling_rate?: unknown;
|
|
382
|
-
private_comment?: unknown;
|
|
383
|
-
interagency_comment?: unknown;
|
|
384
|
-
status_comment?: unknown;
|
|
385
406
|
}[];
|
|
386
407
|
}>;
|
|
408
|
+
/** Calculates the delay before the next retry attempt (1-based attempt index). */
|
|
409
|
+
private retryDelayMs;
|
|
410
|
+
private sleep;
|
|
387
411
|
private getLocalizedCatalogTransformer;
|
|
388
412
|
private catalogTransformer;
|
|
389
413
|
}
|
package/dist/core/api.js
CHANGED
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import Bottleneck from 'bottleneck';
|
|
11
11
|
import { merge } from 'merge-anything';
|
|
12
12
|
import { z } from 'zod';
|
|
13
|
+
import { ApiConfigurationError, ApiResponseValidationError, ApiRetryExhaustedError, isRetryable, throwForStatus, } from '../errors';
|
|
13
14
|
import { getAgencySchema } from '../schemas/agency';
|
|
14
15
|
import { CatalogDefinitionSchema, CatalogEntrySchema } from '../schemas/common';
|
|
15
16
|
import { getPropertySchema } from '../schemas/property';
|
|
@@ -30,6 +31,11 @@ export const DEFAULT_ADDITIONAL_CONFIG = {
|
|
|
30
31
|
active: true,
|
|
31
32
|
},
|
|
32
33
|
},
|
|
34
|
+
retry: {
|
|
35
|
+
attempts: 3,
|
|
36
|
+
initialDelayMs: 200,
|
|
37
|
+
backoff: 'exponential',
|
|
38
|
+
},
|
|
33
39
|
};
|
|
34
40
|
export class Apimo {
|
|
35
41
|
constructor(
|
|
@@ -41,7 +47,23 @@ export class Apimo {
|
|
|
41
47
|
config = DEFAULT_ADDITIONAL_CONFIG) {
|
|
42
48
|
this.provider = provider;
|
|
43
49
|
this.token = token;
|
|
50
|
+
if (!provider || provider.trim() === '') {
|
|
51
|
+
throw new ApiConfigurationError('provider must be a non-empty string.');
|
|
52
|
+
}
|
|
53
|
+
if (!token || token.trim() === '') {
|
|
54
|
+
throw new ApiConfigurationError('token must be a non-empty string.');
|
|
55
|
+
}
|
|
44
56
|
this.config = merge(DEFAULT_ADDITIONAL_CONFIG, config);
|
|
57
|
+
if (!this.config.baseUrl || this.config.baseUrl.trim() === '') {
|
|
58
|
+
throw new ApiConfigurationError('baseUrl must be a non-empty string.');
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
// eslint-disable-next-line no-new
|
|
62
|
+
new URL(this.config.baseUrl);
|
|
63
|
+
}
|
|
64
|
+
catch (_a) {
|
|
65
|
+
throw new ApiConfigurationError(`baseUrl "${this.config.baseUrl}" is not a valid URL.`);
|
|
66
|
+
}
|
|
45
67
|
this.cache = this.config.catalogs.cache.active ? this.config.catalogs.cache.adapter : new DummyCache();
|
|
46
68
|
this.limiter = new Bottleneck({
|
|
47
69
|
reservoir: 10,
|
|
@@ -59,11 +81,43 @@ export class Apimo {
|
|
|
59
81
|
}
|
|
60
82
|
get(path, schema, options) {
|
|
61
83
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
84
|
+
const url = makeApiUrl(path, this.config, Object.assign({ culture: this.config.culture }, options));
|
|
85
|
+
const { attempts, initialDelayMs, backoff } = this.config.retry;
|
|
86
|
+
let lastError;
|
|
87
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
88
|
+
try {
|
|
89
|
+
const response = yield this.fetch(url);
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
let responseBody;
|
|
92
|
+
try {
|
|
93
|
+
responseBody = yield response.json();
|
|
94
|
+
}
|
|
95
|
+
catch (_a) {
|
|
96
|
+
// The body wasn't JSON — leave responseBody as undefined
|
|
97
|
+
}
|
|
98
|
+
throwForStatus(response.status, url.toString(), responseBody);
|
|
99
|
+
}
|
|
100
|
+
const json = yield response.json();
|
|
101
|
+
const result = yield schema.safeParseAsync(json);
|
|
102
|
+
if (!result.success) {
|
|
103
|
+
throw new ApiResponseValidationError(url.toString(), result.error);
|
|
104
|
+
}
|
|
105
|
+
return result.data;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
lastError = error;
|
|
109
|
+
const hasMoreAttempts = attempt < attempts;
|
|
110
|
+
if (!isRetryable(error)) {
|
|
111
|
+
// Non-transient errors (4xx, schema failures, etc.) — propagate immediately
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
if (!hasMoreAttempts) {
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
yield this.sleep(this.retryDelayMs(attempt, initialDelayMs, backoff));
|
|
118
|
+
}
|
|
65
119
|
}
|
|
66
|
-
|
|
120
|
+
throw new ApiRetryExhaustedError(attempts, lastError);
|
|
67
121
|
});
|
|
68
122
|
}
|
|
69
123
|
fetchCatalogs() {
|
|
@@ -128,6 +182,17 @@ export class Apimo {
|
|
|
128
182
|
}), options);
|
|
129
183
|
});
|
|
130
184
|
}
|
|
185
|
+
/** Calculates the delay before the next retry attempt (1-based attempt index). */
|
|
186
|
+
retryDelayMs(attempt, initialDelayMs, backoff) {
|
|
187
|
+
switch (backoff) {
|
|
188
|
+
case 'exponential': return initialDelayMs * Math.pow(2, (attempt - 1));
|
|
189
|
+
case 'linear': return initialDelayMs * attempt;
|
|
190
|
+
case 'fixed': return initialDelayMs;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
sleep(ms) {
|
|
194
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
195
|
+
}
|
|
131
196
|
getLocalizedCatalogTransformer(culture) {
|
|
132
197
|
return (catalogName, id) => __awaiter(this, void 0, void 0, function* () {
|
|
133
198
|
if (!this.config.catalogs.transform.active) {
|