@stonyx/orm 0.3.2-beta.16 → 0.3.2-beta.160
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1409 -11
- package/config/environment.js +99 -12
- package/dist/access-verdict.d.ts +85 -0
- package/dist/access-verdict.js +284 -0
- package/dist/commands.js +34 -0
- package/dist/dynamodb/connection.d.ts +31 -0
- package/dist/dynamodb/connection.js +28 -0
- package/dist/dynamodb/dynamodb-db.d.ts +142 -0
- package/dist/dynamodb/dynamodb-db.js +596 -0
- package/dist/dynamodb/operation-builder.d.ts +76 -0
- package/dist/dynamodb/operation-builder.js +116 -0
- package/dist/dynamodb/type-map.d.ts +31 -0
- package/dist/dynamodb/type-map.js +48 -0
- package/dist/hooks.d.ts +15 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +8 -0
- package/dist/main.d.ts +116 -0
- package/dist/main.js +129 -0
- package/dist/manage-record.js +268 -12
- package/dist/mysql/connection.d.ts +1 -0
- package/dist/mysql/mysql-db.d.ts +8 -0
- package/dist/mysql/mysql-db.js +44 -10
- package/dist/orm-request.d.ts +274 -3
- package/dist/orm-request.js +1259 -65
- package/dist/postgres/connection.d.ts +1 -0
- package/dist/postgres/connection.js +8 -6
- package/dist/postgres/postgres-db.d.ts +8 -0
- package/dist/postgres/postgres-db.js +44 -10
- package/dist/record.d.ts +16 -0
- package/dist/record.js +154 -6
- package/dist/relationships.js +1 -1
- package/dist/serializer.js +38 -2
- package/dist/setup-rest-server.js +51 -5
- package/dist/standalone-db.js +17 -5
- package/dist/store.d.ts +13 -1
- package/dist/store.js +65 -6
- package/dist/types/orm-types.d.ts +260 -0
- package/dist/utils.d.ts +44 -0
- package/dist/utils.js +47 -0
- package/package.json +16 -7
- package/src/access-verdict.ts +312 -0
- package/src/commands.ts +43 -0
- package/src/dynamodb/connection.ts +50 -0
- package/src/dynamodb/dynamodb-db.ts +811 -0
- package/src/dynamodb/operation-builder.ts +202 -0
- package/src/dynamodb/type-map.ts +54 -0
- package/src/hooks.ts +15 -1
- package/src/index.ts +10 -0
- package/src/main.ts +133 -0
- package/src/manage-record.ts +294 -18
- package/src/mysql/connection.ts +1 -0
- package/src/mysql/mysql-db.ts +44 -12
- package/src/orm-request.ts +1281 -67
- package/src/postgres/connection.ts +10 -6
- package/src/postgres/postgres-db.ts +44 -12
- package/src/record.ts +182 -6
- package/src/relationships.ts +1 -1
- package/src/serializer.ts +39 -2
- package/src/setup-rest-server.ts +59 -6
- package/src/standalone-db.ts +17 -6
- package/src/store.ts +68 -6
- package/src/types/orm-types.ts +268 -1
- package/src/types/stonyx-rest-server.d.ts +14 -1
- package/src/types/stonyx.d.ts +7 -1
- package/src/utils.ts +50 -0
- package/config/environment.ts +0 -91
package/dist/orm-request.d.ts
CHANGED
|
@@ -1,4 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST request handling and access enforcement for @stonyx/orm.
|
|
3
|
+
*
|
|
4
|
+
* ---------------------------------------------------------------------------
|
|
5
|
+
* THE `access()` CONTRACT: `access(request, { model, operation })`
|
|
6
|
+
* ---------------------------------------------------------------------------
|
|
7
|
+
* `auth()` calls your predicate with TWO arguments. The second is the access
|
|
8
|
+
* CONTEXT -- the structural facts about the request, which the framework
|
|
9
|
+
* already holds and which you should read INSTEAD of parsing anything:
|
|
10
|
+
*
|
|
11
|
+
* context.model The model this route was mounted for, as a model name:
|
|
12
|
+
* kebab-case, exactly as declared under
|
|
13
|
+
* `config.orm.paths.model` and keyed in the store --
|
|
14
|
+
* `'owner'`, `'animal'`, `'phone-number'`. NOT the
|
|
15
|
+
* pluralised, dasherized, mount-prefixed ROUTE name. It is
|
|
16
|
+
* read from the OrmRequest instance, fixed at mount time,
|
|
17
|
+
* and no request can influence it.
|
|
18
|
+
*
|
|
19
|
+
* context.operation The operation being authorised. Exactly one of the four
|
|
20
|
+
* verbs `'read'`, `'create'`, `'update'`, `'delete'` --
|
|
21
|
+
* no second vocabulary ON THIS PATH, and never an HTTP
|
|
22
|
+
* method name like `'GET'`. These are the same four
|
|
23
|
+
* strings the permission-array return shape is written in
|
|
24
|
+
* (`['read', 'create']`), because both come from the one
|
|
25
|
+
* `methodAccessMap` below.
|
|
26
|
+
*
|
|
27
|
+
* NOT the hook vocabulary. `HookContext.operation`
|
|
28
|
+
* (`src/hooks.ts`, documented under "Hook Context Object"
|
|
29
|
+
* in the README) carries `'list' | 'get' | 'create' |
|
|
30
|
+
* 'update' | 'delete'` on an identically-named key of an
|
|
31
|
+
* identically-shaped context object, and the access
|
|
32
|
+
* vocabulary collapses `list` and `get` into `'read'`. For
|
|
33
|
+
* one `GET /animals/1` a hook sees `'get'` and `access()`
|
|
34
|
+
* sees `'read'`, so a predicate cannot tell a collection
|
|
35
|
+
* read from a record read. `AccessOperation` makes
|
|
36
|
+
* `operation === 'get'` a compile error for a TypeScript
|
|
37
|
+
* consumer, because a predicate that stops matching falls
|
|
38
|
+
* through to the permission array -- the misreading is
|
|
39
|
+
* fail-open shaped.
|
|
40
|
+
*
|
|
41
|
+
* `undefined` when the dispatched method has no entry in
|
|
42
|
+
* that map. Express delivers `HEAD` to the `GET` handler,
|
|
43
|
+
* so this is reachable. It is left undefined rather than
|
|
44
|
+
* defaulted on purpose -- a fabricated `'read'` would turn
|
|
45
|
+
* an unclassified request into an authorised one. Treat
|
|
46
|
+
* `undefined` as "not classified" and deny.
|
|
47
|
+
*
|
|
48
|
+
* So a consumer writes `if (model === 'owner' && operation === 'read')`. There
|
|
49
|
+
* is no string to parse, no variant to miss, and no way to fail open through a
|
|
50
|
+
* URL shape nobody anticipated.
|
|
51
|
+
*
|
|
52
|
+
* WHAT THE CONTEXT DOES NOT TELL YOU: WHICH SURFACE. It names the model and
|
|
53
|
+
* the verb, not the route. Measured over the live router, six surfaces produce
|
|
54
|
+
* one identical context:
|
|
55
|
+
*
|
|
56
|
+
* GET /owners { model: 'owner', operation: 'read' }
|
|
57
|
+
* GET /owners/gina { model: 'owner', operation: 'read' }
|
|
58
|
+
* GET /owners/gina/pets { model: 'owner', operation: 'read' }
|
|
59
|
+
* GET /owners/gina/relationships/pets { model: 'owner', operation: 'read' }
|
|
60
|
+
* GET /owners/archived { model: 'owner', operation: 'read' }
|
|
61
|
+
* GET /owners/gina?include=pets { model: 'owner', operation: 'read' }
|
|
62
|
+
*
|
|
63
|
+
* So a rule that depends on the SUB-PATH still needs `request.path` -- which is
|
|
64
|
+
* mount-relative and query-free, and is the one read of argument one the
|
|
65
|
+
* warning below sanctions. This repo's own fixture has such a rule: its
|
|
66
|
+
* `/archived` deny cannot be expressed from the context alone, and a predicate
|
|
67
|
+
* migrated to context-only would silently drop it, turning a deny into an
|
|
68
|
+
* allow.
|
|
69
|
+
*
|
|
70
|
+
* THE RELATED-RESOURCE HALF OF THAT SENTENCE IS NOW OUT OF DATE AND IS
|
|
71
|
+
* CORRECTED HERE RATHER THAN DELETED. Both relationship route families resolve
|
|
72
|
+
* the RELATED model's own access class and ask it
|
|
73
|
+
* `{ model: <related>, operation: 'read', recordId: null }`
|
|
74
|
+
* (abofs/stonyx-orm#232), so those surfaces no longer serve another model's
|
|
75
|
+
* records under `model: 'owner'` unexamined. What the context still gives no
|
|
76
|
+
* signal of is WHICH related record is being asked about -- `recordId` is
|
|
77
|
+
* `null` there and `request.params` names a record of a different model. See
|
|
78
|
+
* `AccessContext.recordId` in ./types/orm-types.ts for the full statement of
|
|
79
|
+
* that limit. `?include=` is still unfiltered and is abofs/stonyx-orm#233 /
|
|
80
|
+
* #235.
|
|
81
|
+
*
|
|
82
|
+
* SUPERSEDED 2026-09-01 BY abofs/stonyx-orm#236/#237, AND KEPT FOR THE
|
|
83
|
+
* CONSTRAINT IT STATES RATHER THAN AS A DESCRIPTION OF THE CODE. The context
|
|
84
|
+
* now also carries `recordId` -- the DECODED route-parameter id, see
|
|
85
|
+
* `AccessContext.recordId` in ./types/orm-types.ts -- so the fixture's
|
|
86
|
+
* `/archived` deny IS expressible from the context alone, and the shipped
|
|
87
|
+
* sample no longer reads `request.path` at all. Retiring this wording WITH the
|
|
88
|
+
* measurement that retires it, rather than by deletion, is
|
|
89
|
+
* abofs/stonyx-orm#238.
|
|
90
|
+
*
|
|
91
|
+
* `record` IS NOT IN THIS CONTEXT, deliberately. `auth()` runs after route
|
|
92
|
+
* matching but BEFORE any handler executes (`@stonyx/rest-server`
|
|
93
|
+
* `src/request.ts:58-60`), so nothing has been fetched yet -- supplying a
|
|
94
|
+
* record would force a pre-fetch on every request, a second store hit and an
|
|
95
|
+
* ordering change in the middle of an authorization path. It is also
|
|
96
|
+
* unnecessary: the FUNCTION return shape already is the per-record hook. Return
|
|
97
|
+
* `(record) => boolean` and the handlers apply it to every record the request
|
|
98
|
+
* touches. Auth-time and record-time are separate decision points.
|
|
99
|
+
*
|
|
100
|
+
* THE SECOND ARGUMENT IS ADDITIVE. JavaScript ignores extra arguments, so an
|
|
101
|
+
* existing `access(request)` predicate keeps working exactly as before. The
|
|
102
|
+
* warning immediately below is therefore still live: `request` is still
|
|
103
|
+
* argument ONE, and reading it is still how predicates fail open.
|
|
104
|
+
*
|
|
105
|
+
* To reach ANOTHER model's predicate -- e.g. to check an animal while servicing
|
|
106
|
+
* an owners route -- use the boot-time registry:
|
|
107
|
+
*
|
|
108
|
+
* const predicate = Orm.instance.getAccess('animal');
|
|
109
|
+
* if (!predicate) return deny;
|
|
110
|
+
* const verdict = predicate(request, { model: 'animal', operation: 'read' });
|
|
111
|
+
*
|
|
112
|
+
* `undefined` means NO PREDICATE COULD BE RESOLVED for that name -- which
|
|
113
|
+
* includes the case where the model has an access class that failed to load,
|
|
114
|
+
* because `setup-rest-server.ts` catches a load failure, warns, and publishes
|
|
115
|
+
* whatever partial map it had. It does NOT mean the model is unrestricted.
|
|
116
|
+
* Treat it as DENY, the same way `operation === undefined` is treated above.
|
|
117
|
+
*
|
|
118
|
+
* PASSING THE CONTEXT MAKES A MODEL-CORRECT ANSWER POSSIBLE. It does not make
|
|
119
|
+
* the answer model-correct on its own -- the resolved predicate has to READ it.
|
|
120
|
+
* Measured against an ARITY-1 predicate, on a request express dispatched to
|
|
121
|
+
* `GET /owners/angela`, asked about ANIMALS:
|
|
122
|
+
*
|
|
123
|
+
* getAccess('animal')(ownersRequest, { model: 'animal', operation: 'read' })
|
|
124
|
+
* -> record => record.id !== 'angela' && record.id !== 'restricted'
|
|
125
|
+
*
|
|
126
|
+
* That is the OWNERS filter, and it returns `true` for animal 21 -- the record
|
|
127
|
+
* hidden on every animal surface. Under a mount that predicate recognises
|
|
128
|
+
* neither way it is worse: it falls through to
|
|
129
|
+
* `['read', 'create', 'update', 'delete']`, a full CRUD grant. Either way the
|
|
130
|
+
* context was supplied and the answer is not the animal answer, and it is wrong
|
|
131
|
+
* in the GRANTING direction, because that predicate is arity-1 and identifies
|
|
132
|
+
* its collection from the request. (Asserted on a live dispatch by AC9 in
|
|
133
|
+
* test/integration/orm-test.ts, against a deliberately arity-1 predicate.)
|
|
134
|
+
*
|
|
135
|
+
* This repo's own sample access class has since been MIGRATED to read the
|
|
136
|
+
* context (abofs/stonyx-orm#222), so `getAccess('animal')` here now answers
|
|
137
|
+
* with the animal filter. That is not true of a consumer tree: an arity-1
|
|
138
|
+
* predicate keeps working -- the second argument is additive -- and the caller
|
|
139
|
+
* has no supported way to tell which kind it got. The boot-time arity warning
|
|
140
|
+
* that surfaces one is abofs/stonyx-orm#221.
|
|
141
|
+
* So: pass the context, and do not treat a resolved predicate's answer as
|
|
142
|
+
* model-specific until that predicate has been migrated to read the context.
|
|
143
|
+
*
|
|
144
|
+
* ---------------------------------------------------------------------------
|
|
145
|
+
* DO NOT RECONSTRUCT THE REQUEST PATH INSIDE `access()`.
|
|
146
|
+
* ---------------------------------------------------------------------------
|
|
147
|
+
* You do not have to. `auth()` below hands your predicate the ACCESS CONTEXT as
|
|
148
|
+
* argument two, and `context.model` already names the collection -- see the
|
|
149
|
+
* contract section above. Argument ONE is still the raw transport artifact, and
|
|
150
|
+
* everything from here to the end of this banner is the record of what happened
|
|
151
|
+
* when predicates worked the collection out from it. IT IS HISTORY, NOT
|
|
152
|
+
* GUIDANCE: do not write any of it into a new predicate. Every attempt to
|
|
153
|
+
* identify the collection by parsing the request target has failed OPEN. Five
|
|
154
|
+
* distinct variants of the same three-line example have now been found, each
|
|
155
|
+
* after the previous was fixed, by five different people:
|
|
156
|
+
*
|
|
157
|
+
* 1. `request.url` is mount-relative under `RestServer.mountRoute`, so a
|
|
158
|
+
* prefix match against it is ALWAYS false.
|
|
159
|
+
* 2. `request.originalUrl` carries the query string, so an anchored equality
|
|
160
|
+
* check misses `/owners?filter[age]=30`.
|
|
161
|
+
* 3. The router is a bare `express()` (`caseSensitive: false`) while a
|
|
162
|
+
* hand-written matcher is case-SENSITIVE, so `GET /OwNeRs/angela` walks
|
|
163
|
+
* past it. Router-side: abofs/stonyx-rest-server#47.
|
|
164
|
+
* 4. Under a configured `ORM_REST_ROUTE` a hard-coded `/owners` matches
|
|
165
|
+
* nothing -- environment-specifically, which is worse.
|
|
166
|
+
* 5. HTTP/1.1 permits an ABSOLUTE-FORM request-target. Express routes on
|
|
167
|
+
* `parseurl(req).pathname`, but `originalUrl` is the raw target, so
|
|
168
|
+
* `GET http://anything.example/owners/angela` reaches the handler with
|
|
169
|
+
* `originalUrl === 'http://anything.example/owners/angela'`. A `/owners`
|
|
170
|
+
* prefix match is false, `access()` falls through to whatever it returns
|
|
171
|
+
* last, and the record comes back in full. It walks past a hard
|
|
172
|
+
* `return false` deny the same way.
|
|
173
|
+
*
|
|
174
|
+
* The fix is not a sixth rule, and it is not a better string to match. It is to
|
|
175
|
+
* stop identifying the collection at all: read `context.model`. That is a claim
|
|
176
|
+
* about IDENTIFYING THE COLLECTION, not about the sample as a whole -- the
|
|
177
|
+
* `/archived` SUB-PATH rule is still a string match, and abofs/stonyx-orm#228 is
|
|
178
|
+
* a sixth spelling that gets past it.
|
|
179
|
+
*
|
|
180
|
+
* SUPERSEDED 2026-09-01 BY abofs/stonyx-orm#236/#237: the `/archived` rule is
|
|
181
|
+
* no longer a string match against the request target -- it compares the
|
|
182
|
+
* decoded `recordId` the framework supplies -- and abofs/stonyx-orm#228 is
|
|
183
|
+
* CLOSED. Retirement of this wording: abofs/stonyx-orm#238.
|
|
184
|
+
*
|
|
185
|
+
* An intermediate revision of the sample read `request.baseUrl` -- the mount
|
|
186
|
+
* Express ACTUALLY MATCHED. That closed all five variants (no query string,
|
|
187
|
+
* not mount-relative, unaffected by absolute-form, already carrying the
|
|
188
|
+
* configured `ORM_REST_ROUTE` prefix), but it was a transport artifact
|
|
189
|
+
* standing in for a structural fact and the sample no longer does it.
|
|
190
|
+
* `context.model` IS the structural fact, so variants 1, 2, 4 and 5 are
|
|
191
|
+
* unconstructible against a migrated predicate rather than handled.
|
|
192
|
+
*
|
|
193
|
+
* VARIANT 3 SURVIVES, and is deliberately not in that list. It is the general
|
|
194
|
+
* shape "a hand-written matcher normalises differently from the router", and a
|
|
195
|
+
* migrated predicate still runs one string comparison for any SUB-PATH rule --
|
|
196
|
+
* in the shipped sample, the `/archived` deny. That comparison folds case but
|
|
197
|
+
* does not decode, so `GET /owners/%61rchived` steps past it. See the
|
|
198
|
+
* normalisation paragraph below and abofs/stonyx-orm#228.
|
|
199
|
+
*
|
|
200
|
+
* SUPERSEDED 2026-09-01 BY abofs/stonyx-orm#236/#237. Variant 3 lived in that
|
|
201
|
+
* one string comparison, and the comparison is gone: the sample compares the
|
|
202
|
+
* decoded `recordId`. Left standing rather than edited because the same
|
|
203
|
+
* "variant 3 survives" wording sits at four sites -- this header, README.md
|
|
204
|
+
* twice, and test/sample/access/global-access.ts -- three of which SHIP, so
|
|
205
|
+
* retiring one of four leaves the shipped copies contradicting each other.
|
|
206
|
+
* Retiring all four WITH their measurement is abofs/stonyx-orm#238.
|
|
207
|
+
*
|
|
208
|
+
* ONE READ OF ARGUMENT ONE SURVIVES, AND IT MUST: `request.path`. It is
|
|
209
|
+
* mount-relative and query-free, and it is for rules that distinguish SUB-PATHS
|
|
210
|
+
* beneath the mount. The context names which model and which verb, NOT which
|
|
211
|
+
* route, so the sample's `/archived` deny cannot be expressed from the context
|
|
212
|
+
* alone and a context-ONLY rewrite would silently turn that deny into an allow.
|
|
213
|
+
*
|
|
214
|
+
* SUPERSEDED 2026-09-01 BY abofs/stonyx-orm#236/#237: NO read of argument one
|
|
215
|
+
* survives in the shipped sample. `recordId` names WHICH RECORD the route was
|
|
216
|
+
* addressed to, so the `/archived` deny is expressible from the context alone
|
|
217
|
+
* -- and it still must not be dropped; expressible is not optional. Retirement
|
|
218
|
+
* of this wording: abofs/stonyx-orm#238.
|
|
219
|
+
*
|
|
220
|
+
* NORMALISE THE WAY THE ROUTER DOES, AND CASE-FOLDING ALONE IS NOT THAT. The
|
|
221
|
+
* sample lower-cases before comparing, because a matcher stricter than the
|
|
222
|
+
* case-insensitive router can be stepped around. That closes the case gap only.
|
|
223
|
+
* Express sets `request.path` from the RAW, UNDECODED pathname while the router
|
|
224
|
+
* DECODES `:id`, so `GET /owners/%61rchived` reaches a `path === '/archived'`
|
|
225
|
+
* comparison as `/%61rchived` and walks past the deny. That gap is live in the
|
|
226
|
+
* sample and is tracked as abofs/stonyx-orm#228; the `.toLowerCase()` is not a
|
|
227
|
+
* complete normalisation recipe. Compare record ids at their real case.
|
|
228
|
+
*
|
|
229
|
+
* DO NOT FOLLOW THE PARAGRAPH ABOVE. SUPERSEDED 2026-09-01 BY
|
|
230
|
+
* abofs/stonyx-orm#236/#237, and flagged here rather than merely dated because
|
|
231
|
+
* it is an INSTRUCTION, not a stale observation. `.toLowerCase()` on the access
|
|
232
|
+
* path was measured WRONG IN BOTH DIRECTIONS AT ONCE: with a distinct owner
|
|
233
|
+
* seeded at `ARCHIVED`, `GET /owners/ARCHIVED` was a false DENY on the wrong
|
|
234
|
+
* record and `GET /owners/%41RCHIVED` a false ALLOW on that same record. A
|
|
235
|
+
* record id is a VALUE, not a literal route segment, and express's
|
|
236
|
+
* `case sensitive routing` governs literal segments only. Compare
|
|
237
|
+
* `context.recordId` AS IT ARRIVES: do not case-fold it, do not decode it, do
|
|
238
|
+
* not derive it from `request.path`. `AccessContext.recordId` in
|
|
239
|
+
* ./types/orm-types.ts is the contract and says "Do NOT case-fold it"; the same
|
|
240
|
+
* published tarball ships both files, and THIS paragraph is the one that is
|
|
241
|
+
* wrong. Retiring it WITH its measurement is abofs/stonyx-orm#238.
|
|
242
|
+
*
|
|
243
|
+
* `?? ''` is not a defence. It converts an absent request target into an empty
|
|
244
|
+
* string, which matches no collection, which falls through to the permission
|
|
245
|
+
* array -- a total grant. An input you cannot identify must DENY, and that
|
|
246
|
+
* applies to BOTH arguments: since #202 the guard and the read can sit on
|
|
247
|
+
* different objects, and a guard on argument two does not protect a read of
|
|
248
|
+
* argument one. The sample returns `false` for an absent `model` AND for an
|
|
249
|
+
* absent or non-string `request.path`, rather than falling through either way.
|
|
250
|
+
*
|
|
251
|
+
* SUPERSEDED 2026-09-01 BY abofs/stonyx-orm#236/#237 as to WHAT is guarded --
|
|
252
|
+
* the principle is unchanged. The sample no longer reads `request.path`, so it
|
|
253
|
+
* returns `false` for an absent `model` AND for an absent `recordId`
|
|
254
|
+
* (`undefined`, the one spelling `auth()` never produces). Retirement of this
|
|
255
|
+
* wording: abofs/stonyx-orm#238.
|
|
256
|
+
*
|
|
257
|
+
* THE REAL FIX IS abofs/stonyx-orm#202: `access()` should receive the model,
|
|
258
|
+
* the operation and the record. Prefer the array shape (`['read']`) or `false`
|
|
259
|
+
* until #202 lands; the function shape is what requires any matching at all.
|
|
260
|
+
*
|
|
261
|
+
* The enforcement gates in this file (GATE 0/1/2, the create rollback, the
|
|
262
|
+
* per-handler `isDenied` re-checks) are correct independently of that -- they
|
|
263
|
+
* enforce whatever predicate you return. The stopgap is the part where YOU have
|
|
264
|
+
* to work out which predicate to return.
|
|
265
|
+
*
|
|
266
|
+
* AND A PREDICATE IS NOT A GUARANTEE THAT A HIDDEN RECORD CANNOT BE MODIFIED.
|
|
267
|
+
* It is evaluated against the record the route is ADDRESSED TO, on that model
|
|
268
|
+
* only. A write to a DIFFERENT collection can still re-parent a hidden record
|
|
269
|
+
* and de-hide it -- abofs/stonyx-orm#207, which is blocked on #202 and #196.
|
|
270
|
+
* See `### Known limitations` in README.
|
|
271
|
+
*/
|
|
1
272
|
import { Request } from '@stonyx/rest-server';
|
|
273
|
+
import type { AccessFunction } from './types/orm-types.js';
|
|
2
274
|
interface OrmRequest$ extends Request {
|
|
3
275
|
protocol?: string;
|
|
4
276
|
method: string;
|
|
@@ -13,13 +285,12 @@ interface OrmRequest$ extends Request {
|
|
|
13
285
|
};
|
|
14
286
|
get(header: string): string;
|
|
15
287
|
}
|
|
16
|
-
type AccessMethod = string | boolean | string[] | ((record: unknown) => boolean);
|
|
17
288
|
type HandlerFn = (request: OrmRequest$, state: {
|
|
18
289
|
[key: string]: unknown;
|
|
19
290
|
}) => unknown | Promise<unknown>;
|
|
20
291
|
export default class OrmRequest extends Request {
|
|
21
292
|
model: string;
|
|
22
|
-
access:
|
|
293
|
+
access: AccessFunction;
|
|
23
294
|
handlers: {
|
|
24
295
|
[key: string]: {
|
|
25
296
|
[key: string]: HandlerFn;
|
|
@@ -27,7 +298,7 @@ export default class OrmRequest extends Request {
|
|
|
27
298
|
};
|
|
28
299
|
constructor({ model, access }: {
|
|
29
300
|
model: string;
|
|
30
|
-
access:
|
|
301
|
+
access: AccessFunction;
|
|
31
302
|
});
|
|
32
303
|
private _withHooks;
|
|
33
304
|
private _generateRelationshipRoutes;
|