48 lines
2.5 KiB
TypeScript
48 lines
2.5 KiB
TypeScript
import { QxReject } from "@quixos/camino-replica-core";
|
|
import { createRegistry } from "./gen/qx.js";
|
|
export const registry = createRegistry({
|
|
enroll: async ({ input, ports }) => {
|
|
if (!/^[a-f0-9-]{36}$/.test(input.nonce) || input.label.length > 100)
|
|
throw new QxReject("INVALID_DISPLAY_ENROLLMENT");
|
|
const enrolled = await ports.enrolled.resolve();
|
|
for (const previous of enrolled) {
|
|
if ((await ports.existing["nonce.get"]({ receiver: previous.target, input: null })) === input.nonce)
|
|
return previous.target;
|
|
}
|
|
if (enrolled.length >= 128) throw new QxReject("DISPLAY_ENROLLMENT_LIMIT");
|
|
const target = await ports.target.create(
|
|
{ nonce: input.nonce, initial: { label: input.label, generation: 0, presentation: null, observed: null } },
|
|
{ key: "display" },
|
|
);
|
|
const ref = {
|
|
...target,
|
|
expectation: { kind: "interface" as const, id: "interface:org.quixos.web-studio.display-target@1" as const },
|
|
};
|
|
await ports.enrolled.connect(ref, { key: "display" });
|
|
return ref;
|
|
},
|
|
assign: async ({ input, ports }) => {
|
|
if (input && !(await ports.subject["canPresent.call"]({ receiver: input.subject, input: input.presentation })))
|
|
throw new QxReject("INVALID_PRESENTATION");
|
|
const state = await ports.data.get();
|
|
if (state.generation === 4294967295) throw new QxReject("DISPLAY_GENERATION_EXHAUSTED");
|
|
const generation = state.generation + 1;
|
|
for (const previous of await ports.selected.resolve()) await ports.selected.disconnect(previous.entry);
|
|
if (input) await ports.selected.connect(input.subject, { key: "subject" });
|
|
for (const previous of await ports.mount.resolve()) await ports.mount.disconnect(previous.entry);
|
|
if (input?.presentationMount) await ports.mount.connect(input.presentationMount, { key: "presentationMount" });
|
|
await ports.data.set({ ...state, generation, presentation: input?.presentation ?? null, observed: null });
|
|
return generation;
|
|
},
|
|
acknowledge: async ({ input, ports }) => {
|
|
if (!["mounted", "failed", "empty"].includes(input.status) || input.error.length > 2000)
|
|
throw new QxReject("INVALID_DISPLAY_REPORT");
|
|
const state = await ports.data.get();
|
|
if (input.generation !== state.generation || (state.observed && input.sequence <= state.observed.sequence))
|
|
return false;
|
|
if ((state.presentation === null) !== (input.status === "empty")) throw new QxReject("INVALID_DISPLAY_REPORT");
|
|
await ports.data.set({ ...state, observed: input });
|
|
return true;
|
|
},
|
|
});
|