@riverbankcms/sdk 0.7.5 → 0.8.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 (72) hide show
  1. package/README.md +88 -1
  2. package/dist/cli/index.js +3693 -39
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/client/client.d.mts +2 -2
  5. package/dist/client/client.d.ts +2 -2
  6. package/dist/client/client.js +105 -2
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/client.mjs +105 -2
  9. package/dist/client/client.mjs.map +1 -1
  10. package/dist/client/hooks.d.mts +2 -2
  11. package/dist/client/hooks.d.ts +2 -2
  12. package/dist/client/usePage-CdnO2CP5.d.mts +6875 -0
  13. package/dist/client/usePage-_ksKXlUF.d.ts +6875 -0
  14. package/dist/server/{Layout-qWLdVm5-.d.mts → Layout-D4J009eS.d.mts} +1 -1
  15. package/dist/server/{Layout-Yluyb6sK.d.ts → Layout-l2v4Qa6E.d.ts} +1 -1
  16. package/dist/server/{chunk-2NBNOY3C.mjs → chunk-65A5HAUZ.mjs} +106 -3
  17. package/dist/server/chunk-65A5HAUZ.mjs.map +1 -0
  18. package/dist/server/{chunk-KH3EXBJM.js → chunk-WM646WI3.js} +106 -3
  19. package/dist/server/chunk-WM646WI3.js.map +1 -0
  20. package/dist/server/{components-Di5ME6He.d.ts → components-D2uCKCj7.d.ts} +3 -3
  21. package/dist/server/{components-DNHfSCML.d.mts → components-vtYEmmPF.d.mts} +3 -3
  22. package/dist/server/components.d.mts +5 -5
  23. package/dist/server/components.d.ts +5 -5
  24. package/dist/server/config-validation.d.mts +2 -2
  25. package/dist/server/config-validation.d.ts +2 -2
  26. package/dist/server/config.d.mts +3 -3
  27. package/dist/server/config.d.ts +3 -3
  28. package/dist/server/data.d.mts +2 -2
  29. package/dist/server/data.d.ts +2 -2
  30. package/dist/server/{index-Clm3skz_.d.mts → index-2qnY7VH_.d.mts} +1 -1
  31. package/dist/server/{index-DLvNddi-.d.ts → index-BxrAuL9K.d.ts} +1 -1
  32. package/dist/server/{index-C9Ra8dza.d.ts → index-CH_dvF6n.d.ts} +2 -2
  33. package/dist/server/{index--Oyunk_B.d.mts → index-DfWg1Qle.d.mts} +2 -2
  34. package/dist/server/index.d.mts +13 -5
  35. package/dist/server/index.d.ts +13 -5
  36. package/dist/server/index.js +10 -10
  37. package/dist/server/index.mjs +1 -1
  38. package/dist/server/{loadContent-D7LQwI0o.d.ts → loadContent-DECnsp4k.d.ts} +3 -3
  39. package/dist/server/{loadContent-DVfuBLiZ.d.mts → loadContent-Du5kS8UM.d.mts} +3 -3
  40. package/dist/server/{loadPage-BmYJCe_V.d.ts → loadPage-BZohBxxf.d.ts} +2 -2
  41. package/dist/server/{loadPage-BucnLHmE.d.mts → loadPage-VBorKlWv.d.mts} +2 -2
  42. package/dist/server/metadata.d.mts +4 -4
  43. package/dist/server/metadata.d.ts +4 -4
  44. package/dist/server/navigation.d.mts +2 -2
  45. package/dist/server/navigation.d.ts +2 -2
  46. package/dist/server/next.d.mts +38 -7
  47. package/dist/server/next.d.ts +38 -7
  48. package/dist/server/next.js +29 -11
  49. package/dist/server/next.js.map +1 -1
  50. package/dist/server/next.mjs +29 -11
  51. package/dist/server/next.mjs.map +1 -1
  52. package/dist/server/rendering/server.d.mts +4 -4
  53. package/dist/server/rendering/server.d.ts +4 -4
  54. package/dist/server/rendering.d.mts +7 -7
  55. package/dist/server/rendering.d.ts +7 -7
  56. package/dist/server/routing.d.mts +4 -4
  57. package/dist/server/routing.d.ts +4 -4
  58. package/dist/server/server.d.mts +5 -5
  59. package/dist/server/server.d.ts +5 -5
  60. package/dist/server/server.js +2 -2
  61. package/dist/server/server.mjs +1 -1
  62. package/dist/server/{types-C-LShyIg.d.mts → types-BRQ_6yOc.d.mts} +43 -1
  63. package/dist/server/{types-BjgZt8xJ.d.mts → types-CJfJwcuL.d.mts} +37 -0
  64. package/dist/server/{types-Dt98DeYa.d.ts → types-CgSO0yxg.d.ts} +8 -0
  65. package/dist/server/{types-BRQyLrQU.d.ts → types-D0rPF8l5.d.ts} +43 -1
  66. package/dist/server/{types-DLBhEPSt.d.ts → types-D8XqwoVd.d.ts} +37 -0
  67. package/dist/server/{types-BSV6Vc-P.d.mts → types-DT30Qy7x.d.mts} +8 -0
  68. package/dist/server/{validation-DU2YE7u5.d.ts → validation-D1LaY1kQ.d.ts} +1 -1
  69. package/dist/server/{validation-BGuRo8P1.d.mts → validation-Pv3Zs6dP.d.mts} +1 -1
  70. package/package.json +2 -1
  71. package/dist/server/chunk-2NBNOY3C.mjs.map +0 -1
  72. package/dist/server/chunk-KH3EXBJM.js.map +0 -1
package/dist/cli/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  var jiti = require('jiti');
5
5
  var path9 = require('path');
6
- var fs = require('fs');
6
+ var fs6 = require('fs');
7
7
  var dotenv = require('dotenv');
8
8
  var commander = require('commander');
9
9
  var zod = require('zod');
@@ -13,6 +13,10 @@ var readline = require('readline');
13
13
  var equal = require('fast-deep-equal');
14
14
  var os = require('os');
15
15
  var child_process = require('child_process');
16
+ var simpleGit = require('simple-git');
17
+ require('react');
18
+ require('react/jsx-runtime');
19
+ var crypto2 = require('crypto');
16
20
 
17
21
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
18
22
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -36,14 +40,19 @@ function _interopNamespace(e) {
36
40
  }
37
41
 
38
42
  var path9__namespace = /*#__PURE__*/_interopNamespace(path9);
43
+ var fs6__namespace = /*#__PURE__*/_interopNamespace(fs6);
39
44
  var prompts__default = /*#__PURE__*/_interopDefault(prompts);
40
45
  var fs3__namespace = /*#__PURE__*/_interopNamespace(fs3);
41
46
  var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
42
47
  var equal__default = /*#__PURE__*/_interopDefault(equal);
43
48
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
49
+ var simpleGit__default = /*#__PURE__*/_interopDefault(simpleGit);
50
+ var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
44
51
 
45
52
  var __defProp = Object.defineProperty;
53
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
46
54
  var __getOwnPropNames = Object.getOwnPropertyNames;
55
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
47
56
  var __esm = (fn, res) => function __init() {
48
57
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
49
58
  };
@@ -51,6 +60,15 @@ var __export = (target, all) => {
51
60
  for (var name in all)
52
61
  __defProp(target, name, { get: all[name], enumerable: true });
53
62
  };
63
+ var __copyProps = (to, from, except, desc) => {
64
+ if (from && typeof from === "object" || typeof from === "function") {
65
+ for (let key of __getOwnPropNames(from))
66
+ if (!__hasOwnProp.call(to, key) && key !== except)
67
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
68
+ }
69
+ return to;
70
+ };
71
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
54
72
 
55
73
  // src/cli/load-config.ts
56
74
  var load_config_exports = {};
@@ -59,7 +77,7 @@ __export(load_config_exports, {
59
77
  });
60
78
  async function loadConfigFile(configPath) {
61
79
  const resolvedPath = resolveConfigPath(configPath);
62
- if (!fs.existsSync(resolvedPath)) {
80
+ if (!fs6.existsSync(resolvedPath)) {
63
81
  throw new Error(
64
82
  `Config file not found: ${resolvedPath}
65
83
  Create a riverbank.config.ts file or specify a path with --config`
@@ -90,7 +108,7 @@ function resolveConfigPath(configPath) {
90
108
  return path9.resolve(process.cwd(), DEFAULT_CONFIG_FILENAME);
91
109
  }
92
110
  const resolved = path9.resolve(configPath);
93
- if (fs.existsSync(resolved) && !resolved.endsWith(".ts") && !resolved.endsWith(".js")) {
111
+ if (fs6.existsSync(resolved) && !resolved.endsWith(".ts") && !resolved.endsWith(".js")) {
94
112
  return path9.resolve(resolved, DEFAULT_CONFIG_FILENAME);
95
113
  }
96
114
  return resolved;
@@ -102,6 +120,240 @@ var init_load_config = __esm({
102
120
  }
103
121
  });
104
122
 
123
+ // src/constants.ts
124
+ var PREBUILD_PAGE_SIZE, DEFAULT_MAX_PREBUILD_AGE_SEC, DEFAULT_PREBUILD_DIR;
125
+ var init_constants = __esm({
126
+ "src/constants.ts"() {
127
+ PREBUILD_PAGE_SIZE = 50;
128
+ DEFAULT_MAX_PREBUILD_AGE_SEC = 86400;
129
+ DEFAULT_PREBUILD_DIR = ".riverbank-cache";
130
+ }
131
+ });
132
+
133
+ // src/prebuild/loader.ts
134
+ var loader_exports = {};
135
+ __export(loader_exports, {
136
+ PrebuildLoader: () => PrebuildLoader,
137
+ canUsePrebuild: () => canUsePrebuild,
138
+ createPrebuildLoader: () => createPrebuildLoader
139
+ });
140
+ function loadManifest(prebuildDir) {
141
+ if (cachedManifest?.dir === prebuildDir) {
142
+ return cachedManifest.manifest;
143
+ }
144
+ const manifestPath = path9__namespace.join(prebuildDir, "manifest.json");
145
+ if (!fs6__namespace.existsSync(manifestPath)) {
146
+ return null;
147
+ }
148
+ try {
149
+ const content = fs6__namespace.readFileSync(manifestPath, "utf-8");
150
+ const manifest = JSON.parse(content);
151
+ cachedManifest = { manifest, dir: prebuildDir };
152
+ return manifest;
153
+ } catch {
154
+ return null;
155
+ }
156
+ }
157
+ function loadJsonFile(prebuildDir, relativePath) {
158
+ const filePath = path9__namespace.join(prebuildDir, relativePath);
159
+ if (!fs6__namespace.existsSync(filePath)) {
160
+ return null;
161
+ }
162
+ try {
163
+ const content = fs6__namespace.readFileSync(filePath, "utf-8");
164
+ return JSON.parse(content);
165
+ } catch {
166
+ return null;
167
+ }
168
+ }
169
+ function isPrebuildExpired(manifest, maxAgeSec) {
170
+ const ageMs = Date.now() - new Date(manifest.generatedAt).getTime();
171
+ return ageMs > maxAgeSec * 1e3;
172
+ }
173
+ function getPrebuildAgeSec(manifest) {
174
+ const ageMs = Date.now() - new Date(manifest.generatedAt).getTime();
175
+ return Math.floor(ageMs / 1e3);
176
+ }
177
+ function canUsePrebuild() {
178
+ if (typeof process === "undefined" || !process.versions?.node) {
179
+ return false;
180
+ }
181
+ try {
182
+ return typeof fs6__namespace.existsSync === "function";
183
+ } catch {
184
+ return false;
185
+ }
186
+ }
187
+ function createPrebuildLoader(config3) {
188
+ return new PrebuildLoader(config3);
189
+ }
190
+ var cachedManifest, PrebuildLoader;
191
+ var init_loader = __esm({
192
+ "src/prebuild/loader.ts"() {
193
+ init_constants();
194
+ cachedManifest = null;
195
+ PrebuildLoader = class {
196
+ constructor(config3) {
197
+ this.prebuildDir = config3.prebuildDir ?? DEFAULT_PREBUILD_DIR;
198
+ this.maxPrebuildAgeSec = config3.maxPrebuildAgeSec ?? DEFAULT_MAX_PREBUILD_AGE_SEC;
199
+ }
200
+ /**
201
+ * Check if prebuild is available and not expired.
202
+ */
203
+ isAvailable() {
204
+ if (!canUsePrebuild()) {
205
+ return false;
206
+ }
207
+ const manifest = loadManifest(this.prebuildDir);
208
+ if (!manifest) {
209
+ return false;
210
+ }
211
+ return !isPrebuildExpired(manifest, this.maxPrebuildAgeSec);
212
+ }
213
+ /**
214
+ * Load site data from prebuild cache.
215
+ */
216
+ loadSite(siteId) {
217
+ const manifest = loadManifest(this.prebuildDir);
218
+ if (!manifest || isPrebuildExpired(manifest, this.maxPrebuildAgeSec)) {
219
+ return null;
220
+ }
221
+ const cacheFile = loadJsonFile(this.prebuildDir, "site.json");
222
+ if (!cacheFile || cacheFile.data.site.id !== siteId) {
223
+ return null;
224
+ }
225
+ return {
226
+ data: cacheFile.data,
227
+ prebuildAgeSec: getPrebuildAgeSec(manifest)
228
+ };
229
+ }
230
+ /**
231
+ * Load page data from prebuild cache.
232
+ */
233
+ loadPage(siteId, pagePath) {
234
+ const manifest = loadManifest(this.prebuildDir);
235
+ if (!manifest || isPrebuildExpired(manifest, this.maxPrebuildAgeSec)) {
236
+ return null;
237
+ }
238
+ const cacheKey = `page:${siteId}:${pagePath}:false`;
239
+ const relativePath = manifest.keyToFile[cacheKey];
240
+ if (!relativePath) {
241
+ return null;
242
+ }
243
+ const cacheFile = loadJsonFile(this.prebuildDir, relativePath);
244
+ if (!cacheFile) {
245
+ return null;
246
+ }
247
+ return {
248
+ data: cacheFile.data,
249
+ prebuildAgeSec: getPrebuildAgeSec(manifest)
250
+ };
251
+ }
252
+ /**
253
+ * Load entries from prebuild cache with runtime filtering.
254
+ *
255
+ * The prebuild stores ALL entries for each content type.
256
+ * Filtering, ordering, and pagination are applied at runtime.
257
+ */
258
+ loadEntries(siteId, params) {
259
+ if (params.preview) {
260
+ return null;
261
+ }
262
+ if (params.mode === "manual" && params.entryIds?.length) {
263
+ return null;
264
+ }
265
+ const manifest = loadManifest(this.prebuildDir);
266
+ if (!manifest || isPrebuildExpired(manifest, this.maxPrebuildAgeSec)) {
267
+ return null;
268
+ }
269
+ const cacheKey = `entries-all:${siteId}:${params.contentType}`;
270
+ const relativePath = manifest.keyToFile[cacheKey];
271
+ if (!relativePath) {
272
+ return null;
273
+ }
274
+ const cacheFile = loadJsonFile(this.prebuildDir, relativePath);
275
+ if (!cacheFile) {
276
+ return null;
277
+ }
278
+ let entries = [...cacheFile.entries];
279
+ if (params.order === "newest") {
280
+ entries.sort((a, b) => {
281
+ const aTime = a.publishedAt ? new Date(a.publishedAt).getTime() : 0;
282
+ const bTime = b.publishedAt ? new Date(b.publishedAt).getTime() : 0;
283
+ return bTime - aTime;
284
+ });
285
+ } else if (params.order === "oldest") {
286
+ entries.sort((a, b) => {
287
+ const aTime = a.publishedAt ? new Date(a.publishedAt).getTime() : 0;
288
+ const bTime = b.publishedAt ? new Date(b.publishedAt).getTime() : 0;
289
+ return aTime - bTime;
290
+ });
291
+ } else if (params.order === "title") {
292
+ entries.sort((a, b) => (a.title || "").localeCompare(b.title || ""));
293
+ }
294
+ const total = entries.length;
295
+ const offset = params.offset ?? 0;
296
+ const limit = params.limit ?? 10;
297
+ if (offset > 0) {
298
+ entries = entries.slice(offset);
299
+ }
300
+ entries = entries.slice(0, limit);
301
+ const prebuildAgeSec = getPrebuildAgeSec(manifest);
302
+ if (params.includeMeta) {
303
+ return {
304
+ data: {
305
+ entries,
306
+ total,
307
+ hasMore: offset + entries.length < total,
308
+ limit,
309
+ offset,
310
+ totalPages: Math.ceil(total / limit),
311
+ currentPage: Math.floor(offset / limit) + 1
312
+ },
313
+ prebuildAgeSec
314
+ };
315
+ }
316
+ return {
317
+ data: { entries },
318
+ prebuildAgeSec
319
+ };
320
+ }
321
+ /**
322
+ * Load navigation data from prebuild cache.
323
+ */
324
+ loadNavigation() {
325
+ const manifest = loadManifest(this.prebuildDir);
326
+ if (!manifest || isPrebuildExpired(manifest, this.maxPrebuildAgeSec)) {
327
+ return null;
328
+ }
329
+ const cacheFile = loadJsonFile(
330
+ this.prebuildDir,
331
+ "navigation/menus.json"
332
+ );
333
+ if (!cacheFile) {
334
+ return null;
335
+ }
336
+ return {
337
+ data: cacheFile.menus,
338
+ prebuildAgeSec: getPrebuildAgeSec(manifest)
339
+ };
340
+ }
341
+ /**
342
+ * Get the manifest for inspection.
343
+ */
344
+ getManifest() {
345
+ return loadManifest(this.prebuildDir);
346
+ }
347
+ /**
348
+ * Clear the cached manifest (for testing).
349
+ */
350
+ clearCache() {
351
+ cachedManifest = null;
352
+ }
353
+ };
354
+ }
355
+ });
356
+
105
357
  // ../blocks/src/system/manifest/augmentManifest.ts
106
358
  function augmentManifest(manifest) {
107
359
  let augmentedFields = manifest.fields ?? [];
@@ -574,11 +826,11 @@ function bind(from, options) {
574
826
  }
575
827
  });
576
828
  }
577
- function when(path11, options) {
829
+ function when(path13, options) {
578
830
  return (node) => ({
579
831
  ...node,
580
832
  $when: {
581
- when: { from: path11 },
833
+ when: { from: path13 },
582
834
  ...options?.equals !== void 0 ? { equals: options.equals } : {},
583
835
  ...options?.not ? { not: true } : {}
584
836
  }
@@ -651,25 +903,25 @@ function devValidate(node) {
651
903
  }
652
904
 
653
905
  // ../blocks/src/system/node/fragments/backgroundLayer.ts
654
- function backgroundLayer(path11, options = {}) {
906
+ function backgroundLayer(path13, options = {}) {
655
907
  const {
656
908
  styleClassName = "absolute inset-0 -z-10 h-full w-full pointer-events-none",
657
909
  imageClassName
658
910
  } = options;
659
911
  const styleLayer = el("div", {
660
- className: { $bind: { from: path11, transforms: [{ id: "background.resolveClass", options: { baseClass: styleClassName } }] } },
661
- style: { $bind: { from: path11, transforms: [{ id: "background.resolveStyle" }] } }
912
+ className: { $bind: { from: path13, transforms: [{ id: "background.resolveClass", options: { baseClass: styleClassName } }] } },
913
+ style: { $bind: { from: path13, transforms: [{ id: "background.resolveStyle" }] } }
662
914
  });
663
- const imageLayer = createBackgroundImageNode(path11, imageClassName);
915
+ const imageLayer = createBackgroundImageNode(path13, imageClassName);
664
916
  return [styleLayer, imageLayer];
665
917
  }
666
- function createBackgroundImageNode(path11, baseClassName = "absolute -z-10") {
667
- const imagePath = `${path11}.image`;
918
+ function createBackgroundImageNode(path13, baseClassName = "absolute -z-10") {
919
+ const imagePath = `${path13}.image`;
668
920
  return media(
669
921
  {
670
922
  className: {
671
923
  $bind: {
672
- from: path11,
924
+ from: path13,
673
925
  transforms: [{
674
926
  id: "background.resolveImageClassName",
675
927
  options: { baseClass: `background-image ${baseClassName}` }
@@ -678,7 +930,7 @@ function createBackgroundImageNode(path11, baseClassName = "absolute -z-10") {
678
930
  },
679
931
  style: {
680
932
  $bind: {
681
- from: path11,
933
+ from: path13,
682
934
  transforms: [{ id: "background.resolveImageStyle" }]
683
935
  }
684
936
  }
@@ -1106,27 +1358,27 @@ function scopePropValue(value, scope) {
1106
1358
  }
1107
1359
  return value;
1108
1360
  }
1109
- function scopeContentPath(path11, scope) {
1361
+ function scopeContentPath(path13, scope) {
1110
1362
  if (!scope || scope.length === 0) {
1111
- return path11;
1363
+ return path13;
1112
1364
  }
1113
- if (path11 === "content") {
1365
+ if (path13 === "content") {
1114
1366
  return `content.${scope}`;
1115
1367
  }
1116
- if (path11.startsWith("content.")) {
1117
- const remainder = path11.slice("content.".length);
1368
+ if (path13.startsWith("content.")) {
1369
+ const remainder = path13.slice("content.".length);
1118
1370
  return remainder.length > 0 ? `content.${scope}.${remainder}` : `content.${scope}`;
1119
1371
  }
1120
- if (path11.startsWith("content[")) {
1121
- return path11.replace(/^content/, `content.${scope}`);
1372
+ if (path13.startsWith("content[")) {
1373
+ return path13.replace(/^content/, `content.${scope}`);
1122
1374
  }
1123
- if (path11.startsWith("$root.")) {
1124
- return path11;
1375
+ if (path13.startsWith("$root.")) {
1376
+ return path13;
1125
1377
  }
1126
- if (path11.includes(".")) {
1127
- return path11;
1378
+ if (path13.includes(".")) {
1379
+ return path13;
1128
1380
  }
1129
- return `content.${scope}.${path11}`;
1381
+ return `content.${scope}.${path13}`;
1130
1382
  }
1131
1383
 
1132
1384
  // ../blocks/src/system/fragments/builder.ts
@@ -5133,7 +5385,7 @@ var contentConfigSchema = contentConfigBaseSchema.superRefine((data, ctx) => {
5133
5385
  });
5134
5386
  }
5135
5387
  const paths = data.pages.map((p) => p.path);
5136
- const duplicatePaths = paths.filter((path11, i) => paths.indexOf(path11) !== i);
5388
+ const duplicatePaths = paths.filter((path13, i) => paths.indexOf(path13) !== i);
5137
5389
  if (duplicatePaths.length > 0) {
5138
5390
  ctx.addIssue({
5139
5391
  code: zod.z.ZodIssueCode.custom,
@@ -5510,8 +5762,8 @@ var ManagementApiError = class extends Error {
5510
5762
  function createHttpClient(config3) {
5511
5763
  const baseUrl = `${config3.dashboardUrl}/api/sdk/${config3.siteId}`;
5512
5764
  const timeout = config3.timeout ?? 3e4;
5513
- async function request(method, path11, options) {
5514
- let url = `${baseUrl}${path11}`;
5765
+ async function request(method, path13, options) {
5766
+ let url = `${baseUrl}${path13}`;
5515
5767
  if (options?.params && Object.keys(options.params).length > 0) {
5516
5768
  const searchParams = new URLSearchParams(options.params);
5517
5769
  url = `${url}?${searchParams.toString()}`;
@@ -5579,17 +5831,17 @@ function createHttpClient(config3) {
5579
5831
  return json.data;
5580
5832
  }
5581
5833
  return {
5582
- async get(path11, params) {
5583
- return request("GET", path11, { params });
5834
+ async get(path13, params) {
5835
+ return request("GET", path13, { params });
5584
5836
  },
5585
- async post(path11, body) {
5586
- return request("POST", path11, { body });
5837
+ async post(path13, body) {
5838
+ return request("POST", path13, { body });
5587
5839
  },
5588
- async patch(path11, body) {
5589
- return request("PATCH", path11, { body });
5840
+ async patch(path13, body) {
5841
+ return request("PATCH", path13, { body });
5590
5842
  },
5591
- async delete(path11, body) {
5592
- await request("DELETE", path11, { body });
5843
+ async delete(path13, body) {
5844
+ await request("DELETE", path13, { body });
5593
5845
  }
5594
5846
  };
5595
5847
  }
@@ -6748,11 +7000,11 @@ function findChangedFields(local, remote, prefix = "") {
6748
7000
  const changes = [];
6749
7001
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(local), ...Object.keys(remote)]);
6750
7002
  for (const key of allKeys) {
6751
- const path11 = prefix ? `${prefix}.${key}` : key;
7003
+ const path13 = prefix ? `${prefix}.${key}` : key;
6752
7004
  const localVal = local[key];
6753
7005
  const remoteVal = remote[key];
6754
7006
  if (!equal__default.default(localVal, remoteVal)) {
6755
- changes.push(path11);
7007
+ changes.push(path13);
6756
7008
  }
6757
7009
  }
6758
7010
  return changes;
@@ -8505,7 +8757,7 @@ function getContentDir() {
8505
8757
  function loadTemplate(name) {
8506
8758
  const contentDir = getContentDir();
8507
8759
  const filePath = path9__namespace.join(contentDir, `${name}.md`);
8508
- return fs.readFileSync(filePath, "utf-8");
8760
+ return fs6.readFileSync(filePath, "utf-8");
8509
8761
  }
8510
8762
  async function initDocs(options) {
8511
8763
  const { rootDir, configPath, agentsPath } = options;
@@ -8692,6 +8944,3407 @@ Examples:
8692
8944
  $ riverbankcms identifiers backfill
8693
8945
  `).addCommand(backfillCommand);
8694
8946
 
8947
+ // src/cli/commands/deploy.ts
8948
+ init_load_config();
8949
+
8950
+ // ../api/src/endpoints.ts
8951
+ var ENDPOINT_DEFINITIONS = {
8952
+ // AI endpoints - no cache due to dynamic nature
8953
+ aiContentUpdateChat: {
8954
+ path: "/ai/content-update-chat",
8955
+ method: "POST",
8956
+ auth: "user",
8957
+ responseKind: "stream"
8958
+ },
8959
+ aiChat: {
8960
+ path: "/ai/chat",
8961
+ method: "POST",
8962
+ auth: "user",
8963
+ responseKind: "stream"
8964
+ },
8965
+ applySeoChanges: {
8966
+ path: "/seo/apply",
8967
+ method: "POST",
8968
+ auth: "user",
8969
+ responseKind: "json"
8970
+ },
8971
+ aiCreateBriefChat: {
8972
+ path: "/ai/chat/create-brief",
8973
+ method: "POST",
8974
+ auth: "user",
8975
+ responseKind: "json"
8976
+ },
8977
+ aiPrototypeChat: {
8978
+ path: "/ai/chat/create-prototype",
8979
+ method: "POST",
8980
+ revalidate: 30,
8981
+ // Short cache for AI responses to avoid duplicate calls
8982
+ tags: ["ai-prototype"],
8983
+ auth: "user",
8984
+ responseKind: "json"
8985
+ },
8986
+ aiPatchDryRun: {
8987
+ path: "/ai/patch/dry-run",
8988
+ method: "POST",
8989
+ auth: "user",
8990
+ responseKind: "json"
8991
+ },
8992
+ aiPatchApply: {
8993
+ path: "/ai/patch/apply",
8994
+ method: "POST",
8995
+ auth: "user",
8996
+ responseKind: "json"
8997
+ },
8998
+ aiPlaygroundPropose: {
8999
+ path: "/sites/{siteId}/ai/playground/propose",
9000
+ method: "POST",
9001
+ auth: "user",
9002
+ responseKind: "json"
9003
+ },
9004
+ // Admin SEO
9005
+ listGscPropertiesAdmin: {
9006
+ path: "/admin/seo/gsc/properties",
9007
+ method: "GET",
9008
+ auth: "admin",
9009
+ responseKind: "json"
9010
+ },
9011
+ adminSetGscPersist: {
9012
+ path: "/admin/seo/gsc/meta/persist",
9013
+ method: "POST",
9014
+ auth: "admin",
9015
+ responseKind: "json"
9016
+ },
9017
+ adminStartGscVerification: {
9018
+ path: "/admin/seo/gsc/properties/verify/start",
9019
+ method: "POST",
9020
+ auth: "admin",
9021
+ responseKind: "json"
9022
+ },
9023
+ adminConfirmGscVerification: {
9024
+ path: "/admin/seo/gsc/properties/verify/confirm",
9025
+ method: "POST",
9026
+ auth: "admin",
9027
+ responseKind: "json"
9028
+ },
9029
+ adminRunGscIngest: {
9030
+ path: "/admin/seo/ingest/run",
9031
+ method: "POST",
9032
+ auth: "admin",
9033
+ responseKind: "json"
9034
+ },
9035
+ getSeoVerificationMeta: {
9036
+ path: "/public/seo/verification/meta",
9037
+ method: "GET",
9038
+ auth: "public",
9039
+ responseKind: "json"
9040
+ },
9041
+ checkRedirect: {
9042
+ path: "/api/public/content/redirect",
9043
+ method: "GET",
9044
+ revalidate: 86400,
9045
+ // 24 hours - redirects rarely change
9046
+ tags: ["redirect"],
9047
+ auth: "public",
9048
+ responseKind: "json"
9049
+ },
9050
+ listRedirectRules: {
9051
+ path: "/sites/{siteId}/redirects",
9052
+ method: "GET",
9053
+ auth: "user",
9054
+ responseKind: "json"
9055
+ },
9056
+ createRedirectRule: {
9057
+ path: "/sites/{siteId}/redirects",
9058
+ method: "POST",
9059
+ auth: "user",
9060
+ responseKind: "json"
9061
+ },
9062
+ deleteRedirectRule: {
9063
+ path: "/sites/{siteId}/redirects/{ruleId}",
9064
+ method: "DELETE",
9065
+ auth: "user",
9066
+ responseKind: "json"
9067
+ },
9068
+ // API Keys (Account-level - DEPRECATED, use site-scoped endpoints)
9069
+ listApiKeys: {
9070
+ path: "/account/api-keys",
9071
+ method: "GET",
9072
+ auth: "user",
9073
+ responseKind: "json"
9074
+ },
9075
+ createApiKey: {
9076
+ path: "/account/api-keys",
9077
+ method: "POST",
9078
+ auth: "user",
9079
+ responseKind: "json"
9080
+ },
9081
+ revokeApiKey: {
9082
+ path: "/account/api-keys/{keyId}",
9083
+ method: "DELETE",
9084
+ auth: "user",
9085
+ responseKind: "json"
9086
+ },
9087
+ // API Keys (Site-scoped - preferred)
9088
+ listSiteApiKeys: {
9089
+ path: "/sites/{siteId}/api-keys",
9090
+ method: "GET",
9091
+ auth: "user",
9092
+ tags: ["site-{siteId}", "api-keys"],
9093
+ responseKind: "json"
9094
+ },
9095
+ createSiteApiKey: {
9096
+ path: "/sites/{siteId}/api-keys",
9097
+ method: "POST",
9098
+ auth: "user",
9099
+ tags: ["site-{siteId}", "api-keys"],
9100
+ responseKind: "json"
9101
+ },
9102
+ revokeSiteApiKey: {
9103
+ path: "/sites/{siteId}/api-keys/{keyId}",
9104
+ method: "DELETE",
9105
+ auth: "user",
9106
+ tags: ["site-{siteId}", "api-keys"],
9107
+ responseKind: "json"
9108
+ },
9109
+ getSitePreviewKey: {
9110
+ path: "/sites/{siteId}/api-keys/preview",
9111
+ method: "GET",
9112
+ auth: "user",
9113
+ tags: ["site-{siteId}", "api-keys", "preview-key"],
9114
+ responseKind: "json"
9115
+ },
9116
+ regenerateSitePreviewKey: {
9117
+ path: "/sites/{siteId}/api-keys/preview/regenerate",
9118
+ method: "POST",
9119
+ auth: "user",
9120
+ tags: ["site-{siteId}", "api-keys", "preview-key"],
9121
+ responseKind: "json"
9122
+ },
9123
+ getSiteApiKeyAccessLogs: {
9124
+ path: "/sites/{siteId}/api-keys/access-logs",
9125
+ method: "GET",
9126
+ auth: "user",
9127
+ tags: ["site-{siteId}", "api-keys", "access-logs"],
9128
+ responseKind: "json"
9129
+ },
9130
+ // Management API Keys (SDK write operations)
9131
+ listManagementKeys: {
9132
+ path: "/sites/{siteId}/api-keys/management",
9133
+ method: "GET",
9134
+ auth: "user",
9135
+ tags: ["site-{siteId}", "api-keys", "management-keys"],
9136
+ responseKind: "json"
9137
+ },
9138
+ createManagementKey: {
9139
+ path: "/sites/{siteId}/api-keys/management",
9140
+ method: "POST",
9141
+ auth: "user",
9142
+ tags: ["site-{siteId}", "api-keys", "management-keys"],
9143
+ responseKind: "json"
9144
+ },
9145
+ revokeManagementKey: {
9146
+ path: "/sites/{siteId}/api-keys/management",
9147
+ method: "DELETE",
9148
+ auth: "user",
9149
+ tags: ["site-{siteId}", "api-keys", "management-keys"],
9150
+ responseKind: "json"
9151
+ },
9152
+ getBookingSettings: {
9153
+ path: "/sites/{siteId}/bookings/settings",
9154
+ method: "GET",
9155
+ auth: "user",
9156
+ responseKind: "json"
9157
+ },
9158
+ updateBookingSettings: {
9159
+ path: "/sites/{siteId}/bookings/settings",
9160
+ method: "PUT",
9161
+ auth: "user",
9162
+ responseKind: "json"
9163
+ },
9164
+ listAppointmentResources: {
9165
+ path: "/sites/{siteId}/bookings/resources",
9166
+ method: "GET",
9167
+ auth: "user",
9168
+ responseKind: "json"
9169
+ },
9170
+ createAppointmentResource: {
9171
+ path: "/sites/{siteId}/bookings/resources",
9172
+ method: "POST",
9173
+ auth: "user",
9174
+ responseKind: "json"
9175
+ },
9176
+ getAppointmentResource: {
9177
+ path: "/sites/{siteId}/bookings/resources/{resourceId}",
9178
+ method: "GET",
9179
+ auth: "user",
9180
+ responseKind: "json"
9181
+ },
9182
+ updateAppointmentResource: {
9183
+ path: "/sites/{siteId}/bookings/resources/{resourceId}",
9184
+ method: "PUT",
9185
+ auth: "user",
9186
+ responseKind: "json"
9187
+ },
9188
+ deleteAppointmentResource: {
9189
+ path: "/sites/{siteId}/bookings/resources/{resourceId}",
9190
+ method: "DELETE",
9191
+ auth: "user",
9192
+ responseKind: "json"
9193
+ },
9194
+ listAppointmentServices: {
9195
+ path: "/sites/{siteId}/bookings/services",
9196
+ method: "GET",
9197
+ auth: "user",
9198
+ responseKind: "json"
9199
+ },
9200
+ createAppointmentService: {
9201
+ path: "/sites/{siteId}/bookings/services",
9202
+ method: "POST",
9203
+ auth: "user",
9204
+ responseKind: "json"
9205
+ },
9206
+ getAppointmentService: {
9207
+ path: "/sites/{siteId}/bookings/services/{serviceId}",
9208
+ method: "GET",
9209
+ auth: "user",
9210
+ responseKind: "json"
9211
+ },
9212
+ updateAppointmentService: {
9213
+ path: "/sites/{siteId}/bookings/services/{serviceId}",
9214
+ method: "PUT",
9215
+ auth: "user",
9216
+ responseKind: "json"
9217
+ },
9218
+ deleteAppointmentService: {
9219
+ path: "/sites/{siteId}/bookings/services/{serviceId}",
9220
+ method: "DELETE",
9221
+ auth: "user",
9222
+ responseKind: "json"
9223
+ },
9224
+ getAppointmentServicesReference: {
9225
+ path: "/sites/{siteId}/bookings/services/reference",
9226
+ method: "GET",
9227
+ auth: "user",
9228
+ responseKind: "json"
9229
+ },
9230
+ getAppointmentResourcesReference: {
9231
+ path: "/sites/{siteId}/bookings/resources/reference",
9232
+ method: "GET",
9233
+ auth: "user",
9234
+ responseKind: "json"
9235
+ },
9236
+ // Service-Resource linking
9237
+ getResourceServices: {
9238
+ path: "/sites/{siteId}/bookings/resources/{resourceId}/services",
9239
+ method: "GET",
9240
+ auth: "user",
9241
+ responseKind: "json"
9242
+ },
9243
+ updateResourceServices: {
9244
+ path: "/sites/{siteId}/bookings/resources/{resourceId}/services",
9245
+ method: "PUT",
9246
+ auth: "user",
9247
+ responseKind: "json"
9248
+ },
9249
+ getServiceResources: {
9250
+ path: "/sites/{siteId}/bookings/services/{serviceId}/resources",
9251
+ method: "GET",
9252
+ auth: "user",
9253
+ responseKind: "json"
9254
+ },
9255
+ updateServiceResources: {
9256
+ path: "/sites/{siteId}/bookings/services/{serviceId}/resources",
9257
+ method: "PUT",
9258
+ auth: "user",
9259
+ responseKind: "json"
9260
+ },
9261
+ // Availability management
9262
+ listAvailabilityRules: {
9263
+ path: "/sites/{siteId}/bookings/resources/{resourceId}/availability",
9264
+ method: "GET",
9265
+ auth: "user",
9266
+ responseKind: "json"
9267
+ },
9268
+ upsertAvailabilityRule: {
9269
+ path: "/sites/{siteId}/bookings/resources/{resourceId}/availability",
9270
+ method: "POST",
9271
+ auth: "user",
9272
+ responseKind: "json"
9273
+ },
9274
+ deleteAvailabilityRule: {
9275
+ path: "/sites/{siteId}/bookings/resources/{resourceId}/availability/{ruleId}",
9276
+ method: "DELETE",
9277
+ auth: "user",
9278
+ responseKind: "json"
9279
+ },
9280
+ listBlackouts: {
9281
+ path: "/sites/{siteId}/bookings/resources/{resourceId}/blackouts",
9282
+ method: "GET",
9283
+ auth: "user",
9284
+ responseKind: "json"
9285
+ },
9286
+ createBlackout: {
9287
+ path: "/sites/{siteId}/bookings/resources/{resourceId}/blackouts",
9288
+ method: "POST",
9289
+ auth: "user",
9290
+ responseKind: "json"
9291
+ },
9292
+ deleteBlackout: {
9293
+ path: "/sites/{siteId}/bookings/resources/{resourceId}/blackouts/{blackoutId}",
9294
+ method: "DELETE",
9295
+ auth: "user",
9296
+ responseKind: "json"
9297
+ },
9298
+ getAvailableSlots: {
9299
+ path: "/sites/{siteId}/bookings/availability/slots",
9300
+ method: "GET",
9301
+ auth: "user",
9302
+ responseKind: "json"
9303
+ },
9304
+ createAppointment: {
9305
+ path: "/sites/{siteId}/bookings/appointments",
9306
+ method: "POST",
9307
+ auth: "user",
9308
+ responseKind: "json"
9309
+ },
9310
+ // Data retrieval endpoints - good candidates for caching
9311
+ getBrief: {
9312
+ path: "/briefs",
9313
+ method: "GET",
9314
+ revalidate: 120,
9315
+ // 2 minutes
9316
+ tags: ["brief"],
9317
+ auth: "user",
9318
+ responseKind: "json"
9319
+ },
9320
+ // Unified site data endpoint - use this for all site lookups
9321
+ getSite: {
9322
+ path: "/sites",
9323
+ method: "GET",
9324
+ revalidate: 900,
9325
+ // 15 minutes - site data changes less frequently
9326
+ tags: ["site"],
9327
+ auth: "user",
9328
+ responseKind: "json"
9329
+ },
9330
+ // DEPRECATED: Use getSite with ?slug={slug} instead
9331
+ getSiteBySlug: {
9332
+ path: "/sites/by-slug/{slug}",
9333
+ method: "GET",
9334
+ revalidate: 900,
9335
+ // 15 minutes - site data changes less frequently
9336
+ tags: ["site", "site-{slug}"],
9337
+ auth: "user",
9338
+ responseKind: "json"
9339
+ },
9340
+ // DEPRECATED: Use getSite with ?domain={domain} instead
9341
+ getSiteByDomain: {
9342
+ path: "/sites/by-domain/{domain}",
9343
+ method: "GET",
9344
+ revalidate: 900,
9345
+ // 15 minutes - site data changes less frequently
9346
+ tags: ["site", "site-domain-{domain}"],
9347
+ auth: "user",
9348
+ responseKind: "json"
9349
+ },
9350
+ createBriefTurn: {
9351
+ path: "/brief-turns",
9352
+ method: "POST",
9353
+ tags: ["brief"],
9354
+ // Tags for invalidation after mutation
9355
+ auth: "user",
9356
+ responseKind: "json"
9357
+ },
9358
+ upsertBrief: {
9359
+ path: "/briefs",
9360
+ method: "PUT",
9361
+ tags: ["brief"],
9362
+ auth: "user",
9363
+ responseKind: "json"
9364
+ },
9365
+ aiBriefToSpec: {
9366
+ path: "/ai/actions/brief-to-spec",
9367
+ method: "POST",
9368
+ tags: ["brief", "spec"],
9369
+ auth: "user",
9370
+ responseKind: "json"
9371
+ },
9372
+ createSite: {
9373
+ path: "/sites",
9374
+ method: "POST",
9375
+ tags: ["site"],
9376
+ auth: "user",
9377
+ responseKind: "json"
9378
+ },
9379
+ createSiteManual: {
9380
+ path: "/sites/manual",
9381
+ method: "POST",
9382
+ tags: ["site"],
9383
+ auth: "user",
9384
+ responseKind: "json"
9385
+ },
9386
+ updateSite: {
9387
+ path: "/sites",
9388
+ method: "PUT",
9389
+ tags: ["site"],
9390
+ auth: "user",
9391
+ responseKind: "json"
9392
+ },
9393
+ deleteSite: {
9394
+ path: "/sites/{siteId}",
9395
+ method: "DELETE",
9396
+ tags: ["site", "site-{siteId}"],
9397
+ auth: "user",
9398
+ responseKind: "json"
9399
+ },
9400
+ listSiteMembers: {
9401
+ path: "/sites/{siteId}/members",
9402
+ method: "GET",
9403
+ tags: ["site-{siteId}", "site-members-{siteId}"],
9404
+ auth: "user",
9405
+ responseKind: "json"
9406
+ },
9407
+ inviteSiteMember: {
9408
+ path: "/sites/{siteId}/members",
9409
+ method: "POST",
9410
+ tags: ["site-{siteId}", "site-members-{siteId}"],
9411
+ auth: "user",
9412
+ responseKind: "json"
9413
+ },
9414
+ updateSiteMemberRole: {
9415
+ path: "/sites/{siteId}/members/{memberId}",
9416
+ method: "PATCH",
9417
+ tags: ["site-{siteId}", "site-members-{siteId}", "site-member-{memberId}"],
9418
+ auth: "user",
9419
+ responseKind: "json"
9420
+ },
9421
+ authLogin: {
9422
+ path: "/auth/login/submit",
9423
+ method: "POST",
9424
+ tags: ["auth"],
9425
+ auth: "public",
9426
+ responseKind: "json"
9427
+ },
9428
+ authForgotPassword: {
9429
+ path: "/auth/forgot/submit",
9430
+ method: "POST",
9431
+ tags: ["auth"],
9432
+ auth: "public",
9433
+ responseKind: "json"
9434
+ },
9435
+ authRegister: {
9436
+ path: "/auth/register/submit",
9437
+ method: "POST",
9438
+ tags: ["auth"],
9439
+ auth: "public",
9440
+ responseKind: "json"
9441
+ },
9442
+ authReauthenticate: {
9443
+ path: "/auth/reauth/submit",
9444
+ method: "POST",
9445
+ tags: ["auth"],
9446
+ auth: "public",
9447
+ responseKind: "json"
9448
+ },
9449
+ lookupSiteDomains: {
9450
+ path: "/sites/{siteId}/domains/lookup",
9451
+ method: "POST",
9452
+ tags: ["site-{siteId}", "site-domains"],
9453
+ auth: "user",
9454
+ responseKind: "json"
9455
+ },
9456
+ registerSiteDomain: {
9457
+ path: "/sites/{siteId}/domains/register",
9458
+ method: "POST",
9459
+ tags: ["site-{siteId}", "site-domains"],
9460
+ auth: "user",
9461
+ responseKind: "json"
9462
+ },
9463
+ addCustomDomain: {
9464
+ path: "/sites/{siteId}/domains/custom",
9465
+ method: "POST",
9466
+ tags: ["site-{siteId}", "site-domains"],
9467
+ auth: "user",
9468
+ responseKind: "json"
9469
+ },
9470
+ removeCustomDomain: {
9471
+ path: "/sites/{siteId}/domains/custom",
9472
+ method: "DELETE",
9473
+ tags: ["site-{siteId}", "site-domains"],
9474
+ auth: "user",
9475
+ responseKind: "json"
9476
+ },
9477
+ syncCustomDomainToEdgeConfig: {
9478
+ path: "/sites/{siteId}/domains/custom/sync",
9479
+ method: "POST",
9480
+ tags: ["site-{siteId}", "site-domains"],
9481
+ auth: "user",
9482
+ responseKind: "json"
9483
+ },
9484
+ removeSiteMember: {
9485
+ path: "/sites/{siteId}/members/{memberId}",
9486
+ method: "DELETE",
9487
+ tags: ["site-{siteId}", "site-members-{siteId}", "site-member-{memberId}"],
9488
+ auth: "user",
9489
+ responseKind: "json"
9490
+ },
9491
+ revokeSiteInvitation: {
9492
+ path: "/sites/{siteId}/members/invitations/{invitationId}",
9493
+ method: "DELETE",
9494
+ tags: ["site-{siteId}", "site-members-{siteId}", "site-invite-{invitationId}"],
9495
+ auth: "user",
9496
+ responseKind: "json"
9497
+ },
9498
+ transferSiteOwnership: {
9499
+ path: "/sites/{siteId}/members/transfer-ownership",
9500
+ method: "POST",
9501
+ tags: ["site-{siteId}", "site-members-{siteId}"],
9502
+ auth: "user",
9503
+ responseKind: "json"
9504
+ },
9505
+ listContentEntries: {
9506
+ path: "/sites/{siteId}/content/{type}",
9507
+ method: "GET",
9508
+ revalidate: 60,
9509
+ tags: ["site-{siteId}", "content-{siteId}-{type}"],
9510
+ auth: "user",
9511
+ responseKind: "json"
9512
+ },
9513
+ getContentTemplate: {
9514
+ path: "/sites/{siteId}/content/types/{type}/template",
9515
+ method: "GET",
9516
+ revalidate: 60,
9517
+ tags: ["site-{siteId}", "content-template-{siteId}-{type}"],
9518
+ auth: "user",
9519
+ responseKind: "json"
9520
+ },
9521
+ updateContentTemplateBlock: {
9522
+ path: "/sites/{siteId}/content/types/{type}/template/blocks/{blockId}",
9523
+ method: "PATCH",
9524
+ tags: ["site-{siteId}", "content-template-{siteId}-{type}", "content-template-block-{blockId}"],
9525
+ auth: "user",
9526
+ responseKind: "json"
9527
+ },
9528
+ applyContentTemplateAddon: {
9529
+ path: "/sites/{siteId}/content/types/{type}/template/addons",
9530
+ method: "POST",
9531
+ tags: ["site-{siteId}", "content-template-{siteId}-{type}"],
9532
+ auth: "user",
9533
+ responseKind: "json"
9534
+ },
9535
+ updateContentTemplateBlockBindings: {
9536
+ path: "/sites/{siteId}/content/types/{type}/template/blocks/{blockId}/bindings",
9537
+ method: "PATCH",
9538
+ tags: ["site-{siteId}", "content-template-{siteId}-{type}", "content-template-block-{blockId}"],
9539
+ auth: "user",
9540
+ responseKind: "json"
9541
+ },
9542
+ createTemplateBlock: {
9543
+ path: "/sites/{siteId}/content/types/{type}/template/blocks",
9544
+ method: "POST",
9545
+ tags: ["site-{siteId}", "content-template-{siteId}-{type}"],
9546
+ auth: "user",
9547
+ responseKind: "json"
9548
+ },
9549
+ deleteTemplateBlock: {
9550
+ path: "/sites/{siteId}/content/types/{type}/template/blocks/{blockId}",
9551
+ method: "DELETE",
9552
+ tags: ["site-{siteId}", "content-template-{siteId}-{type}", "content-template-block-{blockId}"],
9553
+ auth: "user",
9554
+ responseKind: "json"
9555
+ },
9556
+ reorderTemplateBlocks: {
9557
+ path: "/sites/{siteId}/content/types/{type}/template/blocks/reorder",
9558
+ method: "POST",
9559
+ tags: ["site-{siteId}", "content-template-{siteId}-{type}"],
9560
+ auth: "user",
9561
+ responseKind: "json"
9562
+ },
9563
+ getTransforms: {
9564
+ path: "/transforms",
9565
+ method: "GET",
9566
+ revalidate: 3600,
9567
+ tags: ["transforms"],
9568
+ auth: "public",
9569
+ responseKind: "json"
9570
+ },
9571
+ createContentEntry: {
9572
+ path: "/sites/{siteId}/content/{type}",
9573
+ method: "POST",
9574
+ tags: ["site-{siteId}", "content-{siteId}-{type}"],
9575
+ auth: "user",
9576
+ responseKind: "json"
9577
+ },
9578
+ getContentEntry: {
9579
+ path: "/sites/{siteId}/content/{type}/{entryId}",
9580
+ method: "GET",
9581
+ tags: ["site-{siteId}", "content-{siteId}-{type}", "content-entry-{entryId}"],
9582
+ auth: "user",
9583
+ responseKind: "json"
9584
+ },
9585
+ updateContentEntry: {
9586
+ path: "/sites/{siteId}/content/{type}/{entryId}",
9587
+ method: "PUT",
9588
+ tags: ["site-{siteId}", "content-{siteId}-{type}", "content-entry-{entryId}"],
9589
+ auth: "user",
9590
+ responseKind: "json"
9591
+ },
9592
+ updateContentEntryContent: {
9593
+ path: "/sites/{siteId}/content/{type}/{entryId}/content",
9594
+ method: "PUT",
9595
+ tags: ["site-{siteId}", "content-{siteId}-{type}", "content-entry-{entryId}"],
9596
+ auth: "user",
9597
+ responseKind: "json"
9598
+ },
9599
+ updateRouteMetadata: {
9600
+ path: "/sites/{siteId}/routes/{routeId}/metadata",
9601
+ method: "PATCH",
9602
+ tags: ["site-{siteId}", "route-{routeId}"],
9603
+ auth: "user",
9604
+ responseKind: "json"
9605
+ },
9606
+ publishContentEntry: {
9607
+ path: "/sites/{siteId}/content/{type}/{entryId}/publish",
9608
+ method: "POST",
9609
+ tags: ["site-{siteId}", "content-{siteId}-{type}", "content-entry-{entryId}"],
9610
+ auth: "user",
9611
+ responseKind: "json"
9612
+ },
9613
+ discardContentEntry: {
9614
+ path: "/sites/{siteId}/content/{type}/{entryId}/discard",
9615
+ method: "POST",
9616
+ tags: ["site-{siteId}", "content-{siteId}-{type}", "content-entry-{entryId}"],
9617
+ auth: "user",
9618
+ responseKind: "json"
9619
+ },
9620
+ unpublishContentEntry: {
9621
+ path: "/sites/{siteId}/content/{type}/{entryId}/unpublish",
9622
+ method: "POST",
9623
+ tags: ["site-{siteId}", "content-{siteId}-{type}", "content-entry-{entryId}"],
9624
+ auth: "user",
9625
+ responseKind: "json"
9626
+ },
9627
+ // Content types: enable + setup
9628
+ listContentTypes: {
9629
+ path: "/sites/{siteId}/content-types",
9630
+ method: "GET",
9631
+ revalidate: 120,
9632
+ // 2 minutes
9633
+ tags: ["site-{siteId}", "content-types"],
9634
+ auth: "user",
9635
+ responseKind: "json"
9636
+ },
9637
+ enableContentType: {
9638
+ path: "/sites/{siteId}/content-types/{key}/enable",
9639
+ method: "POST",
9640
+ tags: ["site-{siteId}", "content-types", "content-type-{key}"],
9641
+ auth: "user",
9642
+ responseKind: "json"
9643
+ },
9644
+ setupContentType: {
9645
+ path: "/sites/{siteId}/content-types/{key}/setup",
9646
+ method: "POST",
9647
+ tags: ["site-{siteId}", "content-types", "content-type-{key}"],
9648
+ auth: "user",
9649
+ responseKind: "json"
9650
+ },
9651
+ deleteContentEntry: {
9652
+ path: "/sites/{siteId}/content/{type}/{entryId}",
9653
+ method: "DELETE",
9654
+ tags: ["site-{siteId}", "content-{siteId}-{type}", "content-entry-{entryId}"],
9655
+ auth: "user",
9656
+ responseKind: "json"
9657
+ },
9658
+ updateSiteGeneralSettings: {
9659
+ path: "/sites/{siteId}/settings/general",
9660
+ method: "POST",
9661
+ tags: ["site-{siteId}", "site-settings-{siteId}"],
9662
+ auth: "user",
9663
+ responseKind: "json"
9664
+ },
9665
+ getSiteLayoutSettings: {
9666
+ path: "/sites/{siteId}/settings/layout",
9667
+ method: "GET",
9668
+ revalidate: 120,
9669
+ tags: ["site-{siteId}", "site-settings-{siteId}"],
9670
+ auth: "user",
9671
+ responseKind: "json"
9672
+ },
9673
+ updateSiteLayoutSettings: {
9674
+ path: "/sites/{siteId}/settings/layout",
9675
+ method: "POST",
9676
+ tags: ["site-{siteId}", "site-settings-{siteId}"],
9677
+ auth: "user",
9678
+ responseKind: "json"
9679
+ },
9680
+ getMaintenanceSettings: {
9681
+ path: "/sites/{siteId}/settings/maintenance",
9682
+ method: "GET",
9683
+ revalidate: 120,
9684
+ tags: ["site-{siteId}", "site-settings-{siteId}"],
9685
+ auth: "user",
9686
+ responseKind: "json"
9687
+ },
9688
+ updateMaintenanceSettings: {
9689
+ path: "/sites/{siteId}/settings/maintenance",
9690
+ method: "POST",
9691
+ tags: ["site-{siteId}", "site-settings-{siteId}"],
9692
+ auth: "user",
9693
+ responseKind: "json"
9694
+ },
9695
+ setHomepage: {
9696
+ path: "/sites/{siteId}/settings/homepage",
9697
+ method: "POST",
9698
+ tags: ["site-{siteId}", "site-homepage"],
9699
+ auth: "user",
9700
+ responseKind: "json"
9701
+ },
9702
+ listAccountDomains: {
9703
+ path: "/domains",
9704
+ method: "GET",
9705
+ tags: ["domains"],
9706
+ auth: "user",
9707
+ responseKind: "json"
9708
+ },
9709
+ searchDomains: {
9710
+ path: "/domains/search",
9711
+ method: "POST",
9712
+ tags: ["domains"],
9713
+ auth: "user",
9714
+ responseKind: "json"
9715
+ },
9716
+ registerDomain: {
9717
+ path: "/domains/register",
9718
+ method: "POST",
9719
+ tags: ["domains"],
9720
+ auth: "user",
9721
+ responseKind: "json"
9722
+ },
9723
+ assignDomain: {
9724
+ path: "/domains/{domainId}/assign",
9725
+ method: "POST",
9726
+ tags: ["domains", "domain-{domainId}"],
9727
+ auth: "user",
9728
+ responseKind: "json"
9729
+ },
9730
+ adminStartImpersonation: {
9731
+ path: "/admin/impersonation/start",
9732
+ method: "POST",
9733
+ tags: ["admin", "impersonation"],
9734
+ auth: "user",
9735
+ responseKind: "json"
9736
+ },
9737
+ adminStopImpersonation: {
9738
+ path: "/admin/impersonation/stop",
9739
+ method: "POST",
9740
+ tags: ["admin", "impersonation"],
9741
+ auth: "user",
9742
+ responseKind: "json"
9743
+ },
9744
+ adminAssignRole: {
9745
+ path: "/admin/roles/assign",
9746
+ method: "POST",
9747
+ tags: ["admin", "roles"],
9748
+ auth: "user",
9749
+ responseKind: "json"
9750
+ },
9751
+ adminRevokeRole: {
9752
+ path: "/admin/roles/revoke",
9753
+ method: "POST",
9754
+ tags: ["admin", "roles"],
9755
+ auth: "user",
9756
+ responseKind: "json"
9757
+ },
9758
+ adminChangePlan: {
9759
+ path: "/admin/billing/plan",
9760
+ method: "POST",
9761
+ tags: ["admin", "billing"],
9762
+ auth: "user",
9763
+ responseKind: "json"
9764
+ },
9765
+ changePlan: {
9766
+ path: "/billing/plan/change",
9767
+ method: "POST",
9768
+ tags: ["billing"],
9769
+ auth: "user",
9770
+ responseKind: "json"
9771
+ },
9772
+ mfaTotpEnroll: {
9773
+ path: "/auth/mfa/totp/enroll",
9774
+ method: "POST",
9775
+ tags: ["mfa"],
9776
+ auth: "user",
9777
+ responseKind: "json"
9778
+ },
9779
+ mfaTotpVerify: {
9780
+ path: "/auth/mfa/totp/verify",
9781
+ method: "POST",
9782
+ tags: ["mfa"],
9783
+ auth: "user",
9784
+ responseKind: "json"
9785
+ },
9786
+ mfaTotpActivate: {
9787
+ path: "/auth/mfa/totp/activate",
9788
+ method: "POST",
9789
+ tags: ["mfa"],
9790
+ auth: "user",
9791
+ responseKind: "json"
9792
+ },
9793
+ mfaDeleteFactor: {
9794
+ path: "/auth/mfa/factors/{factorId}",
9795
+ method: "DELETE",
9796
+ tags: ["mfa"],
9797
+ auth: "user",
9798
+ responseKind: "json"
9799
+ },
9800
+ mfaBackupCodesGet: {
9801
+ path: "/auth/mfa/backup-codes",
9802
+ method: "GET",
9803
+ tags: ["mfa"],
9804
+ auth: "user",
9805
+ responseKind: "json"
9806
+ },
9807
+ mfaBackupCodesRotate: {
9808
+ path: "/auth/mfa/backup-codes/rotate",
9809
+ method: "POST",
9810
+ tags: ["mfa"],
9811
+ auth: "user",
9812
+ responseKind: "json"
9813
+ },
9814
+ mfaPhoneEnroll: {
9815
+ path: "/auth/mfa/phone/enroll",
9816
+ method: "POST",
9817
+ tags: ["mfa"],
9818
+ auth: "user",
9819
+ responseKind: "json"
9820
+ },
9821
+ mfaPhoneChallenge: {
9822
+ path: "/auth/mfa/phone/challenge",
9823
+ method: "POST",
9824
+ tags: ["mfa"],
9825
+ auth: "user",
9826
+ responseKind: "json"
9827
+ },
9828
+ mfaPhoneVerify: {
9829
+ path: "/auth/mfa/phone/verify",
9830
+ method: "POST",
9831
+ tags: ["mfa"],
9832
+ auth: "user",
9833
+ responseKind: "json"
9834
+ },
9835
+ accountUpdatePassword: {
9836
+ path: "/account/password/update",
9837
+ method: "POST",
9838
+ tags: ["account"],
9839
+ auth: "user",
9840
+ responseKind: "json"
9841
+ },
9842
+ accountRevokeSessions: {
9843
+ path: "/account/sessions/revoke",
9844
+ method: "POST",
9845
+ tags: ["account"],
9846
+ auth: "user",
9847
+ responseKind: "json"
9848
+ },
9849
+ adminListInvites: {
9850
+ path: "/admin/invites",
9851
+ method: "GET",
9852
+ tags: ["admin", "invites"],
9853
+ auth: "user",
9854
+ responseKind: "json"
9855
+ },
9856
+ adminCreateInvite: {
9857
+ path: "/admin/invites",
9858
+ method: "POST",
9859
+ tags: ["admin", "invites"],
9860
+ auth: "user",
9861
+ responseKind: "json"
9862
+ },
9863
+ adminRevokeInvite: {
9864
+ path: "/admin/invites/{inviteId}",
9865
+ method: "DELETE",
9866
+ tags: ["admin", "invites"],
9867
+ auth: "user",
9868
+ responseKind: "json"
9869
+ },
9870
+ adminCreateUser: {
9871
+ path: "/admin/users",
9872
+ method: "POST",
9873
+ tags: ["admin", "users"],
9874
+ auth: "admin",
9875
+ responseKind: "json"
9876
+ },
9877
+ adminListAllowedDomains: {
9878
+ path: "/admin/allowed-domains",
9879
+ method: "GET",
9880
+ tags: ["admin", "allowed-domains"],
9881
+ auth: "user",
9882
+ responseKind: "json"
9883
+ },
9884
+ adminAddAllowedDomain: {
9885
+ path: "/admin/allowed-domains",
9886
+ method: "POST",
9887
+ tags: ["admin", "allowed-domains"],
9888
+ auth: "user",
9889
+ responseKind: "json"
9890
+ },
9891
+ adminDeleteAllowedDomain: {
9892
+ path: "/admin/allowed-domains/{domainId}",
9893
+ method: "DELETE",
9894
+ tags: ["admin", "allowed-domains"],
9895
+ auth: "user",
9896
+ responseKind: "json"
9897
+ },
9898
+ authAcceptInvite: {
9899
+ path: "/auth/invite/accept",
9900
+ method: "POST",
9901
+ tags: ["auth", "invite"],
9902
+ auth: "user",
9903
+ responseKind: "json"
9904
+ },
9905
+ acceptSiteInvitation: {
9906
+ path: "/sites/invitations/accept",
9907
+ method: "POST",
9908
+ tags: ["site-invitations"],
9909
+ auth: "user",
9910
+ responseKind: "json"
9911
+ },
9912
+ getNavigationMenus: {
9913
+ path: "/sites/{siteId}/navigation/menus",
9914
+ method: "GET",
9915
+ tags: ["site-{siteId}", "navigation"],
9916
+ auth: "user",
9917
+ responseKind: "json"
9918
+ },
9919
+ createNavigationMenu: {
9920
+ path: "/sites/{siteId}/navigation/menus",
9921
+ method: "POST",
9922
+ tags: ["site-{siteId}", "navigation"],
9923
+ auth: "user",
9924
+ responseKind: "json"
9925
+ },
9926
+ updateNavigationMenu: {
9927
+ path: "/sites/{siteId}/navigation/menus/{menuId}",
9928
+ method: "PATCH",
9929
+ tags: ["site-{siteId}", "navigation", "navigation-menu-{menuId}"],
9930
+ auth: "user",
9931
+ responseKind: "json"
9932
+ },
9933
+ deleteNavigationMenu: {
9934
+ path: "/sites/{siteId}/navigation/menus/{menuId}",
9935
+ method: "DELETE",
9936
+ tags: ["site-{siteId}", "navigation", "navigation-menu-{menuId}"],
9937
+ auth: "user",
9938
+ responseKind: "json"
9939
+ },
9940
+ createNavigationItem: {
9941
+ path: "/sites/{siteId}/navigation/menus/{menuId}/items",
9942
+ method: "POST",
9943
+ tags: ["site-{siteId}", "navigation", "navigation-menu-{menuId}"],
9944
+ auth: "user",
9945
+ responseKind: "json"
9946
+ },
9947
+ updateNavigationItem: {
9948
+ path: "/sites/{siteId}/navigation/menus/{menuId}/items/{itemId}",
9949
+ method: "PATCH",
9950
+ tags: ["site-{siteId}", "navigation", "navigation-menu-{menuId}", "navigation-item-{itemId}"],
9951
+ auth: "user",
9952
+ responseKind: "json"
9953
+ },
9954
+ deleteNavigationItem: {
9955
+ path: "/sites/{siteId}/navigation/menus/{menuId}/items/{itemId}",
9956
+ method: "DELETE",
9957
+ tags: ["site-{siteId}", "navigation", "navigation-menu-{menuId}", "navigation-item-{itemId}"],
9958
+ auth: "user",
9959
+ responseKind: "json"
9960
+ },
9961
+ reorderNavigationItems: {
9962
+ path: "/sites/{siteId}/navigation/menus/{menuId}/items/reorder",
9963
+ method: "POST",
9964
+ tags: ["site-{siteId}", "navigation", "navigation-menu-{menuId}"],
9965
+ auth: "user",
9966
+ responseKind: "json"
9967
+ },
9968
+ getRoutableContent: {
9969
+ path: "/sites/{siteId}/routable-content",
9970
+ method: "GET",
9971
+ revalidate: 60,
9972
+ tags: ["site-{siteId}", "routable-content-{siteId}"],
9973
+ auth: "user",
9974
+ responseKind: "json"
9975
+ },
9976
+ // Public routable content for SDK SSG
9977
+ getPublicRoutableContent: {
9978
+ path: "/public/sites/{siteId}/routable-content",
9979
+ method: "GET",
9980
+ revalidate: 60,
9981
+ tags: ["site-{siteId}", "routable-content-{siteId}"],
9982
+ auth: "public",
9983
+ responseKind: "json"
9984
+ },
9985
+ // Generic public content preview (preferred)
9986
+ getPublishedEntryPreview: {
9987
+ path: "/public/content/{siteId}/{type}/{slug}/preview",
9988
+ method: "GET",
9989
+ revalidate: 60,
9990
+ tags: ["content-{siteId}-{type}-{slug}"],
9991
+ auth: "public",
9992
+ responseKind: "json"
9993
+ },
9994
+ listPublishedEntries: {
9995
+ path: "/public/content/{siteId}/{type}/entries",
9996
+ method: "GET",
9997
+ revalidate: 60,
9998
+ tags: ["content-{siteId}-{type}"],
9999
+ auth: "public",
10000
+ responseKind: "json"
10001
+ },
10002
+ getPublishedPostPreview: {
10003
+ path: "/public/posts/{siteId}/{slug}/preview",
10004
+ method: "GET",
10005
+ revalidate: 60,
10006
+ tags: ["blog-post:{siteId}:{slug}"],
10007
+ auth: "public",
10008
+ responseKind: "json"
10009
+ },
10010
+ proposalsSelect: {
10011
+ path: "/proposals/select",
10012
+ method: "POST",
10013
+ tags: ["proposal", "site"],
10014
+ auth: "user",
10015
+ responseKind: "json"
10016
+ },
10017
+ createTheme: {
10018
+ path: "/ai/chat/create-theme",
10019
+ method: "POST",
10020
+ revalidate: 60,
10021
+ // 1 minute cache for theme creation to avoid duplicate requests
10022
+ tags: ["theme", "ai-theme"],
10023
+ auth: "user",
10024
+ responseKind: "json"
10025
+ },
10026
+ generateThemes: {
10027
+ path: "/theme/generate",
10028
+ method: "POST",
10029
+ tags: ["theme"],
10030
+ auth: "user",
10031
+ responseKind: "json"
10032
+ },
10033
+ extractThemeFromInspiration: {
10034
+ path: "/theme/extract-from-inspiration",
10035
+ method: "POST",
10036
+ tags: ["theme", "preferences"],
10037
+ auth: "user",
10038
+ responseKind: "json"
10039
+ },
10040
+ saveSiteTheme: {
10041
+ path: "/sites/{siteId}/theme/save",
10042
+ method: "POST",
10043
+ tags: ["site-{siteId}", "theme"],
10044
+ auth: "user",
10045
+ responseKind: "json"
10046
+ },
10047
+ uploadSiteLogo: {
10048
+ path: "/storage/upload-site-logo",
10049
+ method: "POST",
10050
+ tags: ["site", "logo"],
10051
+ auth: "user",
10052
+ responseKind: "json"
10053
+ },
10054
+ upsertThemePreferences: {
10055
+ path: "/theme-preferences/upsert",
10056
+ method: "POST",
10057
+ tags: ["theme", "preferences"],
10058
+ auth: "user",
10059
+ responseKind: "json"
10060
+ },
10061
+ finalizeSite: {
10062
+ path: "/sites/finalize",
10063
+ method: "POST",
10064
+ tags: ["site"],
10065
+ auth: "user",
10066
+ responseKind: "json"
10067
+ },
10068
+ instagramUploadZip: {
10069
+ path: "/api/instagram/upload-zip",
10070
+ method: "POST",
10071
+ tags: ["instagram-import"],
10072
+ auth: "user",
10073
+ responseKind: "json"
10074
+ },
10075
+ getAnalyticsReport: {
10076
+ path: "/sites/{siteId}/analytics/report",
10077
+ method: "GET",
10078
+ revalidate: 300,
10079
+ tags: ["site-{siteId}", "analytics-{siteId}"],
10080
+ auth: "user",
10081
+ responseKind: "json"
10082
+ },
10083
+ getSeoOverview: {
10084
+ path: "/sites/{siteId}/seo/overview",
10085
+ method: "GET",
10086
+ revalidate: 300,
10087
+ tags: ["site-{siteId}", "seo-overview-{siteId}"],
10088
+ auth: "user",
10089
+ responseKind: "json"
10090
+ },
10091
+ getSeoPages: {
10092
+ path: "/sites/{siteId}/seo/pages",
10093
+ method: "GET",
10094
+ revalidate: 300,
10095
+ tags: ["site-{siteId}", "seo-pages-{siteId}"],
10096
+ auth: "user",
10097
+ responseKind: "json"
10098
+ },
10099
+ getSeoQueries: {
10100
+ path: "/sites/{siteId}/seo/queries",
10101
+ method: "GET",
10102
+ revalidate: 300,
10103
+ tags: ["site-{siteId}", "seo-queries-{siteId}"],
10104
+ auth: "user",
10105
+ responseKind: "json"
10106
+ },
10107
+ getPerformanceOverview: {
10108
+ path: "/sites/{siteId}/performance/overview",
10109
+ method: "GET",
10110
+ revalidate: 300,
10111
+ tags: ["site-{siteId}", "performance-overview-{siteId}"],
10112
+ auth: "user",
10113
+ responseKind: "json"
10114
+ },
10115
+ createMediaAsset: {
10116
+ path: "/media",
10117
+ method: "POST",
10118
+ tags: ["media"],
10119
+ auth: "user",
10120
+ responseKind: "json"
10121
+ },
10122
+ mediaList: {
10123
+ path: "/media",
10124
+ method: "GET",
10125
+ tags: ["media"],
10126
+ auth: "user",
10127
+ responseKind: "json"
10128
+ },
10129
+ mediaGet: {
10130
+ path: "/media/{assetId}",
10131
+ method: "GET",
10132
+ tags: ["media", "media-{assetId}"],
10133
+ auth: "user",
10134
+ responseKind: "json"
10135
+ },
10136
+ mediaUpdate: {
10137
+ path: "/media/{assetId}",
10138
+ method: "PATCH",
10139
+ tags: ["media", "media-{assetId}"],
10140
+ auth: "user",
10141
+ responseKind: "json"
10142
+ },
10143
+ mediaDelete: {
10144
+ path: "/media/{assetId}",
10145
+ method: "DELETE",
10146
+ tags: ["media", "media-{assetId}"],
10147
+ auth: "user",
10148
+ responseKind: "void"
10149
+ },
10150
+ mediaBulkDelete: {
10151
+ path: "/media/bulk-delete",
10152
+ method: "POST",
10153
+ tags: ["media"],
10154
+ auth: "user",
10155
+ responseKind: "json"
10156
+ },
10157
+ mediaGetSignedUrl: {
10158
+ path: "/media/{assetId}/signed-url",
10159
+ method: "GET",
10160
+ tags: ["media", "media-{assetId}"],
10161
+ auth: "user",
10162
+ responseKind: "json"
10163
+ },
10164
+ mediaUpload: {
10165
+ path: "/media/upload",
10166
+ method: "POST",
10167
+ tags: ["media"],
10168
+ auth: "user",
10169
+ responseKind: "json"
10170
+ },
10171
+ getMediaLabels: {
10172
+ path: "/media/labels",
10173
+ method: "GET",
10174
+ tags: ["media", "media-labels"],
10175
+ auth: "user",
10176
+ responseKind: "json"
10177
+ },
10178
+ getMediaSettings: {
10179
+ path: "/media/settings",
10180
+ method: "GET",
10181
+ tags: ["media-settings"],
10182
+ auth: "user",
10183
+ responseKind: "json"
10184
+ },
10185
+ updateMediaSettings: {
10186
+ path: "/media/settings",
10187
+ method: "POST",
10188
+ tags: ["media-settings"],
10189
+ auth: "user",
10190
+ responseKind: "json"
10191
+ },
10192
+ // Media endpoints
10193
+ mediaSearch: {
10194
+ path: "/media/search",
10195
+ method: "POST",
10196
+ tags: ["media-search"],
10197
+ auth: "user",
10198
+ responseKind: "json"
10199
+ },
10200
+ classifyMediaAsset: {
10201
+ path: "/media/{assetId}/classify",
10202
+ method: "POST",
10203
+ tags: ["media", "media-{assetId}"],
10204
+ auth: "user",
10205
+ responseKind: "json"
10206
+ },
10207
+ classifyMediaBatch: {
10208
+ path: "/media/classify",
10209
+ method: "POST",
10210
+ tags: ["media"],
10211
+ auth: "user",
10212
+ responseKind: "json"
10213
+ },
10214
+ mediaJobsStatus: {
10215
+ path: "/media/jobs/status",
10216
+ method: "GET",
10217
+ tags: ["media"],
10218
+ auth: "user",
10219
+ responseKind: "json"
10220
+ },
10221
+ enqueueMediaClassifyJob: {
10222
+ path: "/media/jobs",
10223
+ method: "POST",
10224
+ tags: ["media"],
10225
+ auth: "user",
10226
+ responseKind: "json"
10227
+ },
10228
+ runMediaClassifyJob: {
10229
+ path: "/media/jobs/run",
10230
+ method: "POST",
10231
+ tags: ["media"],
10232
+ auth: "user",
10233
+ responseKind: "json"
10234
+ },
10235
+ runAllMediaClassifyJobs: {
10236
+ path: "/media/jobs/run-all",
10237
+ method: "POST",
10238
+ tags: ["media"],
10239
+ auth: "user",
10240
+ responseKind: "json"
10241
+ },
10242
+ initSiteContent: {
10243
+ path: "/sites/{siteId}/content/init",
10244
+ method: "POST",
10245
+ tags: ["site", "content"],
10246
+ auth: "user",
10247
+ responseKind: "json"
10248
+ },
10249
+ updateBlockContent: {
10250
+ path: "/blocks/{blockId}/content",
10251
+ method: "POST",
10252
+ tags: ["block", "block-{blockId}", "content"],
10253
+ auth: "user",
10254
+ responseKind: "json"
10255
+ },
10256
+ saveBlockContent: {
10257
+ path: "/blocks/{blockId}/content",
10258
+ method: "POST",
10259
+ tags: ["block", "block-{blockId}", "content"],
10260
+ auth: "user",
10261
+ responseKind: "json"
10262
+ },
10263
+ createBlock: {
10264
+ path: "/sites/{siteId}/pages/{pageId}/blocks",
10265
+ method: "POST",
10266
+ tags: ["site-{siteId}", "page-{pageId}", "blocks"],
10267
+ auth: "user",
10268
+ responseKind: "json"
10269
+ },
10270
+ reorderBlocks: {
10271
+ path: "/sites/{siteId}/pages/{pageId}/blocks/reorder",
10272
+ method: "POST",
10273
+ tags: ["site-{siteId}", "page-{pageId}", "blocks"],
10274
+ auth: "user",
10275
+ responseKind: "json"
10276
+ },
10277
+ deleteBlock: {
10278
+ path: "/sites/{siteId}/pages/{pageId}/blocks/{blockId}",
10279
+ method: "DELETE",
10280
+ tags: ["site-{siteId}", "page-{pageId}", "blocks"],
10281
+ auth: "user",
10282
+ responseKind: "json"
10283
+ },
10284
+ listBlocks: {
10285
+ path: "/sites/{siteId}/pages/{pageId}/blocks",
10286
+ method: "GET",
10287
+ tags: ["site-{siteId}", "page-{pageId}", "blocks"],
10288
+ auth: "user",
10289
+ responseKind: "json"
10290
+ },
10291
+ getBlockContent: {
10292
+ path: "/blocks/{blockId}/content",
10293
+ method: "GET",
10294
+ tags: ["block-{blockId}", "content"],
10295
+ auth: "user",
10296
+ responseKind: "json"
10297
+ },
10298
+ // DEPRECATED: Use getSite with ?id={id} instead
10299
+ getSiteById: {
10300
+ path: "/sites/by-id/{id}",
10301
+ method: "GET",
10302
+ revalidate: 900,
10303
+ // 15 minutes
10304
+ tags: ["site-{id}"],
10305
+ auth: "user",
10306
+ responseKind: "json"
10307
+ },
10308
+ // Page data endpoints
10309
+ getPageById: {
10310
+ path: "/sites/{siteId}/pages/{pageId}",
10311
+ method: "GET",
10312
+ revalidate: 900,
10313
+ // 15 minutes
10314
+ tags: ["site-{siteId}", "page-{pageId}"],
10315
+ auth: "user",
10316
+ responseKind: "json"
10317
+ },
10318
+ getContentByPath: {
10319
+ path: "/sites/{siteId}/pages",
10320
+ method: "GET",
10321
+ tags: ["site-{siteId}", "routable-content-{siteId}"],
10322
+ auth: "public",
10323
+ responseKind: "json"
10324
+ },
10325
+ getPageByPath: {
10326
+ path: "/sites/{siteId}/pages",
10327
+ method: "GET",
10328
+ tags: ["site-{siteId}"],
10329
+ auth: "user",
10330
+ responseKind: "json"
10331
+ },
10332
+ // Forms CRUD
10333
+ listForms: {
10334
+ path: "/sites/{siteId}/forms",
10335
+ method: "GET",
10336
+ tags: ["site-{siteId}", "forms"],
10337
+ auth: "user",
10338
+ responseKind: "json"
10339
+ },
10340
+ listBookingForms: {
10341
+ path: "/sites/{siteId}/bookings/forms",
10342
+ method: "GET",
10343
+ tags: ["site-{siteId}", "forms"],
10344
+ auth: "user",
10345
+ responseKind: "json"
10346
+ },
10347
+ createForm: {
10348
+ path: "/sites/{siteId}/forms",
10349
+ method: "POST",
10350
+ tags: ["site-{siteId}", "forms"],
10351
+ auth: "user",
10352
+ responseKind: "json"
10353
+ },
10354
+ updateForm: {
10355
+ path: "/sites/{siteId}/forms/{slug}",
10356
+ method: "PATCH",
10357
+ tags: ["site-{siteId}", "forms", "form-{slug}"],
10358
+ auth: "user",
10359
+ responseKind: "json"
10360
+ },
10361
+ deleteForm: {
10362
+ path: "/sites/{siteId}/forms/{slug}",
10363
+ method: "DELETE",
10364
+ tags: ["site-{siteId}", "forms", "form-{slug}"],
10365
+ auth: "user",
10366
+ responseKind: "json"
10367
+ },
10368
+ listFormSubmissions: {
10369
+ path: "/sites/{siteId}/forms/{slug}/submissions",
10370
+ method: "GET",
10371
+ revalidate: 30,
10372
+ tags: ["site-{siteId}", "form-{slug}", "form-submissions-{slug}"],
10373
+ auth: "user",
10374
+ responseKind: "json"
10375
+ },
10376
+ // Public submit
10377
+ submitForm: {
10378
+ path: "/forms/submit",
10379
+ method: "POST",
10380
+ tags: ["forms-submit"],
10381
+ auth: "public",
10382
+ responseKind: "json"
10383
+ },
10384
+ // Public forms
10385
+ getPublicFormById: {
10386
+ path: "/public/forms/{formId}",
10387
+ method: "GET",
10388
+ revalidate: 60,
10389
+ tags: ["form-{formId}"],
10390
+ auth: "public",
10391
+ responseKind: "json"
10392
+ },
10393
+ // Public booking services
10394
+ getPublicBookingServices: {
10395
+ path: "/public/bookings/services",
10396
+ method: "GET",
10397
+ revalidate: 60,
10398
+ tags: ["site-{siteId}"],
10399
+ auth: "public",
10400
+ responseKind: "json"
10401
+ },
10402
+ devToolsImpersonateAdmin: {
10403
+ path: "/dev-tools/impersonate/admin",
10404
+ method: "POST",
10405
+ auth: "admin",
10406
+ responseKind: "json"
10407
+ },
10408
+ devToolsImpersonateRandom: {
10409
+ path: "/dev-tools/impersonate/random",
10410
+ method: "POST",
10411
+ auth: "admin",
10412
+ responseKind: "json"
10413
+ },
10414
+ devToolsSeedDemoData: {
10415
+ path: "/dev-tools/seed",
10416
+ method: "POST",
10417
+ auth: "admin",
10418
+ responseKind: "json"
10419
+ },
10420
+ // Public analytics collection endpoint
10421
+ analyticsCollect: {
10422
+ path: "/api/analytics/collect",
10423
+ method: "POST",
10424
+ auth: "public",
10425
+ responseKind: "json"
10426
+ },
10427
+ // Public events for event calendar block
10428
+ listPublicEvents: {
10429
+ path: "/public/sites/{siteId}/events",
10430
+ method: "GET",
10431
+ revalidate: 60,
10432
+ tags: ["public-events-{siteId}"],
10433
+ auth: "public",
10434
+ responseKind: "json"
10435
+ },
10436
+ // Resolve event occurrence by URL segment (date or UUID)
10437
+ resolveEventOccurrence: {
10438
+ path: "/public/sites/{siteId}/events/occurrences/resolve",
10439
+ method: "GET",
10440
+ revalidate: 60,
10441
+ tags: ["public-events-{siteId}", "event-occurrence"],
10442
+ auth: "public",
10443
+ responseKind: "json"
10444
+ },
10445
+ // Public event registration
10446
+ registerForEvent: {
10447
+ path: "/public/sites/{siteId}/events/register",
10448
+ method: "POST",
10449
+ tags: ["public-events-{siteId}", "event-registration"],
10450
+ auth: "public",
10451
+ responseKind: "json"
10452
+ },
10453
+ // Content Types CRUD
10454
+ listSiteContentTypes: {
10455
+ path: "/sites/{siteId}/content-types",
10456
+ method: "GET",
10457
+ revalidate: 60,
10458
+ tags: ["site-{siteId}", "content-types-{siteId}"],
10459
+ auth: "user",
10460
+ responseKind: "json"
10461
+ },
10462
+ getContentType: {
10463
+ path: "/sites/{siteId}/content-types/by-id/{typeId}",
10464
+ method: "GET",
10465
+ revalidate: 60,
10466
+ tags: ["site-{siteId}", "content-type-{typeId}"],
10467
+ auth: "user",
10468
+ responseKind: "json"
10469
+ },
10470
+ createContentType: {
10471
+ path: "/sites/{siteId}/content-types",
10472
+ method: "POST",
10473
+ tags: ["site-{siteId}", "content-types-{siteId}"],
10474
+ auth: "user",
10475
+ responseKind: "json"
10476
+ },
10477
+ updateContentType: {
10478
+ path: "/sites/{siteId}/content-types/by-id/{typeId}",
10479
+ method: "PATCH",
10480
+ tags: ["site-{siteId}", "content-type-{typeId}", "content-types-{siteId}"],
10481
+ auth: "user",
10482
+ responseKind: "json"
10483
+ },
10484
+ deleteContentType: {
10485
+ path: "/sites/{siteId}/content-types/by-id/{typeId}",
10486
+ method: "DELETE",
10487
+ tags: ["site-{siteId}", "content-type-{typeId}", "content-types-{sideId}"],
10488
+ auth: "user",
10489
+ responseKind: "json"
10490
+ },
10491
+ duplicateContentType: {
10492
+ path: "/sites/{siteId}/content-types/by-id/{typeId}/duplicate",
10493
+ method: "POST",
10494
+ tags: ["site-{siteId}", "content-type-{typeId}", "content-types-{siteId}"],
10495
+ auth: "user",
10496
+ responseKind: "json"
10497
+ },
10498
+ // Admin site creation
10499
+ adminCreateSite: {
10500
+ path: "/admin/sites",
10501
+ method: "POST",
10502
+ tags: ["admin", "sites"],
10503
+ auth: "admin",
10504
+ responseKind: "json"
10505
+ },
10506
+ // SDK Config
10507
+ refreshSdkConfig: {
10508
+ path: "/sites/{siteId}/refresh-sdk-config",
10509
+ method: "POST",
10510
+ tags: ["site-{siteId}", "sdk-config"],
10511
+ auth: "user",
10512
+ responseKind: "json"
10513
+ },
10514
+ // Stripe Connect - Site billing
10515
+ stripeConnectAuthorize: {
10516
+ path: "/sites/{siteId}/billing/connect/authorize",
10517
+ method: "POST",
10518
+ tags: ["site-{siteId}", "stripe-connect"],
10519
+ auth: "user",
10520
+ responseKind: "json"
10521
+ },
10522
+ stripeConnectStatus: {
10523
+ path: "/sites/{siteId}/billing/connect/status",
10524
+ method: "GET",
10525
+ tags: ["site-{siteId}", "stripe-connect"],
10526
+ auth: "user",
10527
+ responseKind: "json"
10528
+ },
10529
+ stripeConnectDisconnect: {
10530
+ path: "/sites/{siteId}/billing/connect/disconnect",
10531
+ method: "DELETE",
10532
+ tags: ["site-{siteId}", "stripe-connect"],
10533
+ auth: "user",
10534
+ responseKind: "json"
10535
+ },
10536
+ // Backup
10537
+ importSiteBackup: {
10538
+ path: "/sites/{siteId}/backup/import",
10539
+ method: "POST",
10540
+ tags: ["site-{siteId}", "backup"],
10541
+ auth: "user",
10542
+ responseKind: "json"
10543
+ },
10544
+ previewBackup: {
10545
+ path: "/backup/preview",
10546
+ method: "POST",
10547
+ tags: ["backup"],
10548
+ auth: "user",
10549
+ responseKind: "json"
10550
+ },
10551
+ importBackupAsNewSite: {
10552
+ path: "/sites/backup/import-as-new",
10553
+ method: "POST",
10554
+ tags: ["site", "backup"],
10555
+ auth: "user",
10556
+ responseKind: "json"
10557
+ },
10558
+ // Admin billing price overrides
10559
+ adminGetPriceOverride: {
10560
+ path: "/admin/billing/price-override",
10561
+ method: "GET",
10562
+ tags: ["admin", "billing", "price-override"],
10563
+ auth: "admin",
10564
+ responseKind: "json"
10565
+ },
10566
+ adminUpsertPriceOverride: {
10567
+ path: "/admin/billing/price-override",
10568
+ method: "POST",
10569
+ tags: ["admin", "billing", "price-override"],
10570
+ auth: "admin",
10571
+ responseKind: "json"
10572
+ },
10573
+ adminDeletePriceOverride: {
10574
+ path: "/admin/billing/price-override",
10575
+ method: "DELETE",
10576
+ tags: ["admin", "billing", "price-override"],
10577
+ auth: "admin",
10578
+ responseKind: "json"
10579
+ }
10580
+ };
10581
+ var API_ENDPOINTS = ENDPOINT_DEFINITIONS;
10582
+
10583
+ // ../api/src/url.ts
10584
+ function getCmsApiUrl() {
10585
+ if (typeof window !== "undefined") {
10586
+ return "/api";
10587
+ }
10588
+ const internalUrl = process.env.CMS_API_URL;
10589
+ if (internalUrl) {
10590
+ return internalUrl.replace(/\/$/, "");
10591
+ }
10592
+ const dashboardUrl = process.env.NEXT_PUBLIC_DASHBOARD_URL;
10593
+ if (dashboardUrl) {
10594
+ const base = dashboardUrl.replace(/\/$/, "");
10595
+ return `${base}/api`;
10596
+ }
10597
+ const legacyApiUrl = process.env.NEXT_PUBLIC_CMS_API_URL;
10598
+ if (legacyApiUrl) {
10599
+ return legacyApiUrl.replace(/\/$/, "");
10600
+ }
10601
+ throw new Error(
10602
+ "NEXT_PUBLIC_DASHBOARD_URL is not configured. Set it to your dashboard URL (e.g., http://dashboard.local:4000)"
10603
+ );
10604
+ }
10605
+ function resolveApiBaseUrl() {
10606
+ return getCmsApiUrl();
10607
+ }
10608
+
10609
+ // ../api/src/request.ts
10610
+ var revalidateTag = null;
10611
+ if (typeof window === "undefined") {
10612
+ try {
10613
+ const dynamicRequire = new Function("modulePath", "return require(modulePath)");
10614
+ const nextCache = dynamicRequire("next/cache");
10615
+ revalidateTag = nextCache.revalidateTag ?? null;
10616
+ } catch {
10617
+ }
10618
+ }
10619
+ var sdkVersion;
10620
+ function generateRequestId() {
10621
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
10622
+ return crypto.randomUUID();
10623
+ }
10624
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
10625
+ const r = Math.random() * 16 | 0;
10626
+ const v = c === "x" ? r : r & 3 | 8;
10627
+ return v.toString(16);
10628
+ });
10629
+ }
10630
+ function setSdkVersion(version) {
10631
+ sdkVersion = version;
10632
+ }
10633
+ var ApiRequestError = class extends Error {
10634
+ constructor(message, options) {
10635
+ super(message);
10636
+ this.name = "ApiRequestError";
10637
+ this.endpoint = options.endpoint;
10638
+ this.status = options.status;
10639
+ this.method = options.method;
10640
+ this.auth = options.auth;
10641
+ this.requestId = options.requestId;
10642
+ this.body = options.body;
10643
+ this.cause = options.cause;
10644
+ this.errorCode = options.errorCode;
10645
+ this.retryAfterMs = options.retryAfterMs;
10646
+ }
10647
+ };
10648
+ function parseRetryAfterHeader(headerValue) {
10649
+ if (!headerValue) return void 0;
10650
+ if (/^\d+$/.test(headerValue)) {
10651
+ const seconds = parseInt(headerValue, 10);
10652
+ return seconds * 1e3;
10653
+ }
10654
+ const date = new Date(headerValue);
10655
+ if (!isNaN(date.getTime())) {
10656
+ const delayMs = date.getTime() - Date.now();
10657
+ return delayMs > 0 ? delayMs : void 0;
10658
+ }
10659
+ return void 0;
10660
+ }
10661
+ function buildEndpointURL(baseURL, endpoint) {
10662
+ return baseURL + API_ENDPOINTS[endpoint].path;
10663
+ }
10664
+ function invalidateCacheTags(tags, params) {
10665
+ if (typeof window !== "undefined" || !revalidateTag || !tags) return;
10666
+ tags.forEach((tag) => {
10667
+ let processedTag = tag;
10668
+ if (params) {
10669
+ Object.entries(params).forEach(([key, value]) => {
10670
+ processedTag = processedTag.replace(`{${key}}`, String(value));
10671
+ });
10672
+ }
10673
+ try {
10674
+ revalidateTag(processedTag, "max");
10675
+ } catch {
10676
+ }
10677
+ });
10678
+ }
10679
+ async function parseErrorBody(response) {
10680
+ const clone = response.clone();
10681
+ const contentType = clone.headers.get("content-type") ?? "";
10682
+ if (contentType.includes("application/json")) {
10683
+ try {
10684
+ return await clone.json();
10685
+ } catch {
10686
+ }
10687
+ }
10688
+ try {
10689
+ const text2 = await clone.text();
10690
+ return text2.length ? text2 : null;
10691
+ } catch {
10692
+ return null;
10693
+ }
10694
+ }
10695
+ function buildSuccessEnvelope(data, requestId) {
10696
+ return {
10697
+ success: true,
10698
+ data,
10699
+ meta: {
10700
+ requestId: requestId ?? generateRequestId(),
10701
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10702
+ apiVersion: "2025-01-01"
10703
+ }
10704
+ };
10705
+ }
10706
+ function buildErrorEnvelope(code, message, status, requestId) {
10707
+ return {
10708
+ success: false,
10709
+ error: {
10710
+ code,
10711
+ message,
10712
+ requestId: requestId ?? generateRequestId(),
10713
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10714
+ status
10715
+ }
10716
+ };
10717
+ }
10718
+ async function parseSuccessResponse(endpoint, response, config3) {
10719
+ const responseKind = config3.responseKind ?? "json";
10720
+ const auth = config3.auth ?? "user";
10721
+ const requestId = response.headers.get("x-request-id") ?? void 0;
10722
+ switch (responseKind) {
10723
+ case "json": {
10724
+ if (response.status === 204 || response.status === 205 || response.status === 304) {
10725
+ return buildSuccessEnvelope(void 0, requestId);
10726
+ }
10727
+ const raw = await response.text();
10728
+ if (!raw.trim()) {
10729
+ return buildSuccessEnvelope(void 0, requestId);
10730
+ }
10731
+ let parsed;
10732
+ try {
10733
+ parsed = JSON.parse(raw);
10734
+ } catch (cause) {
10735
+ throw new ApiRequestError(
10736
+ `Failed to parse JSON response for endpoint ${String(endpoint)}`,
10737
+ {
10738
+ endpoint,
10739
+ status: response.status,
10740
+ method: config3.method,
10741
+ auth,
10742
+ requestId,
10743
+ body: raw,
10744
+ cause
10745
+ }
10746
+ );
10747
+ }
10748
+ if (parsed && typeof parsed === "object" && "success" in parsed && typeof parsed.success === "boolean") {
10749
+ return parsed;
10750
+ }
10751
+ return buildSuccessEnvelope(parsed, requestId);
10752
+ }
10753
+ case "text": {
10754
+ const text2 = await response.text();
10755
+ return buildSuccessEnvelope(text2, requestId);
10756
+ }
10757
+ case "stream": {
10758
+ const body = response.body;
10759
+ if (!body) {
10760
+ return buildErrorEnvelope(
10761
+ "server:internal_error",
10762
+ `Expected a streamed body for endpoint ${String(endpoint)}`,
10763
+ response.status,
10764
+ requestId
10765
+ );
10766
+ }
10767
+ const stream = body;
10768
+ return buildSuccessEnvelope(stream, requestId);
10769
+ }
10770
+ case "void": {
10771
+ return buildSuccessEnvelope(void 0, requestId);
10772
+ }
10773
+ default: {
10774
+ return buildSuccessEnvelope(void 0, requestId);
10775
+ }
10776
+ }
10777
+ }
10778
+ function createRawCMSClient(headers = {}, baseUrl) {
10779
+ return ({
10780
+ endpoint,
10781
+ body,
10782
+ params,
10783
+ options = {}
10784
+ }) => {
10785
+ const resolvedBaseUrl = baseUrl ?? resolveApiBaseUrl();
10786
+ let url = buildEndpointURL(resolvedBaseUrl, endpoint);
10787
+ const originalPath = API_ENDPOINTS[endpoint].path;
10788
+ const unusedParams = {};
10789
+ if (params) {
10790
+ Object.entries(params).forEach(([key, value]) => {
10791
+ const placeholder = `{${key}}`;
10792
+ if (originalPath.includes(placeholder)) {
10793
+ url = url.replace(placeholder, value);
10794
+ } else {
10795
+ unusedParams[key] = value;
10796
+ }
10797
+ });
10798
+ }
10799
+ const endpointConfig = API_ENDPOINTS[endpoint];
10800
+ const method = endpointConfig.method;
10801
+ const isGetOrHead = method === "GET" || method === "HEAD";
10802
+ if (isGetOrHead) {
10803
+ const queryParams = new URLSearchParams();
10804
+ Object.entries(unusedParams).forEach(([key, value]) => {
10805
+ if (value !== void 0 && value !== null) {
10806
+ queryParams.append(key, String(value));
10807
+ }
10808
+ });
10809
+ if (body) {
10810
+ Object.entries(body).forEach(([key, value]) => {
10811
+ if (value !== void 0 && value !== null) {
10812
+ queryParams.append(key, String(value));
10813
+ }
10814
+ });
10815
+ }
10816
+ const queryString = queryParams.toString();
10817
+ if (queryString) {
10818
+ url += (url.includes("?") ? "&" : "?") + queryString;
10819
+ }
10820
+ }
10821
+ const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
10822
+ const nextOptions = {};
10823
+ if (isGetOrHead && "revalidate" in endpointConfig && typeof endpointConfig.revalidate === "number") {
10824
+ nextOptions.revalidate = endpointConfig.revalidate;
10825
+ }
10826
+ if ("tags" in endpointConfig && Array.isArray(endpointConfig.tags)) {
10827
+ nextOptions.tags = endpointConfig.tags.map((tag) => {
10828
+ let processedTag = tag;
10829
+ if (params) {
10830
+ Object.entries(params).forEach(([key, value]) => {
10831
+ processedTag = processedTag.replace(`{${key}}`, String(value));
10832
+ });
10833
+ }
10834
+ return processedTag;
10835
+ });
10836
+ }
10837
+ const requestInit = {
10838
+ method,
10839
+ ...options,
10840
+ // Include credentials for same-origin requests (sends cookies for auth)
10841
+ credentials: "same-origin",
10842
+ // Don't include body for GET/HEAD requests
10843
+ body: isGetOrHead ? void 0 : isFormData ? body : body ? JSON.stringify(body) : void 0,
10844
+ headers: {
10845
+ ...options.headers,
10846
+ ...headers,
10847
+ // Include SDK version if set
10848
+ ...sdkVersion && { "x-sdk-version": sdkVersion },
10849
+ // Don't set Content-Type for GET/HEAD requests without body
10850
+ ...isGetOrHead ? {} : isFormData ? {} : { "Content-Type": "application/json" }
10851
+ },
10852
+ // Add Next.js caching options
10853
+ next: Object.keys(nextOptions).length > 0 ? nextOptions : void 0
10854
+ };
10855
+ const fetchPromise = fetch(url, requestInit);
10856
+ if (!isGetOrHead && "tags" in endpointConfig && Array.isArray(endpointConfig.tags)) {
10857
+ const tags = endpointConfig.tags.map((tag) => tag);
10858
+ return fetchPromise.then((response) => {
10859
+ if (response.ok) {
10860
+ invalidateCacheTags(tags, params);
10861
+ }
10862
+ return response;
10863
+ });
10864
+ }
10865
+ return fetchPromise;
10866
+ };
10867
+ }
10868
+ function createParsedClient(rawClient) {
10869
+ return async (params) => {
10870
+ const response = await rawClient(params);
10871
+ const endpoint = params.endpoint;
10872
+ const config3 = API_ENDPOINTS[endpoint];
10873
+ const auth = config3.auth ?? "user";
10874
+ if (!response.ok) {
10875
+ const body = await parseErrorBody(response);
10876
+ const requestId = response.headers.get("x-request-id") ?? void 0;
10877
+ const retryAfterMs = parseRetryAfterHeader(response.headers.get("retry-after"));
10878
+ throw new ApiRequestError(
10879
+ `Request to ${String(endpoint)} failed with status ${response.status}`,
10880
+ {
10881
+ endpoint,
10882
+ status: response.status,
10883
+ method: config3.method,
10884
+ auth,
10885
+ requestId,
10886
+ body,
10887
+ retryAfterMs
10888
+ }
10889
+ );
10890
+ }
10891
+ return parseSuccessResponse(endpoint, response, config3);
10892
+ };
10893
+ }
10894
+ function createCMSClient(headers = {}, baseUrl) {
10895
+ return createParsedClient(createRawCMSClient(headers, baseUrl));
10896
+ }
10897
+ function createBearerAPIClient(token, baseUrl) {
10898
+ const authHeaders = {
10899
+ Authorization: `Bearer ${token}`
10900
+ };
10901
+ return createCMSClient(authHeaders, baseUrl);
10902
+ }
10903
+
10904
+ // ../api/src/common/envelope.ts
10905
+ function isApiError(result) {
10906
+ return result.success === false;
10907
+ }
10908
+ function isApiSuccess(result) {
10909
+ return result.success === true;
10910
+ }
10911
+ var ApiEnvelopeError = class extends Error {
10912
+ constructor(error) {
10913
+ super(error.message);
10914
+ this.name = "ApiEnvelopeError";
10915
+ this.code = error.code;
10916
+ this.requestId = error.requestId;
10917
+ this.timestamp = error.timestamp;
10918
+ this.status = error.status;
10919
+ this.fieldErrors = error.fieldErrors;
10920
+ }
10921
+ };
10922
+ function unwrapResponse(result) {
10923
+ if (isApiSuccess(result)) {
10924
+ return result.data;
10925
+ }
10926
+ throw new ApiEnvelopeError(result.error);
10927
+ }
10928
+
10929
+ // src/client/cache.ts
10930
+ var SimpleCache = class {
10931
+ constructor(options = {}) {
10932
+ this.cache = /* @__PURE__ */ new Map();
10933
+ this.maxSize = options.maxSize ?? 100;
10934
+ this.ttl = options.ttl ?? 3e5;
10935
+ this.staleTtl = options.staleTtl ?? 3e5;
10936
+ }
10937
+ /**
10938
+ * Get a fresh value (within TTL)
10939
+ * @returns The value if fresh, null otherwise
10940
+ */
10941
+ getFresh(key) {
10942
+ const entry = this.cache.get(key);
10943
+ if (!entry) return null;
10944
+ const now = Date.now();
10945
+ if (now <= entry.freshUntil) {
10946
+ return entry.value;
10947
+ }
10948
+ return null;
10949
+ }
10950
+ /**
10951
+ * Get a value that may be stale (past TTL but within staleTtl)
10952
+ * @returns Object with value and stale age, or null if expired
10953
+ */
10954
+ getStale(key) {
10955
+ const entry = this.cache.get(key);
10956
+ if (!entry) return null;
10957
+ const now = Date.now();
10958
+ if (now > entry.staleUntil) {
10959
+ this.cache.delete(key);
10960
+ return null;
10961
+ }
10962
+ const staleAgeSec = now <= entry.freshUntil ? 0 : Math.floor((now - entry.freshUntil) / 1e3);
10963
+ return {
10964
+ value: entry.value,
10965
+ staleAgeSec
10966
+ };
10967
+ }
10968
+ /**
10969
+ * Store a value with TTL and stale window
10970
+ */
10971
+ set(key, value, options) {
10972
+ const ttl = options?.ttl ?? this.ttl;
10973
+ const staleTtl = options?.staleTtl ?? this.staleTtl;
10974
+ const now = Date.now();
10975
+ while (this.cache.size >= this.maxSize && !this.cache.has(key)) {
10976
+ this.evictOne(now);
10977
+ }
10978
+ this.cache.set(key, {
10979
+ value,
10980
+ createdAt: now,
10981
+ freshUntil: now + ttl,
10982
+ staleUntil: now + ttl + staleTtl
10983
+ });
10984
+ }
10985
+ /**
10986
+ * Evict one entry to make room for a new one
10987
+ * Priority: oldest stale entry, then oldest fresh entry
10988
+ */
10989
+ evictOne(now) {
10990
+ let oldestStaleKey = null;
10991
+ let oldestStaleTime = Infinity;
10992
+ let oldestFreshKey = null;
10993
+ let oldestFreshTime = Infinity;
10994
+ for (const [key, entry] of this.cache) {
10995
+ if (now > entry.freshUntil) {
10996
+ if (entry.createdAt < oldestStaleTime) {
10997
+ oldestStaleTime = entry.createdAt;
10998
+ oldestStaleKey = key;
10999
+ }
11000
+ } else {
11001
+ if (entry.createdAt < oldestFreshTime) {
11002
+ oldestFreshTime = entry.createdAt;
11003
+ oldestFreshKey = key;
11004
+ }
11005
+ }
11006
+ }
11007
+ const keyToEvict = oldestStaleKey ?? oldestFreshKey;
11008
+ if (keyToEvict) {
11009
+ this.cache.delete(keyToEvict);
11010
+ }
11011
+ }
11012
+ /**
11013
+ * Remove all fully expired entries (past staleUntil)
11014
+ */
11015
+ prune() {
11016
+ const now = Date.now();
11017
+ for (const [key, entry] of this.cache) {
11018
+ if (now > entry.staleUntil) {
11019
+ this.cache.delete(key);
11020
+ }
11021
+ }
11022
+ }
11023
+ /**
11024
+ * Clear all entries
11025
+ */
11026
+ clear() {
11027
+ this.cache.clear();
11028
+ }
11029
+ /**
11030
+ * Check if a key exists and is not fully expired
11031
+ */
11032
+ has(key) {
11033
+ const entry = this.cache.get(key);
11034
+ if (!entry) return false;
11035
+ const now = Date.now();
11036
+ if (now > entry.staleUntil) {
11037
+ this.cache.delete(key);
11038
+ return false;
11039
+ }
11040
+ return now <= entry.freshUntil;
11041
+ }
11042
+ };
11043
+
11044
+ // src/version.ts
11045
+ var SDK_VERSION = "0.8.0";
11046
+
11047
+ // src/client/error.ts
11048
+ var RiverbankApiError = class _RiverbankApiError extends Error {
11049
+ constructor(apiError) {
11050
+ super(apiError.message);
11051
+ this.name = "RiverbankApiError";
11052
+ if ("cause" in apiError && apiError.cause) {
11053
+ this.cause = apiError.cause;
11054
+ }
11055
+ this.code = apiError.code;
11056
+ this.requestId = apiError.requestId;
11057
+ this.status = apiError.status;
11058
+ this.fieldErrors = apiError.fieldErrors;
11059
+ this.timestamp = apiError.timestamp;
11060
+ this.retryAfterMs = "retryAfterMs" in apiError ? apiError.retryAfterMs : void 0;
11061
+ this.isRetryable = this.computeRetryable();
11062
+ Object.setPrototypeOf(this, _RiverbankApiError.prototype);
11063
+ }
11064
+ /**
11065
+ * Compute whether this error is retryable based on HTTP status code.
11066
+ * - 0 (network errors - no HTTP response): retryable
11067
+ * - 429 (rate limit): retryable
11068
+ * - 5xx (server errors): retryable
11069
+ * - 4xx (client errors, except 429): NOT retryable
11070
+ */
11071
+ computeRetryable() {
11072
+ if (this.status === 0) return true;
11073
+ if (this.status === 429) return true;
11074
+ if (this.status >= 500) return true;
11075
+ return false;
11076
+ }
11077
+ /**
11078
+ * Check if this is a network error (no HTTP response received)
11079
+ *
11080
+ * Matches: network:connection_error, network:timeout, network:dns_error
11081
+ */
11082
+ isNetworkError() {
11083
+ return this.code.startsWith("network:");
11084
+ }
11085
+ /**
11086
+ * Check if this error matches a specific error code
11087
+ *
11088
+ * @example
11089
+ * ```ts
11090
+ * if (error.is('auth:unauthenticated')) {
11091
+ * // Redirect to login
11092
+ * }
11093
+ * ```
11094
+ */
11095
+ is(code) {
11096
+ return this.code === code;
11097
+ }
11098
+ /**
11099
+ * Check if this is an authentication or authorization error
11100
+ *
11101
+ * Matches: auth:unauthenticated, auth:token_expired, auth:token_invalid,
11102
+ * auth:forbidden, auth:mfa_required, auth:insufficient_permissions
11103
+ */
11104
+ isAuthError() {
11105
+ return this.code.startsWith("auth:");
11106
+ }
11107
+ /**
11108
+ * Check if this is a validation error
11109
+ *
11110
+ * Matches: validation:invalid_input, validation:missing_field, validation:invalid_format
11111
+ */
11112
+ isValidationError() {
11113
+ return this.code.startsWith("validation:");
11114
+ }
11115
+ /**
11116
+ * Check if this is a resource error (not found, conflict, etc.)
11117
+ *
11118
+ * Matches: resource:not_found, resource:already_exists, resource:conflict, resource:gone
11119
+ */
11120
+ isResourceError() {
11121
+ return this.code.startsWith("resource:");
11122
+ }
11123
+ /**
11124
+ * Check if this is a rate limiting error
11125
+ */
11126
+ isRateLimitError() {
11127
+ return this.code.startsWith("rate_limit:");
11128
+ }
11129
+ /**
11130
+ * Check if this is a billing/payment error
11131
+ */
11132
+ isBillingError() {
11133
+ return this.code.startsWith("billing:");
11134
+ }
11135
+ /**
11136
+ * Check if this is a server error
11137
+ */
11138
+ isServerError() {
11139
+ return this.code.startsWith("server:");
11140
+ }
11141
+ /**
11142
+ * Returns a human-readable string representation of the error.
11143
+ * Includes all key details for debugging.
11144
+ *
11145
+ * @example
11146
+ * "RiverbankApiError: Content keys cannot access preview content | Code: auth:forbidden | Status: 401 | RequestId: req-abc123"
11147
+ */
11148
+ toString() {
11149
+ const parts = [`RiverbankApiError: ${this.message}`];
11150
+ if (this.code) parts.push(`Code: ${this.code}`);
11151
+ if (this.status) parts.push(`Status: ${this.status}`);
11152
+ if (this.requestId) parts.push(`RequestId: ${this.requestId}`);
11153
+ return parts.join(" | ");
11154
+ }
11155
+ /**
11156
+ * Custom Node.js inspect output for better console.log display.
11157
+ * This ensures that console.log(error) shows all relevant details
11158
+ * instead of just "[Object]" for nested properties.
11159
+ */
11160
+ [Symbol.for("nodejs.util.inspect.custom")]() {
11161
+ return this.toDetailedString();
11162
+ }
11163
+ /**
11164
+ * Returns a detailed multi-line string for debugging.
11165
+ * Used by the Node.js inspect symbol for console output.
11166
+ */
11167
+ toDetailedString() {
11168
+ const lines = [
11169
+ `RiverbankApiError: ${this.message}`,
11170
+ ` Code: ${this.code}`,
11171
+ ` Status: ${this.status}`,
11172
+ ` RequestId: ${this.requestId}`,
11173
+ ` Timestamp: ${this.timestamp}`
11174
+ ];
11175
+ if (this.isRetryable) {
11176
+ lines.push(` Retryable: true`);
11177
+ if (this.retryAfterMs) {
11178
+ lines.push(` RetryAfter: ${this.retryAfterMs}ms`);
11179
+ }
11180
+ }
11181
+ if (this.fieldErrors && this.fieldErrors.length > 0) {
11182
+ lines.push(" FieldErrors:");
11183
+ this.fieldErrors.forEach((fe) => {
11184
+ lines.push(` - ${fe.field}: ${fe.message}`);
11185
+ });
11186
+ }
11187
+ return lines.join("\n");
11188
+ }
11189
+ };
11190
+
11191
+ // src/client/resilience.ts
11192
+ var DEFAULT_RETRY_CONFIG = {
11193
+ maxAttempts: 3,
11194
+ baseDelayMs: 200,
11195
+ maxDelayMs: 2e3,
11196
+ jitter: "full"
11197
+ };
11198
+ var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
11199
+ failureThreshold: 5,
11200
+ resetTimeoutMs: 3e4,
11201
+ halfOpenMaxRequests: 2
11202
+ };
11203
+ var PERMANENT_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
11204
+ "ECONNREFUSED",
11205
+ // Server is not running / port not listening
11206
+ "ENOTFOUND",
11207
+ // DNS lookup failed - hostname doesn't exist
11208
+ "EAI_AGAIN"
11209
+ // DNS lookup timeout (usually permanent for invalid hosts)
11210
+ ]);
11211
+ var TRANSIENT_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
11212
+ "ECONNRESET",
11213
+ // Connection was reset mid-request (server dropped it)
11214
+ "EPIPE",
11215
+ // Broken pipe (connection closed while writing)
11216
+ "ETIMEDOUT",
11217
+ // Connection timed out (could be temporary congestion)
11218
+ "ESOCKETTIMEDOUT"
11219
+ // Socket timeout
11220
+ ]);
11221
+ var NODE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
11222
+ // Permanent
11223
+ "ECONNREFUSED",
11224
+ "ENOTFOUND",
11225
+ "EAI_AGAIN",
11226
+ // Transient
11227
+ "ECONNRESET",
11228
+ "EPIPE",
11229
+ "ETIMEDOUT",
11230
+ "ESOCKETTIMEDOUT"
11231
+ ]);
11232
+ function isNodeNetworkErrorCode(code) {
11233
+ return !code.includes(":") && NODE_NETWORK_ERROR_CODES.has(code);
11234
+ }
11235
+ function getErrorCodeFromCause(error) {
11236
+ let current = error;
11237
+ while (current) {
11238
+ const nodeError = current;
11239
+ if (nodeError.code && typeof nodeError.code === "string") {
11240
+ if (isNodeNetworkErrorCode(nodeError.code)) {
11241
+ return nodeError.code;
11242
+ }
11243
+ }
11244
+ const errorWithCause = current;
11245
+ current = errorWithCause.cause;
11246
+ }
11247
+ return void 0;
11248
+ }
11249
+ function isTransientError(error) {
11250
+ if (error instanceof RiverbankApiError) {
11251
+ const errorCode = getErrorCodeFromCause(error);
11252
+ if (errorCode && PERMANENT_NETWORK_ERROR_CODES.has(errorCode)) {
11253
+ return false;
11254
+ }
11255
+ if (error.status === 0) return true;
11256
+ if (error.status === 429) return true;
11257
+ if (error.status >= 500) return true;
11258
+ return false;
11259
+ }
11260
+ if (error instanceof TypeError) {
11261
+ const errorCode = getErrorCodeFromCause(error);
11262
+ if (errorCode) {
11263
+ if (PERMANENT_NETWORK_ERROR_CODES.has(errorCode)) {
11264
+ return false;
11265
+ }
11266
+ if (TRANSIENT_NETWORK_ERROR_CODES.has(errorCode)) {
11267
+ return true;
11268
+ }
11269
+ }
11270
+ return true;
11271
+ }
11272
+ return true;
11273
+ }
11274
+ function calculateBackoff(attempt, config3) {
11275
+ const baseDelayMs = config3.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs;
11276
+ const maxDelayMs = config3.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs;
11277
+ const jitter = config3.jitter ?? DEFAULT_RETRY_CONFIG.jitter;
11278
+ const exponential = baseDelayMs * Math.pow(2, attempt - 1);
11279
+ const capped = Math.min(exponential, maxDelayMs);
11280
+ if (jitter === "full") {
11281
+ return Math.random() * capped;
11282
+ }
11283
+ return capped;
11284
+ }
11285
+ var CircuitBreaker = class {
11286
+ constructor(config3) {
11287
+ this.state = "closed";
11288
+ this.failureCount = 0;
11289
+ this.successCount = 0;
11290
+ this.openUntil = 0;
11291
+ this.halfOpenRequests = 0;
11292
+ this.config = {
11293
+ failureThreshold: config3?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
11294
+ resetTimeoutMs: config3?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
11295
+ halfOpenMaxRequests: config3?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
11296
+ };
11297
+ }
11298
+ /**
11299
+ * Check if circuit is open (requests should be blocked)
11300
+ * Also handles automatic transition from open to half-open after timeout
11301
+ */
11302
+ isOpen() {
11303
+ if (this.state === "open" && Date.now() >= this.openUntil) {
11304
+ this.transitionTo("half-open");
11305
+ }
11306
+ return this.state === "open";
11307
+ }
11308
+ /**
11309
+ * Check if a request can be attempted
11310
+ * - closed: always yes
11311
+ * - open: always no
11312
+ * - half-open: limited number of probes
11313
+ */
11314
+ canAttempt() {
11315
+ if (this.state === "closed") return true;
11316
+ if (this.state === "open") return false;
11317
+ return this.halfOpenRequests < this.config.halfOpenMaxRequests;
11318
+ }
11319
+ /**
11320
+ * Increment half-open request counter (call before making request in half-open)
11321
+ */
11322
+ incrementHalfOpenRequests() {
11323
+ if (this.state === "half-open") {
11324
+ this.halfOpenRequests++;
11325
+ }
11326
+ }
11327
+ /**
11328
+ * Record a successful request
11329
+ */
11330
+ recordSuccess() {
11331
+ if (this.state === "half-open") {
11332
+ this.successCount++;
11333
+ if (this.successCount >= this.config.halfOpenMaxRequests) {
11334
+ this.transitionTo("closed");
11335
+ }
11336
+ } else {
11337
+ this.failureCount = 0;
11338
+ }
11339
+ }
11340
+ /**
11341
+ * Record a failed request
11342
+ * Only counts transient failures toward circuit breaker threshold
11343
+ */
11344
+ recordFailure(error) {
11345
+ if (!isTransientError(error)) return;
11346
+ this.failureCount++;
11347
+ if (this.state === "half-open") {
11348
+ this.transitionTo("open");
11349
+ } else if (this.failureCount >= this.config.failureThreshold) {
11350
+ this.transitionTo("open");
11351
+ }
11352
+ }
11353
+ /**
11354
+ * Get current circuit state
11355
+ */
11356
+ getState() {
11357
+ return {
11358
+ state: this.state,
11359
+ failureCount: this.failureCount,
11360
+ openUntil: this.state === "open" ? this.openUntil : void 0
11361
+ };
11362
+ }
11363
+ /**
11364
+ * Transition to a new state
11365
+ */
11366
+ transitionTo(newState) {
11367
+ this.state = newState;
11368
+ if (newState === "open") {
11369
+ this.openUntil = Date.now() + this.config.resetTimeoutMs;
11370
+ } else if (newState === "half-open") {
11371
+ this.halfOpenRequests = 0;
11372
+ this.successCount = 0;
11373
+ } else if (newState === "closed") {
11374
+ this.failureCount = 0;
11375
+ this.successCount = 0;
11376
+ this.halfOpenRequests = 0;
11377
+ }
11378
+ }
11379
+ };
11380
+ async function fetchWithTimeoutAndRetry(fetcher, config3) {
11381
+ const maxAttempts = config3.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts;
11382
+ const requestTimeoutMs = config3.requestTimeoutMs ?? 8e3;
11383
+ let lastError;
11384
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
11385
+ try {
11386
+ const controller = new AbortController();
11387
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeoutMs);
11388
+ try {
11389
+ const result = await fetcher(controller.signal);
11390
+ return result;
11391
+ } finally {
11392
+ clearTimeout(timeoutId);
11393
+ }
11394
+ } catch (error) {
11395
+ lastError = error;
11396
+ const shouldRetry = shouldRetryError(error, config3.retryOn);
11397
+ if (!shouldRetry) {
11398
+ throw error;
11399
+ }
11400
+ if (attempt < maxAttempts) {
11401
+ const delay = getRetryDelay(error, attempt, config3);
11402
+ await sleep(delay);
11403
+ }
11404
+ }
11405
+ }
11406
+ throw lastError;
11407
+ }
11408
+ function isAbortError(error) {
11409
+ if (typeof DOMException !== "undefined" && error instanceof DOMException && error.name === "AbortError") {
11410
+ return true;
11411
+ }
11412
+ if (error instanceof Error && error.name === "AbortError") {
11413
+ return true;
11414
+ }
11415
+ return false;
11416
+ }
11417
+ function shouldRetryError(error, customRetryOn) {
11418
+ if (isAbortError(error)) {
11419
+ return false;
11420
+ }
11421
+ if (customRetryOn) {
11422
+ const statusCode = error instanceof RiverbankApiError ? error.status : void 0;
11423
+ return customRetryOn(error, statusCode);
11424
+ }
11425
+ return isTransientError(error);
11426
+ }
11427
+ function getRetryDelay(error, attempt, config3) {
11428
+ if (error instanceof RiverbankApiError && error.retryAfterMs) {
11429
+ return error.retryAfterMs;
11430
+ }
11431
+ return calculateBackoff(attempt, config3);
11432
+ }
11433
+ function sleep(ms) {
11434
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
11435
+ }
11436
+ var CircuitOpenError = class extends Error {
11437
+ constructor(state) {
11438
+ super("Circuit breaker is open");
11439
+ this.name = "CircuitOpenError";
11440
+ this.circuitState = state;
11441
+ }
11442
+ };
11443
+
11444
+ // src/client/index.ts
11445
+ var prebuildModule = null;
11446
+ function getPrebuildModule() {
11447
+ if (prebuildModule !== null) return prebuildModule;
11448
+ if (typeof process === "undefined" || !process.versions?.node) {
11449
+ return null;
11450
+ }
11451
+ try {
11452
+ prebuildModule = (init_loader(), __toCommonJS(loader_exports));
11453
+ return prebuildModule;
11454
+ } catch {
11455
+ return null;
11456
+ }
11457
+ }
11458
+ setSdkVersion(SDK_VERSION);
11459
+ var DEFAULT_BROWSER_TIMEOUT_MS = 5e3;
11460
+ var DEFAULT_SERVER_TIMEOUT_MS = 8e3;
11461
+ function generateRequestId2() {
11462
+ return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
11463
+ }
11464
+ function isAbortError2(error) {
11465
+ if (error instanceof DOMException && error.name === "AbortError") {
11466
+ return true;
11467
+ }
11468
+ if (error instanceof Error && error.name === "AbortError") {
11469
+ return true;
11470
+ }
11471
+ return false;
11472
+ }
11473
+ function getNetworkErrorCode(error) {
11474
+ if (error.name === "TimeoutError" || error.name === "AbortError") {
11475
+ return "network:timeout";
11476
+ }
11477
+ const nodeError = error;
11478
+ if (nodeError.code) {
11479
+ switch (nodeError.code) {
11480
+ case "ETIMEDOUT":
11481
+ case "ESOCKETTIMEDOUT":
11482
+ return "network:timeout";
11483
+ case "ENOTFOUND":
11484
+ case "EAI_AGAIN":
11485
+ return "network:dns_error";
11486
+ case "ECONNREFUSED":
11487
+ case "ECONNRESET":
11488
+ case "EPIPE":
11489
+ return "network:connection_error";
11490
+ }
11491
+ }
11492
+ const message = error.message.toLowerCase();
11493
+ if (message.includes("timeout") || message.includes("timed out")) {
11494
+ return "network:timeout";
11495
+ }
11496
+ if (message.includes("dns") || message.includes("getaddrinfo") || message.includes("enotfound")) {
11497
+ return "network:dns_error";
11498
+ }
11499
+ return "network:connection_error";
11500
+ }
11501
+ function convertToTypedError(error) {
11502
+ if (isAbortError2(error)) {
11503
+ throw error;
11504
+ }
11505
+ if (error instanceof ApiEnvelopeError) {
11506
+ throw new RiverbankApiError({
11507
+ code: error.code,
11508
+ message: error.message,
11509
+ requestId: error.requestId,
11510
+ timestamp: error.timestamp,
11511
+ status: error.status,
11512
+ fieldErrors: error.fieldErrors
11513
+ });
11514
+ }
11515
+ if (error instanceof ApiRequestError && error.body && typeof error.body === "object") {
11516
+ const body = error.body;
11517
+ if (isApiError(body)) {
11518
+ const envelopeError = body.error;
11519
+ throw new RiverbankApiError({
11520
+ ...envelopeError,
11521
+ retryAfterMs: error.retryAfterMs
11522
+ });
11523
+ }
11524
+ }
11525
+ if (error instanceof TypeError || error instanceof Error && !("status" in error)) {
11526
+ const networkError = error;
11527
+ throw new RiverbankApiError({
11528
+ code: getNetworkErrorCode(networkError),
11529
+ message: networkError.message || "Network request failed",
11530
+ requestId: `local-${Date.now()}`,
11531
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11532
+ status: 0,
11533
+ // No HTTP response received
11534
+ cause: networkError
11535
+ // Preserve original error for retry/circuit breaker classification
11536
+ });
11537
+ }
11538
+ throw error;
11539
+ }
11540
+ function detectKeyType(apiKey) {
11541
+ if (apiKey.startsWith("bld_live_sk_") || apiKey.startsWith("bld_test_sk_")) {
11542
+ return "content";
11543
+ }
11544
+ if (apiKey.startsWith("bld_preview_sk_")) {
11545
+ return "preview";
11546
+ }
11547
+ return "unknown";
11548
+ }
11549
+ function createRiverbankClient(config3) {
11550
+ if (!config3.baseUrl) {
11551
+ throw new Error(
11552
+ "baseUrl is required when creating a Riverbank client. Expected format: https://dashboard.example.com/api (must include /api path)"
11553
+ );
11554
+ }
11555
+ if (!config3.baseUrl.endsWith("/api")) {
11556
+ throw new Error(
11557
+ `baseUrl must end with '/api'. Received: ${config3.baseUrl}. Expected format: https://dashboard.example.com/api`
11558
+ );
11559
+ }
11560
+ const cacheEnabled = config3.cache?.enabled ?? true;
11561
+ const cacheTTL = (config3.cache?.ttl ?? 300) * 1e3;
11562
+ const cacheMaxSize = config3.cache?.maxSize ?? 100;
11563
+ const resilienceEnabled = config3.resilience?.enabled ?? true;
11564
+ const staleIfError = config3.resilience?.staleIfError ?? true;
11565
+ const staleTtlMs = (config3.resilience?.staleTtlSec ?? 300) * 1e3;
11566
+ const requestTimeoutMs = config3.resilience?.requestTimeoutMs ?? (typeof window !== "undefined" ? DEFAULT_BROWSER_TIMEOUT_MS : DEFAULT_SERVER_TIMEOUT_MS);
11567
+ const retryConfig = {
11568
+ maxAttempts: config3.resilience?.retry?.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts,
11569
+ baseDelayMs: config3.resilience?.retry?.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs,
11570
+ maxDelayMs: config3.resilience?.retry?.maxDelayMs ?? DEFAULT_RETRY_CONFIG.maxDelayMs,
11571
+ jitter: config3.resilience?.retry?.jitter ?? DEFAULT_RETRY_CONFIG.jitter,
11572
+ retryOn: config3.resilience?.retry?.retryOn
11573
+ };
11574
+ const circuitBreakerConfig = {
11575
+ failureThreshold: config3.resilience?.circuitBreaker?.failureThreshold ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.failureThreshold,
11576
+ resetTimeoutMs: config3.resilience?.circuitBreaker?.resetTimeoutMs ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.resetTimeoutMs,
11577
+ halfOpenMaxRequests: config3.resilience?.circuitBreaker?.halfOpenMaxRequests ?? DEFAULT_CIRCUIT_BREAKER_CONFIG.halfOpenMaxRequests
11578
+ };
11579
+ const keyType = detectKeyType(config3.apiKey);
11580
+ const apiClient = createBearerAPIClient(config3.apiKey, config3.baseUrl);
11581
+ const cache = new SimpleCache({
11582
+ maxSize: cacheMaxSize,
11583
+ ttl: cacheTTL,
11584
+ staleTtl: staleTtlMs
11585
+ });
11586
+ const circuitBreaker = new CircuitBreaker(circuitBreakerConfig);
11587
+ const prebuildDir = config3.resilience?.prebuildDir;
11588
+ const prebuildMod = prebuildDir ? getPrebuildModule() : null;
11589
+ const prebuildLoader = prebuildMod?.canUsePrebuild() && prebuildDir ? new prebuildMod.PrebuildLoader({
11590
+ prebuildDir,
11591
+ maxPrebuildAgeSec: config3.resilience?.maxPrebuildAgeSec
11592
+ }) : null;
11593
+ let lastStatus = null;
11594
+ let isDegraded = false;
11595
+ function emitStatus(source, data, details) {
11596
+ const status = {
11597
+ source,
11598
+ isPreview: details.isPreview,
11599
+ cacheKey: details.cacheKey,
11600
+ error: details.error,
11601
+ staleAgeSec: details.staleAgeSec,
11602
+ prebuildAgeSec: details.prebuildAgeSec,
11603
+ circuit: circuitBreaker.getState(),
11604
+ requestId: details.requestId,
11605
+ durationMs: details.durationMs
11606
+ };
11607
+ lastStatus = status;
11608
+ config3.resilience?.onStatusChange?.(status);
11609
+ const nowDegraded = source === "stale" || source === "error";
11610
+ if (nowDegraded !== isDegraded) {
11611
+ isDegraded = nowDegraded;
11612
+ config3.resilience?.onDegradedMode?.(nowDegraded, status);
11613
+ }
11614
+ return data;
11615
+ }
11616
+ async function resilientFetch(cacheKey, fetcher, options) {
11617
+ const requestId = generateRequestId2();
11618
+ const startTime = Date.now();
11619
+ const isPreview = options.preview ?? false;
11620
+ const statusDetails = (extra = {}) => ({
11621
+ requestId,
11622
+ cacheKey,
11623
+ isPreview,
11624
+ durationMs: Date.now() - startTime,
11625
+ ...extra
11626
+ });
11627
+ if (cacheEnabled && !options.force) {
11628
+ const fresh = cache.getFresh(cacheKey);
11629
+ if (fresh !== null) {
11630
+ return emitStatus("cache", fresh, statusDetails());
11631
+ }
11632
+ }
11633
+ if (resilienceEnabled && circuitBreaker.isOpen()) {
11634
+ if (!isPreview && staleIfError) {
11635
+ const stale = cache.getStale(cacheKey);
11636
+ if (stale) {
11637
+ return emitStatus("stale", stale.value, statusDetails({
11638
+ staleAgeSec: stale.staleAgeSec,
11639
+ error: { code: "circuit_open", message: "Circuit breaker is open" }
11640
+ }));
11641
+ }
11642
+ }
11643
+ if (!isPreview && options.prebuildFallback) {
11644
+ const prebuildResult = options.prebuildFallback();
11645
+ if (prebuildResult) {
11646
+ return emitStatus("prebuild", prebuildResult.data, statusDetails({
11647
+ prebuildAgeSec: prebuildResult.prebuildAgeSec,
11648
+ error: { code: "circuit_open", message: "Circuit breaker is open" }
11649
+ }));
11650
+ }
11651
+ }
11652
+ const circuitState = circuitBreaker.getState();
11653
+ emitStatus("error", null, statusDetails({
11654
+ error: { code: "circuit_open", message: "Circuit breaker is open" }
11655
+ }));
11656
+ throw new CircuitOpenError(circuitState);
11657
+ }
11658
+ try {
11659
+ let data;
11660
+ if (resilienceEnabled) {
11661
+ if (circuitBreaker.getState().state === "half-open") {
11662
+ circuitBreaker.incrementHalfOpenRequests();
11663
+ }
11664
+ data = await fetchWithTimeoutAndRetry(
11665
+ async (timeoutSignal) => {
11666
+ const combinedSignal = options.signal ? combineAbortSignals(timeoutSignal, options.signal) : timeoutSignal;
11667
+ try {
11668
+ const response = await fetcher(combinedSignal);
11669
+ return unwrapResponse(response);
11670
+ } catch (error) {
11671
+ convertToTypedError(error);
11672
+ }
11673
+ },
11674
+ {
11675
+ ...retryConfig,
11676
+ requestTimeoutMs
11677
+ }
11678
+ );
11679
+ circuitBreaker.recordSuccess();
11680
+ } else {
11681
+ try {
11682
+ const response = await fetcher(options.signal ?? new AbortController().signal);
11683
+ data = unwrapResponse(response);
11684
+ } catch (error) {
11685
+ convertToTypedError(error);
11686
+ }
11687
+ }
11688
+ if (cacheEnabled) {
11689
+ cache.set(cacheKey, data);
11690
+ }
11691
+ return emitStatus("live", data, statusDetails());
11692
+ } catch (error) {
11693
+ if (resilienceEnabled && error instanceof Error) {
11694
+ circuitBreaker.recordFailure(error);
11695
+ }
11696
+ if (!isPreview && staleIfError && cacheEnabled) {
11697
+ const stale = cache.getStale(cacheKey);
11698
+ if (stale) {
11699
+ const errorInfo2 = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
11700
+ return emitStatus("stale", stale.value, statusDetails({
11701
+ staleAgeSec: stale.staleAgeSec,
11702
+ error: errorInfo2
11703
+ }));
11704
+ }
11705
+ }
11706
+ if (!isPreview && options.prebuildFallback) {
11707
+ const prebuildResult = options.prebuildFallback();
11708
+ if (prebuildResult) {
11709
+ const errorInfo2 = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
11710
+ return emitStatus("prebuild", prebuildResult.data, statusDetails({
11711
+ prebuildAgeSec: prebuildResult.prebuildAgeSec,
11712
+ error: errorInfo2
11713
+ }));
11714
+ }
11715
+ }
11716
+ const errorInfo = error instanceof RiverbankApiError ? { code: error.code, message: error.message } : { message: error.message };
11717
+ emitStatus("error", null, statusDetails({ error: errorInfo }));
11718
+ throw error;
11719
+ }
11720
+ }
11721
+ function combineAbortSignals(...signals) {
11722
+ const controller = new AbortController();
11723
+ for (const signal of signals) {
11724
+ if (signal.aborted) {
11725
+ controller.abort(signal.reason);
11726
+ break;
11727
+ }
11728
+ signal.addEventListener("abort", () => controller.abort(signal.reason), { once: true });
11729
+ }
11730
+ return controller.signal;
11731
+ }
11732
+ return {
11733
+ async getSite(params) {
11734
+ const { slug, domain, id, signal } = params;
11735
+ if (!slug && !domain && !id) {
11736
+ throw new Error(
11737
+ `getSite() requires at least one identifier: slug, domain, or id. Received: ${JSON.stringify(params)}`
11738
+ );
11739
+ }
11740
+ const cacheKey = `site:${slug || domain || id}`;
11741
+ const siteId = id || slug || domain;
11742
+ return resilientFetch(cacheKey, async (sig) => {
11743
+ const apiParams = {};
11744
+ if (params.slug) apiParams.slug = params.slug;
11745
+ if (params.domain) apiParams.domain = params.domain;
11746
+ if (params.id) apiParams.id = params.id;
11747
+ return await apiClient({ endpoint: "getSite", params: apiParams, options: { signal: sig } });
11748
+ }, {
11749
+ signal,
11750
+ prebuildFallback: prebuildLoader && siteId ? () => prebuildLoader.loadSite(siteId) : void 0
11751
+ });
11752
+ },
11753
+ async getPage(params) {
11754
+ const { siteId, path: path13, preview = false, signal } = params;
11755
+ const cacheKey = `page:${siteId}:${path13}:${preview}`;
11756
+ return resilientFetch(cacheKey, async (sig) => {
11757
+ return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path: path13, preview }, options: { signal: sig } });
11758
+ }, {
11759
+ preview,
11760
+ signal,
11761
+ // Prebuild fallback only for published pages (not preview)
11762
+ prebuildFallback: prebuildLoader && !preview ? () => prebuildLoader.loadPage(siteId, path13) : void 0
11763
+ });
11764
+ },
11765
+ async getEntries(params) {
11766
+ const { siteId, contentType, limit, offset, order, preview = false, mode, entryIds, includeMeta, signal } = params;
11767
+ const entryIdsCacheKey = mode === "manual" && entryIds?.length ? entryIds.join(",") : "";
11768
+ const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ""}:${offset ?? ""}:${order ?? ""}:${preview}:${mode ?? ""}:${entryIdsCacheKey}:${includeMeta ?? ""}`;
11769
+ return resilientFetch(cacheKey, async (sig) => {
11770
+ let orderParam;
11771
+ if (order === "newest") {
11772
+ orderParam = "published_at.desc";
11773
+ } else if (order === "oldest") {
11774
+ orderParam = "published_at.asc";
11775
+ } else if (order === "title") {
11776
+ orderParam = "title.asc";
11777
+ }
11778
+ const apiParams = {
11779
+ siteId,
11780
+ type: contentType,
11781
+ ...typeof limit === "number" && { limit: String(limit) },
11782
+ ...typeof offset === "number" && { offset: String(offset) },
11783
+ ...includeMeta && { meta: "true" },
11784
+ ...orderParam && { order: orderParam },
11785
+ ...preview && { stage: "preview" },
11786
+ ...mode === "manual" && entryIds?.length && {
11787
+ mode: "manual",
11788
+ entryIds: JSON.stringify(entryIds)
11789
+ }
11790
+ };
11791
+ return await apiClient({ endpoint: "listPublishedEntries", params: apiParams, options: { signal: sig } });
11792
+ }, {
11793
+ preview,
11794
+ signal,
11795
+ // Prebuild fallback only for published entries (not preview, not manual mode)
11796
+ prebuildFallback: prebuildLoader && !preview ? () => prebuildLoader.loadEntries(siteId, params) : void 0
11797
+ });
11798
+ },
11799
+ async getEntry(params) {
11800
+ const { siteId, contentType, slug, signal } = params;
11801
+ const cacheKey = `entry:${siteId}:${contentType}:${slug}`;
11802
+ return resilientFetch(cacheKey, async (sig) => {
11803
+ return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug }, options: { signal: sig } });
11804
+ }, { signal });
11805
+ },
11806
+ async getPublicFormById(params) {
11807
+ const { formId, signal } = params;
11808
+ if (!formId) {
11809
+ throw new Error("getPublicFormById() requires formId");
11810
+ }
11811
+ const cacheKey = `public-form:${formId}`;
11812
+ return resilientFetch(cacheKey, async (sig) => {
11813
+ return await apiClient({ endpoint: "getPublicFormById", params: { formId }, options: { signal: sig } });
11814
+ }, { signal });
11815
+ },
11816
+ async getPublicBookingServices(params) {
11817
+ const { siteId, ids, signal } = params;
11818
+ if (!siteId) {
11819
+ throw new Error("getPublicBookingServices() requires siteId");
11820
+ }
11821
+ const cacheKey = `public-booking-services:${siteId}:${ids ?? ""}`;
11822
+ return resilientFetch(cacheKey, async (sig) => {
11823
+ const apiParams = {
11824
+ siteId,
11825
+ ...ids && { ids }
11826
+ };
11827
+ return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams, options: { signal: sig } });
11828
+ }, { signal });
11829
+ },
11830
+ async listPublicEvents(params) {
11831
+ const { siteId, limit, from, to, stage, signal } = params;
11832
+ if (!siteId) {
11833
+ throw new Error("listPublicEvents() requires siteId");
11834
+ }
11835
+ const cacheKey = `public-events:${siteId}:${limit ?? ""}:${from ?? ""}:${to ?? ""}:${stage ?? ""}`;
11836
+ return resilientFetch(cacheKey, async (sig) => {
11837
+ const apiParams = {
11838
+ siteId,
11839
+ ...typeof limit === "number" && { limit: String(limit) },
11840
+ ...from && { from },
11841
+ ...to && { to },
11842
+ ...stage && { stage }
11843
+ };
11844
+ return await apiClient({ endpoint: "listPublicEvents", params: apiParams, options: { signal: sig } });
11845
+ }, { signal });
11846
+ },
11847
+ async resolveEventOccurrence(params) {
11848
+ const { siteId, entryId, segment, signal } = params;
11849
+ if (!siteId || !entryId || !segment) {
11850
+ throw new Error("resolveEventOccurrence() requires siteId, entryId, and segment");
11851
+ }
11852
+ const cacheKey = `event-occurrence:${siteId}:${entryId}:${segment}`;
11853
+ return resilientFetch(cacheKey, async (sig) => {
11854
+ return await apiClient({
11855
+ endpoint: "resolveEventOccurrence",
11856
+ params: { siteId, entryId, segment },
11857
+ options: { signal: sig }
11858
+ });
11859
+ }, { signal });
11860
+ },
11861
+ async checkRedirect(params) {
11862
+ const { siteId, path: path13, signal } = params;
11863
+ if (!siteId || !path13) {
11864
+ throw new Error("checkRedirect() requires siteId and path");
11865
+ }
11866
+ const cacheKey = `redirect:${siteId}:${path13}`;
11867
+ return resilientFetch(cacheKey, async (sig) => {
11868
+ return await apiClient({
11869
+ endpoint: "checkRedirect",
11870
+ params: { site: siteId, path: path13 },
11871
+ options: { signal: sig }
11872
+ });
11873
+ }, { signal });
11874
+ },
11875
+ async getAllPublishedRoutes(params) {
11876
+ const { siteId, signal } = params;
11877
+ if (!siteId) {
11878
+ throw new Error("getAllPublishedRoutes() requires siteId");
11879
+ }
11880
+ const cacheKey = `routable-content:${siteId}:published`;
11881
+ return resilientFetch(cacheKey, async (sig) => {
11882
+ return await apiClient({
11883
+ endpoint: "getPublicRoutableContent",
11884
+ params: { siteId, publishedOnly: "true" },
11885
+ options: { signal: sig }
11886
+ });
11887
+ }, { signal });
11888
+ },
11889
+ clearCache() {
11890
+ cache.clear();
11891
+ },
11892
+ getKeyType() {
11893
+ return keyType;
11894
+ },
11895
+ getLastEmittedStatus() {
11896
+ return lastStatus;
11897
+ },
11898
+ getCircuitState() {
11899
+ return circuitBreaker.getState();
11900
+ }
11901
+ };
11902
+ }
11903
+ init_constants();
11904
+ var MANIFEST_VERSION = "1.0.0";
11905
+ var MANIFEST_FILENAME = "manifest.json";
11906
+ function pathToFilename(routePath) {
11907
+ if (routePath === "/") return "_home.json";
11908
+ return routePath.slice(1).replace(/[^a-zA-Z0-9\-\/]/g, "_").replace(/\//g, "-") + ".json";
11909
+ }
11910
+ function ensureDir3(dirPath) {
11911
+ if (!fs6__namespace.existsSync(dirPath)) {
11912
+ fs6__namespace.mkdirSync(dirPath, { recursive: true });
11913
+ }
11914
+ }
11915
+ function writeJsonFile2(filePath, data) {
11916
+ const content = JSON.stringify(data, null, 2);
11917
+ fs6__namespace.writeFileSync(filePath, content, "utf-8");
11918
+ return Buffer.byteLength(content, "utf-8");
11919
+ }
11920
+ function calculateChecksum(data) {
11921
+ const { checksum: _, ...rest } = data;
11922
+ const content = JSON.stringify(rest);
11923
+ return crypto2__namespace.createHash("sha256").update(content).digest("hex");
11924
+ }
11925
+ async function fetchAllEntries(client, siteId, contentType, onProgress) {
11926
+ const allEntries = [];
11927
+ let offset = 0;
11928
+ let hasMore = true;
11929
+ while (hasMore) {
11930
+ onProgress?.(`${contentType} (batch ${Math.floor(offset / PREBUILD_PAGE_SIZE) + 1})`);
11931
+ const response = await client.getEntries({
11932
+ siteId,
11933
+ contentType,
11934
+ limit: PREBUILD_PAGE_SIZE,
11935
+ offset,
11936
+ preview: false
11937
+ // Published content only
11938
+ });
11939
+ allEntries.push(...response.entries);
11940
+ offset += PREBUILD_PAGE_SIZE;
11941
+ hasMore = response.entries.length === PREBUILD_PAGE_SIZE;
11942
+ }
11943
+ return allEntries;
11944
+ }
11945
+ async function prebuildSite(client, siteId, outputDir) {
11946
+ const site = await client.getSite({ id: siteId });
11947
+ const filename = "site.json";
11948
+ const filePath = path9__namespace.join(outputDir, filename);
11949
+ const cacheFile = {
11950
+ data: site,
11951
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
11952
+ };
11953
+ const size = writeJsonFile2(filePath, cacheFile);
11954
+ return { files: [filename], size, siteData: site };
11955
+ }
11956
+ async function prebuildPages(client, siteId, routes, outputDir, onProgress) {
11957
+ const pagesDir = path9__namespace.join(outputDir, "pages");
11958
+ ensureDir3(pagesDir);
11959
+ const files = [];
11960
+ let totalSize = 0;
11961
+ const publishedPaths = Object.entries(routes).filter(([_, route]) => route.status === "published").map(([_, route]) => route.path);
11962
+ const pageIndex = [];
11963
+ const total = publishedPaths.length;
11964
+ let current = 0;
11965
+ for (const pagePath of publishedPaths) {
11966
+ current++;
11967
+ onProgress?.({
11968
+ current,
11969
+ total,
11970
+ item: `Page: ${pagePath}`,
11971
+ contentType: "pages"
11972
+ });
11973
+ try {
11974
+ const pageData = await client.getPage({ siteId, path: pagePath, preview: false });
11975
+ const filename = pathToFilename(pagePath);
11976
+ const filePath = path9__namespace.join(pagesDir, filename);
11977
+ const cacheFile = {
11978
+ data: pageData,
11979
+ path: pagePath,
11980
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
11981
+ };
11982
+ totalSize += writeJsonFile2(filePath, cacheFile);
11983
+ files.push(`pages/${filename}`);
11984
+ if ("page" in pageData) {
11985
+ pageIndex.push({
11986
+ path: pagePath,
11987
+ pageId: pageData.page.routeId || "",
11988
+ title: pageData.page.name || "Untitled"
11989
+ });
11990
+ }
11991
+ } catch (error) {
11992
+ console.warn(`[Prebuild] Failed to fetch page ${pagePath}:`, error.message);
11993
+ }
11994
+ }
11995
+ const indexFile = {
11996
+ pages: pageIndex,
11997
+ totalCount: pageIndex.length,
11998
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
11999
+ };
12000
+ const indexPath = path9__namespace.join(pagesDir, "_index.json");
12001
+ totalSize += writeJsonFile2(indexPath, indexFile);
12002
+ files.push("pages/_index.json");
12003
+ return { files, size: totalSize };
12004
+ }
12005
+ async function prebuildEntries(client, siteId, contentTypes, outputDir, onProgress) {
12006
+ const entriesDir = path9__namespace.join(outputDir, "entries");
12007
+ ensureDir3(entriesDir);
12008
+ const files = [];
12009
+ let totalSize = 0;
12010
+ const total = contentTypes.length;
12011
+ let current = 0;
12012
+ for (const contentType of contentTypes) {
12013
+ current++;
12014
+ const entries = await fetchAllEntries(
12015
+ client,
12016
+ siteId,
12017
+ contentType,
12018
+ (item) => {
12019
+ onProgress?.({
12020
+ current,
12021
+ total,
12022
+ item: `Entries: ${item}`,
12023
+ contentType: "entries"
12024
+ });
12025
+ }
12026
+ );
12027
+ const typeDir = path9__namespace.join(entriesDir, contentType);
12028
+ ensureDir3(typeDir);
12029
+ const cacheFile = {
12030
+ entries,
12031
+ contentType,
12032
+ totalCount: entries.length,
12033
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
12034
+ };
12035
+ const filename = `entries/${contentType}/all.json`;
12036
+ const filePath = path9__namespace.join(entriesDir, contentType, "all.json");
12037
+ totalSize += writeJsonFile2(filePath, cacheFile);
12038
+ files.push(filename);
12039
+ }
12040
+ return { files, size: totalSize };
12041
+ }
12042
+ async function prebuildNavigation(siteData, outputDir, onProgress) {
12043
+ const navDir = path9__namespace.join(outputDir, "navigation");
12044
+ ensureDir3(navDir);
12045
+ const files = [];
12046
+ let totalSize = 0;
12047
+ const menus = siteData.navigation || [];
12048
+ onProgress?.({
12049
+ current: 1,
12050
+ total: 1,
12051
+ item: "Navigation menus",
12052
+ contentType: "navigation"
12053
+ });
12054
+ const cacheFile = {
12055
+ menus: menus.map((menu) => ({
12056
+ identifier: menu.identifier,
12057
+ id: menu.id,
12058
+ name: menu.name,
12059
+ items: menu.items
12060
+ })),
12061
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
12062
+ };
12063
+ const filename = "navigation/menus.json";
12064
+ const filePath = path9__namespace.join(navDir, "menus.json");
12065
+ totalSize += writeJsonFile2(filePath, cacheFile);
12066
+ files.push(filename);
12067
+ return { files, size: totalSize };
12068
+ }
12069
+ async function prebuildCache(options) {
12070
+ const {
12071
+ client,
12072
+ siteId,
12073
+ outputDir = DEFAULT_PREBUILD_DIR,
12074
+ include = ["site", "pages", "entries", "navigation"],
12075
+ contentTypes,
12076
+ onProgress
12077
+ } = options;
12078
+ const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
12079
+ const files = [];
12080
+ let totalSize = 0;
12081
+ const errors = [];
12082
+ let siteData = null;
12083
+ ensureDir3(outputDir);
12084
+ if (include.includes("site") || include.includes("pages") || include.includes("navigation")) {
12085
+ try {
12086
+ const result = await prebuildSite(client, siteId, outputDir);
12087
+ siteData = result.siteData;
12088
+ if (include.includes("site")) {
12089
+ files.push(...result.files);
12090
+ totalSize += result.size;
12091
+ }
12092
+ onProgress?.({ current: 1, total: 4, item: "Site data", contentType: "site" });
12093
+ } catch (error) {
12094
+ errors.push(`Site prebuild failed: ${error.message}`);
12095
+ }
12096
+ }
12097
+ if (include.includes("pages") && siteData) {
12098
+ try {
12099
+ const result = await prebuildPages(
12100
+ client,
12101
+ siteId,
12102
+ siteData.routes,
12103
+ outputDir,
12104
+ onProgress
12105
+ );
12106
+ files.push(...result.files);
12107
+ totalSize += result.size;
12108
+ } catch (error) {
12109
+ errors.push(`Pages prebuild failed: ${error.message}`);
12110
+ }
12111
+ }
12112
+ if (include.includes("entries")) {
12113
+ try {
12114
+ const typesToPrebuild = contentTypes || [];
12115
+ if (typesToPrebuild.length > 0) {
12116
+ const result = await prebuildEntries(
12117
+ client,
12118
+ siteId,
12119
+ typesToPrebuild,
12120
+ outputDir,
12121
+ onProgress
12122
+ );
12123
+ files.push(...result.files);
12124
+ totalSize += result.size;
12125
+ } else {
12126
+ console.warn("[Prebuild] No contentTypes provided - skipping entries prebuild");
12127
+ }
12128
+ } catch (error) {
12129
+ errors.push(`Entries prebuild failed: ${error.message}`);
12130
+ }
12131
+ }
12132
+ if (include.includes("navigation") && siteData) {
12133
+ try {
12134
+ const result = await prebuildNavigation(siteData, outputDir, onProgress);
12135
+ files.push(...result.files);
12136
+ totalSize += result.size;
12137
+ } catch (error) {
12138
+ errors.push(`Navigation prebuild failed: ${error.message}`);
12139
+ }
12140
+ }
12141
+ const keyToFile = {};
12142
+ if (files.includes("site.json")) {
12143
+ keyToFile[`site:${siteId}`] = "site.json";
12144
+ }
12145
+ for (const file of files) {
12146
+ if (file.startsWith("pages/") && file !== "pages/_index.json") {
12147
+ const filename = file.replace("pages/", "").replace(".json", "");
12148
+ const pagePath = filename === "_home" ? "/" : "/" + filename.replace(/-/g, "/");
12149
+ keyToFile[`page:${siteId}:${pagePath}:false`] = file;
12150
+ }
12151
+ if (file.startsWith("entries/") && file.endsWith("/all.json")) {
12152
+ const contentType = file.split("/")[1];
12153
+ keyToFile[`entries-all:${siteId}:${contentType}`] = file;
12154
+ }
12155
+ }
12156
+ const manifest = {
12157
+ version: MANIFEST_VERSION,
12158
+ generatedAt,
12159
+ siteId,
12160
+ sdkVersion: SDK_VERSION,
12161
+ keyToFile,
12162
+ includedTypes: include,
12163
+ fileCount: files.length,
12164
+ totalSize
12165
+ };
12166
+ const checksum = calculateChecksum(manifest);
12167
+ manifest.checksum = checksum;
12168
+ const manifestPath = path9__namespace.join(outputDir, MANIFEST_FILENAME);
12169
+ writeJsonFile2(manifestPath, manifest);
12170
+ return {
12171
+ success: errors.length === 0,
12172
+ outputDir,
12173
+ files,
12174
+ totalSize,
12175
+ generatedAt,
12176
+ checksum,
12177
+ errors: errors.length > 0 ? errors : void 0
12178
+ };
12179
+ }
12180
+
12181
+ // src/cli/commands/deploy.ts
12182
+ init_constants();
12183
+ async function loadDeployConfig() {
12184
+ const rawConfig = await loadConfigFile();
12185
+ const config3 = rawConfig;
12186
+ if (!config3.siteId) {
12187
+ throw new Error("siteId is required in riverbank.config.ts");
12188
+ }
12189
+ const contentTypes = config3.content?.contentTypes?.map((ct) => ct.key);
12190
+ return {
12191
+ siteId: config3.siteId,
12192
+ deploy: config3.deploy ?? {},
12193
+ contentTypes
12194
+ };
12195
+ }
12196
+ async function checkWorkingDirectoryClean(git, prebuildOutput) {
12197
+ const status = await git.status();
12198
+ const dirtyFiles = status.files.map((f) => f.path).filter((path13) => !path13.startsWith(prebuildOutput));
12199
+ return {
12200
+ clean: dirtyFiles.length === 0,
12201
+ dirtyFiles
12202
+ };
12203
+ }
12204
+ async function commitCacheIfChanged(git, prebuildOutput) {
12205
+ const status = await git.status();
12206
+ const cacheChanges = status.files.filter((f) => f.path.startsWith(prebuildOutput));
12207
+ if (cacheChanges.length === 0) {
12208
+ return false;
12209
+ }
12210
+ await git.add(prebuildOutput);
12211
+ const log = await git.log({ maxCount: 1 });
12212
+ const lastCommit = log.latest;
12213
+ const isLastCommitCache = lastCommit?.message.startsWith("chore: update prebuild cache");
12214
+ let isUnpushed = false;
12215
+ if (isLastCommitCache && lastCommit) {
12216
+ try {
12217
+ const branches = await git.branch(["-r", "--contains", lastCommit.hash]);
12218
+ isUnpushed = branches.all.length === 0;
12219
+ } catch (error) {
12220
+ if (process.env.DEBUG) {
12221
+ console.debug("[deploy] Could not check remote branches:", error);
12222
+ }
12223
+ isUnpushed = true;
12224
+ }
12225
+ }
12226
+ if (isLastCommitCache && isUnpushed) {
12227
+ await git.commit([], { "--amend": null, "--no-edit": null });
12228
+ } else {
12229
+ await git.commit("chore: update prebuild cache");
12230
+ }
12231
+ return true;
12232
+ }
12233
+ var deployCommand = new commander.Command("deploy").description("Deploy site with prebuild cache generation").option("--preview", "Preview deploy - skip prebuild cache generation").addHelpText("after", `
12234
+ Examples:
12235
+ $ riverbankcms deploy # Full deploy with cache generation
12236
+ $ riverbankcms deploy --preview # Deploy without regenerating cache
12237
+
12238
+ Configuration (riverbank.config.ts):
12239
+ deploy: {
12240
+ verifyCommand: 'pnpm verify', // Command to run before deploy
12241
+ prebuildOutput: '.riverbank-cache', // Prebuild output directory
12242
+ }
12243
+
12244
+ Workflow:
12245
+ 1. Run verifyCommand (if configured)
12246
+ 2. Check working directory is clean
12247
+ 3. Generate prebuild cache (unless --preview)
12248
+ 4. Commit cache changes (squashes consecutive unpushed commits)
12249
+ 5. Push to remote
12250
+
12251
+ Notes:
12252
+ - Requires git repository with remote configured
12253
+ - CMS failure during prebuild continues with existing cache
12254
+ - Uses --remote environment variables for API access
12255
+ `).action(async (options, command) => {
12256
+ const { output } = getOutputContext(command);
12257
+ const git = simpleGit__default.default();
12258
+ try {
12259
+ if (!await git.checkIsRepo()) {
12260
+ return output.error("Not a git repository", {
12261
+ suggestion: "Run this command from your project root directory"
12262
+ });
12263
+ }
12264
+ output.info("Loading configuration...");
12265
+ const config3 = await loadDeployConfig();
12266
+ const prebuildOutput = config3.deploy.prebuildOutput ?? DEFAULT_PREBUILD_DIR;
12267
+ if (config3.deploy.verifyCommand) {
12268
+ output.info(`Running verification: ${config3.deploy.verifyCommand}`);
12269
+ try {
12270
+ child_process.execSync(config3.deploy.verifyCommand, { stdio: "inherit" });
12271
+ output.success("Verification passed");
12272
+ } catch {
12273
+ return output.error("Verification failed", {
12274
+ suggestion: "Fix the issues reported by the verify command and try again"
12275
+ });
12276
+ }
12277
+ } else {
12278
+ output.warn("No verifyCommand configured, skipping verification");
12279
+ }
12280
+ const { clean, dirtyFiles } = await checkWorkingDirectoryClean(git, prebuildOutput);
12281
+ if (!clean) {
12282
+ output.warn("Uncommitted changes detected:");
12283
+ dirtyFiles.slice(0, 5).forEach((f) => output.warn(` - ${f}`));
12284
+ if (dirtyFiles.length > 5) {
12285
+ output.warn(` ... and ${dirtyFiles.length - 5} more files`);
12286
+ }
12287
+ return output.error("Working directory not clean", {
12288
+ suggestion: "Commit or stash your changes before deploying"
12289
+ });
12290
+ }
12291
+ if (!options.preview) {
12292
+ output.info("Generating prebuild cache...");
12293
+ try {
12294
+ const env = loadEnvironment(true);
12295
+ const client = createRiverbankClient({
12296
+ apiKey: env.managementApiKey,
12297
+ baseUrl: env.dashboardUrl
12298
+ });
12299
+ const result = await prebuildCache({
12300
+ client,
12301
+ siteId: config3.siteId,
12302
+ outputDir: prebuildOutput,
12303
+ contentTypes: config3.contentTypes,
12304
+ onProgress: (p) => {
12305
+ output.info(` ${p.item}`);
12306
+ }
12307
+ });
12308
+ if (result.success) {
12309
+ output.success(`Prebuild complete: ${result.files.length} files (${formatBytes(result.totalSize)})`);
12310
+ } else {
12311
+ output.warn("Prebuild completed with errors:");
12312
+ result.errors?.forEach((e) => output.warn(` - ${e}`));
12313
+ }
12314
+ const committed = await commitCacheIfChanged(git, prebuildOutput);
12315
+ if (committed) {
12316
+ output.success("Cache committed");
12317
+ } else {
12318
+ output.info("Cache unchanged, no commit needed");
12319
+ }
12320
+ } catch (error) {
12321
+ const message = error instanceof Error ? error.message : "Unknown error";
12322
+ output.warn(`Prebuild failed: ${message}`);
12323
+ output.warn("Continuing with existing cache...");
12324
+ }
12325
+ } else {
12326
+ output.info("Skipping prebuild cache (--preview mode)");
12327
+ }
12328
+ output.info("Pushing to remote...");
12329
+ try {
12330
+ await git.push();
12331
+ output.success("Deploy triggered successfully!");
12332
+ } catch (error) {
12333
+ const message = error instanceof Error ? error.message : "Unknown error";
12334
+ return output.error(`Push failed: ${message}`, {
12335
+ suggestion: "Check your git remote configuration and permissions"
12336
+ });
12337
+ }
12338
+ } catch (error) {
12339
+ handleCommandError(error, output);
12340
+ }
12341
+ });
12342
+ function formatBytes(bytes) {
12343
+ if (bytes < 1024) return `${bytes} B`;
12344
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
12345
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
12346
+ }
12347
+
8695
12348
  // src/cli/index.ts
8696
12349
  dotenv.config({ path: ".env.local" });
8697
12350
  dotenv.config({ path: ".env" });
@@ -8729,6 +12382,7 @@ program.addCommand(deleteCommand);
8729
12382
  program.addCommand(previewCommand);
8730
12383
  program.addCommand(initDocsCommand);
8731
12384
  program.addCommand(identifiersCommand);
12385
+ program.addCommand(deployCommand);
8732
12386
  program.parse();
8733
12387
  //# sourceMappingURL=index.js.map
8734
12388
  //# sourceMappingURL=index.js.map