jxp 3.0.0 → 4.1.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/.env.sample +43 -6
- package/README.md +27 -13
- package/dist/bin/init_db.d.ts +3 -0
- package/dist/bin/init_db.d.ts.map +1 -0
- package/dist/bin/init_db.js +48 -0
- package/dist/bin/init_db.js.map +1 -0
- package/dist/bin/server.d.ts +4 -0
- package/dist/bin/server.d.ts.map +1 -0
- package/dist/bin/server.js +132 -0
- package/dist/bin/server.js.map +1 -0
- package/dist/bin/setup.d.ts +3 -0
- package/dist/bin/setup.d.ts.map +1 -0
- package/dist/bin/setup.js +185 -0
- package/dist/bin/setup.js.map +1 -0
- package/dist/globals.d.ts +14 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +3 -0
- package/dist/globals.js.map +1 -0
- package/dist/libs/aggregate_guard.d.ts +5 -0
- package/dist/libs/aggregate_guard.d.ts.map +1 -0
- package/dist/libs/aggregate_guard.js +58 -0
- package/dist/libs/aggregate_guard.js.map +1 -0
- package/dist/libs/bulkwrite_guard.d.ts +5 -0
- package/dist/libs/bulkwrite_guard.d.ts.map +1 -0
- package/dist/libs/bulkwrite_guard.js +44 -0
- package/dist/libs/bulkwrite_guard.js.map +1 -0
- package/dist/libs/cache.d.ts +2 -0
- package/dist/libs/cache.d.ts.map +1 -0
- package/dist/libs/cache.js +94 -0
- package/dist/libs/cache.js.map +1 -0
- package/dist/libs/call_guard.d.ts +3 -0
- package/dist/libs/call_guard.d.ts.map +1 -0
- package/dist/libs/call_guard.js +17 -0
- package/dist/libs/call_guard.js.map +1 -0
- package/dist/libs/connection_string.d.ts +3 -0
- package/dist/libs/connection_string.d.ts.map +1 -0
- package/dist/libs/connection_string.js +4 -0
- package/dist/libs/connection_string.js.map +1 -0
- package/dist/libs/datamunging.d.ts +2 -0
- package/dist/libs/datamunging.d.ts.map +1 -0
- package/dist/libs/datamunging.js +320 -0
- package/dist/libs/datamunging.js.map +1 -0
- package/dist/libs/docs-auth.d.ts +25 -0
- package/dist/libs/docs-auth.d.ts.map +1 -0
- package/dist/libs/docs-auth.js +205 -0
- package/dist/libs/docs-auth.js.map +1 -0
- package/dist/libs/docs.d.ts +2 -0
- package/dist/libs/docs.d.ts.map +1 -0
- package/dist/libs/docs.js +328 -0
- package/dist/libs/docs.js.map +1 -0
- package/dist/libs/groups.d.ts +2 -0
- package/dist/libs/groups.d.ts.map +1 -0
- package/dist/libs/groups.js +136 -0
- package/dist/libs/groups.js.map +1 -0
- package/dist/libs/jxp.d.ts +4 -0
- package/dist/libs/jxp.d.ts.map +1 -0
- package/dist/libs/jxp.js +1176 -0
- package/dist/libs/jxp.js.map +1 -0
- package/dist/libs/link_index.d.ts +14 -0
- package/dist/libs/link_index.d.ts.map +1 -0
- package/dist/libs/link_index.js +37 -0
- package/dist/libs/link_index.js.map +1 -0
- package/dist/libs/load-config.d.ts +16 -0
- package/dist/libs/load-config.d.ts.map +1 -0
- package/dist/libs/load-config.js +166 -0
- package/dist/libs/load-config.js.map +1 -0
- package/dist/libs/login.d.ts +2 -0
- package/dist/libs/login.d.ts.map +1 -0
- package/dist/libs/login.js +244 -0
- package/dist/libs/login.js.map +1 -0
- package/dist/libs/login_rate_limit.d.ts +16 -0
- package/dist/libs/login_rate_limit.d.ts.map +1 -0
- package/dist/libs/login_rate_limit.js +49 -0
- package/dist/libs/login_rate_limit.js.map +1 -0
- package/dist/libs/modeldir.d.ts +5 -0
- package/dist/libs/modeldir.d.ts.map +1 -0
- package/dist/libs/modeldir.js +15 -0
- package/dist/libs/modeldir.js.map +1 -0
- package/dist/libs/query_limits.d.ts +2 -0
- package/dist/libs/query_limits.d.ts.map +1 -0
- package/dist/libs/query_limits.js +84 -0
- package/dist/libs/query_limits.js.map +1 -0
- package/dist/libs/query_manipulation.d.ts +3 -0
- package/dist/libs/query_manipulation.d.ts.map +1 -0
- package/{libs → dist/libs}/query_manipulation.js +22 -21
- package/dist/libs/query_manipulation.js.map +1 -0
- package/dist/libs/query_sanitize.d.ts +5 -0
- package/dist/libs/query_sanitize.d.ts.map +1 -0
- package/dist/libs/query_sanitize.js +109 -0
- package/dist/libs/query_sanitize.js.map +1 -0
- package/dist/libs/response_sanitize.d.ts +7 -0
- package/dist/libs/response_sanitize.d.ts.map +1 -0
- package/dist/libs/response_sanitize.js +57 -0
- package/dist/libs/response_sanitize.js.map +1 -0
- package/dist/libs/safe_error.d.ts +3 -0
- package/dist/libs/safe_error.d.ts.map +1 -0
- package/dist/libs/safe_error.js +14 -0
- package/dist/libs/safe_error.js.map +1 -0
- package/dist/libs/schema.d.ts +14 -0
- package/dist/libs/schema.d.ts.map +1 -0
- package/dist/libs/schema.js +98 -0
- package/dist/libs/schema.js.map +1 -0
- package/dist/libs/schema_description.d.ts +3 -0
- package/dist/libs/schema_description.d.ts.map +1 -0
- package/{libs → dist/libs}/schema_description.js +12 -21
- package/dist/libs/schema_description.js.map +1 -0
- package/dist/libs/security.d.ts +2 -0
- package/dist/libs/security.d.ts.map +1 -0
- package/dist/libs/security.js +428 -0
- package/dist/libs/security.js.map +1 -0
- package/dist/libs/setup.d.ts +2 -0
- package/dist/libs/setup.d.ts.map +1 -0
- package/dist/libs/setup.js +87 -0
- package/dist/libs/setup.js.map +1 -0
- package/dist/libs/startup-deprecations.d.ts +2 -0
- package/dist/libs/startup-deprecations.d.ts.map +1 -0
- package/dist/libs/startup-deprecations.js +21 -0
- package/dist/libs/startup-deprecations.js.map +1 -0
- package/dist/libs/startup.d.ts +16 -0
- package/dist/libs/startup.d.ts.map +1 -0
- package/dist/libs/startup.js +63 -0
- package/dist/libs/startup.js.map +1 -0
- package/dist/libs/ws.d.ts +2 -0
- package/dist/libs/ws.d.ts.map +1 -0
- package/{libs → dist/libs}/ws.js +91 -73
- package/dist/libs/ws.js.map +1 -0
- package/dist/models/apikey_model.d.ts +10 -0
- package/dist/models/apikey_model.d.ts.map +1 -0
- package/dist/models/apikey_model.js +14 -0
- package/dist/models/apikey_model.js.map +1 -0
- package/dist/models/link_model.d.ts +9 -0
- package/dist/models/link_model.d.ts.map +1 -0
- package/dist/models/link_model.js +20 -0
- package/dist/models/link_model.js.map +1 -0
- package/dist/models/refreshtoken_model.d.ts +11 -0
- package/dist/models/refreshtoken_model.d.ts.map +1 -0
- package/dist/models/refreshtoken_model.js +22 -0
- package/dist/models/refreshtoken_model.js.map +1 -0
- package/dist/models/test_model.d.ts +24 -0
- package/dist/models/test_model.d.ts.map +1 -0
- package/dist/models/test_model.js +44 -0
- package/dist/models/test_model.js.map +1 -0
- package/dist/models/token_model.d.ts +14 -0
- package/dist/models/token_model.d.ts.map +1 -0
- package/dist/models/token_model.js +25 -0
- package/dist/models/token_model.js.map +1 -0
- package/dist/models/user_model.d.ts +15 -0
- package/dist/models/user_model.d.ts.map +1 -0
- package/dist/models/user_model.js +38 -0
- package/dist/models/user_model.js.map +1 -0
- package/dist/models/usergroups_model.d.ts +9 -0
- package/dist/models/usergroups_model.d.ts.map +1 -0
- package/dist/models/usergroups_model.js +18 -0
- package/dist/models/usergroups_model.js.map +1 -0
- package/dist/types/jxp-config.d.ts +151 -0
- package/dist/types/jxp-config.d.ts.map +1 -0
- package/dist/types/jxp-config.js +3 -0
- package/dist/types/jxp-config.js.map +1 -0
- package/dist/types/schema-fields.d.ts +43 -0
- package/dist/types/schema-fields.d.ts.map +1 -0
- package/dist/types/schema-fields.js +3 -0
- package/dist/types/schema-fields.js.map +1 -0
- package/docs/aggregations.md +40 -21
- package/docs/api.md +55 -15
- package/docs/authentication.md +60 -37
- package/docs/bulk_writes.md +11 -8
- package/docs/caching.md +28 -11
- package/docs/changelog.md +258 -31
- package/docs/configuration.md +126 -115
- package/docs/hooks.md +12 -8
- package/docs/index.md +17 -17
- package/docs/installation.md +23 -18
- package/docs/permissions.md +33 -19
- package/docs/queries.md +9 -5
- package/docs/schemas.md +21 -10
- package/docs/special.md +4 -4
- package/docs/typescript.md +86 -0
- package/docs/websocket.md +99 -1
- package/mkdocs.yml +1 -0
- package/package.json +121 -69
- package/templates/api.pug +32 -0
- package/templates/app-server.js +43 -0
- package/templates/app.env.sample +8 -0
- package/templates/assets/api-console.js +151 -0
- package/templates/assets/docs-login.js +66 -0
- package/templates/assets/docs.css +244 -0
- package/templates/index.pug +67 -2
- package/templates/layout.pug +21 -11
- package/templates/login.pug +39 -0
- package/templates/md.pug +1 -1
- package/templates/model.pug +117 -68
- package/templates/navbar.pug +25 -21
- package/templates/sidebar.pug +30 -0
- package/.env +0 -9
- package/.eslintrc.json +0 -20
- package/.jshintrc +0 -4
- package/.vscode/launch.json +0 -34
- package/.vscode/settings.json +0 -3
- package/Dockerfile +0 -7
- package/bin/init_db.js +0 -54
- package/bin/server.js +0 -131
- package/bin/setup.js +0 -190
- package/config_sample.json +0 -10
- package/docker-compose.yml +0 -32
- package/libs/cache.js +0 -92
- package/libs/connection_string.js +0 -24
- package/libs/datamunging.js +0 -335
- package/libs/docs.js +0 -162
- package/libs/groups.js +0 -133
- package/libs/jxp.js +0 -1208
- package/libs/login.js +0 -222
- package/libs/modeldir.js +0 -14
- package/libs/schema.js +0 -99
- package/libs/security.js +0 -410
- package/libs/setup.js +0 -90
- package/models/apikey_model.js +0 -10
- package/models/link_model.js +0 -17
- package/models/refreshtoken_model.js +0 -20
- package/models/test_model.js +0 -50
- package/models/token_model.js +0 -23
- package/models/user_model.js +0 -38
- package/models/usergroups_model.js +0 -15
- package/setup.sh +0 -3
- package/test/.eslintrc.json +0 -13
- package/test/auth.js +0 -190
- package/test/init.js +0 -92
- package/test/setup.test.js +0 -62
- package/test/test.js +0 -1527
- package/test/wstest.js.old +0 -124
package/docs/changelog.md
CHANGED
|
@@ -1,56 +1,283 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Notable changes to [JXP](https://github.com/WorkSpaceMan/jxp).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## v4.1.0 — 2026-05-25
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
API docs browser security: gated model explorer, real API login, and brute-force limits.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
### Added
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- **Docs access control** (`DOCS_ACCESS`) — `protected` (default), `disabled`, or `public`. Home (`/`) and usage guides (`/docs/md/*`) stay open; model explorer (`/docs/api`, `/docs/model/*`) requires sign-in.
|
|
12
|
+
- **Docs sign-in flow** — `/docs/login` calls `POST /login`, then `POST /docs/session` to store an HttpOnly cookie; API key auto-fills for “Try it” panels (`GET /docs/session`).
|
|
13
|
+
- **Login rate limiting** — per-IP token bucket on `POST /login` and `POST /docs/session` (default: burst 8, 12/min). Env: `LOGIN_RATE_LIMIT_*`; HTTP **429** when exceeded.
|
|
14
|
+
- **`src/libs/docs-auth.ts`**, **`src/libs/login_rate_limit.ts`** — middleware, session cookie, and throttle helpers.
|
|
15
|
+
- **Tests** — `test/docs_auth.test.js`, `test/login_rate_limit.test.js`.
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
### Changed
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
- **Docs browser default** — model explorer is no longer world-readable; guides and landing page remain public in `protected` mode.
|
|
20
|
+
- **Configuration** — [configuration.md](configuration.md) documents `DOCS_*` and `LOGIN_RATE_LIMIT_*` variables.
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
### Fixed
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
- **Restify async routes** — docs login/session handlers use `(req, res)` only; redirects use `sendRedirect()` where `res.redirect()` requires `next`.
|
|
20
25
|
|
|
21
|
-
-
|
|
26
|
+
## v4.0.0 — 2026-05-19
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
Major release: complete TypeScript rewrite and configuration overhaul.
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
### Breaking changes
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
- **Security hardening (4.0)** — see [migration](#security-hardening-migration) below.
|
|
33
|
+
- **No `config` package** — configuration via `.env` / environment variables and `jxp/libs/load-config` (compiled to `dist/libs/load-config.js`). Removed `/config/*.json` and [node-config](https://www.npmjs.com/package/config).
|
|
34
|
+
- **TypeScript** — framework source under `src/`; npm package ships compiled `dist/` with `.d.ts` types.
|
|
35
|
+
- **Build from source** — `npm run build` when developing from a git clone; npm registry installs ship prebuilt `dist/`.
|
|
36
|
+
- **Entry point** — `main` / `types` → `dist/libs/jxp.js` and `dist/libs/jxp.d.ts`.
|
|
37
|
+
- **Node 22+** — `engines.node` is `>=22.0.0`.
|
|
38
|
+
- **Relative paths** — `model_dir` and `log` resolve from `process.cwd()`, not the server script directory.
|
|
39
|
+
- **Built-in models** — compile from `src/models/*.ts` to `dist/models/`; consumer apps still use `*_model.js` in `MODEL_DIR`.
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
- Move to "connection_string" for MongoDB connection - allows connectivity to Atlas, for example
|
|
31
|
-
- Use our own (much smarter) Schema class
|
|
41
|
+
### Added
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
- **`loadJxpConfig()`** — builds `JXP()` options from environment variables (`.env`, `.env.test`).
|
|
44
|
+
- **`package.json` `exports` map** — `jxp`, `jxp/libs/query_manipulation`, `jxp/libs/load-config`, `jxp/globals`.
|
|
45
|
+
- **Globals types** — `/// <reference types="jxp/globals" />` for JavaScript model authoring.
|
|
46
|
+
- **[docs/typescript.md](typescript.md)** — v4 migration guide.
|
|
47
|
+
- **Built-in documentation UI** — landing page, MkDocs nav sidebar, per-model API reference.
|
|
48
|
+
- **Interactive API console** — try REST endpoints from model pages; optional API key in docs navbar.
|
|
49
|
+
- **Query limits** (from v3.1) — env/config `query_limits`; default limit on all list/query requests; required explicit `?limit=` on large collections.
|
|
50
|
+
- **Security modules** — `query_sanitize`, `aggregate_guard`, `bulkwrite_guard`, `call_guard`, `response_sanitize`, `link_index`, `safe_error`.
|
|
51
|
+
- **Schema options** — `callable_statics` (string array); `advanced_queries: { query?, aggregate?, bulkwrite? }` (bulkwrite off by default).
|
|
52
|
+
- **Config / env** — `security.strip_fields`, `cors.origins`; `QUERY_LIMITS_DEFAULT`, `QUERY_LIMITS_SKIP_COUNT_UNLESS_PAGINATED`, `CORS_ORIGINS` (see [configuration.md](configuration.md)).
|
|
53
|
+
- **Startup helpers** — Node 22+ deprecation warnings; `quiet_startup` option.
|
|
34
54
|
|
|
35
|
-
|
|
55
|
+
### Changed
|
|
36
56
|
|
|
37
|
-
|
|
57
|
+
- **List responses** — `count` and `page_count` are omitted unless the client passes `?count=true` or `?page=` (avoids `countDocuments` on every list request).
|
|
58
|
+
- **CORS** — origins read from `config.cors.origins` (default `["*"]` if unset).
|
|
59
|
+
- **`/update/:model/:id`** — uses document load + `save()` (validators/hooks) instead of deprecated `Model.update()`.
|
|
60
|
+
- **Delete** — referrer checks use a pre-built link index and run in parallel.
|
|
61
|
+
- **`admin_only` middleware** — passes errors via `next(err)` for correct Restify handling.
|
|
62
|
+
- **Mongoose 6.13.9** (pinned).
|
|
63
|
+
- **Cache** — in-process [node-cache](https://www.npmjs.com/package/node-cache) *(replaces apicache from v2.6)*.
|
|
64
|
+
- **CSV** — `@json2csv/plainjs` replaces `json2csv`.
|
|
65
|
+
- **Email** — `nodemailer` 8.x; removed `nodemailer-smtp-transport`.
|
|
66
|
+
- **Docs rendering** — `markdown-it`; MkDocs pages from `docs/*.md`.
|
|
67
|
+
- **Tests** — Mocha 11; `test/env.js` loads `.env.test`; `test/security_hardening.test.js` for guards and allowlists.
|
|
68
|
+
- **Documentation** — full MkDocs audit for v4 behavior; security notes in [api.md](api.md), [queries.md](queries.md), [aggregations.md](aggregations.md), [bulk_writes.md](bulk_writes.md), [caching.md](caching.md), [schemas.md](schemas.md), [special.md](special.md).
|
|
38
69
|
|
|
39
|
-
|
|
40
|
-
- Bulk uploads
|
|
41
|
-
- Advanced queries
|
|
70
|
+
### Fixed
|
|
42
71
|
|
|
43
|
-
|
|
72
|
+
- **`actionCallItem`** — `findById` is awaited; deleted documents are rejected; request body is passed to the static.
|
|
73
|
+
- **`apiKeyAuth`** — missing `await` on `User.findOne` when resolving API key users.
|
|
74
|
+
- **`middlewareModel`** — returns 404 when model name is unknown (no silent `undefined` model).
|
|
75
|
+
- **Filter depth** — exceeding max depth returns 400 instead of passing raw input through.
|
|
44
76
|
|
|
45
|
-
|
|
77
|
+
### Security hardening migration
|
|
46
78
|
|
|
47
|
-
|
|
79
|
+
Consumer apps (e.g. RevEngine) should adjust clients and models as follows:
|
|
48
80
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
| Area | Before | After |
|
|
82
|
+
|------|--------|--------|
|
|
83
|
+
| List GET / POST `/query` | Unbounded or large default on small collections | Default `?limit=100` when omitted; collections ≥10k docs still require explicit `?limit=` |
|
|
84
|
+
| Totals in list JSON | `count` always present | Pass `?count=true` or `?page=` when you need `count` / `page_count` |
|
|
85
|
+
| `/call/:model/:method` | Any schema static callable | Only names listed in `callable_statics` |
|
|
86
|
+
| `/cache/stats`, `/cache/clear` | No auth | Admin login required |
|
|
87
|
+
| `password_override=1` | Any authenticated user | Admin only |
|
|
88
|
+
| User PUT | Could set `admin` / `password` | Non-admins have privilege fields stripped |
|
|
89
|
+
| `?filter[$where]=…` | Accepted | **400** — operator denied |
|
|
90
|
+
| POST `/aggregate` | Any pipeline stage | Allowlisted stages; `$out` / `$merge` / `$function` need admin |
|
|
91
|
+
| POST `/bulkwrite` | Open | **Disabled per model** unless `advanced_queries.bulkwrite: true`; op allowlist |
|
|
92
|
+
| List passwords | Could leak on `GET /api/user` | Stripped from list/query/aggregate responses |
|
|
52
93
|
|
|
53
|
-
|
|
94
|
+
Example model opts:
|
|
54
95
|
|
|
55
|
-
|
|
56
|
-
|
|
96
|
+
```js
|
|
97
|
+
new JXPSchema({ ... }, {
|
|
98
|
+
perms: { admin: "crud", user: "r" },
|
|
99
|
+
callable_statics: ["preview_segment", "apply_segment"],
|
|
100
|
+
advanced_queries: { bulkwrite: true }, // only if HTTP bulkwrite is required
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## v3.1.0 — 2026-05-19
|
|
107
|
+
|
|
108
|
+
- **Query limits for large collections** — `query_limits` config; `GET /api/<model>`, `GET /csv/<model>`, and `POST /query/<model>` require `?limit=` when collection size exceeds threshold (default 10,000 documents).
|
|
109
|
+
- New `query_limits.js` module, tests, and API documentation.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## v3.0.0 — 2025-04-17
|
|
114
|
+
|
|
115
|
+
Repository refresh and dependency modernization:
|
|
116
|
+
|
|
117
|
+
- Better MongoDB connection handling.
|
|
118
|
+
- Proper HTTP errors on login failure.
|
|
119
|
+
- Additional request logging.
|
|
120
|
+
- Package upgrades; Docker and ESLint scaffolding.
|
|
121
|
+
|
|
122
|
+
### Patch-level (same era)
|
|
123
|
+
|
|
124
|
+
- **2025-04-17** — Correct documentation for `x-api-key` header.
|
|
125
|
+
- **2025-04-05** — Fix `deepExtend` bug.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## v2.15.0 — 2025-03-25
|
|
130
|
+
|
|
131
|
+
- Fix potential stack size exceeded errors.
|
|
132
|
+
- Fix documentation circular reference errors.
|
|
133
|
+
- Dependency updates.
|
|
134
|
+
- Date range handling improvements.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## v2.14.6 — 2024-01-24
|
|
139
|
+
|
|
140
|
+
- Package upgrades.
|
|
141
|
+
- Log Mongoose version on startup.
|
|
142
|
+
|
|
143
|
+
## v2.14.5 — 2023-12-21
|
|
144
|
+
|
|
145
|
+
- Maintenance release.
|
|
146
|
+
|
|
147
|
+
## v2.14.4 — 2023-12-21
|
|
148
|
+
|
|
149
|
+
- Dependency bumps.
|
|
150
|
+
|
|
151
|
+
## v2.14.3 — 2023-12-21
|
|
152
|
+
|
|
153
|
+
- `jxp-helper` version update.
|
|
154
|
+
|
|
155
|
+
## v2.14.0 — 2023-02-27
|
|
156
|
+
|
|
157
|
+
- **`.env` support** — environment-based configuration instructions and loading.
|
|
158
|
+
- Link to external docs instead of inline documentation.
|
|
159
|
+
- Repository moved to [WorkSpaceMan/jxp](https://github.com/WorkSpaceMan/jxp) (2023-07-10).
|
|
160
|
+
- Dependency upgrades.
|
|
161
|
+
|
|
162
|
+
### Caching (v2.14 era, 2023-01)
|
|
163
|
+
|
|
164
|
+
- In-memory response caching with smarter invalidation.
|
|
165
|
+
- Invalidate whole cache when links complicate partial invalidation.
|
|
166
|
+
- Don't crash when cache object isn't configured.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## v2.12.3 — 2023-01-18
|
|
171
|
+
|
|
172
|
+
- Dependency upgrades.
|
|
173
|
+
- Require Mongoose as peer dependency.
|
|
174
|
+
|
|
175
|
+
## v2.12.0 — 2022-12-05
|
|
176
|
+
|
|
177
|
+
- Better error handling; server stays up on non-fatal errors.
|
|
178
|
+
- Tests passing again.
|
|
179
|
+
- Mongoose and Restify upgrades.
|
|
180
|
+
- Default to `127.0.0.1` instead of `localhost`.
|
|
181
|
+
- Show JXP version on load; reduce noisy logging.
|
|
182
|
+
- `--legacy-peer-deps` note for source installs.
|
|
183
|
+
|
|
184
|
+
## v2.11.0 — 2022-11-28
|
|
185
|
+
|
|
186
|
+
- Pass `__user` on `get` and `getOne` actions.
|
|
187
|
+
- Async/`next` fixes.
|
|
188
|
+
- **Note:** Node versions above 17 were unsupported at this release.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## v2.7.0 — 2021-02-09
|
|
193
|
+
|
|
194
|
+
- **Permanent delete** — `?_permaDelete=1`.
|
|
195
|
+
- **Cascade delete** — `?_cascade=1`.
|
|
196
|
+
- **`_updated_by_id`** set on PUT; populated as `_updated_by`.
|
|
197
|
+
- Default `count` returns `-1` on very large collections (performance).
|
|
198
|
+
- `/setup/data` casts `_id` fields to ObjectIds and sets `_deleted: false`.
|
|
199
|
+
|
|
200
|
+
## v2.6.x — 2021-01-06
|
|
201
|
+
|
|
202
|
+
- **apicache** replaces home-grown cache; configurable cache timeout.
|
|
203
|
+
- Major **GET performance** improvement on large collections.
|
|
204
|
+
- **Built-in documentation system** (MkDocs + in-server docs routes).
|
|
205
|
+
- Default port changed to **4001** (conflict on M1 Macs).
|
|
206
|
+
- Model docs refactored to separate library.
|
|
207
|
+
- Dependency upgrades (including Axios security fix).
|
|
208
|
+
- Return 404 for missing model.
|
|
209
|
+
|
|
210
|
+
## v2.5.x — 2021-01-06
|
|
211
|
+
|
|
212
|
+
- Documentation system introduced (see v2.6.x).
|
|
213
|
+
|
|
214
|
+
## v2.4.x — 2020-07 – 2020-08
|
|
215
|
+
|
|
216
|
+
- **WebSockets** — subscribe to model/item changes; auth via basic, apikey, or bearer token; filtering on subscriptions.
|
|
217
|
+
- **Bulk writes** — `/bulkwrite/<model>` endpoint.
|
|
218
|
+
- **`/query/<model>`** — POST advanced MongoDB queries.
|
|
219
|
+
- **`/aggregate/<model>`** — aggregation pipelines; `allowDiskUse` query param; inline ObjectId and Date strings.
|
|
220
|
+
- **`relative_date()`** in aggregation pipelines.
|
|
221
|
+
- **`/count/<model>`** endpoint.
|
|
222
|
+
- Populate `_owner_id` as `_owner`.
|
|
223
|
+
- OAuth login uses renewable API keys (2022-01).
|
|
224
|
+
|
|
225
|
+
## v2.0.x — 2020-05-06 – 2020-07
|
|
226
|
+
|
|
227
|
+
Major v2 rewrite ([PR #11](https://github.com/WorkSpaceMan/jxp/pull/11)):
|
|
228
|
+
|
|
229
|
+
- Renamed project to **JXP**; MongoDB **connection string** (Atlas-compatible).
|
|
230
|
+
- **JXPSchema** — links, autopopulate, `ObjectId`/`Mixed` globals, automagic `_owner_id` / `_deleted`.
|
|
231
|
+
- **Bearer tokens** and refresh tokens as preferred auth.
|
|
232
|
+
- **Stored procedures** via `/call/<model>/<static>`.
|
|
233
|
+
- **Hooks** — `pre_hooks` / `post_hooks` on server config.
|
|
234
|
+
- Response shape `{ data }` for single records.
|
|
235
|
+
- Setup scaffolding (`jxp-setup`), link model, soft delete.
|
|
236
|
+
- Pre/post Mongoose middleware documented.
|
|
237
|
+
- WebSocket support started (completed in v2.4).
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## v1.x — 2016 – 2019
|
|
242
|
+
|
|
243
|
+
### v1.2.4 — 2019-11-06
|
|
244
|
+
|
|
245
|
+
- Time log includes operation number.
|
|
246
|
+
|
|
247
|
+
### v1.2.3 — 2019-11-06
|
|
248
|
+
|
|
249
|
+
- Request **throttling**.
|
|
250
|
+
|
|
251
|
+
### v1.0.16 — 2019-05-02
|
|
252
|
+
|
|
253
|
+
- **`POST /query/<model>`** for advanced queries.
|
|
254
|
+
|
|
255
|
+
### v1.0.12 — 2019-04-03
|
|
256
|
+
|
|
257
|
+
- Select individual fields in populate joins.
|
|
258
|
+
|
|
259
|
+
### v1.0.1 — 2019-02-13
|
|
260
|
+
|
|
261
|
+
- **Security:** only admins can assign user groups.
|
|
262
|
+
|
|
263
|
+
### Earlier v1 highlights
|
|
264
|
+
|
|
265
|
+
- **2019-03** — CSV export; async/await refactor; non-blocking bcrypt password checks; caching (early).
|
|
266
|
+
- **2019-02** — Renamed to JXP; CORS plugin; Mongoose 5; full-text search.
|
|
267
|
+
- **2018-12** — Soft delete (`_deleted`); `showDeleted`; refactor from Q to async/await; `bcryptjs`.
|
|
268
|
+
- **2018-02** — Password field auto-encryption; config module.
|
|
269
|
+
- **2017** — Setup endpoint; pre-hooks; `model_dir` (relative/absolute); field selection; groups.
|
|
270
|
+
- **2016-05** — Initial release: REST CRUD from Mongoose models, auth, populate, filter, search, pagination, permissions, `jexpress-setup` CLI.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Version notes
|
|
275
|
+
|
|
276
|
+
| Era | Mongoose | Node (documented) |
|
|
277
|
+
|-----|----------|-------------------|
|
|
278
|
+
| v4 | 6.13.9 | 22+ |
|
|
279
|
+
| v3.x | 6.x | — |
|
|
280
|
+
| v2.11 | — | ≤17 (warning in release) |
|
|
281
|
+
| v1 / early v2 | 5.x | — |
|
|
282
|
+
|
|
283
|
+
See the [v4.0.0 release](https://github.com/WorkSpaceMan/jxp/releases/tag/v4.0.0) and [compare view since v3.1.0](https://github.com/WorkSpaceMan/jxp/compare/7224093...v4.0.0).
|
package/docs/configuration.md
CHANGED
|
@@ -1,162 +1,173 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Configuration
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
JXP 4 uses **environment variables** and [dotenv](https://github.com/motdotla/dotenv). Copy [`.env.sample`](../.env.sample) to `.env` and adjust values.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
_As of version 4, there is no `config` npm package and no `/config/*.json` hierarchy._
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## MongoDB
|
|
8
|
+
|
|
9
|
+
Set a full connection string:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
MONGO_CONNECTION_STRING=mongodb://127.0.0.1:27017/myapp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Or build from parts (common in Docker):
|
|
8
16
|
|
|
9
17
|
```
|
|
10
18
|
MONGODB_HOST=127.0.0.1
|
|
11
19
|
MONGODB_PORT=27017
|
|
12
|
-
MONGODB_NAME=
|
|
20
|
+
MONGODB_NAME=myapp
|
|
21
|
+
MONGODB_USER=
|
|
22
|
+
MONGODB_PASSWORD=
|
|
13
23
|
MONGODB_AUTH_DB=admin
|
|
14
|
-
MONGODB_USER=user
|
|
15
|
-
MONGODB_PASS=pass
|
|
16
24
|
```
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
The config files are stored in `/config` in strict JSON format. (Remember to enclose your keys in inverted commas!) Typically, you'd use `/config/default.json` for a simple configuration, or `/config/development.json` and `/config/production.json` for separating development and production.
|
|
26
|
+
Optional driver options as JSON:
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
```
|
|
29
|
+
MONGO_OPTIONS={"maxPoolSize":50}
|
|
30
|
+
```
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
## Server
|
|
25
33
|
|
|
26
|
-
|
|
34
|
+
| Variable | Description | Default |
|
|
35
|
+
|----------|-------------|---------|
|
|
36
|
+
| `PORT` | HTTP port | `4001` |
|
|
37
|
+
| `API_URL` / `API_SERVER` | Public base URL | `http://localhost:{PORT}` |
|
|
38
|
+
| `MODEL_DIR` | Path to `*_model.js` files | `./dist/models` (sample server) |
|
|
39
|
+
| `LOG_FILE` | Access log path | `access.log` |
|
|
40
|
+
| `SHARED_SECRET` | JWT / recovery signing | — |
|
|
41
|
+
| `TOKEN_EXPIRY` | Access token TTL (seconds) | `86400` |
|
|
42
|
+
| `REFRESH_TOKEN_EXPIRY` | Refresh token TTL (seconds) | `2678400` |
|
|
43
|
+
| `APIKEY` | Internal API key for schema helpers | — |
|
|
27
44
|
|
|
28
|
-
|
|
29
|
-
```json
|
|
30
|
-
"port": 4001,
|
|
31
|
-
```
|
|
45
|
+
## API docs browser
|
|
32
46
|
|
|
33
|
-
|
|
47
|
+
| `DOCS_ACCESS` | Behavior |
|
|
48
|
+
|---------------|----------|
|
|
49
|
+
| `protected` (default) | Home (`/`) and guides (`/docs/md/*`) are public; model explorer (`/docs/api`, `/docs/model/*`) requires sign-in |
|
|
50
|
+
| `disabled` | Model explorer routes return 404 |
|
|
51
|
+
| `public` | Model explorer open without sign-in |
|
|
34
52
|
|
|
35
|
-
|
|
53
|
+
Sign-in uses the normal `POST /login` endpoint (same credentials as the API). The docs UI then stores a session cookie via `POST /docs/session` and auto-fills the API key for “Try it” panels.
|
|
36
54
|
|
|
37
|
-
|
|
55
|
+
| Variable | Description |
|
|
56
|
+
|----------|-------------|
|
|
57
|
+
| `DOCS_USER_EMAIL` | Optional email pre-fill on the docs sign-in form |
|
|
58
|
+
| `DOCS_COOKIE_SECURE` | Set to `true` for `Secure` on the docs session cookie (HTTPS) |
|
|
38
59
|
|
|
39
|
-
|
|
60
|
+
You can also set `docs: { access, user_email }` on the object passed to `JXP()`.
|
|
40
61
|
|
|
41
|
-
|
|
62
|
+
## Login rate limiting
|
|
42
63
|
|
|
43
|
-
|
|
64
|
+
Enabled by default on `POST /login` and `POST /docs/session` (docs sign-in after login):
|
|
44
65
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
A Mongo Atlas connection:
|
|
54
|
-
```json
|
|
55
|
-
"mongo": {
|
|
56
|
-
"connection_string": "mongodb+srv://admin:<your password>@<your server>.gcp.mongodb.net/<your database>?retryWrites=true&w=majority",
|
|
57
|
-
"options": {
|
|
58
|
-
"readPreference": "nearest",
|
|
59
|
-
"poolSize": 20,
|
|
60
|
-
"authSource": "admin"
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
```
|
|
66
|
+
| Variable | Default | Description |
|
|
67
|
+
|----------|---------|-------------|
|
|
68
|
+
| `LOGIN_RATE_LIMIT_ENABLED` | `true` | Set `false` to disable |
|
|
69
|
+
| `LOGIN_RATE_BURST` | `8` | Short burst of attempts per client |
|
|
70
|
+
| `LOGIN_RATE_PER_MINUTE` | `12` | Sustained attempts per minute per client |
|
|
71
|
+
| `LOGIN_RATE_LIMIT_XFF` | `false` | Use `X-Forwarded-For` when behind a reverse proxy |
|
|
64
72
|
|
|
65
|
-
|
|
73
|
+
Over-limit clients receive HTTP **429**. Response headers include rate-limit hints when supported by Restify.
|
|
66
74
|
|
|
67
|
-
|
|
75
|
+
## Cache
|
|
68
76
|
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
|
|
77
|
+
```
|
|
78
|
+
CACHE_ENABLED=true
|
|
79
|
+
CACHE_DEBUG=false
|
|
80
|
+
CACHE_TTL=300
|
|
72
81
|
```
|
|
73
82
|
|
|
74
|
-
|
|
83
|
+
When enabled, JXP uses an in-process cache ([node-cache](https://www.npmjs.com/package/node-cache)). GET responses may include `jxp-cache` (`hit` / `miss`) and `jxp-cache-key` headers. Admin endpoints (**require admin login**):
|
|
75
84
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"log": "/var/log/openmembers/access.log",
|
|
79
|
-
```
|
|
85
|
+
- `GET /cache/stats` — cache statistics, or `{ cache_enabled: false }` when disabled
|
|
86
|
+
- `GET /cache/clear` — flush all cached entries
|
|
80
87
|
|
|
81
|
-
|
|
88
|
+
See [Caching](caching.md) for details.
|
|
82
89
|
|
|
83
|
-
|
|
90
|
+
## Query limits
|
|
84
91
|
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
```
|
|
93
|
+
QUERY_LIMITS_ENABLED=true
|
|
94
|
+
QUERY_LIMITS_LARGE_COLLECTION_THRESHOLD=10000
|
|
95
|
+
QUERY_LIMITS_MAX=1000
|
|
96
|
+
QUERY_LIMITS_DEFAULT=100
|
|
97
|
+
QUERY_LIMITS_SKIP_COUNT_UNLESS_PAGINATED=true
|
|
98
|
+
CORS_ORIGINS=http://localhost:3000,http://localhost:4001
|
|
90
99
|
```
|
|
91
100
|
|
|
92
101
|
## Throttling
|
|
93
102
|
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
"throttle": {
|
|
97
|
-
"burst": 10,
|
|
98
|
-
"rate": 5,
|
|
99
|
-
"ip": true,
|
|
100
|
-
"overrides": {
|
|
101
|
-
"192.168.1.1": {
|
|
102
|
-
"rate": 0,
|
|
103
|
-
"burst": 0
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
```
|
|
103
|
+
Optional JSON blob:
|
|
108
104
|
|
|
109
|
-
|
|
105
|
+
```
|
|
106
|
+
THROTTLE_JSON={"burst":100,"rate":50,"ip":true}
|
|
107
|
+
```
|
|
110
108
|
|
|
111
|
-
|
|
109
|
+
## Model directory
|
|
112
110
|
|
|
113
|
-
|
|
111
|
+
JXP discovers models by scanning `MODEL_DIR` for `*_model.js`. You can also pass `model_dir` in the object given to `JXP(apiconfig)`.
|
|
114
112
|
|
|
115
|
-
|
|
113
|
+
Relative `model_dir` paths resolve from `process.cwd()` (typical for npm scripts), not from the server script path.
|
|
116
114
|
|
|
117
|
-
|
|
118
|
-
"shared_secret": "SomeRandomString",
|
|
119
|
-
"password_recovery_url": "https://blah.com/login/reset",
|
|
120
|
-
"smtp": {
|
|
121
|
-
"host": "smtp.gmail.com",
|
|
122
|
-
"port": 587,
|
|
123
|
-
"auth": {
|
|
124
|
-
"user": "blah@blah.com",
|
|
125
|
-
"pass": "blah"
|
|
126
|
-
},
|
|
127
|
-
"secureConnection": true
|
|
128
|
-
},
|
|
129
|
-
```
|
|
115
|
+
## Programmatic config
|
|
130
116
|
|
|
131
|
-
|
|
117
|
+
Apps typically build an options object and pass it to `JXP()`:
|
|
132
118
|
|
|
133
|
-
|
|
119
|
+
```javascript
|
|
120
|
+
const JXP = require("jxp");
|
|
121
|
+
const server = JXP({
|
|
122
|
+
port: 4001,
|
|
123
|
+
mongo: { connection_string: process.env.MONGO_CONNECTION_STRING },
|
|
124
|
+
model_dir: "./models",
|
|
125
|
+
pre_hooks: { get: (req, res, next) => next() },
|
|
126
|
+
});
|
|
127
|
+
```
|
|
134
128
|
|
|
135
|
-
|
|
129
|
+
The sample JXP server uses `loadJxpConfig()` from `jxp/libs/load-config` (resolved via `package.json` `exports` to compiled `dist/libs/load-config.js`) to build the same shape from `.env`.
|
|
136
130
|
|
|
137
|
-
|
|
131
|
+
### SMTP and password recovery
|
|
138
132
|
|
|
139
|
-
|
|
133
|
+
SMTP and password-recovery URLs are **not** read from environment variables by `loadJxpConfig()`. Pass them on the `JXP()` options object:
|
|
140
134
|
|
|
135
|
+
```javascript
|
|
136
|
+
JXP({
|
|
137
|
+
smtp_server: "mail.example.com",
|
|
138
|
+
smtp_username: "user",
|
|
139
|
+
smtp_password: "secret",
|
|
140
|
+
smtp_from: "noreply@example.com",
|
|
141
|
+
password_recovery_url: "https://myapp.example.com/reset",
|
|
142
|
+
});
|
|
141
143
|
```
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
144
|
+
|
|
145
|
+
Used by `POST /login/recover` (see [Authentication](authentication.md)).
|
|
146
|
+
|
|
147
|
+
### OAuth
|
|
148
|
+
|
|
149
|
+
OAuth2 providers are configured programmatically on the `oauth` key:
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
JXP({
|
|
153
|
+
url: "http://localhost:4001",
|
|
154
|
+
oauth: {
|
|
155
|
+
success_uri: "https://myapp.example.com/oauth/success",
|
|
156
|
+
fail_uri: "https://myapp.example.com/oauth/fail",
|
|
157
|
+
google: {
|
|
158
|
+
auth_uri: "https://accounts.google.com/o/oauth2/v2/auth",
|
|
159
|
+
token_uri: "https://oauth2.googleapis.com/token",
|
|
160
|
+
api_uri: "https://www.googleapis.com/oauth2/v2/userinfo",
|
|
161
|
+
app_id: "...",
|
|
162
|
+
app_secret: "...",
|
|
163
|
+
scope: "email profile",
|
|
152
164
|
},
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
```
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Routes: `GET /login/oauth/:provider` and `GET /login/oauth/callback/:provider`. See [Authentication](authentication.md).
|
|
170
|
+
|
|
171
|
+
## Tests
|
|
172
|
+
|
|
173
|
+
Tests load `.env.test` via `test/env.js` (see `npm test`). Set `NODE_ENV=test` and `MONGO_CONNECTION_STRING` for your local Mongo instance.
|
package/docs/hooks.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Hooks
|
|
2
2
|
|
|
3
|
-
In
|
|
3
|
+
In your app's server bootstrap (eg. `dist/bin/server.js` compiled from `src/bin/server.ts`), configure `pre_hooks` and `post_hooks` on the object passed to `JXP()`. These run after authentication but before (or after, for post-hooks) the operation.
|
|
4
4
|
|
|
5
|
-
We've used
|
|
5
|
+
We've used pre-hooks on `get` and `getOne` to add query constraints so certain users only see allowed rows. We've also used `post`, `put`, and `delete` hooks alongside JXP's built-in WebSocket emitter to notify subscribed clients of changes.
|
|
6
6
|
|
|
7
7
|
```javascript
|
|
8
8
|
config.pre_hooks = {
|
|
@@ -21,19 +21,23 @@ config.pre_hooks = {
|
|
|
21
21
|
put: (req, res, next) => {
|
|
22
22
|
next();
|
|
23
23
|
},
|
|
24
|
+
update: (req, res, next) => {
|
|
25
|
+
next();
|
|
26
|
+
},
|
|
24
27
|
delete: (req, res, next) => {
|
|
25
28
|
next();
|
|
26
29
|
},
|
|
27
30
|
};
|
|
28
31
|
```
|
|
29
32
|
|
|
30
|
-
For _login_ there
|
|
33
|
+
For _login_ there is also a post-hook if you need to inject more information into the login result:
|
|
31
34
|
|
|
32
35
|
```javascript
|
|
33
|
-
config.post_hooks =
|
|
34
|
-
res
|
|
35
|
-
|
|
36
|
-
}
|
|
36
|
+
config.post_hooks = {
|
|
37
|
+
login: (req, res) => {
|
|
38
|
+
res.result.some_field = "Some Value";
|
|
39
|
+
},
|
|
40
|
+
};
|
|
37
41
|
```
|
|
38
42
|
|
|
39
|
-
To suppress a
|
|
43
|
+
To suppress model callbacks (eg. to avoid infinite loops when a PUT updates the same model), pass `_silence=true` as a query parameter or in the request body.
|