feat!: curer n'est plus un appel, c'est ce que fait le traitement de l'inbox
This commit is contained in:
+40
-17
@@ -1,5 +1,6 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { indexing } from "../src/indexing";
|
||||
import { curate } from "../src/curator";
|
||||
import { ENTRY_VALUE, INDEX_FIELD } from "../src/vocabulary";
|
||||
import type { NextGraphPort, Nuri } from "../src/port";
|
||||
import { DESTRUCTIVE, blankLiterals, installFakePolyfill } from "./fake-polyfill";
|
||||
@@ -85,25 +86,47 @@ async function publish(port: NextGraphPort, field: string, value: string): Promi
|
||||
// --- the whole loop, through the real adapter -----------------------------
|
||||
|
||||
test("the real adapter carries the whole loop: create, publish, refer, curate, read", async () => {
|
||||
const index = await as("alice", (alice) => indexing(alice).createIndex(FIELD));
|
||||
const index = await as("alice", async (alice) => (await indexing(alice)).createIndex(FIELD));
|
||||
|
||||
const article = await as("bob", async (bob) => {
|
||||
const object = await publish(bob, FIELD, "2026-07-08");
|
||||
await indexing(bob).refer(index, object);
|
||||
await (await indexing(bob)).refer(index, object);
|
||||
return object;
|
||||
});
|
||||
|
||||
const report = await as("alice", (alice) => indexing(alice).curate(index));
|
||||
const report = await as("alice", (alice) => curate(alice, index));
|
||||
expect(report.outcomes).toEqual([{ result: "indexed", object: article, value: "2026-07-08" }]);
|
||||
|
||||
const entries = await as("alice", (alice) => indexing(alice).read(index));
|
||||
const entries = await as("alice", async (alice) => (await indexing(alice)).read(index));
|
||||
expect(entries).toEqual([{ object: article, value: "2026-07-08" }]);
|
||||
});
|
||||
|
||||
test("a deposit made while the owner is connected is curated as it lands, with nobody asking", async () => {
|
||||
const seen = await as("alice", async (alice) => {
|
||||
const api = await indexing(alice);
|
||||
const index = await api.createIndex(FIELD);
|
||||
// An owner may deposit into her own index: `refer` is open to anyone, and here it
|
||||
// keeps both sides on one session, which is all this fake models at a time.
|
||||
const object = await publish(alice, FIELD, "2026-09-09");
|
||||
await api.refer(index, object);
|
||||
|
||||
// NOTHING CALLS CURATION. The session is told a deposit landed on an inbox it
|
||||
// watches, and processes that inbox itself — through the real adapter, so the
|
||||
// address resolution and `inbox.watch` are the ones an application would get.
|
||||
await world.deliverNotifications();
|
||||
|
||||
return { object, subjects: await alice.readDocument(index) };
|
||||
});
|
||||
|
||||
expect(seen.subjects.find((s) => s.subject === seen.object)?.props[ENTRY_VALUE]).toEqual([
|
||||
"2026-09-09",
|
||||
]);
|
||||
});
|
||||
|
||||
test("two indexes are two documents, each owned by whoever created it", async () => {
|
||||
const [first, second] = await as("alice", async (alice) => [
|
||||
await indexing(alice).createIndex(FIELD),
|
||||
await indexing(alice).createIndex(FIELD),
|
||||
await (await indexing(alice)).createIndex(FIELD),
|
||||
await (await indexing(alice)).createIndex(FIELD),
|
||||
]);
|
||||
expect(first).not.toBe(second);
|
||||
|
||||
@@ -116,10 +139,10 @@ test("two indexes are two documents, each owned by whoever created it", async ()
|
||||
// --- the two answers a resolve may give, and why they must stay apart -----
|
||||
|
||||
test("a reference that could not be READ comes back unresolved", async () => {
|
||||
const index = await as("alice", (alice) => indexing(alice).createIndex(FIELD));
|
||||
const index = await as("alice", async (alice) => (await indexing(alice)).createIndex(FIELD));
|
||||
const article = await as("bob", async (bob) => {
|
||||
const object = await publish(bob, FIELD, "2026-07-08");
|
||||
await indexing(bob).refer(index, object);
|
||||
await (await indexing(bob)).refer(index, object);
|
||||
return object;
|
||||
});
|
||||
|
||||
@@ -128,7 +151,7 @@ test("a reference that could not be READ comes back unresolved", async () => {
|
||||
// the failure as a FACT about the object is what must not happen.
|
||||
world.breakReadsOf(article, "broker unreachable");
|
||||
try {
|
||||
const report = await as("alice", (alice) => indexing(alice).curate(index));
|
||||
const report = await as("alice", (alice) => curate(alice, index));
|
||||
expect(report.outcomes).toEqual([
|
||||
{ result: "unresolved", object: article, reason: expect.stringContaining("absent") },
|
||||
]);
|
||||
@@ -138,10 +161,10 @@ test("a reference that could not be READ comes back unresolved", async () => {
|
||||
});
|
||||
|
||||
test("an object that really carries nothing for the field is SKIPPED — a different answer", async () => {
|
||||
const index = await as("alice", (alice) => indexing(alice).createIndex(FIELD));
|
||||
const index = await as("alice", async (alice) => (await indexing(alice)).createIndex(FIELD));
|
||||
const unrelated = await as("bob", async (bob) => {
|
||||
const object = await publish(bob, "http://schema.org/name", "Anemone");
|
||||
await indexing(bob).refer(index, object);
|
||||
await (await indexing(bob)).refer(index, object);
|
||||
return object;
|
||||
});
|
||||
|
||||
@@ -149,7 +172,7 @@ test("an object that really carries nothing for the field is SKIPPED — a diffe
|
||||
// keeping these two apart: replace `resolutionFromRead(subjects)` with
|
||||
// `{ state: "present", subjects }` and the unreadable object above is reported
|
||||
// here's answer instead — a broker failure filed as a property of the object.
|
||||
const report = await as("alice", (alice) => indexing(alice).curate(index));
|
||||
const report = await as("alice", (alice) => curate(alice, index));
|
||||
expect(report.outcomes).toEqual([
|
||||
{ result: "skipped", object: unrelated, reason: "no-field" },
|
||||
]);
|
||||
@@ -187,8 +210,8 @@ test("a document whose owner never opened an inbox REFUSES the deposit", async (
|
||||
});
|
||||
|
||||
test("anyone may deposit into an index, only its owner may read what was deposited", async () => {
|
||||
const index = await as("alice", (alice) => indexing(alice).createIndex(FIELD));
|
||||
await as("bob", (bob) => indexing(bob).refer(index, "did:ng:o:some-object"));
|
||||
const index = await as("alice", async (alice) => (await indexing(alice)).createIndex(FIELD));
|
||||
await as("bob", async (bob) => (await indexing(bob)).refer(index, "did:ng:o:some-object"));
|
||||
|
||||
const own = await as("alice", (alice) => alice.readDeposits(index));
|
||||
expect(own.map((deposit) => deposit.payload)).toEqual(["did:ng:o:some-object"]);
|
||||
@@ -202,18 +225,18 @@ test("anyone may deposit into an index, only its owner may read what was deposit
|
||||
// --- what the adapter actually wrote --------------------------------------
|
||||
|
||||
test("readDocument returns what was written, and refuses a document that is no index", async () => {
|
||||
const index = await as("alice", (alice) => indexing(alice).createIndex(FIELD));
|
||||
const index = await as("alice", async (alice) => (await indexing(alice)).createIndex(FIELD));
|
||||
const subjects = await as("alice", (alice) => alice.readDocument(index));
|
||||
expect(subjects).toEqual([{ subject: index, graph: index, props: { [INDEX_FIELD]: [FIELD] } }]);
|
||||
|
||||
const ordinary = await as("alice", (alice) => alice.createPublicDocument());
|
||||
await expect(as("alice", (alice) => indexing(alice).read(ordinary))).rejects.toThrow(
|
||||
await expect(as("alice", async (alice) => (await indexing(alice)).read(ordinary))).rejects.toThrow(
|
||||
/declares no index field/,
|
||||
);
|
||||
});
|
||||
|
||||
test("the write is the polyfill's canonical anchored form: the document named once, as the anchor", async () => {
|
||||
const index = await as("alice", (alice) => indexing(alice).createIndex(FIELD));
|
||||
const index = await as("alice", async (alice) => (await indexing(alice)).createIndex(FIELD));
|
||||
const writes = world.calls.filter((call) => call.entry === "docs.sparqlUpdate");
|
||||
const last = writes.at(-1);
|
||||
expect(last?.args[1]).toBe(`INSERT DATA { <${index}> <${INDEX_FIELD}> "${FIELD}" }`);
|
||||
|
||||
Reference in New Issue
Block a user