@riverbankcms/sdk 0.1.0

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.
Files changed (157) hide show
  1. package/README.md +1892 -0
  2. package/dist/cli/index.js +327 -0
  3. package/dist/cli/index.js.map +1 -0
  4. package/dist/client/analytics.d.mts +103 -0
  5. package/dist/client/analytics.d.ts +103 -0
  6. package/dist/client/analytics.js +197 -0
  7. package/dist/client/analytics.js.map +1 -0
  8. package/dist/client/analytics.mjs +169 -0
  9. package/dist/client/analytics.mjs.map +1 -0
  10. package/dist/client/bookings.d.mts +89 -0
  11. package/dist/client/bookings.d.ts +89 -0
  12. package/dist/client/bookings.js +34 -0
  13. package/dist/client/bookings.js.map +1 -0
  14. package/dist/client/bookings.mjs +11 -0
  15. package/dist/client/bookings.mjs.map +1 -0
  16. package/dist/client/client.d.mts +195 -0
  17. package/dist/client/client.d.ts +195 -0
  18. package/dist/client/client.js +606 -0
  19. package/dist/client/client.js.map +1 -0
  20. package/dist/client/client.mjs +572 -0
  21. package/dist/client/client.mjs.map +1 -0
  22. package/dist/client/hooks.d.mts +71 -0
  23. package/dist/client/hooks.d.ts +71 -0
  24. package/dist/client/hooks.js +264 -0
  25. package/dist/client/hooks.js.map +1 -0
  26. package/dist/client/hooks.mjs +235 -0
  27. package/dist/client/hooks.mjs.map +1 -0
  28. package/dist/client/rendering/client.d.mts +1 -0
  29. package/dist/client/rendering/client.d.ts +1 -0
  30. package/dist/client/rendering/client.js +33 -0
  31. package/dist/client/rendering/client.js.map +1 -0
  32. package/dist/client/rendering/client.mjs +8 -0
  33. package/dist/client/rendering/client.mjs.map +1 -0
  34. package/dist/client/usePage-BvKAa3Zw.d.mts +366 -0
  35. package/dist/client/usePage-BvKAa3Zw.d.ts +366 -0
  36. package/dist/server/chunk-2RW5HAQQ.mjs +86 -0
  37. package/dist/server/chunk-2RW5HAQQ.mjs.map +1 -0
  38. package/dist/server/chunk-3KKZVGH4.mjs +179 -0
  39. package/dist/server/chunk-3KKZVGH4.mjs.map +1 -0
  40. package/dist/server/chunk-4Z3GPTCS.js +179 -0
  41. package/dist/server/chunk-4Z3GPTCS.js.map +1 -0
  42. package/dist/server/chunk-4Z5FBFRL.mjs +211 -0
  43. package/dist/server/chunk-4Z5FBFRL.mjs.map +1 -0
  44. package/dist/server/chunk-ADREPXFU.js +86 -0
  45. package/dist/server/chunk-ADREPXFU.js.map +1 -0
  46. package/dist/server/chunk-F472SMKX.js +140 -0
  47. package/dist/server/chunk-F472SMKX.js.map +1 -0
  48. package/dist/server/chunk-GWBMJPLH.mjs +57 -0
  49. package/dist/server/chunk-GWBMJPLH.mjs.map +1 -0
  50. package/dist/server/chunk-JB4LIEFS.js +85 -0
  51. package/dist/server/chunk-JB4LIEFS.js.map +1 -0
  52. package/dist/server/chunk-PEAXKTDU.mjs +140 -0
  53. package/dist/server/chunk-PEAXKTDU.mjs.map +1 -0
  54. package/dist/server/chunk-QQ6U4QX6.js +120 -0
  55. package/dist/server/chunk-QQ6U4QX6.js.map +1 -0
  56. package/dist/server/chunk-R5YGLRUG.mjs +122 -0
  57. package/dist/server/chunk-R5YGLRUG.mjs.map +1 -0
  58. package/dist/server/chunk-SW7LE4M3.js +211 -0
  59. package/dist/server/chunk-SW7LE4M3.js.map +1 -0
  60. package/dist/server/chunk-W3K7LVPS.mjs +120 -0
  61. package/dist/server/chunk-W3K7LVPS.mjs.map +1 -0
  62. package/dist/server/chunk-WKG57P2H.mjs +85 -0
  63. package/dist/server/chunk-WKG57P2H.mjs.map +1 -0
  64. package/dist/server/chunk-YHEZMVTS.js +122 -0
  65. package/dist/server/chunk-YHEZMVTS.js.map +1 -0
  66. package/dist/server/chunk-YXDDFG3N.js +57 -0
  67. package/dist/server/chunk-YXDDFG3N.js.map +1 -0
  68. package/dist/server/components.d.mts +49 -0
  69. package/dist/server/components.d.ts +49 -0
  70. package/dist/server/components.js +22 -0
  71. package/dist/server/components.js.map +1 -0
  72. package/dist/server/components.mjs +22 -0
  73. package/dist/server/components.mjs.map +1 -0
  74. package/dist/server/config-validation.d.mts +300 -0
  75. package/dist/server/config-validation.d.ts +300 -0
  76. package/dist/server/config-validation.js +50 -0
  77. package/dist/server/config-validation.js.map +1 -0
  78. package/dist/server/config-validation.mjs +50 -0
  79. package/dist/server/config-validation.mjs.map +1 -0
  80. package/dist/server/config.d.mts +38 -0
  81. package/dist/server/config.d.ts +38 -0
  82. package/dist/server/config.js +44 -0
  83. package/dist/server/config.js.map +1 -0
  84. package/dist/server/config.mjs +44 -0
  85. package/dist/server/config.mjs.map +1 -0
  86. package/dist/server/data.d.mts +108 -0
  87. package/dist/server/data.d.ts +108 -0
  88. package/dist/server/data.js +15 -0
  89. package/dist/server/data.js.map +1 -0
  90. package/dist/server/data.mjs +15 -0
  91. package/dist/server/data.mjs.map +1 -0
  92. package/dist/server/index-B0yI_V6Z.d.mts +18 -0
  93. package/dist/server/index-C6M0Wfjq.d.ts +18 -0
  94. package/dist/server/index.d.mts +5 -0
  95. package/dist/server/index.d.ts +5 -0
  96. package/dist/server/index.js +12 -0
  97. package/dist/server/index.js.map +1 -0
  98. package/dist/server/index.mjs +12 -0
  99. package/dist/server/index.mjs.map +1 -0
  100. package/dist/server/loadContent-CJcbYF3J.d.ts +152 -0
  101. package/dist/server/loadContent-zhlL4YSE.d.mts +152 -0
  102. package/dist/server/loadPage-BYmVMk0V.d.ts +216 -0
  103. package/dist/server/loadPage-CCf15nt8.d.mts +216 -0
  104. package/dist/server/loadPage-DVH3DW6E.js +9 -0
  105. package/dist/server/loadPage-DVH3DW6E.js.map +1 -0
  106. package/dist/server/loadPage-PHQZ6XQZ.mjs +9 -0
  107. package/dist/server/loadPage-PHQZ6XQZ.mjs.map +1 -0
  108. package/dist/server/metadata.d.mts +135 -0
  109. package/dist/server/metadata.d.ts +135 -0
  110. package/dist/server/metadata.js +68 -0
  111. package/dist/server/metadata.js.map +1 -0
  112. package/dist/server/metadata.mjs +68 -0
  113. package/dist/server/metadata.mjs.map +1 -0
  114. package/dist/server/rendering/server.d.mts +83 -0
  115. package/dist/server/rendering/server.d.ts +83 -0
  116. package/dist/server/rendering/server.js +14 -0
  117. package/dist/server/rendering/server.js.map +1 -0
  118. package/dist/server/rendering/server.mjs +14 -0
  119. package/dist/server/rendering/server.mjs.map +1 -0
  120. package/dist/server/rendering.d.mts +12 -0
  121. package/dist/server/rendering.d.ts +12 -0
  122. package/dist/server/rendering.js +40 -0
  123. package/dist/server/rendering.js.map +1 -0
  124. package/dist/server/rendering.mjs +40 -0
  125. package/dist/server/rendering.mjs.map +1 -0
  126. package/dist/server/routing.d.mts +115 -0
  127. package/dist/server/routing.d.ts +115 -0
  128. package/dist/server/routing.js +57 -0
  129. package/dist/server/routing.js.map +1 -0
  130. package/dist/server/routing.mjs +57 -0
  131. package/dist/server/routing.mjs.map +1 -0
  132. package/dist/server/server.d.mts +9 -0
  133. package/dist/server/server.d.ts +9 -0
  134. package/dist/server/server.js +21 -0
  135. package/dist/server/server.js.map +1 -0
  136. package/dist/server/server.mjs +21 -0
  137. package/dist/server/server.mjs.map +1 -0
  138. package/dist/server/theme-bridge.d.mts +232 -0
  139. package/dist/server/theme-bridge.d.ts +232 -0
  140. package/dist/server/theme-bridge.js +231 -0
  141. package/dist/server/theme-bridge.js.map +1 -0
  142. package/dist/server/theme-bridge.mjs +231 -0
  143. package/dist/server/theme-bridge.mjs.map +1 -0
  144. package/dist/server/theme.d.mts +40 -0
  145. package/dist/server/theme.d.ts +40 -0
  146. package/dist/server/theme.js +17 -0
  147. package/dist/server/theme.js.map +1 -0
  148. package/dist/server/theme.mjs +17 -0
  149. package/dist/server/theme.mjs.map +1 -0
  150. package/dist/server/types-BCeqWtI2.d.mts +333 -0
  151. package/dist/server/types-BCeqWtI2.d.ts +333 -0
  152. package/dist/server/types-Bbo01M7P.d.mts +76 -0
  153. package/dist/server/types-Bbo01M7P.d.ts +76 -0
  154. package/dist/server/types-C6gmRHLe.d.mts +150 -0
  155. package/dist/server/types-C6gmRHLe.d.ts +150 -0
  156. package/package.json +147 -0
  157. package/src/styles/index.css +10 -0
@@ -0,0 +1,572 @@
1
+ "use client";
2
+ // src/rendering/hooks/usePage.ts
3
+ import { useState, useEffect } from "react";
4
+
5
+ // src/data/prefetchBlockData.ts
6
+ import { prefetchBlockData as prefetchBlockDataCore } from "@riverbankcms/blocks/system/data";
7
+ var SUPPORTED_LOADER_ENDPOINTS = [
8
+ "listPublishedEntries",
9
+ "getPublishedEntryPreview",
10
+ "listPublicEvents",
11
+ "getPublicFormById",
12
+ "getPublicBookingServices"
13
+ ];
14
+ async function prefetchBlockData(page, context, client, options) {
15
+ const { customBlocks } = options ?? {};
16
+ const customBlockMap = new Map(
17
+ (customBlocks ?? []).map((block) => [block.id, block])
18
+ );
19
+ return prefetchBlockDataCore(page, context, {
20
+ apiClient: async ({ endpoint, params }) => {
21
+ if (!isSupportedEndpoint(endpoint)) {
22
+ throw new Error(
23
+ `Unsupported loader endpoint: ${endpoint}. SDK only supports: ${SUPPORTED_LOADER_ENDPOINTS.join(", ")}`
24
+ );
25
+ }
26
+ switch (endpoint) {
27
+ case "listPublishedEntries": {
28
+ const { siteId, type, orderBy, limit, stage, mode, entryIds } = params ?? {};
29
+ if (!siteId || !type) {
30
+ throw new Error("listPublishedEntries requires siteId and type params");
31
+ }
32
+ const parsedLimit = typeof limit === "string" ? Number.parseInt(limit, 10) : typeof limit === "number" ? limit : void 0;
33
+ const order = orderBy === "newest" || orderBy === "oldest" || orderBy === "title" || orderBy === "order" ? orderBy : void 0;
34
+ let parsedEntryIds;
35
+ if (mode === "manual" && Array.isArray(entryIds)) {
36
+ parsedEntryIds = entryIds.map((item) => {
37
+ if (typeof item === "object" && item !== null && "entryId" in item) {
38
+ return item.entryId;
39
+ }
40
+ if (typeof item === "string") {
41
+ return item;
42
+ }
43
+ return null;
44
+ }).filter((id) => id !== null);
45
+ }
46
+ return await client.getEntries({
47
+ siteId,
48
+ contentType: type,
49
+ limit: parsedLimit,
50
+ order,
51
+ preview: stage === "preview",
52
+ // Manual mode - pass entry IDs for hydration
53
+ mode: mode === "manual" ? "manual" : void 0,
54
+ entryIds: parsedEntryIds
55
+ });
56
+ }
57
+ case "getPublishedEntryPreview": {
58
+ const { siteId, type, slug } = params ?? {};
59
+ if (!siteId || !type || !slug) {
60
+ throw new Error("getPublishedEntryPreview requires siteId, type, and slug params");
61
+ }
62
+ return await client.getEntry({ siteId, contentType: type, slug });
63
+ }
64
+ case "listPublicEvents": {
65
+ const { siteId, limit, from, to, stage } = params ?? {};
66
+ if (!siteId) {
67
+ throw new Error("listPublicEvents requires siteId param");
68
+ }
69
+ const parsedLimit = typeof limit === "string" ? Number.parseInt(limit, 10) : typeof limit === "number" ? limit : void 0;
70
+ return await client.listPublicEvents({ siteId, limit: parsedLimit, from, to, stage });
71
+ }
72
+ case "getPublicFormById": {
73
+ const { formId } = params ?? {};
74
+ if (!formId) {
75
+ throw new Error("getPublicFormById requires formId param");
76
+ }
77
+ return await client.getPublicFormById({ formId });
78
+ }
79
+ case "getPublicBookingServices": {
80
+ const { siteId, ids } = params ?? {};
81
+ if (!siteId) {
82
+ throw new Error("getPublicBookingServices requires siteId param");
83
+ }
84
+ return await client.getPublicBookingServices({ siteId, ids });
85
+ }
86
+ default: {
87
+ const _exhaustive = endpoint;
88
+ throw new Error(`Unhandled endpoint: ${_exhaustive}`);
89
+ }
90
+ }
91
+ },
92
+ isValidEndpoint: isSupportedEndpoint,
93
+ onError: (error, { block, loader }) => {
94
+ console.warn("[prefetchBlockData] failed to prefetch block data", {
95
+ block,
96
+ loader,
97
+ error
98
+ });
99
+ },
100
+ // Provide custom block loader lookup for SDK custom blocks
101
+ getCustomBlockLoaders: (blockKind) => {
102
+ const customBlock = customBlockMap.get(blockKind);
103
+ if (!customBlock?.dataLoaders) return void 0;
104
+ const loaders = {};
105
+ for (const [key, loader] of Object.entries(customBlock.dataLoaders)) {
106
+ loaders[key] = {
107
+ endpoint: loader.endpoint,
108
+ params: loader.params,
109
+ mode: loader.mode
110
+ };
111
+ }
112
+ return loaders;
113
+ }
114
+ });
115
+ }
116
+ function isSupportedEndpoint(endpoint) {
117
+ return SUPPORTED_LOADER_ENDPOINTS.includes(endpoint);
118
+ }
119
+
120
+ // src/rendering/hooks/usePage.ts
121
+ function usePage(params) {
122
+ const { client, siteId, path, pageId, preview = false } = params;
123
+ const [result, setResult] = useState({
124
+ loading: true,
125
+ error: null,
126
+ page: null,
127
+ theme: null,
128
+ siteId,
129
+ resolvedData: null,
130
+ sdkConfig: null
131
+ });
132
+ useEffect(() => {
133
+ let cancelled = false;
134
+ async function fetchPage() {
135
+ try {
136
+ const [site, pageResponse] = await Promise.all([
137
+ client.getSite({ id: siteId }),
138
+ client.getPage({ siteId, path, preview })
139
+ ]);
140
+ if (cancelled) return;
141
+ if ("entry" in pageResponse) {
142
+ throw new Error(
143
+ "This path resolves to a content entry, not a page. Use useContent() instead, which handles both pages and entries. For entries, useContent() returns the raw entry data for custom rendering."
144
+ );
145
+ }
146
+ const { page: pageData } = pageResponse;
147
+ const blocks = pageData.blocks.map((block) => {
148
+ if (!block || typeof block !== "object") {
149
+ throw new Error("Invalid block format in API response");
150
+ }
151
+ if (typeof block.id !== "string" && block.id !== null) {
152
+ throw new Error(`Invalid block id: expected string or null, got ${typeof block.id}`);
153
+ }
154
+ if (typeof block.kind !== "string") {
155
+ throw new Error(`Invalid block kind: expected string, got ${typeof block.kind}`);
156
+ }
157
+ if (typeof block.purpose !== "string") {
158
+ throw new Error(`Invalid block purpose: expected string, got ${typeof block.purpose}`);
159
+ }
160
+ return {
161
+ id: block.id,
162
+ kind: block.kind,
163
+ purpose: block.purpose
164
+ };
165
+ });
166
+ const pageOutline = {
167
+ name: pageData.name,
168
+ path: pageData.path,
169
+ purpose: pageData.purpose,
170
+ blocks
171
+ };
172
+ const resolvedData = await prefetchBlockData(
173
+ pageOutline,
174
+ {
175
+ siteId,
176
+ pageId: pageId ?? pageData.id,
177
+ previewStage: preview ? "preview" : "published"
178
+ },
179
+ client
180
+ );
181
+ if (cancelled) return;
182
+ setResult({
183
+ loading: false,
184
+ error: null,
185
+ page: pageOutline,
186
+ theme: site.theme,
187
+ siteId,
188
+ resolvedData,
189
+ sdkConfig: site.sdkConfig ?? null
190
+ });
191
+ } catch (error) {
192
+ if (cancelled) return;
193
+ setResult({
194
+ loading: false,
195
+ error: error instanceof Error ? error : new Error(String(error)),
196
+ page: null,
197
+ theme: null,
198
+ siteId,
199
+ resolvedData: null,
200
+ sdkConfig: null
201
+ });
202
+ }
203
+ }
204
+ fetchPage();
205
+ return () => {
206
+ cancelled = true;
207
+ };
208
+ }, [client, siteId, path, pageId, preview]);
209
+ return result;
210
+ }
211
+
212
+ // src/rendering/hooks/useContent.ts
213
+ import { useState as useState2, useEffect as useEffect2 } from "react";
214
+ function isContentLoading(result) {
215
+ return result.loading === true;
216
+ }
217
+ function isContentError(result) {
218
+ return result.loading === false && result.error !== null;
219
+ }
220
+ function isPageContentResult(result) {
221
+ return result.loading === false && result.error === null && result.type === "page";
222
+ }
223
+ function isEntryContentResult(result) {
224
+ return result.loading === false && result.error === null && result.type === "entry";
225
+ }
226
+ function useContent(params) {
227
+ const { client, siteId, path, preview = false } = params;
228
+ const [result, setResult] = useState2({
229
+ loading: true,
230
+ error: null,
231
+ type: null,
232
+ page: null,
233
+ entry: null,
234
+ theme: null,
235
+ siteId,
236
+ resolvedData: null
237
+ });
238
+ useEffect2(() => {
239
+ let cancelled = false;
240
+ async function fetchContent() {
241
+ try {
242
+ const [site, contentResponse] = await Promise.all([
243
+ client.getSite({ id: siteId }),
244
+ client.getPage({ siteId, path, preview })
245
+ ]);
246
+ if (cancelled) return;
247
+ if (isEntryResponse(contentResponse)) {
248
+ const entryData = contentResponse.entry;
249
+ const entry = {
250
+ id: entryData.id,
251
+ type: entryData.type,
252
+ title: entryData.title,
253
+ slug: entryData.slug,
254
+ path: entryData.path,
255
+ status: entryData.status,
256
+ publishAt: entryData.publishAt,
257
+ content: preview ? entryData.draftContent ?? entryData.content : entryData.content,
258
+ metaTitle: preview ? entryData.draftMetaTitle ?? entryData.metaTitle : entryData.metaTitle,
259
+ metaDescription: preview ? entryData.draftMetaDescription ?? entryData.metaDescription : entryData.metaDescription,
260
+ createdAt: entryData.createdAt,
261
+ updatedAt: entryData.updatedAt
262
+ };
263
+ setResult({
264
+ loading: false,
265
+ error: null,
266
+ type: "entry",
267
+ page: null,
268
+ entry,
269
+ theme: site.theme,
270
+ siteId,
271
+ resolvedData: null
272
+ });
273
+ return;
274
+ }
275
+ const { page: pageData } = contentResponse;
276
+ const blocks = pageData.blocks.map((block) => {
277
+ if (!block || typeof block !== "object") {
278
+ throw new Error("Invalid block format in API response");
279
+ }
280
+ if (typeof block.id !== "string" && block.id !== null) {
281
+ throw new Error(`Invalid block id: expected string or null, got ${typeof block.id}`);
282
+ }
283
+ if (typeof block.kind !== "string") {
284
+ throw new Error(`Invalid block kind: expected string, got ${typeof block.kind}`);
285
+ }
286
+ if (typeof block.purpose !== "string") {
287
+ throw new Error(`Invalid block purpose: expected string, got ${typeof block.purpose}`);
288
+ }
289
+ return {
290
+ id: block.id,
291
+ kind: block.kind,
292
+ purpose: block.purpose
293
+ };
294
+ });
295
+ const pageOutline = {
296
+ name: pageData.name,
297
+ path: pageData.path,
298
+ purpose: pageData.purpose,
299
+ blocks
300
+ };
301
+ const resolvedData = await prefetchBlockData(
302
+ pageOutline,
303
+ {
304
+ siteId,
305
+ pageId: pageData.id,
306
+ previewStage: preview ? "preview" : "published"
307
+ },
308
+ client
309
+ );
310
+ if (cancelled) return;
311
+ setResult({
312
+ loading: false,
313
+ error: null,
314
+ type: "page",
315
+ page: pageOutline,
316
+ entry: null,
317
+ theme: site.theme,
318
+ siteId,
319
+ resolvedData
320
+ });
321
+ } catch (error) {
322
+ if (cancelled) return;
323
+ setResult({
324
+ loading: false,
325
+ error: error instanceof Error ? error : new Error(String(error)),
326
+ type: null,
327
+ page: null,
328
+ entry: null,
329
+ theme: null,
330
+ siteId,
331
+ resolvedData: null
332
+ });
333
+ }
334
+ }
335
+ fetchContent();
336
+ return () => {
337
+ cancelled = true;
338
+ };
339
+ }, [client, siteId, path, preview]);
340
+ return result;
341
+ }
342
+ function isEntryResponse(response) {
343
+ return "type" in response && response.type === "entry";
344
+ }
345
+
346
+ // src/rendering/components/Page.tsx
347
+ import { PageRenderer, buildThemeRuntime } from "@riverbankcms/blocks";
348
+ import { jsx } from "react/jsx-runtime";
349
+ function Page({
350
+ page,
351
+ theme,
352
+ themeTokens: providedTokens,
353
+ siteId,
354
+ resolvedData,
355
+ routeMap,
356
+ wrapBlock,
357
+ registry,
358
+ usePlaceholders = false,
359
+ blockOverrides,
360
+ sdkConfig,
361
+ dataContext
362
+ }) {
363
+ const baseTokens = providedTokens ?? buildThemeRuntime(theme).tokens;
364
+ const themeTokens = sdkConfig?.theme?.palette ? { ...baseTokens, palette: { ...baseTokens.palette, ...sdkConfig.theme.palette } } : baseTokens;
365
+ return /* @__PURE__ */ jsx(
366
+ PageRenderer,
367
+ {
368
+ theme,
369
+ page,
370
+ themeTokens,
371
+ usePlaceholders,
372
+ dataContext: {
373
+ siteId,
374
+ resolvedData,
375
+ routes: routeMap,
376
+ occurrenceContext: dataContext?.occurrenceContext ?? null,
377
+ contentEntry: dataContext?.contentEntry ?? null
378
+ },
379
+ routeMap,
380
+ wrapBlock,
381
+ registry,
382
+ blockOverrides,
383
+ sdkConfig
384
+ }
385
+ );
386
+ }
387
+
388
+ // src/client/index.ts
389
+ import { createBearerAPIClient } from "@riverbankcms/api";
390
+
391
+ // src/client/cache.ts
392
+ var SimpleCache = class {
393
+ constructor(options = {}) {
394
+ this.cache = /* @__PURE__ */ new Map();
395
+ this.maxSize = options.maxSize ?? 100;
396
+ this.ttl = options.ttl ?? 3e5;
397
+ }
398
+ get(key) {
399
+ const entry = this.cache.get(key);
400
+ if (!entry) return void 0;
401
+ if (Date.now() > entry.expires) {
402
+ this.cache.delete(key);
403
+ return void 0;
404
+ }
405
+ return entry.value;
406
+ }
407
+ set(key, value) {
408
+ if (this.cache.size >= this.maxSize) {
409
+ const firstKey = this.cache.keys().next().value;
410
+ if (firstKey) {
411
+ this.cache.delete(firstKey);
412
+ }
413
+ }
414
+ this.cache.set(key, {
415
+ value,
416
+ expires: Date.now() + this.ttl
417
+ });
418
+ }
419
+ clear() {
420
+ this.cache.clear();
421
+ }
422
+ has(key) {
423
+ return this.get(key) !== void 0;
424
+ }
425
+ };
426
+
427
+ // src/client/index.ts
428
+ function createRiverbankClient(config) {
429
+ if (!config.baseUrl) {
430
+ throw new Error(
431
+ "baseUrl is required when creating a Builder client. Expected format: https://dashboard.example.com/api (must include /api path)"
432
+ );
433
+ }
434
+ if (!config.baseUrl.endsWith("/api")) {
435
+ throw new Error(
436
+ `baseUrl must end with '/api'. Received: ${config.baseUrl}. Expected format: https://dashboard.example.com/api`
437
+ );
438
+ }
439
+ const cacheEnabled = config.cache?.enabled ?? true;
440
+ const cacheTTL = (config.cache?.ttl ?? 300) * 1e3;
441
+ const cacheMaxSize = config.cache?.maxSize ?? 100;
442
+ const apiClient = createBearerAPIClient(config.apiKey, config.baseUrl);
443
+ const cache = new SimpleCache({
444
+ maxSize: cacheMaxSize,
445
+ ttl: cacheTTL
446
+ });
447
+ async function cachedFetch(cacheKey, fetcher, options) {
448
+ if (cacheEnabled && !options?.force) {
449
+ const cached = cache.get(cacheKey);
450
+ if (cached !== void 0) {
451
+ return cached;
452
+ }
453
+ }
454
+ const data = await fetcher();
455
+ if (cacheEnabled) {
456
+ cache.set(cacheKey, data);
457
+ }
458
+ return data;
459
+ }
460
+ return {
461
+ async getSite(params) {
462
+ const { slug, domain, id } = params;
463
+ if (!slug && !domain && !id) {
464
+ throw new Error(
465
+ `getSite() requires at least one identifier: slug, domain, or id. Received: ${JSON.stringify(params)}`
466
+ );
467
+ }
468
+ const cacheKey = `site:${slug || domain || id}`;
469
+ return cachedFetch(cacheKey, async () => {
470
+ const apiParams = {};
471
+ if (params.slug) apiParams.slug = params.slug;
472
+ if (params.domain) apiParams.domain = params.domain;
473
+ if (params.id) apiParams.id = params.id;
474
+ return await apiClient({ endpoint: "getSite", params: apiParams });
475
+ });
476
+ },
477
+ async getPage(params) {
478
+ const { siteId, path, preview = false } = params;
479
+ const cacheKey = `page:${siteId}:${path}:${preview}`;
480
+ return cachedFetch(cacheKey, async () => {
481
+ return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path, preview } });
482
+ });
483
+ },
484
+ async getEntries(params) {
485
+ const { siteId, contentType, limit, order, preview = false, mode, entryIds } = params;
486
+ const entryIdsCacheKey = mode === "manual" && entryIds?.length ? entryIds.join(",") : "";
487
+ const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ""}:${order ?? ""}:${preview}:${mode ?? ""}:${entryIdsCacheKey}`;
488
+ return cachedFetch(cacheKey, async () => {
489
+ const apiParams = {
490
+ siteId,
491
+ type: contentType
492
+ };
493
+ if (typeof limit === "number") {
494
+ apiParams.limit = String(limit);
495
+ }
496
+ if (order === "newest") {
497
+ apiParams.order = "published_at.desc";
498
+ } else if (order === "oldest") {
499
+ apiParams.order = "published_at.asc";
500
+ } else if (order === "title") {
501
+ apiParams.order = "title.asc";
502
+ }
503
+ if (preview) {
504
+ apiParams.stage = "preview";
505
+ }
506
+ if (mode === "manual" && entryIds?.length) {
507
+ apiParams.mode = "manual";
508
+ apiParams.entryIds = JSON.stringify(entryIds);
509
+ }
510
+ return await apiClient({ endpoint: "listPublishedEntries", params: apiParams });
511
+ });
512
+ },
513
+ async getEntry(params) {
514
+ const { siteId, contentType, slug } = params;
515
+ const cacheKey = `entry:${siteId}:${contentType}:${slug}`;
516
+ return cachedFetch(cacheKey, async () => {
517
+ return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug } });
518
+ });
519
+ },
520
+ async getPublicFormById(params) {
521
+ const { formId } = params;
522
+ if (!formId) {
523
+ throw new Error("getPublicFormById() requires formId");
524
+ }
525
+ const cacheKey = `public-form:${formId}`;
526
+ return cachedFetch(cacheKey, async () => {
527
+ return await apiClient({ endpoint: "getPublicFormById", params: { formId } });
528
+ });
529
+ },
530
+ async getPublicBookingServices(params) {
531
+ const { siteId, ids } = params;
532
+ if (!siteId) {
533
+ throw new Error("getPublicBookingServices() requires siteId");
534
+ }
535
+ const cacheKey = `public-booking-services:${siteId}:${ids ?? ""}`;
536
+ return cachedFetch(cacheKey, async () => {
537
+ const apiParams = { siteId };
538
+ if (ids) apiParams.ids = ids;
539
+ return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams });
540
+ });
541
+ },
542
+ async listPublicEvents(params) {
543
+ const { siteId, limit, from, to, stage } = params;
544
+ if (!siteId) {
545
+ throw new Error("listPublicEvents() requires siteId");
546
+ }
547
+ const cacheKey = `public-events:${siteId}:${limit ?? ""}:${from ?? ""}:${to ?? ""}:${stage ?? ""}`;
548
+ return cachedFetch(cacheKey, async () => {
549
+ const apiParams = { siteId };
550
+ if (typeof limit === "number") apiParams.limit = String(limit);
551
+ if (from) apiParams.from = from;
552
+ if (to) apiParams.to = to;
553
+ if (stage) apiParams.stage = stage;
554
+ return await apiClient({ endpoint: "listPublicEvents", params: apiParams });
555
+ });
556
+ },
557
+ clearCache() {
558
+ cache.clear();
559
+ }
560
+ };
561
+ }
562
+ export {
563
+ Page,
564
+ createRiverbankClient,
565
+ isContentError,
566
+ isContentLoading,
567
+ isEntryContentResult,
568
+ isPageContentResult,
569
+ useContent,
570
+ usePage
571
+ };
572
+ //# sourceMappingURL=client.mjs.map