create-blitzpack 0.1.4 → 0.1.6

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";
@@ -181,7 +353,8 @@ var GITHUB_REPO = "github:CarboxyDev/blitzpack";
181
353
  var POST_DOWNLOAD_EXCLUDES = [
182
354
  "create-blitzpack",
183
355
  "scripts/setup.js",
184
- ".github"
356
+ ".github",
357
+ "apps/marketing"
185
358
  ];
186
359
  async function cleanupExcludes(targetDir) {
187
360
  for (const exclude of POST_DOWNLOAD_EXCLUDES) {
@@ -191,12 +364,36 @@ async function cleanupExcludes(targetDir) {
191
364
  }
192
365
  }
193
366
  }
194
- async function downloadAndPrepareTemplate(targetDir) {
367
+ async function downloadAndPrepareTemplate(targetDir, spinner) {
368
+ spinner.text = "Fetching template from GitHub...";
195
369
  await downloadTemplate(GITHUB_REPO, {
196
370
  dir: targetDir,
197
371
  force: true
198
372
  });
373
+ spinner.text = "Extracting files...";
374
+ await new Promise((resolve) => setTimeout(resolve, 100));
375
+ spinner.text = "Cleaning up template files...";
199
376
  await cleanupExcludes(targetDir);
377
+ const files = await countFiles(targetDir);
378
+ spinner.succeed(`Downloaded template (${files} files)`);
379
+ }
380
+ async function countFiles(dir) {
381
+ try {
382
+ let count = 0;
383
+ const items = await fs.readdir(dir);
384
+ for (const item of items) {
385
+ const fullPath = path2.join(dir, item);
386
+ const stat = await fs.stat(fullPath);
387
+ if (stat.isDirectory()) {
388
+ count += await countFiles(fullPath);
389
+ } else {
390
+ count++;
391
+ }
392
+ }
393
+ return count;
394
+ } catch {
395
+ return 0;
396
+ }
200
397
  }
201
398
 
202
399
  // src/transform.ts
@@ -218,7 +415,7 @@ function transformSiteConfig(content, vars) {
218
415
  return content.replace(/name: ['"].*['"]/, `name: '${vars.projectName}'`).replace(
219
416
  /description: ['"].*['"]/,
220
417
  `description: '${vars.projectDescription}'`
221
- ).replace(/github: ['"].*['"]/, `github: ''`);
418
+ );
222
419
  }
223
420
  function transformLayout(content, vars) {
224
421
  return content.replace(/title: ['"].*['"]/, `title: '${vars.projectName}'`).replace(
@@ -328,32 +525,36 @@ function runInstall(cwd) {
328
525
  });
329
526
  }
330
527
  function printDryRun(options) {
331
- console.log(chalk2.yellow(" Dry run mode - no changes will be made"));
528
+ console.log(chalk4.yellow(" Dry run mode - no changes will be made"));
332
529
  console.log();
333
- console.log(chalk2.bold(" Would create:"));
530
+ console.log(chalk4.bold(" Would create:"));
334
531
  console.log();
335
- console.log(` ${chalk2.cyan("Directory:")} ${options.targetDir}`);
336
- console.log(` ${chalk2.cyan("Name:")} ${options.projectName}`);
337
- console.log(` ${chalk2.cyan("Slug:")} ${options.projectSlug}`);
532
+ console.log(` ${chalk4.cyan("Directory:")} ${options.targetDir}`);
533
+ console.log(` ${chalk4.cyan("Name:")} ${options.projectName}`);
534
+ console.log(` ${chalk4.cyan("Slug:")} ${options.projectSlug}`);
338
535
  console.log(
339
- ` ${chalk2.cyan("Description:")} ${options.projectDescription}`
536
+ ` ${chalk4.cyan("Description:")} ${options.projectDescription}`
340
537
  );
341
538
  console.log();
342
- console.log(chalk2.bold(" Would run:"));
539
+ console.log(chalk4.bold(" Would run:"));
343
540
  console.log();
344
- console.log(` ${chalk2.dim("\u2022")} Download template from GitHub`);
345
- console.log(` ${chalk2.dim("\u2022")} Transform package.json files`);
346
- console.log(` ${chalk2.dim("\u2022")} Create .env.local files`);
541
+ console.log(` ${chalk4.dim("\u2022")} Download template from GitHub`);
542
+ console.log(` ${chalk4.dim("\u2022")} Transform package.json files`);
543
+ console.log(` ${chalk4.dim("\u2022")} Create .env.local files`);
347
544
  if (!options.skipGit) {
348
- console.log(` ${chalk2.dim("\u2022")} Initialize git repository`);
545
+ console.log(` ${chalk4.dim("\u2022")} Initialize git repository`);
349
546
  }
350
547
  if (!options.skipInstall) {
351
- console.log(` ${chalk2.dim("\u2022")} Install dependencies (pnpm install)`);
548
+ console.log(` ${chalk4.dim("\u2022")} Install dependencies (pnpm install)`);
352
549
  }
353
550
  console.log();
354
551
  }
355
552
  async function create(projectName, flags) {
356
553
  printHeader();
554
+ const checksPass = await runPreflightChecks();
555
+ if (!checksPass) {
556
+ process.exit(1);
557
+ }
357
558
  const options = await getProjectOptions(projectName, flags);
358
559
  if (!options) {
359
560
  return;
@@ -392,8 +593,7 @@ async function create(projectName, flags) {
392
593
  const spinner = ora();
393
594
  try {
394
595
  spinner.start("Downloading template from GitHub...");
395
- await downloadAndPrepareTemplate(targetDir);
396
- spinner.succeed("Downloaded template");
596
+ await downloadAndPrepareTemplate(targetDir, spinner);
397
597
  spinner.start("Configuring project...");
398
598
  await transformFiles(targetDir, {
399
599
  projectName: options.projectName,
@@ -422,9 +622,34 @@ async function create(projectName, flags) {
422
622
  );
423
623
  }
424
624
  }
625
+ let ranAutomaticSetup = false;
626
+ const shouldRunSetup = await promptAutomaticSetup();
627
+ if (shouldRunSetup) {
628
+ console.log();
629
+ spinner.start("Starting PostgreSQL database...");
630
+ const dockerSuccess = runDockerCompose(targetDir);
631
+ if (dockerSuccess) {
632
+ spinner.succeed("Started PostgreSQL database");
633
+ spinner.start("Running database migrations...");
634
+ const migrationsSuccess = runDatabaseMigrations(targetDir);
635
+ if (migrationsSuccess) {
636
+ spinner.succeed("Database migrations complete");
637
+ ranAutomaticSetup = true;
638
+ } else {
639
+ spinner.warn(
640
+ 'Failed to run migrations. Run "pnpm db:migrate" manually.'
641
+ );
642
+ }
643
+ } else {
644
+ spinner.warn(
645
+ 'Failed to start Docker. Run "docker compose up -d" manually.'
646
+ );
647
+ }
648
+ }
425
649
  printSuccess(
426
650
  options.projectName,
427
- options.useCurrentDir ? "." : options.projectName
651
+ options.useCurrentDir ? "." : options.projectName,
652
+ ranAutomaticSetup
428
653
  );
429
654
  } catch (error) {
430
655
  spinner.fail();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-blitzpack",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Create a new Blitzpack project - full-stack TypeScript monorepo with Next.js and Fastify",
5
5
  "type": "module",
6
6
  "bin": {