f4050b95c0
69 tests unitaires, trois rounds d'auto-critique, et rien n'avait jamais tourné contre un vrai broker. Sept parcours, vingt vérifications, à travers ng-e2e-helpers — rien de réimplémenté. La forme d'écriture est ACCEPTÉE par oxigraph, établie en relisant le document et non parce que la mise à jour n'a pas levé : après curation, readUnion rend deux sujets, celui de l'index et celui de l'objet de Bob, l'entrée portant sa valeur. C'était l'une des deux inconnues. L'autre est REPRODUITE, et c'est un défaut : un openInbox qui échoue en cours de createIndex laisse un document orphelin. L'appel rejette et ne rend rien, mais le document existe dans le store public du propriétaire, porte le descripteur, et refuse les dépôts. Le paquet n'expose pas openInbox, donc il ne peut ni le réparer ni le supprimer — orphelin permanent. Injecté pour être atteint : rien de ce que contrôle un appelant ne fait échouer un vrai openDocumentInbox. Et quatre endroits où la suite unitaire prouve moins qu'elle ne l'annonce, tous vérifiés. Le plus net : les treize tests d'adaptateur ne chargent JAMAIS le vrai polyfill. Preuve dure — la copie installée avait perdu un fichier qu'importe surface/inbox.ts, et 69 sur 69 passaient quand même. Aucun des deux côtés n'a tort ; c'est l'affirmation « l'adaptateur fonctionne » qui n'était pas testée. Rien n'a été affaibli, l'e2e est ce qui la teste enfin. Les trois autres sont de la même nature — une doublure trop faible plutôt qu'un code faux : ses NURI n'ont pas la forme réelle, elle n'écrit pas la machinerie que le vrai document porte, et étant une seule Map elle ne peut par construction jamais révéler un retard de cohérence. Trois exécutions, 27/27 chacune, autour de 58 secondes, aucune reprise.
85 lines
3.9 KiB
TypeScript
85 lines
3.9 KiB
TypeScript
/**
|
|
* The contract between the application page and the suite that drives it.
|
|
*
|
|
* It is declared ONCE and imported by both sides — `indexing-app.ts` implements it,
|
|
* `run.ts` calls it — so a method that changes shape breaks the typecheck instead of
|
|
* failing at run time inside a browser, where the only symptom would be `undefined is
|
|
* not a function` three minutes into a broker crossing.
|
|
*
|
|
* Everything crossing `frame.evaluate` must be structured-cloneable, which is why every
|
|
* member below takes and returns plain strings, numbers and object literals. A `Nuri` is
|
|
* a template-literal string type upstream (`did:ng:${string}`), so it crosses as itself;
|
|
* it is declared `string` here because a value that has been through structured clone
|
|
* carries no proof of its shape, and pretending otherwise is how an unvalidated string
|
|
* ends up typed as a reference.
|
|
*/
|
|
|
|
import type { CurationReport, IndexEntry, UnionSubject } from "../src/index";
|
|
|
|
/** What the leak probe observed — see `run.ts`'s last journey. */
|
|
export interface BrokenInboxOutcome {
|
|
/** The message `createIndex` rejected with, or `null` if it did not reject. */
|
|
readonly rejected: string | null;
|
|
/** What `createIndex` returned, on the impossible branch where it did not reject. */
|
|
readonly returned: string | null;
|
|
/** The documents that appeared in this identity's public store despite the failure. */
|
|
readonly appeared: readonly string[];
|
|
}
|
|
|
|
/**
|
|
* The acts this application can perform — and ONLY acts an application can perform.
|
|
*
|
|
* There is no back door onto the library's internals here. The one method that is not
|
|
* something an application does (`createIndexWithBrokenInbox`) injects a failure and is
|
|
* named for it, because the alternative — leaving the question unanswered — is worse
|
|
* than a probe that says what it is.
|
|
*/
|
|
export interface IndexingBridge {
|
|
/** `connecting` → `ready`, or `failed`. */
|
|
status(): string;
|
|
/** Why the boot failed, or `null`. */
|
|
error(): string | null;
|
|
/** Who this page signed in as. */
|
|
whoami(): string;
|
|
/**
|
|
* The index this deployment was BUILT to contribute to, read off its own configuration.
|
|
*
|
|
* An index is an ordinary document; what makes it an index is that an application
|
|
* references its NURI in its own source (`src/indexing.ts`). This page is configured
|
|
* through its URL rather than through a compiled-in constant, which is the same thing
|
|
* one build step earlier — and it is how the reference reaches a SECOND identity
|
|
* without the suite handing it over through a variable no application would have.
|
|
*/
|
|
configuredIndex(): string | null;
|
|
|
|
/** Create an index in this identity's public store, indexing by `field`. */
|
|
createIndex(field: string): Promise<string>;
|
|
/** Publish a public document carrying one value for one predicate. */
|
|
publishObject(predicate: string, value: string): Promise<string>;
|
|
/** Hand the CONFIGURED index a reference to an object. Anyone may. */
|
|
referConfigured(object: string): Promise<void>;
|
|
/** Hand a NAMED index a reference — used where no identity boundary is crossed. */
|
|
referTo(index: string, object: string): Promise<void>;
|
|
/** Resolve the references this index received and add what can be added. Owner only. */
|
|
curate(index: string): Promise<CurationReport>;
|
|
/** The index's entries, ordered by value. */
|
|
read(index: string): Promise<IndexEntry[]>;
|
|
|
|
/** What a document literally holds, straight off `readUnion` — the write-form probe. */
|
|
readRaw(doc: string): Promise<UnionSubject[]>;
|
|
/** This identity's public documents. How an owner discovers a document it did not keep. */
|
|
listPublicDocs(): Promise<string[]>;
|
|
|
|
/**
|
|
* `createIndex` with its inbox step made to fail — everything else real, against the
|
|
* real broker. Answers whether a half-created index is left behind.
|
|
*/
|
|
createIndexWithBrokenInbox(field: string): Promise<BrokenInboxOutcome>;
|
|
}
|
|
|
|
declare global {
|
|
interface Window {
|
|
__indexing: IndexingBridge;
|
|
}
|
|
}
|