@riverbankcms/sdk 0.6.1 → 0.7.2
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 +175 -0
- package/dist/cli/index.js +42 -95
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init-docs/content/agents-section.md +50 -0
- package/dist/cli/init-docs/content/cli-reference.md +574 -0
- package/dist/cli/init-docs/content/content-management.md +384 -0
- package/dist/cli/init-docs/content/context-brand.md +125 -0
- package/dist/cli/init-docs/content/context-brief.md +77 -0
- package/dist/cli/init-docs/content/context-knowledge.md +111 -0
- package/dist/cli/init-docs/content/getting-started.md +130 -0
- package/dist/cli/init-docs/content/site-workflows-readme.md +96 -0
- package/dist/cli/init-docs/content/workflow-add-block.md +228 -0
- package/dist/cli/init-docs/content/workflow-create-page.md +193 -0
- package/dist/cli/init-docs/content/workflow-publish.md +280 -0
- package/dist/client/client.d.mts +2 -2
- package/dist/client/client.d.ts +2 -2
- package/dist/client/client.js +536 -71
- package/dist/client/client.js.map +1 -1
- package/dist/client/client.mjs +536 -78
- package/dist/client/client.mjs.map +1 -1
- package/dist/client/hooks.d.mts +2 -2
- package/dist/client/hooks.d.ts +2 -2
- package/dist/client/usePage-C9tJpuKa.d.mts +6813 -0
- package/dist/client/usePage-Db9kzA41.d.ts +6813 -0
- package/dist/server/{Layout-wBtJLTVX.d.ts → Layout-Ce7PU9I5.d.ts} +1 -1
- package/dist/server/{Layout-B7cvis7r.d.mts → Layout-WllR8Zug.d.mts} +1 -1
- package/dist/server/{chunk-I7ZR2WO3.mjs → chunk-5JT452F2.mjs} +537 -76
- package/dist/server/chunk-5JT452F2.mjs.map +1 -0
- package/dist/server/{chunk-Z5ZA6Q4D.mjs → chunk-74XUVNOO.mjs} +5 -3
- package/dist/server/chunk-74XUVNOO.mjs.map +1 -0
- package/dist/server/{chunk-3B364WO2.js → chunk-7BVRA5MY.js} +4 -49
- package/dist/server/chunk-7BVRA5MY.js.map +1 -0
- package/dist/server/chunk-AET56TQX.mjs +45 -0
- package/dist/server/chunk-AET56TQX.mjs.map +1 -0
- package/dist/server/chunk-ARNCLSQT.mjs +52 -0
- package/dist/server/chunk-ARNCLSQT.mjs.map +1 -0
- package/dist/server/chunk-BNQV3PXP.js +69 -0
- package/dist/server/chunk-BNQV3PXP.js.map +1 -0
- package/dist/server/{chunk-IVHIQFJH.js → chunk-HMENX4Y7.js} +543 -82
- package/dist/server/chunk-HMENX4Y7.js.map +1 -0
- package/dist/server/{chunk-I2D7KOEA.js → chunk-JWRNMNWI.js} +5 -3
- package/dist/server/chunk-JWRNMNWI.js.map +1 -0
- package/dist/server/chunk-LQUKXIW7.mjs +13 -0
- package/dist/server/chunk-LQUKXIW7.mjs.map +1 -0
- package/dist/server/{chunk-XXFF4RVR.mjs → chunk-RBJFXNDM.mjs} +1 -46
- package/dist/server/chunk-RBJFXNDM.mjs.map +1 -0
- package/dist/server/chunk-SWYWZT3L.mjs +69 -0
- package/dist/server/chunk-SWYWZT3L.mjs.map +1 -0
- package/dist/server/chunk-T26N3P26.js +52 -0
- package/dist/server/chunk-T26N3P26.js.map +1 -0
- package/dist/server/chunk-VODFQMUW.js +45 -0
- package/dist/server/chunk-VODFQMUW.js.map +1 -0
- package/dist/server/chunk-WYNEYDXO.js +13 -0
- package/dist/server/chunk-WYNEYDXO.js.map +1 -0
- package/dist/server/{components-CICSJyp_.d.ts → components--LT61IKp.d.ts} +2 -2
- package/dist/server/{components-CMMwDXTW.d.mts → components-RPzRQve6.d.mts} +2 -2
- package/dist/server/components.d.mts +4 -4
- package/dist/server/components.d.ts +4 -4
- package/dist/server/components.js +5 -4
- package/dist/server/components.js.map +1 -1
- package/dist/server/components.mjs +5 -4
- package/dist/server/config-validation.js +0 -1
- package/dist/server/config-validation.js.map +1 -1
- package/dist/server/config-validation.mjs +0 -1
- package/dist/server/config.js +0 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +0 -1
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/data.d.mts +1 -1
- package/dist/server/data.d.ts +1 -1
- package/dist/server/data.js +0 -1
- package/dist/server/data.js.map +1 -1
- package/dist/server/data.mjs +0 -1
- package/dist/server/env.d.mts +23 -0
- package/dist/server/env.d.ts +23 -0
- package/dist/server/env.js +7 -0
- package/dist/server/env.js.map +1 -0
- package/dist/server/env.mjs +7 -0
- package/dist/server/index-BL66CU6d.d.mts +130 -0
- package/dist/server/{index-Bucs6UqG.d.mts → index-Bkva0WAj.d.mts} +1 -1
- package/dist/server/index-CJk9iQQW.d.ts +130 -0
- package/dist/server/{index-Cp7tJuRt.d.ts → index-CSBWKA3r.d.ts} +1 -1
- package/dist/server/index.d.mts +3 -3
- package/dist/server/index.d.ts +3 -3
- package/dist/server/index.js +2 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1 -2
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/{loadContent-Buvmudee.d.ts → loadContent-CXUWMuzY.d.ts} +11 -3
- package/dist/server/{loadContent-BS-3wesN.d.mts → loadContent-F_tAS0Nl.d.mts} +11 -3
- package/dist/server/{loadPage-IDGVDFBB.js → loadPage-6I7F6GRF.js} +1 -2
- package/dist/server/loadPage-6I7F6GRF.js.map +1 -0
- package/dist/server/{loadPage-B8mQUUSo.d.mts → loadPage-CxlYLe5K.d.mts} +1 -1
- package/dist/server/{loadPage-DNQTTRHL.mjs → loadPage-JI2SML4M.mjs} +1 -2
- package/dist/server/{loadPage-DP3nrHBi.d.ts → loadPage-i2r-X5b9.d.ts} +1 -1
- package/dist/server/metadata.d.mts +8 -135
- package/dist/server/metadata.d.ts +8 -135
- package/dist/server/metadata.js +4 -65
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/metadata.mjs +4 -65
- package/dist/server/metadata.mjs.map +1 -1
- package/dist/server/navigation.js +0 -1
- package/dist/server/navigation.js.map +1 -1
- package/dist/server/navigation.mjs +0 -1
- package/dist/server/next/revalidate.d.mts +66 -0
- package/dist/server/next/revalidate.d.ts +66 -0
- package/dist/server/next/revalidate.js +59 -0
- package/dist/server/next/revalidate.js.map +1 -0
- package/dist/server/next/revalidate.mjs +59 -0
- package/dist/server/next/revalidate.mjs.map +1 -0
- package/dist/server/next/tags.d.mts +78 -0
- package/dist/server/next/tags.d.ts +78 -0
- package/dist/server/next/tags.js +34 -0
- package/dist/server/next/tags.js.map +1 -0
- package/dist/server/next/tags.mjs +34 -0
- package/dist/server/next/tags.mjs.map +1 -0
- package/dist/server/next.d.mts +432 -0
- package/dist/server/next.d.ts +432 -0
- package/dist/server/next.js +217 -0
- package/dist/server/next.js.map +1 -0
- package/dist/server/next.mjs +217 -0
- package/dist/server/next.mjs.map +1 -0
- package/dist/server/rendering/server.d.mts +3 -3
- package/dist/server/rendering/server.d.ts +3 -3
- package/dist/server/rendering/server.js +5 -4
- package/dist/server/rendering/server.js.map +1 -1
- package/dist/server/rendering/server.mjs +5 -4
- package/dist/server/rendering.d.mts +6 -6
- package/dist/server/rendering.d.ts +6 -6
- package/dist/server/rendering.js +7 -6
- package/dist/server/rendering.js.map +1 -1
- package/dist/server/rendering.mjs +9 -8
- package/dist/server/routing.d.mts +2 -2
- package/dist/server/routing.d.ts +2 -2
- package/dist/server/routing.js +2 -4
- package/dist/server/routing.js.map +1 -1
- package/dist/server/routing.mjs +1 -3
- package/dist/server/routing.mjs.map +1 -1
- package/dist/server/server.d.mts +4 -4
- package/dist/server/server.d.ts +4 -4
- package/dist/server/server.js +4 -5
- package/dist/server/server.js.map +1 -1
- package/dist/server/server.mjs +5 -6
- package/dist/server/theme-bridge.js +0 -1
- package/dist/server/theme-bridge.js.map +1 -1
- package/dist/server/theme-bridge.mjs +0 -1
- package/dist/server/theme-bridge.mjs.map +1 -1
- package/dist/server/theme.js +1 -3
- package/dist/server/theme.js.map +1 -1
- package/dist/server/theme.mjs +0 -2
- package/dist/server/theme.mjs.map +1 -1
- package/dist/server/{types-BvcJU7zk.d.ts → types-DnkRh0UL.d.ts} +118 -9
- package/dist/server/{types-1cLz0vnq.d.mts → types-MF2AWoKv.d.mts} +118 -9
- package/dist/server/webhooks.d.mts +75 -0
- package/dist/server/webhooks.d.ts +75 -0
- package/dist/server/webhooks.js +11 -0
- package/dist/server/webhooks.js.map +1 -0
- package/dist/server/webhooks.mjs +11 -0
- package/dist/server/webhooks.mjs.map +1 -0
- package/package.json +33 -1
- package/dist/server/chunk-3B364WO2.js.map +0 -1
- package/dist/server/chunk-BJTO5JO5.mjs +0 -11
- package/dist/server/chunk-DGUM43GV.js +0 -11
- package/dist/server/chunk-DGUM43GV.js.map +0 -1
- package/dist/server/chunk-I2D7KOEA.js.map +0 -1
- package/dist/server/chunk-I7ZR2WO3.mjs.map +0 -1
- package/dist/server/chunk-IVHIQFJH.js.map +0 -1
- package/dist/server/chunk-XXFF4RVR.mjs.map +0 -1
- package/dist/server/chunk-Z5ZA6Q4D.mjs.map +0 -1
- package/dist/server/loadPage-IDGVDFBB.js.map +0 -1
- /package/dist/server/{chunk-BJTO5JO5.mjs.map → env.mjs.map} +0 -0
- /package/dist/server/{loadPage-DNQTTRHL.mjs.map → loadPage-JI2SML4M.mjs.map} +0 -0
package/dist/client/client.js
CHANGED
|
@@ -17332,10 +17332,10 @@ function resolveApiBaseUrl() {
|
|
|
17332
17332
|
var revalidateTag = null;
|
|
17333
17333
|
if (typeof window === "undefined") {
|
|
17334
17334
|
try {
|
|
17335
|
-
const
|
|
17336
|
-
|
|
17335
|
+
const dynamicRequire = new Function("modulePath", "return require(modulePath)");
|
|
17336
|
+
const nextCache = dynamicRequire("next/cache");
|
|
17337
|
+
revalidateTag = nextCache.revalidateTag ?? null;
|
|
17337
17338
|
} catch {
|
|
17338
|
-
revalidateTag = null;
|
|
17339
17339
|
}
|
|
17340
17340
|
}
|
|
17341
17341
|
var sdkVersion;
|
|
@@ -17364,8 +17364,22 @@ var ApiRequestError = class extends Error {
|
|
|
17364
17364
|
this.body = options.body;
|
|
17365
17365
|
this.cause = options.cause;
|
|
17366
17366
|
this.errorCode = options.errorCode;
|
|
17367
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
17367
17368
|
}
|
|
17368
17369
|
};
|
|
17370
|
+
function parseRetryAfterHeader(headerValue) {
|
|
17371
|
+
if (!headerValue) return void 0;
|
|
17372
|
+
if (/^\d+$/.test(headerValue)) {
|
|
17373
|
+
const seconds = parseInt(headerValue, 10);
|
|
17374
|
+
return seconds * 1e3;
|
|
17375
|
+
}
|
|
17376
|
+
const date = new Date(headerValue);
|
|
17377
|
+
if (!isNaN(date.getTime())) {
|
|
17378
|
+
const delayMs = date.getTime() - Date.now();
|
|
17379
|
+
return delayMs > 0 ? delayMs : void 0;
|
|
17380
|
+
}
|
|
17381
|
+
return void 0;
|
|
17382
|
+
}
|
|
17369
17383
|
function buildEndpointURL(baseURL, endpoint) {
|
|
17370
17384
|
return baseURL + API_ENDPOINTS[endpoint].path;
|
|
17371
17385
|
}
|
|
@@ -17582,6 +17596,7 @@ function createParsedClient(rawClient) {
|
|
|
17582
17596
|
if (!response.ok) {
|
|
17583
17597
|
const body = await parseErrorBody(response);
|
|
17584
17598
|
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
17599
|
+
const retryAfterMs = parseRetryAfterHeader(response.headers.get("retry-after"));
|
|
17585
17600
|
throw new ApiRequestError(
|
|
17586
17601
|
`Request to ${String(endpoint)} failed with status ${response.status}`,
|
|
17587
17602
|
{
|
|
@@ -17590,7 +17605,8 @@ function createParsedClient(rawClient) {
|
|
|
17590
17605
|
method: config.method,
|
|
17591
17606
|
auth,
|
|
17592
17607
|
requestId,
|
|
17593
|
-
body
|
|
17608
|
+
body,
|
|
17609
|
+
retryAfterMs
|
|
17594
17610
|
}
|
|
17595
17611
|
);
|
|
17596
17612
|
}
|
|
@@ -17638,38 +17654,117 @@ var SimpleCache = class {
|
|
|
17638
17654
|
this.cache = /* @__PURE__ */ new Map();
|
|
17639
17655
|
this.maxSize = options.maxSize ?? 100;
|
|
17640
17656
|
this.ttl = options.ttl ?? 3e5;
|
|
17657
|
+
this.staleTtl = options.staleTtl ?? 3e5;
|
|
17658
|
+
}
|
|
17659
|
+
/**
|
|
17660
|
+
* Get a fresh value (within TTL)
|
|
17661
|
+
* @returns The value if fresh, null otherwise
|
|
17662
|
+
*/
|
|
17663
|
+
getFresh(key) {
|
|
17664
|
+
const entry = this.cache.get(key);
|
|
17665
|
+
if (!entry) return null;
|
|
17666
|
+
const now = Date.now();
|
|
17667
|
+
if (now <= entry.freshUntil) {
|
|
17668
|
+
return entry.value;
|
|
17669
|
+
}
|
|
17670
|
+
return null;
|
|
17641
17671
|
}
|
|
17642
|
-
|
|
17672
|
+
/**
|
|
17673
|
+
* Get a value that may be stale (past TTL but within staleTtl)
|
|
17674
|
+
* @returns Object with value and stale age, or null if expired
|
|
17675
|
+
*/
|
|
17676
|
+
getStale(key) {
|
|
17643
17677
|
const entry = this.cache.get(key);
|
|
17644
|
-
if (!entry) return
|
|
17645
|
-
|
|
17678
|
+
if (!entry) return null;
|
|
17679
|
+
const now = Date.now();
|
|
17680
|
+
if (now > entry.staleUntil) {
|
|
17646
17681
|
this.cache.delete(key);
|
|
17647
|
-
return
|
|
17682
|
+
return null;
|
|
17648
17683
|
}
|
|
17649
|
-
|
|
17684
|
+
const staleAgeSec = now <= entry.freshUntil ? 0 : Math.floor((now - entry.freshUntil) / 1e3);
|
|
17685
|
+
return {
|
|
17686
|
+
value: entry.value,
|
|
17687
|
+
staleAgeSec
|
|
17688
|
+
};
|
|
17650
17689
|
}
|
|
17651
|
-
|
|
17652
|
-
|
|
17653
|
-
|
|
17654
|
-
|
|
17655
|
-
|
|
17656
|
-
|
|
17690
|
+
/**
|
|
17691
|
+
* Store a value with TTL and stale window
|
|
17692
|
+
*/
|
|
17693
|
+
set(key, value, options) {
|
|
17694
|
+
const ttl = options?.ttl ?? this.ttl;
|
|
17695
|
+
const staleTtl = options?.staleTtl ?? this.staleTtl;
|
|
17696
|
+
const now = Date.now();
|
|
17697
|
+
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
17698
|
+
this.evictOne(now);
|
|
17657
17699
|
}
|
|
17658
17700
|
this.cache.set(key, {
|
|
17659
17701
|
value,
|
|
17660
|
-
|
|
17702
|
+
createdAt: now,
|
|
17703
|
+
freshUntil: now + ttl,
|
|
17704
|
+
staleUntil: now + ttl + staleTtl
|
|
17661
17705
|
});
|
|
17662
17706
|
}
|
|
17707
|
+
/**
|
|
17708
|
+
* Evict one entry to make room for a new one
|
|
17709
|
+
* Priority: oldest stale entry, then oldest fresh entry
|
|
17710
|
+
*/
|
|
17711
|
+
evictOne(now) {
|
|
17712
|
+
let oldestStaleKey = null;
|
|
17713
|
+
let oldestStaleTime = Infinity;
|
|
17714
|
+
let oldestFreshKey = null;
|
|
17715
|
+
let oldestFreshTime = Infinity;
|
|
17716
|
+
for (const [key, entry] of this.cache) {
|
|
17717
|
+
if (now > entry.freshUntil) {
|
|
17718
|
+
if (entry.createdAt < oldestStaleTime) {
|
|
17719
|
+
oldestStaleTime = entry.createdAt;
|
|
17720
|
+
oldestStaleKey = key;
|
|
17721
|
+
}
|
|
17722
|
+
} else {
|
|
17723
|
+
if (entry.createdAt < oldestFreshTime) {
|
|
17724
|
+
oldestFreshTime = entry.createdAt;
|
|
17725
|
+
oldestFreshKey = key;
|
|
17726
|
+
}
|
|
17727
|
+
}
|
|
17728
|
+
}
|
|
17729
|
+
const keyToEvict = oldestStaleKey ?? oldestFreshKey;
|
|
17730
|
+
if (keyToEvict) {
|
|
17731
|
+
this.cache.delete(keyToEvict);
|
|
17732
|
+
}
|
|
17733
|
+
}
|
|
17734
|
+
/**
|
|
17735
|
+
* Remove all fully expired entries (past staleUntil)
|
|
17736
|
+
*/
|
|
17737
|
+
prune() {
|
|
17738
|
+
const now = Date.now();
|
|
17739
|
+
for (const [key, entry] of this.cache) {
|
|
17740
|
+
if (now > entry.staleUntil) {
|
|
17741
|
+
this.cache.delete(key);
|
|
17742
|
+
}
|
|
17743
|
+
}
|
|
17744
|
+
}
|
|
17745
|
+
/**
|
|
17746
|
+
* Clear all entries
|
|
17747
|
+
*/
|
|
17663
17748
|
clear() {
|
|
17664
17749
|
this.cache.clear();
|
|
17665
17750
|
}
|
|
17751
|
+
/**
|
|
17752
|
+
* Check if a key exists and is not fully expired
|
|
17753
|
+
*/
|
|
17666
17754
|
has(key) {
|
|
17667
|
-
|
|
17755
|
+
const entry = this.cache.get(key);
|
|
17756
|
+
if (!entry) return false;
|
|
17757
|
+
const now = Date.now();
|
|
17758
|
+
if (now > entry.staleUntil) {
|
|
17759
|
+
this.cache.delete(key);
|
|
17760
|
+
return false;
|
|
17761
|
+
}
|
|
17762
|
+
return now <= entry.freshUntil;
|
|
17668
17763
|
}
|
|
17669
17764
|
};
|
|
17670
17765
|
|
|
17671
17766
|
// src/version.ts
|
|
17672
|
-
var SDK_VERSION = "0.
|
|
17767
|
+
var SDK_VERSION = "0.7.2";
|
|
17673
17768
|
|
|
17674
17769
|
// src/client/error.ts
|
|
17675
17770
|
var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
@@ -17681,8 +17776,31 @@ var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
|
17681
17776
|
this.status = apiError.status;
|
|
17682
17777
|
this.fieldErrors = apiError.fieldErrors;
|
|
17683
17778
|
this.timestamp = apiError.timestamp;
|
|
17779
|
+
this.retryAfterMs = "retryAfterMs" in apiError ? apiError.retryAfterMs : void 0;
|
|
17780
|
+
this.isRetryable = this.computeRetryable();
|
|
17684
17781
|
Object.setPrototypeOf(this, _RiverbankApiError.prototype);
|
|
17685
17782
|
}
|
|
17783
|
+
/**
|
|
17784
|
+
* Compute whether this error is retryable based on HTTP status code.
|
|
17785
|
+
* - 0 (network errors - no HTTP response): retryable
|
|
17786
|
+
* - 429 (rate limit): retryable
|
|
17787
|
+
* - 5xx (server errors): retryable
|
|
17788
|
+
* - 4xx (client errors, except 429): NOT retryable
|
|
17789
|
+
*/
|
|
17790
|
+
computeRetryable() {
|
|
17791
|
+
if (this.status === 0) return true;
|
|
17792
|
+
if (this.status === 429) return true;
|
|
17793
|
+
if (this.status >= 500) return true;
|
|
17794
|
+
return false;
|
|
17795
|
+
}
|
|
17796
|
+
/**
|
|
17797
|
+
* Check if this is a network error (no HTTP response received)
|
|
17798
|
+
*
|
|
17799
|
+
* Matches: network:connection_error, network:timeout, network:dns_error
|
|
17800
|
+
*/
|
|
17801
|
+
isNetworkError() {
|
|
17802
|
+
return this.code.startsWith("network:");
|
|
17803
|
+
}
|
|
17686
17804
|
/**
|
|
17687
17805
|
* Check if this error matches a specific error code
|
|
17688
17806
|
*
|
|
@@ -17741,9 +17859,215 @@ var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
|
17741
17859
|
}
|
|
17742
17860
|
};
|
|
17743
17861
|
|
|
17862
|
+
// src/client/resilience.ts
|
|
17863
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
17864
|
+
maxAttempts: 3,
|
|
17865
|
+
baseDelayMs: 200,
|
|
17866
|
+
maxDelayMs: 2e3,
|
|
17867
|
+
jitter: "full"
|
|
17868
|
+
};
|
|
17869
|
+
var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
|
|
17870
|
+
failureThreshold: 5,
|
|
17871
|
+
resetTimeoutMs: 3e4,
|
|
17872
|
+
halfOpenMaxRequests: 2
|
|
17873
|
+
};
|
|
17874
|
+
function isTransientError(error) {
|
|
17875
|
+
if (error instanceof RiverbankApiError) {
|
|
17876
|
+
if (error.status === 0) return true;
|
|
17877
|
+
if (error.status === 429) return true;
|
|
17878
|
+
if (error.status >= 500) return true;
|
|
17879
|
+
return false;
|
|
17880
|
+
}
|
|
17881
|
+
return true;
|
|
17882
|
+
}
|
|
17883
|
+
function calculateBackoff(attempt, config) {
|
|
17884
|
+
const baseDelayMs = config.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs;
|
|
17885
|
+
const maxDelayMs = config.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs;
|
|
17886
|
+
const jitter = config.jitter ?? DEFAULT_RETRY_CONFIG.jitter;
|
|
17887
|
+
const exponential = baseDelayMs * Math.pow(2, attempt - 1);
|
|
17888
|
+
const capped = Math.min(exponential, maxDelayMs);
|
|
17889
|
+
if (jitter === "full") {
|
|
17890
|
+
return Math.random() * capped;
|
|
17891
|
+
}
|
|
17892
|
+
return capped;
|
|
17893
|
+
}
|
|
17894
|
+
var CircuitBreaker = class {
|
|
17895
|
+
constructor(config) {
|
|
17896
|
+
this.state = "closed";
|
|
17897
|
+
this.failureCount = 0;
|
|
17898
|
+
this.successCount = 0;
|
|
17899
|
+
this.openUntil = 0;
|
|
17900
|
+
this.halfOpenRequests = 0;
|
|
17901
|
+
this.config = {
|
|
17902
|
+
failureThreshold: config?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
17903
|
+
resetTimeoutMs: config?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
|
|
17904
|
+
halfOpenMaxRequests: config?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
|
|
17905
|
+
};
|
|
17906
|
+
}
|
|
17907
|
+
/**
|
|
17908
|
+
* Check if circuit is open (requests should be blocked)
|
|
17909
|
+
* Also handles automatic transition from open to half-open after timeout
|
|
17910
|
+
*/
|
|
17911
|
+
isOpen() {
|
|
17912
|
+
if (this.state === "open" && Date.now() >= this.openUntil) {
|
|
17913
|
+
this.transitionTo("half-open");
|
|
17914
|
+
}
|
|
17915
|
+
return this.state === "open";
|
|
17916
|
+
}
|
|
17917
|
+
/**
|
|
17918
|
+
* Check if a request can be attempted
|
|
17919
|
+
* - closed: always yes
|
|
17920
|
+
* - open: always no
|
|
17921
|
+
* - half-open: limited number of probes
|
|
17922
|
+
*/
|
|
17923
|
+
canAttempt() {
|
|
17924
|
+
if (this.state === "closed") return true;
|
|
17925
|
+
if (this.state === "open") return false;
|
|
17926
|
+
return this.halfOpenRequests < this.config.halfOpenMaxRequests;
|
|
17927
|
+
}
|
|
17928
|
+
/**
|
|
17929
|
+
* Increment half-open request counter (call before making request in half-open)
|
|
17930
|
+
*/
|
|
17931
|
+
incrementHalfOpenRequests() {
|
|
17932
|
+
if (this.state === "half-open") {
|
|
17933
|
+
this.halfOpenRequests++;
|
|
17934
|
+
}
|
|
17935
|
+
}
|
|
17936
|
+
/**
|
|
17937
|
+
* Record a successful request
|
|
17938
|
+
*/
|
|
17939
|
+
recordSuccess() {
|
|
17940
|
+
if (this.state === "half-open") {
|
|
17941
|
+
this.successCount++;
|
|
17942
|
+
if (this.successCount >= this.config.halfOpenMaxRequests) {
|
|
17943
|
+
this.transitionTo("closed");
|
|
17944
|
+
}
|
|
17945
|
+
} else {
|
|
17946
|
+
this.failureCount = 0;
|
|
17947
|
+
}
|
|
17948
|
+
}
|
|
17949
|
+
/**
|
|
17950
|
+
* Record a failed request
|
|
17951
|
+
* Only counts transient failures toward circuit breaker threshold
|
|
17952
|
+
*/
|
|
17953
|
+
recordFailure(error) {
|
|
17954
|
+
if (!isTransientError(error)) return;
|
|
17955
|
+
this.failureCount++;
|
|
17956
|
+
if (this.state === "half-open") {
|
|
17957
|
+
this.transitionTo("open");
|
|
17958
|
+
} else if (this.failureCount >= this.config.failureThreshold) {
|
|
17959
|
+
this.transitionTo("open");
|
|
17960
|
+
}
|
|
17961
|
+
}
|
|
17962
|
+
/**
|
|
17963
|
+
* Get current circuit state
|
|
17964
|
+
*/
|
|
17965
|
+
getState() {
|
|
17966
|
+
return {
|
|
17967
|
+
state: this.state,
|
|
17968
|
+
failureCount: this.failureCount,
|
|
17969
|
+
openUntil: this.state === "open" ? this.openUntil : void 0
|
|
17970
|
+
};
|
|
17971
|
+
}
|
|
17972
|
+
/**
|
|
17973
|
+
* Transition to a new state
|
|
17974
|
+
*/
|
|
17975
|
+
transitionTo(newState) {
|
|
17976
|
+
this.state = newState;
|
|
17977
|
+
if (newState === "open") {
|
|
17978
|
+
this.openUntil = Date.now() + this.config.resetTimeoutMs;
|
|
17979
|
+
} else if (newState === "half-open") {
|
|
17980
|
+
this.halfOpenRequests = 0;
|
|
17981
|
+
this.successCount = 0;
|
|
17982
|
+
} else if (newState === "closed") {
|
|
17983
|
+
this.failureCount = 0;
|
|
17984
|
+
this.successCount = 0;
|
|
17985
|
+
this.halfOpenRequests = 0;
|
|
17986
|
+
}
|
|
17987
|
+
}
|
|
17988
|
+
};
|
|
17989
|
+
async function fetchWithTimeoutAndRetry(fetcher, config) {
|
|
17990
|
+
const maxAttempts = config.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts;
|
|
17991
|
+
const requestTimeoutMs = config.requestTimeoutMs ?? 8e3;
|
|
17992
|
+
let lastError;
|
|
17993
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
17994
|
+
try {
|
|
17995
|
+
const controller = new AbortController();
|
|
17996
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
17997
|
+
try {
|
|
17998
|
+
const result = await fetcher(controller.signal);
|
|
17999
|
+
return result;
|
|
18000
|
+
} finally {
|
|
18001
|
+
clearTimeout(timeoutId);
|
|
18002
|
+
}
|
|
18003
|
+
} catch (error) {
|
|
18004
|
+
lastError = error;
|
|
18005
|
+
const shouldRetry = shouldRetryError(error, config.retryOn);
|
|
18006
|
+
if (!shouldRetry) {
|
|
18007
|
+
throw error;
|
|
18008
|
+
}
|
|
18009
|
+
if (attempt < maxAttempts) {
|
|
18010
|
+
const delay = getRetryDelay(error, attempt, config);
|
|
18011
|
+
await sleep(delay);
|
|
18012
|
+
}
|
|
18013
|
+
}
|
|
18014
|
+
}
|
|
18015
|
+
throw lastError;
|
|
18016
|
+
}
|
|
18017
|
+
function shouldRetryError(error, customRetryOn) {
|
|
18018
|
+
if (customRetryOn) {
|
|
18019
|
+
const statusCode = error instanceof RiverbankApiError ? error.status : void 0;
|
|
18020
|
+
return customRetryOn(error, statusCode);
|
|
18021
|
+
}
|
|
18022
|
+
return isTransientError(error);
|
|
18023
|
+
}
|
|
18024
|
+
function getRetryDelay(error, attempt, config) {
|
|
18025
|
+
if (error instanceof RiverbankApiError && error.retryAfterMs) {
|
|
18026
|
+
return error.retryAfterMs;
|
|
18027
|
+
}
|
|
18028
|
+
return calculateBackoff(attempt, config);
|
|
18029
|
+
}
|
|
18030
|
+
function sleep(ms) {
|
|
18031
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18032
|
+
}
|
|
18033
|
+
var CircuitOpenError = class extends Error {
|
|
18034
|
+
constructor(state) {
|
|
18035
|
+
super("Circuit breaker is open");
|
|
18036
|
+
this.name = "CircuitOpenError";
|
|
18037
|
+
this.circuitState = state;
|
|
18038
|
+
}
|
|
18039
|
+
};
|
|
18040
|
+
|
|
17744
18041
|
// src/client/index.ts
|
|
17745
18042
|
setSdkVersion(SDK_VERSION);
|
|
18043
|
+
var DEFAULT_BROWSER_TIMEOUT_MS = 5e3;
|
|
18044
|
+
var DEFAULT_SERVER_TIMEOUT_MS = 8e3;
|
|
18045
|
+
function generateRequestId2() {
|
|
18046
|
+
return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
18047
|
+
}
|
|
18048
|
+
function isAbortError(error) {
|
|
18049
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
18050
|
+
return true;
|
|
18051
|
+
}
|
|
18052
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
18053
|
+
return true;
|
|
18054
|
+
}
|
|
18055
|
+
return false;
|
|
18056
|
+
}
|
|
18057
|
+
function getNetworkErrorCode(error) {
|
|
18058
|
+
const message = error.message.toLowerCase();
|
|
18059
|
+
if (message.includes("timeout") || message.includes("timed out")) {
|
|
18060
|
+
return "network:timeout";
|
|
18061
|
+
}
|
|
18062
|
+
if (message.includes("dns") || message.includes("getaddrinfo") || message.includes("enotfound")) {
|
|
18063
|
+
return "network:dns_error";
|
|
18064
|
+
}
|
|
18065
|
+
return "network:connection_error";
|
|
18066
|
+
}
|
|
17746
18067
|
function convertToTypedError(error) {
|
|
18068
|
+
if (isAbortError(error)) {
|
|
18069
|
+
throw error;
|
|
18070
|
+
}
|
|
17747
18071
|
if (error instanceof ApiEnvelopeError) {
|
|
17748
18072
|
throw new RiverbankApiError({
|
|
17749
18073
|
code: error.code,
|
|
@@ -17757,15 +18081,30 @@ function convertToTypedError(error) {
|
|
|
17757
18081
|
if (error instanceof ApiRequestError && error.body && typeof error.body === "object") {
|
|
17758
18082
|
const body = error.body;
|
|
17759
18083
|
if (isApiError(body)) {
|
|
17760
|
-
|
|
18084
|
+
const envelopeError = body.error;
|
|
18085
|
+
throw new RiverbankApiError({
|
|
18086
|
+
...envelopeError,
|
|
18087
|
+
retryAfterMs: error.retryAfterMs
|
|
18088
|
+
});
|
|
17761
18089
|
}
|
|
17762
18090
|
}
|
|
18091
|
+
if (error instanceof TypeError || error instanceof Error && !("status" in error)) {
|
|
18092
|
+
const networkError = error;
|
|
18093
|
+
throw new RiverbankApiError({
|
|
18094
|
+
code: getNetworkErrorCode(networkError),
|
|
18095
|
+
message: networkError.message || "Network request failed",
|
|
18096
|
+
requestId: `local-${Date.now()}`,
|
|
18097
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18098
|
+
status: 0
|
|
18099
|
+
// No HTTP response received
|
|
18100
|
+
});
|
|
18101
|
+
}
|
|
17763
18102
|
throw error;
|
|
17764
18103
|
}
|
|
17765
18104
|
function createRiverbankClient(config) {
|
|
17766
18105
|
if (!config.baseUrl) {
|
|
17767
18106
|
throw new Error(
|
|
17768
|
-
"baseUrl is required when creating a
|
|
18107
|
+
"baseUrl is required when creating a Riverbank client. Expected format: https://dashboard.example.com/api (must include /api path)"
|
|
17769
18108
|
);
|
|
17770
18109
|
}
|
|
17771
18110
|
if (!config.baseUrl.endsWith("/api")) {
|
|
@@ -17776,59 +18115,179 @@ function createRiverbankClient(config) {
|
|
|
17776
18115
|
const cacheEnabled = config.cache?.enabled ?? true;
|
|
17777
18116
|
const cacheTTL = (config.cache?.ttl ?? 300) * 1e3;
|
|
17778
18117
|
const cacheMaxSize = config.cache?.maxSize ?? 100;
|
|
18118
|
+
const resilienceEnabled = config.resilience?.enabled ?? true;
|
|
18119
|
+
const staleIfError = config.resilience?.staleIfError ?? true;
|
|
18120
|
+
const staleTtlMs = (config.resilience?.staleTtlSec ?? 300) * 1e3;
|
|
18121
|
+
const requestTimeoutMs = config.resilience?.requestTimeoutMs ?? (typeof window !== "undefined" ? DEFAULT_BROWSER_TIMEOUT_MS : DEFAULT_SERVER_TIMEOUT_MS);
|
|
18122
|
+
const retryConfig = {
|
|
18123
|
+
maxAttempts: config.resilience?.retry?.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts,
|
|
18124
|
+
baseDelayMs: config.resilience?.retry?.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs,
|
|
18125
|
+
maxDelayMs: config.resilience?.retry?.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs,
|
|
18126
|
+
jitter: config.resilience?.retry?.jitter ?? DEFAULT_RETRY_CONFIG.jitter,
|
|
18127
|
+
retryOn: config.resilience?.retry?.retryOn
|
|
18128
|
+
};
|
|
18129
|
+
const circuitBreakerConfig = {
|
|
18130
|
+
failureThreshold: config.resilience?.circuitBreaker?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
18131
|
+
resetTimeoutMs: config.resilience?.circuitBreaker?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
|
|
18132
|
+
halfOpenMaxRequests: config.resilience?.circuitBreaker?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
|
|
18133
|
+
};
|
|
17779
18134
|
const apiClient = createBearerAPIClient(config.apiKey, config.baseUrl);
|
|
17780
18135
|
const cache = new SimpleCache({
|
|
17781
18136
|
maxSize: cacheMaxSize,
|
|
17782
|
-
ttl: cacheTTL
|
|
18137
|
+
ttl: cacheTTL,
|
|
18138
|
+
staleTtl: staleTtlMs
|
|
17783
18139
|
});
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
|
|
17787
|
-
|
|
17788
|
-
|
|
18140
|
+
const circuitBreaker = new CircuitBreaker(circuitBreakerConfig);
|
|
18141
|
+
let lastStatus = null;
|
|
18142
|
+
let isDegraded = false;
|
|
18143
|
+
function emitStatus(source, data, details) {
|
|
18144
|
+
const status = {
|
|
18145
|
+
source,
|
|
18146
|
+
isPreview: details.isPreview,
|
|
18147
|
+
cacheKey: details.cacheKey,
|
|
18148
|
+
error: details.error,
|
|
18149
|
+
staleAgeSec: details.staleAgeSec,
|
|
18150
|
+
circuit: circuitBreaker.getState(),
|
|
18151
|
+
requestId: details.requestId,
|
|
18152
|
+
durationMs: details.durationMs
|
|
18153
|
+
};
|
|
18154
|
+
lastStatus = status;
|
|
18155
|
+
config.resilience?.onStatusChange?.(status);
|
|
18156
|
+
const nowDegraded = source === "stale" || source === "error";
|
|
18157
|
+
if (nowDegraded !== isDegraded) {
|
|
18158
|
+
isDegraded = nowDegraded;
|
|
18159
|
+
config.resilience?.onDegradedMode?.(nowDegraded, status);
|
|
18160
|
+
}
|
|
18161
|
+
return data;
|
|
18162
|
+
}
|
|
18163
|
+
async function resilientFetch(cacheKey, fetcher, options) {
|
|
18164
|
+
const requestId = generateRequestId2();
|
|
18165
|
+
const startTime = Date.now();
|
|
18166
|
+
const isPreview = options.preview ?? false;
|
|
18167
|
+
const statusDetails = (extra = {}) => ({
|
|
18168
|
+
requestId,
|
|
18169
|
+
cacheKey,
|
|
18170
|
+
isPreview,
|
|
18171
|
+
durationMs: Date.now() - startTime,
|
|
18172
|
+
...extra
|
|
18173
|
+
});
|
|
18174
|
+
if (cacheEnabled && !options.force) {
|
|
18175
|
+
const fresh = cache.getFresh(cacheKey);
|
|
18176
|
+
if (fresh !== null) {
|
|
18177
|
+
return emitStatus("cache", fresh, statusDetails());
|
|
18178
|
+
}
|
|
18179
|
+
}
|
|
18180
|
+
if (resilienceEnabled && circuitBreaker.isOpen()) {
|
|
18181
|
+
if (!isPreview && staleIfError) {
|
|
18182
|
+
const stale = cache.getStale(cacheKey);
|
|
18183
|
+
if (stale) {
|
|
18184
|
+
return emitStatus("stale", stale.value, statusDetails({
|
|
18185
|
+
staleAgeSec: stale.staleAgeSec,
|
|
18186
|
+
error: { code: "circuit_open", message: "Circuit breaker is open" }
|
|
18187
|
+
}));
|
|
18188
|
+
}
|
|
18189
|
+
}
|
|
18190
|
+
if (!options.force) {
|
|
18191
|
+
const circuitState = circuitBreaker.getState();
|
|
18192
|
+
emitStatus("error", null, statusDetails({
|
|
18193
|
+
error: { code: "circuit_open", message: "Circuit breaker is open" }
|
|
18194
|
+
}));
|
|
18195
|
+
throw new CircuitOpenError(circuitState);
|
|
17789
18196
|
}
|
|
17790
18197
|
}
|
|
17791
|
-
let data;
|
|
17792
18198
|
try {
|
|
17793
|
-
|
|
17794
|
-
|
|
18199
|
+
let data;
|
|
18200
|
+
if (resilienceEnabled) {
|
|
18201
|
+
if (circuitBreaker.getState().state === "half-open") {
|
|
18202
|
+
circuitBreaker.incrementHalfOpenRequests();
|
|
18203
|
+
}
|
|
18204
|
+
data = await fetchWithTimeoutAndRetry(
|
|
18205
|
+
async (timeoutSignal) => {
|
|
18206
|
+
const combinedSignal = options.signal ? combineAbortSignals(timeoutSignal, options.signal) : timeoutSignal;
|
|
18207
|
+
try {
|
|
18208
|
+
const response = await fetcher(combinedSignal);
|
|
18209
|
+
return unwrapResponse(response);
|
|
18210
|
+
} catch (error) {
|
|
18211
|
+
convertToTypedError(error);
|
|
18212
|
+
}
|
|
18213
|
+
},
|
|
18214
|
+
{
|
|
18215
|
+
...retryConfig,
|
|
18216
|
+
requestTimeoutMs
|
|
18217
|
+
}
|
|
18218
|
+
);
|
|
18219
|
+
circuitBreaker.recordSuccess();
|
|
18220
|
+
} else {
|
|
18221
|
+
try {
|
|
18222
|
+
const response = await fetcher(options.signal ?? new AbortController().signal);
|
|
18223
|
+
data = unwrapResponse(response);
|
|
18224
|
+
} catch (error) {
|
|
18225
|
+
convertToTypedError(error);
|
|
18226
|
+
}
|
|
18227
|
+
}
|
|
18228
|
+
if (cacheEnabled) {
|
|
18229
|
+
cache.set(cacheKey, data);
|
|
18230
|
+
}
|
|
18231
|
+
return emitStatus("live", data, statusDetails());
|
|
17795
18232
|
} catch (error) {
|
|
17796
|
-
|
|
18233
|
+
if (resilienceEnabled && error instanceof Error) {
|
|
18234
|
+
circuitBreaker.recordFailure(error);
|
|
18235
|
+
}
|
|
18236
|
+
if (!isPreview && staleIfError && cacheEnabled) {
|
|
18237
|
+
const stale = cache.getStale(cacheKey);
|
|
18238
|
+
if (stale) {
|
|
18239
|
+
const errorInfo2 = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
|
|
18240
|
+
return emitStatus("stale", stale.value, statusDetails({
|
|
18241
|
+
staleAgeSec: stale.staleAgeSec,
|
|
18242
|
+
error: errorInfo2
|
|
18243
|
+
}));
|
|
18244
|
+
}
|
|
18245
|
+
}
|
|
18246
|
+
const errorInfo = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
|
|
18247
|
+
emitStatus("error", null, statusDetails({ error: errorInfo }));
|
|
18248
|
+
throw error;
|
|
17797
18249
|
}
|
|
17798
|
-
|
|
17799
|
-
|
|
18250
|
+
}
|
|
18251
|
+
function combineAbortSignals(...signals) {
|
|
18252
|
+
const controller = new AbortController();
|
|
18253
|
+
for (const signal of signals) {
|
|
18254
|
+
if (signal.aborted) {
|
|
18255
|
+
controller.abort(signal.reason);
|
|
18256
|
+
break;
|
|
18257
|
+
}
|
|
18258
|
+
signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
|
|
17800
18259
|
}
|
|
17801
|
-
return
|
|
18260
|
+
return controller.signal;
|
|
17802
18261
|
}
|
|
17803
18262
|
return {
|
|
17804
18263
|
async getSite(params) {
|
|
17805
|
-
const { slug, domain, id } = params;
|
|
18264
|
+
const { slug, domain, id, signal } = params;
|
|
17806
18265
|
if (!slug && !domain && !id) {
|
|
17807
18266
|
throw new Error(
|
|
17808
18267
|
`getSite() requires at least one identifier: slug, domain, or id. Received: ${JSON.stringify(params)}`
|
|
17809
18268
|
);
|
|
17810
18269
|
}
|
|
17811
18270
|
const cacheKey = `site:${slug || domain || id}`;
|
|
17812
|
-
return
|
|
18271
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17813
18272
|
const apiParams = {};
|
|
17814
18273
|
if (params.slug) apiParams.slug = params.slug;
|
|
17815
18274
|
if (params.domain) apiParams.domain = params.domain;
|
|
17816
18275
|
if (params.id) apiParams.id = params.id;
|
|
17817
|
-
return await apiClient({ endpoint: "getSite", params: apiParams });
|
|
17818
|
-
});
|
|
18276
|
+
return await apiClient({ endpoint: "getSite", params: apiParams, options: { signal: sig } });
|
|
18277
|
+
}, { signal });
|
|
17819
18278
|
},
|
|
17820
18279
|
async getPage(params) {
|
|
17821
|
-
const { siteId, path, preview = false } = params;
|
|
18280
|
+
const { siteId, path, preview = false, signal } = params;
|
|
17822
18281
|
const cacheKey = `page:${siteId}:${path}:${preview}`;
|
|
17823
|
-
return
|
|
17824
|
-
return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path, preview } });
|
|
17825
|
-
});
|
|
18282
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
18283
|
+
return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path, preview }, options: { signal: sig } });
|
|
18284
|
+
}, { preview, signal });
|
|
17826
18285
|
},
|
|
17827
18286
|
async getEntries(params) {
|
|
17828
|
-
const { siteId, contentType, limit, offset, order, preview = false, mode, entryIds, includeMeta } = params;
|
|
18287
|
+
const { siteId, contentType, limit, offset, order, preview = false, mode, entryIds, includeMeta, signal } = params;
|
|
17829
18288
|
const entryIdsCacheKey = mode === "manual" && entryIds?.length ? entryIds.join(",") : "";
|
|
17830
18289
|
const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ""}:${offset ?? ""}:${order ?? ""}:${preview}:${mode ?? ""}:${entryIdsCacheKey}:${includeMeta ?? ""}`;
|
|
17831
|
-
return
|
|
18290
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17832
18291
|
let orderParam;
|
|
17833
18292
|
if (order === "newest") {
|
|
17834
18293
|
orderParam = "published_at.desc";
|
|
@@ -17850,47 +18309,47 @@ function createRiverbankClient(config) {
|
|
|
17850
18309
|
entryIds: JSON.stringify(entryIds)
|
|
17851
18310
|
}
|
|
17852
18311
|
};
|
|
17853
|
-
return await apiClient({ endpoint: "listPublishedEntries", params: apiParams });
|
|
17854
|
-
});
|
|
18312
|
+
return await apiClient({ endpoint: "listPublishedEntries", params: apiParams, options: { signal: sig } });
|
|
18313
|
+
}, { preview, signal });
|
|
17855
18314
|
},
|
|
17856
18315
|
async getEntry(params) {
|
|
17857
|
-
const { siteId, contentType, slug } = params;
|
|
18316
|
+
const { siteId, contentType, slug, signal } = params;
|
|
17858
18317
|
const cacheKey = `entry:${siteId}:${contentType}:${slug}`;
|
|
17859
|
-
return
|
|
17860
|
-
return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug } });
|
|
17861
|
-
});
|
|
18318
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
18319
|
+
return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug }, options: { signal: sig } });
|
|
18320
|
+
}, { signal });
|
|
17862
18321
|
},
|
|
17863
18322
|
async getPublicFormById(params) {
|
|
17864
|
-
const { formId } = params;
|
|
18323
|
+
const { formId, signal } = params;
|
|
17865
18324
|
if (!formId) {
|
|
17866
18325
|
throw new Error("getPublicFormById() requires formId");
|
|
17867
18326
|
}
|
|
17868
18327
|
const cacheKey = `public-form:${formId}`;
|
|
17869
|
-
return
|
|
17870
|
-
return await apiClient({ endpoint: "getPublicFormById", params: { formId } });
|
|
17871
|
-
});
|
|
18328
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
18329
|
+
return await apiClient({ endpoint: "getPublicFormById", params: { formId }, options: { signal: sig } });
|
|
18330
|
+
}, { signal });
|
|
17872
18331
|
},
|
|
17873
18332
|
async getPublicBookingServices(params) {
|
|
17874
|
-
const { siteId, ids } = params;
|
|
18333
|
+
const { siteId, ids, signal } = params;
|
|
17875
18334
|
if (!siteId) {
|
|
17876
18335
|
throw new Error("getPublicBookingServices() requires siteId");
|
|
17877
18336
|
}
|
|
17878
18337
|
const cacheKey = `public-booking-services:${siteId}:${ids ?? ""}`;
|
|
17879
|
-
return
|
|
18338
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17880
18339
|
const apiParams = {
|
|
17881
18340
|
siteId,
|
|
17882
18341
|
...ids && { ids }
|
|
17883
18342
|
};
|
|
17884
|
-
return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams });
|
|
17885
|
-
});
|
|
18343
|
+
return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams, options: { signal: sig } });
|
|
18344
|
+
}, { signal });
|
|
17886
18345
|
},
|
|
17887
18346
|
async listPublicEvents(params) {
|
|
17888
|
-
const { siteId, limit, from, to, stage } = params;
|
|
18347
|
+
const { siteId, limit, from, to, stage, signal } = params;
|
|
17889
18348
|
if (!siteId) {
|
|
17890
18349
|
throw new Error("listPublicEvents() requires siteId");
|
|
17891
18350
|
}
|
|
17892
18351
|
const cacheKey = `public-events:${siteId}:${limit ?? ""}:${from ?? ""}:${to ?? ""}:${stage ?? ""}`;
|
|
17893
|
-
return
|
|
18352
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17894
18353
|
const apiParams = {
|
|
17895
18354
|
siteId,
|
|
17896
18355
|
...typeof limit === "number" && { limit: String(limit) },
|
|
@@ -17898,40 +18357,46 @@ function createRiverbankClient(config) {
|
|
|
17898
18357
|
...to && { to },
|
|
17899
18358
|
...stage && { stage }
|
|
17900
18359
|
};
|
|
17901
|
-
return await apiClient({ endpoint: "listPublicEvents", params: apiParams });
|
|
17902
|
-
});
|
|
18360
|
+
return await apiClient({ endpoint: "listPublicEvents", params: apiParams, options: { signal: sig } });
|
|
18361
|
+
}, { signal });
|
|
17903
18362
|
},
|
|
17904
18363
|
async resolveEventOccurrence(params) {
|
|
17905
|
-
const { siteId, entryId, segment } = params;
|
|
18364
|
+
const { siteId, entryId, segment, signal } = params;
|
|
17906
18365
|
if (!siteId || !entryId || !segment) {
|
|
17907
18366
|
throw new Error("resolveEventOccurrence() requires siteId, entryId, and segment");
|
|
17908
18367
|
}
|
|
17909
18368
|
const cacheKey = `event-occurrence:${siteId}:${entryId}:${segment}`;
|
|
17910
|
-
return
|
|
18369
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17911
18370
|
return await apiClient({
|
|
17912
18371
|
endpoint: "resolveEventOccurrence",
|
|
17913
|
-
params: { siteId, entryId, segment }
|
|
18372
|
+
params: { siteId, entryId, segment },
|
|
18373
|
+
options: { signal: sig }
|
|
17914
18374
|
});
|
|
17915
|
-
});
|
|
18375
|
+
}, { signal });
|
|
17916
18376
|
},
|
|
17917
18377
|
async checkRedirect(params) {
|
|
17918
|
-
const { siteId, path } = params;
|
|
18378
|
+
const { siteId, path, signal } = params;
|
|
17919
18379
|
if (!siteId || !path) {
|
|
17920
18380
|
throw new Error("checkRedirect() requires siteId and path");
|
|
17921
18381
|
}
|
|
17922
18382
|
const cacheKey = `redirect:${siteId}:${path}`;
|
|
17923
|
-
return
|
|
18383
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17924
18384
|
return await apiClient({
|
|
17925
18385
|
endpoint: "checkRedirect",
|
|
17926
|
-
params: { site: siteId, path }
|
|
18386
|
+
params: { site: siteId, path },
|
|
18387
|
+
options: { signal: sig }
|
|
17927
18388
|
});
|
|
17928
|
-
});
|
|
18389
|
+
}, { signal });
|
|
17929
18390
|
},
|
|
17930
18391
|
clearCache() {
|
|
17931
18392
|
cache.clear();
|
|
18393
|
+
},
|
|
18394
|
+
getLastEmittedStatus() {
|
|
18395
|
+
return lastStatus;
|
|
18396
|
+
},
|
|
18397
|
+
getCircuitState() {
|
|
18398
|
+
return circuitBreaker.getState();
|
|
17932
18399
|
}
|
|
17933
|
-
// Cast to RiverbankClient to satisfy overloaded getEntries signature
|
|
17934
|
-
// The implementation correctly returns the right type based on includeMeta
|
|
17935
18400
|
};
|
|
17936
18401
|
}
|
|
17937
18402
|
// Annotate the CommonJS export names for ESM import in node:
|