@riverbankcms/sdk 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +73 -0
  2. package/dist/cli/index.js +46 -5
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/client/client.d.mts +3 -3
  5. package/dist/client/client.d.ts +3 -3
  6. package/dist/client/client.js +80 -170
  7. package/dist/client/client.js.map +1 -1
  8. package/dist/client/client.mjs +80 -170
  9. package/dist/client/client.mjs.map +1 -1
  10. package/dist/client/hooks.d.mts +3 -3
  11. package/dist/client/hooks.d.ts +3 -3
  12. package/dist/client/rendering/client.d.mts +1 -1
  13. package/dist/client/rendering/client.d.ts +1 -1
  14. package/dist/client/rendering/client.js +80 -142
  15. package/dist/client/rendering/client.js.map +1 -1
  16. package/dist/client/rendering/client.mjs +80 -142
  17. package/dist/client/rendering/client.mjs.map +1 -1
  18. package/dist/client/resolver-CYyfzTQ9.d.mts +61 -0
  19. package/dist/client/resolver-CYyfzTQ9.d.ts +61 -0
  20. package/dist/client/usePage-BC8Q2E3t.d.mts +6431 -0
  21. package/dist/client/usePage-CHEybPMD.d.ts +6429 -0
  22. package/dist/client/usePage-D4fxZbRR.d.mts +6429 -0
  23. package/dist/client/usePage-DpRNZUtP.d.ts +6431 -0
  24. package/dist/server/{Layout-B_zUr9ci.d.mts → Layout-ByUnm35V.d.mts} +1 -1
  25. package/dist/server/{Layout-CHG77dhK.d.ts → Layout-kRv5sU81.d.ts} +1 -1
  26. package/dist/server/{chunk-ZIM53VP6.js → chunk-6JBKKV3G.js} +27 -4
  27. package/dist/server/chunk-6JBKKV3G.js.map +1 -0
  28. package/dist/server/{chunk-SFQ7VF3G.mjs → chunk-7BOIO2S7.mjs} +7 -5
  29. package/dist/server/{chunk-SFQ7VF3G.mjs.map → chunk-7BOIO2S7.mjs.map} +1 -1
  30. package/dist/server/{chunk-M5KTLZTD.mjs → chunk-A2FZMRDW.mjs} +3 -2
  31. package/dist/server/chunk-A2FZMRDW.mjs.map +1 -0
  32. package/dist/server/{chunk-P6CDRJN3.js → chunk-BLKVTULP.js} +13 -11
  33. package/dist/server/chunk-BLKVTULP.js.map +1 -0
  34. package/dist/server/{chunk-BOHTTHY5.mjs → chunk-I6K5REFT.mjs} +27 -4
  35. package/dist/server/chunk-I6K5REFT.mjs.map +1 -0
  36. package/dist/server/{chunk-BUCJWG6G.js → chunk-NW5KHH4A.js} +5 -5
  37. package/dist/server/{chunk-BUCJWG6G.js.map → chunk-NW5KHH4A.js.map} +1 -1
  38. package/dist/server/{chunk-XK2YIISA.mjs → chunk-SPXMMX3C.mjs} +2 -2
  39. package/dist/server/{chunk-FPYK6527.js → chunk-SWPHIUVE.js} +7 -6
  40. package/dist/server/chunk-SWPHIUVE.js.map +1 -0
  41. package/dist/server/{chunk-IT5ICP43.js → chunk-TKMA6D6U.js} +139 -229
  42. package/dist/server/chunk-TKMA6D6U.js.map +1 -0
  43. package/dist/server/{chunk-NKXS4TBK.mjs → chunk-TNRADRPH.mjs} +79 -169
  44. package/dist/server/chunk-TNRADRPH.mjs.map +1 -0
  45. package/dist/server/{chunk-G4CKM4EN.js → chunk-Y7347JMZ.js} +3 -2
  46. package/dist/server/chunk-Y7347JMZ.js.map +1 -0
  47. package/dist/server/{chunk-VVFYHAUD.mjs → chunk-ZEAJW6T3.mjs} +5 -4
  48. package/dist/server/chunk-ZEAJW6T3.mjs.map +1 -0
  49. package/dist/server/{components-Ci5nlyUj.d.mts → components-CY8jDQjv.d.mts} +20 -12
  50. package/dist/server/{components-BYxloYJm.d.ts → components-D1Z2mSDr.d.ts} +20 -12
  51. package/dist/server/components.d.mts +6 -6
  52. package/dist/server/components.d.ts +6 -6
  53. package/dist/server/components.js +3 -3
  54. package/dist/server/components.mjs +2 -2
  55. package/dist/server/config-validation.d.mts +2 -2
  56. package/dist/server/config-validation.d.ts +2 -2
  57. package/dist/server/config-validation.js +3 -3
  58. package/dist/server/config-validation.mjs +2 -2
  59. package/dist/server/config.d.mts +3 -3
  60. package/dist/server/config.d.ts +3 -3
  61. package/dist/server/config.js +3 -3
  62. package/dist/server/config.mjs +2 -2
  63. package/dist/server/data.d.mts +7 -5
  64. package/dist/server/data.d.ts +7 -5
  65. package/dist/server/data.js +2 -2
  66. package/dist/server/data.mjs +1 -1
  67. package/dist/server/{index-DbSfrRA0.d.ts → index-DCIz9Ptv.d.ts} +1 -1
  68. package/dist/server/{index-Dj7VKH34.d.mts → index-DFQwtj3J.d.mts} +1 -1
  69. package/dist/server/index.d.mts +4 -4
  70. package/dist/server/index.d.ts +4 -4
  71. package/dist/server/{loadContent-Czu7xTOU.d.mts → loadContent-CWuE8FCx.d.mts} +4 -4
  72. package/dist/server/{loadContent-BqQ-VPMW.d.ts → loadContent-DynBuR5f.d.ts} +4 -4
  73. package/dist/server/{loadPage-Dw57_n5N.d.mts → loadPage-B8RmlYgV.d.mts} +80 -28
  74. package/dist/server/{loadPage-BElEkA_J.d.ts → loadPage-BTkKpizX.d.ts} +80 -28
  75. package/dist/server/loadPage-DUHBXDEW.js +11 -0
  76. package/dist/server/{loadPage-E3ZC6NHB.js.map → loadPage-DUHBXDEW.js.map} +1 -1
  77. package/dist/server/{loadPage-E7L7NMR3.mjs → loadPage-LYVKY3WZ.mjs} +3 -3
  78. package/dist/server/metadata.d.mts +4 -4
  79. package/dist/server/metadata.d.ts +4 -4
  80. package/dist/server/navigation.d.mts +2 -2
  81. package/dist/server/navigation.d.ts +2 -2
  82. package/dist/server/rendering/server.d.mts +5 -5
  83. package/dist/server/rendering/server.d.ts +5 -5
  84. package/dist/server/rendering/server.js +4 -4
  85. package/dist/server/rendering/server.mjs +3 -3
  86. package/dist/server/rendering.d.mts +8 -8
  87. package/dist/server/rendering.d.ts +8 -8
  88. package/dist/server/rendering.js +6 -6
  89. package/dist/server/rendering.mjs +5 -5
  90. package/dist/server/routing.d.mts +79 -6
  91. package/dist/server/routing.d.ts +79 -6
  92. package/dist/server/routing.js +57 -3
  93. package/dist/server/routing.js.map +1 -1
  94. package/dist/server/routing.mjs +55 -1
  95. package/dist/server/routing.mjs.map +1 -1
  96. package/dist/server/server.d.mts +6 -6
  97. package/dist/server/server.d.ts +6 -6
  98. package/dist/server/server.js +3 -3
  99. package/dist/server/server.mjs +2 -2
  100. package/dist/server/theme-bridge.js +7 -7
  101. package/dist/server/theme-bridge.mjs +1 -1
  102. package/dist/server/{types-5XdVD2J1.d.ts → types-BiRZnxDx.d.ts} +17 -6
  103. package/dist/server/{types-CMqVHYLG.d.ts → types-CL916r6x.d.ts} +23 -1
  104. package/dist/server/{types-BuZJWVmj.d.mts → types-CbagRQ_7.d.mts} +15 -0
  105. package/dist/server/{types-BA-J9K8r.d.mts → types-CdrJqlKx.d.mts} +17 -6
  106. package/dist/server/{types-BC9eB2KH.d.mts → types-DkKEctWn.d.mts} +1 -1
  107. package/dist/server/{types-DSFvXKhO.d.ts → types-DuQCNVV0.d.ts} +15 -0
  108. package/dist/server/{types-CAnC529E.d.ts → types-oCM-fw4O.d.ts} +1 -1
  109. package/dist/server/{types-CYfHxUhe.d.mts → types-txWsSxN7.d.mts} +23 -1
  110. package/dist/server/{validation-C7W2Fe0i.d.ts → validation-CoU8uAiu.d.ts} +1 -1
  111. package/dist/server/{validation-hg1sqhrt.d.mts → validation-DzvDwwRo.d.mts} +1 -1
  112. package/package.json +1 -1
  113. package/dist/server/chunk-BOHTTHY5.mjs.map +0 -1
  114. package/dist/server/chunk-FPYK6527.js.map +0 -1
  115. package/dist/server/chunk-G4CKM4EN.js.map +0 -1
  116. package/dist/server/chunk-IT5ICP43.js.map +0 -1
  117. package/dist/server/chunk-M5KTLZTD.mjs.map +0 -1
  118. package/dist/server/chunk-NKXS4TBK.mjs.map +0 -1
  119. package/dist/server/chunk-P6CDRJN3.js.map +0 -1
  120. package/dist/server/chunk-VVFYHAUD.mjs.map +0 -1
  121. package/dist/server/chunk-ZIM53VP6.js.map +0 -1
  122. package/dist/server/loadPage-E3ZC6NHB.js +0 -11
  123. /package/dist/server/{chunk-XK2YIISA.mjs.map → chunk-SPXMMX3C.mjs.map} +0 -0
  124. /package/dist/server/{loadPage-E7L7NMR3.mjs.map → loadPage-LYVKY3WZ.mjs.map} +0 -0
@@ -1,14 +1,15 @@
1
- import { R as RiverbankClient } from './types-BC9eB2KH.mjs';
2
- import { a as LoadPageResult } from './loadPage-Dw57_n5N.mjs';
3
- import './types-BA-J9K8r.mjs';
4
- import '@riverbankcms/ai';
1
+ import { R as RiverbankClient } from './types-DkKEctWn.mjs';
2
+ import { a as LoadPageResult } from './loadPage-B8RmlYgV.mjs';
3
+ import { R as RiverbankSiteConfig } from './types-txWsSxN7.mjs';
5
4
  import './schema-Bpy9N5ZI.mjs';
5
+ import './types-CdrJqlKx.mjs';
6
+ import '@riverbankcms/ai';
6
7
  import 'zod';
7
8
  import '@riverbankcms/media-storage-supabase';
8
9
  import '@riverbankcms/db';
9
10
  import 'react/jsx-runtime';
10
11
  import 'react';
11
- import './types-BuZJWVmj.mjs';
12
+ import './types-CbagRQ_7.mjs';
12
13
  import './blockKinds-B6MWzNWp.mjs';
13
14
 
14
15
  /**
@@ -117,4 +118,76 @@ declare function resolveRoutes(params: {
117
118
  resolution: RouteResolution;
118
119
  }>>;
119
120
 
120
- export { type ResolveRouteParams, type RouteResolution, resolveRoute, resolveRoutes };
121
+ /**
122
+ * Content route matching utilities.
123
+ *
124
+ * Derive route matching from SDK config to determine whether a URL path
125
+ * is a CMS page or a content entry, without duplicating route patterns.
126
+ */
127
+
128
+ /**
129
+ * Extract the first path segment from each routable content type's routePattern.
130
+ *
131
+ * Useful for simple prefix-based routing decisions. For more precise matching
132
+ * that handles nested patterns, use `isContentEntryPath` instead.
133
+ *
134
+ * @param config - The SDK config object from defineConfig()
135
+ * @returns Array of first path segments from content type routePatterns
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * import { getContentEntryPrefixes } from '@riverbankcms/sdk/routing';
140
+ * import config from '../riverbank.config';
141
+ *
142
+ * // Config with routePatterns: '/blog/{slug}', '/work/projects/{slug}'
143
+ * const prefixes = getContentEntryPrefixes(config);
144
+ * // Returns ['blog', 'work']
145
+ * ```
146
+ */
147
+ declare function getContentEntryPrefixes(config: RiverbankSiteConfig): string[];
148
+ /**
149
+ * Result of checking if a path matches a content entry route.
150
+ */
151
+ type ContentEntryMatch = {
152
+ /** Whether the path matches a content entry route pattern */
153
+ isEntry: boolean;
154
+ /** The content type key if matched (e.g., 'blog-post') */
155
+ contentType?: string;
156
+ /** The slug extracted from the path if matched */
157
+ slug?: string;
158
+ };
159
+ /**
160
+ * Check if a URL path matches any content entry route pattern.
161
+ *
162
+ * Supports nested patterns like '/work/projects/{slug}'. Returns the matched
163
+ * content type key and extracted slug, useful for routing decisions.
164
+ *
165
+ * **Note:** Content types are checked in array order. If multiple patterns
166
+ * could match a path, the first matching content type wins. Order more specific
167
+ * patterns before generic ones in your config.
168
+ *
169
+ * @param config - The SDK config object from defineConfig()
170
+ * @param path - URL path as string ('/blog/my-post') or segments ['blog', 'my-post']
171
+ * @returns Match result with content type and slug if matched
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * import { isContentEntryPath } from '@riverbankcms/sdk/routing';
176
+ * import config from '../riverbank.config';
177
+ *
178
+ * // Simple pattern: '/blog/{slug}'
179
+ * isContentEntryPath(config, '/blog/my-post');
180
+ * // Returns { isEntry: true, contentType: 'blog-post', slug: 'my-post' }
181
+ *
182
+ * // Nested pattern: '/work/projects/{slug}'
183
+ * isContentEntryPath(config, '/work/projects/website-redesign');
184
+ * // Returns { isEntry: true, contentType: 'project', slug: 'website-redesign' }
185
+ *
186
+ * // Non-matching path
187
+ * isContentEntryPath(config, '/about');
188
+ * // Returns { isEntry: false }
189
+ * ```
190
+ */
191
+ declare function isContentEntryPath(config: RiverbankSiteConfig, path: string | string[]): ContentEntryMatch;
192
+
193
+ export { type ContentEntryMatch, type ResolveRouteParams, type RouteResolution, getContentEntryPrefixes, isContentEntryPath, resolveRoute, resolveRoutes };
@@ -1,14 +1,15 @@
1
- import { R as RiverbankClient } from './types-CAnC529E.js';
2
- import { a as LoadPageResult } from './loadPage-BElEkA_J.js';
3
- import './types-5XdVD2J1.js';
4
- import '@riverbankcms/ai';
1
+ import { R as RiverbankClient } from './types-oCM-fw4O.js';
2
+ import { a as LoadPageResult } from './loadPage-BTkKpizX.js';
3
+ import { R as RiverbankSiteConfig } from './types-CL916r6x.js';
5
4
  import './schema-Bpy9N5ZI.js';
5
+ import './types-BiRZnxDx.js';
6
+ import '@riverbankcms/ai';
6
7
  import 'zod';
7
8
  import '@riverbankcms/media-storage-supabase';
8
9
  import '@riverbankcms/db';
9
10
  import 'react/jsx-runtime';
10
11
  import 'react';
11
- import './types-DSFvXKhO.js';
12
+ import './types-DuQCNVV0.js';
12
13
  import './blockKinds-B6MWzNWp.js';
13
14
 
14
15
  /**
@@ -117,4 +118,76 @@ declare function resolveRoutes(params: {
117
118
  resolution: RouteResolution;
118
119
  }>>;
119
120
 
120
- export { type ResolveRouteParams, type RouteResolution, resolveRoute, resolveRoutes };
121
+ /**
122
+ * Content route matching utilities.
123
+ *
124
+ * Derive route matching from SDK config to determine whether a URL path
125
+ * is a CMS page or a content entry, without duplicating route patterns.
126
+ */
127
+
128
+ /**
129
+ * Extract the first path segment from each routable content type's routePattern.
130
+ *
131
+ * Useful for simple prefix-based routing decisions. For more precise matching
132
+ * that handles nested patterns, use `isContentEntryPath` instead.
133
+ *
134
+ * @param config - The SDK config object from defineConfig()
135
+ * @returns Array of first path segments from content type routePatterns
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * import { getContentEntryPrefixes } from '@riverbankcms/sdk/routing';
140
+ * import config from '../riverbank.config';
141
+ *
142
+ * // Config with routePatterns: '/blog/{slug}', '/work/projects/{slug}'
143
+ * const prefixes = getContentEntryPrefixes(config);
144
+ * // Returns ['blog', 'work']
145
+ * ```
146
+ */
147
+ declare function getContentEntryPrefixes(config: RiverbankSiteConfig): string[];
148
+ /**
149
+ * Result of checking if a path matches a content entry route.
150
+ */
151
+ type ContentEntryMatch = {
152
+ /** Whether the path matches a content entry route pattern */
153
+ isEntry: boolean;
154
+ /** The content type key if matched (e.g., 'blog-post') */
155
+ contentType?: string;
156
+ /** The slug extracted from the path if matched */
157
+ slug?: string;
158
+ };
159
+ /**
160
+ * Check if a URL path matches any content entry route pattern.
161
+ *
162
+ * Supports nested patterns like '/work/projects/{slug}'. Returns the matched
163
+ * content type key and extracted slug, useful for routing decisions.
164
+ *
165
+ * **Note:** Content types are checked in array order. If multiple patterns
166
+ * could match a path, the first matching content type wins. Order more specific
167
+ * patterns before generic ones in your config.
168
+ *
169
+ * @param config - The SDK config object from defineConfig()
170
+ * @param path - URL path as string ('/blog/my-post') or segments ['blog', 'my-post']
171
+ * @returns Match result with content type and slug if matched
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * import { isContentEntryPath } from '@riverbankcms/sdk/routing';
176
+ * import config from '../riverbank.config';
177
+ *
178
+ * // Simple pattern: '/blog/{slug}'
179
+ * isContentEntryPath(config, '/blog/my-post');
180
+ * // Returns { isEntry: true, contentType: 'blog-post', slug: 'my-post' }
181
+ *
182
+ * // Nested pattern: '/work/projects/{slug}'
183
+ * isContentEntryPath(config, '/work/projects/website-redesign');
184
+ * // Returns { isEntry: true, contentType: 'project', slug: 'website-redesign' }
185
+ *
186
+ * // Non-matching path
187
+ * isContentEntryPath(config, '/about');
188
+ * // Returns { isEntry: false }
189
+ * ```
190
+ */
191
+ declare function isContentEntryPath(config: RiverbankSiteConfig, path: string | string[]): ContentEntryMatch;
192
+
193
+ export { type ContentEntryMatch, type ResolveRouteParams, type RouteResolution, getContentEntryPrefixes, isContentEntryPath, resolveRoute, resolveRoutes };
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }require('./chunk-DGUM43GV.js');
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } 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; }require('./chunk-DGUM43GV.js');
2
2
 
3
3
  // src/routing/resolveRoute.ts
4
4
  async function resolveRoute(params) {
@@ -10,7 +10,7 @@ async function resolveRoute(params) {
10
10
  preview
11
11
  });
12
12
  if (pageResponse) {
13
- const { loadPage } = await Promise.resolve().then(() => _interopRequireWildcard(require("./loadPage-E3ZC6NHB.js")));
13
+ const { loadPage } = await Promise.resolve().then(() => _interopRequireWildcard(require("./loadPage-DUHBXDEW.js")));
14
14
  const pageData = await loadPage({
15
15
  client,
16
16
  siteId,
@@ -53,7 +53,61 @@ async function resolveRoutes(params) {
53
53
  return resolutions;
54
54
  }
55
55
 
56
+ // src/routing/contentRoutes.ts
57
+ function getContentEntryPrefixes(config) {
58
+ const contentTypes = _nullishCoalesce(_optionalChain([config, 'access', _ => _.content, 'optionalAccess', _2 => _2.contentTypes]), () => ( []));
59
+ return contentTypes.filter(
60
+ (ct) => ct.hasPages && typeof ct.routePattern === "string"
61
+ ).map((ct) => {
62
+ const match = ct.routePattern.match(/^\/([^/]+)/);
63
+ const segment = _optionalChain([match, 'optionalAccess', _3 => _3[1]]);
64
+ if (_optionalChain([segment, 'optionalAccess', _4 => _4.includes, 'call', _5 => _5("{")])) return void 0;
65
+ return segment;
66
+ }).filter((prefix) => typeof prefix === "string");
67
+ }
68
+ function isContentEntryPath(config, path) {
69
+ const segments = typeof path === "string" ? path.split("/").filter(Boolean) : path;
70
+ const contentTypes = _nullishCoalesce(_optionalChain([config, 'access', _6 => _6.content, 'optionalAccess', _7 => _7.contentTypes]), () => ( []));
71
+ for (const ct of contentTypes) {
72
+ if (!ct.hasPages || !ct.routePattern) continue;
73
+ const patternSegments = parseRoutePattern(ct.routePattern);
74
+ const match = matchPattern(segments, patternSegments);
75
+ if (match.matches) {
76
+ return {
77
+ isEntry: true,
78
+ contentType: ct.key,
79
+ slug: match.slug
80
+ };
81
+ }
82
+ }
83
+ return { isEntry: false };
84
+ }
85
+ function parseRoutePattern(pattern) {
86
+ const segments = pattern.split("/").filter(Boolean);
87
+ const staticSegments = [];
88
+ for (const segment of segments) {
89
+ if (segment.includes("{")) break;
90
+ staticSegments.push(segment);
91
+ }
92
+ return staticSegments;
93
+ }
94
+ function matchPattern(pathSegments, patternSegments) {
95
+ if (pathSegments.length < patternSegments.length + 1) {
96
+ return { matches: false };
97
+ }
98
+ for (let i = 0; i < patternSegments.length; i++) {
99
+ if (pathSegments[i] !== patternSegments[i]) {
100
+ return { matches: false };
101
+ }
102
+ }
103
+ const slugSegments = pathSegments.slice(patternSegments.length);
104
+ const slug = slugSegments.join("/");
105
+ return { matches: true, slug };
106
+ }
107
+
108
+
109
+
56
110
 
57
111
 
58
- exports.resolveRoute = resolveRoute; exports.resolveRoutes = resolveRoutes;
112
+ exports.getContentEntryPrefixes = getContentEntryPrefixes; exports.isContentEntryPath = isContentEntryPath; exports.resolveRoute = resolveRoute; exports.resolveRoutes = resolveRoutes;
59
113
  //# sourceMappingURL=routing.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/routing.js","../../src/routing/resolveRoute.ts"],"names":[],"mappings":"AAAA,0XAA4B;AAC5B;AACA;ACgFA,MAAA,SAAsB,YAAA,CACpB,MAAA,EAC0B;AAC1B,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,MAAM,EAAA,EAAI,MAAA;AAElD,EAAA,IAAI;AAEF,IAAA,MAAM,aAAA,EAAe,MAAM,MAAA,CAAO,OAAA,CAAQ;AAAA,MACxC,MAAA;AAAA,MACA,IAAA;AAAA,MACA;AAAA,IACF,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,YAAA,EAAc;AAEhB,MAAA,MAAM,EAAE,SAAS,EAAA,EAAI,MAAM,4DAAA,CAAO,wBAA+B,GAAA;AACjE,MAAA,MAAM,SAAA,EAAW,MAAM,QAAA,CAAS;AAAA,QAC9B,MAAA;AAAA,QACA,MAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA,MACF,CAAC,CAAA;AAED,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,MAAA;AAAA,QACN;AAAA,MACF,CAAA;AAAA,IACF;AAAA,EACF,EAAA,MAAA,CAAS,KAAA,EAAO;AAEd,IAAA,MAAM,MAAA,EAAQ,MAAA,WAAiB,MAAA,GAAA,CAC5B,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,KAAK,EAAA,GAC5B,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,WAAW,EAAA,GAClC,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,WAAW,CAAA,CAAA;AAErC,IAAA,GAAA,CAAI,KAAA,EAAO;AACT,MAAA,OAAA,CAAQ,KAAA,CAAM,+BAAA,EAAiC,EAAE,KAAK,CAAC,CAAA;AAAA,IACzD,EAAA,KAAO;AAEL,MAAA,OAAA,CAAQ,IAAA,CAAK,qCAAA,EAAuC;AAAA,QAClD,IAAA;AAAA,QACA,KAAA,EAAO,MAAA,WAAiB,MAAA,EAAQ,KAAA,CAAM,QAAA,EAAU,MAAA,CAAO,KAAK;AAAA,MAC9D,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAIA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,EACR,CAAA;AACF;AA0BA,MAAA,SAAsB,aAAA,CAAc,MAAA,EAK8B;AAChE,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,QAAQ,EAAA,EAAI,MAAA;AAE3C,EAAA,MAAM,YAAA,EAAc,MAAM,OAAA,CAAQ,GAAA;AAAA,IAChC,KAAA,CAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAA,GAAS;AACxB,MAAA,MAAM,WAAA,EAAa,MAAM,YAAA,CAAa;AAAA,QACpC,MAAA;AAAA,QACA,MAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA,MACF,CAAC,CAAA;AAED,MAAA,OAAO,EAAE,IAAA,EAAM,WAAW,CAAA;AAAA,IAC5B,CAAC;AAAA,EACH,CAAA;AAEA,EAAA,OAAO,WAAA;AACT;AD/HA;AACE;AACA;AACF,2EAAC","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/routing.js","sourcesContent":[null,"/**\n * Route resolution helper for dynamic page routing\n *\n * Resolves URL paths to pages, entries, redirects, or 404s.\n */\n\nimport type { RiverbankClient } from '../client/types';\nimport type { LoadPageResult } from '../rendering/helpers/loadPage';\n\nexport type RouteResolution =\n | {\n type: 'page';\n pageData: LoadPageResult;\n }\n | {\n type: 'redirect';\n destination: string;\n permanent: boolean;\n }\n | {\n type: 'not-found';\n };\n\nexport type ResolveRouteParams = {\n /**\n * Builder client instance\n */\n client: RiverbankClient;\n\n /**\n * Site ID\n */\n siteId: string;\n\n /**\n * URL path to resolve (e.g., '/about', '/blog/post-1')\n */\n path: string;\n\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * @default false\n */\n preview?: boolean;\n};\n\n/**\n * Resolve a URL path to page data, redirect, or 404\n *\n * This helper attempts to fetch the page at the given path and returns\n * a discriminated union indicating whether the page was found or not.\n *\n * **Note:** Redirect support is not yet implemented. The `redirect` type\n * exists in the return type for future compatibility, but this function\n * currently only returns `page` or `not-found` types.\n *\n * @example\n * ```tsx\n * import { resolveRoute } from '@riverbankcms/sdk/routing';\n * import { notFound, redirect } from 'next/navigation';\n *\n * export default async function DynamicPage({ params }) {\n * const path = `/${params.slug?.join('/') || ''}`;\n * const resolution = await resolveRoute({\n * client,\n * siteId: 'your-site-id',\n * path,\n * });\n *\n * if (resolution.type === 'redirect') {\n * redirect(resolution.destination);\n * }\n *\n * if (resolution.type === 'not-found') {\n * notFound();\n * }\n *\n * // resolution.type === 'page'\n * return <Page {...resolution.pageData} />;\n * }\n * ```\n */\nexport async function resolveRoute(\n params: ResolveRouteParams\n): Promise<RouteResolution> {\n const { client, siteId, path, preview = false } = params;\n\n try {\n // Attempt to fetch page data\n const pageResponse = await client.getPage({\n siteId,\n path,\n preview,\n });\n\n if (pageResponse) {\n // Successfully found page - load full page data\n const { loadPage } = await import('../rendering/helpers/loadPage');\n const pageData = await loadPage({\n client,\n siteId,\n path,\n preview,\n });\n\n return {\n type: 'page',\n pageData,\n };\n }\n } catch (error) {\n // Distinguish between expected 404s and unexpected errors\n const is404 = error instanceof Error &&\n (error.message.includes('404') ||\n error.message.includes('Not Found') ||\n error.message.includes('not found'));\n\n if (is404) {\n console.debug('[resolveRoute] Page not found', { path });\n } else {\n // Unexpected error - log as warning for visibility\n console.warn('[resolveRoute] Failed to fetch page', {\n path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // No page found - return not-found\n // Note: Redirect support will be added when client.getRedirect() API is available\n return {\n type: 'not-found',\n };\n}\n\n/**\n * Batch resolve multiple routes in parallel\n *\n * Useful for pre-fetching multiple routes or validating a sitemap.\n *\n * @example\n * ```tsx\n * const resolutions = await resolveRoutes({\n * client,\n * siteId: 'your-site-id',\n * paths: ['/', '/about', '/blog', '/contact'],\n * });\n *\n * resolutions.forEach(({ path, resolution }) => {\n * if (resolution.type === 'page') {\n * console.log(`${path} → Page: ${resolution.pageData.page.name}`);\n * } else if (resolution.type === 'redirect') {\n * console.log(`${path} → Redirect to ${resolution.destination}`);\n * } else {\n * console.log(`${path} → Not found`);\n * }\n * });\n * ```\n */\nexport async function resolveRoutes(params: {\n client: RiverbankClient;\n siteId: string;\n paths: string[];\n preview?: boolean;\n}): Promise<Array<{ path: string; resolution: RouteResolution }>> {\n const { client, siteId, paths, preview } = params;\n\n const resolutions = await Promise.all(\n paths.map(async (path) => {\n const resolution = await resolveRoute({\n client,\n siteId,\n path,\n preview,\n });\n\n return { path, resolution };\n })\n );\n\n return resolutions;\n}\n"]}
1
+ {"version":3,"sources":["/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/routing.js","../../src/routing/resolveRoute.ts","../../src/routing/contentRoutes.ts"],"names":[],"mappings":"AAAA,k+BAA4B;AAC5B;AACA;ACgFA,MAAA,SAAsB,YAAA,CACpB,MAAA,EAC0B;AAC1B,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,MAAM,EAAA,EAAI,MAAA;AAElD,EAAA,IAAI;AAEF,IAAA,MAAM,aAAA,EAAe,MAAM,MAAA,CAAO,OAAA,CAAQ;AAAA,MACxC,MAAA;AAAA,MACA,IAAA;AAAA,MACA;AAAA,IACF,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,YAAA,EAAc;AAEhB,MAAA,MAAM,EAAE,SAAS,EAAA,EAAI,MAAM,4DAAA,CAAO,wBAA+B,GAAA;AACjE,MAAA,MAAM,SAAA,EAAW,MAAM,QAAA,CAAS;AAAA,QAC9B,MAAA;AAAA,QACA,MAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA,MACF,CAAC,CAAA;AAED,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,MAAA;AAAA,QACN;AAAA,MACF,CAAA;AAAA,IACF;AAAA,EACF,EAAA,MAAA,CAAS,KAAA,EAAO;AAEd,IAAA,MAAM,MAAA,EAAQ,MAAA,WAAiB,MAAA,GAAA,CAC5B,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,KAAK,EAAA,GAC5B,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,WAAW,EAAA,GAClC,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,WAAW,CAAA,CAAA;AAErC,IAAA,GAAA,CAAI,KAAA,EAAO;AACT,MAAA,OAAA,CAAQ,KAAA,CAAM,+BAAA,EAAiC,EAAE,KAAK,CAAC,CAAA;AAAA,IACzD,EAAA,KAAO;AAEL,MAAA,OAAA,CAAQ,IAAA,CAAK,qCAAA,EAAuC;AAAA,QAClD,IAAA;AAAA,QACA,KAAA,EAAO,MAAA,WAAiB,MAAA,EAAQ,KAAA,CAAM,QAAA,EAAU,MAAA,CAAO,KAAK;AAAA,MAC9D,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAIA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM;AAAA,EACR,CAAA;AACF;AA0BA,MAAA,SAAsB,aAAA,CAAc,MAAA,EAK8B;AAChE,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,QAAQ,EAAA,EAAI,MAAA;AAE3C,EAAA,MAAM,YAAA,EAAc,MAAM,OAAA,CAAQ,GAAA;AAAA,IAChC,KAAA,CAAM,GAAA,CAAI,MAAA,CAAO,IAAA,EAAA,GAAS;AACxB,MAAA,MAAM,WAAA,EAAa,MAAM,YAAA,CAAa;AAAA,QACpC,MAAA;AAAA,QACA,MAAA;AAAA,QACA,IAAA;AAAA,QACA;AAAA,MACF,CAAC,CAAA;AAED,MAAA,OAAO,EAAE,IAAA,EAAM,WAAW,CAAA;AAAA,IAC5B,CAAC;AAAA,EACH,CAAA;AAEA,EAAA,OAAO,WAAA;AACT;AD/HA;AACA;AE3BO,SAAS,uBAAA,CAAwB,MAAA,EAAuC;AAC7E,EAAA,MAAM,aAAA,mCAAe,MAAA,mBAAO,OAAA,6BAAS,cAAA,UAAgB,CAAC,GAAA;AAEtD,EAAA,OAAO,YAAA,CACJ,MAAA;AAAA,IAAO,CAAC,EAAA,EAAA,GACP,EAAA,CAAG,SAAA,GAAY,OAAO,EAAA,CAAG,aAAA,IAAiB;AAAA,EAC5C,CAAA,CACC,GAAA,CAAI,CAAA,EAAA,EAAA,GAAM;AAIT,IAAA,MAAM,MAAA,EAAQ,EAAA,CAAG,YAAA,CAAa,KAAA,CAAM,YAAY,CAAA;AAChD,IAAA,MAAM,QAAA,kBAAU,KAAA,4BAAA,CAAQ,CAAC,GAAA;AAEzB,IAAA,GAAA,iBAAI,OAAA,6BAAS,QAAA,mBAAS,GAAG,GAAA,EAAG,OAAO,KAAA,CAAA;AACnC,IAAA,OAAO,OAAA;AAAA,EACT,CAAC,CAAA,CACA,MAAA,CAAO,CAAC,MAAA,EAAA,GAA6B,OAAO,OAAA,IAAW,QAAQ,CAAA;AACpE;AA8CO,SAAS,kBAAA,CACd,MAAA,EACA,IAAA,EACmB;AACnB,EAAA,MAAM,SAAA,EAAW,OAAO,KAAA,IAAS,SAAA,EAC7B,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,MAAA,CAAO,OAAO,EAAA,EAC9B,IAAA;AAEJ,EAAA,MAAM,aAAA,mCAAe,MAAA,qBAAO,OAAA,6BAAS,cAAA,UAAgB,CAAC,GAAA;AAEtD,EAAA,IAAA,CAAA,MAAW,GAAA,GAAM,YAAA,EAAc;AAC7B,IAAA,GAAA,CAAI,CAAC,EAAA,CAAG,SAAA,GAAY,CAAC,EAAA,CAAG,YAAA,EAAc,QAAA;AAGtC,IAAA,MAAM,gBAAA,EAAkB,iBAAA,CAAkB,EAAA,CAAG,YAAY,CAAA;AAGzD,IAAA,MAAM,MAAA,EAAQ,YAAA,CAAa,QAAA,EAAU,eAAe,CAAA;AACpD,IAAA,GAAA,CAAI,KAAA,CAAM,OAAA,EAAS;AACjB,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,IAAA;AAAA,QACT,WAAA,EAAa,EAAA,CAAG,GAAA;AAAA,QAChB,IAAA,EAAM,KAAA,CAAM;AAAA,MACd,CAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,MAAM,CAAA;AAC1B;AAUA,SAAS,iBAAA,CAAkB,OAAA,EAA2B;AACpD,EAAA,MAAM,SAAA,EAAW,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA;AAClD,EAAA,MAAM,eAAA,EAA2B,CAAC,CAAA;AAElC,EAAA,IAAA,CAAA,MAAW,QAAA,GAAW,QAAA,EAAU;AAC9B,IAAA,GAAA,CAAI,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG,KAAA;AAC3B,IAAA,cAAA,CAAe,IAAA,CAAK,OAAO,CAAA;AAAA,EAC7B;AAEA,EAAA,OAAO,cAAA;AACT;AAQA,SAAS,YAAA,CACP,YAAA,EACA,eAAA,EACqC;AAErC,EAAA,GAAA,CAAI,YAAA,CAAa,OAAA,EAAS,eAAA,CAAgB,OAAA,EAAS,CAAA,EAAG;AACpD,IAAA,OAAO,EAAE,OAAA,EAAS,MAAM,CAAA;AAAA,EAC1B;AAGA,EAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,eAAA,CAAgB,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/C,IAAA,GAAA,CAAI,YAAA,CAAa,CAAC,EAAA,IAAM,eAAA,CAAgB,CAAC,CAAA,EAAG;AAC1C,MAAA,OAAO,EAAE,OAAA,EAAS,MAAM,CAAA;AAAA,IAC1B;AAAA,EACF;AAKA,EAAA,MAAM,aAAA,EAAe,YAAA,CAAa,KAAA,CAAM,eAAA,CAAgB,MAAM,CAAA;AAC9D,EAAA,MAAM,KAAA,EAAO,YAAA,CAAa,IAAA,CAAK,GAAG,CAAA;AAElC,EAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,KAAK,CAAA;AAC/B;AFjEA;AACE;AACA;AACA;AACA;AACF,uLAAC","file":"/Users/will/Projects/Business/cms/builder/packages/sdk/dist/server/routing.js","sourcesContent":[null,"/**\n * Route resolution helper for dynamic page routing\n *\n * Resolves URL paths to pages, entries, redirects, or 404s.\n */\n\nimport type { RiverbankClient } from '../client/types';\nimport type { LoadPageResult } from '../rendering/helpers/loadPage';\n\nexport type RouteResolution =\n | {\n type: 'page';\n pageData: LoadPageResult;\n }\n | {\n type: 'redirect';\n destination: string;\n permanent: boolean;\n }\n | {\n type: 'not-found';\n };\n\nexport type ResolveRouteParams = {\n /**\n * Builder client instance\n */\n client: RiverbankClient;\n\n /**\n * Site ID\n */\n siteId: string;\n\n /**\n * URL path to resolve (e.g., '/about', '/blog/post-1')\n */\n path: string;\n\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * @default false\n */\n preview?: boolean;\n};\n\n/**\n * Resolve a URL path to page data, redirect, or 404\n *\n * This helper attempts to fetch the page at the given path and returns\n * a discriminated union indicating whether the page was found or not.\n *\n * **Note:** Redirect support is not yet implemented. The `redirect` type\n * exists in the return type for future compatibility, but this function\n * currently only returns `page` or `not-found` types.\n *\n * @example\n * ```tsx\n * import { resolveRoute } from '@riverbankcms/sdk/routing';\n * import { notFound, redirect } from 'next/navigation';\n *\n * export default async function DynamicPage({ params }) {\n * const path = `/${params.slug?.join('/') || ''}`;\n * const resolution = await resolveRoute({\n * client,\n * siteId: 'your-site-id',\n * path,\n * });\n *\n * if (resolution.type === 'redirect') {\n * redirect(resolution.destination);\n * }\n *\n * if (resolution.type === 'not-found') {\n * notFound();\n * }\n *\n * // resolution.type === 'page'\n * return <Page {...resolution.pageData} />;\n * }\n * ```\n */\nexport async function resolveRoute(\n params: ResolveRouteParams\n): Promise<RouteResolution> {\n const { client, siteId, path, preview = false } = params;\n\n try {\n // Attempt to fetch page data\n const pageResponse = await client.getPage({\n siteId,\n path,\n preview,\n });\n\n if (pageResponse) {\n // Successfully found page - load full page data\n const { loadPage } = await import('../rendering/helpers/loadPage');\n const pageData = await loadPage({\n client,\n siteId,\n path,\n preview,\n });\n\n return {\n type: 'page',\n pageData,\n };\n }\n } catch (error) {\n // Distinguish between expected 404s and unexpected errors\n const is404 = error instanceof Error &&\n (error.message.includes('404') ||\n error.message.includes('Not Found') ||\n error.message.includes('not found'));\n\n if (is404) {\n console.debug('[resolveRoute] Page not found', { path });\n } else {\n // Unexpected error - log as warning for visibility\n console.warn('[resolveRoute] Failed to fetch page', {\n path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // No page found - return not-found\n // Note: Redirect support will be added when client.getRedirect() API is available\n return {\n type: 'not-found',\n };\n}\n\n/**\n * Batch resolve multiple routes in parallel\n *\n * Useful for pre-fetching multiple routes or validating a sitemap.\n *\n * @example\n * ```tsx\n * const resolutions = await resolveRoutes({\n * client,\n * siteId: 'your-site-id',\n * paths: ['/', '/about', '/blog', '/contact'],\n * });\n *\n * resolutions.forEach(({ path, resolution }) => {\n * if (resolution.type === 'page') {\n * console.log(`${path} → Page: ${resolution.pageData.page.name}`);\n * } else if (resolution.type === 'redirect') {\n * console.log(`${path} → Redirect to ${resolution.destination}`);\n * } else {\n * console.log(`${path} → Not found`);\n * }\n * });\n * ```\n */\nexport async function resolveRoutes(params: {\n client: RiverbankClient;\n siteId: string;\n paths: string[];\n preview?: boolean;\n}): Promise<Array<{ path: string; resolution: RouteResolution }>> {\n const { client, siteId, paths, preview } = params;\n\n const resolutions = await Promise.all(\n paths.map(async (path) => {\n const resolution = await resolveRoute({\n client,\n siteId,\n path,\n preview,\n });\n\n return { path, resolution };\n })\n );\n\n return resolutions;\n}\n","/**\n * Content route matching utilities.\n *\n * Derive route matching from SDK config to determine whether a URL path\n * is a CMS page or a content entry, without duplicating route patterns.\n */\n\nimport type { RiverbankSiteConfig, ContentTypeConfig } from '../config';\n\n/**\n * Extract the first path segment from each routable content type's routePattern.\n *\n * Useful for simple prefix-based routing decisions. For more precise matching\n * that handles nested patterns, use `isContentEntryPath` instead.\n *\n * @param config - The SDK config object from defineConfig()\n * @returns Array of first path segments from content type routePatterns\n *\n * @example\n * ```typescript\n * import { getContentEntryPrefixes } from '@riverbankcms/sdk/routing';\n * import config from '../riverbank.config';\n *\n * // Config with routePatterns: '/blog/{slug}', '/work/projects/{slug}'\n * const prefixes = getContentEntryPrefixes(config);\n * // Returns ['blog', 'work']\n * ```\n */\nexport function getContentEntryPrefixes(config: RiverbankSiteConfig): string[] {\n const contentTypes = config.content?.contentTypes ?? [];\n\n return contentTypes\n .filter((ct): ct is ContentTypeConfig & { routePattern: string } =>\n ct.hasPages && typeof ct.routePattern === 'string'\n )\n .map(ct => {\n // '/blog/{slug}' → 'blog'\n // '/work/projects/{slug}' → 'work'\n // '/{slug}' → undefined (no static prefix)\n const match = ct.routePattern.match(/^\\/([^/]+)/);\n const segment = match?.[1];\n // Skip dynamic segments (those containing {})\n if (segment?.includes('{')) return undefined;\n return segment;\n })\n .filter((prefix): prefix is string => typeof prefix === 'string');\n}\n\n/**\n * Result of checking if a path matches a content entry route.\n */\nexport type ContentEntryMatch = {\n /** Whether the path matches a content entry route pattern */\n isEntry: boolean;\n /** The content type key if matched (e.g., 'blog-post') */\n contentType?: string;\n /** The slug extracted from the path if matched */\n slug?: string;\n};\n\n/**\n * Check if a URL path matches any content entry route pattern.\n *\n * Supports nested patterns like '/work/projects/{slug}'. Returns the matched\n * content type key and extracted slug, useful for routing decisions.\n *\n * **Note:** Content types are checked in array order. If multiple patterns\n * could match a path, the first matching content type wins. Order more specific\n * patterns before generic ones in your config.\n *\n * @param config - The SDK config object from defineConfig()\n * @param path - URL path as string ('/blog/my-post') or segments ['blog', 'my-post']\n * @returns Match result with content type and slug if matched\n *\n * @example\n * ```typescript\n * import { isContentEntryPath } from '@riverbankcms/sdk/routing';\n * import config from '../riverbank.config';\n *\n * // Simple pattern: '/blog/{slug}'\n * isContentEntryPath(config, '/blog/my-post');\n * // Returns { isEntry: true, contentType: 'blog-post', slug: 'my-post' }\n *\n * // Nested pattern: '/work/projects/{slug}'\n * isContentEntryPath(config, '/work/projects/website-redesign');\n * // Returns { isEntry: true, contentType: 'project', slug: 'website-redesign' }\n *\n * // Non-matching path\n * isContentEntryPath(config, '/about');\n * // Returns { isEntry: false }\n * ```\n */\nexport function isContentEntryPath(\n config: RiverbankSiteConfig,\n path: string | string[]\n): ContentEntryMatch {\n const segments = typeof path === 'string'\n ? path.split('/').filter(Boolean)\n : path;\n\n const contentTypes = config.content?.contentTypes ?? [];\n\n for (const ct of contentTypes) {\n if (!ct.hasPages || !ct.routePattern) continue;\n\n // Parse pattern: '/blog/{slug}' → ['blog'], '/work/projects/{slug}' → ['work', 'projects']\n const patternSegments = parseRoutePattern(ct.routePattern);\n\n // Check if path segments match the pattern\n const match = matchPattern(segments, patternSegments);\n if (match.matches) {\n return {\n isEntry: true,\n contentType: ct.key,\n slug: match.slug,\n };\n }\n }\n\n return { isEntry: false };\n}\n\n/**\n * Parse a route pattern into static segments before {slug}.\n *\n * @example\n * parseRoutePattern('/blog/{slug}') // ['blog']\n * parseRoutePattern('/work/projects/{slug}') // ['work', 'projects']\n * parseRoutePattern('/{slug}') // []\n */\nfunction parseRoutePattern(pattern: string): string[] {\n const segments = pattern.split('/').filter(Boolean);\n const staticSegments: string[] = [];\n\n for (const segment of segments) {\n if (segment.includes('{')) break; // Stop at dynamic segment\n staticSegments.push(segment);\n }\n\n return staticSegments;\n}\n\n/**\n * Check if path segments match pattern segments.\n * Path must have at least one more segment than pattern (the slug).\n *\n * @returns Match result with extracted slug if matched\n */\nfunction matchPattern(\n pathSegments: string[],\n patternSegments: string[]\n): { matches: boolean; slug?: string } {\n // Path needs: pattern segments + at least 1 slug segment\n if (pathSegments.length < patternSegments.length + 1) {\n return { matches: false };\n }\n\n // All pattern segments must match exactly\n for (let i = 0; i < patternSegments.length; i++) {\n if (pathSegments[i] !== patternSegments[i]) {\n return { matches: false };\n }\n }\n\n // Extract slug (everything after the pattern segments)\n // For '/blog/{slug}' with path '/blog/my-post' → slug = 'my-post'\n // For nested slugs, join remaining segments (rare but supported)\n const slugSegments = pathSegments.slice(patternSegments.length);\n const slug = slugSegments.join('/');\n\n return { matches: true, slug };\n}\n"]}
@@ -10,7 +10,7 @@ async function resolveRoute(params) {
10
10
  preview
11
11
  });
12
12
  if (pageResponse) {
13
- const { loadPage } = await import("./loadPage-E7L7NMR3.mjs");
13
+ const { loadPage } = await import("./loadPage-LYVKY3WZ.mjs");
14
14
  const pageData = await loadPage({
15
15
  client,
16
16
  siteId,
@@ -52,7 +52,61 @@ async function resolveRoutes(params) {
52
52
  );
53
53
  return resolutions;
54
54
  }
55
+
56
+ // src/routing/contentRoutes.ts
57
+ function getContentEntryPrefixes(config) {
58
+ const contentTypes = config.content?.contentTypes ?? [];
59
+ return contentTypes.filter(
60
+ (ct) => ct.hasPages && typeof ct.routePattern === "string"
61
+ ).map((ct) => {
62
+ const match = ct.routePattern.match(/^\/([^/]+)/);
63
+ const segment = match?.[1];
64
+ if (segment?.includes("{")) return void 0;
65
+ return segment;
66
+ }).filter((prefix) => typeof prefix === "string");
67
+ }
68
+ function isContentEntryPath(config, path) {
69
+ const segments = typeof path === "string" ? path.split("/").filter(Boolean) : path;
70
+ const contentTypes = config.content?.contentTypes ?? [];
71
+ for (const ct of contentTypes) {
72
+ if (!ct.hasPages || !ct.routePattern) continue;
73
+ const patternSegments = parseRoutePattern(ct.routePattern);
74
+ const match = matchPattern(segments, patternSegments);
75
+ if (match.matches) {
76
+ return {
77
+ isEntry: true,
78
+ contentType: ct.key,
79
+ slug: match.slug
80
+ };
81
+ }
82
+ }
83
+ return { isEntry: false };
84
+ }
85
+ function parseRoutePattern(pattern) {
86
+ const segments = pattern.split("/").filter(Boolean);
87
+ const staticSegments = [];
88
+ for (const segment of segments) {
89
+ if (segment.includes("{")) break;
90
+ staticSegments.push(segment);
91
+ }
92
+ return staticSegments;
93
+ }
94
+ function matchPattern(pathSegments, patternSegments) {
95
+ if (pathSegments.length < patternSegments.length + 1) {
96
+ return { matches: false };
97
+ }
98
+ for (let i = 0; i < patternSegments.length; i++) {
99
+ if (pathSegments[i] !== patternSegments[i]) {
100
+ return { matches: false };
101
+ }
102
+ }
103
+ const slugSegments = pathSegments.slice(patternSegments.length);
104
+ const slug = slugSegments.join("/");
105
+ return { matches: true, slug };
106
+ }
55
107
  export {
108
+ getContentEntryPrefixes,
109
+ isContentEntryPath,
56
110
  resolveRoute,
57
111
  resolveRoutes
58
112
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/routing/resolveRoute.ts"],"sourcesContent":["/**\n * Route resolution helper for dynamic page routing\n *\n * Resolves URL paths to pages, entries, redirects, or 404s.\n */\n\nimport type { RiverbankClient } from '../client/types';\nimport type { LoadPageResult } from '../rendering/helpers/loadPage';\n\nexport type RouteResolution =\n | {\n type: 'page';\n pageData: LoadPageResult;\n }\n | {\n type: 'redirect';\n destination: string;\n permanent: boolean;\n }\n | {\n type: 'not-found';\n };\n\nexport type ResolveRouteParams = {\n /**\n * Builder client instance\n */\n client: RiverbankClient;\n\n /**\n * Site ID\n */\n siteId: string;\n\n /**\n * URL path to resolve (e.g., '/about', '/blog/post-1')\n */\n path: string;\n\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * @default false\n */\n preview?: boolean;\n};\n\n/**\n * Resolve a URL path to page data, redirect, or 404\n *\n * This helper attempts to fetch the page at the given path and returns\n * a discriminated union indicating whether the page was found or not.\n *\n * **Note:** Redirect support is not yet implemented. The `redirect` type\n * exists in the return type for future compatibility, but this function\n * currently only returns `page` or `not-found` types.\n *\n * @example\n * ```tsx\n * import { resolveRoute } from '@riverbankcms/sdk/routing';\n * import { notFound, redirect } from 'next/navigation';\n *\n * export default async function DynamicPage({ params }) {\n * const path = `/${params.slug?.join('/') || ''}`;\n * const resolution = await resolveRoute({\n * client,\n * siteId: 'your-site-id',\n * path,\n * });\n *\n * if (resolution.type === 'redirect') {\n * redirect(resolution.destination);\n * }\n *\n * if (resolution.type === 'not-found') {\n * notFound();\n * }\n *\n * // resolution.type === 'page'\n * return <Page {...resolution.pageData} />;\n * }\n * ```\n */\nexport async function resolveRoute(\n params: ResolveRouteParams\n): Promise<RouteResolution> {\n const { client, siteId, path, preview = false } = params;\n\n try {\n // Attempt to fetch page data\n const pageResponse = await client.getPage({\n siteId,\n path,\n preview,\n });\n\n if (pageResponse) {\n // Successfully found page - load full page data\n const { loadPage } = await import('../rendering/helpers/loadPage');\n const pageData = await loadPage({\n client,\n siteId,\n path,\n preview,\n });\n\n return {\n type: 'page',\n pageData,\n };\n }\n } catch (error) {\n // Distinguish between expected 404s and unexpected errors\n const is404 = error instanceof Error &&\n (error.message.includes('404') ||\n error.message.includes('Not Found') ||\n error.message.includes('not found'));\n\n if (is404) {\n console.debug('[resolveRoute] Page not found', { path });\n } else {\n // Unexpected error - log as warning for visibility\n console.warn('[resolveRoute] Failed to fetch page', {\n path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // No page found - return not-found\n // Note: Redirect support will be added when client.getRedirect() API is available\n return {\n type: 'not-found',\n };\n}\n\n/**\n * Batch resolve multiple routes in parallel\n *\n * Useful for pre-fetching multiple routes or validating a sitemap.\n *\n * @example\n * ```tsx\n * const resolutions = await resolveRoutes({\n * client,\n * siteId: 'your-site-id',\n * paths: ['/', '/about', '/blog', '/contact'],\n * });\n *\n * resolutions.forEach(({ path, resolution }) => {\n * if (resolution.type === 'page') {\n * console.log(`${path} → Page: ${resolution.pageData.page.name}`);\n * } else if (resolution.type === 'redirect') {\n * console.log(`${path} → Redirect to ${resolution.destination}`);\n * } else {\n * console.log(`${path} → Not found`);\n * }\n * });\n * ```\n */\nexport async function resolveRoutes(params: {\n client: RiverbankClient;\n siteId: string;\n paths: string[];\n preview?: boolean;\n}): Promise<Array<{ path: string; resolution: RouteResolution }>> {\n const { client, siteId, paths, preview } = params;\n\n const resolutions = await Promise.all(\n paths.map(async (path) => {\n const resolution = await resolveRoute({\n client,\n siteId,\n path,\n preview,\n });\n\n return { path, resolution };\n })\n );\n\n return resolutions;\n}\n"],"mappings":";;;AAkFA,eAAsB,aACpB,QAC0B;AAC1B,QAAM,EAAE,QAAQ,QAAQ,MAAM,UAAU,MAAM,IAAI;AAElD,MAAI;AAEF,UAAM,eAAe,MAAM,OAAO,QAAQ;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,cAAc;AAEhB,YAAM,EAAE,SAAS,IAAI,MAAM,OAAO,yBAA+B;AACjE,YAAM,WAAW,MAAM,SAAS;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAEd,UAAM,QAAQ,iBAAiB,UAC5B,MAAM,QAAQ,SAAS,KAAK,KAC5B,MAAM,QAAQ,SAAS,WAAW,KAClC,MAAM,QAAQ,SAAS,WAAW;AAErC,QAAI,OAAO;AACT,cAAQ,MAAM,iCAAiC,EAAE,KAAK,CAAC;AAAA,IACzD,OAAO;AAEL,cAAQ,KAAK,uCAAuC;AAAA,QAClD;AAAA,QACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH;AAAA,EACF;AAIA,SAAO;AAAA,IACL,MAAM;AAAA,EACR;AACF;AA0BA,eAAsB,cAAc,QAK8B;AAChE,QAAM,EAAE,QAAQ,QAAQ,OAAO,QAAQ,IAAI;AAE3C,QAAM,cAAc,MAAM,QAAQ;AAAA,IAChC,MAAM,IAAI,OAAO,SAAS;AACxB,YAAM,aAAa,MAAM,aAAa;AAAA,QACpC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO,EAAE,MAAM,WAAW;AAAA,IAC5B,CAAC;AAAA,EACH;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/routing/resolveRoute.ts","../../src/routing/contentRoutes.ts"],"sourcesContent":["/**\n * Route resolution helper for dynamic page routing\n *\n * Resolves URL paths to pages, entries, redirects, or 404s.\n */\n\nimport type { RiverbankClient } from '../client/types';\nimport type { LoadPageResult } from '../rendering/helpers/loadPage';\n\nexport type RouteResolution =\n | {\n type: 'page';\n pageData: LoadPageResult;\n }\n | {\n type: 'redirect';\n destination: string;\n permanent: boolean;\n }\n | {\n type: 'not-found';\n };\n\nexport type ResolveRouteParams = {\n /**\n * Builder client instance\n */\n client: RiverbankClient;\n\n /**\n * Site ID\n */\n siteId: string;\n\n /**\n * URL path to resolve (e.g., '/about', '/blog/post-1')\n */\n path: string;\n\n /**\n * If true, fetches draft/unpublished content instead of published content.\n * @default false\n */\n preview?: boolean;\n};\n\n/**\n * Resolve a URL path to page data, redirect, or 404\n *\n * This helper attempts to fetch the page at the given path and returns\n * a discriminated union indicating whether the page was found or not.\n *\n * **Note:** Redirect support is not yet implemented. The `redirect` type\n * exists in the return type for future compatibility, but this function\n * currently only returns `page` or `not-found` types.\n *\n * @example\n * ```tsx\n * import { resolveRoute } from '@riverbankcms/sdk/routing';\n * import { notFound, redirect } from 'next/navigation';\n *\n * export default async function DynamicPage({ params }) {\n * const path = `/${params.slug?.join('/') || ''}`;\n * const resolution = await resolveRoute({\n * client,\n * siteId: 'your-site-id',\n * path,\n * });\n *\n * if (resolution.type === 'redirect') {\n * redirect(resolution.destination);\n * }\n *\n * if (resolution.type === 'not-found') {\n * notFound();\n * }\n *\n * // resolution.type === 'page'\n * return <Page {...resolution.pageData} />;\n * }\n * ```\n */\nexport async function resolveRoute(\n params: ResolveRouteParams\n): Promise<RouteResolution> {\n const { client, siteId, path, preview = false } = params;\n\n try {\n // Attempt to fetch page data\n const pageResponse = await client.getPage({\n siteId,\n path,\n preview,\n });\n\n if (pageResponse) {\n // Successfully found page - load full page data\n const { loadPage } = await import('../rendering/helpers/loadPage');\n const pageData = await loadPage({\n client,\n siteId,\n path,\n preview,\n });\n\n return {\n type: 'page',\n pageData,\n };\n }\n } catch (error) {\n // Distinguish between expected 404s and unexpected errors\n const is404 = error instanceof Error &&\n (error.message.includes('404') ||\n error.message.includes('Not Found') ||\n error.message.includes('not found'));\n\n if (is404) {\n console.debug('[resolveRoute] Page not found', { path });\n } else {\n // Unexpected error - log as warning for visibility\n console.warn('[resolveRoute] Failed to fetch page', {\n path,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // No page found - return not-found\n // Note: Redirect support will be added when client.getRedirect() API is available\n return {\n type: 'not-found',\n };\n}\n\n/**\n * Batch resolve multiple routes in parallel\n *\n * Useful for pre-fetching multiple routes or validating a sitemap.\n *\n * @example\n * ```tsx\n * const resolutions = await resolveRoutes({\n * client,\n * siteId: 'your-site-id',\n * paths: ['/', '/about', '/blog', '/contact'],\n * });\n *\n * resolutions.forEach(({ path, resolution }) => {\n * if (resolution.type === 'page') {\n * console.log(`${path} → Page: ${resolution.pageData.page.name}`);\n * } else if (resolution.type === 'redirect') {\n * console.log(`${path} → Redirect to ${resolution.destination}`);\n * } else {\n * console.log(`${path} → Not found`);\n * }\n * });\n * ```\n */\nexport async function resolveRoutes(params: {\n client: RiverbankClient;\n siteId: string;\n paths: string[];\n preview?: boolean;\n}): Promise<Array<{ path: string; resolution: RouteResolution }>> {\n const { client, siteId, paths, preview } = params;\n\n const resolutions = await Promise.all(\n paths.map(async (path) => {\n const resolution = await resolveRoute({\n client,\n siteId,\n path,\n preview,\n });\n\n return { path, resolution };\n })\n );\n\n return resolutions;\n}\n","/**\n * Content route matching utilities.\n *\n * Derive route matching from SDK config to determine whether a URL path\n * is a CMS page or a content entry, without duplicating route patterns.\n */\n\nimport type { RiverbankSiteConfig, ContentTypeConfig } from '../config';\n\n/**\n * Extract the first path segment from each routable content type's routePattern.\n *\n * Useful for simple prefix-based routing decisions. For more precise matching\n * that handles nested patterns, use `isContentEntryPath` instead.\n *\n * @param config - The SDK config object from defineConfig()\n * @returns Array of first path segments from content type routePatterns\n *\n * @example\n * ```typescript\n * import { getContentEntryPrefixes } from '@riverbankcms/sdk/routing';\n * import config from '../riverbank.config';\n *\n * // Config with routePatterns: '/blog/{slug}', '/work/projects/{slug}'\n * const prefixes = getContentEntryPrefixes(config);\n * // Returns ['blog', 'work']\n * ```\n */\nexport function getContentEntryPrefixes(config: RiverbankSiteConfig): string[] {\n const contentTypes = config.content?.contentTypes ?? [];\n\n return contentTypes\n .filter((ct): ct is ContentTypeConfig & { routePattern: string } =>\n ct.hasPages && typeof ct.routePattern === 'string'\n )\n .map(ct => {\n // '/blog/{slug}' → 'blog'\n // '/work/projects/{slug}' → 'work'\n // '/{slug}' → undefined (no static prefix)\n const match = ct.routePattern.match(/^\\/([^/]+)/);\n const segment = match?.[1];\n // Skip dynamic segments (those containing {})\n if (segment?.includes('{')) return undefined;\n return segment;\n })\n .filter((prefix): prefix is string => typeof prefix === 'string');\n}\n\n/**\n * Result of checking if a path matches a content entry route.\n */\nexport type ContentEntryMatch = {\n /** Whether the path matches a content entry route pattern */\n isEntry: boolean;\n /** The content type key if matched (e.g., 'blog-post') */\n contentType?: string;\n /** The slug extracted from the path if matched */\n slug?: string;\n};\n\n/**\n * Check if a URL path matches any content entry route pattern.\n *\n * Supports nested patterns like '/work/projects/{slug}'. Returns the matched\n * content type key and extracted slug, useful for routing decisions.\n *\n * **Note:** Content types are checked in array order. If multiple patterns\n * could match a path, the first matching content type wins. Order more specific\n * patterns before generic ones in your config.\n *\n * @param config - The SDK config object from defineConfig()\n * @param path - URL path as string ('/blog/my-post') or segments ['blog', 'my-post']\n * @returns Match result with content type and slug if matched\n *\n * @example\n * ```typescript\n * import { isContentEntryPath } from '@riverbankcms/sdk/routing';\n * import config from '../riverbank.config';\n *\n * // Simple pattern: '/blog/{slug}'\n * isContentEntryPath(config, '/blog/my-post');\n * // Returns { isEntry: true, contentType: 'blog-post', slug: 'my-post' }\n *\n * // Nested pattern: '/work/projects/{slug}'\n * isContentEntryPath(config, '/work/projects/website-redesign');\n * // Returns { isEntry: true, contentType: 'project', slug: 'website-redesign' }\n *\n * // Non-matching path\n * isContentEntryPath(config, '/about');\n * // Returns { isEntry: false }\n * ```\n */\nexport function isContentEntryPath(\n config: RiverbankSiteConfig,\n path: string | string[]\n): ContentEntryMatch {\n const segments = typeof path === 'string'\n ? path.split('/').filter(Boolean)\n : path;\n\n const contentTypes = config.content?.contentTypes ?? [];\n\n for (const ct of contentTypes) {\n if (!ct.hasPages || !ct.routePattern) continue;\n\n // Parse pattern: '/blog/{slug}' → ['blog'], '/work/projects/{slug}' → ['work', 'projects']\n const patternSegments = parseRoutePattern(ct.routePattern);\n\n // Check if path segments match the pattern\n const match = matchPattern(segments, patternSegments);\n if (match.matches) {\n return {\n isEntry: true,\n contentType: ct.key,\n slug: match.slug,\n };\n }\n }\n\n return { isEntry: false };\n}\n\n/**\n * Parse a route pattern into static segments before {slug}.\n *\n * @example\n * parseRoutePattern('/blog/{slug}') // ['blog']\n * parseRoutePattern('/work/projects/{slug}') // ['work', 'projects']\n * parseRoutePattern('/{slug}') // []\n */\nfunction parseRoutePattern(pattern: string): string[] {\n const segments = pattern.split('/').filter(Boolean);\n const staticSegments: string[] = [];\n\n for (const segment of segments) {\n if (segment.includes('{')) break; // Stop at dynamic segment\n staticSegments.push(segment);\n }\n\n return staticSegments;\n}\n\n/**\n * Check if path segments match pattern segments.\n * Path must have at least one more segment than pattern (the slug).\n *\n * @returns Match result with extracted slug if matched\n */\nfunction matchPattern(\n pathSegments: string[],\n patternSegments: string[]\n): { matches: boolean; slug?: string } {\n // Path needs: pattern segments + at least 1 slug segment\n if (pathSegments.length < patternSegments.length + 1) {\n return { matches: false };\n }\n\n // All pattern segments must match exactly\n for (let i = 0; i < patternSegments.length; i++) {\n if (pathSegments[i] !== patternSegments[i]) {\n return { matches: false };\n }\n }\n\n // Extract slug (everything after the pattern segments)\n // For '/blog/{slug}' with path '/blog/my-post' → slug = 'my-post'\n // For nested slugs, join remaining segments (rare but supported)\n const slugSegments = pathSegments.slice(patternSegments.length);\n const slug = slugSegments.join('/');\n\n return { matches: true, slug };\n}\n"],"mappings":"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","names":[]}
@@ -1,8 +1,8 @@
1
- export { c as createRiverbankClient } from './index-Dj7VKH34.mjs';
2
- export { E as EntriesResponse, b as EntryResponse, P as PageResponse, R as RiverbankClient, a as RiverbankClientConfig, S as SiteResponse } from './types-BC9eB2KH.mjs';
3
- export { L as LoadPageParams, a as LoadPageResult, R as RuntimeSdkConfig, l as loadPage } from './loadPage-Dw57_n5N.mjs';
4
- export { C as ContentEntryData, E as EntryContentResult, L as LoadContentParams, b as LoadContentResult, P as PageContentResult, a as isEntryContent, i as isPageContent, l as loadContent } from './loadContent-Czu7xTOU.mjs';
5
- import './types-BA-J9K8r.mjs';
1
+ export { c as createRiverbankClient } from './index-DFQwtj3J.mjs';
2
+ export { E as EntriesResponse, b as EntryResponse, P as PageResponse, R as RiverbankClient, a as RiverbankClientConfig, S as SiteResponse } from './types-DkKEctWn.mjs';
3
+ export { L as LoadPageParams, a as LoadPageResult, R as RuntimeSdkConfig, l as loadPage } from './loadPage-B8RmlYgV.mjs';
4
+ export { C as ContentEntryData, E as EntryContentResult, L as LoadContentParams, b as LoadContentResult, P as PageContentResult, a as isEntryContent, i as isPageContent, l as loadContent } from './loadContent-CWuE8FCx.mjs';
5
+ import './types-CdrJqlKx.mjs';
6
6
  import '@riverbankcms/ai';
7
7
  import './schema-Bpy9N5ZI.mjs';
8
8
  import 'zod';
@@ -10,5 +10,5 @@ import '@riverbankcms/media-storage-supabase';
10
10
  import '@riverbankcms/db';
11
11
  import 'react/jsx-runtime';
12
12
  import 'react';
13
- import './types-BuZJWVmj.mjs';
13
+ import './types-CbagRQ_7.mjs';
14
14
  import './blockKinds-B6MWzNWp.mjs';
@@ -1,8 +1,8 @@
1
- export { c as createRiverbankClient } from './index-DbSfrRA0.js';
2
- export { E as EntriesResponse, b as EntryResponse, P as PageResponse, R as RiverbankClient, a as RiverbankClientConfig, S as SiteResponse } from './types-CAnC529E.js';
3
- export { L as LoadPageParams, a as LoadPageResult, R as RuntimeSdkConfig, l as loadPage } from './loadPage-BElEkA_J.js';
4
- export { C as ContentEntryData, E as EntryContentResult, L as LoadContentParams, b as LoadContentResult, P as PageContentResult, a as isEntryContent, i as isPageContent, l as loadContent } from './loadContent-BqQ-VPMW.js';
5
- import './types-5XdVD2J1.js';
1
+ export { c as createRiverbankClient } from './index-DCIz9Ptv.js';
2
+ export { E as EntriesResponse, b as EntryResponse, P as PageResponse, R as RiverbankClient, a as RiverbankClientConfig, S as SiteResponse } from './types-oCM-fw4O.js';
3
+ export { L as LoadPageParams, a as LoadPageResult, R as RuntimeSdkConfig, l as loadPage } from './loadPage-BTkKpizX.js';
4
+ export { C as ContentEntryData, E as EntryContentResult, L as LoadContentParams, b as LoadContentResult, P as PageContentResult, a as isEntryContent, i as isPageContent, l as loadContent } from './loadContent-DynBuR5f.js';
5
+ import './types-BiRZnxDx.js';
6
6
  import '@riverbankcms/ai';
7
7
  import './schema-Bpy9N5ZI.js';
8
8
  import 'zod';
@@ -10,5 +10,5 @@ import '@riverbankcms/media-storage-supabase';
10
10
  import '@riverbankcms/db';
11
11
  import 'react/jsx-runtime';
12
12
  import 'react';
13
- import './types-DSFvXKhO.js';
13
+ import './types-DuQCNVV0.js';
14
14
  import './blockKinds-B6MWzNWp.js';
@@ -8,8 +8,8 @@ var _chunkR5B6IOFQjs = require('./chunk-R5B6IOFQ.js');
8
8
  var _chunkTO7FD6TQjs = require('./chunk-TO7FD6TQ.js');
9
9
 
10
10
 
11
- var _chunkFPYK6527js = require('./chunk-FPYK6527.js');
12
- require('./chunk-G4CKM4EN.js');
11
+ var _chunkSWPHIUVEjs = require('./chunk-SWPHIUVE.js');
12
+ require('./chunk-Y7347JMZ.js');
13
13
  require('./chunk-HOY77YBF.js');
14
14
  require('./chunk-EGTDJ4PL.js');
15
15
  require('./chunk-DGUM43GV.js');
@@ -19,5 +19,5 @@ require('./chunk-DGUM43GV.js');
19
19
 
20
20
 
21
21
 
22
- exports.createRiverbankClient = _chunkR5B6IOFQjs.createRiverbankClient; exports.isEntryContent = _chunkTO7FD6TQjs.isEntryContent; exports.isPageContent = _chunkTO7FD6TQjs.isPageContent; exports.loadContent = _chunkTO7FD6TQjs.loadContent; exports.loadPage = _chunkFPYK6527js.loadPage;
22
+ exports.createRiverbankClient = _chunkR5B6IOFQjs.createRiverbankClient; exports.isEntryContent = _chunkTO7FD6TQjs.isEntryContent; exports.isPageContent = _chunkTO7FD6TQjs.isPageContent; exports.loadContent = _chunkTO7FD6TQjs.loadContent; exports.loadPage = _chunkSWPHIUVEjs.loadPage;
23
23
  //# sourceMappingURL=server.js.map
@@ -8,8 +8,8 @@ import {
8
8
  } from "./chunk-OP2GHK27.mjs";
9
9
  import {
10
10
  loadPage
11
- } from "./chunk-VVFYHAUD.mjs";
12
- import "./chunk-M5KTLZTD.mjs";
11
+ } from "./chunk-ZEAJW6T3.mjs";
12
+ import "./chunk-A2FZMRDW.mjs";
13
13
  import "./chunk-7DS4Q3GA.mjs";
14
14
  import "./chunk-USQF2XTU.mjs";
15
15
  import "./chunk-BJTO5JO5.mjs";
@@ -5,7 +5,7 @@
5
5
 
6
6
 
7
7
 
8
- var _chunkIT5ICP43js = require('./chunk-IT5ICP43.js');
8
+ var _chunkTKMA6D6Ujs = require('./chunk-TKMA6D6U.js');
9
9
  require('./chunk-EGTDJ4PL.js');
10
10
  require('./chunk-DGUM43GV.js');
11
11
 
@@ -147,7 +147,7 @@ ${cssLines}
147
147
  }
148
148
  function generateButtonsCss(config, corners, shadows) {
149
149
  const buttonConfig = _optionalChain([config, 'access', _7 => _7.components, 'optionalAccess', _8 => _8.buttons]);
150
- let variants = _chunkIT5ICP43js.getDefaultButtonVariants.call(void 0, );
150
+ let variants = _chunkTKMA6D6Ujs.getDefaultButtonVariants.call(void 0, );
151
151
  if (typeof buttonConfig === "object" && buttonConfig.variants) {
152
152
  const requestedIds = new Set(buttonConfig.variants);
153
153
  variants = variants.filter((v) => requestedIds.has(v.id));
@@ -159,11 +159,11 @@ function generateButtonsCss(config, corners, shadows) {
159
159
  fontWeight: 500,
160
160
  textTransform: "none"
161
161
  };
162
- return _chunkIT5ICP43js.generateButtonCoreCss.call(void 0, SCOPE_ID, variants, settings);
162
+ return _chunkTKMA6D6Ujs.generateButtonCoreCss.call(void 0, SCOPE_ID, variants, settings);
163
163
  }
164
164
  function generateCardsCss(config, corners, shadows) {
165
165
  const cardConfig = _optionalChain([config, 'access', _9 => _9.components, 'optionalAccess', _10 => _10.cards]);
166
- let variants = _chunkIT5ICP43js.getDefaultCardVariants.call(void 0, );
166
+ let variants = _chunkTKMA6D6Ujs.getDefaultCardVariants.call(void 0, );
167
167
  if (typeof cardConfig === "object" && cardConfig.variants) {
168
168
  const requestedIds = new Set(cardConfig.variants);
169
169
  variants = variants.filter((v) => requestedIds.has(v.id));
@@ -173,13 +173,13 @@ function generateCardsCss(config, corners, shadows) {
173
173
  shadow: shadows,
174
174
  borderWidth: "thin"
175
175
  };
176
- return _chunkIT5ICP43js.generateCardCoreCss.call(void 0, SCOPE_ID, variants, settings);
176
+ return _chunkTKMA6D6Ujs.generateCardCoreCss.call(void 0, SCOPE_ID, variants, settings);
177
177
  }
178
178
  function generateInputsCss(config, corners, shadows) {
179
- const settings = _chunkIT5ICP43js.getDefaultInputSettings.call(void 0, );
179
+ const settings = _chunkTKMA6D6Ujs.getDefaultInputSettings.call(void 0, );
180
180
  settings.corners = corners;
181
181
  settings.shadow = shadows === "none" ? "none" : "low";
182
- return _chunkIT5ICP43js.generateInputCoreCss.call(void 0, SCOPE_ID, settings);
182
+ return _chunkTKMA6D6Ujs.generateInputCoreCss.call(void 0, SCOPE_ID, settings);
183
183
  }
184
184
  function generateOverrideCss(overrides) {
185
185
  const chunks = [];
@@ -5,7 +5,7 @@ import {
5
5
  getDefaultButtonVariants,
6
6
  getDefaultCardVariants,
7
7
  getDefaultInputSettings
8
- } from "./chunk-NKXS4TBK.mjs";
8
+ } from "./chunk-TNRADRPH.mjs";
9
9
  import "./chunk-USQF2XTU.mjs";
10
10
  import "./chunk-BJTO5JO5.mjs";
11
11
 
@@ -2320,15 +2320,20 @@ type DevToolsSeedResponse = {
2320
2320
  blocksCreated: number;
2321
2321
  };
2322
2322
  };
2323
+ type SiteInvitee = {
2324
+ email: string;
2325
+ role: 'editor' | 'administrator';
2326
+ };
2323
2327
  type CreateManualSiteRequest = {
2324
2328
  title: string;
2329
+ deploymentMode?: 'managed' | 'headless_full';
2325
2330
  description?: string | null;
2326
- themeKey: string;
2327
- contentTypes: Array<'page' | 'post' | 'event' | 'testimonial'>;
2328
- scaffoldHome: boolean;
2329
- scaffoldContact: boolean;
2330
- scaffoldBlog: boolean;
2331
- invitees?: string[];
2331
+ themeKey?: string;
2332
+ contentTypes?: Array<'page' | 'post' | 'event' | 'testimonial'>;
2333
+ scaffoldHome?: boolean;
2334
+ scaffoldContact?: boolean;
2335
+ scaffoldBlog?: boolean;
2336
+ invitees?: SiteInvitee[];
2332
2337
  };
2333
2338
  type CreateManualSiteResponse = {
2334
2339
  siteId: string;
@@ -2346,6 +2351,10 @@ type CreateManualSiteResponse = {
2346
2351
  }>;
2347
2352
  contentTypes: Array<'page' | 'post' | 'event' | 'testimonial'>;
2348
2353
  };
2354
+ invitations?: {
2355
+ sent: number;
2356
+ failed: number;
2357
+ };
2349
2358
  };
2350
2359
  type APIEndpoints = {
2351
2360
  aiContentUpdateChat: APIEndpoint<{
@@ -3921,6 +3930,7 @@ type ContentTypeSummary = {
3921
3930
  hasPages: boolean;
3922
3931
  routePattern: string | null;
3923
3932
  isBuiltin: boolean;
3933
+ isSingleton: boolean;
3924
3934
  createdAt: string;
3925
3935
  updatedAt: string;
3926
3936
  };
@@ -3934,6 +3944,7 @@ type CreateContentTypeRequest = {
3934
3944
  description?: string | null;
3935
3945
  schema: Record<string, unknown>;
3936
3946
  titleField?: string | null;
3947
+ isSingleton?: boolean;
3937
3948
  };
3938
3949
  type UpdateContentTypeRequest = {
3939
3950
  name?: string;