create-arkos 2.0.0-next.16 → 2.0.0-next.17

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 (28) hide show
  1. package/README.md +182 -57
  2. package/dist/utils/project-config-inquirer.js +45 -44
  3. package/dist/utils/project-config-inquirer.js.map +1 -1
  4. package/dist/utils/template-compiler.js +3 -11
  5. package/dist/utils/template-compiler.js.map +1 -1
  6. package/package.json +8 -8
  7. package/templates/basic/.env.hbs +1 -5
  8. package/templates/basic/README.md.hbs +2 -4
  9. package/templates/basic/arkos.config.ts.hbs +5 -18
  10. package/templates/basic/jsconfig.json.hbs +2 -2
  11. package/templates/basic/package.json.hbs +8 -8
  12. package/templates/basic/prisma/schema/__tests__/user-role.prisma.hbs.test.ts +1 -1
  13. package/templates/basic/prisma/schema/__tests__/user.prisma.hbs.test.ts +2 -2
  14. package/templates/basic/prisma/schema/user.prisma.hbs +1 -1
  15. package/templates/basic/src/app.ts.hbs +4 -8
  16. package/templates/basic/src/modules/auth-permission/auth-permission.router.ts.hbs +1 -9
  17. package/templates/basic/src/modules/auth-permission/dtos/create-auth-permission.dto.ts.hbs +1 -5
  18. package/templates/basic/src/modules/auth-permission/dtos/update-auth-permission.dto.ts.hbs +6 -4
  19. package/templates/basic/src/modules/auth-role/auth-role.router.ts.hbs +1 -9
  20. package/templates/basic/src/modules/auth-role/dtos/create-auth-role.dto.ts.hbs +2 -7
  21. package/templates/basic/src/modules/auth-role/dtos/update-auth-role.dto.ts.hbs +1 -5
  22. package/templates/basic/src/modules/file-upload/file-upload.router.ts.hbs +2 -9
  23. package/templates/basic/src/modules/user/user.router.ts.hbs +1 -9
  24. package/templates/basic/src/router.ts.hbs +1 -4
  25. package/templates/basic/src/utils/validation/api-actions.ts.hbs +1 -1
  26. package/templates/basic/tsconfig.json.hbs +2 -2
  27. package/templates/basic/public/favicon.ico +0 -0
  28. package/templates/basic/src/server.ts.hbs +0 -8
package/README.md CHANGED
@@ -1,18 +1,18 @@
1
- ![Header Image](https://www.arkosjs.com/img/arkos-readme-header.webp?v=3)
1
+ ![Header Image](https://www.arkosjs.com/img/arkos-readme-header.webp?v=4)
2
2
 
3
3
  <div align="center">
4
4
 
5
- [![Socket Badge](https://badge.socket.dev/npm/package/create-arkos)](https://badge.socket.dev/npm/package/create-arkos)
6
- ![npm](https://img.shields.io/npm/v/create-arkos)
7
- ![npm](https://img.shields.io/npm/dt/create-arkos)
5
+ [![Socket Badge](https://badge.socket.dev/npm/package/arkos)](https://badge.socket.dev/npm/package/arkos)
6
+ ![npm](https://img.shields.io/npm/v/arkos)
7
+ ![npm](https://img.shields.io/npm/dt/arkos)
8
8
  ![GitHub](https://img.shields.io/github/license/uanela/arkos)
9
9
  ![GitHub Repo stars](https://img.shields.io/github/stars/uanela/arkos)
10
10
 
11
11
  </div>
12
12
 
13
13
  <div align="center">
14
- <h2>Scaffold Your Arkos Project in Seconds</h2>
15
- <p>The official CLI scaffolding tool for Arkos.js</p>
14
+ <h2>The Express & Prisma RESTful Framework</h2>
15
+ <p>A tool for backend developers and teams who ship software with complex business logic under tight deadlines</p>
16
16
  </div>
17
17
 
18
18
  <div align="center">
@@ -23,91 +23,192 @@
23
23
  **[Tutorial](https://arkosjs.com/learn)** •
24
24
  **[GitHub](https://github.com/uanela/arkos)** •
25
25
  **[Blog](https://www.arkosjs.com/blog)** •
26
- **[Npm](https://www.npmjs.com/package/create-arkos)**
26
+ **[Npm](https://www.npmjs.com/package/arkos)**
27
27
 
28
28
  </div>
29
29
 
30
30
  ## Quick Start
31
31
 
32
32
  ```bash
33
- pnpm create arkos@latest my-project
33
+ npm create arkos@latest my-project
34
34
  ```
35
35
 
36
- Follow the interactive prompts. Your project comes with JWT auth, customizable CRUD routes, Swagger docs at `/api/docs`, file uploads, validation, and a full security middleware stack. Understand the generated [Project Structure](https://www.arkosjs.com/docs/getting-started/project-structure).
36
+ Your new project already has JWT auth, customizable CRUD routes, Swagger docs at `/api/docs`, file uploads, validation, and a full security middleware stack. Understand the generated [Project Structure](https://www.arkosjs.com/docs/getting-started/project-structure).
37
37
 
38
- ## Interactive Setup
38
+ ## Your Entry Point
39
39
 
40
- ```bash
41
- ? What is the name of your project? my-project
42
- ? Would you like to use TypeScript? Yes
43
- ? What db provider will be used for Prisma? postgresql
44
- ? Which Validation library would you like to use? zod
45
- ? Which Authentication mode would you like to use? static
46
- ? Enter the Prisma field name to use as the login username: email
47
- ? Would you like to use Strict Routing? No
40
+ ```typescript
41
+ // src/app.ts
42
+ import arkos from "arkos";
43
+ import postRouter from "@/src/modules/post/post.router"; // custom router
44
+
45
+ const app = arkos();
46
+
47
+ app.use(postRouter);
48
+
49
+ app.listen();
48
50
  ```
49
51
 
50
- ## From Zero to Running API
52
+ Arkos replaces the Express `app` — but it _is_ Express under the hood. You can still use `app.use()`, custom middleware, and raw Express code wherever you need it.
51
53
 
52
- ```bash
53
- # 1. Create your project
54
- pnpm create arkos@latest my-project
54
+ ## Automatic CRUD: One Model, Full REST Endpoints
55
+
56
+ **Define The Prisma model:**
57
+
58
+ ```prisma
59
+ model Post {
60
+ id String @id @default(uuid())
61
+ title String
62
+ content String
63
+ authorId String
64
+ author User @relation(fields: [authorId], references: [id])
65
+ createdAt DateTime @default(now())
66
+ updatedAt DateTime @updatedAt
67
+ }
68
+ ```
69
+
70
+ **Get a full REST API — instantly:**
71
+
72
+ ```
73
+ POST /api/posts Create a post
74
+ GET /api/posts List all posts
75
+ GET /api/posts/:id Get a post
76
+ PATCH /api/posts/:id Update a post
77
+ DELETE /api/posts/:id Delete a post
78
+ ```
79
+
80
+ Authenticated, validated, and documented. Zero boilerplate.
81
+
82
+ ## Creating a Router Beyond Express
55
83
 
56
- # 2. Navigate to it
57
- cd my-project
84
+ ```typescript
85
+ // src/modules/post/post.router.ts
86
+ import { ArkosRouter } from "arkos";
87
+ import CreatePostSchema from "@/src/modules/post/schemas/create-post.schema";
88
+ import postService from "@/src/modules/post/post.service";
89
+ import postPolicy from "@/src/modules/post/post.policy"; // Authorization component
58
90
 
59
- # 3. Configure your database
60
- # Edit .env with your DATABASE_URL
91
+ const postRouter = ArkosRouter({ prefix: "/api/posts" });
61
92
 
62
- # 4. Push the schema
63
- npx prisma db push
93
+ postRouter.post(
94
+ {
95
+ path: "/", // auto registered into openapi
96
+ authentication: postPolicy.Create, // Authentication and authorization with RBAC
97
+ validation: { body: CreatePostSchema }, // auto documented into openapi requestBody
98
+ },
99
+ async (req, res) => {
100
+ const post = await postService.createOne(req.body); // no error handling need, arkos already handles it
101
+ res.json({ data: post });
102
+ }
103
+ );
64
104
 
65
- # 5. Start building
66
- npm run dev
105
+ export default postRouter;
67
106
  ```
68
107
 
69
- Your API is now running at `http://localhost:8000` OpenAPI at `/api/docs`.
108
+ See more about the enhanced express-based router (ArkosRouter) at [ArkosRouter Guide](https://www.arkosjs.com/docs/core-concepts/components/routers).
70
109
 
71
- ## Configuration Options
110
+ ## Define Permissions Once, Guard Everywhere
72
111
 
73
- **Database providers:** PostgreSQL · MongoDB · MySQL · SQLite · SQL Server · CockroachDB
112
+ ```typescript
113
+ // src/modules/post/post.policy.ts
114
+ import { ArkosPolicy } from "arkos";
74
115
 
75
- **Validation:** Zod · class-validator
116
+ const postPolicy: ArkosPolicy<"post"> = ArkosPolicy("post");
117
+
118
+ postPolicy.rule("Create", ["Writer", "Admin"]);
119
+ postPolicy.rule("View", ["Writer", "Admin", "User"]);
120
+
121
+ export default postPolicy;
122
+ ```
76
123
 
77
- **Authentication types:**
124
+ Define who can do what, once, per resource. Arkos enforces it across every route that references the policy — no scattered middleware, no repeated role checks.
78
125
 
79
- - **Static** file-based, roles defined in code via `ArkosPolicy`
80
- - **Dynamic** — database-level, roles and permissions stored in tables
81
- - **None** — skip for now, add when ready
126
+ **Customize CRUD Routes just like normal router:**
82
127
 
83
- ## Generated Project Structure
128
+ ```typescript
129
+ // src/modules/post/post.router.ts
130
+ import { ArkosRouter, RouteHook } from "arkos";
131
+ import postPolicy from "@/src/modules/post/post.policy";
132
+ import UpdatePostSchema from "@/src/modules/post/post.schema";
84
133
 
134
+ export const hook: RouteHook<"prisma"> = {
135
+ findMany: { authentication: false }, // Making GET /api/posts public
136
+ createOne: { authentication: postPolicy.Create },
137
+ updateOne: {
138
+ authentication: postPolicy.Update,
139
+ validation: { body: UpdatePostSchema },
140
+ },
141
+ deleteOne: { authentication: postPolicy.Delete },
142
+ };
143
+
144
+ const postRouter = ArkosRouter({ prefix: "/api/posts" });
145
+
146
+ export default postRouter;
85
147
  ```
86
- my-project/
87
- ├── prisma/
88
- │ └── schema.prisma
89
- ├── src/
90
- │ ├── modules
91
- │ ├── utils/
92
- │ │ └── prisma/
93
- │ │ └── index.ts
94
- │ └── app.ts
95
- ├── .env
96
- ├── arkos.config.ts
97
- ├── package.json
98
- └── tsconfig.json
148
+
149
+ Your auto-generated CRUD routes accept the same config as any ArkosRouter route — authentication, validation, rate limiting, all in one place.
150
+
151
+ **Add business logic exactly where you need it:**
152
+
153
+ ```typescript
154
+ // src/modules/post/post.interceptor.ts
155
+ import { ArkosRequest, ArkosResponse, ArkosNextFunction } from "arkos";
156
+ import { BadRequestError } from "arkos/error-handler";
157
+
158
+ export const beforeCreateOne = [
159
+ async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {
160
+ if (req.body.title.length < 5)
161
+ throw new BadRequestError("Title is too short", "TitleTooShort");
162
+
163
+ req.body.slug = req.body.title.toLowerCase().replace(/\s/g, "-");
164
+ req.body.authorId = req.user.id;
165
+ next();
166
+ },
167
+ ];
99
168
  ```
100
169
 
170
+ Name the file, export the hook, and Arkos picks it up automatically. No registration needed.
171
+
172
+ ## What You Stop Building From Scratch
173
+
174
+ | What you'd normally write | What Arkos gives you |
175
+ | ---------------------------------------- | --------------------------------- |
176
+ | JWT setup, refresh tokens, bcrypt | ✅ Built-in auth system |
177
+ | 5 route handlers per Prisma model | ✅ Auto-generated CRUD |
178
+ | Zod/CV schemas per endpoint | ✅ Auto generate from your models |
179
+ | Swagger config + schema upkeep | ✅ Auto-generated OpenAPI docs |
180
+ | Multer setup + file type validation | ✅ File upload system |
181
+ | Rate limiting, CORS, Helmet, compression | ✅ Pre-configured security stack |
182
+ | **Total setup time** | **~5 minutes vs ~8–12 hours** |
183
+
184
+ ## Documentation
185
+
186
+ For comprehensive guides, API reference, and examples, visit our [official documentation](https://arkosjs.com/docs).
187
+
188
+ **Quick Links:**
189
+
190
+ - [Getting Started Guide](https://arkosjs.com/docs)
191
+ - [Authentication Setup](https://arkosjs.com/docs/core-concepts/authentication/setup)
192
+ - [Using Interceptors](https://arkosjs.com/docs/core-concepts/components/interceptors)
193
+ - [File Uploads](https://arkosjs.com/docs/guides/file-handling/file-uploads/setup)
194
+ - [Validation](https://arkosjs.com/docs/guides/validation/setup)
195
+ - [Email Service](https://arkosjs.com/docs/guides/email-service)
196
+
101
197
  ## Getting Nightly Updates
102
198
 
199
+ You can get the latest features we're testing before releasing them:
200
+
103
201
  ```bash
104
202
  pnpm create arkos@next my-project
105
203
  ```
106
204
 
107
- ## Requirements
205
+ ## Built With
206
+
207
+ Arkos.js is built on top of industry-leading tools:
108
208
 
109
- - Node.js 20 or higher
110
- - npm, yarn, or pnpm
209
+ - **[Express](https://expressjs.com/)** - Fast, unopinionated, minimalist web framework for Node.js
210
+ - **[Prisma](https://www.prisma.io/)** - Next-generation ORM for Node.js and TypeScript
211
+ - **[Node.js](https://nodejs.org/)** - JavaScript runtime built on Chrome's V8 engine
111
212
 
112
213
  ## Support & Contributing
113
214
 
@@ -118,6 +219,30 @@ pnpm create arkos@next my-project
118
219
 
119
220
  Contributions are welcome! We appreciate all contributions, from bug fixes to new features.
120
221
 
222
+ ## What Developers Say
223
+
224
+ > "Arkos.js changed how I work on the backend: with a Prisma model I already get CRUD routes, auth, and validation out-of-the-box — I saved a lot of time and could focus on business logic."
225
+ >
226
+ > **— Gelson Matavela, Founder / Grupo Vergui**
227
+
228
+ > "It removes boilerplate and provides a clean structure to build products. Built-in auth is powerful and ready. Automatic CRUD and docs save time, while interceptors allow flexible business logic."
229
+ >
230
+ > **— Augusto Domingos, Tech Lead / DSAI For Moz**
231
+
232
+ > "With Arkos.js, I can build backends in just a few minutes. It removes the boilerplate and lets me focus entirely on the core logic. Fast, simple, and incredibly productive."
233
+ >
234
+ > **— Niuro Langa, Software Developer / SparkTech**
235
+
236
+ [See more testimonials →](https://arkosjs.com)
237
+
238
+ ## Philosophy
239
+
240
+ Arkos sits between minimal frameworks like Express/Fastify and opinionated ones like NestJS/AdonisJS. It doesn't ask you to learn a new paradigm — it enhances the one most Node.js developers already use, by automating everything that's standardized and staying out of the way everywhere else.
241
+
242
+ Inspired by how Django and Laravel work in their ecosystems: batteries included, nothing forced on you.
243
+
244
+ > The name "Arkos" comes from the Greek word **ἀρχή** _(Arkhē)_, meaning "beginning" or "foundation".
245
+
121
246
  ## License
122
247
 
123
248
  This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -130,11 +255,11 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
130
255
  **[Tutorial](https://arkosjs.com/learn)** •
131
256
  **[GitHub](https://github.com/uanela/arkos)** •
132
257
  **[Blog](https://www.arkosjs.com/blog)** •
133
- **[Npm](https://www.npmjs.com/package/create-arkos)**
258
+ **[Npm](https://www.npmjs.com/package/arkos)**
134
259
 
135
260
  Built with ❤️ by [Uanela Como](https://github.com/uanela) and contributors
136
261
 
137
262
  _The name "Arkos" comes from the Greek word "ἀρχή" (Arkhē), meaning "beginning" or "foundation", reflecting our goal of providing a solid foundation for backend development._
138
263
 
139
264
  </div>
140
- ```
265
+
@@ -1,10 +1,13 @@
1
1
  import path from "path";
2
2
  import inquirer from "inquirer";
3
3
  import chalk from "chalk";
4
+ import { detectPackageManagerFromUserAgent } from "./helpers/npm.helpers.js";
4
5
  class ProjectConfigInquirer {
5
6
  config;
6
7
  constructor() {
7
- this.config = {};
8
+ this.config = {
9
+ packageManager: detectPackageManagerFromUserAgent(),
10
+ };
8
11
  }
9
12
  async run() {
10
13
  await this.promptProjectName();
@@ -13,7 +16,6 @@ class ProjectConfigInquirer {
13
16
  await this.promptValidation();
14
17
  await this.promptAuthentication();
15
18
  await this.promptStrictRouting();
16
- await this.promptEntryPoint();
17
19
  if (this.config.projectName === ".") {
18
20
  this.config.projectName = path.basename(process.cwd());
19
21
  this.config.projectPath = path.resolve(process.cwd());
@@ -22,9 +24,6 @@ class ProjectConfigInquirer {
22
24
  this.config.projectPath = path.resolve(process.cwd(), this.config.projectName);
23
25
  if (process?.argv?.includes?.("--advanced"))
24
26
  this.config.advanced = true;
25
- if (this.config.prisma.defaultDatabaseUrl)
26
- this.config.prisma.defaultDatabaseUrl =
27
- this.config.prisma.defaultDatabaseUrl.replaceAll("{{projectName}}", this.config.projectName);
28
27
  return this.config;
29
28
  }
30
29
  async promptProjectName() {
@@ -81,7 +80,7 @@ class ProjectConfigInquirer {
81
80
  type: "confirm",
82
81
  name: "typescript",
83
82
  message: `Would you like to use ${chalk.cyan("TypeScript")}?`,
84
- default: true,
83
+ default: false,
85
84
  },
86
85
  ]);
87
86
  this.config.typescript = typescript;
@@ -99,69 +98,82 @@ class ProjectConfigInquirer {
99
98
  "sqlite",
100
99
  "sqlserver",
101
100
  "cockroachdb",
102
- "none",
103
101
  ],
104
102
  },
105
103
  ]);
106
104
  let idDatabaseType;
107
- let defaultDatabaseUrl;
105
+ let defaultDBurl;
108
106
  switch (prismaProvider) {
109
107
  case "mongodb":
110
108
  idDatabaseType = '@id @default(auto()) @map("_id") @db.ObjectId';
111
- defaultDatabaseUrl = `mongodb://localhost:27017/{{projectName}}`;
109
+ defaultDBurl = `mongodb://localhost:27017/${this.config.projectName}`;
112
110
  break;
113
111
  case "sqlite":
114
112
  idDatabaseType = "@id @default(cuid())";
115
- defaultDatabaseUrl = "file:../../file.db";
113
+ defaultDBurl = "file:../../file.db";
116
114
  break;
117
115
  case "mysql":
118
116
  idDatabaseType = "@id @default(uuid())";
119
- defaultDatabaseUrl = `mysql://username:password@localhost:3306/{{projectName}}`;
117
+ defaultDBurl = `mysql://username:password@localhost:3306/${this.config.projectName}`;
120
118
  break;
121
119
  case "postgresql":
122
120
  idDatabaseType = "@id @default(uuid())";
123
- defaultDatabaseUrl = `postgresql://username:password@localhost:5432/{{projectName}}`;
121
+ defaultDBurl = `postgresql://username:password@localhost:5432/${this.config.projectName}`;
124
122
  break;
125
123
  case "sqlserver":
126
124
  idDatabaseType = "@id @default(uuid())";
127
- defaultDatabaseUrl = `sqlserver://localhost:1433;database={{projectName}};username=sa;password=password;encrypt=DANGER_PLAINTEXT`;
125
+ defaultDBurl = `sqlserver://localhost:1433;database=${this.config.projectName};username=sa;password=password;encrypt=DANGER_PLAINTEXT`;
128
126
  break;
129
127
  case "cockroachdb":
130
128
  idDatabaseType = "@id @default(uuid())";
131
- defaultDatabaseUrl = `postgresql://username:password@localhost:26257/{{projectName}}?sslmode=require`;
129
+ defaultDBurl = `postgresql://username:password@localhost:26257/${this.config.projectName}?sslmode=require`;
132
130
  break;
133
131
  default:
134
132
  idDatabaseType = "@id @default(uuid())";
135
- defaultDatabaseUrl = `postgresql://username:password@localhost:5432/{{projectName}}`;
133
+ defaultDBurl = `postgresql://username:password@localhost:5432/${this.config.projectName}`;
136
134
  }
137
135
  this.config.prisma = {
138
136
  provider: prismaProvider,
139
- idDatabaseType,
140
- defaultDatabaseUrl,
137
+ idDatabaseType: idDatabaseType,
138
+ defaultDBurl: defaultDBurl,
141
139
  };
142
140
  }
143
141
  async promptValidation() {
144
- const choices = this.config.typescript
145
- ? ["zod", "class-validator", "none"]
146
- : ["zod", "none"];
147
- const { validationType } = await inquirer.prompt([
142
+ const { useValidation } = await inquirer.prompt([
148
143
  {
149
- type: "list",
150
- name: "validationType",
151
- message: `Which ${chalk.cyan("Validation")} library would you like to use?`,
152
- choices,
153
- default: "zod",
144
+ type: "confirm",
145
+ name: "useValidation",
146
+ message: `Would you like to set up ${chalk.cyan("Validation")}?`,
147
+ default: true,
154
148
  },
155
149
  ]);
156
- if (validationType !== "none") {
150
+ if (useValidation) {
151
+ let validationTypeResponse = { validationType: "zod" };
152
+ if (this.config.typescript)
153
+ validationTypeResponse = await inquirer.prompt([
154
+ {
155
+ type: "list",
156
+ name: "validationType",
157
+ message: "Choose validation library:",
158
+ choices: ["zod", "class-validator"],
159
+ },
160
+ ]);
161
+ else {
162
+ console.info(chalk.bold(`${chalk.greenBright("?")} Validation library set to zod (class-validator is not supported on JavaScript):`), chalk.cyan("zod"));
163
+ }
157
164
  this.config.validation = {
158
- type: validationType,
165
+ type: validationTypeResponse.validationType,
159
166
  };
160
167
  }
168
+ else if (!this.config.typescript) {
169
+ }
161
170
  }
162
171
  async promptAuthentication() {
163
172
  if (this.config.prisma.provider === "none") {
164
- console.info(`Skipping authentication setup as it requires prisma.`);
173
+ console.info(`${chalk.green("! ")}${chalk.bold("Skipping authentication setup as it requires prisma.")}`);
174
+ this.config.authentication = {
175
+ type: "none",
176
+ };
165
177
  return;
166
178
  }
167
179
  const { authenticationType } = await inquirer.prompt([
@@ -197,8 +209,9 @@ class ProjectConfigInquirer {
197
209
  usernameField,
198
210
  multipleRoles: false,
199
211
  };
200
- if (authenticationType !== "static" &&
201
- this.config.prisma.provider !== "sqlite") {
212
+ if (authenticationType !== "static" ||
213
+ (authenticationType == "static" &&
214
+ this.config.prisma.provider !== "sqlite")) {
202
215
  const { multipleRoles } = await inquirer.prompt([
203
216
  {
204
217
  type: "confirm",
@@ -213,6 +226,7 @@ class ProjectConfigInquirer {
213
226
  };
214
227
  }
215
228
  else if (this.config.prisma.provider === "sqlite") {
229
+ console.info(`${chalk.green("! ")}${chalk.bold("Skipping multiple roles option because it is not supported with sqlite prisma provider and static authentication mode.")}`);
216
230
  }
217
231
  }
218
232
  async promptStrictRouting() {
@@ -228,19 +242,6 @@ class ProjectConfigInquirer {
228
242
  strict: strictRouting,
229
243
  };
230
244
  }
231
- async promptEntryPoint() {
232
- const ext = this.config.typescript ? "ts" : "js";
233
- const { entryPoint } = await inquirer.prompt([
234
- {
235
- type: "list",
236
- name: "entryPoint",
237
- message: `Which ${chalk.cyan("Entry Point")} would you like to use?`,
238
- choices: [`src/app.${ext}`, `src/server.${ext}`],
239
- default: `src/app.${ext}`,
240
- },
241
- ]);
242
- this.config.entryPoint = entryPoint.replace(`.${ext}`, "");
243
- }
244
245
  }
245
246
  const projectConfigInquirer = new ProjectConfigInquirer();
246
247
  export default projectConfigInquirer;
@@ -1 +1 @@
1
- {"version":3,"file":"project-config-inquirer.js","sourceRoot":"","sources":["../../src/utils/project-config-inquirer.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"path\";\nimport inquirer from \"inquirer\";\nimport chalk from \"chalk\";\n\nexport interface ProjectConfig {\n projectName: string;\n argProjectName?: string;\n typescript: boolean;\n validation?: {\n type?: \"zod\" | \"class-validator\";\n };\n authentication?: {\n type?: \"static\" | \"dynamic\" | \"none\";\n usernameField?: string;\n multipleRoles: boolean;\n };\n prisma: {\n provider:\n | \"postgresql\"\n | \"mysql\"\n | \"sqlite\"\n | \"sqlserver\"\n | \"cockroachdb\"\n | \"mongodb\"\n | \"none\";\n idDatabaseType: string;\n defaultDatabaseUrl: string;\n };\n projectPath: string;\n routing?: {\n strict?: boolean;\n };\n advanced?: boolean;\n entryPoint: \"src/app\" | \"src/server\";\n}\n\nclass ProjectConfigInquirer {\n private config: ProjectConfig;\n\n constructor() {\n this.config = {} as ProjectConfig;\n }\n\n async run() {\n await this.promptProjectName();\n await this.promptTypescript();\n await this.promptPrismaProvider();\n await this.promptValidation();\n await this.promptAuthentication();\n await this.promptStrictRouting();\n await this.promptEntryPoint();\n\n if (this.config.projectName === \".\") {\n this.config.projectName = path.basename(process.cwd());\n this.config.projectPath = path.resolve(process.cwd());\n } else\n this.config.projectPath = path.resolve(\n process.cwd(),\n this.config.projectName\n );\n\n if (process?.argv?.includes?.(\"--advanced\")) this.config.advanced = true;\n if (this.config.prisma.defaultDatabaseUrl)\n this.config.prisma.defaultDatabaseUrl =\n this.config.prisma.defaultDatabaseUrl.replaceAll(\n \"{{projectName}}\",\n this.config.projectName\n );\n\n return this.config;\n }\n\n private async promptProjectName() {\n let projectName = process?.argv?.[2];\n this.config.argProjectName = process?.argv?.[2];\n\n if (!projectName) {\n const result = await inquirer.prompt([\n {\n type: \"input\",\n name: \"projectName\",\n message: \"What is the name of your project?\",\n default: \"my-arkos-project\",\n validate: this.validateProjectName,\n },\n ]);\n projectName = result.projectName;\n } else {\n const validation = this.validateProjectName(projectName);\n if (validation !== true) {\n console.error(chalk.red(`\\nError: ${validation}`));\n process.exit(1);\n }\n }\n\n this.config.projectName = projectName;\n }\n\n private validateProjectName(input: string): boolean | string {\n if (input === \".\") return true;\n\n if (!input || input.length === 0) {\n return \"Project name cannot be empty\";\n }\n\n if (!/^[a-zA-Z0-9_-]+$/.test(input)) {\n return \"Project name can only contain letters, numbers, hyphens, and underscores\";\n }\n\n if (!/^[a-zA-Z0-9]/.test(input)) {\n return \"Project name must start with a letter or number\";\n }\n\n if (!/[a-zA-Z0-9]$/.test(input)) {\n return \"Project name must end with a letter or number\";\n }\n\n if (input.length > 50) {\n return \"Project name must be 50 characters or less\";\n }\n\n const reservedNames = [\"node_modules\"];\n if (reservedNames.includes(input.toLowerCase())) {\n return \"Project name cannot be a reserved name\";\n }\n\n return true;\n }\n\n private async promptTypescript() {\n const { typescript } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"typescript\",\n message: `Would you like to use ${chalk.cyan(\"TypeScript\")}?`,\n default: true,\n },\n ]);\n this.config.typescript = typescript;\n }\n\n private async promptPrismaProvider() {\n const { prismaProvider } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"prismaProvider\",\n message: `What db provider will be used for ${chalk.cyan(\"Prisma\")}?`,\n choices: [\n \"postgresql\",\n \"mongodb\",\n \"mysql\",\n \"sqlite\",\n \"sqlserver\",\n \"cockroachdb\",\n \"none\",\n ],\n },\n ]);\n\n let idDatabaseType: string;\n let defaultDatabaseUrl: string;\n\n switch (prismaProvider) {\n case \"mongodb\":\n idDatabaseType = '@id @default(auto()) @map(\"_id\") @db.ObjectId';\n defaultDatabaseUrl = `mongodb://localhost:27017/{{projectName}}`;\n break;\n case \"sqlite\":\n idDatabaseType = \"@id @default(cuid())\";\n defaultDatabaseUrl = \"file:../../file.db\";\n break;\n case \"mysql\":\n idDatabaseType = \"@id @default(uuid())\";\n defaultDatabaseUrl = `mysql://username:password@localhost:3306/{{projectName}}`;\n break;\n case \"postgresql\":\n idDatabaseType = \"@id @default(uuid())\";\n defaultDatabaseUrl = `postgresql://username:password@localhost:5432/{{projectName}}`;\n break;\n case \"sqlserver\":\n idDatabaseType = \"@id @default(uuid())\";\n defaultDatabaseUrl = `sqlserver://localhost:1433;database={{projectName}};username=sa;password=password;encrypt=DANGER_PLAINTEXT`;\n break;\n case \"cockroachdb\":\n idDatabaseType = \"@id @default(uuid())\";\n defaultDatabaseUrl = `postgresql://username:password@localhost:26257/{{projectName}}?sslmode=require`;\n break;\n default:\n idDatabaseType = \"@id @default(uuid())\";\n defaultDatabaseUrl = `postgresql://username:password@localhost:5432/{{projectName}}`;\n }\n\n this.config.prisma = {\n provider: prismaProvider,\n idDatabaseType,\n defaultDatabaseUrl,\n };\n }\n\n private async promptValidation() {\n // For JS projects, class-validator is not supported — skip the choice\n const choices = this.config.typescript\n ? [\"zod\", \"class-validator\", \"none\"]\n : [\"zod\", \"none\"];\n\n const { validationType } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"validationType\",\n message: `Which ${chalk.cyan(\"Validation\")} library would you like to use?`,\n choices,\n default: \"zod\",\n },\n ]);\n\n if (validationType !== \"none\") {\n this.config.validation = {\n type: validationType as \"zod\" | \"class-validator\",\n };\n }\n // validation stays undefined when \"none\" is chosen — matches original behaviour\n }\n\n private async promptAuthentication() {\n if (this.config.prisma.provider === \"none\") {\n console.info(`Skipping authentication setup as it requires prisma.`);\n return;\n }\n\n const { authenticationType } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"authenticationType\",\n message: `Which ${chalk.cyan(\"Authentication\")} mode would you like to use?`,\n choices: [\"static\", \"dynamic\", \"none\"],\n default: \"static\",\n },\n ]);\n\n if (authenticationType === \"none\") {\n this.config.authentication = { type: \"none\", multipleRoles: false };\n return;\n }\n\n const { usernameField } = await inquirer.prompt([\n {\n type: \"input\",\n name: \"usernameField\",\n message: \"Enter the Prisma field name to use as the login username:\",\n default: \"email\",\n validate: (input: string) => {\n if (!input || input.length === 0) return \"Field name cannot be empty\";\n if (!/^[a-z][a-zA-Z0-9]*$/.test(input))\n return \"Must be a valid Prisma field name (camelCase, starts with lowercase, letters and numbers only)\";\n return true;\n },\n },\n ]);\n\n this.config.authentication = {\n type: authenticationType as \"static\" | \"dynamic\",\n usernameField,\n multipleRoles: false,\n };\n\n if (\n authenticationType !== \"static\" &&\n this.config.prisma.provider !== \"sqlite\"\n ) {\n const { multipleRoles } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"multipleRoles\",\n default: true,\n message: `Would you like to use authentication with ${chalk.cyan(\"Multiple Roles\")}?`,\n },\n ]);\n\n this.config.authentication = {\n ...this.config.authentication,\n multipleRoles,\n };\n } else if (this.config.prisma.provider === \"sqlite\") {\n // console.info(\n // `Skipping multiple roles option because it is not supported with sqlite prisma provider and static authentication mode.`\n // );\n }\n }\n\n private async promptStrictRouting() {\n const { strictRouting } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"strictRouting\",\n message: `Would you like to use ${chalk.cyan(\"Strict Routing\")}?`,\n default: false,\n },\n ]);\n this.config.routing = {\n strict: strictRouting,\n };\n }\n\n private async promptEntryPoint() {\n const ext = this.config.typescript ? \"ts\" : \"js\";\n const { entryPoint } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"entryPoint\",\n message: `Which ${chalk.cyan(\"Entry Point\")} would you like to use?`,\n choices: [`src/app.${ext}`, `src/server.${ext}`],\n default: `src/app.${ext}`,\n },\n ]);\n\n this.config.entryPoint = entryPoint.replace(`.${ext}`, \"\");\n }\n}\n\nconst projectConfigInquirer = new ProjectConfigInquirer();\n\nexport default projectConfigInquirer;\n"]}
1
+ {"version":3,"file":"project-config-inquirer.js","sourceRoot":"","sources":["../../src/utils/project-config-inquirer.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"path\";\nimport inquirer from \"inquirer\";\nimport chalk from \"chalk\";\nimport { detectPackageManagerFromUserAgent } from \"./helpers/npm.helpers\";\n\nexport interface ProjectConfig {\n projectName: string;\n argProjectName?: string;\n typescript: boolean;\n validation?: {\n type?: \"zod\" | \"class-validator\" | \"none\";\n };\n authentication?: {\n type?: \"static\" | \"dynamic\" | \"none\";\n usernameField?: \"username\" | \"email\" | \"custom\";\n multipleRoles?: boolean;\n };\n prisma: {\n provider:\n | \"postgresql\"\n | \"mysql\"\n | \"sqlite\"\n | \"sqlserver\"\n | \"cockroachdb\"\n | \"mongodb\"\n | \"none\";\n idDatabaseType: string;\n defaultDBurl: string;\n };\n projectPath: string;\n routing?: {\n strict?: boolean;\n };\n advanced?: boolean;\n entryPoint: \"src/app\" | \"src/server\";\n packageManager: string;\n}\n\nclass ProjectConfigInquirer {\n private config: ProjectConfig;\n\n constructor() {\n this.config = {\n packageManager: detectPackageManagerFromUserAgent(),\n } as ProjectConfig;\n }\n\n async run() {\n await this.promptProjectName();\n await this.promptTypescript();\n await this.promptPrismaProvider();\n await this.promptValidation();\n await this.promptAuthentication();\n await this.promptStrictRouting();\n\n if (this.config.projectName === \".\") {\n this.config.projectName = path.basename(process.cwd());\n this.config.projectPath = path.resolve(process.cwd());\n } else\n this.config.projectPath = path.resolve(\n process.cwd(),\n this.config.projectName\n );\n\n if (process?.argv?.includes?.(\"--advanced\")) this.config.advanced = true;\n\n return this.config;\n }\n\n private async promptProjectName() {\n let projectName = process?.argv?.[2];\n this.config.argProjectName = process?.argv?.[2];\n\n if (!projectName) {\n const result = await inquirer.prompt([\n {\n type: \"input\",\n name: \"projectName\",\n message: \"What is the name of your project?\",\n default: \"my-arkos-project\",\n validate: this.validateProjectName,\n },\n ]);\n projectName = result.projectName;\n } else {\n // Validate the project name from command line args\n const validation = this.validateProjectName(projectName);\n if (validation !== true) {\n console.error(chalk.red(`\\nError: ${validation}`));\n process.exit(1);\n }\n }\n\n this.config.projectName = projectName;\n }\n\n private validateProjectName(input: string): boolean | string {\n if (input === \".\") return true;\n\n if (!input || input.length === 0) {\n return \"Project name cannot be empty\";\n }\n\n if (!/^[a-zA-Z0-9_-]+$/.test(input)) {\n return \"Project name can only contain letters, numbers, hyphens, and underscores\";\n }\n\n if (!/^[a-zA-Z0-9]/.test(input)) {\n return \"Project name must start with a letter or number\";\n }\n\n if (!/[a-zA-Z0-9]$/.test(input)) {\n return \"Project name must end with a letter or number\";\n }\n\n if (input.length > 50) {\n return \"Project name must be 50 characters or less\";\n }\n\n const reservedNames = [\"node_modules\"];\n if (reservedNames.includes(input.toLowerCase())) {\n return \"Project name cannot be a reserved name\";\n }\n\n return true;\n }\n\n private async promptTypescript() {\n const { typescript } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"typescript\",\n message: `Would you like to use ${chalk.cyan(\"TypeScript\")}?`,\n default: false,\n },\n ]);\n this.config.typescript = typescript;\n }\n\n private async promptPrismaProvider() {\n const { prismaProvider } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"prismaProvider\",\n message: `What db provider will be used for ${chalk.cyan(\"Prisma\")}?`,\n choices: [\n \"postgresql\",\n \"mongodb\",\n \"mysql\",\n \"sqlite\",\n \"sqlserver\",\n \"cockroachdb\",\n ],\n },\n ]);\n\n // Set the correct idDatabaseType based on provider\n let idDatabaseType: string;\n let defaultDBurl: string;\n\n switch (prismaProvider) {\n case \"mongodb\":\n idDatabaseType = '@id @default(auto()) @map(\"_id\") @db.ObjectId';\n defaultDBurl = `mongodb://localhost:27017/${this.config.projectName}`;\n break;\n case \"sqlite\":\n idDatabaseType = \"@id @default(cuid())\";\n defaultDBurl = \"file:../../file.db\";\n break;\n case \"mysql\":\n idDatabaseType = \"@id @default(uuid())\";\n defaultDBurl = `mysql://username:password@localhost:3306/${this.config.projectName}`;\n break;\n case \"postgresql\":\n idDatabaseType = \"@id @default(uuid())\";\n defaultDBurl = `postgresql://username:password@localhost:5432/${this.config.projectName}`;\n break;\n case \"sqlserver\":\n idDatabaseType = \"@id @default(uuid())\";\n defaultDBurl = `sqlserver://localhost:1433;database=${this.config.projectName};username=sa;password=password;encrypt=DANGER_PLAINTEXT`;\n break;\n case \"cockroachdb\":\n idDatabaseType = \"@id @default(uuid())\";\n defaultDBurl = `postgresql://username:password@localhost:26257/${this.config.projectName}?sslmode=require`;\n break;\n default:\n idDatabaseType = \"@id @default(uuid())\";\n defaultDBurl = `postgresql://username:password@localhost:5432/${this.config.projectName}`;\n }\n\n this.config.prisma = {\n provider: prismaProvider,\n idDatabaseType: idDatabaseType,\n defaultDBurl: defaultDBurl,\n };\n }\n\n private async promptValidation() {\n const { useValidation } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"useValidation\",\n message: `Would you like to set up ${chalk.cyan(\"Validation\")}?`,\n default: true,\n },\n ]);\n\n if (useValidation) {\n let validationTypeResponse: {\n validationType: \"zod\" | \"class-validator\";\n } = { validationType: \"zod\" };\n\n if (this.config.typescript)\n validationTypeResponse = await inquirer.prompt([\n {\n type: \"list\",\n name: \"validationType\",\n message: \"Choose validation library:\",\n choices: [\"zod\", \"class-validator\"],\n },\n ]);\n else {\n console.info(\n chalk.bold(\n `${chalk.greenBright(\"?\")} Validation library set to zod (class-validator is not supported on JavaScript):`\n ),\n chalk.cyan(\"zod\")\n );\n }\n this.config.validation = {\n type: validationTypeResponse.validationType,\n };\n } else if (!this.config.typescript) {\n }\n }\n\n private async promptAuthentication() {\n if (this.config.prisma.provider === \"none\") {\n console.info(\n `${chalk.green(\"! \")}${chalk.bold(\"Skipping authentication setup as it requires prisma.\")}`\n );\n this.config.authentication = {\n type: \"none\",\n };\n return;\n }\n\n const { authenticationType } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"authenticationType\",\n message: `Which ${chalk.cyan(\"Authentication\")} mode would you like to use?`,\n choices: [\"static\", \"dynamic\", \"none\"],\n default: \"static\",\n },\n ]);\n\n if (authenticationType === \"none\") {\n this.config.authentication = { type: \"none\", multipleRoles: false };\n return;\n }\n\n const { usernameField } = await inquirer.prompt([\n {\n type: \"input\",\n name: \"usernameField\",\n message: \"Enter the Prisma field name to use as the login username:\",\n default: \"email\",\n validate: (input: string) => {\n if (!input || input.length === 0) return \"Field name cannot be empty\";\n if (!/^[a-z][a-zA-Z0-9]*$/.test(input))\n return \"Must be a valid Prisma field name (camelCase, starts with lowercase, letters and numbers only)\";\n return true;\n },\n },\n ]);\n\n this.config.authentication = {\n type: authenticationType as \"static\" | \"dynamic\",\n usernameField,\n multipleRoles: false,\n };\n\n if (\n authenticationType !== \"static\" ||\n (authenticationType == \"static\" &&\n this.config.prisma.provider !== \"sqlite\")\n ) {\n const { multipleRoles } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"multipleRoles\",\n default: true,\n message: `Would you like to use authentication with ${chalk.cyan(\"Multiple Roles\")}?`,\n },\n ]);\n\n this.config.authentication = {\n ...this.config.authentication,\n multipleRoles,\n };\n } else if (this.config.prisma.provider === \"sqlite\") {\n console.info(\n `${chalk.green(\"! \")}${chalk.bold(\"Skipping multiple roles option because it is not supported with sqlite prisma provider and static authentication mode.\")}`\n );\n }\n }\n\n private async promptStrictRouting() {\n const { strictRouting } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"strictRouting\",\n message: `Would you like to use ${chalk.cyan(\"Strict Routing\")}?`,\n default: false,\n },\n ]);\n this.config.routing = {\n strict: strictRouting,\n };\n }\n}\n\nconst projectConfigInquirer = new ProjectConfigInquirer();\n\nexport default projectConfigInquirer;\n"]}
@@ -55,20 +55,17 @@ class TemplateCompiler {
55
55
  "user.router.ts.hbs",
56
56
  "user.policy.ts.hbs",
57
57
  ];
58
- if (config.prisma?.provider === "none")
59
- files.push(...authSharedPrismaFiles, ...dynamicAuthPrismaFiles, "schema.prisma.hbs", ...userModuleComponents, ...authModuleComponents, ...authPermissionModuleComponents, ...authRoleModuleComponents, "file-upload.auth.ts.hbs", "index.ts.hbs");
60
- if (!config.authentication?.type || config.authentication?.type === "none")
58
+ if (!config.authentication?.type ||
59
+ config.authentication?.type === "none")
61
60
  files.push(...authSharedPrismaFiles, ...dynamicAuthPrismaFiles, ...sharedAuthDtoFiles, ...dynamicAuthDtoFiles, ...userModuleComponents, ...authModuleComponents, ...authPermissionModuleComponents, ...authRoleModuleComponents, ...userDtoFiles, "file-upload.policy.ts.hbs");
62
61
  if (config.authentication?.type === "static")
63
62
  files.push(...dynamicAuthPrismaFiles, ...dynamicAuthDtoFiles, ...authPermissionModuleComponents, ...authRoleModuleComponents);
64
63
  if (!config.validation?.type)
65
- files.push(...sharedAuthDtoFiles, ...dynamicAuthDtoFiles, ...userDtoFiles, "api-actions.hbs.ts");
64
+ files.push(...sharedAuthDtoFiles, ...dynamicAuthDtoFiles, ...userDtoFiles);
66
65
  if (!config.typescript)
67
66
  files.push(...["tsconfig.json.hbs"]);
68
67
  if (config?.typescript)
69
68
  files.push(...["jsconfig.json.hbs"]);
70
- if (config.entryPoint === "src/app")
71
- files.push("server.ts.hbs");
72
69
  return files;
73
70
  }
74
71
  async compile(templatesDir, config) {
@@ -98,11 +95,6 @@ class TemplateCompiler {
98
95
  fs.mkdirSync(path.dirname(outputPath), { recursive: true });
99
96
  fs.writeFileSync(outputPath, content);
100
97
  }
101
- else {
102
- const outputPath = path.join(outputDir, relativePath);
103
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
104
- fs.copyFileSync(fullPath, outputPath);
105
- }
106
98
  });
107
99
  }
108
100
  processTemplates(templatesDir);
@@ -1 +1 @@
1
- {"version":3,"file":"template-compiler.js","sourceRoot":"","sources":["../../src/utils/template-compiler.ts"],"names":[],"mappings":"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","sourcesContent":["import { ProjectConfig } from \"./project-config-inquirer\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport handlebars from \"handlebars\";\n\nclass TemplateCompiler {\n async canCompileAuthenticationTemplates(config: ProjectConfig) {\n return !!config.authentication;\n }\n\n filesToBeSkipped(config: ProjectConfig) {\n const files: string[] = [];\n const authSharedPrismaFiles = [\"user.prisma.hbs\"];\n\n const dynamicAuthPrismaFiles = [\n \"auth-permission.prisma.hbs\",\n \"auth-role.prisma.hbs\",\n \"user-role.prisma.hbs\",\n ];\n\n const userDtoFiles = [\n \"create-user.dto.ts.hbs\",\n \"update-user.dto.ts.hbs\",\n \"query-user.dto.ts.hbs\",\n ];\n\n const sharedAuthDtoFiles = [\n \"login.dto.ts.hbs\",\n \"signup.dto.ts.hbs\",\n \"update-password.dto.ts.hbs\",\n \"update-me.dto.ts.hbs\",\n ];\n\n const dynamicAuthDtoFiles = [\n \"create-auth-permission.dto.ts.hbs\",\n \"update-auth-permission.dto.ts.hbs\",\n \"query-auth-permission.dto.ts.hbs\",\n \"create-auth-role.dto.ts.hbs\",\n \"update-auth-role.dto.ts.hbs\",\n \"query-auth-role.dto.ts.hbs\",\n ];\n\n const authModuleComponents = [\n \"auth.route-hook.ts.hbs\",\n \"auth.policy.ts.hbs\",\n \"auth.router.ts.hbs\",\n ];\n\n const authPermissionModuleComponents = [\n \"auth-permission.router.ts.hbs\",\n \"auth-permission.policy.ts.hbs\",\n \"auth-permission.route-hook.ts.hbs\",\n \"auth-permission.service.ts.hbs\",\n ];\n\n const authRoleModuleComponents = [\n \"auth-role.router.ts.hbs\",\n \"auth-role.policy.ts.hbs\",\n \"auth-role.route-hook.ts.hbs\",\n \"auth-role.service.ts.hbs\",\n ];\n\n const userModuleComponents = [\n \"user.route-hook.ts.hbs\",\n \"user.service.ts.hbs\",\n \"user.router.ts.hbs\",\n \"user.policy.ts.hbs\",\n ];\n\n if (config.prisma?.provider === \"none\")\n files.push(\n ...authSharedPrismaFiles,\n ...dynamicAuthPrismaFiles,\n \"schema.prisma.hbs\",\n ...userModuleComponents,\n ...authModuleComponents,\n ...authPermissionModuleComponents,\n ...authRoleModuleComponents,\n \"file-upload.auth.ts.hbs\",\n \"index.ts.hbs\"\n );\n\n if (!config.authentication?.type || config.authentication?.type === \"none\")\n files.push(\n ...authSharedPrismaFiles,\n ...dynamicAuthPrismaFiles,\n ...sharedAuthDtoFiles,\n ...dynamicAuthDtoFiles,\n ...userModuleComponents,\n ...authModuleComponents,\n ...authPermissionModuleComponents,\n ...authRoleModuleComponents,\n ...userDtoFiles,\n \"file-upload.policy.ts.hbs\"\n );\n\n if (config.authentication?.type === \"static\")\n files.push(\n ...dynamicAuthPrismaFiles,\n ...dynamicAuthDtoFiles,\n ...authPermissionModuleComponents,\n ...authRoleModuleComponents\n );\n\n if (!config.validation?.type)\n files.push(\n ...sharedAuthDtoFiles,\n ...dynamicAuthDtoFiles,\n ...userDtoFiles,\n \"api-actions.hbs.ts\"\n );\n\n // Ignoring typescript related files when typescript false\n if (!config.typescript) files.push(...[\"tsconfig.json.hbs\"]);\n\n // Ignoring javascript related files when typescript true\n if (config?.typescript) files.push(...[\"jsconfig.json.hbs\"]);\n\n if (config.entryPoint === \"src/app\") files.push(\"server.ts.hbs\");\n\n return files;\n }\n /**\n * Compiles the Arkos.js project with handlebars templates\n *\n * @param templatesDir {string} templates location\n * @param config {ProjectConfig} the project configuration\n * @returns void\n * */\n async compile(templatesDir: string, config: ProjectConfig) {\n const outputDir = config.projectPath;\n const isTypescript = config.typescript;\n const filesToBeSkipped = this.filesToBeSkipped(config);\n\n function processTemplates(dir: string, relativeDir = \"\") {\n fs.readdirSync(dir, { withFileTypes: true }).forEach(async (dirent) => {\n if (\n filesToBeSkipped.includes(dirent.name) ||\n dirent.name === \"__tests__\" ||\n dirent.name?.includes(\".test.ts\")\n )\n return;\n\n const fullPath = path.join(dir, dirent.name);\n const relativePath = path.join(relativeDir, dirent.name);\n\n if (dirent.isDirectory()) {\n processTemplates(fullPath, relativePath);\n } else if (dirent.name.endsWith(\".hbs\")) {\n const templatePath = fullPath;\n const template = handlebars.compile(\n fs.readFileSync(templatePath, \"utf8\")\n );\n\n let arkosCurrentVersion = \"{{arkosCurrentVersion}}\";\n\n const content = template({ ...config, arkosCurrentVersion });\n const ext = isTypescript ? \".ts\" : \".js\";\n\n let outputPath = path.join(\n outputDir,\n relativePath.replace(\".hbs\", \"\")\n );\n if (dirent.name.endsWith(\".ts.hbs\"))\n outputPath = path.join(\n outputDir,\n relativePath.replace(\".ts.hbs\", ext)\n );\n\n fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n fs.writeFileSync(outputPath, content);\n } else {\n const outputPath = path.join(outputDir, relativePath);\n fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n fs.copyFileSync(fullPath, outputPath);\n }\n });\n }\n\n processTemplates(templatesDir);\n }\n}\n\nconst templateCompiler = new TemplateCompiler();\n\nexport default templateCompiler;\n"]}
1
+ {"version":3,"file":"template-compiler.js","sourceRoot":"","sources":["../../src/utils/template-compiler.ts"],"names":[],"mappings":"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","sourcesContent":["import { ProjectConfig } from \"./project-config-inquirer\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport handlebars from \"handlebars\";\n\nclass TemplateCompiler {\n async canCompileAuthenticationTemplates(config: ProjectConfig) {\n return !!config.authentication;\n }\n\n filesToBeSkipped(config: ProjectConfig) {\n const files: string[] = [];\n const authSharedPrismaFiles = [\"user.prisma.hbs\"];\n\n const dynamicAuthPrismaFiles = [\n \"auth-permission.prisma.hbs\",\n \"auth-role.prisma.hbs\",\n \"user-role.prisma.hbs\",\n ];\n\n const userDtoFiles = [\n \"create-user.dto.ts.hbs\",\n \"update-user.dto.ts.hbs\",\n \"query-user.dto.ts.hbs\",\n ];\n\n const sharedAuthDtoFiles = [\n \"login.dto.ts.hbs\",\n \"signup.dto.ts.hbs\",\n \"update-password.dto.ts.hbs\",\n \"update-me.dto.ts.hbs\",\n ];\n\n const dynamicAuthDtoFiles = [\n \"create-auth-permission.dto.ts.hbs\",\n \"update-auth-permission.dto.ts.hbs\",\n \"query-auth-permission.dto.ts.hbs\",\n \"create-auth-role.dto.ts.hbs\",\n \"update-auth-role.dto.ts.hbs\",\n \"query-auth-role.dto.ts.hbs\",\n ];\n\n const authModuleComponents = [\n \"auth.route-hook.ts.hbs\",\n \"auth.policy.ts.hbs\",\n \"auth.router.ts.hbs\",\n ];\n\n const authPermissionModuleComponents = [\n \"auth-permission.router.ts.hbs\",\n \"auth-permission.policy.ts.hbs\",\n \"auth-permission.route-hook.ts.hbs\",\n \"auth-permission.service.ts.hbs\",\n ];\n\n const authRoleModuleComponents = [\n \"auth-role.router.ts.hbs\",\n \"auth-role.policy.ts.hbs\",\n \"auth-role.route-hook.ts.hbs\",\n \"auth-role.service.ts.hbs\",\n ];\n\n const userModuleComponents = [\n \"user.route-hook.ts.hbs\",\n \"user.service.ts.hbs\",\n \"user.router.ts.hbs\",\n \"user.policy.ts.hbs\",\n ];\n\n if (\n !config.authentication?.type ||\n config.authentication?.type === \"none\"\n )\n files.push(\n ...authSharedPrismaFiles,\n ...dynamicAuthPrismaFiles,\n ...sharedAuthDtoFiles,\n ...dynamicAuthDtoFiles,\n ...userModuleComponents,\n ...authModuleComponents,\n ...authPermissionModuleComponents,\n ...authRoleModuleComponents,\n ...userDtoFiles,\n \"file-upload.policy.ts.hbs\"\n );\n\n if (config.authentication?.type === \"static\")\n files.push(\n ...dynamicAuthPrismaFiles,\n ...dynamicAuthDtoFiles,\n ...authPermissionModuleComponents,\n ...authRoleModuleComponents\n );\n\n if (!config.validation?.type)\n files.push(\n ...sharedAuthDtoFiles,\n ...dynamicAuthDtoFiles,\n ...userDtoFiles\n );\n\n // Ignoring typescript related files when typescript false\n if (!config.typescript) files.push(...[\"tsconfig.json.hbs\"]);\n\n // Ignoring javascript related files when typescript true\n if (config?.typescript) files.push(...[\"jsconfig.json.hbs\"]);\n\n return files;\n }\n /**\n * Compiles the Arkos.js project with handlebars templates\n *\n * @param templatesDir {string} templates location\n * @param config {ProjectConfig} the project configuration\n * @returns void\n * */\n async compile(templatesDir: string, config: ProjectConfig) {\n const outputDir = config.projectPath;\n const isTypescript = config.typescript;\n const filesToBeSkipped = this.filesToBeSkipped(config);\n\n function processTemplates(dir: string, relativeDir = \"\") {\n fs.readdirSync(dir, { withFileTypes: true }).forEach(async (dirent) => {\n if (\n filesToBeSkipped.includes(dirent.name) ||\n dirent.name === \"__tests__\" ||\n dirent.name?.includes(\".test.ts\")\n )\n return;\n\n const fullPath = path.join(dir, dirent.name);\n const relativePath = path.join(relativeDir, dirent.name);\n\n if (dirent.isDirectory()) {\n processTemplates(fullPath, relativePath);\n } else if (dirent.name.endsWith(\".hbs\")) {\n const templatePath = fullPath;\n const template = handlebars.compile(\n fs.readFileSync(templatePath, \"utf8\")\n );\n\n let arkosCurrentVersion = \"{{arkosCurrentVersion}}\";\n\n const content = template({ ...config, arkosCurrentVersion });\n const ext = isTypescript ? \".ts\" : \".js\";\n\n let outputPath = path.join(\n outputDir,\n relativePath.replace(\".hbs\", \"\")\n );\n if (dirent.name.endsWith(\".ts.hbs\"))\n outputPath = path.join(\n outputDir,\n relativePath.replace(\".ts.hbs\", ext)\n );\n\n fs.mkdirSync(path.dirname(outputPath), { recursive: true });\n fs.writeFileSync(outputPath, content);\n }\n });\n }\n\n processTemplates(templatesDir);\n }\n}\n\nconst templateCompiler = new TemplateCompiler();\n\nexport default templateCompiler;\n"]}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "create-arkos",
3
- "version": "2.0.0-next.16",
3
+ "version": "2.0.0-next.17",
4
4
  "type": "module",
5
5
  "description": "CLI for creating Arkos.js projects, see docs at www.arkosjs.com",
6
6
  "bin": {
7
- "create-arkos": "dist/index.js"
7
+ "create-arkos": "./dist/index.js"
8
8
  },
9
9
  "scripts": {
10
10
  "test": "vitest --coverage",
@@ -26,23 +26,23 @@
26
26
  "bugs": {
27
27
  "url": "https://github.com/uanela/arkos/issues"
28
28
  },
29
- "homepage": "https://www.arkosjs.com/docs/cli/create-arkos",
29
+ "homepage": "https://www.arkosjs.com/docs/tooling/cli/overviewcreate-arkos",
30
30
  "files": ["dist", "templates", "cli.js", "README.md"],
31
31
  "devDependencies": {
32
- "@types/inquirer": "9.0.9",
32
+ "@types/inquirer": "8.1.0",
33
33
  "@types/node": "16.18.126",
34
- "@vitest/coverage-v8": "4.1.7",
34
+ "@vitest/coverage-v8": "3.2.4",
35
35
  "rimraf": "6.1.3",
36
36
  "ts-node": "10.9.2",
37
37
  "tsx": "4.21.0",
38
38
  "typescript": "4.9.5",
39
- "vitest": "4.1.7"
39
+ "vitest": "3.2.4"
40
40
  },
41
41
  "dependencies": {
42
42
  "@clack/prompts": "0.11.0",
43
- "@inquirer/prompts": "7",
43
+ "@inquirer/prompts": "7.6.0",
44
44
  "chalk": "5.4.1",
45
- "handlebars": "^4.7.9",
45
+ "handlebars": "4.7.8",
46
46
  "inquirer": "8.2.6"
47
47
  }
48
48
  }
@@ -1,13 +1,9 @@
1
- {{#if (neq prisma.provider "none")}}
2
1
  # Database connection
3
- DATABASE_URL={{prisma.defaultDatabaseUrl}}
4
- {{/if}}
2
+ DATABASE_URL={{prisma.defaultDBurl}}
5
3
 
6
- {{#if (neq authentication.type "none")}}
7
4
  # JWT secrets
8
5
  # JWT_SECRET=
9
6
  # JWT_EXPIRES_IN=30d
10
- {{/if}}
11
7
 
12
8
  # Server configuration
13
9
  PORT=8000
@@ -1,13 +1,11 @@
1
- This is a [Arkos.js](https://arkosjs.com) project scaffolded with [`create-arkos`](https://arkosjs.com/docs/tooling/cli/overviewcreate-arkos).
1
+ This is an [Arkos.js](https://arkosjs.com) project scaffolded with [`create-arkos`](https://arkosjs.com/docs/tooling/cli/overviewcreate-arkos).
2
2
 
3
3
  ## Getting Started
4
4
 
5
5
  First, run the development server:
6
6
 
7
7
  ```bash
8
- pnpm dev
9
- # or
10
- npm run dev
8
+ {{packageManager}} run dev
11
9
  ```
12
10
 
13
11
  - Visit [http://localhost:8000/api/docs](http://localhost:8000/api/docs) with your browser to see the swagger api documentation.
@@ -1,17 +1,12 @@
1
1
  import { defineConfig } from "arkos/config"
2
- import prisma from "./src/utils/prisma"
2
+ import prisma from "@/src/utils/prisma"
3
3
 
4
4
  const arkosConfig = defineConfig({
5
5
  globalPrefix: "/api",
6
6
  prisma: {
7
7
  instance: prisma
8
8
  },
9
- {{#if (eq entryPoint "src/server")}}
10
- source: {
11
- entryPoint: "{{entryPoint}}{{#if typescript}}.ts{{else}}.js{{/if}}"
12
- },
13
- {{/if}}
14
- {{#if (neq authentication.type "none")}}
9
+ {{#if authentication.type}}
15
10
  authentication: {
16
11
  mode: '{{authentication.type}}',
17
12
  login: {
@@ -35,18 +30,10 @@ const arkosConfig = defineConfig({
35
30
  strict: false,
36
31
  },
37
32
  middlewares: {
38
- cors: {},
39
- },
40
- {{#if (eq prisma.provider "none")}}
41
- warnings: {
42
- suppress: {
43
- prisma: {
44
- noInstanceFound: true,
45
- noSchemaFound: true,
46
- },
33
+ cors: {
34
+ allowedOrigins: process.env.NODE_ENV !== "production" ? "*" : "your-production-url"
47
35
  },
48
- },
49
- {{/if}}
36
+ }
50
37
  })
51
38
 
52
39
  export default arkosConfig
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "es2022",
4
- "module": "es2022",
3
+ "target": "ES6",
4
+ "module": "es2020",
5
5
  "moduleResolution": "bundler",
6
6
  "rootDir": ".",
7
7
  "baseUrl": ".",
@@ -17,17 +17,17 @@
17
17
  "@types/express": "5.0.0",
18
18
  {{/if}}
19
19
  "tsx-strict": "0.7.0",
20
- "tsx": "4.21.0"{{#if (neq prisma.provider "none")}},
21
- "prisma": "6.19.2"
20
+ "tsx": "4.23.1"{{#if (neq prisma.provider "none")}},
21
+ "prisma": "6.19.3"
22
22
  {{/if}}
23
23
  },
24
24
  "dependencies": {
25
- "arkos": "2.0.0-next.16",
26
- "express": "4.22.1",
27
- "@scalar/express-api-reference": "0.8.35",
28
- "@scalar/api-reference": "1.55.3",
25
+ "arkos": "2.0.0-next.17",
26
+ "express": "4.22.2",
27
+ "@scalar/express-api-reference": "0.10.2",
28
+ "@scalar/api-reference": "1.55.3"{{#if (or (neq prisma.provider "none") validation.type)}},{{/if}}
29
29
  {{#if (neq prisma.provider "none")}}
30
- "@prisma/client": "6.19.2"{{#if validation.type}},{{/if}}
30
+ "@prisma/client": "6.19.3"{{#if validation.type}},{{/if}}
31
31
  {{/if}}
32
32
  {{#if (eq validation.type "class-validator")}}
33
33
  "reflect-metadata": "0.2.2",
@@ -35,7 +35,7 @@
35
35
  "class-validator": "0.14.1"
36
36
  {{/if}}
37
37
  {{#if (eq validation.type "zod")}}
38
- "zod": "3.24.2"
38
+ "zod": "3.25.76"
39
39
  {{/if}}
40
40
  }
41
41
  }
@@ -27,7 +27,7 @@ describe("UserRole model template rendering", () => {
27
27
  // Test case 2: Define later authentication
28
28
  const context2 = {
29
29
  authentication: {
30
- type: "none",
30
+ type: "define later",
31
31
  multipleRoles: false,
32
32
  },
33
33
  prisma: {
@@ -65,10 +65,10 @@ describe("User model template rendering", () => {
65
65
  expect(result3).toContain("roles UserRole[]");
66
66
  });
67
67
 
68
- it('should handle "none" authentication type', () => {
68
+ it('should handle "define later" authentication type', () => {
69
69
  const context = {
70
70
  authentication: {
71
- type: "none",
71
+ type: "define later",
72
72
  usernameField: "email",
73
73
  },
74
74
  prisma: {
@@ -1,4 +1,4 @@
1
- {{#if (neq authentication.type "none")}}
1
+ {{#if (neq authentication.type "define later")}}
2
2
  model User {
3
3
  id String {{{prisma.idDatabaseType}}}
4
4
  {{authentication.usernameField}} String @unique
@@ -2,15 +2,11 @@ import arkos from "arkos";
2
2
  import router from "@/src/router"
3
3
  import loadables from "@/src/loadables"
4
4
 
5
- const app = arkos();
5
+ const app = arkos()
6
6
 
7
- app.set("trust proxy", 1);
7
+ app.set("trust proxy", 1)
8
8
 
9
9
  app.load(loadables)
10
- app.use(router);
10
+ app.use(router)
11
11
 
12
- {{#if (eq entryPoint "src/app")}}
13
- app.listen();
14
- {{else}}
15
- export default app;
16
- {{/if}}
12
+ app.listen()
@@ -1,14 +1,6 @@
1
- import { ArkosRouter{{#if typescript}}, RouteHook{{/if}} } from "arkos";
1
+ import { ArkosRouter } from "arkos";
2
2
  {{#if authentication}}
3
3
  import authPermissionPolicy from "@/src/modules/auth-permission/auth-permission.policy";
4
-
5
- export const hook{{#if typescript}}: RouteHook{{/if}} = {
6
- createOne: { authentication: authPermissionPolicy.Create },
7
- findMany: { authentication: authPermissionPolicy.View },
8
- findOne: { authentication: authPermissionPolicy.View },
9
- updateOne: { authentication: authPermissionPolicy.Update },
10
- deleteOne: { authentication: authPermissionPolicy.Delete },
11
- };
12
4
  {{/if}}
13
5
 
14
6
  const authPermissionRouter = ArkosRouter({
@@ -37,11 +37,7 @@ export default class CreateAuthPermissionDto {
37
37
 
38
38
  @ValidateNested()
39
39
  @Type(() => RoleConnectDto)
40
- role!: RoleConnectDto;
41
-
42
40
  @IsOptional()
43
- @IsString()
44
- @Transform(({ value }) => value)
45
- description?: string;
41
+ roles?: RoleConnectDto[];
46
42
  }
47
43
  {{/if}}
@@ -24,11 +24,13 @@ export default class UpdateAuthPermissionDto {
24
24
 
25
25
  @IsOptional()
26
26
  @IsString()
27
- @Transform(({ value }) => value)
28
- action?: string;
27
+ @Transform(({ value }) => String(value))
28
+ action?: string
29
29
 
30
+ @ValidateNested({ each: true })
31
+ @IsArray()
32
+ @Type(() => RoleConnectDto)
30
33
  @IsOptional()
31
- @IsString()
32
- description?: string;
34
+ roles?: RoleConnectDto[];
33
35
  }
34
36
  {{/if}}
@@ -1,14 +1,6 @@
1
- import { ArkosRouter{{#if typescript}}, RouteHook{{/if}} } from "arkos";
1
+ import { ArkosRouter } from "arkos";
2
2
  {{#if authentication}}
3
3
  import authRolePolicy from "@/src/modules/auth-role/auth-role.policy";
4
-
5
- export const hook{{#if typescript}}: RouteHook{{/if}} = {
6
- createOne: { authentication: authRolePolicy.Create },
7
- findMany: { authentication: authRolePolicy.View },
8
- findOne: { authentication: authRolePolicy.View },
9
- updateOne: { authentication: authRolePolicy.Update },
10
- deleteOne: { authentication: authRolePolicy.Delete },
11
- };
12
4
  {{/if}}
13
5
 
14
6
  const authRoleRouter = ArkosRouter({
@@ -29,13 +29,8 @@ class CreatePermissionForRoleDto {
29
29
  resource!: string;
30
30
 
31
31
  @IsString()
32
- @Transform(({ value }) => value || 'View')
33
- action: string = 'View';
34
-
35
- @IsOptional()
36
- @IsString()
37
- @Transform(({ value }) => value)
38
- description?: string;
32
+ @Transform(({ value }) => String(value))
33
+ action!: string;
39
34
  }
40
35
 
41
36
  export default class CreateAuthRoleDto {
@@ -45,11 +45,7 @@ class UpdatePermissionForRoleDto {
45
45
  @IsNotEmpty()
46
46
  action!: string;
47
47
 
48
- @IsOptional()
49
- @IsString()
50
- @Transform(({ value }) => value)
51
- description?: string;
52
-
48
+ @IsEnum(ApiAction)
53
49
  @IsOptional()
54
50
  @IsString()
55
51
  apiAction?: ApiAction;
@@ -1,15 +1,8 @@
1
- import { ArkosRouter{{#if typescript}}, RouteHook{{/if}} } from "arkos";
2
- import config from "@/arkos.config"
1
+ import { ArkosRouter } from "arkos";
3
2
  {{#if authentication}}
4
3
  import fileUploadPolicy from "@/src/modules/file-upload/file-upload.policy";
5
-
6
- export const hook{{#if typescript}}: RouteHook<"file-upload">{{/if}} = {
7
- findFile: { authentication: fileUploadPolicy.View },
8
- uploadFile: { authentication: fileUploadPolicy.Create },
9
- updateFile: { authentication: fileUploadPolicy.Update },
10
- deleteFile: { authentication: fileUploadPolicy.Delete },
11
- };
12
4
  {{/if}}
5
+ import config from "@/arkos.config"
13
6
 
14
7
  const fileUploadRouter = ArkosRouter({
15
8
  prefix: config?.fileUpload?.baseRoute,
@@ -1,14 +1,6 @@
1
- import { ArkosRouter{{#if typescript}}, RouteHook{{/if}} } from "arkos";
1
+ import { ArkosRouter } from "arkos";
2
2
  {{#if authentication}}
3
3
  import userPolicy from "@/src/modules/user/user.policy";
4
-
5
- export const hook{{#if typescript}}: RouteHook{{/if}} = {
6
- createOne: { authentication: userPolicy.Create },
7
- findMany: { authentication: userPolicy.View },
8
- findOne: { authentication: userPolicy.View },
9
- updateOne: { authentication: userPolicy.Update },
10
- deleteOne: { authentication: userPolicy.Delete },
11
- };
12
4
  {{/if}}
13
5
 
14
6
  const userRouter = ArkosRouter({
@@ -1,5 +1,4 @@
1
1
  import { ArkosRouter } from "arkos";
2
- import arkosConfig from "@/arkos.config";
3
2
  import fileUploadRouter from "@/src/modules/file-upload/file-upload.router";
4
3
  {{#if authentication.type}}
5
4
  import authRouter from "@/src/modules/auth/auth.router";
@@ -10,9 +9,7 @@ import authRoleRouter from "@/src/modules/auth-role/auth-role.router";
10
9
  import authPermissionRouter from "@/src/modules/auth-permission/auth-permission.router";
11
10
  {{/if}}
12
11
 
13
- const router = ArkosRouter({
14
- prefix: arkosConfig.globalPrefix || "/api",
15
- })
12
+ const router = ArkosRouter();
16
13
 
17
14
  router.use(fileUploadRouter);
18
15
  {{#if authentication.type}}
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * Is worth mentioning that this will be addded into `arkos` as an util.
6
6
  *
7
- * @see {@link https://www.arkosjs.com/docs/core-concepts/prisma-orm/handling-relations}
7
+ * @see {@link https://www.arkosjs.com/docs/advanced-guide/handling-relation-fields-in-prisma-body-requests#the-apiaction-property}
8
8
  */
9
9
  const apiActions = ["connect", "disconnect", "delete", "update", "create"]{{#if typescript}} as const{{/if}};
10
10
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "target": "es2022",
4
- "module": "es2022",
3
+ "target": "ES6",
4
+ "module": "es2020",
5
5
  "moduleResolution": "bundler",
6
6
  "rootDir": ".",
7
7
  "baseUrl": ".",
Binary file
@@ -1,8 +0,0 @@
1
- import app from "@/src/app";
2
- import http from "node:http";
3
-
4
- await app.build();
5
-
6
- const server = http.createServer(app);
7
-
8
- app.listen(server);