riverbankcms 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 +21 -0
- package/dist/acceptance/matrix.mjs +784 -0
- package/dist/cli/index.mjs +110989 -0
- package/dist/cli/init-docs/content/agents-section.md +67 -0
- package/dist/cli/init-docs/content/cli-reference.md +1238 -0
- package/dist/cli/init-docs/content/content-management.md +792 -0
- package/dist/cli/init-docs/content/context-brand.md +125 -0
- package/dist/cli/init-docs/content/context-brief.md +77 -0
- package/dist/cli/init-docs/content/context-knowledge.md +111 -0
- package/dist/cli/init-docs/content/getting-started.md +171 -0
- package/dist/cli/init-docs/content/site-workflows-readme.md +96 -0
- package/dist/cli/init-docs/content/workflow-add-block.md +299 -0
- package/dist/cli/init-docs/content/workflow-agent-safe-sync.md +83 -0
- package/dist/cli/init-docs/content/workflow-block-extensions.md +370 -0
- package/dist/cli/init-docs/content/workflow-cmsify-page.md +357 -0
- package/dist/cli/init-docs/content/workflow-content-types.md +330 -0
- package/dist/cli/init-docs/content/workflow-create-page.md +212 -0
- package/dist/cli/init-docs/content/workflow-custom-block.md +470 -0
- package/dist/cli/init-docs/content/workflow-editor-workflows.md +130 -0
- package/dist/cli/init-docs/content/workflow-isr-revalidation.md +158 -0
- package/dist/cli/init-docs/content/workflow-preview-mode.md +252 -0
- package/dist/cli/init-docs/content/workflow-publish.md +285 -0
- package/dist/cli/init-docs/content/workflow-remote-setup.md +51 -0
- package/dist/cli/init-docs/content/workflow-templates.md +381 -0
- package/dist/load-config-CRB4AHKq.mjs +5 -0
- package/dist/load-config-r1s4htWu.mjs +87 -0
- package/dist/sdk-peer-DrblJmno.mjs +217 -0
- package/dist/style-Chv9Gcwq.mjs +49167 -0
- package/dist/testing.mjs +5 -0
- package/package.json +76 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { n as assertCompatibleSdkPeer } from "./sdk-peer-DrblJmno.mjs";
|
|
3
|
+
import { dirname, resolve } from "path";
|
|
4
|
+
import { createJiti } from "jiti";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
|
|
8
|
+
//#region src/load-config.ts
|
|
9
|
+
/**
|
|
10
|
+
* Config file loader for riverbank.config.ts
|
|
11
|
+
*
|
|
12
|
+
* Uses jiti to load TypeScript config files at runtime without
|
|
13
|
+
* requiring a build step.
|
|
14
|
+
*/
|
|
15
|
+
const DEFAULT_CONFIG_FILENAME = "riverbank.config.ts";
|
|
16
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
/**
|
|
18
|
+
* Load builder config from a TypeScript file.
|
|
19
|
+
*
|
|
20
|
+
* @param configPath - Path to config file, or directory containing riverbank.config.ts
|
|
21
|
+
* @returns The loaded config object
|
|
22
|
+
* @throws Error if config file not found or invalid
|
|
23
|
+
*/
|
|
24
|
+
async function loadConfigFile(configPath) {
|
|
25
|
+
const resolvedPath = resolveConfigPath(configPath);
|
|
26
|
+
if (!existsSync(resolvedPath)) {
|
|
27
|
+
throw new Error(`Config file not found: ${resolvedPath}\n` + `Create a riverbank.config.ts file or specify a path with --config`);
|
|
28
|
+
}
|
|
29
|
+
assertCompatibleSdkPeer(resolvedPath);
|
|
30
|
+
process.stderr.write(`Loading config from ${resolvedPath}...\n`);
|
|
31
|
+
const alias = {};
|
|
32
|
+
const sourceConfigPath = resolve(currentDir, "..", "config", "index.ts");
|
|
33
|
+
const sourceIndexPath = resolve(currentDir, "..", "index.ts");
|
|
34
|
+
if (existsSync(sourceConfigPath)) {
|
|
35
|
+
alias["@riverbankcms/sdk/config"] = sourceConfigPath;
|
|
36
|
+
}
|
|
37
|
+
if (existsSync(sourceIndexPath)) {
|
|
38
|
+
alias["@riverbankcms/sdk"] = sourceIndexPath;
|
|
39
|
+
}
|
|
40
|
+
const blocksDir = resolve(currentDir, "../../../blocks/src");
|
|
41
|
+
if (existsSync(blocksDir)) {
|
|
42
|
+
alias["@riverbankcms/blocks"] = blocksDir;
|
|
43
|
+
}
|
|
44
|
+
const mediaCorePath = resolve(currentDir, "../../../media-core/src/index.ts");
|
|
45
|
+
if (existsSync(mediaCorePath)) {
|
|
46
|
+
alias["@riverbankcms/media-core"] = mediaCorePath;
|
|
47
|
+
}
|
|
48
|
+
const jiti = createJiti(import.meta.url, {
|
|
49
|
+
fsCache: false,
|
|
50
|
+
moduleCache: false,
|
|
51
|
+
alias: Object.keys(alias).length > 0 ? alias : undefined,
|
|
52
|
+
jsx: Object.keys(alias).length > 0
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
const configModule = await jiti.import(resolvedPath);
|
|
56
|
+
const config = configModule.default ?? configModule.config ?? configModule;
|
|
57
|
+
if (!config || typeof config !== "object") {
|
|
58
|
+
throw new Error("Config file must export a configuration object");
|
|
59
|
+
}
|
|
60
|
+
return config;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (error instanceof Error) {
|
|
63
|
+
throw new Error(`Failed to load config: ${error.message}`);
|
|
64
|
+
}
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Resolve config path from user input.
|
|
70
|
+
*
|
|
71
|
+
* If no path provided, looks for riverbank.config.ts in cwd.
|
|
72
|
+
* If path is a directory, looks for riverbank.config.ts in that directory.
|
|
73
|
+
* If path is a file, uses it directly.
|
|
74
|
+
*/
|
|
75
|
+
function resolveConfigPath(configPath) {
|
|
76
|
+
if (!configPath) {
|
|
77
|
+
return resolve(process.cwd(), DEFAULT_CONFIG_FILENAME);
|
|
78
|
+
}
|
|
79
|
+
const resolved = resolve(configPath);
|
|
80
|
+
if (existsSync(resolved) && !resolved.endsWith(".ts") && !resolved.endsWith(".js")) {
|
|
81
|
+
return resolve(resolved, DEFAULT_CONFIG_FILENAME);
|
|
82
|
+
}
|
|
83
|
+
return resolved;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
export { loadConfigFile as t };
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join, parse } from "node:path";
|
|
4
|
+
|
|
5
|
+
//#region package.json
|
|
6
|
+
var version = "0.1.0";
|
|
7
|
+
var peerDependencies = { "@riverbankcms/sdk": ">=0.129.1 <1.0.0" };
|
|
8
|
+
var package_default = {
|
|
9
|
+
name: "riverbankcms",
|
|
10
|
+
version,
|
|
11
|
+
description: "Riverbank CMS command-line tools for SDK site developers",
|
|
12
|
+
bin: { "riverbankcms": "dist/cli/index.mjs" },
|
|
13
|
+
exports: {
|
|
14
|
+
"./testing": "./dist/testing.mjs",
|
|
15
|
+
"./acceptance/matrix": "./dist/acceptance/matrix.mjs",
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
files: ["dist", "README.md"],
|
|
19
|
+
engines: { "node": ">=18" },
|
|
20
|
+
scripts: {
|
|
21
|
+
"clean:dist": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
22
|
+
"build": "node scripts/build.mjs",
|
|
23
|
+
"dev": "node scripts/build.mjs --watch",
|
|
24
|
+
"typecheck": "tsgo --noEmit",
|
|
25
|
+
"lint": "node ../../scripts/run-package-lint.mjs src",
|
|
26
|
+
"test": "node scripts/run-tests.mjs",
|
|
27
|
+
"test:bun": "node scripts/run-bun-tests.mjs",
|
|
28
|
+
"test:bun:check": "node scripts/run-bun-tests.mjs --check",
|
|
29
|
+
"test:bun:list": "node scripts/run-bun-tests.mjs --list",
|
|
30
|
+
"check:packed-exports": "node scripts/check-packed-exports.mjs",
|
|
31
|
+
"check:consumer-contract": "node scripts/check-packed-consumer-contract.mjs",
|
|
32
|
+
"cli": "pnpm --filter @riverbankcms/sdk build && pnpm build && node dist/cli/index.mjs"
|
|
33
|
+
},
|
|
34
|
+
dependencies: {
|
|
35
|
+
"commander": "^12.1.0",
|
|
36
|
+
"dotenv": "^16.4.5",
|
|
37
|
+
"fast-deep-equal": "^3.1.3",
|
|
38
|
+
"jiti": "^2.7.0",
|
|
39
|
+
"prompts": "^2.4.2",
|
|
40
|
+
"simple-git": "^3.36.0",
|
|
41
|
+
"zod": "^4.3.6"
|
|
42
|
+
},
|
|
43
|
+
peerDependencies,
|
|
44
|
+
devDependencies: {
|
|
45
|
+
"@riverbankcms/api": "workspace:*",
|
|
46
|
+
"@riverbankcms/blocks": "workspace:*",
|
|
47
|
+
"@riverbankcms/content-model": "workspace:*",
|
|
48
|
+
"@riverbankcms/core": "workspace:*",
|
|
49
|
+
"@riverbankcms/management-client": "workspace:*",
|
|
50
|
+
"@riverbankcms/media-core": "workspace:*",
|
|
51
|
+
"@riverbankcms/sdk": "workspace:*",
|
|
52
|
+
"@riverbankcms/site-commands": "workspace:*",
|
|
53
|
+
"@riverbankcms/test-support": "workspace:*",
|
|
54
|
+
"@riverbankcms/theme-core": "workspace:*",
|
|
55
|
+
"@types/node": "^22.18.5",
|
|
56
|
+
"@types/prompts": "^2.4.9",
|
|
57
|
+
"tsdown": "^0.16.5",
|
|
58
|
+
"tsx": "^4.20.6",
|
|
59
|
+
"typescript": "^6.0.3"
|
|
60
|
+
},
|
|
61
|
+
repository: {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "git+https://github.com/riverbankcms/riverbankcms.git",
|
|
64
|
+
"directory": "packages/cli"
|
|
65
|
+
},
|
|
66
|
+
keywords: [
|
|
67
|
+
"headless-cms",
|
|
68
|
+
"riverbankcms",
|
|
69
|
+
"cms",
|
|
70
|
+
"cli"
|
|
71
|
+
],
|
|
72
|
+
license: "MIT",
|
|
73
|
+
"private": false
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/version.ts
|
|
78
|
+
/** The package manifest is the source-run fallback; builds inject this value. */
|
|
79
|
+
const CLI_VERSION = typeof "0.1.0" === "string" ? "0.1.0" : version;
|
|
80
|
+
/**
|
|
81
|
+
* The CLI's SDK peer range is bundled from the CLI manifest alongside its
|
|
82
|
+
* version. Runtime config loading uses this value as the single compatibility
|
|
83
|
+
* contract for the SDK installed by the site.
|
|
84
|
+
*/
|
|
85
|
+
const CLI_SDK_PEER_RANGE = peerDependencies["@riverbankcms/sdk"];
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/sdk-peer.ts
|
|
89
|
+
const SDK_PACKAGE_NAME = "@riverbankcms/sdk";
|
|
90
|
+
const SDK_INSTALL_COMMAND = (range) => `pnpm add ${SDK_PACKAGE_NAME}@'${range}'`;
|
|
91
|
+
/**
|
|
92
|
+
* A typed config-load failure raised before jiti imports the site config. This
|
|
93
|
+
* keeps missing/incompatible SDK failures actionable and prevents Node's raw
|
|
94
|
+
* module-resolution stack from reaching CLI users.
|
|
95
|
+
*/
|
|
96
|
+
var CliSdkPeerError = class extends Error {
|
|
97
|
+
constructor(options) {
|
|
98
|
+
const { status, requiredRange, installedVersion } = options;
|
|
99
|
+
const detail = status === "missing" ? `No ${SDK_PACKAGE_NAME} package was found in this site.` : `This site has ${SDK_PACKAGE_NAME}@${installedVersion ?? "an invalid version"}.`;
|
|
100
|
+
const installCommand = SDK_INSTALL_COMMAND(requiredRange);
|
|
101
|
+
super(`${detail} The Riverbank CLI requires ${SDK_PACKAGE_NAME}@${requiredRange}. ` + `Install a compatible SDK with: ${installCommand}`);
|
|
102
|
+
this.code = "sdk:incompatible-sdk";
|
|
103
|
+
this.name = "CliSdkPeerError";
|
|
104
|
+
this.status = status;
|
|
105
|
+
this.requiredRange = requiredRange;
|
|
106
|
+
this.installedVersion = installedVersion;
|
|
107
|
+
this.installCommand = installCommand;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
function parseStableVersion(value) {
|
|
111
|
+
const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(value.trim());
|
|
112
|
+
if (!match) return undefined;
|
|
113
|
+
const major = Number(match[1]);
|
|
114
|
+
const minor = Number(match[2]);
|
|
115
|
+
const patch = Number(match[3]);
|
|
116
|
+
if (![
|
|
117
|
+
major,
|
|
118
|
+
minor,
|
|
119
|
+
patch
|
|
120
|
+
].every(Number.isSafeInteger)) return undefined;
|
|
121
|
+
return [
|
|
122
|
+
major,
|
|
123
|
+
minor,
|
|
124
|
+
patch
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
function compareVersions(left, right) {
|
|
128
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
129
|
+
const leftPart = left[index];
|
|
130
|
+
const rightPart = right[index];
|
|
131
|
+
if (leftPart === undefined || rightPart === undefined) continue;
|
|
132
|
+
if (leftPart < rightPart) return -1;
|
|
133
|
+
if (leftPart > rightPart) return 1;
|
|
134
|
+
}
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
function parsePeerRange(value) {
|
|
138
|
+
const match = /^\s*>=\s*(\d+\.\d+\.\d+)\s+<\s*(\d+\.\d+\.\d+)\s*$/.exec(value);
|
|
139
|
+
if (!match) return undefined;
|
|
140
|
+
const floor = parseStableVersion(match[1] ?? "");
|
|
141
|
+
const ceiling = parseStableVersion(match[2] ?? "");
|
|
142
|
+
if (!floor || !ceiling || compareVersions(floor, ceiling) >= 0) return undefined;
|
|
143
|
+
return {
|
|
144
|
+
floor,
|
|
145
|
+
ceiling
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const parsedCliSdkPeerRange = parsePeerRange(CLI_SDK_PEER_RANGE);
|
|
149
|
+
if (!parsedCliSdkPeerRange) {
|
|
150
|
+
throw new Error(`CLI package contains an unsupported SDK peer range: ${CLI_SDK_PEER_RANGE}`);
|
|
151
|
+
}
|
|
152
|
+
function isVersionInPeerRange(version$1, range) {
|
|
153
|
+
const parsedVersion = parseStableVersion(version$1);
|
|
154
|
+
if (!parsedVersion) return false;
|
|
155
|
+
return compareVersions(parsedVersion, range.floor) >= 0 && compareVersions(parsedVersion, range.ceiling) < 0;
|
|
156
|
+
}
|
|
157
|
+
function resolveSdkMetadataPath(fromPath) {
|
|
158
|
+
let directory = dirname(fromPath);
|
|
159
|
+
const root = parse(directory).root;
|
|
160
|
+
while (true) {
|
|
161
|
+
const manifestPath = join(directory, "node_modules", SDK_PACKAGE_NAME, "package.json");
|
|
162
|
+
if (existsSync(manifestPath)) return manifestPath;
|
|
163
|
+
if (directory === root) break;
|
|
164
|
+
directory = dirname(directory);
|
|
165
|
+
}
|
|
166
|
+
throw new Error(`Unable to locate ${SDK_PACKAGE_NAME} package metadata.`);
|
|
167
|
+
}
|
|
168
|
+
function readSdkMetadata(metadataPath) {
|
|
169
|
+
const manifest = JSON.parse(readFileSync(metadataPath, "utf8"));
|
|
170
|
+
if (manifest.name !== SDK_PACKAGE_NAME || typeof manifest.version !== "string") {
|
|
171
|
+
throw new Error(`Invalid ${SDK_PACKAGE_NAME} package metadata.`);
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
name: SDK_PACKAGE_NAME,
|
|
175
|
+
version: manifest.version
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Resolve and validate the one SDK package that the site config can import.
|
|
180
|
+
* Only package metadata is read here; the config import later resolves the
|
|
181
|
+
* same package through jiti, so this check cannot introduce another SDK copy.
|
|
182
|
+
*/
|
|
183
|
+
function assertCompatibleSdkPeer(fromPath, options = {}) {
|
|
184
|
+
const requiredRange = options.requiredRange ?? CLI_SDK_PEER_RANGE;
|
|
185
|
+
const parsedRequiredRange = requiredRange === CLI_SDK_PEER_RANGE ? parsedCliSdkPeerRange : parsePeerRange(requiredRange);
|
|
186
|
+
const resolveMetadataPath = options.resolveMetadataPath ?? resolveSdkMetadataPath;
|
|
187
|
+
const readMetadata = options.readMetadata ?? readSdkMetadata;
|
|
188
|
+
let metadataPath;
|
|
189
|
+
try {
|
|
190
|
+
metadataPath = resolveMetadataPath(fromPath);
|
|
191
|
+
} catch {
|
|
192
|
+
throw new CliSdkPeerError({
|
|
193
|
+
status: "missing",
|
|
194
|
+
requiredRange
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
let metadata;
|
|
198
|
+
try {
|
|
199
|
+
metadata = readMetadata(metadataPath);
|
|
200
|
+
} catch {
|
|
201
|
+
throw new CliSdkPeerError({
|
|
202
|
+
status: "missing",
|
|
203
|
+
requiredRange
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
if (!parsedRequiredRange || !isVersionInPeerRange(metadata.version, parsedRequiredRange)) {
|
|
207
|
+
throw new CliSdkPeerError({
|
|
208
|
+
status: "incompatible",
|
|
209
|
+
requiredRange,
|
|
210
|
+
installedVersion: metadata.version
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return metadata;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
//#endregion
|
|
217
|
+
export { assertCompatibleSdkPeer as n, CLI_VERSION as r, CliSdkPeerError as t };
|