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.
- package/README.md +182 -57
- package/dist/utils/project-config-inquirer.js +45 -44
- package/dist/utils/project-config-inquirer.js.map +1 -1
- package/dist/utils/template-compiler.js +3 -11
- package/dist/utils/template-compiler.js.map +1 -1
- package/package.json +8 -8
- package/templates/basic/.env.hbs +1 -5
- package/templates/basic/README.md.hbs +2 -4
- package/templates/basic/arkos.config.ts.hbs +5 -18
- package/templates/basic/jsconfig.json.hbs +2 -2
- package/templates/basic/package.json.hbs +8 -8
- package/templates/basic/prisma/schema/__tests__/user-role.prisma.hbs.test.ts +1 -1
- package/templates/basic/prisma/schema/__tests__/user.prisma.hbs.test.ts +2 -2
- package/templates/basic/prisma/schema/user.prisma.hbs +1 -1
- package/templates/basic/src/app.ts.hbs +4 -8
- package/templates/basic/src/modules/auth-permission/auth-permission.router.ts.hbs +1 -9
- package/templates/basic/src/modules/auth-permission/dtos/create-auth-permission.dto.ts.hbs +1 -5
- package/templates/basic/src/modules/auth-permission/dtos/update-auth-permission.dto.ts.hbs +6 -4
- package/templates/basic/src/modules/auth-role/auth-role.router.ts.hbs +1 -9
- package/templates/basic/src/modules/auth-role/dtos/create-auth-role.dto.ts.hbs +2 -7
- package/templates/basic/src/modules/auth-role/dtos/update-auth-role.dto.ts.hbs +1 -5
- package/templates/basic/src/modules/file-upload/file-upload.router.ts.hbs +2 -9
- package/templates/basic/src/modules/user/user.router.ts.hbs +1 -9
- package/templates/basic/src/router.ts.hbs +1 -4
- package/templates/basic/src/utils/validation/api-actions.ts.hbs +1 -1
- package/templates/basic/tsconfig.json.hbs +2 -2
- package/templates/basic/public/favicon.ico +0 -0
- package/templates/basic/src/server.ts.hbs +0 -8
package/README.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-

|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
|
|
5
|
-
[](https://badge.socket.dev/npm/package/arkos)
|
|
6
|
+

|
|
7
|
+

|
|
8
8
|

|
|
9
9
|

|
|
10
10
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
13
13
|
<div align="center">
|
|
14
|
-
<h2>
|
|
15
|
-
<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/
|
|
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
|
-
|
|
33
|
+
npm create arkos@latest my-project
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
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
|
-
##
|
|
38
|
+
## Your Entry Point
|
|
39
39
|
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
57
|
-
|
|
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
|
-
|
|
60
|
-
# Edit .env with your DATABASE_URL
|
|
91
|
+
const postRouter = ArkosRouter({ prefix: "/api/posts" });
|
|
61
92
|
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
66
|
-
npm run dev
|
|
105
|
+
export default postRouter;
|
|
67
106
|
```
|
|
68
107
|
|
|
69
|
-
|
|
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
|
-
##
|
|
110
|
+
## Define Permissions Once, Guard Everywhere
|
|
72
111
|
|
|
73
|
-
|
|
112
|
+
```typescript
|
|
113
|
+
// src/modules/post/post.policy.ts
|
|
114
|
+
import { ArkosPolicy } from "arkos";
|
|
74
115
|
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
##
|
|
205
|
+
## Built With
|
|
206
|
+
|
|
207
|
+
Arkos.js is built on top of industry-leading tools:
|
|
108
208
|
|
|
109
|
-
-
|
|
110
|
-
-
|
|
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/
|
|
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:
|
|
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
|
|
105
|
+
let defaultDBurl;
|
|
108
106
|
switch (prismaProvider) {
|
|
109
107
|
case "mongodb":
|
|
110
108
|
idDatabaseType = '@id @default(auto()) @map("_id") @db.ObjectId';
|
|
111
|
-
|
|
109
|
+
defaultDBurl = `mongodb://localhost:27017/${this.config.projectName}`;
|
|
112
110
|
break;
|
|
113
111
|
case "sqlite":
|
|
114
112
|
idDatabaseType = "@id @default(cuid())";
|
|
115
|
-
|
|
113
|
+
defaultDBurl = "file:../../file.db";
|
|
116
114
|
break;
|
|
117
115
|
case "mysql":
|
|
118
116
|
idDatabaseType = "@id @default(uuid())";
|
|
119
|
-
|
|
117
|
+
defaultDBurl = `mysql://username:password@localhost:3306/${this.config.projectName}`;
|
|
120
118
|
break;
|
|
121
119
|
case "postgresql":
|
|
122
120
|
idDatabaseType = "@id @default(uuid())";
|
|
123
|
-
|
|
121
|
+
defaultDBurl = `postgresql://username:password@localhost:5432/${this.config.projectName}`;
|
|
124
122
|
break;
|
|
125
123
|
case "sqlserver":
|
|
126
124
|
idDatabaseType = "@id @default(uuid())";
|
|
127
|
-
|
|
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
|
-
|
|
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
|
-
|
|
133
|
+
defaultDBurl = `postgresql://username:password@localhost:5432/${this.config.projectName}`;
|
|
136
134
|
}
|
|
137
135
|
this.config.prisma = {
|
|
138
136
|
provider: prismaProvider,
|
|
139
|
-
idDatabaseType,
|
|
140
|
-
|
|
137
|
+
idDatabaseType: idDatabaseType,
|
|
138
|
+
defaultDBurl: defaultDBurl,
|
|
141
139
|
};
|
|
142
140
|
}
|
|
143
141
|
async promptValidation() {
|
|
144
|
-
const
|
|
145
|
-
? ["zod", "class-validator", "none"]
|
|
146
|
-
: ["zod", "none"];
|
|
147
|
-
const { validationType } = await inquirer.prompt([
|
|
142
|
+
const { useValidation } = await inquirer.prompt([
|
|
148
143
|
{
|
|
149
|
-
type: "
|
|
150
|
-
name: "
|
|
151
|
-
message: `
|
|
152
|
-
|
|
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 (
|
|
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(
|
|
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
|
-
|
|
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.
|
|
59
|
-
|
|
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
|
|
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":"AACA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,UAAU,MAAM,YAAY,CAAC;AAEpC,MAAM,gBAAgB;IACpB,KAAK,CAAC,iCAAiC,CAAC,MAAqB;QAC3D,OAAO,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC;IACjC,CAAC;IAED,gBAAgB,CAAC,MAAqB;QACpC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,qBAAqB,GAAG,CAAC,iBAAiB,CAAC,CAAC;QAElD,MAAM,sBAAsB,GAAG;YAC7B,4BAA4B;YAC5B,sBAAsB;YACtB,sBAAsB;SACvB,CAAC;QAEF,MAAM,YAAY,GAAG;YACnB,wBAAwB;YACxB,wBAAwB;YACxB,uBAAuB;SACxB,CAAC;QAEF,MAAM,kBAAkB,GAAG;YACzB,kBAAkB;YAClB,mBAAmB;YACnB,4BAA4B;YAC5B,sBAAsB;SACvB,CAAC;QAEF,MAAM,mBAAmB,GAAG;YAC1B,mCAAmC;YACnC,mCAAmC;YACnC,kCAAkC;YAClC,6BAA6B;YAC7B,6BAA6B;YAC7B,4BAA4B;SAC7B,CAAC;QAEF,MAAM,oBAAoB,GAAG;YAC3B,wBAAwB;YACxB,oBAAoB;YACpB,oBAAoB;SACrB,CAAC;QAEF,MAAM,8BAA8B,GAAG;YACrC,+BAA+B;YAC/B,+BAA+B;YAC/B,mCAAmC;YACnC,gCAAgC;SACjC,CAAC;QAEF,MAAM,wBAAwB,GAAG;YAC/B,yBAAyB;YACzB,yBAAyB;YACzB,6BAA6B;YAC7B,0BAA0B;SAC3B,CAAC;QAEF,MAAM,oBAAoB,GAAG;YAC3B,wBAAwB;YACxB,qBAAqB;YACrB,oBAAoB;YACpB,oBAAoB;SACrB,CAAC;QAEF,
|
|
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.
|
|
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/
|
|
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": "
|
|
32
|
+
"@types/inquirer": "8.1.0",
|
|
33
33
|
"@types/node": "16.18.126",
|
|
34
|
-
"@vitest/coverage-v8": "
|
|
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": "
|
|
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": "
|
|
45
|
+
"handlebars": "4.7.8",
|
|
46
46
|
"inquirer": "8.2.6"
|
|
47
47
|
}
|
|
48
48
|
}
|
package/templates/basic/.env.hbs
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
{{#if (neq prisma.provider "none")}}
|
|
2
1
|
# Database connection
|
|
3
|
-
DATABASE_URL={{prisma.
|
|
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
|
|
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
|
-
|
|
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 "
|
|
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
|
|
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
|
|
@@ -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
|
-
"prisma": "6.19.
|
|
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.
|
|
26
|
-
"express": "4.22.
|
|
27
|
-
"@scalar/express-api-reference": "0.
|
|
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.
|
|
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.
|
|
38
|
+
"zod": "3.25.76"
|
|
39
39
|
{{/if}}
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -65,10 +65,10 @@ describe("User model template rendering", () => {
|
|
|
65
65
|
expect(result3).toContain("roles UserRole[]");
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
it('should handle "
|
|
68
|
+
it('should handle "define later" authentication type', () => {
|
|
69
69
|
const context = {
|
|
70
70
|
authentication: {
|
|
71
|
-
type: "
|
|
71
|
+
type: "define later",
|
|
72
72
|
usernameField: "email",
|
|
73
73
|
},
|
|
74
74
|
prisma: {
|
|
@@ -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
|
-
|
|
13
|
-
app.listen();
|
|
14
|
-
{{else}}
|
|
15
|
-
export default app;
|
|
16
|
-
{{/if}}
|
|
12
|
+
app.listen()
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import { ArkosRouter
|
|
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
|
-
|
|
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
|
-
|
|
32
|
-
description?: string;
|
|
34
|
+
roles?: RoleConnectDto[];
|
|
33
35
|
}
|
|
34
36
|
{{/if}}
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import { ArkosRouter
|
|
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
|
|
33
|
-
action
|
|
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 {
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import { ArkosRouter
|
|
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
|
|
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/
|
|
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
|
|
|
Binary file
|