@vexblocks/cli 1.0.0 → 1.0.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/README.md +7 -7
- package/dist/index.js +603 -607
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,101 +4,12 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import pc6 from "picocolors";
|
|
6
6
|
|
|
7
|
-
// src/commands/
|
|
7
|
+
// src/commands/add.ts
|
|
8
8
|
import path4 from "path";
|
|
9
|
+
import { checkbox, confirm } from "@inquirer/prompts";
|
|
9
10
|
import fs4 from "fs-extra";
|
|
10
|
-
import pc2 from "picocolors";
|
|
11
11
|
import ora from "ora";
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
// src/utils/logger.ts
|
|
15
|
-
import pc from "picocolors";
|
|
16
|
-
var logger = {
|
|
17
|
-
info: (message) => {
|
|
18
|
-
console.log(pc.blue("\u2139"), message);
|
|
19
|
-
},
|
|
20
|
-
success: (message) => {
|
|
21
|
-
console.log(pc.green("\u2714"), message);
|
|
22
|
-
},
|
|
23
|
-
warn: (message) => {
|
|
24
|
-
console.log(pc.yellow("\u26A0"), message);
|
|
25
|
-
},
|
|
26
|
-
error: (message) => {
|
|
27
|
-
console.log(pc.red("\u2716"), message);
|
|
28
|
-
},
|
|
29
|
-
log: (message) => {
|
|
30
|
-
console.log(message);
|
|
31
|
-
},
|
|
32
|
-
break: () => {
|
|
33
|
-
console.log();
|
|
34
|
-
},
|
|
35
|
-
title: (message) => {
|
|
36
|
-
console.log();
|
|
37
|
-
console.log(pc.bold(pc.cyan(message)));
|
|
38
|
-
console.log();
|
|
39
|
-
},
|
|
40
|
-
step: (step, total, message) => {
|
|
41
|
-
console.log(pc.dim(`[${step}/${total}]`), message);
|
|
42
|
-
},
|
|
43
|
-
list: (items) => {
|
|
44
|
-
for (const item of items) {
|
|
45
|
-
console.log(pc.dim(" \u2022"), item);
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
box: (title, content) => {
|
|
49
|
-
const maxLength = Math.max(title.length, ...content.map((c) => c.length));
|
|
50
|
-
const border = "\u2500".repeat(maxLength + 4);
|
|
51
|
-
console.log();
|
|
52
|
-
console.log(pc.dim(`\u250C${border}\u2510`));
|
|
53
|
-
console.log(pc.dim("\u2502"), pc.bold(title.padEnd(maxLength + 2)), pc.dim("\u2502"));
|
|
54
|
-
console.log(pc.dim(`\u251C${border}\u2524`));
|
|
55
|
-
for (const line of content) {
|
|
56
|
-
console.log(pc.dim("\u2502"), line.padEnd(maxLength + 2), pc.dim("\u2502"));
|
|
57
|
-
}
|
|
58
|
-
console.log(pc.dim(`\u2514${border}\u2518`));
|
|
59
|
-
console.log();
|
|
60
|
-
},
|
|
61
|
-
code: (code, language) => {
|
|
62
|
-
console.log();
|
|
63
|
-
console.log(pc.dim(`\`\`\`${language || ""}`));
|
|
64
|
-
console.log(code);
|
|
65
|
-
console.log(pc.dim("```"));
|
|
66
|
-
console.log();
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// src/utils/fs.ts
|
|
71
|
-
import fs from "fs-extra";
|
|
72
|
-
import path from "path";
|
|
73
|
-
import crypto from "crypto";
|
|
74
|
-
async function isTurborepoProject(cwd) {
|
|
75
|
-
const turboJsonPath = path.join(cwd, "turbo.json");
|
|
76
|
-
return fs.pathExists(turboJsonPath);
|
|
77
|
-
}
|
|
78
|
-
async function getPackageManager(cwd) {
|
|
79
|
-
if (await fs.pathExists(path.join(cwd, "pnpm-lock.yaml"))) {
|
|
80
|
-
return "pnpm";
|
|
81
|
-
}
|
|
82
|
-
if (await fs.pathExists(path.join(cwd, "yarn.lock"))) {
|
|
83
|
-
return "yarn";
|
|
84
|
-
}
|
|
85
|
-
if (await fs.pathExists(path.join(cwd, "bun.lockb"))) {
|
|
86
|
-
return "bun";
|
|
87
|
-
}
|
|
88
|
-
return "npm";
|
|
89
|
-
}
|
|
90
|
-
async function createBackup(filePath) {
|
|
91
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
92
|
-
const backupPath = `${filePath}.backup-${timestamp}`;
|
|
93
|
-
if (await fs.pathExists(filePath)) {
|
|
94
|
-
await fs.copy(filePath, backupPath);
|
|
95
|
-
}
|
|
96
|
-
return backupPath;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// src/utils/manifest.ts
|
|
100
|
-
import fs2 from "fs-extra";
|
|
101
|
-
import path2 from "path";
|
|
12
|
+
import pc2 from "picocolors";
|
|
102
13
|
|
|
103
14
|
// src/utils/constants.ts
|
|
104
15
|
var GITHUB_REPO = "vexblocks/vexblocks";
|
|
@@ -151,33 +62,38 @@ var OPTIONAL_ENV_VARS = {
|
|
|
151
62
|
]
|
|
152
63
|
};
|
|
153
64
|
|
|
154
|
-
// src/utils/
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return null;
|
|
162
|
-
} catch {
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
65
|
+
// src/utils/fs.ts
|
|
66
|
+
import crypto from "crypto";
|
|
67
|
+
import path from "path";
|
|
68
|
+
import fs from "fs-extra";
|
|
69
|
+
async function isTurborepoProject(cwd) {
|
|
70
|
+
const turboJsonPath = path.join(cwd, "turbo.json");
|
|
71
|
+
return fs.pathExists(turboJsonPath);
|
|
165
72
|
}
|
|
166
|
-
async function
|
|
167
|
-
|
|
168
|
-
|
|
73
|
+
async function getPackageManager(cwd) {
|
|
74
|
+
if (await fs.pathExists(path.join(cwd, "pnpm-lock.yaml"))) {
|
|
75
|
+
return "pnpm";
|
|
76
|
+
}
|
|
77
|
+
if (await fs.pathExists(path.join(cwd, "yarn.lock"))) {
|
|
78
|
+
return "yarn";
|
|
79
|
+
}
|
|
80
|
+
if (await fs.pathExists(path.join(cwd, "bun.lockb"))) {
|
|
81
|
+
return "bun";
|
|
82
|
+
}
|
|
83
|
+
return "npm";
|
|
169
84
|
}
|
|
170
|
-
function
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
85
|
+
async function createBackup(filePath) {
|
|
86
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
87
|
+
const backupPath = `${filePath}.backup-${timestamp}`;
|
|
88
|
+
if (await fs.pathExists(filePath)) {
|
|
89
|
+
await fs.copy(filePath, backupPath);
|
|
90
|
+
}
|
|
91
|
+
return backupPath;
|
|
176
92
|
}
|
|
177
93
|
|
|
178
94
|
// src/utils/github.ts
|
|
179
|
-
import
|
|
180
|
-
import
|
|
95
|
+
import path2 from "path";
|
|
96
|
+
import fs2 from "fs-extra";
|
|
181
97
|
async function fetchRemoteManifest() {
|
|
182
98
|
const url = `${GITHUB_RAW_URL}/templates/manifest.json`;
|
|
183
99
|
const response = await fetch(url);
|
|
@@ -200,9 +116,9 @@ async function downloadFile(remotePath, localPath) {
|
|
|
200
116
|
if (!response.ok) {
|
|
201
117
|
throw new Error(`Failed to download ${remotePath}: ${response.statusText}`);
|
|
202
118
|
}
|
|
203
|
-
await
|
|
119
|
+
await fs2.ensureDir(path2.dirname(localPath));
|
|
204
120
|
const content = await response.text();
|
|
205
|
-
await
|
|
121
|
+
await fs2.writeFile(localPath, content, "utf-8");
|
|
206
122
|
}
|
|
207
123
|
async function downloadAndExtractPackage(packagePath, targetDir, onProgress) {
|
|
208
124
|
const treeUrl = `https://api.github.com/repos/${GITHUB_REPO}/git/trees/${GITHUB_BRANCH}?recursive=1`;
|
|
@@ -221,7 +137,7 @@ async function downloadAndExtractPackage(packagePath, targetDir, onProgress) {
|
|
|
221
137
|
);
|
|
222
138
|
for (const file of files) {
|
|
223
139
|
const relativePath = file.path.slice(packagePath.length + 1);
|
|
224
|
-
const localPath =
|
|
140
|
+
const localPath = path2.join(targetDir, relativePath);
|
|
225
141
|
onProgress?.(relativePath);
|
|
226
142
|
await downloadFile(file.path, localPath);
|
|
227
143
|
}
|
|
@@ -296,261 +212,98 @@ function compareVersions(a, b) {
|
|
|
296
212
|
return 0;
|
|
297
213
|
}
|
|
298
214
|
|
|
299
|
-
// src/
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
}
|
|
332
|
-
]
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
if (projectType === "new") {
|
|
336
|
-
await createNewProject(cwd, options);
|
|
337
|
-
} else {
|
|
338
|
-
await initializeExisting(cwd, options);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
async function createNewProject(cwd, options) {
|
|
342
|
-
const projectName = await input({
|
|
343
|
-
message: "Project name:",
|
|
344
|
-
default: path4.basename(cwd),
|
|
345
|
-
validate: (value) => {
|
|
346
|
-
if (!value) return "Project name is required";
|
|
347
|
-
if (!/^[a-z0-9-_]+$/.test(value)) {
|
|
348
|
-
return "Project name can only contain lowercase letters, numbers, hyphens, and underscores";
|
|
349
|
-
}
|
|
350
|
-
return true;
|
|
215
|
+
// src/utils/logger.ts
|
|
216
|
+
import pc from "picocolors";
|
|
217
|
+
var logger = {
|
|
218
|
+
info: (message) => {
|
|
219
|
+
console.log(pc.blue("\u2139"), message);
|
|
220
|
+
},
|
|
221
|
+
success: (message) => {
|
|
222
|
+
console.log(pc.green("\u2714"), message);
|
|
223
|
+
},
|
|
224
|
+
warn: (message) => {
|
|
225
|
+
console.log(pc.yellow("\u26A0"), message);
|
|
226
|
+
},
|
|
227
|
+
error: (message) => {
|
|
228
|
+
console.log(pc.red("\u2716"), message);
|
|
229
|
+
},
|
|
230
|
+
log: (message) => {
|
|
231
|
+
console.log(message);
|
|
232
|
+
},
|
|
233
|
+
break: () => {
|
|
234
|
+
console.log();
|
|
235
|
+
},
|
|
236
|
+
title: (message) => {
|
|
237
|
+
console.log();
|
|
238
|
+
console.log(pc.bold(pc.cyan(message)));
|
|
239
|
+
console.log();
|
|
240
|
+
},
|
|
241
|
+
step: (step, total, message) => {
|
|
242
|
+
console.log(pc.dim(`[${step}/${total}]`), message);
|
|
243
|
+
},
|
|
244
|
+
list: (items) => {
|
|
245
|
+
for (const item of items) {
|
|
246
|
+
console.log(pc.dim(" \u2022"), item);
|
|
351
247
|
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
248
|
+
},
|
|
249
|
+
box: (title, content) => {
|
|
250
|
+
const maxLength = Math.max(title.length, ...content.map((c) => c.length));
|
|
251
|
+
const border = "\u2500".repeat(maxLength + 4);
|
|
252
|
+
console.log();
|
|
253
|
+
console.log(pc.dim(`\u250C${border}\u2510`));
|
|
254
|
+
console.log(pc.dim("\u2502"), pc.bold(title.padEnd(maxLength + 2)), pc.dim("\u2502"));
|
|
255
|
+
console.log(pc.dim(`\u251C${border}\u2524`));
|
|
256
|
+
for (const line of content) {
|
|
257
|
+
console.log(pc.dim("\u2502"), line.padEnd(maxLength + 2), pc.dim("\u2502"));
|
|
362
258
|
}
|
|
363
|
-
|
|
259
|
+
console.log(pc.dim(`\u2514${border}\u2518`));
|
|
260
|
+
console.log();
|
|
261
|
+
},
|
|
262
|
+
code: (code, language) => {
|
|
263
|
+
console.log();
|
|
264
|
+
console.log(pc.dim(`\`\`\`${language || ""}`));
|
|
265
|
+
console.log(code);
|
|
266
|
+
console.log(pc.dim("```"));
|
|
267
|
+
console.log();
|
|
364
268
|
}
|
|
365
|
-
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// src/utils/manifest.ts
|
|
272
|
+
import path3 from "path";
|
|
273
|
+
import fs3 from "fs-extra";
|
|
274
|
+
async function readManifest(cwd) {
|
|
275
|
+
const manifestPath = path3.join(cwd, MANIFEST_FILE);
|
|
366
276
|
try {
|
|
367
|
-
await
|
|
368
|
-
|
|
369
|
-
await fs4.ensureDir(path4.join(projectDir, "packages"));
|
|
370
|
-
const packageJson = {
|
|
371
|
-
name: projectName,
|
|
372
|
-
version: "0.1.0",
|
|
373
|
-
private: true,
|
|
374
|
-
packageManager: "pnpm@9.15.0",
|
|
375
|
-
workspaces: ["apps/*", "packages/*"],
|
|
376
|
-
scripts: {
|
|
377
|
-
dev: "turbo run dev",
|
|
378
|
-
build: "turbo run build",
|
|
379
|
-
lint: "turbo run lint",
|
|
380
|
-
"generate-types": "pnpm --filter @repo/type-generator generate"
|
|
381
|
-
},
|
|
382
|
-
devDependencies: {
|
|
383
|
-
turbo: "^2.6.1"
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
await fs4.writeJson(path4.join(projectDir, "package.json"), packageJson, {
|
|
387
|
-
spaces: 2
|
|
388
|
-
});
|
|
389
|
-
const turboJson = {
|
|
390
|
-
$schema: "https://turbo.build/schema.json",
|
|
391
|
-
globalDependencies: ["**/.env.*local"],
|
|
392
|
-
globalEnv: [
|
|
393
|
-
"CONVEX_DEPLOYMENT",
|
|
394
|
-
"NEXT_PUBLIC_CONVEX_URL",
|
|
395
|
-
"NEXT_PUBLIC_CONVEX_SITE_URL",
|
|
396
|
-
"SITE_URL",
|
|
397
|
-
"CLOUDFLARE_ACCOUNT_ID",
|
|
398
|
-
"CLOUDFLARE_SECRET_TOKEN"
|
|
399
|
-
],
|
|
400
|
-
ui: "tui",
|
|
401
|
-
tasks: {
|
|
402
|
-
dev: {
|
|
403
|
-
cache: false,
|
|
404
|
-
persistent: true
|
|
405
|
-
},
|
|
406
|
-
build: {
|
|
407
|
-
dependsOn: ["^build"],
|
|
408
|
-
inputs: ["$TURBO_DEFAULT$", ".env*"],
|
|
409
|
-
outputs: [".next/**", "dist/**"]
|
|
410
|
-
},
|
|
411
|
-
lint: {
|
|
412
|
-
outputs: []
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
await fs4.writeJson(path4.join(projectDir, "turbo.json"), turboJson, {
|
|
417
|
-
spaces: 2
|
|
418
|
-
});
|
|
419
|
-
const pnpmWorkspace = `packages:
|
|
420
|
-
- "apps/*"
|
|
421
|
-
- "packages/*"
|
|
422
|
-
`;
|
|
423
|
-
await fs4.writeFile(
|
|
424
|
-
path4.join(projectDir, "pnpm-workspace.yaml"),
|
|
425
|
-
pnpmWorkspace
|
|
426
|
-
);
|
|
427
|
-
const gitignore = `# Dependencies
|
|
428
|
-
node_modules
|
|
429
|
-
.pnpm-store
|
|
430
|
-
|
|
431
|
-
# Build outputs
|
|
432
|
-
dist
|
|
433
|
-
.next
|
|
434
|
-
.turbo
|
|
435
|
-
|
|
436
|
-
# Environment files
|
|
437
|
-
.env
|
|
438
|
-
.env.local
|
|
439
|
-
.env.*.local
|
|
440
|
-
|
|
441
|
-
# IDE
|
|
442
|
-
.idea
|
|
443
|
-
.vscode
|
|
444
|
-
*.swp
|
|
445
|
-
*.swo
|
|
446
|
-
|
|
447
|
-
# OS
|
|
448
|
-
.DS_Store
|
|
449
|
-
Thumbs.db
|
|
450
|
-
|
|
451
|
-
# Logs
|
|
452
|
-
*.log
|
|
453
|
-
npm-debug.log*
|
|
454
|
-
pnpm-debug.log*
|
|
455
|
-
|
|
456
|
-
# Convex
|
|
457
|
-
.convex
|
|
458
|
-
`;
|
|
459
|
-
await fs4.writeFile(path4.join(projectDir, ".gitignore"), gitignore);
|
|
460
|
-
const envExample = `# Convex
|
|
461
|
-
CONVEX_DEPLOYMENT=
|
|
462
|
-
NEXT_PUBLIC_CONVEX_URL=
|
|
463
|
-
|
|
464
|
-
# Better Auth
|
|
465
|
-
SITE_URL=http://localhost:3001
|
|
466
|
-
|
|
467
|
-
# Cloudflare Images (optional, for media library)
|
|
468
|
-
CLOUDFLARE_ACCOUNT_ID=
|
|
469
|
-
CLOUDFLARE_SECRET_TOKEN=
|
|
470
|
-
|
|
471
|
-
# Revalidation (optional, for ISR)
|
|
472
|
-
REVALIDATE_SECRET=
|
|
473
|
-
FRONTEND_URL=http://localhost:3000
|
|
474
|
-
`;
|
|
475
|
-
await fs4.writeFile(path4.join(projectDir, ".env.example"), envExample);
|
|
476
|
-
const version = await getLatestVersion();
|
|
477
|
-
const manifest = createManifest(version);
|
|
478
|
-
await writeManifest(projectDir, manifest);
|
|
479
|
-
spinner.succeed("Project structure created");
|
|
480
|
-
logger.break();
|
|
481
|
-
logger.box("\u2705 Project created successfully!", [
|
|
482
|
-
`Directory: ${pc2.cyan(projectDir)}`,
|
|
483
|
-
"",
|
|
484
|
-
pc2.bold("Next steps:"),
|
|
485
|
-
`1. ${pc2.cyan(`cd ${projectName}`)}`,
|
|
486
|
-
`2. ${pc2.cyan("pnpm install")}`,
|
|
487
|
-
`3. ${pc2.cyan("npx vexblocks add all")}`,
|
|
488
|
-
"4. Set up your Convex project",
|
|
489
|
-
`5. ${pc2.cyan("pnpm dev")}`
|
|
490
|
-
]);
|
|
491
|
-
const addPackages = options.yes || await confirm({
|
|
492
|
-
message: "Would you like to add VexBlocks packages now?",
|
|
493
|
-
default: true
|
|
494
|
-
});
|
|
495
|
-
if (addPackages) {
|
|
496
|
-
logger.break();
|
|
497
|
-
logger.info(`Run: ${pc2.cyan("npx vexblocks add all")}`);
|
|
498
|
-
logger.info("After navigating to your project directory.");
|
|
277
|
+
if (await fs3.pathExists(manifestPath)) {
|
|
278
|
+
return await fs3.readJson(manifestPath);
|
|
499
279
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
280
|
+
return null;
|
|
281
|
+
} catch {
|
|
282
|
+
return null;
|
|
503
283
|
}
|
|
504
284
|
}
|
|
505
|
-
async function
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
const version = await getLatestVersion();
|
|
518
|
-
const manifest = createManifest(version);
|
|
519
|
-
await writeManifest(cwd, manifest);
|
|
520
|
-
spinner.succeed("VexBlocks initialized");
|
|
521
|
-
const packageManager = await getPackageManager(cwd);
|
|
522
|
-
logger.break();
|
|
523
|
-
logger.box("\u2705 VexBlocks initialized!", [
|
|
524
|
-
`Manifest: ${pc2.cyan(MANIFEST_FILE)}`,
|
|
525
|
-
`Version: ${pc2.cyan(version)}`,
|
|
526
|
-
"",
|
|
527
|
-
pc2.bold("Next steps:"),
|
|
528
|
-
`1. ${pc2.cyan("npx vexblocks add all")} - Add all CMS packages`,
|
|
529
|
-
"2. Configure your environment variables",
|
|
530
|
-
`3. ${pc2.cyan(`${packageManager} install`)}`,
|
|
531
|
-
`4. ${pc2.cyan(`${packageManager === "npm" ? "npm run" : packageManager} dev`)}`
|
|
532
|
-
]);
|
|
533
|
-
} catch (error) {
|
|
534
|
-
spinner.fail("Failed to initialize");
|
|
535
|
-
throw error;
|
|
536
|
-
}
|
|
285
|
+
async function writeManifest(cwd, manifest) {
|
|
286
|
+
const manifestPath = path3.join(cwd, MANIFEST_FILE);
|
|
287
|
+
await fs3.writeJson(manifestPath, manifest, { spaces: 2 });
|
|
288
|
+
}
|
|
289
|
+
function createManifest(version) {
|
|
290
|
+
return {
|
|
291
|
+
$schema: "https://vexblocks.com/schema/vexblocks.json",
|
|
292
|
+
version,
|
|
293
|
+
packages: {}
|
|
294
|
+
};
|
|
537
295
|
}
|
|
538
296
|
|
|
539
297
|
// src/commands/add.ts
|
|
540
|
-
import path5 from "path";
|
|
541
|
-
import fs5 from "fs-extra";
|
|
542
|
-
import pc3 from "picocolors";
|
|
543
|
-
import ora2 from "ora";
|
|
544
|
-
import { confirm as confirm2, checkbox } from "@inquirer/prompts";
|
|
545
298
|
var ALL_PACKAGES = ["backend", "shared", "types", "cms"];
|
|
546
299
|
async function addCommand(packages, options) {
|
|
547
|
-
const cwd = options.cwd ?
|
|
300
|
+
const cwd = options.cwd ? path4.resolve(options.cwd) : process.cwd();
|
|
548
301
|
logger.title("\u{1F4E6} Add VexBlocks Packages");
|
|
549
302
|
const isTurbo = await isTurborepoProject(cwd);
|
|
550
303
|
if (!isTurbo) {
|
|
551
304
|
logger.error("This is not a Turborepo project.");
|
|
552
305
|
logger.info(
|
|
553
|
-
`Run ${
|
|
306
|
+
`Run ${pc2.cyan("npx @vexblocks/cli init")} first to set up your project.`
|
|
554
307
|
);
|
|
555
308
|
process.exit(1);
|
|
556
309
|
}
|
|
@@ -600,13 +353,13 @@ async function addCommand(packages, options) {
|
|
|
600
353
|
const existingPackages = [];
|
|
601
354
|
for (const pkg of resolvedPackages) {
|
|
602
355
|
const targetPath = getPackageTargetPath(cwd, pkg);
|
|
603
|
-
if (await
|
|
356
|
+
if (await fs4.pathExists(targetPath)) {
|
|
604
357
|
existingPackages.push(pkg);
|
|
605
358
|
}
|
|
606
359
|
}
|
|
607
360
|
if (existingPackages.length > 0 && !options.overwrite) {
|
|
608
361
|
logger.warn(`These packages already exist: ${existingPackages.join(", ")}`);
|
|
609
|
-
const overwrite = options.yes || await
|
|
362
|
+
const overwrite = options.yes || await confirm({
|
|
610
363
|
message: "Overwrite existing packages?",
|
|
611
364
|
default: false
|
|
612
365
|
});
|
|
@@ -623,16 +376,16 @@ async function addCommand(packages, options) {
|
|
|
623
376
|
}
|
|
624
377
|
}
|
|
625
378
|
logger.break();
|
|
626
|
-
logger.log(
|
|
379
|
+
logger.log(pc2.bold("Packages to install:"));
|
|
627
380
|
for (const pkg of resolvedPackages) {
|
|
628
381
|
const targetPath = getPackageTargetPath(cwd, pkg);
|
|
629
|
-
const relativePath =
|
|
382
|
+
const relativePath = path4.relative(cwd, targetPath);
|
|
630
383
|
logger.log(
|
|
631
|
-
` ${
|
|
384
|
+
` ${pc2.green("+")} ${PACKAGE_NAMES[pkg]} \u2192 ${pc2.dim(relativePath)}`
|
|
632
385
|
);
|
|
633
386
|
}
|
|
634
387
|
logger.break();
|
|
635
|
-
const proceed = options.yes || await
|
|
388
|
+
const proceed = options.yes || await confirm({
|
|
636
389
|
message: "Proceed with installation?",
|
|
637
390
|
default: true
|
|
638
391
|
});
|
|
@@ -673,34 +426,34 @@ function resolveDependencies(packages) {
|
|
|
673
426
|
function getPackageTargetPath(cwd, pkg) {
|
|
674
427
|
switch (pkg) {
|
|
675
428
|
case "cms":
|
|
676
|
-
return
|
|
429
|
+
return path4.join(cwd, "apps", "cms");
|
|
677
430
|
case "backend":
|
|
678
|
-
return
|
|
431
|
+
return path4.join(cwd, "packages", "backend");
|
|
679
432
|
case "shared":
|
|
680
|
-
return
|
|
433
|
+
return path4.join(cwd, "packages", "cms-shared");
|
|
681
434
|
case "types":
|
|
682
|
-
return
|
|
435
|
+
return path4.join(cwd, "packages", "type-generator");
|
|
683
436
|
default:
|
|
684
|
-
return
|
|
437
|
+
return path4.join(cwd, PACKAGE_PATHS[pkg]);
|
|
685
438
|
}
|
|
686
439
|
}
|
|
687
440
|
async function installPackage(cwd, pkg, version, manifest) {
|
|
688
|
-
const spinner =
|
|
441
|
+
const spinner = ora(`Installing ${PACKAGE_NAMES[pkg]}...`).start();
|
|
689
442
|
try {
|
|
690
443
|
const targetPath = getPackageTargetPath(cwd, pkg);
|
|
691
444
|
const sourcePath = PACKAGE_PATHS[pkg];
|
|
692
445
|
if (pkg === "backend") {
|
|
693
446
|
await installBackendPackage(targetPath, sourcePath, spinner);
|
|
694
447
|
} else {
|
|
695
|
-
await
|
|
448
|
+
await fs4.ensureDir(targetPath);
|
|
696
449
|
await downloadAndExtractPackage(sourcePath, targetPath, (file) => {
|
|
697
|
-
spinner.text = `Installing ${PACKAGE_NAMES[pkg]}... ${
|
|
450
|
+
spinner.text = `Installing ${PACKAGE_NAMES[pkg]}... ${pc2.dim(file)}`;
|
|
698
451
|
});
|
|
699
452
|
}
|
|
700
453
|
const config = {
|
|
701
454
|
version,
|
|
702
455
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
703
|
-
path:
|
|
456
|
+
path: path4.relative(cwd, targetPath)
|
|
704
457
|
};
|
|
705
458
|
manifest.packages[pkg] = config;
|
|
706
459
|
spinner.succeed(`Installed ${PACKAGE_NAMES[pkg]}`);
|
|
@@ -710,14 +463,14 @@ async function installPackage(cwd, pkg, version, manifest) {
|
|
|
710
463
|
}
|
|
711
464
|
}
|
|
712
465
|
async function installBackendPackage(targetPath, sourcePath, spinner) {
|
|
713
|
-
const convexPath =
|
|
714
|
-
const existingSchemaPath =
|
|
715
|
-
const hasSchema = await
|
|
466
|
+
const convexPath = path4.join(targetPath, "convex");
|
|
467
|
+
const existingSchemaPath = path4.join(convexPath, "schema.ts");
|
|
468
|
+
const hasSchema = await fs4.pathExists(existingSchemaPath);
|
|
716
469
|
if (hasSchema) {
|
|
717
470
|
spinner.text = "Detected existing Convex schema, merging CMS tables...";
|
|
718
471
|
const backupPath = `${existingSchemaPath}.backup-${Date.now()}`;
|
|
719
|
-
await
|
|
720
|
-
logger.info(`Backed up existing schema to ${
|
|
472
|
+
await fs4.copy(existingSchemaPath, backupPath);
|
|
473
|
+
logger.info(`Backed up existing schema to ${path4.basename(backupPath)}`);
|
|
721
474
|
const cmsFiles = [
|
|
722
475
|
"convex/cms",
|
|
723
476
|
"convex/schema.cms.ts",
|
|
@@ -730,15 +483,15 @@ async function installBackendPackage(targetPath, sourcePath, spinner) {
|
|
|
730
483
|
];
|
|
731
484
|
for (const file of cmsFiles) {
|
|
732
485
|
const fullSourcePath = `${sourcePath}/${file}`;
|
|
733
|
-
const fullTargetPath =
|
|
486
|
+
const fullTargetPath = path4.join(targetPath, file);
|
|
734
487
|
spinner.text = `Downloading ${file}...`;
|
|
735
488
|
try {
|
|
736
489
|
await downloadAndExtractPackage(fullSourcePath, fullTargetPath);
|
|
737
490
|
} catch {
|
|
738
491
|
try {
|
|
739
492
|
const content = await fetchFile(fullSourcePath);
|
|
740
|
-
await
|
|
741
|
-
await
|
|
493
|
+
await fs4.ensureDir(path4.dirname(fullTargetPath));
|
|
494
|
+
await fs4.writeFile(fullTargetPath, content);
|
|
742
495
|
} catch {
|
|
743
496
|
}
|
|
744
497
|
}
|
|
@@ -756,14 +509,14 @@ async function installBackendPackage(targetPath, sourcePath, spinner) {
|
|
|
756
509
|
// })
|
|
757
510
|
// === END VEXBLOCKS CMS ===
|
|
758
511
|
`;
|
|
759
|
-
const existingContent = await
|
|
512
|
+
const existingContent = await fs4.readFile(existingSchemaPath, "utf-8");
|
|
760
513
|
if (!existingContent.includes("VEXBLOCKS CMS")) {
|
|
761
|
-
await
|
|
514
|
+
await fs4.appendFile(existingSchemaPath, schemaInstructions);
|
|
762
515
|
}
|
|
763
516
|
} else {
|
|
764
|
-
await
|
|
517
|
+
await fs4.ensureDir(targetPath);
|
|
765
518
|
await downloadAndExtractPackage(sourcePath, targetPath, (file) => {
|
|
766
|
-
spinner.text = `Installing backend... ${
|
|
519
|
+
spinner.text = `Installing backend... ${pc2.dim(file)}`;
|
|
767
520
|
});
|
|
768
521
|
}
|
|
769
522
|
}
|
|
@@ -772,28 +525,28 @@ function showNextSteps(packages) {
|
|
|
772
525
|
logger.break();
|
|
773
526
|
logger.box("\u2705 Packages installed successfully!", [
|
|
774
527
|
"",
|
|
775
|
-
|
|
528
|
+
pc2.bold("Next steps:"),
|
|
776
529
|
"",
|
|
777
|
-
`1. Install dependencies: ${
|
|
530
|
+
`1. Install dependencies: ${pc2.cyan(`${packageManager} install`)}`,
|
|
778
531
|
"",
|
|
779
532
|
"2. Set up environment variables:",
|
|
780
|
-
...getRequiredEnvVars(packages).map((v) => ` ${
|
|
533
|
+
...getRequiredEnvVars(packages).map((v) => ` ${pc2.dim(v)}`),
|
|
781
534
|
"",
|
|
782
535
|
"3. Set up Convex (if not already):",
|
|
783
|
-
` ${
|
|
536
|
+
` ${pc2.cyan("npx convex dev")} in packages/backend`,
|
|
784
537
|
"",
|
|
785
538
|
"4. Start development:",
|
|
786
|
-
` ${
|
|
539
|
+
` ${pc2.cyan(`${packageManager} dev`)}`,
|
|
787
540
|
"",
|
|
788
|
-
|
|
541
|
+
pc2.dim("CMS will be available at http://localhost:3001")
|
|
789
542
|
]);
|
|
790
543
|
const optionalVars = getOptionalEnvVars(packages);
|
|
791
544
|
if (optionalVars.length > 0) {
|
|
792
545
|
logger.break();
|
|
793
|
-
logger.log(
|
|
546
|
+
logger.log(pc2.bold("Optional environment variables:"));
|
|
794
547
|
for (const { name, description } of optionalVars) {
|
|
795
|
-
logger.log(` ${
|
|
796
|
-
logger.log(` ${
|
|
548
|
+
logger.log(` ${pc2.yellow(name)}`);
|
|
549
|
+
logger.log(` ${pc2.dim(description)}`);
|
|
797
550
|
}
|
|
798
551
|
}
|
|
799
552
|
}
|
|
@@ -822,219 +575,50 @@ function getOptionalEnvVars(packages) {
|
|
|
822
575
|
return vars;
|
|
823
576
|
}
|
|
824
577
|
|
|
825
|
-
// src/commands/
|
|
826
|
-
import
|
|
827
|
-
import
|
|
828
|
-
import
|
|
829
|
-
import
|
|
830
|
-
import
|
|
831
|
-
async function
|
|
832
|
-
const cwd = options.cwd ?
|
|
833
|
-
logger.title("\
|
|
578
|
+
// src/commands/diff.ts
|
|
579
|
+
import path5 from "path";
|
|
580
|
+
import { createTwoFilesPatch } from "diff";
|
|
581
|
+
import fs5 from "fs-extra";
|
|
582
|
+
import ora2 from "ora";
|
|
583
|
+
import pc3 from "picocolors";
|
|
584
|
+
async function diffCommand(packageArg, options) {
|
|
585
|
+
const cwd = options.cwd ? path5.resolve(options.cwd) : process.cwd();
|
|
586
|
+
logger.title("\u{1F50D} VexBlocks Diff");
|
|
834
587
|
const manifest = await readManifest(cwd);
|
|
835
588
|
if (!manifest) {
|
|
836
|
-
logger.error("No vexblocks.json found. Run `vexblocks init` first.");
|
|
589
|
+
logger.error("No vexblocks.json found. Run `npx @vexblocks/cli init` first.");
|
|
837
590
|
process.exit(1);
|
|
838
591
|
}
|
|
839
|
-
const spinner = ora3("Checking for updates...").start();
|
|
840
|
-
const latestVersion = await getLatestVersion();
|
|
841
|
-
spinner.stop();
|
|
842
592
|
const installedPackages = Object.keys(manifest.packages);
|
|
843
593
|
if (installedPackages.length === 0) {
|
|
844
|
-
logger.info("No packages installed.
|
|
594
|
+
logger.info("No packages installed.");
|
|
845
595
|
return;
|
|
846
596
|
}
|
|
847
|
-
let
|
|
848
|
-
if (
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
(p) => installedPackages.includes(p)
|
|
853
|
-
);
|
|
854
|
-
if (packagesToUpgrade.length === 0) {
|
|
855
|
-
logger.error("None of the specified packages are installed.");
|
|
597
|
+
let packageToDiff;
|
|
598
|
+
if (packageArg) {
|
|
599
|
+
if (!installedPackages.includes(packageArg)) {
|
|
600
|
+
logger.error(`Package "${packageArg}" is not installed.`);
|
|
601
|
+
logger.info(`Installed packages: ${installedPackages.join(", ")}`);
|
|
856
602
|
return;
|
|
857
603
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
updates.push({
|
|
866
|
-
pkg,
|
|
867
|
-
from: config.version,
|
|
868
|
-
to: latestVersion
|
|
869
|
-
});
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
if (updates.length === 0) {
|
|
873
|
-
logger.success("All packages are up to date!");
|
|
874
|
-
logger.info(`Current version: ${pc4.cyan(latestVersion)}`);
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
logger.log(pc4.bold("\nAvailable updates:"));
|
|
878
|
-
logger.break();
|
|
879
|
-
for (const update of updates) {
|
|
880
|
-
const isManaged = MANAGED_PACKAGES.includes(update.pkg);
|
|
881
|
-
logger.log(
|
|
882
|
-
` ${PACKAGE_NAMES[update.pkg]}`,
|
|
883
|
-
pc4.dim(`${update.from} \u2192 `),
|
|
884
|
-
pc4.green(update.to),
|
|
885
|
-
isManaged ? pc4.yellow(" (managed)") : ""
|
|
886
|
-
);
|
|
887
|
-
}
|
|
888
|
-
const changelog = await getChangelog(updates[0].from, latestVersion);
|
|
889
|
-
if (Object.keys(changelog).length > 0) {
|
|
890
|
-
logger.break();
|
|
891
|
-
logger.log(pc4.bold("Changelog:"));
|
|
892
|
-
for (const [version, changes] of Object.entries(changelog)) {
|
|
893
|
-
logger.log(`
|
|
894
|
-
${pc4.cyan(version)}`);
|
|
895
|
-
for (const change of changes) {
|
|
896
|
-
logger.log(` ${pc4.dim("\u2022")} ${change}`);
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
if (options.check) {
|
|
901
|
-
logger.break();
|
|
902
|
-
logger.info(
|
|
903
|
-
`Run ${pc4.cyan("npx vexblocks upgrade")} to apply these updates.`
|
|
904
|
-
);
|
|
905
|
-
return;
|
|
906
|
-
}
|
|
907
|
-
logger.break();
|
|
908
|
-
const proceed = options.yes || await confirm3({
|
|
909
|
-
message: `Upgrade ${updates.length} package(s)?`,
|
|
910
|
-
default: true
|
|
911
|
-
});
|
|
912
|
-
if (!proceed) {
|
|
913
|
-
logger.info("Aborted.");
|
|
604
|
+
packageToDiff = packageArg;
|
|
605
|
+
} else if (installedPackages.length === 1) {
|
|
606
|
+
packageToDiff = installedPackages[0];
|
|
607
|
+
} else {
|
|
608
|
+
logger.error("Please specify a package to diff.");
|
|
609
|
+
logger.info(`Usage: ${pc3.cyan("vexblocks diff <package>")}`);
|
|
610
|
+
logger.info(`Installed packages: ${installedPackages.join(", ")}`);
|
|
914
611
|
return;
|
|
915
612
|
}
|
|
916
|
-
|
|
917
|
-
await upgradePackage(cwd, update.pkg, update.to, manifest, options);
|
|
918
|
-
}
|
|
919
|
-
manifest.version = latestVersion;
|
|
920
|
-
await writeManifest(cwd, manifest);
|
|
921
|
-
logger.break();
|
|
922
|
-
logger.success(`Upgraded to version ${pc4.cyan(latestVersion)}`);
|
|
923
|
-
logger.info(
|
|
924
|
-
"Run your package manager's install command to update dependencies."
|
|
925
|
-
);
|
|
926
|
-
}
|
|
927
|
-
async function upgradePackage(cwd, pkg, version, manifest, options) {
|
|
928
|
-
const spinner = ora3(`Upgrading ${PACKAGE_NAMES[pkg]}...`).start();
|
|
613
|
+
const spinner = ora2(`Comparing ${PACKAGE_NAMES[packageToDiff]}...`).start();
|
|
929
614
|
try {
|
|
930
|
-
const config = manifest.packages[
|
|
615
|
+
const config = manifest.packages[packageToDiff];
|
|
931
616
|
if (!config) {
|
|
932
|
-
spinner.
|
|
933
|
-
return;
|
|
934
|
-
}
|
|
935
|
-
const targetPath = path6.join(cwd, config.path);
|
|
936
|
-
if (!await fs6.pathExists(targetPath)) {
|
|
937
|
-
spinner.warn(
|
|
938
|
-
`${PACKAGE_NAMES[pkg]} directory not found at ${config.path}`
|
|
939
|
-
);
|
|
617
|
+
spinner.fail("Package configuration not found");
|
|
940
618
|
return;
|
|
941
619
|
}
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
const backupPath = await createBackup(targetPath);
|
|
945
|
-
spinner.text = `Created backup at ${path6.basename(backupPath)}`;
|
|
946
|
-
await fs6.remove(targetPath);
|
|
947
|
-
const sourcePath = getSourcePath(pkg);
|
|
948
|
-
await downloadAndExtractPackage(sourcePath, targetPath, (file) => {
|
|
949
|
-
spinner.text = `Upgrading ${PACKAGE_NAMES[pkg]}... ${pc4.dim(file)}`;
|
|
950
|
-
});
|
|
951
|
-
} else {
|
|
952
|
-
spinner.text = `Upgrading CMS files in ${PACKAGE_NAMES[pkg]}...`;
|
|
953
|
-
const cmsFiles = ["convex/cms", "convex/schema.cms.ts"];
|
|
954
|
-
for (const file of cmsFiles) {
|
|
955
|
-
const targetFilePath = path6.join(targetPath, file);
|
|
956
|
-
const sourceFilePath = `packages/backend/${file}`;
|
|
957
|
-
if (await fs6.pathExists(targetFilePath)) {
|
|
958
|
-
await createBackup(targetFilePath);
|
|
959
|
-
}
|
|
960
|
-
try {
|
|
961
|
-
await fs6.remove(targetFilePath);
|
|
962
|
-
await downloadAndExtractPackage(sourceFilePath, targetFilePath);
|
|
963
|
-
} catch {
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
const newConfig = {
|
|
968
|
-
...config,
|
|
969
|
-
version,
|
|
970
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
971
|
-
};
|
|
972
|
-
manifest.packages[pkg] = newConfig;
|
|
973
|
-
spinner.succeed(`Upgraded ${PACKAGE_NAMES[pkg]} to ${version}`);
|
|
974
|
-
} catch (error) {
|
|
975
|
-
spinner.fail(`Failed to upgrade ${PACKAGE_NAMES[pkg]}`);
|
|
976
|
-
throw error;
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
function getSourcePath(pkg) {
|
|
980
|
-
switch (pkg) {
|
|
981
|
-
case "cms":
|
|
982
|
-
return "apps/cms";
|
|
983
|
-
case "backend":
|
|
984
|
-
return "packages/backend";
|
|
985
|
-
case "shared":
|
|
986
|
-
return "packages/cms-shared";
|
|
987
|
-
case "types":
|
|
988
|
-
return "packages/type-generator";
|
|
989
|
-
default:
|
|
990
|
-
throw new Error(`Unknown package: ${pkg}`);
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
// src/commands/diff.ts
|
|
995
|
-
import path7 from "path";
|
|
996
|
-
import fs7 from "fs-extra";
|
|
997
|
-
import pc5 from "picocolors";
|
|
998
|
-
import ora4 from "ora";
|
|
999
|
-
import { createTwoFilesPatch } from "diff";
|
|
1000
|
-
async function diffCommand(packageArg, options) {
|
|
1001
|
-
const cwd = options.cwd ? path7.resolve(options.cwd) : process.cwd();
|
|
1002
|
-
logger.title("\u{1F50D} VexBlocks Diff");
|
|
1003
|
-
const manifest = await readManifest(cwd);
|
|
1004
|
-
if (!manifest) {
|
|
1005
|
-
logger.error("No vexblocks.json found. Run `vexblocks init` first.");
|
|
1006
|
-
process.exit(1);
|
|
1007
|
-
}
|
|
1008
|
-
const installedPackages = Object.keys(manifest.packages);
|
|
1009
|
-
if (installedPackages.length === 0) {
|
|
1010
|
-
logger.info("No packages installed.");
|
|
1011
|
-
return;
|
|
1012
|
-
}
|
|
1013
|
-
let packageToDiff;
|
|
1014
|
-
if (packageArg) {
|
|
1015
|
-
if (!installedPackages.includes(packageArg)) {
|
|
1016
|
-
logger.error(`Package "${packageArg}" is not installed.`);
|
|
1017
|
-
logger.info(`Installed packages: ${installedPackages.join(", ")}`);
|
|
1018
|
-
return;
|
|
1019
|
-
}
|
|
1020
|
-
packageToDiff = packageArg;
|
|
1021
|
-
} else if (installedPackages.length === 1) {
|
|
1022
|
-
packageToDiff = installedPackages[0];
|
|
1023
|
-
} else {
|
|
1024
|
-
logger.error("Please specify a package to diff.");
|
|
1025
|
-
logger.info(`Usage: ${pc5.cyan("vexblocks diff <package>")}`);
|
|
1026
|
-
logger.info(`Installed packages: ${installedPackages.join(", ")}`);
|
|
1027
|
-
return;
|
|
1028
|
-
}
|
|
1029
|
-
const spinner = ora4(`Comparing ${PACKAGE_NAMES[packageToDiff]}...`).start();
|
|
1030
|
-
try {
|
|
1031
|
-
const config = manifest.packages[packageToDiff];
|
|
1032
|
-
if (!config) {
|
|
1033
|
-
spinner.fail("Package configuration not found");
|
|
1034
|
-
return;
|
|
1035
|
-
}
|
|
1036
|
-
const localPath = path7.join(cwd, config.path);
|
|
1037
|
-
const remotePath = getSourcePath2(packageToDiff);
|
|
620
|
+
const localPath = path5.join(cwd, config.path);
|
|
621
|
+
const remotePath = getSourcePath(packageToDiff);
|
|
1038
622
|
const remoteFiles = await getPackageFiles(remotePath);
|
|
1039
623
|
let totalDiffs = 0;
|
|
1040
624
|
let newFiles = 0;
|
|
@@ -1042,12 +626,12 @@ async function diffCommand(packageArg, options) {
|
|
|
1042
626
|
let deletedFiles = 0;
|
|
1043
627
|
spinner.stop();
|
|
1044
628
|
for (const file of remoteFiles) {
|
|
1045
|
-
const localFilePath =
|
|
629
|
+
const localFilePath = path5.join(localPath, file);
|
|
1046
630
|
const remoteFilePath = `${remotePath}/${file}`;
|
|
1047
631
|
let localContent = "";
|
|
1048
632
|
let remoteContent = "";
|
|
1049
|
-
if (await
|
|
1050
|
-
localContent = await
|
|
633
|
+
if (await fs5.pathExists(localFilePath)) {
|
|
634
|
+
localContent = await fs5.readFile(localFilePath, "utf-8");
|
|
1051
635
|
}
|
|
1052
636
|
try {
|
|
1053
637
|
remoteContent = await fetchFile(remoteFilePath);
|
|
@@ -1057,11 +641,11 @@ async function diffCommand(packageArg, options) {
|
|
|
1057
641
|
if (!localContent && remoteContent) {
|
|
1058
642
|
newFiles++;
|
|
1059
643
|
totalDiffs++;
|
|
1060
|
-
logger.log(`${
|
|
644
|
+
logger.log(`${pc3.green("+")} ${file} ${pc3.dim("(new file)")}`);
|
|
1061
645
|
} else if (localContent !== remoteContent) {
|
|
1062
646
|
modifiedFiles++;
|
|
1063
647
|
totalDiffs++;
|
|
1064
|
-
logger.log(`${
|
|
648
|
+
logger.log(`${pc3.yellow("~")} ${file} ${pc3.dim("(modified)")}`);
|
|
1065
649
|
const patch = createTwoFilesPatch(
|
|
1066
650
|
`local/${file}`,
|
|
1067
651
|
`remote/${file}`,
|
|
@@ -1075,14 +659,14 @@ async function diffCommand(packageArg, options) {
|
|
|
1075
659
|
let lineCount = 0;
|
|
1076
660
|
for (const line of lines) {
|
|
1077
661
|
if (lineCount >= maxLines) {
|
|
1078
|
-
logger.log(
|
|
662
|
+
logger.log(pc3.dim(` ... (${lines.length - maxLines} more lines)`));
|
|
1079
663
|
break;
|
|
1080
664
|
}
|
|
1081
665
|
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
1082
|
-
logger.log(
|
|
666
|
+
logger.log(pc3.green(` ${line}`));
|
|
1083
667
|
lineCount++;
|
|
1084
668
|
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
1085
|
-
logger.log(
|
|
669
|
+
logger.log(pc3.red(` ${line}`));
|
|
1086
670
|
lineCount++;
|
|
1087
671
|
}
|
|
1088
672
|
}
|
|
@@ -1097,7 +681,7 @@ async function diffCommand(packageArg, options) {
|
|
|
1097
681
|
}
|
|
1098
682
|
deletedFiles++;
|
|
1099
683
|
totalDiffs++;
|
|
1100
|
-
logger.log(`${
|
|
684
|
+
logger.log(`${pc3.red("-")} ${file} ${pc3.dim("(deleted in remote)")}`);
|
|
1101
685
|
}
|
|
1102
686
|
}
|
|
1103
687
|
logger.break();
|
|
@@ -1106,15 +690,15 @@ async function diffCommand(packageArg, options) {
|
|
|
1106
690
|
"No differences found. Local files match the latest version."
|
|
1107
691
|
);
|
|
1108
692
|
} else {
|
|
1109
|
-
logger.log(
|
|
1110
|
-
if (newFiles > 0) logger.log(` ${
|
|
693
|
+
logger.log(pc3.bold("Summary:"));
|
|
694
|
+
if (newFiles > 0) logger.log(` ${pc3.green(`+${newFiles}`)} new files`);
|
|
1111
695
|
if (modifiedFiles > 0)
|
|
1112
|
-
logger.log(` ${
|
|
696
|
+
logger.log(` ${pc3.yellow(`~${modifiedFiles}`)} modified files`);
|
|
1113
697
|
if (deletedFiles > 0)
|
|
1114
|
-
logger.log(` ${
|
|
698
|
+
logger.log(` ${pc3.red(`-${deletedFiles}`)} files removed in remote`);
|
|
1115
699
|
logger.break();
|
|
1116
700
|
logger.info(
|
|
1117
|
-
`Run ${
|
|
701
|
+
`Run ${pc3.cyan("npx @vexblocks/cli upgrade")} to update to the latest version.`
|
|
1118
702
|
);
|
|
1119
703
|
}
|
|
1120
704
|
} catch (error) {
|
|
@@ -1122,7 +706,7 @@ async function diffCommand(packageArg, options) {
|
|
|
1122
706
|
throw error;
|
|
1123
707
|
}
|
|
1124
708
|
}
|
|
1125
|
-
function
|
|
709
|
+
function getSourcePath(pkg) {
|
|
1126
710
|
switch (pkg) {
|
|
1127
711
|
case "cms":
|
|
1128
712
|
return "apps/cms";
|
|
@@ -1138,10 +722,10 @@ function getSourcePath2(pkg) {
|
|
|
1138
722
|
}
|
|
1139
723
|
async function getLocalFiles(dir, base = "") {
|
|
1140
724
|
const files = [];
|
|
1141
|
-
if (!await
|
|
725
|
+
if (!await fs5.pathExists(dir)) {
|
|
1142
726
|
return files;
|
|
1143
727
|
}
|
|
1144
|
-
const entries = await
|
|
728
|
+
const entries = await fs5.readdir(dir, { withFileTypes: true });
|
|
1145
729
|
for (const entry of entries) {
|
|
1146
730
|
const relativePath = base ? `${base}/${entry.name}` : entry.name;
|
|
1147
731
|
if (entry.isDirectory()) {
|
|
@@ -1149,7 +733,7 @@ async function getLocalFiles(dir, base = "") {
|
|
|
1149
733
|
continue;
|
|
1150
734
|
}
|
|
1151
735
|
const subFiles = await getLocalFiles(
|
|
1152
|
-
|
|
736
|
+
path5.join(dir, entry.name),
|
|
1153
737
|
relativePath
|
|
1154
738
|
);
|
|
1155
739
|
files.push(...subFiles);
|
|
@@ -1160,10 +744,422 @@ async function getLocalFiles(dir, base = "") {
|
|
|
1160
744
|
return files;
|
|
1161
745
|
}
|
|
1162
746
|
|
|
747
|
+
// src/commands/init.ts
|
|
748
|
+
import path6 from "path";
|
|
749
|
+
import { confirm as confirm2, input, select } from "@inquirer/prompts";
|
|
750
|
+
import fs6 from "fs-extra";
|
|
751
|
+
import ora3 from "ora";
|
|
752
|
+
import pc4 from "picocolors";
|
|
753
|
+
async function initCommand(options) {
|
|
754
|
+
const cwd = options.cwd ? path6.resolve(options.cwd) : process.cwd();
|
|
755
|
+
logger.title("\u{1F680} VexBlocks CMS Setup");
|
|
756
|
+
const manifestPath = path6.join(cwd, MANIFEST_FILE);
|
|
757
|
+
if (await fs6.pathExists(manifestPath)) {
|
|
758
|
+
logger.warn("VexBlocks is already initialized in this directory.");
|
|
759
|
+
const continueAnyway = options.yes || await confirm2({
|
|
760
|
+
message: "Do you want to reinitialize?",
|
|
761
|
+
default: false
|
|
762
|
+
});
|
|
763
|
+
if (!continueAnyway) {
|
|
764
|
+
logger.info("Run `npx @vexblocks/cli add <package>` to add packages.");
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
const isTurbo = await isTurborepoProject(cwd);
|
|
769
|
+
let projectType;
|
|
770
|
+
if (isTurbo) {
|
|
771
|
+
logger.success("Detected existing Turborepo project");
|
|
772
|
+
projectType = "existing";
|
|
773
|
+
} else {
|
|
774
|
+
projectType = await select({
|
|
775
|
+
message: "What would you like to do?",
|
|
776
|
+
choices: [
|
|
777
|
+
{
|
|
778
|
+
name: "Create a new Turborepo project with VexBlocks",
|
|
779
|
+
value: "new"
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
name: "Add VexBlocks to this directory (I'll set up Turborepo manually)",
|
|
783
|
+
value: "existing"
|
|
784
|
+
}
|
|
785
|
+
]
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
if (projectType === "new") {
|
|
789
|
+
await createNewProject(cwd, options);
|
|
790
|
+
} else {
|
|
791
|
+
await initializeExisting(cwd, options);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
async function createNewProject(cwd, options) {
|
|
795
|
+
const projectName = await input({
|
|
796
|
+
message: "Project name:",
|
|
797
|
+
default: path6.basename(cwd),
|
|
798
|
+
validate: (value) => {
|
|
799
|
+
if (!value) return "Project name is required";
|
|
800
|
+
if (!/^[a-z0-9-_]+$/.test(value)) {
|
|
801
|
+
return "Project name can only contain lowercase letters, numbers, hyphens, and underscores";
|
|
802
|
+
}
|
|
803
|
+
return true;
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
const projectDir = path6.join(cwd, projectName);
|
|
807
|
+
if (await fs6.pathExists(projectDir)) {
|
|
808
|
+
const overwrite = await confirm2({
|
|
809
|
+
message: `Directory ${projectName} already exists. Overwrite?`,
|
|
810
|
+
default: false
|
|
811
|
+
});
|
|
812
|
+
if (!overwrite) {
|
|
813
|
+
logger.info("Aborted.");
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
await fs6.remove(projectDir);
|
|
817
|
+
}
|
|
818
|
+
const spinner = ora3("Creating project structure...").start();
|
|
819
|
+
try {
|
|
820
|
+
await fs6.ensureDir(projectDir);
|
|
821
|
+
await fs6.ensureDir(path6.join(projectDir, "apps"));
|
|
822
|
+
await fs6.ensureDir(path6.join(projectDir, "packages"));
|
|
823
|
+
const packageJson = {
|
|
824
|
+
name: projectName,
|
|
825
|
+
version: "0.1.0",
|
|
826
|
+
private: true,
|
|
827
|
+
packageManager: "pnpm@9.15.0",
|
|
828
|
+
workspaces: ["apps/*", "packages/*"],
|
|
829
|
+
scripts: {
|
|
830
|
+
dev: "turbo run dev",
|
|
831
|
+
build: "turbo run build",
|
|
832
|
+
lint: "turbo run lint",
|
|
833
|
+
"generate-types": "pnpm --filter @repo/type-generator generate"
|
|
834
|
+
},
|
|
835
|
+
devDependencies: {
|
|
836
|
+
turbo: "^2.6.1"
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
await fs6.writeJson(path6.join(projectDir, "package.json"), packageJson, {
|
|
840
|
+
spaces: 2
|
|
841
|
+
});
|
|
842
|
+
const turboJson = {
|
|
843
|
+
$schema: "https://turbo.build/schema.json",
|
|
844
|
+
globalDependencies: ["**/.env.*local"],
|
|
845
|
+
globalEnv: [
|
|
846
|
+
"CONVEX_DEPLOYMENT",
|
|
847
|
+
"NEXT_PUBLIC_CONVEX_URL",
|
|
848
|
+
"NEXT_PUBLIC_CONVEX_SITE_URL",
|
|
849
|
+
"SITE_URL",
|
|
850
|
+
"CLOUDFLARE_ACCOUNT_ID",
|
|
851
|
+
"CLOUDFLARE_SECRET_TOKEN"
|
|
852
|
+
],
|
|
853
|
+
ui: "tui",
|
|
854
|
+
tasks: {
|
|
855
|
+
dev: {
|
|
856
|
+
cache: false,
|
|
857
|
+
persistent: true
|
|
858
|
+
},
|
|
859
|
+
build: {
|
|
860
|
+
dependsOn: ["^build"],
|
|
861
|
+
inputs: ["$TURBO_DEFAULT$", ".env*"],
|
|
862
|
+
outputs: [".next/**", "dist/**"]
|
|
863
|
+
},
|
|
864
|
+
lint: {
|
|
865
|
+
outputs: []
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
await fs6.writeJson(path6.join(projectDir, "turbo.json"), turboJson, {
|
|
870
|
+
spaces: 2
|
|
871
|
+
});
|
|
872
|
+
const pnpmWorkspace = `packages:
|
|
873
|
+
- "apps/*"
|
|
874
|
+
- "packages/*"
|
|
875
|
+
`;
|
|
876
|
+
await fs6.writeFile(
|
|
877
|
+
path6.join(projectDir, "pnpm-workspace.yaml"),
|
|
878
|
+
pnpmWorkspace
|
|
879
|
+
);
|
|
880
|
+
const gitignore = `# Dependencies
|
|
881
|
+
node_modules
|
|
882
|
+
.pnpm-store
|
|
883
|
+
|
|
884
|
+
# Build outputs
|
|
885
|
+
dist
|
|
886
|
+
.next
|
|
887
|
+
.turbo
|
|
888
|
+
|
|
889
|
+
# Environment files
|
|
890
|
+
.env
|
|
891
|
+
.env.local
|
|
892
|
+
.env.*.local
|
|
893
|
+
|
|
894
|
+
# IDE
|
|
895
|
+
.idea
|
|
896
|
+
.vscode
|
|
897
|
+
*.swp
|
|
898
|
+
*.swo
|
|
899
|
+
|
|
900
|
+
# OS
|
|
901
|
+
.DS_Store
|
|
902
|
+
Thumbs.db
|
|
903
|
+
|
|
904
|
+
# Logs
|
|
905
|
+
*.log
|
|
906
|
+
npm-debug.log*
|
|
907
|
+
pnpm-debug.log*
|
|
908
|
+
|
|
909
|
+
# Convex
|
|
910
|
+
.convex
|
|
911
|
+
`;
|
|
912
|
+
await fs6.writeFile(path6.join(projectDir, ".gitignore"), gitignore);
|
|
913
|
+
const envExample = `# Convex
|
|
914
|
+
CONVEX_DEPLOYMENT=
|
|
915
|
+
NEXT_PUBLIC_CONVEX_URL=
|
|
916
|
+
|
|
917
|
+
# Better Auth
|
|
918
|
+
SITE_URL=http://localhost:3001
|
|
919
|
+
|
|
920
|
+
# Cloudflare Images (optional, for media library)
|
|
921
|
+
CLOUDFLARE_ACCOUNT_ID=
|
|
922
|
+
CLOUDFLARE_SECRET_TOKEN=
|
|
923
|
+
|
|
924
|
+
# Revalidation (optional, for ISR)
|
|
925
|
+
REVALIDATE_SECRET=
|
|
926
|
+
FRONTEND_URL=http://localhost:3000
|
|
927
|
+
`;
|
|
928
|
+
await fs6.writeFile(path6.join(projectDir, ".env.example"), envExample);
|
|
929
|
+
const version = await getLatestVersion();
|
|
930
|
+
const manifest = createManifest(version);
|
|
931
|
+
await writeManifest(projectDir, manifest);
|
|
932
|
+
spinner.succeed("Project structure created");
|
|
933
|
+
logger.break();
|
|
934
|
+
logger.box("\u2705 Project created successfully!", [
|
|
935
|
+
`Directory: ${pc4.cyan(projectDir)}`,
|
|
936
|
+
"",
|
|
937
|
+
pc4.bold("Next steps:"),
|
|
938
|
+
`1. ${pc4.cyan(`cd ${projectName}`)}`,
|
|
939
|
+
`2. ${pc4.cyan("pnpm install")}`,
|
|
940
|
+
`3. ${pc4.cyan("npx @vexblocks/cli add all")}`,
|
|
941
|
+
"4. Set up your Convex project",
|
|
942
|
+
`5. ${pc4.cyan("pnpm dev")}`
|
|
943
|
+
]);
|
|
944
|
+
const addPackages = options.yes || await confirm2({
|
|
945
|
+
message: "Would you like to add VexBlocks packages now?",
|
|
946
|
+
default: true
|
|
947
|
+
});
|
|
948
|
+
if (addPackages) {
|
|
949
|
+
logger.break();
|
|
950
|
+
logger.info(`Run: ${pc4.cyan("npx @vexblocks/cli add all")}`);
|
|
951
|
+
logger.info("After navigating to your project directory.");
|
|
952
|
+
}
|
|
953
|
+
} catch (error) {
|
|
954
|
+
spinner.fail("Failed to create project");
|
|
955
|
+
throw error;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
async function initializeExisting(cwd, _options) {
|
|
959
|
+
const spinner = ora3("Initializing VexBlocks...").start();
|
|
960
|
+
try {
|
|
961
|
+
const hasTurbo = await isTurborepoProject(cwd);
|
|
962
|
+
if (!hasTurbo) {
|
|
963
|
+
spinner.warn("No turbo.json found");
|
|
964
|
+
logger.warn(
|
|
965
|
+
"VexBlocks requires Turborepo. Please set up Turborepo first."
|
|
966
|
+
);
|
|
967
|
+
logger.info(`Run: ${pc4.cyan("npx create-turbo@latest")}`);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
const version = await getLatestVersion();
|
|
971
|
+
const manifest = createManifest(version);
|
|
972
|
+
await writeManifest(cwd, manifest);
|
|
973
|
+
spinner.succeed("VexBlocks initialized");
|
|
974
|
+
const packageManager = await getPackageManager(cwd);
|
|
975
|
+
logger.break();
|
|
976
|
+
logger.box("\u2705 VexBlocks initialized!", [
|
|
977
|
+
`Manifest: ${pc4.cyan(MANIFEST_FILE)}`,
|
|
978
|
+
`Version: ${pc4.cyan(version)}`,
|
|
979
|
+
"",
|
|
980
|
+
pc4.bold("Next steps:"),
|
|
981
|
+
`1. ${pc4.cyan("npx @vexblocks/cli add all")} - Add all CMS packages`,
|
|
982
|
+
"2. Configure your environment variables",
|
|
983
|
+
`3. ${pc4.cyan(`${packageManager} install`)}`,
|
|
984
|
+
`4. ${pc4.cyan(`${packageManager === "npm" ? "npm run" : packageManager} dev`)}`
|
|
985
|
+
]);
|
|
986
|
+
} catch (error) {
|
|
987
|
+
spinner.fail("Failed to initialize");
|
|
988
|
+
throw error;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// src/commands/upgrade.ts
|
|
993
|
+
import path7 from "path";
|
|
994
|
+
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
995
|
+
import fs7 from "fs-extra";
|
|
996
|
+
import ora4 from "ora";
|
|
997
|
+
import pc5 from "picocolors";
|
|
998
|
+
async function upgradeCommand(packages, options) {
|
|
999
|
+
const cwd = options.cwd ? path7.resolve(options.cwd) : process.cwd();
|
|
1000
|
+
logger.title("\u2B06\uFE0F Upgrade VexBlocks Packages");
|
|
1001
|
+
const manifest = await readManifest(cwd);
|
|
1002
|
+
if (!manifest) {
|
|
1003
|
+
logger.error("No vexblocks.json found. Run `npx @vexblocks/cli init` first.");
|
|
1004
|
+
process.exit(1);
|
|
1005
|
+
}
|
|
1006
|
+
const spinner = ora4("Checking for updates...").start();
|
|
1007
|
+
const latestVersion = await getLatestVersion();
|
|
1008
|
+
spinner.stop();
|
|
1009
|
+
const installedPackages = Object.keys(manifest.packages);
|
|
1010
|
+
if (installedPackages.length === 0) {
|
|
1011
|
+
logger.info("No packages installed. Run `npx @vexblocks/cli add <package>` first.");
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
let packagesToUpgrade;
|
|
1015
|
+
if (packages.length === 0) {
|
|
1016
|
+
packagesToUpgrade = installedPackages;
|
|
1017
|
+
} else {
|
|
1018
|
+
packagesToUpgrade = packages.filter(
|
|
1019
|
+
(p) => installedPackages.includes(p)
|
|
1020
|
+
);
|
|
1021
|
+
if (packagesToUpgrade.length === 0) {
|
|
1022
|
+
logger.error("None of the specified packages are installed.");
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
const updates = [];
|
|
1027
|
+
for (const pkg of packagesToUpgrade) {
|
|
1028
|
+
const config = manifest.packages[pkg];
|
|
1029
|
+
if (!config) continue;
|
|
1030
|
+
const comparison = compareVersions(config.version, latestVersion);
|
|
1031
|
+
if (comparison < 0) {
|
|
1032
|
+
updates.push({
|
|
1033
|
+
pkg,
|
|
1034
|
+
from: config.version,
|
|
1035
|
+
to: latestVersion
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
if (updates.length === 0) {
|
|
1040
|
+
logger.success("All packages are up to date!");
|
|
1041
|
+
logger.info(`Current version: ${pc5.cyan(latestVersion)}`);
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
logger.log(pc5.bold("\nAvailable updates:"));
|
|
1045
|
+
logger.break();
|
|
1046
|
+
for (const update of updates) {
|
|
1047
|
+
const isManaged = MANAGED_PACKAGES.includes(update.pkg);
|
|
1048
|
+
const managedLabel = isManaged ? pc5.yellow(" (managed)") : "";
|
|
1049
|
+
logger.log(
|
|
1050
|
+
` ${PACKAGE_NAMES[update.pkg]} ${pc5.dim(`${update.from} \u2192 `)}${pc5.green(update.to)}${managedLabel}`
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
const changelog = await getChangelog(updates[0].from, latestVersion);
|
|
1054
|
+
if (Object.keys(changelog).length > 0) {
|
|
1055
|
+
logger.break();
|
|
1056
|
+
logger.log(pc5.bold("Changelog:"));
|
|
1057
|
+
for (const [version, changes] of Object.entries(changelog)) {
|
|
1058
|
+
logger.log(`
|
|
1059
|
+
${pc5.cyan(version)}`);
|
|
1060
|
+
for (const change of changes) {
|
|
1061
|
+
logger.log(` ${pc5.dim("\u2022")} ${change}`);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
if (options.check) {
|
|
1066
|
+
logger.break();
|
|
1067
|
+
logger.info(
|
|
1068
|
+
`Run ${pc5.cyan("npx @vexblocks/cli upgrade")} to apply these updates.`
|
|
1069
|
+
);
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
logger.break();
|
|
1073
|
+
const proceed = options.yes || await confirm3({
|
|
1074
|
+
message: `Upgrade ${updates.length} package(s)?`,
|
|
1075
|
+
default: true
|
|
1076
|
+
});
|
|
1077
|
+
if (!proceed) {
|
|
1078
|
+
logger.info("Aborted.");
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
for (const update of updates) {
|
|
1082
|
+
await upgradePackage(cwd, update.pkg, update.to, manifest, options);
|
|
1083
|
+
}
|
|
1084
|
+
manifest.version = latestVersion;
|
|
1085
|
+
await writeManifest(cwd, manifest);
|
|
1086
|
+
logger.break();
|
|
1087
|
+
logger.success(`Upgraded to version ${pc5.cyan(latestVersion)}`);
|
|
1088
|
+
logger.info(
|
|
1089
|
+
"Run your package manager's install command to update dependencies."
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
async function upgradePackage(cwd, pkg, version, manifest, options) {
|
|
1093
|
+
const spinner = ora4(`Upgrading ${PACKAGE_NAMES[pkg]}...`).start();
|
|
1094
|
+
try {
|
|
1095
|
+
const config = manifest.packages[pkg];
|
|
1096
|
+
if (!config) {
|
|
1097
|
+
spinner.info(`${PACKAGE_NAMES[pkg]} not installed`);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
const targetPath = path7.join(cwd, config.path);
|
|
1101
|
+
if (!await fs7.pathExists(targetPath)) {
|
|
1102
|
+
spinner.warn(
|
|
1103
|
+
`${PACKAGE_NAMES[pkg]} directory not found at ${config.path}`
|
|
1104
|
+
);
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
const isManaged = MANAGED_PACKAGES.includes(pkg);
|
|
1108
|
+
if (isManaged || options.force) {
|
|
1109
|
+
const backupPath = await createBackup(targetPath);
|
|
1110
|
+
spinner.text = `Created backup at ${path7.basename(backupPath)}`;
|
|
1111
|
+
await fs7.remove(targetPath);
|
|
1112
|
+
const sourcePath = getSourcePath2(pkg);
|
|
1113
|
+
await downloadAndExtractPackage(sourcePath, targetPath, (file) => {
|
|
1114
|
+
spinner.text = `Upgrading ${PACKAGE_NAMES[pkg]}... ${pc5.dim(file)}`;
|
|
1115
|
+
});
|
|
1116
|
+
} else {
|
|
1117
|
+
spinner.text = `Upgrading CMS files in ${PACKAGE_NAMES[pkg]}...`;
|
|
1118
|
+
const cmsFiles = ["convex/cms", "convex/schema.cms.ts"];
|
|
1119
|
+
for (const file of cmsFiles) {
|
|
1120
|
+
const targetFilePath = path7.join(targetPath, file);
|
|
1121
|
+
const sourceFilePath = `packages/backend/${file}`;
|
|
1122
|
+
if (await fs7.pathExists(targetFilePath)) {
|
|
1123
|
+
await createBackup(targetFilePath);
|
|
1124
|
+
}
|
|
1125
|
+
try {
|
|
1126
|
+
await fs7.remove(targetFilePath);
|
|
1127
|
+
await downloadAndExtractPackage(sourceFilePath, targetFilePath);
|
|
1128
|
+
} catch {
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
const newConfig = {
|
|
1133
|
+
...config,
|
|
1134
|
+
version,
|
|
1135
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1136
|
+
};
|
|
1137
|
+
manifest.packages[pkg] = newConfig;
|
|
1138
|
+
spinner.succeed(`Upgraded ${PACKAGE_NAMES[pkg]} to ${version}`);
|
|
1139
|
+
} catch (error) {
|
|
1140
|
+
spinner.fail(`Failed to upgrade ${PACKAGE_NAMES[pkg]}`);
|
|
1141
|
+
throw error;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
function getSourcePath2(pkg) {
|
|
1145
|
+
switch (pkg) {
|
|
1146
|
+
case "cms":
|
|
1147
|
+
return "apps/cms";
|
|
1148
|
+
case "backend":
|
|
1149
|
+
return "packages/backend";
|
|
1150
|
+
case "shared":
|
|
1151
|
+
return "packages/cms-shared";
|
|
1152
|
+
case "types":
|
|
1153
|
+
return "packages/type-generator";
|
|
1154
|
+
default:
|
|
1155
|
+
throw new Error(`Unknown package: ${pkg}`);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1163
1159
|
// src/utils/package-info.ts
|
|
1164
|
-
import fs8 from "fs-extra";
|
|
1165
1160
|
import path8 from "path";
|
|
1166
1161
|
import { fileURLToPath } from "url";
|
|
1162
|
+
import fs8 from "fs-extra";
|
|
1167
1163
|
var __filename = fileURLToPath(import.meta.url);
|
|
1168
1164
|
var __dirname = path8.dirname(__filename);
|
|
1169
1165
|
async function getPackageInfo() {
|