beech-api 3.7.23 → 3.8.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.
Files changed (43) hide show
  1. package/README.md +490 -168
  2. package/index.js +2 -2
  3. package/package.json +8 -1
  4. package/packages/cli/beech +2 -2
  5. package/packages/cli/bin/beech-app.js +10 -8
  6. package/packages/cli/bin/beech-service.js +1 -1
  7. package/packages/cli/core/auth/Credentials.js +139 -89
  8. package/packages/cli/core/auth/Passport.js +264 -164
  9. package/packages/cli/core/auth/_Request.js +1 -1
  10. package/packages/cli/core/configure/app.config-basic.js +2 -2
  11. package/packages/cli/core/configure/app.config-sequelize.js +2 -2
  12. package/packages/cli/core/configure/beech.config.js +1 -0
  13. package/packages/cli/core/configure/passport.config.js +33 -13
  14. package/packages/cli/core/databases/sequelize.js +3 -0
  15. package/packages/cli/core/databases/test.js +5 -3
  16. package/packages/cli/core/generator/_endpoints +5 -9
  17. package/packages/cli/core/generator/_endpoints_basic +11 -8
  18. package/packages/cli/core/generator/_help +1 -1
  19. package/packages/cli/core/generator/_models +5 -4
  20. package/packages/cli/core/generator/_models_basic +2 -2
  21. package/packages/cli/core/generator/_package +5 -1
  22. package/packages/cli/core/generator/{_add-on → _scheduler} +1 -1
  23. package/packages/cli/core/generator/_spec +15 -10
  24. package/packages/cli/core/generator/index.js +19 -44
  25. package/packages/cli/core/helpers/2fa.js +85 -0
  26. package/packages/cli/core/helpers/math.js +55 -7
  27. package/packages/cli/core/helpers/poolEntity.js +29 -1
  28. package/packages/cli/core/index.js +65 -34
  29. package/packages/cli/core/middleware/express/duplicateRequest.js +12 -0
  30. package/packages/cli/core/middleware/express/jwtCheckAllow.js +68 -0
  31. package/packages/cli/core/middleware/express/rateLimit.js +17 -0
  32. package/packages/cli/core/middleware/express/slowDown.js +2 -0
  33. package/packages/cli/core/middleware/index.js +6 -0
  34. package/packages/cli/core/middleware/origin/guard/advance.js +74 -0
  35. package/packages/cli/core/{origin → middleware/origin}/whitelist/cors.js +15 -12
  36. package/packages/cli/core/services/http.express.js +116 -72
  37. package/packages/lib/index.js +3 -1
  38. package/packages/lib/src/endpoint.js +523 -89
  39. package/packages/lib/src/guard.js +61 -0
  40. package/packages/lib/src/schema.js +57 -26
  41. package/packages/lib/src/specificExpress.js +7 -0
  42. package/packages/lib/src/user.js +94 -18
  43. package/packages/cli/core/origin/index.js +0 -2
package/README.md CHANGED
@@ -1,38 +1,36 @@
1
1
  [![N|Solid](https://i.ibb.co/NKxx9NQ/beech320.jpg)](https://github.com/bombkiml)
2
2
 
3
3
  # Beech API framework
4
+ #### Stable v.3.8.0 (LTS)
4
5
 
5
- [![beech-api release](https://img.shields.io/github/v/release/bombkiml/beech-api)](https://github.com/bombkiml/beech-api/releases/)
6
+ [![beech-api release](https://img.shields.io/github/v/release/bombkiml/beech-api)](https://github.com/bombkiml/beech-api/releases/tag/3.8.0)
6
7
  [![PyPI license](https://shields.io/pypi/l/ansicolortags.svg)](https://github.com/bombkiml/beech-api/blob/master/README.md)
7
8
 
8
- ## What is Beech API ?
9
+ # What is Beech API ?
9
10
 
10
- `Beech API` is a Node.js framework it's help you with very easy create API project under [Node.js](https://nodejs.org)
11
+ The Beech API is API framework, It's help you with very easy to create API project under [Node.js](https://nodejs.org)
11
12
 
12
- ## Why Beech API ?
13
-
14
- `Beech API` is a Very easy for using, very feather framework, easy to installation, easy to implementation, and high security.
15
-
16
- ## Powered by Node.js & Express.js
17
-
18
- ![N|Solid](https://i.ibb.co/CQqYZkK/node-epressjs.jpg)
19
-
20
- ## Environment
13
+ # Environment
21
14
 
22
15
  - [`Node.js`](https://nodejs.org) >= 14.19.0+ (recommended)
23
16
 
24
- ## Installation
17
+ # Installation
25
18
 
26
19
  Beech API requires Node.js version 14.19.0 or above. You can manage multiple versions of Node on the same machine with [nvm](https://github.com/creationix/nvm) or [nvm-windows](https://github.com/coreybutler/nvm-windows). So, Let's go to install `beech-api`
27
20
 
28
21
  ```sh
29
- // NPM
22
+ # NPM
30
23
  $ npm install beech-api --global
31
24
 
32
- // Yarn
25
+ # Yarn
33
26
  $ yarn global add beech-api
34
27
  ```
35
28
 
29
+ Installation demo:
30
+
31
+ [Demo](https://i.ibb.co/hySFxy3/install-beech720-1.gif)
32
+ ![Alt Text](https://i.ibb.co/hySFxy3/install-beech720-1.gif)
33
+
36
34
  After installation, you will have access to the `beech-app` binary in your command line.
37
35
  You can check you have the right version with this command:
38
36
 
@@ -40,7 +38,7 @@ You can check you have the right version with this command:
40
38
  $ beech-app --version
41
39
  ```
42
40
 
43
- ## Creating a project
41
+ # Creating a project
44
42
 
45
43
  Create a new project run:
46
44
 
@@ -52,14 +50,14 @@ Run your project:
52
50
  $ cd hello-world
53
51
 
54
52
  $ npm start
55
- // OR
53
+ # OR
56
54
  $ yarn start
57
55
  ```
58
56
 
59
57
  ❓ **Note:** The Beech API it's start server at [http://localhost:9000](http://localhost:9000) you can change new a port in `app.config.js` file.
60
58
 
61
59
 
62
- ## Upgrade to latest version ##
60
+ # Upgrade to latest version
63
61
  The Beech API upgrade to latest version command avariable :
64
62
 
65
63
  ```sh
@@ -70,7 +68,7 @@ $ beech-app update
70
68
  $ beech-app update -g, --global
71
69
  ```
72
70
 
73
- ## Beech CLI tool available ##
71
+ # Beech CLI tool available
74
72
  After installation, you will have access to the `beech` binary in your command line.
75
73
  The `beech` command has a number of options and you can explore them all by running:
76
74
 
@@ -96,13 +94,13 @@ The following commands are available:
96
94
  $ beech make <model> -M, --model Create a new Models file.
97
95
  $ beech make <helper> --helper Create a new Helpers file.
98
96
  $ beech passport init Initialize authentication with passport-jwt.
99
- $ beech add-on init Initialize add-on file.
97
+ $ beech skd init Initialize Job Scheduler file.
100
98
  $ beech key:generate, key:gen Re-Generate application key (Dangerous!).
101
99
  $ beech hash:<text> Hash text for Access to Database connection.
102
100
  ```
103
101
  ❓ **Note:** Every to create new project will be generated new ``app_key`` in ``app.config.js`` file, If you can re-generate. Can use command ``$ beech key:generate`` or ``$ beech key:gen``
104
102
 
105
- ## Database connection ##
103
+ # Database connection
106
104
 
107
105
  You might connection to Database with `database_config` object in `app.config.js` file. Anything can support to multiple Database connections.
108
106
 
@@ -116,11 +114,11 @@ In case Access to Database must to Hash the `username` and `password` with Beech
116
114
  ```sh
117
115
  // Hash database username
118
116
  $ beech hash:root
119
- Output: m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SfuLCgI431oafWBtQJoJDnoCL
117
+ Output: m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SLCgI431oafWBtQJoJDnoCL
120
118
 
121
119
  // Hash database password
122
120
  $ beech hash:password
123
- Output: FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3T4ATk3YYAyvprdrQejtMGu3dcDS0ejA
121
+ Output: FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA
124
122
 
125
123
  ```
126
124
  Example:
@@ -136,13 +134,27 @@ database_config: [
136
134
  dialect: "mysql",
137
135
  name: "mysql_my_store_db",
138
136
  host: "localhost",
139
- username: "m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SfuLCgI431oafWBtQJoJDnoCL",
140
- password: "FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3T4ATk3YYAyvprdrQejtMGu3dcDS0ejA",
137
+ username: "m42BVxQ6Q4kLdRX7xS_Hm7WbQiNqShJDvw9SLCgI431oafWBtQJoJDnoCL",
138
+ password: "FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA",
141
139
  database: "my_store_db",
142
140
  port: "3306",
141
+
142
+ // Specify global options, which are used when Define is called.
143
+ define: {
144
+ charset: "utf8",
145
+ freezeTableName: true,
146
+ ...
147
+ },
148
+
149
+ timezone: "+07:00", // Example: GMT+2
150
+ // or use a named timezone supported by Intl.Locale
151
+ // timezone: 'America/Los_Angeles',
152
+
153
+ logging: console.log, // SQL trace logs
154
+
143
155
  is_connect: true, // boolean, Turn ON/OFF to connect
144
156
  },
145
-
157
+
146
158
  ...
147
159
 
148
160
  ],
@@ -151,9 +163,9 @@ database_config: [
151
163
  ```
152
164
  ❓ **Caution! :** Every re-new generate `app_key`. Must to new Hash your Access and change to ALL Database connections.
153
165
 
154
- ## Part of generate file
166
+ # Part of generate file
155
167
 
156
- ### # Generate Endpoints ###
168
+ ## # Generate Endpoints
157
169
 
158
170
  The `endpoints` keep the endpoints basic request files currently support `GET`, `POST`, `PUT`, `PATCH` and `DELETE`.
159
171
 
@@ -162,27 +174,32 @@ So, you might create new endpoints with constant `endpoint` object variable in `
162
174
  ```sh
163
175
  $ beech make endpointName
164
176
  ```
165
- **Example ***(Basic)***** : Fruits endpoints.
177
+ You might using [special] `-R, --require` for choose Model(s) used for that endpoint.
178
+
179
+ ### Example ***(Basic)*** : Fruit endpoints.
166
180
 
167
- 📂 fruits-endpoints.js
181
+ 📂 fruit-endpoints.js
168
182
  ```js
169
183
  exports.init = () => {
170
184
 
171
185
  // GET method
172
- endpoint.get("/fruits", Credentials, (req, res) => {
186
+ endpoint.get("/fruit", Credentials, (req, res) => {
173
187
  // @response
174
188
  res.json({
175
189
  code: 200,
176
- message: "Got a GET request.",
190
+ status: "SUCCESS",
191
+ message: "GET /fruit request.",
177
192
  });
178
193
  });
179
194
 
180
195
 
181
196
  // POST method
182
- endpoint.post("/fruits", Credentials, (req, res) => {
197
+ endpoint.post("/fruit", Credentials, (req, res) => {
183
198
  // @response
184
199
  res.json({
185
200
  code: 200,
201
+ status: "SUCCESS",
202
+ message: "POST request at /fruit",
186
203
  result: {
187
204
  id: req.body.id,
188
205
  name: req.body.name,
@@ -192,21 +209,23 @@ exports.init = () => {
192
209
 
193
210
 
194
211
  // PUT method
195
- endpoint.put("/fruits/:id", Credentials, (req, res) => {
212
+ endpoint.put("/fruit/:id", Credentials, (req, res) => {
196
213
  // @response
197
214
  res.json({
198
215
  code: 200,
199
- message: "Got a PUT request /fruits/" + req.params.id,
216
+ status: "SUCCESS",
217
+ message: "PUT request at /fruit/" + req.params.id,
200
218
  });
201
219
  });
202
220
 
203
221
 
204
222
  // DELETE method
205
- endpoint.delete("/fruits/:id", Credentials, (req, res) => {
223
+ endpoint.delete("/fruit/:id", Credentials, (req, res) => {
206
224
  // @response
207
225
  res.json({
208
226
  code: 200,
209
- message: "Got a DELETE request /fruits/" + req.params.id,
227
+ status: "SUCCESS",
228
+ message: "DELETE request at /fruit/" + req.params.id,
210
229
  });
211
230
  });
212
231
 
@@ -215,30 +234,23 @@ exports.init = () => {
215
234
  }
216
235
  ```
217
236
 
218
- **Example ***(Sequelize)***** : Fruits endpoints.
237
+ ### Example ***(Sequelize)*** : Fruit endpoints.
219
238
 
220
- 📂 fruits-endpoints.js
239
+ 📂 fruit-endpoints.js
221
240
  ```js
222
- // You can declare Base with Beech Core for initial default endpoint [GET, POST, PATCH, DELETE]
223
- const { Base } = require("beech-api"); 👈
224
-
225
- // Model schema & function
226
- const { Fruits } = require("@/models/Fruits");
241
+ // Require Model schema, Function & Others
242
+ const { Fruit } = require("@/models/Fruit");
227
243
 
228
244
  exports.init = () => {
229
245
 
230
- // initialize Fruits Model
231
- Base([Fruits]); 👈 // It's like magic creating endpoints for you (CRUD) ✨
232
-
233
- // Now you can request /fruits with methods GET, POST, PATCH and DELETE
234
- // (C) POST: /fruits with { body }
235
- // (R) GET: /fruits /:limit?/:offset?
236
- // (U) PATCH: /fruits/:id with { body }
237
- // (D) DELETE: /fruits/:id
238
-
239
- // Other GET method
240
- endpoint.get('/example-fruits', (req, res) => {
241
- ...
246
+ // GET method
247
+ endpoint.get('/fruit', async (req, res) => {
248
+ // example call Fruit model for get data
249
+ res.json({
250
+ code: 200,
251
+ status: "SUCCESS",
252
+ results: await Fruit.findAll();
253
+ });
242
254
  });
243
255
 
244
256
  ...
@@ -247,17 +259,17 @@ exports.init = () => {
247
259
  ```
248
260
 
249
261
 
250
- ### # Generate Models ###
262
+ ## # Generate Models ###
251
263
 
252
- The `models` keep the files of function(s) for retriving, inserting, updating and deleting with SQL data. for understanding you might make model name same your table name in `src/models` folder.
264
+ The `models` keep the files of function(s) data managemnets for Retriving, Creating, Updating and Destroying (CRUD). for understanding you might make model name same your table name inside `src/models` folder.
253
265
 
254
266
  ```sh
255
267
  $ beech make modelName --model
256
268
  ```
257
269
 
258
- **Example ***(Basic)***** : Fruits model.
270
+ ### Example ***(Basic)*** : Fruit model.
259
271
 
260
- 📂 Fruits.js
272
+ 📂 Fruit.js
261
273
  ```js
262
274
  module.exports = {
263
275
 
@@ -272,10 +284,10 @@ module.exports = {
272
284
  },
273
285
 
274
286
  // Example basic function get data from MySQL table
275
- getFruits() {
287
+ getFruit() {
276
288
 
277
- // call example mysql `mysql.default_db` connection name
278
- mysql.default_db.query("SELECT * FROM fruits", (err, results) => {
289
+ // calling Pool connection name by `mysql.default_db`
290
+ mysql.default_db.query("SELECT * FROM fruit", (err, results) => {
279
291
 
280
292
  if (err) { throw err }
281
293
  return results;
@@ -287,64 +299,208 @@ module.exports = {
287
299
  };
288
300
  ```
289
301
 
290
- **Example ***(Sequelize)***** : Fruits model.
302
+ ### Example ***(Sequelize)*** : Fruit model.
291
303
 
292
304
  You can asign more DataTypes, Learn more : [Sequelize docs](https://sequelize.org/docs/v6/core-concepts/model-basics/#data-types)
293
305
 
294
- 📂Fruits.js
306
+ 📂Fruit.js
295
307
  ```js
296
308
  const { Schema } = require("beech-api");
297
309
 
298
310
  // Define table Schema with `Schema(sql.default_db)` connection name
299
- const Fruits = Schema(sql.default_db).define("fruits", {
311
+ const Fruit = Schema(sql.default_db).define("fruit", {
300
312
  fruit_id: {
301
- field: "id", // Ref: field `id` in fruits table
313
+ field: "id", // Rename PK field to fruit_id Ref: `id` field in fruit table
302
314
  type: DataTypes.INTEGER,
303
315
  autoIncrement: true,
304
316
  primaryKey: true
305
317
  },
306
- fruitsName: DataTypes.STRING,
307
- fruitsQty: DataTypes.INTEGER,
308
- fruitsPrice: {
318
+ friut_uuid: {
319
+ field: "uuid",
320
+ type: DataTypes.STRING(100),
321
+ allowNull: true,
322
+ defaultValue: DataTypes.UUIDV4,
323
+ },
324
+ fruitName: DataTypes.STRING,
325
+ fruitQty: DataTypes.INTEGER,
326
+ fruitPrice: {
309
327
  type: DataTypes.INTEGER,
310
328
  allowNull: false, // Allow null feilds
311
329
  },
312
- createdAt: DataTypes.DATE,
313
- updatedAt: DataTypes.DATE,
330
+ createdAt: {
331
+ type: DataTypes.DATE,
332
+ allowNull: false,
333
+ defaultValue: DataTypes.NOW,
334
+ },
335
+ updatedAt: {
336
+ type: DataTypes.DATE,
337
+ allowNull: true,
338
+ },
339
+ }, {
340
+ // Enables timestamps with createdAt and updatedAt
341
+ timestamps: true,
342
+ // Custom field names createdAt and updatedAt
343
+ createdAt: "createdAt",
344
+ updatedAt: "updatedAt",
314
345
  });
315
346
 
347
+ Fruit.options = {
348
+ // Choose one for Allow magic generate default Endpoint (CRUD), It's like magic creating The endpoints for you (CRUD) ✨
349
+
350
+ // Option 1: Allow all methods
351
+ defaultEndpoint: true,
352
+
353
+ // Option 2: Allow with specific per methods
354
+ defaultEndpoint: {
355
+ GET: true,
356
+ POST: false,
357
+ PATCH: {
358
+ allow: true, // allow Auto-Endpoint
359
+ jwt: {
360
+ allow: true, // allow JWT
361
+ broken_role: [
362
+ { role: [1, 2] },
363
+ ],
364
+ },
365
+ },
366
+ DELETE: false,
367
+ },
368
+
369
+ limitRows: 100, // Limit rows default 100
370
+
371
+ };
372
+
316
373
  // Example Finder by id (ORM), Learn more: https://sequelize.org/docs/v6/core-concepts/model-querying-finders/
317
- function exampleFindOneFruitsById(id) {
318
- return Fruits.findOne({ where: { id: id } });
374
+ function exampleFindOneFruitById(id) {
375
+ return Fruit.findOne({ where: { id: id } });
319
376
  }
320
377
 
321
- // Example Raw Query, Learn more: https://sequelize.org/docs/v6/core-concepts/raw-queries/
322
- function exampleGetAllFruits(id) {
323
- return Fruits.query("SELECT * FROM fruits");
324
- }
325
378
 
326
379
  // Example Raw Query with Model Instances. This allows you to easily map a query to a predefined model
327
- function exampleGetAllFruitsWithModelInstance(id) {
328
- return Fruits.query("SELECT * FROM fruits", {
329
- model: Fruits, // When JOIN table needed register that table [Fruits, ...]
380
+ function exampleGetAllFruitWithModelInstance(id) {
381
+ return Fruit.query("SELECT * FROM fruit", {
382
+ model: Fruit, // When JOIN table needed register that table [Fruit, ...]
330
383
  mapToModel: true // pass true here if you have any mapped fields
331
384
  });
332
385
  }
333
386
 
387
+ // Example Raw Query, Learn more: https://sequelize.org/docs/v6/core-concepts/raw-queries/
388
+ function exampleGetAllFruit(id) {
389
+ return Fruit.query("SELECT * FROM fruit");
390
+ }
391
+
334
392
  ...
335
393
 
336
394
  // Export Schema, Function, ...
337
395
  module.exports = {
338
- Fruits,
339
- exampleFindFruitsById,
340
- exampleGetAllFruits,
341
- exampleGetAllFruitsWithModelInstance,
396
+ Fruit,
397
+ exampleFindOneFruitById,
398
+ exampleGetAllFruitWithModelInstance,
399
+ exampleGetAllFruit,
342
400
  ...
343
401
  };
344
402
  ```
403
+ #### That's cool! It's like magic creating The endpoints for you (CRUD) ✨
404
+
405
+ Now! you can request to `/fruit` with methods GET, POST, PATCH and DELETE like this.
406
+
407
+ | Efficacy | Method | Endpoint | Body |
408
+ |:---------|:---------|:-----------------------|:-----------|
409
+ | Create | POST | /fruit | { } |
410
+ | Read | GET | /fruit | No |
411
+ | Read | GET | /fruit/:id | No |
412
+ | Read | GET | /fruit/:limit/:offset | No |
413
+ | Update | PATCH | /fruit/:id | { } |
414
+ | Delete | DELETE | /fruit/:id | No |
415
+
416
+ ## # Transactions
417
+
418
+ Sequelize does not use transactions by default. However, for production-ready usage of Sequelize, you should definitely configure Sequelize to use transactions.
419
+
420
+ Beech use Sequelize supports three ways of using transactions:
421
+
422
+ - ### Way 1 - Disorganized transactions :
423
+ ```js
424
+ // First, we start a transaction from your connection and save it into a variable
425
+ const t = await Fruit.transaction();
426
+
427
+ try {
428
+
429
+ // Then, we do some calls passing this transaction as an option:
430
+ const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
431
+ await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
432
+
433
+ // If the execution reaches this line, no errors were thrown.
434
+ // We commit the transaction.
435
+ await t.commit();
436
+
437
+ } catch (error) {
438
+
439
+ // If the execution reaches this line, an error was thrown.
440
+ // We rollback the transaction.
441
+ await t.rollback();
442
+
443
+ }
444
+ ```
345
445
 
446
+ - ### Way 2 - Organized transactions :
447
+ ```js
448
+ // First, we start a transaction from your connection and save it into a variable
449
+ Fruit.transaction(async t => {
450
+ try {
451
+
452
+ // Then, we do some calls passing this transaction as an option:
453
+ const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
454
+ await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
455
+
456
+ // If the execution reaches this line, no errors were thrown.
457
+ // We commit the transaction.
458
+ await t.commit();
459
+
460
+ } catch (error) {
346
461
 
347
- ### # Generate Helpers ###
462
+ // If the execution reaches this line, an error was thrown.
463
+ // We rollback the transaction.
464
+ await t.rollback();
465
+
466
+ }
467
+ });
468
+ ```
469
+
470
+ - ### Way 3 - Transactions set Isolation levels :
471
+
472
+ The possible [isolations levels](https://sequelize.org/docs/v6/other-topics/transactions/#isolation-levels) to use when starting a transaction:
473
+
474
+ ```js
475
+ const { Transaction } = require('sequelize');
476
+
477
+ // First, we start a transaction from your connection and save it into a variable
478
+ Fruit.transaction(
479
+ {
480
+ isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
481
+ },
482
+ async t => {
483
+ try {
484
+
485
+ // Then, we do some calls passing this transaction as an option:
486
+ const fruit = await Fruit.create({ fruitName: 'Banana', fruitQty: '5', }, { transaction: t });
487
+ await fruit.addSibling({ fruitName: 'Litle', fruitQty: '2', }, { transaction: t }); // Error function
488
+
489
+ // If the execution reaches this line, no errors were thrown.
490
+ // We commit the transaction.
491
+ await t.commit();
492
+
493
+ } catch (error) {
494
+
495
+ // If the execution reaches this line, an error was thrown.
496
+ // We rollback the transaction.
497
+ await t.rollback();
498
+
499
+ }
500
+ });
501
+ ```
502
+
503
+ ## # Generate Helpers ###
348
504
 
349
505
  The `helpers` keep the files of functions for process specific something in the project. So, you might create the `helpers` in path `src/helpers` folder.
350
506
 
@@ -352,7 +508,7 @@ The `helpers` keep the files of functions for process specific something in the
352
508
  $ beech make helperName --helper
353
509
  ```
354
510
 
355
- **Example:** Text editor helper.
511
+ ***Example:*** Text editor helper.
356
512
 
357
513
  📂 TextEditor.js
358
514
  ```js
@@ -371,11 +527,11 @@ module.exports = {
371
527
  };
372
528
  ```
373
529
 
374
- ## Authentication (passport-jwt)
530
+ # Authentication (passport-jwt)
375
531
 
376
532
  Passport is authentication middleware for Node. It is designed to serve a singular purpose: authenticate requests. When writing modules, encapsulation is a virtue, so Passport delegates all other functionality to the application. This separation of concerns keeps code clean and maintainable, and makes Passport extremely easy to integrate into an application.
377
533
 
378
- Passport-jwt initiation :
534
+ ### Passport-jwt Initialization
379
535
 
380
536
  ```sh
381
537
  $ beech passport init
@@ -386,7 +542,7 @@ After passport initialized the `passport.config.js` it's appeared
386
542
  📂 passport.config.js
387
543
  ```js
388
544
  module.exports = {
389
- // allow using passport-jwt
545
+ // Allow for using passport-jwt
390
546
  jwt_allow: true,
391
547
 
392
548
  // custom authenticaiton endpoint name, default `/authentication`
@@ -398,6 +554,11 @@ module.exports = {
398
554
  // token expiry time (seconds), default 86400 sec. it's expired in 24 hr.
399
555
  token_expired: 86400,
400
556
 
557
+ // Allow for using global jwt broken role
558
+ jwt_broken_role: [
559
+ // { role: [1, 2, 9] },
560
+ ],
561
+
401
562
  model: {
402
563
  // Main sql connection name. You must make sure connection name like inside `app.config.js` file and choose one connection name.
403
564
  name: "default_db",
@@ -410,10 +571,27 @@ module.exports = {
410
571
  password_field: "",
411
572
 
412
573
  // JWT playload data, You can add it. Example: ["name", "email", ...]
413
- fields: []
574
+ fields: [],
575
+
576
+ // Other fields add for authentication.
577
+ guard: {
578
+ // Basic guard field, Example: ["pin", "hint", "2fa"]
579
+ guard_field: [],
580
+
581
+ // Advanced guard jwt request (needed some logical from front-end)
582
+ advanced_guard: {
583
+ allow: false,
584
+ entity: "", // default entity `timing`
585
+ secret: "top_secret",
586
+ time_expired: {
587
+ minutes: 1, // should length [0-60]
588
+ seconds: 0, // should length [0-60]
589
+ },
590
+ },
591
+ },
414
592
  },
415
593
 
416
- // allow using request with app_key (Every request needed app_key headers)
594
+ // Allow for using request with app_key entity (Every request must be using the app_key entity in headers)
417
595
  app_key_allow: false
418
596
 
419
597
  ...
@@ -421,7 +599,7 @@ module.exports = {
421
599
  };
422
600
  ```
423
601
 
424
- ***Authentication structure :*** Simple ``users`` table:
602
+ **Authentication structure :** Simple ``users`` table:
425
603
  ```
426
604
  ==============================================================
427
605
  | id | username | password | name | email |
@@ -434,10 +612,10 @@ When you config passport with ```users``` table already. You will got Auth endpo
434
612
  ```js
435
613
  POST: "/authentication" // Request token
436
614
  POST: "/authentication/create" // Create new Auth data
437
- PATCH: "/authentication/update/:id" // Update old Auth data
615
+ PATCH: "/authentication/update/:id" // Update old Auth data (needed id)
438
616
  ```
439
617
 
440
- Example :
618
+ ***XHR Example :***
441
619
 
442
620
  ```js
443
621
  // Request with body for gether Token
@@ -460,7 +638,7 @@ POST: "/authentication/create"
460
638
 
461
639
  // Request with body for Update Auth data
462
640
  PATCH: "/authentication/update/1"
463
- Bearer Authorization: your_token
641
+ headers: Authorization: Bearer <your_token>
464
642
  {
465
643
  username: "update_bombkiml",
466
644
  password: "update_secret",
@@ -469,7 +647,88 @@ Bearer Authorization: your_token
469
647
  }
470
648
  ```
471
649
 
472
- ### Beech auth managements with User ###
650
+ # Beech Two Factor (2FA)
651
+ You can easy using 2 Factor authenticate with ```guard_field``` inside ```passport.config.js``` file and add your Guard field ex: ```2fa``` field for Authenticate Conditions.
652
+
653
+ ## # Usage guard (2FA, Other)
654
+
655
+ 📂 passport.config.js
656
+ ```js
657
+ module.exports = {
658
+ ...
659
+
660
+ guard: {
661
+ // Other fields add for authenticate, exmaple ["pin", "hint", "2fa"]
662
+ guard_field: ["2fa"], 👈 // your feild guard.
663
+
664
+ ...
665
+ },
666
+
667
+ ...
668
+
669
+ }
670
+ ```
671
+
672
+ ## # Beech Advanced Guard (Timing)
673
+ Advance Guard for Protection your Endpoint with Timing. You can allow in object ```advance_guard``` inside ```passport.config.js``` file. So let's go add your Advance Guard Configuration.
674
+
675
+ 📂 passport.config.js
676
+ ```js
677
+ module.exports = {
678
+ ...
679
+
680
+ guard: {
681
+ ...
682
+
683
+ // Advanced guard jwt request (needed some logical from front-end)
684
+ advanced_guard: {
685
+ allow: false, 👈 // advanced guard allow for All Endpoint.
686
+ entity: "", // default entity `timing`
687
+ secret: "your_advance_guard_secret",
688
+ time_expired: {
689
+ minutes: 1, // should length [0-60]
690
+ seconds: 0, // should length [0-60]
691
+ },
692
+ },
693
+ },
694
+
695
+ ...
696
+
697
+ }
698
+
699
+ ```
700
+
701
+ <b>After configure</b>, You must add some logic in your front-end like this.
702
+
703
+ Before add logic, We needed [```beech-auth0```](https://github.com/bombkiml/beech-auth0) and [```moment.js```](https://momentjs.com) for apply in Policy.
704
+
705
+ ```sh
706
+ # NPM
707
+ $ npm install --save beech-auth0 moment
708
+
709
+ # Yarn
710
+ $ yarn add beech-auth0 moment
711
+ ```
712
+ Now! you can add some logic.
713
+ ```js
714
+ const { Auth0 } = require("beech-auth0");
715
+ const moment = require("moment");
716
+
717
+ // Get UNIX TIME with moment
718
+ let unix_time = moment().unix();
719
+
720
+ // Auth0 Policy.
721
+ Auth0(unix_time, 'your_advance_guard_secret', (error, hashing) => {
722
+
723
+ // Your XHR request for All Endpoint.
724
+ POST: "/authentication"
725
+ headers: timing: hashing, 👈 // Assign advance guard entity to headers with callback hashing.
726
+
727
+ });
728
+
729
+ ```
730
+
731
+ ## # Beech User Auth Managements ###
473
732
  You can easy management `users` data with Beech, Only ```Store, Update``` NO ```Delete```, Anything you can make DELETE endpoint by yourself
474
733
 
475
734
  ```js
@@ -513,12 +772,12 @@ Update(data, id, (err, updated) => {
513
772
  });
514
773
  ```
515
774
 
516
- ## Beech with Official Strategy
775
+ # Beech with Official Strategy
517
776
 
518
777
  Latest supported with ``Google`` and ``Facebook`` Strategy.
519
778
 
520
779
 
521
- ### Google Strategy
780
+ ## # Google Strategy
522
781
 
523
782
 
524
783
  The Google OAuth 2.0 authentication strategy authenticates users using a Google account and OAuth 2.0 tokens. The strategy requires a verify callback, which accepts these credentials and calls done providing a user, as well as options specifying a client ID, client secret, and callback URL.
@@ -535,7 +794,7 @@ strategy: {
535
794
 
536
795
  google: {
537
796
 
538
- // Allow using google strategy
797
+ // Allow for using google strategy
539
798
  allow: true,
540
799
 
541
800
  // Authen profile store fields available: `google_id`, `name`, `email`, `photos`, `locate`
@@ -577,7 +836,7 @@ Place a button on the application's login page, prompting the user to sign in wi
577
836
  ❓ **Note:** The URL "``/authentication``" will be follow by ``auth_endpoint`` when you custom it.
578
837
 
579
838
 
580
- ### Facebook Strategy
839
+ ## # Facebook Strategy
581
840
 
582
841
 
583
842
  Facebook Login allows users to sign in using their Facebook account. Support for Faceboook Login is provided by the ``passport-facebook`` package.
@@ -594,7 +853,7 @@ strategy: {
594
853
 
595
854
  facebook: {
596
855
 
597
- // Allow using facebook strategy
856
+ // Allow for using facebook strategy
598
857
  allow: true,
599
858
 
600
859
  // Authen profile store fields available: `facebook_id`, `name`, `email`, `photos`, `locate`
@@ -641,16 +900,35 @@ Place a button on the application's login page, prompting the user to sign in wi
641
900
 
642
901
  ❓ **Note:** The URL "``/authentication``" will be follow by ``auth_endpoint`` when you custom it.
643
902
 
644
- ## CORS Origin allowments
903
+ # CORS Origin & Server Configuration
645
904
  The origin array to the callback can be any value allowed for the origin option of the middleware. Certain CORS requests are considered `complex` and require an initial OPTIONS request (called the `pre-flight request`). You can allowed CORS origin inside file `beech.config.js`
646
905
 
647
906
  📂 beech.config.js
648
907
  ```js
649
908
  module.exports = {
650
909
  defineConfig: {
910
+ // Base public path when served in development or production.
911
+ base: process.env.NODE_ENV === "production"
912
+ ? "/my-api/" // For Production
913
+ : "/", // For Development
914
+
651
915
  server: {
916
+ // Client request allow origin whitelist
652
917
  origin: ["http://example.com", "http://my-webapp:8080", "https://cat.io"],
653
918
  originSensitive: false, // Sensitive with contrasts wording
919
+
920
+ // API Request rate limit (Disabled for Remove it.)
921
+ rateLimit: {
922
+ windowMs: 15 * 60 * 1000, // 15 minutes
923
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
924
+ // store: ... , // Redis, Memcached, etc.
925
+ // See more: https://www.npmjs.com/package/express-rate-limit#Configuration
926
+ },
927
+
928
+ // API Duplicate Request (Disabled for Set expiration to 0 zero.)
929
+ duplicateRequest: {
930
+ expiration: 500, // Can't duplicate request for 5 milliseconds each IP requests per `window`
931
+ },
654
932
  },
655
933
  },
656
934
  }
@@ -658,16 +936,95 @@ module.exports = {
658
936
 
659
937
  ❓ **Note:** When you must to allowed all Origin. You can assign `*` or `[]` null value to `origin` variable.
660
938
 
939
+ ## # Custom Endpoint Specific Rate Limit
940
+ When you need assign specific request Endpoint with [express-rate-limit](https://www.npmjs.com/package/express-rate-limit), You can managemnet with Beech object ```rateLimit``` for your custom Rate Limit like this.
661
941
 
662
- ## Databases managements
942
+ ```js
943
+ const { rateLimit } = require("beech-api").Express;
663
944
 
664
- ### # Migrations & Seeder
945
+ // Specific of your rate limit
946
+ const specificRateLimit1 = rateLimit({
947
+ windowMs: 5 * 60 * 1000, // 5 minutes
948
+ limit: 20,
949
+ // more...
950
+ });
951
+
952
+ // Your Endpoints...
953
+ endpoint.get("/banana", specificRateLimit1, (req, res) => {
954
+ ...
955
+ });
956
+
957
+ ...
958
+ ```
959
+
960
+ ## # Custom Endpoint Specific Slow Down
961
+ **DON'T DO IT.** &nbsp; Because it's annoying to users.
962
+
963
+ When you need assign specific request Endpoint with [express-slow-down](https://www.npmjs.com/package/express-slow-down), You can managemnet with Beech object ```slowDown``` for your custom Slow Down like this.
964
+
965
+ ```js
966
+ const { slowDown } = require("beech-api").Express;
967
+
968
+ // Specific of your slow down
969
+ const specificSlowDown1 = slowDown({
970
+ windowMs: 15 * 60 * 1000, // 15 minutes
971
+ delayAfter: 5, // Allow 5 requests per 15 minutes.
972
+ delayMs: (hits) => hits * 100, // Add 100 ms of delay to every request after the 5th one.
973
+ // more...
974
+
975
+ /**
976
+ * So:
977
+ *
978
+ * - requests 1-5 are not delayed.
979
+ * - request 6 is delayed by 600ms
980
+ * - request 7 is delayed by 700ms
981
+ * - request 8 is delayed by 800ms
982
+ *
983
+ * and so on. After 15 minutes, the delay is reset to 0.
984
+ */
985
+ });
986
+
987
+ // Your Endpoints...
988
+ endpoint.get("/banana", specificSlowDown1, (req, res) => {
989
+ ...
990
+ });
991
+
992
+ ...
993
+ ```
994
+
995
+ ## # Custom Endpoint Specific Duplicate Request
996
+ This middleware to Limit each IP duplicated requests per window.
997
+
998
+ When you need assign specific request Endpoint with duplicate request use [express-duplicate-request](https://github.com/bombkiml/express-duplicate-request), You can managemnet with Beech object ```duplicateRequest``` for your custom Duplicate Request like this.
999
+
1000
+ ```js
1001
+ const { duplicateRequest } = require("beech-api").Express;
1002
+
1003
+ // Specific of your duplicate request
1004
+ const specificDup1 = duplicateRequest({
1005
+ expiration: 500, // Can't duplicate request for 5 milliseconds, Should 0 to disabled
1006
+ // more...
1007
+ });
1008
+
1009
+ // Your Endpoints...
1010
+ endpoint.get("/banana", specificDup1, (req, res) => {
1011
+ ...
1012
+ });
1013
+
1014
+ ...
1015
+ ```
1016
+
1017
+
1018
+
1019
+ # Databases managements
1020
+
1021
+ ## # Migrations & Seeder
665
1022
 
666
1023
  Just like you use Git / SVN to manage changes in your source code, you can use migrations to keep track of changes to the database. With migrations you can transfer your existing database into another state and vice versa: Those state transitions are saved in migration files, which describe how to get to the new state and how to revert the changes in order to get back to the old state.
667
1024
 
668
1025
  You will need [Sequelize CLI.](https://github.com/sequelize/cli) The CLI ships support for [migrations](https://sequelize.org/v5/manual/migrations.html) and project.
669
1026
 
670
- ### # Usage
1027
+ ## # Usage
671
1028
 
672
1029
  To create an empty project you will need to execute `init` command
673
1030
 
@@ -682,7 +1039,7 @@ This will create following folders inside `databases` folder.
682
1039
  - `migrations`, contains all migration files.
683
1040
  - `seeders`, contains all seed files.
684
1041
 
685
- ### # Configuration
1042
+ ## # Configuration
686
1043
 
687
1044
  Before continuing further we will need to tell CLI how to connect to database. To do that let's open default config file `databases/config/database.json` It looks something like this:
688
1045
 
@@ -716,7 +1073,7 @@ Before continuing further we will need to tell CLI how to connect to database. T
716
1073
 
717
1074
  ❓ **Note:** If your database doesn't exists yet, you can just call `npx sequelize-cli db:create` command. With proper access it will create that database for you.
718
1075
 
719
- ### # Creating first Migrations
1076
+ ## # Creating first Migrations
720
1077
 
721
1078
  Create `model` use `model:generate` command. This command requires two options.
722
1079
 
@@ -729,7 +1086,7 @@ Let's create a model name example `User`. See more about of [Datatypes](https://
729
1086
  $ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string,birhday:date
730
1087
  ```
731
1088
 
732
- ### # Migrations Up and Down
1089
+ ## # Migrations Up and Down
733
1090
 
734
1091
  Until this step, we haven't inserted anything into the database. We have just created required model and migration files for our first model User.
735
1092
 
@@ -744,7 +1101,7 @@ Until this step, we haven't inserted anything into the database. We have just cr
744
1101
  $ npx sequelize-cli db:migrate:undo
745
1102
  ```
746
1103
 
747
- ### # Creating First Seeder
1104
+ ## # Creating First Seeder
748
1105
 
749
1106
  To manage all data migrations you can use seeders. Seed files are some change in data that can be used to populate database table with sample data or test data.
750
1107
 
@@ -754,7 +1111,7 @@ Let's create a seed file which will add a demo user to our User table.
754
1111
  $ npx sequelize-cli seed:generate --name user
755
1112
  ```
756
1113
 
757
- ### # Seeder Up and Down
1114
+ ## # Seeder Up and Down
758
1115
 
759
1116
  In last step you have create a seed file. It's still not committed to database. To do that we need to run a simple command.
760
1117
 
@@ -784,7 +1141,7 @@ In last step you have create a seed file. It's still not committed to database.
784
1141
  $ npx sequelize-cli db:seed:undo:all
785
1142
  ```
786
1143
 
787
- ## Testing
1144
+ # Testing
788
1145
 
789
1146
  Test using [Jest](https://jestjs.io/en/) for testing the project. Jest is a delightful JavaScript Testing Framework with a focus on simplicity. Learn more [Jest docs](https://jestjs.io/docs/en/getting-started.html)
790
1147
 
@@ -792,13 +1149,13 @@ So, When you make the new endpoints it's automatic create test file end with `.s
792
1149
 
793
1150
  Example endpoints testing :
794
1151
 
795
- 📂 fruits-endpoints.spec.js
1152
+ 📂 fruit-endpoints.spec.js
796
1153
  ```js
797
- const endpoint = baseUrl.concat("/fruits/fruits");
1154
+ const endpoint = baseUrl.concat("/fruit");
798
1155
 
799
1156
  describe("Test endpoint : " + endpoint, () => {
800
1157
  it("Truthy!", () => {
801
- expect("/fruits/fruits").toBeTruthy();
1158
+ expect("/fruit").toBeTruthy();
802
1159
  });
803
1160
 
804
1161
  it("Respond with basic GET status code 200", (done) => {
@@ -811,26 +1168,13 @@ describe("Test endpoint : " + endpoint, () => {
811
1168
  ```
812
1169
 
813
1170
 
814
- ## Implementation
815
-
816
- ### # Implement with [PM2](https://pm2.keymetrics.io/)
817
- [PM2](https://pm2.keymetrics.io/) is a daemon process manager that will help you manage and keep your application online. Getting started with PM2 is straightforward, it is offered as a simple and intuitive CLI, installable via [NPM](https://www.npmjs.com/).
818
-
819
- ```sh
820
- # Start service as standalone
821
- $ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName>
1171
+ # Implementation
822
1172
 
823
- # OR
824
-
825
- # Start service as cluster mode
826
- $ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName> -i <instances>
827
- ```
828
-
829
- ### # Implement with [Docker](https://www.docker.com)
1173
+ ## # Implement with [Docker](https://www.docker.com)
830
1174
 
831
1175
  [Docker](https://www.docker.com) is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly.
832
1176
 
833
- - **Create Dockerfile**
1177
+ - ### **Create Dockerfile**
834
1178
 
835
1179
  Docker builds images automatically by reading the instructions from a Dockerfile -- a text file that contains all commands, in order, needed to build a given image. A Dockerfile adheres to a specific format and set of instructions which you can find at [Dockerfile reference](https://docs.docker.com/engine/reference/builder/).
836
1180
 
@@ -839,14 +1183,14 @@ Docker builds images automatically by reading the instructions from a Dockerfile
839
1183
  FROM node:14.19-alpine
840
1184
  ENV NODE_ENV=production
841
1185
  WORKDIR /usr/src/api
842
- COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
1186
+ COPY ["package.json", "package-lock.json*", "./"]
843
1187
  RUN npm install --production --silent && mv node_modules .
844
1188
  COPY . .
845
1189
  EXPOSE 9000
846
1190
  CMD ["node", "./node_modules/beech-api/packages/cli/beech"]
847
1191
  ```
848
1192
 
849
- - **Docker build image**
1193
+ - ### **Docker build image**
850
1194
 
851
1195
  The docker build command builds an image from a Dockerfile and a context. The build’s context is the set of files at a specified location ```PATH``` or ```URL```. The PATH is a directory on your local filesystem. The URL is a Git repository location.
852
1196
 
@@ -856,16 +1200,16 @@ $ docker build -t <imageName> .
856
1200
 
857
1201
  ❓ **Note:** You can specify a repository and tag at which to save the new image : ``` $ docker build -t <imageName>:<tags> . ```
858
1202
 
859
- - **Run docker**
1203
+ - ### **Run docker**
860
1204
 
861
1205
  After create ``image`` you can run docker engine following :
862
1206
 
863
- - **Docker Container (Standalone)**
1207
+ - ### **Docker Container (Standalone)**
864
1208
  ```sh
865
1209
  $ docker run -d -p 9000:9000 --name <containerName> <imageName>
866
1210
  ```
867
1211
 
868
- - **Create Docker Swarm (Cluster)**
1212
+ - ### **Create Docker Swarm (Cluster)**
869
1213
  ```sh
870
1214
  # Initiate swarm
871
1215
  $ docker swarm init
@@ -874,42 +1218,20 @@ $ docker build -t <imageName> .
874
1218
  $ docker service create --replicas <instances> --name <containerName> --publish 9000:9000 <imageName>
875
1219
  ```
876
1220
 
1221
+ ## # Implement with [PM2](https://pm2.keymetrics.io/)
1222
+ [PM2](https://pm2.keymetrics.io/) is a daemon process manager that will help you manage and keep your application online. Getting started with PM2 is straightforward, it is offered as a simple and intuitive CLI, installable via [NPM](https://www.npmjs.com/).
877
1223
 
878
- ## Bonus
879
-
880
- Free `helpers` you can make [LINE Notify](https://github.com/Yuhsak/line-api#readme) by using [line-api](https://notify-bot.line.me/en/) package with create the helper function following.
881
-
882
- Installation the package:
883
-
884
- ```
885
- $ npm install line-api
886
- ```
887
-
888
- Create file `Line.js` in `src/helpers` folder and copy code below:
889
-
890
- 📂 Line.js
891
- ```js
892
- const Line = require("line-api");
893
-
894
- module.exports = {
1224
+ ```sh
1225
+ # Start service as standalone
1226
+ $ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName>
895
1227
 
896
- notify(message, token) {
897
- const notify = new Line.Notify({
898
- token: token
899
- });
900
- notify
901
- .send({
902
- message: message
903
- })
904
- .then(console.log);
905
- }
1228
+ # OR
906
1229
 
907
- };
1230
+ # Start service as cluster mode
1231
+ $ pm2 start ./node_modules/beech-api/packages/cli/beech --name <serviceName> -i <instances>
908
1232
  ```
909
1233
 
910
- Enjoy.
911
-
912
- ## Development
1234
+ # Development
913
1235
 
914
1236
  Want to contribute or join for great job!, You can contact to me via
915
1237
 
@@ -917,6 +1239,6 @@ Want to contribute or join for great job!, You can contact to me via
917
1239
  - E-mail: nattapat.jquery@gmail.com
918
1240
  - Facebook: [https://www.facebook.com/bombkiml](https://www.facebook.com/bombkiml)
919
1241
 
920
- ## License
1242
+ # License
921
1243
 
922
1244
  The Beech API framework is open-sourced software licensed under the [MIT license.](https://opensource.org/licenses/MIT)