beech-api 3.8.0 → 3.9.0-beta.9-rc

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,22 +1,74 @@
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
+ #### Auto endpoint v.3.9.0 (LTS)
5
5
 
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
+ [![beech-api release](https://img.shields.io/github/v/release/bombkiml/beech-api)](https://github.com/bombkiml/beech-api/releases/)
7
7
  [![PyPI license](https://shields.io/pypi/l/ansicolortags.svg)](https://github.com/bombkiml/beech-api/blob/master/README.md)
8
8
 
9
9
  # What is Beech API ?
10
10
 
11
11
  The Beech API is API framework, It's help you with very easy to create API project under [Node.js](https://nodejs.org)
12
12
 
13
+ ## Let's go
14
+ - <b>[Installation](#installation)</b>
15
+ - <b>[Creating a project](#creating-a-project)</b>
16
+ - <b>[Upgrade to latest version](#upgrade-to-latest-version)</b>
17
+ - <b>[Beech CLI tool available](#beech-cli-tool-available)</b>
18
+ - ✨ <b>Automation Endpoints with CRUD</b>
19
+ - [Database Connection](#database-connection)
20
+ - [Model](#models)
21
+ - [Retrieving data with Query String](#retrieving-data-with-query-string)
22
+ - Conditions
23
+ - Grouping
24
+ - Ordering
25
+ - Timestamps (Add-on in Store and Update)
26
+ - [Transactions](#-transactions)
27
+ - [Disorganized transactions](#way-1---disorganized-transactions-)
28
+ - [Organized transactions](#way-2---organized-transactions-)
29
+ - [Transactions set Isolation levels](#way-3---transactions-set-isolation-levels-)
30
+ - [Endpoints](#endpoints)
31
+ - [Helpers](#helpers)
32
+ - 🔐 <b>System Management of Authentication</b>
33
+ - [Authentication Manegement](#authentication-passport-jwt)
34
+ - [Request Token](#request-token)
35
+ - [Beech Guard](#beech-guard)
36
+ - Verify Identity Management
37
+ - Two Factor (2fa, OTP, etc.)
38
+ - [Beech User Authentication Managements](#-beech-user-authentication-managements)
39
+ - Create Auth
40
+ - Update Auth
41
+ - 🛠️ <b>Safe Endpoints Request</b>
42
+ - [Rate Limit](#-custom-endpoint-specific-rate-limit)
43
+ - [Slow Down](#-custom-endpoint-specific-slow-down)
44
+ - [Block Duplicate Request per Window](#-custom-endpoint-specific-duplicate-request)
45
+ - [JWT Broken Role](#jwt-broken-role)
46
+ - [Advance Guard (Timimg)](#-beech-advanced-guard-timing)
47
+ - 🙂 <b>Hight Security under passport-jwt, oauth2</b>
48
+ - 🌐 <b>Supported Official Strategy</b>
49
+ - [Google](#-google-strategy)
50
+ - [Facebook](#-facebook-strategy)
51
+ - 🖥️ <b>CORS Origin & Server Configuration</b>
52
+ - [Config Base public path `./`](#cors-origin--server-configuration)
53
+ - [Allow origin whitelist](#cors-origin--server-configuration)
54
+ - 📚 <b>Databases Managements</b>
55
+ - [Migrations](#databases-managements)
56
+ - [Seeder](#-creating-first-seeder)
57
+ - ☕ <b>Testing</b>
58
+ - [Jest](#testing)
59
+ - 🏃 <b>Implementration</b>
60
+ - [Docker](#implementation)
61
+ - [PM2](#-implement-with-pm2)
62
+
13
63
  # Environment
14
64
 
15
- - [`Node.js`](https://nodejs.org) >= 14.19.0+ (recommended)
65
+ - [`Node.js`](https://nodejs.org) >= 18.17.1+ (recommended)
16
66
 
17
67
  # Installation
18
68
 
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`
69
+ Beech API needed Node.js version 18.17.1 or above. You can management multiple versions on the same machine with [nvm](https://github.com/creationix/nvm) or [nvm-windows](https://github.com/coreybutler/nvm-windows).
70
+
71
+ <b>So, Let's go to install</b> `beech-api`
20
72
 
21
73
  ```sh
22
74
  # NPM
@@ -28,8 +80,11 @@ $ yarn global add beech-api
28
80
 
29
81
  Installation demo:
30
82
 
31
- [Demo](https://i.ibb.co/hySFxy3/install-beech720-1.gif)
32
- ![Alt Text](https://i.ibb.co/hySFxy3/install-beech720-1.gif)
83
+ [Demo 1](https://i.ibb.co/TBjNgVrF/1-11.gif)
84
+ ![Alt Text](https://i.ibb.co/TBjNgVrF/1-11.gif)
85
+
86
+ [Demo 2](https://i.ibb.co/wrdgyzDP/ezgif-8539024298ec62a9.gif)
87
+ ![Alt Text](https://i.ibb.co/wrdgyzDP/ezgif-8539024298ec62a9.gif)
33
88
 
34
89
  After installation, you will have access to the `beech-app` binary in your command line.
35
90
  You can check you have the right version with this command:
@@ -98,7 +153,9 @@ The following commands are available:
98
153
  $ beech key:generate, key:gen Re-Generate application key (Dangerous!).
99
154
  $ beech hash:<text> Hash text for Access to Database connection.
100
155
  ```
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``
156
+ ❓ **Note:** Every to create new project will be generated new ``app_key`` in ``app.config.js`` file.
157
+
158
+ ❓ **Note:** If you can re-generate. Can use command ``$ beech key:generate`` or ``$ beech key:gen``
102
159
 
103
160
  # Database connection
104
161
 
@@ -121,11 +178,11 @@ $ beech hash:password
121
178
  Output: FjgcgJPylkV7EeQJjea_EeifPwaHVO9onD3ATk3YYAyvjtMGu3dcDS0ejA
122
179
 
123
180
  ```
124
- Example:
181
+ ***For Example :***
125
182
 
126
183
  📂 app.config.js
127
184
  ```js
128
- // basic & sequelize (needed Hash)
185
+ // Database configuration Only Basic & Sequelize (needed Hash)
129
186
 
130
187
  ...
131
188
 
@@ -150,9 +207,9 @@ database_config: [
150
207
  // or use a named timezone supported by Intl.Locale
151
208
  // timezone: 'America/Los_Angeles',
152
209
 
153
- logging: console.log, // SQL trace logs
210
+ logging: console.log, // SQL trace logs. Learn more: https://sequelize.org/docs/v6/getting-started/#logging
154
211
 
155
- is_connect: true, // boolean, Turn ON/OFF to connect
212
+ is_connect: true, // Boolean, Turn ON/OFF to connect
156
213
  },
157
214
 
158
215
  ...
@@ -163,113 +220,26 @@ database_config: [
163
220
  ```
164
221
  ❓ **Caution! :** Every re-new generate `app_key`. Must to new Hash your Access and change to ALL Database connections.
165
222
 
166
- # Part of generate file
167
-
168
- ## # Generate Endpoints
223
+ **Development** : You can add ```dev: true``` in ```main_config``` for a better experience.
169
224
 
170
- The `endpoints` keep the endpoints basic request files currently support `GET`, `POST`, `PUT`, `PATCH` and `DELETE`.
225
+ # Models
171
226
 
172
- So, you might create new endpoints with constant `endpoint` object variable in `src/endpoints/` folder and file neme must be end with `-endpoints.js`
227
+ 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.
173
228
 
174
229
  ```sh
175
- $ beech make endpointName
176
- ```
177
- You might using [special] `-R, --require` for choose Model(s) used for that endpoint.
178
-
179
- ### Example ***(Basic)*** : Fruit endpoints.
180
-
181
- 📂 fruit-endpoints.js
182
- ```js
183
- exports.init = () => {
184
-
185
- // GET method
186
- endpoint.get("/fruit", Credentials, (req, res) => {
187
- // @response
188
- res.json({
189
- code: 200,
190
- status: "SUCCESS",
191
- message: "GET /fruit request.",
192
- });
193
- });
194
-
195
-
196
- // POST method
197
- endpoint.post("/fruit", Credentials, (req, res) => {
198
- // @response
199
- res.json({
200
- code: 200,
201
- status: "SUCCESS",
202
- message: "POST request at /fruit",
203
- result: {
204
- id: req.body.id,
205
- name: req.body.name,
206
- },
207
- });
208
- });
209
-
210
-
211
- // PUT method
212
- endpoint.put("/fruit/:id", Credentials, (req, res) => {
213
- // @response
214
- res.json({
215
- code: 200,
216
- status: "SUCCESS",
217
- message: "PUT request at /fruit/" + req.params.id,
218
- });
219
- });
220
-
221
-
222
- // DELETE method
223
- endpoint.delete("/fruit/:id", Credentials, (req, res) => {
224
- // @response
225
- res.json({
226
- code: 200,
227
- status: "SUCCESS",
228
- message: "DELETE request at /fruit/" + req.params.id,
229
- });
230
- });
231
-
232
- ...
233
-
234
- }
235
- ```
236
-
237
- ### Example ***(Sequelize)*** : Fruit endpoints.
238
-
239
- 📂 fruit-endpoints.js
240
- ```js
241
- // Require Model schema, Function & Others
242
- const { Fruit } = require("@/models/Fruit");
243
-
244
- exports.init = () => {
245
-
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
- });
254
- });
255
-
256
- ...
257
-
258
- }
230
+ $ beech make modelName --model
259
231
  ```
260
232
 
233
+ ## # Model (Basic)
261
234
 
262
- ## # Generate Models ###
235
+ Basic model only support `MySQL` Raw Query format and freedom of your SQL query
263
236
 
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.
237
+ ❓ **Note:** The Basic pool engine it's not support auto Endpoints.
265
238
 
266
- ```sh
267
- $ beech make modelName --model
268
- ```
269
239
 
270
- ### Example ***(Basic)*** : Fruit model.
240
+ ***For example :***
271
241
 
272
- 📂 Fruit.js
242
+ 📂 models/Fruit.js
273
243
  ```js
274
244
  module.exports = {
275
245
 
@@ -299,11 +269,17 @@ module.exports = {
299
269
  };
300
270
  ```
301
271
 
302
- ### Example ***(Sequelize)*** : Fruit model.
272
+ ## # Model (Sequelize)
303
273
 
274
+ Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite, Microsoft SQL Server, Oracle Database, Amazon Redshift and Snowflake’s Data Cloud. It features solid transaction support, relations, eager and lazy loading, read replication and more. <br/>You can learn more: [Sequelize docs](https://sequelize.org/docs/v6)
275
+
304
276
  You can asign more DataTypes, Learn more : [Sequelize docs](https://sequelize.org/docs/v6/core-concepts/model-basics/#data-types)
305
277
 
306
- 📂Fruit.js
278
+ ❓ **Note:** When you generate a model it's create table structure for automatically for you.
279
+
280
+ ***For example :***
281
+
282
+ 📂 models/Fruit.js
307
283
  ```js
308
284
  const { Schema } = require("beech-api");
309
285
 
@@ -327,6 +303,7 @@ const Fruit = Schema(sql.default_db).define("fruit", {
327
303
  type: DataTypes.INTEGER,
328
304
  allowNull: false, // Allow null feilds
329
305
  },
306
+ sort: DataTypes.STRING,
330
307
  createdAt: {
331
308
  type: DataTypes.DATE,
332
309
  allowNull: false,
@@ -350,11 +327,10 @@ Fruit.options = {
350
327
  // Option 1: Allow all methods
351
328
  defaultEndpoint: true,
352
329
 
353
- // Option 2: Allow with specific per methods
330
+ // Option 2: Allow with specific per methods
354
331
  defaultEndpoint: {
355
332
  GET: true,
356
- POST: false,
357
- PATCH: {
333
+ POST: {
358
334
  allow: true, // allow Auto-Endpoint
359
335
  jwt: {
360
336
  allow: true, // allow JWT
@@ -362,12 +338,23 @@ Fruit.options = {
362
338
  { role: [1, 2] },
363
339
  ],
364
340
  },
341
+ // Rate Limit for POST
342
+ rate_limit: {
343
+ windowMs: 15 * 60 * 1000, // 15 minutes
344
+ limit: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
345
+ // store: ... , // Redis, Memcached, etc.
346
+ // See more: https://www.npmjs.com/package/express-rate-limit#Configuration
347
+ },
348
+ // Duplicate Request for POST
349
+ duplicate_request: {
350
+ expiration: 500, // Can't duplicate request for 5 milliseconds each IP requests per `window` (Disabled for Set expiration to 0 zero.)
351
+ },
365
352
  },
353
+ PATCH: false,
366
354
  DELETE: false,
367
355
  },
368
356
 
369
357
  limitRows: 100, // Limit rows default 100
370
-
371
358
  };
372
359
 
373
360
  // Example Finder by id (ORM), Learn more: https://sequelize.org/docs/v6/core-concepts/model-querying-finders/
@@ -375,7 +362,6 @@ function exampleFindOneFruitById(id) {
375
362
  return Fruit.findOne({ where: { id: id } });
376
363
  }
377
364
 
378
-
379
365
  // Example Raw Query with Model Instances. This allows you to easily map a query to a predefined model
380
366
  function exampleGetAllFruitWithModelInstance(id) {
381
367
  return Fruit.query("SELECT * FROM fruit", {
@@ -400,18 +386,98 @@ module.exports = {
400
386
  ...
401
387
  };
402
388
  ```
403
- #### That's cool! It's like magic creating The endpoints for you (CRUD) ✨
404
389
 
405
- Now! you can request to `/fruit` with methods GET, POST, PATCH and DELETE like this.
390
+ ## Retrieving data with Query String
391
+
392
+ Now you can add Query String with Conditional, Grouping and Ordering (Now Support Readonly for GET method)
393
+
394
+ ### ✨ That's cool! It's like magic Creating The Endpoints for you (CRUD) ✨
395
+
396
+ <b style="font-size:12pt">For Example, Now!</b>, You can request to `/fruit` with methods GET, POST, PATCH and DELETE like this.
406
397
 
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 |
398
+ | Efficacy | Method | Endpoint | Body | Mode |
399
+ |:---------|:---------|:-----------------------|:-------------|:--------|
400
+ | Create | POST | /fruit | { } | Single |
401
+ | Create | POST | /fruit | [ ] | Bulk |
402
+ | Read | GET | /fruit | No | Fetch |
403
+ | Read | GET | /fruit/:limit/:offset | No | Fetch |
404
+ | Read | GET | /fruit?someField=1 | No | Fetch |
405
+ | Read | GET | /fruit?orderby=sort | No | Fetch |
406
+ | Read | GET | /fruit?groupby=id | No | Fetch |
407
+ | Update | PATCH | /fruit/:id | { } | Single |
408
+ | Delete | DELETE | /fruit/:id | No | Single |
409
+
410
+ Add some Basic Conditions, Grouping and Ordering with `QUERY STRING` under GET methods<br/>
411
+
412
+ Retrieving `fruit` data with GET : `/fruit?someField=[eq,1]&groupby=[id]&orderby=[id,desc]`
413
+
414
+ ***For Example :***
415
+
416
+ ```java
417
+ // WHERE Conditions
418
+ GET: /fruit?id=1 // id = 1
419
+ GET: /fruit?isActived=[eq,1] // isActived = 1
420
+ GET: /fruit?fruitName=[like,Banana%] // fruitName LIKE 'Banana%' (Not allow with date, time)
421
+ GET: /fruit?cost=[gt,50]&qty=[lt,10] // cost > 50 AND qty < 10
422
+ GET: /fruit/10/0?qty=[lt,10] // qty < 10 LIMIT 0,10
423
+
424
+ // Grouping
425
+ GET: /fruit?groupby=id // GROUP BY id
426
+ GET: /fruit?groupby=[id,fruitName] // GROUP BY id, fruitName
427
+
428
+ // Ordering
429
+ GET: /fruit?oderby=id // ORDER BY id ASC
430
+ GET: /fruit?oderby=[sort,desc] // ORDER BY sort DESC
431
+ ```
432
+
433
+ For usage avariable:
434
+
435
+ ```java
436
+ // Basics conditions
437
+ 3 // = 3
438
+ [eq, 3] // = 3
439
+ [ne, 20] // != 20
440
+ [is, null] // IS NULL
441
+ [not, null] // IS NOT NULL
442
+ [or, [5, 6]] // (someField = 5) OR (someField = 6) // Not support NULL value
443
+
444
+ // Number comparisons conditions
445
+ [gt, 6] // > 6
446
+ [gte, 6] // >= 6
447
+ [lt, 10] // < 10
448
+ [lte, 10] // <= 10
449
+ [between, [6, 10]] // BETWEEN 6 AND 10
450
+ [between, [2025-01-01, 2025-04-30]] // BETWEEN '2025-01-01 00:00:00' AND '2025-04-30 23:59:59'
451
+ // When assign Datetime format will only support field datatype is `Date`, `Datetime`, `Time`
452
+
453
+ // OR You can assign Datetime like this.
454
+ [between, [2025-01-01 12:00:00, 2025-04-30 15:00:00]] // BETWEEN '2025-01-01 12:00:00' AND '2025-04-30 15:00:00'
455
+
456
+ [notBetween, [11, 15]] // NOT BETWEEN 11 AND 15
457
+
458
+ // Other operators conditions
459
+ [in, [1, 2, 3]], // IN [1, 2, 3]
460
+ [notIn, [1, 2, 3]], // NOT IN [1, 2, 3]
461
+ [like, %hat] // LIKE '%hat' (Avoid use #, % and %<Number> between wording)
462
+ // Becuase URL will be decoded it, Reccommand use startsWith, endsWith and substring when you need assing Number value)
463
+ // And NOT SUPPORT field datatype is `date`, `datetime`, `time`. Should be use with datatype is `String` or `Number` it work!.
464
+
465
+ [notLike, %hat] // NOT LIKE '%hat'
466
+ [startsWith, hat] // LIKE 'hat%'
467
+ [endsWith, hat] // LIKE '%hat'
468
+ [substring, hat] // LIKE '%hat%'
469
+
470
+ // Grouping
471
+ groupby=id // GROUP BY id
472
+ groupby=[id] // ORDER BY id
473
+ groupby=[id, fruitName] // ORDER BY id, fruitName
474
+
475
+ // Ordering
476
+ oderby=id // ORDER BY id ASC (Basic usage default Ascending)
477
+ oderby=[id, asc] // ORDER BY id ASC
478
+ oderby=[id, desc] // ORDER BY id ASC
479
+ oderby=[[id, desc], [sort, asc]] // ORDER BY id DESC, sort ASC
480
+ ```
415
481
 
416
482
  ## # Transactions
417
483
 
@@ -500,7 +566,306 @@ Fruit.transaction(
500
566
  });
501
567
  ```
502
568
 
503
- ## # Generate Helpers ###
569
+ # Endpoints
570
+
571
+ The `endpoints` keep the endpoints basic request files currently support `GET`, `POST`, `PUT`, `PATCH` and `DELETE`.
572
+
573
+ So, you might create new endpoints with constant `endpoint` object variable in `src/endpoints/` folder and file neme must be end with `-endpoints.js`
574
+
575
+ ```sh
576
+ $ beech make endpointName
577
+ ```
578
+ You might using [special] `-R, --require` for choose Model(s) used for that endpoint.
579
+
580
+ ***For Example :***
581
+
582
+ 📂 endpoints/fruit-endpoints.js
583
+ ```js
584
+ // Require Model schema, Function & Others
585
+ const { Fruit } = require("@/models/Fruit");
586
+
587
+ exports.init = () => {
588
+
589
+ // GET method
590
+ endpoint.get("/fruit", Credentials, async (req, res) => {
591
+ // example call Fruit model for get data
592
+ res.json({
593
+ code: 200,
594
+ status: "SUCCESS",
595
+ results: await Fruit.findAll();
596
+ });
597
+ });
598
+
599
+
600
+ // POST method
601
+ endpoint.post("/fruit", Credentials, (req, res) => {
602
+ // @response
603
+ res.json({
604
+ code: 200,
605
+ status: "SUCCESS",
606
+ message: "POST request at /fruit",
607
+ result: {
608
+ id: req.body.id,
609
+ name: req.body.name,
610
+ },
611
+ });
612
+ });
613
+
614
+
615
+ // PUT method
616
+ endpoint.put("/fruit/:id", Credentials, (req, res) => {
617
+ // @response
618
+ res.json({
619
+ code: 200,
620
+ status: "SUCCESS",
621
+ message: "PUT request at /fruit/" + req.params.id,
622
+ });
623
+ });
624
+
625
+
626
+ // DELETE method
627
+ endpoint.delete("/fruit/:id", Credentials, (req, res) => {
628
+ // @response
629
+ res.json({
630
+ code: 200,
631
+ status: "SUCCESS",
632
+ message: "DELETE request at /fruit/" + req.params.id,
633
+ });
634
+ });
635
+
636
+ ...
637
+
638
+ }
639
+ ```
640
+
641
+ # JWT Broken Role
642
+
643
+ The **JWT Broken Role** mechanism provides a flexible way to bypass or override role-based authorization rules when using JWT.
644
+
645
+ #### It can be applied in three different levels, depending on your use case.
646
+
647
+ | Priority | Level | Scope | Best For |
648
+ |:---------|:--------------------------------|:-------------------------|:--------------------------------|
649
+ | 3rd | Global (``passport.config.js``) | All endpoints | Common authorization exceptions |
650
+ | 2nd | Model-level options | Per model & HTTP method | Structured, reusable rules |
651
+ | 1st | Endpoint middleware | Single endpoint | Custom or special cases |
652
+
653
+ This multi-layer approach allows you to design **secure, flexible, and maintainable JWT authorization flows**.
654
+
655
+ ### 1. Global Configuration (passport.config.js) - Priority 3
656
+
657
+ You can define global JWT Broken Role rules that apply to all endpoints by configuring them in ``passport.config.js``.
658
+ ```js
659
+ module.exports = {
660
+ // Enable JWT authentication
661
+ jwt_allow: true,
662
+
663
+ ...
664
+
665
+ // Global JWT broken role configuration
666
+ jwt_broken_role: [
667
+ {
668
+ role: [0, 2, 4],
669
+ email: "john.doe@company.com",
670
+ }, // Basic role matching
671
+
672
+ {
673
+ role: { $in: [0, 2, 4] },
674
+ email: { $regex: /@company\.com$/ },
675
+ }, // Advanced matching using operators
676
+ ],
677
+
678
+ ...
679
+ };
680
+ ```
681
+
682
+ **Use cases**
683
+
684
+ - Apply common authorization exceptions across the entire application
685
+ - Support both simple role arrays and advanced operators (``$in``, ``$regex``, etc.)
686
+
687
+ ### 2. Model-Level Configuration (Per HTTP Method) - Priority 2
688
+
689
+ You can configure JWT and Broken Role rules per model and per HTTP method using model options.
690
+
691
+ 📂 src/models/Fruit.js
692
+ ```js
693
+ Fruit.options = {
694
+ ...
695
+
696
+ // Auto-endpoint configuration by HTTP method
697
+ defaultEndpoint: {
698
+ GET: true, // Enable auto-generated GET endpoint
699
+
700
+ POST: {
701
+ allow: true,
702
+ jwt: {
703
+ allow: true,
704
+ broken_role: [
705
+ { role: [5, 6] },
706
+ ],
707
+ },
708
+ },
709
+
710
+ PATCH: {
711
+ allow: true,
712
+ jwt: {
713
+ allow: true,
714
+ broken_role: [
715
+ { role: [5, 6, 9] },
716
+ { department: "IT" },
717
+ ],
718
+ },
719
+ },
720
+
721
+ DELETE: false, // Disable auto-generated DELETE endpoint
722
+ },
723
+
724
+ ...
725
+ };
726
+ ```
727
+
728
+ **Use cases**
729
+
730
+ - Fine-grained access control per HTTP method
731
+ - Different role requirements for POST, PATCH, etc.
732
+ - Combine role-based and attribute-based conditions
733
+
734
+ ### 3. Endpoint-Level Configuration (Credentials Middleware) - Priority 1
735
+
736
+ For maximum flexibility, you can define Broken Role rules directly on a specific endpoint using the Credentials middleware.
737
+
738
+ 📂 endpoints/custom-fruit-endpoints.js
739
+ ```js
740
+ const { Fruit } = require("@/models/Fruit");
741
+
742
+ endpoint.delete(
743
+ "/destroy-fruit-by-id/:id",
744
+ Credentials([{ role: [5, 9] }]),
745
+ async (req, res) => {
746
+
747
+ // Only JWT tokens with role level 5 or 9 are allowed
748
+
749
+ const deleted = await Fruit.destroy({
750
+ where: {
751
+ id: req.params.id,
752
+ },
753
+ });
754
+
755
+ console.log("result:", deleted);
756
+
757
+ // @response
758
+ }
759
+ );
760
+ ```
761
+
762
+ **Use cases**
763
+
764
+ - One-off or custom endpoints
765
+ - Highly specific authorization rules
766
+ - Override global or model-level behavior when necessary
767
+
768
+ ## Supported Basic & Operators Usage
769
+
770
+ The JWT Broken Role system supports both basic value matching and advanced operators for flexible authorization rules.
771
+
772
+ | Operator | Meaning | Description |
773
+ |:---------|:-------------------|:--------------------------------------------------------------|
774
+ | $eq | equal | Matches when the value is equal |
775
+ | $ne | not equal | Matches when the value is not equal |
776
+ | $in | value IN array | Matches when the value exists in the specified array |
777
+ | $not | value NOT IN array | Matches when the value does not exist in the specified array |
778
+ | $regex | regex match | Matches using a regular expression |
779
+ | $fn | custom function | Matches using a custom evaluation function |
780
+
781
+ ## Evaluation Logic (Very Important !)
782
+ ```js
783
+ [
784
+ { rule1 AND rule1 },
785
+ { rule2 AND rule2 }
786
+ ]
787
+
788
+ OR
789
+ ```
790
+
791
+ ## Basic Usage for Examples :
792
+
793
+ ```js
794
+ Credentials([
795
+ { role: [9] }, // Only role check
796
+ { email: 'a@b.com' }, // OR email
797
+ ])
798
+
799
+ // Common Matching Patterns
800
+ { role: [1, 2, 3] } // IN
801
+ { role: 1 } // Equal
802
+ { email: 'a@b.com' } // Equal
803
+ { department: 'IT' } // Equal
804
+ { status: ['active'] } // Dynamic key
805
+ ```
806
+
807
+ ## Operators Usage for Examples :
808
+
809
+ ```js
810
+ // Equal with Role
811
+ Credentials([
812
+ {
813
+ role: { $eq: [1, 2, 5] }
814
+ }
815
+ ])
816
+
817
+ // Not Equal with Role
818
+ Credentials([
819
+ {
820
+ role: { $ne: [0, 3] }
821
+ }
822
+ ])
823
+
824
+ // Regex with Email domain
825
+ Credentials([
826
+ {
827
+ email: { $regex: /@company\.com$/ }
828
+ }
829
+ ])
830
+
831
+ // IN with Role
832
+ Credentials([
833
+ {
834
+ role: { $in: [1, 2, 4] }
835
+ }
836
+ ])
837
+
838
+ // NOT IN with Role
839
+ Credentials([
840
+ {
841
+ role: { $not: [0, 3] }
842
+ }
843
+ ])
844
+
845
+ // Multiple OR rules
846
+ Credentials([
847
+ {
848
+ role: { $in: [1] },
849
+ email: 'john.doe@company.com'
850
+ },
851
+ // OR
852
+ {
853
+ role: { $in: [4] },
854
+ email: { $regex: /@company\.com$/ }
855
+ },
856
+ ])
857
+
858
+ // Custom Function
859
+ Credentials([
860
+ {
861
+ role: {
862
+ $fn: (value, user) => value >= 4 && user.department === 'IT'
863
+ }
864
+ }
865
+ ])
866
+ ```
867
+
868
+ # Helpers
504
869
 
505
870
  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.
506
871
 
@@ -508,9 +873,9 @@ The `helpers` keep the files of functions for process specific something in the
508
873
  $ beech make helperName --helper
509
874
  ```
510
875
 
511
- ***Example:*** Text editor helper.
876
+ ***For Example :***
512
877
 
513
- 📂 TextEditor.js
878
+ 📂 helpers/TextEditor.js
514
879
  ```js
515
880
  module.exports = {
516
881
 
@@ -598,7 +963,7 @@ module.exports = {
598
963
 
599
964
  };
600
965
  ```
601
-
966
+ ### Request Token
602
967
  **Authentication structure :** Simple ``users`` table:
603
968
  ```
604
969
  ==============================================================
@@ -611,8 +976,9 @@ module.exports = {
611
976
  When you config passport with ```users``` table already. You will got Auth endpoint in available.
612
977
  ```js
613
978
  POST: "/authentication" // Request token
979
+ POST: "/authentication/refresh" // Request refresh token
614
980
  POST: "/authentication/create" // Create new Auth data
615
- PATCH: "/authentication/update/:id" // Update old Auth data (needed id)
981
+ PATCH: "/authentication/update/:id" // Update old Auth data (needed user id)
616
982
  ```
617
983
 
618
984
  ***XHR Example :***
@@ -620,26 +986,28 @@ PATCH: "/authentication/update/:id" // Update old Auth data (needed id)
620
986
  ```js
621
987
  // Request with body for gether Token
622
988
  POST: "/authentication"
623
- {
989
+ payload: {
624
990
  username: "bombkiml",
625
991
  password: "secret"
626
992
  }
627
993
 
994
+ // Request with header for refresh token
995
+ POST: "/authentication/refresh"
996
+ headers: Authorization: Bearer <your_token>
628
997
 
629
998
  // Request with body for Create Auth data
630
999
  POST: "/authentication/create"
631
- {
1000
+ payload: {
632
1001
  username: "add_new_username",
633
1002
  password: "add_new_secret",
634
1003
  name: "add_new_my_name",
635
1004
  email: "add_new_email"
636
1005
  }
637
1006
 
638
-
639
1007
  // Request with body for Update Auth data
640
1008
  PATCH: "/authentication/update/1"
641
1009
  headers: Authorization: Bearer <your_token>
642
- {
1010
+ payload: {
643
1011
  username: "update_bombkiml",
644
1012
  password: "update_secret",
645
1013
  name: "update_my_name",
@@ -647,10 +1015,10 @@ headers: Authorization: Bearer <your_token>
647
1015
  }
648
1016
  ```
649
1017
 
650
- # Beech Two Factor (2FA)
1018
+ # Beech Guard
651
1019
  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
1020
 
653
- ## # Usage guard (2FA, Other)
1021
+ ## # Guard (2FA, Other)
654
1022
 
655
1023
  📂 passport.config.js
656
1024
  ```js
@@ -659,7 +1027,7 @@ module.exports = {
659
1027
 
660
1028
  guard: {
661
1029
  // Other fields add for authenticate, exmaple ["pin", "hint", "2fa"]
662
- guard_field: ["2fa"], 👈 // your feild guard.
1030
+ guard_field: ["2fa"], 👈 // your feild guard. (Disabled to remove it.)
663
1031
 
664
1032
  ...
665
1033
  },
@@ -680,7 +1048,7 @@ module.exports = {
680
1048
  guard: {
681
1049
  ...
682
1050
 
683
- // Advanced guard jwt request (needed some logical from front-end)
1051
+ // Advanced guard to Request (Needed some logical from front-end)
684
1052
  advanced_guard: {
685
1053
  allow: false, 👈 // advanced guard allow for All Endpoint.
686
1054
  entity: "", // default entity `timing`
@@ -709,26 +1077,42 @@ $ npm install --save beech-auth0 moment
709
1077
  # Yarn
710
1078
  $ yarn add beech-auth0 moment
711
1079
  ```
712
- Now! you can add some logic.
1080
+ Now! you can add some logic like this.
1081
+
1082
+ - Import packages
1083
+
713
1084
  ```js
1085
+ // CommonJS
714
1086
  const { Auth0 } = require("beech-auth0");
715
1087
  const moment = require("moment");
716
1088
 
1089
+ // ES6
1090
+ import { Auth0 } from "beech-auth0";
1091
+ import moment from "moment";
1092
+ ```
1093
+
1094
+ - Get unix time with momentJS
1095
+
1096
+ ```js
717
1097
  // Get UNIX TIME with moment
718
1098
  let unix_time = moment().unix();
1099
+ ```
1100
+
1101
+ - Get hashing with Beech Auth0
719
1102
 
1103
+ ```js
720
1104
  // Auth0 Policy.
721
1105
  Auth0(unix_time, 'your_advance_guard_secret', (error, hashing) => {
722
-
1106
+
723
1107
  // Your XHR request for All Endpoint.
724
1108
  POST: "/authentication"
725
- headers: timing: hashing, 👈 // Assign advance guard entity to headers with callback hashing.
1109
+ headers: { timing: hashing } 👈 // Assign advance guard entity to headers with callback hashing.
726
1110
 
727
1111
  });
728
1112
 
729
1113
  ```
730
1114
 
731
- ## # Beech User Auth Managements ###
1115
+ ## # Beech User Authentication Managements ###
732
1116
  You can easy management `users` data with Beech, Only ```Store, Update``` NO ```Delete```, Anything you can make DELETE endpoint by yourself
733
1117
 
734
1118
  ```js
@@ -929,6 +1313,23 @@ module.exports = {
929
1313
  duplicateRequest: {
930
1314
  expiration: 500, // Can't duplicate request for 5 milliseconds each IP requests per `window`
931
1315
  },
1316
+
1317
+ payload: {
1318
+ // The limit of request body size, json default "100KB", urlencoded default "100KB". Learn more: https://expressjs.com/en/4x/api.html#express.json
1319
+ json: {
1320
+ limit: "100KB", // default: "100KB"
1321
+ },
1322
+ urlencoded: {
1323
+ limit: "100KB", // default: "100KB"
1324
+ extended: true, // default: true (reccomended: true)
1325
+ },
1326
+ file: {
1327
+ uploadAllowMethod: ["POST", "PATCH", "PUT"], // Only apply file upload limit for POST, PATCH, PUT method.
1328
+ allowedTypes: ["image/jpeg", "image/png", "application/pdf"], // Example: Allow only JPEG, PNG, and PDF files. Learn more: https://www.digipres.org/formats/mime-types/
1329
+ limit: 5 * 1024 * 1024, // 5MB (default: Infinity)
1330
+ },
1331
+ },
1332
+
932
1333
  },
933
1334
  },
934
1335
  }
@@ -1014,8 +1415,6 @@ endpoint.get("/banana", specificDup1, (req, res) => {
1014
1415
  ...
1015
1416
  ```
1016
1417
 
1017
-
1018
-
1019
1418
  # Databases managements
1020
1419
 
1021
1420
  ## # Migrations & Seeder
@@ -1050,6 +1449,7 @@ Before continuing further we will need to tell CLI how to connect to database. T
1050
1449
  "password": null,
1051
1450
  "database": "database_development",
1052
1451
  "host": "127.0.0.1",
1452
+ "port": 3306, // IF your another port
1053
1453
  "dialect": "mysql"
1054
1454
  },
1055
1455
  "test": {
@@ -1098,7 +1498,12 @@ Until this step, we haven't inserted anything into the database. We have just cr
1098
1498
 
1099
1499
  - **Migrate Down** : you can use `db:migrate:undo`, this command will revert most recent migration.
1100
1500
  ```sh
1501
+ // Step to undo
1101
1502
  $ npx sequelize-cli db:migrate:undo
1503
+
1504
+ // All to undo
1505
+ $ npx sequelize-cli db:migrate:undo:all
1506
+
1102
1507
  ```
1103
1508
 
1104
1509
  ## # Creating First Seeder
@@ -1147,9 +1552,9 @@ Test using [Jest](https://jestjs.io/en/) for testing the project. Jest is a deli
1147
1552
 
1148
1553
  So, When you make the new endpoints it's automatic create test file end with `.spec.js` in `__test__` folder with constant `baseUrl` variable and `axios` package.
1149
1554
 
1150
- Example endpoints testing :
1555
+ ***For Example :***
1151
1556
 
1152
- 📂 fruit-endpoints.spec.js
1557
+ 📂 \_\_test\_\_/unit/endpoints/fruit-endpoints.spec.js
1153
1558
  ```js
1154
1559
  const endpoint = baseUrl.concat("/fruit");
1155
1560
 
@@ -1180,7 +1585,7 @@ Docker builds images automatically by reading the instructions from a Dockerfile
1180
1585
 
1181
1586
  📂 Dockerfile
1182
1587
  ```js
1183
- FROM node:14.19-alpine
1588
+ FROM node:18-alpine
1184
1589
  ENV NODE_ENV=production
1185
1590
  WORKDIR /usr/src/api
1186
1591
  COPY ["package.json", "package-lock.json*", "./"]