@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
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
__require
|
|
3
|
-
} from "./chunk-BJTO5JO5.mjs";
|
|
4
|
-
|
|
5
1
|
// ../api/src/endpoints.ts
|
|
6
2
|
var ENDPOINT_DEFINITIONS = {
|
|
7
3
|
// AI endpoints - no cache due to dynamic nature
|
|
@@ -1659,10 +1655,10 @@ function resolveApiBaseUrl() {
|
|
|
1659
1655
|
var revalidateTag = null;
|
|
1660
1656
|
if (typeof window === "undefined") {
|
|
1661
1657
|
try {
|
|
1662
|
-
const
|
|
1663
|
-
|
|
1658
|
+
const dynamicRequire = new Function("modulePath", "return require(modulePath)");
|
|
1659
|
+
const nextCache = dynamicRequire("next/cache");
|
|
1660
|
+
revalidateTag = nextCache.revalidateTag ?? null;
|
|
1664
1661
|
} catch {
|
|
1665
|
-
revalidateTag = null;
|
|
1666
1662
|
}
|
|
1667
1663
|
}
|
|
1668
1664
|
var sdkVersion;
|
|
@@ -1691,8 +1687,22 @@ var ApiRequestError = class extends Error {
|
|
|
1691
1687
|
this.body = options.body;
|
|
1692
1688
|
this.cause = options.cause;
|
|
1693
1689
|
this.errorCode = options.errorCode;
|
|
1690
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
1694
1691
|
}
|
|
1695
1692
|
};
|
|
1693
|
+
function parseRetryAfterHeader(headerValue) {
|
|
1694
|
+
if (!headerValue) return void 0;
|
|
1695
|
+
if (/^\d+$/.test(headerValue)) {
|
|
1696
|
+
const seconds = parseInt(headerValue, 10);
|
|
1697
|
+
return seconds * 1e3;
|
|
1698
|
+
}
|
|
1699
|
+
const date = new Date(headerValue);
|
|
1700
|
+
if (!isNaN(date.getTime())) {
|
|
1701
|
+
const delayMs = date.getTime() - Date.now();
|
|
1702
|
+
return delayMs > 0 ? delayMs : void 0;
|
|
1703
|
+
}
|
|
1704
|
+
return void 0;
|
|
1705
|
+
}
|
|
1696
1706
|
function buildEndpointURL2(baseURL, endpoint) {
|
|
1697
1707
|
return baseURL + API_ENDPOINTS[endpoint].path;
|
|
1698
1708
|
}
|
|
@@ -1909,6 +1919,7 @@ function createParsedClient(rawClient) {
|
|
|
1909
1919
|
if (!response.ok) {
|
|
1910
1920
|
const body = await parseErrorBody(response);
|
|
1911
1921
|
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
1922
|
+
const retryAfterMs = parseRetryAfterHeader(response.headers.get("retry-after"));
|
|
1912
1923
|
throw new ApiRequestError(
|
|
1913
1924
|
`Request to ${String(endpoint)} failed with status ${response.status}`,
|
|
1914
1925
|
{
|
|
@@ -1917,7 +1928,8 @@ function createParsedClient(rawClient) {
|
|
|
1917
1928
|
method: config.method,
|
|
1918
1929
|
auth,
|
|
1919
1930
|
requestId,
|
|
1920
|
-
body
|
|
1931
|
+
body,
|
|
1932
|
+
retryAfterMs
|
|
1921
1933
|
}
|
|
1922
1934
|
);
|
|
1923
1935
|
}
|
|
@@ -1965,38 +1977,117 @@ var SimpleCache = class {
|
|
|
1965
1977
|
this.cache = /* @__PURE__ */ new Map();
|
|
1966
1978
|
this.maxSize = options.maxSize ?? 100;
|
|
1967
1979
|
this.ttl = options.ttl ?? 3e5;
|
|
1980
|
+
this.staleTtl = options.staleTtl ?? 3e5;
|
|
1968
1981
|
}
|
|
1969
|
-
|
|
1982
|
+
/**
|
|
1983
|
+
* Get a fresh value (within TTL)
|
|
1984
|
+
* @returns The value if fresh, null otherwise
|
|
1985
|
+
*/
|
|
1986
|
+
getFresh(key) {
|
|
1970
1987
|
const entry = this.cache.get(key);
|
|
1971
|
-
if (!entry) return
|
|
1972
|
-
|
|
1988
|
+
if (!entry) return null;
|
|
1989
|
+
const now = Date.now();
|
|
1990
|
+
if (now <= entry.freshUntil) {
|
|
1991
|
+
return entry.value;
|
|
1992
|
+
}
|
|
1993
|
+
return null;
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Get a value that may be stale (past TTL but within staleTtl)
|
|
1997
|
+
* @returns Object with value and stale age, or null if expired
|
|
1998
|
+
*/
|
|
1999
|
+
getStale(key) {
|
|
2000
|
+
const entry = this.cache.get(key);
|
|
2001
|
+
if (!entry) return null;
|
|
2002
|
+
const now = Date.now();
|
|
2003
|
+
if (now > entry.staleUntil) {
|
|
1973
2004
|
this.cache.delete(key);
|
|
1974
|
-
return
|
|
2005
|
+
return null;
|
|
1975
2006
|
}
|
|
1976
|
-
|
|
2007
|
+
const staleAgeSec = now <= entry.freshUntil ? 0 : Math.floor((now - entry.freshUntil) / 1e3);
|
|
2008
|
+
return {
|
|
2009
|
+
value: entry.value,
|
|
2010
|
+
staleAgeSec
|
|
2011
|
+
};
|
|
1977
2012
|
}
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
2013
|
+
/**
|
|
2014
|
+
* Store a value with TTL and stale window
|
|
2015
|
+
*/
|
|
2016
|
+
set(key, value, options) {
|
|
2017
|
+
const ttl = options?.ttl ?? this.ttl;
|
|
2018
|
+
const staleTtl = options?.staleTtl ?? this.staleTtl;
|
|
2019
|
+
const now = Date.now();
|
|
2020
|
+
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
2021
|
+
this.evictOne(now);
|
|
1984
2022
|
}
|
|
1985
2023
|
this.cache.set(key, {
|
|
1986
2024
|
value,
|
|
1987
|
-
|
|
2025
|
+
createdAt: now,
|
|
2026
|
+
freshUntil: now + ttl,
|
|
2027
|
+
staleUntil: now + ttl + staleTtl
|
|
1988
2028
|
});
|
|
1989
2029
|
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Evict one entry to make room for a new one
|
|
2032
|
+
* Priority: oldest stale entry, then oldest fresh entry
|
|
2033
|
+
*/
|
|
2034
|
+
evictOne(now) {
|
|
2035
|
+
let oldestStaleKey = null;
|
|
2036
|
+
let oldestStaleTime = Infinity;
|
|
2037
|
+
let oldestFreshKey = null;
|
|
2038
|
+
let oldestFreshTime = Infinity;
|
|
2039
|
+
for (const [key, entry] of this.cache) {
|
|
2040
|
+
if (now > entry.freshUntil) {
|
|
2041
|
+
if (entry.createdAt < oldestStaleTime) {
|
|
2042
|
+
oldestStaleTime = entry.createdAt;
|
|
2043
|
+
oldestStaleKey = key;
|
|
2044
|
+
}
|
|
2045
|
+
} else {
|
|
2046
|
+
if (entry.createdAt < oldestFreshTime) {
|
|
2047
|
+
oldestFreshTime = entry.createdAt;
|
|
2048
|
+
oldestFreshKey = key;
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
const keyToEvict = oldestStaleKey ?? oldestFreshKey;
|
|
2053
|
+
if (keyToEvict) {
|
|
2054
|
+
this.cache.delete(keyToEvict);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
/**
|
|
2058
|
+
* Remove all fully expired entries (past staleUntil)
|
|
2059
|
+
*/
|
|
2060
|
+
prune() {
|
|
2061
|
+
const now = Date.now();
|
|
2062
|
+
for (const [key, entry] of this.cache) {
|
|
2063
|
+
if (now > entry.staleUntil) {
|
|
2064
|
+
this.cache.delete(key);
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
/**
|
|
2069
|
+
* Clear all entries
|
|
2070
|
+
*/
|
|
1990
2071
|
clear() {
|
|
1991
2072
|
this.cache.clear();
|
|
1992
2073
|
}
|
|
2074
|
+
/**
|
|
2075
|
+
* Check if a key exists and is not fully expired
|
|
2076
|
+
*/
|
|
1993
2077
|
has(key) {
|
|
1994
|
-
|
|
2078
|
+
const entry = this.cache.get(key);
|
|
2079
|
+
if (!entry) return false;
|
|
2080
|
+
const now = Date.now();
|
|
2081
|
+
if (now > entry.staleUntil) {
|
|
2082
|
+
this.cache.delete(key);
|
|
2083
|
+
return false;
|
|
2084
|
+
}
|
|
2085
|
+
return now <= entry.freshUntil;
|
|
1995
2086
|
}
|
|
1996
2087
|
};
|
|
1997
2088
|
|
|
1998
2089
|
// src/version.ts
|
|
1999
|
-
var SDK_VERSION = "0.7.
|
|
2090
|
+
var SDK_VERSION = "0.7.2";
|
|
2000
2091
|
|
|
2001
2092
|
// src/client/error.ts
|
|
2002
2093
|
var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
@@ -2008,8 +2099,31 @@ var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
|
2008
2099
|
this.status = apiError.status;
|
|
2009
2100
|
this.fieldErrors = apiError.fieldErrors;
|
|
2010
2101
|
this.timestamp = apiError.timestamp;
|
|
2102
|
+
this.retryAfterMs = "retryAfterMs" in apiError ? apiError.retryAfterMs : void 0;
|
|
2103
|
+
this.isRetryable = this.computeRetryable();
|
|
2011
2104
|
Object.setPrototypeOf(this, _RiverbankApiError.prototype);
|
|
2012
2105
|
}
|
|
2106
|
+
/**
|
|
2107
|
+
* Compute whether this error is retryable based on HTTP status code.
|
|
2108
|
+
* - 0 (network errors - no HTTP response): retryable
|
|
2109
|
+
* - 429 (rate limit): retryable
|
|
2110
|
+
* - 5xx (server errors): retryable
|
|
2111
|
+
* - 4xx (client errors, except 429): NOT retryable
|
|
2112
|
+
*/
|
|
2113
|
+
computeRetryable() {
|
|
2114
|
+
if (this.status === 0) return true;
|
|
2115
|
+
if (this.status === 429) return true;
|
|
2116
|
+
if (this.status >= 500) return true;
|
|
2117
|
+
return false;
|
|
2118
|
+
}
|
|
2119
|
+
/**
|
|
2120
|
+
* Check if this is a network error (no HTTP response received)
|
|
2121
|
+
*
|
|
2122
|
+
* Matches: network:connection_error, network:timeout, network:dns_error
|
|
2123
|
+
*/
|
|
2124
|
+
isNetworkError() {
|
|
2125
|
+
return this.code.startsWith("network:");
|
|
2126
|
+
}
|
|
2013
2127
|
/**
|
|
2014
2128
|
* Check if this error matches a specific error code
|
|
2015
2129
|
*
|
|
@@ -2068,9 +2182,215 @@ var RiverbankApiError = class _RiverbankApiError extends Error {
|
|
|
2068
2182
|
}
|
|
2069
2183
|
};
|
|
2070
2184
|
|
|
2185
|
+
// src/client/resilience.ts
|
|
2186
|
+
var DEFAULT_RETRY_CONFIG = {
|
|
2187
|
+
maxAttempts: 3,
|
|
2188
|
+
baseDelayMs: 200,
|
|
2189
|
+
maxDelayMs: 2e3,
|
|
2190
|
+
jitter: "full"
|
|
2191
|
+
};
|
|
2192
|
+
var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
|
|
2193
|
+
failureThreshold: 5,
|
|
2194
|
+
resetTimeoutMs: 3e4,
|
|
2195
|
+
halfOpenMaxRequests: 2
|
|
2196
|
+
};
|
|
2197
|
+
function isTransientError(error) {
|
|
2198
|
+
if (error instanceof RiverbankApiError) {
|
|
2199
|
+
if (error.status === 0) return true;
|
|
2200
|
+
if (error.status === 429) return true;
|
|
2201
|
+
if (error.status >= 500) return true;
|
|
2202
|
+
return false;
|
|
2203
|
+
}
|
|
2204
|
+
return true;
|
|
2205
|
+
}
|
|
2206
|
+
function calculateBackoff(attempt, config) {
|
|
2207
|
+
const baseDelayMs = config.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs;
|
|
2208
|
+
const maxDelayMs = config.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs;
|
|
2209
|
+
const jitter = config.jitter ?? DEFAULT_RETRY_CONFIG.jitter;
|
|
2210
|
+
const exponential = baseDelayMs * Math.pow(2, attempt - 1);
|
|
2211
|
+
const capped = Math.min(exponential, maxDelayMs);
|
|
2212
|
+
if (jitter === "full") {
|
|
2213
|
+
return Math.random() * capped;
|
|
2214
|
+
}
|
|
2215
|
+
return capped;
|
|
2216
|
+
}
|
|
2217
|
+
var CircuitBreaker = class {
|
|
2218
|
+
constructor(config) {
|
|
2219
|
+
this.state = "closed";
|
|
2220
|
+
this.failureCount = 0;
|
|
2221
|
+
this.successCount = 0;
|
|
2222
|
+
this.openUntil = 0;
|
|
2223
|
+
this.halfOpenRequests = 0;
|
|
2224
|
+
this.config = {
|
|
2225
|
+
failureThreshold: config?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
2226
|
+
resetTimeoutMs: config?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
|
|
2227
|
+
halfOpenMaxRequests: config?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
|
|
2228
|
+
};
|
|
2229
|
+
}
|
|
2230
|
+
/**
|
|
2231
|
+
* Check if circuit is open (requests should be blocked)
|
|
2232
|
+
* Also handles automatic transition from open to half-open after timeout
|
|
2233
|
+
*/
|
|
2234
|
+
isOpen() {
|
|
2235
|
+
if (this.state === "open" && Date.now() >= this.openUntil) {
|
|
2236
|
+
this.transitionTo("half-open");
|
|
2237
|
+
}
|
|
2238
|
+
return this.state === "open";
|
|
2239
|
+
}
|
|
2240
|
+
/**
|
|
2241
|
+
* Check if a request can be attempted
|
|
2242
|
+
* - closed: always yes
|
|
2243
|
+
* - open: always no
|
|
2244
|
+
* - half-open: limited number of probes
|
|
2245
|
+
*/
|
|
2246
|
+
canAttempt() {
|
|
2247
|
+
if (this.state === "closed") return true;
|
|
2248
|
+
if (this.state === "open") return false;
|
|
2249
|
+
return this.halfOpenRequests < this.config.halfOpenMaxRequests;
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* Increment half-open request counter (call before making request in half-open)
|
|
2253
|
+
*/
|
|
2254
|
+
incrementHalfOpenRequests() {
|
|
2255
|
+
if (this.state === "half-open") {
|
|
2256
|
+
this.halfOpenRequests++;
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
/**
|
|
2260
|
+
* Record a successful request
|
|
2261
|
+
*/
|
|
2262
|
+
recordSuccess() {
|
|
2263
|
+
if (this.state === "half-open") {
|
|
2264
|
+
this.successCount++;
|
|
2265
|
+
if (this.successCount >= this.config.halfOpenMaxRequests) {
|
|
2266
|
+
this.transitionTo("closed");
|
|
2267
|
+
}
|
|
2268
|
+
} else {
|
|
2269
|
+
this.failureCount = 0;
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
/**
|
|
2273
|
+
* Record a failed request
|
|
2274
|
+
* Only counts transient failures toward circuit breaker threshold
|
|
2275
|
+
*/
|
|
2276
|
+
recordFailure(error) {
|
|
2277
|
+
if (!isTransientError(error)) return;
|
|
2278
|
+
this.failureCount++;
|
|
2279
|
+
if (this.state === "half-open") {
|
|
2280
|
+
this.transitionTo("open");
|
|
2281
|
+
} else if (this.failureCount >= this.config.failureThreshold) {
|
|
2282
|
+
this.transitionTo("open");
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
/**
|
|
2286
|
+
* Get current circuit state
|
|
2287
|
+
*/
|
|
2288
|
+
getState() {
|
|
2289
|
+
return {
|
|
2290
|
+
state: this.state,
|
|
2291
|
+
failureCount: this.failureCount,
|
|
2292
|
+
openUntil: this.state === "open" ? this.openUntil : void 0
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
/**
|
|
2296
|
+
* Transition to a new state
|
|
2297
|
+
*/
|
|
2298
|
+
transitionTo(newState) {
|
|
2299
|
+
this.state = newState;
|
|
2300
|
+
if (newState === "open") {
|
|
2301
|
+
this.openUntil = Date.now() + this.config.resetTimeoutMs;
|
|
2302
|
+
} else if (newState === "half-open") {
|
|
2303
|
+
this.halfOpenRequests = 0;
|
|
2304
|
+
this.successCount = 0;
|
|
2305
|
+
} else if (newState === "closed") {
|
|
2306
|
+
this.failureCount = 0;
|
|
2307
|
+
this.successCount = 0;
|
|
2308
|
+
this.halfOpenRequests = 0;
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
};
|
|
2312
|
+
async function fetchWithTimeoutAndRetry(fetcher, config) {
|
|
2313
|
+
const maxAttempts = config.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts;
|
|
2314
|
+
const requestTimeoutMs = config.requestTimeoutMs ?? 8e3;
|
|
2315
|
+
let lastError;
|
|
2316
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2317
|
+
try {
|
|
2318
|
+
const controller = new AbortController();
|
|
2319
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
2320
|
+
try {
|
|
2321
|
+
const result = await fetcher(controller.signal);
|
|
2322
|
+
return result;
|
|
2323
|
+
} finally {
|
|
2324
|
+
clearTimeout(timeoutId);
|
|
2325
|
+
}
|
|
2326
|
+
} catch (error) {
|
|
2327
|
+
lastError = error;
|
|
2328
|
+
const shouldRetry = shouldRetryError(error, config.retryOn);
|
|
2329
|
+
if (!shouldRetry) {
|
|
2330
|
+
throw error;
|
|
2331
|
+
}
|
|
2332
|
+
if (attempt < maxAttempts) {
|
|
2333
|
+
const delay = getRetryDelay(error, attempt, config);
|
|
2334
|
+
await sleep(delay);
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
throw lastError;
|
|
2339
|
+
}
|
|
2340
|
+
function shouldRetryError(error, customRetryOn) {
|
|
2341
|
+
if (customRetryOn) {
|
|
2342
|
+
const statusCode = error instanceof RiverbankApiError ? error.status : void 0;
|
|
2343
|
+
return customRetryOn(error, statusCode);
|
|
2344
|
+
}
|
|
2345
|
+
return isTransientError(error);
|
|
2346
|
+
}
|
|
2347
|
+
function getRetryDelay(error, attempt, config) {
|
|
2348
|
+
if (error instanceof RiverbankApiError && error.retryAfterMs) {
|
|
2349
|
+
return error.retryAfterMs;
|
|
2350
|
+
}
|
|
2351
|
+
return calculateBackoff(attempt, config);
|
|
2352
|
+
}
|
|
2353
|
+
function sleep(ms) {
|
|
2354
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2355
|
+
}
|
|
2356
|
+
var CircuitOpenError = class extends Error {
|
|
2357
|
+
constructor(state) {
|
|
2358
|
+
super("Circuit breaker is open");
|
|
2359
|
+
this.name = "CircuitOpenError";
|
|
2360
|
+
this.circuitState = state;
|
|
2361
|
+
}
|
|
2362
|
+
};
|
|
2363
|
+
|
|
2071
2364
|
// src/client/index.ts
|
|
2072
2365
|
setSdkVersion(SDK_VERSION);
|
|
2366
|
+
var DEFAULT_BROWSER_TIMEOUT_MS = 5e3;
|
|
2367
|
+
var DEFAULT_SERVER_TIMEOUT_MS = 8e3;
|
|
2368
|
+
function generateRequestId2() {
|
|
2369
|
+
return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
2370
|
+
}
|
|
2371
|
+
function isAbortError(error) {
|
|
2372
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
2373
|
+
return true;
|
|
2374
|
+
}
|
|
2375
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
2376
|
+
return true;
|
|
2377
|
+
}
|
|
2378
|
+
return false;
|
|
2379
|
+
}
|
|
2380
|
+
function getNetworkErrorCode(error) {
|
|
2381
|
+
const message = error.message.toLowerCase();
|
|
2382
|
+
if (message.includes("timeout") || message.includes("timed out")) {
|
|
2383
|
+
return "network:timeout";
|
|
2384
|
+
}
|
|
2385
|
+
if (message.includes("dns") || message.includes("getaddrinfo") || message.includes("enotfound")) {
|
|
2386
|
+
return "network:dns_error";
|
|
2387
|
+
}
|
|
2388
|
+
return "network:connection_error";
|
|
2389
|
+
}
|
|
2073
2390
|
function convertToTypedError(error) {
|
|
2391
|
+
if (isAbortError(error)) {
|
|
2392
|
+
throw error;
|
|
2393
|
+
}
|
|
2074
2394
|
if (error instanceof ApiEnvelopeError) {
|
|
2075
2395
|
throw new RiverbankApiError({
|
|
2076
2396
|
code: error.code,
|
|
@@ -2084,15 +2404,30 @@ function convertToTypedError(error) {
|
|
|
2084
2404
|
if (error instanceof ApiRequestError && error.body && typeof error.body === "object") {
|
|
2085
2405
|
const body = error.body;
|
|
2086
2406
|
if (isApiError(body)) {
|
|
2087
|
-
|
|
2407
|
+
const envelopeError = body.error;
|
|
2408
|
+
throw new RiverbankApiError({
|
|
2409
|
+
...envelopeError,
|
|
2410
|
+
retryAfterMs: error.retryAfterMs
|
|
2411
|
+
});
|
|
2088
2412
|
}
|
|
2089
2413
|
}
|
|
2414
|
+
if (error instanceof TypeError || error instanceof Error && !("status" in error)) {
|
|
2415
|
+
const networkError = error;
|
|
2416
|
+
throw new RiverbankApiError({
|
|
2417
|
+
code: getNetworkErrorCode(networkError),
|
|
2418
|
+
message: networkError.message || "Network request failed",
|
|
2419
|
+
requestId: `local-${Date.now()}`,
|
|
2420
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2421
|
+
status: 0
|
|
2422
|
+
// No HTTP response received
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2090
2425
|
throw error;
|
|
2091
2426
|
}
|
|
2092
2427
|
function createRiverbankClient(config) {
|
|
2093
2428
|
if (!config.baseUrl) {
|
|
2094
2429
|
throw new Error(
|
|
2095
|
-
"baseUrl is required when creating a
|
|
2430
|
+
"baseUrl is required when creating a Riverbank client. Expected format: https://dashboard.example.com/api (must include /api path)"
|
|
2096
2431
|
);
|
|
2097
2432
|
}
|
|
2098
2433
|
if (!config.baseUrl.endsWith("/api")) {
|
|
@@ -2103,59 +2438,179 @@ function createRiverbankClient(config) {
|
|
|
2103
2438
|
const cacheEnabled = config.cache?.enabled ?? true;
|
|
2104
2439
|
const cacheTTL = (config.cache?.ttl ?? 300) * 1e3;
|
|
2105
2440
|
const cacheMaxSize = config.cache?.maxSize ?? 100;
|
|
2441
|
+
const resilienceEnabled = config.resilience?.enabled ?? true;
|
|
2442
|
+
const staleIfError = config.resilience?.staleIfError ?? true;
|
|
2443
|
+
const staleTtlMs = (config.resilience?.staleTtlSec ?? 300) * 1e3;
|
|
2444
|
+
const requestTimeoutMs = config.resilience?.requestTimeoutMs ?? (typeof window !== "undefined" ? DEFAULT_BROWSER_TIMEOUT_MS : DEFAULT_SERVER_TIMEOUT_MS);
|
|
2445
|
+
const retryConfig = {
|
|
2446
|
+
maxAttempts: config.resilience?.retry?.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts,
|
|
2447
|
+
baseDelayMs: config.resilience?.retry?.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs,
|
|
2448
|
+
maxDelayMs: config.resilience?.retry?.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs,
|
|
2449
|
+
jitter: config.resilience?.retry?.jitter ?? DEFAULT_RETRY_CONFIG.jitter,
|
|
2450
|
+
retryOn: config.resilience?.retry?.retryOn
|
|
2451
|
+
};
|
|
2452
|
+
const circuitBreakerConfig = {
|
|
2453
|
+
failureThreshold: config.resilience?.circuitBreaker?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
|
|
2454
|
+
resetTimeoutMs: config.resilience?.circuitBreaker?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
|
|
2455
|
+
halfOpenMaxRequests: config.resilience?.circuitBreaker?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
|
|
2456
|
+
};
|
|
2106
2457
|
const apiClient = createBearerAPIClient(config.apiKey, config.baseUrl);
|
|
2107
2458
|
const cache = new SimpleCache({
|
|
2108
2459
|
maxSize: cacheMaxSize,
|
|
2109
|
-
ttl: cacheTTL
|
|
2460
|
+
ttl: cacheTTL,
|
|
2461
|
+
staleTtl: staleTtlMs
|
|
2110
2462
|
});
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2463
|
+
const circuitBreaker = new CircuitBreaker(circuitBreakerConfig);
|
|
2464
|
+
let lastStatus = null;
|
|
2465
|
+
let isDegraded = false;
|
|
2466
|
+
function emitStatus(source, data, details) {
|
|
2467
|
+
const status = {
|
|
2468
|
+
source,
|
|
2469
|
+
isPreview: details.isPreview,
|
|
2470
|
+
cacheKey: details.cacheKey,
|
|
2471
|
+
error: details.error,
|
|
2472
|
+
staleAgeSec: details.staleAgeSec,
|
|
2473
|
+
circuit: circuitBreaker.getState(),
|
|
2474
|
+
requestId: details.requestId,
|
|
2475
|
+
durationMs: details.durationMs
|
|
2476
|
+
};
|
|
2477
|
+
lastStatus = status;
|
|
2478
|
+
config.resilience?.onStatusChange?.(status);
|
|
2479
|
+
const nowDegraded = source === "stale" || source === "error";
|
|
2480
|
+
if (nowDegraded !== isDegraded) {
|
|
2481
|
+
isDegraded = nowDegraded;
|
|
2482
|
+
config.resilience?.onDegradedMode?.(nowDegraded, status);
|
|
2483
|
+
}
|
|
2484
|
+
return data;
|
|
2485
|
+
}
|
|
2486
|
+
async function resilientFetch(cacheKey, fetcher, options) {
|
|
2487
|
+
const requestId = generateRequestId2();
|
|
2488
|
+
const startTime = Date.now();
|
|
2489
|
+
const isPreview = options.preview ?? false;
|
|
2490
|
+
const statusDetails = (extra = {}) => ({
|
|
2491
|
+
requestId,
|
|
2492
|
+
cacheKey,
|
|
2493
|
+
isPreview,
|
|
2494
|
+
durationMs: Date.now() - startTime,
|
|
2495
|
+
...extra
|
|
2496
|
+
});
|
|
2497
|
+
if (cacheEnabled && !options.force) {
|
|
2498
|
+
const fresh = cache.getFresh(cacheKey);
|
|
2499
|
+
if (fresh !== null) {
|
|
2500
|
+
return emitStatus("cache", fresh, statusDetails());
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
if (resilienceEnabled && circuitBreaker.isOpen()) {
|
|
2504
|
+
if (!isPreview && staleIfError) {
|
|
2505
|
+
const stale = cache.getStale(cacheKey);
|
|
2506
|
+
if (stale) {
|
|
2507
|
+
return emitStatus("stale", stale.value, statusDetails({
|
|
2508
|
+
staleAgeSec: stale.staleAgeSec,
|
|
2509
|
+
error: { code: "circuit_open", message: "Circuit breaker is open" }
|
|
2510
|
+
}));
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
if (!options.force) {
|
|
2514
|
+
const circuitState = circuitBreaker.getState();
|
|
2515
|
+
emitStatus("error", null, statusDetails({
|
|
2516
|
+
error: { code: "circuit_open", message: "Circuit breaker is open" }
|
|
2517
|
+
}));
|
|
2518
|
+
throw new CircuitOpenError(circuitState);
|
|
2116
2519
|
}
|
|
2117
2520
|
}
|
|
2118
|
-
let data;
|
|
2119
2521
|
try {
|
|
2120
|
-
|
|
2121
|
-
|
|
2522
|
+
let data;
|
|
2523
|
+
if (resilienceEnabled) {
|
|
2524
|
+
if (circuitBreaker.getState().state === "half-open") {
|
|
2525
|
+
circuitBreaker.incrementHalfOpenRequests();
|
|
2526
|
+
}
|
|
2527
|
+
data = await fetchWithTimeoutAndRetry(
|
|
2528
|
+
async (timeoutSignal) => {
|
|
2529
|
+
const combinedSignal = options.signal ? combineAbortSignals(timeoutSignal, options.signal) : timeoutSignal;
|
|
2530
|
+
try {
|
|
2531
|
+
const response = await fetcher(combinedSignal);
|
|
2532
|
+
return unwrapResponse(response);
|
|
2533
|
+
} catch (error) {
|
|
2534
|
+
convertToTypedError(error);
|
|
2535
|
+
}
|
|
2536
|
+
},
|
|
2537
|
+
{
|
|
2538
|
+
...retryConfig,
|
|
2539
|
+
requestTimeoutMs
|
|
2540
|
+
}
|
|
2541
|
+
);
|
|
2542
|
+
circuitBreaker.recordSuccess();
|
|
2543
|
+
} else {
|
|
2544
|
+
try {
|
|
2545
|
+
const response = await fetcher(options.signal ?? new AbortController().signal);
|
|
2546
|
+
data = unwrapResponse(response);
|
|
2547
|
+
} catch (error) {
|
|
2548
|
+
convertToTypedError(error);
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
if (cacheEnabled) {
|
|
2552
|
+
cache.set(cacheKey, data);
|
|
2553
|
+
}
|
|
2554
|
+
return emitStatus("live", data, statusDetails());
|
|
2122
2555
|
} catch (error) {
|
|
2123
|
-
|
|
2556
|
+
if (resilienceEnabled && error instanceof Error) {
|
|
2557
|
+
circuitBreaker.recordFailure(error);
|
|
2558
|
+
}
|
|
2559
|
+
if (!isPreview && staleIfError && cacheEnabled) {
|
|
2560
|
+
const stale = cache.getStale(cacheKey);
|
|
2561
|
+
if (stale) {
|
|
2562
|
+
const errorInfo2 = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
|
|
2563
|
+
return emitStatus("stale", stale.value, statusDetails({
|
|
2564
|
+
staleAgeSec: stale.staleAgeSec,
|
|
2565
|
+
error: errorInfo2
|
|
2566
|
+
}));
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
const errorInfo = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
|
|
2570
|
+
emitStatus("error", null, statusDetails({ error: errorInfo }));
|
|
2571
|
+
throw error;
|
|
2124
2572
|
}
|
|
2125
|
-
|
|
2126
|
-
|
|
2573
|
+
}
|
|
2574
|
+
function combineAbortSignals(...signals) {
|
|
2575
|
+
const controller = new AbortController();
|
|
2576
|
+
for (const signal of signals) {
|
|
2577
|
+
if (signal.aborted) {
|
|
2578
|
+
controller.abort(signal.reason);
|
|
2579
|
+
break;
|
|
2580
|
+
}
|
|
2581
|
+
signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
|
|
2127
2582
|
}
|
|
2128
|
-
return
|
|
2583
|
+
return controller.signal;
|
|
2129
2584
|
}
|
|
2130
2585
|
return {
|
|
2131
2586
|
async getSite(params) {
|
|
2132
|
-
const { slug, domain, id } = params;
|
|
2587
|
+
const { slug, domain, id, signal } = params;
|
|
2133
2588
|
if (!slug && !domain && !id) {
|
|
2134
2589
|
throw new Error(
|
|
2135
2590
|
`getSite() requires at least one identifier: slug, domain, or id. Received: ${JSON.stringify(params)}`
|
|
2136
2591
|
);
|
|
2137
2592
|
}
|
|
2138
2593
|
const cacheKey = `site:${slug || domain || id}`;
|
|
2139
|
-
return
|
|
2594
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2140
2595
|
const apiParams = {};
|
|
2141
2596
|
if (params.slug) apiParams.slug = params.slug;
|
|
2142
2597
|
if (params.domain) apiParams.domain = params.domain;
|
|
2143
2598
|
if (params.id) apiParams.id = params.id;
|
|
2144
|
-
return await apiClient({ endpoint: "getSite", params: apiParams });
|
|
2145
|
-
});
|
|
2599
|
+
return await apiClient({ endpoint: "getSite", params: apiParams, options: { signal: sig } });
|
|
2600
|
+
}, { signal });
|
|
2146
2601
|
},
|
|
2147
2602
|
async getPage(params) {
|
|
2148
|
-
const { siteId, path, preview = false } = params;
|
|
2603
|
+
const { siteId, path, preview = false, signal } = params;
|
|
2149
2604
|
const cacheKey = `page:${siteId}:${path}:${preview}`;
|
|
2150
|
-
return
|
|
2151
|
-
return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path, preview } });
|
|
2152
|
-
});
|
|
2605
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2606
|
+
return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path, preview }, options: { signal: sig } });
|
|
2607
|
+
}, { preview, signal });
|
|
2153
2608
|
},
|
|
2154
2609
|
async getEntries(params) {
|
|
2155
|
-
const { siteId, contentType, limit, offset, order, preview = false, mode, entryIds, includeMeta } = params;
|
|
2610
|
+
const { siteId, contentType, limit, offset, order, preview = false, mode, entryIds, includeMeta, signal } = params;
|
|
2156
2611
|
const entryIdsCacheKey = mode === "manual" && entryIds?.length ? entryIds.join(",") : "";
|
|
2157
2612
|
const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ""}:${offset ?? ""}:${order ?? ""}:${preview}:${mode ?? ""}:${entryIdsCacheKey}:${includeMeta ?? ""}`;
|
|
2158
|
-
return
|
|
2613
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2159
2614
|
let orderParam;
|
|
2160
2615
|
if (order === "newest") {
|
|
2161
2616
|
orderParam = "published_at.desc";
|
|
@@ -2177,47 +2632,47 @@ function createRiverbankClient(config) {
|
|
|
2177
2632
|
entryIds: JSON.stringify(entryIds)
|
|
2178
2633
|
}
|
|
2179
2634
|
};
|
|
2180
|
-
return await apiClient({ endpoint: "listPublishedEntries", params: apiParams });
|
|
2181
|
-
});
|
|
2635
|
+
return await apiClient({ endpoint: "listPublishedEntries", params: apiParams, options: { signal: sig } });
|
|
2636
|
+
}, { preview, signal });
|
|
2182
2637
|
},
|
|
2183
2638
|
async getEntry(params) {
|
|
2184
|
-
const { siteId, contentType, slug } = params;
|
|
2639
|
+
const { siteId, contentType, slug, signal } = params;
|
|
2185
2640
|
const cacheKey = `entry:${siteId}:${contentType}:${slug}`;
|
|
2186
|
-
return
|
|
2187
|
-
return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug } });
|
|
2188
|
-
});
|
|
2641
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2642
|
+
return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug }, options: { signal: sig } });
|
|
2643
|
+
}, { signal });
|
|
2189
2644
|
},
|
|
2190
2645
|
async getPublicFormById(params) {
|
|
2191
|
-
const { formId } = params;
|
|
2646
|
+
const { formId, signal } = params;
|
|
2192
2647
|
if (!formId) {
|
|
2193
2648
|
throw new Error("getPublicFormById() requires formId");
|
|
2194
2649
|
}
|
|
2195
2650
|
const cacheKey = `public-form:${formId}`;
|
|
2196
|
-
return
|
|
2197
|
-
return await apiClient({ endpoint: "getPublicFormById", params: { formId } });
|
|
2198
|
-
});
|
|
2651
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2652
|
+
return await apiClient({ endpoint: "getPublicFormById", params: { formId }, options: { signal: sig } });
|
|
2653
|
+
}, { signal });
|
|
2199
2654
|
},
|
|
2200
2655
|
async getPublicBookingServices(params) {
|
|
2201
|
-
const { siteId, ids } = params;
|
|
2656
|
+
const { siteId, ids, signal } = params;
|
|
2202
2657
|
if (!siteId) {
|
|
2203
2658
|
throw new Error("getPublicBookingServices() requires siteId");
|
|
2204
2659
|
}
|
|
2205
2660
|
const cacheKey = `public-booking-services:${siteId}:${ids ?? ""}`;
|
|
2206
|
-
return
|
|
2661
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2207
2662
|
const apiParams = {
|
|
2208
2663
|
siteId,
|
|
2209
2664
|
...ids && { ids }
|
|
2210
2665
|
};
|
|
2211
|
-
return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams });
|
|
2212
|
-
});
|
|
2666
|
+
return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams, options: { signal: sig } });
|
|
2667
|
+
}, { signal });
|
|
2213
2668
|
},
|
|
2214
2669
|
async listPublicEvents(params) {
|
|
2215
|
-
const { siteId, limit, from, to, stage } = params;
|
|
2670
|
+
const { siteId, limit, from, to, stage, signal } = params;
|
|
2216
2671
|
if (!siteId) {
|
|
2217
2672
|
throw new Error("listPublicEvents() requires siteId");
|
|
2218
2673
|
}
|
|
2219
2674
|
const cacheKey = `public-events:${siteId}:${limit ?? ""}:${from ?? ""}:${to ?? ""}:${stage ?? ""}`;
|
|
2220
|
-
return
|
|
2675
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2221
2676
|
const apiParams = {
|
|
2222
2677
|
siteId,
|
|
2223
2678
|
...typeof limit === "number" && { limit: String(limit) },
|
|
@@ -2225,40 +2680,46 @@ function createRiverbankClient(config) {
|
|
|
2225
2680
|
...to && { to },
|
|
2226
2681
|
...stage && { stage }
|
|
2227
2682
|
};
|
|
2228
|
-
return await apiClient({ endpoint: "listPublicEvents", params: apiParams });
|
|
2229
|
-
});
|
|
2683
|
+
return await apiClient({ endpoint: "listPublicEvents", params: apiParams, options: { signal: sig } });
|
|
2684
|
+
}, { signal });
|
|
2230
2685
|
},
|
|
2231
2686
|
async resolveEventOccurrence(params) {
|
|
2232
|
-
const { siteId, entryId, segment } = params;
|
|
2687
|
+
const { siteId, entryId, segment, signal } = params;
|
|
2233
2688
|
if (!siteId || !entryId || !segment) {
|
|
2234
2689
|
throw new Error("resolveEventOccurrence() requires siteId, entryId, and segment");
|
|
2235
2690
|
}
|
|
2236
2691
|
const cacheKey = `event-occurrence:${siteId}:${entryId}:${segment}`;
|
|
2237
|
-
return
|
|
2692
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2238
2693
|
return await apiClient({
|
|
2239
2694
|
endpoint: "resolveEventOccurrence",
|
|
2240
|
-
params: { siteId, entryId, segment }
|
|
2695
|
+
params: { siteId, entryId, segment },
|
|
2696
|
+
options: { signal: sig }
|
|
2241
2697
|
});
|
|
2242
|
-
});
|
|
2698
|
+
}, { signal });
|
|
2243
2699
|
},
|
|
2244
2700
|
async checkRedirect(params) {
|
|
2245
|
-
const { siteId, path } = params;
|
|
2701
|
+
const { siteId, path, signal } = params;
|
|
2246
2702
|
if (!siteId || !path) {
|
|
2247
2703
|
throw new Error("checkRedirect() requires siteId and path");
|
|
2248
2704
|
}
|
|
2249
2705
|
const cacheKey = `redirect:${siteId}:${path}`;
|
|
2250
|
-
return
|
|
2706
|
+
return resilientFetch(cacheKey, async (sig) => {
|
|
2251
2707
|
return await apiClient({
|
|
2252
2708
|
endpoint: "checkRedirect",
|
|
2253
|
-
params: { site: siteId, path }
|
|
2709
|
+
params: { site: siteId, path },
|
|
2710
|
+
options: { signal: sig }
|
|
2254
2711
|
});
|
|
2255
|
-
});
|
|
2712
|
+
}, { signal });
|
|
2256
2713
|
},
|
|
2257
2714
|
clearCache() {
|
|
2258
2715
|
cache.clear();
|
|
2716
|
+
},
|
|
2717
|
+
getLastEmittedStatus() {
|
|
2718
|
+
return lastStatus;
|
|
2719
|
+
},
|
|
2720
|
+
getCircuitState() {
|
|
2721
|
+
return circuitBreaker.getState();
|
|
2259
2722
|
}
|
|
2260
|
-
// Cast to RiverbankClient to satisfy overloaded getEntries signature
|
|
2261
|
-
// The implementation correctly returns the right type based on includeMeta
|
|
2262
2723
|
};
|
|
2263
2724
|
}
|
|
2264
2725
|
|
|
@@ -2267,4 +2728,4 @@ export {
|
|
|
2267
2728
|
buildEndpointURL,
|
|
2268
2729
|
createRiverbankClient
|
|
2269
2730
|
};
|
|
2270
|
-
//# sourceMappingURL=chunk-
|
|
2731
|
+
//# sourceMappingURL=chunk-5JT452F2.mjs.map
|