create-kide-app 0.0.16 → 0.0.18

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/index.js CHANGED
@@ -1,14 +1,32 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import * as p from "@clack/prompts";
4
- import { execSync } from "node:child_process";
5
- import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { execSync, spawn } from "node:child_process";
5
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
6
6
  import path from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
 
9
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
10
  const TEMPLATES_DIR = path.join(__dirname, "templates");
11
11
 
12
+ // Async spawn wrapper so long-running commands don't block clack spinners
13
+ const runAsync = (cmd, cwd) =>
14
+ new Promise((resolve, reject) => {
15
+ const child = spawn(cmd, { cwd, shell: true });
16
+ let stdout = "";
17
+ let stderr = "";
18
+ child.stdout.on("data", (d) => (stdout += d.toString()));
19
+ child.stderr.on("data", (d) => (stderr += d.toString()));
20
+ child.on("close", (code) => {
21
+ if (code === 0) resolve(stdout);
22
+ else {
23
+ const err = new Error(`Command failed: ${cmd}`);
24
+ err.stderr = stderr;
25
+ reject(err);
26
+ }
27
+ });
28
+ });
29
+
12
30
  // --- Package manager detection ---
13
31
 
14
32
  const pm = { name: "pnpm", exec: "pnpm dlx", run: "pnpm", install: "pnpm install" };
@@ -77,6 +95,13 @@ async function main() {
77
95
 
78
96
  cpSync(path.join(TEMPLATES_DIR, "base"), projectDir, { recursive: true });
79
97
 
98
+ // Rename gitignore → .gitignore (npm strips dotfiles from published tarballs)
99
+ const gitignoreSrc = path.join(projectDir, "gitignore");
100
+ if (existsSync(gitignoreSrc)) {
101
+ cpSync(gitignoreSrc, path.join(projectDir, ".gitignore"));
102
+ rmSync(gitignoreSrc);
103
+ }
104
+
80
105
  // Apply demo schema and seed data if selected
81
106
  if (seedDemo) {
82
107
  cpSync(path.join(TEMPLATES_DIR, "demo"), projectDir, { recursive: true });
@@ -133,9 +158,8 @@ async function main() {
133
158
 
134
159
  if (target === "cloudflare") {
135
160
  const gitignorePath = path.join(projectDir, ".gitignore");
136
- let gitignore = readFileSync(gitignorePath, "utf-8");
137
- gitignore += "\n# Cloudflare\n.wrangler/\n";
138
- writeFileSync(gitignorePath, gitignore);
161
+ const gitignore = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
162
+ writeFileSync(gitignorePath, gitignore + "\n# Cloudflare\n.wrangler/\n");
139
163
  }
140
164
 
141
165
  s.stop("Configuration applied");
@@ -144,7 +168,7 @@ async function main() {
144
168
 
145
169
  s.start("Installing dependencies");
146
170
  try {
147
- execSync(pm.install, { cwd: projectDir, stdio: "pipe" });
171
+ await runAsync(pm.install, projectDir);
148
172
  s.stop("Dependencies installed");
149
173
  } catch {
150
174
  s.stop(`${pm.install} failed — run it manually`);
@@ -193,7 +217,7 @@ async function main() {
193
217
 
194
218
  // --- Cloudflare resource setup ---
195
219
 
196
- const cf = { d1Created: false, r2Created: false, migrationsApplied: false };
220
+ const cf = { d1Created: false, r2Created: false, migrationsApplied: false, deployed: false, url: null };
197
221
  if (target === "cloudflare") {
198
222
  const setupNow = await p.confirm({
199
223
  message: "Set up Cloudflare resources now? (creates D1 database and R2 bucket)",
@@ -293,6 +317,7 @@ async function main() {
293
317
  execSync(`${pm.exec} wrangler d1 migrations apply ${projectName}-db --remote`, {
294
318
  cwd: projectDir,
295
319
  stdio: "pipe",
320
+ input: "y\n",
296
321
  });
297
322
  cf.migrationsApplied = true;
298
323
  s.stop("Migrations applied");
@@ -300,6 +325,27 @@ async function main() {
300
325
  s.stop("Migration apply failed — run manually with: wrangler d1 migrations apply --remote");
301
326
  }
302
327
  }
328
+
329
+ // Deploy to Cloudflare
330
+ if (cf.migrationsApplied) {
331
+ const doDeploy = await p.confirm({
332
+ message: "Deploy to Cloudflare now?",
333
+ initialValue: true,
334
+ });
335
+ if (!p.isCancel(doDeploy) && doDeploy) {
336
+ s.start("Building and deploying to Cloudflare");
337
+ try {
338
+ const deployOutput = await runAsync(`${pm.run} deploy`, projectDir);
339
+ const urlMatch = deployOutput.match(/https:\/\/[^\s]+\.workers\.dev/);
340
+ if (urlMatch) cf.url = urlMatch[0];
341
+ cf.deployed = true;
342
+ s.stop("Deployed to Cloudflare");
343
+ } catch (err) {
344
+ s.stop("Deploy failed — run manually with: pnpm run deploy");
345
+ if (err.stderr) console.error(err.stderr.slice(-500));
346
+ }
347
+ }
348
+ }
303
349
  }
304
350
  }
305
351
  }
@@ -315,26 +361,34 @@ async function main() {
315
361
  console.log(` To start again: cd ${projectName} && pnpm dev\n`);
316
362
  }
317
363
  } else {
318
- const lines = [`cd ${projectName}`];
319
- const remaining = [];
320
- if (!cf.d1Created) {
321
- remaining.push(
322
- ` ${pm.exec} wrangler d1 create ${projectName}-db`,
323
- " # Copy the database_id to wrangler.toml",
324
- );
325
- }
326
- if (!cf.r2Created) {
327
- remaining.push(` ${pm.exec} wrangler r2 bucket create ${projectName}-assets`);
328
- }
329
- if (!cf.migrationsApplied) {
330
- remaining.push(` ${pm.exec} wrangler d1 migrations apply ${projectName}-db --remote`);
331
- }
332
- if (remaining.length > 0) {
333
- lines.push("", "Remaining setup:", ...remaining);
364
+ if (cf.deployed && cf.url) {
365
+ p.note([`Live at: ${cf.url}`, `Admin: ${cf.url}/admin`, "", `cd ${projectName}`, "", "Local development:", ` ${pm.run} dev`, "", "Redeploy:", " pnpm run deploy"].join("\n"), "🎉 Your Kide CMS is live");
366
+ p.outro("Project created!");
367
+ } else {
368
+ const lines = [`cd ${projectName}`];
369
+ const remaining = [];
370
+ if (!cf.d1Created) {
371
+ remaining.push(
372
+ ` ${pm.exec} wrangler d1 create ${projectName}-db`,
373
+ " # Copy the database_id to wrangler.toml",
374
+ );
375
+ }
376
+ if (!cf.r2Created) {
377
+ remaining.push(` ${pm.exec} wrangler r2 bucket create ${projectName}-assets`);
378
+ }
379
+ if (!cf.migrationsApplied) {
380
+ remaining.push(` ${pm.exec} wrangler d1 migrations apply ${projectName}-db --remote`);
381
+ }
382
+ if (!cf.deployed) {
383
+ remaining.push(` ${pm.run} run deploy`);
384
+ }
385
+ if (remaining.length > 0) {
386
+ lines.push("", "Remaining setup:", ...remaining);
387
+ }
388
+ lines.push("", "Local development:", ` ${pm.run} dev`);
389
+ p.note(lines.join("\n"), "Next steps");
390
+ p.outro("Project created!");
334
391
  }
335
- lines.push("", "Local development:", ` ${pm.run} dev`, "", "Deploy:", " pnpm run deploy");
336
- p.note(lines.join("\n"), "Next steps");
337
- p.outro("Project created!");
338
392
  }
339
393
  }
340
394
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kide-app",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "description": "Scaffold a new Kide CMS project",
5
5
  "author": "Matti Hernesniemi",
6
6
  "license": "MIT",
@@ -0,0 +1,8 @@
1
+ node_modules/
2
+ dist/
3
+ .astro/
4
+ data/
5
+ src/cms/.generated/
6
+ public/uploads/
7
+ .cms-cache/
8
+ .env
@@ -1,11 +1,17 @@
1
- import { readdirSync } from "node:fs";
1
+ import { existsSync, readdirSync } from "node:fs";
2
2
  import { defineConfig } from "drizzle-kit";
3
3
 
4
- function getLocalD1Path() {
4
+ // Look for the local D1 sqlite file (created by wrangler after first run).
5
+ // Returns null if it doesn't exist yet — `drizzle-kit generate` doesn't need it.
6
+ function getLocalD1Path(): string | null {
5
7
  const dir = ".wrangler/state/v3/d1/miniflare-D1DatabaseObject";
6
- const file = readdirSync(dir).find((f) => f.endsWith(".sqlite") && f !== "*.sqlite");
7
- if (!file) throw new Error(`No D1 sqlite file found in ${dir}`);
8
- return `${dir}/${file}`;
8
+ if (!existsSync(dir)) return null;
9
+ try {
10
+ const file = readdirSync(dir).find((f) => f.endsWith(".sqlite") && f !== "*.sqlite");
11
+ return file ? `${dir}/${file}` : null;
12
+ } catch {
13
+ return null;
14
+ }
9
15
  }
10
16
 
11
17
  export default defineConfig({
@@ -13,6 +19,6 @@ export default defineConfig({
13
19
  out: "./src/cms/migrations",
14
20
  dialect: "sqlite",
15
21
  dbCredentials: {
16
- url: getLocalD1Path(),
22
+ url: getLocalD1Path() ?? ":memory:",
17
23
  },
18
24
  });