@riverbankcms/sdk 0.7.0 → 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-7FIJSGHU.mjs → chunk-5JT452F2.mjs} +537 -76
- package/dist/server/chunk-5JT452F2.mjs.map +1 -0
- package/dist/server/chunk-AET56TQX.mjs +45 -0
- package/dist/server/chunk-AET56TQX.mjs.map +1 -0
- package/dist/server/{chunk-P7UVAMK6.js → chunk-HMENX4Y7.js} +543 -82
- package/dist/server/chunk-HMENX4Y7.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-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 +0 -1
- package/dist/server/components.js.map +1 -1
- package/dist/server/components.mjs +0 -1
- 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-DI_qlYx3.d.mts → index-BL66CU6d.d.mts} +2 -2
- package/dist/server/{index-Bucs6UqG.d.mts → index-Bkva0WAj.d.mts} +1 -1
- package/dist/server/{index-BTwWvSBu.d.ts → index-CJk9iQQW.d.ts} +2 -2
- 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-DmgpFcFC.d.ts → loadContent-CXUWMuzY.d.ts} +2 -2
- package/dist/server/{loadContent-C-YYUKQa.d.mts → loadContent-F_tAS0Nl.d.mts} +2 -2
- 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 +3 -3
- package/dist/server/metadata.d.ts +3 -3
- package/dist/server/metadata.js +0 -1
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/metadata.mjs +0 -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 +163 -5
- package/dist/server/next.d.ts +163 -5
- package/dist/server/next.js +78 -11
- package/dist/server/next.js.map +1 -1
- package/dist/server/next.mjs +75 -8
- package/dist/server/next.mjs.map +1 -1
- package/dist/server/rendering/server.d.mts +3 -3
- package/dist/server/rendering/server.d.ts +3 -3
- package/dist/server/rendering/server.js +0 -1
- package/dist/server/rendering/server.js.map +1 -1
- package/dist/server/rendering/server.mjs +0 -1
- package/dist/server/rendering.d.mts +6 -6
- package/dist/server/rendering.d.ts +6 -6
- package/dist/server/rendering.js +2 -3
- package/dist/server/rendering.js.map +1 -1
- package/dist/server/rendering.mjs +3 -4
- 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 +4 -5
- 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 +23 -3
- package/dist/server/chunk-7FIJSGHU.mjs.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-P7UVAMK6.js.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.mjs
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
-
}) : x)(function(x) {
|
|
5
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
-
});
|
|
8
|
-
|
|
9
2
|
// src/rendering/hooks/usePage.ts
|
|
10
3
|
import { useState, useEffect } from "react";
|
|
11
4
|
|
|
@@ -17296,10 +17289,10 @@ function resolveApiBaseUrl() {
|
|
|
17296
17289
|
var revalidateTag = null;
|
|
17297
17290
|
if (typeof window === "undefined") {
|
|
17298
17291
|
try {
|
|
17299
|
-
const
|
|
17300
|
-
|
|
17292
|
+
const dynamicRequire = new Function("modulePath", "return require(modulePath)");
|
|
17293
|
+
const nextCache = dynamicRequire("next/cache");
|
|
17294
|
+
revalidateTag = nextCache.revalidateTag ?? null;
|
|
17301
17295
|
} catch {
|
|
17302
|
-
revalidateTag = null;
|
|
17303
17296
|
}
|
|
17304
17297
|
}
|
|
17305
17298
|
var sdkVersion;
|
|
@@ -17328,8 +17321,22 @@ var ApiRequestError = class extends Error {
|
|
|
17328
17321
|
this.body = options.body;
|
|
17329
17322
|
this.cause = options.cause;
|
|
17330
17323
|
this.errorCode = options.errorCode;
|
|
17324
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
17331
17325
|
}
|
|
17332
17326
|
};
|
|
17327
|
+
function parseRetryAfterHeader(headerValue) {
|
|
17328
|
+
if (!headerValue) return void 0;
|
|
17329
|
+
if (/^\d+$/.test(headerValue)) {
|
|
17330
|
+
const seconds = parseInt(headerValue, 10);
|
|
17331
|
+
return seconds * 1e3;
|
|
17332
|
+
}
|
|
17333
|
+
const date = new Date(headerValue);
|
|
17334
|
+
if (!isNaN(date.getTime())) {
|
|
17335
|
+
const delayMs = date.getTime() - Date.now();
|
|
17336
|
+
return delayMs > 0 ? delayMs : void 0;
|
|
17337
|
+
}
|
|
17338
|
+
return void 0;
|
|
17339
|
+
}
|
|
17333
17340
|
function buildEndpointURL(baseURL, endpoint) {
|
|
17334
17341
|
return baseURL + API_ENDPOINTS[endpoint].path;
|
|
17335
17342
|
}
|
|
@@ -17546,6 +17553,7 @@ function createParsedClient(rawClient) {
|
|
|
17546
17553
|
if (!response.ok) {
|
|
17547
17554
|
const body = await parseErrorBody(response);
|
|
17548
17555
|
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
17556
|
+
const retryAfterMs = parseRetryAfterHeader(response.headers.get("retry-after"));
|
|
17549
17557
|
throw new ApiRequestError(
|
|
17550
17558
|
`Request to ${String(endpoint)} failed with status ${response.status}`,
|
|
17551
17559
|
{
|
|
@@ -17554,7 +17562,8 @@ function createParsedClient(rawClient) {
|
|
|
17554
17562
|
method: config.method,
|
|
17555
17563
|
auth,
|
|
17556
17564
|
requestId,
|
|
17557
|
-
body
|
|
17565
|
+
body,
|
|
17566
|
+
retryAfterMs
|
|
17558
17567
|
}
|
|
17559
17568
|
);
|
|
17560
17569
|
}
|
|
@@ -17602,38 +17611,117 @@ var SimpleCache = class {
|
|
|
17602
17611
|
this.cache = /* @__PURE__ */ new Map();
|
|
17603
17612
|
this.maxSize = options.maxSize ?? 100;
|
|
17604
17613
|
this.ttl = options.ttl ?? 3e5;
|
|
17614
|
+
this.staleTtl = options.staleTtl ?? 3e5;
|
|
17615
|
+
}
|
|
17616
|
+
/**
|
|
17617
|
+
* Get a fresh value (within TTL)
|
|
17618
|
+
* @returns The value if fresh, null otherwise
|
|
17619
|
+
*/
|
|
17620
|
+
getFresh(key) {
|
|
17621
|
+
const entry = this.cache.get(key);
|
|
17622
|
+
if (!entry) return null;
|
|
17623
|
+
const now = Date.now();
|
|
17624
|
+
if (now <= entry.freshUntil) {
|
|
17625
|
+
return entry.value;
|
|
17626
|
+
}
|
|
17627
|
+
return null;
|
|
17605
17628
|
}
|
|
17606
|
-
|
|
17629
|
+
/**
|
|
17630
|
+
* Get a value that may be stale (past TTL but within staleTtl)
|
|
17631
|
+
* @returns Object with value and stale age, or null if expired
|
|
17632
|
+
*/
|
|
17633
|
+
getStale(key) {
|
|
17607
17634
|
const entry = this.cache.get(key);
|
|
17608
|
-
if (!entry) return
|
|
17609
|
-
|
|
17635
|
+
if (!entry) return null;
|
|
17636
|
+
const now = Date.now();
|
|
17637
|
+
if (now > entry.staleUntil) {
|
|
17610
17638
|
this.cache.delete(key);
|
|
17611
|
-
return
|
|
17639
|
+
return null;
|
|
17612
17640
|
}
|
|
17613
|
-
|
|
17641
|
+
const staleAgeSec = now <= entry.freshUntil ? 0 : Math.floor((now - entry.freshUntil) / 1e3);
|
|
17642
|
+
return {
|
|
17643
|
+
value: entry.value,
|
|
17644
|
+
staleAgeSec
|
|
17645
|
+
};
|
|
17614
17646
|
}
|
|
17615
|
-
|
|
17616
|
-
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
|
|
17647
|
+
/**
|
|
17648
|
+
* Store a value with TTL and stale window
|
|
17649
|
+
*/
|
|
17650
|
+
set(key, value, options) {
|
|
17651
|
+
const ttl = options?.ttl ?? this.ttl;
|
|
17652
|
+
const staleTtl = options?.staleTtl ?? this.staleTtl;
|
|
17653
|
+
const now = Date.now();
|
|
17654
|
+
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
17655
|
+
this.evictOne(now);
|
|
17621
17656
|
}
|
|
17622
17657
|
this.cache.set(key, {
|
|
17623
17658
|
value,
|
|
17624
|
-
|
|
17659
|
+
createdAt: now,
|
|
17660
|
+
freshUntil: now + ttl,
|
|
17661
|
+
staleUntil: now + ttl + staleTtl
|
|
17625
17662
|
});
|
|
17626
17663
|
}
|
|
17664
|
+
/**
|
|
17665
|
+
* Evict one entry to make room for a new one
|
|
17666
|
+
* Priority: oldest stale entry, then oldest fresh entry
|
|
17667
|
+
*/
|
|
17668
|
+
evictOne(now) {
|
|
17669
|
+
let oldestStaleKey = null;
|
|
17670
|
+
let oldestStaleTime = Infinity;
|
|
17671
|
+
let oldestFreshKey = null;
|
|
17672
|
+
let oldestFreshTime = Infinity;
|
|
17673
|
+
for (const [key, entry] of this.cache) {
|
|
17674
|
+
if (now > entry.freshUntil) {
|
|
17675
|
+
if (entry.createdAt < oldestStaleTime) {
|
|
17676
|
+
oldestStaleTime = entry.createdAt;
|
|
17677
|
+
oldestStaleKey = key;
|
|
17678
|
+
}
|
|
17679
|
+
} else {
|
|
17680
|
+
if (entry.createdAt < oldestFreshTime) {
|
|
17681
|
+
oldestFreshTime = entry.createdAt;
|
|
17682
|
+
oldestFreshKey = key;
|
|
17683
|
+
}
|
|
17684
|
+
}
|
|
17685
|
+
}
|
|
17686
|
+
const keyToEvict = oldestStaleKey ?? oldestFreshKey;
|
|
17687
|
+
if (keyToEvict) {
|
|
17688
|
+
this.cache.delete(keyToEvict);
|
|
17689
|
+
}
|
|
17690
|
+
}
|
|
17691
|
+
/**
|
|
17692
|
+
* Remove all fully expired entries (past staleUntil)
|
|
17693
|
+
*/
|
|
17694
|
+
prune() {
|
|
17695
|
+
const now = Date.now();
|
|
17696
|
+
for (const [key, entry] of this.cache) {
|
|
17697
|
+
if (now > entry.staleUntil) {
|
|
17698
|
+
this.cache.delete(key);
|
|
17699
|
+
}
|
|
17700
|
+
}
|
|
17701
|
+
}
|
|
17702
|
+
/**
|
|
17703
|
+
* Clear all entries
|
|
17704
|
+
*/
|
|
17627
17705
|
clear() {
|
|
17628
17706
|
this.cache.clear();
|
|
17629
17707
|
}
|
|
17708
|
+
/**
|
|
17709
|
+
* Check if a key exists and is not fully expired
|
|
17710
|
+
*/
|
|
17630
17711
|
has(key) {
|
|
17631
|
-
|
|
17712
|
+
const entry = this.cache.get(key);
|
|
17713
|
+
if (!entry) return false;
|
|
17714
|
+
const now = Date.now();
|
|
17715
|
+
if (now > entry.staleUntil) {
|
|
17716
|
+
this.cache.delete(key);
|
|
17717
|
+
return false;
|
|
17718
|
+
}
|
|
17719
|
+
return now <= entry.freshUntil;
|
|
17632
17720
|
}
|
|
17633
17721
|
};
|
|
17634
17722
|
|
|
17635
17723
|
// src/version.ts
|
|
17636
|
-
var SDK_VERSION = "0.7.
|
|
17724
|
+
var SDK_VERSION = "0.7.2";
|
|
17637
17725
|
|
|
17638
17726
|
// src/client/error.ts
|
|
17639
17727
|
var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
@@ -17645,8 +17733,31 @@ var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
|
17645
17733
|
this.status = apiError.status;
|
|
17646
17734
|
this.fieldErrors = apiError.fieldErrors;
|
|
17647
17735
|
this.timestamp = apiError.timestamp;
|
|
17736
|
+
this.retryAfterMs = "retryAfterMs" in apiError ? apiError.retryAfterMs : void 0;
|
|
17737
|
+
this.isRetryable = this.computeRetryable();
|
|
17648
17738
|
Object.setPrototypeOf(this, _RiverbankApiError.prototype);
|
|
17649
17739
|
}
|
|
17740
|
+
/**
|
|
17741
|
+
* Compute whether this error is retryable based on HTTP status code.
|
|
17742
|
+
* - 0 (network errors - no HTTP response): retryable
|
|
17743
|
+
* - 429 (rate limit): retryable
|
|
17744
|
+
* - 5xx (server errors): retryable
|
|
17745
|
+
* - 4xx (client errors, except 429): NOT retryable
|
|
17746
|
+
*/
|
|
17747
|
+
computeRetryable() {
|
|
17748
|
+
if (this.status === 0) return true;
|
|
17749
|
+
if (this.status === 429) return true;
|
|
17750
|
+
if (this.status >= 500) return true;
|
|
17751
|
+
return false;
|
|
17752
|
+
}
|
|
17753
|
+
/**
|
|
17754
|
+
* Check if this is a network error (no HTTP response received)
|
|
17755
|
+
*
|
|
17756
|
+
* Matches: network:connection_error, network:timeout, network:dns_error
|
|
17757
|
+
*/
|
|
17758
|
+
isNetworkError() {
|
|
17759
|
+
return this.code.startsWith("network:");
|
|
17760
|
+
}
|
|
17650
17761
|
/**
|
|
17651
17762
|
* Check if this error matches a specific error code
|
|
17652
17763
|
*
|
|
@@ -17705,9 +17816,215 @@ var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
|
17705
17816
|
}
|
|
17706
17817
|
};
|
|
17707
17818
|
|
|
17819
|
+
// src/client/resilience.ts
|
|
17820
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
17821
|
+
maxAttempts: 3,
|
|
17822
|
+
baseDelayMs: 200,
|
|
17823
|
+
maxDelayMs: 2e3,
|
|
17824
|
+
jitter: "full"
|
|
17825
|
+
};
|
|
17826
|
+
var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
|
|
17827
|
+
failureThreshold: 5,
|
|
17828
|
+
resetTimeoutMs: 3e4,
|
|
17829
|
+
halfOpenMaxRequests: 2
|
|
17830
|
+
};
|
|
17831
|
+
function isTransientError(error) {
|
|
17832
|
+
if (error instanceof RiverbankApiError) {
|
|
17833
|
+
if (error.status === 0) return true;
|
|
17834
|
+
if (error.status === 429) return true;
|
|
17835
|
+
if (error.status >= 500) return true;
|
|
17836
|
+
return false;
|
|
17837
|
+
}
|
|
17838
|
+
return true;
|
|
17839
|
+
}
|
|
17840
|
+
function calculateBackoff(attempt, config) {
|
|
17841
|
+
const baseDelayMs = config.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs;
|
|
17842
|
+
const maxDelayMs = config.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs;
|
|
17843
|
+
const jitter = config.jitter ?? DEFAULT_RETRY_CONFIG.jitter;
|
|
17844
|
+
const exponential = baseDelayMs * Math.pow(2, attempt - 1);
|
|
17845
|
+
const capped = Math.min(exponential, maxDelayMs);
|
|
17846
|
+
if (jitter === "full") {
|
|
17847
|
+
return Math.random() * capped;
|
|
17848
|
+
}
|
|
17849
|
+
return capped;
|
|
17850
|
+
}
|
|
17851
|
+
var CircuitBreaker = class {
|
|
17852
|
+
constructor(config) {
|
|
17853
|
+
this.state = "closed";
|
|
17854
|
+
this.failureCount = 0;
|
|
17855
|
+
this.successCount = 0;
|
|
17856
|
+
this.openUntil = 0;
|
|
17857
|
+
this.halfOpenRequests = 0;
|
|
17858
|
+
this.config = {
|
|
17859
|
+
failureThreshold: config?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
17860
|
+
resetTimeoutMs: config?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
|
|
17861
|
+
halfOpenMaxRequests: config?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
|
|
17862
|
+
};
|
|
17863
|
+
}
|
|
17864
|
+
/**
|
|
17865
|
+
* Check if circuit is open (requests should be blocked)
|
|
17866
|
+
* Also handles automatic transition from open to half-open after timeout
|
|
17867
|
+
*/
|
|
17868
|
+
isOpen() {
|
|
17869
|
+
if (this.state === "open" && Date.now() >= this.openUntil) {
|
|
17870
|
+
this.transitionTo("half-open");
|
|
17871
|
+
}
|
|
17872
|
+
return this.state === "open";
|
|
17873
|
+
}
|
|
17874
|
+
/**
|
|
17875
|
+
* Check if a request can be attempted
|
|
17876
|
+
* - closed: always yes
|
|
17877
|
+
* - open: always no
|
|
17878
|
+
* - half-open: limited number of probes
|
|
17879
|
+
*/
|
|
17880
|
+
canAttempt() {
|
|
17881
|
+
if (this.state === "closed") return true;
|
|
17882
|
+
if (this.state === "open") return false;
|
|
17883
|
+
return this.halfOpenRequests < this.config.halfOpenMaxRequests;
|
|
17884
|
+
}
|
|
17885
|
+
/**
|
|
17886
|
+
* Increment half-open request counter (call before making request in half-open)
|
|
17887
|
+
*/
|
|
17888
|
+
incrementHalfOpenRequests() {
|
|
17889
|
+
if (this.state === "half-open") {
|
|
17890
|
+
this.halfOpenRequests++;
|
|
17891
|
+
}
|
|
17892
|
+
}
|
|
17893
|
+
/**
|
|
17894
|
+
* Record a successful request
|
|
17895
|
+
*/
|
|
17896
|
+
recordSuccess() {
|
|
17897
|
+
if (this.state === "half-open") {
|
|
17898
|
+
this.successCount++;
|
|
17899
|
+
if (this.successCount >= this.config.halfOpenMaxRequests) {
|
|
17900
|
+
this.transitionTo("closed");
|
|
17901
|
+
}
|
|
17902
|
+
} else {
|
|
17903
|
+
this.failureCount = 0;
|
|
17904
|
+
}
|
|
17905
|
+
}
|
|
17906
|
+
/**
|
|
17907
|
+
* Record a failed request
|
|
17908
|
+
* Only counts transient failures toward circuit breaker threshold
|
|
17909
|
+
*/
|
|
17910
|
+
recordFailure(error) {
|
|
17911
|
+
if (!isTransientError(error)) return;
|
|
17912
|
+
this.failureCount++;
|
|
17913
|
+
if (this.state === "half-open") {
|
|
17914
|
+
this.transitionTo("open");
|
|
17915
|
+
} else if (this.failureCount >= this.config.failureThreshold) {
|
|
17916
|
+
this.transitionTo("open");
|
|
17917
|
+
}
|
|
17918
|
+
}
|
|
17919
|
+
/**
|
|
17920
|
+
* Get current circuit state
|
|
17921
|
+
*/
|
|
17922
|
+
getState() {
|
|
17923
|
+
return {
|
|
17924
|
+
state: this.state,
|
|
17925
|
+
failureCount: this.failureCount,
|
|
17926
|
+
openUntil: this.state === "open" ? this.openUntil : void 0
|
|
17927
|
+
};
|
|
17928
|
+
}
|
|
17929
|
+
/**
|
|
17930
|
+
* Transition to a new state
|
|
17931
|
+
*/
|
|
17932
|
+
transitionTo(newState) {
|
|
17933
|
+
this.state = newState;
|
|
17934
|
+
if (newState === "open") {
|
|
17935
|
+
this.openUntil = Date.now() + this.config.resetTimeoutMs;
|
|
17936
|
+
} else if (newState === "half-open") {
|
|
17937
|
+
this.halfOpenRequests = 0;
|
|
17938
|
+
this.successCount = 0;
|
|
17939
|
+
} else if (newState === "closed") {
|
|
17940
|
+
this.failureCount = 0;
|
|
17941
|
+
this.successCount = 0;
|
|
17942
|
+
this.halfOpenRequests = 0;
|
|
17943
|
+
}
|
|
17944
|
+
}
|
|
17945
|
+
};
|
|
17946
|
+
async function fetchWithTimeoutAndRetry(fetcher, config) {
|
|
17947
|
+
const maxAttempts = config.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts;
|
|
17948
|
+
const requestTimeoutMs = config.requestTimeoutMs ?? 8e3;
|
|
17949
|
+
let lastError;
|
|
17950
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
17951
|
+
try {
|
|
17952
|
+
const controller = new AbortController();
|
|
17953
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
17954
|
+
try {
|
|
17955
|
+
const result = await fetcher(controller.signal);
|
|
17956
|
+
return result;
|
|
17957
|
+
} finally {
|
|
17958
|
+
clearTimeout(timeoutId);
|
|
17959
|
+
}
|
|
17960
|
+
} catch (error) {
|
|
17961
|
+
lastError = error;
|
|
17962
|
+
const shouldRetry = shouldRetryError(error, config.retryOn);
|
|
17963
|
+
if (!shouldRetry) {
|
|
17964
|
+
throw error;
|
|
17965
|
+
}
|
|
17966
|
+
if (attempt < maxAttempts) {
|
|
17967
|
+
const delay = getRetryDelay(error, attempt, config);
|
|
17968
|
+
await sleep(delay);
|
|
17969
|
+
}
|
|
17970
|
+
}
|
|
17971
|
+
}
|
|
17972
|
+
throw lastError;
|
|
17973
|
+
}
|
|
17974
|
+
function shouldRetryError(error, customRetryOn) {
|
|
17975
|
+
if (customRetryOn) {
|
|
17976
|
+
const statusCode = error instanceof RiverbankApiError ? error.status : void 0;
|
|
17977
|
+
return customRetryOn(error, statusCode);
|
|
17978
|
+
}
|
|
17979
|
+
return isTransientError(error);
|
|
17980
|
+
}
|
|
17981
|
+
function getRetryDelay(error, attempt, config) {
|
|
17982
|
+
if (error instanceof RiverbankApiError && error.retryAfterMs) {
|
|
17983
|
+
return error.retryAfterMs;
|
|
17984
|
+
}
|
|
17985
|
+
return calculateBackoff(attempt, config);
|
|
17986
|
+
}
|
|
17987
|
+
function sleep(ms) {
|
|
17988
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
17989
|
+
}
|
|
17990
|
+
var CircuitOpenError = class extends Error {
|
|
17991
|
+
constructor(state) {
|
|
17992
|
+
super("Circuit breaker is open");
|
|
17993
|
+
this.name = "CircuitOpenError";
|
|
17994
|
+
this.circuitState = state;
|
|
17995
|
+
}
|
|
17996
|
+
};
|
|
17997
|
+
|
|
17708
17998
|
// src/client/index.ts
|
|
17709
17999
|
setSdkVersion(SDK_VERSION);
|
|
18000
|
+
var DEFAULT_BROWSER_TIMEOUT_MS = 5e3;
|
|
18001
|
+
var DEFAULT_SERVER_TIMEOUT_MS = 8e3;
|
|
18002
|
+
function generateRequestId2() {
|
|
18003
|
+
return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
18004
|
+
}
|
|
18005
|
+
function isAbortError(error) {
|
|
18006
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
18007
|
+
return true;
|
|
18008
|
+
}
|
|
18009
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
18010
|
+
return true;
|
|
18011
|
+
}
|
|
18012
|
+
return false;
|
|
18013
|
+
}
|
|
18014
|
+
function getNetworkErrorCode(error) {
|
|
18015
|
+
const message = error.message.toLowerCase();
|
|
18016
|
+
if (message.includes("timeout") || message.includes("timed out")) {
|
|
18017
|
+
return "network:timeout";
|
|
18018
|
+
}
|
|
18019
|
+
if (message.includes("dns") || message.includes("getaddrinfo") || message.includes("enotfound")) {
|
|
18020
|
+
return "network:dns_error";
|
|
18021
|
+
}
|
|
18022
|
+
return "network:connection_error";
|
|
18023
|
+
}
|
|
17710
18024
|
function convertToTypedError(error) {
|
|
18025
|
+
if (isAbortError(error)) {
|
|
18026
|
+
throw error;
|
|
18027
|
+
}
|
|
17711
18028
|
if (error instanceof ApiEnvelopeError) {
|
|
17712
18029
|
throw new RiverbankApiError({
|
|
17713
18030
|
code: error.code,
|
|
@@ -17721,15 +18038,30 @@ function convertToTypedError(error) {
|
|
|
17721
18038
|
if (error instanceof ApiRequestError && error.body && typeof error.body === "object") {
|
|
17722
18039
|
const body = error.body;
|
|
17723
18040
|
if (isApiError(body)) {
|
|
17724
|
-
|
|
18041
|
+
const envelopeError = body.error;
|
|
18042
|
+
throw new RiverbankApiError({
|
|
18043
|
+
...envelopeError,
|
|
18044
|
+
retryAfterMs: error.retryAfterMs
|
|
18045
|
+
});
|
|
17725
18046
|
}
|
|
17726
18047
|
}
|
|
18048
|
+
if (error instanceof TypeError || error instanceof Error && !("status" in error)) {
|
|
18049
|
+
const networkError = error;
|
|
18050
|
+
throw new RiverbankApiError({
|
|
18051
|
+
code: getNetworkErrorCode(networkError),
|
|
18052
|
+
message: networkError.message || "Network request failed",
|
|
18053
|
+
requestId: `local-${Date.now()}`,
|
|
18054
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18055
|
+
status: 0
|
|
18056
|
+
// No HTTP response received
|
|
18057
|
+
});
|
|
18058
|
+
}
|
|
17727
18059
|
throw error;
|
|
17728
18060
|
}
|
|
17729
18061
|
function createRiverbankClient(config) {
|
|
17730
18062
|
if (!config.baseUrl) {
|
|
17731
18063
|
throw new Error(
|
|
17732
|
-
"baseUrl is required when creating a
|
|
18064
|
+
"baseUrl is required when creating a Riverbank client. Expected format: https://dashboard.example.com/api (must include /api path)"
|
|
17733
18065
|
);
|
|
17734
18066
|
}
|
|
17735
18067
|
if (!config.baseUrl.endsWith("/api")) {
|
|
@@ -17740,59 +18072,179 @@ function createRiverbankClient(config) {
|
|
|
17740
18072
|
const cacheEnabled = config.cache?.enabled ?? true;
|
|
17741
18073
|
const cacheTTL = (config.cache?.ttl ?? 300) * 1e3;
|
|
17742
18074
|
const cacheMaxSize = config.cache?.maxSize ?? 100;
|
|
18075
|
+
const resilienceEnabled = config.resilience?.enabled ?? true;
|
|
18076
|
+
const staleIfError = config.resilience?.staleIfError ?? true;
|
|
18077
|
+
const staleTtlMs = (config.resilience?.staleTtlSec ?? 300) * 1e3;
|
|
18078
|
+
const requestTimeoutMs = config.resilience?.requestTimeoutMs ?? (typeof window !== "undefined" ? DEFAULT_BROWSER_TIMEOUT_MS : DEFAULT_SERVER_TIMEOUT_MS);
|
|
18079
|
+
const retryConfig = {
|
|
18080
|
+
maxAttempts: config.resilience?.retry?.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts,
|
|
18081
|
+
baseDelayMs: config.resilience?.retry?.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs,
|
|
18082
|
+
maxDelayMs: config.resilience?.retry?.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs,
|
|
18083
|
+
jitter: config.resilience?.retry?.jitter ?? DEFAULT_RETRY_CONFIG.jitter,
|
|
18084
|
+
retryOn: config.resilience?.retry?.retryOn
|
|
18085
|
+
};
|
|
18086
|
+
const circuitBreakerConfig = {
|
|
18087
|
+
failureThreshold: config.resilience?.circuitBreaker?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
18088
|
+
resetTimeoutMs: config.resilience?.circuitBreaker?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
|
|
18089
|
+
halfOpenMaxRequests: config.resilience?.circuitBreaker?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
|
|
18090
|
+
};
|
|
17743
18091
|
const apiClient = createBearerAPIClient(config.apiKey, config.baseUrl);
|
|
17744
18092
|
const cache = new SimpleCache({
|
|
17745
18093
|
maxSize: cacheMaxSize,
|
|
17746
|
-
ttl: cacheTTL
|
|
18094
|
+
ttl: cacheTTL,
|
|
18095
|
+
staleTtl: staleTtlMs
|
|
17747
18096
|
});
|
|
17748
|
-
|
|
17749
|
-
|
|
17750
|
-
|
|
17751
|
-
|
|
17752
|
-
|
|
18097
|
+
const circuitBreaker = new CircuitBreaker(circuitBreakerConfig);
|
|
18098
|
+
let lastStatus = null;
|
|
18099
|
+
let isDegraded = false;
|
|
18100
|
+
function emitStatus(source, data, details) {
|
|
18101
|
+
const status = {
|
|
18102
|
+
source,
|
|
18103
|
+
isPreview: details.isPreview,
|
|
18104
|
+
cacheKey: details.cacheKey,
|
|
18105
|
+
error: details.error,
|
|
18106
|
+
staleAgeSec: details.staleAgeSec,
|
|
18107
|
+
circuit: circuitBreaker.getState(),
|
|
18108
|
+
requestId: details.requestId,
|
|
18109
|
+
durationMs: details.durationMs
|
|
18110
|
+
};
|
|
18111
|
+
lastStatus = status;
|
|
18112
|
+
config.resilience?.onStatusChange?.(status);
|
|
18113
|
+
const nowDegraded = source === "stale" || source === "error";
|
|
18114
|
+
if (nowDegraded !== isDegraded) {
|
|
18115
|
+
isDegraded = nowDegraded;
|
|
18116
|
+
config.resilience?.onDegradedMode?.(nowDegraded, status);
|
|
18117
|
+
}
|
|
18118
|
+
return data;
|
|
18119
|
+
}
|
|
18120
|
+
async function resilientFetch(cacheKey, fetcher, options) {
|
|
18121
|
+
const requestId = generateRequestId2();
|
|
18122
|
+
const startTime = Date.now();
|
|
18123
|
+
const isPreview = options.preview ?? false;
|
|
18124
|
+
const statusDetails = (extra = {}) => ({
|
|
18125
|
+
requestId,
|
|
18126
|
+
cacheKey,
|
|
18127
|
+
isPreview,
|
|
18128
|
+
durationMs: Date.now() - startTime,
|
|
18129
|
+
...extra
|
|
18130
|
+
});
|
|
18131
|
+
if (cacheEnabled && !options.force) {
|
|
18132
|
+
const fresh = cache.getFresh(cacheKey);
|
|
18133
|
+
if (fresh !== null) {
|
|
18134
|
+
return emitStatus("cache", fresh, statusDetails());
|
|
18135
|
+
}
|
|
18136
|
+
}
|
|
18137
|
+
if (resilienceEnabled && circuitBreaker.isOpen()) {
|
|
18138
|
+
if (!isPreview && staleIfError) {
|
|
18139
|
+
const stale = cache.getStale(cacheKey);
|
|
18140
|
+
if (stale) {
|
|
18141
|
+
return emitStatus("stale", stale.value, statusDetails({
|
|
18142
|
+
staleAgeSec: stale.staleAgeSec,
|
|
18143
|
+
error: { code: "circuit_open", message: "Circuit breaker is open" }
|
|
18144
|
+
}));
|
|
18145
|
+
}
|
|
18146
|
+
}
|
|
18147
|
+
if (!options.force) {
|
|
18148
|
+
const circuitState = circuitBreaker.getState();
|
|
18149
|
+
emitStatus("error", null, statusDetails({
|
|
18150
|
+
error: { code: "circuit_open", message: "Circuit breaker is open" }
|
|
18151
|
+
}));
|
|
18152
|
+
throw new CircuitOpenError(circuitState);
|
|
17753
18153
|
}
|
|
17754
18154
|
}
|
|
17755
|
-
let data;
|
|
17756
18155
|
try {
|
|
17757
|
-
|
|
17758
|
-
|
|
18156
|
+
let data;
|
|
18157
|
+
if (resilienceEnabled) {
|
|
18158
|
+
if (circuitBreaker.getState().state === "half-open") {
|
|
18159
|
+
circuitBreaker.incrementHalfOpenRequests();
|
|
18160
|
+
}
|
|
18161
|
+
data = await fetchWithTimeoutAndRetry(
|
|
18162
|
+
async (timeoutSignal) => {
|
|
18163
|
+
const combinedSignal = options.signal ? combineAbortSignals(timeoutSignal, options.signal) : timeoutSignal;
|
|
18164
|
+
try {
|
|
18165
|
+
const response = await fetcher(combinedSignal);
|
|
18166
|
+
return unwrapResponse(response);
|
|
18167
|
+
} catch (error) {
|
|
18168
|
+
convertToTypedError(error);
|
|
18169
|
+
}
|
|
18170
|
+
},
|
|
18171
|
+
{
|
|
18172
|
+
...retryConfig,
|
|
18173
|
+
requestTimeoutMs
|
|
18174
|
+
}
|
|
18175
|
+
);
|
|
18176
|
+
circuitBreaker.recordSuccess();
|
|
18177
|
+
} else {
|
|
18178
|
+
try {
|
|
18179
|
+
const response = await fetcher(options.signal ?? new AbortController().signal);
|
|
18180
|
+
data = unwrapResponse(response);
|
|
18181
|
+
} catch (error) {
|
|
18182
|
+
convertToTypedError(error);
|
|
18183
|
+
}
|
|
18184
|
+
}
|
|
18185
|
+
if (cacheEnabled) {
|
|
18186
|
+
cache.set(cacheKey, data);
|
|
18187
|
+
}
|
|
18188
|
+
return emitStatus("live", data, statusDetails());
|
|
17759
18189
|
} catch (error) {
|
|
17760
|
-
|
|
18190
|
+
if (resilienceEnabled && error instanceof Error) {
|
|
18191
|
+
circuitBreaker.recordFailure(error);
|
|
18192
|
+
}
|
|
18193
|
+
if (!isPreview && staleIfError && cacheEnabled) {
|
|
18194
|
+
const stale = cache.getStale(cacheKey);
|
|
18195
|
+
if (stale) {
|
|
18196
|
+
const errorInfo2 = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
|
|
18197
|
+
return emitStatus("stale", stale.value, statusDetails({
|
|
18198
|
+
staleAgeSec: stale.staleAgeSec,
|
|
18199
|
+
error: errorInfo2
|
|
18200
|
+
}));
|
|
18201
|
+
}
|
|
18202
|
+
}
|
|
18203
|
+
const errorInfo = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
|
|
18204
|
+
emitStatus("error", null, statusDetails({ error: errorInfo }));
|
|
18205
|
+
throw error;
|
|
17761
18206
|
}
|
|
17762
|
-
|
|
17763
|
-
|
|
18207
|
+
}
|
|
18208
|
+
function combineAbortSignals(...signals) {
|
|
18209
|
+
const controller = new AbortController();
|
|
18210
|
+
for (const signal of signals) {
|
|
18211
|
+
if (signal.aborted) {
|
|
18212
|
+
controller.abort(signal.reason);
|
|
18213
|
+
break;
|
|
18214
|
+
}
|
|
18215
|
+
signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
|
|
17764
18216
|
}
|
|
17765
|
-
return
|
|
18217
|
+
return controller.signal;
|
|
17766
18218
|
}
|
|
17767
18219
|
return {
|
|
17768
18220
|
async getSite(params) {
|
|
17769
|
-
const { slug, domain, id } = params;
|
|
18221
|
+
const { slug, domain, id, signal } = params;
|
|
17770
18222
|
if (!slug && !domain && !id) {
|
|
17771
18223
|
throw new Error(
|
|
17772
18224
|
`getSite() requires at least one identifier: slug, domain, or id. Received: ${JSON.stringify(params)}`
|
|
17773
18225
|
);
|
|
17774
18226
|
}
|
|
17775
18227
|
const cacheKey = `site:${slug || domain || id}`;
|
|
17776
|
-
return
|
|
18228
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17777
18229
|
const apiParams = {};
|
|
17778
18230
|
if (params.slug) apiParams.slug = params.slug;
|
|
17779
18231
|
if (params.domain) apiParams.domain = params.domain;
|
|
17780
18232
|
if (params.id) apiParams.id = params.id;
|
|
17781
|
-
return await apiClient({ endpoint: "getSite", params: apiParams });
|
|
17782
|
-
});
|
|
18233
|
+
return await apiClient({ endpoint: "getSite", params: apiParams, options: { signal: sig } });
|
|
18234
|
+
}, { signal });
|
|
17783
18235
|
},
|
|
17784
18236
|
async getPage(params) {
|
|
17785
|
-
const { siteId, path, preview = false } = params;
|
|
18237
|
+
const { siteId, path, preview = false, signal } = params;
|
|
17786
18238
|
const cacheKey = `page:${siteId}:${path}:${preview}`;
|
|
17787
|
-
return
|
|
17788
|
-
return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path, preview } });
|
|
17789
|
-
});
|
|
18239
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
18240
|
+
return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path, preview }, options: { signal: sig } });
|
|
18241
|
+
}, { preview, signal });
|
|
17790
18242
|
},
|
|
17791
18243
|
async getEntries(params) {
|
|
17792
|
-
const { siteId, contentType, limit, offset, order, preview = false, mode, entryIds, includeMeta } = params;
|
|
18244
|
+
const { siteId, contentType, limit, offset, order, preview = false, mode, entryIds, includeMeta, signal } = params;
|
|
17793
18245
|
const entryIdsCacheKey = mode === "manual" && entryIds?.length ? entryIds.join(",") : "";
|
|
17794
18246
|
const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ""}:${offset ?? ""}:${order ?? ""}:${preview}:${mode ?? ""}:${entryIdsCacheKey}:${includeMeta ?? ""}`;
|
|
17795
|
-
return
|
|
18247
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17796
18248
|
let orderParam;
|
|
17797
18249
|
if (order === "newest") {
|
|
17798
18250
|
orderParam = "published_at.desc";
|
|
@@ -17814,47 +18266,47 @@ function createRiverbankClient(config) {
|
|
|
17814
18266
|
entryIds: JSON.stringify(entryIds)
|
|
17815
18267
|
}
|
|
17816
18268
|
};
|
|
17817
|
-
return await apiClient({ endpoint: "listPublishedEntries", params: apiParams });
|
|
17818
|
-
});
|
|
18269
|
+
return await apiClient({ endpoint: "listPublishedEntries", params: apiParams, options: { signal: sig } });
|
|
18270
|
+
}, { preview, signal });
|
|
17819
18271
|
},
|
|
17820
18272
|
async getEntry(params) {
|
|
17821
|
-
const { siteId, contentType, slug } = params;
|
|
18273
|
+
const { siteId, contentType, slug, signal } = params;
|
|
17822
18274
|
const cacheKey = `entry:${siteId}:${contentType}:${slug}`;
|
|
17823
|
-
return
|
|
17824
|
-
return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug } });
|
|
17825
|
-
});
|
|
18275
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
18276
|
+
return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug }, options: { signal: sig } });
|
|
18277
|
+
}, { signal });
|
|
17826
18278
|
},
|
|
17827
18279
|
async getPublicFormById(params) {
|
|
17828
|
-
const { formId } = params;
|
|
18280
|
+
const { formId, signal } = params;
|
|
17829
18281
|
if (!formId) {
|
|
17830
18282
|
throw new Error("getPublicFormById() requires formId");
|
|
17831
18283
|
}
|
|
17832
18284
|
const cacheKey = `public-form:${formId}`;
|
|
17833
|
-
return
|
|
17834
|
-
return await apiClient({ endpoint: "getPublicFormById", params: { formId } });
|
|
17835
|
-
});
|
|
18285
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
18286
|
+
return await apiClient({ endpoint: "getPublicFormById", params: { formId }, options: { signal: sig } });
|
|
18287
|
+
}, { signal });
|
|
17836
18288
|
},
|
|
17837
18289
|
async getPublicBookingServices(params) {
|
|
17838
|
-
const { siteId, ids } = params;
|
|
18290
|
+
const { siteId, ids, signal } = params;
|
|
17839
18291
|
if (!siteId) {
|
|
17840
18292
|
throw new Error("getPublicBookingServices() requires siteId");
|
|
17841
18293
|
}
|
|
17842
18294
|
const cacheKey = `public-booking-services:${siteId}:${ids ?? ""}`;
|
|
17843
|
-
return
|
|
18295
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17844
18296
|
const apiParams = {
|
|
17845
18297
|
siteId,
|
|
17846
18298
|
...ids && { ids }
|
|
17847
18299
|
};
|
|
17848
|
-
return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams });
|
|
17849
|
-
});
|
|
18300
|
+
return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams, options: { signal: sig } });
|
|
18301
|
+
}, { signal });
|
|
17850
18302
|
},
|
|
17851
18303
|
async listPublicEvents(params) {
|
|
17852
|
-
const { siteId, limit, from, to, stage } = params;
|
|
18304
|
+
const { siteId, limit, from, to, stage, signal } = params;
|
|
17853
18305
|
if (!siteId) {
|
|
17854
18306
|
throw new Error("listPublicEvents() requires siteId");
|
|
17855
18307
|
}
|
|
17856
18308
|
const cacheKey = `public-events:${siteId}:${limit ?? ""}:${from ?? ""}:${to ?? ""}:${stage ?? ""}`;
|
|
17857
|
-
return
|
|
18309
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17858
18310
|
const apiParams = {
|
|
17859
18311
|
siteId,
|
|
17860
18312
|
...typeof limit === "number" && { limit: String(limit) },
|
|
@@ -17862,40 +18314,46 @@ function createRiverbankClient(config) {
|
|
|
17862
18314
|
...to && { to },
|
|
17863
18315
|
...stage && { stage }
|
|
17864
18316
|
};
|
|
17865
|
-
return await apiClient({ endpoint: "listPublicEvents", params: apiParams });
|
|
17866
|
-
});
|
|
18317
|
+
return await apiClient({ endpoint: "listPublicEvents", params: apiParams, options: { signal: sig } });
|
|
18318
|
+
}, { signal });
|
|
17867
18319
|
},
|
|
17868
18320
|
async resolveEventOccurrence(params) {
|
|
17869
|
-
const { siteId, entryId, segment } = params;
|
|
18321
|
+
const { siteId, entryId, segment, signal } = params;
|
|
17870
18322
|
if (!siteId || !entryId || !segment) {
|
|
17871
18323
|
throw new Error("resolveEventOccurrence() requires siteId, entryId, and segment");
|
|
17872
18324
|
}
|
|
17873
18325
|
const cacheKey = `event-occurrence:${siteId}:${entryId}:${segment}`;
|
|
17874
|
-
return
|
|
18326
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17875
18327
|
return await apiClient({
|
|
17876
18328
|
endpoint: "resolveEventOccurrence",
|
|
17877
|
-
params: { siteId, entryId, segment }
|
|
18329
|
+
params: { siteId, entryId, segment },
|
|
18330
|
+
options: { signal: sig }
|
|
17878
18331
|
});
|
|
17879
|
-
});
|
|
18332
|
+
}, { signal });
|
|
17880
18333
|
},
|
|
17881
18334
|
async checkRedirect(params) {
|
|
17882
|
-
const { siteId, path } = params;
|
|
18335
|
+
const { siteId, path, signal } = params;
|
|
17883
18336
|
if (!siteId || !path) {
|
|
17884
18337
|
throw new Error("checkRedirect() requires siteId and path");
|
|
17885
18338
|
}
|
|
17886
18339
|
const cacheKey = `redirect:${siteId}:${path}`;
|
|
17887
|
-
return
|
|
18340
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
17888
18341
|
return await apiClient({
|
|
17889
18342
|
endpoint: "checkRedirect",
|
|
17890
|
-
params: { site: siteId, path }
|
|
18343
|
+
params: { site: siteId, path },
|
|
18344
|
+
options: { signal: sig }
|
|
17891
18345
|
});
|
|
17892
|
-
});
|
|
18346
|
+
}, { signal });
|
|
17893
18347
|
},
|
|
17894
18348
|
clearCache() {
|
|
17895
18349
|
cache.clear();
|
|
18350
|
+
},
|
|
18351
|
+
getLastEmittedStatus() {
|
|
18352
|
+
return lastStatus;
|
|
18353
|
+
},
|
|
18354
|
+
getCircuitState() {
|
|
18355
|
+
return circuitBreaker.getState();
|
|
17896
18356
|
}
|
|
17897
|
-
// Cast to RiverbankClient to satisfy overloaded getEntries signature
|
|
17898
|
-
// The implementation correctly returns the right type based on includeMeta
|
|
17899
18357
|
};
|
|
17900
18358
|
}
|
|
17901
18359
|
export {
|