fix: le descripteur d-un membre repond ce que le lire repond
Trouve en rejouant l-adversaire sur le correctif precedent, et mesure : `Object.getOwnPropertyDescriptor(resultat, "data")` rendait la collection BRUTE, et `(..., "subscription")` le handle que `get` refuse. Cet appel ne passe pas par le piege `get` - ni l-etalement, ni `Object.entries`, ni `JSON.stringify`, ni une inspection console. Une deuxieme porte sur la meme piece, ouverte par un piege que personne n-avait ecrit. Le meme trou existait sur la vue de collection pour la trappe dunder. La forme ordonnee dit combien d-objets elle porte a QUATRE endroits : `length`, `Object.keys`, `in`, et le descripteur de chaque index. Un seul etait filtre, donc le compte de ce que le porteur ne peut pas lire ressortait par les trois autres, et le descripteur rendait les objets eux-memes. Les quatre pieges appellent maintenant une seule fonction `read`, pas trois copies de la regle : une frontiere faite de `switch` paralleles est une frontiere qui derive. Et l-index nomme une position dans ce qui est LISIBLE, donc la forme ordonnee sert son porteur au lieu de refuser.
This commit is contained in:
@@ -260,7 +260,7 @@ Where a call must first find out whether something already exists — a document
|
||||
|
||||
**TWO COPIES OF THIS PACKAGE IN ONE APPLICATION MISBEHAVE SILENTLY, and nothing here can detect it.** What this package remembers it keeps in the package itself, not in any handle you hold: which documents are subscribed and who is listening for them, which identity the session settled on, which documents are open. None of that is shared between two copies. An application that ends up with two therefore runs two of everything — a document subscribed through one copy is invisible to the other, so changes to it simply never arrive; and the identity settled in one is not the identity the other acts as, so the same call writes as one user or the other depending on which copy it reached. Nothing raises, nothing warns, and no call can report it: from every entry point a second copy is indistinguishable from the first, and the symptoms surface far from the cause as missing updates and writes attributed to the wrong person. This is a packaging property, not a behaviour to code around — **declare this package once, as one dependency of the application**, and let your own code and every library built on it resolve to that copy. A library that builds on this package should declare it a *peer* rather than a dependency for exactly this reason, so that the application remains the one place it is named.
|
||||
|
||||
**No unfiltered read through `useShape`, and no way round it through the object it hands back.** What the call returns is NextGraph's own result, filtered: `data` and `promise` carry only items in documents you hold the key for, `isLoading` and the two page commands pass through, and `subscription` - the ORM's own handle, which reads and writes with no capability filter at all - is refused out loud rather than handed on. Any other member of that object is refused too unless what is behind it is a plain scalar, which is how a member a later `@ng-org/orm` adds is decided before anyone has seen it: whatever can carry an item is an object or a function, and both refuse. Inside `data`, every member that yields items is filtered, mutations pass through, `size` and `length` count what you may read and not what is there, and an index into an ordered result is refused rather than guessed at. A document reached through that view alone, read nowhere else first, does not appear.
|
||||
**No unfiltered read through `useShape`, and no way round it through the object it hands back.** What the call returns is NextGraph's own result, filtered: `data` and `promise` carry only items in documents you hold the key for, `isLoading` and the two page commands pass through, and `subscription` - the ORM's own handle, which reads and writes with no capability filter at all - is refused out loud rather than handed on. Any other member of that object is refused too unless what is behind it is a plain scalar, which is how a member a later `@ng-org/orm` adds is decided before anyone has seen it: whatever can carry an item is an object or a function, and both refuse. Inside `data`, every member that yields items is filtered, mutations pass through, and an ordered result addresses and counts the items you may read: `size`, `length`, an index, `Object.keys`, `in` and `JSON.stringify` all agree, and none of them says how many you may not. **Reading a member's DESCRIPTOR answers exactly what reading the member answers**, which is not a detail: `Object.getOwnPropertyDescriptor` - and the spread, `Object.entries` and console inspection built on it - reads a property without going through the view's own read, so a refused member throws there too rather than handing its value over. A document reached through that view alone, read nowhere else first, does not appear.
|
||||
|
||||
**`getObjects` does not fetch a public store's key for you either**, for the same reason as the two shape reads below: it goes through the same ORM query and spends no round-trip asking. Read the document once by naming it — `docs.sparqlQuery` anchored on it — and it appears.
|
||||
|
||||
@@ -290,7 +290,8 @@ What each level means here, in this package's own terms:
|
||||
- **`subscription` is REFUSED where it used to be handed over.** It is the ORM's own `RdfOrmSubscription`, which reads and writes with no capability filter at all and which `## Non-guarantees` has always said this package does not publish. Reading it now throws, naming itself. `data`, `promise`, `isLoading` and the two page commands are what remains, and they are what a caller needs: the SDK's own example destructures `data` and `isLoading` and nothing else.
|
||||
- **A member of that object that this package does not know is refused unless it is a plain scalar.** The rule is the value's TYPE, not its name: whatever can carry an item is an object or a function, so a member the next `@ng-org/orm` adds is already decided, while a flag or a count still passes. The previous rule - "anything that is not a function is harmless" - is precisely what let three members of the new shape through, so it has been replaced rather than extended with three names.
|
||||
- **The two arguments are the SDK's own types**, where the signature took `unknown` for both. `useShape(shapeType: ShapeType<T>, conf: RdfOrmConfig<T> | string | undefined)`, which is what the surface already said the pair was. A caller passing the SDK's shape and config compiles unchanged; one passing something else now does not, which is why this counts.
|
||||
- **`size` and `length` count what you may read.** An ordered config (`orderBy`) makes the collection an array, whose count is a number - and a number used to pass through untouched, publishing how many items you may NOT read. Indexing that array (`data[0]`) is refused rather than projected.
|
||||
- **`size` and `length` count what you may read, and so does every other way of asking.** An ordered config (`orderBy`) makes the collection an array, which says how many items it holds in four places - `length`, `Object.keys`, `in`, and the descriptor of each index - and only the first was filtered. `data[0]` now names the first item you may read rather than the first the engine returned, and the positions past them do not exist.
|
||||
- **A member's DESCRIPTOR answers what reading it answers.** `Object.getOwnPropertyDescriptor(result, "data")` returned the collection UNFILTERED, and `...(result, "subscription")` the handle that reading it refuses: that call does not go through the view's own read. Neither does a spread, `Object.entries`, `JSON.stringify` or a console inspection, so all of them were reading round the filter. They now read through it - which also means `{...result}` and `console.log(result)` throw on `subscription`, where they used to print it. Log `data`.
|
||||
- **Unchanged**: the read still spends no round-trip asking a public store for a key, a document you have read nowhere else still does not appear, mutations of the live collection still pass through, and nothing about `useShapeQuery`, `getObjects` or `insertObject` moves.
|
||||
|
||||
`1.0.0-dev.10` is a **major**, and all of it is one rule: **"is this document open in this session" now has exactly one answer.** This package kept three records of that fact - a set of live bootstrap subscriptions, a per-document barrier state, and the subscription layer's own listeners - and the first two outlived the third. Only one remains, the state of the document's one real subscription; the other two are gone rather than reconciled, because two records of one fact can disagree and these did. Nothing is added, renamed or removed from the entry.
|
||||
|
||||
Reference in New Issue
Block a user