@anthonylzq/simba.js 5.0.0 → 5.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/README.md CHANGED
@@ -1,9 +1,13 @@
1
- # Simba.js
1
+ <h1 align="center">
2
+ <!-- <p align="center">Simba.js</p> -->
3
+ <a href="https://simbajs.notion.site/783092dc7d444067b4c56a25d671f658?v=31060f3d17524ca58870e86c2960a6df"><img src="https://i.ibb.co/QFX0WnH/simba-pink.png" alt="Simba.js"></a>
4
+ </h1>
2
5
 
3
6
  [![NPM version](https://img.shields.io/npm/v/@anthonylzq/simba.js.svg?style=flat)](https://www.npmjs.com/package/@anthonylzq/simba.js)
4
7
  [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/AnthonyLzq/simba.js/blob/master/LICENSE)
5
8
  [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
6
9
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
10
+ [![Lint](https://github.com/AnthonyLzq/simba.js/actions/workflows/lint.yml/badge.svg)](https://github.com/AnthonyLzq/simba.js/actions/workflows/lint.yml)
7
11
 
8
12
  Set up a modern backend app by running one command. This project has the goal to create a complete setup for a backend application using `TypeScript` and `Express` or `Fastify`. It will create many files that are usually created manually. Think about Simba.js like a [CRA](https://create-react-app.dev/), but for backend development. Check the [**project structure**](#project-structure) for more information.
9
13
 
@@ -439,6 +443,7 @@ If you want to check the content of the files, please check the [example](https:
439
443
  - If you provide a project name that contains spaces, something like 'My awesome Project', every space will be replaced with a hyphen. So at the end your project name will be 'My-awesome-project', but in its README.md file, the hyphens will be removed and the project name will be parsed to title case (My Awesome Project).
440
444
  - Finally, `git` will be initialized and a list of libraries will be installed. Check the [**notes**](#notes).
441
445
  - Relative imports is already configured, you do not need to import a file using `../../../some/very/nested/stuff/in/other/folder`, you can use `some/very/nested/stuff/in/other/folder` assuming that your folder is under the `src` folder.
446
+ - The Fastify version is set to v3 because Apollo Server has not yet provided support for Fastify v4 yet, and it is difficult to have support for two different major versions of Fastify, so until Apollo Server supports Fastify v4, this package will use Fastify v3.
442
447
 
443
448
  ## What is new?
444
449
 
@@ -72,13 +72,14 @@ export { UserModel }
72
72
  file: `${projectName}/src/database/mongo/queries/index.ts`
73
73
  },
74
74
  user: {
75
- content: `import { Document, Types } from 'mongoose'
75
+ content: `import { Document, MergeType, Types } from 'mongoose'
76
76
 
77
77
  import { UserModel } from '..'
78
- import { UserDTO } from 'schemas'
78
+ import { User, UserDTO, UserWithId } from 'schemas'
79
79
 
80
80
  const userDBOtoDTO = (
81
- userDBO: Document<unknown, unknown, UserDBO> &
81
+ userDBO: Document<unknown, unknown, MergeType<UserDBO, UserDBO>> &
82
+ Omit<UserDBO, keyof UserDBO> &
82
83
  UserDBO & {
83
84
  _id: Types.ObjectId
84
85
  }
@@ -88,7 +89,7 @@ const userDBOtoDTO = (
88
89
  updatedAt: userDBO.updatedAt.toISOString()
89
90
  })
90
91
 
91
- const store = async (userData: UserDTO): Promise<UserDTO> => {
92
+ const store = async (userData: User): Promise<UserDTO> => {
92
93
  const user = new UserModel(userData)
93
94
 
94
95
  await user.save()
@@ -124,7 +125,7 @@ const get = async (
124
125
  return users.map(u => userDBOtoDTO(u))
125
126
  }
126
127
 
127
- const update = async (userData: UserDTO): Promise<UserDTO | null> => {
128
+ const update = async (userData: UserWithId): Promise<UserDTO | null> => {
128
129
  const { id, ...rest } = userData
129
130
  const user = await UserModel.findByIdAndUpdate(id, rest, { new: true })
130
131
 
@@ -73,7 +73,8 @@ export { applyRoutes }
73
73
  file: `${projectName}/src/network/router.ts`
74
74
  },
75
75
  server: {
76
- content: `import express from 'express'
76
+ content: `import { Server as HttpServer } from 'http'
77
+ import express from 'express'
77
78
  import mongoose from 'mongoose'
78
79
  import cors from 'cors'
79
80
  import pino, { HttpLogger } from 'express-pino-logger'
@@ -86,16 +87,21 @@ class Server {
86
87
  #app: express.Application
87
88
  #connection: mongoose.Connection | undefined
88
89
  #log: HttpLogger
90
+ #server: HttpServer | undefined
89
91
 
90
92
  constructor() {
91
93
  this.#app = express()
92
94
  this.#log = pino({
93
- transport: {
94
- target: 'pino-pretty',
95
- options: {
96
- colorize: true
97
- }
98
- }
95
+ transport:
96
+ process.env.ENVIRONMENT !== 'production'
97
+ ? {
98
+ target: 'pino-pretty',
99
+ options: {
100
+ translateTime: 'HH:MM:ss Z',
101
+ ignore: 'pid,hostname'
102
+ }
103
+ }
104
+ : undefined
99
105
  })
100
106
  this.#config()
101
107
  }
@@ -104,6 +110,7 @@ class Server {
104
110
  this.#app.use(cors())
105
111
  this.#app.use(express.json())
106
112
  this.#app.use(express.urlencoded({ extended: false }))
113
+ this.#app.use(this.#log)
107
114
  this.#app.use(
108
115
  (
109
116
  req: express.Request,
@@ -158,7 +165,7 @@ class Server {
158
165
  }
159
166
 
160
167
  public start(): void {
161
- this.#app.listen(PORT, () => {
168
+ this.#server = this.#app.listen(PORT, () => {
162
169
  this.#log.logger.info(\`Server running at port \${PORT}\`)
163
170
  })
164
171
 
@@ -168,6 +175,16 @@ class Server {
168
175
  this.#log.logger.error(e)
169
176
  }
170
177
  }
178
+
179
+ public stop(): void {
180
+ try {
181
+ if (this.#server) this.#server.close()
182
+
183
+ process.exit(0)
184
+ } catch (e) {
185
+ this.#log.logger.error(e)
186
+ }
187
+ }
171
188
  }
172
189
 
173
190
  const server = new Server()
@@ -208,14 +225,14 @@ export * from './user'
208
225
 
209
226
  import { response } from 'network/response'
210
227
  import { UserService } from 'services'
211
- import { idSchema, storeUserSchema, UserDTO } from 'schemas'
228
+ import { idSchema, storeUserDto, UserWithId } from 'schemas'
212
229
  import { validatorCompiler } from './utils'
213
230
 
214
231
  const User = Router()
215
232
 
216
233
  User.route('/users')
217
234
  .post(
218
- validatorCompiler(storeUserSchema, 'body'),
235
+ validatorCompiler(storeUserDto, 'body'),
219
236
  async (
220
237
  req: CustomRequest,
221
238
  res: CustomResponse,
@@ -223,9 +240,9 @@ User.route('/users')
223
240
  ): Promise<void> => {
224
241
  try {
225
242
  const {
226
- body: { args }
243
+ body: { args: user }
227
244
  } = req
228
- const us = new UserService({ userDtoWithoutId: args })
245
+ const us = new UserService({ user })
229
246
  const result = await us.process({ type: 'store' })
230
247
 
231
248
  response({ error: false, message: result, res, status: 201 })
@@ -290,7 +307,7 @@ User.route('/user/:id')
290
307
  )
291
308
  .patch(
292
309
  validatorCompiler(idSchema, 'params'),
293
- validatorCompiler(storeUserSchema, 'body'),
310
+ validatorCompiler(storeUserDto, 'body'),
294
311
  async (
295
312
  req: CustomRequest,
296
313
  res: CustomResponse,
@@ -301,11 +318,11 @@ User.route('/user/:id')
301
318
  body: { args },
302
319
  params: { id }
303
320
  } = req
304
- const userDto = {
321
+ const userWithId = {
305
322
  id,
306
323
  ...args
307
- } as UserDTO
308
- const us = new UserService({ userDto })
324
+ } as UserWithId
325
+ const us = new UserService({ userWithId })
309
326
  const result = await us.process({ type: 'update' })
310
327
 
311
328
  response({ error: false, message: result, res, status: 200 })
@@ -447,11 +464,11 @@ export { User }
447
464
  content: `import { ApolloError } from 'apollo-server-core'
448
465
 
449
466
  import { store, remove, update } from 'database'
450
- import { UserDTO } from 'schemas'
467
+ import { User, UserDTO, UserWithId } from 'schemas'
451
468
  import { EFU, MFU, GE, errorHandling } from '../utils'
452
469
 
453
470
  const storeUser = async (
454
- { user }: { user: UserDTO },
471
+ { user }: { user: User },
455
472
  { log }: Context
456
473
  ): Promise<UserDTO> => {
457
474
  try {
@@ -489,7 +506,7 @@ const deleteAllUsers = async ({ log }: Context): Promise<string> => {
489
506
  }
490
507
 
491
508
  const updateUser = async (
492
- { user }: { user: UserDTO },
509
+ { user }: { user: UserWithId },
493
510
  { log }: Context
494
511
  ): Promise<UserDTO> => {
495
512
  try {
@@ -536,15 +553,22 @@ export { storeUser, deleteAllUsers, updateUser, deleteUser }
536
553
  content: `import { DefinedError } from 'ajv'
537
554
  import { ApolloError } from 'apollo-server-core'
538
555
 
539
- import { ajv, idSchema, UserDTO } from 'schemas'
540
- import { storeUserSchema, updateUserSchema } from './schemas'
556
+ import {
557
+ ajv,
558
+ idSchema,
559
+ User,
560
+ user as storeUserSchema,
561
+ UserDTO,
562
+ UserWithId,
563
+ userWithId as updateUserSchema
564
+ } from 'schemas'
541
565
  import { storeUser, updateUser, deleteUser, deleteAllUsers } from './mutations'
542
566
  import { errorHandling, GE } from '../utils'
543
567
 
544
568
  const Mutation = {
545
569
  storeUser: async (
546
570
  parent: unknown,
547
- { user }: { user: UserDTO },
571
+ { user }: { user: User },
548
572
  context: Context
549
573
  ): Promise<UserDTO> => {
550
574
  const { log } = context
@@ -576,7 +600,7 @@ const Mutation = {
576
600
  },
577
601
  updateUser: async (
578
602
  parent: unknown,
579
- { user }: { user: UserDTO },
603
+ { user }: { user: UserWithId },
580
604
  context: Context
581
605
  ): Promise<UserDTO> => {
582
606
  const validate = ajv.compile(updateUserSchema)
@@ -756,30 +780,6 @@ export { Query }
756
780
  `,
757
781
  file: `${projectName}/src/graphQL/models/User/queriesResolver.ts`
758
782
  },
759
- schemas: {
760
- content: `import { Type } from '@sinclair/typebox'
761
-
762
- const updateUserSchema = Type.Object(
763
- {
764
- id: Type.String({ minLength: 24, maxLength: 24 }),
765
- lastName: Type.String(),
766
- name: Type.String()
767
- },
768
- { additionalProperties: false }
769
- )
770
-
771
- const storeUserSchema = Type.Object(
772
- {
773
- lastName: Type.String({ minLength: 1 }),
774
- name: Type.String({ minLength: 1 })
775
- },
776
- { additionalProperties: false }
777
- )
778
-
779
- export { updateUserSchema, storeUserSchema }
780
- `,
781
- file: `${projectName}/src/graphQL/models/User/schemas.ts`
782
- },
783
783
  typeDefs: {
784
784
  content: `import { gql } from 'apollo-server-core'
785
785
 
@@ -788,6 +788,7 @@ const User = gql\`
788
788
  id: ID!
789
789
  name: String!
790
790
  lastName: String!
791
+ createdAt: String!
791
792
  updatedAt: String!
792
793
  }
793
794
 
@@ -850,7 +851,7 @@ export { ErrorForUser as EFU, MessageForUser as MFU }
850
851
  },
851
852
  index: {
852
853
  content: `import { ApolloError } from 'apollo-server-core'
853
- import { FastifyLoggerInstance } from 'fastify'
854
+ import { HttpLogger } from 'express-pino-logger'
854
855
 
855
856
  const errorHandling = ({
856
857
  e,
@@ -862,7 +863,7 @@ const errorHandling = ({
862
863
  e: any
863
864
  message: string
864
865
  code: string
865
- log: FastifyLoggerInstance
866
+ log: HttpLogger['logger']
866
867
  }): never => {
867
868
  log.error(e)
868
869
 
@@ -952,7 +953,7 @@ export { applyRoutes }
952
953
  file: `${projectName}/src/network/router.ts`
953
954
  },
954
955
  server: {
955
- content: `import http from 'http'
956
+ content: `import { createServer, Server as HttpServer } from 'http'
956
957
  import express from 'express'
957
958
  import mongoose from 'mongoose'
958
959
  import cors from 'cors'
@@ -972,28 +973,32 @@ const PORT = (process.env.PORT as string) || 1996
972
973
  class Server {
973
974
  #app: express.Application
974
975
  #connection: mongoose.Connection | undefined
975
- #httpServer: http.Server
976
+ #server: HttpServer
976
977
  #log: HttpLogger
977
978
 
978
979
  constructor() {
979
980
  this.#app = express()
980
- this.#httpServer = http.createServer(this.#app)
981
+ this.#server = createServer(this.#app)
981
982
  this.#log = pino({
982
- transport: {
983
- target: 'pino-pretty',
984
- options: {
985
- colorize: true
986
- }
987
- }
983
+ transport:
984
+ process.env.ENVIRONMENT !== 'production'
985
+ ? {
986
+ target: 'pino-pretty',
987
+ options: {
988
+ translateTime: 'HH:MM:ss Z',
989
+ ignore: 'pid,hostname'
990
+ }
991
+ }
992
+ : undefined
988
993
  })
989
994
  this.#config()
990
995
  }
991
996
 
992
997
  #config() {
993
998
  this.#app.use(cors())
994
- this.#app.use(this.#log)
995
999
  this.#app.use(express.json())
996
1000
  this.#app.use(express.urlencoded({ extended: false }))
1001
+ this.#app.use(this.#log)
997
1002
  this.#app.use(
998
1003
  (
999
1004
  req: express.Request,
@@ -1050,7 +1055,7 @@ class Server {
1050
1055
  const server = new ApolloServer({
1051
1056
  schema,
1052
1057
  plugins: [
1053
- ApolloServerPluginDrainHttpServer({ httpServer: this.#httpServer }),
1058
+ ApolloServerPluginDrainHttpServer({ httpServer: this.#server }),
1054
1059
  process.env.NODE_ENV === 'production'
1055
1060
  ? ApolloServerPluginLandingPageDisabled()
1056
1061
  : ApolloServerPluginLandingPageGraphQLPlayground()
@@ -1068,7 +1073,7 @@ class Server {
1068
1073
  })
1069
1074
  applyRoutes(this.#app)
1070
1075
  await this.#mongo()
1071
- this.#httpServer.listen(PORT, () => {
1076
+ this.#server.listen(PORT, () => {
1072
1077
  this.#log.logger.info(\`Server listening at port: \${PORT}\`)
1073
1078
  this.#log.logger.info(
1074
1079
  \`GraphQL server listening at: http://localhost:\${PORT}\${server.graphqlPath}\`
@@ -1078,6 +1083,16 @@ class Server {
1078
1083
  console.error(e)
1079
1084
  }
1080
1085
  }
1086
+
1087
+ public stop(): void {
1088
+ try {
1089
+ if (this.#server) this.#server.close()
1090
+
1091
+ process.exit(0)
1092
+ } catch (e) {
1093
+ this.#log.logger.error(e)
1094
+ }
1095
+ }
1081
1096
  }
1082
1097
 
1083
1098
  const server = new Server()
@@ -1180,10 +1195,6 @@ export { validatorCompiler }
1180
1195
  graphQL.models.User.queriesResolver.file,
1181
1196
  graphQL.models.User.queriesResolver.content
1182
1197
  ),
1183
- writeFile(
1184
- graphQL.models.User.schemas.file,
1185
- graphQL.models.User.schemas.content
1186
- ),
1187
1198
  writeFile(
1188
1199
  graphQL.models.User.typeDefs.file,
1189
1200
  graphQL.models.User.typeDefs.content
@@ -1295,12 +1306,14 @@ class Server {
1295
1306
  #connection: mongoose.Connection | undefined
1296
1307
 
1297
1308
  constructor() {
1298
- this.#app = fastify({ logger: { prettyPrint: true } })
1309
+ this.#app = fastify({
1310
+ logger: { prettyPrint: process.env.NODE_ENV !== 'production' }
1311
+ })
1299
1312
  this.#config()
1300
1313
  }
1301
1314
 
1302
1315
  #config() {
1303
- this.#app.register(require('fastify-cors'), {})
1316
+ this.#app.register(require('@fastify/cors'), {})
1304
1317
  this.#app.addHook('preHandler', (req, reply, done) => {
1305
1318
  reply.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE')
1306
1319
  reply.header('Access-Control-Allow-Origin', '*')
@@ -1357,6 +1370,15 @@ class Server {
1357
1370
  console.error(e)
1358
1371
  }
1359
1372
  }
1373
+
1374
+ public async stop(): Promise<void> {
1375
+ try {
1376
+ await this.#app.close()
1377
+ process.exit(0)
1378
+ } catch (e) {
1379
+ console.error(e)
1380
+ }
1381
+ }
1360
1382
  }
1361
1383
 
1362
1384
  const server = new Server()
@@ -1368,7 +1390,7 @@ export { server as Server }
1368
1390
  routes: {
1369
1391
  docs: {
1370
1392
  content: `import { FastifyInstance } from 'fastify'
1371
- import fastifySwagger from 'fastify-swagger'
1393
+ import fastifySwagger from '@fastify/swagger'
1372
1394
 
1373
1395
  const Docs = (app: FastifyInstance, prefix = '/api'): void => {
1374
1396
  app.register(fastifySwagger, {
@@ -1442,18 +1464,18 @@ import {
1442
1464
  userDto,
1443
1465
  idSchema,
1444
1466
  IdSchema,
1445
- storeUserSchema,
1446
- StoreUser
1467
+ storeUserDto,
1468
+ StoreUserDTO
1447
1469
  } from 'schemas'
1448
1470
  import { UserService } from 'services'
1449
1471
 
1450
1472
  const User = (app: FastifyInstance, prefix = '/api'): void => {
1451
1473
  app
1452
- .post<{ Body: StoreUser }>(
1474
+ .post<{ Body: StoreUserDTO }>(
1453
1475
  \`\${prefix}/users\`,
1454
1476
  {
1455
1477
  schema: {
1456
- body: storeUserSchema,
1478
+ body: storeUserDto,
1457
1479
  response: {
1458
1480
  200: {
1459
1481
  error: {
@@ -1472,7 +1494,7 @@ const User = (app: FastifyInstance, prefix = '/api'): void => {
1472
1494
  }
1473
1495
  } = request
1474
1496
  const us = new UserService({
1475
- userDtoWithoutId: { lastName, name }
1497
+ user: { lastName, name }
1476
1498
  })
1477
1499
  const user = await us.process({ type: 'store' })
1478
1500
 
@@ -1571,11 +1593,11 @@ const User = (app: FastifyInstance, prefix = '/api'): void => {
1571
1593
  })
1572
1594
  }
1573
1595
  )
1574
- .patch<{ Body: StoreUser; Params: IdSchema }>(
1596
+ .patch<{ Body: StoreUserDTO; Params: IdSchema }>(
1575
1597
  \`\${prefix}/user/:id\`,
1576
1598
  {
1577
1599
  schema: {
1578
- body: storeUserSchema,
1600
+ body: storeUserDto,
1579
1601
  params: idSchema,
1580
1602
  response: {
1581
1603
  200: {
@@ -1596,7 +1618,7 @@ const User = (app: FastifyInstance, prefix = '/api'): void => {
1596
1618
  params: { id }
1597
1619
  } = request
1598
1620
  const us = new UserService({
1599
- userDto: { name, lastName, id }
1621
+ userWithId: { name, lastName, id }
1600
1622
  })
1601
1623
  const user = await us.process({ type: 'update' })
1602
1624
 
@@ -1749,11 +1771,11 @@ export { User }
1749
1771
  content: `import { ApolloError } from 'apollo-server-core'
1750
1772
 
1751
1773
  import { store, remove, update } from 'database'
1752
- import { UserDTO } from 'schemas'
1774
+ import { User, UserDTO, UserWithId } from 'schemas'
1753
1775
  import { EFU, MFU, GE, errorHandling } from '../utils'
1754
1776
 
1755
1777
  const storeUser = async (
1756
- { user }: { user: UserDTO },
1778
+ { user }: { user: User },
1757
1779
  { log }: Context
1758
1780
  ): Promise<UserDTO> => {
1759
1781
  try {
@@ -1791,7 +1813,7 @@ const deleteAllUsers = async ({ log }: Context): Promise<string> => {
1791
1813
  }
1792
1814
 
1793
1815
  const updateUser = async (
1794
- { user }: { user: UserDTO },
1816
+ { user }: { user: UserWithId },
1795
1817
  { log }: Context
1796
1818
  ): Promise<UserDTO> => {
1797
1819
  try {
@@ -1838,15 +1860,22 @@ export { storeUser, deleteAllUsers, updateUser, deleteUser }
1838
1860
  content: `import { DefinedError } from 'ajv'
1839
1861
  import { ApolloError } from 'apollo-server-core'
1840
1862
 
1841
- import { ajv, idSchema, UserDTO } from 'schemas'
1842
- import { storeUserSchema, updateUserSchema } from './schemas'
1863
+ import {
1864
+ ajv,
1865
+ idSchema,
1866
+ User,
1867
+ user as storeUserSchema,
1868
+ UserDTO,
1869
+ UserWithId,
1870
+ userWithId as updateUserSchema
1871
+ } from 'schemas'
1843
1872
  import { storeUser, updateUser, deleteUser, deleteAllUsers } from './mutations'
1844
1873
  import { errorHandling, GE } from '../utils'
1845
1874
 
1846
1875
  const Mutation = {
1847
1876
  storeUser: async (
1848
1877
  parent: unknown,
1849
- { user }: { user: UserDTO },
1878
+ { user }: { user: User },
1850
1879
  context: Context
1851
1880
  ): Promise<UserDTO> => {
1852
1881
  const { log } = context
@@ -1878,7 +1907,7 @@ const Mutation = {
1878
1907
  },
1879
1908
  updateUser: async (
1880
1909
  parent: unknown,
1881
- { user }: { user: UserDTO },
1910
+ { user }: { user: UserWithId },
1882
1911
  context: Context
1883
1912
  ): Promise<UserDTO> => {
1884
1913
  const validate = ajv.compile(updateUserSchema)
@@ -2058,30 +2087,6 @@ export { Query }
2058
2087
  `,
2059
2088
  file: `${projectName}/src/graphQL/models/User/queriesResolver.ts`
2060
2089
  },
2061
- schemas: {
2062
- content: `import { Type } from '@sinclair/typebox'
2063
-
2064
- const updateUserSchema = Type.Object(
2065
- {
2066
- id: Type.String({ minLength: 24, maxLength: 24 }),
2067
- lastName: Type.String(),
2068
- name: Type.String()
2069
- },
2070
- { additionalProperties: false }
2071
- )
2072
-
2073
- const storeUserSchema = Type.Object(
2074
- {
2075
- lastName: Type.String({ minLength: 1 }),
2076
- name: Type.String({ minLength: 1 })
2077
- },
2078
- { additionalProperties: false }
2079
- )
2080
-
2081
- export { updateUserSchema, storeUserSchema }
2082
- `,
2083
- file: `${projectName}/src/graphQL/models/User/schemas.ts`
2084
- },
2085
2090
  typeDefs: {
2086
2091
  content: `import { gql } from 'apollo-server-core'
2087
2092
 
@@ -2090,6 +2095,7 @@ const User = gql\`
2090
2095
  id: ID!
2091
2096
  name: String!
2092
2097
  lastName: String!
2098
+ createdAt: String!
2093
2099
  updatedAt: String!
2094
2100
  }
2095
2101
 
@@ -2272,7 +2278,9 @@ class Server {
2272
2278
  #connection: mongoose.Connection | undefined
2273
2279
 
2274
2280
  constructor() {
2275
- this.#app = fastify({ logger: { prettyPrint: true } })
2281
+ this.#app = fastify({
2282
+ logger: { prettyPrint: process.env.NODE_ENV !== 'production' }
2283
+ })
2276
2284
  this.#config()
2277
2285
  }
2278
2286
 
@@ -2369,6 +2377,15 @@ class Server {
2369
2377
  console.error(e)
2370
2378
  }
2371
2379
  }
2380
+
2381
+ public async stop(): Promise<void> {
2382
+ try {
2383
+ await this.#app.close()
2384
+ process.exit(0)
2385
+ } catch (e) {
2386
+ console.error(e)
2387
+ }
2388
+ }
2372
2389
  }
2373
2390
 
2374
2391
  const server = new Server()
@@ -2380,7 +2397,7 @@ export { server as Server }
2380
2397
  routes: {
2381
2398
  docs: {
2382
2399
  content: `import { FastifyInstance } from 'fastify'
2383
- import fastifySwagger from 'fastify-swagger'
2400
+ import fastifySwagger from '@fastify/swagger'
2384
2401
 
2385
2402
  const Docs = (app: FastifyInstance, prefix = '/api'): void => {
2386
2403
  app.register(fastifySwagger, {
@@ -2469,10 +2486,6 @@ export * from './docs'
2469
2486
  graphQL.models.User.queriesResolver.file,
2470
2487
  graphQL.models.User.queriesResolver.content
2471
2488
  ),
2472
- writeFile(
2473
- graphQL.models.User.schemas.file,
2474
- graphQL.models.User.schemas.content
2475
- ),
2476
2489
  writeFile(
2477
2490
  graphQL.models.User.typeDefs.file,
2478
2491
  graphQL.models.User.typeDefs.content
@@ -46,6 +46,10 @@ const user = Type.Object({
46
46
 
47
47
  type User = Static<typeof user>
48
48
 
49
+ const userWithId = Type.Intersect([user, Type.Object({ id })])
50
+
51
+ type UserWithId = Static<typeof userWithId>
52
+
49
53
  const userDto = Type.Object({
50
54
  id: Type.Optional(id),
51
55
  lastName: Type.String(),
@@ -56,19 +60,28 @@ const userDto = Type.Object({
56
60
 
57
61
  type UserDTO = Static<typeof userDto>
58
62
 
59
- const storeUserSchema = Type.Object({
63
+ const storeUserDto = Type.Object({
60
64
  args: user
61
65
  })
62
66
 
63
- type StoreUser = Static<typeof storeUserSchema>
64
-
65
- export { userDto, UserDTO, user, User, storeUserSchema, StoreUser }
67
+ type StoreUserDTO = Static<typeof storeUserDto>
68
+
69
+ export {
70
+ userDto,
71
+ UserDTO,
72
+ userWithId,
73
+ UserWithId,
74
+ user,
75
+ User,
76
+ storeUserDto,
77
+ StoreUserDTO
78
+ }
66
79
  `,
67
80
  file: `${projectName}/src/schemas/user.ts`
68
81
  }
69
82
  }
70
83
 
71
- if (graphql) {
84
+ if (graphql)
72
85
  schemas.index.content = `import { Static, Type } from '@sinclair/typebox'
73
86
  import Ajv from 'ajv/dist/2019.js'
74
87
  import addFormats from 'ajv-formats'
@@ -90,30 +103,6 @@ const ajv = addFormats(new Ajv(), ['email'])
90
103
  export { id, ID, idSchema, IDSchema, ajv }
91
104
  export * from './user'
92
105
  `
93
- schemas.user.content = `import { Static, Type } from '@sinclair/typebox'
94
-
95
- import { id } from '.'
96
-
97
- const user = Type.Object({
98
- lastName: Type.String(),
99
- name: Type.String()
100
- })
101
-
102
- type User = Static<typeof user>
103
-
104
- const userDto = Type.Object({
105
- id: Type.Optional(id),
106
- lastName: Type.String(),
107
- name: Type.String(),
108
- createdAt: Type.Optional(Type.String()),
109
- updatedAt: Type.Optional(Type.String())
110
- })
111
-
112
- type UserDTO = Static<typeof userDto>
113
-
114
- export { userDto, UserDTO, user, User }
115
- `
116
- }
117
106
 
118
107
  await Promise.all([
119
108
  writeFile(schemas.index.file, schemas.index.content),
@@ -25,7 +25,7 @@ ${projectName}/src/services/utils/messages`
25
25
  content: `import httpErrors from 'http-errors'
26
26
 
27
27
  import { store, remove, get, update } from 'database'
28
- import { UserDTO } from 'schemas'
28
+ import { User, UserDTO, UserWithId } from 'schemas'
29
29
  import { EFU, MFU, GE, errorHandling } from './utils'
30
30
 
31
31
  type Process = {
@@ -34,8 +34,8 @@ type Process = {
34
34
 
35
35
  type Arguments = {
36
36
  id?: string
37
- userDto?: UserDTO
38
- userDtoWithoutId?: Omit<UserDTO, 'id'>
37
+ user?: User
38
+ userWithId?: UserWithId
39
39
  }
40
40
 
41
41
  class UserService {
@@ -66,12 +66,10 @@ class UserService {
66
66
 
67
67
  async #store(): Promise<UserDTO> {
68
68
  try {
69
- if (!this.#args.userDtoWithoutId)
69
+ if (!this.#args.user)
70
70
  throw new httpErrors.UnprocessableEntity(GE.INTERNAL_SERVER_ERROR)
71
71
 
72
- const result = await store({
73
- ...this.#args.userDtoWithoutId
74
- })
72
+ const result = await store(this.#args.user)
75
73
 
76
74
  return result
77
75
  } catch (e) {
@@ -122,10 +120,10 @@ class UserService {
122
120
 
123
121
  async #update(): Promise<UserDTO> {
124
122
  try {
125
- if (!this.#args.userDto || !this.#args.userDto.id)
123
+ if (!this.#args.userWithId || !this.#args.userWithId.id)
126
124
  throw new httpErrors.UnprocessableEntity(GE.INTERNAL_SERVER_ERROR)
127
125
 
128
- const updatedUser = await update(this.#args.userDto)
126
+ const updatedUser = await update(this.#args.userWithId)
129
127
 
130
128
  if (!updatedUser) throw new httpErrors.NotFound(EFU.NOT_FOUND)
131
129
 
@@ -32,7 +32,6 @@ export {}
32
32
  models: {
33
33
  user: {
34
34
  content: `interface UserDBO {
35
- id: string
36
35
  name: string
37
36
  lastName: string
38
37
  createdAt: Date
@@ -10,7 +10,7 @@ module.exports = async projectName => {
10
10
 
11
11
  WORKDIR /app
12
12
 
13
- COPY package.json ./
13
+ COPY . ./
14
14
 
15
15
  RUN yarn install --prod
16
16
 
@@ -20,12 +20,28 @@ RUN yarn build
20
20
 
21
21
  RUN yarn remove webpack webpack-node-externals tsconfig-paths-webpack-plugin
22
22
 
23
- COPY dist /app/dist
24
-
25
23
  CMD [ "yarn", "start" ]
26
24
  `,
27
- dockerFile: 'Dockerfile'
25
+ dockerFile: 'Dockerfile',
26
+ dockerIgnoreContent: `.eslintignore
27
+ .eslintrc
28
+ .gitignore
29
+ CHANGELOG.md
30
+ Dockerfile
31
+ heroku.yml
32
+ *.http
33
+ LICENSE
34
+ nodemon.json
35
+ README.md
36
+
37
+ # optionally you may want to ignore the .env file, but that depends on your own implementation
38
+ .env`,
39
+ dockerIgnoreFile: '.dockerignore'
28
40
  }
29
41
 
30
42
  await writeFile(`${projectName}/${data.dockerFile}`, data.dockerContent)
43
+ await writeFile(
44
+ `${projectName}/${data.dockerIgnoreFile}`,
45
+ data.dockerIgnoreContent
46
+ )
31
47
  }
package/lib/src/index.js CHANGED
@@ -62,7 +62,7 @@ module.exports = async ({
62
62
  graphql ? 'apollo-server-express' : ''
63
63
  }`
64
64
 
65
- const fastifyProdPackages = `fastify fastify-swagger fastify-cors ${
65
+ const fastifyProdPackages = `fastify@^3 @fastify/swagger@^6 @fastify/cors@^7 ${
66
66
  graphql ? 'apollo-server-fastify apollo-server-plugin-base' : ''
67
67
  }`
68
68
 
package/package.json CHANGED
@@ -1,12 +1,8 @@
1
1
  {
2
2
  "name": "@anthonylzq/simba.js",
3
- "version": "5.0.0",
3
+ "version": "5.2.0",
4
4
  "description": "set up a modern backend app by running one command",
5
5
  "main": "lib/index.js",
6
- "directories": {
7
- "example": "example",
8
- "lib": "lib"
9
- },
10
6
  "scripts": {
11
7
  "service": "node ./bin",
12
8
  "help": "node ./bin --help",
@@ -45,23 +41,23 @@
45
41
  "author": "AnthonyLzq",
46
42
  "license": "MIT",
47
43
  "dependencies": {
48
- "cli-progress": "^3.10.0",
44
+ "cli-progress": "^3.11.2",
49
45
  "colors": "^1.4.0",
50
46
  "readline-sync": "^1.4.10",
51
- "underscore": "^1.13.2",
52
- "yargs": "^17.4.1"
47
+ "underscore": "^1.13.4",
48
+ "yargs": "^17.5.1"
53
49
  },
54
50
  "devDependencies": {
55
- "dotenv": "^16.0.0",
56
- "eslint": "^8.13.0",
51
+ "dotenv": "^16.0.1",
52
+ "eslint": "^8.18.0",
57
53
  "eslint-config-prettier": "^8.5.0",
58
- "eslint-config-standard": "^16.0.3",
54
+ "eslint-config-standard": "^17.0.0",
59
55
  "eslint-plugin-import": "^2.26.0",
60
56
  "eslint-plugin-node": "^11.1.0",
61
57
  "eslint-plugin-prettier": "^4.0.0",
62
58
  "eslint-plugin-promise": "^6.0.0",
63
- "prettier": "^2.6.2",
64
- "standard-version": "^9.3.2"
59
+ "prettier": "^2.7.1",
60
+ "standard-version": "^9.5.0"
65
61
  },
66
62
  "repository": {
67
63
  "type": "git",
@@ -81,5 +77,9 @@
81
77
  "commit": true,
82
78
  "bump": true
83
79
  }
80
+ },
81
+ "engines": {
82
+ "npm": ">=8.0.0",
83
+ "node": ">=16.0.0"
84
84
  }
85
85
  }