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.
Files changed (229) hide show
  1. package/.env.sample +43 -6
  2. package/README.md +27 -13
  3. package/dist/bin/init_db.d.ts +3 -0
  4. package/dist/bin/init_db.d.ts.map +1 -0
  5. package/dist/bin/init_db.js +48 -0
  6. package/dist/bin/init_db.js.map +1 -0
  7. package/dist/bin/server.d.ts +4 -0
  8. package/dist/bin/server.d.ts.map +1 -0
  9. package/dist/bin/server.js +132 -0
  10. package/dist/bin/server.js.map +1 -0
  11. package/dist/bin/setup.d.ts +3 -0
  12. package/dist/bin/setup.d.ts.map +1 -0
  13. package/dist/bin/setup.js +185 -0
  14. package/dist/bin/setup.js.map +1 -0
  15. package/dist/globals.d.ts +14 -0
  16. package/dist/globals.d.ts.map +1 -0
  17. package/dist/globals.js +3 -0
  18. package/dist/globals.js.map +1 -0
  19. package/dist/libs/aggregate_guard.d.ts +5 -0
  20. package/dist/libs/aggregate_guard.d.ts.map +1 -0
  21. package/dist/libs/aggregate_guard.js +58 -0
  22. package/dist/libs/aggregate_guard.js.map +1 -0
  23. package/dist/libs/bulkwrite_guard.d.ts +5 -0
  24. package/dist/libs/bulkwrite_guard.d.ts.map +1 -0
  25. package/dist/libs/bulkwrite_guard.js +44 -0
  26. package/dist/libs/bulkwrite_guard.js.map +1 -0
  27. package/dist/libs/cache.d.ts +2 -0
  28. package/dist/libs/cache.d.ts.map +1 -0
  29. package/dist/libs/cache.js +94 -0
  30. package/dist/libs/cache.js.map +1 -0
  31. package/dist/libs/call_guard.d.ts +3 -0
  32. package/dist/libs/call_guard.d.ts.map +1 -0
  33. package/dist/libs/call_guard.js +17 -0
  34. package/dist/libs/call_guard.js.map +1 -0
  35. package/dist/libs/connection_string.d.ts +3 -0
  36. package/dist/libs/connection_string.d.ts.map +1 -0
  37. package/dist/libs/connection_string.js +4 -0
  38. package/dist/libs/connection_string.js.map +1 -0
  39. package/dist/libs/datamunging.d.ts +2 -0
  40. package/dist/libs/datamunging.d.ts.map +1 -0
  41. package/dist/libs/datamunging.js +320 -0
  42. package/dist/libs/datamunging.js.map +1 -0
  43. package/dist/libs/docs-auth.d.ts +25 -0
  44. package/dist/libs/docs-auth.d.ts.map +1 -0
  45. package/dist/libs/docs-auth.js +205 -0
  46. package/dist/libs/docs-auth.js.map +1 -0
  47. package/dist/libs/docs.d.ts +2 -0
  48. package/dist/libs/docs.d.ts.map +1 -0
  49. package/dist/libs/docs.js +328 -0
  50. package/dist/libs/docs.js.map +1 -0
  51. package/dist/libs/groups.d.ts +2 -0
  52. package/dist/libs/groups.d.ts.map +1 -0
  53. package/dist/libs/groups.js +136 -0
  54. package/dist/libs/groups.js.map +1 -0
  55. package/dist/libs/jxp.d.ts +4 -0
  56. package/dist/libs/jxp.d.ts.map +1 -0
  57. package/dist/libs/jxp.js +1176 -0
  58. package/dist/libs/jxp.js.map +1 -0
  59. package/dist/libs/link_index.d.ts +14 -0
  60. package/dist/libs/link_index.d.ts.map +1 -0
  61. package/dist/libs/link_index.js +37 -0
  62. package/dist/libs/link_index.js.map +1 -0
  63. package/dist/libs/load-config.d.ts +16 -0
  64. package/dist/libs/load-config.d.ts.map +1 -0
  65. package/dist/libs/load-config.js +166 -0
  66. package/dist/libs/load-config.js.map +1 -0
  67. package/dist/libs/login.d.ts +2 -0
  68. package/dist/libs/login.d.ts.map +1 -0
  69. package/dist/libs/login.js +244 -0
  70. package/dist/libs/login.js.map +1 -0
  71. package/dist/libs/login_rate_limit.d.ts +16 -0
  72. package/dist/libs/login_rate_limit.d.ts.map +1 -0
  73. package/dist/libs/login_rate_limit.js +49 -0
  74. package/dist/libs/login_rate_limit.js.map +1 -0
  75. package/dist/libs/modeldir.d.ts +5 -0
  76. package/dist/libs/modeldir.d.ts.map +1 -0
  77. package/dist/libs/modeldir.js +15 -0
  78. package/dist/libs/modeldir.js.map +1 -0
  79. package/dist/libs/query_limits.d.ts +2 -0
  80. package/dist/libs/query_limits.d.ts.map +1 -0
  81. package/dist/libs/query_limits.js +84 -0
  82. package/dist/libs/query_limits.js.map +1 -0
  83. package/dist/libs/query_manipulation.d.ts +3 -0
  84. package/dist/libs/query_manipulation.d.ts.map +1 -0
  85. package/{libs → dist/libs}/query_manipulation.js +22 -21
  86. package/dist/libs/query_manipulation.js.map +1 -0
  87. package/dist/libs/query_sanitize.d.ts +5 -0
  88. package/dist/libs/query_sanitize.d.ts.map +1 -0
  89. package/dist/libs/query_sanitize.js +109 -0
  90. package/dist/libs/query_sanitize.js.map +1 -0
  91. package/dist/libs/response_sanitize.d.ts +7 -0
  92. package/dist/libs/response_sanitize.d.ts.map +1 -0
  93. package/dist/libs/response_sanitize.js +57 -0
  94. package/dist/libs/response_sanitize.js.map +1 -0
  95. package/dist/libs/safe_error.d.ts +3 -0
  96. package/dist/libs/safe_error.d.ts.map +1 -0
  97. package/dist/libs/safe_error.js +14 -0
  98. package/dist/libs/safe_error.js.map +1 -0
  99. package/dist/libs/schema.d.ts +14 -0
  100. package/dist/libs/schema.d.ts.map +1 -0
  101. package/dist/libs/schema.js +98 -0
  102. package/dist/libs/schema.js.map +1 -0
  103. package/dist/libs/schema_description.d.ts +3 -0
  104. package/dist/libs/schema_description.d.ts.map +1 -0
  105. package/{libs → dist/libs}/schema_description.js +12 -21
  106. package/dist/libs/schema_description.js.map +1 -0
  107. package/dist/libs/security.d.ts +2 -0
  108. package/dist/libs/security.d.ts.map +1 -0
  109. package/dist/libs/security.js +428 -0
  110. package/dist/libs/security.js.map +1 -0
  111. package/dist/libs/setup.d.ts +2 -0
  112. package/dist/libs/setup.d.ts.map +1 -0
  113. package/dist/libs/setup.js +87 -0
  114. package/dist/libs/setup.js.map +1 -0
  115. package/dist/libs/startup-deprecations.d.ts +2 -0
  116. package/dist/libs/startup-deprecations.d.ts.map +1 -0
  117. package/dist/libs/startup-deprecations.js +21 -0
  118. package/dist/libs/startup-deprecations.js.map +1 -0
  119. package/dist/libs/startup.d.ts +16 -0
  120. package/dist/libs/startup.d.ts.map +1 -0
  121. package/dist/libs/startup.js +63 -0
  122. package/dist/libs/startup.js.map +1 -0
  123. package/dist/libs/ws.d.ts +2 -0
  124. package/dist/libs/ws.d.ts.map +1 -0
  125. package/{libs → dist/libs}/ws.js +91 -73
  126. package/dist/libs/ws.js.map +1 -0
  127. package/dist/models/apikey_model.d.ts +10 -0
  128. package/dist/models/apikey_model.d.ts.map +1 -0
  129. package/dist/models/apikey_model.js +14 -0
  130. package/dist/models/apikey_model.js.map +1 -0
  131. package/dist/models/link_model.d.ts +9 -0
  132. package/dist/models/link_model.d.ts.map +1 -0
  133. package/dist/models/link_model.js +20 -0
  134. package/dist/models/link_model.js.map +1 -0
  135. package/dist/models/refreshtoken_model.d.ts +11 -0
  136. package/dist/models/refreshtoken_model.d.ts.map +1 -0
  137. package/dist/models/refreshtoken_model.js +22 -0
  138. package/dist/models/refreshtoken_model.js.map +1 -0
  139. package/dist/models/test_model.d.ts +24 -0
  140. package/dist/models/test_model.d.ts.map +1 -0
  141. package/dist/models/test_model.js +44 -0
  142. package/dist/models/test_model.js.map +1 -0
  143. package/dist/models/token_model.d.ts +14 -0
  144. package/dist/models/token_model.d.ts.map +1 -0
  145. package/dist/models/token_model.js +25 -0
  146. package/dist/models/token_model.js.map +1 -0
  147. package/dist/models/user_model.d.ts +15 -0
  148. package/dist/models/user_model.d.ts.map +1 -0
  149. package/dist/models/user_model.js +38 -0
  150. package/dist/models/user_model.js.map +1 -0
  151. package/dist/models/usergroups_model.d.ts +9 -0
  152. package/dist/models/usergroups_model.d.ts.map +1 -0
  153. package/dist/models/usergroups_model.js +18 -0
  154. package/dist/models/usergroups_model.js.map +1 -0
  155. package/dist/types/jxp-config.d.ts +151 -0
  156. package/dist/types/jxp-config.d.ts.map +1 -0
  157. package/dist/types/jxp-config.js +3 -0
  158. package/dist/types/jxp-config.js.map +1 -0
  159. package/dist/types/schema-fields.d.ts +43 -0
  160. package/dist/types/schema-fields.d.ts.map +1 -0
  161. package/dist/types/schema-fields.js +3 -0
  162. package/dist/types/schema-fields.js.map +1 -0
  163. package/docs/aggregations.md +40 -21
  164. package/docs/api.md +55 -15
  165. package/docs/authentication.md +60 -37
  166. package/docs/bulk_writes.md +11 -8
  167. package/docs/caching.md +28 -11
  168. package/docs/changelog.md +258 -31
  169. package/docs/configuration.md +126 -115
  170. package/docs/hooks.md +12 -8
  171. package/docs/index.md +17 -17
  172. package/docs/installation.md +23 -18
  173. package/docs/permissions.md +33 -19
  174. package/docs/queries.md +9 -5
  175. package/docs/schemas.md +21 -10
  176. package/docs/special.md +4 -4
  177. package/docs/typescript.md +86 -0
  178. package/docs/websocket.md +99 -1
  179. package/mkdocs.yml +1 -0
  180. package/package.json +121 -69
  181. package/templates/api.pug +32 -0
  182. package/templates/app-server.js +43 -0
  183. package/templates/app.env.sample +8 -0
  184. package/templates/assets/api-console.js +151 -0
  185. package/templates/assets/docs-login.js +66 -0
  186. package/templates/assets/docs.css +244 -0
  187. package/templates/index.pug +67 -2
  188. package/templates/layout.pug +21 -11
  189. package/templates/login.pug +39 -0
  190. package/templates/md.pug +1 -1
  191. package/templates/model.pug +117 -68
  192. package/templates/navbar.pug +25 -21
  193. package/templates/sidebar.pug +30 -0
  194. package/.env +0 -9
  195. package/.eslintrc.json +0 -20
  196. package/.jshintrc +0 -4
  197. package/.vscode/launch.json +0 -34
  198. package/.vscode/settings.json +0 -3
  199. package/Dockerfile +0 -7
  200. package/bin/init_db.js +0 -54
  201. package/bin/server.js +0 -131
  202. package/bin/setup.js +0 -190
  203. package/config_sample.json +0 -10
  204. package/docker-compose.yml +0 -32
  205. package/libs/cache.js +0 -92
  206. package/libs/connection_string.js +0 -24
  207. package/libs/datamunging.js +0 -335
  208. package/libs/docs.js +0 -162
  209. package/libs/groups.js +0 -133
  210. package/libs/jxp.js +0 -1208
  211. package/libs/login.js +0 -222
  212. package/libs/modeldir.js +0 -14
  213. package/libs/schema.js +0 -99
  214. package/libs/security.js +0 -410
  215. package/libs/setup.js +0 -90
  216. package/models/apikey_model.js +0 -10
  217. package/models/link_model.js +0 -17
  218. package/models/refreshtoken_model.js +0 -20
  219. package/models/test_model.js +0 -50
  220. package/models/token_model.js +0 -23
  221. package/models/user_model.js +0 -38
  222. package/models/usergroups_model.js +0 -15
  223. package/setup.sh +0 -3
  224. package/test/.eslintrc.json +0 -13
  225. package/test/auth.js +0 -190
  226. package/test/init.js +0 -92
  227. package/test/setup.test.js +0 -62
  228. package/test/test.js +0 -1527
  229. package/test/wstest.js.old +0 -124
package/docs/changelog.md CHANGED
@@ -1,56 +1,283 @@
1
1
  # Changelog
2
2
 
3
- ## v1.0.0
3
+ Notable changes to [JXP](https://github.com/WorkSpaceMan/jxp).
4
4
 
5
- - Mongoose v5
5
+ ## v4.1.0 — 2026-05-25
6
6
 
7
- ## v1.0.1
7
+ API docs browser security: gated model explorer, real API login, and brute-force limits.
8
8
 
9
- - Closed bad security hole in groups - now only admins can set groups. (Will probably change this in future so that only those defined in the usergroup model can change groups.)
9
+ ### Added
10
10
 
11
- ## v1.0.12
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
- - Select individual fields in populate joins
17
+ ### Changed
14
18
 
15
- ## v1.0.16
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
- - Add a /query endpoint, that allows you to POST { query } for advanced queries
22
+ ### Fixed
18
23
 
19
- ## v1.2.3
24
+ - **Restify async routes** — docs login/session handlers use `(req, res)` only; redirects use `sendRedirect()` where `res.redirect()` requires `next`.
20
25
 
21
- - Throttling
26
+ ## v4.0.0 — 2026-05-19
22
27
 
23
- ## v1.2.4
28
+ Major release: complete TypeScript rewrite and configuration overhaul.
24
29
 
25
- - Time log includes operation number
30
+ ### Breaking changes
26
31
 
27
- ## v2.0.1-0
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
- - Start v2!
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
- ## v2.0.1-1
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
- - Tokens as the preferred login methodology
55
+ ### Changed
36
56
 
37
- ## v2.4.x
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
- - Websockets
40
- - Bulk uploads
41
- - Advanced queries
70
+ ### Fixed
42
71
 
43
- ## v2.5.x
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
- - Documentation system
77
+ ### Security hardening migration
46
78
 
47
- ## 2.6.x
79
+ Consumer apps (e.g. RevEngine) should adjust clients and models as follows:
48
80
 
49
- - Replace home-grown cache with apicache
50
- - Major performance boost when getting large collections (50secs to < 1 sec)
51
- - /setup/data endpoint for scaffolding a complete system
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
- ## 2.7.x
94
+ Example model opts:
54
95
 
55
- - Permanent Delete
56
- - Cascade Delete
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).
@@ -1,162 +1,173 @@
1
- # Configuring JXP
1
+ # Configuration
2
2
 
3
- ## Connecting to MongoDB
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
- JXP uses MongoDB for storage. You can use a local MongoDB instance, or a hosted one such as Mongo Atlas.
5
+ _As of version 4, there is no `config` npm package and no `/config/*.json` hierarchy._
6
6
 
7
- The configuration for the MongoDB connection is set as environmental variables (for instance, if running in Docker), or in the `.env` file. Alternatively, you can set the connection string in the config file as described below, although this is not recommended.
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=jxp
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
- ## Config files
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
- If you used the `jxp-setup` command for setting everything up, you should have a basic `/config/default.json` file ready to go.
28
+ ```
29
+ MONGO_OPTIONS={"maxPoolSize":50}
30
+ ```
23
31
 
24
- JXP uses [config](https://www.npmjs.com/package/config) for configuration. This allows you to have different configuration files for development, staging and production, set config variables through [environmental variables](https://github.com/lorenwest/node-config/wiki/Environment-Variables) or [command line overrides](https://github.com/lorenwest/node-config/wiki/Command-Line-Overrides), and do lots of other cool config magic.
32
+ ## Server
25
33
 
26
- ## Port
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
- The `port` key defines the port you want the server to run on. The default is `4001`.
29
- ```json
30
- "port": 4001,
31
- ```
45
+ ## API docs browser
32
46
 
33
- ## Model Directory
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
- JXP will search for a model directory with "user_model.js" in it, else you can override this with the config parameter `model_dir`. (This should be an absolute directory.)
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
- ## MongoDB
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
- The `connection_string` can include port, username and password, options, and other fancy stuff. If you have advanced needs, you can find out more (here)[https://docs.mongodb.com/manual/reference/connection-string/].
60
+ You can also set `docs: { access, user_email }` on the object passed to `JXP()`.
40
61
 
41
- If you use Atlas, it will give you a connection string that you can use as-is.
62
+ ## Login rate limiting
42
63
 
43
- The `options` allow you to pass extra options such as `poolSize`, `useNewUrlParser`, `useCreateIndex`, and `authSource`, amongst others. We use Mongoose's connection, so you can find out about the connection options (here)[https://mongoosejs.com/docs/connections.html]. Typically we only use `poolSize` and `authSource` in production, and no options in development.
64
+ Enabled by default on `POST /login` and `POST /docs/session` (docs sign-in after login):
44
65
 
45
- A simple, local connection:
46
- ```json
47
- "mongo": {
48
- "connection_string": "mongodb://localhost/test",
49
- "options": {}
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
- ## Token lifespans
73
+ Over-limit clients receive HTTP **429**. Response headers include rate-limit hints when supported by Restify.
66
74
 
67
- Set how long you want your users' tokens to live for. Defaults to 24 hours for a token and 30 days for a refresh token.
75
+ ## Cache
68
76
 
69
- ```json
70
- "token_expiry": 86400,
71
- "refresh_token_expiry": 2678400
77
+ ```
78
+ CACHE_ENABLED=true
79
+ CACHE_DEBUG=false
80
+ CACHE_TTL=300
72
81
  ```
73
82
 
74
- ## Log
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
- You can define an access log as follows:
77
- ```json
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
- ## Memcached
88
+ See [Caching](caching.md) for details.
82
89
 
83
- Memcached is entirely optional. Leave it out completely to not use Memcached.
90
+ ## Query limits
84
91
 
85
- ```json
86
- "memcached": {
87
- "server": "localhost:11211",
88
- "lifetime": 604800
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
- You can throttle the API performance. In the following example, we offer 5 requests per second, 10 concurrent requests, throttle by IP, and allow clients from 192.168.1.1 to go crazy.
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
- ## Password recovery setup
105
+ ```
106
+ THROTTLE_JSON={"burst":100,"rate":50,"ip":true}
107
+ ```
110
108
 
111
- We have a secret that we share with the front end in order to create Javascript Web Tokens as a login option. This would allow you to send a link to a client that would auto-log them in. We also use it for password recovery links. If you used `jxp-setup` it would have generated a random one for you.
109
+ ## Model directory
112
110
 
113
- We also configure a recovery url, which is a front-end page you'll want to hit, such as a password reset page.
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
- We configure an SMTP connection to send out forgotten password links.
113
+ Relative `model_dir` paths resolve from `process.cwd()` (typical for npm scripts), not from the server script path.
116
114
 
117
- ```json
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
- ## oAuth
117
+ Apps typically build an options object and pass it to `JXP()`:
132
118
 
133
- If you want users to be able to log in with an oAuth 2 provider, such as Google or Facebook, you would set it up as follows.
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
- We have a `success_uri` and `fail_uri` that will direct the user to your front end's success and failure page, respectively.
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
- Then, for each service you'd like to support, define the `app_id`, `app_secret`, `scope`, `auth_uri`, `token_uri` and `api_uri`.
131
+ ### SMTP and password recovery
138
132
 
139
- Here are some examples. We used to support LinkedIn but they made some weird decisions that effectively broke their oAuth2 support.
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
- "oauth": {
143
- "success_uri": "https://my.workshop17.co.za/login/oauth",
144
- "fail_uri": "https://my.workshop17.co.za/login/oauth/fail",
145
- "facebook": {
146
- "app_id": "<your app id>",
147
- "app_secret": "<your app secret>",
148
- "scope": "email",
149
- "auth_uri": "https://www.facebook.com/dialog/oauth",
150
- "token_uri": "https://graph.facebook.com/v2.3/oauth/access_token",
151
- "api_uri": "https://graph.facebook.com/me?fields=id,name,about,age_range,email,picture"
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
- "google": {
154
- "app_id": "<your app id>",
155
- "app_secret": "<your app secret>",
156
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
157
- "scope": "email+profile",
158
- "api_uri": "https://www.googleapis.com/oauth2/v1/userinfo?alt=json",
159
- "token_uri": "https://www.googleapis.com/oauth2/v3/token"
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 `/bin/server.js` you will find some pre-operation hooks. These will run after `auth` but before the operation.
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 callbacks to add parameters on `get` and `getOne` to our queries to limit what certain users see in the results. We've also use the `post`, `put` and `delete` to fire emits on an external Websocket server.
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's also a post-hook, eg. if you need to inject more information into the login result.
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 = (req, res, next) => {
34
- res.result.some_field = "Some Value";
35
- next();
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 callback, pass `_silence=true` as a parameter. This helps avoid infinite loops, for instance when your PUT updates the same model.
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.