@vulkano/core 1.20.1 → 1.22.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 (31) hide show
  1. package/README.md +380 -70
  2. package/controllers/controllers.js +36 -8
  3. package/database/mongodb.js +11 -4
  4. package/examples/config/express/cookies.js +15 -0
  5. package/examples/config/express/cors.js +23 -0
  6. package/examples/config/express/csp.js +74 -0
  7. package/examples/config/express/helmet.js +19 -0
  8. package/examples/config/express/json.js +14 -0
  9. package/examples/config/express/jwt.js +39 -0
  10. package/examples/config/express/permissionPolicy.js +24 -0
  11. package/examples/config/express/settings.js +25 -0
  12. package/examples/config/middlewares/auth.js +38 -0
  13. package/examples/config/sockets/adapters/mongodb.js +12 -0
  14. package/examples/config/sockets/adapters/redis.js +9 -0
  15. package/examples/config/sockets/config.js +50 -0
  16. package/examples/config/sockets/cors.js +32 -0
  17. package/examples/config/sockets/events.js +12 -0
  18. package/examples/config/sockets/middlewares/auth.js +20 -0
  19. package/examples/config/views/config.js +8 -0
  20. package/examples/config/views/filters/example.js +6 -0
  21. package/examples/config/views/helpers/strpad.js +51 -0
  22. package/examples/controllers/ExampleController.js +22 -0
  23. package/examples/controllers/RestExampleController.js +78 -0
  24. package/examples/controllers/RestScaffoldController.js +18 -0
  25. package/examples/models/Example.js +238 -0
  26. package/examples/models/ExampleWithScaffold.js +51 -0
  27. package/examples/routes.js +55 -0
  28. package/examples/views/_shared/templates/default.html +20 -0
  29. package/examples/views/index.html +7 -0
  30. package/package.json +1 -1
  31. package/pnpm-workspace.yaml +7 -1
@@ -175,12 +175,17 @@ module.exports = async function loadDatabaseApplication() {
175
175
  }
176
176
 
177
177
  // Update
178
+ // Bound to "updateOne" (the Mongoose 8 document method) rather than the
179
+ // legacy "update" hook name: Mongoose no longer fires "update" middleware,
180
+ // and that name collides with the scaffold's own `Model.update()` static
181
+ // (schema.statics.update), which Mongoose auto-wraps with any hook whose
182
+ // name matches an existing static method.
178
183
  if (current.beforeUpdate) {
179
- schema.pre('update', current.beforeUpdate);
184
+ schema.pre('updateOne', { document: true, query: false }, current.beforeUpdate);
180
185
  delete schema.statics.beforeUpdate;
181
186
  }
182
187
  if (current.afterUpdate) {
183
- schema.post('update', current.afterUpdate);
188
+ schema.post('updateOne', { document: true, query: false }, current.afterUpdate);
184
189
  delete schema.statics.afterUpdate;
185
190
  }
186
191
 
@@ -195,12 +200,14 @@ module.exports = async function loadDatabaseApplication() {
195
200
  }
196
201
 
197
202
  // Remove
203
+ // Bound to "deleteOne" (the Mongoose 8 document method): `doc.remove()`
204
+ // and the legacy "remove" hook name were both removed upstream.
198
205
  if (current.beforeRemove) {
199
- schema.pre('remove', current.beforeRemove);
206
+ schema.pre('deleteOne', { document: true, query: false }, current.beforeRemove);
200
207
  delete schema.statics.beforeRemove;
201
208
  }
202
209
  if (current.afterRemove) {
203
- schema.post('remove', current.afterRemove);
210
+ schema.post('deleteOne', { document: true, query: false }, current.afterRemove);
204
211
  delete schema.statics.afterRemove;
205
212
  }
206
213
 
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Cookies Config
3
+ */
4
+
5
+ module.exports = {
6
+
7
+ // Enable cookie parser middleware
8
+ // @type Boolean
9
+ enabled: false,
10
+
11
+ // Secret key used to sign cookies — use https://api.wordpress.org/secret-key/1.1/salt/
12
+ // @type String
13
+ secret: process.env.COOKIES_SECRET_KEY || ''
14
+
15
+ };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * CORS Config
3
+ */
4
+
5
+ module.exports = {
6
+
7
+ // Enable CORS
8
+ // @type Boolean
9
+ enabled: false,
10
+
11
+ // Path where CORS headers are applied
12
+ // @type String
13
+ path: '/',
14
+
15
+ // Allowed origin
16
+ // @type String
17
+ origin: '*',
18
+
19
+ // Additional allowed request headers
20
+ // @type Array
21
+ headers: ['x-token-auth']
22
+
23
+ };
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Content Security Policy
3
+ *
4
+ * Requires an endpoint to receive CSP violation reports.
5
+ */
6
+
7
+ module.exports = {
8
+
9
+ // Enable CSP
10
+ enabled: false,
11
+
12
+ // Reporting endpoint
13
+ report: {
14
+ group: 'csp-endpoint',
15
+ max_age: '10886400',
16
+ endpoints: [
17
+ {
18
+ // Replace with your domain
19
+ url: 'https://yourdomain.com/__cspreport__'
20
+ }
21
+ ]
22
+ },
23
+
24
+ // CSP rules
25
+ rules: {
26
+
27
+ 'default-src': ["'self'"],
28
+
29
+ 'form-action': ["'self'"],
30
+
31
+ 'font-src': [
32
+ "'self'",
33
+ 'data:',
34
+ // 'fonts.googleapis.com',
35
+ // 'fonts.gstatic.com',
36
+ ],
37
+
38
+ 'img-src': [
39
+ "'self'",
40
+ 'data:',
41
+ // '*.google-analytics.com',
42
+ ],
43
+
44
+ 'script-src': [
45
+ "'self'",
46
+ // "'unsafe-inline'",
47
+ // "'unsafe-eval'",
48
+ ],
49
+
50
+ 'style-src': [
51
+ "'self'",
52
+ "'unsafe-inline'",
53
+ 'cdnjs.cloudflare.com'
54
+ ],
55
+
56
+ 'style-src-elem': [
57
+ "'self'",
58
+ // 'fonts.googleapis.com',
59
+ ],
60
+
61
+ 'frame-src': ["'self'"],
62
+
63
+ 'frame-ancestors': ["'self'"],
64
+
65
+ 'connect-src': [
66
+ "'self'",
67
+ // '*.google-analytics.com',
68
+ ],
69
+
70
+ 'report-to': ['csp-endpoint']
71
+
72
+ }
73
+
74
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Helmet Config
3
+ * See https://helmetjs.github.io/ for all available options
4
+ */
5
+
6
+ module.exports = {
7
+
8
+ // Referrer policy header
9
+ referrerPolicy: {
10
+ policy: 'strict-origin-when-cross-origin'
11
+ },
12
+
13
+ // Disable built-in CSP — managed separately via csp.js
14
+ contentSecurityPolicy: false,
15
+
16
+ // Disable COEP to allow embedding cross-origin resources
17
+ crossOriginEmbedderPolicy: false
18
+
19
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Express JSON body parser config
3
+ */
4
+
5
+ module.exports = {
6
+
7
+ // MIME types accepted as JSON body
8
+ type: [
9
+ 'application/json',
10
+ 'application/csp-report',
11
+ 'application/reports+json'
12
+ ]
13
+
14
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * JWT Config
3
+ */
4
+
5
+ module.exports = {
6
+
7
+ // Enable JWT
8
+ // @type Boolean
9
+ enabled: false,
10
+
11
+ // Secret key — use https://api.wordpress.org/secret-key/1.1/salt/ to generate one
12
+ // @type String
13
+ key: process.env.JWT_SECRET_KEY || '',
14
+
15
+ // Header name used to send the token
16
+ // @type String
17
+ header: 'x-token-auth',
18
+
19
+ // Query parameter name used to send the token
20
+ // @type String
21
+ queryParameter: 'token',
22
+
23
+ // Cookie name used to send the token
24
+ // @type String
25
+ cookieName: 'token',
26
+
27
+ // Path where the token is required
28
+ // @type String
29
+ path: '/api/',
30
+
31
+ // Paths excluded from token verification
32
+ // See https://github.com/jfromaniello/express-unless for pattern examples
33
+ // @type Array
34
+ ignore: [
35
+ '/api/',
36
+ /^\/api\/auth(?!\/(current))/i
37
+ ]
38
+
39
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Permission Policy Config
3
+ */
4
+
5
+ module.exports = {
6
+
7
+ // Enable Permission Policy header
8
+ // @type Boolean
9
+ enabled: false,
10
+
11
+ // Browser features to restrict — empty list means blocked for all origins
12
+ // @type Array
13
+ permissions: [
14
+ 'accelerometer=()',
15
+ 'camera=()',
16
+ 'geolocation=()',
17
+ 'gyroscope=()',
18
+ 'magnetometer=()',
19
+ 'microphone=()',
20
+ 'payment=()',
21
+ 'usb=()'
22
+ ]
23
+
24
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Express server settings
3
+ */
4
+
5
+ module.exports = {
6
+
7
+ // Show "X-Powered-By" header
8
+ // @type Boolean
9
+ poweredBy: false,
10
+
11
+ // Request timeout in milliseconds
12
+ // @type Number
13
+ timeout: 120000,
14
+
15
+ // Folder to upload files
16
+ // @type String
17
+ uploadPath: 'public/files',
18
+
19
+ // Number of proxy hops to trust for X-Forwarded-* headers.
20
+ // Use 1 when behind a single load balancer, true to trust all (less secure).
21
+ // See https://expressjs.com/en/guide/behind-proxies.html
22
+ // @type Number | Boolean
23
+ trustProxy: 1
24
+
25
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Middleware.js
3
+ *
4
+ * This file intercept all requests to make validations before running a controller
5
+ *
6
+ */
7
+ module.exports = (req, res, next) => {
8
+
9
+ const {
10
+ auth: authEncripted
11
+ } = req;
12
+
13
+ if (authEncripted) {
14
+ const decoded = Jwt.decrypt(authEncripted);
15
+ req.auth = (decoded) ? { ...decoded, token: Jwt.getToken(req) } : {};
16
+ }
17
+
18
+ // Remove this line if you need make validations
19
+ next();
20
+
21
+ //
22
+ // You can make validations to check ACL or anything before to run a controller
23
+ // Example:
24
+ //
25
+
26
+ /*
27
+ if (req.auth && +req.auth.role !== 1) {
28
+ const data = {
29
+ success: false,
30
+ error: 'You don\'t have permissions to access this option.'
31
+ }
32
+ res.status(403).jsonp(data);
33
+ } else {
34
+ next();
35
+ }
36
+ */
37
+
38
+ };
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+
3
+ //
4
+ // Connection: you can use the same connection
5
+ // set a custom Mongo URI connection to manage the sockets
6
+ //
7
+ connection: process.env.SOCKETS_MONGO_URI || null,
8
+
9
+ // Collection to save the records
10
+ collection: process.env.SOCKETS_MONGO_COLLECTION || 'socket.io-adapter-events'
11
+
12
+ };
@@ -0,0 +1,9 @@
1
+ module.exports = {
2
+
3
+ host: process.env.REDIS_HOST || 'localhost',
4
+
5
+ port: process.env.REDIS_PORT || '6379',
6
+
7
+ password: process.env.REDIS_PASSWORD || ''
8
+
9
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ *
3
+ * Sockets Config
4
+ *
5
+ */
6
+
7
+ module.exports = {
8
+
9
+ // Enable sockets
10
+ enabled: true,
11
+
12
+ // Socket IO Adapter (redis|mongodb|memory)
13
+ adapter: 'memory',
14
+
15
+ // Socket configuration
16
+ config: {
17
+
18
+ // Transports
19
+ transports: ['websocket', 'polling'],
20
+
21
+ // Socket timeout
22
+ timeout: 4000,
23
+
24
+ // Interval
25
+ interval: 2000,
26
+
27
+ },
28
+
29
+ // Connections
30
+ connections: {
31
+
32
+ users: 0,
33
+
34
+ // Clients connected
35
+ clients: {}
36
+
37
+ },
38
+
39
+ // Event handlers
40
+ // onConnect: (io, socket, clients, counter) => {
41
+ // counter.users++;
42
+ // clients[socket.request.user._id] = socket.id;
43
+ // io.emit('users:counter', counter.users);
44
+ // },
45
+ // onDisconnect: (io, socket, clients, counter) => {
46
+ // counter.users--;
47
+ // delete clients[socket.request.user._id];
48
+ // io.emit('users:counter', counter.users);
49
+ // }
50
+ };
@@ -0,0 +1,32 @@
1
+ module.exports = (req, callback) => {
2
+
3
+ const {
4
+ origin,
5
+ host,
6
+ } = req.headers || {};
7
+
8
+ const realOrigin = origin || host;
9
+
10
+ const allowedOrigin = [
11
+ 'localhost',
12
+ 'yourdomain.com'
13
+ ];
14
+
15
+ let found = false;
16
+
17
+ allowedOrigin.forEach((o) => {
18
+
19
+ if ((realOrigin || '').indexOf(o) !== -1) {
20
+ found = true;
21
+ }
22
+
23
+ });
24
+
25
+ if (found) {
26
+ callback(null, true);
27
+ } else {
28
+ console.log('Invalid origin', realOrigin || 'No Origin');
29
+ callback(new Error(`Invalid origin ${realOrigin} - Socket CORS`));
30
+ }
31
+
32
+ };
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+
3
+ // Examples Chat
4
+ // event:action: folder.YourController.method
5
+ //
6
+ // 'chat:signin': 'sockets.ChatController.signin',
7
+ // 'chat:message': 'sockets.ChatController.save',
8
+ // 'chat:history': 'sockets.ChatController.get'
9
+
10
+ 'echo': 'sockets.EchoController.echo'
11
+
12
+ };
@@ -0,0 +1,20 @@
1
+ module.exports = (socket, next) => {
2
+
3
+ // Security
4
+ const user = Jwt.socket(socket);
5
+
6
+ const {
7
+ _id
8
+ } = user || {};
9
+
10
+ if (!_id) {
11
+ console.log('Sockets Middleware: Invalid ID');
12
+ next(new Error(`Invalid user ${_id || 'or token'}`));
13
+ }
14
+
15
+ // eslint-disable-next-line no-param-reassign
16
+ socket.request.user = user || {};
17
+
18
+ next();
19
+
20
+ };
@@ -0,0 +1,8 @@
1
+
2
+ module.exports = {
3
+
4
+ engine: 'nunjucks|handlebars',
5
+
6
+ ext: '.html'
7
+
8
+ };
@@ -0,0 +1,6 @@
1
+ // Filter-style helper (positional arg):
2
+ // Nunjucks: {{ 'hello' | example }}
3
+ // Handlebars: {{ example 'hello' }}
4
+ module.exports = (str) => {
5
+ return (str || '').split('').join(' ');
6
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Pads a string to a certain length with another string.
3
+ * The padding is applied from the left, right, or both sides of the string.
4
+ *
5
+ * Example: {{ strpad('hello world', 20, '*', 'left') }} => '*********hello world'
6
+ *
7
+ * @param {*} str
8
+ * @param {*} _len
9
+ * @param {*} _pad
10
+ * @param {*} _dir
11
+ * @returns String
12
+ */
13
+
14
+ module.exports = (str, _len, _pad, _dir) => {
15
+
16
+ const STR_PAD_LEFT = 1;
17
+ const STR_PAD_RIGHT = 2;
18
+ const STR_PAD_BOTH = 3;
19
+
20
+ const len = _len || 0;
21
+ const pad = _pad || ' ';
22
+ const dir = _dir || STR_PAD_RIGHT;
23
+
24
+ let newStr = '';
25
+
26
+ if (len + 1 >= str.length) {
27
+
28
+ const padlen = len - str.length;
29
+ const right = Math.ceil(padlen / 2);
30
+ const left = padlen - right;
31
+
32
+ switch (dir) {
33
+ case STR_PAD_LEFT:
34
+ newStr = Array(len + 1 - str.length).join(pad) + str;
35
+ break;
36
+ case 'left':
37
+ newStr = Array(len + 1 - str.length).join(pad) + str;
38
+ break;
39
+ case STR_PAD_BOTH:
40
+ newStr = Array(left + 1).join(pad) + str + Array(right + 1).join(pad);
41
+ break;
42
+ default:
43
+ newStr = str + Array(len + 1 - str.length).join(pad);
44
+ break;
45
+ }
46
+
47
+ }
48
+
49
+ return newStr;
50
+
51
+ };
@@ -0,0 +1,22 @@
1
+ // This is an example for a simple controller that renders a view.
2
+ // It is a good starting point for creating a simple web application.
3
+
4
+ module.exports = {
5
+
6
+ // Method to render the home page
7
+ // Example: domain.com/example/
8
+ get(req, res) {
9
+
10
+ res.render('example/index.html', { title: 'This is an example home page' });
11
+
12
+ },
13
+
14
+ // Method to render the about page
15
+ // Example: domain.com/example/about/
16
+ about(req, res) {
17
+
18
+ res.render('example/about.html', { title: 'This is an example about page' });
19
+
20
+ }
21
+
22
+ };
@@ -0,0 +1,78 @@
1
+ /* global Example */
2
+
3
+ /*
4
+ * This endpoint is protected by JWT, please disabled it to test
5
+ */
6
+
7
+ // This is an example for Full API Rest controller that provides CRUD operations.
8
+ // It is a good starting point for creating a RESTful API.
9
+ // The business logic is implemented in the Example model, which is a good practice
10
+ // to keep the controller thin and focused on handling requests and responses.
11
+
12
+ module.exports = {
13
+
14
+ // Method to get all records from the model
15
+ // Example: GET /projects/?page=1
16
+ get(req, res) {
17
+
18
+ // Status code: 200 (default)
19
+ res.vsr(Example.getAll(req.query || {}));
20
+
21
+ },
22
+
23
+ // Method to create a new record in the model
24
+ // Example: POST /projects/
25
+ post(req, res) {
26
+
27
+ const {
28
+ body
29
+ } = req || {};
30
+
31
+ // Status code: 201 (created)
32
+ res.vsr(Example.create(body), 201);
33
+
34
+ },
35
+
36
+ // Method to get a record by id from the model
37
+ // Example: GET /projects/:id
38
+ 'get :id': (req, res) => {
39
+
40
+ const {
41
+ id
42
+ } = req.params;
43
+
44
+ // Status code: 200 (default)
45
+ res.vsr(Example.getExample(id));
46
+
47
+ },
48
+
49
+ // Method to update a record by id in the model
50
+ // Example: PUT /projects/:id
51
+ 'put :id': (req, res) => {
52
+
53
+ const {
54
+ id
55
+ } = req.params;
56
+
57
+ const {
58
+ body
59
+ } = req || {};
60
+
61
+ // Status code: 202 (accepted)
62
+ res.vsr(Example.update(id, body), 202);
63
+
64
+ },
65
+
66
+ // Method to delete a record by id from the model
67
+ // Example: DELETE /projects/:id
68
+ 'delete :id': (req, res) => {
69
+
70
+ const {
71
+ id
72
+ } = req.params;
73
+
74
+ res.vsr(Example.remove(id), 204);
75
+
76
+ }
77
+
78
+ };
@@ -0,0 +1,18 @@
1
+ /*
2
+ * This endpoint is protected by JWT, please disable it to test
3
+ */
4
+
5
+ // Scaffold Controller is a controller that provides CRUD operations for a model.
6
+ // It is a generic controller that can be used to create, read, update, and delete records
7
+ // from a model. It is a good starting point for creating a
8
+ // RESTful API.
9
+
10
+ module.exports = {
11
+
12
+ // Model to CRUD (create, read, update, and delete) records — must exist as global.ExampleWithScaffold
13
+ scaffold: 'ExampleWithScaffold',
14
+
15
+ // Allowed methods
16
+ allowedMethods: ['get', 'post', 'put', 'delete']
17
+
18
+ };