@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.
- package/README.md +1892 -0
- package/dist/cli/index.js +327 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/client/analytics.d.mts +103 -0
- package/dist/client/analytics.d.ts +103 -0
- package/dist/client/analytics.js +197 -0
- package/dist/client/analytics.js.map +1 -0
- package/dist/client/analytics.mjs +169 -0
- package/dist/client/analytics.mjs.map +1 -0
- package/dist/client/bookings.d.mts +89 -0
- package/dist/client/bookings.d.ts +89 -0
- package/dist/client/bookings.js +34 -0
- package/dist/client/bookings.js.map +1 -0
- package/dist/client/bookings.mjs +11 -0
- package/dist/client/bookings.mjs.map +1 -0
- package/dist/client/client.d.mts +195 -0
- package/dist/client/client.d.ts +195 -0
- package/dist/client/client.js +606 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/client.mjs +572 -0
- package/dist/client/client.mjs.map +1 -0
- package/dist/client/hooks.d.mts +71 -0
- package/dist/client/hooks.d.ts +71 -0
- package/dist/client/hooks.js +264 -0
- package/dist/client/hooks.js.map +1 -0
- package/dist/client/hooks.mjs +235 -0
- package/dist/client/hooks.mjs.map +1 -0
- package/dist/client/rendering/client.d.mts +1 -0
- package/dist/client/rendering/client.d.ts +1 -0
- package/dist/client/rendering/client.js +33 -0
- package/dist/client/rendering/client.js.map +1 -0
- package/dist/client/rendering/client.mjs +8 -0
- package/dist/client/rendering/client.mjs.map +1 -0
- package/dist/client/usePage-BvKAa3Zw.d.mts +366 -0
- package/dist/client/usePage-BvKAa3Zw.d.ts +366 -0
- package/dist/server/chunk-2RW5HAQQ.mjs +86 -0
- package/dist/server/chunk-2RW5HAQQ.mjs.map +1 -0
- package/dist/server/chunk-3KKZVGH4.mjs +179 -0
- package/dist/server/chunk-3KKZVGH4.mjs.map +1 -0
- package/dist/server/chunk-4Z3GPTCS.js +179 -0
- package/dist/server/chunk-4Z3GPTCS.js.map +1 -0
- package/dist/server/chunk-4Z5FBFRL.mjs +211 -0
- package/dist/server/chunk-4Z5FBFRL.mjs.map +1 -0
- package/dist/server/chunk-ADREPXFU.js +86 -0
- package/dist/server/chunk-ADREPXFU.js.map +1 -0
- package/dist/server/chunk-F472SMKX.js +140 -0
- package/dist/server/chunk-F472SMKX.js.map +1 -0
- package/dist/server/chunk-GWBMJPLH.mjs +57 -0
- package/dist/server/chunk-GWBMJPLH.mjs.map +1 -0
- package/dist/server/chunk-JB4LIEFS.js +85 -0
- package/dist/server/chunk-JB4LIEFS.js.map +1 -0
- package/dist/server/chunk-PEAXKTDU.mjs +140 -0
- package/dist/server/chunk-PEAXKTDU.mjs.map +1 -0
- package/dist/server/chunk-QQ6U4QX6.js +120 -0
- package/dist/server/chunk-QQ6U4QX6.js.map +1 -0
- package/dist/server/chunk-R5YGLRUG.mjs +122 -0
- package/dist/server/chunk-R5YGLRUG.mjs.map +1 -0
- package/dist/server/chunk-SW7LE4M3.js +211 -0
- package/dist/server/chunk-SW7LE4M3.js.map +1 -0
- package/dist/server/chunk-W3K7LVPS.mjs +120 -0
- package/dist/server/chunk-W3K7LVPS.mjs.map +1 -0
- package/dist/server/chunk-WKG57P2H.mjs +85 -0
- package/dist/server/chunk-WKG57P2H.mjs.map +1 -0
- package/dist/server/chunk-YHEZMVTS.js +122 -0
- package/dist/server/chunk-YHEZMVTS.js.map +1 -0
- package/dist/server/chunk-YXDDFG3N.js +57 -0
- package/dist/server/chunk-YXDDFG3N.js.map +1 -0
- package/dist/server/components.d.mts +49 -0
- package/dist/server/components.d.ts +49 -0
- package/dist/server/components.js +22 -0
- package/dist/server/components.js.map +1 -0
- package/dist/server/components.mjs +22 -0
- package/dist/server/components.mjs.map +1 -0
- package/dist/server/config-validation.d.mts +300 -0
- package/dist/server/config-validation.d.ts +300 -0
- package/dist/server/config-validation.js +50 -0
- package/dist/server/config-validation.js.map +1 -0
- package/dist/server/config-validation.mjs +50 -0
- package/dist/server/config-validation.mjs.map +1 -0
- package/dist/server/config.d.mts +38 -0
- package/dist/server/config.d.ts +38 -0
- package/dist/server/config.js +44 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/config.mjs +44 -0
- package/dist/server/config.mjs.map +1 -0
- package/dist/server/data.d.mts +108 -0
- package/dist/server/data.d.ts +108 -0
- package/dist/server/data.js +15 -0
- package/dist/server/data.js.map +1 -0
- package/dist/server/data.mjs +15 -0
- package/dist/server/data.mjs.map +1 -0
- package/dist/server/index-B0yI_V6Z.d.mts +18 -0
- package/dist/server/index-C6M0Wfjq.d.ts +18 -0
- package/dist/server/index.d.mts +5 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +12 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +12 -0
- package/dist/server/index.mjs.map +1 -0
- package/dist/server/loadContent-CJcbYF3J.d.ts +152 -0
- package/dist/server/loadContent-zhlL4YSE.d.mts +152 -0
- package/dist/server/loadPage-BYmVMk0V.d.ts +216 -0
- package/dist/server/loadPage-CCf15nt8.d.mts +216 -0
- package/dist/server/loadPage-DVH3DW6E.js +9 -0
- package/dist/server/loadPage-DVH3DW6E.js.map +1 -0
- package/dist/server/loadPage-PHQZ6XQZ.mjs +9 -0
- package/dist/server/loadPage-PHQZ6XQZ.mjs.map +1 -0
- package/dist/server/metadata.d.mts +135 -0
- package/dist/server/metadata.d.ts +135 -0
- package/dist/server/metadata.js +68 -0
- package/dist/server/metadata.js.map +1 -0
- package/dist/server/metadata.mjs +68 -0
- package/dist/server/metadata.mjs.map +1 -0
- package/dist/server/rendering/server.d.mts +83 -0
- package/dist/server/rendering/server.d.ts +83 -0
- package/dist/server/rendering/server.js +14 -0
- package/dist/server/rendering/server.js.map +1 -0
- package/dist/server/rendering/server.mjs +14 -0
- package/dist/server/rendering/server.mjs.map +1 -0
- package/dist/server/rendering.d.mts +12 -0
- package/dist/server/rendering.d.ts +12 -0
- package/dist/server/rendering.js +40 -0
- package/dist/server/rendering.js.map +1 -0
- package/dist/server/rendering.mjs +40 -0
- package/dist/server/rendering.mjs.map +1 -0
- package/dist/server/routing.d.mts +115 -0
- package/dist/server/routing.d.ts +115 -0
- package/dist/server/routing.js +57 -0
- package/dist/server/routing.js.map +1 -0
- package/dist/server/routing.mjs +57 -0
- package/dist/server/routing.mjs.map +1 -0
- package/dist/server/server.d.mts +9 -0
- package/dist/server/server.d.ts +9 -0
- package/dist/server/server.js +21 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/server.mjs +21 -0
- package/dist/server/server.mjs.map +1 -0
- package/dist/server/theme-bridge.d.mts +232 -0
- package/dist/server/theme-bridge.d.ts +232 -0
- package/dist/server/theme-bridge.js +231 -0
- package/dist/server/theme-bridge.js.map +1 -0
- package/dist/server/theme-bridge.mjs +231 -0
- package/dist/server/theme-bridge.mjs.map +1 -0
- package/dist/server/theme.d.mts +40 -0
- package/dist/server/theme.d.ts +40 -0
- package/dist/server/theme.js +17 -0
- package/dist/server/theme.js.map +1 -0
- package/dist/server/theme.mjs +17 -0
- package/dist/server/theme.mjs.map +1 -0
- package/dist/server/types-BCeqWtI2.d.mts +333 -0
- package/dist/server/types-BCeqWtI2.d.ts +333 -0
- package/dist/server/types-Bbo01M7P.d.mts +76 -0
- package/dist/server/types-Bbo01M7P.d.ts +76 -0
- package/dist/server/types-C6gmRHLe.d.mts +150 -0
- package/dist/server/types-C6gmRHLe.d.ts +150 -0
- package/package.json +147 -0
- package/src/styles/index.css +10 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var commander = require('commander');
|
|
5
|
+
var zod = require('zod');
|
|
6
|
+
var blocks = require('@riverbankcms/blocks');
|
|
7
|
+
require('@riverbankcms/blocks/system/data');
|
|
8
|
+
var jiti = require('jiti');
|
|
9
|
+
var path = require('path');
|
|
10
|
+
var fs = require('fs');
|
|
11
|
+
|
|
12
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
13
|
+
var SUPPORTED_LOADER_ENDPOINTS = [
|
|
14
|
+
"listPublishedEntries",
|
|
15
|
+
"getPublishedEntryPreview",
|
|
16
|
+
"listPublicEvents",
|
|
17
|
+
"getPublicFormById",
|
|
18
|
+
"getPublicBookingServices"
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
// src/config/validation.ts
|
|
22
|
+
var sdkThemePaletteSchema = zod.z.record(zod.z.string(), zod.z.string());
|
|
23
|
+
var sdkThemeConfigSchema = zod.z.object({
|
|
24
|
+
palette: sdkThemePaletteSchema
|
|
25
|
+
});
|
|
26
|
+
var sectionBackgroundSchema = zod.z.object({
|
|
27
|
+
id: zod.z.string(),
|
|
28
|
+
label: zod.z.string(),
|
|
29
|
+
token: zod.z.string()
|
|
30
|
+
// Reference to theme palette token
|
|
31
|
+
});
|
|
32
|
+
var sectionSpacingSchema = zod.z.enum(["compact", "default", "spacious"]);
|
|
33
|
+
var containerMaxWidthSchema = zod.z.enum(["narrow", "default", "wide", "full"]);
|
|
34
|
+
var containerAlignmentSchema = zod.z.enum(["left", "center", "right"]);
|
|
35
|
+
var sectionOptionsSchema = zod.z.object({
|
|
36
|
+
backgroundColor: zod.z.boolean().optional(),
|
|
37
|
+
backgroundImage: zod.z.boolean().optional(),
|
|
38
|
+
backgroundGradient: zod.z.boolean().optional(),
|
|
39
|
+
spacing: zod.z.union([
|
|
40
|
+
zod.z.array(sectionSpacingSchema),
|
|
41
|
+
zod.z.boolean()
|
|
42
|
+
]).optional(),
|
|
43
|
+
textColor: zod.z.boolean().optional()
|
|
44
|
+
}).optional();
|
|
45
|
+
var containerOptionsSchema = zod.z.object({
|
|
46
|
+
maxWidth: zod.z.union([
|
|
47
|
+
zod.z.array(containerMaxWidthSchema),
|
|
48
|
+
zod.z.boolean()
|
|
49
|
+
]).optional(),
|
|
50
|
+
alignment: zod.z.union([
|
|
51
|
+
zod.z.array(containerAlignmentSchema),
|
|
52
|
+
zod.z.boolean()
|
|
53
|
+
]).optional()
|
|
54
|
+
}).optional();
|
|
55
|
+
var siteStyleConfigSchema = zod.z.object({
|
|
56
|
+
sectionBackgrounds: zod.z.array(sectionBackgroundSchema).optional(),
|
|
57
|
+
sectionOptions: sectionOptionsSchema,
|
|
58
|
+
containerOptions: containerOptionsSchema
|
|
59
|
+
}).optional();
|
|
60
|
+
var sdkLoaderEndpointSchema = zod.z.enum(SUPPORTED_LOADER_ENDPOINTS);
|
|
61
|
+
var loaderParamBindingSchema = zod.z.object({
|
|
62
|
+
$bind: zod.z.object({
|
|
63
|
+
from: zod.z.string().min(1, "Binding path is required"),
|
|
64
|
+
fallback: zod.z.string().optional()
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
var loaderParamValueSchema = zod.z.union([
|
|
68
|
+
zod.z.string(),
|
|
69
|
+
zod.z.number(),
|
|
70
|
+
zod.z.boolean(),
|
|
71
|
+
loaderParamBindingSchema
|
|
72
|
+
]);
|
|
73
|
+
var sdkConfigLoaderSchema = zod.z.object({
|
|
74
|
+
endpoint: sdkLoaderEndpointSchema,
|
|
75
|
+
params: zod.z.record(zod.z.string(), loaderParamValueSchema),
|
|
76
|
+
mode: zod.z.enum(["server", "client"]).default("server")
|
|
77
|
+
});
|
|
78
|
+
var sdkDataLoadersSchema = zod.z.record(zod.z.string(), sdkConfigLoaderSchema).refine(
|
|
79
|
+
(loaders) => Object.keys(loaders).length <= 5,
|
|
80
|
+
{ message: "Maximum 5 data loaders per block" }
|
|
81
|
+
).optional();
|
|
82
|
+
var fieldSelectOptionSchema = zod.z.object({
|
|
83
|
+
value: zod.z.string().min(1, "Option value is required"),
|
|
84
|
+
label: zod.z.string().min(1, "Option label is required")
|
|
85
|
+
});
|
|
86
|
+
var blockFieldConfigSchema = zod.z.object({
|
|
87
|
+
options: zod.z.array(fieldSelectOptionSchema).min(1, "At least one option is required").optional()
|
|
88
|
+
});
|
|
89
|
+
var blockFieldOptionsSchema = zod.z.record(
|
|
90
|
+
zod.z.string().regex(/^(block\.|custom\.)[a-z][a-z0-9-]*$/, {
|
|
91
|
+
message: "Block ID must be 'block.*' or 'custom.*' format"
|
|
92
|
+
}),
|
|
93
|
+
zod.z.record(
|
|
94
|
+
zod.z.string().min(1, "Field ID is required"),
|
|
95
|
+
blockFieldConfigSchema
|
|
96
|
+
)
|
|
97
|
+
).optional();
|
|
98
|
+
var blockFieldExtensionSchema = zod.z.object({
|
|
99
|
+
fields: blocks.fieldSchema.array().min(1, "At least one field is required")
|
|
100
|
+
}).refine(
|
|
101
|
+
(data) => {
|
|
102
|
+
return data.fields.every((field) => {
|
|
103
|
+
if (!field.required) return true;
|
|
104
|
+
return field.defaultValue !== void 0;
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
message: "Required fields must have a defaultValue to support existing blocks"
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
var blockFieldExtensionsSchema = zod.z.record(
|
|
112
|
+
zod.z.string().regex(/^block\.[a-z][a-zA-Z0-9]*$/, {
|
|
113
|
+
message: "Block ID must be 'block.*' format (system blocks only)"
|
|
114
|
+
}),
|
|
115
|
+
blockFieldExtensionSchema
|
|
116
|
+
).optional();
|
|
117
|
+
function validateFieldIdConflicts(blockFieldExtensions) {
|
|
118
|
+
if (!blockFieldExtensions) return [];
|
|
119
|
+
const conflicts = [];
|
|
120
|
+
for (const [blockId, extension] of Object.entries(blockFieldExtensions)) {
|
|
121
|
+
const definition = blocks.getBlockDefinition(blockId);
|
|
122
|
+
if (!definition) {
|
|
123
|
+
conflicts.push({
|
|
124
|
+
blockId,
|
|
125
|
+
fieldId: "",
|
|
126
|
+
message: `Unknown block type: ${blockId}`
|
|
127
|
+
});
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const existingFieldIds = /* @__PURE__ */ new Set();
|
|
131
|
+
const collectFieldIds = (fields) => {
|
|
132
|
+
if (!fields) return;
|
|
133
|
+
for (const field of fields) {
|
|
134
|
+
existingFieldIds.add(field.id);
|
|
135
|
+
if (field.type === "group" || field.type === "modal") {
|
|
136
|
+
collectFieldIds(field.schema?.fields);
|
|
137
|
+
} else if (field.type === "repeater" && field.schema?.fields) {
|
|
138
|
+
collectFieldIds(field.schema.fields);
|
|
139
|
+
} else if (field.type === "tabGroup") {
|
|
140
|
+
for (const tab of field.tabs ?? []) {
|
|
141
|
+
collectFieldIds(tab.fields);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
collectFieldIds(definition.manifest.fields);
|
|
147
|
+
for (const field of extension.fields) {
|
|
148
|
+
if (existingFieldIds.has(field.id)) {
|
|
149
|
+
conflicts.push({
|
|
150
|
+
blockId,
|
|
151
|
+
fieldId: field.id,
|
|
152
|
+
message: `Field ID "${field.id}" conflicts with existing field in ${blockId}`
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return conflicts;
|
|
158
|
+
}
|
|
159
|
+
var sdkCustomBlockSchema = zod.z.object({
|
|
160
|
+
// Block ID must start with 'custom.'
|
|
161
|
+
id: zod.z.string().min(8).regex(/^custom\.[a-z][a-z0-9-]*$/, {
|
|
162
|
+
message: "Block ID must start with 'custom.' followed by lowercase letters, numbers, or hyphens"
|
|
163
|
+
}),
|
|
164
|
+
title: zod.z.string().min(1, "Title is required"),
|
|
165
|
+
titleSource: zod.z.string().optional(),
|
|
166
|
+
description: zod.z.string().optional(),
|
|
167
|
+
category: blocks.blockCategoryEnum,
|
|
168
|
+
icon: zod.z.string().optional(),
|
|
169
|
+
tags: zod.z.array(zod.z.string()).optional(),
|
|
170
|
+
// Reuse the exact field schema from @riverbankcms/blocks - all field types supported
|
|
171
|
+
fields: blocks.fieldSchema.array().min(1, "Custom blocks must have at least one field"),
|
|
172
|
+
// Data loaders for CMS endpoints
|
|
173
|
+
dataLoaders: sdkDataLoadersSchema
|
|
174
|
+
}).refine(
|
|
175
|
+
// Validate titleSource references a valid field if provided
|
|
176
|
+
(data) => {
|
|
177
|
+
if (!data.titleSource) return true;
|
|
178
|
+
return data.fields.some((f) => f.id === data.titleSource);
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
message: "titleSource must reference a valid field ID",
|
|
182
|
+
path: ["titleSource"]
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
var riverbankSiteConfigSchema = zod.z.object({
|
|
186
|
+
siteId: zod.z.string().uuid(),
|
|
187
|
+
theme: sdkThemeConfigSchema.optional(),
|
|
188
|
+
styles: siteStyleConfigSchema,
|
|
189
|
+
customBlocks: zod.z.array(sdkCustomBlockSchema).max(20, "Maximum 20 custom blocks per site").refine(
|
|
190
|
+
// Ensure unique block IDs
|
|
191
|
+
(blocks) => {
|
|
192
|
+
const ids = blocks.map((b) => b.id);
|
|
193
|
+
return ids.length === new Set(ids).size;
|
|
194
|
+
},
|
|
195
|
+
{ message: "Block IDs must be unique" }
|
|
196
|
+
).optional(),
|
|
197
|
+
blockFieldOptions: blockFieldOptionsSchema,
|
|
198
|
+
blockFieldExtensions: blockFieldExtensionsSchema
|
|
199
|
+
}).strict();
|
|
200
|
+
var DEFAULT_CONFIG_FILENAME = "riverbank.config.ts";
|
|
201
|
+
async function loadConfigFile(configPath) {
|
|
202
|
+
const resolvedPath = resolveConfigPath(configPath);
|
|
203
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`Config file not found: ${resolvedPath}
|
|
206
|
+
Create a riverbank.config.ts file or specify a path with --config`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
console.log(`Loading config from ${resolvedPath}...`);
|
|
210
|
+
const jiti$1 = jiti.createJiti((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)), {
|
|
211
|
+
// Disable caching for CLI tool
|
|
212
|
+
fsCache: false,
|
|
213
|
+
moduleCache: false
|
|
214
|
+
});
|
|
215
|
+
try {
|
|
216
|
+
const configModule = await jiti$1.import(resolvedPath);
|
|
217
|
+
const config = configModule.default ?? configModule.config ?? configModule;
|
|
218
|
+
if (!config || typeof config !== "object") {
|
|
219
|
+
throw new Error("Config file must export a configuration object");
|
|
220
|
+
}
|
|
221
|
+
return config;
|
|
222
|
+
} catch (error) {
|
|
223
|
+
if (error instanceof Error) {
|
|
224
|
+
throw new Error(`Failed to load config: ${error.message}`);
|
|
225
|
+
}
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function resolveConfigPath(configPath) {
|
|
230
|
+
if (!configPath) {
|
|
231
|
+
return path.resolve(process.cwd(), DEFAULT_CONFIG_FILENAME);
|
|
232
|
+
}
|
|
233
|
+
const resolved = path.resolve(configPath);
|
|
234
|
+
if (fs.existsSync(resolved) && !resolved.endsWith(".ts") && !resolved.endsWith(".js")) {
|
|
235
|
+
return path.resolve(resolved, DEFAULT_CONFIG_FILENAME);
|
|
236
|
+
}
|
|
237
|
+
return resolved;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// src/cli/push-config.ts
|
|
241
|
+
async function pushToDashboard(dashboardUrl, siteId, apiKey, config) {
|
|
242
|
+
const pushUrl = `${dashboardUrl}/api/sites/${siteId}/sdk-config`;
|
|
243
|
+
console.log(`Pushing config to ${pushUrl}...`);
|
|
244
|
+
let response;
|
|
245
|
+
try {
|
|
246
|
+
response = await fetch(pushUrl, {
|
|
247
|
+
method: "POST",
|
|
248
|
+
headers: {
|
|
249
|
+
"Content-Type": "application/json",
|
|
250
|
+
"X-API-Key": apiKey
|
|
251
|
+
},
|
|
252
|
+
body: JSON.stringify({ config }),
|
|
253
|
+
signal: AbortSignal.timeout(3e4)
|
|
254
|
+
});
|
|
255
|
+
} catch (error) {
|
|
256
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
257
|
+
throw new Error(`Failed to connect to dashboard: ${message}`);
|
|
258
|
+
}
|
|
259
|
+
if (!response.ok) {
|
|
260
|
+
let errorMessage = `Dashboard returned ${response.status}`;
|
|
261
|
+
try {
|
|
262
|
+
const errorBody = await response.json();
|
|
263
|
+
if (errorBody.error) {
|
|
264
|
+
errorMessage = errorBody.error;
|
|
265
|
+
if (errorBody.details) {
|
|
266
|
+
errorMessage += ":\n" + errorBody.details.map((d) => ` - ${d.path}: ${d.message}`).join("\n");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} catch {
|
|
270
|
+
}
|
|
271
|
+
throw new Error(errorMessage);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
async function pushConfigAction(options) {
|
|
275
|
+
try {
|
|
276
|
+
const rawConfig = await loadConfigFile(options.config);
|
|
277
|
+
console.log("Validating config...");
|
|
278
|
+
const parseResult = riverbankSiteConfigSchema.safeParse(rawConfig);
|
|
279
|
+
if (!parseResult.success) {
|
|
280
|
+
console.error("Invalid config:");
|
|
281
|
+
for (const issue of parseResult.error.issues) {
|
|
282
|
+
console.error(` - ${issue.path.join(".")}: ${issue.message}`);
|
|
283
|
+
}
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
const conflicts = validateFieldIdConflicts(parseResult.data.blockFieldExtensions);
|
|
287
|
+
if (conflicts.length > 0) {
|
|
288
|
+
console.error("Field ID conflicts detected in blockFieldExtensions:");
|
|
289
|
+
for (const conflict of conflicts) {
|
|
290
|
+
console.error(` - ${conflict.message}`);
|
|
291
|
+
}
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
const { siteId } = parseResult.data;
|
|
295
|
+
await pushToDashboard(
|
|
296
|
+
options.dashboard,
|
|
297
|
+
siteId,
|
|
298
|
+
options.apiKey,
|
|
299
|
+
parseResult.data
|
|
300
|
+
);
|
|
301
|
+
console.log("Config pushed successfully!");
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
304
|
+
process.exit(1);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function resolveDashboardUrl(cliOption) {
|
|
308
|
+
const url = cliOption || process.env.NEXT_PUBLIC_DASHBOARD_URL;
|
|
309
|
+
if (!url) {
|
|
310
|
+
console.error("Error: Dashboard URL is required.");
|
|
311
|
+
console.error("Provide --dashboard <url> or set NEXT_PUBLIC_DASHBOARD_URL environment variable.");
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
return url;
|
|
315
|
+
}
|
|
316
|
+
var pushConfigCommand = new commander.Command("push-config").description("Push SDK config from riverbank.config.ts to dashboard").requiredOption("--api-key <key>", "Dashboard API key").option("--config <path>", "Path to riverbank.config.ts (default: ./riverbank.config.ts)").option("--dashboard <url>", "Dashboard API URL (or set NEXT_PUBLIC_DASHBOARD_URL)").action((options) => {
|
|
317
|
+
const dashboard = resolveDashboardUrl(options.dashboard);
|
|
318
|
+
return pushConfigAction({ ...options, dashboard });
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// src/cli/index.ts
|
|
322
|
+
var program = new commander.Command();
|
|
323
|
+
program.name("riverbankcms").description("Builder SDK CLI tools").version("0.1.0");
|
|
324
|
+
program.addCommand(pushConfigCommand);
|
|
325
|
+
program.parse();
|
|
326
|
+
//# sourceMappingURL=index.js.map
|
|
327
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data/prefetchBlockData.ts","../../src/config/validation.ts","../../src/cli/load-config.ts","../../src/cli/push-config.ts","../../src/cli/index.ts"],"names":["z","fieldSchema","getBlockDefinition","blockCategoryEnum","existsSync","jiti","createJiti","resolve","Command"],"mappings":";;;;;;;;;;;;AAqBO,IAAM,0BAAA,GAA6B;AAAA,EACxC,sBAAA;AAAA,EACA,0BAAA;AAAA,EACA,kBAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAAA;;;ACZO,IAAM,qBAAA,GAAwBA,MAAE,MAAA,CAAOA,KAAA,CAAE,QAAO,EAAGA,KAAA,CAAE,QAAQ,CAAA;AAK7D,IAAM,oBAAA,GAAuBA,MAAE,MAAA,CAAO;AAAA,EAC3C,OAAA,EAAS;AACX,CAAC,CAAA;AAKM,IAAM,uBAAA,GAA0BA,MAAE,MAAA,CAAO;AAAA,EAC9C,EAAA,EAAIA,MAAE,MAAA,EAAO;AAAA,EACb,KAAA,EAAOA,MAAE,MAAA,EAAO;AAAA,EAChB,KAAA,EAAOA,MAAE,MAAA;AAAO;AAClB,CAAC,CAAA;AAKM,IAAM,uBAAuBA,KAAA,CAAE,IAAA,CAAK,CAAC,SAAA,EAAW,SAAA,EAAW,UAAU,CAAC,CAAA;AAKtE,IAAM,uBAAA,GAA0BA,MAAE,IAAA,CAAK,CAAC,UAAU,SAAA,EAAW,MAAA,EAAQ,MAAM,CAAC,CAAA;AAK5E,IAAM,2BAA2BA,KAAA,CAAE,IAAA,CAAK,CAAC,MAAA,EAAQ,QAAA,EAAU,OAAO,CAAC,CAAA;AAKnE,IAAM,oBAAA,GAAuBA,MAAE,MAAA,CAAO;AAAA,EAC3C,eAAA,EAAiBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACtC,eAAA,EAAiBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACtC,kBAAA,EAAoBA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,EAAS;AAAA,EACzC,OAAA,EAASA,MAAE,KAAA,CAAM;AAAA,IACfA,KAAA,CAAE,MAAM,oBAAoB,CAAA;AAAA,IAC5BA,MAAE,OAAA;AAAQ,GACX,EAAE,QAAA,EAAS;AAAA,EACZ,SAAA,EAAWA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAA;AACzB,CAAC,EAAE,QAAA,EAAS;AAKL,IAAM,sBAAA,GAAyBA,MAAE,MAAA,CAAO;AAAA,EAC7C,QAAA,EAAUA,MAAE,KAAA,CAAM;AAAA,IAChBA,KAAA,CAAE,MAAM,uBAAuB,CAAA;AAAA,IAC/BA,MAAE,OAAA;AAAQ,GACX,EAAE,QAAA,EAAS;AAAA,EACZ,SAAA,EAAWA,MAAE,KAAA,CAAM;AAAA,IACjBA,KAAA,CAAE,MAAM,wBAAwB,CAAA;AAAA,IAChCA,MAAE,OAAA;AAAQ,GACX,EAAE,QAAA;AACL,CAAC,EAAE,QAAA,EAAS;AAKL,IAAM,qBAAA,GAAwBA,MAAE,MAAA,CAAO;AAAA,EAC5C,kBAAA,EAAoBA,KAAA,CAAE,KAAA,CAAM,uBAAuB,EAAE,QAAA,EAAS;AAAA,EAC9D,cAAA,EAAgB,oBAAA;AAAA,EAChB,gBAAA,EAAkB;AACpB,CAAC,EAAE,QAAA,EAAS;AAgBL,IAAM,uBAAA,GAA0BA,KAAA,CAAE,IAAA,CAAK,0BAA0B,CAAA;AAYjE,IAAM,wBAAA,GAA2BA,MAAE,MAAA,CAAO;AAAA,EAC/C,KAAA,EAAOA,MAAE,MAAA,CAAO;AAAA,IACd,MAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,0BAA0B,CAAA;AAAA,IAClD,QAAA,EAAUA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GAC/B;AACH,CAAC,CAAA;AAKM,IAAM,sBAAA,GAAyBA,MAAE,KAAA,CAAM;AAAA,EAC5CA,MAAE,MAAA,EAAO;AAAA,EACTA,MAAE,MAAA,EAAO;AAAA,EACTA,MAAE,OAAA,EAAQ;AAAA,EACV;AACF,CAAC,CAAA;AAQM,IAAM,qBAAA,GAAwBA,MAAE,MAAA,CAAO;AAAA,EAC5C,QAAA,EAAU,uBAAA;AAAA,EACV,QAAQA,KAAA,CAAE,MAAA,CAAOA,KAAA,CAAE,MAAA,IAAU,sBAAsB,CAAA;AAAA,EACnD,IAAA,EAAMA,MAAE,IAAA,CAAK,CAAC,UAAU,QAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,QAAQ;AACrD,CAAC,CAAA;AAMM,IAAM,uBAAuBA,KAAA,CAAE,MAAA,CAAOA,MAAE,MAAA,EAAO,EAAG,qBAAqB,CAAA,CAC3E,MAAA;AAAA,EACC,CAAC,OAAA,KAAY,MAAA,CAAO,IAAA,CAAK,OAAO,EAAE,MAAA,IAAU,CAAA;AAAA,EAC5C,EAAE,SAAS,kCAAA;AACb,CAAA,CACC,QAAA,EAAS;AASL,IAAM,uBAAA,GAA0BA,MAAE,MAAA,CAAO;AAAA,EAC9C,OAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,0BAA0B,CAAA;AAAA,EACnD,OAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,0BAA0B;AACrD,CAAC,CAAA;AAKM,IAAM,sBAAA,GAAyBA,MAAE,MAAA,CAAO;AAAA,EAC7C,OAAA,EAASA,MAAE,KAAA,CAAM,uBAAuB,EAAE,GAAA,CAAI,CAAA,EAAG,iCAAiC,CAAA,CAAE,QAAA;AACtF,CAAC,CAAA;AAQM,IAAM,0BAA2DA,KAAA,CAAE,MAAA;AAAA,EACxEA,KAAA,CAAE,MAAA,EAAO,CAAE,KAAA,CAAM,qCAAA,EAAuC;AAAA,IACtD,OAAA,EAAS;AAAA,GACV,CAAA;AAAA,EACDA,KAAA,CAAE,MAAA;AAAA,IACAA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,sBAAsB,CAAA;AAAA,IACxC;AAAA;AAEJ,CAAA,CAAE,QAAA,EAAS;AAcJ,IAAM,yBAAA,GAA4DA,MAAE,MAAA,CAAO;AAAA,EAChF,QAAQC,kBAAA,CAAY,KAAA,EAAM,CAAE,GAAA,CAAI,GAAG,gCAAgC;AACrE,CAAC,CAAA,CAAE,MAAA;AAAA,EACD,CAAC,IAAA,KAAS;AAER,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAC,KAAA,KAA2B;AACnD,MAAA,IAAI,CAAC,KAAA,CAAM,QAAA,EAAU,OAAO,IAAA;AAC5B,MAAA,OAAO,MAAM,YAAA,KAAiB,MAAA;AAAA,IAChC,CAAC,CAAA;AAAA,EACH,CAAA;AAAA,EACA;AAAA,IACE,OAAA,EAAS;AAAA;AAEb,CAAA;AAQO,IAAM,6BAA6ED,KAAA,CAAE,MAAA;AAAA,EAC1FA,KAAA,CAAE,MAAA,EAAO,CAAE,KAAA,CAAM,4BAAA,EAA8B;AAAA,IAC7C,OAAA,EAAS;AAAA,GACV,CAAA;AAAA,EACD;AACF,CAAA,CAAE,QAAA,EAAS;AAgBJ,SAAS,yBACd,oBAAA,EACyD;AACzD,EAAA,IAAI,CAAC,oBAAA,EAAsB,OAAO,EAAC;AAEnC,EAAA,MAAM,YAAqE,EAAC;AAE5E,EAAA,KAAA,MAAW,CAAC,OAAA,EAAS,SAAS,KAAK,MAAA,CAAO,OAAA,CAAQ,oBAAoB,CAAA,EAAG;AACvE,IAAA,MAAM,UAAA,GAAaE,0BAAmB,OAAO,CAAA;AAC7C,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,SAAA,CAAU,IAAA,CAAK;AAAA,QACb,OAAA;AAAA,QACA,OAAA,EAAS,EAAA;AAAA,QACT,OAAA,EAAS,uBAAuB,OAAO,CAAA;AAAA,OACxC,CAAA;AACD,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,gBAAA,uBAAuB,GAAA,EAAY;AACzC,IAAA,MAAM,eAAA,GAAkB,CAAC,MAAA,KAA0C;AACjE,MAAA,IAAI,CAAC,MAAA,EAAQ;AACb,MAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,QAAA,gBAAA,CAAiB,GAAA,CAAI,MAAM,EAAE,CAAA;AAE7B,QAAA,IAAI,KAAA,CAAM,IAAA,KAAS,OAAA,IAAW,KAAA,CAAM,SAAS,OAAA,EAAS;AACpD,UAAA,eAAA,CAAgB,KAAA,CAAM,QAAQ,MAAM,CAAA;AAAA,QACtC,WAAW,KAAA,CAAM,IAAA,KAAS,UAAA,IAAc,KAAA,CAAM,QAAQ,MAAA,EAAQ;AAC5D,UAAA,eAAA,CAAgB,KAAA,CAAM,OAAO,MAAM,CAAA;AAAA,QACrC,CAAA,MAAA,IAAW,KAAA,CAAM,IAAA,KAAS,UAAA,EAAY;AACpC,UAAA,KAAA,MAAW,GAAA,IAAO,KAAA,CAAM,IAAA,IAAQ,EAAC,EAAG;AAClC,YAAA,eAAA,CAAgB,IAAI,MAAM,CAAA;AAAA,UAC5B;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AACA,IAAA,eAAA,CAAgB,UAAA,CAAW,SAAS,MAAM,CAAA;AAG1C,IAAA,KAAA,MAAW,KAAA,IAAS,UAAU,MAAA,EAAQ;AACpC,MAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,KAAA,CAAM,EAAE,CAAA,EAAG;AAClC,QAAA,SAAA,CAAU,IAAA,CAAK;AAAA,UACb,OAAA;AAAA,UACA,SAAS,KAAA,CAAM,EAAA;AAAA,UACf,OAAA,EAAS,CAAA,UAAA,EAAa,KAAA,CAAM,EAAE,sCAAsC,OAAO,CAAA;AAAA,SAC5E,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,SAAA;AACT;AAUO,IAAM,oBAAA,GAAkDF,MAAE,MAAA,CAAO;AAAA;AAAA,EAEtE,EAAA,EAAIA,MAAE,MAAA,EAAO,CACV,IAAI,CAAC,CAAA,CACL,MAAM,2BAAA,EAA6B;AAAA,IAClC,OAAA,EAAS;AAAA,GACV,CAAA;AAAA,EACH,OAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,mBAAmB,CAAA;AAAA,EAC5C,WAAA,EAAaA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,WAAA,EAAaA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,QAAA,EAAUG,wBAAA;AAAA,EACV,IAAA,EAAMH,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,MAAMA,KAAA,CAAE,KAAA,CAAMA,MAAE,MAAA,EAAQ,EAAE,QAAA,EAAS;AAAA;AAAA,EAEnC,QAAQC,kBAAA,CAAY,KAAA,EAAM,CAAE,GAAA,CAAI,GAAG,4CAA4C,CAAA;AAAA;AAAA,EAE/E,WAAA,EAAa;AACf,CAAC,CAAA,CAAE,MAAA;AAAA;AAAA,EAED,CAAC,IAAA,KAAS;AACR,IAAA,IAAI,CAAC,IAAA,CAAK,WAAA,EAAa,OAAO,IAAA;AAC9B,IAAA,OAAO,KAAK,MAAA,CAAO,IAAA,CAAK,OAAK,CAAA,CAAE,EAAA,KAAO,KAAK,WAAW,CAAA;AAAA,EACxD,CAAA;AAAA,EACA;AAAA,IACE,OAAA,EAAS,6CAAA;AAAA,IACT,IAAA,EAAM,CAAC,aAAa;AAAA;AAExB,CAAA;AAgBO,IAAM,yBAAA,GAA4DD,MAAE,MAAA,CAAO;AAAA,EAChF,MAAA,EAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAA,EAAK;AAAA,EACxB,KAAA,EAAO,qBAAqB,QAAA,EAAS;AAAA,EACrC,MAAA,EAAQ,qBAAA;AAAA,EACR,YAAA,EAAcA,MAAE,KAAA,CAAM,oBAAoB,EACvC,GAAA,CAAI,EAAA,EAAI,mCAAmC,CAAA,CAC3C,MAAA;AAAA;AAAA,IAEC,CAAC,MAAA,KAAW;AACV,MAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,CAAI,CAAA,CAAA,KAAK,EAAE,EAAE,CAAA;AAChC,MAAA,OAAO,GAAA,CAAI,MAAA,KAAW,IAAI,GAAA,CAAI,GAAG,CAAA,CAAE,IAAA;AAAA,IACrC,CAAA;AAAA,IACA,EAAE,SAAS,0BAAA;AAA2B,IAEvC,QAAA,EAAS;AAAA,EACZ,iBAAA,EAAmB,uBAAA;AAAA,EACnB,oBAAA,EAAsB;AACxB,CAAC,EAAE,MAAA,EAAO;AC9VV,IAAM,uBAAA,GAA0B,qBAAA;AAShC,eAAsB,eAAe,UAAA,EAAuC;AAE1E,EAAA,MAAM,YAAA,GAAe,kBAAkB,UAAU,CAAA;AAEjD,EAAA,IAAI,CAACI,aAAA,CAAW,YAAY,CAAA,EAAG;AAC7B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,0BAA0B,YAAY;AAAA,iEAAA;AAAA,KAExC;AAAA,EACF;AAEA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,oBAAA,EAAuB,YAAY,CAAA,GAAA,CAAK,CAAA;AAGpD,EAAA,MAAMC,MAAA,GAAOC,eAAA,CAAW,0PAAY,EAAK;AAAA;AAAA,IAEvC,OAAA,EAAS,KAAA;AAAA,IACT,WAAA,EAAa;AAAA,GACd,CAAA;AAED,EAAA,IAAI;AAEF,IAAA,MAAM,YAAA,GAAe,MAAMD,MAAA,CAAK,MAAA,CAAO,YAAY,CAAA;AAGnD,IAAA,MAAM,MAAA,GAAU,YAAA,CAAyC,OAAA,IACnD,YAAA,CAAyC,MAAA,IAC1C,YAAA;AAEL,IAAA,IAAI,CAAC,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,EAAU;AACzC,MAAA,MAAM,IAAI,MAAM,gDAAgD,CAAA;AAAA,IAClE;AAEA,IAAA,OAAO,MAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,iBAAiB,KAAA,EAAO;AAC1B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0B,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,IAC3D;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AACF;AASA,SAAS,kBAAkB,UAAA,EAA6B;AACtD,EAAA,IAAI,CAAC,UAAA,EAAY;AAEf,IAAA,OAAOE,YAAA,CAAQ,OAAA,CAAQ,GAAA,EAAI,EAAG,uBAAuB,CAAA;AAAA,EACvD;AAEA,EAAA,MAAM,QAAA,GAAWA,aAAQ,UAAU,CAAA;AAGnC,EAAA,IAAIH,aAAA,CAAW,QAAQ,CAAA,IAAK,CAAC,QAAA,CAAS,QAAA,CAAS,KAAK,CAAA,IAAK,CAAC,QAAA,CAAS,QAAA,CAAS,KAAK,CAAA,EAAG;AAClF,IAAA,OAAOG,YAAA,CAAQ,UAAU,uBAAuB,CAAA;AAAA,EAClD;AAGA,EAAA,OAAO,QAAA;AACT;;;ACjEA,eAAe,eAAA,CACb,YAAA,EACA,MAAA,EACA,MAAA,EACA,MAAA,EACe;AACf,EAAA,MAAM,OAAA,GAAU,CAAA,EAAG,YAAY,CAAA,WAAA,EAAc,MAAM,CAAA,WAAA,CAAA;AACnD,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,kBAAA,EAAqB,OAAO,CAAA,GAAA,CAAK,CAAA;AAE7C,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,MAAM,OAAA,EAAS;AAAA,MAC9B,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB,kBAAA;AAAA,QAChB,WAAA,EAAa;AAAA,OACf;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,QAAQ,CAAA;AAAA,MAC/B,MAAA,EAAQ,WAAA,CAAY,OAAA,CAAQ,GAAK;AAAA,KAClC,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,OAAA,GAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,eAAA;AACzD,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,OAAO,CAAA,CAAE,CAAA;AAAA,EAC9D;AAEA,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,IAAA,IAAI,YAAA,GAAe,CAAA,mBAAA,EAAsB,QAAA,CAAS,MAAM,CAAA,CAAA;AACxD,IAAA,IAAI;AACF,MAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,IAAA,EAAK;AACtC,MAAA,IAAI,UAAU,KAAA,EAAO;AACnB,QAAA,YAAA,GAAe,SAAA,CAAU,KAAA;AACzB,QAAA,IAAI,UAAU,OAAA,EAAS;AACrB,UAAA,YAAA,IAAgB,KAAA,GAAQ,SAAA,CAAU,OAAA,CAC/B,GAAA,CAAI,CAAC,CAAA,KAAyC,CAAA,IAAA,EAAO,CAAA,CAAE,IAAI,KAAK,CAAA,CAAE,OAAO,CAAA,CAAE,CAAA,CAC3E,KAAK,IAAI,CAAA;AAAA,QACd;AAAA,MACF;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,MAAM,IAAI,MAAM,YAAY,CAAA;AAAA,EAC9B;AACF;AAKA,eAAe,iBAAiB,OAAA,EAA2C;AACzE,EAAA,IAAI;AAEF,IAAA,MAAM,SAAA,GAAY,MAAM,cAAA,CAAe,OAAA,CAAQ,MAAM,CAAA;AAGrD,IAAA,OAAA,CAAQ,IAAI,sBAAsB,CAAA;AAClC,IAAA,MAAM,WAAA,GAAc,yBAAA,CAA0B,SAAA,CAAU,SAAS,CAAA;AACjE,IAAA,IAAI,CAAC,YAAY,OAAA,EAAS;AACxB,MAAA,OAAA,CAAQ,MAAM,iBAAiB,CAAA;AAC/B,MAAA,KAAA,MAAW,KAAA,IAAS,WAAA,CAAY,KAAA,CAAM,MAAA,EAAQ;AAC5C,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,IAAA,EAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAAA,MAC/D;AACA,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB;AAGA,IAAA,MAAM,SAAA,GAAY,wBAAA,CAAyB,WAAA,CAAY,IAAA,CAAK,oBAAoB,CAAA;AAChF,IAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EAAG;AACxB,MAAA,OAAA,CAAQ,MAAM,sDAAsD,CAAA;AACpE,MAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,QAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,IAAA,EAAO,QAAA,CAAS,OAAO,CAAA,CAAE,CAAA;AAAA,MACzC;AACA,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB;AAEA,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,WAAA,CAAY,IAAA;AAG/B,IAAA,MAAM,eAAA;AAAA,MACJ,OAAA,CAAQ,SAAA;AAAA,MACR,MAAA;AAAA,MACA,OAAA,CAAQ,MAAA;AAAA,MACR,WAAA,CAAY;AAAA,KACd;AAEA,IAAA,OAAA,CAAQ,IAAI,6BAA6B,CAAA;AAAA,EAC3C,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,MAAM,QAAA,EAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,UAAU,KAAK,CAAA;AACtE,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF;AAMA,SAAS,oBAAoB,SAAA,EAA4B;AACvD,EAAA,MAAM,GAAA,GAAM,SAAA,IAAa,OAAA,CAAQ,GAAA,CAAI,yBAAA;AACrC,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,OAAA,CAAQ,MAAM,mCAAmC,CAAA;AACjD,IAAA,OAAA,CAAQ,MAAM,kFAAkF,CAAA;AAChG,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,GAAA;AACT;AAKO,IAAM,iBAAA,GAAoB,IAAIC,iBAAA,CAAQ,aAAa,EACvD,WAAA,CAAY,uDAAuD,CAAA,CACnE,cAAA,CAAe,iBAAA,EAAmB,mBAAmB,EACrD,MAAA,CAAO,iBAAA,EAAmB,8DAA8D,CAAA,CACxF,MAAA,CAAO,qBAAqB,sDAAsD,CAAA,CAClF,MAAA,CAAO,CAAC,OAAA,KAA2E;AAClF,EAAA,MAAM,SAAA,GAAY,mBAAA,CAAoB,OAAA,CAAQ,SAAS,CAAA;AACvD,EAAA,OAAO,gBAAA,CAAiB,EAAE,GAAG,OAAA,EAAS,WAAW,CAAA;AACnD,CAAC,CAAA;;;AC7HH,IAAM,OAAA,GAAU,IAAIA,iBAAAA,EAAQ;AAE5B,OAAA,CACG,KAAK,cAAc,CAAA,CACnB,YAAY,uBAAuB,CAAA,CACnC,QAAQ,OAAO,CAAA;AAGlB,OAAA,CAAQ,WAAW,iBAAiB,CAAA;AAEpC,OAAA,CAAQ,KAAA,EAAM","file":"index.js","sourcesContent":["/**\n * SDK wrapper for block data prefetching.\n * Uses the shared core implementation from @riverbankcms/blocks with the SDK client.\n */\n\nimport type { BlockDataLoader, PageOutline, SdkCustomBlock } from '@riverbankcms/blocks';\nimport { prefetchBlockData as prefetchBlockDataCore } from '@riverbankcms/blocks/system/data';\nimport type { PrefetchContext, ResolvedBlockData } from '@riverbankcms/blocks/system/data';\nimport type { RiverbankClient } from '../client/types';\n\nexport type { PrefetchContext, ResolvedBlockData };\n\n/**\n * Supported loader endpoints for SDK data fetching.\n * Only these endpoints can be used in block data loaders when using the SDK.\n *\n * This is the SINGLE SOURCE OF TRUTH for whitelisted endpoints.\n * - Zod validation schema derives from this array\n * - TypeScript types derive from this array\n * - Runtime validation uses this array\n */\nexport const SUPPORTED_LOADER_ENDPOINTS = [\n 'listPublishedEntries',\n 'getPublishedEntryPreview',\n 'listPublicEvents',\n 'getPublicFormById',\n 'getPublicBookingServices',\n] as const;\n\n/**\n * Union type of all supported loader endpoints.\n * Derived from SUPPORTED_LOADER_ENDPOINTS array.\n */\nexport type SupportedLoaderEndpoint = typeof SUPPORTED_LOADER_ENDPOINTS[number];\n\n/**\n * Options for SDK block data prefetching.\n */\nexport type SdkPrefetchOptions = {\n /**\n * SDK custom blocks from site config.\n * Used to look up data loaders for custom.* blocks.\n */\n customBlocks?: SdkCustomBlock[];\n};\n\n/**\n * Prefetch block data for SDK-based applications.\n * Maps loader endpoints to corresponding SDK client methods.\n *\n * Supports both system blocks and SDK custom blocks with data loaders.\n *\n * @example\n * ```typescript\n * import { createRiverbankClient } from '@riverbankcms/sdk';\n * import { prefetchBlockData } from '@riverbankcms/sdk/data';\n *\n * const client = createRiverbankClient({ apiKey, baseUrl });\n * const page = await client.getPage({ siteId, path: '/' });\n *\n * // Basic usage (system blocks only)\n * const blockData = await prefetchBlockData(page.outline, {\n * siteId: page.siteId,\n * pageId: page.id,\n * }, client);\n *\n * // With custom blocks from SDK config\n * const blockData = await prefetchBlockData(page.outline, context, client, {\n * customBlocks: site.sdkConfig?.customBlocks,\n * });\n * ```\n */\nexport async function prefetchBlockData(\n page: PageOutline,\n context: PrefetchContext,\n client: RiverbankClient,\n options?: SdkPrefetchOptions,\n): Promise<ResolvedBlockData> {\n const { customBlocks } = options ?? {};\n\n // Build lookup map for custom block loaders\n // Key is string (blockKind from page) matching block.id (custom.xxx)\n const customBlockMap = new Map<string, SdkCustomBlock>(\n (customBlocks ?? []).map((block) => [block.id as string, block])\n );\n\n return prefetchBlockDataCore(page, context, {\n apiClient: async ({ endpoint, params }) => {\n // Only support whitelisted loader endpoints\n if (!isSupportedEndpoint(endpoint)) {\n throw new Error(\n `Unsupported loader endpoint: ${endpoint}. ` +\n `SDK only supports: ${SUPPORTED_LOADER_ENDPOINTS.join(', ')}`\n );\n }\n\n // Map endpoint to SDK client method\n switch (endpoint) {\n case 'listPublishedEntries': {\n const { siteId, type, orderBy, limit, stage, mode, entryIds } = params ?? {};\n if (!siteId || !type) {\n throw new Error('listPublishedEntries requires siteId and type params');\n }\n\n // Parse limit if provided (can come as string from bindings)\n const parsedLimit = typeof limit === 'string'\n ? Number.parseInt(limit, 10)\n : typeof limit === 'number'\n ? limit\n : undefined;\n\n // Map orderBy to order param (matching embed block field values)\n const order = (orderBy === 'newest' || orderBy === 'oldest' || orderBy === 'title' || orderBy === 'order')\n ? orderBy as 'newest' | 'oldest' | 'title' | 'order'\n : undefined;\n\n // Extract entry IDs for manual mode\n // entryIds comes from binding to entries field which contains { entryId: \"uuid\" } objects\n let parsedEntryIds: string[] | undefined;\n if (mode === 'manual' && Array.isArray(entryIds)) {\n parsedEntryIds = entryIds\n .map((item: unknown) => {\n if (typeof item === 'object' && item !== null && 'entryId' in item) {\n return (item as { entryId: string }).entryId;\n }\n // Also support direct string IDs\n if (typeof item === 'string') {\n return item;\n }\n return null;\n })\n .filter((id): id is string => id !== null);\n }\n\n return await client.getEntries({\n siteId,\n contentType: type,\n limit: parsedLimit,\n order,\n preview: stage === 'preview',\n // Manual mode - pass entry IDs for hydration\n mode: mode === 'manual' ? 'manual' : undefined,\n entryIds: parsedEntryIds,\n });\n }\n\n case 'getPublishedEntryPreview': {\n const { siteId, type, slug } = params ?? {};\n if (!siteId || !type || !slug) {\n throw new Error('getPublishedEntryPreview requires siteId, type, and slug params');\n }\n return await client.getEntry({ siteId, contentType: type, slug });\n }\n case 'listPublicEvents': {\n const { siteId, limit, from, to, stage } = params ?? {};\n if (!siteId) {\n throw new Error('listPublicEvents requires siteId param');\n }\n const parsedLimit =\n typeof limit === 'string'\n ? Number.parseInt(limit, 10)\n : typeof limit === 'number'\n ? limit\n : undefined;\n return await client.listPublicEvents({ siteId, limit: parsedLimit, from, to, stage });\n }\n case 'getPublicFormById': {\n const { formId } = params ?? {};\n if (!formId) {\n throw new Error('getPublicFormById requires formId param');\n }\n return await client.getPublicFormById({ formId });\n }\n case 'getPublicBookingServices': {\n const { siteId, ids } = params ?? {};\n if (!siteId) {\n throw new Error('getPublicBookingServices requires siteId param');\n }\n return await client.getPublicBookingServices({ siteId, ids });\n }\n\n default: {\n // TypeScript should never reach here due to isSupportedEndpoint check\n const _exhaustive: never = endpoint;\n throw new Error(`Unhandled endpoint: ${_exhaustive}`);\n }\n }\n },\n isValidEndpoint: isSupportedEndpoint,\n onError: (error, { block, loader }) => {\n console.warn('[prefetchBlockData] failed to prefetch block data', {\n block,\n loader,\n error,\n });\n },\n // Provide custom block loader lookup for SDK custom blocks\n getCustomBlockLoaders: (blockKind): Record<string, BlockDataLoader> | undefined => {\n const customBlock = customBlockMap.get(blockKind);\n if (!customBlock?.dataLoaders) return undefined;\n\n // Convert SdkConfigLoader to BlockDataLoader\n // SdkConfigLoader.endpoint is SdkLoaderEndpoint (string union) -> string\n // SdkConfigLoader.params is Record<string, LoaderParamValue> -> Record<string, unknown>\n // Both are structurally compatible via covariance\n const loaders: Record<string, BlockDataLoader> = {};\n for (const [key, loader] of Object.entries(customBlock.dataLoaders)) {\n loaders[key] = {\n endpoint: loader.endpoint,\n params: loader.params,\n mode: loader.mode,\n };\n }\n return loaders;\n },\n });\n}\n\n/**\n * Type guard for supported loader endpoints\n */\nfunction isSupportedEndpoint(endpoint: string): endpoint is SupportedLoaderEndpoint {\n return SUPPORTED_LOADER_ENDPOINTS.includes(endpoint as SupportedLoaderEndpoint);\n}\n","/**\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","/**\n * Config file loader for riverbank.config.ts\n *\n * Uses jiti to load TypeScript config files at runtime without\n * requiring a build step.\n */\n\nimport { createJiti } from 'jiti';\nimport { resolve } from 'path';\nimport { existsSync } from 'fs';\n\nconst DEFAULT_CONFIG_FILENAME = 'riverbank.config.ts';\n\n/**\n * Load builder config from a TypeScript file.\n *\n * @param configPath - Path to config file, or directory containing riverbank.config.ts\n * @returns The loaded config object\n * @throws Error if config file not found or invalid\n */\nexport async function loadConfigFile(configPath?: string): Promise<unknown> {\n // Resolve the config file path\n const resolvedPath = resolveConfigPath(configPath);\n\n if (!existsSync(resolvedPath)) {\n throw new Error(\n `Config file not found: ${resolvedPath}\\n` +\n `Create a riverbank.config.ts file or specify a path with --config`\n );\n }\n\n console.log(`Loading config from ${resolvedPath}...`);\n\n // Create jiti instance for loading TypeScript files\n const jiti = createJiti(import.meta.url, {\n // Disable caching for CLI tool\n fsCache: false,\n moduleCache: false,\n });\n\n try {\n // Load the config file\n const configModule = await jiti.import(resolvedPath);\n\n // Support both default export and named 'config' export\n const config = (configModule as Record<string, unknown>).default\n ?? (configModule as Record<string, unknown>).config\n ?? configModule;\n\n if (!config || typeof config !== 'object') {\n throw new Error('Config file must export a configuration object');\n }\n\n return config;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to load config: ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Resolve config path from user input.\n *\n * If no path provided, looks for riverbank.config.ts in cwd.\n * If path is a directory, looks for riverbank.config.ts in that directory.\n * If path is a file, uses it directly.\n */\nfunction resolveConfigPath(configPath?: string): string {\n if (!configPath) {\n // Default: look in current directory\n return resolve(process.cwd(), DEFAULT_CONFIG_FILENAME);\n }\n\n const resolved = resolve(configPath);\n\n // If it's a directory, append the default filename\n if (existsSync(resolved) && !resolved.endsWith('.ts') && !resolved.endsWith('.js')) {\n return resolve(resolved, DEFAULT_CONFIG_FILENAME);\n }\n\n // Otherwise use as-is (could be a specific file)\n return resolved;\n}\n","/**\n * push-config CLI command\n *\n * Pushes SDK site configuration from a riverbank.config.ts file to the dashboard API.\n */\n\nimport { Command } from 'commander';\nimport { riverbankSiteConfigSchema, validateFieldIdConflicts } from '../config/validation';\nimport { loadConfigFile } from './load-config';\n\ninterface PushConfigOptions {\n config?: string;\n apiKey: string;\n dashboard: string;\n}\n\n/**\n * Push config to dashboard API\n */\nasync function pushToDashboard(\n dashboardUrl: string,\n siteId: string,\n apiKey: string,\n config: unknown\n): Promise<void> {\n const pushUrl = `${dashboardUrl}/api/sites/${siteId}/sdk-config`;\n console.log(`Pushing config to ${pushUrl}...`);\n\n let response: Response;\n try {\n response = await fetch(pushUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n },\n body: JSON.stringify({ config }),\n signal: AbortSignal.timeout(30000),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n throw new Error(`Failed to connect to dashboard: ${message}`);\n }\n\n if (!response.ok) {\n let errorMessage = `Dashboard returned ${response.status}`;\n try {\n const errorBody = await response.json();\n if (errorBody.error) {\n errorMessage = errorBody.error;\n if (errorBody.details) {\n errorMessage += ':\\n' + errorBody.details\n .map((d: { path: string; message: string }) => ` - ${d.path}: ${d.message}`)\n .join('\\n');\n }\n }\n } catch {\n // Use default error message if JSON parsing fails\n }\n throw new Error(errorMessage);\n }\n}\n\n/**\n * Main push-config action\n */\nasync function pushConfigAction(options: PushConfigOptions): Promise<void> {\n try {\n // 1. Load config from file\n const rawConfig = await loadConfigFile(options.config);\n\n // 2. Validate config\n console.log('Validating config...');\n const parseResult = riverbankSiteConfigSchema.safeParse(rawConfig);\n if (!parseResult.success) {\n console.error('Invalid config:');\n for (const issue of parseResult.error.issues) {\n console.error(` - ${issue.path.join('.')}: ${issue.message}`);\n }\n process.exit(1);\n }\n\n // 2b. Validate field ID conflicts for blockFieldExtensions\n const conflicts = validateFieldIdConflicts(parseResult.data.blockFieldExtensions);\n if (conflicts.length > 0) {\n console.error('Field ID conflicts detected in blockFieldExtensions:');\n for (const conflict of conflicts) {\n console.error(` - ${conflict.message}`);\n }\n process.exit(1);\n }\n\n const { siteId } = parseResult.data;\n\n // 3. Push to dashboard (send full config, dashboard will verify siteId matches)\n await pushToDashboard(\n options.dashboard,\n siteId,\n options.apiKey,\n parseResult.data\n );\n\n console.log('Config pushed successfully!');\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : error);\n process.exit(1);\n }\n}\n\n/**\n * Resolve dashboard URL from CLI option or environment variable.\n * Requires one of them to be set.\n */\nfunction resolveDashboardUrl(cliOption?: string): string {\n const url = cliOption || process.env.NEXT_PUBLIC_DASHBOARD_URL;\n if (!url) {\n console.error('Error: Dashboard URL is required.');\n console.error('Provide --dashboard <url> or set NEXT_PUBLIC_DASHBOARD_URL environment variable.');\n process.exit(1);\n }\n return url;\n}\n\n/**\n * push-config command definition\n */\nexport const pushConfigCommand = new Command('push-config')\n .description('Push SDK config from riverbank.config.ts to dashboard')\n .requiredOption('--api-key <key>', 'Dashboard API key')\n .option('--config <path>', 'Path to riverbank.config.ts (default: ./riverbank.config.ts)')\n .option('--dashboard <url>', 'Dashboard API URL (or set NEXT_PUBLIC_DASHBOARD_URL)')\n .action((options: Omit<PushConfigOptions, 'dashboard'> & { dashboard?: string }) => {\n const dashboard = resolveDashboardUrl(options.dashboard);\n return pushConfigAction({ ...options, dashboard });\n });\n","/**\n * Builder SDK CLI\n *\n * CLI tools for SDK site developers.\n */\n\nimport { Command } from 'commander';\nimport { pushConfigCommand } from './push-config';\n\nconst program = new Command();\n\nprogram\n .name('riverbankcms')\n .description('Builder SDK CLI tools')\n .version('0.1.0');\n\n// Add push-config command\nprogram.addCommand(pushConfigCommand);\n\nprogram.parse();\n"]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics Bootstrap Component
|
|
3
|
+
*
|
|
4
|
+
* Client component that initializes analytics tracking for a Builder site.
|
|
5
|
+
* Auto-tracks page views and provides helpers for tracking custom events.
|
|
6
|
+
*/
|
|
7
|
+
type AnalyticsConfig = {
|
|
8
|
+
/**
|
|
9
|
+
* Site ID for analytics tracking
|
|
10
|
+
*/
|
|
11
|
+
siteId: string;
|
|
12
|
+
/**
|
|
13
|
+
* Site slug for analytics tracking
|
|
14
|
+
*/
|
|
15
|
+
siteSlug: string;
|
|
16
|
+
/**
|
|
17
|
+
* Analytics endpoint URL
|
|
18
|
+
* @default '/api/analytics/collect'
|
|
19
|
+
*/
|
|
20
|
+
endpoint?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Custom session cookie name
|
|
23
|
+
* @default 'builder_analytics_session'
|
|
24
|
+
*/
|
|
25
|
+
sessionCookieName?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Disable analytics tracking
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
};
|
|
32
|
+
type AnalyticsClient = {
|
|
33
|
+
track: (event: TrackEventInput) => Promise<void>;
|
|
34
|
+
trackCtaClick: (metadata?: Record<string, unknown>) => Promise<void>;
|
|
35
|
+
trackFormSubmit: (metadata?: Record<string, unknown>) => Promise<void>;
|
|
36
|
+
destroy: () => void;
|
|
37
|
+
};
|
|
38
|
+
type TrackEventInput = {
|
|
39
|
+
eventType: string;
|
|
40
|
+
metadata?: Record<string, unknown>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Analytics helpers returned by useAnalytics hook
|
|
44
|
+
*/
|
|
45
|
+
type AnalyticsHelpers = {
|
|
46
|
+
trackEvent: (event: TrackEventInput) => void;
|
|
47
|
+
trackCtaClick: (metadata?: Record<string, unknown>) => void;
|
|
48
|
+
trackFormSubmit: (metadata?: Record<string, unknown>) => void;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Analytics Bootstrap component
|
|
52
|
+
*
|
|
53
|
+
* Place this component in your layout to enable analytics tracking.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* import { AnalyticsBootstrap } from '@riverbankcms/sdk/analytics';
|
|
58
|
+
*
|
|
59
|
+
* export default function Layout({ children }) {
|
|
60
|
+
* return (
|
|
61
|
+
* <html>
|
|
62
|
+
* <body>
|
|
63
|
+
* {children}
|
|
64
|
+
* <AnalyticsBootstrap
|
|
65
|
+
* siteId="your-site-id"
|
|
66
|
+
* siteSlug="your-site-slug"
|
|
67
|
+
* />
|
|
68
|
+
* </body>
|
|
69
|
+
* </html>
|
|
70
|
+
* );
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare function AnalyticsBootstrap(config: AnalyticsConfig): null;
|
|
75
|
+
/**
|
|
76
|
+
* Hook for tracking analytics events
|
|
77
|
+
*
|
|
78
|
+
* @param config - Analytics configuration. Pass null to disable analytics.
|
|
79
|
+
* @returns Analytics helpers for tracking events
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```tsx
|
|
83
|
+
* 'use client';
|
|
84
|
+
*
|
|
85
|
+
* import { useAnalytics } from '@riverbankcms/sdk/analytics';
|
|
86
|
+
*
|
|
87
|
+
* export function MyComponent() {
|
|
88
|
+
* const analytics = useAnalytics({
|
|
89
|
+
* siteId: 'your-site-id',
|
|
90
|
+
* siteSlug: 'your-site-slug',
|
|
91
|
+
* });
|
|
92
|
+
*
|
|
93
|
+
* const handleClick = () => {
|
|
94
|
+
* analytics.trackCtaClick({ buttonLabel: 'Sign Up' });
|
|
95
|
+
* };
|
|
96
|
+
*
|
|
97
|
+
* return <button onClick={handleClick}>Sign Up</button>;
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
declare function useAnalytics(config: AnalyticsConfig | null): AnalyticsHelpers;
|
|
102
|
+
|
|
103
|
+
export { AnalyticsBootstrap, type AnalyticsClient, type AnalyticsConfig, type AnalyticsHelpers, type TrackEventInput, useAnalytics };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analytics Bootstrap Component
|
|
3
|
+
*
|
|
4
|
+
* Client component that initializes analytics tracking for a Builder site.
|
|
5
|
+
* Auto-tracks page views and provides helpers for tracking custom events.
|
|
6
|
+
*/
|
|
7
|
+
type AnalyticsConfig = {
|
|
8
|
+
/**
|
|
9
|
+
* Site ID for analytics tracking
|
|
10
|
+
*/
|
|
11
|
+
siteId: string;
|
|
12
|
+
/**
|
|
13
|
+
* Site slug for analytics tracking
|
|
14
|
+
*/
|
|
15
|
+
siteSlug: string;
|
|
16
|
+
/**
|
|
17
|
+
* Analytics endpoint URL
|
|
18
|
+
* @default '/api/analytics/collect'
|
|
19
|
+
*/
|
|
20
|
+
endpoint?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Custom session cookie name
|
|
23
|
+
* @default 'builder_analytics_session'
|
|
24
|
+
*/
|
|
25
|
+
sessionCookieName?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Disable analytics tracking
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
disabled?: boolean;
|
|
31
|
+
};
|
|
32
|
+
type AnalyticsClient = {
|
|
33
|
+
track: (event: TrackEventInput) => Promise<void>;
|
|
34
|
+
trackCtaClick: (metadata?: Record<string, unknown>) => Promise<void>;
|
|
35
|
+
trackFormSubmit: (metadata?: Record<string, unknown>) => Promise<void>;
|
|
36
|
+
destroy: () => void;
|
|
37
|
+
};
|
|
38
|
+
type TrackEventInput = {
|
|
39
|
+
eventType: string;
|
|
40
|
+
metadata?: Record<string, unknown>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Analytics helpers returned by useAnalytics hook
|
|
44
|
+
*/
|
|
45
|
+
type AnalyticsHelpers = {
|
|
46
|
+
trackEvent: (event: TrackEventInput) => void;
|
|
47
|
+
trackCtaClick: (metadata?: Record<string, unknown>) => void;
|
|
48
|
+
trackFormSubmit: (metadata?: Record<string, unknown>) => void;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Analytics Bootstrap component
|
|
52
|
+
*
|
|
53
|
+
* Place this component in your layout to enable analytics tracking.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```tsx
|
|
57
|
+
* import { AnalyticsBootstrap } from '@riverbankcms/sdk/analytics';
|
|
58
|
+
*
|
|
59
|
+
* export default function Layout({ children }) {
|
|
60
|
+
* return (
|
|
61
|
+
* <html>
|
|
62
|
+
* <body>
|
|
63
|
+
* {children}
|
|
64
|
+
* <AnalyticsBootstrap
|
|
65
|
+
* siteId="your-site-id"
|
|
66
|
+
* siteSlug="your-site-slug"
|
|
67
|
+
* />
|
|
68
|
+
* </body>
|
|
69
|
+
* </html>
|
|
70
|
+
* );
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare function AnalyticsBootstrap(config: AnalyticsConfig): null;
|
|
75
|
+
/**
|
|
76
|
+
* Hook for tracking analytics events
|
|
77
|
+
*
|
|
78
|
+
* @param config - Analytics configuration. Pass null to disable analytics.
|
|
79
|
+
* @returns Analytics helpers for tracking events
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```tsx
|
|
83
|
+
* 'use client';
|
|
84
|
+
*
|
|
85
|
+
* import { useAnalytics } from '@riverbankcms/sdk/analytics';
|
|
86
|
+
*
|
|
87
|
+
* export function MyComponent() {
|
|
88
|
+
* const analytics = useAnalytics({
|
|
89
|
+
* siteId: 'your-site-id',
|
|
90
|
+
* siteSlug: 'your-site-slug',
|
|
91
|
+
* });
|
|
92
|
+
*
|
|
93
|
+
* const handleClick = () => {
|
|
94
|
+
* analytics.trackCtaClick({ buttonLabel: 'Sign Up' });
|
|
95
|
+
* };
|
|
96
|
+
*
|
|
97
|
+
* return <button onClick={handleClick}>Sign Up</button>;
|
|
98
|
+
* }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
declare function useAnalytics(config: AnalyticsConfig | null): AnalyticsHelpers;
|
|
102
|
+
|
|
103
|
+
export { AnalyticsBootstrap, type AnalyticsClient, type AnalyticsConfig, type AnalyticsHelpers, type TrackEventInput, useAnalytics };
|