create-kide-app 0.1.10 → 0.2.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.
- package/README.md +6 -4
- package/index.js +105 -57
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,17 +11,19 @@ pnpm create kide-app my-project
|
|
|
11
11
|
The CLI asks for:
|
|
12
12
|
|
|
13
13
|
1. **Project name** — directory to create
|
|
14
|
-
2. **
|
|
15
|
-
3. **
|
|
14
|
+
2. **Distribution mode** — Package (recommended: thin project + `@kidecms/core` npm dependency; `pnpm exec kide eject` converts to embedded later, one-way) or Embedded (full CMS source in `src/cms/`, yours to modify)
|
|
15
|
+
3. **Deploy target** — Local/Node.js or Cloudflare
|
|
16
|
+
|
|
17
|
+
Every project starts bare-bones: one `pages` collection (`title`, `slug`, `body`) and a minimal public page — no demo content, no seeds.
|
|
16
18
|
|
|
17
19
|
## What it does
|
|
18
20
|
|
|
19
|
-
- Clones the latest Kide CMS from GitHub.
|
|
21
|
+
- Clones the latest Kide CMS release from GitHub (package mode then swaps the embedded runtime for the published `@kidecms/core` at the same version).
|
|
20
22
|
- Applies target-specific configuration (Node.js adapter, or Cloudflare D1/R2/Workers).
|
|
21
23
|
- Installs dependencies with pnpm.
|
|
22
24
|
- Optionally creates a GitHub repo (if the `gh` CLI is installed and authenticated).
|
|
23
25
|
- Generates the CMS schema.
|
|
24
|
-
- For **local**:
|
|
26
|
+
- For **local**: starts the dev server.
|
|
25
27
|
- For **Cloudflare**: logs into wrangler (if needed), creates a D1 database and R2 bucket, applies migrations, builds and deploys, and prints the live URL + admin URL.
|
|
26
28
|
|
|
27
29
|
## Requirements
|
package/index.js
CHANGED
|
@@ -51,6 +51,8 @@ const CLEANUP = [
|
|
|
51
51
|
"docs",
|
|
52
52
|
"CLAUDE.md",
|
|
53
53
|
".claude/settings.local.json",
|
|
54
|
+
".github/workflows", // upstream CI + @kidecms/core release pipeline — wrong in any scaffold
|
|
55
|
+
"scripts/verify-cloudflare.mjs", // needs the adapters/ overlay, which every scaffold deletes
|
|
54
56
|
"data",
|
|
55
57
|
".cms-data",
|
|
56
58
|
"dist",
|
|
@@ -58,6 +60,20 @@ const CLEANUP = [
|
|
|
58
60
|
".DS_Store",
|
|
59
61
|
];
|
|
60
62
|
|
|
63
|
+
// Managed runtime dirs inside src/cms — the contents of the @kidecms/core
|
|
64
|
+
// package. Deleted in package mode (the npm dependency provides them);
|
|
65
|
+
// everything else in src/cms (cms.config, collections, adapters, fields,
|
|
66
|
+
// runtime.ts, migrations) is project-owned and stays in both modes.
|
|
67
|
+
const MANAGED_DIRS = [
|
|
68
|
+
"admin",
|
|
69
|
+
"client",
|
|
70
|
+
"core",
|
|
71
|
+
"internals",
|
|
72
|
+
"middleware",
|
|
73
|
+
"platform",
|
|
74
|
+
"routes",
|
|
75
|
+
];
|
|
76
|
+
|
|
61
77
|
// The project name reaches shell commands (git, wrangler) and path.resolve, so it is
|
|
62
78
|
// validated before either. Restricting it to one path segment of safe characters keeps
|
|
63
79
|
// `$(...)`, backticks, `;` and separators out of those commands and out of the target
|
|
@@ -126,7 +142,30 @@ async function main() {
|
|
|
126
142
|
process.exit(1);
|
|
127
143
|
}
|
|
128
144
|
|
|
129
|
-
// 2.
|
|
145
|
+
// 2. Distribution mode — package is the recommended default; embedded stays
|
|
146
|
+
// first-class for teams that want to own and modify the runtime source.
|
|
147
|
+
const mode = await p.select({
|
|
148
|
+
message: "How do you want the CMS runtime?",
|
|
149
|
+
options: [
|
|
150
|
+
{
|
|
151
|
+
label: "Package (recommended)",
|
|
152
|
+
value: "package",
|
|
153
|
+
hint: "thin project + @kidecms/core dependency — most updates are a version bump; eject to embedded later",
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
label: "Embedded",
|
|
157
|
+
value: "embedded",
|
|
158
|
+
hint: "full CMS source in src/cms/ — modify internals, audit everything; upgrades arrive as release packets",
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (p.isCancel(mode)) {
|
|
164
|
+
p.cancel("Setup cancelled.");
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 3. Deploy target
|
|
130
169
|
const target = await p.select({
|
|
131
170
|
message: "Where will you deploy?",
|
|
132
171
|
options: [
|
|
@@ -140,21 +179,6 @@ async function main() {
|
|
|
140
179
|
process.exit(0);
|
|
141
180
|
}
|
|
142
181
|
|
|
143
|
-
// 3. Demo content (local only — Cloudflare uses remote D1)
|
|
144
|
-
let seedDemo = false;
|
|
145
|
-
if (target === "local") {
|
|
146
|
-
const seed = await p.confirm({
|
|
147
|
-
message: "Seed database with demo content?",
|
|
148
|
-
initialValue: false,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
if (p.isCancel(seed)) {
|
|
152
|
-
p.cancel("Setup cancelled.");
|
|
153
|
-
process.exit(0);
|
|
154
|
-
}
|
|
155
|
-
seedDemo = seed;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
182
|
const s = p.spinner();
|
|
159
183
|
|
|
160
184
|
// --- Scaffold via git clone ---
|
|
@@ -197,10 +221,46 @@ async function main() {
|
|
|
197
221
|
rmSync(path.join(projectDir, f), { recursive: true, force: true });
|
|
198
222
|
}
|
|
199
223
|
|
|
224
|
+
// Both modes scaffold the same template at the same tag; package mode then
|
|
225
|
+
// deletes the managed runtime dirs and swaps the workspace link for the
|
|
226
|
+
// published @kidecms/core at exactly that version — same source either way.
|
|
227
|
+
const corePkgPath = path.join(projectDir, "src/cms/package.json");
|
|
228
|
+
let coreVersion = null;
|
|
229
|
+
if (existsSync(corePkgPath)) {
|
|
230
|
+
coreVersion = JSON.parse(readFileSync(corePkgPath, "utf-8")).version;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (mode === "package") {
|
|
234
|
+
if (!coreVersion) {
|
|
235
|
+
s.stop("Scaffolding failed");
|
|
236
|
+
p.cancel(
|
|
237
|
+
"This template release predates package mode — choose Embedded, or wait for the next release.",
|
|
238
|
+
);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
for (const managed of MANAGED_DIRS) {
|
|
242
|
+
rmSync(path.join(projectDir, "src/cms", managed), {
|
|
243
|
+
recursive: true,
|
|
244
|
+
force: true,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
rmSync(corePkgPath, { force: true });
|
|
248
|
+
rmSync(path.join(projectDir, "pnpm-workspace.yaml"), { force: true });
|
|
249
|
+
// Upstream distribution tooling that assumes the embedded workspace package.
|
|
250
|
+
rmSync(path.join(projectDir, "scripts/verify-pack.mjs"), { force: true });
|
|
251
|
+
rmSync(path.join(projectDir, "scripts/verify-package-mode.mjs"), {
|
|
252
|
+
force: true,
|
|
253
|
+
});
|
|
254
|
+
// Worker tests and the Cloudflare type profile live in the deleted
|
|
255
|
+
// src/cms/platform — their configs would match zero files.
|
|
256
|
+
rmSync(path.join(projectDir, "vitest.workers.config.ts"), { force: true });
|
|
257
|
+
rmSync(path.join(projectDir, "tsconfig.cloudflare.json"), { force: true });
|
|
258
|
+
}
|
|
259
|
+
|
|
200
260
|
s.stop(
|
|
201
261
|
templateRef
|
|
202
|
-
? `Project scaffolded from ${templateRef}`
|
|
203
|
-
:
|
|
262
|
+
? `Project scaffolded from ${templateRef} (${mode})`
|
|
263
|
+
: `Project scaffolded (${mode})`,
|
|
204
264
|
);
|
|
205
265
|
|
|
206
266
|
// --- Apply target-specific files ---
|
|
@@ -224,12 +284,18 @@ async function main() {
|
|
|
224
284
|
);
|
|
225
285
|
writeFileSync(
|
|
226
286
|
path.join(projectDir, "src/cms/adapters/db.ts"),
|
|
227
|
-
'export * from "
|
|
287
|
+
'export * from "@kidecms/core/platform/cloudflare/database";\n',
|
|
228
288
|
);
|
|
229
289
|
writeFileSync(
|
|
230
290
|
path.join(projectDir, "src/cms/adapters/storage.ts"),
|
|
231
|
-
'export * from "
|
|
291
|
+
'export * from "@kidecms/core/platform/cloudflare/storage";\n',
|
|
232
292
|
);
|
|
293
|
+
// The adapter test asserts Node filesystem storage — meaningless (and failing)
|
|
294
|
+
// once the adapter re-exports the R2 profile.
|
|
295
|
+
rmSync(path.join(projectDir, "src/cms/adapters/__tests__"), {
|
|
296
|
+
recursive: true,
|
|
297
|
+
force: true,
|
|
298
|
+
});
|
|
233
299
|
}
|
|
234
300
|
|
|
235
301
|
const pkgPath = path.join(projectDir, "package.json");
|
|
@@ -237,6 +303,22 @@ async function main() {
|
|
|
237
303
|
|
|
238
304
|
pkg.name = projectName;
|
|
239
305
|
|
|
306
|
+
// Upstream-repo tooling that no scaffold can run (needs the deleted adapters/ overlay).
|
|
307
|
+
delete pkg.scripts["verify:cloudflare"];
|
|
308
|
+
|
|
309
|
+
if (mode === "package" && pkg.dependencies["@kidecms/core"]) {
|
|
310
|
+
pkg.dependencies["@kidecms/core"] = `^${coreVersion}`;
|
|
311
|
+
delete pkg.scripts["verify:pack"];
|
|
312
|
+
delete pkg.scripts["verify:package"];
|
|
313
|
+
// The runtime (and its worker tests + Cloudflare type profile) now lives in
|
|
314
|
+
// node_modules — keep check/test scoped to project code, and let vitest pass
|
|
315
|
+
// until the project has tests of its own.
|
|
316
|
+
delete pkg.scripts["test:workers"];
|
|
317
|
+
delete pkg.scripts["check:cloudflare"];
|
|
318
|
+
pkg.scripts.check = "astro check && eslint .";
|
|
319
|
+
pkg.scripts.test = "pnpm cms:generate && vitest run --passWithNoTests";
|
|
320
|
+
}
|
|
321
|
+
|
|
240
322
|
if (target === "cloudflare") {
|
|
241
323
|
delete pkg.dependencies["@astrojs/node"];
|
|
242
324
|
pkg.dependencies["@astrojs/cloudflare"] = "~14.1.7";
|
|
@@ -268,7 +350,7 @@ async function main() {
|
|
|
268
350
|
);
|
|
269
351
|
writeFileSync(path.join(projectDir, "wrangler.toml"), wranglerContent);
|
|
270
352
|
|
|
271
|
-
pkg.devDependencies.wrangler = "^4.
|
|
353
|
+
pkg.devDependencies.wrangler = "^4.121.0";
|
|
272
354
|
|
|
273
355
|
pkg.scripts.dev = "astro dev";
|
|
274
356
|
pkg.scripts.build = "astro build";
|
|
@@ -308,10 +390,11 @@ async function main() {
|
|
|
308
390
|
}
|
|
309
391
|
const versionStamp = {
|
|
310
392
|
template: REPO.replace(/\.git$/, ""),
|
|
311
|
-
kideVersion: pkg.version ?? null,
|
|
393
|
+
kideVersion: coreVersion ?? pkg.version ?? null,
|
|
312
394
|
ref: templateRef ?? "HEAD",
|
|
313
395
|
commit: templateCommit,
|
|
314
396
|
target,
|
|
397
|
+
mode,
|
|
315
398
|
corePath: "src/cms",
|
|
316
399
|
scaffoldedAt: new Date().toISOString(),
|
|
317
400
|
createKideApp: cliVersion,
|
|
@@ -475,41 +558,6 @@ async function main() {
|
|
|
475
558
|
s.stop("Schema generation failed — run `cms:generate` manually");
|
|
476
559
|
}
|
|
477
560
|
|
|
478
|
-
// --- Seed demo content ---
|
|
479
|
-
|
|
480
|
-
if (seedDemo && target === "local") {
|
|
481
|
-
s.start("Pushing schema to database");
|
|
482
|
-
// The guarded sync script (exits non-zero on failure, creates data/ itself) —
|
|
483
|
-
// same path the dev server and deploys use.
|
|
484
|
-
try {
|
|
485
|
-
execSync(`${pm.run} cms:push`, { cwd: projectDir, stdio: "pipe" });
|
|
486
|
-
s.stop("Schema pushed");
|
|
487
|
-
} catch {
|
|
488
|
-
s.stop("Schema push failed — run `pnpm cms:push` manually");
|
|
489
|
-
}
|
|
490
|
-
s.start("Seeding demo content");
|
|
491
|
-
try {
|
|
492
|
-
execSync(`${pm.run} cms:seed`, { cwd: projectDir, stdio: "pipe" });
|
|
493
|
-
s.stop("Demo content seeded");
|
|
494
|
-
} catch (err) {
|
|
495
|
-
s.stop("Seeding failed — run `pnpm cms:seed` manually");
|
|
496
|
-
if (err.stderr) console.error(err.stderr.toString());
|
|
497
|
-
if (err.stdout) console.error(err.stdout.toString());
|
|
498
|
-
}
|
|
499
|
-
} else if (seedDemo && target === "cloudflare") {
|
|
500
|
-
p.note(
|
|
501
|
-
[
|
|
502
|
-
"Seeding for Cloudflare requires a D1 database.",
|
|
503
|
-
"",
|
|
504
|
-
` ${pm.dlx} wrangler d1 create ${projectName}-db`,
|
|
505
|
-
" # then replace the placeholder database_id in wrangler.toml",
|
|
506
|
-
` ${pm.dlx} wrangler d1 migrations apply ${projectName}-db --local`,
|
|
507
|
-
` ${pm.run} cms:seed`,
|
|
508
|
-
].join("\n"),
|
|
509
|
-
"Seed manually",
|
|
510
|
-
);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
561
|
// --- Cloudflare resource setup ---
|
|
514
562
|
|
|
515
563
|
const cf = {
|