@stonyx/orm 0.3.2-alpha.93 → 0.3.2-alpha.94
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 +35 -3
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -318,16 +318,48 @@ await setupRestServer('/', './access');
|
|
|
318
318
|
Access classes define models and provide custom filtering/authorization logic:
|
|
319
319
|
|
|
320
320
|
```js
|
|
321
|
-
export default class
|
|
322
|
-
models = ['owner'
|
|
321
|
+
export default class OwnerAccess {
|
|
322
|
+
models = ['owner'];
|
|
323
323
|
|
|
324
324
|
access(request) {
|
|
325
|
-
|
|
325
|
+
// `access` runs after route matching, so `request.params` is populated and
|
|
326
|
+
// `id` has already been URL-decoded. Authorize on it.
|
|
327
|
+
const { id } = request.params;
|
|
328
|
+
|
|
329
|
+
// Returning false explicitly denies access to this record
|
|
330
|
+
if (id === 'angela') return false;
|
|
331
|
+
|
|
332
|
+
// No `id` means the collection route. Returning a function plugs it in to
|
|
333
|
+
// the response object as a filter
|
|
334
|
+
if (id === undefined) return record => record.id !== 'angela';
|
|
335
|
+
|
|
336
|
+
// Returning a list of operations allows full access to everything else
|
|
326
337
|
return ['read', 'create', 'update', 'delete'];
|
|
327
338
|
}
|
|
328
339
|
}
|
|
329
340
|
```
|
|
330
341
|
|
|
342
|
+
**Do not authorize on the request URL.** `request.url` is rewritten relative to
|
|
343
|
+
the mount point, so inside the REST server it is `/angela`, not `/owners/angela`
|
|
344
|
+
— a suffix comparison against it never matches and the request falls through to
|
|
345
|
+
whatever the method returns next. `request.originalUrl` keeps the full path but
|
|
346
|
+
is still the raw text the client sent, so it varies with query strings
|
|
347
|
+
(`/owners?x=1`), trailing slashes (`/owners/angela/`), casing (`/OwNeRs/angela`,
|
|
348
|
+
which Express routes to the same handler) and percent-encoding
|
|
349
|
+
(`/owners/%61ngela`). Each of those is a plain address-bar request, and each one
|
|
350
|
+
slips past a URL predicate. `request.params.id` is identical for all of them.
|
|
351
|
+
|
|
352
|
+
**One access class per model when the rules are model-specific.** `access()`
|
|
353
|
+
receives only the request, and the request does not carry the model name in any
|
|
354
|
+
form that is safe to match on — `request.baseUrl` is the mount text as the
|
|
355
|
+
client spelled it (`/OWNERS`), not the model. A class may still list several
|
|
356
|
+
models in `models` when they share one rule.
|
|
357
|
+
|
|
358
|
+
The sample above is executed verbatim against a live server by
|
|
359
|
+
`test/integration/readme-access/`, which reads it out of this file: the request
|
|
360
|
+
`DELETE /owners/angela` is asserted to return 403 with the record intact, along
|
|
361
|
+
with each of the spellings named above.
|
|
362
|
+
|
|
331
363
|
### Upgrading: behaviour changes
|
|
332
364
|
|
|
333
365
|
**Advertised `links.self` / `links.related` now carry the REST mount route.**
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"stonyx-async",
|
|
5
5
|
"stonyx-module"
|
|
6
6
|
],
|
|
7
|
-
"version": "0.3.2-alpha.
|
|
7
|
+
"version": "0.3.2-alpha.94",
|
|
8
8
|
"description": "",
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"type": "module",
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
},
|
|
62
62
|
"homepage": "https://github.com/abofs/stonyx-orm#readme",
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@stonyx/cron": "0.2.1-beta.
|
|
65
|
-
"@stonyx/events": "0.1.1-beta.
|
|
64
|
+
"@stonyx/cron": "0.2.1-beta.98",
|
|
65
|
+
"@stonyx/events": "0.1.1-beta.54",
|
|
66
66
|
"@stonyx/utils": "0.2.3-beta.26",
|
|
67
67
|
"stonyx": "0.2.3-beta.81"
|
|
68
68
|
},
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
}
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
|
-
"@stonyx/rest-server": "0.2.1-beta.
|
|
94
|
+
"@stonyx/rest-server": "0.2.1-beta.100",
|
|
95
95
|
"@types/node": "^25.6.0",
|
|
96
96
|
"mysql2": "^3.20.0",
|
|
97
97
|
"pg": "^8.20.0",
|
|
@@ -103,8 +103,10 @@
|
|
|
103
103
|
"scripts": {
|
|
104
104
|
"build": "tsc",
|
|
105
105
|
"build:test": "tsc -p tsconfig.test.json",
|
|
106
|
-
"test": "pnpm build && NODE_ENV=test node --import tsx/esm --import ./test/setup.ts node_modules/qunit/bin/qunit.js 'test/**/*-test.ts' && ORM_TEST_ROUTE=/ pnpm test:mounted && ORM_TEST_ROUTE=/api pnpm test:mounted && ORM_TEST_ROUTE=api pnpm test:mounted && ORM_TEST_ROUTE=/api/v1 pnpm test:mounted && ORM_TEST_ROUTE=/api/ pnpm test:mounted",
|
|
106
|
+
"test": "pnpm build && NODE_ENV=test node --import tsx/esm --import ./test/setup.ts node_modules/qunit/bin/qunit.js 'test/**/*-test.ts' && ORM_TEST_ROUTE=/ pnpm test:mounted && ORM_TEST_ROUTE=/api pnpm test:mounted && ORM_TEST_ROUTE=api pnpm test:mounted && ORM_TEST_ROUTE=/api/v1 pnpm test:mounted && ORM_TEST_ROUTE=/api/ pnpm test:mounted && pnpm test:readme && pnpm test:reference",
|
|
107
107
|
"test:mounted": "node --import tsx/esm --import ./test/integration/mounted-route/setup.ts node_modules/qunit/bin/qunit.js 'test/integration/mounted-route/links-mounted.ts' 'test/zz-exit-test.ts'",
|
|
108
|
+
"test:readme": "node --import tsx/esm --import ./test/integration/readme-access/setup.ts node_modules/qunit/bin/qunit.js 'test/integration/readme-access/readme-sample.ts' 'test/zz-exit-test.ts'",
|
|
109
|
+
"test:reference": "node --import tsx/esm --import ./test/integration/reference-access/setup.ts node_modules/qunit/bin/qunit.js 'test/integration/reference-access/reference-sample.ts' 'test/zz-exit-test.ts'",
|
|
108
110
|
"test:dynamodb": "pnpm build && node --import tsx/esm --import ./test/integration/dynamodb/setup.ts node_modules/qunit/bin/qunit.js 'test/integration/dynamodb/**/*-test.ts'"
|
|
109
111
|
}
|
|
110
112
|
}
|