create-init-mtv-app 1.0.3 → 1.0.5
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.mjs +405 -152
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execa } from "execa";
|
|
3
2
|
import fs from "fs-extra";
|
|
4
3
|
import path from "path";
|
|
4
|
+
import { execa } from "execa";
|
|
5
5
|
import inquirer from "inquirer";
|
|
6
6
|
|
|
7
7
|
//#region src/enum/db_provider.ts
|
|
@@ -41,134 +41,6 @@ let UI_LIB = /* @__PURE__ */ function(UI_LIB$1) {
|
|
|
41
41
|
return UI_LIB$1;
|
|
42
42
|
}({});
|
|
43
43
|
|
|
44
|
-
//#endregion
|
|
45
|
-
//#region src/installers/expressjs/expressjs.ts
|
|
46
|
-
async function createExpressApp(projectName) {
|
|
47
|
-
await fs.ensureDir(projectName);
|
|
48
|
-
await execa("npm", ["init", "-y"], {
|
|
49
|
-
cwd: projectName,
|
|
50
|
-
stdio: "inherit"
|
|
51
|
-
});
|
|
52
|
-
const dtosDir = path.join(projectName, "src", "dtos");
|
|
53
|
-
const handlersDir = path.join(projectName, "src", "handlers");
|
|
54
|
-
const repositoriesDir = path.join(projectName, "src", "repositories");
|
|
55
|
-
const servicesDir = path.join(projectName, "src", "services");
|
|
56
|
-
const routesDir = path.join(projectName, "src", "routes");
|
|
57
|
-
const middlewareDir = path.join(projectName, "src", "middleware");
|
|
58
|
-
await Promise.all([
|
|
59
|
-
fs.ensureDir(dtosDir),
|
|
60
|
-
fs.ensureDir(handlersDir),
|
|
61
|
-
fs.ensureDir(repositoriesDir),
|
|
62
|
-
fs.ensureDir(servicesDir),
|
|
63
|
-
fs.ensureDir(routesDir),
|
|
64
|
-
fs.ensureDir(middlewareDir)
|
|
65
|
-
]);
|
|
66
|
-
const idParamDtoPath = path.join(dtosDir, "idParam.dto.ts");
|
|
67
|
-
const paginationDtoPath = path.join(dtosDir, "pagination.dto.ts");
|
|
68
|
-
const responseDtoPath = path.join(dtosDir, "response.dto.ts");
|
|
69
|
-
await Promise.all([
|
|
70
|
-
fs.ensureFile(idParamDtoPath),
|
|
71
|
-
fs.ensureFile(paginationDtoPath),
|
|
72
|
-
fs.ensureFile(responseDtoPath)
|
|
73
|
-
]);
|
|
74
|
-
await Promise.all([
|
|
75
|
-
fs.writeFile(idParamDtoPath, idParamDtoTemplate),
|
|
76
|
-
fs.writeFile(paginationDtoPath, paginationDtoTemplate),
|
|
77
|
-
fs.writeFile(responseDtoPath, responseDtoTemplate)
|
|
78
|
-
]);
|
|
79
|
-
const appFilePath = path.join(projectName, "src", "app.ts");
|
|
80
|
-
const indexFilePath = path.join(projectName, "index.ts");
|
|
81
|
-
await Promise.all([fs.ensureFile(appFilePath), fs.ensureFile(indexFilePath)]);
|
|
82
|
-
await Promise.all([fs.writeFile(appFilePath, appTemplate), fs.writeFile(indexFilePath, indexTemplate)]);
|
|
83
|
-
}
|
|
84
|
-
const appTemplate = `import express from "express";
|
|
85
|
-
import helmet from "helmet";
|
|
86
|
-
import cors from "cors";
|
|
87
|
-
import cookieParser from "cookie-parser";
|
|
88
|
-
import "dotenv/config";
|
|
89
|
-
import swaggerUi from "swagger-ui-express";
|
|
90
|
-
import swaggerDocument from "./swagger.json";
|
|
91
|
-
import morgan from "morgan";
|
|
92
|
-
|
|
93
|
-
const app = express();
|
|
94
|
-
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // mabe AI will help to generate the json file
|
|
95
|
-
app.use(helmet());
|
|
96
|
-
app.use(cors());
|
|
97
|
-
app.use(express.json());
|
|
98
|
-
app.use(express.urlencoded({ extended: true }));
|
|
99
|
-
app.use(cookieParser());
|
|
100
|
-
app.use(morgan("dev"));
|
|
101
|
-
|
|
102
|
-
app.get("/health", (_req, res) => {
|
|
103
|
-
res.json({ status: "ok" });
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
export default app;`;
|
|
107
|
-
const indexTemplate = `import app from "./src/app";
|
|
108
|
-
|
|
109
|
-
const port = process.env.PORT || 8080;
|
|
110
|
-
app.listen(port, () => {
|
|
111
|
-
console.log(\`Server is running on port \${ port }\`);
|
|
112
|
-
});`;
|
|
113
|
-
const idParamDtoTemplate = `export type IdParam = {
|
|
114
|
-
id: string;
|
|
115
|
-
};`;
|
|
116
|
-
const paginationDtoTemplate = `export type Pagination = {
|
|
117
|
-
page: number;
|
|
118
|
-
limit: number;
|
|
119
|
-
};`;
|
|
120
|
-
const responseDtoTemplate = `export type Response<T> = {
|
|
121
|
-
data?: T;
|
|
122
|
-
message: string;
|
|
123
|
-
statusCode: number;
|
|
124
|
-
success: boolean;
|
|
125
|
-
};`;
|
|
126
|
-
|
|
127
|
-
//#endregion
|
|
128
|
-
//#region src/installers/expressjs/dependencies.ts
|
|
129
|
-
async function installDependencies$1(projectName, dependencies) {
|
|
130
|
-
await execa("npm", ["install", ...dependencies], {
|
|
131
|
-
cwd: projectName,
|
|
132
|
-
stdio: "inherit"
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
//#endregion
|
|
137
|
-
//#region src/installers/expressjs/devDependencies.ts
|
|
138
|
-
async function installDevDependencies$1(projectName, devDependencies) {
|
|
139
|
-
await execa("npm", [
|
|
140
|
-
"install",
|
|
141
|
-
"-D",
|
|
142
|
-
...devDependencies
|
|
143
|
-
], {
|
|
144
|
-
cwd: projectName,
|
|
145
|
-
stdio: "inherit"
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
//#endregion
|
|
150
|
-
//#region src/installers/nestjs.ts
|
|
151
|
-
async function createNestApp(projectName) {
|
|
152
|
-
await execa("npx", [
|
|
153
|
-
"@nestjs/cli",
|
|
154
|
-
"new",
|
|
155
|
-
projectName
|
|
156
|
-
], { stdio: "inherit" });
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
//#endregion
|
|
160
|
-
//#region src/installers/react.ts
|
|
161
|
-
async function createReactApp(projectName) {
|
|
162
|
-
await execa("npm", [
|
|
163
|
-
"create",
|
|
164
|
-
"vite@latest",
|
|
165
|
-
projectName,
|
|
166
|
-
"--",
|
|
167
|
-
"--template",
|
|
168
|
-
"react"
|
|
169
|
-
], { stdio: "inherit" });
|
|
170
|
-
}
|
|
171
|
-
|
|
172
44
|
//#endregion
|
|
173
45
|
//#region src/configs/husky_lint-staged.ts
|
|
174
46
|
async function setupHuskyLintStaged(projectName) {
|
|
@@ -323,7 +195,7 @@ async function setupDrizzle(projectName) {
|
|
|
323
195
|
fs.ensureDir(migrationsDir),
|
|
324
196
|
fs.ensureFile(drizzleConfigPath)
|
|
325
197
|
]);
|
|
326
|
-
await fs.writeFile(drizzleConfigPath, drizzleConfigTemplate$
|
|
198
|
+
await fs.writeFile(drizzleConfigPath, drizzleConfigTemplate$2);
|
|
327
199
|
const packageJsonPath = path.join(projectName, "package.json");
|
|
328
200
|
const packageJson = await fs.readJson(packageJsonPath);
|
|
329
201
|
packageJson.scripts["db:generate"] = "npx drizzle-kit generate --config=./src/backend/db/drizzle.config.ts";
|
|
@@ -333,7 +205,7 @@ async function setupDrizzle(projectName) {
|
|
|
333
205
|
packageJson.scripts["db:check"] = "npx drizzle-kit check --config=./src/backend/db/drizzle.config.ts";
|
|
334
206
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
335
207
|
}
|
|
336
|
-
const drizzleConfigTemplate$
|
|
208
|
+
const drizzleConfigTemplate$2 = `import "server-only";
|
|
337
209
|
import { defineConfig } from "drizzle-kit";
|
|
338
210
|
import { serverEnv } from "../env.server";
|
|
339
211
|
|
|
@@ -504,7 +376,7 @@ export const env = parsed.data;
|
|
|
504
376
|
|
|
505
377
|
//#endregion
|
|
506
378
|
//#region src/configs/expressjs/supabase_client.ts
|
|
507
|
-
async function configSupabaseClient(projectName) {
|
|
379
|
+
async function configSupabaseClient$1(projectName) {
|
|
508
380
|
const supabaseDir = path.join(projectName, "src", "db", "supabase");
|
|
509
381
|
await fs.ensureDir(supabaseDir);
|
|
510
382
|
const supabaseClientPath = path.join(supabaseDir, "client.ts");
|
|
@@ -536,7 +408,7 @@ export default supabaseAdmin;
|
|
|
536
408
|
|
|
537
409
|
//#endregion
|
|
538
410
|
//#region src/configs/expressjs/supabase_local.ts
|
|
539
|
-
async function configSupabaseLocal(projectDir) {
|
|
411
|
+
async function configSupabaseLocal$1(projectDir) {
|
|
540
412
|
execa("npx", ["supabase", "init"], {
|
|
541
413
|
cwd: projectDir,
|
|
542
414
|
stdio: "inherit"
|
|
@@ -551,7 +423,7 @@ async function configSupabaseLocal(projectDir) {
|
|
|
551
423
|
|
|
552
424
|
//#endregion
|
|
553
425
|
//#region src/configs/expressjs/drizzle.ts
|
|
554
|
-
async function configDrizzle(projectName) {
|
|
426
|
+
async function configDrizzle$1(projectName) {
|
|
555
427
|
const schemasDir = path.join(projectName, "src", "db", "schemas");
|
|
556
428
|
const migrationsDir = path.join(projectName, "src", "db", "migrations");
|
|
557
429
|
const drizzleConfigPath = path.join(projectName, "drizzle.config.ts");
|
|
@@ -560,7 +432,7 @@ async function configDrizzle(projectName) {
|
|
|
560
432
|
fs.ensureDir(migrationsDir),
|
|
561
433
|
fs.ensureFile(drizzleConfigPath)
|
|
562
434
|
]);
|
|
563
|
-
await fs.writeFile(drizzleConfigPath, drizzleConfigTemplate);
|
|
435
|
+
await fs.writeFile(drizzleConfigPath, drizzleConfigTemplate$1);
|
|
564
436
|
const packageJsonPath = path.join(projectName, "package.json");
|
|
565
437
|
const packageJson = await fs.readJson(packageJsonPath);
|
|
566
438
|
packageJson.scripts["db:generate"] = "npx drizzle-kit generate --config=./drizzle.config.ts";
|
|
@@ -570,7 +442,7 @@ async function configDrizzle(projectName) {
|
|
|
570
442
|
packageJson.scripts["db:check"] = "npx drizzle-kit check --config=./drizzle.config.ts";
|
|
571
443
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
572
444
|
}
|
|
573
|
-
const drizzleConfigTemplate = `import { defineConfig } from "drizzle-kit";
|
|
445
|
+
const drizzleConfigTemplate$1 = `import { defineConfig } from "drizzle-kit";
|
|
574
446
|
import { env } from "./src/env";
|
|
575
447
|
|
|
576
448
|
export default defineConfig({
|
|
@@ -587,7 +459,7 @@ export default defineConfig({
|
|
|
587
459
|
|
|
588
460
|
//#endregion
|
|
589
461
|
//#region src/configs/expressjs/biome.ts
|
|
590
|
-
async function configBiome(projectName) {
|
|
462
|
+
async function configBiome$1(projectName) {
|
|
591
463
|
execa("npx", ["biome", "init"], {
|
|
592
464
|
cwd: projectName,
|
|
593
465
|
stdio: "inherit"
|
|
@@ -673,6 +545,111 @@ async function configNodemon(projectName) {
|
|
|
673
545
|
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
674
546
|
}
|
|
675
547
|
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/installers/expressjs/expressjs.ts
|
|
550
|
+
async function createExpressApp(projectName) {
|
|
551
|
+
await fs.ensureDir(projectName);
|
|
552
|
+
await execa("npm", ["init", "-y"], {
|
|
553
|
+
cwd: projectName,
|
|
554
|
+
stdio: "inherit"
|
|
555
|
+
});
|
|
556
|
+
const dtosDir = path.join(projectName, "src", "dtos");
|
|
557
|
+
const handlersDir = path.join(projectName, "src", "handlers");
|
|
558
|
+
const repositoriesDir = path.join(projectName, "src", "repositories");
|
|
559
|
+
const servicesDir = path.join(projectName, "src", "services");
|
|
560
|
+
const routesDir = path.join(projectName, "src", "routes");
|
|
561
|
+
const middlewareDir = path.join(projectName, "src", "middleware");
|
|
562
|
+
await Promise.all([
|
|
563
|
+
fs.ensureDir(dtosDir),
|
|
564
|
+
fs.ensureDir(handlersDir),
|
|
565
|
+
fs.ensureDir(repositoriesDir),
|
|
566
|
+
fs.ensureDir(servicesDir),
|
|
567
|
+
fs.ensureDir(routesDir),
|
|
568
|
+
fs.ensureDir(middlewareDir)
|
|
569
|
+
]);
|
|
570
|
+
const idParamDtoPath = path.join(dtosDir, "idParam.dto.ts");
|
|
571
|
+
const paginationDtoPath = path.join(dtosDir, "pagination.dto.ts");
|
|
572
|
+
const responseDtoPath = path.join(dtosDir, "response.dto.ts");
|
|
573
|
+
await Promise.all([
|
|
574
|
+
fs.ensureFile(idParamDtoPath),
|
|
575
|
+
fs.ensureFile(paginationDtoPath),
|
|
576
|
+
fs.ensureFile(responseDtoPath)
|
|
577
|
+
]);
|
|
578
|
+
await Promise.all([
|
|
579
|
+
fs.writeFile(idParamDtoPath, idParamDtoTemplate),
|
|
580
|
+
fs.writeFile(paginationDtoPath, paginationDtoTemplate),
|
|
581
|
+
fs.writeFile(responseDtoPath, responseDtoTemplate)
|
|
582
|
+
]);
|
|
583
|
+
const appFilePath = path.join(projectName, "src", "app.ts");
|
|
584
|
+
const indexFilePath = path.join(projectName, "index.ts");
|
|
585
|
+
await Promise.all([fs.ensureFile(appFilePath), fs.ensureFile(indexFilePath)]);
|
|
586
|
+
await Promise.all([fs.writeFile(appFilePath, appTemplate), fs.writeFile(indexFilePath, indexTemplate)]);
|
|
587
|
+
}
|
|
588
|
+
const appTemplate = `import express from "express";
|
|
589
|
+
import helmet from "helmet";
|
|
590
|
+
import cors from "cors";
|
|
591
|
+
import cookieParser from "cookie-parser";
|
|
592
|
+
import "dotenv/config";
|
|
593
|
+
import swaggerUi from "swagger-ui-express";
|
|
594
|
+
import swaggerDocument from "./swagger.json";
|
|
595
|
+
import morgan from "morgan";
|
|
596
|
+
|
|
597
|
+
const app = express();
|
|
598
|
+
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // mabe AI will help to generate the json file
|
|
599
|
+
app.use(helmet());
|
|
600
|
+
app.use(cors());
|
|
601
|
+
app.use(express.json());
|
|
602
|
+
app.use(express.urlencoded({ extended: true }));
|
|
603
|
+
app.use(cookieParser());
|
|
604
|
+
app.use(morgan("dev"));
|
|
605
|
+
|
|
606
|
+
app.get("/health", (_req, res) => {
|
|
607
|
+
res.json({ status: "ok" });
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
export default app;`;
|
|
611
|
+
const indexTemplate = `import app from "./src/app";
|
|
612
|
+
|
|
613
|
+
const port = process.env.PORT || 8080;
|
|
614
|
+
app.listen(port, () => {
|
|
615
|
+
console.log(\`Server is running on port \${ port }\`);
|
|
616
|
+
});`;
|
|
617
|
+
const idParamDtoTemplate = `export type IdParam = {
|
|
618
|
+
id: string;
|
|
619
|
+
};`;
|
|
620
|
+
const paginationDtoTemplate = `export type Pagination = {
|
|
621
|
+
page: number;
|
|
622
|
+
limit: number;
|
|
623
|
+
};`;
|
|
624
|
+
const responseDtoTemplate = `export type Response<T> = {
|
|
625
|
+
data?: T;
|
|
626
|
+
message: string;
|
|
627
|
+
statusCode: number;
|
|
628
|
+
success: boolean;
|
|
629
|
+
};`;
|
|
630
|
+
|
|
631
|
+
//#endregion
|
|
632
|
+
//#region src/installers/expressjs/dependencies.ts
|
|
633
|
+
async function installDependencies$2(projectName, dependencies) {
|
|
634
|
+
await execa("npm", ["install", ...dependencies], {
|
|
635
|
+
cwd: projectName,
|
|
636
|
+
stdio: "inherit"
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
//#endregion
|
|
641
|
+
//#region src/installers/expressjs/devDependencies.ts
|
|
642
|
+
async function installDevDependencies$2(projectName, devDependencies) {
|
|
643
|
+
await execa("npm", [
|
|
644
|
+
"install",
|
|
645
|
+
"-D",
|
|
646
|
+
...devDependencies
|
|
647
|
+
], {
|
|
648
|
+
cwd: projectName,
|
|
649
|
+
stdio: "inherit"
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
|
|
676
653
|
//#endregion
|
|
677
654
|
//#region src/setup/expressjs.ts
|
|
678
655
|
async function setupExpressjs(projectName, dbProvider, dbTool, isNeverThrow) {
|
|
@@ -712,18 +689,275 @@ async function setupExpressjs(projectName, dbProvider, dbTool, isNeverThrow) {
|
|
|
712
689
|
devDependencies.push("drizzle-kit");
|
|
713
690
|
}
|
|
714
691
|
if (isNeverThrow) dependencies.push("neverthrow");
|
|
692
|
+
await installDependencies$2(projectName, dependencies);
|
|
693
|
+
await installDevDependencies$2(projectName, devDependencies);
|
|
694
|
+
await setupHuskyLintStaged(projectName);
|
|
695
|
+
await configEnv(projectName, dbProvider === DB_PROVIDERS.SUPABASE);
|
|
696
|
+
if (dbProvider === DB_PROVIDERS.DOCKER) await setupDockerPostgres(projectName);
|
|
697
|
+
if (dbProvider === DB_PROVIDERS.SUPABASE) await configSupabaseClient$1(projectName);
|
|
698
|
+
if (dbTool === DB_TOOLS.SUPABASE_JS_SDK) await configSupabaseLocal$1(projectName);
|
|
699
|
+
if (dbTool === DB_TOOLS.DRIZZLE_ORM) await configDrizzle$1(projectName);
|
|
700
|
+
await configBiome$1(projectName);
|
|
701
|
+
await configJest(projectName);
|
|
702
|
+
await configTypescript(projectName);
|
|
703
|
+
await configNodemon(projectName);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
//#endregion
|
|
707
|
+
//#region src/configs/nestjs/biome.ts
|
|
708
|
+
async function configBiome(projectName) {
|
|
709
|
+
const eslintConfigPath = path.join(projectName, "eslint.config.mjs");
|
|
710
|
+
const prettierConfigPath = path.join(projectName, ".prettierrc");
|
|
711
|
+
await Promise.all([
|
|
712
|
+
execa("npx", ["biome", "init"], {
|
|
713
|
+
cwd: projectName,
|
|
714
|
+
stdio: "inherit"
|
|
715
|
+
}),
|
|
716
|
+
execa("npm", [
|
|
717
|
+
"remove",
|
|
718
|
+
"@eslint/eslintrc",
|
|
719
|
+
"@eslint/js",
|
|
720
|
+
"eslint",
|
|
721
|
+
"eslint-config-prettier",
|
|
722
|
+
"eslint-plugin-prettier",
|
|
723
|
+
"typescript-eslint",
|
|
724
|
+
"prettier"
|
|
725
|
+
], {
|
|
726
|
+
cwd: projectName,
|
|
727
|
+
stdio: "inherit"
|
|
728
|
+
}),
|
|
729
|
+
fs.remove(eslintConfigPath),
|
|
730
|
+
fs.remove(prettierConfigPath)
|
|
731
|
+
]);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region src/configs/nestjs/drizzle.ts
|
|
736
|
+
async function configDrizzle(projectName) {
|
|
737
|
+
const schemasDir = path.join(projectName, "src", "drizzle", "schemas");
|
|
738
|
+
const migrationsDir = path.join(projectName, "src", "drizzle", "migrations");
|
|
739
|
+
const drizzleConfigPath = path.join(projectName, "drizzle.config.ts");
|
|
740
|
+
const drizzleModulePath = path.join(projectName, "src", "drizzle", "drizzle.module.ts");
|
|
741
|
+
await Promise.all([
|
|
742
|
+
fs.ensureDir(schemasDir),
|
|
743
|
+
fs.ensureDir(migrationsDir),
|
|
744
|
+
fs.ensureFile(drizzleConfigPath),
|
|
745
|
+
fs.ensureFile(drizzleModulePath)
|
|
746
|
+
]);
|
|
747
|
+
await fs.writeFile(drizzleConfigPath, drizzleConfigTemplate);
|
|
748
|
+
await fs.writeFile(drizzleModulePath, drizzleModuleTemplate);
|
|
749
|
+
const packageJsonPath = path.join(projectName, "package.json");
|
|
750
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
751
|
+
packageJson.scripts["db:generate"] = "npx drizzle-kit generate --config=./drizzle.config.ts";
|
|
752
|
+
packageJson.scripts["db:migrate"] = "npx drizzle-kit push --config=./drizzle.config.ts";
|
|
753
|
+
packageJson.scripts["db:studio"] = "npx drizzle-kit studio --verbose --config=./drizzle.config.ts";
|
|
754
|
+
packageJson.scripts["db:pull"] = "npx drizzle-kit pull --config=./drizzle.config.ts";
|
|
755
|
+
packageJson.scripts["db:check"] = "npx drizzle-kit check --config=./drizzle.config.ts";
|
|
756
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
757
|
+
}
|
|
758
|
+
const drizzleConfigTemplate = `import { defineConfig } from "drizzle-kit";
|
|
759
|
+
import { env } from "./src/env";
|
|
760
|
+
|
|
761
|
+
export default defineConfig({
|
|
762
|
+
dialect: "postgresql",
|
|
763
|
+
schema: "./src/db/schemas/*",
|
|
764
|
+
out: "./src/db/migrations",
|
|
765
|
+
dbCredentials: {
|
|
766
|
+
url: env.DATABASE_URL,
|
|
767
|
+
},
|
|
768
|
+
verbose: true,
|
|
769
|
+
strict: true,
|
|
770
|
+
});
|
|
771
|
+
`.trimStart();
|
|
772
|
+
const drizzleModuleTemplate = `import { Module } from '@nestjs/common';
|
|
773
|
+
import { ConfigService } from '@nestjs/config';
|
|
774
|
+
import postgres from 'postgres';
|
|
775
|
+
import { drizzle } from "drizzle-orm/postgres-js";
|
|
776
|
+
|
|
777
|
+
const DRIZZLE=Symbol("drizzle")
|
|
778
|
+
@Module({
|
|
779
|
+
providers:[
|
|
780
|
+
{
|
|
781
|
+
provide: DRIZZLE,
|
|
782
|
+
inject: [ConfigService],
|
|
783
|
+
useFactory: (configService: ConfigService) => {
|
|
784
|
+
const databaseUrl = configService.get<string>("DATABASE_URL");
|
|
785
|
+
if(!databaseUrl) {
|
|
786
|
+
throw new Error("DATABASE_URL is not set in the environment variables");
|
|
787
|
+
}
|
|
788
|
+
const client = postgres(databaseUrl);
|
|
789
|
+
return drizzle({client});
|
|
790
|
+
},
|
|
791
|
+
}
|
|
792
|
+
],
|
|
793
|
+
exports: [DRIZZLE],
|
|
794
|
+
})
|
|
795
|
+
export class DrizzleModule {
|
|
796
|
+
}
|
|
797
|
+
`.trimStart();
|
|
798
|
+
|
|
799
|
+
//#endregion
|
|
800
|
+
//#region src/configs/nestjs/supabase_client.ts
|
|
801
|
+
async function configSupabaseClient(projectName) {
|
|
802
|
+
const supabaseDir = path.join(projectName, "src", "supabase");
|
|
803
|
+
await fs.ensureDir(supabaseDir);
|
|
804
|
+
const supabaseModulePath = path.join(supabaseDir, "supabase.module.ts");
|
|
805
|
+
await fs.ensureFile(supabaseModulePath);
|
|
806
|
+
await fs.writeFile(supabaseModulePath, supabaseModuleTemplate);
|
|
807
|
+
}
|
|
808
|
+
const supabaseModuleTemplate = `import { Module, Scope } from '@nestjs/common';
|
|
809
|
+
import { ConfigService } from '@nestjs/config';
|
|
810
|
+
import { REQUEST } from '@nestjs/core';
|
|
811
|
+
import { createClient } from '@supabase/supabase-js';
|
|
812
|
+
import { Request } from 'express';
|
|
813
|
+
|
|
814
|
+
export const SUPABASE_CLIENT=Symbol("supabase-client")
|
|
815
|
+
export const SUPABASE_ADMIN=Symbol("supabase-admin")
|
|
816
|
+
@Module({
|
|
817
|
+
providers: [
|
|
818
|
+
{
|
|
819
|
+
provide: SUPABASE_CLIENT,
|
|
820
|
+
inject: [ConfigService,REQUEST],
|
|
821
|
+
scope: Scope.REQUEST,
|
|
822
|
+
useFactory: (configService: ConfigService, request: Request) => {
|
|
823
|
+
const supabaseUrl = configService.get<string>("SUPABASE_URL");
|
|
824
|
+
const supabaseAnonKey = configService.get<string>("SUPABASE_ANON_KEY");
|
|
825
|
+
if(!supabaseUrl || !supabaseAnonKey) {
|
|
826
|
+
throw new Error("SUPABASE_URL or SUPABASE_ANON_KEY is not set in the environment variables");
|
|
827
|
+
}
|
|
828
|
+
return createClient(supabaseUrl, supabaseAnonKey,{global:{headers:{
|
|
829
|
+
Authorization: request.headers.authorization as string,
|
|
830
|
+
}}});
|
|
831
|
+
},
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
provide: SUPABASE_ADMIN,
|
|
835
|
+
inject: [ConfigService],
|
|
836
|
+
useFactory: (configService: ConfigService) => {
|
|
837
|
+
const supabaseUrl = configService.get<string>("SUPABASE_URL");
|
|
838
|
+
const supabaseServiceRoleKey = configService.get<string>("SUPABASE_SERVICE_ROLE_KEY");
|
|
839
|
+
if(!supabaseUrl || !supabaseServiceRoleKey) {
|
|
840
|
+
throw new Error("SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY is not set in the environment variables");
|
|
841
|
+
}
|
|
842
|
+
return createClient(supabaseUrl, supabaseServiceRoleKey);
|
|
843
|
+
},
|
|
844
|
+
},
|
|
845
|
+
],
|
|
846
|
+
exports:[SUPABASE_CLIENT, SUPABASE_ADMIN]
|
|
847
|
+
})
|
|
848
|
+
export class SupabaseModule {}
|
|
849
|
+
`;
|
|
850
|
+
|
|
851
|
+
//#endregion
|
|
852
|
+
//#region src/configs/nestjs/supabase_local.ts
|
|
853
|
+
async function configSupabaseLocal(projectDir) {
|
|
854
|
+
execa("npx", ["supabase", "init"], {
|
|
855
|
+
cwd: projectDir,
|
|
856
|
+
stdio: "inherit"
|
|
857
|
+
});
|
|
858
|
+
const migrationsDir = path.join(projectDir, "supabase", "migrations");
|
|
859
|
+
const schemaDir = path.join(projectDir, "supabase", "schemas");
|
|
860
|
+
const dbDir = path.join(schemaDir, "db");
|
|
861
|
+
const storageDir = path.join(schemaDir, "storage");
|
|
862
|
+
await Promise.all([fs.ensureDir(migrationsDir), fs.ensureDir(schemaDir)]);
|
|
863
|
+
await Promise.all([fs.ensureDir(dbDir), fs.ensureDir(storageDir)]);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
//#endregion
|
|
867
|
+
//#region src/installers/nestjs/nestjs.ts
|
|
868
|
+
async function createNestApp(projectName) {
|
|
869
|
+
await execa("npx", [
|
|
870
|
+
"@nestjs/cli",
|
|
871
|
+
"new",
|
|
872
|
+
projectName,
|
|
873
|
+
"-p",
|
|
874
|
+
"npm"
|
|
875
|
+
], { stdio: "inherit" });
|
|
876
|
+
const mainPath = path.join(projectName, "src", "main.ts");
|
|
877
|
+
await fs.writeFile(mainPath, mainTemplate);
|
|
878
|
+
}
|
|
879
|
+
const mainTemplate = `import { NestFactory } from "@nestjs/core";
|
|
880
|
+
import { AppModule } from "./app.module";
|
|
881
|
+
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
882
|
+
import helmet from 'helmet';
|
|
883
|
+
import cookieParser from 'cookie-parser';
|
|
884
|
+
|
|
885
|
+
async function bootstrap() {
|
|
886
|
+
const app = await NestFactory.create(AppModule);
|
|
887
|
+
|
|
888
|
+
const config = new DocumentBuilder()
|
|
889
|
+
.setTitle('My Project API')
|
|
890
|
+
.setDescription('The my project API description')
|
|
891
|
+
.setVersion('1.0')
|
|
892
|
+
.addTag('my project')
|
|
893
|
+
.build();
|
|
894
|
+
|
|
895
|
+
const documentFactory = () => SwaggerModule.createDocument(app, config);
|
|
896
|
+
SwaggerModule.setup('api-docs', app, documentFactory);
|
|
897
|
+
|
|
898
|
+
app.enableCors();
|
|
899
|
+
app.use(helmet());
|
|
900
|
+
app.use(cookieParser());
|
|
901
|
+
|
|
902
|
+
await app.listen(process.env.PORT ?? 8080);
|
|
903
|
+
}
|
|
904
|
+
bootstrap();
|
|
905
|
+
`.trimStart();
|
|
906
|
+
|
|
907
|
+
//#endregion
|
|
908
|
+
//#region src/installers/nestjs/dependencies.ts
|
|
909
|
+
async function installDependencies$1(projectName, dependencies) {
|
|
910
|
+
await execa("npm", ["install", ...dependencies], {
|
|
911
|
+
cwd: projectName,
|
|
912
|
+
stdio: "inherit"
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
//#endregion
|
|
917
|
+
//#region src/installers/nestjs/devDependencies.ts
|
|
918
|
+
async function installDevDependencies$1(projectName, devDependencies) {
|
|
919
|
+
await execa("npm", [
|
|
920
|
+
"install",
|
|
921
|
+
"-D",
|
|
922
|
+
...devDependencies
|
|
923
|
+
], {
|
|
924
|
+
cwd: projectName,
|
|
925
|
+
stdio: "inherit"
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
//#endregion
|
|
930
|
+
//#region src/setup/nestjs.ts
|
|
931
|
+
async function setupNestjs(projectName, dbProvider, dbTool, isNeverThrow) {
|
|
932
|
+
await createNestApp(projectName);
|
|
933
|
+
const dependencies = [
|
|
934
|
+
"@nestjs/config",
|
|
935
|
+
"@nestjs/swagger",
|
|
936
|
+
"class-transformer",
|
|
937
|
+
"class-validator",
|
|
938
|
+
"cookie-parser",
|
|
939
|
+
"helmet"
|
|
940
|
+
];
|
|
941
|
+
const devDependencies = [
|
|
942
|
+
"@biomejs/biome",
|
|
943
|
+
"@types/cookie-parser",
|
|
944
|
+
"husky",
|
|
945
|
+
"lint-staged"
|
|
946
|
+
];
|
|
947
|
+
if (dbProvider === DB_PROVIDERS.SUPABASE) dependencies.push("@supabase/supabase-js");
|
|
948
|
+
if (dbTool === DB_TOOLS.DRIZZLE_ORM) {
|
|
949
|
+
dependencies.push("drizzle-orm", "postgres");
|
|
950
|
+
devDependencies.push("drizzle-kit");
|
|
951
|
+
}
|
|
952
|
+
if (isNeverThrow) dependencies.push("neverthrow");
|
|
715
953
|
await installDependencies$1(projectName, dependencies);
|
|
716
954
|
await installDevDependencies$1(projectName, devDependencies);
|
|
717
955
|
await setupHuskyLintStaged(projectName);
|
|
718
|
-
await configEnv(projectName, dbProvider === DB_PROVIDERS.SUPABASE);
|
|
719
956
|
if (dbProvider === DB_PROVIDERS.DOCKER) await setupDockerPostgres(projectName);
|
|
720
957
|
if (dbProvider === DB_PROVIDERS.SUPABASE) await configSupabaseClient(projectName);
|
|
721
958
|
if (dbTool === DB_TOOLS.SUPABASE_JS_SDK) await configSupabaseLocal(projectName);
|
|
722
959
|
if (dbTool === DB_TOOLS.DRIZZLE_ORM) await configDrizzle(projectName);
|
|
723
960
|
await configBiome(projectName);
|
|
724
|
-
await configJest(projectName);
|
|
725
|
-
await configTypescript(projectName);
|
|
726
|
-
await configNodemon(projectName);
|
|
727
961
|
}
|
|
728
962
|
|
|
729
963
|
//#endregion
|
|
@@ -801,6 +1035,28 @@ async function setupNextjs(projectName, dbProvider, dbTool, uiLibrary, isNeverTh
|
|
|
801
1035
|
await setupJest(projectName);
|
|
802
1036
|
}
|
|
803
1037
|
|
|
1038
|
+
//#endregion
|
|
1039
|
+
//#region src/installers/reactTSRouter/reactTSRouter.ts
|
|
1040
|
+
async function createReactTSRouterApp(projectName) {
|
|
1041
|
+
await execa("npx", [
|
|
1042
|
+
"create-tsrouter-app@latest",
|
|
1043
|
+
projectName,
|
|
1044
|
+
"--template",
|
|
1045
|
+
"file-router",
|
|
1046
|
+
"--tailwind",
|
|
1047
|
+
"--toolchain",
|
|
1048
|
+
"biome",
|
|
1049
|
+
"--add-ons",
|
|
1050
|
+
"shadcn,tanstack-query,compiler,form"
|
|
1051
|
+
], { stdio: "inherit" });
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
//#endregion
|
|
1055
|
+
//#region src/setup/reactTSRouter.ts
|
|
1056
|
+
async function setupReactTSRouter(projectName) {
|
|
1057
|
+
await createReactTSRouterApp(projectName);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
804
1060
|
//#endregion
|
|
805
1061
|
//#region src/create.ts
|
|
806
1062
|
async function createProject(answers) {
|
|
@@ -813,16 +1069,13 @@ async function createProject(answers) {
|
|
|
813
1069
|
await Promise.all([setupNextjs(projectName + "-fe", DB_PROVIDERS.NONE, DB_TOOLS.NONE, uiLibrary, isNeverThrow), setupExpressjs(projectName + "-be", dbProvider, dbTool, isNeverThrow)]);
|
|
814
1070
|
break;
|
|
815
1071
|
case FRAMEWORKS.NEXT_NEST:
|
|
816
|
-
await setupNextjs(projectName + "-fe", DB_PROVIDERS.NONE, DB_TOOLS.NONE, uiLibrary, isNeverThrow);
|
|
817
|
-
createNestApp(projectName + "-be");
|
|
1072
|
+
await Promise.all([setupNextjs(projectName + "-fe", DB_PROVIDERS.NONE, DB_TOOLS.NONE, uiLibrary, isNeverThrow), setupNestjs(projectName + "-be", dbProvider, dbTool, isNeverThrow)]);
|
|
818
1073
|
break;
|
|
819
1074
|
case FRAMEWORKS.REACT_EXPRESS:
|
|
820
|
-
|
|
821
|
-
createExpressApp(projectName + "-be");
|
|
1075
|
+
await Promise.all([setupReactTSRouter(projectName + "-fe"), setupExpressjs(projectName + "-be", dbProvider, dbTool, isNeverThrow)]);
|
|
822
1076
|
break;
|
|
823
1077
|
case FRAMEWORKS.REACT_NEST:
|
|
824
|
-
|
|
825
|
-
createNestApp(projectName + "-be");
|
|
1078
|
+
await Promise.all([setupReactTSRouter(projectName + "-fe"), setupNestjs(projectName + "-be", dbProvider, dbTool, isNeverThrow)]);
|
|
826
1079
|
break;
|
|
827
1080
|
}
|
|
828
1081
|
}
|
|
@@ -860,16 +1113,16 @@ async function ask() {
|
|
|
860
1113
|
name: "Next.js + Express",
|
|
861
1114
|
value: FRAMEWORKS.NEXT_EXPRESS
|
|
862
1115
|
},
|
|
863
|
-
{
|
|
864
|
-
name: "React.js + Express",
|
|
865
|
-
value: FRAMEWORKS.REACT_EXPRESS
|
|
866
|
-
},
|
|
867
1116
|
{
|
|
868
1117
|
name: "Next.js + NestJS",
|
|
869
1118
|
value: FRAMEWORKS.NEXT_NEST
|
|
870
1119
|
},
|
|
871
1120
|
{
|
|
872
|
-
name: "React.js +
|
|
1121
|
+
name: "React.js (tanstack router) + Express",
|
|
1122
|
+
value: FRAMEWORKS.REACT_EXPRESS
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
name: "React.js (tanstack router) + NestJS",
|
|
873
1126
|
value: FRAMEWORKS.REACT_NEST
|
|
874
1127
|
}
|
|
875
1128
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-init-mtv-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "CLI for create init app",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"create-init-app"
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
"prepublishOnly": "npm run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@types/fs-extra": "^11.0.4",
|
|
34
33
|
"chalk": "^5.6.2",
|
|
35
34
|
"commander": "^14.0.2",
|
|
36
35
|
"execa": "^9.6.1",
|
|
@@ -39,6 +38,7 @@
|
|
|
39
38
|
"ora": "^9.0.0"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
|
41
|
+
"@types/fs-extra": "^11.0.4",
|
|
42
42
|
"@types/node": "^25.0.3",
|
|
43
43
|
"tsdown": "^0.18.2",
|
|
44
44
|
"typescript": "^5.9.3"
|