@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.
- package/README.md +380 -70
- package/controllers/controllers.js +36 -8
- package/database/mongodb.js +11 -4
- package/examples/config/express/cookies.js +15 -0
- package/examples/config/express/cors.js +23 -0
- package/examples/config/express/csp.js +74 -0
- package/examples/config/express/helmet.js +19 -0
- package/examples/config/express/json.js +14 -0
- package/examples/config/express/jwt.js +39 -0
- package/examples/config/express/permissionPolicy.js +24 -0
- package/examples/config/express/settings.js +25 -0
- package/examples/config/middlewares/auth.js +38 -0
- package/examples/config/sockets/adapters/mongodb.js +12 -0
- package/examples/config/sockets/adapters/redis.js +9 -0
- package/examples/config/sockets/config.js +50 -0
- package/examples/config/sockets/cors.js +32 -0
- package/examples/config/sockets/events.js +12 -0
- package/examples/config/sockets/middlewares/auth.js +20 -0
- package/examples/config/views/config.js +8 -0
- package/examples/config/views/filters/example.js +6 -0
- package/examples/config/views/helpers/strpad.js +51 -0
- package/examples/controllers/ExampleController.js +22 -0
- package/examples/controllers/RestExampleController.js +78 -0
- package/examples/controllers/RestScaffoldController.js +18 -0
- package/examples/models/Example.js +238 -0
- package/examples/models/ExampleWithScaffold.js +51 -0
- package/examples/routes.js +55 -0
- package/examples/views/_shared/templates/default.html +20 -0
- package/examples/views/index.html +7 -0
- package/package.json +1 -1
- package/pnpm-workspace.yaml +7 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/* global Example */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Example.js
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// This is an example for a simple model that provides CRUD operations.
|
|
8
|
+
// Provide a flexible way to implement business logic in the model, which is a good practice
|
|
9
|
+
// to keep the controller thin and focused on handling requests and responses.
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fields
|
|
15
|
+
*/
|
|
16
|
+
attributes: {
|
|
17
|
+
name: {
|
|
18
|
+
type: String,
|
|
19
|
+
required: true
|
|
20
|
+
},
|
|
21
|
+
age: {
|
|
22
|
+
type: Number,
|
|
23
|
+
required: false,
|
|
24
|
+
validate: {
|
|
25
|
+
validator: (value) => {
|
|
26
|
+
const isValid = (value >= 21) ? true : false;
|
|
27
|
+
return isValid;
|
|
28
|
+
},
|
|
29
|
+
message: 'Invalid Age: Must be +21.',
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// the fields:
|
|
33
|
+
// active, createdAt, updatedAt
|
|
34
|
+
// was created automatically
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// Custom Index
|
|
38
|
+
indexes: [
|
|
39
|
+
{
|
|
40
|
+
name: 'text'
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Method to get all records by page
|
|
46
|
+
*
|
|
47
|
+
* @param {Object} props (page, perPage, search, sort)
|
|
48
|
+
* @returns {Promise}
|
|
49
|
+
*/
|
|
50
|
+
getAll(props) {
|
|
51
|
+
|
|
52
|
+
// Props to Query
|
|
53
|
+
const defaultProps = {
|
|
54
|
+
sort: 'createdAt|DESC',
|
|
55
|
+
searchBy: ['name'],
|
|
56
|
+
fields: ['name', 'age', 'active', 'createdAt', 'updatedAt'],
|
|
57
|
+
filter: {
|
|
58
|
+
active: true
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Populate
|
|
63
|
+
const populate = [];
|
|
64
|
+
|
|
65
|
+
// Query to Run
|
|
66
|
+
const query = Paginate.serializeQuery(defaultProps, props);
|
|
67
|
+
|
|
68
|
+
// Pagination
|
|
69
|
+
return Paginate.get(Example, query, populate);
|
|
70
|
+
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Method to get a record by id
|
|
75
|
+
*
|
|
76
|
+
* @param {ObjectID} id
|
|
77
|
+
* @returns {Promise}
|
|
78
|
+
*/
|
|
79
|
+
getExample(_id) {
|
|
80
|
+
|
|
81
|
+
// This is to prevent error while run the findOne
|
|
82
|
+
if (!(/^[a-fA-F0-9]{24}$/).test(_id)) {
|
|
83
|
+
return VSError.reject('Invalid ID. Record not found', 404);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return Example.findOne({ _id })
|
|
87
|
+
.then( (r) => {
|
|
88
|
+
|
|
89
|
+
if (!r) {
|
|
90
|
+
return VSError.notFound();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return r.toObject({ transform: true });
|
|
94
|
+
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Method to create a new record
|
|
101
|
+
* @param {Promise} data
|
|
102
|
+
*/
|
|
103
|
+
create(data) {
|
|
104
|
+
|
|
105
|
+
const obj = new Example(data);
|
|
106
|
+
return obj.save();
|
|
107
|
+
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Method to update a record
|
|
112
|
+
* @param {ObjectID} id
|
|
113
|
+
* @param {Object} data
|
|
114
|
+
* @returns {Promise}
|
|
115
|
+
*/
|
|
116
|
+
update(_id, data) {
|
|
117
|
+
|
|
118
|
+
return Example.getExample(_id)
|
|
119
|
+
.then( (record) => {
|
|
120
|
+
|
|
121
|
+
// Merge current info with incoming values
|
|
122
|
+
const merged = { ...record, ...data };
|
|
123
|
+
|
|
124
|
+
return Example
|
|
125
|
+
.findOneAndUpdate({ _id }, merged, { new: true })
|
|
126
|
+
.then( (r) => {
|
|
127
|
+
|
|
128
|
+
const tmp = r.toObject({ transform: true });
|
|
129
|
+
return tmp;
|
|
130
|
+
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Method to delete a record
|
|
139
|
+
* @param {ObjectID} id
|
|
140
|
+
* @returns {Promise}
|
|
141
|
+
*/
|
|
142
|
+
delete(id) {
|
|
143
|
+
|
|
144
|
+
// Soft delete
|
|
145
|
+
return this.update(id, { active: false });
|
|
146
|
+
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Before validate callback — runs before beforeSave, as part of obj.save()
|
|
151
|
+
* (create() above). Does NOT run for update()/delete(): Mongoose's update
|
|
152
|
+
* validators (runValidators) validate each changed path directly and never
|
|
153
|
+
* go through this callback, even when a validator rejects the value.
|
|
154
|
+
* @param {Callback} cb
|
|
155
|
+
*/
|
|
156
|
+
beforeValidate(cb) {
|
|
157
|
+
|
|
158
|
+
console.log('Running callback before validate');
|
|
159
|
+
|
|
160
|
+
// All good!
|
|
161
|
+
cb();
|
|
162
|
+
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Callback after validate
|
|
167
|
+
* @param {Callback} cb
|
|
168
|
+
*/
|
|
169
|
+
afterValidate(cb) {
|
|
170
|
+
|
|
171
|
+
console.log('Running callback after validate');
|
|
172
|
+
|
|
173
|
+
// All good!
|
|
174
|
+
cb();
|
|
175
|
+
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Before save callback
|
|
180
|
+
* @param {Callback} cb
|
|
181
|
+
*/
|
|
182
|
+
beforeSave(cb) {
|
|
183
|
+
|
|
184
|
+
const doc = this;
|
|
185
|
+
|
|
186
|
+
console.log('Running callback before save');
|
|
187
|
+
console.log(doc);
|
|
188
|
+
|
|
189
|
+
// All good!
|
|
190
|
+
cb();
|
|
191
|
+
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Callback after save
|
|
196
|
+
* @param {Callback} cb
|
|
197
|
+
*/
|
|
198
|
+
afterSave(doc, cb) {
|
|
199
|
+
|
|
200
|
+
console.log('Running callback after save');
|
|
201
|
+
console.log(doc);
|
|
202
|
+
|
|
203
|
+
// All good!
|
|
204
|
+
cb();
|
|
205
|
+
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Before findOneAndUpdate callback — runs on update() and delete() above,
|
|
210
|
+
* since both call Example.findOneAndUpdate() directly. `this` is the Query,
|
|
211
|
+
* not the document.
|
|
212
|
+
* @param {Callback} cb
|
|
213
|
+
*/
|
|
214
|
+
beforeFindOneAndUpdate(cb) {
|
|
215
|
+
|
|
216
|
+
console.log('Running callback before findOneAndUpdate');
|
|
217
|
+
|
|
218
|
+
// All good!
|
|
219
|
+
cb();
|
|
220
|
+
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Callback after findOneAndUpdate
|
|
225
|
+
* @param {Object} doc Updated document
|
|
226
|
+
* @param {Callback} cb
|
|
227
|
+
*/
|
|
228
|
+
afterFindOneAndUpdate(doc, cb) {
|
|
229
|
+
|
|
230
|
+
console.log('Running callback after findOneAndUpdate');
|
|
231
|
+
console.log(doc);
|
|
232
|
+
|
|
233
|
+
// All good!
|
|
234
|
+
cb();
|
|
235
|
+
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExampleWithScaffold.js
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// This is an example for a simple model that provides CRUD operations with a scaffold.
|
|
6
|
+
// Provide a flexible way to implement business logic in the model, which is a good practice
|
|
7
|
+
// to keep the controller thin and focused on handling requests and responses.
|
|
8
|
+
|
|
9
|
+
// Scaffold (Model name: ExampleWithScaffold) - Allowed Methods:
|
|
10
|
+
// ExampleWidthScaffold.getAllExampleWidthScaffold(props) { page, perPage, search, sort }
|
|
11
|
+
// ExampleWidthScaffold.getAll(props) (alias to getAllModelName)
|
|
12
|
+
// ExampleWidthScaffold.create(payload) { name, age }
|
|
13
|
+
// ExampleWidthScaffold.getByField(email, 'email') (alias)
|
|
14
|
+
// ExampleWidthScaffold.getExampleWidthScaffold(id)
|
|
15
|
+
// ExampleWidthScaffold.update(id, payload)
|
|
16
|
+
// ExampleWidthScaffold.delete(id)
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Fillable fields for the update method
|
|
22
|
+
* to prevent update of non-allowed fields like createdAt, updatedAt, etc.
|
|
23
|
+
* @type Array
|
|
24
|
+
*/
|
|
25
|
+
fillable: ['name', 'age'],
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Fields
|
|
29
|
+
*/
|
|
30
|
+
attributes: {
|
|
31
|
+
name: {
|
|
32
|
+
type: String,
|
|
33
|
+
required: true
|
|
34
|
+
},
|
|
35
|
+
age: {
|
|
36
|
+
type: Number,
|
|
37
|
+
required: false,
|
|
38
|
+
validate: {
|
|
39
|
+
validator: (value) => {
|
|
40
|
+
const isValid = (value >= 21) ? true : false;
|
|
41
|
+
return isValid;
|
|
42
|
+
},
|
|
43
|
+
message: 'Invalid Age: Must be +21.',
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
// the fields:
|
|
47
|
+
// active, createdAt, updatedAt
|
|
48
|
+
// was created automatically
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* global app */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Alias Route Mappings
|
|
5
|
+
*
|
|
6
|
+
* Your routes map URLs to views and controllers.
|
|
7
|
+
*
|
|
8
|
+
* Notes: Vulkano automatically matches the URL to a controller
|
|
9
|
+
* and HTTP method (get, post, put, delete) ;)
|
|
10
|
+
*
|
|
11
|
+
* Example:
|
|
12
|
+
* - GET /users/ -> File: UsersController, Method: 'get': (req, res) => {}
|
|
13
|
+
* - GET /users/123 -> File: UsersController, Method: 'get :id': (req, res) => {}
|
|
14
|
+
* - POST /users/ -> File: UsersController, Method: 'post': (req, res) => {}
|
|
15
|
+
* - PUT /users/123 -> File: UsersController, Method: 'put :id': (req, res) => {}
|
|
16
|
+
* - DELETE /users/123 -> File: UsersController, Method: 'delete :id': (req, res) => {}
|
|
17
|
+
*
|
|
18
|
+
* With nested folders, the same rules apply:
|
|
19
|
+
* - GET /api/users/123 -> Folder: api -> File: UsersController, Method: 'get :id': (req, res) => {}
|
|
20
|
+
*
|
|
21
|
+
* But you can write your own routes manually :P
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
|
|
27
|
+
// Routes as string - Simple and easy to use
|
|
28
|
+
'/about-me': 'AboutController.get',
|
|
29
|
+
|
|
30
|
+
// Catch-all for React/Vue Router (SPA)
|
|
31
|
+
'/admin*': 'AdminController.get',
|
|
32
|
+
|
|
33
|
+
// Routes as definition - Most flexible
|
|
34
|
+
'/test': (req, res) => {
|
|
35
|
+
res.json({ message: 'Hello, world!' });
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// Routes as method - More Advanced
|
|
39
|
+
custom() {
|
|
40
|
+
|
|
41
|
+
app.vulkano.get('/test', (req, res) => {
|
|
42
|
+
res.json({ hello: 'world' });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
app.vulkano.get('/test2', (req, res) => {
|
|
46
|
+
res.json({ hello: 'world2' });
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
app.vulkano.get('/test3', (req, res) => {
|
|
50
|
+
res.json({ hello: 'world3' });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!DOCTYPE HTML>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<title>{{ title }}</title>
|
|
5
|
+
<meta charset=UTF-8 >
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
+
<link rel="shortcut icon" type="image/png" href="/favicon.png?v={{ app.pkg.version }}" />
|
|
9
|
+
|
|
10
|
+
{{ vite({ entry: 'app', type: 'style' }) | safe }}
|
|
11
|
+
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
|
|
15
|
+
<div id="app">{% block content %}{% endblock %}</div>
|
|
16
|
+
|
|
17
|
+
{{ vite({ entry: 'app', type: 'script' }) | safe }}
|
|
18
|
+
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
package/package.json
CHANGED
package/pnpm-workspace.yaml
CHANGED
|
@@ -4,10 +4,16 @@ allowBuilds:
|
|
|
4
4
|
catalog:
|
|
5
5
|
vite: npm:@voidzero-dev/vite-plus-core@latest
|
|
6
6
|
vitest: npm:@voidzero-dev/vite-plus-test@latest
|
|
7
|
-
vite-plus:
|
|
7
|
+
vite-plus: ^0.2.4
|
|
8
8
|
overrides:
|
|
9
9
|
vite: "catalog:"
|
|
10
10
|
vitest: "catalog:"
|
|
11
|
+
# Safety floor for the real "vite" package pnpm auto-installs to satisfy
|
|
12
|
+
# @voidzero-dev/vite-plus-test / @vitest/mocker's peerDependency (they
|
|
13
|
+
# require actual vite, not the vite-plus-core alias). Keeps it above the
|
|
14
|
+
# server.fs.deny bypass (GHSA-v6wh-96g9-6wx3), fixed in 8.0.16.
|
|
15
|
+
"@vitest/mocker>vite": ^8.1.4
|
|
16
|
+
"@voidzero-dev/vite-plus-test>vite": ^8.1.4
|
|
11
17
|
peerDependencyRules:
|
|
12
18
|
allowAny:
|
|
13
19
|
- vite
|