create-blitzpack 0.1.5 → 0.1.7

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.
Files changed (2) hide show
  1. package/dist/index.js +279 -54
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7,18 +7,122 @@ import { dirname, join } from "path";
7
7
  import { fileURLToPath } from "url";
8
8
 
9
9
  // src/commands/create.ts
10
- import chalk2 from "chalk";
10
+ import chalk4 from "chalk";
11
11
  import { spawn } from "child_process";
12
12
  import fs3 from "fs-extra";
13
13
  import ora from "ora";
14
14
  import path4 from "path";
15
15
  import prompts2 from "prompts";
16
16
 
17
- // src/git.ts
17
+ // src/checks.ts
18
+ import chalk from "chalk";
18
19
  import { execSync } from "child_process";
20
+ function checkNodeVersion() {
21
+ try {
22
+ const nodeVersion = process.version;
23
+ const majorVersion = parseInt(nodeVersion.slice(1).split(".")[0], 10);
24
+ if (majorVersion >= 20) {
25
+ return {
26
+ passed: true,
27
+ name: "Node.js"
28
+ };
29
+ }
30
+ return {
31
+ passed: false,
32
+ name: "Node.js",
33
+ message: `Node.js >= 20.0.0 required (found ${nodeVersion})`
34
+ };
35
+ } catch {
36
+ return {
37
+ passed: false,
38
+ name: "Node.js",
39
+ message: "Failed to check Node.js version"
40
+ };
41
+ }
42
+ }
43
+ function checkPnpmInstalled() {
44
+ try {
45
+ execSync("pnpm --version", { stdio: "ignore" });
46
+ return {
47
+ passed: true,
48
+ name: "pnpm"
49
+ };
50
+ } catch {
51
+ return {
52
+ passed: false,
53
+ name: "pnpm",
54
+ message: "pnpm not found. Install: npm install -g pnpm"
55
+ };
56
+ }
57
+ }
58
+ async function runPreflightChecks() {
59
+ console.log();
60
+ console.log(chalk.bold(" Checking requirements..."));
61
+ console.log();
62
+ const checks = [checkNodeVersion(), checkPnpmInstalled()];
63
+ let hasErrors = false;
64
+ for (const check of checks) {
65
+ if (check.passed) {
66
+ console.log(chalk.green(" \u2714"), check.name);
67
+ } else {
68
+ hasErrors = true;
69
+ console.log(chalk.red(" \u2716"), check.name);
70
+ if (check.message) {
71
+ console.log(chalk.dim(` ${check.message}`));
72
+ }
73
+ }
74
+ }
75
+ console.log();
76
+ if (hasErrors) {
77
+ console.log(
78
+ chalk.red(" \u2716"),
79
+ "Requirements not met. Please fix the errors above."
80
+ );
81
+ console.log();
82
+ return false;
83
+ }
84
+ return true;
85
+ }
86
+
87
+ // src/docker.ts
88
+ import { execSync as execSync2 } from "child_process";
89
+ function isDockerRunning() {
90
+ try {
91
+ execSync2("docker info", { stdio: "ignore", timeout: 3e3 });
92
+ return true;
93
+ } catch {
94
+ return false;
95
+ }
96
+ }
97
+ function runDockerCompose(targetDir) {
98
+ try {
99
+ execSync2("docker compose up -d", {
100
+ cwd: targetDir,
101
+ stdio: "inherit"
102
+ });
103
+ return true;
104
+ } catch {
105
+ return false;
106
+ }
107
+ }
108
+ function runDatabaseMigrations(targetDir) {
109
+ try {
110
+ const isWindows = process.platform === "win32";
111
+ execSync2(isWindows ? "pnpm.cmd db:migrate" : "pnpm db:migrate", {
112
+ cwd: targetDir,
113
+ stdio: "inherit"
114
+ });
115
+ return true;
116
+ } catch {
117
+ return false;
118
+ }
119
+ }
120
+
121
+ // src/git.ts
122
+ import { execSync as execSync3 } from "child_process";
19
123
  function isGitInstalled() {
20
124
  try {
21
- execSync("git --version", { stdio: "ignore" });
125
+ execSync3("git --version", { stdio: "ignore" });
22
126
  return true;
23
127
  } catch {
24
128
  return false;
@@ -26,9 +130,9 @@ function isGitInstalled() {
26
130
  }
27
131
  function initGit(targetDir) {
28
132
  try {
29
- execSync("git init", { cwd: targetDir, stdio: "ignore" });
30
- execSync("git add -A", { cwd: targetDir, stdio: "ignore" });
31
- execSync('git commit -m "Initial commit from create-blitzpack"', {
133
+ execSync3("git init", { cwd: targetDir, stdio: "ignore" });
134
+ execSync3("git add -A", { cwd: targetDir, stdio: "ignore" });
135
+ execSync3('git commit -m "Initial commit from create-blitzpack"', {
32
136
  cwd: targetDir,
33
137
  stdio: "ignore"
34
138
  });
@@ -39,6 +143,7 @@ function initGit(targetDir) {
39
143
  }
40
144
 
41
145
  // src/prompts.ts
146
+ import chalk3 from "chalk";
42
147
  import prompts from "prompts";
43
148
 
44
149
  // src/constants.ts
@@ -52,7 +157,7 @@ var REPLACEABLE_FILES = [
52
157
  var DEFAULT_DESCRIPTION = "A full-stack TypeScript monorepo built with Blitzpack";
53
158
 
54
159
  // src/utils.ts
55
- import chalk from "chalk";
160
+ import chalk2 from "chalk";
56
161
  import path from "path";
57
162
  import validatePackageName from "validate-npm-package-name";
58
163
  function getCurrentDirName() {
@@ -74,51 +179,95 @@ function validateProjectName(name) {
74
179
  }
75
180
  function printHeader() {
76
181
  console.log();
77
- console.log(chalk.bold.cyan(" Create Blitzpack"));
78
- console.log(chalk.dim(" Full-stack TypeScript monorepo"));
182
+ console.log(chalk2.bold.cyan(" Create Blitzpack"));
183
+ console.log(chalk2.dim(" Full-stack TypeScript monorepo"));
79
184
  console.log();
80
185
  }
81
- function printSuccess(projectName, targetDir) {
82
- console.log();
83
- console.log(chalk.green("\u2714"), chalk.bold(`Created ${projectName}`));
186
+ function printSuccess(projectName, targetDir, ranAutomaticSetup = false) {
84
187
  console.log();
85
- console.log(chalk.bold(" Next steps:"));
188
+ console.log(chalk2.green("\u2714"), chalk2.bold(`Created ${projectName}`));
86
189
  console.log();
87
- let stepNumber = 1;
88
- if (targetDir !== ".") {
89
- console.log(chalk.cyan(` ${stepNumber}.`), `cd ${targetDir}`);
190
+ if (ranAutomaticSetup) {
191
+ console.log(
192
+ chalk2.green("\u2714"),
193
+ chalk2.dim("Database setup complete! Ready to start developing.")
194
+ );
195
+ console.log();
196
+ console.log(chalk2.bold(" Next steps:"));
197
+ console.log();
198
+ let stepNumber = 1;
199
+ if (targetDir !== ".") {
200
+ console.log(
201
+ chalk2.cyan(` ${stepNumber}.`),
202
+ chalk2.bold(`cd ${targetDir}`)
203
+ );
204
+ stepNumber++;
205
+ }
206
+ console.log(chalk2.cyan(` ${stepNumber}.`), chalk2.bold("pnpm dev"));
207
+ console.log(chalk2.dim(" Start development servers (web + api)"));
208
+ console.log();
209
+ console.log(chalk2.dim(" Optional commands:"));
210
+ console.log(
211
+ chalk2.dim(
212
+ " \u2022 pnpm db:seed Add test data (admin accounts, users)"
213
+ )
214
+ );
215
+ console.log(
216
+ chalk2.dim(" \u2022 pnpm db:studio Open Prisma Studio to view data")
217
+ );
218
+ } else {
219
+ console.log(
220
+ chalk2.dim(" Setup complete! Follow these steps to start developing:")
221
+ );
222
+ console.log();
223
+ let stepNumber = 1;
224
+ if (targetDir !== ".") {
225
+ console.log(
226
+ chalk2.cyan(` ${stepNumber}.`),
227
+ chalk2.bold(`cd ${targetDir}`)
228
+ );
229
+ stepNumber++;
230
+ }
231
+ console.log(
232
+ chalk2.cyan(` ${stepNumber}.`),
233
+ chalk2.bold("docker compose up -d")
234
+ );
235
+ console.log(chalk2.dim(" Start PostgreSQL database (requires Docker)"));
236
+ console.log();
237
+ stepNumber++;
238
+ console.log(chalk2.cyan(` ${stepNumber}.`), chalk2.bold("pnpm db:migrate"));
239
+ console.log(chalk2.dim(" Run database migrations and setup schema"));
240
+ console.log();
90
241
  stepNumber++;
242
+ console.log(chalk2.cyan(` ${stepNumber}.`), chalk2.bold("pnpm dev"));
243
+ console.log(chalk2.dim(" Start development servers (web + api)"));
244
+ console.log();
245
+ console.log(chalk2.dim(" Optional commands:"));
246
+ console.log(
247
+ chalk2.dim(
248
+ " \u2022 pnpm db:seed Add test data (admin accounts, users)"
249
+ )
250
+ );
251
+ console.log(
252
+ chalk2.dim(" \u2022 pnpm db:studio Open Prisma Studio to view data")
253
+ );
91
254
  }
255
+ console.log();
256
+ console.log(chalk2.bold(" Your app will be running at:"));
92
257
  console.log(
93
- chalk.cyan(` ${stepNumber}.`),
94
- "docker compose up -d",
95
- chalk.dim(" # Start PostgreSQL")
96
- );
97
- stepNumber++;
98
- console.log(
99
- chalk.cyan(` ${stepNumber}.`),
100
- "pnpm db:migrate",
101
- chalk.dim(" # Run database migrations")
258
+ chalk2.dim(" \u2022 Web: ") + chalk2.cyan("http://localhost:3000")
102
259
  );
103
- stepNumber++;
104
260
  console.log(
105
- chalk.cyan(` ${stepNumber}.`),
106
- "pnpm dev",
107
- chalk.dim(" # Start dev servers")
261
+ chalk2.dim(" \u2022 API: ") + chalk2.cyan("http://localhost:8080/api")
108
262
  );
109
- console.log();
110
- console.log(
111
- chalk.dim(" Optional: pnpm db:seed to add test data like admin accounts")
112
- );
113
- console.log();
114
263
  console.log(
115
- chalk.dim(" Web: http://localhost:3000 | API: http://localhost:8080")
264
+ chalk2.dim(" \u2022 API Docs: ") + chalk2.cyan("http://localhost:8080/docs")
116
265
  );
117
266
  console.log();
118
267
  }
119
268
  function printError(message) {
120
269
  console.log();
121
- console.log(chalk.red("\u2716"), message);
270
+ console.log(chalk2.red("\u2716"), message);
122
271
  console.log();
123
272
  }
124
273
 
@@ -172,6 +321,29 @@ async function getProjectOptions(providedName, flags = {}) {
172
321
  useCurrentDir
173
322
  };
174
323
  }
324
+ async function promptAutomaticSetup() {
325
+ const dockerRunning = isDockerRunning();
326
+ if (!dockerRunning) {
327
+ console.log();
328
+ console.log(
329
+ chalk3.yellow(" \u26A0"),
330
+ "Docker is not running. Skipping automatic setup."
331
+ );
332
+ console.log(
333
+ chalk3.dim(" Start Docker and run setup steps manually (see below).")
334
+ );
335
+ console.log();
336
+ return false;
337
+ }
338
+ console.log();
339
+ const { runSetup } = await prompts({
340
+ type: "confirm",
341
+ name: "runSetup",
342
+ message: "Run initial setup now? (docker compose + database migrations)",
343
+ initial: true
344
+ });
345
+ return runSetup || false;
346
+ }
175
347
 
176
348
  // src/template.ts
177
349
  import fs from "fs-extra";
@@ -180,9 +352,10 @@ import path2 from "path";
180
352
  var GITHUB_REPO = "github:CarboxyDev/blitzpack";
181
353
  var POST_DOWNLOAD_EXCLUDES = [
182
354
  "create-blitzpack",
183
- "scripts/setup.js",
184
355
  ".github",
185
- "apps/marketing"
356
+ "apps/marketing",
357
+ "Dockerfile",
358
+ "docker-compose.prod.yml"
186
359
  ];
187
360
  async function cleanupExcludes(targetDir) {
188
361
  for (const exclude of POST_DOWNLOAD_EXCLUDES) {
@@ -192,12 +365,36 @@ async function cleanupExcludes(targetDir) {
192
365
  }
193
366
  }
194
367
  }
195
- async function downloadAndPrepareTemplate(targetDir) {
368
+ async function downloadAndPrepareTemplate(targetDir, spinner) {
369
+ spinner.text = "Fetching template from GitHub...";
196
370
  await downloadTemplate(GITHUB_REPO, {
197
371
  dir: targetDir,
198
372
  force: true
199
373
  });
374
+ spinner.text = "Extracting files...";
375
+ await new Promise((resolve) => setTimeout(resolve, 100));
376
+ spinner.text = "Cleaning up template files...";
200
377
  await cleanupExcludes(targetDir);
378
+ const files = await countFiles(targetDir);
379
+ spinner.succeed(`Downloaded template (${files} files)`);
380
+ }
381
+ async function countFiles(dir) {
382
+ try {
383
+ let count = 0;
384
+ const items = await fs.readdir(dir);
385
+ for (const item of items) {
386
+ const fullPath = path2.join(dir, item);
387
+ const stat = await fs.stat(fullPath);
388
+ if (stat.isDirectory()) {
389
+ count += await countFiles(fullPath);
390
+ } else {
391
+ count++;
392
+ }
393
+ }
394
+ return count;
395
+ } catch {
396
+ return 0;
397
+ }
201
398
  }
202
399
 
203
400
  // src/transform.ts
@@ -329,32 +526,36 @@ function runInstall(cwd) {
329
526
  });
330
527
  }
331
528
  function printDryRun(options) {
332
- console.log(chalk2.yellow(" Dry run mode - no changes will be made"));
529
+ console.log(chalk4.yellow(" Dry run mode - no changes will be made"));
333
530
  console.log();
334
- console.log(chalk2.bold(" Would create:"));
531
+ console.log(chalk4.bold(" Would create:"));
335
532
  console.log();
336
- console.log(` ${chalk2.cyan("Directory:")} ${options.targetDir}`);
337
- console.log(` ${chalk2.cyan("Name:")} ${options.projectName}`);
338
- console.log(` ${chalk2.cyan("Slug:")} ${options.projectSlug}`);
533
+ console.log(` ${chalk4.cyan("Directory:")} ${options.targetDir}`);
534
+ console.log(` ${chalk4.cyan("Name:")} ${options.projectName}`);
535
+ console.log(` ${chalk4.cyan("Slug:")} ${options.projectSlug}`);
339
536
  console.log(
340
- ` ${chalk2.cyan("Description:")} ${options.projectDescription}`
537
+ ` ${chalk4.cyan("Description:")} ${options.projectDescription}`
341
538
  );
342
539
  console.log();
343
- console.log(chalk2.bold(" Would run:"));
540
+ console.log(chalk4.bold(" Would run:"));
344
541
  console.log();
345
- console.log(` ${chalk2.dim("\u2022")} Download template from GitHub`);
346
- console.log(` ${chalk2.dim("\u2022")} Transform package.json files`);
347
- console.log(` ${chalk2.dim("\u2022")} Create .env.local files`);
542
+ console.log(` ${chalk4.dim("\u2022")} Download template from GitHub`);
543
+ console.log(` ${chalk4.dim("\u2022")} Transform package.json files`);
544
+ console.log(` ${chalk4.dim("\u2022")} Create .env.local files`);
348
545
  if (!options.skipGit) {
349
- console.log(` ${chalk2.dim("\u2022")} Initialize git repository`);
546
+ console.log(` ${chalk4.dim("\u2022")} Initialize git repository`);
350
547
  }
351
548
  if (!options.skipInstall) {
352
- console.log(` ${chalk2.dim("\u2022")} Install dependencies (pnpm install)`);
549
+ console.log(` ${chalk4.dim("\u2022")} Install dependencies (pnpm install)`);
353
550
  }
354
551
  console.log();
355
552
  }
356
553
  async function create(projectName, flags) {
357
554
  printHeader();
555
+ const checksPass = await runPreflightChecks();
556
+ if (!checksPass) {
557
+ process.exit(1);
558
+ }
358
559
  const options = await getProjectOptions(projectName, flags);
359
560
  if (!options) {
360
561
  return;
@@ -393,8 +594,7 @@ async function create(projectName, flags) {
393
594
  const spinner = ora();
394
595
  try {
395
596
  spinner.start("Downloading template from GitHub...");
396
- await downloadAndPrepareTemplate(targetDir);
397
- spinner.succeed("Downloaded template");
597
+ await downloadAndPrepareTemplate(targetDir, spinner);
398
598
  spinner.start("Configuring project...");
399
599
  await transformFiles(targetDir, {
400
600
  projectName: options.projectName,
@@ -423,9 +623,34 @@ async function create(projectName, flags) {
423
623
  );
424
624
  }
425
625
  }
626
+ let ranAutomaticSetup = false;
627
+ const shouldRunSetup = await promptAutomaticSetup();
628
+ if (shouldRunSetup) {
629
+ console.log();
630
+ spinner.start("Starting PostgreSQL database...");
631
+ const dockerSuccess = runDockerCompose(targetDir);
632
+ if (dockerSuccess) {
633
+ spinner.succeed("Started PostgreSQL database");
634
+ spinner.start("Running database migrations...");
635
+ const migrationsSuccess = runDatabaseMigrations(targetDir);
636
+ if (migrationsSuccess) {
637
+ spinner.succeed("Database migrations complete");
638
+ ranAutomaticSetup = true;
639
+ } else {
640
+ spinner.warn(
641
+ 'Failed to run migrations. Run "pnpm db:migrate" manually.'
642
+ );
643
+ }
644
+ } else {
645
+ spinner.warn(
646
+ 'Failed to start Docker. Run "docker compose up -d" manually.'
647
+ );
648
+ }
649
+ }
426
650
  printSuccess(
427
651
  options.projectName,
428
- options.useCurrentDir ? "." : options.projectName
652
+ options.useCurrentDir ? "." : options.projectName,
653
+ ranAutomaticSetup
429
654
  );
430
655
  } catch (error) {
431
656
  spinner.fail();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-blitzpack",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Create a new Blitzpack project - full-stack TypeScript monorepo with Next.js and Fastify",
5
5
  "type": "module",
6
6
  "bin": {