@lokalise/node-core 9.8.1 → 10.0.0-RC1
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/dist/index.cjs +898 -0
- package/dist/index.d.cts +304 -0
- package/dist/index.d.mts +304 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +848 -0
- package/dist/src/http/httpClient.d.ts +0 -3
- package/dist/src/http/httpClient.js +1 -4
- package/dist/src/http/httpClient.js.map +1 -1
- package/package.json +10 -3
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,898 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const undici = require('undici');
|
|
4
|
+
const undiciRetry = require('undici-retry');
|
|
5
|
+
const node_util = require('node:util');
|
|
6
|
+
const pino = require('pino');
|
|
7
|
+
const node_http2 = require('node:http2');
|
|
8
|
+
|
|
9
|
+
var __defProp$3 = Object.defineProperty;
|
|
10
|
+
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
+
var __publicField$3 = (obj, key, value) => {
|
|
12
|
+
__defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
13
|
+
return value;
|
|
14
|
+
};
|
|
15
|
+
class InternalError extends Error {
|
|
16
|
+
constructor(params) {
|
|
17
|
+
super(params.message);
|
|
18
|
+
__publicField$3(this, "details");
|
|
19
|
+
__publicField$3(this, "errorCode");
|
|
20
|
+
this.name = "InternalError";
|
|
21
|
+
this.details = params.details;
|
|
22
|
+
this.errorCode = params.errorCode;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var __defProp$2 = Object.defineProperty;
|
|
27
|
+
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
28
|
+
var __publicField$2 = (obj, key, value) => {
|
|
29
|
+
__defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
class ResponseStatusError extends InternalError {
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
constructor(requestResult, requestLabel = "N/A") {
|
|
35
|
+
super({
|
|
36
|
+
message: `Response status code ${requestResult.statusCode}`,
|
|
37
|
+
details: {
|
|
38
|
+
requestLabel,
|
|
39
|
+
response: {
|
|
40
|
+
statusCode: requestResult.statusCode,
|
|
41
|
+
body: requestResult.body
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
errorCode: "REQUEST_ERROR"
|
|
45
|
+
});
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
|
+
__publicField$2(this, "response");
|
|
48
|
+
__publicField$2(this, "isResponseStatusError", true);
|
|
49
|
+
this.response = requestResult;
|
|
50
|
+
this.name = "ResponseStatusError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function copyWithoutUndefined(originalValue) {
|
|
55
|
+
return Object.keys(originalValue).reduce(
|
|
56
|
+
(acc, key) => {
|
|
57
|
+
if (originalValue[key] !== void 0) {
|
|
58
|
+
acc[key] = originalValue[key];
|
|
59
|
+
}
|
|
60
|
+
return acc;
|
|
61
|
+
},
|
|
62
|
+
{}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
function pick(source, propNames) {
|
|
66
|
+
const result = {};
|
|
67
|
+
let idx = 0;
|
|
68
|
+
while (idx < propNames.length) {
|
|
69
|
+
if (propNames[idx] in source) {
|
|
70
|
+
result[propNames[idx]] = source[propNames[idx]];
|
|
71
|
+
}
|
|
72
|
+
idx += 1;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
function pickWithoutUndefined(source, propNames) {
|
|
77
|
+
const result = {};
|
|
78
|
+
let idx = 0;
|
|
79
|
+
while (idx < propNames.length) {
|
|
80
|
+
if (propNames[idx] in source && source[propNames[idx]] !== void 0) {
|
|
81
|
+
result[propNames[idx]] = source[propNames[idx]];
|
|
82
|
+
}
|
|
83
|
+
idx += 1;
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
function isEmptyObject(params) {
|
|
88
|
+
for (const key in params) {
|
|
89
|
+
if (Object.hasOwn(params, key) && params[key] !== void 0) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
function groupBy(array, selector) {
|
|
96
|
+
return array.reduce(
|
|
97
|
+
(acc, item) => {
|
|
98
|
+
const key = item[selector];
|
|
99
|
+
if (key === void 0 || key === null) {
|
|
100
|
+
return acc;
|
|
101
|
+
}
|
|
102
|
+
if (!acc[key]) {
|
|
103
|
+
acc[key] = [];
|
|
104
|
+
}
|
|
105
|
+
acc[key].push(item);
|
|
106
|
+
return acc;
|
|
107
|
+
},
|
|
108
|
+
{}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
function groupByUnique(array, selector) {
|
|
112
|
+
return array.reduce(
|
|
113
|
+
(acc, item) => {
|
|
114
|
+
const key = item[selector];
|
|
115
|
+
if (key === void 0 || key === null) {
|
|
116
|
+
return acc;
|
|
117
|
+
}
|
|
118
|
+
if (acc[key] !== void 0) {
|
|
119
|
+
throw new InternalError({
|
|
120
|
+
message: `Duplicated item for selector ${selector.toString()} with value ${key.toString()}`,
|
|
121
|
+
errorCode: "DUPLICATED_ITEM",
|
|
122
|
+
details: { selector, value: key }
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
acc[key] = item;
|
|
126
|
+
return acc;
|
|
127
|
+
},
|
|
128
|
+
{}
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
function convertDateFieldsToIsoString(object) {
|
|
132
|
+
if (Array.isArray(object)) {
|
|
133
|
+
return object.map(convertDateFieldsToIsoStringAux);
|
|
134
|
+
}
|
|
135
|
+
return Object.entries(object).reduce((result, [key, value]) => {
|
|
136
|
+
result[key] = convertDateFieldsToIsoStringAux(value);
|
|
137
|
+
return result;
|
|
138
|
+
}, {});
|
|
139
|
+
}
|
|
140
|
+
function convertDateFieldsToIsoStringAux(item) {
|
|
141
|
+
if (item instanceof Date) {
|
|
142
|
+
return item.toISOString();
|
|
143
|
+
} else if (item && typeof item === "object") {
|
|
144
|
+
return convertDateFieldsToIsoString(item);
|
|
145
|
+
} else {
|
|
146
|
+
return item;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function deepClone(object) {
|
|
150
|
+
if (object === void 0 || object === null) {
|
|
151
|
+
return object;
|
|
152
|
+
}
|
|
153
|
+
return structuredClone(object);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const DEFAULT_OPTIONS = {
|
|
157
|
+
validateResponse: true,
|
|
158
|
+
throwOnError: true,
|
|
159
|
+
timeout: 3e4
|
|
160
|
+
};
|
|
161
|
+
const defaultClientOptions = {
|
|
162
|
+
keepAliveMaxTimeout: 3e5,
|
|
163
|
+
keepAliveTimeout: 4e3
|
|
164
|
+
};
|
|
165
|
+
async function sendGet(client, path, options = {}) {
|
|
166
|
+
const result = await undiciRetry.sendWithRetry(
|
|
167
|
+
client,
|
|
168
|
+
{
|
|
169
|
+
...DEFAULT_OPTIONS,
|
|
170
|
+
path,
|
|
171
|
+
method: "GET",
|
|
172
|
+
query: options.query,
|
|
173
|
+
headers: copyWithoutUndefined({
|
|
174
|
+
"x-request-id": options.reqContext?.reqId,
|
|
175
|
+
...options.headers
|
|
176
|
+
}),
|
|
177
|
+
reset: options.disableKeepAlive ?? false,
|
|
178
|
+
bodyTimeout: options.timeout,
|
|
179
|
+
throwOnError: false
|
|
180
|
+
},
|
|
181
|
+
resolveRetryConfig(options),
|
|
182
|
+
resolveRequestConfig(options)
|
|
183
|
+
);
|
|
184
|
+
return resolveResult(
|
|
185
|
+
result,
|
|
186
|
+
options.throwOnError ?? DEFAULT_OPTIONS.throwOnError,
|
|
187
|
+
options.validateResponse ?? DEFAULT_OPTIONS.validateResponse,
|
|
188
|
+
options.responseSchema,
|
|
189
|
+
options.requestLabel
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
async function sendDelete(client, path, options = {}) {
|
|
193
|
+
const result = await undiciRetry.sendWithRetry(
|
|
194
|
+
client,
|
|
195
|
+
{
|
|
196
|
+
...DEFAULT_OPTIONS,
|
|
197
|
+
path,
|
|
198
|
+
method: "DELETE",
|
|
199
|
+
query: options.query,
|
|
200
|
+
headers: copyWithoutUndefined({
|
|
201
|
+
"x-request-id": options.reqContext?.reqId,
|
|
202
|
+
...options.headers
|
|
203
|
+
}),
|
|
204
|
+
reset: options.disableKeepAlive ?? false,
|
|
205
|
+
bodyTimeout: options.timeout,
|
|
206
|
+
throwOnError: false
|
|
207
|
+
},
|
|
208
|
+
resolveRetryConfig(options),
|
|
209
|
+
resolveRequestConfig(options)
|
|
210
|
+
);
|
|
211
|
+
return resolveResult(
|
|
212
|
+
result,
|
|
213
|
+
options.throwOnError ?? DEFAULT_OPTIONS.throwOnError,
|
|
214
|
+
options.validateResponse ?? DEFAULT_OPTIONS.validateResponse,
|
|
215
|
+
options.responseSchema
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
async function sendPost(client, path, body, options = {}) {
|
|
219
|
+
const result = await undiciRetry.sendWithRetry(
|
|
220
|
+
client,
|
|
221
|
+
{
|
|
222
|
+
...DEFAULT_OPTIONS,
|
|
223
|
+
path,
|
|
224
|
+
method: "POST",
|
|
225
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
226
|
+
query: options.query,
|
|
227
|
+
headers: copyWithoutUndefined({
|
|
228
|
+
"x-request-id": options.reqContext?.reqId,
|
|
229
|
+
...options.headers
|
|
230
|
+
}),
|
|
231
|
+
reset: options.disableKeepAlive ?? false,
|
|
232
|
+
bodyTimeout: options.timeout,
|
|
233
|
+
throwOnError: false
|
|
234
|
+
},
|
|
235
|
+
resolveRetryConfig(options),
|
|
236
|
+
resolveRequestConfig(options)
|
|
237
|
+
);
|
|
238
|
+
return resolveResult(
|
|
239
|
+
result,
|
|
240
|
+
options.throwOnError ?? DEFAULT_OPTIONS.throwOnError,
|
|
241
|
+
options.validateResponse ?? DEFAULT_OPTIONS.validateResponse,
|
|
242
|
+
options.responseSchema
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
async function sendPostBinary(client, path, body, options = {}) {
|
|
246
|
+
const result = await undiciRetry.sendWithRetry(
|
|
247
|
+
client,
|
|
248
|
+
{
|
|
249
|
+
...DEFAULT_OPTIONS,
|
|
250
|
+
path,
|
|
251
|
+
method: "POST",
|
|
252
|
+
body,
|
|
253
|
+
query: options.query,
|
|
254
|
+
headers: copyWithoutUndefined({
|
|
255
|
+
"x-request-id": options.reqContext?.reqId,
|
|
256
|
+
...options.headers
|
|
257
|
+
}),
|
|
258
|
+
reset: options.disableKeepAlive ?? false,
|
|
259
|
+
bodyTimeout: options.timeout,
|
|
260
|
+
throwOnError: false
|
|
261
|
+
},
|
|
262
|
+
resolveRetryConfig(options),
|
|
263
|
+
resolveRequestConfig(options)
|
|
264
|
+
);
|
|
265
|
+
return resolveResult(
|
|
266
|
+
result,
|
|
267
|
+
options.throwOnError ?? DEFAULT_OPTIONS.throwOnError,
|
|
268
|
+
options.validateResponse ?? DEFAULT_OPTIONS.validateResponse,
|
|
269
|
+
options.responseSchema
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
async function sendPut(client, path, body, options = {}) {
|
|
273
|
+
const result = await undiciRetry.sendWithRetry(
|
|
274
|
+
client,
|
|
275
|
+
{
|
|
276
|
+
...DEFAULT_OPTIONS,
|
|
277
|
+
path,
|
|
278
|
+
method: "PUT",
|
|
279
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
280
|
+
query: options.query,
|
|
281
|
+
headers: copyWithoutUndefined({
|
|
282
|
+
"x-request-id": options.reqContext?.reqId,
|
|
283
|
+
...options.headers
|
|
284
|
+
}),
|
|
285
|
+
reset: options.disableKeepAlive ?? false,
|
|
286
|
+
bodyTimeout: options.timeout,
|
|
287
|
+
throwOnError: false
|
|
288
|
+
},
|
|
289
|
+
resolveRetryConfig(options),
|
|
290
|
+
resolveRequestConfig(options)
|
|
291
|
+
);
|
|
292
|
+
return resolveResult(
|
|
293
|
+
result,
|
|
294
|
+
options.throwOnError ?? DEFAULT_OPTIONS.throwOnError,
|
|
295
|
+
options.validateResponse ?? DEFAULT_OPTIONS.validateResponse,
|
|
296
|
+
options.responseSchema
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
async function sendPutBinary(client, path, body, options = {}) {
|
|
300
|
+
const result = await undiciRetry.sendWithRetry(
|
|
301
|
+
client,
|
|
302
|
+
{
|
|
303
|
+
...DEFAULT_OPTIONS,
|
|
304
|
+
path,
|
|
305
|
+
method: "PUT",
|
|
306
|
+
body,
|
|
307
|
+
query: options.query,
|
|
308
|
+
headers: copyWithoutUndefined({
|
|
309
|
+
"x-request-id": options.reqContext?.reqId,
|
|
310
|
+
...options.headers
|
|
311
|
+
}),
|
|
312
|
+
reset: options.disableKeepAlive ?? false,
|
|
313
|
+
bodyTimeout: options.timeout,
|
|
314
|
+
throwOnError: false
|
|
315
|
+
},
|
|
316
|
+
resolveRetryConfig(options),
|
|
317
|
+
resolveRequestConfig(options)
|
|
318
|
+
);
|
|
319
|
+
return resolveResult(
|
|
320
|
+
result,
|
|
321
|
+
options.throwOnError ?? DEFAULT_OPTIONS.throwOnError,
|
|
322
|
+
options.validateResponse ?? DEFAULT_OPTIONS.validateResponse,
|
|
323
|
+
options.responseSchema
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
async function sendPatch(client, path, body, options = {}) {
|
|
327
|
+
const result = await undiciRetry.sendWithRetry(
|
|
328
|
+
client,
|
|
329
|
+
{
|
|
330
|
+
...DEFAULT_OPTIONS,
|
|
331
|
+
path,
|
|
332
|
+
method: "PATCH",
|
|
333
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
334
|
+
query: options.query,
|
|
335
|
+
headers: copyWithoutUndefined({
|
|
336
|
+
"x-request-id": options.reqContext?.reqId,
|
|
337
|
+
...options.headers
|
|
338
|
+
}),
|
|
339
|
+
reset: options.disableKeepAlive ?? false,
|
|
340
|
+
bodyTimeout: options.timeout,
|
|
341
|
+
throwOnError: false
|
|
342
|
+
},
|
|
343
|
+
resolveRetryConfig(options),
|
|
344
|
+
resolveRequestConfig(options)
|
|
345
|
+
);
|
|
346
|
+
return resolveResult(
|
|
347
|
+
result,
|
|
348
|
+
options.throwOnError ?? DEFAULT_OPTIONS.throwOnError,
|
|
349
|
+
options.validateResponse ?? DEFAULT_OPTIONS.validateResponse,
|
|
350
|
+
options.responseSchema
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
function resolveRequestConfig(options) {
|
|
354
|
+
return {
|
|
355
|
+
safeParseJson: options.safeParseJson ?? false,
|
|
356
|
+
blobBody: options.blobResponseBody ?? false,
|
|
357
|
+
throwOnInternalError: false,
|
|
358
|
+
requestLabel: options.requestLabel
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
function resolveRetryConfig(options) {
|
|
362
|
+
return options.retryConfig ?? undiciRetry.NO_RETRY_CONFIG;
|
|
363
|
+
}
|
|
364
|
+
function buildClient(baseUrl, clientOptions) {
|
|
365
|
+
const newClient = new undici.Client(baseUrl, {
|
|
366
|
+
...defaultClientOptions,
|
|
367
|
+
...clientOptions
|
|
368
|
+
});
|
|
369
|
+
return newClient;
|
|
370
|
+
}
|
|
371
|
+
function resolveResult(requestResult, throwOnError, validateResponse, validationSchema, requestLabel) {
|
|
372
|
+
if (requestResult.error && throwOnError) {
|
|
373
|
+
if (undiciRetry.isRequestResult(requestResult.error)) {
|
|
374
|
+
throw new ResponseStatusError(requestResult.error, requestLabel);
|
|
375
|
+
}
|
|
376
|
+
throw requestResult.error;
|
|
377
|
+
}
|
|
378
|
+
if (requestResult.result && validateResponse && validationSchema) {
|
|
379
|
+
requestResult.result.body = validationSchema.parse(requestResult.result.body);
|
|
380
|
+
}
|
|
381
|
+
return requestResult;
|
|
382
|
+
}
|
|
383
|
+
const httpClient = {
|
|
384
|
+
get: sendGet,
|
|
385
|
+
post: sendPost,
|
|
386
|
+
put: sendPut,
|
|
387
|
+
patch: sendPatch,
|
|
388
|
+
del: sendDelete
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
var __defProp$1 = Object.defineProperty;
|
|
392
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
393
|
+
var __publicField$1 = (obj, key, value) => {
|
|
394
|
+
__defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
395
|
+
return value;
|
|
396
|
+
};
|
|
397
|
+
class PublicNonRecoverableError extends Error {
|
|
398
|
+
constructor(params) {
|
|
399
|
+
super(params.message);
|
|
400
|
+
__publicField$1(this, "details");
|
|
401
|
+
__publicField$1(this, "errorCode");
|
|
402
|
+
__publicField$1(this, "httpStatusCode");
|
|
403
|
+
this.name = "PublicNonRecoverableError";
|
|
404
|
+
this.details = params.details;
|
|
405
|
+
this.errorCode = params.errorCode;
|
|
406
|
+
this.httpStatusCode = params.httpStatusCode ?? 500;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function isResponseStatusError(entity) {
|
|
411
|
+
return "isResponseStatusError" in entity;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
var __defProp = Object.defineProperty;
|
|
415
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
416
|
+
var __publicField = (obj, key, value) => {
|
|
417
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
418
|
+
return value;
|
|
419
|
+
};
|
|
420
|
+
class ConfigScope {
|
|
421
|
+
constructor(envOverride) {
|
|
422
|
+
__publicField(this, "env");
|
|
423
|
+
this.env = envOverride ?? { ...process.env };
|
|
424
|
+
}
|
|
425
|
+
updateEnv() {
|
|
426
|
+
this.env = { ...process.env };
|
|
427
|
+
}
|
|
428
|
+
getMandatoryInteger(param) {
|
|
429
|
+
const rawValue = this.env[param];
|
|
430
|
+
if (!rawValue) {
|
|
431
|
+
throw new InternalError({
|
|
432
|
+
message: `Missing mandatory configuration parameter: ${param}`,
|
|
433
|
+
errorCode: "CONFIGURATION_ERROR"
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
return validateNumber(
|
|
437
|
+
Number.parseInt(rawValue),
|
|
438
|
+
`Configuration parameter ${param}\` must be a number, but was ${rawValue}`
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
getMandatory(param) {
|
|
442
|
+
const result = this.env[param];
|
|
443
|
+
if (!result) {
|
|
444
|
+
throw new InternalError({
|
|
445
|
+
message: `Missing mandatory configuration parameter: ${param}`,
|
|
446
|
+
errorCode: "CONFIGURATION_ERROR"
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
return result;
|
|
450
|
+
}
|
|
451
|
+
getMandatoryOneOf(param, supportedValues) {
|
|
452
|
+
const result = this.getMandatory(param);
|
|
453
|
+
return validateOneOf(
|
|
454
|
+
result,
|
|
455
|
+
supportedValues,
|
|
456
|
+
`Unsupported ${param}: ${result}. Supported values: ${supportedValues.toString()}`
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
getMandatoryValidatedInteger(param, validator) {
|
|
460
|
+
const value = this.getMandatoryInteger(param);
|
|
461
|
+
if (!validator(value)) {
|
|
462
|
+
throw new InternalError({
|
|
463
|
+
message: `Value ${value} is invalid for parameter ${param}`,
|
|
464
|
+
errorCode: "CONFIGURATION_ERROR"
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
return value;
|
|
468
|
+
}
|
|
469
|
+
getOptionalNullable(param, defaultValue) {
|
|
470
|
+
return this.env[param] || defaultValue;
|
|
471
|
+
}
|
|
472
|
+
getOptional(param, defaultValue) {
|
|
473
|
+
return this.env[param] || defaultValue;
|
|
474
|
+
}
|
|
475
|
+
getOptionalInteger(param, defaultValue) {
|
|
476
|
+
const rawValue = this.env[param];
|
|
477
|
+
if (!rawValue) {
|
|
478
|
+
return defaultValue;
|
|
479
|
+
}
|
|
480
|
+
return validateNumber(
|
|
481
|
+
Number.parseInt(rawValue),
|
|
482
|
+
`Configuration parameter ${param}\` must be a number, but was ${rawValue}`
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
getOptionalNullableInteger(param, defaultValue) {
|
|
486
|
+
const rawValue = this.env[param];
|
|
487
|
+
if (!rawValue) {
|
|
488
|
+
return defaultValue;
|
|
489
|
+
}
|
|
490
|
+
return validateNumber(
|
|
491
|
+
Number.parseInt(rawValue),
|
|
492
|
+
`Configuration parameter ${param}\` must be a number, but was ${rawValue}`
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
getOptionalOneOf(param, defaultValue, supportedValues) {
|
|
496
|
+
const result = this.getOptional(param, defaultValue);
|
|
497
|
+
return validateOneOf(
|
|
498
|
+
result,
|
|
499
|
+
supportedValues,
|
|
500
|
+
`Unsupported ${param}: ${result}. Supported values: ${supportedValues.toString()}`
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
getOptionalValidated(param, defaultValue, validator) {
|
|
504
|
+
const value = this.env[param] || defaultValue;
|
|
505
|
+
if (!validator(value)) {
|
|
506
|
+
throw new InternalError({
|
|
507
|
+
message: `Value ${value} is invalid for parameter ${param}`,
|
|
508
|
+
errorCode: "CONFIGURATION_ERROR"
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
return value;
|
|
512
|
+
}
|
|
513
|
+
getOptionalValidatedInteger(param, defaultValue, validator) {
|
|
514
|
+
const value = this.getOptionalInteger(param, defaultValue);
|
|
515
|
+
if (!validator(value)) {
|
|
516
|
+
throw new InternalError({
|
|
517
|
+
message: `Value ${value} is invalid for parameter ${param}`,
|
|
518
|
+
errorCode: "CONFIGURATION_ERROR"
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
return value;
|
|
522
|
+
}
|
|
523
|
+
getOptionalTransformed(param, defaultValue, transformer) {
|
|
524
|
+
const value = this.env[param] || defaultValue;
|
|
525
|
+
return transformer(value);
|
|
526
|
+
}
|
|
527
|
+
getOptionalNullableTransformed(param, defaultValue, transformer) {
|
|
528
|
+
const value = this.env[param] || defaultValue;
|
|
529
|
+
return transformer(value);
|
|
530
|
+
}
|
|
531
|
+
getMandatoryTransformed(param, transformer) {
|
|
532
|
+
const value = this.getMandatory(param);
|
|
533
|
+
return transformer(value);
|
|
534
|
+
}
|
|
535
|
+
getOptionalBoolean(param, defaultValue) {
|
|
536
|
+
const rawValue = this.env[param]?.toLowerCase();
|
|
537
|
+
if (rawValue === void 0 || rawValue === "") {
|
|
538
|
+
return defaultValue;
|
|
539
|
+
}
|
|
540
|
+
validateOneOf(rawValue, ["true", "false"]);
|
|
541
|
+
return rawValue === "true";
|
|
542
|
+
}
|
|
543
|
+
getMandatoryJsonObject(param, schema) {
|
|
544
|
+
const rawValue = this.getMandatory(param);
|
|
545
|
+
return this.validateSchema(
|
|
546
|
+
JSON.parse(rawValue),
|
|
547
|
+
schema,
|
|
548
|
+
`Configuration parameter ${param} must be a valid JSON meeting the given schema, but was ${rawValue}`
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
getOptionalNullableJsonObject(param, schema, defaultValue) {
|
|
552
|
+
const rawValue = this.getOptionalNullable(param, void 0);
|
|
553
|
+
if (!rawValue) {
|
|
554
|
+
return defaultValue;
|
|
555
|
+
}
|
|
556
|
+
return this.validateSchema(
|
|
557
|
+
JSON.parse(rawValue),
|
|
558
|
+
schema,
|
|
559
|
+
`Configuration parameter ${param} must be a valid JSON meeting the given schema, but was ${rawValue}`
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
getOptionalJsonObject(param, schema, defaultValue) {
|
|
563
|
+
return this.getOptionalNullableJsonObject(param, schema, defaultValue);
|
|
564
|
+
}
|
|
565
|
+
isProduction() {
|
|
566
|
+
return this.env.NODE_ENV === "production";
|
|
567
|
+
}
|
|
568
|
+
isDevelopment() {
|
|
569
|
+
return this.env.NODE_ENV !== "production";
|
|
570
|
+
}
|
|
571
|
+
isTest() {
|
|
572
|
+
return this.env.NODE_ENV === "test";
|
|
573
|
+
}
|
|
574
|
+
validateSchema(value, schema, errorMessage) {
|
|
575
|
+
const parsedValue = schema.safeParse(value);
|
|
576
|
+
if (!parsedValue.success) {
|
|
577
|
+
throw new InternalError({
|
|
578
|
+
message: errorMessage,
|
|
579
|
+
errorCode: "CONFIGURATION_ERROR",
|
|
580
|
+
details: parsedValue.error
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
return parsedValue.data;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
function validateOneOf(validatedEntity, expectedOneOfEntities, errorText) {
|
|
587
|
+
if (!expectedOneOfEntities.includes(validatedEntity)) {
|
|
588
|
+
throw new InternalError({
|
|
589
|
+
message: errorText || // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
590
|
+
`Validated entity ${validatedEntity} is not one of: ${expectedOneOfEntities.toString()}`,
|
|
591
|
+
errorCode: "CONFIGURATION_ERROR"
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
return validatedEntity;
|
|
595
|
+
}
|
|
596
|
+
function validateNumber(validatedObject, errorText) {
|
|
597
|
+
if (!Number.isFinite(validatedObject)) {
|
|
598
|
+
throw new InternalError({
|
|
599
|
+
message: errorText,
|
|
600
|
+
errorCode: "CONFIGURATION_ERROR"
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
return validatedObject;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const ensureClosingSlashTransformer = (value) => {
|
|
607
|
+
if (!value) {
|
|
608
|
+
return "";
|
|
609
|
+
}
|
|
610
|
+
const lastChar = value.at(-1);
|
|
611
|
+
if (lastChar !== "/") {
|
|
612
|
+
return `${value}/`;
|
|
613
|
+
}
|
|
614
|
+
return value;
|
|
615
|
+
};
|
|
616
|
+
|
|
617
|
+
const createRangeValidator = (greaterOrEqualThan, lessOrEqualThan) => {
|
|
618
|
+
return (value) => {
|
|
619
|
+
return value >= greaterOrEqualThan && value <= lessOrEqualThan;
|
|
620
|
+
};
|
|
621
|
+
};
|
|
622
|
+
|
|
623
|
+
const isFailure = (e) => {
|
|
624
|
+
return e.error !== void 0;
|
|
625
|
+
};
|
|
626
|
+
const isSuccess = (e) => {
|
|
627
|
+
return e.result !== void 0;
|
|
628
|
+
};
|
|
629
|
+
const failure = (error) => ({ error });
|
|
630
|
+
const success = (result) => ({ result });
|
|
631
|
+
|
|
632
|
+
function chunk(array, chunkSize) {
|
|
633
|
+
const length = array.length;
|
|
634
|
+
if (!length || chunkSize < 1) {
|
|
635
|
+
return [];
|
|
636
|
+
}
|
|
637
|
+
let index = 0;
|
|
638
|
+
let resIndex = 0;
|
|
639
|
+
const result = new Array(Math.ceil(length / chunkSize));
|
|
640
|
+
while (index < length) {
|
|
641
|
+
result[resIndex++] = array.slice(index, index += chunkSize);
|
|
642
|
+
}
|
|
643
|
+
return result;
|
|
644
|
+
}
|
|
645
|
+
async function callChunked(chunkSize, array, processFn) {
|
|
646
|
+
for (let i = 0; i < array.length; i += chunkSize) {
|
|
647
|
+
const arrayChunk = array.slice(i, i + chunkSize);
|
|
648
|
+
await processFn(arrayChunk);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
function removeNullish(array) {
|
|
652
|
+
return array.filter((e) => e !== void 0 && e !== null);
|
|
653
|
+
}
|
|
654
|
+
function removeFalsy(array) {
|
|
655
|
+
return array.filter((e) => e);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function hasMessage(maybe) {
|
|
659
|
+
return isObject(maybe) && typeof maybe.message === "string";
|
|
660
|
+
}
|
|
661
|
+
function isObject(maybeObject) {
|
|
662
|
+
return typeof maybeObject === "object" && maybeObject !== null;
|
|
663
|
+
}
|
|
664
|
+
function isStandardizedError(error) {
|
|
665
|
+
return isObject(error) && typeof error.code === "string" && typeof error.message === "string";
|
|
666
|
+
}
|
|
667
|
+
function isInternalError(error) {
|
|
668
|
+
return isObject(error) && error.name === "InternalError";
|
|
669
|
+
}
|
|
670
|
+
function isPublicNonRecoverableError(error) {
|
|
671
|
+
return isObject(error) && error.name === "PublicNonRecoverableError";
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function resolveMonorepoLoggerConfiguration(appConfig) {
|
|
675
|
+
if (appConfig.nodeEnv !== "development") {
|
|
676
|
+
return resolveLoggerConfiguration(appConfig);
|
|
677
|
+
}
|
|
678
|
+
return {
|
|
679
|
+
level: appConfig.logLevel,
|
|
680
|
+
formatters: {
|
|
681
|
+
level: (label) => {
|
|
682
|
+
return { level: label };
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
transport: {
|
|
686
|
+
target: "pino/file",
|
|
687
|
+
options: {
|
|
688
|
+
destination: appConfig.targetFile ?? "./service.log",
|
|
689
|
+
mkdir: true,
|
|
690
|
+
append: appConfig.append ?? false
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function resolveLoggerConfiguration(appConfig) {
|
|
696
|
+
const config = {
|
|
697
|
+
level: appConfig.logLevel,
|
|
698
|
+
formatters: {
|
|
699
|
+
level: (label) => {
|
|
700
|
+
return { level: label };
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
base: appConfig.base
|
|
704
|
+
};
|
|
705
|
+
if (appConfig.nodeEnv !== "production") {
|
|
706
|
+
config.transport = {
|
|
707
|
+
target: "pino-pretty",
|
|
708
|
+
options: {
|
|
709
|
+
colorize: true,
|
|
710
|
+
translateTime: "SYS:standard",
|
|
711
|
+
ignore: "hostname,pid"
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
return config;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
const globalLogger = pino.pino({
|
|
719
|
+
formatters: {
|
|
720
|
+
level: (label, numericLevel) => {
|
|
721
|
+
const level = pino.levels.labels[numericLevel] || "unknown";
|
|
722
|
+
return { level };
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
function resolveGlobalErrorLogObject(err, correlationID) {
|
|
727
|
+
if (node_util.types.isNativeError(err)) {
|
|
728
|
+
return {
|
|
729
|
+
...pino.stdSerializers.err(err),
|
|
730
|
+
correlationID
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
if (hasMessage(err)) {
|
|
734
|
+
return correlationID ? `${err.message} (${correlationID})` : err.message;
|
|
735
|
+
}
|
|
736
|
+
return "Unknown error";
|
|
737
|
+
}
|
|
738
|
+
function logGlobalErrorLogObject(logObject) {
|
|
739
|
+
if (typeof logObject === "string") {
|
|
740
|
+
globalLogger.error(`Global error: ${logObject}`);
|
|
741
|
+
} else {
|
|
742
|
+
globalLogger.error(logObject, logObject.message);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
function executeAndHandleGlobalErrors(operation) {
|
|
746
|
+
try {
|
|
747
|
+
const result = operation();
|
|
748
|
+
return result;
|
|
749
|
+
} catch (err) {
|
|
750
|
+
const logObject = resolveGlobalErrorLogObject(err);
|
|
751
|
+
logGlobalErrorLogObject(logObject);
|
|
752
|
+
process.exit(1);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
async function executeAsyncAndHandleGlobalErrors(operation, stopOnError = true) {
|
|
756
|
+
try {
|
|
757
|
+
const result = await operation();
|
|
758
|
+
return result;
|
|
759
|
+
} catch (err) {
|
|
760
|
+
const logObject = resolveGlobalErrorLogObject(err);
|
|
761
|
+
logGlobalErrorLogObject(logObject);
|
|
762
|
+
if (stopOnError) {
|
|
763
|
+
process.exit(1);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
async function executeSettleAllAndHandleGlobalErrors(promises, stopOnError = true) {
|
|
768
|
+
const result = await Promise.allSettled(promises);
|
|
769
|
+
let errorsHappened;
|
|
770
|
+
for (const entry of result) {
|
|
771
|
+
if (entry.status === "rejected") {
|
|
772
|
+
const logObject = resolveGlobalErrorLogObject(entry.reason);
|
|
773
|
+
logGlobalErrorLogObject(logObject);
|
|
774
|
+
errorsHappened = true;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (stopOnError && errorsHappened) {
|
|
778
|
+
process.exit(1);
|
|
779
|
+
}
|
|
780
|
+
return result;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
class RequestValidationError extends PublicNonRecoverableError {
|
|
784
|
+
constructor(errors) {
|
|
785
|
+
super({
|
|
786
|
+
message: "Invalid params",
|
|
787
|
+
errorCode: "VALIDATION_ERROR",
|
|
788
|
+
httpStatusCode: node_http2.constants.HTTP_STATUS_BAD_REQUEST,
|
|
789
|
+
details: {
|
|
790
|
+
error: errors
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
class AccessDeniedError extends PublicNonRecoverableError {
|
|
796
|
+
constructor(params) {
|
|
797
|
+
super({
|
|
798
|
+
message: params.message,
|
|
799
|
+
errorCode: "ACCESS_DENIED",
|
|
800
|
+
httpStatusCode: node_http2.constants.HTTP_STATUS_FORBIDDEN,
|
|
801
|
+
details: params.details
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
class EntityNotFoundError extends PublicNonRecoverableError {
|
|
806
|
+
constructor(params) {
|
|
807
|
+
super({
|
|
808
|
+
message: params.message,
|
|
809
|
+
errorCode: "ENTITY_NOT_FOUND",
|
|
810
|
+
httpStatusCode: node_http2.constants.HTTP_STATUS_NOT_FOUND,
|
|
811
|
+
details: params.details
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
class AuthFailedError extends PublicNonRecoverableError {
|
|
816
|
+
constructor(params = {}) {
|
|
817
|
+
super({
|
|
818
|
+
message: params.message ?? "Authentication failed",
|
|
819
|
+
errorCode: "AUTH_FAILED",
|
|
820
|
+
httpStatusCode: node_http2.constants.HTTP_STATUS_UNAUTHORIZED,
|
|
821
|
+
details: params.details
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
const waitAndRetry = async (predicateFn, sleepTime = 20, maxRetryCount = 15) => {
|
|
827
|
+
return new Promise((resolve, reject) => {
|
|
828
|
+
let retryCount = 0;
|
|
829
|
+
function performCheck() {
|
|
830
|
+
if (maxRetryCount !== 0 && retryCount > maxRetryCount) {
|
|
831
|
+
resolve(predicateFn());
|
|
832
|
+
}
|
|
833
|
+
Promise.resolve().then(() => {
|
|
834
|
+
return predicateFn();
|
|
835
|
+
}).then((result) => {
|
|
836
|
+
if (result) {
|
|
837
|
+
resolve(result);
|
|
838
|
+
} else {
|
|
839
|
+
retryCount++;
|
|
840
|
+
setTimeout(performCheck, sleepTime);
|
|
841
|
+
}
|
|
842
|
+
}).catch((err) => {
|
|
843
|
+
reject(err);
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
performCheck();
|
|
847
|
+
});
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
exports.AccessDeniedError = AccessDeniedError;
|
|
851
|
+
exports.AuthFailedError = AuthFailedError;
|
|
852
|
+
exports.ConfigScope = ConfigScope;
|
|
853
|
+
exports.EntityNotFoundError = EntityNotFoundError;
|
|
854
|
+
exports.InternalError = InternalError;
|
|
855
|
+
exports.PublicNonRecoverableError = PublicNonRecoverableError;
|
|
856
|
+
exports.RequestValidationError = RequestValidationError;
|
|
857
|
+
exports.ResponseStatusError = ResponseStatusError;
|
|
858
|
+
exports.buildClient = buildClient;
|
|
859
|
+
exports.callChunked = callChunked;
|
|
860
|
+
exports.chunk = chunk;
|
|
861
|
+
exports.convertDateFieldsToIsoString = convertDateFieldsToIsoString;
|
|
862
|
+
exports.copyWithoutUndefined = copyWithoutUndefined;
|
|
863
|
+
exports.createRangeValidator = createRangeValidator;
|
|
864
|
+
exports.deepClone = deepClone;
|
|
865
|
+
exports.ensureClosingSlashTransformer = ensureClosingSlashTransformer;
|
|
866
|
+
exports.executeAndHandleGlobalErrors = executeAndHandleGlobalErrors;
|
|
867
|
+
exports.executeAsyncAndHandleGlobalErrors = executeAsyncAndHandleGlobalErrors;
|
|
868
|
+
exports.executeSettleAllAndHandleGlobalErrors = executeSettleAllAndHandleGlobalErrors;
|
|
869
|
+
exports.failure = failure;
|
|
870
|
+
exports.globalLogger = globalLogger;
|
|
871
|
+
exports.groupBy = groupBy;
|
|
872
|
+
exports.groupByUnique = groupByUnique;
|
|
873
|
+
exports.hasMessage = hasMessage;
|
|
874
|
+
exports.httpClient = httpClient;
|
|
875
|
+
exports.isEmptyObject = isEmptyObject;
|
|
876
|
+
exports.isFailure = isFailure;
|
|
877
|
+
exports.isInternalError = isInternalError;
|
|
878
|
+
exports.isObject = isObject;
|
|
879
|
+
exports.isPublicNonRecoverableError = isPublicNonRecoverableError;
|
|
880
|
+
exports.isResponseStatusError = isResponseStatusError;
|
|
881
|
+
exports.isStandardizedError = isStandardizedError;
|
|
882
|
+
exports.isSuccess = isSuccess;
|
|
883
|
+
exports.pick = pick;
|
|
884
|
+
exports.pickWithoutUndefined = pickWithoutUndefined;
|
|
885
|
+
exports.removeFalsy = removeFalsy;
|
|
886
|
+
exports.removeNullish = removeNullish;
|
|
887
|
+
exports.resolveGlobalErrorLogObject = resolveGlobalErrorLogObject;
|
|
888
|
+
exports.resolveLoggerConfiguration = resolveLoggerConfiguration;
|
|
889
|
+
exports.resolveMonorepoLoggerConfiguration = resolveMonorepoLoggerConfiguration;
|
|
890
|
+
exports.sendDelete = sendDelete;
|
|
891
|
+
exports.sendGet = sendGet;
|
|
892
|
+
exports.sendPatch = sendPatch;
|
|
893
|
+
exports.sendPost = sendPost;
|
|
894
|
+
exports.sendPostBinary = sendPostBinary;
|
|
895
|
+
exports.sendPut = sendPut;
|
|
896
|
+
exports.sendPutBinary = sendPutBinary;
|
|
897
|
+
exports.success = success;
|
|
898
|
+
exports.waitAndRetry = waitAndRetry;
|