create-kide-app 0.1.2 → 0.1.3
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 +164 -31
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import * as p from "@clack/prompts";
|
|
4
|
-
import { execSync } from "node:child_process";
|
|
4
|
+
import { exec as execCb, execSync } from "node:child_process";
|
|
5
5
|
import { cpSync, existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
6
6
|
import path from "node:path";
|
|
7
|
+
import { promisify } from "node:util";
|
|
7
8
|
|
|
9
|
+
const exec = promisify(execCb);
|
|
8
10
|
const REPO = "https://github.com/mhernesniemi/kide-cms.git";
|
|
9
11
|
|
|
12
|
+
function run(cmd, cwd) {
|
|
13
|
+
return exec(cmd, { cwd });
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
function applyPackagePatch(pkg, patch) {
|
|
11
17
|
for (const [k, v] of Object.entries(patch.dependencies?.add ?? {})) {
|
|
12
18
|
pkg.dependencies[k] = v;
|
|
@@ -76,11 +82,17 @@ async function main() {
|
|
|
76
82
|
|
|
77
83
|
const s = p.spinner();
|
|
78
84
|
|
|
85
|
+
// --- Clone kide-cms ---
|
|
86
|
+
|
|
79
87
|
s.start("Cloning kide-cms");
|
|
80
|
-
|
|
88
|
+
await run(`git clone --depth 1 ${REPO} "${projectDir}"`);
|
|
81
89
|
rmSync(path.join(projectDir, ".git"), { recursive: true, force: true });
|
|
82
90
|
s.stop("Cloned");
|
|
83
91
|
|
|
92
|
+
// --- Adjust package.json and apply adapter overlay ---
|
|
93
|
+
|
|
94
|
+
s.start(cloudflare ? "Applying Cloudflare adapter" : "Configuring project");
|
|
95
|
+
|
|
84
96
|
const pkgPath = path.join(projectDir, "package.json");
|
|
85
97
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
86
98
|
pkg.name = projectName;
|
|
@@ -89,9 +101,7 @@ async function main() {
|
|
|
89
101
|
const adaptersDir = path.join(projectDir, "adapters");
|
|
90
102
|
|
|
91
103
|
if (cloudflare) {
|
|
92
|
-
s.start("Applying Cloudflare adapter");
|
|
93
104
|
const cfDir = path.join(adaptersDir, "cloudflare");
|
|
94
|
-
|
|
95
105
|
const overlayFiles = [
|
|
96
106
|
"astro.config.mjs",
|
|
97
107
|
"drizzle.config.ts",
|
|
@@ -111,25 +121,29 @@ async function main() {
|
|
|
111
121
|
|
|
112
122
|
const patch = JSON.parse(readFileSync(path.join(cfDir, "package.patch.json"), "utf-8"));
|
|
113
123
|
applyPackagePatch(pkg, patch);
|
|
114
|
-
|
|
115
|
-
s.stop("Cloudflare adapter applied");
|
|
116
124
|
}
|
|
117
125
|
|
|
118
126
|
rmSync(adaptersDir, { recursive: true, force: true });
|
|
119
127
|
writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
120
128
|
|
|
129
|
+
s.stop(cloudflare ? "Cloudflare adapter applied" : "Project configured");
|
|
130
|
+
|
|
131
|
+
// --- Install dependencies ---
|
|
132
|
+
|
|
121
133
|
s.start("Installing dependencies");
|
|
122
134
|
try {
|
|
123
|
-
|
|
135
|
+
await run("pnpm install", projectDir);
|
|
124
136
|
s.stop("Dependencies installed");
|
|
125
137
|
} catch {
|
|
126
138
|
s.stop("pnpm install failed — run it manually");
|
|
127
139
|
}
|
|
128
140
|
|
|
141
|
+
// --- Seed demo content (local only) ---
|
|
142
|
+
|
|
129
143
|
if (seedDemo) {
|
|
130
144
|
s.start("Generating CMS schema");
|
|
131
145
|
try {
|
|
132
|
-
|
|
146
|
+
await run("pnpm cms:generate", projectDir);
|
|
133
147
|
s.stop("Schema generated");
|
|
134
148
|
} catch {
|
|
135
149
|
s.stop("Schema generation failed — run `pnpm cms:generate` manually");
|
|
@@ -137,7 +151,7 @@ async function main() {
|
|
|
137
151
|
|
|
138
152
|
s.start("Pushing schema to database");
|
|
139
153
|
try {
|
|
140
|
-
|
|
154
|
+
await run("pnpm exec drizzle-kit push --force", projectDir);
|
|
141
155
|
s.stop("Schema pushed");
|
|
142
156
|
} catch {
|
|
143
157
|
s.stop("Schema push failed — will be set up on first dev start");
|
|
@@ -145,37 +159,156 @@ async function main() {
|
|
|
145
159
|
|
|
146
160
|
s.start("Seeding demo content");
|
|
147
161
|
try {
|
|
148
|
-
|
|
162
|
+
await run("pnpm cms:seed", projectDir);
|
|
149
163
|
s.stop("Demo content seeded");
|
|
150
164
|
} catch {
|
|
151
165
|
s.stop("Seeding failed — run `pnpm cms:seed` manually");
|
|
152
166
|
}
|
|
153
167
|
}
|
|
154
168
|
|
|
169
|
+
// --- Cloudflare resource setup ---
|
|
170
|
+
|
|
171
|
+
const cf = { d1Created: false, r2Created: false, migrationsApplied: false };
|
|
155
172
|
if (cloudflare) {
|
|
156
|
-
p.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
"
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
"",
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
173
|
+
const setupNow = await p.confirm({
|
|
174
|
+
message: "Set up Cloudflare resources now? (creates D1 database and R2 bucket)",
|
|
175
|
+
initialValue: true,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
if (!p.isCancel(setupNow) && setupNow) {
|
|
179
|
+
// Check wrangler authentication
|
|
180
|
+
let authenticated = false;
|
|
181
|
+
try {
|
|
182
|
+
await run("pnpm wrangler whoami", projectDir);
|
|
183
|
+
authenticated = true;
|
|
184
|
+
} catch {
|
|
185
|
+
p.note("You need to log in to Cloudflare first.", "Wrangler login required");
|
|
186
|
+
const doLogin = await p.confirm({ message: "Open browser to log in?", initialValue: true });
|
|
187
|
+
if (!p.isCancel(doLogin) && doLogin) {
|
|
188
|
+
try {
|
|
189
|
+
execSync("pnpm wrangler login", { cwd: projectDir, stdio: "inherit" });
|
|
190
|
+
authenticated = true;
|
|
191
|
+
} catch {
|
|
192
|
+
// Login failed
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (authenticated) {
|
|
198
|
+
// Create D1 database
|
|
199
|
+
let databaseId = null;
|
|
200
|
+
s.start("Creating D1 database");
|
|
201
|
+
try {
|
|
202
|
+
const { stdout } = await run(`pnpm wrangler d1 create ${projectName}-db`, projectDir);
|
|
203
|
+
const match = stdout.match(/database_id\s*=\s*"([^"]+)"/);
|
|
204
|
+
if (match) databaseId = match[1];
|
|
205
|
+
cf.d1Created = true;
|
|
206
|
+
s.stop("D1 database created");
|
|
207
|
+
} catch {
|
|
208
|
+
// Already exists — look it up
|
|
209
|
+
try {
|
|
210
|
+
const { stdout } = await run("pnpm wrangler d1 list", projectDir);
|
|
211
|
+
const dbLine = stdout.split("\n").find((l) => l.includes(`${projectName}-db`));
|
|
212
|
+
if (dbLine) {
|
|
213
|
+
const idMatch = dbLine.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/);
|
|
214
|
+
if (idMatch) databaseId = idMatch[0];
|
|
215
|
+
}
|
|
216
|
+
if (databaseId) {
|
|
217
|
+
cf.d1Created = true;
|
|
218
|
+
s.stop("D1 database already exists — using existing");
|
|
219
|
+
} else {
|
|
220
|
+
s.stop("D1 setup failed");
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
s.stop("D1 setup failed");
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Update wrangler.toml with database_id
|
|
228
|
+
if (databaseId) {
|
|
229
|
+
const wranglerPath = path.join(projectDir, "wrangler.toml");
|
|
230
|
+
let wranglerContent = readFileSync(wranglerPath, "utf-8");
|
|
231
|
+
wranglerContent = wranglerContent.replace(
|
|
232
|
+
/database_id = "" #[^\n]*/,
|
|
233
|
+
`database_id = "${databaseId}"`,
|
|
234
|
+
);
|
|
235
|
+
writeFileSync(wranglerPath, wranglerContent);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Create R2 bucket
|
|
239
|
+
s.start("Creating R2 bucket");
|
|
240
|
+
try {
|
|
241
|
+
await run(`pnpm wrangler r2 bucket create ${projectName}-assets`, projectDir);
|
|
242
|
+
cf.r2Created = true;
|
|
243
|
+
s.stop("R2 bucket created");
|
|
244
|
+
} catch {
|
|
245
|
+
// Already exists is fine
|
|
246
|
+
cf.r2Created = true;
|
|
247
|
+
s.stop("R2 bucket already exists");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Generate schema + migrations, apply to remote D1
|
|
251
|
+
if (databaseId) {
|
|
252
|
+
s.start("Generating CMS schema");
|
|
253
|
+
try {
|
|
254
|
+
await run("pnpm cms:generate", projectDir);
|
|
255
|
+
s.stop("Schema generated");
|
|
256
|
+
} catch {
|
|
257
|
+
s.stop("Schema generation failed");
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
s.start("Generating database migrations");
|
|
261
|
+
try {
|
|
262
|
+
await run("pnpm exec drizzle-kit generate", projectDir);
|
|
263
|
+
s.stop("Migrations generated");
|
|
264
|
+
} catch {
|
|
265
|
+
s.stop("Migration generation failed");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
s.start("Applying migrations to remote D1");
|
|
269
|
+
try {
|
|
270
|
+
await run(`pnpm wrangler d1 migrations apply ${projectName}-db --remote`, projectDir);
|
|
271
|
+
cf.migrationsApplied = true;
|
|
272
|
+
s.stop("Migrations applied");
|
|
273
|
+
} catch {
|
|
274
|
+
s.stop("Migration apply failed — run manually with: wrangler d1 migrations apply --remote");
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// --- Done ---
|
|
282
|
+
|
|
283
|
+
if (cloudflare) {
|
|
284
|
+
const lines = [`cd ${projectName}`];
|
|
285
|
+
const remaining = [];
|
|
286
|
+
if (!cf.d1Created) {
|
|
287
|
+
remaining.push(
|
|
288
|
+
` pnpm wrangler d1 create ${projectName}-db`,
|
|
289
|
+
" # Paste the database_id into wrangler.toml",
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
if (!cf.r2Created) {
|
|
293
|
+
remaining.push(` pnpm wrangler r2 bucket create ${projectName}-assets`);
|
|
294
|
+
}
|
|
295
|
+
if (!cf.migrationsApplied) {
|
|
296
|
+
remaining.push(` pnpm wrangler d1 migrations apply ${projectName}-db --remote`);
|
|
297
|
+
}
|
|
298
|
+
if (remaining.length > 0) {
|
|
299
|
+
lines.push("", "Remaining setup:", ...remaining);
|
|
300
|
+
}
|
|
301
|
+
lines.push("", "Local development:", " pnpm dev", "", "Deploy:", " pnpm deploy");
|
|
302
|
+
p.note(lines.join("\n"), "Next steps");
|
|
175
303
|
p.outro("Project created!");
|
|
176
304
|
} else {
|
|
177
|
-
p.
|
|
178
|
-
|
|
305
|
+
p.outro("Starting dev server...");
|
|
306
|
+
try {
|
|
307
|
+
execSync("pnpm dev", { cwd: projectDir, stdio: "inherit" });
|
|
308
|
+
} catch {
|
|
309
|
+
console.log(`\n Project directory: ${projectDir}`);
|
|
310
|
+
console.log(` To start again: cd ${projectName} && pnpm dev\n`);
|
|
311
|
+
}
|
|
179
312
|
}
|
|
180
313
|
}
|
|
181
314
|
|