docs: chaque symbole dit d'où il vient
98 annotations posées à côté des déclarations, et un test qui les exige sur la surface publiée. Elles portent trois choses : le niveau qui répond, la référence amont, et la catégorie parmi les cinq. La cinquième est celle qui manquait : declared-not-wired, quand la cible DÉFINIT la forme et ne la câble pas. Neuf symboles en relèvent, dont readLinks — que j'avais classé « notre invention » en raisonnant depuis l'absence, alors que c'est le meilleur alignement disponible. Les références citent un SYMBOLE, jamais une ligne : trois citations du document avaient déjà pourri. Cinq corrections au passage, toutes vérifiées à la source — un chemin ORM qui n'existe pas, deux plages de lignes fausses, et surtout docs.* et subscribeDoc étiquetés PASSTHROUGH alors qu'ils sont alignés : nos noms, plus un argument jamais transmis. La sémantique survit à la migration, les sites d'appel non, et la nuance disparaissait sous une étiquette trop flatteuse. Le test échoue à l'annotation retirée, à la catégorie mal orthographiée, et à une invention qui prétendrait citer une référence — vérifié en cassant les trois. Il a aussi attrapé un défaut en lui-même : le gabarit de format placé dans index.ts se faisait analyser comme une annotation. La classification couvre l'interne qui prétend ressembler à la cible — tout emulated-verifier — et exclut ce qui ne le prétend pas. La faute d'origine portait sur une fonction non exportée ; n'être pas publié n'a protégé personne. Quatre symboles ont résisté et sont annotés avec leur catégorie dominante, la seconde nommée dans la note plutôt que lissée.
This commit is contained in:
@@ -68,6 +68,7 @@ import type { InboxScope, Nuri, NuriLike, PrincipalId, ReadCap, Scope } from "..
|
||||
* inbox read guard consults (`inbox.ts`). Anonymous holds no inbox, so it is false
|
||||
* for everyone until an identity is set.
|
||||
*/
|
||||
// @provenance isOwnInbox kind=aligned level=1 ref=engine/repo/src/types.rs:AddInboxCapV0 — 'which inboxes may I read' is answered by the User branch's records
|
||||
export async function isOwnInbox(nuri: Nuri): Promise<boolean> {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null) return false;
|
||||
@@ -100,6 +101,7 @@ export async function isOwnInbox(nuri: Nuri): Promise<boolean> {
|
||||
* not ours to hold. `id` is compared through the shim key, so it matches however
|
||||
* the consumer spells the identity.
|
||||
*/
|
||||
// @provenance holdOwnCap kind=aligned level=1 ref=engine/repo/src/types.rs:AddRepoV0 — the cap of a document you created, filed on the store's Store branch. WIRED upstream — `send_add_repo_to_store` constructs it
|
||||
export function holdOwnCap(id: string, scope: Scope, doc: Nuri, cap: ReadCap): void {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null || accountKey(holder) !== accountKey(id)) return;
|
||||
@@ -124,6 +126,7 @@ export function holdOwnCap(id: string, scope: Scope, doc: Nuri, cap: ReadCap): v
|
||||
* Scoped to the current holder, like {@link holdOwnCap}: another user's stores are
|
||||
* emphatically not ours to hold.
|
||||
*/
|
||||
// @provenance fileOwnStructure kind=aligned level=1 ref=engine/verifier/src/site.rs:create_individual_ — a user's three stores are its own repos; it holds their caps by BEING a user
|
||||
export function fileOwnStructure(id: string, record: VirtualUserRecord): void {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null || accountKey(holder) !== accountKey(id)) return;
|
||||
@@ -135,6 +138,7 @@ export function fileOwnStructure(id: string, record: VirtualUserRecord): void {
|
||||
|
||||
/** Same, for the user's own inbox — it is its document, and it must be able to
|
||||
* read it. Depositing into someone else's needs no cap (see `register-write.depositInto`). */
|
||||
// @provenance fileOwnInbox kind=aligned level=1 ref=engine/repo/src/types.rs:AddInboxCapV0 — upstream the record IS the key (`priv_key`); here the cap is minted for the holder the record belongs to
|
||||
export function fileOwnInbox(id: string, inbox: Nuri): void {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null || accountKey(holder) !== accountKey(id)) return;
|
||||
@@ -160,6 +164,7 @@ export function fileOwnInbox(id: string, inbox: Nuri): void {
|
||||
* did not: the address that WAS published is gone, and every future deposit on that
|
||||
* document is refused as "this document has no inbox".
|
||||
*/
|
||||
// @provenance publishInboxAddress kind=divergent level=1 ref=engine/net/src/types.rs:ContactDetails — upstream an inbox address is TRANSMITTED (a message, a profile QR) and lands in the verifier's own per-user `inboxes` table; PUBLISHING it on the document is this library's deliberate divergence
|
||||
export async function publishInboxAddress(doc: Nuri, inbox: Nuri): Promise<void> {
|
||||
const s = await session();
|
||||
try {
|
||||
@@ -197,6 +202,7 @@ export async function publishInboxAddress(doc: Nuri, inbox: Nuri): Promise<void>
|
||||
* its whole contract is that the connection either did the restore or says it did not.
|
||||
* A caller that genuinely prefers to carry on catches it itself, and one of them does.
|
||||
*/
|
||||
// @provenance readStoreCaps kind=aligned level=1 ref=engine/repo/src/types.rs:AddRepoV0 — the replay of the Store branch — what reloads a store's documents with their keys
|
||||
export async function readStoreCaps(storeDoc: Nuri): Promise<ReadCap[]> {
|
||||
const s = await session();
|
||||
const out: ReadCap[] = [];
|
||||
@@ -246,6 +252,7 @@ export async function readStoreCaps(storeDoc: Nuri): Promise<ReadCap[]> {
|
||||
* read. A failed READ is one, and it propagates — the caller is `connect.connectedUser`,
|
||||
* whose contract is that it did the work or said it did not.
|
||||
*/
|
||||
// @provenance restoreOwnCaps kind=aligned level=1 ref=engine/verifier/src/verifier.rs:load_repo_from_read_cap — `AddRepo::verify` loads each repo from its read cap at replay; this is that replay, at connection
|
||||
export async function restoreOwnCaps(holderKey: string): Promise<void> {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null) return;
|
||||
@@ -294,6 +301,7 @@ export async function restoreOwnCaps(holderKey: string): Promise<void> {
|
||||
* **Never creates.** Asking where to deposit must not bring an inbox into existence —
|
||||
* only its owner opens one, and only on its own document.
|
||||
*/
|
||||
// @provenance documentInboxAddress kind=divergent level=1 ref=engine/net/src/types.rs:ContactDetails — the deposit-side half of the same divergence: upstream you are TOLD an address, you never read one off a document
|
||||
export async function documentInboxAddress(doc: Nuri): Promise<Nuri | undefined> {
|
||||
// RULE 2 — do not even attempt. Not holding the document, we have no address to
|
||||
// find: upstream the inbox pubkey travels WITH what you can read, so "where do I
|
||||
@@ -333,6 +341,7 @@ export async function documentInboxAddress(doc: Nuri): Promise<Nuri | undefined>
|
||||
* place that records authorship. Holding a cap is NOT ownership: a cap can be
|
||||
* received, and a recipient must not be able to open an inbox on what it merely reads.
|
||||
*/
|
||||
// @provenance ownsDocument kind=aligned level=1 ref=engine/repo/src/types.rs:AddRepoV0 — authorship is what the Store branch records; holding a cap is NOT ownership, since a cap can be received
|
||||
export async function ownsDocument(doc: Nuri): Promise<boolean> {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null) return false;
|
||||
@@ -381,6 +390,7 @@ function encodeInboxCap(doc: Nuri, inbox: Nuri): string {
|
||||
* make a document's queue silently un-drained — a share that was delivered and never
|
||||
* applied, with nothing to see anywhere.
|
||||
*/
|
||||
// @provenance readInboxCapPairs kind=declared-not-wired level=1 ref=engine/repo/src/types.rs:AddInboxCapV0 — the record is keyed by `repo_id` and `update_inbox_cap_v0` applies it with no is-store check — but the engine only ever commits one for the two STORE repos, never for a plain document
|
||||
export async function readInboxCapPairs(): Promise<Array<{ doc: Nuri; inbox: Nuri }>> {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null) return [];
|
||||
@@ -411,6 +421,7 @@ export async function readInboxCapPairs(): Promise<Array<{ doc: Nuri; inbox: Nur
|
||||
}
|
||||
|
||||
/** The inbox recorded for one document, if this user opened one. */
|
||||
// @provenance readInboxCapsFor kind=declared-not-wired level=1 ref=engine/repo/src/types.rs:AddInboxCapV0 — the per-document lookup over the same unwired record
|
||||
export async function readInboxCapsFor(doc: Nuri): Promise<Nuri | undefined> {
|
||||
return (await readInboxCapPairs()).find((p) => p.doc === doc)?.inbox;
|
||||
}
|
||||
@@ -437,6 +448,7 @@ export async function readInboxCapsFor(doc: Nuri): Promise<Nuri | undefined> {
|
||||
* sign-in, on a document the application had never named, repeating at every connection
|
||||
* because the record is durable. Reported live, three sign-ins out of three.
|
||||
*/
|
||||
// @provenance myInboxes kind=aligned level=1 ref=engine/repo/src/types.rs:AddInboxCapV0 — the User branch answers 'which inboxes may I read'. The document-inbox half of this list is declared-not-wired — see `readInboxCapPairs`
|
||||
export async function myInboxes(): Promise<Nuri[]> {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null) return [];
|
||||
@@ -473,6 +485,7 @@ export async function myInboxes(): Promise<Nuri[]> {
|
||||
* wrong is not a near-miss: a Link filed under the wrong holder gives one user another's
|
||||
* capability and leaves the real recipient with nothing.
|
||||
*/
|
||||
// @provenance addLink kind=declared-not-wired level=1 ref=engine/repo/src/types.rs:AddLinkV0 — the type is DEFINED and its `CommitVerifier::verify` is a no-op `Ok(())`; nothing in the engine constructs one
|
||||
export async function addLink(cap: ReadCap, forHolder?: PrincipalId): Promise<void> {
|
||||
const holder = forHolder ?? getCurrentUser();
|
||||
if (holder === null) return;
|
||||
@@ -525,6 +538,7 @@ function holderRing(forHolder: PrincipalId | undefined): string | undefined {
|
||||
* `forHolder` names whose User branch is read when it is not the connected identity's —
|
||||
* see {@link addLink}, whose idempotence check is the caller that needs it.
|
||||
*/
|
||||
// @provenance readLinks kind=declared-not-wired level=1 ref=engine/repo/src/types.rs:AddLinkV0 — same: defined, verifier is a no-op, constructed nowhere. NOT this library's invention — an absent implementation says nothing about the target
|
||||
export async function readLinks(forHolder?: PrincipalId): Promise<ReadCap[]> {
|
||||
const holder = forHolder ?? getCurrentUser();
|
||||
if (holder === null) return [];
|
||||
@@ -608,6 +622,7 @@ export async function readLinks(forHolder?: PrincipalId): Promise<ReadCap[]> {
|
||||
* owner. To deposit into someone else's document, resolve
|
||||
* {@link documentInboxAddress} and `inbox.post` into it.
|
||||
*/
|
||||
// @provenance storeRegistry.openDocumentInbox kind=declared-not-wired level=1 ref=engine/repo/src/types.rs:AddInboxCapV0 — every `Repo` carries `inbox: Option<PrivKey>` and the record is keyed by any `repo_id`, but `new_store_default` attaches one only to non-private STORES and `doc_create` leaves `inbox: None`. PUBLISHING the address is a separate, divergent act — see `publishInboxAddress`
|
||||
export async function openDocumentInbox(docLike: NuriLike): Promise<Nuri> {
|
||||
// Permissive in, precise out — see `model/nuri.ts`. Published through
|
||||
// `surface/placement.ts`, so it is a door an application types against.
|
||||
|
||||
@@ -83,6 +83,7 @@ const STAND_IN_CAP = "OK";
|
||||
* Build the cap-bearing form of `nuri` — `{target}:r:OK`. Passing an already
|
||||
* cap-bearing reference yields the same value. INTERNAL to the emulated verifier.
|
||||
*/
|
||||
// @provenance mintCap kind=divergent level=1 ref=engine/repo/src/types.rs:readcap_nuri — upstream a cap is SERIALIZED from the ObjectRef at repo creation; here it is DERIVED from a NURI with a stand-in key. Unreachable from outside on purpose
|
||||
export function mintCap(nuri: Nuri): ReadCap {
|
||||
return `${targetOf(nuri)}${CAP_SEGMENT}${STAND_IN_CAP}`;
|
||||
}
|
||||
@@ -90,6 +91,7 @@ export function mintCap(nuri: Nuri): ReadCap {
|
||||
/** The map key of the anonymous holder (no identity established yet). */
|
||||
const ANONYMOUS = "";
|
||||
|
||||
// @provenance CapRegistry kind=aligned level=1 ref=engine/repo/src/repo.rs:Repo — the session's record of which repos it holds a `read_cap` for; upstream that record is the verifier's opened repos, never a queryable registry
|
||||
export class CapRegistry {
|
||||
/** holder → the caps they hold, indexed by the cap-less NURI. */
|
||||
private heldByHolder = new Map<string, Map<Nuri, ReadCap>>();
|
||||
|
||||
@@ -126,6 +126,7 @@ const inFlight = new Map<string, Promise<void>>();
|
||||
* Not fixed with a retry, a timeout or a flag on purpose: deciding *what to do* about a
|
||||
* broker that cannot answer belongs to the caller, and it can only decide if it is told.
|
||||
*/
|
||||
// @provenance connectedUser kind=aligned level=1 ref=engine/verifier/src/verifier.rs:inbox — upstream the verifier restores and processes with nothing for a caller to await; this is the awaitable form, for a deterministic start
|
||||
export async function connectedUser(): Promise<void> {
|
||||
const holder = getCurrentUser();
|
||||
if (holder === null) return;
|
||||
@@ -223,6 +224,7 @@ export async function connectedUser(): Promise<void> {
|
||||
* inherits it, failure included. That is what `ensureIdentity()` does, and it is the path
|
||||
* on which the guarantee is published.
|
||||
*/
|
||||
// @provenance startConnect kind=aligned level=1 ref=engine/verifier/src/verifier.rs:inbox — the fire-and-forget form of the same — upstream no application asks for it at all
|
||||
export function startConnect(): void {
|
||||
void connectedUser().catch((error: unknown) => {
|
||||
console.error(accessLogPrefix() + " connect failed:", error);
|
||||
|
||||
@@ -126,6 +126,7 @@ function fire(inbox: Nuri, process: () => Promise<void>): void {
|
||||
*
|
||||
* Idempotent inside the window: a second deposit into the same inbox joins the pending run.
|
||||
*/
|
||||
// @provenance scheduleInboxProcessing kind=divergent level=1 ref=engine/verifier/src/verifier.rs:inbox — upstream the RECIPIENT's own verifier applies its inbox; here another identity's session drains it on a timer. Deliberate, unpublished, and only possible on one shared wallet
|
||||
export function scheduleInboxProcessing(inbox: Nuri, process: () => Promise<void>): void {
|
||||
if (scheduled.has(inbox)) return;
|
||||
const handle = setTimeout(() => fire(inbox, process), PROCESSING_DELAY_MS);
|
||||
@@ -145,6 +146,7 @@ export function scheduleInboxProcessing(inbox: Nuri, process: () => Promise<void
|
||||
* Resolves rather than rejects, like the timer path it stands in for: a drain's failure is
|
||||
* reported where failures go, and a caller of this is not the party that asked for the work.
|
||||
*/
|
||||
// @provenance runScheduledInboxProcessingNow kind=divergent level=1 ref=engine/verifier/src/verifier.rs:inbox — the same drain, run at once; a test seam over the divergence above
|
||||
export async function runScheduledInboxProcessingNow(): Promise<void> {
|
||||
for (const [inbox, entry] of [...scheduled]) {
|
||||
clearTimeout(entry.handle);
|
||||
@@ -161,12 +163,14 @@ export async function runScheduledInboxProcessingNow(): Promise<void> {
|
||||
* session that no longer exists. In-flight runs are not cancelled (nothing can un-issue a
|
||||
* write already sent); they end where they end.
|
||||
*/
|
||||
// @provenance cancelScheduledInboxProcessing kind=divergent level=1 ref=engine/verifier/src/verifier.rs:inbox — cancels a pending drain — upstream there is no pending anything to cancel
|
||||
export function cancelScheduledInboxProcessing(): void {
|
||||
for (const entry of scheduled.values()) clearTimeout(entry.handle);
|
||||
scheduled.clear();
|
||||
}
|
||||
|
||||
/** Trace one completed drain — diagnostics, so gated by the access-log flag. */
|
||||
// @provenance traceProcessed kind=invention level=none ref=none — a diagnostic line in this package's own log stream
|
||||
export function traceProcessed(inbox: Nuri, holder: string, applied: number): void {
|
||||
logStage(
|
||||
"DEFERRED PROCESS " + shortNuri(inbox) + " for " + holder + " → " + applied + " link(s) applied",
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
* its reads. That is a deliberate reservation, not a hazard to guard against: the
|
||||
* namespace names this library.
|
||||
*/
|
||||
// @provenance MACHINERY_NS kind=invention level=none ref=none — upstream a branch is a distinct CRDT with its own topic; a reserved subject prefix exists only because this library has no branches
|
||||
export const MACHINERY_NS = "urn:ng-eventually:";
|
||||
|
||||
/**
|
||||
@@ -37,6 +38,7 @@ export const MACHINERY_NS = "urn:ng-eventually:";
|
||||
* Tolerant of `undefined` so a read path can hand it a possibly-absent binding
|
||||
* without a preliminary check — an absent subject is not machinery.
|
||||
*/
|
||||
// @provenance isMachinerySubject kind=invention level=none ref=none — same — upstream nothing has to be filtered out of a document's own graph
|
||||
export function isMachinerySubject(subject: string | undefined): boolean {
|
||||
return subject !== undefined && subject.startsWith(MACHINERY_NS);
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ import type { Nuri } from "../model/types";
|
||||
* - `"timed-out"` fallback fired without a `State` — open proceeded, sync UNconfirmed;
|
||||
* `"unknown"` (from {@link getSyncState}) means "never requested / no `State` semantics".
|
||||
*/
|
||||
// @provenance SyncState kind=aligned level=1 ref=engine/net/src/app_protocol.rs:AppResponseV0 — the first `State` push IS the barrier; `timed-out` names the bounded fallback and is deliberately not `synced`
|
||||
export type SyncState = "syncing" | "synced" | "timed-out";
|
||||
|
||||
/** Repos whose bootstrap open has completed (first `State` received OR timed out). */
|
||||
@@ -114,12 +115,14 @@ let OPEN_TIMEOUT_MS = 8000;
|
||||
* 8s production wait, too slow for a unit test. Production never calls this — the
|
||||
* default stands. `resetOpenedRepos` restores the default.
|
||||
*/
|
||||
// @provenance setOpenTimeoutForTests kind=invention level=none ref=none — a test seam over the bounded fallback
|
||||
export function setOpenTimeoutForTests(ms: number): void {
|
||||
OPEN_TIMEOUT_MS = ms;
|
||||
}
|
||||
|
||||
/** Reset the open registry (mainly for tests / a switched wallet). Tears down the
|
||||
* held bootstrap subscriptions so a subsequent open re-subscribes cleanly. */
|
||||
// @provenance resetOpenedRepos kind=invention level=none ref=none — per-session bookkeeping reset; upstream the verifier owns `self.repos` and nothing resets it from outside
|
||||
export function resetOpenedRepos(): void {
|
||||
for (const unsub of held.values()) {
|
||||
try {
|
||||
@@ -145,6 +148,7 @@ export function resetOpenedRepos(): void {
|
||||
* `"timed-out"` (fallback fired without a `State`). `"synced"` and `"timed-out"`
|
||||
* are deliberately distinct — a later readiness signal must not confuse them.
|
||||
*/
|
||||
// @provenance getSyncState kind=aligned level=1 ref=engine/net/src/app_protocol.rs:AppResponseV0 — reports whether the first `State` arrived; upstream this is not observable from JS
|
||||
export function getSyncState(nuri: Nuri): SyncState | "unknown" {
|
||||
return syncState.get(nuri) ?? "unknown";
|
||||
}
|
||||
@@ -184,6 +188,7 @@ async function syncSession(): Promise<void> {
|
||||
* another holder would put a cap in the wrong ring, and a caller on that path has already
|
||||
* established what its holder holds.
|
||||
*/
|
||||
// @provenance ensureRepoOpen kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_subscribe — a real subscription held for the session — upstream `doc_subscribe` is what brings a repo into `self.repos`, which `resolve_target_for_sparql` then requires
|
||||
export async function ensureRepoOpen(nuri: Nuri, holderKey?: string): Promise<void> {
|
||||
if (!nuri) return;
|
||||
// A repo in a PUBLIC store hands its cap to whoever asks — upstream by serving it on
|
||||
@@ -204,6 +209,7 @@ export async function ensureRepoOpen(nuri: Nuri, holderKey?: string): Promise<vo
|
||||
* for nobody else; neither entry point re-exports it. The `Unguarded` suffix is the
|
||||
* warning, and the single importer is what keeps it honest.
|
||||
*/
|
||||
// @provenance openRepoUnguarded kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_subscribe — the same open without the reach guard; internal
|
||||
export async function openRepoUnguarded(nuri: Nuri): Promise<void> {
|
||||
// Drop the registry if the session changed (in-page re-login → fresh verifier).
|
||||
await syncSession();
|
||||
@@ -274,6 +280,7 @@ export async function openRepoUnguarded(nuri: Nuri): Promise<void> {
|
||||
* Open a SET of repos before an anchored batch read, in parallel, each tolerant
|
||||
* ({@link ensureRepoOpen} never throws). Empty / falsy entries are ignored.
|
||||
*/
|
||||
// @provenance ensureReposOpen kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_subscribe — the batch form, with per-doc isolation
|
||||
export async function ensureReposOpen(nuris: Nuri[]): Promise<void> {
|
||||
const unique = [...new Set(nuris.filter(Boolean))];
|
||||
if (unique.length === 0) return;
|
||||
|
||||
@@ -110,6 +110,7 @@ import type { Nuri, ReadCap } from "../model/types";
|
||||
const attempted = new Map<Nuri, Promise<ReadCap | null>>();
|
||||
|
||||
/** Forget every outer-overlay fetch (tests / a switched session or wallet). */
|
||||
// @provenance resetPublicStoreFetches kind=invention level=none ref=none — forgets the memoised fetches; upstream there is nothing to memoise, the broker answers
|
||||
export function resetPublicStoreFetches(): void {
|
||||
attempted.clear();
|
||||
}
|
||||
@@ -130,6 +131,7 @@ export function resetPublicStoreFetches(): void {
|
||||
* caller `createEntityDoc` already refuses to hand back a reference whose bookkeeping did
|
||||
* not land, for the same reason and in the same words.
|
||||
*/
|
||||
// @provenance exposeReadCap kind=divergent level=1 ref=engine/net/src/types.rs:PublicRepoLinkV0 — upstream NOTHING is written to make a repo public: the store is public and the broker exposes its outer overlay. Here the cap is written on the document's Header branch
|
||||
export async function exposeReadCap(doc: Nuri, cap: ReadCap): Promise<void> {
|
||||
const s = await session();
|
||||
try {
|
||||
@@ -164,6 +166,7 @@ export async function exposeReadCap(doc: Nuri, cap: ReadCap): Promise<void> {
|
||||
* Never throws — a document that is not in a public store simply answers nothing, which
|
||||
* is not an error but the normal case.
|
||||
*/
|
||||
// @provenance fetchReadCap kind=declared-not-wired level=1 ref=engine/net/src/types.rs:PublicRepoLinkV0 — the type DECLARES the cap is downloaded from the outer overlay if the brokers allow; it is constructed nowhere, both `PinRepo` constructors hard-code `expose_outer: false`, and `ExtTopicSyncReq` is `unimplemented!()`
|
||||
export async function fetchReadCap(docLike: Nuri): Promise<boolean> {
|
||||
const doc = targetOf(docLike);
|
||||
const caps = getCaps();
|
||||
@@ -221,6 +224,7 @@ async function downloadReadCap(doc: Nuri): Promise<ReadCap | null> {
|
||||
* Ask for a SET of documents' caps, in parallel — what a batch read does before it
|
||||
* decides which documents it may touch. Each fetch is independent and tolerant.
|
||||
*/
|
||||
// @provenance fetchReadCaps kind=declared-not-wired level=1 ref=engine/net/src/types.rs:PublicRepoLinkV0 — the batch form of the same unwired mechanism
|
||||
export async function fetchReadCaps(docs: Nuri[]): Promise<void> {
|
||||
const unique = [...new Set(docs.filter(Boolean))];
|
||||
if (unique.length === 0) return;
|
||||
|
||||
@@ -71,6 +71,7 @@ import type { Nuri } from "../model/types";
|
||||
* fixes is which ring the question is about, so that work decided for one identity is not
|
||||
* judged against another's possession.
|
||||
*/
|
||||
// @provenance mayReach kind=aligned level=1 ref=engine/verifier/src/verifier.rs:load_repo_from_read_cap — upstream possession decides by whether the key opens the repo at all; here it is a lookup, because nothing is encrypted yet
|
||||
export function mayReach(nuri: Nuri, holderKey?: string): boolean {
|
||||
const caps = getCaps();
|
||||
if (!caps.isEnforcing()) return true;
|
||||
@@ -94,6 +95,7 @@ export function mayReach(nuri: Nuri, holderKey?: string): boolean {
|
||||
* {@link mayReach}. The refusal names it too, or a processor's refusal would read as the
|
||||
* connected identity's, which is the one thing nobody would then go and check.
|
||||
*/
|
||||
// @provenance assertMayReach kind=aligned level=1 ref=engine/verifier/src/verifier.rs:load_repo_from_read_cap — the throwing form, at the passage points; upstream the equivalent failure is a repo that simply never decrypts
|
||||
export function assertMayReach(nuri: Nuri, op: string, holderKey?: string): void {
|
||||
if (mayReach(nuri, holderKey)) return;
|
||||
const who = holderKey === undefined ? "the connected user" : `holder ${JSON.stringify(holderKey)}`;
|
||||
@@ -144,6 +146,7 @@ export function assertMayReach(nuri: Nuri, op: string, holderKey?: string): void
|
||||
* `docs.registerUpdate`, because a store document is not OWNED in this sense — it IS a
|
||||
* store, and the verifier commits to it on its own behalf.
|
||||
*/
|
||||
// @provenance assertMayWrite kind=aligned level=1 ref=engine/repo/src/commit.rs:verify_perm — upstream the right to write is membership of the repo, checked on commits only; ownership stands in for it here
|
||||
export async function assertMayWrite(nuri: Nuri, op: string): Promise<void> {
|
||||
const caps = getCaps();
|
||||
if (!caps.isEnforcing()) return;
|
||||
@@ -175,6 +178,7 @@ export async function assertMayWrite(nuri: Nuri, op: string): Promise<void> {
|
||||
*
|
||||
* `holderKey` names the ring the question is about — see {@link mayReach}.
|
||||
*/
|
||||
// @provenance mustNotAttempt kind=aligned level=1 ref=engine/verifier/src/request_processor.rs:resolve_target — upstream a repo you cannot open answers `RepoNotFound`; this is the do-not-even-attempt form of the same absence
|
||||
export function mustNotAttempt(nuri: Nuri, holderKey?: string): boolean {
|
||||
return !mayReach(nuri, holderKey);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ function readable(item: unknown, caps: CapRegistry): boolean {
|
||||
}
|
||||
|
||||
/** Pure: keep only the items whose document the current holder holds. */
|
||||
// @provenance filterReadable kind=aligned level=1 ref=engine/verifier/src/verifier.rs:load_repo_from_read_cap — upstream the broker only delivers what the wallet's keys decrypt; the access unit is the DOCUMENT, which is why this filters per `@graph`
|
||||
export function filterReadable<T>(items: Iterable<T>, caps: CapRegistry): T[] {
|
||||
const out: T[] = [];
|
||||
for (const item of items) if (readable(item, caps)) out.push(item);
|
||||
@@ -85,6 +86,7 @@ export function filterReadable<T>(items: Iterable<T>, caps: CapRegistry): T[] {
|
||||
* Everything that is not a function passes through untouched (`size` is handled above):
|
||||
* a plain property carries no items.
|
||||
*/
|
||||
// @provenance makeReadFilteredView kind=aligned level=1 ref=engine/verifier/src/verifier.rs:load_repo_from_read_cap — the same filter as a live view over a reactive set; removed at migration
|
||||
export function makeReadFilteredView<S extends object>(set: S, caps: CapRegistry): S {
|
||||
const keep = (item: unknown): boolean => readable(item, caps);
|
||||
/** The readable items, as a plain array — what every handled member works from. */
|
||||
|
||||
@@ -41,6 +41,7 @@ import type { Nuri } from "../model/types";
|
||||
* during someone else's session. The guard still fires, against the named ring; see
|
||||
* {@link assertMayReach}.
|
||||
*/
|
||||
// @provenance registerUpdate kind=aligned level=1 ref=engine/repo/src/types.rs:BranchCrdt — upstream these are service commits on branches whose CRDT is `None`, made by the verifier on its own behalf; here they are SPARQL writes that skip the ownership guard
|
||||
export async function registerUpdate(
|
||||
sessionId: string | number,
|
||||
query: string,
|
||||
@@ -79,6 +80,7 @@ function forHolderSuffix(holderKey: string | undefined): string {
|
||||
*
|
||||
* Never exported from the package — it reads a document the connected identity may not.
|
||||
*/
|
||||
// @provenance readForHolder kind=invention level=none ref=none — reading on behalf of an identity other than the session's exists only because one wallet hosts every identity
|
||||
export async function readForHolder(
|
||||
sessionId: string | number,
|
||||
query: string,
|
||||
@@ -115,6 +117,7 @@ export async function readForHolder(
|
||||
* The recipient's ownership of the inbox is what bounds this: `inbox.post` is the
|
||||
* only caller, and reading is guarded separately (`inbox.read`).
|
||||
*/
|
||||
// @provenance depositInto kind=aligned level=1 ref=engine/verifier/src/inbox_processor.rs:post_to_inbox — the one write that legitimately crosses: upstream a deposit is an anonymous sealed box, so it holds no cap and gets nothing back
|
||||
export async function depositInto(
|
||||
sessionId: string | number,
|
||||
query: string,
|
||||
|
||||
@@ -43,8 +43,20 @@
|
||||
*/
|
||||
|
||||
// ── SDK-SHAPED — a target counterpart for every symbol ──────────────────────
|
||||
// At migration the build alias is removed and these resolve to the real SDK. The
|
||||
// per-symbol ruling, with its epistemic label, is in `docs/api-contract.md`.
|
||||
// At migration the build alias is removed and these resolve to the real SDK.
|
||||
//
|
||||
// WHAT each symbol is aligned on is recorded BESIDE IT, not in a document that drifts:
|
||||
//
|
||||
// // @provenance <name> kind=<kind> level=<1|2|3|none> ref=<path:symbol|none> — <note>
|
||||
//
|
||||
// `level` numbers the target's stack from the bottom (1 engine, 2 wasm binding /
|
||||
// `@ng-org/web`, 3 JS ORM); `ref` cites a SYMBOL in `nextgraph-rs`, never a line number.
|
||||
// `kind` is closed: `passthrough` (upstream's own symbol, name and shape), `aligned` (our
|
||||
// name or ergonomics, upstream's semantics), `declared-not-wired` (upstream DEFINES the
|
||||
// shape and constructs it nowhere — an absence, which is NOT evidence the thing is ours),
|
||||
// `invention` (nothing answers, a documented bet), `divergent` (upstream does this, we do
|
||||
// it differently). Pinned by `test/provenance.test.ts`; the reasoning behind each ruling
|
||||
// stays in `docs/api-contract.md`, and where the two disagree the annotation wins.
|
||||
|
||||
// A type is published only when a PUBLISHED SIGNATURE uses it. `export *` published
|
||||
// eight in one gesture (2026-08-10: it was a blanket re-export), of which two named
|
||||
@@ -81,8 +93,13 @@ export * as storeRegistry from "./surface/placement";
|
||||
// SDK type re-exports — so the app imports these from @ng-eventually/polyfill too, not from
|
||||
// @ng-org. `export type` is ERASED at build, so this adds NO runtime @ng-org import to
|
||||
// the lib (no risk of a duplicate SDK copy in the bundle).
|
||||
// @provenance ShapeType kind=passthrough level=3 ref=sdk/js/shex-orm/src/types.ts:ShapeType
|
||||
// @provenance BaseType kind=passthrough level=3 ref=sdk/js/shex-orm/src/types.ts:BaseType
|
||||
// @provenance Schema kind=passthrough level=3 ref=sdk/js/shex-orm/src/types.ts:Schema
|
||||
export type { ShapeType, BaseType, Schema } from "@ng-org/shex-orm";
|
||||
// @provenance DeepSignalSet kind=passthrough level=3 ref=sdk/js/alien-deepsignals/src/types.ts:DeepSignalSet
|
||||
export type { DeepSignalSet } from "@ng-org/alien-deepsignals";
|
||||
// @provenance NG kind=passthrough level=2 ref=sdk/js/web/src/index.ts:NG — 88 members, all forwarded; the proxy adds none and removes none
|
||||
export type { NG } from "@ng-org/web";
|
||||
|
||||
// ── POLYFILL-ERA — THE DELETION LIST ────────────────────────────────────────
|
||||
@@ -150,4 +167,5 @@ import { makeNg } from "./surface/ng-proxy";
|
||||
* `Record<string, any>` until 2026-08-14, which announced a different surface from the one
|
||||
* it forwards to: an application got no completion and no check on any of the 88 members.
|
||||
*/
|
||||
// @provenance ng kind=passthrough level=2 ref=sdk/js/web/src/index.ts:ng — a Proxy over the injected real `ng`; only `sparql_update` is overridden (the emulated write guard)
|
||||
export const ng: NG = makeNg();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* `did:ng:` is the URI scheme prefix, not a "without cap" marker; the discriminant
|
||||
* is the `:r:` segment (see {@link ReadCap}).
|
||||
*/
|
||||
// @provenance Nuri kind=aligned level=1 ref=engine/net/src/app_protocol.rs:NuriV0 — the cap-less reference form upstream's parser accepts; `:r:` is the cap-bearing discriminant
|
||||
export type Nuri = `did:ng:${string}`;
|
||||
|
||||
/**
|
||||
@@ -31,14 +32,17 @@ export type Nuri = `did:ng:${string}`;
|
||||
* out. The runtime checks stay regardless — a JavaScript consumer never meets the
|
||||
* compiler, and a cast bypasses it.
|
||||
*/
|
||||
// @provenance ReadCap kind=aligned level=1 ref=engine/repo/src/types.rs:readcap_nuri — the `r:` segment and its one-opaque-segment encoding are upstream's; the key material is a stand-in constant
|
||||
export type ReadCap = `did:ng:${string}:r:${string}`;
|
||||
|
||||
/** NextGraph-native store scopes. The *mapping* of entities to scopes is the
|
||||
* consumer's concern; this layer only knows the three scopes exist. */
|
||||
// @provenance Scope kind=aligned level=1 ref=engine/repo/src/types.rs:from_type_and_repo — upstream's store types; `group` is omitted here and `dialog` is `unimplemented!()` upstream
|
||||
export type Scope = "public" | "protected" | "private";
|
||||
|
||||
/** The current identity id. Target: the wallet user (`session.user`). Polyfill:
|
||||
* a chosen id, because everyone shares one wallet. */
|
||||
// @provenance PrincipalId kind=divergent level=1 ref=engine/repo/src/types.rs:UserId — upstream a user id is a PubKey obtained FROM the wallet; here it is a chosen name, because one wallet hosts every identity
|
||||
export type PrincipalId = string;
|
||||
|
||||
/**
|
||||
@@ -48,9 +52,11 @@ export type PrincipalId = string;
|
||||
* makes the wrapper testable with a fake. Permissive on purpose: the real `ng`
|
||||
* carries non-function members too, so we accept any property bag.
|
||||
*/
|
||||
// @provenance NgLike kind=invention level=none ref=none — nothing upstream is injected; the type exists only to describe what `configure` receives
|
||||
export type NgLike = Record<string, any>;
|
||||
|
||||
/** Loose shape of `@ng-org/orm`'s `useShape` (a generic hook). */
|
||||
// @provenance UseShapeLike kind=invention level=none ref=none — same, for the injected `useShape`
|
||||
export type UseShapeLike = (...args: any[]) => any;
|
||||
|
||||
/**
|
||||
@@ -76,6 +82,8 @@ export type UseShapeLike = (...args: any[]) => any;
|
||||
* So: precise on the way out, permissive on the way in, and validated inside
|
||||
* (`assertNuri`). The guards remain, internal, where the validation happens.
|
||||
*/
|
||||
// @provenance NuriLike kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_subscribe — the binding takes `repo_o: String`, so permissive-in matches the target's own door
|
||||
export type NuriLike = Nuri | string;
|
||||
|
||||
// @provenance InboxScope kind=aligned level=1 ref=engine/verifier/src/verifier.rs:new_store_default — an inbox is attached only `if !private`, so the private scope cannot carry one
|
||||
export type InboxScope = Extract<Scope, "public" | "protected">;
|
||||
|
||||
@@ -150,6 +150,7 @@ const URL_PARAM = "ng-id";
|
||||
* passes the VALUES here. A library that read `process.env` would impose its build
|
||||
* system on every consumer, and would be untestable with other values.
|
||||
*/
|
||||
// @provenance SharedWalletConfig kind=invention level=none ref=none — describes what a DEPLOYMENT hands out for the one shared wallet; it goes with the gate
|
||||
export interface SharedWalletConfig {
|
||||
/** URL of the `.ngw` file served by the application's own bundle. */
|
||||
fileUrl: string;
|
||||
@@ -555,6 +556,7 @@ async function resolveIdentity(): Promise<PrincipalId> {
|
||||
* application had to read the gate's own private storage key — a boundary no consumer
|
||||
* should be able to see, let alone depend on.
|
||||
*/
|
||||
// @provenance ensureIdentity kind=invention level=none ref=none — nothing answers 'gate a shared wallet'. Upstream a user opens THEIR wallet and `session_start(wallet_name, user_id)` takes an id that came from it — so the CALL SITE survives, the substance does not
|
||||
export async function ensureIdentity(): Promise<PrincipalId> {
|
||||
const settled = await settleIdentity();
|
||||
refuseAWaitNothingCanEnd();
|
||||
|
||||
@@ -968,6 +968,7 @@ async function scopeStoreNuri(scope: Scope): Promise<Nuri> {
|
||||
* store-id and builds no NURI. Use the returned value as both the read scope
|
||||
* (`useShape(shape, nuri)`) and the `@graph` write target.
|
||||
*/
|
||||
// @provenance storeRegistry.resolveScopeGraph kind=aligned level=2 ref=sdk/js/web/src/index.ts:Session — `did:ng:` + `private_store_id | protected_store_id | public_store_id`, straight off the session
|
||||
export async function resolveScopeGraph(scope: Scope): Promise<Nuri> {
|
||||
return scopeStoreNuri(scope);
|
||||
}
|
||||
@@ -1043,6 +1044,7 @@ const inboxCache = new Map<string, Nuri>();
|
||||
* At migration these become the site's native store inboxes and the resolution moves
|
||||
* there — the consumer-facing act (deposit to an inbox, process my own) is unchanged.
|
||||
*/
|
||||
// @provenance userInbox kind=aligned level=1 ref=engine/verifier/src/site.rs:create_individual_ — a user's inboxes are its public and protected STORE repos' — the engine's only two `AddInboxCap` commits
|
||||
export async function userInbox(id: string, scope: InboxScope): Promise<Nuri> {
|
||||
const key = `${accountKey(id)}\u0000${scope}`;
|
||||
const cached = inboxCache.get(key);
|
||||
@@ -1261,6 +1263,7 @@ export async function readUserStore(indexDoc: Nuri): Promise<Nuri[]> {
|
||||
* here). Idempotent via `ensureAccount`'s cache. At migration this becomes the
|
||||
* user's real per-scope store NURI (the container the store itself provides).
|
||||
*/
|
||||
// @provenance userStoreDoc kind=aligned level=2 ref=sdk/js/web/src/index.ts:Session — the per-scope index document stands in for the store the session names directly
|
||||
export async function userStoreDoc(id: string, scope: Scope): Promise<Nuri> {
|
||||
const record = await ensureAccount(id);
|
||||
return storeOf(record, scope);
|
||||
|
||||
@@ -105,6 +105,7 @@ export interface StoreRegistryDeps {
|
||||
* carried two defects at once. Both remain substitutable through {@link StoreRegistryDeps},
|
||||
* which the published entry cannot reach.
|
||||
*/
|
||||
// @provenance EventuallyConfig kind=invention level=none ref=none — nothing upstream takes an injected SDK; this is the shape of the build-alias, and it is on the deletion list
|
||||
export interface EventuallyConfig {
|
||||
/** The REAL `@ng-org/web` `ng` (injected to avoid a hard import / alias loop). */
|
||||
ng: NgLike;
|
||||
@@ -188,6 +189,7 @@ function capsHolder(): PrincipalId | null {
|
||||
*/
|
||||
let caps = new CapRegistry(capsHolder);
|
||||
|
||||
// @provenance configure kind=invention level=none ref=none — same — the whole call disappears at migration, when the consumer initialises the real SDK directly
|
||||
export function configure(c: EventuallyConfig): void {
|
||||
cfg = c;
|
||||
// Not taken from the config: an application never supplies its own identity — upstream
|
||||
|
||||
@@ -51,6 +51,7 @@ function rowCount(result: unknown): number {
|
||||
// through this chain — never normalise it, and above all never stringify it: a JS string
|
||||
// fails that deserialization, observed live as
|
||||
// `Deserialization error of session_id JsValue("1")`.
|
||||
// @provenance docs.docCreate kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_create — same arguments in the same order; JS-cased name, and the broker's answer is validated into a `Nuri`
|
||||
export async function docCreate(
|
||||
sessionId: string | number,
|
||||
crdt: string,
|
||||
@@ -98,6 +99,7 @@ export async function docCreate(
|
||||
* {@link sparqlQuery} already renders the same upstream `Promise<any>`: the value is
|
||||
* the broker's to shape, and a caller that ignores it is unaffected.
|
||||
*/
|
||||
// @provenance docs.sparqlUpdate kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:sparql_update — same arguments; the trailing `label` is a lib-internal access-log tag, never forwarded
|
||||
export async function sparqlUpdate(
|
||||
sessionId: string | number,
|
||||
query: string,
|
||||
@@ -131,6 +133,7 @@ export async function sparqlUpdate(
|
||||
* Mirrors `ng.sparql_query(session_id, query, base?, anchor?)`. `base` is the
|
||||
* query base IRI (usually `undefined`); `anchor` is the document NURI to query.
|
||||
*/
|
||||
// @provenance docs.sparqlQuery kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:sparql_query — same arguments; the trailing `label` is a lib-internal access-log tag, never forwarded
|
||||
export async function sparqlQuery(
|
||||
sessionId: string | number,
|
||||
query: string,
|
||||
|
||||
@@ -58,6 +58,7 @@ import type { Nuri, NuriLike, PrincipalId, ReadCap } from "../model/types";
|
||||
// --- deposit model --------------------------------------------------------
|
||||
|
||||
/** One deposit as materialized from an inbox document. */
|
||||
// @provenance inbox.Deposit kind=aligned level=1 ref=engine/net/src/types.rs:InboxMsgBody — `from` optional like `from_inbox`, and NO target-document field because the address identifies the recipient repo; `payload`/`ts` have no upstream field
|
||||
export interface Deposit {
|
||||
/** The sender, if identified; `null` when the deposit was anonymous. */
|
||||
from: PrincipalId | null;
|
||||
@@ -68,6 +69,7 @@ export interface Deposit {
|
||||
}
|
||||
|
||||
/** Options for {@link post}. `from` and `ts` are both optional. */
|
||||
// @provenance inbox.PostOptions kind=aligned level=1 ref=engine/net/src/types.rs:InboxMsgBody — same shape as Deposit on the way in; `from: null` mirrors `from_inbox: None`
|
||||
export interface PostOptions {
|
||||
/**
|
||||
* Who is depositing. Omit (or pass `null`) for an ANONYMOUS deposit; pass a
|
||||
@@ -169,6 +171,7 @@ function readBindings(result: unknown): Array<Record<string, { value: string }>>
|
||||
* another's identity. This check is redundant once the seal enforces it, but
|
||||
* until then it closes the spoof the shared wallet would otherwise allow.
|
||||
*/
|
||||
// @provenance inbox.post kind=aligned level=1 ref=engine/verifier/src/inbox_processor.rs:post_to_inbox — the act exists at level 1 and the broker routes it (`inbox_post`); no JS surface at level 2/3. An arbitrary `payload` is a BET — `InboxMsgContent` has no generic variant
|
||||
export async function post(targetInboxLike: NuriLike, opts: PostOptions): Promise<void> {
|
||||
const targetInbox = toNuri(targetInboxLike, "inbox.post");
|
||||
const current = getCurrentUser();
|
||||
@@ -269,6 +272,7 @@ export async function post(targetInboxLike: NuriLike, opts: PostOptions): Promis
|
||||
* address in advance, because an application must name a document or a person, never an
|
||||
* inbox.
|
||||
*/
|
||||
// @provenance inbox.postToDocument kind=declared-not-wired level=1 ref=engine/repo/src/repo.rs:Repo — every repo carries `inbox: Option<PrivKey>`, but nothing opens one for a plain document. Resolving the address by READING the document is our divergence — see `publishInboxAddress`
|
||||
export async function postToDocument(docLike: NuriLike, opts: PostOptions): Promise<void> {
|
||||
const doc = toNuri(docLike, "inbox.postToDocument");
|
||||
const target = await documentInboxAddress(doc);
|
||||
@@ -364,6 +368,7 @@ function capOfPayload(payload: unknown): ReadCap | null {
|
||||
* The shape is right; the implementation is absent at both ends, so we emulate it
|
||||
* meanwhile.
|
||||
*/
|
||||
// @provenance inbox.share kind=declared-not-wired level=1 ref=engine/net/src/types.rs:ContactDetails — `read_cap: Option<ReadCap>` is defined; building the message is `unimplemented!()`, its only caller passes `with_readcap: false`, and the receiving arm never reads the field
|
||||
export async function share(doc: NuriLike, toUser: string): Promise<void> {
|
||||
const target = toNuri(doc, "inbox.share");
|
||||
// Names the DOCUMENT and the PERSON — the two things an application has. Neither the
|
||||
@@ -431,6 +436,7 @@ export async function share(doc: NuriLike, toUser: string): Promise<void> {
|
||||
* no more reason to handle an inbox address than a depositor does. Empty when the
|
||||
* document has no inbox, which is a state and not an error.
|
||||
*/
|
||||
// @provenance inbox.readForDocument kind=divergent level=1 ref=engine/verifier/src/inbox_processor.rs:process_inbox — upstream an inbox is a queue the verifier consumes and APPLIES; this enumerates it instead, non-destructively
|
||||
export async function readForDocument(docLike: NuriLike): Promise<Deposit[]> {
|
||||
const doc = toNuri(docLike, "inbox.readForDocument");
|
||||
const address = await documentInboxAddress(doc);
|
||||
@@ -484,6 +490,7 @@ async function assertOwnInbox(targetInbox: Nuri, op: string): Promise<void> {
|
||||
* watching its inbox gets them, and the resulting change re-triggers the
|
||||
* reads that were empty for want of that cap.
|
||||
*/
|
||||
// @provenance inbox.read kind=divergent level=1 ref=engine/verifier/src/inbox_processor.rs:process_inbox — same: a re-readable list where upstream has a consumed queue. Coding a mailbox UI on this is coding against emulation detail
|
||||
export async function read(targetInboxLike: NuriLike): Promise<Deposit[]> {
|
||||
const targetInbox = toNuri(targetInboxLike, "inbox.read");
|
||||
await assertOwnInbox(targetInbox, "read");
|
||||
@@ -578,6 +585,7 @@ export async function read(targetInboxLike: NuriLike): Promise<Deposit[]> {
|
||||
* `discovery.readIndex` does. Idempotent per session (no polling); a no-op open on
|
||||
* the unit fake-ng path (no `doc_subscribe`) so `bun test` is unaffected.
|
||||
*/
|
||||
// @provenance inbox.readSynced kind=divergent level=1 ref=engine/verifier/src/inbox_processor.rs:process_inbox — same as `read`, gated on the sync barrier first
|
||||
export async function readSynced(targetInboxLike: NuriLike): Promise<Deposit[]> {
|
||||
const targetInbox = toNuri(targetInboxLike, "inbox.readSynced");
|
||||
// Marks the cold, connection-triggered entry point in the trace — the BARRIER
|
||||
@@ -604,6 +612,7 @@ export async function readSynced(targetInboxLike: NuriLike): Promise<Deposit[]>
|
||||
* second tab, a reconnect) costs nothing. Returns the consumer deposits, exactly as
|
||||
* {@link read} does — Links are never surfaced.
|
||||
*/
|
||||
// @provenance inbox.processInbox kind=aligned level=1 ref=engine/verifier/src/inbox_processor.rs:process_inbox — unseal-and-apply: Links are filed durably and never surfaced. Returning the remaining deposits is the divergent half it shares with `read`
|
||||
export async function processInbox(targetInboxLike: NuriLike): Promise<Deposit[]> {
|
||||
const targetInbox = toNuri(targetInboxLike, "inbox.processInbox");
|
||||
const deposits = await readSynced(targetInbox);
|
||||
@@ -711,6 +720,7 @@ async function processForOwner(targetInbox: Nuri): Promise<void> {
|
||||
* there is no polling. (The inbox document is a single doc, so this is immune to
|
||||
* the ORM fan-out hang — see {@link subscribeDoc}.)
|
||||
*/
|
||||
// @provenance inbox.watch kind=divergent level=1 ref=engine/verifier/src/verifier.rs:inbox — upstream a message is applied on arrival and there is nothing to subscribe to; this pushes the raw deposit list on every change
|
||||
export function watch(
|
||||
targetInboxLike: NuriLike,
|
||||
onDeposits: (deposits: Deposit[]) => void,
|
||||
|
||||
@@ -58,6 +58,7 @@ import { captureSession, expectSession } from "../shared-wallet/session";
|
||||
* it (`callback: Function | null`, and the call site is guarded). The wrapper still goes in,
|
||||
* so the package gets its session either way, and calls nothing afterwards.
|
||||
*/
|
||||
// @provenance init kind=passthrough level=2 ref=sdk/js/web/src/index.ts:init — arguments and return pass straight through; the callback in position 0 is wrapped to keep the session it carries
|
||||
export function init(...args: any[]): any {
|
||||
const f = getConfig().init;
|
||||
if (!f) throw new Error("[ng-eventually] init() not injected — pass it to configure()");
|
||||
@@ -90,6 +91,7 @@ export function init(...args: any[]): any {
|
||||
}
|
||||
|
||||
/** Forwards to the real `@ng-org/orm` `initNg` (ORM signals). */
|
||||
// @provenance initNg kind=passthrough level=3 ref=sdk/js/orm/src/core.ts:initNg — upstream's own exported name for `initNgSignals`
|
||||
export function initNg(...args: any[]): any {
|
||||
const f = getConfig().initNg;
|
||||
if (!f) throw new Error("[ng-eventually] initNg() not injected — pass it to configure()");
|
||||
|
||||
@@ -61,16 +61,19 @@ function connectedIdentity(op: string): string {
|
||||
}
|
||||
|
||||
/** Create a document for ONE entity in `scope`, and record it in that scope's store. */
|
||||
// @provenance storeRegistry.createEntityDoc kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_create — upstream `doc_create` performs the `ldp:contains` listing and the `AddRepo { read_cap }` natively; here they are two explicit writes
|
||||
export async function createEntityDoc(scope: Scope): Promise<Nuri> {
|
||||
return registryCreateEntityDoc(connectedIdentity("createEntityDoc"), scope);
|
||||
}
|
||||
|
||||
/** The entity documents this user owns in `scope` — with their caps recovered. */
|
||||
// @provenance storeRegistry.listMyEntityDocs kind=aligned level=1 ref=engine/verifier/src/request_processor.rs:doc_create — reads back the `ldp:contains` listing that `doc_create` writes on the store's Main branch
|
||||
export async function listMyEntityDocs(scope: Scope): Promise<Nuri[]> {
|
||||
return registryListMyEntityDocs(connectedIdentity("listMyEntityDocs"), scope);
|
||||
}
|
||||
|
||||
/** The NURI where GROUPED entities of `scope` are written (no per-entity document). */
|
||||
// @provenance storeRegistry.resolveWriteGraph kind=aligned level=2 ref=sdk/js/web/src/index.ts:Session — a scope resolves to the session's own store id; upstream the store IS the container and the per-scope index document disappears
|
||||
export async function resolveWriteGraph(scope: Scope): Promise<Nuri> {
|
||||
return registryResolveWriteGraph(connectedIdentity("resolveWriteGraph"), scope);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ void docCreate;
|
||||
void sparqlUpdate;
|
||||
|
||||
/** One subject read from a doc, with its properties (predicate → values). */
|
||||
// @provenance UnionSubject kind=invention level=none ref=none — no upstream type groups triples per (document, subject); a polyfill property bag, to be mapped into app types at the boundary
|
||||
export interface UnionSubject {
|
||||
/**
|
||||
* The subject IRI (`?s`), exactly as the document carries it.
|
||||
@@ -163,6 +164,7 @@ async function readDoc(
|
||||
* read with an anchored default-graph query, O(1) per doc, independent of wallet
|
||||
* size — a non-empty wallet no longer matters. Reads run in parallel via `Promise.all`.
|
||||
*/
|
||||
// @provenance readUnion kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:sparql_query — one anchored query per document — upstream's own anchoring (`resolve_target_for_sparql`), composed client-side
|
||||
export async function readUnion(docsLike: NuriLike[]): Promise<UnionSubject[]> {
|
||||
const sid = await sessionId();
|
||||
// Drop the empties BEFORE validating, not after: this call has always tolerated a
|
||||
|
||||
@@ -45,6 +45,7 @@ import type { Nuri, NuriLike } from "../model/types";
|
||||
* change SIGNAL (re-query on change — the read-model pattern), so this stays
|
||||
* permissive rather than modelling every AppResponse variant.
|
||||
*/
|
||||
// @provenance DocChange kind=aligned level=1 ref=engine/net/src/app_protocol.rs:AppResponseV0 — the raw serialized response, left `unknown` rather than modelling every variant
|
||||
export type DocChange = unknown;
|
||||
|
||||
/**
|
||||
@@ -58,6 +59,7 @@ export type DocChange = unknown;
|
||||
* `TabInfo`/`Patch` pushes — see `open-repo.ts`. Most callers ignore it and use
|
||||
* any push as a plain change signal.
|
||||
*/
|
||||
// @provenance DocChangeType kind=aligned level=1 ref=engine/net/src/app_protocol.rs:AppResponseV0 — the variant discriminant; a bare string because the enum is open (State | Patch | TabInfo | …)
|
||||
export type DocChangeType = string | undefined;
|
||||
|
||||
/**
|
||||
@@ -67,6 +69,7 @@ export type DocChangeType = string | undefined;
|
||||
* is not a recognisable `{ V0: { <Variant>: … } }` object. Inspects the variant
|
||||
* proplerly (no `any`-cast to force it) so a `State` push is identifiable.
|
||||
*/
|
||||
// @provenance docChangeType kind=aligned level=1 ref=engine/net/src/app_protocol.rs:AppResponseV0 — reads the variant key out of the payload — a convenience over a verified shape, not an upstream call
|
||||
export function docChangeType(resp: DocChange): DocChangeType {
|
||||
if (!resp || typeof resp !== "object") return undefined;
|
||||
const outer = resp as { V0?: unknown; v0?: unknown };
|
||||
@@ -77,6 +80,7 @@ export function docChangeType(resp: DocChange): DocChangeType {
|
||||
}
|
||||
|
||||
/** An unsubscribe function — idempotent (calling it twice is a no-op). */
|
||||
// @provenance Unsubscribe kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_subscribe — upstream resolves to this function; ours is returned synchronously
|
||||
export type Unsubscribe = () => void;
|
||||
|
||||
async function sessionId(): Promise<string | number> {
|
||||
@@ -102,6 +106,7 @@ async function sessionId(): Promise<string | number> {
|
||||
*
|
||||
* Calls the REAL injected `ng.doc_subscribe` directly (never `makeNg`).
|
||||
*/
|
||||
// @provenance subscribeDoc kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_subscribe — two deliberate deltas: the unsubscribe is returned synchronously, and the callback gets a pre-extracted `type`
|
||||
export function subscribeDoc(
|
||||
nuriLike: NuriLike,
|
||||
onChange: (r: DocChange, type: DocChangeType) => void,
|
||||
@@ -118,6 +123,7 @@ export function subscribeDoc(
|
||||
* owns the machinery's entire privileged door — and for nobody else. It is not
|
||||
* re-exported by either entry point; the `Unguarded` suffix is the warning.
|
||||
*/
|
||||
// @provenance subscribeDocUnguarded kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_subscribe — the same call without the reach guard; internal, never published
|
||||
export function subscribeDocUnguarded(
|
||||
nuri: Nuri,
|
||||
onChange: (r: DocChange, type: DocChangeType) => void,
|
||||
@@ -177,6 +183,7 @@ export function subscribeDocUnguarded(
|
||||
* ORM fan-out hang — do NOT replace this with `orm_start_graph(graphs:[…])`). The
|
||||
* set is deduplicated; an empty set returns a no-op unsubscribe.
|
||||
*/
|
||||
// @provenance subscribeDocs kind=aligned level=2 ref=sdk/js/lib-wasm/src/lib.rs:doc_subscribe — client-side composition with per-doc error isolation; `orm_start_graph` is deliberately unused — it aborts wholesale on one RepoNotFound
|
||||
export function subscribeDocs(
|
||||
nuris: Nuri[],
|
||||
onChange: (nuri: Nuri, r: DocChange, type: DocChangeType) => void,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { getConfig, getCaps } from "../shared-wallet/bootstrap";
|
||||
import { makeReadFilteredView } from "../emulated-verifier/read-filter";
|
||||
|
||||
// @provenance useShape kind=passthrough level=3 ref=sdk/js/orm/src/frontendAdapters/react/useShape.ts:useShape — forwards to the injected real hook; the read-filtered view emulates cryptographic isolation and the generic `T` is widened to `unknown`
|
||||
export function useShape(shapeType: unknown, scope: unknown): unknown {
|
||||
const set = getConfig().useShape(shapeType, scope) as object;
|
||||
const caps = getCaps();
|
||||
|
||||
@@ -70,6 +70,7 @@ const RDF_TYPE = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
|
||||
* the generic per-subject property bags of the read-model (NO application domain);
|
||||
* the app maps them to its own entity types in phase B.
|
||||
*/
|
||||
// @provenance ShapeQuery kind=invention level=none ref=none — no upstream type carries load state; the distinction IS expressible (`OrmSubscription.readyPromise`) but this vocabulary is ours
|
||||
export interface ShapeQuery<T = UnionSubject> {
|
||||
/** The subjects of the requested shape/scope. Empty array when none (never undefined). */
|
||||
data: T[];
|
||||
@@ -87,6 +88,7 @@ export interface ShapeQuery<T = UnionSubject> {
|
||||
}
|
||||
|
||||
/** The observable a caller binds with `useSyncExternalStore` (phase B). */
|
||||
// @provenance ShapeObservable kind=invention level=none ref=none — no upstream observable exists; the ORM exposes a hook returning a DeepSignalSet and nothing else
|
||||
export interface ShapeObservable<T = UnionSubject> {
|
||||
/** The current snapshot. STABLE across calls until it actually changes (so
|
||||
* `useSyncExternalStore` does not loop): the same reference is returned until a
|
||||
@@ -163,6 +165,7 @@ function barrierReached(docs: Nuri[]): boolean {
|
||||
* what kicks off resolution, opening and the first read; before then `getSnapshot`
|
||||
* reports the initial pending snapshot.
|
||||
*/
|
||||
// @provenance watchShape kind=invention level=none ref=none — nothing upstream distinguishes syncing from synced-empty at the hook; the header's 'planned useShape upgrade' has NO upstream provenance
|
||||
export function watchShape<T = UnionSubject>(
|
||||
shapeType: unknown,
|
||||
scope: Scope,
|
||||
|
||||
Reference in New Issue
Block a user