@riverbankcms/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +1892 -0
  2. package/dist/cli/index.js +327 -0
  3. package/dist/cli/index.js.map +1 -0
  4. package/dist/client/analytics.d.mts +103 -0
  5. package/dist/client/analytics.d.ts +103 -0
  6. package/dist/client/analytics.js +197 -0
  7. package/dist/client/analytics.js.map +1 -0
  8. package/dist/client/analytics.mjs +169 -0
  9. package/dist/client/analytics.mjs.map +1 -0
  10. package/dist/client/bookings.d.mts +89 -0
  11. package/dist/client/bookings.d.ts +89 -0
  12. package/dist/client/bookings.js +34 -0
  13. package/dist/client/bookings.js.map +1 -0
  14. package/dist/client/bookings.mjs +11 -0
  15. package/dist/client/bookings.mjs.map +1 -0
  16. package/dist/client/client.d.mts +195 -0
  17. package/dist/client/client.d.ts +195 -0
  18. package/dist/client/client.js +606 -0
  19. package/dist/client/client.js.map +1 -0
  20. package/dist/client/client.mjs +572 -0
  21. package/dist/client/client.mjs.map +1 -0
  22. package/dist/client/hooks.d.mts +71 -0
  23. package/dist/client/hooks.d.ts +71 -0
  24. package/dist/client/hooks.js +264 -0
  25. package/dist/client/hooks.js.map +1 -0
  26. package/dist/client/hooks.mjs +235 -0
  27. package/dist/client/hooks.mjs.map +1 -0
  28. package/dist/client/rendering/client.d.mts +1 -0
  29. package/dist/client/rendering/client.d.ts +1 -0
  30. package/dist/client/rendering/client.js +33 -0
  31. package/dist/client/rendering/client.js.map +1 -0
  32. package/dist/client/rendering/client.mjs +8 -0
  33. package/dist/client/rendering/client.mjs.map +1 -0
  34. package/dist/client/usePage-BvKAa3Zw.d.mts +366 -0
  35. package/dist/client/usePage-BvKAa3Zw.d.ts +366 -0
  36. package/dist/server/chunk-2RW5HAQQ.mjs +86 -0
  37. package/dist/server/chunk-2RW5HAQQ.mjs.map +1 -0
  38. package/dist/server/chunk-3KKZVGH4.mjs +179 -0
  39. package/dist/server/chunk-3KKZVGH4.mjs.map +1 -0
  40. package/dist/server/chunk-4Z3GPTCS.js +179 -0
  41. package/dist/server/chunk-4Z3GPTCS.js.map +1 -0
  42. package/dist/server/chunk-4Z5FBFRL.mjs +211 -0
  43. package/dist/server/chunk-4Z5FBFRL.mjs.map +1 -0
  44. package/dist/server/chunk-ADREPXFU.js +86 -0
  45. package/dist/server/chunk-ADREPXFU.js.map +1 -0
  46. package/dist/server/chunk-F472SMKX.js +140 -0
  47. package/dist/server/chunk-F472SMKX.js.map +1 -0
  48. package/dist/server/chunk-GWBMJPLH.mjs +57 -0
  49. package/dist/server/chunk-GWBMJPLH.mjs.map +1 -0
  50. package/dist/server/chunk-JB4LIEFS.js +85 -0
  51. package/dist/server/chunk-JB4LIEFS.js.map +1 -0
  52. package/dist/server/chunk-PEAXKTDU.mjs +140 -0
  53. package/dist/server/chunk-PEAXKTDU.mjs.map +1 -0
  54. package/dist/server/chunk-QQ6U4QX6.js +120 -0
  55. package/dist/server/chunk-QQ6U4QX6.js.map +1 -0
  56. package/dist/server/chunk-R5YGLRUG.mjs +122 -0
  57. package/dist/server/chunk-R5YGLRUG.mjs.map +1 -0
  58. package/dist/server/chunk-SW7LE4M3.js +211 -0
  59. package/dist/server/chunk-SW7LE4M3.js.map +1 -0
  60. package/dist/server/chunk-W3K7LVPS.mjs +120 -0
  61. package/dist/server/chunk-W3K7LVPS.mjs.map +1 -0
  62. package/dist/server/chunk-WKG57P2H.mjs +85 -0
  63. package/dist/server/chunk-WKG57P2H.mjs.map +1 -0
  64. package/dist/server/chunk-YHEZMVTS.js +122 -0
  65. package/dist/server/chunk-YHEZMVTS.js.map +1 -0
  66. package/dist/server/chunk-YXDDFG3N.js +57 -0
  67. package/dist/server/chunk-YXDDFG3N.js.map +1 -0
  68. package/dist/server/components.d.mts +49 -0
  69. package/dist/server/components.d.ts +49 -0
  70. package/dist/server/components.js +22 -0
  71. package/dist/server/components.js.map +1 -0
  72. package/dist/server/components.mjs +22 -0
  73. package/dist/server/components.mjs.map +1 -0
  74. package/dist/server/config-validation.d.mts +300 -0
  75. package/dist/server/config-validation.d.ts +300 -0
  76. package/dist/server/config-validation.js +50 -0
  77. package/dist/server/config-validation.js.map +1 -0
  78. package/dist/server/config-validation.mjs +50 -0
  79. package/dist/server/config-validation.mjs.map +1 -0
  80. package/dist/server/config.d.mts +38 -0
  81. package/dist/server/config.d.ts +38 -0
  82. package/dist/server/config.js +44 -0
  83. package/dist/server/config.js.map +1 -0
  84. package/dist/server/config.mjs +44 -0
  85. package/dist/server/config.mjs.map +1 -0
  86. package/dist/server/data.d.mts +108 -0
  87. package/dist/server/data.d.ts +108 -0
  88. package/dist/server/data.js +15 -0
  89. package/dist/server/data.js.map +1 -0
  90. package/dist/server/data.mjs +15 -0
  91. package/dist/server/data.mjs.map +1 -0
  92. package/dist/server/index-B0yI_V6Z.d.mts +18 -0
  93. package/dist/server/index-C6M0Wfjq.d.ts +18 -0
  94. package/dist/server/index.d.mts +5 -0
  95. package/dist/server/index.d.ts +5 -0
  96. package/dist/server/index.js +12 -0
  97. package/dist/server/index.js.map +1 -0
  98. package/dist/server/index.mjs +12 -0
  99. package/dist/server/index.mjs.map +1 -0
  100. package/dist/server/loadContent-CJcbYF3J.d.ts +152 -0
  101. package/dist/server/loadContent-zhlL4YSE.d.mts +152 -0
  102. package/dist/server/loadPage-BYmVMk0V.d.ts +216 -0
  103. package/dist/server/loadPage-CCf15nt8.d.mts +216 -0
  104. package/dist/server/loadPage-DVH3DW6E.js +9 -0
  105. package/dist/server/loadPage-DVH3DW6E.js.map +1 -0
  106. package/dist/server/loadPage-PHQZ6XQZ.mjs +9 -0
  107. package/dist/server/loadPage-PHQZ6XQZ.mjs.map +1 -0
  108. package/dist/server/metadata.d.mts +135 -0
  109. package/dist/server/metadata.d.ts +135 -0
  110. package/dist/server/metadata.js +68 -0
  111. package/dist/server/metadata.js.map +1 -0
  112. package/dist/server/metadata.mjs +68 -0
  113. package/dist/server/metadata.mjs.map +1 -0
  114. package/dist/server/rendering/server.d.mts +83 -0
  115. package/dist/server/rendering/server.d.ts +83 -0
  116. package/dist/server/rendering/server.js +14 -0
  117. package/dist/server/rendering/server.js.map +1 -0
  118. package/dist/server/rendering/server.mjs +14 -0
  119. package/dist/server/rendering/server.mjs.map +1 -0
  120. package/dist/server/rendering.d.mts +12 -0
  121. package/dist/server/rendering.d.ts +12 -0
  122. package/dist/server/rendering.js +40 -0
  123. package/dist/server/rendering.js.map +1 -0
  124. package/dist/server/rendering.mjs +40 -0
  125. package/dist/server/rendering.mjs.map +1 -0
  126. package/dist/server/routing.d.mts +115 -0
  127. package/dist/server/routing.d.ts +115 -0
  128. package/dist/server/routing.js +57 -0
  129. package/dist/server/routing.js.map +1 -0
  130. package/dist/server/routing.mjs +57 -0
  131. package/dist/server/routing.mjs.map +1 -0
  132. package/dist/server/server.d.mts +9 -0
  133. package/dist/server/server.d.ts +9 -0
  134. package/dist/server/server.js +21 -0
  135. package/dist/server/server.js.map +1 -0
  136. package/dist/server/server.mjs +21 -0
  137. package/dist/server/server.mjs.map +1 -0
  138. package/dist/server/theme-bridge.d.mts +232 -0
  139. package/dist/server/theme-bridge.d.ts +232 -0
  140. package/dist/server/theme-bridge.js +231 -0
  141. package/dist/server/theme-bridge.js.map +1 -0
  142. package/dist/server/theme-bridge.mjs +231 -0
  143. package/dist/server/theme-bridge.mjs.map +1 -0
  144. package/dist/server/theme.d.mts +40 -0
  145. package/dist/server/theme.d.ts +40 -0
  146. package/dist/server/theme.js +17 -0
  147. package/dist/server/theme.js.map +1 -0
  148. package/dist/server/theme.mjs +17 -0
  149. package/dist/server/theme.mjs.map +1 -0
  150. package/dist/server/types-BCeqWtI2.d.mts +333 -0
  151. package/dist/server/types-BCeqWtI2.d.ts +333 -0
  152. package/dist/server/types-Bbo01M7P.d.mts +76 -0
  153. package/dist/server/types-Bbo01M7P.d.ts +76 -0
  154. package/dist/server/types-C6gmRHLe.d.mts +150 -0
  155. package/dist/server/types-C6gmRHLe.d.ts +150 -0
  156. package/package.json +147 -0
  157. package/src/styles/index.css +10 -0
@@ -0,0 +1,179 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/client/index.ts
2
+ var _api = require('@riverbankcms/api');
3
+
4
+ // src/client/cache.ts
5
+ var SimpleCache = class {
6
+ constructor(options = {}) {
7
+ this.cache = /* @__PURE__ */ new Map();
8
+ this.maxSize = _nullishCoalesce(options.maxSize, () => ( 100));
9
+ this.ttl = _nullishCoalesce(options.ttl, () => ( 3e5));
10
+ }
11
+ get(key) {
12
+ const entry = this.cache.get(key);
13
+ if (!entry) return void 0;
14
+ if (Date.now() > entry.expires) {
15
+ this.cache.delete(key);
16
+ return void 0;
17
+ }
18
+ return entry.value;
19
+ }
20
+ set(key, value) {
21
+ if (this.cache.size >= this.maxSize) {
22
+ const firstKey = this.cache.keys().next().value;
23
+ if (firstKey) {
24
+ this.cache.delete(firstKey);
25
+ }
26
+ }
27
+ this.cache.set(key, {
28
+ value,
29
+ expires: Date.now() + this.ttl
30
+ });
31
+ }
32
+ clear() {
33
+ this.cache.clear();
34
+ }
35
+ has(key) {
36
+ return this.get(key) !== void 0;
37
+ }
38
+ };
39
+
40
+ // src/client/index.ts
41
+ function createRiverbankClient(config) {
42
+ if (!config.baseUrl) {
43
+ throw new Error(
44
+ "baseUrl is required when creating a Builder client. Expected format: https://dashboard.example.com/api (must include /api path)"
45
+ );
46
+ }
47
+ if (!config.baseUrl.endsWith("/api")) {
48
+ throw new Error(
49
+ `baseUrl must end with '/api'. Received: ${config.baseUrl}. Expected format: https://dashboard.example.com/api`
50
+ );
51
+ }
52
+ const cacheEnabled = _nullishCoalesce(_optionalChain([config, 'access', _ => _.cache, 'optionalAccess', _2 => _2.enabled]), () => ( true));
53
+ const cacheTTL = (_nullishCoalesce(_optionalChain([config, 'access', _3 => _3.cache, 'optionalAccess', _4 => _4.ttl]), () => ( 300))) * 1e3;
54
+ const cacheMaxSize = _nullishCoalesce(_optionalChain([config, 'access', _5 => _5.cache, 'optionalAccess', _6 => _6.maxSize]), () => ( 100));
55
+ const apiClient = _api.createBearerAPIClient.call(void 0, config.apiKey, config.baseUrl);
56
+ const cache = new SimpleCache({
57
+ maxSize: cacheMaxSize,
58
+ ttl: cacheTTL
59
+ });
60
+ async function cachedFetch(cacheKey, fetcher, options) {
61
+ if (cacheEnabled && !_optionalChain([options, 'optionalAccess', _7 => _7.force])) {
62
+ const cached = cache.get(cacheKey);
63
+ if (cached !== void 0) {
64
+ return cached;
65
+ }
66
+ }
67
+ const data = await fetcher();
68
+ if (cacheEnabled) {
69
+ cache.set(cacheKey, data);
70
+ }
71
+ return data;
72
+ }
73
+ return {
74
+ async getSite(params) {
75
+ const { slug, domain, id } = params;
76
+ if (!slug && !domain && !id) {
77
+ throw new Error(
78
+ `getSite() requires at least one identifier: slug, domain, or id. Received: ${JSON.stringify(params)}`
79
+ );
80
+ }
81
+ const cacheKey = `site:${slug || domain || id}`;
82
+ return cachedFetch(cacheKey, async () => {
83
+ const apiParams = {};
84
+ if (params.slug) apiParams.slug = params.slug;
85
+ if (params.domain) apiParams.domain = params.domain;
86
+ if (params.id) apiParams.id = params.id;
87
+ return await apiClient({ endpoint: "getSite", params: apiParams });
88
+ });
89
+ },
90
+ async getPage(params) {
91
+ const { siteId, path, preview = false } = params;
92
+ const cacheKey = `page:${siteId}:${path}:${preview}`;
93
+ return cachedFetch(cacheKey, async () => {
94
+ return await apiClient({ endpoint: "getContentByPath", params: { siteId }, body: { path, preview } });
95
+ });
96
+ },
97
+ async getEntries(params) {
98
+ const { siteId, contentType, limit, order, preview = false, mode, entryIds } = params;
99
+ const entryIdsCacheKey = mode === "manual" && _optionalChain([entryIds, 'optionalAccess', _8 => _8.length]) ? entryIds.join(",") : "";
100
+ const cacheKey = `entries:${siteId}:${contentType}:${_nullishCoalesce(limit, () => ( ""))}:${_nullishCoalesce(order, () => ( ""))}:${preview}:${_nullishCoalesce(mode, () => ( ""))}:${entryIdsCacheKey}`;
101
+ return cachedFetch(cacheKey, async () => {
102
+ const apiParams = {
103
+ siteId,
104
+ type: contentType
105
+ };
106
+ if (typeof limit === "number") {
107
+ apiParams.limit = String(limit);
108
+ }
109
+ if (order === "newest") {
110
+ apiParams.order = "published_at.desc";
111
+ } else if (order === "oldest") {
112
+ apiParams.order = "published_at.asc";
113
+ } else if (order === "title") {
114
+ apiParams.order = "title.asc";
115
+ }
116
+ if (preview) {
117
+ apiParams.stage = "preview";
118
+ }
119
+ if (mode === "manual" && _optionalChain([entryIds, 'optionalAccess', _9 => _9.length])) {
120
+ apiParams.mode = "manual";
121
+ apiParams.entryIds = JSON.stringify(entryIds);
122
+ }
123
+ return await apiClient({ endpoint: "listPublishedEntries", params: apiParams });
124
+ });
125
+ },
126
+ async getEntry(params) {
127
+ const { siteId, contentType, slug } = params;
128
+ const cacheKey = `entry:${siteId}:${contentType}:${slug}`;
129
+ return cachedFetch(cacheKey, async () => {
130
+ return await apiClient({ endpoint: "getPublishedEntryPreview", params: { siteId, type: contentType, slug } });
131
+ });
132
+ },
133
+ async getPublicFormById(params) {
134
+ const { formId } = params;
135
+ if (!formId) {
136
+ throw new Error("getPublicFormById() requires formId");
137
+ }
138
+ const cacheKey = `public-form:${formId}`;
139
+ return cachedFetch(cacheKey, async () => {
140
+ return await apiClient({ endpoint: "getPublicFormById", params: { formId } });
141
+ });
142
+ },
143
+ async getPublicBookingServices(params) {
144
+ const { siteId, ids } = params;
145
+ if (!siteId) {
146
+ throw new Error("getPublicBookingServices() requires siteId");
147
+ }
148
+ const cacheKey = `public-booking-services:${siteId}:${_nullishCoalesce(ids, () => ( ""))}`;
149
+ return cachedFetch(cacheKey, async () => {
150
+ const apiParams = { siteId };
151
+ if (ids) apiParams.ids = ids;
152
+ return await apiClient({ endpoint: "getPublicBookingServices", params: apiParams });
153
+ });
154
+ },
155
+ async listPublicEvents(params) {
156
+ const { siteId, limit, from, to, stage } = params;
157
+ if (!siteId) {
158
+ throw new Error("listPublicEvents() requires siteId");
159
+ }
160
+ const cacheKey = `public-events:${siteId}:${_nullishCoalesce(limit, () => ( ""))}:${_nullishCoalesce(from, () => ( ""))}:${_nullishCoalesce(to, () => ( ""))}:${_nullishCoalesce(stage, () => ( ""))}`;
161
+ return cachedFetch(cacheKey, async () => {
162
+ const apiParams = { siteId };
163
+ if (typeof limit === "number") apiParams.limit = String(limit);
164
+ if (from) apiParams.from = from;
165
+ if (to) apiParams.to = to;
166
+ if (stage) apiParams.stage = stage;
167
+ return await apiClient({ endpoint: "listPublicEvents", params: apiParams });
168
+ });
169
+ },
170
+ clearCache() {
171
+ cache.clear();
172
+ }
173
+ };
174
+ }
175
+
176
+
177
+
178
+ exports.createRiverbankClient = createRiverbankClient;
179
+ //# sourceMappingURL=chunk-4Z3GPTCS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-4Z3GPTCS.js","../../src/client/index.ts","../../src/client/cache.ts"],"names":[],"mappings":"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","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-4Z3GPTCS.js","sourcesContent":[null,"import { createBearerAPIClient } from '@riverbankcms/api';\nimport type {\n RiverbankClient,\n RiverbankClientConfig,\n PublicBookingServicesResponse,\n PublicEventsResponse,\n PublicFormResponse,\n} from './types';\nimport { SimpleCache } from './cache';\n\n/**\n * Create a Riverbank CMS client for fetching content\n *\n * @example\n * ```ts\n * const client = createRiverbankClient({\n * apiKey: 'bld_live_sk_...',\n * baseUrl: 'https://dashboard.example.com/api',\n * });\n *\n * const site = await client.getSite({ slug: 'my-site' });\n * ```\n */\nexport function createRiverbankClient(config: RiverbankClientConfig): RiverbankClient {\n if (!config.baseUrl) {\n throw new Error(\n 'baseUrl is required when creating a Builder client. ' +\n 'Expected format: https://dashboard.example.com/api (must include /api path)'\n );\n }\n\n // Validate baseUrl format\n if (!config.baseUrl.endsWith('/api')) {\n throw new Error(\n `baseUrl must end with '/api'. Received: ${config.baseUrl}. ` +\n 'Expected format: https://dashboard.example.com/api'\n );\n }\n\n const cacheEnabled = config.cache?.enabled ?? true;\n const cacheTTL = (config.cache?.ttl ?? 300) * 1000; // Convert seconds to milliseconds\n const cacheMaxSize = config.cache?.maxSize ?? 100;\n\n // Create internal API client with Bearer token auth\n const apiClient = createBearerAPIClient(config.apiKey, config.baseUrl);\n\n // Create cache instance\n const cache = new SimpleCache<unknown>({\n maxSize: cacheMaxSize,\n ttl: cacheTTL,\n });\n\n /**\n * Helper to cache API calls\n */\n async function cachedFetch<T>(\n cacheKey: string,\n fetcher: () => Promise<T>,\n options?: { force?: boolean }\n ): Promise<T> {\n // Check cache unless force is true\n if (cacheEnabled && !options?.force) {\n const cached = cache.get(cacheKey) as T | undefined;\n if (cached !== undefined) {\n return cached;\n }\n }\n\n // Fetch fresh data\n const data = await fetcher();\n\n // Store in cache\n if (cacheEnabled) {\n cache.set(cacheKey, data);\n }\n\n return data;\n }\n\n return {\n async getSite(params) {\n const { slug, domain, id } = params;\n\n if (!slug && !domain && !id) {\n throw new Error(\n 'getSite() requires at least one identifier: slug, domain, or id. ' +\n `Received: ${JSON.stringify(params)}`\n );\n }\n\n const cacheKey = `site:${slug || domain || id}`;\n\n return cachedFetch(cacheKey, async () => {\n // Convert params to string record for API client\n const apiParams: Record<string, string> = {};\n if (params.slug) apiParams.slug = params.slug;\n if (params.domain) apiParams.domain = params.domain;\n if (params.id) apiParams.id = params.id;\n return await apiClient({ endpoint: 'getSite', params: apiParams });\n });\n },\n\n async getPage(params) {\n const { siteId, path, preview = false } = params;\n const cacheKey = `page:${siteId}:${path}:${preview}`;\n\n return cachedFetch(cacheKey, async () => {\n return await apiClient({ endpoint: 'getContentByPath', params: { siteId }, body: { path, preview } });\n });\n },\n\n async getEntries(params) {\n const { siteId, contentType, limit, order, preview = false, mode, entryIds } = params;\n\n // Include all params in cache key to ensure different queries are cached separately\n const entryIdsCacheKey = mode === 'manual' && entryIds?.length ? entryIds.join(',') : '';\n const cacheKey = `entries:${siteId}:${contentType}:${limit ?? ''}:${order ?? ''}:${preview}:${mode ?? ''}:${entryIdsCacheKey}`;\n\n return cachedFetch(cacheKey, async () => {\n // Build API params\n const apiParams: Record<string, string> = {\n siteId,\n type: contentType,\n };\n\n // Add optional pagination\n if (typeof limit === 'number') {\n apiParams.limit = String(limit);\n }\n\n // Convert user-friendly order to API format\n // 'order' means custom ordering - we don't pass an order param (API default)\n if (order === 'newest') {\n apiParams.order = 'published_at.desc';\n } else if (order === 'oldest') {\n apiParams.order = 'published_at.asc';\n } else if (order === 'title') {\n apiParams.order = 'title.asc';\n }\n // 'order' or undefined: don't set order param, use API default\n\n // Add preview stage if enabled\n if (preview) {\n apiParams.stage = 'preview';\n }\n\n // Manual mode - pass entry IDs for hydration\n if (mode === 'manual' && entryIds?.length) {\n apiParams.mode = 'manual';\n apiParams.entryIds = JSON.stringify(entryIds);\n }\n\n return await apiClient({ endpoint: 'listPublishedEntries', params: apiParams });\n });\n },\n\n async getEntry(params) {\n const { siteId, contentType, slug } = params;\n const cacheKey = `entry:${siteId}:${contentType}:${slug}`;\n\n return cachedFetch(cacheKey, async () => {\n return await apiClient({ endpoint: 'getPublishedEntryPreview', params: { siteId, type: contentType, slug } });\n });\n },\n\n async getPublicFormById(params) {\n const { formId } = params;\n if (!formId) {\n throw new Error('getPublicFormById() requires formId');\n }\n const cacheKey = `public-form:${formId}`;\n return cachedFetch(cacheKey, async () => {\n return await apiClient({ endpoint: 'getPublicFormById', params: { formId } }) as PublicFormResponse;\n });\n },\n\n async getPublicBookingServices(params) {\n const { siteId, ids } = params;\n if (!siteId) {\n throw new Error('getPublicBookingServices() requires siteId');\n }\n const cacheKey = `public-booking-services:${siteId}:${ids ?? ''}`;\n return cachedFetch(cacheKey, async () => {\n const apiParams: Record<string, string> = { siteId };\n if (ids) apiParams.ids = ids;\n return await apiClient({ endpoint: 'getPublicBookingServices', params: apiParams }) as PublicBookingServicesResponse;\n });\n },\n\n async listPublicEvents(params) {\n const { siteId, limit, from, to, stage } = params;\n if (!siteId) {\n throw new Error('listPublicEvents() requires siteId');\n }\n const cacheKey = `public-events:${siteId}:${limit ?? ''}:${from ?? ''}:${to ?? ''}:${stage ?? ''}`;\n return cachedFetch(cacheKey, async () => {\n const apiParams: Record<string, string> = { siteId };\n if (typeof limit === 'number') apiParams.limit = String(limit);\n if (from) apiParams.from = from;\n if (to) apiParams.to = to;\n if (stage) apiParams.stage = stage;\n return await apiClient({ endpoint: 'listPublicEvents', params: apiParams }) as PublicEventsResponse;\n });\n },\n\n clearCache() {\n cache.clear();\n },\n };\n}\n\n// Re-export types\nexport type { RiverbankClient, RiverbankClientConfig } from './types';\n","/**\n * Simple in-memory cache with TTL support\n */\nexport class SimpleCache<T> {\n private cache = new Map<string, { value: T; expires: number }>();\n private maxSize: number;\n private ttl: number;\n\n constructor(options: { maxSize?: number; ttl?: number } = {}) {\n this.maxSize = options.maxSize ?? 100;\n this.ttl = options.ttl ?? 300000; // 5 minutes in milliseconds\n }\n\n get(key: string): T | undefined {\n const entry = this.cache.get(key);\n if (!entry) return undefined;\n\n // Check if expired\n if (Date.now() > entry.expires) {\n this.cache.delete(key);\n return undefined;\n }\n\n return entry.value;\n }\n\n set(key: string, value: T): void {\n // Enforce max size with simple FIFO eviction\n if (this.cache.size >= this.maxSize) {\n const firstKey = this.cache.keys().next().value;\n if (firstKey) {\n this.cache.delete(firstKey);\n }\n }\n\n this.cache.set(key, {\n value,\n expires: Date.now() + this.ttl,\n });\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n has(key: string): boolean {\n return this.get(key) !== undefined;\n }\n}\n"]}
@@ -0,0 +1,211 @@
1
+ import {
2
+ SUPPORTED_LOADER_ENDPOINTS
3
+ } from "./chunk-W3K7LVPS.mjs";
4
+
5
+ // src/config/validation.ts
6
+ import { z } from "zod";
7
+ import { blockCategoryEnum, fieldSchema, getBlockDefinition } from "@riverbankcms/blocks";
8
+ var sdkThemePaletteSchema = z.record(z.string(), z.string());
9
+ var sdkThemeConfigSchema = z.object({
10
+ palette: sdkThemePaletteSchema
11
+ });
12
+ var sectionBackgroundSchema = z.object({
13
+ id: z.string(),
14
+ label: z.string(),
15
+ token: z.string()
16
+ // Reference to theme palette token
17
+ });
18
+ var sectionSpacingSchema = z.enum(["compact", "default", "spacious"]);
19
+ var containerMaxWidthSchema = z.enum(["narrow", "default", "wide", "full"]);
20
+ var containerAlignmentSchema = z.enum(["left", "center", "right"]);
21
+ var sectionOptionsSchema = z.object({
22
+ backgroundColor: z.boolean().optional(),
23
+ backgroundImage: z.boolean().optional(),
24
+ backgroundGradient: z.boolean().optional(),
25
+ spacing: z.union([
26
+ z.array(sectionSpacingSchema),
27
+ z.boolean()
28
+ ]).optional(),
29
+ textColor: z.boolean().optional()
30
+ }).optional();
31
+ var containerOptionsSchema = z.object({
32
+ maxWidth: z.union([
33
+ z.array(containerMaxWidthSchema),
34
+ z.boolean()
35
+ ]).optional(),
36
+ alignment: z.union([
37
+ z.array(containerAlignmentSchema),
38
+ z.boolean()
39
+ ]).optional()
40
+ }).optional();
41
+ var siteStyleConfigSchema = z.object({
42
+ sectionBackgrounds: z.array(sectionBackgroundSchema).optional(),
43
+ sectionOptions: sectionOptionsSchema,
44
+ containerOptions: containerOptionsSchema
45
+ }).optional();
46
+ var sdkLoaderEndpointSchema = z.enum(SUPPORTED_LOADER_ENDPOINTS);
47
+ var loaderParamBindingSchema = z.object({
48
+ $bind: z.object({
49
+ from: z.string().min(1, "Binding path is required"),
50
+ fallback: z.string().optional()
51
+ })
52
+ });
53
+ var loaderParamValueSchema = z.union([
54
+ z.string(),
55
+ z.number(),
56
+ z.boolean(),
57
+ loaderParamBindingSchema
58
+ ]);
59
+ var sdkConfigLoaderSchema = z.object({
60
+ endpoint: sdkLoaderEndpointSchema,
61
+ params: z.record(z.string(), loaderParamValueSchema),
62
+ mode: z.enum(["server", "client"]).default("server")
63
+ });
64
+ var sdkDataLoadersSchema = z.record(z.string(), sdkConfigLoaderSchema).refine(
65
+ (loaders) => Object.keys(loaders).length <= 5,
66
+ { message: "Maximum 5 data loaders per block" }
67
+ ).optional();
68
+ var fieldSelectOptionSchema = z.object({
69
+ value: z.string().min(1, "Option value is required"),
70
+ label: z.string().min(1, "Option label is required")
71
+ });
72
+ var blockFieldConfigSchema = z.object({
73
+ options: z.array(fieldSelectOptionSchema).min(1, "At least one option is required").optional()
74
+ });
75
+ var blockFieldOptionsSchema = z.record(
76
+ z.string().regex(/^(block\.|custom\.)[a-z][a-z0-9-]*$/, {
77
+ message: "Block ID must be 'block.*' or 'custom.*' format"
78
+ }),
79
+ z.record(
80
+ z.string().min(1, "Field ID is required"),
81
+ blockFieldConfigSchema
82
+ )
83
+ ).optional();
84
+ var blockFieldExtensionSchema = z.object({
85
+ fields: fieldSchema.array().min(1, "At least one field is required")
86
+ }).refine(
87
+ (data) => {
88
+ return data.fields.every((field) => {
89
+ if (!field.required) return true;
90
+ return field.defaultValue !== void 0;
91
+ });
92
+ },
93
+ {
94
+ message: "Required fields must have a defaultValue to support existing blocks"
95
+ }
96
+ );
97
+ var blockFieldExtensionsSchema = z.record(
98
+ z.string().regex(/^block\.[a-z][a-zA-Z0-9]*$/, {
99
+ message: "Block ID must be 'block.*' format (system blocks only)"
100
+ }),
101
+ blockFieldExtensionSchema
102
+ ).optional();
103
+ function validateFieldIdConflicts(blockFieldExtensions) {
104
+ if (!blockFieldExtensions) return [];
105
+ const conflicts = [];
106
+ for (const [blockId, extension] of Object.entries(blockFieldExtensions)) {
107
+ const definition = getBlockDefinition(blockId);
108
+ if (!definition) {
109
+ conflicts.push({
110
+ blockId,
111
+ fieldId: "",
112
+ message: `Unknown block type: ${blockId}`
113
+ });
114
+ continue;
115
+ }
116
+ const existingFieldIds = /* @__PURE__ */ new Set();
117
+ const collectFieldIds = (fields) => {
118
+ if (!fields) return;
119
+ for (const field of fields) {
120
+ existingFieldIds.add(field.id);
121
+ if (field.type === "group" || field.type === "modal") {
122
+ collectFieldIds(field.schema?.fields);
123
+ } else if (field.type === "repeater" && field.schema?.fields) {
124
+ collectFieldIds(field.schema.fields);
125
+ } else if (field.type === "tabGroup") {
126
+ for (const tab of field.tabs ?? []) {
127
+ collectFieldIds(tab.fields);
128
+ }
129
+ }
130
+ }
131
+ };
132
+ collectFieldIds(definition.manifest.fields);
133
+ for (const field of extension.fields) {
134
+ if (existingFieldIds.has(field.id)) {
135
+ conflicts.push({
136
+ blockId,
137
+ fieldId: field.id,
138
+ message: `Field ID "${field.id}" conflicts with existing field in ${blockId}`
139
+ });
140
+ }
141
+ }
142
+ }
143
+ return conflicts;
144
+ }
145
+ var sdkCustomBlockSchema = z.object({
146
+ // Block ID must start with 'custom.'
147
+ id: z.string().min(8).regex(/^custom\.[a-z][a-z0-9-]*$/, {
148
+ message: "Block ID must start with 'custom.' followed by lowercase letters, numbers, or hyphens"
149
+ }),
150
+ title: z.string().min(1, "Title is required"),
151
+ titleSource: z.string().optional(),
152
+ description: z.string().optional(),
153
+ category: blockCategoryEnum,
154
+ icon: z.string().optional(),
155
+ tags: z.array(z.string()).optional(),
156
+ // Reuse the exact field schema from @riverbankcms/blocks - all field types supported
157
+ fields: fieldSchema.array().min(1, "Custom blocks must have at least one field"),
158
+ // Data loaders for CMS endpoints
159
+ dataLoaders: sdkDataLoadersSchema
160
+ }).refine(
161
+ // Validate titleSource references a valid field if provided
162
+ (data) => {
163
+ if (!data.titleSource) return true;
164
+ return data.fields.some((f) => f.id === data.titleSource);
165
+ },
166
+ {
167
+ message: "titleSource must reference a valid field ID",
168
+ path: ["titleSource"]
169
+ }
170
+ );
171
+ var riverbankSiteConfigSchema = z.object({
172
+ siteId: z.string().uuid(),
173
+ theme: sdkThemeConfigSchema.optional(),
174
+ styles: siteStyleConfigSchema,
175
+ customBlocks: z.array(sdkCustomBlockSchema).max(20, "Maximum 20 custom blocks per site").refine(
176
+ // Ensure unique block IDs
177
+ (blocks) => {
178
+ const ids = blocks.map((b) => b.id);
179
+ return ids.length === new Set(ids).size;
180
+ },
181
+ { message: "Block IDs must be unique" }
182
+ ).optional(),
183
+ blockFieldOptions: blockFieldOptionsSchema,
184
+ blockFieldExtensions: blockFieldExtensionsSchema
185
+ }).strict();
186
+
187
+ export {
188
+ sdkThemePaletteSchema,
189
+ sdkThemeConfigSchema,
190
+ sectionBackgroundSchema,
191
+ sectionSpacingSchema,
192
+ containerMaxWidthSchema,
193
+ containerAlignmentSchema,
194
+ sectionOptionsSchema,
195
+ containerOptionsSchema,
196
+ siteStyleConfigSchema,
197
+ sdkLoaderEndpointSchema,
198
+ loaderParamBindingSchema,
199
+ loaderParamValueSchema,
200
+ sdkConfigLoaderSchema,
201
+ sdkDataLoadersSchema,
202
+ fieldSelectOptionSchema,
203
+ blockFieldConfigSchema,
204
+ blockFieldOptionsSchema,
205
+ blockFieldExtensionSchema,
206
+ blockFieldExtensionsSchema,
207
+ validateFieldIdConflicts,
208
+ sdkCustomBlockSchema,
209
+ riverbankSiteConfigSchema
210
+ };
211
+ //# sourceMappingURL=chunk-4Z5FBFRL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/config/validation.ts"],"sourcesContent":["/**\n * Zod validation schemas for SDK site configuration.\n *\n * These schemas are used to validate configuration fetched from\n * SDK sites before storing in the database.\n */\n\nimport { z } from 'zod';\nimport { blockCategoryEnum, fieldSchema, getBlockDefinition, type SdkCustomBlock, type FieldDefinition } from '@riverbankcms/blocks';\nimport type { RiverbankSiteConfig, BlockFieldOptionsMap, BlockFieldExtensionsMap, BlockFieldExtension } from './types';\n\n/**\n * Schema for SDK theme palette.\n * Maps token names to CSS color values.\n */\nexport const sdkThemePaletteSchema = z.record(z.string(), z.string());\n\n/**\n * Schema for SDK theme configuration.\n */\nexport const sdkThemeConfigSchema = z.object({\n palette: sdkThemePaletteSchema,\n});\n\n/**\n * Schema for section background color options.\n */\nexport const sectionBackgroundSchema = z.object({\n id: z.string(),\n label: z.string(),\n token: z.string(), // Reference to theme palette token\n});\n\n/**\n * Schema for section spacing values.\n */\nexport const sectionSpacingSchema = z.enum(['compact', 'default', 'spacious']);\n\n/**\n * Schema for container max-width values.\n */\nexport const containerMaxWidthSchema = z.enum(['narrow', 'default', 'wide', 'full']);\n\n/**\n * Schema for container alignment values.\n */\nexport const containerAlignmentSchema = z.enum(['left', 'center', 'right']);\n\n/**\n * Schema for section options configuration.\n */\nexport const sectionOptionsSchema = z.object({\n backgroundColor: z.boolean().optional(),\n backgroundImage: z.boolean().optional(),\n backgroundGradient: z.boolean().optional(),\n spacing: z.union([\n z.array(sectionSpacingSchema),\n z.boolean(),\n ]).optional(),\n textColor: z.boolean().optional(),\n}).optional();\n\n/**\n * Schema for container options configuration.\n */\nexport const containerOptionsSchema = z.object({\n maxWidth: z.union([\n z.array(containerMaxWidthSchema),\n z.boolean(),\n ]).optional(),\n alignment: z.union([\n z.array(containerAlignmentSchema),\n z.boolean(),\n ]).optional(),\n}).optional();\n\n/**\n * Schema for site style configuration.\n */\nexport const siteStyleConfigSchema = z.object({\n sectionBackgrounds: z.array(sectionBackgroundSchema).optional(),\n sectionOptions: sectionOptionsSchema,\n containerOptions: containerOptionsSchema,\n}).optional();\n\n// ============================================================================\n// Data Loader Schemas\n// ============================================================================\n\nimport { SUPPORTED_LOADER_ENDPOINTS } from '../data/prefetchBlockData';\n\n/**\n * Whitelisted endpoints for SDK data loaders.\n *\n * These are the only CMS endpoints that can be called from config-based loaders.\n * This ensures SDK sites can only access safe, read-only public endpoints.\n *\n * Derived from SUPPORTED_LOADER_ENDPOINTS - the single source of truth.\n */\nexport const sdkLoaderEndpointSchema = z.enum(SUPPORTED_LOADER_ENDPOINTS);\n\n/**\n * A binding expression for dynamic loader params.\n *\n * @example\n * ```typescript\n * { $bind: { from: 'content.categoryId' } }\n * { $bind: { from: '$root.siteId' } }\n * { $bind: { from: 'content.limit', fallback: '10' } }\n * ```\n */\nexport const loaderParamBindingSchema = z.object({\n $bind: z.object({\n from: z.string().min(1, \"Binding path is required\"),\n fallback: z.string().optional(),\n }),\n});\n\n/**\n * A loader param value can be static or a binding expression.\n */\nexport const loaderParamValueSchema = z.union([\n z.string(),\n z.number(),\n z.boolean(),\n loaderParamBindingSchema,\n]);\n\n/**\n * Schema for config-based data loader.\n *\n * Config loaders execute server-side during loadPage() and are\n * restricted to whitelisted CMS endpoints.\n */\nexport const sdkConfigLoaderSchema = z.object({\n endpoint: sdkLoaderEndpointSchema,\n params: z.record(z.string(), loaderParamValueSchema),\n mode: z.enum(['server', 'client']).default('server'),\n});\n\n/**\n * Schema for the dataLoaders field on custom blocks.\n * Validates the loader configuration and limits the number of loaders.\n */\nexport const sdkDataLoadersSchema = z.record(z.string(), sdkConfigLoaderSchema)\n .refine(\n (loaders) => Object.keys(loaders).length <= 5,\n { message: \"Maximum 5 data loaders per block\" }\n )\n .optional();\n\n// ============================================================================\n// Custom Block Schema\n// ============================================================================\n\n/**\n * Schema for field select option.\n */\nexport const fieldSelectOptionSchema = z.object({\n value: z.string().min(1, \"Option value is required\"),\n label: z.string().min(1, \"Option label is required\"),\n});\n\n/**\n * Schema for per-field configuration within a block.\n */\nexport const blockFieldConfigSchema = z.object({\n options: z.array(fieldSelectOptionSchema).min(1, \"At least one option is required\").optional(),\n});\n\n/**\n * Schema for per-block field options.\n *\n * Block IDs must be either 'block.*' (system blocks) or 'custom.*' (custom blocks).\n * Field IDs can be any valid identifier string.\n */\nexport const blockFieldOptionsSchema: z.ZodType<BlockFieldOptionsMap> = z.record(\n z.string().regex(/^(block\\.|custom\\.)[a-z][a-z0-9-]*$/, {\n message: \"Block ID must be 'block.*' or 'custom.*' format\",\n }),\n z.record(\n z.string().min(1, \"Field ID is required\"),\n blockFieldConfigSchema\n )\n).optional() as z.ZodType<BlockFieldOptionsMap>;\n\n// ============================================================================\n// Block Field Extensions Schema\n// ============================================================================\n\n/**\n * Schema for block field extension configuration.\n *\n * Validates additional fields to be appended to a built-in block.\n * Includes refinement to ensure required fields have defaultValue.\n *\n * Note: Explicit type annotation required due to recursive fieldSchema complexity.\n */\nexport const blockFieldExtensionSchema: z.ZodType<BlockFieldExtension> = z.object({\n fields: fieldSchema.array().min(1, \"At least one field is required\"),\n}).refine(\n (data) => {\n // All required fields must have a defaultValue\n return data.fields.every((field: FieldDefinition) => {\n if (!field.required) return true;\n return field.defaultValue !== undefined;\n });\n },\n {\n message: \"Required fields must have a defaultValue to support existing blocks\",\n }\n) as z.ZodType<BlockFieldExtension>;\n\n/**\n * Schema for block field extensions map.\n *\n * Block IDs must be system blocks (e.g., 'block.bodyText', 'block.hero').\n * Custom blocks ('custom.*') should define their fields directly, not via extensions.\n */\nexport const blockFieldExtensionsSchema: z.ZodType<BlockFieldExtensionsMap | undefined> = z.record(\n z.string().regex(/^block\\.[a-z][a-zA-Z0-9]*$/, {\n message: \"Block ID must be 'block.*' format (system blocks only)\",\n }),\n blockFieldExtensionSchema\n).optional() as z.ZodType<BlockFieldExtensionsMap | undefined>;\n\n/**\n * Validates that extended field IDs don't conflict with existing block fields.\n *\n * This validation should be called during config push to provide clear error messages.\n * Returns an array of conflict errors, or empty array if valid.\n *\n * @example\n * ```typescript\n * const conflicts = validateFieldIdConflicts(config.blockFieldExtensions);\n * if (conflicts.length > 0) {\n * throw new Error(conflicts.map(c => c.message).join('\\n'));\n * }\n * ```\n */\nexport function validateFieldIdConflicts(\n blockFieldExtensions?: BlockFieldExtensionsMap | null\n): { blockId: string; fieldId: string; message: string }[] {\n if (!blockFieldExtensions) return [];\n\n const conflicts: { blockId: string; fieldId: string; message: string }[] = [];\n\n for (const [blockId, extension] of Object.entries(blockFieldExtensions)) {\n const definition = getBlockDefinition(blockId);\n if (!definition) {\n conflicts.push({\n blockId,\n fieldId: '',\n message: `Unknown block type: ${blockId}`,\n });\n continue;\n }\n\n // Get all existing field IDs from the block manifest\n const existingFieldIds = new Set<string>();\n const collectFieldIds = (fields: FieldDefinition[] | undefined) => {\n if (!fields) return;\n for (const field of fields) {\n existingFieldIds.add(field.id);\n // Also collect nested field IDs from groups, modals, repeaters, tab groups\n if (field.type === 'group' || field.type === 'modal') {\n collectFieldIds(field.schema?.fields);\n } else if (field.type === 'repeater' && field.schema?.fields) {\n collectFieldIds(field.schema.fields);\n } else if (field.type === 'tabGroup') {\n for (const tab of field.tabs ?? []) {\n collectFieldIds(tab.fields);\n }\n }\n }\n };\n collectFieldIds(definition.manifest.fields);\n\n // Check for conflicts\n for (const field of extension.fields) {\n if (existingFieldIds.has(field.id)) {\n conflicts.push({\n blockId,\n fieldId: field.id,\n message: `Field ID \"${field.id}\" conflicts with existing field in ${blockId}`,\n });\n }\n }\n }\n\n return conflicts;\n}\n\n/**\n * Schema for SDK custom block definitions.\n *\n * Validates custom blocks defined in riverbank.config.ts.\n * Reuses fieldSchema from @riverbankcms/blocks for field validation.\n *\n * Note: Explicit type annotation required due to recursive fieldSchema complexity.\n */\nexport const sdkCustomBlockSchema: z.ZodType<SdkCustomBlock> = z.object({\n // Block ID must start with 'custom.'\n id: z.string()\n .min(8) // 'custom.' + at least 1 char\n .regex(/^custom\\.[a-z][a-z0-9-]*$/, {\n message: \"Block ID must start with 'custom.' followed by lowercase letters, numbers, or hyphens\",\n }),\n title: z.string().min(1, \"Title is required\"),\n titleSource: z.string().optional(),\n description: z.string().optional(),\n category: blockCategoryEnum,\n icon: z.string().optional(),\n tags: z.array(z.string()).optional(),\n // Reuse the exact field schema from @riverbankcms/blocks - all field types supported\n fields: fieldSchema.array().min(1, \"Custom blocks must have at least one field\"),\n // Data loaders for CMS endpoints\n dataLoaders: sdkDataLoadersSchema,\n}).refine(\n // Validate titleSource references a valid field if provided\n (data) => {\n if (!data.titleSource) return true;\n return data.fields.some(f => f.id === data.titleSource);\n },\n {\n message: \"titleSource must reference a valid field ID\",\n path: [\"titleSource\"],\n }\n) as z.ZodType<SdkCustomBlock>;\n\n/**\n * Schema for the complete SDK site configuration.\n *\n * Use this schema to validate configuration fetched from SDK sites\n * before storing in the database.\n *\n * @example\n * ```typescript\n * import { riverbankSiteConfigSchema } from '@riverbankcms/sdk/config/validation';\n *\n * const rawConfig = await response.json();\n * const config = riverbankSiteConfigSchema.parse(rawConfig);\n * ```\n */\nexport const riverbankSiteConfigSchema: z.ZodType<RiverbankSiteConfig> = z.object({\n siteId: z.string().uuid(),\n theme: sdkThemeConfigSchema.optional(),\n styles: siteStyleConfigSchema,\n customBlocks: z.array(sdkCustomBlockSchema)\n .max(20, \"Maximum 20 custom blocks per site\")\n .refine(\n // Ensure unique block IDs\n (blocks) => {\n const ids = blocks.map(b => b.id);\n return ids.length === new Set(ids).size;\n },\n { message: \"Block IDs must be unique\" }\n )\n .optional(),\n blockFieldOptions: blockFieldOptionsSchema,\n blockFieldExtensions: blockFieldExtensionsSchema,\n}).strict() as z.ZodType<RiverbankSiteConfig>;\n\n/**\n * Type inferred from the validation schema.\n * This should match the RiverbankSiteConfig type from ./types.ts\n */\nexport type ValidatedRiverbankSiteConfig = z.infer<typeof riverbankSiteConfigSchema>;\n\n/**\n * Type for a validated SDK custom block.\n */\nexport type ValidatedSdkCustomBlock = z.infer<typeof sdkCustomBlockSchema>;\n\n// ============================================================================\n// Compile-time type assertions\n//\n// These assertions ensure the Zod schemas stay in sync with the TypeScript types.\n// If the schema output diverges from the expected type, TypeScript will error here.\n// ============================================================================\n\n/** Asserts sdkCustomBlockSchema output matches SdkCustomBlock */\ntype _AssertSdkCustomBlockSchema = z.infer<typeof sdkCustomBlockSchema> extends SdkCustomBlock\n ? SdkCustomBlock extends z.infer<typeof sdkCustomBlockSchema>\n ? true\n : never\n : never;\n\n/** Asserts riverbankSiteConfigSchema output matches RiverbankSiteConfig */\ntype _AssertRiverbankSiteConfigSchema = z.infer<typeof riverbankSiteConfigSchema> extends RiverbankSiteConfig\n ? RiverbankSiteConfig extends z.infer<typeof riverbankSiteConfigSchema>\n ? true\n : never\n : never;\n\n// These assignments will fail to compile if the types don't match\nconst _checkSdkCustomBlock: _AssertSdkCustomBlockSchema = true;\nconst _checkRiverbankSiteConfig: _AssertRiverbankSiteConfigSchema = true;\n\n// Prevent unused variable warnings\nvoid _checkSdkCustomBlock;\nvoid _checkRiverbankSiteConfig;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,86 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+ var _chunkYXDDFG3Njs = require('./chunk-YXDDFG3N.js');
5
+
6
+
7
+ var _chunkQQ6U4QX6js = require('./chunk-QQ6U4QX6.js');
8
+
9
+ // src/rendering/helpers/loadPage.ts
10
+ async function loadPage(params) {
11
+ const { client, siteId, path, pageId, preview = false, dataLoaderOverrides } = params;
12
+ const [site, pageResponse] = await Promise.all([
13
+ client.getSite({ id: siteId }),
14
+ client.getPage({ siteId, path, preview })
15
+ ]);
16
+ if ("entry" in pageResponse) {
17
+ throw new Error(
18
+ "This path resolves to a content entry, not a page. Use loadContent() instead, which handles both pages and entries. For entries, loadContent() returns the raw entry data for custom rendering."
19
+ );
20
+ }
21
+ const { page: pageData } = pageResponse;
22
+ const blocks = pageData.blocks.map((block) => {
23
+ if (!block || typeof block !== "object") {
24
+ throw new Error("Invalid block format in API response");
25
+ }
26
+ if (typeof block.id !== "string" && block.id !== null) {
27
+ throw new Error(`Invalid block id: expected string or null, got ${typeof block.id}`);
28
+ }
29
+ if (typeof block.kind !== "string") {
30
+ throw new Error(`Invalid block kind: expected string, got ${typeof block.kind}`);
31
+ }
32
+ if (typeof block.purpose !== "string") {
33
+ throw new Error(`Invalid block purpose: expected string, got ${typeof block.purpose}`);
34
+ }
35
+ const typedBlock = block;
36
+ return {
37
+ id: typedBlock.id,
38
+ kind: typedBlock.kind,
39
+ purpose: typedBlock.purpose,
40
+ // Include content for PageRenderer's getRenderableContent()
41
+ content: _nullishCoalesce(typedBlock.content, () => ( {})),
42
+ // Include draftContent if available (for preview mode)
43
+ draftContent: _nullishCoalesce(_optionalChain([typedBlock, 'access', _ => _.draftContent, 'optionalAccess', _2 => _2.data]), () => ( null))
44
+ };
45
+ });
46
+ const pageOutline = {
47
+ name: pageData.name,
48
+ path: pageData.path,
49
+ purpose: pageData.purpose,
50
+ blocks
51
+ };
52
+ const prefetchContext = {
53
+ siteId,
54
+ pageId: _nullishCoalesce(pageId, () => ( pageData.id)),
55
+ previewStage: preview ? "preview" : "published"
56
+ };
57
+ const configData = await _chunkQQ6U4QX6js.prefetchBlockData.call(void 0,
58
+ pageOutline,
59
+ prefetchContext,
60
+ client,
61
+ {
62
+ // Pass custom blocks so their config-based loaders are discovered
63
+ customBlocks: _optionalChain([site, 'access', _3 => _3.sdkConfig, 'optionalAccess', _4 => _4.customBlocks])
64
+ }
65
+ );
66
+ let resolvedData = configData;
67
+ if (dataLoaderOverrides && Object.keys(dataLoaderOverrides).length > 0) {
68
+ const codeData = await _chunkYXDDFG3Njs.executeCodeLoaders.call(void 0, pageOutline, prefetchContext, dataLoaderOverrides);
69
+ resolvedData = _chunkYXDDFG3Njs.mergeLoaderResults.call(void 0, configData, codeData);
70
+ }
71
+ return {
72
+ page: pageOutline,
73
+ theme: site.theme,
74
+ sdkConfig: _nullishCoalesce(site.sdkConfig, () => ( null)),
75
+ siteId,
76
+ resolvedData
77
+ // Note: routeMap is optional and can be built from site data if needed for internal links.
78
+ // Consumers can construct it from site.pages and pass explicitly via Page component props.
79
+ // Example: const routeMap = site.pages.reduce((map, p) => ({ ...map, [p.id]: p.path }), {});
80
+ };
81
+ }
82
+
83
+
84
+
85
+ exports.loadPage = loadPage;
86
+ //# sourceMappingURL=chunk-ADREPXFU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-ADREPXFU.js","../../src/rendering/helpers/loadPage.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACA;ACqHA,MAAA,SAAsB,QAAA,CAAS,MAAA,EAAiD;AAC9E,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,MAAA,EAAQ,QAAA,EAAU,KAAA,EAAO,oBAAoB,EAAA,EAAI,MAAA;AAG/E,EAAA,MAAM,CAAC,IAAA,EAAM,YAAY,EAAA,EAAI,MAAM,OAAA,CAAQ,GAAA,CAAI;AAAA,IAC7C,MAAA,CAAO,OAAA,CAAQ,EAAE,EAAA,EAAI,OAAO,CAAC,CAAA;AAAA,IAC7B,MAAA,CAAO,OAAA,CAAQ,EAAE,MAAA,EAAQ,IAAA,EAAM,QAAQ,CAAC;AAAA,EAC1C,CAAC,CAAA;AAGD,EAAA,GAAA,CAAI,QAAA,GAAW,YAAA,EAAc;AAC3B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,IAGF,CAAA;AAAA,EACF;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,SAAS,EAAA,EAAI,YAAA;AAI3B,EAAA,MAAM,OAAA,EAAS,QAAA,CAAS,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,EAAA,GAAU;AAC5C,IAAA,GAAA,CAAI,CAAC,MAAA,GAAS,OAAO,MAAA,IAAU,QAAA,EAAU;AACvC,MAAA,MAAM,IAAI,KAAA,CAAM,sCAAsC,CAAA;AAAA,IACxD;AACA,IAAA,GAAA,CAAI,OAAO,KAAA,CAAM,GAAA,IAAO,SAAA,GAAY,KAAA,CAAM,GAAA,IAAO,IAAA,EAAM;AACrD,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,+CAAA,EAAkD,OAAO,KAAA,CAAM,EAAE,CAAA,CAAA;AACnF,IAAA;AACoC,IAAA;AAC6C,MAAA;AACjF,IAAA;AACuC,IAAA;AACuC,MAAA;AAC9E,IAAA;AAKmB,IAAA;AAQZ,IAAA;AACU,MAAA;AACE,MAAA;AACG,MAAA;AAAA;AAEY,MAAA;AAAA;AAEe,MAAA;AACjD,IAAA;AACD,EAAA;AAEmB,EAAA;AACH,IAAA;AACA,IAAA;AACG,IAAA;AAClB,IAAA;AACF,EAAA;AAGmG,EAAA;AACjG,IAAA;AAC2B,IAAA;AACS,IAAA;AACtC,EAAA;AAGyB,EAAA;AACvB,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AAAA;AAEgC,MAAA;AAChC,IAAA;AACF,EAAA;AAGmB,EAAA;AACqD,EAAA;AACE,IAAA;AAClB,IAAA;AACxD,EAAA;AAEO,EAAA;AACC,IAAA;AACM,IAAA;AACiB,IAAA;AAC7B,IAAA;AACA,IAAA;AAAA;AAAA;AAAA;AAIF,EAAA;AACF;ADhJwF;AACA;AACA;AACA","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/chunk-ADREPXFU.js","sourcesContent":[null,"/**\n * Server-side helper to fetch all data needed for <Page> component.\n *\n * Use this in server components, getServerSideProps, or API routes.\n */\n\nimport type { RiverbankClient, SiteResponse } from '../../client/types';\nimport type { PageProps } from '../components/Page';\nimport { prefetchBlockData } from '../../data/prefetchBlockData';\nimport { executeCodeLoaders, mergeLoaderResults } from '../../data/executeCodeLoaders';\nimport type { DataLoaderOverrides } from '../../data/types';\n\n/**\n * SDK config from API response (without siteId which is stripped at storage).\n * This is the runtime representation - for defining configs, use RiverbankSiteConfig.\n */\nexport type RuntimeSdkConfig = NonNullable<SiteResponse['sdkConfig']>;\n\nexport type LoadPageParams = {\n client: RiverbankClient;\n siteId: string;\n path: string;\n pageId?: string;\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * This affects both the page structure and block data loaders.\n * Requires API key with site access.\n *\n * @default false\n */\n preview?: boolean;\n /**\n * Code-based data loaders for custom blocks.\n *\n * Use this to fetch data from external APIs (not just whitelisted CMS endpoints).\n * Keys are block kinds (e.g., 'custom.featured-products').\n *\n * Config-based loaders (defined in riverbank.config.ts) run first.\n * Code loaders run second and take precedence on key conflicts.\n *\n * @example\n * ```typescript\n * const pageData = await loadPage({\n * client,\n * siteId: 'site-123',\n * path: '/',\n * dataLoaderOverrides: {\n * 'custom.featured-products': {\n * products: async (ctx) => {\n * const res = await fetch(`https://api.shop.com/products?category=${ctx.content.categoryId}`);\n * return res.json();\n * },\n * },\n * },\n * });\n * ```\n */\n dataLoaderOverrides?: DataLoaderOverrides;\n};\n\nexport type LoadPageResult = Omit<PageProps, 'registry' | 'wrapBlock' | 'usePlaceholders' | 'blockOverrides'> & {\n /**\n * SDK site configuration, if available.\n * Contains SDK-defined theme palette, section backgrounds, and style options.\n */\n sdkConfig: RuntimeSdkConfig | null;\n};\n\n/**\n * Server-side helper to fetch all data needed for <Page> component.\n *\n * Fetches site data, page data, and prefetches block data loaders in parallel.\n *\n * @example Next.js App Router (published content)\n * ```tsx\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { loadPage, Page } from '@riverbankcms/sdk/rendering';\n *\n * const client = createRiverbankClient({\n * apiKey: process.env.RIVERBANK_API_KEY!,\n * baseUrl: process.env.NEXT_PUBLIC_DASHBOARD_URL + '/api',\n * });\n *\n * export default async function PageRoute({ params }) {\n * const pageData = await loadPage({\n * client,\n * siteId: 'site-123',\n * path: `/${params.slug || ''}`,\n * });\n *\n * return <Page {...pageData} />;\n * }\n * ```\n *\n * @example Next.js App Router (preview/draft content)\n * ```tsx\n * export default async function PreviewRoute({ params, searchParams }) {\n * const pageData = await loadPage({\n * client,\n * siteId: searchParams.siteId,\n * path: `/${params.slug || ''}`,\n * preview: true, // Fetch draft content\n * });\n *\n * return <Page {...pageData} />;\n * }\n * ```\n *\n * @example Next.js Pages Router (getServerSideProps)\n * ```tsx\n * export async function getServerSideProps({ params }) {\n * const pageData = await loadPage({\n * client,\n * siteId: 'site-123',\n * path: `/${params.slug || ''}`,\n * });\n *\n * return { props: pageData };\n * }\n *\n * export default function PageRoute(props) {\n * return <Page {...props} />;\n * }\n * ```\n */\nexport async function loadPage(params: LoadPageParams): Promise<LoadPageResult> {\n const { client, siteId, path, pageId, preview = false, dataLoaderOverrides } = params;\n\n // Fetch site and page data in parallel\n const [site, pageResponse] = await Promise.all([\n client.getSite({ id: siteId }),\n client.getPage({ siteId, path, preview }),\n ]);\n\n // Extract page data (getContentByPath can return page or entry)\n if ('entry' in pageResponse) {\n throw new Error(\n 'This path resolves to a content entry, not a page. ' +\n 'Use loadContent() instead, which handles both pages and entries. ' +\n 'For entries, loadContent() returns the raw entry data for custom rendering.'\n );\n }\n\n const { page: pageData } = pageResponse;\n\n // Convert API response blocks to PageOutline format with content\n // API returns blocks with full content - PageRenderer needs the content field for rendering\n const blocks = pageData.blocks.map((block) => {\n if (!block || typeof block !== 'object') {\n throw new Error('Invalid block format in API response');\n }\n if (typeof block.id !== 'string' && block.id !== null) {\n throw new Error(`Invalid block id: expected string or null, got ${typeof block.id}`);\n }\n if (typeof block.kind !== 'string') {\n throw new Error(`Invalid block kind: expected string, got ${typeof block.kind}`);\n }\n if (typeof block.purpose !== 'string') {\n throw new Error(`Invalid block purpose: expected string, got ${typeof block.purpose}`);\n }\n\n // Include content for rendering\n // API provides `content` (active content for the requested stage)\n // and optionally `draftContent` for preview mode\n const typedBlock = block as {\n id: string | null;\n kind: string;\n purpose: string;\n content?: Record<string, unknown>;\n draftContent?: { data: Record<string, unknown> } | null;\n };\n\n return {\n id: typedBlock.id,\n kind: typedBlock.kind,\n purpose: typedBlock.purpose,\n // Include content for PageRenderer's getRenderableContent()\n content: typedBlock.content ?? {},\n // Include draftContent if available (for preview mode)\n draftContent: typedBlock.draftContent?.data ?? null,\n };\n });\n\n const pageOutline = {\n name: pageData.name,\n path: pageData.path,\n purpose: pageData.purpose,\n blocks,\n };\n\n // Build prefetch context\n const prefetchContext: { siteId: string; pageId: string; previewStage: 'published' | 'preview' } = {\n siteId,\n pageId: pageId ?? pageData.id,\n previewStage: preview ? 'preview' : 'published',\n };\n\n // Prefetch block data loaders (config-based loaders for CMS endpoints)\n const configData = await prefetchBlockData(\n pageOutline,\n prefetchContext,\n client,\n {\n // Pass custom blocks so their config-based loaders are discovered\n customBlocks: site.sdkConfig?.customBlocks,\n }\n );\n\n // Execute code-based loaders (external APIs) and merge results\n let resolvedData = configData;\n if (dataLoaderOverrides && Object.keys(dataLoaderOverrides).length > 0) {\n const codeData = await executeCodeLoaders(pageOutline, prefetchContext, dataLoaderOverrides);\n resolvedData = mergeLoaderResults(configData, codeData);\n }\n\n return {\n page: pageOutline,\n theme: site.theme,\n sdkConfig: site.sdkConfig ?? null,\n siteId,\n resolvedData,\n // Note: routeMap is optional and can be built from site data if needed for internal links.\n // Consumers can construct it from site.pages and pass explicitly via Page component props.\n // Example: const routeMap = site.pages.reduce((map, p) => ({ ...map, [p.id]: p.path }), {});\n };\n}\n"]}