nodejs-quickstart-structure 2.1.2 → 2.2.0
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/CHANGELOG.md +11 -0
- package/README.md +12 -17
- package/bin/index.js +1 -0
- package/lib/generator.js +1 -1
- package/lib/modules/app-setup.js +16 -0
- package/lib/modules/auth-setup.js +46 -4
- package/lib/prompts.js +44 -4
- package/package.json +1 -1
- package/templates/clean-architecture/js/src/infrastructure/config/env.js.ejs +12 -2
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.js.ejs +27 -0
- package/templates/clean-architecture/js/src/infrastructure/repositories/UserRepository.spec.js.ejs +24 -0
- package/templates/clean-architecture/js/src/infrastructure/webserver/server.js.ejs +3 -1
- package/templates/clean-architecture/ts/src/config/env.ts.ejs +12 -2
- package/templates/clean-architecture/ts/src/domain/user.ts.ejs +14 -0
- package/templates/clean-architecture/ts/src/infrastructure/repositories/UserRepository.spec.ts.ejs +24 -0
- package/templates/clean-architecture/ts/src/infrastructure/repositories/userRepository.ts.ejs +43 -45
- package/templates/clean-architecture/ts/src/interfaces/graphql/resolvers/user.resolvers.ts.ejs +5 -5
- package/templates/common/.env.example.ejs +10 -0
- package/templates/common/README.md.ejs +65 -14
- package/templates/common/auth/js/controllers/authController.js.ejs +326 -13
- package/templates/common/auth/js/controllers/authController.spec.js.ejs +237 -51
- package/templates/common/auth/js/middleware/authMiddleware.js.ejs +10 -6
- package/templates/common/auth/js/routes/authRoutes.js.ejs +11 -0
- package/templates/common/auth/js/services/jwtService.js.ejs +3 -3
- package/templates/common/auth/js/services/jwtService.spec.js.ejs +30 -0
- package/templates/common/auth/js/services/socialAuthService.js.ejs +175 -0
- package/templates/common/auth/js/services/socialAuthService.spec.js.ejs +194 -0
- package/templates/common/auth/js/usecases/SocialLoginUseCase.js.ejs +114 -0
- package/templates/common/auth/js/usecases/SocialLoginUseCase.spec.js.ejs +143 -0
- package/templates/common/auth/ts/controllers/authController.spec.ts.ejs +344 -64
- package/templates/common/auth/ts/controllers/authController.ts.ejs +341 -9
- package/templates/common/auth/ts/middleware/authMiddleware.ts.ejs +10 -6
- package/templates/common/auth/ts/routes/authRoutes.ts.ejs +11 -0
- package/templates/common/auth/ts/services/jwtService.spec.ts.ejs +18 -0
- package/templates/common/auth/ts/services/jwtService.ts.ejs +3 -3
- package/templates/common/auth/ts/services/socialAuthService.spec.ts.ejs +187 -0
- package/templates/common/auth/ts/services/socialAuthService.ts.ejs +189 -0
- package/templates/common/auth/ts/usecases/SocialLoginUseCase.spec.ts.ejs +143 -0
- package/templates/common/auth/ts/usecases/SocialLoginUseCase.ts.ejs +117 -0
- package/templates/common/database/js/models/User.js.ejs +13 -5
- package/templates/common/database/js/models/User.js.mongoose.ejs +15 -1
- package/templates/common/database/ts/models/User.ts.ejs +23 -7
- package/templates/common/database/ts/models/User.ts.mongoose.ejs +18 -2
- package/templates/common/docker-compose.yml.ejs +21 -0
- package/templates/common/ecosystem.config.js.ejs +10 -0
- package/templates/common/jest.config.js.ejs +1 -1
- package/templates/common/kafka/js/services/kafkaService.js.ejs +1 -1
- package/templates/common/kafka/ts/services/kafkaService.ts.ejs +1 -1
- package/templates/common/package.json.ejs +2 -0
- package/templates/common/src/tests/e2e/e2e.users.test.js.ejs +13 -1
- package/templates/common/src/tests/e2e/e2e.users.test.ts.ejs +13 -1
- package/templates/common/swagger.yml.ejs +62 -3
- package/templates/common/views/ejs/login.ejs.ejs +84 -0
- package/templates/common/views/ejs/signup.ejs.ejs +84 -0
- package/templates/common/views/pug/login.pug.ejs +78 -0
- package/templates/common/views/pug/signup.pug.ejs +78 -0
- package/templates/db/mysql/V1__Initial_Setup.sql.ejs +3 -1
- package/templates/db/postgres/V1__Initial_Setup.sql.ejs +3 -1
- package/templates/mvc/js/src/config/env.js.ejs +12 -2
- package/templates/mvc/js/src/controllers/userController.js.ejs +1 -1
- package/templates/mvc/js/src/graphql/resolvers/user.resolvers.js.ejs +4 -3
- package/templates/mvc/ts/src/config/env.ts.ejs +12 -2
- package/templates/mvc/ts/src/controllers/userController.ts.ejs +1 -0
- package/templates/mvc/ts/src/graphql/resolvers/user.resolvers.ts.ejs +5 -5
- package/templates/mvc/ts/src/index.ts.ejs +2 -1
- package/templates/clean-architecture/ts/src/domain/user.ts +0 -9
|
@@ -176,6 +176,63 @@ html(lang="en")
|
|
|
176
176
|
font-size: 12px;
|
|
177
177
|
opacity: 0.5;
|
|
178
178
|
}
|
|
179
|
+
|
|
180
|
+
.divider {
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
text-align: center;
|
|
184
|
+
margin: 24px 0;
|
|
185
|
+
color: var(--text-muted);
|
|
186
|
+
font-size: 13px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.divider::before,
|
|
190
|
+
.divider::after {
|
|
191
|
+
content: '';
|
|
192
|
+
flex: 1;
|
|
193
|
+
border-bottom: 1px solid var(--card-border);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.divider:not(:empty)::before {
|
|
197
|
+
margin-right: .5em;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.divider:not(:empty)::after {
|
|
201
|
+
margin-left: .5em;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.social-login {
|
|
205
|
+
display: grid;
|
|
206
|
+
grid-template-columns: 1fr 1fr;
|
|
207
|
+
gap: 12px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.btn-social {
|
|
211
|
+
display: flex;
|
|
212
|
+
align-items: center;
|
|
213
|
+
justify-content: center;
|
|
214
|
+
gap: 8px;
|
|
215
|
+
background: rgba(255, 255, 255, 0.05);
|
|
216
|
+
border: 1px solid var(--card-border);
|
|
217
|
+
border-radius: 12px;
|
|
218
|
+
padding: 12px;
|
|
219
|
+
color: #fff;
|
|
220
|
+
font-size: 14px;
|
|
221
|
+
font-weight: 500;
|
|
222
|
+
cursor: pointer;
|
|
223
|
+
transition: all 0.3s ease;
|
|
224
|
+
text-decoration: none;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.btn-social:hover {
|
|
228
|
+
background: rgba(255, 255, 255, 0.08);
|
|
229
|
+
border-color: var(--text-muted);
|
|
230
|
+
transform: translateY(-1px);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.social-full {
|
|
234
|
+
grid-column: span 2;
|
|
235
|
+
}
|
|
179
236
|
body
|
|
180
237
|
div.background-blobs
|
|
181
238
|
div.blob.blob-1
|
|
@@ -194,6 +251,27 @@ html(lang="en")
|
|
|
194
251
|
label(for="password") Choose Password
|
|
195
252
|
input(type="password" id="password" name="password" placeholder="••••••••" required)
|
|
196
253
|
button.btn-primary(type="submit") Create Account
|
|
254
|
+
|
|
255
|
+
<% if (socialAuth && socialAuth.filter(a => a !== 'None').length > 0) { %>
|
|
256
|
+
div.divider Or join with
|
|
257
|
+
div.social-login
|
|
258
|
+
<% if (socialAuth.includes('Google')) { %>
|
|
259
|
+
a.btn-social(href="/api/auth/google" class="<%= socialAuth.includes('GitHub') ? '' : 'social-full' %>")
|
|
260
|
+
svg(width="20" height="20" viewBox="0 0 24 24" fill="currentColor")
|
|
261
|
+
path(d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4")
|
|
262
|
+
path(d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853")
|
|
263
|
+
path(d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05")
|
|
264
|
+
path(d="M12 5.38c1.62 0 3.06.56 4.21 1.66l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335")
|
|
265
|
+
| Google
|
|
266
|
+
<% } %>
|
|
267
|
+
<% if (socialAuth.includes('GitHub')) { %>
|
|
268
|
+
a.btn-social(href="/api/auth/github" class="<%= socialAuth.includes('Google') ? '' : 'social-full' %>")
|
|
269
|
+
svg(width="20" height="20" viewBox="0 0 24 24" fill="currentColor")
|
|
270
|
+
path(d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12")
|
|
271
|
+
| GitHub
|
|
272
|
+
<% } %>
|
|
273
|
+
<% } %>
|
|
274
|
+
|
|
197
275
|
div.footer
|
|
198
276
|
p Already have an account?
|
|
199
277
|
a(href="/login") Sign in
|
|
@@ -2,7 +2,9 @@ CREATE TABLE users (
|
|
|
2
2
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
3
3
|
name VARCHAR(255) NOT NULL,
|
|
4
4
|
email VARCHAR(255) NOT NULL UNIQUE,
|
|
5
|
-
<% if (auth.includes('JWT')) { %>password VARCHAR(255)
|
|
5
|
+
<% if (auth.includes('JWT')) { %>password VARCHAR(255) NULL, <% } %>
|
|
6
|
+
<% if (socialAuth && socialAuth.includes('Google')) { %>google_id VARCHAR(255) NULL UNIQUE, <% } %>
|
|
7
|
+
<% if (socialAuth && socialAuth.includes('GitHub')) { %>github_id VARCHAR(255) NULL UNIQUE, <% } %>
|
|
6
8
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
7
9
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
8
10
|
deleted_at TIMESTAMP NULL
|
|
@@ -2,7 +2,9 @@ CREATE TABLE users (
|
|
|
2
2
|
id SERIAL PRIMARY KEY,
|
|
3
3
|
name VARCHAR(255) NOT NULL,
|
|
4
4
|
email VARCHAR(255) NOT NULL UNIQUE,
|
|
5
|
-
<% if (auth.includes('JWT')) { %>password VARCHAR(255)
|
|
5
|
+
<% if (auth.includes('JWT')) { %>password VARCHAR(255) NULL, <% } %>
|
|
6
|
+
<% if (socialAuth && socialAuth.includes('Google')) { %>google_id VARCHAR(255) NULL UNIQUE, <% } %>
|
|
7
|
+
<% if (socialAuth && socialAuth.includes('GitHub')) { %>github_id VARCHAR(255) NULL UNIQUE, <% } %>
|
|
6
8
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
7
9
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
8
10
|
deleted_at TIMESTAMP NULL
|
|
@@ -29,12 +29,22 @@ const envSchema = z.object({
|
|
|
29
29
|
REDIS_PORT: z.string().transform(Number),
|
|
30
30
|
REDIS_PASSWORD: z.string().optional(),
|
|
31
31
|
<%_ } -%>
|
|
32
|
-
<%_ if (auth.includes('JWT')) {
|
|
32
|
+
<%_ if (auth.includes('JWT')) { _%>
|
|
33
33
|
JWT_SECRET: z.string(),
|
|
34
34
|
JWT_EXPIRES_IN: z.string().default('15m'),
|
|
35
35
|
JWT_REFRESH_SECRET: z.string().default('your-secret-refresh-key'),
|
|
36
36
|
JWT_REFRESH_EXPIRES_IN: z.string().default('7d'),
|
|
37
|
-
<%_
|
|
37
|
+
<%_ if (socialAuth && socialAuth.includes('Google')) { _%>
|
|
38
|
+
GOOGLE_CLIENT_ID: z.string(),
|
|
39
|
+
GOOGLE_CLIENT_SECRET: z.string(),
|
|
40
|
+
GOOGLE_CALLBACK_URL: z.string().optional(),
|
|
41
|
+
<%_ } _%>
|
|
42
|
+
<%_ if (socialAuth && socialAuth.includes('GitHub')) { _%>
|
|
43
|
+
GITHUB_CLIENT_ID: z.string(),
|
|
44
|
+
GITHUB_CLIENT_SECRET: z.string(),
|
|
45
|
+
GITHUB_CALLBACK_URL: z.string().optional(),
|
|
46
|
+
<%_ } _%>
|
|
47
|
+
<%_ } _%>
|
|
38
48
|
<%_ if (communication === 'Kafka') { -%>
|
|
39
49
|
KAFKA_BROKER: z.string(),
|
|
40
50
|
<%_ } -%>
|
|
@@ -17,11 +17,12 @@ const userResolvers = {
|
|
|
17
17
|
<% if (auth.includes('JWT')) { %>if (!user) throw new Error('Unauthorized');<% } %>
|
|
18
18
|
return await userController.updateUser(id, { name, email });
|
|
19
19
|
},
|
|
20
|
-
deleteUser: async (_, { id }, <% if (auth.includes('JWT')) { %>{ user }<% } else { %>_context<% } %>) => {
|
|
21
|
-
<% if (auth.includes('JWT')) { %>if (!
|
|
20
|
+
deleteUser: async (_, { id }, <% if (auth.includes('JWT')) { %>{ user: authUser }<% } else { %>_context<% } %>) => {
|
|
21
|
+
<% if (auth.includes('JWT')) { %>if (!authUser) throw new Error('Unauthorized');<% } %>
|
|
22
22
|
return await userController.deleteUser(id);
|
|
23
23
|
}
|
|
24
|
-
}<%_ if (database === 'MongoDB') {
|
|
24
|
+
}<%_ if (database === 'MongoDB') { -%>
|
|
25
|
+
,
|
|
25
26
|
User: {
|
|
26
27
|
id: (parent) => parent.id || parent._id
|
|
27
28
|
}<%_ } %>
|
|
@@ -33,12 +33,22 @@ const envSchema = z.object({
|
|
|
33
33
|
<%_ if (communication === 'Kafka') { -%>
|
|
34
34
|
KAFKA_BROKER: z.string(),
|
|
35
35
|
<%_ } -%>
|
|
36
|
-
<%_ if (auth.includes('JWT')) {
|
|
36
|
+
<%_ if (auth.includes('JWT')) { _%>
|
|
37
37
|
JWT_SECRET: z.string(),
|
|
38
38
|
JWT_EXPIRES_IN: z.string().default('15m'),
|
|
39
39
|
JWT_REFRESH_SECRET: z.string().default('your-secret-refresh-key'),
|
|
40
40
|
JWT_REFRESH_EXPIRES_IN: z.string().default('7d'),
|
|
41
|
-
<%_
|
|
41
|
+
<%_ if (socialAuth && socialAuth.includes('Google')) { _%>
|
|
42
|
+
GOOGLE_CLIENT_ID: z.string(),
|
|
43
|
+
GOOGLE_CLIENT_SECRET: z.string(),
|
|
44
|
+
GOOGLE_CALLBACK_URL: z.string().optional(),
|
|
45
|
+
<%_ } _%>
|
|
46
|
+
<%_ if (socialAuth && socialAuth.includes('GitHub')) { _%>
|
|
47
|
+
GITHUB_CLIENT_ID: z.string(),
|
|
48
|
+
GITHUB_CLIENT_SECRET: z.string(),
|
|
49
|
+
GITHUB_CALLBACK_URL: z.string().optional(),
|
|
50
|
+
<%_ } _%>
|
|
51
|
+
<%_ } _%>
|
|
42
52
|
});
|
|
43
53
|
|
|
44
54
|
const _env = envSchema.safeParse(process.env);
|
|
@@ -25,15 +25,15 @@ export const userResolvers = {
|
|
|
25
25
|
const user = await userController.updateUser(id, { name, email });
|
|
26
26
|
return user;
|
|
27
27
|
},
|
|
28
|
-
deleteUser: async (_: unknown, { id }: { id: string }, <% if (auth.includes('JWT')) { %>context<% } else { %>_context<% } %>: MyContext) => {
|
|
29
|
-
<%_ if (auth.includes('JWT')) {
|
|
28
|
+
deleteUser: async (_: unknown, { id }: { id: string }, <%_ if (auth.includes('JWT')) { _%>context<%_ } else { _%>_context<%_ } _%>: MyContext) => {
|
|
29
|
+
<%_ if (auth.includes('JWT')) { _%>
|
|
30
30
|
if (!context.user) throw new Error('Unauthorized');
|
|
31
|
-
<%_ }
|
|
31
|
+
<%_ } _%>
|
|
32
32
|
const result = await userController.deleteUser(id);
|
|
33
33
|
return result;
|
|
34
34
|
}
|
|
35
|
-
}<%_ if (database === 'MongoDB') {
|
|
35
|
+
}<%_ if (database === 'MongoDB') { _%>,
|
|
36
36
|
User: {
|
|
37
37
|
id: (parent: { id?: string; _id?: unknown }) => parent.id || parent._id
|
|
38
|
-
}<%_ } %>
|
|
38
|
+
}<%_ } _%>
|
|
39
39
|
};
|
|
@@ -66,7 +66,8 @@ app.set('view engine', '<%= viewEngine.toLowerCase() %>');
|
|
|
66
66
|
app.use(express.static(path.join(__dirname, '../public')));<%_ } %>
|
|
67
67
|
<%_ if (communication === 'REST APIs' || communication === 'Kafka') { -%>
|
|
68
68
|
app.use('/api', apiRoutes);
|
|
69
|
-
<%_ }
|
|
69
|
+
<%_ } -%>
|
|
70
|
+
<%_ if (auth.includes('JWT')) { -%>
|
|
70
71
|
app.use('/api/auth', authRoutes);
|
|
71
72
|
<%_ } -%>
|
|
72
73
|
|