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
@@ -1,25 +1,39 @@
1
1
  # Aggregation Queries
2
2
 
3
- You can apply an aggregation pipeline through the `/aggregate/<modelname>` endpoint. See [MongoDB's aggregation documentation](https://docs.mongodb.com/manual/aggregation/).
3
+ You can apply an aggregation pipeline through the `/aggregate/<modelname>` endpoint. See [MongoDB's aggregation documentation](https://www.mongodb.com/docs/manual/aggregation/).
4
4
 
5
- POST the query as JSON, and wrap it with a "query" variable, like so *:
6
- ```JSON
5
+ Only allowlisted stages are permitted (e.g. `$match`, `$group`, `$lookup`, `$project`, `$sort`, `$limit`). Stages such as `$out`, `$merge`, and `$function` require an admin user. Disable per model with `advanced_queries: { aggregate: false }`.
6
+
7
+ POST the pipeline as a **JSON array**, or wrap it in a `"query"` property. Both forms are accepted:
8
+
9
+ ```json
10
+ [
11
+ {
12
+ "$group": {
13
+ "_id": null,
14
+ "count": {
15
+ "$sum": 1
16
+ }
17
+ }
18
+ }
19
+ ]
20
+ ```
21
+
22
+ ```json
7
23
  {
8
24
  "query": [
9
25
  {
10
- "$group": {
26
+ "$group": {
11
27
  "_id": null,
12
- "count": {
13
- "$sum": 1
14
- }
15
- }
28
+ "count": {
29
+ "$sum": 1
30
+ }
31
+ }
16
32
  }
17
33
  ]
18
34
  }
19
35
  ```
20
36
 
21
- * Note that embedding in a "query" is no longer necessary
22
-
23
37
  ### Aggregations with ObjectIds
24
38
 
25
39
  Because we can't define ObjectIds in our aggregate functions, we need to send the ObjectIds as strings and then convert them in the pipeline.
@@ -27,12 +41,13 @@ Because we can't define ObjectIds in our aggregate functions, we need to send th
27
41
  There are two ways of doing this. We can embed `"ObjectId(\"<your object id>\")"` or you can convert in the pipeline. Embedding will be faster on execution.
28
42
 
29
43
  Embedding:
30
- ```JSON
44
+
45
+ ```json
31
46
  {
32
47
  "query": [
33
48
  {
34
49
  "$match": {
35
- "$campaign_id", "ObjectId(\"5fd45d05f2b93af8d59588fb\")"
50
+ "campaign_id": "ObjectId(\"5fd45d05f2b93af8d59588fb\")"
36
51
  }
37
52
  }
38
53
  ]
@@ -40,13 +55,14 @@ Embedding:
40
55
  ```
41
56
 
42
57
  Using a pipeline to add a field:
43
- ```JSON
58
+
59
+ ```json
44
60
  {
45
61
  "query": [
46
- {
62
+ {
47
63
  "$addFields": {
48
64
  "campaign_id_obj": {
49
- "$toObjectId": "5fd45d05f2b93af8d59588fb"
65
+ "$toObjectId": "5fd45d05f2b93af8d59588fb"
50
66
  }
51
67
  }
52
68
  },
@@ -70,12 +86,13 @@ Because we can't define Date objects in our aggregate functions, we need to send
70
86
  There are two ways of doing this. We can embed `"new Date(\"<your date>\")"` or you can convert in the pipeline. Embedding will be faster on execution.
71
87
 
72
88
  Embedding:
73
- ```JSON
89
+
90
+ ```json
74
91
  {
75
92
  "query": [
76
93
  {
77
94
  "$match": {
78
- "$timestamp": {
95
+ "timestamp": {
79
96
  "$gte": "new Date(\"2021-03-03T00:00:00.0Z\")"
80
97
  }
81
98
  }
@@ -85,7 +102,8 @@ Embedding:
85
102
  ```
86
103
 
87
104
  Using a pipeline to add a date field:
88
- ```JSON
105
+
106
+ ```json
89
107
  {
90
108
  "query": [
91
109
  {
@@ -115,12 +133,13 @@ Using a pipeline to add a date field:
115
133
  Say you want to use a date relative to today's date, you can use `relative_date(offset, offset_unit, startof_unit, endof_unit)`, similar to the method of embedding in a string above. It will also take `null` as a value.
116
134
 
117
135
  Eg. to get the beginning of this month:
118
- ```JSON
136
+
137
+ ```json
119
138
  {
120
139
  "query": [
121
140
  {
122
141
  "$match": {
123
- "$timestamp": {
142
+ "timestamp": {
124
143
  "$gte": "relative_date(null, null, \"month\")"
125
144
  }
126
145
  }
@@ -131,4 +150,4 @@ Eg. to get the beginning of this month:
131
150
 
132
151
  ### AllowDiskUse
133
152
 
134
- ***Tip*** Aggregates can use a lot of memory. If you're unable to complete your query, try using the disk. To enable allowDiskUse, add `?allowDiskUse=true` as a query parameter to the calling url.
153
+ Aggregates can use a lot of memory. If you're unable to complete your query, try using the disk. To enable `allowDiskUse`, add `?allowDiskUse=true` as a query parameter to the calling URL.
package/docs/api.md CHANGED
@@ -92,6 +92,41 @@ You can paginate with the `page=<page number>` parameter. Page count starts at 1
92
92
 
93
93
  If you go beyond the total number of pages, you will get an empty `data` array.
94
94
 
95
+ #### Default limit
96
+
97
+ When `query_limits.enabled` is true (default), list and query endpoints apply **`?limit=100`** if you omit `limit`. Use `?limit=` up to the configured maximum (default **1000**) for larger pages.
98
+
99
+ #### Large collections (explicit limit)
100
+
101
+ For collections with at least **10,000** documents (by default), you must pass an explicit `?limit=` between 1 and the maximum. Omitting `limit` on a large collection returns **400 Bad Request** (the default limit does not satisfy this rule).
102
+
103
+ Use `GET /count/<model>` for totals. Add **`?count=true`** (or **`?page=`**) when you need `count` / `page_count` in the list response without paginating.
104
+
105
+ #### Totals in list responses
106
+
107
+ By default, list responses **omit** `count` unless you pass **`?count=true`** or **`?page=`**, to avoid expensive `countDocuments` on every request.
108
+
109
+ Configure globally when starting JXP:
110
+
111
+ ```js
112
+ query_limits: {
113
+ enabled: true,
114
+ large_collection_threshold: 10000,
115
+ max: 1000,
116
+ default: 100,
117
+ skip_count_unless_paginated: true,
118
+ }
119
+ ```
120
+
121
+ Override per model in schema options:
122
+
123
+ ```js
124
+ const ReaderSchema = new JXPSchema({ ... }, {
125
+ perms: { ... },
126
+ query_limits: { large_collection_threshold: 5000, max: 500 },
127
+ });
128
+ ```
129
+
95
130
  *Note* If you have more than 100,000 items in your collection, `count` will return as -1, else doing a full-dataset filtered count becomes too expensive and can cause serious performance issues.
96
131
 
97
132
  ### Counting
@@ -149,7 +184,7 @@ To ensure a full-text index across all fields on your model, add this to your sc
149
184
 
150
185
  `MySchema.index( { "$**": "text" } );`
151
186
 
152
- See [https://docs.mongodb.com/manual/core/index-text/](MongoDB Text Indexes) for more options, such as weighted indexing.
187
+ See [MongoDB Text Indexes](https://www.mongodb.com/docs/manual/core/index-text/) for more options, such as weighted indexing.
153
188
 
154
189
  Note that you can only declare one index per collection (and hence schema).
155
190
 
@@ -168,28 +203,33 @@ As with PUT, we need to reference a specific item, so the endpoint needs to incl
168
203
 
169
204
  ## Advanced queries
170
205
 
171
- If you need to send an advanced query, such as a combined $and/$or, you can _POST_ a `{query}` variable to the `/query/{modelname}` endpoint. Most of the other features you'd use for `/get/{modelname}` (except for _search_ since it's a query) will still work.
206
+ If you need to send an advanced query, such as a combined `$and`/`$or`, POST JSON to `/query/{modelname}` with a **`query` object** (required). Most URL features from `GET /api/{modelname}` still apply (`limit`, `page`, `sort`, `populate`, `filter`, `autopopulate`, `fields`) except `search`.
172
207
 
173
208
  Eg.
174
- ```javascript
175
- query = {
176
- "$and": [
177
- {
178
- "foo": {
179
- "$regex": "foo",
180
- "$options": "i"
209
+
210
+ ```json
211
+ {
212
+ "query": {
213
+ "$and": [
214
+ {
215
+ "foo": {
216
+ "$regex": "foo",
217
+ "$options": "i"
218
+ }
219
+ },
220
+ {
221
+ "bar": "Bar"
181
222
  }
182
- },
183
- {
184
- "bar": "Bar"
185
- }
186
- ]
223
+ ]
224
+ }
187
225
  }
188
226
  ```
189
227
 
228
+ See [Queries](queries.md) for more examples.
229
+
190
230
  ## Aggregate queries
191
231
 
192
- You can perform an aggregate query by POSTing your query to `/aggregate/{modelname}`. The aggregation pipeline must be wrapped in an array
232
+ You can perform an aggregate query by POSTing a pipeline array to `/aggregate/{modelname}`, or wrapping it in `{ "query": [ ... ] }`. See [Aggregations](aggregations.md).
193
233
 
194
234
  Eg.
195
235
  ```javascript
@@ -1,19 +1,17 @@
1
1
  # Authentication
2
2
 
3
- ## API Key
4
-
5
3
  There are four ways of authenticating:
6
4
 
7
5
  * Basic Auth
8
6
  * A Bearer Token
9
7
  * An API Key
10
- * A Javascript Web Token
8
+ * A Javascript Web Token (JWT)
11
9
 
12
- We always use `email` and `password` to identify the user. The passwords are always one-way encrypted using bcrypt.
10
+ We always use `email` and `password` to identify the user. Passwords are one-way encrypted using bcrypt.
13
11
 
14
- In a typical application, your front-end site would present a login page asking for the user's email and password. In addition, you would present a "Forgotten Password" link.
12
+ In a typical application, your front-end site would present a login page asking for the user's email and password. In addition, you would present a "Forgotten Password" link.
15
13
 
16
- When the user submits their username and password, you would POST that data to the `/login` endpoint. If the login succeeds, the page will return their API key and bearer token.
14
+ When the user submits their username and password, you would POST that data to the `/login` endpoint. If the login succeeds, the response includes their API key and bearer token.
17
15
 
18
16
  ## Login endpoints
19
17
 
@@ -22,7 +20,9 @@ When the user submits their username and password, you would POST that data to t
22
20
  Logging in will always delete the previous token and give you a new one.
23
21
 
24
22
  POST `http://localhost:4001/login`
23
+
25
24
  Data:
25
+
26
26
  ```json
27
27
  {
28
28
  "email": "blah@blah.com",
@@ -31,6 +31,7 @@ Data:
31
31
  ```
32
32
 
33
33
  Successful Response (Status 200):
34
+
34
35
  ```json
35
36
  {
36
37
  "user_id": "5dadbd7e2384ad419975e4a1",
@@ -43,6 +44,7 @@ Successful Response (Status 200):
43
44
  ```
44
45
 
45
46
  Failed Response (Status 401):
47
+
46
48
  ```json
47
49
  {
48
50
  "status": "fail",
@@ -53,19 +55,22 @@ Failed Response (Status 401):
53
55
 
54
56
  ### Refresh Token
55
57
 
56
- You can use your refresh_token to refresh a token, even if it's expired. By default, refresh tokens last 30 days, whereas tokens last 24 hours.
58
+ You can use your refresh_token to refresh a token, even if it's expired. By default, refresh tokens last 30 days, whereas tokens last 24 hours (configurable via `REFRESH_TOKEN_EXPIRY` and `TOKEN_EXPIRY`).
57
59
 
58
60
  Note that the response is almost identical to the `/login` endpoint, except it doesn't have the `apikey`.
59
61
 
60
62
  POST `http://localhost:4001/refresh`
61
- Header:
63
+
64
+ Header:
65
+
62
66
  ```json
63
67
  {
64
- "Authorization": "Bearer <refresh token>",
68
+ "Authorization": "Bearer <refresh token>"
65
69
  }
66
70
  ```
67
71
 
68
72
  Successful Response (Status 200):
73
+
69
74
  ```json
70
75
  {
71
76
  "user_id": "5dadbd7e2384ad419975e4a1",
@@ -77,6 +82,7 @@ Successful Response (Status 200):
77
82
  ```
78
83
 
79
84
  Failed Response (Status 401):
85
+
80
86
  ```json
81
87
  {
82
88
  "status": "fail",
@@ -87,65 +93,74 @@ Failed Response (Status 401):
87
93
 
88
94
  ### Logout
89
95
 
90
- This will immeditately expire the token.
96
+ This will immediately expire the token. You must be authenticated (Bearer token or other method).
97
+
98
+ GET `http://localhost:4001/login/logout`
99
+
100
+ GET `http://localhost:4001/logout`
91
101
 
92
- POST or GET `http://localhost:4001/login/logout`
102
+ Successful Response (200):
103
+
104
+ ```json
105
+ {
106
+ "status": "ok",
107
+ "message": "User logged out"
108
+ }
109
+ ```
93
110
 
94
111
  ### Recover Password
95
112
 
96
- Send the user an email with their JWT embedded so that they can reset their password
113
+ Send the user an email with a JWT embedded so that they can reset their password. Requires SMTP settings on the `JXP()` config object (see [Configuration](configuration.md#smtp-and-password-recovery)).
97
114
 
98
115
  POST `http://localhost:4001/login/recover`
99
116
 
100
117
  Data:
101
- ```
118
+
119
+ ```json
102
120
  {
103
121
  "email": "blah@blah.com"
104
122
  }
105
123
  ```
106
124
 
107
- Successful Response (200):
108
- ```
125
+ Successful Response (200):
126
+
127
+ ```json
109
128
  {
110
129
  "status": "ok",
111
130
  "message": "Sent recovery email"
112
131
  }
113
132
  ```
114
133
 
115
- Failed Response (403):
116
- ```
117
- {
118
- "status": "fail",
119
- "message": "Unauthorized",
120
- "err": "Could not find email"
121
- }
122
- ```
134
+ Failed responses include 400 (missing email), 404 (user not found), or 401/500 depending on configuration errors.
123
135
 
124
- ***Note:*** You will still have to build the password reset page on your front end.
136
+ ***Note:*** You will still have to build the password reset page on your front end. The recovery link uses `password_recovery_url` from config plus the JWT token.
125
137
 
126
138
  ### JWT
127
139
 
128
- A Javascript Web Token can be used to log the user in through a URL.
140
+ A Javascript Web Token can be used to log the user in through a URL.
129
141
 
130
142
  POST `http://localhost:4001/login/getjwt`
131
143
 
132
144
  Data:
133
- ```
145
+
146
+ ```json
134
147
  {
135
148
  "email": "blah@blah.com"
136
149
  }
137
150
  ```
138
151
 
139
- Successful Response (200):
140
- ```
152
+ Successful Response (200):
153
+
154
+ ```json
141
155
  {
142
156
  "status": "ok",
143
157
  "jwt": "<jwt>"
144
158
  }
145
159
  ```
146
160
 
147
- Failed Response (403):
148
- ```
161
+ Failed Response (403 or 404):
162
+
163
+ ```json
149
164
  {
150
165
  "status": "fail",
151
166
  "message": "Unauthorized",
@@ -153,7 +168,16 @@ Failed Response (403):
153
168
  }
154
169
  ```
155
170
 
156
- ## Authenticating
171
+ ### OAuth2
172
+
173
+ OAuth login is configured programmatically (see [Configuration](configuration.md#oauth)).
174
+
175
+ - `GET /login/oauth/:provider` — redirects to the provider's authorization URL
176
+ - `GET /login/oauth/callback/:provider` — handles the callback and redirects to `oauth.success_uri` or `oauth.fail_uri` with a token or error
177
+
178
+ The provider name (`:provider`) must match a key under `oauth` in your config (excluding `success_uri` and `fail_uri`).
179
+
180
+ ## Authenticating API requests
157
181
 
158
182
  ### Basic Auth
159
183
 
@@ -161,11 +185,11 @@ Basic auth encodes (NOTE: ***NOT*** encrypts) your username and password and sen
161
185
 
162
186
  ***WARNING:*** You must only use basic auth over SSL, since it is trivial to decode the username and password. In fact, you should use SSL for everything, anyway.
163
187
 
164
- A basic auth is created by base64-encoding your username and password, separated by a colon.
188
+ A basic auth token is created by base64-encoding your username and password, separated by a colon.
165
189
 
166
- Eg. `echo "blah@blah.com:password" | base64` would generate a basic auth token on the command line. (In this case, it would encode to `YmxhaEBibGFoLmNvbTpwYXNzd29yZAo=`.)
190
+ Eg. `echo -n "blah@blah.com:password" | base64` would generate a basic auth token on the command line.
167
191
 
168
- However, `echo "YmxhaEBibGFoLmNvbTpwYXNzd29yZAo=" | base64 --decode` would reveal the uesrname and password, which is why it's not safe to use it on an unencrypted connection.
192
+ However, `echo "YmxhaEBibGFoLmNvbTpwYXNzd29yZA==" | base64 --decode` would reveal the username and password, which is why it's not safe to use it on an unencrypted connection.
169
193
 
170
194
  Header: `Authorization: Basic <your basic token>`
171
195
 
@@ -173,11 +197,10 @@ Header: `Authorization: Basic <your basic token>`
173
197
 
174
198
  _This is the preferred method of authenticating._
175
199
 
176
- Bearer tokens are ephemeral tokens that will expire in a certain time period. When a user logs out of a session, they will be destroyed.
200
+ Bearer tokens are ephemeral tokens that will expire after a configured period. When a user logs out of a session, they are revoked.
177
201
 
178
202
  Header: `Authorization: Bearer <your bearer token>`
179
203
 
180
204
  ### API Key
181
205
 
182
- The API Key is a permanent key that doesn't expire. It can be used by adding `?apikey=<apikey>` to the end of any request, or sending `x-api-key: <apikey>` in the header.
183
-
206
+ The API Key is a permanent key that doesn't expire. It can be used by adding `?apikey=<apikey>` to the end of any request, or sending `x-api-key: <apikey>` in the header.
@@ -1,20 +1,23 @@
1
1
  # Bulk Writes
2
2
 
3
- You can bulk writes through the `/bulkwrite/<modelname>` endpoint. Note that authorisation works a little differently - the user must have permissions to Create, Edit, Update and Read.
3
+ You can perform bulk writes through the `/bulkwrite/<modelname>` endpoint. **Disabled by default** unless the model opts in with `advanced_queries: { bulkwrite: true }`. Only allowlisted operations (`insertOne`, `updateOne`, `replaceOne`, `deleteOne`) are accepted; `updateMany` / `deleteMany` require admin.
4
+
5
+ Authorisation works a little differently — the user must have **create, read, update, and delete** permissions on the model.
4
6
 
5
7
  ***WARNING*** Be cautious when using bulk writes because you can destroy your data. Don't forget to back up!
6
8
 
7
9
  Eg:
8
- ```JSON
10
+
11
+ ```json
9
12
  [
10
13
  {
11
14
  "insertOne": {
12
15
  "document": {
13
16
  "foo": "Foo2",
14
17
  "bar": "Bar2",
15
- "yack": { "yack": "yack2", "shmack": 2 },
18
+ "yack": { "yack": "yack2", "shmack": 2 }
16
19
  }
17
- },
20
+ }
18
21
  },
19
22
  {
20
23
  "updateOne": {
@@ -36,10 +39,10 @@ Eg:
36
39
  "update": {
37
40
  "foo": "Foo3",
38
41
  "bar": "Bar3",
39
- "yack": { "yack": "yack3", "shmack": 3 },
42
+ "yack": { "yack": "yack3", "shmack": 3 }
40
43
  },
41
44
  "upsert": true
42
- },
45
+ }
43
46
  }
44
- ];
45
- ```
47
+ ]
48
+ ```
package/docs/caching.md CHANGED
@@ -1,13 +1,30 @@
1
1
  # Caching
2
2
 
3
- Enable caching to speed up your queries. Caching is disabled by default. Enable caching through the config:
4
-
5
- ```JSON
6
- {
7
- "cache": {
8
- "enabled": true,
9
- "debug": false,
10
- "ttl": 3600
11
- }
12
- }
13
- ```
3
+ Enable caching to speed up repeated GET requests. Caching is disabled by default. Enable via environment variables (or pass `cache` in the object to `JXP()`):
4
+
5
+ ```
6
+ CACHE_ENABLED=true
7
+ CACHE_DEBUG=false
8
+ CACHE_TTL=3600
9
+ ```
10
+
11
+ ## How it works
12
+
13
+ JXP uses an in-process [node-cache](https://www.npmjs.com/package/node-cache) store (not Memcached or Redis). When caching is enabled:
14
+
15
+ - Successful GET responses for list and single-item routes may be stored under a key derived from the model name, item id, and query string.
16
+ - Response headers include:
17
+ - `jxp-cache`: `hit` or `miss`
18
+ - `jxp-cache-key`: the cache key used for that request
19
+ - POST, PUT, and DELETE operations clear cached keys for the affected model.
20
+
21
+ Set `CACHE_DEBUG=true` to log cache expiry and flush events to the console.
22
+
23
+ ## Admin endpoints
24
+
25
+ Requires **admin** authentication (same as other admin-only routes):
26
+
27
+ - `GET /cache/stats` — returns node-cache statistics when caching is enabled, or `{ "cache_enabled": false }` when disabled
28
+ - `GET /cache/clear` — flushes all cached entries
29
+
30
+ See also [Configuration](configuration.md#cache).