create-kide-app 0.1.7 → 0.1.9
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 +1 -1
- package/index.js +63 -29
- package/package.json +4 -1
package/README.md
CHANGED
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import * as p from "@clack/prompts";
|
|
4
|
-
import { execSync, spawn } from "node:child_process";
|
|
4
|
+
import { execFileSync, execSync, spawn } from "node:child_process";
|
|
5
5
|
import {
|
|
6
6
|
cpSync,
|
|
7
7
|
existsSync,
|
|
@@ -59,6 +59,19 @@ const CLEANUP = [
|
|
|
59
59
|
".DS_Store",
|
|
60
60
|
];
|
|
61
61
|
|
|
62
|
+
// The project name reaches shell commands (git, wrangler) and path.resolve, so it is
|
|
63
|
+
// validated before either. Restricting it to one path segment of safe characters keeps
|
|
64
|
+
// `$(...)`, backticks, `;` and separators out of those commands and out of the target
|
|
65
|
+
// path. Must start alphanumeric so "." and ".." can never be the whole name.
|
|
66
|
+
const PROJECT_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
|
|
67
|
+
|
|
68
|
+
const validateProjectName = (value) => {
|
|
69
|
+
if (!PROJECT_NAME_PATTERN.test(value)) {
|
|
70
|
+
return "Project name must start with a letter or number and contain only letters, numbers, dots, dashes and underscores.";
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
};
|
|
74
|
+
|
|
62
75
|
// Resolve the latest release tag (v-prefixed semver) so scaffolds pin to a
|
|
63
76
|
// deliberate release instead of whatever HEAD happens to be. Returns null when
|
|
64
77
|
// the repo has no tags (falls back to the default branch).
|
|
@@ -91,6 +104,7 @@ async function main() {
|
|
|
91
104
|
placeholder: "my-cms-app",
|
|
92
105
|
validate: (value) => {
|
|
93
106
|
if (!value) return "Project name is required";
|
|
107
|
+
return validateProjectName(value);
|
|
94
108
|
},
|
|
95
109
|
}));
|
|
96
110
|
|
|
@@ -99,6 +113,14 @@ async function main() {
|
|
|
99
113
|
process.exit(0);
|
|
100
114
|
}
|
|
101
115
|
|
|
116
|
+
// Re-check: the interactive path validates above, but a name from argv skips it,
|
|
117
|
+
// and this value reaches shell commands and path.resolve below.
|
|
118
|
+
const nameError = validateProjectName(projectName);
|
|
119
|
+
if (nameError) {
|
|
120
|
+
p.cancel(nameError);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
|
|
102
124
|
const projectDir = path.resolve(process.cwd(), projectName);
|
|
103
125
|
if (existsSync(projectDir)) {
|
|
104
126
|
p.cancel(`Directory "${projectName}" already exists.`);
|
|
@@ -144,10 +166,16 @@ async function main() {
|
|
|
144
166
|
let templateCommit = null;
|
|
145
167
|
|
|
146
168
|
try {
|
|
147
|
-
const
|
|
148
|
-
execSync
|
|
149
|
-
|
|
150
|
-
|
|
169
|
+
const branchArgs = templateRef ? ["--branch", templateRef] : [];
|
|
170
|
+
// execFileSync, not execSync: no shell, so projectDir is passed as one argv entry
|
|
171
|
+
// and can never be reinterpreted as a command regardless of what it contains.
|
|
172
|
+
execFileSync(
|
|
173
|
+
"git",
|
|
174
|
+
["clone", "--depth", "1", ...branchArgs, REPO, projectDir],
|
|
175
|
+
{
|
|
176
|
+
stdio: "pipe",
|
|
177
|
+
},
|
|
178
|
+
);
|
|
151
179
|
try {
|
|
152
180
|
templateCommit = execSync("git rev-parse HEAD", {
|
|
153
181
|
cwd: projectDir,
|
|
@@ -184,31 +212,24 @@ async function main() {
|
|
|
184
212
|
const targetDir = path.join(adaptersDir, target);
|
|
185
213
|
|
|
186
214
|
if (target === "cloudflare") {
|
|
215
|
+
// The Cloudflare adapter/storage/env implementations live in the tree at
|
|
216
|
+
// src/cms/platform/cloudflare. We only copy the target's Astro/Drizzle/wrangler config and
|
|
217
|
+
// flip the two platform selectors to point at that profile — no source files are overwritten.
|
|
187
218
|
cpSync(
|
|
188
219
|
path.join(targetDir, "astro.config.mjs"),
|
|
189
220
|
path.join(projectDir, "astro.config.mjs"),
|
|
190
221
|
);
|
|
191
|
-
cpSync(
|
|
192
|
-
path.join(targetDir, "src/cms/adapters/db.ts"),
|
|
193
|
-
path.join(projectDir, "src/cms/adapters/db.ts"),
|
|
194
|
-
);
|
|
195
222
|
cpSync(
|
|
196
223
|
path.join(targetDir, "drizzle.config.ts"),
|
|
197
224
|
path.join(projectDir, "drizzle.config.ts"),
|
|
198
225
|
);
|
|
199
|
-
|
|
200
|
-
path.join(
|
|
201
|
-
|
|
202
|
-
);
|
|
203
|
-
cpSync(
|
|
204
|
-
path.join(targetDir, "src/cms/adapters/cf-env.ts"),
|
|
205
|
-
path.join(projectDir, "src/cms/adapters/cf-env.ts"),
|
|
226
|
+
writeFileSync(
|
|
227
|
+
path.join(projectDir, "src/cms/adapters/db.ts"),
|
|
228
|
+
'export * from "../platform/cloudflare/database";\n',
|
|
206
229
|
);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
path.join(targetDir, "src/pages/uploads/[...path].ts"),
|
|
211
|
-
path.join(uploadsRouteDir, "[...path].ts"),
|
|
230
|
+
writeFileSync(
|
|
231
|
+
path.join(projectDir, "src/cms/adapters/storage.ts"),
|
|
232
|
+
'export * from "../platform/cloudflare/storage";\n',
|
|
212
233
|
);
|
|
213
234
|
}
|
|
214
235
|
|
|
@@ -219,7 +240,7 @@ async function main() {
|
|
|
219
240
|
|
|
220
241
|
if (target === "cloudflare") {
|
|
221
242
|
delete pkg.dependencies["@astrojs/node"];
|
|
222
|
-
pkg.dependencies["@astrojs/cloudflare"] = "
|
|
243
|
+
pkg.dependencies["@astrojs/cloudflare"] = "~14.1.7";
|
|
223
244
|
|
|
224
245
|
// Move better-sqlite3 to devDependencies — drizzle-kit needs it to push schema to local D1
|
|
225
246
|
if (pkg.dependencies["better-sqlite3"]) {
|
|
@@ -248,7 +269,7 @@ async function main() {
|
|
|
248
269
|
);
|
|
249
270
|
writeFileSync(path.join(projectDir, "wrangler.toml"), wranglerContent);
|
|
250
271
|
|
|
251
|
-
pkg.devDependencies.wrangler = "^4.
|
|
272
|
+
pkg.devDependencies.wrangler = "^4.83.0";
|
|
252
273
|
|
|
253
274
|
pkg.scripts.dev = "astro dev";
|
|
254
275
|
pkg.scripts.build = "astro build";
|
|
@@ -689,12 +710,25 @@ async function main() {
|
|
|
689
710
|
// --- Done ---
|
|
690
711
|
|
|
691
712
|
if (target === "local") {
|
|
692
|
-
p.
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
|
|
713
|
+
const startDev = await p.confirm({
|
|
714
|
+
message: "Start the dev server now?",
|
|
715
|
+
initialValue: true,
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
if (!p.isCancel(startDev) && startDev) {
|
|
719
|
+
p.outro("Starting dev server...");
|
|
720
|
+
try {
|
|
721
|
+
execSync(`${pm.run} dev`, { cwd: projectDir, stdio: "inherit" });
|
|
722
|
+
} catch {
|
|
723
|
+
console.log(`\n Project directory: ${projectDir}`);
|
|
724
|
+
console.log(` To start again: cd ${projectName} && pnpm dev\n`);
|
|
725
|
+
}
|
|
726
|
+
} else {
|
|
727
|
+
p.note(
|
|
728
|
+
[`cd ${projectName}`, "", `${pm.run} dev`].join("\n"),
|
|
729
|
+
"Next steps",
|
|
730
|
+
);
|
|
731
|
+
p.outro("Project created!");
|
|
698
732
|
}
|
|
699
733
|
} else {
|
|
700
734
|
if (cf.deployed && cf.url) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-kide-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Scaffold a new Kide CMS project",
|
|
5
5
|
"author": "Matti Hernesniemi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
"bin": {
|
|
9
9
|
"create-kide-app": "./index.js"
|
|
10
10
|
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"release": "npm version patch && git push --follow-tags && npm publish"
|
|
13
|
+
},
|
|
11
14
|
"files": [
|
|
12
15
|
"index.js"
|
|
13
16
|
],
|