@vulkano/core 1.27.0 → 1.30.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/AGENTS.md +24 -9
- package/CHANGELOG.md +92 -0
- package/README.md +26 -0
- package/bootstrap/express.js +7 -1
- package/libs/ApiClient.js +6 -2
- package/libs/Crontab.js +1 -1
- package/libs/Upload.js +4 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
`@vulkano/core` (v1.
|
|
5
|
+
`@vulkano/core` (v1.30.0) is the engine of the Vulkano MVC framework. It bootstraps the environment, connects to the database, and auto-loads all models, controllers, services, and responses before starting the Express server. The user app only calls `require('@vulkano/core')`.
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
/**
|
|
@@ -39,7 +39,7 @@ core/
|
|
|
39
39
|
│ ├── models.js ← Loads user models, merges lifecycle callbacks and scaffold methods
|
|
40
40
|
│ └── scaffold.js ← Base CRUD methods: getAll, getByField, create, update, delete, subdocs
|
|
41
41
|
├── libs/
|
|
42
|
-
│ ├── ApiClient.js ←
|
|
42
|
+
│ ├── ApiClient.js ← fetch/undici wrapper for outbound HTTP requests (SSL-verified by default)
|
|
43
43
|
│ ├── Crontab.js ← node-cron wrapper for scheduled tasks
|
|
44
44
|
│ ├── Download.js ← File download helper
|
|
45
45
|
│ ├── Encrypter.js ← AES-256-CBC encrypt/decrypt
|
|
@@ -291,7 +291,7 @@ These are set automatically — never import them manually:
|
|
|
291
291
|
| `Jwt` | `services.js` | JWT encode/decode library |
|
|
292
292
|
| `Encrypter` | `services.js` | AES-256-CBC encrypt/decrypt |
|
|
293
293
|
| `ApiClient` | `services.js` | Outbound HTTP client |
|
|
294
|
-
| `Crontab` | `services.js` | Cron job scheduler |
|
|
294
|
+
| `Crontab` | `services.js` | Cron job scheduler (`timeZone` defaults to `UTC`) |
|
|
295
295
|
| `i18n` | `services.js` | i18next instance |
|
|
296
296
|
| `View` | `services.js` | `View.render(view, data)` → Promise<html>, renders outside the request/response cycle |
|
|
297
297
|
| `_` | `app.js` | Underscore.js |
|
|
@@ -589,7 +589,7 @@ All sources are deep-merged with `deepmerge`. Final result is in `app.config`.
|
|
|
589
589
|
|
|
590
590
|
**Key config files:**
|
|
591
591
|
- `settings.js` — port, database connection, paths
|
|
592
|
-
- `express/cors.js`, `express/jwt.js`, `express/csp.js`, `express/cookies.js`
|
|
592
|
+
- `express/cors.js`, `express/jwt.js`, `express/csp.js`, `express/cookies.js`, `express/multer.js` (default `limits.fileSize` 25MB)
|
|
593
593
|
- `routes.js` — explicit route mappings
|
|
594
594
|
- `bootstrap.js` — startup hook (**required**)
|
|
595
595
|
- `sockets/` — Socket.io config and adapters
|
|
@@ -616,11 +616,7 @@ Available globally as `io` and `app.socket`.
|
|
|
616
616
|
|
|
617
617
|
## Known issues / tech debt
|
|
618
618
|
|
|
619
|
-
- **`services.js`** — All libs/services are injected into `global`. Makes unit testing hard without mocking globals.
|
|
620
|
-
- **`bluebird`** — Still imported in a few places. Not needed in Node 18+ where `Promise` is native.
|
|
621
|
-
- **`ApiClient`** — `rejectUnauthorized: false` disables SSL verification by default for all outbound requests.
|
|
622
|
-
- **`Crontab`** — Default timezone is `America/New_York` instead of UTC.
|
|
623
|
-
- **`path` and `fs` npm packages** — These are Node.js built-ins and should not be in `package.json` dependencies.
|
|
619
|
+
- **`services.js`** — All libs/services are injected into `global`. Makes unit testing hard without mocking globals; core libs also depend on each other via the global instead of `require()`-ing one another directly (e.g. `ApiClient` assumes `global.VSError` exists rather than requiring `./VSError`).
|
|
624
620
|
|
|
625
621
|
---
|
|
626
622
|
|
|
@@ -648,3 +644,22 @@ Requires `core/.env.test` with `TEST_DB_URI`, `TEST_PORT`, and `JWT_SECRET_KEY`
|
|
|
648
644
|
- Starts a full Vulkano fixture server as a child process
|
|
649
645
|
- Drops and rebuilds the test database on every run
|
|
650
646
|
- Covers: VSR response format, routing (params + query strings), scaffold CRUD, pagination, model validation, ReDoS protection, file uploads, sockets (handshake auth + event routing)
|
|
647
|
+
|
|
648
|
+
### Unit tests (`test/unit/`) — testing a core lib in isolation
|
|
649
|
+
|
|
650
|
+
Core libs (`core/libs/*.js`) read globals (`app`, `VSError`, `CORE_PATH`, `APP_PATH`, …) that are
|
|
651
|
+
normally set by `bootstrap/services.js` at framework boot — a unit test skips that boot to test one
|
|
652
|
+
lib alone, so those globals don't exist yet. Use the shared helper instead of hand-rolling a fake
|
|
653
|
+
per file:
|
|
654
|
+
|
|
655
|
+
```js
|
|
656
|
+
const { setupGlobals, setupEncrypter, setupFilter } = require('../helpers/globals');
|
|
657
|
+
|
|
658
|
+
setupGlobals(); // app, VSError (the real one), CORE_PATH, APP_PATH
|
|
659
|
+
setupGlobals({ app: { config: { jwt: {...} } } }); // override app (shallow) for lib-specific config
|
|
660
|
+
setupEncrypter(); // only if the lib under test needs global.Encrypter
|
|
661
|
+
setupFilter(); // only if the lib under test needs global.Filter
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
`setupGlobals()` always installs the real `libs/VSError.js`, not a per-file stand-in — keeps unit
|
|
665
|
+
tests honest about its actual behavior instead of drifting from a hand-copied fake.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@vulkano/core` are documented here.
|
|
4
|
+
|
|
5
|
+
## [1.30.0]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `bootstrap/express.js` — default multer `limits.fileSize` of **25MB**. Previously unbounded:
|
|
9
|
+
an upload could buffer to disk in full before `Upload.js`'s own `maxSize` check ever ran,
|
|
10
|
+
a real DoS surface (disk/memory/bandwidth) for any controller receiving uploads without an
|
|
11
|
+
explicit limit. Override via `app/config/express/multer.js` (`limits.fileSize`) — deep-merges,
|
|
12
|
+
doesn't drop the existing `fieldNestingDepth: 5` default.
|
|
13
|
+
|
|
14
|
+
### Tests
|
|
15
|
+
- `test/unit/bootstrap/express.test.js` — default `fileSize`, override, and that
|
|
16
|
+
`fieldNestingDepth` survives a partial `limits` override (deep merge).
|
|
17
|
+
|
|
18
|
+
### Docs
|
|
19
|
+
- `README.md` / `AGENTS.md`: documented the default and the override path.
|
|
20
|
+
|
|
21
|
+
## [1.29.0]
|
|
22
|
+
|
|
23
|
+
### Changed — BREAKING (default behavior)
|
|
24
|
+
- `Crontab.schedule()` default `timeZone` is now `UTC`, was `America/New_York`. Any job that
|
|
25
|
+
relied on the implicit New York default without passing `timeZone` explicitly now runs on a
|
|
26
|
+
different schedule relative to wall-clock time in that zone — pass `timeZone: 'America/New_York'`
|
|
27
|
+
explicitly to keep the old behavior. A job with an explicit `timeZone` is unaffected.
|
|
28
|
+
|
|
29
|
+
### Tests
|
|
30
|
+
- `test/unit/libs/Crontab.test.js` — default/override timezone, `start: true/false`, manual tick.
|
|
31
|
+
|
|
32
|
+
### Docs
|
|
33
|
+
- `AGENTS.md` / `README.md`: documented the `UTC` default; removed the now-resolved
|
|
34
|
+
`Crontab` timezone known-issue entry.
|
|
35
|
+
|
|
36
|
+
## [1.28.1]
|
|
37
|
+
|
|
38
|
+
### Changed (internal, no runtime/public API impact)
|
|
39
|
+
- `test/unit/` — added `test/unit/helpers/globals.js`, a shared `setupGlobals()` /
|
|
40
|
+
`setupEncrypter()` / `setupFilter()` bootstrap for unit-testing a core lib in isolation.
|
|
41
|
+
Replaces 4 duplicated, hand-rolled `VSError` stand-in classes across
|
|
42
|
+
`ApiClient.test.js` / `Encrypter.test.js` / `Jwt.test.js` with the real `libs/VSError.js`,
|
|
43
|
+
and a fragile `delete global.app` pattern in `Encrypter.test.js` with restoring the
|
|
44
|
+
baseline via `setupGlobals()`.
|
|
45
|
+
- Removed two stale `Known issues / tech debt` entries from `AGENTS.md` (`bluebird` and
|
|
46
|
+
`path`/`fs` as dependencies) — neither is present in the codebase or `package.json` anymore.
|
|
47
|
+
|
|
48
|
+
## [1.28.0]
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
- `ApiClient` — SSL verification stays enabled (secure) by default, but the default itself can
|
|
52
|
+
now be flipped app-wide via `.env` with `API_CLIENT_REJECT_UNAUTHORIZED=false` (e.g. same-server
|
|
53
|
+
calls to other internal services on self-signed certs). A per-call `rejectUnauthorized` still
|
|
54
|
+
always wins over the env default, in either direction.
|
|
55
|
+
|
|
56
|
+
### Tests
|
|
57
|
+
- Env-driven default, per-call override in both directions, and non-`"false"` values keeping
|
|
58
|
+
verification on.
|
|
59
|
+
|
|
60
|
+
### Docs
|
|
61
|
+
- `AGENTS.md` / `README.md`: documented `API_CLIENT_REJECT_UNAUTHORIZED`; removed the stale
|
|
62
|
+
"SSL disabled by default" known-issue entry and the outdated "Axios wrapper" description.
|
|
63
|
+
|
|
64
|
+
## [1.27.0]
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
- Global `View` lib — `View.render(view, data)` returns a Promise<html>, rendering a view
|
|
68
|
+
outside the normal request/response cycle (email bodies, PDF generation, etc.), without
|
|
69
|
+
the `req.app.render` boilerplate.
|
|
70
|
+
|
|
71
|
+
### Tests
|
|
72
|
+
- Nunjucks and Handlebars coverage for `View.render()`, verifying markup matches `res.render()`
|
|
73
|
+
on the same template.
|
|
74
|
+
|
|
75
|
+
### Docs
|
|
76
|
+
- `AGENTS.md` / `README.md`: documented the `View` global.
|
|
77
|
+
|
|
78
|
+
## [1.26.0]
|
|
79
|
+
|
|
80
|
+
### Added
|
|
81
|
+
- Controllers support **arbitrary nesting depth** under `app/controllers/` (e.g.
|
|
82
|
+
`api/config/VatTypesController.js` → `/api/config/vat-types/...`), not just one subfolder
|
|
83
|
+
level — ideal for grouping controllers by module/domain. The route loader
|
|
84
|
+
(`controllers/controllers.js`) now walks the folder tree recursively instead of handling
|
|
85
|
+
a single hardcoded nesting level.
|
|
86
|
+
|
|
87
|
+
### Tests
|
|
88
|
+
- `test/integration/nested-modules.test.js` — same controller name (`VatTypesController`) at
|
|
89
|
+
root, one, and two levels of nesting, all 5 CRUD methods, verifying full route isolation.
|
|
90
|
+
|
|
91
|
+
### Docs
|
|
92
|
+
- `AGENTS.md` / `README.md`: documented multi-level controller nesting.
|
package/README.md
CHANGED
|
@@ -354,6 +354,18 @@ All files in `app/services/` are auto-loaded as globals. The framework also expo
|
|
|
354
354
|
| `Upload` | Validate, save and return the local path of an uploaded file |
|
|
355
355
|
| `i18n` | Internationalization via i18next |
|
|
356
356
|
| `mongoose` | Mongoose instance |
|
|
357
|
+
| `View` | `View.render(view, data)` → Promise<html>, renders outside the request/response cycle |
|
|
358
|
+
|
|
359
|
+
`ApiClient` verifies SSL by default. A single call can opt out with `rejectUnauthorized: false`
|
|
360
|
+
(and force it back on with `rejectUnauthorized: true`), and the default itself can be flipped for
|
|
361
|
+
the whole app via `.env`:
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
# .env — disables SSL verification by default for every ApiClient call
|
|
365
|
+
# (e.g. calling other services on the same server over self-signed certs).
|
|
366
|
+
# A per-call rejectUnauthorized always overrides this, in either direction.
|
|
367
|
+
API_CLIENT_REJECT_UNAUTHORIZED=false
|
|
368
|
+
```
|
|
357
369
|
|
|
358
370
|
---
|
|
359
371
|
|
|
@@ -361,6 +373,17 @@ All files in `app/services/` are auto-loaded as globals. The framework also expo
|
|
|
361
373
|
|
|
362
374
|
Vulkano uses [Multer](https://github.com/expressjs/multer) v2. Files are available on `req.files` after a `multipart/form-data` POST — Multer writes them straight into `PUBLIC_PATH/files` under a temporary name.
|
|
363
375
|
|
|
376
|
+
Multer rejects any single file over **25MB** by default (`limits.fileSize`) — before it's fully
|
|
377
|
+
buffered to disk, unlike `Upload.file()`'s own `maxSize` check which only runs after. Override it
|
|
378
|
+
in `app/config/express/multer.js`:
|
|
379
|
+
|
|
380
|
+
```js
|
|
381
|
+
// app/config/express/multer.js
|
|
382
|
+
module.exports = {
|
|
383
|
+
limits: { fileSize: 100 * 1024 * 1024 } // 100MB
|
|
384
|
+
};
|
|
385
|
+
```
|
|
386
|
+
|
|
364
387
|
### The `Upload` lib
|
|
365
388
|
|
|
366
389
|
`Upload.file(files, opts)` validates a single uploaded file (mimetype, extension, size, write
|
|
@@ -512,6 +535,9 @@ const { _id } = Jwt.decode(Jwt.getToken(req)) || {};
|
|
|
512
535
|
|
|
513
536
|
When Vulkano starts, you can configure your own tasks to run at a given time.
|
|
514
537
|
|
|
538
|
+
`timeZone` defaults to `UTC` when omitted — pass it explicitly (e.g. `'America/New_York'`) for a
|
|
539
|
+
task that should run relative to a specific local time instead.
|
|
540
|
+
|
|
515
541
|
```js
|
|
516
542
|
// app/config/bootstrap.js
|
|
517
543
|
module.exports = (start) => {
|
package/bootstrap/express.js
CHANGED
|
@@ -55,7 +55,13 @@ module.exports = function getExpressConfiguration() {
|
|
|
55
55
|
limits: {
|
|
56
56
|
// Prevents DoS via deeply nested field names (e.g. a[b][c][d]...),
|
|
57
57
|
// which multer forwards to append-field's unbounded recursive parser.
|
|
58
|
-
fieldNestingDepth: 5
|
|
58
|
+
fieldNestingDepth: 5,
|
|
59
|
+
// Rejects an oversized upload mid-stream instead of buffering the
|
|
60
|
+
// whole file to disk first — Upload.js's own maxSize check only runs
|
|
61
|
+
// after multer has already written the file. Override via
|
|
62
|
+
// app/config/express/multer.js (limits.fileSize) if a project needs
|
|
63
|
+
// a different ceiling.
|
|
64
|
+
fileSize: 25 * 1024 * 1024
|
|
59
65
|
}
|
|
60
66
|
},
|
|
61
67
|
morgan: {
|
package/libs/ApiClient.js
CHANGED
|
@@ -67,8 +67,12 @@ module.exports = {
|
|
|
67
67
|
? { url: props, method: 'GET' }
|
|
68
68
|
: (props || {});
|
|
69
69
|
|
|
70
|
-
// SSL verification is enabled by default
|
|
71
|
-
|
|
70
|
+
// SSL verification is enabled by default (secure). It can be turned off globally via
|
|
71
|
+
// API_CLIENT_REJECT_UNAUTHORIZED=false in .env (e.g. internal calls to other services on
|
|
72
|
+
// the same server using self-signed certs) — a per-call `rejectUnauthorized` always wins
|
|
73
|
+
// over the env default, in either direction.
|
|
74
|
+
const envDefault = process.env.API_CLIENT_REJECT_UNAUTHORIZED !== 'false';
|
|
75
|
+
const sslVerify = rejectUnauthorized !== undefined ? rejectUnauthorized !== false : envDefault;
|
|
72
76
|
|
|
73
77
|
const optHeaders = {
|
|
74
78
|
'Content-Type': 'application/json',
|
package/libs/Crontab.js
CHANGED
package/libs/Upload.js
CHANGED
|
@@ -70,6 +70,10 @@ const MIME_EXTENSION_MAP = {
|
|
|
70
70
|
'video/x-mpg': 'mpg'
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
// This only rejects a file after multer has already buffered it to disk —
|
|
74
|
+
// it never runs on an upload multer already rejected via its own
|
|
75
|
+
// limits.fileSize (bootstrap/express.js, default 25MB). Set maxSize below
|
|
76
|
+
// that ceiling for it to ever actually apply.
|
|
73
77
|
const DEFAULT_MAX_SIZE = 10 * 1024 * 1024;
|
|
74
78
|
|
|
75
79
|
module.exports = {
|