@cms0/cms0 0.2.2 → 0.2.3
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/cjs/index.cjs +305 -42
- package/dist/esm/index.js +305 -42
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -4,6 +4,11 @@ exports.createCmsClient = createCmsClient;
|
|
|
4
4
|
exports.cms0 = cms0;
|
|
5
5
|
const schema_descriptors_1 = require("@cms0/cms0/schema-descriptors");
|
|
6
6
|
const shared_1 = require("@cms0/shared");
|
|
7
|
+
const DEFAULT_REQUEST_CONCURRENCY = 6;
|
|
8
|
+
const DEFAULT_REQUEST_RETRIES = 3;
|
|
9
|
+
const DEFAULT_REQUEST_RETRY_BASE_MS = 250;
|
|
10
|
+
const DEFAULT_REQUEST_RETRY_MAX_MS = 4000;
|
|
11
|
+
const DEFAULT_MODEL_NORMALIZATION_CONCURRENCY = 8;
|
|
7
12
|
const COLLECTION_SHAPE_ERROR = "Invalid collection response. Expected array or { items, total }.";
|
|
8
13
|
function normalizeUploadsPath(uploadsPath) {
|
|
9
14
|
const raw = uploadsPath?.trim() || "/uploads";
|
|
@@ -247,6 +252,146 @@ function ensureCollectionEnvelope(data, path) {
|
|
|
247
252
|
}
|
|
248
253
|
throw new Error(`${COLLECTION_SHAPE_ERROR} Path: '${path}'.`);
|
|
249
254
|
}
|
|
255
|
+
function clampInteger(value, fallback, minimum) {
|
|
256
|
+
if (!Number.isFinite(value))
|
|
257
|
+
return fallback;
|
|
258
|
+
const normalized = Math.floor(value);
|
|
259
|
+
return normalized >= minimum ? normalized : fallback;
|
|
260
|
+
}
|
|
261
|
+
function normalizeRequestOptions(options) {
|
|
262
|
+
const concurrency = clampInteger(options?.concurrency, DEFAULT_REQUEST_CONCURRENCY, 1);
|
|
263
|
+
const retries = clampInteger(options?.retries, DEFAULT_REQUEST_RETRIES, 0);
|
|
264
|
+
const baseDelayMs = clampInteger(options?.retryBaseMs, DEFAULT_REQUEST_RETRY_BASE_MS, 1);
|
|
265
|
+
const maxDelayCandidate = clampInteger(options?.retryMaxMs, DEFAULT_REQUEST_RETRY_MAX_MS, 1);
|
|
266
|
+
const maxDelayMs = Math.max(maxDelayCandidate, baseDelayMs);
|
|
267
|
+
const modelNormalizationConcurrency = Math.max(concurrency, DEFAULT_MODEL_NORMALIZATION_CONCURRENCY);
|
|
268
|
+
return {
|
|
269
|
+
concurrency,
|
|
270
|
+
retry: {
|
|
271
|
+
retries,
|
|
272
|
+
baseDelayMs,
|
|
273
|
+
maxDelayMs,
|
|
274
|
+
},
|
|
275
|
+
modelNormalizationConcurrency,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function createAbortError() {
|
|
279
|
+
const error = new Error("The operation was aborted.");
|
|
280
|
+
error.name = "AbortError";
|
|
281
|
+
return error;
|
|
282
|
+
}
|
|
283
|
+
function isAbortError(error) {
|
|
284
|
+
return !!error && typeof error === "object" && error.name === "AbortError";
|
|
285
|
+
}
|
|
286
|
+
function waitForDelay(ms, signal) {
|
|
287
|
+
if (!Number.isFinite(ms) || ms <= 0) {
|
|
288
|
+
if (signal?.aborted)
|
|
289
|
+
return Promise.reject(createAbortError());
|
|
290
|
+
return Promise.resolve();
|
|
291
|
+
}
|
|
292
|
+
return new Promise((resolve, reject) => {
|
|
293
|
+
if (signal?.aborted) {
|
|
294
|
+
reject(createAbortError());
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const timer = setTimeout(() => {
|
|
298
|
+
signal?.removeEventListener("abort", onAbort);
|
|
299
|
+
resolve();
|
|
300
|
+
}, ms);
|
|
301
|
+
function onAbort() {
|
|
302
|
+
clearTimeout(timer);
|
|
303
|
+
signal?.removeEventListener("abort", onAbort);
|
|
304
|
+
reject(createAbortError());
|
|
305
|
+
}
|
|
306
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
function parseRetryAfterMs(retryAfterValue) {
|
|
310
|
+
if (!retryAfterValue)
|
|
311
|
+
return null;
|
|
312
|
+
const value = retryAfterValue.trim();
|
|
313
|
+
if (!value)
|
|
314
|
+
return null;
|
|
315
|
+
const seconds = Number(value);
|
|
316
|
+
if (Number.isFinite(seconds)) {
|
|
317
|
+
return Math.max(0, Math.round(seconds * 1000));
|
|
318
|
+
}
|
|
319
|
+
const at = Date.parse(value);
|
|
320
|
+
if (Number.isNaN(at))
|
|
321
|
+
return null;
|
|
322
|
+
return Math.max(0, at - Date.now());
|
|
323
|
+
}
|
|
324
|
+
function shouldRetryStatus(status) {
|
|
325
|
+
return status === 429 || (status >= 500 && status <= 599);
|
|
326
|
+
}
|
|
327
|
+
function createRequestScheduler(maxConcurrency) {
|
|
328
|
+
let active = 0;
|
|
329
|
+
const queue = [];
|
|
330
|
+
const pump = () => {
|
|
331
|
+
while (active < maxConcurrency && queue.length > 0) {
|
|
332
|
+
const next = queue.shift();
|
|
333
|
+
if (!next)
|
|
334
|
+
continue;
|
|
335
|
+
next();
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
return (task, signal) => new Promise((resolve, reject) => {
|
|
339
|
+
if (signal?.aborted) {
|
|
340
|
+
reject(createAbortError());
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
let queued = true;
|
|
344
|
+
let settled = false;
|
|
345
|
+
const run = () => {
|
|
346
|
+
if (settled)
|
|
347
|
+
return;
|
|
348
|
+
queued = false;
|
|
349
|
+
active += 1;
|
|
350
|
+
Promise.resolve()
|
|
351
|
+
.then(task)
|
|
352
|
+
.then(resolve, reject)
|
|
353
|
+
.finally(() => {
|
|
354
|
+
settled = true;
|
|
355
|
+
active = Math.max(0, active - 1);
|
|
356
|
+
signal?.removeEventListener("abort", onAbort);
|
|
357
|
+
pump();
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
const onAbort = () => {
|
|
361
|
+
if (!queued || settled)
|
|
362
|
+
return;
|
|
363
|
+
settled = true;
|
|
364
|
+
const index = queue.indexOf(run);
|
|
365
|
+
if (index >= 0) {
|
|
366
|
+
queue.splice(index, 1);
|
|
367
|
+
}
|
|
368
|
+
reject(createAbortError());
|
|
369
|
+
};
|
|
370
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
371
|
+
queue.push(run);
|
|
372
|
+
pump();
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
async function mapWithConcurrency(items, concurrency, mapper) {
|
|
376
|
+
if (items.length === 0)
|
|
377
|
+
return [];
|
|
378
|
+
const limit = Math.max(1, Math.floor(concurrency));
|
|
379
|
+
if (limit >= items.length) {
|
|
380
|
+
return Promise.all(items.map((item, index) => mapper(item, index)));
|
|
381
|
+
}
|
|
382
|
+
const results = new Array(items.length);
|
|
383
|
+
let nextIndex = 0;
|
|
384
|
+
const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
385
|
+
while (true) {
|
|
386
|
+
const current = nextIndex++;
|
|
387
|
+
if (current >= items.length)
|
|
388
|
+
break;
|
|
389
|
+
results[current] = await mapper(items[current], current);
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
await Promise.all(workers);
|
|
393
|
+
return results;
|
|
394
|
+
}
|
|
250
395
|
function extractId(value) {
|
|
251
396
|
if (typeof value === "string" && value.length > 0)
|
|
252
397
|
return value;
|
|
@@ -308,6 +453,34 @@ function extractModelRefId(raw, modelName, options) {
|
|
|
308
453
|
}
|
|
309
454
|
return null;
|
|
310
455
|
}
|
|
456
|
+
function buildModelRefCacheKey(modelName, id, context, isCollectionItem) {
|
|
457
|
+
const locale = context.options.locale ?? "";
|
|
458
|
+
const defaultLocale = context.options.defaultLocale ?? "";
|
|
459
|
+
const includeIdMode = context.options.includeIdMode;
|
|
460
|
+
const refsMode = context.options.resolveModelRefs ? "resolve" : "ids";
|
|
461
|
+
const collectionFlag = isCollectionItem ? "collection" : "single";
|
|
462
|
+
return [
|
|
463
|
+
modelName,
|
|
464
|
+
id,
|
|
465
|
+
locale,
|
|
466
|
+
defaultLocale,
|
|
467
|
+
includeIdMode,
|
|
468
|
+
refsMode,
|
|
469
|
+
collectionFlag,
|
|
470
|
+
].join("|");
|
|
471
|
+
}
|
|
472
|
+
function extractInlineModelObject(raw, modelDescriptor) {
|
|
473
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
474
|
+
return null;
|
|
475
|
+
if (!isObjectDescriptor(modelDescriptor))
|
|
476
|
+
return null;
|
|
477
|
+
const source = raw;
|
|
478
|
+
const propertyKeys = Object.keys(modelDescriptor.properties ?? {});
|
|
479
|
+
const hasModelField = propertyKeys.some((key) => key in source);
|
|
480
|
+
if (!hasModelField)
|
|
481
|
+
return null;
|
|
482
|
+
return source;
|
|
483
|
+
}
|
|
311
484
|
function formatValidationError(name, error) {
|
|
312
485
|
const payload = error && typeof error === "object" && "format" in error
|
|
313
486
|
? error.format()
|
|
@@ -356,12 +529,12 @@ function unknownKeyError(key, roots, models) {
|
|
|
356
529
|
: "";
|
|
357
530
|
throw new Error(`Unknown schema key '${key}'. ${rootsText}${modelsText}.${suggestionText}`);
|
|
358
531
|
}
|
|
359
|
-
async function normalizeModelRef(modelName, id, context, trail, isCollectionItem) {
|
|
532
|
+
async function normalizeModelRef(modelName, id, context, trail, isCollectionItem, inlineValue) {
|
|
360
533
|
if (!id)
|
|
361
534
|
return null;
|
|
362
535
|
if (!context.options.resolveModelRefs)
|
|
363
536
|
return id;
|
|
364
|
-
const nodeKey =
|
|
537
|
+
const nodeKey = buildModelRefCacheKey(modelName, id, context, isCollectionItem);
|
|
365
538
|
if (trail.has(nodeKey)) {
|
|
366
539
|
return shouldIncludeObjectId(context.options.includeIdMode, isCollectionItem)
|
|
367
540
|
? { id }
|
|
@@ -371,25 +544,37 @@ async function normalizeModelRef(modelName, id, context, trail, isCollectionItem
|
|
|
371
544
|
if (!modelDescriptor) {
|
|
372
545
|
return id;
|
|
373
546
|
}
|
|
547
|
+
const inlineModel = extractInlineModelObject(inlineValue, modelDescriptor);
|
|
374
548
|
const cached = context.modelCache.get(nodeKey);
|
|
375
549
|
if (cached) {
|
|
376
550
|
return cached;
|
|
377
551
|
}
|
|
552
|
+
const sharedInflight = context.sharedModelInflightCache.get(nodeKey);
|
|
553
|
+
if (sharedInflight) {
|
|
554
|
+
context.modelCache.set(nodeKey, sharedInflight);
|
|
555
|
+
return sharedInflight;
|
|
556
|
+
}
|
|
378
557
|
const nextTrail = new Set(trail);
|
|
379
558
|
nextTrail.add(nodeKey);
|
|
380
559
|
const promise = (async () => {
|
|
381
|
-
const rawModel =
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
560
|
+
const rawModel = inlineModel ??
|
|
561
|
+
(await context.requestJson(`models/${modelName}/${id}`, {
|
|
562
|
+
query: {
|
|
563
|
+
raw: 1,
|
|
564
|
+
...(context.options.locale ? { locale: context.options.locale } : {}),
|
|
565
|
+
},
|
|
566
|
+
}));
|
|
387
567
|
return normalizeField(modelDescriptor, `models/${modelName}/${encodeURIComponent(id)}`, rawModel, context, nextTrail, isCollectionItem);
|
|
388
|
-
})()
|
|
568
|
+
})();
|
|
569
|
+
context.modelCache.set(nodeKey, promise);
|
|
570
|
+
context.sharedModelInflightCache.set(nodeKey, promise);
|
|
571
|
+
promise
|
|
572
|
+
.then(() => undefined, () => {
|
|
389
573
|
context.modelCache.delete(nodeKey);
|
|
390
|
-
|
|
574
|
+
})
|
|
575
|
+
.finally(() => {
|
|
576
|
+
context.sharedModelInflightCache.delete(nodeKey);
|
|
391
577
|
});
|
|
392
|
-
context.modelCache.set(nodeKey, promise);
|
|
393
578
|
return promise;
|
|
394
579
|
}
|
|
395
580
|
function missingModelRefValue(descriptor) {
|
|
@@ -412,10 +597,19 @@ async function normalizeObjectField(descriptor, path, raw, context, trail, isCol
|
|
|
412
597
|
continue;
|
|
413
598
|
}
|
|
414
599
|
if (isModelRefDescriptor(propertyDescriptor)) {
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
600
|
+
const inlineValue = source[propertyName];
|
|
601
|
+
const inlineModelDescriptor = context.modelDescriptors.get(propertyDescriptor.model);
|
|
602
|
+
const inlineModel = inlineModelDescriptor
|
|
603
|
+
? extractInlineModelObject(inlineValue, inlineModelDescriptor)
|
|
604
|
+
: null;
|
|
605
|
+
const refId = extractModelRefId(inlineValue, propertyDescriptor.model, {
|
|
606
|
+
allowObjectIdFallback: true,
|
|
607
|
+
}) ??
|
|
608
|
+
(inlineModel ? extractId(inlineModel) : null) ??
|
|
609
|
+
extractModelRefId(source, propertyDescriptor.model, {
|
|
610
|
+
propertyName,
|
|
611
|
+
allowObjectIdFallback: false,
|
|
612
|
+
});
|
|
419
613
|
if (!refId) {
|
|
420
614
|
const missing = missingModelRefValue(propertyDescriptor);
|
|
421
615
|
if (missing !== undefined) {
|
|
@@ -423,7 +617,7 @@ async function normalizeObjectField(descriptor, path, raw, context, trail, isCol
|
|
|
423
617
|
}
|
|
424
618
|
continue;
|
|
425
619
|
}
|
|
426
|
-
output[propertyName] = await normalizeModelRef(propertyDescriptor.model, refId, context, trail, false);
|
|
620
|
+
output[propertyName] = await normalizeModelRef(propertyDescriptor.model, refId, context, trail, false, inlineValue);
|
|
427
621
|
continue;
|
|
428
622
|
}
|
|
429
623
|
if (isArrayDescriptor(propertyDescriptor)) {
|
|
@@ -486,22 +680,25 @@ async function normalizeArrayField(descriptor, path, raw, context, trail) {
|
|
|
486
680
|
});
|
|
487
681
|
}
|
|
488
682
|
if (isModelRefDescriptor(itemDescriptor)) {
|
|
489
|
-
const
|
|
683
|
+
const inlineModelDescriptor = context.modelDescriptors.get(itemDescriptor.model);
|
|
684
|
+
return mapWithConcurrency(envelope.items, context.options.modelNormalizationConcurrency, async (row) => {
|
|
685
|
+
const inlineModel = inlineModelDescriptor
|
|
686
|
+
? extractInlineModelObject(row, inlineModelDescriptor)
|
|
687
|
+
: null;
|
|
490
688
|
const refId = extractModelRefId(row, itemDescriptor.model, {
|
|
491
689
|
allowObjectIdFallback: false,
|
|
492
|
-
});
|
|
493
|
-
return normalizeModelRef(itemDescriptor.model, refId, context, trail, true);
|
|
494
|
-
})
|
|
495
|
-
return resolved;
|
|
690
|
+
}) ?? (inlineModel ? extractId(inlineModel) : null);
|
|
691
|
+
return normalizeModelRef(itemDescriptor.model, refId, context, trail, true, row);
|
|
692
|
+
});
|
|
496
693
|
}
|
|
497
694
|
if (isObjectDescriptor(itemDescriptor)) {
|
|
498
|
-
return
|
|
695
|
+
return mapWithConcurrency(envelope.items, context.options.modelNormalizationConcurrency, async (row) => {
|
|
499
696
|
const rowId = extractId(row);
|
|
500
697
|
const rowPath = rowId
|
|
501
698
|
? `${path}/${encodeURIComponent(rowId)}`
|
|
502
699
|
: path;
|
|
503
700
|
return normalizeObjectField(itemDescriptor, rowPath, row, context, trail, true);
|
|
504
|
-
})
|
|
701
|
+
});
|
|
505
702
|
}
|
|
506
703
|
return envelope.items;
|
|
507
704
|
}
|
|
@@ -517,11 +714,17 @@ async function normalizeField(descriptor, path, raw, context, trail, isCollectio
|
|
|
517
714
|
});
|
|
518
715
|
}
|
|
519
716
|
if (isModelRefDescriptor(descriptor)) {
|
|
520
|
-
const
|
|
717
|
+
const inlineModelDescriptor = context.modelDescriptors.get(descriptor.model);
|
|
718
|
+
const inlineModel = inlineModelDescriptor
|
|
719
|
+
? extractInlineModelObject(raw, inlineModelDescriptor)
|
|
720
|
+
: null;
|
|
721
|
+
const refId = extractModelRefId(raw, descriptor.model, {
|
|
722
|
+
allowObjectIdFallback: true,
|
|
723
|
+
}) ?? (inlineModel ? extractId(inlineModel) : null);
|
|
521
724
|
if (!refId) {
|
|
522
725
|
return missingModelRefValue(descriptor);
|
|
523
726
|
}
|
|
524
|
-
return normalizeModelRef(descriptor.model, refId, context, trail, isCollectionItem);
|
|
727
|
+
return normalizeModelRef(descriptor.model, refId, context, trail, isCollectionItem, raw);
|
|
525
728
|
}
|
|
526
729
|
if (isArrayDescriptor(descriptor)) {
|
|
527
730
|
const normalized = await normalizeArrayField(descriptor, path, raw, context, trail);
|
|
@@ -576,20 +779,71 @@ function createResourceRegistry(descriptor) {
|
|
|
576
779
|
modelsCaseInsensitive,
|
|
577
780
|
};
|
|
578
781
|
}
|
|
579
|
-
async function requestJson(baseUrl, apiKey, path, options) {
|
|
782
|
+
async function requestJson(baseUrl, apiKey, path, options, runtime) {
|
|
580
783
|
const params = buildSearchParams(options?.query);
|
|
581
784
|
const url = `${baseUrl}/${path}${params.toString() ? `?${params.toString()}` : ""}`;
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
785
|
+
const execute = async () => {
|
|
786
|
+
const retry = runtime?.retry ?? {
|
|
787
|
+
retries: DEFAULT_REQUEST_RETRIES,
|
|
788
|
+
baseDelayMs: DEFAULT_REQUEST_RETRY_BASE_MS,
|
|
789
|
+
maxDelayMs: DEFAULT_REQUEST_RETRY_MAX_MS,
|
|
790
|
+
};
|
|
791
|
+
let attempt = 0;
|
|
792
|
+
while (true) {
|
|
793
|
+
let response;
|
|
794
|
+
try {
|
|
795
|
+
response = runtime?.scheduler
|
|
796
|
+
? await runtime.scheduler(() => fetch(url, {
|
|
797
|
+
method: "GET",
|
|
798
|
+
signal: options?.signal,
|
|
799
|
+
headers: {
|
|
800
|
+
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
801
|
+
},
|
|
802
|
+
}), options?.signal)
|
|
803
|
+
: await fetch(url, {
|
|
804
|
+
method: "GET",
|
|
805
|
+
signal: options?.signal,
|
|
806
|
+
headers: {
|
|
807
|
+
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
808
|
+
},
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
catch (error) {
|
|
812
|
+
if (isAbortError(error))
|
|
813
|
+
throw error;
|
|
814
|
+
if (attempt >= retry.retries)
|
|
815
|
+
throw error;
|
|
816
|
+
const delayMs = Math.min(retry.baseDelayMs * 2 ** attempt, retry.maxDelayMs);
|
|
817
|
+
attempt += 1;
|
|
818
|
+
await waitForDelay(delayMs, options?.signal);
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
if (response.ok) {
|
|
822
|
+
return response.json();
|
|
823
|
+
}
|
|
824
|
+
const canRetry = shouldRetryStatus(response.status) && attempt < retry.retries;
|
|
825
|
+
if (!canRetry) {
|
|
826
|
+
throw new Error(`Request failed for '${path}' with status ${response.status}: ${response.statusText}`);
|
|
827
|
+
}
|
|
828
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
|
|
829
|
+
const fallbackDelay = Math.min(retry.baseDelayMs * 2 ** attempt, retry.maxDelayMs);
|
|
830
|
+
const delayMs = retryAfterMs ?? fallbackDelay;
|
|
831
|
+
attempt += 1;
|
|
832
|
+
await waitForDelay(delayMs, options?.signal);
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
const useInflightDedup = !options?.signal && !!runtime;
|
|
836
|
+
if (!useInflightDedup || !runtime) {
|
|
837
|
+
return execute();
|
|
591
838
|
}
|
|
592
|
-
|
|
839
|
+
const cached = runtime.inflightRequestCache.get(url);
|
|
840
|
+
if (cached)
|
|
841
|
+
return cached;
|
|
842
|
+
const promise = execute().finally(() => {
|
|
843
|
+
runtime.inflightRequestCache.delete(url);
|
|
844
|
+
});
|
|
845
|
+
runtime.inflightRequestCache.set(url, promise);
|
|
846
|
+
return promise;
|
|
593
847
|
}
|
|
594
848
|
function validateResult(resource, result, descriptor, includeIdMode, zodSchemas, modelZodSchemas) {
|
|
595
849
|
if (includeIdMode === "all")
|
|
@@ -624,7 +878,7 @@ function validateResult(resource, result, descriptor, includeIdMode, zodSchemas,
|
|
|
624
878
|
throw new Error(formatValidationError(modelName, parsed.error));
|
|
625
879
|
}
|
|
626
880
|
}
|
|
627
|
-
async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale, assetUrlBuilder, zodSchemas, modelZodSchemas, options, byId) {
|
|
881
|
+
async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale, assetUrlBuilder, requestRuntime, sharedModelInflightCache, modelNormalizationConcurrency, zodSchemas, modelZodSchemas, options, byId) {
|
|
628
882
|
const responseMode = options?.response ?? "normalized";
|
|
629
883
|
const includeIdMode = resolveIncludeIdMode(options?.includeId);
|
|
630
884
|
const resolveModelRefs = options?.resolveModelRefs !== false;
|
|
@@ -650,7 +904,7 @@ async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale,
|
|
|
650
904
|
const rawData = await requestJson(baseUrl, apiKey, resourcePath, {
|
|
651
905
|
query,
|
|
652
906
|
signal: options?.signal,
|
|
653
|
-
});
|
|
907
|
+
}, requestRuntime);
|
|
654
908
|
if (!shouldNormalize) {
|
|
655
909
|
return rawData;
|
|
656
910
|
}
|
|
@@ -662,15 +916,17 @@ async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale,
|
|
|
662
916
|
requestJson: (path, requestOptions) => requestJson(baseUrl, apiKey, path, {
|
|
663
917
|
...requestOptions,
|
|
664
918
|
signal: options?.signal,
|
|
665
|
-
}),
|
|
919
|
+
}, requestRuntime),
|
|
666
920
|
modelDescriptors,
|
|
667
921
|
modelCache: new Map(),
|
|
922
|
+
sharedModelInflightCache,
|
|
668
923
|
options: {
|
|
669
924
|
includeIdMode,
|
|
670
925
|
resolveModelRefs,
|
|
671
926
|
locale,
|
|
672
927
|
defaultLocale,
|
|
673
928
|
assetUrlBuilder,
|
|
929
|
+
modelNormalizationConcurrency,
|
|
674
930
|
},
|
|
675
931
|
};
|
|
676
932
|
if (resource.isCollection && !byId) {
|
|
@@ -706,9 +962,16 @@ function createCmsClient(descriptor, config) {
|
|
|
706
962
|
const rootKeys = Array.from(registry.roots.keys());
|
|
707
963
|
const modelKeys = Array.from(registry.models.keys());
|
|
708
964
|
const { zodSchemas, modelZodSchemas } = (0, shared_1.buildZodSchemasFromDescriptor)(descriptor);
|
|
965
|
+
const requestOptions = normalizeRequestOptions(config.requests);
|
|
966
|
+
const requestRuntime = {
|
|
967
|
+
scheduler: createRequestScheduler(requestOptions.concurrency),
|
|
968
|
+
inflightRequestCache: new Map(),
|
|
969
|
+
retry: requestOptions.retry,
|
|
970
|
+
};
|
|
971
|
+
const sharedModelInflightCache = new Map();
|
|
709
972
|
const buildModelAccessor = (entry) => {
|
|
710
|
-
const accessor = (async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, zodSchemas, modelZodSchemas, options));
|
|
711
|
-
accessor.byId = async (id, options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, zodSchemas, modelZodSchemas, options, id);
|
|
973
|
+
const accessor = (async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, requestRuntime, sharedModelInflightCache, requestOptions.modelNormalizationConcurrency, zodSchemas, modelZodSchemas, options));
|
|
974
|
+
accessor.byId = async (id, options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, requestRuntime, sharedModelInflightCache, requestOptions.modelNormalizationConcurrency, zodSchemas, modelZodSchemas, options, id);
|
|
712
975
|
return accessor;
|
|
713
976
|
};
|
|
714
977
|
const modelsProxy = new Proxy({}, {
|
|
@@ -738,7 +1001,7 @@ function createCmsClient(descriptor, config) {
|
|
|
738
1001
|
if (!entry) {
|
|
739
1002
|
unknownKeyError(property, rootKeys, []);
|
|
740
1003
|
}
|
|
741
|
-
return async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, zodSchemas, modelZodSchemas, options);
|
|
1004
|
+
return async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, requestRuntime, sharedModelInflightCache, requestOptions.modelNormalizationConcurrency, zodSchemas, modelZodSchemas, options);
|
|
742
1005
|
},
|
|
743
1006
|
});
|
|
744
1007
|
return rootProxy;
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { schemaDescriptor } from "@cms0/cms0/schema-descriptors";
|
|
2
2
|
import { buildZodSchemasFromDescriptor, } from "@cms0/shared";
|
|
3
|
+
const DEFAULT_REQUEST_CONCURRENCY = 6;
|
|
4
|
+
const DEFAULT_REQUEST_RETRIES = 3;
|
|
5
|
+
const DEFAULT_REQUEST_RETRY_BASE_MS = 250;
|
|
6
|
+
const DEFAULT_REQUEST_RETRY_MAX_MS = 4000;
|
|
7
|
+
const DEFAULT_MODEL_NORMALIZATION_CONCURRENCY = 8;
|
|
3
8
|
const COLLECTION_SHAPE_ERROR = "Invalid collection response. Expected array or { items, total }.";
|
|
4
9
|
function normalizeUploadsPath(uploadsPath) {
|
|
5
10
|
const raw = uploadsPath?.trim() || "/uploads";
|
|
@@ -243,6 +248,146 @@ function ensureCollectionEnvelope(data, path) {
|
|
|
243
248
|
}
|
|
244
249
|
throw new Error(`${COLLECTION_SHAPE_ERROR} Path: '${path}'.`);
|
|
245
250
|
}
|
|
251
|
+
function clampInteger(value, fallback, minimum) {
|
|
252
|
+
if (!Number.isFinite(value))
|
|
253
|
+
return fallback;
|
|
254
|
+
const normalized = Math.floor(value);
|
|
255
|
+
return normalized >= minimum ? normalized : fallback;
|
|
256
|
+
}
|
|
257
|
+
function normalizeRequestOptions(options) {
|
|
258
|
+
const concurrency = clampInteger(options?.concurrency, DEFAULT_REQUEST_CONCURRENCY, 1);
|
|
259
|
+
const retries = clampInteger(options?.retries, DEFAULT_REQUEST_RETRIES, 0);
|
|
260
|
+
const baseDelayMs = clampInteger(options?.retryBaseMs, DEFAULT_REQUEST_RETRY_BASE_MS, 1);
|
|
261
|
+
const maxDelayCandidate = clampInteger(options?.retryMaxMs, DEFAULT_REQUEST_RETRY_MAX_MS, 1);
|
|
262
|
+
const maxDelayMs = Math.max(maxDelayCandidate, baseDelayMs);
|
|
263
|
+
const modelNormalizationConcurrency = Math.max(concurrency, DEFAULT_MODEL_NORMALIZATION_CONCURRENCY);
|
|
264
|
+
return {
|
|
265
|
+
concurrency,
|
|
266
|
+
retry: {
|
|
267
|
+
retries,
|
|
268
|
+
baseDelayMs,
|
|
269
|
+
maxDelayMs,
|
|
270
|
+
},
|
|
271
|
+
modelNormalizationConcurrency,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function createAbortError() {
|
|
275
|
+
const error = new Error("The operation was aborted.");
|
|
276
|
+
error.name = "AbortError";
|
|
277
|
+
return error;
|
|
278
|
+
}
|
|
279
|
+
function isAbortError(error) {
|
|
280
|
+
return !!error && typeof error === "object" && error.name === "AbortError";
|
|
281
|
+
}
|
|
282
|
+
function waitForDelay(ms, signal) {
|
|
283
|
+
if (!Number.isFinite(ms) || ms <= 0) {
|
|
284
|
+
if (signal?.aborted)
|
|
285
|
+
return Promise.reject(createAbortError());
|
|
286
|
+
return Promise.resolve();
|
|
287
|
+
}
|
|
288
|
+
return new Promise((resolve, reject) => {
|
|
289
|
+
if (signal?.aborted) {
|
|
290
|
+
reject(createAbortError());
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const timer = setTimeout(() => {
|
|
294
|
+
signal?.removeEventListener("abort", onAbort);
|
|
295
|
+
resolve();
|
|
296
|
+
}, ms);
|
|
297
|
+
function onAbort() {
|
|
298
|
+
clearTimeout(timer);
|
|
299
|
+
signal?.removeEventListener("abort", onAbort);
|
|
300
|
+
reject(createAbortError());
|
|
301
|
+
}
|
|
302
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
function parseRetryAfterMs(retryAfterValue) {
|
|
306
|
+
if (!retryAfterValue)
|
|
307
|
+
return null;
|
|
308
|
+
const value = retryAfterValue.trim();
|
|
309
|
+
if (!value)
|
|
310
|
+
return null;
|
|
311
|
+
const seconds = Number(value);
|
|
312
|
+
if (Number.isFinite(seconds)) {
|
|
313
|
+
return Math.max(0, Math.round(seconds * 1000));
|
|
314
|
+
}
|
|
315
|
+
const at = Date.parse(value);
|
|
316
|
+
if (Number.isNaN(at))
|
|
317
|
+
return null;
|
|
318
|
+
return Math.max(0, at - Date.now());
|
|
319
|
+
}
|
|
320
|
+
function shouldRetryStatus(status) {
|
|
321
|
+
return status === 429 || (status >= 500 && status <= 599);
|
|
322
|
+
}
|
|
323
|
+
function createRequestScheduler(maxConcurrency) {
|
|
324
|
+
let active = 0;
|
|
325
|
+
const queue = [];
|
|
326
|
+
const pump = () => {
|
|
327
|
+
while (active < maxConcurrency && queue.length > 0) {
|
|
328
|
+
const next = queue.shift();
|
|
329
|
+
if (!next)
|
|
330
|
+
continue;
|
|
331
|
+
next();
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
return (task, signal) => new Promise((resolve, reject) => {
|
|
335
|
+
if (signal?.aborted) {
|
|
336
|
+
reject(createAbortError());
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
let queued = true;
|
|
340
|
+
let settled = false;
|
|
341
|
+
const run = () => {
|
|
342
|
+
if (settled)
|
|
343
|
+
return;
|
|
344
|
+
queued = false;
|
|
345
|
+
active += 1;
|
|
346
|
+
Promise.resolve()
|
|
347
|
+
.then(task)
|
|
348
|
+
.then(resolve, reject)
|
|
349
|
+
.finally(() => {
|
|
350
|
+
settled = true;
|
|
351
|
+
active = Math.max(0, active - 1);
|
|
352
|
+
signal?.removeEventListener("abort", onAbort);
|
|
353
|
+
pump();
|
|
354
|
+
});
|
|
355
|
+
};
|
|
356
|
+
const onAbort = () => {
|
|
357
|
+
if (!queued || settled)
|
|
358
|
+
return;
|
|
359
|
+
settled = true;
|
|
360
|
+
const index = queue.indexOf(run);
|
|
361
|
+
if (index >= 0) {
|
|
362
|
+
queue.splice(index, 1);
|
|
363
|
+
}
|
|
364
|
+
reject(createAbortError());
|
|
365
|
+
};
|
|
366
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
367
|
+
queue.push(run);
|
|
368
|
+
pump();
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
async function mapWithConcurrency(items, concurrency, mapper) {
|
|
372
|
+
if (items.length === 0)
|
|
373
|
+
return [];
|
|
374
|
+
const limit = Math.max(1, Math.floor(concurrency));
|
|
375
|
+
if (limit >= items.length) {
|
|
376
|
+
return Promise.all(items.map((item, index) => mapper(item, index)));
|
|
377
|
+
}
|
|
378
|
+
const results = new Array(items.length);
|
|
379
|
+
let nextIndex = 0;
|
|
380
|
+
const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
381
|
+
while (true) {
|
|
382
|
+
const current = nextIndex++;
|
|
383
|
+
if (current >= items.length)
|
|
384
|
+
break;
|
|
385
|
+
results[current] = await mapper(items[current], current);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
await Promise.all(workers);
|
|
389
|
+
return results;
|
|
390
|
+
}
|
|
246
391
|
function extractId(value) {
|
|
247
392
|
if (typeof value === "string" && value.length > 0)
|
|
248
393
|
return value;
|
|
@@ -304,6 +449,34 @@ function extractModelRefId(raw, modelName, options) {
|
|
|
304
449
|
}
|
|
305
450
|
return null;
|
|
306
451
|
}
|
|
452
|
+
function buildModelRefCacheKey(modelName, id, context, isCollectionItem) {
|
|
453
|
+
const locale = context.options.locale ?? "";
|
|
454
|
+
const defaultLocale = context.options.defaultLocale ?? "";
|
|
455
|
+
const includeIdMode = context.options.includeIdMode;
|
|
456
|
+
const refsMode = context.options.resolveModelRefs ? "resolve" : "ids";
|
|
457
|
+
const collectionFlag = isCollectionItem ? "collection" : "single";
|
|
458
|
+
return [
|
|
459
|
+
modelName,
|
|
460
|
+
id,
|
|
461
|
+
locale,
|
|
462
|
+
defaultLocale,
|
|
463
|
+
includeIdMode,
|
|
464
|
+
refsMode,
|
|
465
|
+
collectionFlag,
|
|
466
|
+
].join("|");
|
|
467
|
+
}
|
|
468
|
+
function extractInlineModelObject(raw, modelDescriptor) {
|
|
469
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
470
|
+
return null;
|
|
471
|
+
if (!isObjectDescriptor(modelDescriptor))
|
|
472
|
+
return null;
|
|
473
|
+
const source = raw;
|
|
474
|
+
const propertyKeys = Object.keys(modelDescriptor.properties ?? {});
|
|
475
|
+
const hasModelField = propertyKeys.some((key) => key in source);
|
|
476
|
+
if (!hasModelField)
|
|
477
|
+
return null;
|
|
478
|
+
return source;
|
|
479
|
+
}
|
|
307
480
|
function formatValidationError(name, error) {
|
|
308
481
|
const payload = error && typeof error === "object" && "format" in error
|
|
309
482
|
? error.format()
|
|
@@ -352,12 +525,12 @@ function unknownKeyError(key, roots, models) {
|
|
|
352
525
|
: "";
|
|
353
526
|
throw new Error(`Unknown schema key '${key}'. ${rootsText}${modelsText}.${suggestionText}`);
|
|
354
527
|
}
|
|
355
|
-
async function normalizeModelRef(modelName, id, context, trail, isCollectionItem) {
|
|
528
|
+
async function normalizeModelRef(modelName, id, context, trail, isCollectionItem, inlineValue) {
|
|
356
529
|
if (!id)
|
|
357
530
|
return null;
|
|
358
531
|
if (!context.options.resolveModelRefs)
|
|
359
532
|
return id;
|
|
360
|
-
const nodeKey =
|
|
533
|
+
const nodeKey = buildModelRefCacheKey(modelName, id, context, isCollectionItem);
|
|
361
534
|
if (trail.has(nodeKey)) {
|
|
362
535
|
return shouldIncludeObjectId(context.options.includeIdMode, isCollectionItem)
|
|
363
536
|
? { id }
|
|
@@ -367,25 +540,37 @@ async function normalizeModelRef(modelName, id, context, trail, isCollectionItem
|
|
|
367
540
|
if (!modelDescriptor) {
|
|
368
541
|
return id;
|
|
369
542
|
}
|
|
543
|
+
const inlineModel = extractInlineModelObject(inlineValue, modelDescriptor);
|
|
370
544
|
const cached = context.modelCache.get(nodeKey);
|
|
371
545
|
if (cached) {
|
|
372
546
|
return cached;
|
|
373
547
|
}
|
|
548
|
+
const sharedInflight = context.sharedModelInflightCache.get(nodeKey);
|
|
549
|
+
if (sharedInflight) {
|
|
550
|
+
context.modelCache.set(nodeKey, sharedInflight);
|
|
551
|
+
return sharedInflight;
|
|
552
|
+
}
|
|
374
553
|
const nextTrail = new Set(trail);
|
|
375
554
|
nextTrail.add(nodeKey);
|
|
376
555
|
const promise = (async () => {
|
|
377
|
-
const rawModel =
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
556
|
+
const rawModel = inlineModel ??
|
|
557
|
+
(await context.requestJson(`models/${modelName}/${id}`, {
|
|
558
|
+
query: {
|
|
559
|
+
raw: 1,
|
|
560
|
+
...(context.options.locale ? { locale: context.options.locale } : {}),
|
|
561
|
+
},
|
|
562
|
+
}));
|
|
383
563
|
return normalizeField(modelDescriptor, `models/${modelName}/${encodeURIComponent(id)}`, rawModel, context, nextTrail, isCollectionItem);
|
|
384
|
-
})()
|
|
564
|
+
})();
|
|
565
|
+
context.modelCache.set(nodeKey, promise);
|
|
566
|
+
context.sharedModelInflightCache.set(nodeKey, promise);
|
|
567
|
+
promise
|
|
568
|
+
.then(() => undefined, () => {
|
|
385
569
|
context.modelCache.delete(nodeKey);
|
|
386
|
-
|
|
570
|
+
})
|
|
571
|
+
.finally(() => {
|
|
572
|
+
context.sharedModelInflightCache.delete(nodeKey);
|
|
387
573
|
});
|
|
388
|
-
context.modelCache.set(nodeKey, promise);
|
|
389
574
|
return promise;
|
|
390
575
|
}
|
|
391
576
|
function missingModelRefValue(descriptor) {
|
|
@@ -408,10 +593,19 @@ async function normalizeObjectField(descriptor, path, raw, context, trail, isCol
|
|
|
408
593
|
continue;
|
|
409
594
|
}
|
|
410
595
|
if (isModelRefDescriptor(propertyDescriptor)) {
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
596
|
+
const inlineValue = source[propertyName];
|
|
597
|
+
const inlineModelDescriptor = context.modelDescriptors.get(propertyDescriptor.model);
|
|
598
|
+
const inlineModel = inlineModelDescriptor
|
|
599
|
+
? extractInlineModelObject(inlineValue, inlineModelDescriptor)
|
|
600
|
+
: null;
|
|
601
|
+
const refId = extractModelRefId(inlineValue, propertyDescriptor.model, {
|
|
602
|
+
allowObjectIdFallback: true,
|
|
603
|
+
}) ??
|
|
604
|
+
(inlineModel ? extractId(inlineModel) : null) ??
|
|
605
|
+
extractModelRefId(source, propertyDescriptor.model, {
|
|
606
|
+
propertyName,
|
|
607
|
+
allowObjectIdFallback: false,
|
|
608
|
+
});
|
|
415
609
|
if (!refId) {
|
|
416
610
|
const missing = missingModelRefValue(propertyDescriptor);
|
|
417
611
|
if (missing !== undefined) {
|
|
@@ -419,7 +613,7 @@ async function normalizeObjectField(descriptor, path, raw, context, trail, isCol
|
|
|
419
613
|
}
|
|
420
614
|
continue;
|
|
421
615
|
}
|
|
422
|
-
output[propertyName] = await normalizeModelRef(propertyDescriptor.model, refId, context, trail, false);
|
|
616
|
+
output[propertyName] = await normalizeModelRef(propertyDescriptor.model, refId, context, trail, false, inlineValue);
|
|
423
617
|
continue;
|
|
424
618
|
}
|
|
425
619
|
if (isArrayDescriptor(propertyDescriptor)) {
|
|
@@ -482,22 +676,25 @@ async function normalizeArrayField(descriptor, path, raw, context, trail) {
|
|
|
482
676
|
});
|
|
483
677
|
}
|
|
484
678
|
if (isModelRefDescriptor(itemDescriptor)) {
|
|
485
|
-
const
|
|
679
|
+
const inlineModelDescriptor = context.modelDescriptors.get(itemDescriptor.model);
|
|
680
|
+
return mapWithConcurrency(envelope.items, context.options.modelNormalizationConcurrency, async (row) => {
|
|
681
|
+
const inlineModel = inlineModelDescriptor
|
|
682
|
+
? extractInlineModelObject(row, inlineModelDescriptor)
|
|
683
|
+
: null;
|
|
486
684
|
const refId = extractModelRefId(row, itemDescriptor.model, {
|
|
487
685
|
allowObjectIdFallback: false,
|
|
488
|
-
});
|
|
489
|
-
return normalizeModelRef(itemDescriptor.model, refId, context, trail, true);
|
|
490
|
-
})
|
|
491
|
-
return resolved;
|
|
686
|
+
}) ?? (inlineModel ? extractId(inlineModel) : null);
|
|
687
|
+
return normalizeModelRef(itemDescriptor.model, refId, context, trail, true, row);
|
|
688
|
+
});
|
|
492
689
|
}
|
|
493
690
|
if (isObjectDescriptor(itemDescriptor)) {
|
|
494
|
-
return
|
|
691
|
+
return mapWithConcurrency(envelope.items, context.options.modelNormalizationConcurrency, async (row) => {
|
|
495
692
|
const rowId = extractId(row);
|
|
496
693
|
const rowPath = rowId
|
|
497
694
|
? `${path}/${encodeURIComponent(rowId)}`
|
|
498
695
|
: path;
|
|
499
696
|
return normalizeObjectField(itemDescriptor, rowPath, row, context, trail, true);
|
|
500
|
-
})
|
|
697
|
+
});
|
|
501
698
|
}
|
|
502
699
|
return envelope.items;
|
|
503
700
|
}
|
|
@@ -513,11 +710,17 @@ async function normalizeField(descriptor, path, raw, context, trail, isCollectio
|
|
|
513
710
|
});
|
|
514
711
|
}
|
|
515
712
|
if (isModelRefDescriptor(descriptor)) {
|
|
516
|
-
const
|
|
713
|
+
const inlineModelDescriptor = context.modelDescriptors.get(descriptor.model);
|
|
714
|
+
const inlineModel = inlineModelDescriptor
|
|
715
|
+
? extractInlineModelObject(raw, inlineModelDescriptor)
|
|
716
|
+
: null;
|
|
717
|
+
const refId = extractModelRefId(raw, descriptor.model, {
|
|
718
|
+
allowObjectIdFallback: true,
|
|
719
|
+
}) ?? (inlineModel ? extractId(inlineModel) : null);
|
|
517
720
|
if (!refId) {
|
|
518
721
|
return missingModelRefValue(descriptor);
|
|
519
722
|
}
|
|
520
|
-
return normalizeModelRef(descriptor.model, refId, context, trail, isCollectionItem);
|
|
723
|
+
return normalizeModelRef(descriptor.model, refId, context, trail, isCollectionItem, raw);
|
|
521
724
|
}
|
|
522
725
|
if (isArrayDescriptor(descriptor)) {
|
|
523
726
|
const normalized = await normalizeArrayField(descriptor, path, raw, context, trail);
|
|
@@ -572,20 +775,71 @@ function createResourceRegistry(descriptor) {
|
|
|
572
775
|
modelsCaseInsensitive,
|
|
573
776
|
};
|
|
574
777
|
}
|
|
575
|
-
async function requestJson(baseUrl, apiKey, path, options) {
|
|
778
|
+
async function requestJson(baseUrl, apiKey, path, options, runtime) {
|
|
576
779
|
const params = buildSearchParams(options?.query);
|
|
577
780
|
const url = `${baseUrl}/${path}${params.toString() ? `?${params.toString()}` : ""}`;
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
781
|
+
const execute = async () => {
|
|
782
|
+
const retry = runtime?.retry ?? {
|
|
783
|
+
retries: DEFAULT_REQUEST_RETRIES,
|
|
784
|
+
baseDelayMs: DEFAULT_REQUEST_RETRY_BASE_MS,
|
|
785
|
+
maxDelayMs: DEFAULT_REQUEST_RETRY_MAX_MS,
|
|
786
|
+
};
|
|
787
|
+
let attempt = 0;
|
|
788
|
+
while (true) {
|
|
789
|
+
let response;
|
|
790
|
+
try {
|
|
791
|
+
response = runtime?.scheduler
|
|
792
|
+
? await runtime.scheduler(() => fetch(url, {
|
|
793
|
+
method: "GET",
|
|
794
|
+
signal: options?.signal,
|
|
795
|
+
headers: {
|
|
796
|
+
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
797
|
+
},
|
|
798
|
+
}), options?.signal)
|
|
799
|
+
: await fetch(url, {
|
|
800
|
+
method: "GET",
|
|
801
|
+
signal: options?.signal,
|
|
802
|
+
headers: {
|
|
803
|
+
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
804
|
+
},
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
catch (error) {
|
|
808
|
+
if (isAbortError(error))
|
|
809
|
+
throw error;
|
|
810
|
+
if (attempt >= retry.retries)
|
|
811
|
+
throw error;
|
|
812
|
+
const delayMs = Math.min(retry.baseDelayMs * 2 ** attempt, retry.maxDelayMs);
|
|
813
|
+
attempt += 1;
|
|
814
|
+
await waitForDelay(delayMs, options?.signal);
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
if (response.ok) {
|
|
818
|
+
return response.json();
|
|
819
|
+
}
|
|
820
|
+
const canRetry = shouldRetryStatus(response.status) && attempt < retry.retries;
|
|
821
|
+
if (!canRetry) {
|
|
822
|
+
throw new Error(`Request failed for '${path}' with status ${response.status}: ${response.statusText}`);
|
|
823
|
+
}
|
|
824
|
+
const retryAfterMs = parseRetryAfterMs(response.headers.get("retry-after"));
|
|
825
|
+
const fallbackDelay = Math.min(retry.baseDelayMs * 2 ** attempt, retry.maxDelayMs);
|
|
826
|
+
const delayMs = retryAfterMs ?? fallbackDelay;
|
|
827
|
+
attempt += 1;
|
|
828
|
+
await waitForDelay(delayMs, options?.signal);
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
const useInflightDedup = !options?.signal && !!runtime;
|
|
832
|
+
if (!useInflightDedup || !runtime) {
|
|
833
|
+
return execute();
|
|
587
834
|
}
|
|
588
|
-
|
|
835
|
+
const cached = runtime.inflightRequestCache.get(url);
|
|
836
|
+
if (cached)
|
|
837
|
+
return cached;
|
|
838
|
+
const promise = execute().finally(() => {
|
|
839
|
+
runtime.inflightRequestCache.delete(url);
|
|
840
|
+
});
|
|
841
|
+
runtime.inflightRequestCache.set(url, promise);
|
|
842
|
+
return promise;
|
|
589
843
|
}
|
|
590
844
|
function validateResult(resource, result, descriptor, includeIdMode, zodSchemas, modelZodSchemas) {
|
|
591
845
|
if (includeIdMode === "all")
|
|
@@ -620,7 +874,7 @@ function validateResult(resource, result, descriptor, includeIdMode, zodSchemas,
|
|
|
620
874
|
throw new Error(formatValidationError(modelName, parsed.error));
|
|
621
875
|
}
|
|
622
876
|
}
|
|
623
|
-
async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale, assetUrlBuilder, zodSchemas, modelZodSchemas, options, byId) {
|
|
877
|
+
async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale, assetUrlBuilder, requestRuntime, sharedModelInflightCache, modelNormalizationConcurrency, zodSchemas, modelZodSchemas, options, byId) {
|
|
624
878
|
const responseMode = options?.response ?? "normalized";
|
|
625
879
|
const includeIdMode = resolveIncludeIdMode(options?.includeId);
|
|
626
880
|
const resolveModelRefs = options?.resolveModelRefs !== false;
|
|
@@ -646,7 +900,7 @@ async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale,
|
|
|
646
900
|
const rawData = await requestJson(baseUrl, apiKey, resourcePath, {
|
|
647
901
|
query,
|
|
648
902
|
signal: options?.signal,
|
|
649
|
-
});
|
|
903
|
+
}, requestRuntime);
|
|
650
904
|
if (!shouldNormalize) {
|
|
651
905
|
return rawData;
|
|
652
906
|
}
|
|
@@ -658,15 +912,17 @@ async function runResource(resource, descriptor, baseUrl, apiKey, defaultLocale,
|
|
|
658
912
|
requestJson: (path, requestOptions) => requestJson(baseUrl, apiKey, path, {
|
|
659
913
|
...requestOptions,
|
|
660
914
|
signal: options?.signal,
|
|
661
|
-
}),
|
|
915
|
+
}, requestRuntime),
|
|
662
916
|
modelDescriptors,
|
|
663
917
|
modelCache: new Map(),
|
|
918
|
+
sharedModelInflightCache,
|
|
664
919
|
options: {
|
|
665
920
|
includeIdMode,
|
|
666
921
|
resolveModelRefs,
|
|
667
922
|
locale,
|
|
668
923
|
defaultLocale,
|
|
669
924
|
assetUrlBuilder,
|
|
925
|
+
modelNormalizationConcurrency,
|
|
670
926
|
},
|
|
671
927
|
};
|
|
672
928
|
if (resource.isCollection && !byId) {
|
|
@@ -702,9 +958,16 @@ export function createCmsClient(descriptor, config) {
|
|
|
702
958
|
const rootKeys = Array.from(registry.roots.keys());
|
|
703
959
|
const modelKeys = Array.from(registry.models.keys());
|
|
704
960
|
const { zodSchemas, modelZodSchemas } = buildZodSchemasFromDescriptor(descriptor);
|
|
961
|
+
const requestOptions = normalizeRequestOptions(config.requests);
|
|
962
|
+
const requestRuntime = {
|
|
963
|
+
scheduler: createRequestScheduler(requestOptions.concurrency),
|
|
964
|
+
inflightRequestCache: new Map(),
|
|
965
|
+
retry: requestOptions.retry,
|
|
966
|
+
};
|
|
967
|
+
const sharedModelInflightCache = new Map();
|
|
705
968
|
const buildModelAccessor = (entry) => {
|
|
706
|
-
const accessor = (async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, zodSchemas, modelZodSchemas, options));
|
|
707
|
-
accessor.byId = async (id, options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, zodSchemas, modelZodSchemas, options, id);
|
|
969
|
+
const accessor = (async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, requestRuntime, sharedModelInflightCache, requestOptions.modelNormalizationConcurrency, zodSchemas, modelZodSchemas, options));
|
|
970
|
+
accessor.byId = async (id, options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, requestRuntime, sharedModelInflightCache, requestOptions.modelNormalizationConcurrency, zodSchemas, modelZodSchemas, options, id);
|
|
708
971
|
return accessor;
|
|
709
972
|
};
|
|
710
973
|
const modelsProxy = new Proxy({}, {
|
|
@@ -734,7 +997,7 @@ export function createCmsClient(descriptor, config) {
|
|
|
734
997
|
if (!entry) {
|
|
735
998
|
unknownKeyError(property, rootKeys, []);
|
|
736
999
|
}
|
|
737
|
-
return async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, zodSchemas, modelZodSchemas, options);
|
|
1000
|
+
return async (options) => runResource(entry, descriptor, baseUrl, apiKey, config.defaultLocale, assetUrlBuilder, requestRuntime, sharedModelInflightCache, requestOptions.modelNormalizationConcurrency, zodSchemas, modelZodSchemas, options);
|
|
738
1001
|
},
|
|
739
1002
|
});
|
|
740
1003
|
return rootProxy;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -10,6 +10,12 @@ export interface CmsAssetOptions {
|
|
|
10
10
|
baseUrl?: string;
|
|
11
11
|
uploadsPath?: string;
|
|
12
12
|
}
|
|
13
|
+
export interface CmsRequestOptions {
|
|
14
|
+
concurrency?: number;
|
|
15
|
+
retries?: number;
|
|
16
|
+
retryBaseMs?: number;
|
|
17
|
+
retryMaxMs?: number;
|
|
18
|
+
}
|
|
13
19
|
export interface CmsAccessorOptions {
|
|
14
20
|
query?: CmsQuery;
|
|
15
21
|
response?: CmsResponseMode;
|
|
@@ -70,6 +76,7 @@ export interface Cms0Options {
|
|
|
70
76
|
locales?: string[];
|
|
71
77
|
defaultLocale?: string;
|
|
72
78
|
assets?: CmsAssetOptions;
|
|
79
|
+
requests?: CmsRequestOptions;
|
|
73
80
|
}
|
|
74
81
|
type PrimitiveValueFromDescriptor<TypeName extends string> = TypeName extends "string" ? string : TypeName extends "number" ? number : TypeName extends "boolean" ? boolean : any;
|
|
75
82
|
type CustomTypeValueFromDescriptor<TypeName extends string> = TypeName extends "RichText" ? CmsRichText : TypeName extends "LocalizedString" ? CmsLocalizedString : TypeName extends "LocalizedRichText" ? CmsLocalizedRichText : never;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|