Une seconde suite e2e, `packages/sdk/e2e/notebook.ts` (`test:e2e:app`), qui pilote `examples/notebook` par le DOM — une page de navigateur par identité — contre le même broker réel. **Pourquoi une seconde suite plutôt qu'un ajout dans la première.** `run.ts` parle à un sac de méthodes sur `window.__sdk` : cela prouve que les fonctions TOURNENT, jamais qu'une application peut s'écrire avec. L'écart a déjà coûté un défaut livré — l'inbox d'un document était verte ici et inutilisable en pratique, parce que le harnais pouvait faire traverser une adresse d'une identité à l'autre par une variable, canal qu'aucune application n'a. Ici, rien ne traverse que ce qui traverse dans la vie : la RÉFÉRENCE d'une note, recopiée d'un écran, et un identifiant tapé dans un champ. Quatre parcours, qui se lisent comme des parcours : - Bob lit la note publique d'Alice depuis sa seule référence — la propriété pour laquelle l'émulation du store public existe, vérifiée bout en bout et sans qu'aucune clé ne circule ; - la note protégée d'Alice reste fermée jusqu'à ce qu'elle la partage — même geste côté Bob, issue opposée, décidée par où la note se trouve ; - Bob laisse un message sur la note d'Alice, et seule Alice le lit — il TROUVE l'adresse depuis la note, personne ne la lui donne ; - la liste de chacun ne contient que ses notes. **Deux étapes quittent `run.ts`** (`documentInboxDeposit`, `capsShareCap`), avec un commentaire disant où elles sont parties : ce sont des parcours, et ils valent plus joués sur deux écrans que sur deux appels d'une même page. Ce qui reste là-bas est ce qu'une application ne fait pas : primitives, caractérisation, régressions de démarrage à froid. **Trois défauts trouvés en écrivant la suite**, tous côté application et invisibles pour le harnais : `connectedUser()` devait être attendu à la connexion (sinon une note qu'on vient de vous partager se lit comme illisible — ce qui ressemble à un problème de droits alors que c'est un problème de moment) ; une réponse périmée restait affichée à côté d'une question fraîche ; et changer de portée ne rafraîchissait pas la liste. L'app affiche désormais la référence de chaque note — ce qu'aucun écran ne montre, aucun utilisateur ne peut le faire circuler. Corrigé au passage : le `.gitignore` pointait encore `packages/client/`, si bien que le commit de renommage a embarqué le profil Playwright de la suite e2e (226 fichiers). Les chemins sont réalignés et le commit précédent a été amendé — rien n'était poussé. 179 tests unitaires, e2e 40/40 (3,2 min) et applicatif 10/10 (0,7 min).
2.9 KiB
Notebook — the library's example application
A minimal application written against @ng-eventually/sdk, in plain DOM.
It exists for two reasons, and the second is the one that matters.
It shows how to use the library. Every call in app.ts is what a real consumer writes. There is no test scaffolding, no privileged import, no reaching into the library's internals — it resolves @ng-eventually/sdk as an external consumer does. If something reads awkwardly here, it reads awkwardly for everyone.
It is what the applicative e2e suite drives (packages/sdk/e2e/notebook.ts, bun run test:e2e:app). The other suite talks to a bag of methods on window.__sdk, which proves the functions run but never that an application can be written with them — and that gap shipped a real defect once: a document's inbox was green in tests and unusable in practice, because the harness handed an address across an identity boundary through a variable, something no application can do. Here each identity is its own browser page, and the only values that cross between them are the ones that cross in life: a note's reference, copied off one screen, and an identifier typed into a field.
It has already paid for itself: writing it surfaced that UnionSubject returned string where the values are always document references (so a consumer had to cast whatever it had just read before passing it back), and that the access gate normalized what a user typed but not what the URL carried.
What it exercises
Signing in, writing notes by scope, listing one's own, reading a note from its bare reference, handing a reader the key to a protected note, opening a note for messages, leaving a message on someone else's note, and reacting to changes.
The four journeys the suite runs, and what each proves:
| Journey | What it proves |
|---|---|
| Bob reads Alice's PUBLIC note from its reference alone | A public store serves its notes' keys — a bare reference is enough, and no key ever crosses |
| Alice's PROTECTED note stays shut until she shares it | The same gesture, the opposite outcome, decided by where the note sits and not by what was sent |
| Bob leaves a message on Alice's note, and only Alice reads it | A depositor FINDS the address from the note itself; depositing grants no reading |
| Each actor's list holds their own notes | The boundary, seen from the only place that matters: the screen |
It has also found three defects of its own, each an application-side one the harness could not see: connectedUser() had to be awaited at sign-in (a note just shared with you reads as unreadable otherwise), a stale answer stayed on screen beside a fresh question, and changing the scope did not refresh the list.
Running it
cd packages/sdk && bun run test:e2e:app builds it, serves it, and drives it against the real broker. To open it by hand you need a wallet: serve the folder with a bundled app.js and a /shared-wallet.ngw, and set __NOTEBOOK_WALLET_PASSWORD__.