create-blitzpack 0.1.9 → 0.1.11
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/dist/index.js +331 -16
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -155,6 +155,65 @@ var REPLACEABLE_FILES = [
|
|
|
155
155
|
"README.md"
|
|
156
156
|
];
|
|
157
157
|
var DEFAULT_DESCRIPTION = "A full-stack TypeScript monorepo built with Blitzpack";
|
|
158
|
+
var OPTIONAL_FEATURES = [
|
|
159
|
+
{
|
|
160
|
+
key: "testing",
|
|
161
|
+
name: "Testing",
|
|
162
|
+
description: "vitest, integration tests, test helpers"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
key: "admin",
|
|
166
|
+
name: "Admin Dashboard",
|
|
167
|
+
description: "user management, stats, sessions admin"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
key: "uploads",
|
|
171
|
+
name: "File Uploads",
|
|
172
|
+
description: "S3 storage, upload routes, file components"
|
|
173
|
+
}
|
|
174
|
+
];
|
|
175
|
+
var FEATURE_EXCLUSIONS = {
|
|
176
|
+
testing: [
|
|
177
|
+
"vitest.workspace.ts",
|
|
178
|
+
"vitest.shared.ts",
|
|
179
|
+
"apps/api/test",
|
|
180
|
+
"apps/api/vitest.config.ts",
|
|
181
|
+
"apps/web/src/test",
|
|
182
|
+
"apps/web/vitest.config.ts",
|
|
183
|
+
"packages/types/src/__tests__",
|
|
184
|
+
"packages/types/vitest.config.ts",
|
|
185
|
+
"packages/utils/src/__tests__",
|
|
186
|
+
"packages/utils/vitest.config.ts",
|
|
187
|
+
"packages/ui/src/__tests__",
|
|
188
|
+
"packages/ui/vitest.config.ts",
|
|
189
|
+
"packages/ui/vitest.setup.ts",
|
|
190
|
+
"packages/ui/test-config.js",
|
|
191
|
+
"apps/web/src/hooks/api/__tests__"
|
|
192
|
+
],
|
|
193
|
+
admin: [
|
|
194
|
+
"apps/web/src/app/(admin)",
|
|
195
|
+
"apps/web/src/components/admin",
|
|
196
|
+
"apps/web/src/hooks/api/use-admin-sessions.ts",
|
|
197
|
+
"apps/web/src/hooks/api/use-admin-stats.ts",
|
|
198
|
+
"apps/web/src/hooks/use-realtime-metrics.ts",
|
|
199
|
+
"apps/api/src/routes/admin-sessions.ts",
|
|
200
|
+
"apps/api/src/routes/stats.ts",
|
|
201
|
+
"apps/api/src/routes/metrics.ts",
|
|
202
|
+
"apps/api/src/services/stats.service.ts",
|
|
203
|
+
"apps/api/src/services/metrics.service.ts",
|
|
204
|
+
"packages/types/src/stats.ts"
|
|
205
|
+
],
|
|
206
|
+
uploads: [
|
|
207
|
+
"apps/api/src/routes/uploads.ts",
|
|
208
|
+
"apps/api/src/routes/uploads-serve.ts",
|
|
209
|
+
"apps/api/src/services/uploads.service.ts",
|
|
210
|
+
"apps/api/src/services/file-storage.service.ts",
|
|
211
|
+
"apps/api/public/uploads",
|
|
212
|
+
"apps/web/src/hooks/api/use-uploads.ts",
|
|
213
|
+
"packages/ui/src/file-upload-input.tsx",
|
|
214
|
+
"packages/types/src/upload.ts"
|
|
215
|
+
]
|
|
216
|
+
};
|
|
158
217
|
|
|
159
218
|
// src/utils.ts
|
|
160
219
|
import chalk2 from "chalk";
|
|
@@ -310,6 +369,10 @@ async function getProjectOptions(providedName, flags = {}) {
|
|
|
310
369
|
console.log(`Invalid project name: ${validation.problems?.[0]}`);
|
|
311
370
|
return null;
|
|
312
371
|
}
|
|
372
|
+
const features = await promptFeatureSelection();
|
|
373
|
+
if (!features) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
313
376
|
const useCurrentDir = projectName === ".";
|
|
314
377
|
const actualProjectName = useCurrentDir ? getCurrentDirName() : projectName;
|
|
315
378
|
return {
|
|
@@ -318,7 +381,40 @@ async function getProjectOptions(providedName, flags = {}) {
|
|
|
318
381
|
projectDescription: response.projectDescription || DEFAULT_DESCRIPTION,
|
|
319
382
|
skipGit: flags.skipGit || false,
|
|
320
383
|
skipInstall: flags.skipInstall || false,
|
|
321
|
-
useCurrentDir
|
|
384
|
+
useCurrentDir,
|
|
385
|
+
features
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
async function promptFeatureSelection() {
|
|
389
|
+
const featureChoices = OPTIONAL_FEATURES.map((feature) => ({
|
|
390
|
+
title: `${feature.name} ${chalk3.dim(`(${feature.description})`)}`,
|
|
391
|
+
value: feature.key,
|
|
392
|
+
selected: true
|
|
393
|
+
}));
|
|
394
|
+
let cancelled = false;
|
|
395
|
+
const { selectedFeatures } = await prompts(
|
|
396
|
+
{
|
|
397
|
+
type: "multiselect",
|
|
398
|
+
name: "selectedFeatures",
|
|
399
|
+
message: "Include optional features:",
|
|
400
|
+
choices: featureChoices,
|
|
401
|
+
hint: "- Space to toggle, Enter to confirm",
|
|
402
|
+
instructions: false
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
onCancel: () => {
|
|
406
|
+
cancelled = true;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
);
|
|
410
|
+
if (cancelled) {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
const selected = selectedFeatures || [];
|
|
414
|
+
return {
|
|
415
|
+
testing: selected.includes("testing"),
|
|
416
|
+
admin: selected.includes("admin"),
|
|
417
|
+
uploads: selected.includes("uploads")
|
|
322
418
|
};
|
|
323
419
|
}
|
|
324
420
|
async function promptAutomaticSetup() {
|
|
@@ -357,15 +453,25 @@ var POST_DOWNLOAD_EXCLUDES = [
|
|
|
357
453
|
"Dockerfile",
|
|
358
454
|
"docker-compose.prod.yml"
|
|
359
455
|
];
|
|
360
|
-
|
|
361
|
-
|
|
456
|
+
function getFeatureExclusions(features) {
|
|
457
|
+
const exclusions = [];
|
|
458
|
+
for (const [key, enabled] of Object.entries(features)) {
|
|
459
|
+
if (!enabled) {
|
|
460
|
+
exclusions.push(...FEATURE_EXCLUSIONS[key]);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return exclusions;
|
|
464
|
+
}
|
|
465
|
+
async function cleanupExcludes(targetDir, additionalExcludes = []) {
|
|
466
|
+
const allExcludes = [...POST_DOWNLOAD_EXCLUDES, ...additionalExcludes];
|
|
467
|
+
for (const exclude of allExcludes) {
|
|
362
468
|
const fullPath = path2.join(targetDir, exclude);
|
|
363
469
|
if (await fs.pathExists(fullPath)) {
|
|
364
470
|
await fs.remove(fullPath);
|
|
365
471
|
}
|
|
366
472
|
}
|
|
367
473
|
}
|
|
368
|
-
async function downloadAndPrepareTemplate(targetDir, spinner) {
|
|
474
|
+
async function downloadAndPrepareTemplate(targetDir, spinner, features) {
|
|
369
475
|
spinner.text = "Fetching template from GitHub...";
|
|
370
476
|
await downloadTemplate(GITHUB_REPO, {
|
|
371
477
|
dir: targetDir,
|
|
@@ -374,7 +480,8 @@ async function downloadAndPrepareTemplate(targetDir, spinner) {
|
|
|
374
480
|
spinner.text = "Extracting files...";
|
|
375
481
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
376
482
|
spinner.text = "Cleaning up template files...";
|
|
377
|
-
|
|
483
|
+
const featureExclusions = getFeatureExclusions(features);
|
|
484
|
+
await cleanupExcludes(targetDir, featureExclusions);
|
|
378
485
|
const files = await countFiles(targetDir);
|
|
379
486
|
spinner.succeed(`Downloaded template (${files} files)`);
|
|
380
487
|
}
|
|
@@ -400,7 +507,25 @@ async function countFiles(dir) {
|
|
|
400
507
|
// src/transform.ts
|
|
401
508
|
import fs2 from "fs-extra";
|
|
402
509
|
import path3 from "path";
|
|
403
|
-
|
|
510
|
+
var TESTING_SCRIPTS = [
|
|
511
|
+
"test",
|
|
512
|
+
"test:unit",
|
|
513
|
+
"test:integration",
|
|
514
|
+
"test:watch",
|
|
515
|
+
"test:coverage",
|
|
516
|
+
"test:parallel"
|
|
517
|
+
];
|
|
518
|
+
var TESTING_ROOT_DEVDEPS = [
|
|
519
|
+
"@testing-library/jest-dom",
|
|
520
|
+
"@testing-library/react",
|
|
521
|
+
"@testing-library/user-event",
|
|
522
|
+
"@vitest/coverage-v8",
|
|
523
|
+
"jsdom",
|
|
524
|
+
"vitest"
|
|
525
|
+
];
|
|
526
|
+
var TESTING_APP_DEVDEPS = ["vitest", "vite-tsconfig-paths"];
|
|
527
|
+
var UPLOADS_API_DEPS = ["@aws-sdk/client-s3", "sharp"];
|
|
528
|
+
function transformPackageJson(content, vars, filePath, features) {
|
|
404
529
|
const pkg = JSON.parse(content);
|
|
405
530
|
if (filePath === "package.json") {
|
|
406
531
|
pkg.name = vars.projectSlug;
|
|
@@ -409,6 +534,31 @@ function transformPackageJson(content, vars, filePath) {
|
|
|
409
534
|
delete pkg.homepage;
|
|
410
535
|
delete pkg.scripts?.["init:project"];
|
|
411
536
|
pkg.version = "0.1.0";
|
|
537
|
+
if (!features.testing) {
|
|
538
|
+
for (const script of TESTING_SCRIPTS) {
|
|
539
|
+
delete pkg.scripts?.[script];
|
|
540
|
+
}
|
|
541
|
+
for (const dep of TESTING_ROOT_DEVDEPS) {
|
|
542
|
+
delete pkg.devDependencies?.[dep];
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (filePath === "apps/api/package.json" || filePath === "apps/web/package.json") {
|
|
547
|
+
if (!features.testing) {
|
|
548
|
+
for (const script of TESTING_SCRIPTS) {
|
|
549
|
+
delete pkg.scripts?.[script];
|
|
550
|
+
}
|
|
551
|
+
for (const dep of TESTING_APP_DEVDEPS) {
|
|
552
|
+
delete pkg.devDependencies?.[dep];
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (filePath === "apps/api/package.json") {
|
|
557
|
+
if (!features.uploads) {
|
|
558
|
+
for (const dep of UPLOADS_API_DEPS) {
|
|
559
|
+
delete pkg.dependencies?.[dep];
|
|
560
|
+
}
|
|
561
|
+
}
|
|
412
562
|
}
|
|
413
563
|
return JSON.stringify(pkg, null, 2) + "\n";
|
|
414
564
|
}
|
|
@@ -475,8 +625,13 @@ pnpm db:seed # Seed database
|
|
|
475
625
|
Built with [Blitzpack](https://github.com/CarboxyDev/blitzpack)
|
|
476
626
|
`;
|
|
477
627
|
}
|
|
478
|
-
async function transformFiles(targetDir, vars) {
|
|
479
|
-
|
|
628
|
+
async function transformFiles(targetDir, vars, features) {
|
|
629
|
+
const filesToTransform = [
|
|
630
|
+
...REPLACEABLE_FILES,
|
|
631
|
+
"apps/api/package.json",
|
|
632
|
+
"apps/web/package.json"
|
|
633
|
+
];
|
|
634
|
+
for (const relativePath of filesToTransform) {
|
|
480
635
|
const filePath = path3.join(targetDir, relativePath);
|
|
481
636
|
if (!await fs2.pathExists(filePath)) {
|
|
482
637
|
continue;
|
|
@@ -486,7 +641,7 @@ async function transformFiles(targetDir, vars) {
|
|
|
486
641
|
if (relativePath === "README.md") {
|
|
487
642
|
transformed = generateReadme(vars);
|
|
488
643
|
} else if (relativePath.endsWith("package.json")) {
|
|
489
|
-
transformed = transformPackageJson(content, vars, relativePath);
|
|
644
|
+
transformed = transformPackageJson(content, vars, relativePath, features);
|
|
490
645
|
} else if (relativePath.includes("site.ts")) {
|
|
491
646
|
transformed = transformSiteConfig(content, vars);
|
|
492
647
|
} else if (relativePath.includes("layout.tsx")) {
|
|
@@ -498,6 +653,148 @@ async function transformFiles(targetDir, vars) {
|
|
|
498
653
|
}
|
|
499
654
|
await fs2.writeFile(filePath, transformed, "utf-8");
|
|
500
655
|
}
|
|
656
|
+
await applyFeatureTransforms(targetDir, features);
|
|
657
|
+
}
|
|
658
|
+
async function applyFeatureTransforms(targetDir, features) {
|
|
659
|
+
if (!features.testing) {
|
|
660
|
+
await transformForNoTesting(targetDir);
|
|
661
|
+
}
|
|
662
|
+
if (!features.admin) {
|
|
663
|
+
await transformForNoAdmin(targetDir);
|
|
664
|
+
}
|
|
665
|
+
if (!features.uploads) {
|
|
666
|
+
await transformForNoUploads(targetDir);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
async function transformForNoTesting(targetDir) {
|
|
670
|
+
const turboPath = path3.join(targetDir, "turbo.json");
|
|
671
|
+
if (await fs2.pathExists(turboPath)) {
|
|
672
|
+
const content = await fs2.readFile(turboPath, "utf-8");
|
|
673
|
+
const turbo = JSON.parse(content);
|
|
674
|
+
delete turbo.tasks?.test;
|
|
675
|
+
delete turbo.tasks?.["test:unit"];
|
|
676
|
+
delete turbo.tasks?.["test:integration"];
|
|
677
|
+
delete turbo.tasks?.["test:watch"];
|
|
678
|
+
delete turbo.tasks?.["test:coverage"];
|
|
679
|
+
await fs2.writeFile(turboPath, JSON.stringify(turbo, null, 2) + "\n");
|
|
680
|
+
}
|
|
681
|
+
const huskyPath = path3.join(targetDir, ".husky/pre-push");
|
|
682
|
+
if (await fs2.pathExists(huskyPath)) {
|
|
683
|
+
await fs2.writeFile(huskyPath, "pnpm typecheck\n");
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
async function transformForNoAdmin(targetDir) {
|
|
687
|
+
const appPath = path3.join(targetDir, "apps/api/src/app.ts");
|
|
688
|
+
if (await fs2.pathExists(appPath)) {
|
|
689
|
+
let content = await fs2.readFile(appPath, "utf-8");
|
|
690
|
+
content = content.replace(
|
|
691
|
+
/import { metricsService } from '@\/services\/metrics\.service';\n/,
|
|
692
|
+
""
|
|
693
|
+
);
|
|
694
|
+
content = content.replace(
|
|
695
|
+
/const { default: statsRoutes } = await import\('@\/routes\/stats\.js'\);\n/,
|
|
696
|
+
""
|
|
697
|
+
);
|
|
698
|
+
content = content.replace(
|
|
699
|
+
/const { default: metricsRoutes } = await import\('@\/routes\/metrics\.js'\);\n/,
|
|
700
|
+
""
|
|
701
|
+
);
|
|
702
|
+
content = content.replace(
|
|
703
|
+
/const { default: adminSessionsRoutes } = await import\(\n\s*'@\/routes\/admin-sessions\.js'\n\s*\);\n/,
|
|
704
|
+
""
|
|
705
|
+
);
|
|
706
|
+
content = content.replace(/metricsService\.start\(\);\n\n/, "");
|
|
707
|
+
content = content.replace(
|
|
708
|
+
/\s*metricsService\.recordRequest\(responseTime, reply\.statusCode\);\n/,
|
|
709
|
+
""
|
|
710
|
+
);
|
|
711
|
+
content = content.replace(/\s*await app\.register\(statsRoutes\);/g, "");
|
|
712
|
+
content = content.replace(/\s*await app\.register\(metricsRoutes\);/g, "");
|
|
713
|
+
content = content.replace(
|
|
714
|
+
/\s*await app\.register\(adminSessionsRoutes\);/g,
|
|
715
|
+
""
|
|
716
|
+
);
|
|
717
|
+
await fs2.writeFile(appPath, content);
|
|
718
|
+
}
|
|
719
|
+
const servicesPath = path3.join(targetDir, "apps/api/src/plugins/services.ts");
|
|
720
|
+
if (await fs2.pathExists(servicesPath)) {
|
|
721
|
+
let content = await fs2.readFile(servicesPath, "utf-8");
|
|
722
|
+
content = content.replace(
|
|
723
|
+
/import { StatsService } from '@\/services\/stats\.service';\n/,
|
|
724
|
+
""
|
|
725
|
+
);
|
|
726
|
+
content = content.replace(
|
|
727
|
+
/\s*const statsService = new StatsService\(app\.prisma, app\.logger\);/,
|
|
728
|
+
""
|
|
729
|
+
);
|
|
730
|
+
content = content.replace(
|
|
731
|
+
/\s*app\.decorate\('statsService', statsService\);/,
|
|
732
|
+
""
|
|
733
|
+
);
|
|
734
|
+
content = content.replace(/\s*statsService: StatsService;/, "");
|
|
735
|
+
await fs2.writeFile(servicesPath, content);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
async function transformForNoUploads(targetDir) {
|
|
739
|
+
const appPath = path3.join(targetDir, "apps/api/src/app.ts");
|
|
740
|
+
if (await fs2.pathExists(appPath)) {
|
|
741
|
+
let content = await fs2.readFile(appPath, "utf-8");
|
|
742
|
+
content = content.replace(
|
|
743
|
+
/const { default: uploadsRoutes } = await import\('@\/routes\/uploads\.js'\);\n/,
|
|
744
|
+
""
|
|
745
|
+
);
|
|
746
|
+
content = content.replace(
|
|
747
|
+
/const { default: uploadsServeRoutes } = await import\(\n\s*'@\/routes\/uploads-serve\.js'\n\s*\);\n/,
|
|
748
|
+
""
|
|
749
|
+
);
|
|
750
|
+
content = content.replace(
|
|
751
|
+
/await app\.register\(uploadsServeRoutes\);\n\n/,
|
|
752
|
+
""
|
|
753
|
+
);
|
|
754
|
+
content = content.replace(/\s*await app\.register\(uploadsRoutes\);/g, "");
|
|
755
|
+
await fs2.writeFile(appPath, content);
|
|
756
|
+
}
|
|
757
|
+
const servicesPath = path3.join(targetDir, "apps/api/src/plugins/services.ts");
|
|
758
|
+
if (await fs2.pathExists(servicesPath)) {
|
|
759
|
+
let content = await fs2.readFile(servicesPath, "utf-8");
|
|
760
|
+
content = content.replace(
|
|
761
|
+
/import { FileStorageService } from '@\/services\/file-storage\.service';\n/,
|
|
762
|
+
""
|
|
763
|
+
);
|
|
764
|
+
content = content.replace(
|
|
765
|
+
/import { UploadsService } from '@\/services\/uploads\.service';\n/,
|
|
766
|
+
""
|
|
767
|
+
);
|
|
768
|
+
content = content.replace(
|
|
769
|
+
/\s*const fileStorageService = new FileStorageService\(env, app\.logger\);/,
|
|
770
|
+
""
|
|
771
|
+
);
|
|
772
|
+
content = content.replace(
|
|
773
|
+
/\s*const uploadsService = new UploadsService\(\n\s*app\.prisma,\n\s*fileStorageService,\n\s*app\.logger\n\s*\);/,
|
|
774
|
+
""
|
|
775
|
+
);
|
|
776
|
+
content = content.replace(
|
|
777
|
+
/\s*app\.decorate\('fileStorageService', fileStorageService\);/,
|
|
778
|
+
""
|
|
779
|
+
);
|
|
780
|
+
content = content.replace(
|
|
781
|
+
/\s*app\.decorate\('uploadsService', uploadsService\);/,
|
|
782
|
+
""
|
|
783
|
+
);
|
|
784
|
+
content = content.replace(/\s*fileStorageService: FileStorageService;/, "");
|
|
785
|
+
content = content.replace(/\s*uploadsService: UploadsService;/, "");
|
|
786
|
+
await fs2.writeFile(servicesPath, content);
|
|
787
|
+
}
|
|
788
|
+
const schemaPath = path3.join(targetDir, "apps/api/prisma/schema.prisma");
|
|
789
|
+
if (await fs2.pathExists(schemaPath)) {
|
|
790
|
+
let content = await fs2.readFile(schemaPath, "utf-8");
|
|
791
|
+
content = content.replace(/\s*uploads\s+Upload\[\]/, "");
|
|
792
|
+
content = content.replace(
|
|
793
|
+
/\n\nmodel Upload \{[\s\S]*?@@map\("uploads"\)\n\}/,
|
|
794
|
+
""
|
|
795
|
+
);
|
|
796
|
+
await fs2.writeFile(schemaPath, content);
|
|
797
|
+
}
|
|
501
798
|
}
|
|
502
799
|
|
|
503
800
|
// src/commands/create.ts
|
|
@@ -537,6 +834,19 @@ function printDryRun(options) {
|
|
|
537
834
|
` ${chalk4.cyan("Description:")} ${options.projectDescription}`
|
|
538
835
|
);
|
|
539
836
|
console.log();
|
|
837
|
+
console.log(chalk4.bold(" Features:"));
|
|
838
|
+
console.log();
|
|
839
|
+
const featureStatus = (enabled) => enabled ? chalk4.green("\u2713") : chalk4.red("\u2717");
|
|
840
|
+
console.log(
|
|
841
|
+
` ${featureStatus(options.features.testing)} Testing ${chalk4.dim("(vitest, integration tests)")}`
|
|
842
|
+
);
|
|
843
|
+
console.log(
|
|
844
|
+
` ${featureStatus(options.features.admin)} Admin Dashboard ${chalk4.dim("(user management, stats)")}`
|
|
845
|
+
);
|
|
846
|
+
console.log(
|
|
847
|
+
` ${featureStatus(options.features.uploads)} File Uploads ${chalk4.dim("(S3 storage, upload routes)")}`
|
|
848
|
+
);
|
|
849
|
+
console.log();
|
|
540
850
|
console.log(chalk4.bold(" Would run:"));
|
|
541
851
|
console.log();
|
|
542
852
|
console.log(` ${chalk4.dim("\u2022")} Download template from GitHub`);
|
|
@@ -568,7 +878,8 @@ async function create(projectName, flags) {
|
|
|
568
878
|
projectDescription: options.projectDescription,
|
|
569
879
|
targetDir,
|
|
570
880
|
skipGit: options.skipGit,
|
|
571
|
-
skipInstall: options.skipInstall
|
|
881
|
+
skipInstall: options.skipInstall,
|
|
882
|
+
features: options.features
|
|
572
883
|
});
|
|
573
884
|
return;
|
|
574
885
|
}
|
|
@@ -594,13 +905,17 @@ async function create(projectName, flags) {
|
|
|
594
905
|
const spinner = ora();
|
|
595
906
|
try {
|
|
596
907
|
spinner.start("Downloading template from GitHub...");
|
|
597
|
-
await downloadAndPrepareTemplate(targetDir, spinner);
|
|
908
|
+
await downloadAndPrepareTemplate(targetDir, spinner, options.features);
|
|
598
909
|
spinner.start("Configuring project...");
|
|
599
|
-
await transformFiles(
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
910
|
+
await transformFiles(
|
|
911
|
+
targetDir,
|
|
912
|
+
{
|
|
913
|
+
projectName: options.projectName,
|
|
914
|
+
projectSlug: options.projectSlug,
|
|
915
|
+
projectDescription: options.projectDescription
|
|
916
|
+
},
|
|
917
|
+
options.features
|
|
918
|
+
);
|
|
604
919
|
await copyEnvFiles(targetDir);
|
|
605
920
|
spinner.succeed("Configured project");
|
|
606
921
|
if (!options.skipGit && isGitInstalled()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-blitzpack",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Create a new Blitzpack project - full-stack TypeScript monorepo with Next.js and Fastify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,21 +16,21 @@
|
|
|
16
16
|
"clean": "rm -rf dist"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"chalk": "^5.
|
|
19
|
+
"chalk": "^5.6.2",
|
|
20
20
|
"commander": "^13.1.0",
|
|
21
|
-
"fs-extra": "^11.3.
|
|
21
|
+
"fs-extra": "^11.3.3",
|
|
22
22
|
"giget": "^2.0.0",
|
|
23
23
|
"ora": "^8.2.0",
|
|
24
24
|
"prompts": "^2.4.2",
|
|
25
|
-
"validate-npm-package-name": "^6.0.
|
|
25
|
+
"validate-npm-package-name": "^6.0.2"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/fs-extra": "^11.0.4",
|
|
29
|
-
"@types/node": "^22.
|
|
29
|
+
"@types/node": "^22.19.3",
|
|
30
30
|
"@types/prompts": "^2.4.9",
|
|
31
31
|
"@types/validate-npm-package-name": "^4.0.2",
|
|
32
|
-
"tsup": "^8.5.
|
|
33
|
-
"typescript": "^5.
|
|
32
|
+
"tsup": "^8.5.1",
|
|
33
|
+
"typescript": "^5.9.3"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"create",
|