138 lines
6.4 KiB
TypeScript
138 lines
6.4 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 { UnionSubject } from "@ng-eventually/polyfill";
|
|
|
|
/**
|
|
* One entry, as THIS APPLICATION decodes one out of the index document.
|
|
*
|
|
* It is declared here and not imported, because `@ng-helpers/indexing` publishes no
|
|
* such type and no call that produces one: an index is an ordinary document, so its
|
|
* contents are whatever `readUnion` hands back, read with the two published IRIs.
|
|
* A subject carrying several values shows up as several rows — the document's own
|
|
* truth, and the application's business to make something of.
|
|
*/
|
|
export interface IndexRow {
|
|
readonly object: string;
|
|
readonly value: string;
|
|
}
|
|
|
|
/** What the leak probe observed — see `run.ts`'s last journey. */
|
|
export interface BrokenInboxOutcome {
|
|
/** The message `create` rejected with, or `null` if it did not reject. */
|
|
readonly rejected: string | null;
|
|
/** What `create` 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[];
|
|
}
|
|
|
|
/**
|
|
* What one anchored SPARQL SELECT answered — or how it failed.
|
|
*
|
|
* The three fields are kept apart deliberately. "Nothing came back" and "the call failed"
|
|
* are different answers, and a shape that folded them together would let a failure read as
|
|
* an empty index — the defect class this repository keeps finding. `raw` carries the answer
|
|
* BEFORE anything here decodes it, so a decoder that is wrong about the result's shape
|
|
* cannot pass its own blindness off as a query that returned nothing.
|
|
*/
|
|
export interface SelectOutcome {
|
|
/** The message the query rejected with, or `null` when it returned. */
|
|
readonly failed: string | null;
|
|
/** Whatever came back, rendered as JSON — the answer before any decoding of it. */
|
|
readonly raw: string;
|
|
/** The SELECT's bindings, decoded to plain `variable → value` rows. */
|
|
readonly rows: ReadonlyArray<Readonly<Record<string, 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. */
|
|
addToConfigured(object: string): Promise<void>;
|
|
/** Hand a NAMED index a reference — used where no identity boundary is crossed. */
|
|
addTo(index: string, object: string): Promise<void>;
|
|
/**
|
|
* Obtain a fresh `Indexing` handle, which is what a page load does.
|
|
*
|
|
* It reaches NOTHING — a handle is a session id and two acts, and building one talks
|
|
* to nobody. That is precisely what one journey asserts: taking a handle again changes
|
|
* nothing an index holds. It is NOT a settle point and cannot be used as one; what a
|
|
* journey waits on after a deposit is the INDEX, read like any other document (`run.ts`,
|
|
* `settled`).
|
|
*/
|
|
rebuildHandle(): Promise<void>;
|
|
/**
|
|
* The index's entries, ordered by value — decoded BY THIS APPLICATION, out of an
|
|
* ordinary `readUnion` of the index document, with nothing from the library but the
|
|
* two IRIs it publishes. That the suite can do this at all is the claim under test.
|
|
*/
|
|
read(index: string): Promise<IndexRow[]>;
|
|
|
|
/** What a document literally holds, straight off `readUnion` — the write-form probe. */
|
|
readRaw(doc: string): Promise<UnionSubject[]>;
|
|
/**
|
|
* Run a SPARQL SELECT anchored on a document, through `docs.sparqlQuery`.
|
|
*
|
|
* An index is claimed to be an ORDINARY document, which means an ordinary query must
|
|
* reach it. Nothing in `src/` ever issues one — this layer composes SPARQL only to
|
|
* write — so this is the one act here that no code of this package performs, and it is
|
|
* on the bridge because the claim had never been measured against a broker.
|
|
*/
|
|
select(anchor: string, query: string): Promise<SelectOutcome>;
|
|
/** This identity's public documents. How an owner discovers a document it did not keep. */
|
|
listPublicDocs(): Promise<string[]>;
|
|
|
|
/**
|
|
* `create` 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;
|
|
}
|
|
}
|