import { afterEach, beforeEach, describe, it } from "@std/testing/bdd";
import { expect } from "@std/expect";
import { Identity } from "@commonfabric/identity";
import { StorageManager } from "@commonfabric/runner/storage/cache.deno";
import { Runtime } from "../src/runtime.ts";
import type { RuntimeProgram } from "../src/harness/types.ts";
import type { RuntimeTelemetryEvent } from "../src/telemetry.ts";
const signer = await Identity.fromPassphrase("imported-writer-binding");
const space = signer.did();
// The claim is written in the importing module; the writer is declared in
// another, and reached through a re-export under a different name. The
// schema must name the DECLARING module and the declared name, and that
// module must give the handler its binding identity, or the runtime finds no
// identity to verify the claim against and refuses the very write the claim
// authorizes. The policy type is spelled three ways — as the library names
// it, renamed at the import, and renamed through an authored re-export — and
// the claim, the identity and the admitted write must agree under each.
const WRITER = {
name: "/writer.ts",
contents: `///
import { handler, Writable } from "commonfabric";
export const writer = handler }>(
(_event, { name }) => { name.set("updated"); },
);`,
};
const BARREL = { name: "/barrel.ts", contents: `export * from "./writer.ts";` };
const program = (
imports: string,
policy: string,
extra: RuntimeProgram["files"] = [],
): RuntimeProgram => ({
main: "/main.tsx",
files: [
{
name: "/main.tsx",
contents: `///
${imports}
import { writer as save } from "./barrel.ts";
export default pattern, {
name: ${policy};
save: Stream;
}>(() => {
const name = new Writable("").for("name");
return { name, save: save({ name }) };
});`,
},
...extra,
BARREL,
WRITER,
],
});
const PROGRAMS: [string, RuntimeProgram][] = [
[
"the library's name",
program(
`import { pattern, Stream, Writable, WriteAuthorizedBy } from "commonfabric";`,
"WriteAuthorizedBy",
),
],
[
"a renamed import",
program(
`import { pattern, Stream, Writable, WriteAuthorizedBy as Guarded } from "commonfabric";`,
"Guarded",
),
],
[
"a renamed re-export",
program(
`import { pattern, Stream, Writable } from "commonfabric";
import { Guarded } from "./policy.ts";`,
"Guarded",
[{
name: "/policy.ts",
contents:
`export { WriteAuthorizedBy as Guarded } from "commonfabric";`,
}],
),
],
];
describe("a writer imported from another module", () => {
let storageManager: ReturnType;
beforeEach(() => {
storageManager = StorageManager.emulate({ as: signer });
});
afterEach(async () => {
await storageManager?.close();
});
for (const [spelling, PROGRAM] of PROGRAMS) {
it(`carries its binding identity and satisfies a claim spelled with ${spelling}`, async () => {
const rt = new Runtime({
apiUrl: new URL(import.meta.url),
storageManager,
});
const bindingPaths: string[][] = [];
rt.telemetry.addEventListener("telemetry", (event: Event) => {
const { marker } = (event as RuntimeTelemetryEvent).detail;
if (
marker.type === "harness.implementation.register" &&
marker.bindingPath !== undefined
) bindingPaths.push(marker.bindingPath);
});
try {
const tx = rt.edit();
const pattern = await rt.patternManager.compilePattern(PROGRAM, {
space,
tx,
});
const resultCell = rt.getCell<{ name: string }>(
space,
`imported-writer-binding ${spelling}`,
undefined,
tx,
);
const result = rt.run(tx, pattern, {}, resultCell);
rt.prepareTxForCommit(tx);
expect((await tx.commit().settled).error).toBeUndefined();
await result.pull();
await rt.idle();
// The declaring module minted the identity, under the declared name.
expect(bindingPaths).toContainEqual(["writer"]);
const send = rt.edit();
result.withTx(send).key("save").send(undefined);
expect((await send.commit().settled).error).toBeUndefined();
await rt.idle();
await result.pull();
expect(result.key("name").get()).toBe("updated");
} finally {
await rt.dispose();
}
});
}
});