@stonyx/orm 0.3.2-alpha.82 → 0.3.2-alpha.84
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 +95 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -967,11 +967,29 @@ per-record filter. An input you cannot identify must **deny**.
|
|
|
967
967
|
([#232](https://github.com/abofs/stonyx-orm/issues/232)). This is
|
|
968
968
|
**membership**: the related resource is the route's *primary* data, so the
|
|
969
969
|
filter decides whether it is served at all, not merely which ids a document
|
|
970
|
-
may name. A denied `hasMany` member is **dropped from the array**
|
|
971
|
-
|
|
972
|
-
|
|
970
|
+
may name. A denied `hasMany` member is **dropped from the array** and nothing
|
|
971
|
+
in the relationship marks the drop: `links` intact, no `errors` member, same
|
|
972
|
+
status, and an array of survivors shaped exactly like one from a parent that
|
|
973
|
+
only ever had those members. A denied `belongsTo` target answers **`200` with
|
|
973
974
|
`data: null`**, byte-identical to a target that is genuinely absent, for the
|
|
974
|
-
same reason.
|
|
975
|
+
same reason.
|
|
976
|
+
|
|
977
|
+
**That is a claim about the relationship, not about the document, and the gap
|
|
978
|
+
is measurable in this repo's own fixture.** `owner` declares a computed
|
|
979
|
+
`totalPets` returning `this.pets.length`, which reads the **store** and is
|
|
980
|
+
never filtered. Measured on this branch, unauthenticated, at zero query
|
|
981
|
+
parameters: `GET /owners/gina` answers `attributes.totalPets: 5` while its
|
|
982
|
+
`relationships.pets.data` names **four** ids, and both relationship routes
|
|
983
|
+
serve the same four. The relationship discloses nothing; the document it
|
|
984
|
+
arrives in discloses that exactly one child was withheld. Do not read
|
|
985
|
+
"indistinguishable" as a property of the response — it is a property of the
|
|
986
|
+
relationship member alone. The other channels in the same class are
|
|
987
|
+
[#245](https://github.com/abofs/stonyx-orm/issues/245) (computed attributes,
|
|
988
|
+
which is the one measured above),
|
|
989
|
+
[#233](https://github.com/abofs/stonyx-orm/issues/233) (`included`
|
|
990
|
+
membership) and [#246](https://github.com/abofs/stonyx-orm/issues/246) (the
|
|
991
|
+
absence of `attributes.<fk>` on a `POST` response), all open. **Audit your
|
|
992
|
+
computed properties before you treat a dropped member as unobservable.** Nothing on either family errors and no status changes — the
|
|
975
993
|
status on these routes belongs to the **parent**, and `data` carries the
|
|
976
994
|
answer about the related record. The `/relationships/` family built its `{type, id}` by
|
|
977
995
|
hand rather than through `toJSON()`, which is why the linkage filter shipped in
|
|
@@ -1468,10 +1486,31 @@ they are recorded here.
|
|
|
1468
1486
|
return 404. Only affects function-style `access` users, for whom the old
|
|
1469
1487
|
behaviour was the bypass.
|
|
1470
1488
|
|
|
1471
|
-
"Seven surfaces" means the seven endpoints of **the filtered model
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
is
|
|
1489
|
+
"Seven surfaces" means the seven endpoints of **the filtered model** —
|
|
1490
|
+
`GET /:models`, `GET /:models/:id`, `GET /:models/:id/{relationship}`,
|
|
1491
|
+
`GET /:models/:id/relationships/{relationship}`, `POST /:models`,
|
|
1492
|
+
`PATCH /:models/:id` and `DELETE /:models/:id`. That count is still seven and
|
|
1493
|
+
is still the model's own endpoints, but **it is no longer the whole
|
|
1494
|
+
population**: the boundary moved outward rather than the number changing, and
|
|
1495
|
+
this sentence used to be read as saying a filtered model's predicate is
|
|
1496
|
+
consulted nowhere else. It now is, in two further places, both from
|
|
1497
|
+
*another* model's routes —
|
|
1498
|
+
|
|
1499
|
+
- on **both relationship route families**, where the related record is the
|
|
1500
|
+
primary data and the filtered model's own class decides whether it is
|
|
1501
|
+
served at all (breaking change 9 below,
|
|
1502
|
+
[#232](https://github.com/abofs/stonyx-orm/issues/232)); and
|
|
1503
|
+
- on the `relationships.*.data` **linkage** of every request-bound surface
|
|
1504
|
+
that serializes a record through `toJSON()`
|
|
1505
|
+
([#234](https://github.com/abofs/stonyx-orm/issues/234),
|
|
1506
|
+
[#235](https://github.com/abofs/stonyx-orm/issues/235)), which decides
|
|
1507
|
+
which ids another model's document may name.
|
|
1508
|
+
|
|
1509
|
+
A **write** to another collection can still reach one of its records through
|
|
1510
|
+
a relationship — [#207](https://github.com/abofs/stonyx-orm/issues/207),
|
|
1511
|
+
which is **not** closed here. That is the half of the old sentence that
|
|
1512
|
+
survives, and it is a read/write asymmetry now rather than a blanket
|
|
1513
|
+
statement about cross-model reach.
|
|
1475
1514
|
5. **A predicate that throws is treated as a denial** rather than propagating to
|
|
1476
1515
|
Express's default 500 handler. So is an `access()` that throws.
|
|
1477
1516
|
6. **`access()` returning a bare string is one permission, not full access.**
|
|
@@ -1546,6 +1585,54 @@ they are recorded here.
|
|
|
1546
1585
|
`stonyx/log`. Previously this case threw out of the handler and express
|
|
1547
1586
|
answered `500` with a stack trace.
|
|
1548
1587
|
|
|
1588
|
+
9. **Both relationship route families now resolve the *related* model's own
|
|
1589
|
+
access class, so a related record that is hidden on its own routes is no
|
|
1590
|
+
longer served through another model's.**
|
|
1591
|
+
[#232](https://github.com/abofs/stonyx-orm/issues/232). Affects
|
|
1592
|
+
function-style `access` users with relationships between filtered models. The
|
|
1593
|
+
old behaviour was a bypass at **zero query parameters** and with no
|
|
1594
|
+
`include=`: measured on `dev @ 8dda5d6`, `GET /animals/1/owner` returned
|
|
1595
|
+
angela's full document and `GET /animals/1/relationships/owner` returned
|
|
1596
|
+
`{"type":"owner","id":"angela"}`, while `GET /owners/angela` answered `404`.
|
|
1597
|
+
The severe case is a model claimed by **no** access class — `getAccess()`
|
|
1598
|
+
returns `undefined`, no route is mounted for it at all, and it was still
|
|
1599
|
+
readable as a related resource.
|
|
1600
|
+
|
|
1601
|
+
**The shapes, on both families.** A denied `hasMany` member is **dropped from
|
|
1602
|
+
the array**: `200`, `links` intact, no `errors` member. A denied `belongsTo`
|
|
1603
|
+
target answers **`200` with `data: null`**, byte-identical to a target that
|
|
1604
|
+
genuinely does not exist — same status, same bytes modulo the parent id the
|
|
1605
|
+
caller put in the URL. `404` on these routes is now reserved for the
|
|
1606
|
+
**parent**.
|
|
1607
|
+
|
|
1608
|
+
**`data: null` and not `404`, deliberately.** The 404 spelling was an
|
|
1609
|
+
existence oracle and was measured as one on this branch: unauthenticated, no
|
|
1610
|
+
query string, one request each, against `tag` — the model with no route
|
|
1611
|
+
mounted at all — `GET /traits/1/tag` (absent) answered `200`
|
|
1612
|
+
`application/json` at 68 bytes while `GET /traits/2/tag` (denied) answered
|
|
1613
|
+
`404` `text/plain` at 9 bytes, and the document surface reported both as
|
|
1614
|
+
`{"data":null}`. It also brings these two routes into line with this module's
|
|
1615
|
+
rule that every status on a record route is identical for filtered-out and
|
|
1616
|
+
does-not-exist (see [Filter functions](#filter-functions)), which the `404`
|
|
1617
|
+
spelling was the one exception to.
|
|
1618
|
+
|
|
1619
|
+
**What to check before you upgrade.** If a consumer reaches a related record
|
|
1620
|
+
through `GET /:models/:id/{relationship}` that it cannot reach on that
|
|
1621
|
+
record's own collection route, it was relying on the bypass and will now get
|
|
1622
|
+
`data: null` or a shorter array. And the related model's class is resolved
|
|
1623
|
+
through the same `Orm.instance.getAccess` path as the linkage filter, so it
|
|
1624
|
+
inherits the same arity limit: a **single-argument** predicate answers about
|
|
1625
|
+
the collection the request was *addressed to*, not the one it was asked
|
|
1626
|
+
about, and that is the direction that **grants**. See
|
|
1627
|
+
[Known limitations](#known-limitations) and
|
|
1628
|
+
[#221](https://github.com/abofs/stonyx-orm/issues/221).
|
|
1629
|
+
|
|
1630
|
+
**Not closed here:** whether a related resource appears in `included` at all
|
|
1631
|
+
([#233](https://github.com/abofs/stonyx-orm/issues/233)), and the
|
|
1632
|
+
re-parenting write ([#207](https://github.com/abofs/stonyx-orm/issues/207)).
|
|
1633
|
+
A **per-record** deny for a related resource is not expressible on these
|
|
1634
|
+
routes at all — see [Consumer Contracts](#consumer-contracts).
|
|
1635
|
+
|
|
1549
1636
|
### Include Parameter (Sideloading Relationships)
|
|
1550
1637
|
|
|
1551
1638
|
The ORM supports JSON API-compliant relationship sideloading via the `include` query parameter. This reduces the need for multiple API requests by embedding related records in a single response.
|