Testclient: losmaken maakt nu werkelijk los

Gemeld door de gebruiker: een eigenaar uit het register halen liet de relay hem
zien tot het proces stopte. `vergeet` koppelt netjes af, maar de socket zit niet
in de Evolu-instantie: hij zit in de gedeelde worker, en die blijft staan zolang
er nog een eigenaar open is. Een transport dat je in de config van `createEvolu`
meegeeft, kun je daarna nergens opzeggen.

Nu start de instantie met `transports: []` en gaat de transport erin met
`evolu.useOwner`, ook al is het de eigen appOwner. Die geeft een opzegging terug
en Evolu telt de verwijzingen, dus de laatste opzegging sluit de socket.

Bewezen met een wegwerpproef tegen een relay op localhost die iedereen toelaat:
twee eigenaars open, dan de ene sluiten. Gemeten in de verbindingstabel van het
besturingssysteem en niet met de `dicht`-melding van de cliënt, want
`closeSocket` in @evolu/common zet `socket.onclose` op null voordat het sluit.
Oude vorm: 2 verbindingen na het sluiten. Nieuwe vorm: 1, en de andere eigenaar
kon daarna nog schrijven.

Suite groen: 42, 90, 36, 22, 54 en 68 goed, 0 fout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Harmen
2026-09-10 09:55:05 +02:00
co-authored by Claude Opus 5
parent e4b0aa5df9
commit 090843a523
4 changed files with 51 additions and 2 deletions
+1 -1
View File
@@ -24,7 +24,7 @@
| Plan | App | Volgende stap | Status |
|-|-|-|-|
| [Umbrelapp](Plannen/Actief/008-Umbrelapp/TAKEN.md) | Relay | **0.7.1 bouwen, duwen en pinnen op de Umbrel. Eigenaar: gebruiker.** De compose staat op `evolu-relay:0.7.1` zónder digest, zodat een installatie hard faalt tot de image bestaat. **0.7.0 draait sinds 10-09-2026** en de wachtlijst is daar de enige weg naar binnen; 0.7.1 is wat een dag gebruiken opleverde, vier punten van de gebruiker over de twee eigenaarskaders. Eén ervan was meer dan een woordkeuze: een rij werd hoger op het moment dat je hem een naam gaf, en nu zijn alle rijen even hoog | 🔶 |
| [Testclient](Plannen/Actief/003-Testclient/TAKEN.md) | Relay | **Wacht op 0.7.0 op het apparaat.** De cliënt is af en werkt: register, negen opdrachten, een bedieningsvlak op `127.0.0.1:4380` met `Start.bat` en `Start.command`, en `test` die de HTTP-status van de WebSocket-upgrade toont. De eerste proef is geslaagd: een onbekende eigenaar krijgt 401 over `wss://` via de reverse proxy, en dat stond tot dan alleen als redenering in `Upstream-evolu-relay.md` §10. De rest van fase 4 vraagt een relay die eigenaars toelaat. Uitkomst die het meeste stuurt: `@evolu/nodejs` bevat géén cliënt, dus de afhankelijkheden voor `createEvolu` worden zelf samengesteld; de valstrikken staan in `PLAN.md` §4e | 🔶 |
| [Testclient](Plannen/Actief/003-Testclient/TAKEN.md) | Relay | **Wacht niet meer: 0.7.0 draait sinds 10-09-2026, dus fase 4 kan af.** De drie resterende proeven vragen om en om een handeling op de statuspagina en een ronde met de cliënt. Op 10-09-2026 opgelost: losmaken maakte niets los, want de socket zit in de gedeelde worker en een transport uit de config van `createEvolu` is nergens op te zeggen; nu gaat hij erin met `evolu.useOwner`. De cliënt is af en werkt: register, negen opdrachten, een bedieningsvlak op `127.0.0.1:4380` met `Start.bat` en `Start.command`, en `test` die de HTTP-status van de WebSocket-upgrade toont. De eerste proef is geslaagd: een onbekende eigenaar krijgt 401 over `wss://` via de reverse proxy, en dat stond tot dan alleen als redenering in `Upstream-evolu-relay.md` §10. De rest van fase 4 vraagt een relay die eigenaars toelaat. Uitkomst die het meeste stuurt: `@evolu/nodejs` bevat géén cliënt, dus de afhankelijkheden voor `createEvolu` worden zelf samengesteld; de valstrikken staan in `PLAN.md` §4e | 🔶 |
## B - Los oppakbaar (geen blokkade, geen vaste volgorde)
@@ -1,5 +1,24 @@
# Voortgang - Testclient
## 10-09-2026 - losmaken maakte niets los
Gemeld door de gebruiker: hij haalde een eigenaar uit het register, de rij verdween uit het bedieningsvlak,
en de relay bleef hem zien tot het proces stopte. Dat was geen vergissing in `vergeet`: die koppelt netjes
af. De socket zit niet in de Evolu-instantie maar in de gedeelde worker, en die blijft staan zolang er nog
één eigenaar open is. Een transport dat je in de config van `createEvolu` meegeeft, kun je daarna nergens
meer opzeggen.
De uitweg staat in de API zelf: `createEvolu` starten met `transports: []` en de transport erna met
`evolu.useOwner` erin zetten, ook al is het de eigen appOwner. Die geeft een opzegging terug en Evolu telt
de verwijzingen, dus de laatste opzegging sluit de socket werkelijk.
**Bewezen met een wegwerpproef tegen een relay op localhost die iedereen toelaat, want tegen de echte relay
is er niets te meten:** een geweigerde eigenaar levert nauwelijks verkeer op. Twee eigenaars open, dan de
ene sluiten. De maat is de verbindingstabel van het besturingssysteem en niet de `dicht`-melding van de
cliënt: `closeSocket` in `@evolu/common` zet `socket.onclose` op null vóórdat het sluit, dus een sluiting
die je zelf veroorzaakt meldt zichzelf nooit. Met de oude vorm bleven het 2 verbindingen, met de nieuwe
werd het 1, en de andere eigenaar kon daarna nog schrijven.
## 09-09-2026 - plan geschreven, gepromoveerd, en de samenstelling werkt
Het masterplan is geschreven en dezelfde dag gepromoveerd naar `Actief/003-Testclient/`, op verzoek van de
@@ -12,6 +12,15 @@
## Volgende stap
- [ ] **Fase 4 afmaken, nu 0.7.0 op het apparaat draait.** De wachtlijst is daar de enige weg naar binnen,
dus de drie proeven die een toegelaten eigenaar nodig hebben kunnen. Ze vragen om en om een handeling
van de gebruiker op de statuspagina en een ronde met de cliënt
- [x] **Losmaken maakte niets los (10-09-2026).** Gemeld door de gebruiker: een eigenaar uit het register
halen liet de relay hem zien tot het proces stopte. De socket zit in de gedeelde worker, niet in de
instantie, en een transport uit de config van `createEvolu` is nergens meer op te zeggen. Nu start de
instantie met `transports: []` en gaat de transport erin met `evolu.useOwner`, die een opzegging
teruggeeft. Bewezen tegen een relay op localhost: met de oude vorm bleven het 2 verbindingen na het
sluiten van de ene eigenaar, met de nieuwe 1
- [ ] **De logregels van de relay-container lezen, want daar zit het antwoord op [OPEN.md](OPEN.md) punt
9.** Twee eigenaars die toegelaten waren zijn uit de allowlist verdwenen, en de cliënt kan niet zien
waarom. Gezocht wordt naar `learned a new owner`, `owners.json was unreadable`, `refused a write of
+22 -1
View File
@@ -179,8 +179,20 @@ export const openStore = async ({
? [createOwnerWebSocketTransport({ url: relayUrl, ownerId: owner.id })]
: [];
// De instantie start ZONDER sync en de transport gaat er daarna met `useOwner`
// in, ook al is het de eigen appOwner. Dat is geen omweg maar het enige wat
// losmaken werkelijk losmaakt.
//
// Waarom: de socket zit niet in deze instantie maar in de gedeelde worker, en
// die blijft staan zolang er nog één store open is (zie `gedeeld` bovenaan).
// Een transport die je in de config meegeeft, kun je daarna nergens meer
// opzeggen; het gevolg was dat de relay een eigenaar bleef zien nadat je hem
// in de cliënt had losgekoppeld of zelfs vergeten, tot je het proces stopte.
// Gemeld door de gebruiker op 10-09-2026. `useOwner` geeft een opzegging terug
// en Evolu telt de verwijzingen naar een transport, dus de laatste opzegging
// sluit de socket.
const uitkomst = await run(
createEvolu(Schema, { appName: APP_NAME, appOwner: owner, transports }),
createEvolu(Schema, { appName: APP_NAME, appOwner: owner, transports: [] }),
);
if (!uitkomst.ok) {
@@ -193,6 +205,9 @@ export const openStore = async ({
const evolu = uitkomst.value;
// `useOwner` eist een niet-lege lijst, dus alleen als er een relay is.
let zegSyncOp = transports.length > 0 ? evolu.useOwner(owner, transports) : null;
return {
ownerId: owner.id,
/** De URL waarmee verbonden wordt, of null bij een instantie zonder sync. */
@@ -228,6 +243,12 @@ export const openStore = async ({
* de uitleg bovenaan bij `gedeeld`.
*/
sluit: async () => {
// Eerst de sync opzeggen en dan de run weggooien. Andersom is de instantie
// al weg als de opzegging aankomt.
if (zegSyncOp) {
zegSyncOp();
zegSyncOp = null;
}
await run[Symbol.asyncDispose]();
if (onDefect) defectMelders.delete(onDefect);
if (onWebSocket) socketMelders.delete(onWebSocket);