Implement Studio root and placement capabilities on the replica graph (WI-10)

This commit is contained in:
Timothy J. Aveni
2026-09-21 16:37:00 -07:00
parent 2cf53280e4
commit e1ad15c620
9 changed files with 103 additions and 19 deletions
+34 -2
View File
@@ -1,3 +1,4 @@
import { portableReflectionType } from "../execution-world/reflection.js";
import type { BindingSchema } from "./index.js";
import type {
ValueType,
@@ -98,7 +99,7 @@ interface Method {
name: string;
portId: string;
portName: string;
action: { kind: string; primitive?: string; operationId?: string };
action: { kind: string; primitive?: string; operationId?: string; selector?: string };
input: ValueType;
output: ValueType;
keyed: boolean;
@@ -126,6 +127,15 @@ function methods(
throw new PortableBindingError(path, "Snapshot context cannot expose mutation ports");
};
switch (req.kind) {
case "reflection":
if (remote)
throw new PortableBindingError(
path,
"Use an ordinary portable snapshot capability to read installation metadata",
);
return req.selectors.map((selector) =>
method(selector, { kind: "reflection", selector }, unit, portableReflectionType(selector)),
);
case "creation":
writable();
return [
@@ -301,5 +311,27 @@ function generateBindings(
methods: all.map((m) => ({ ...m, input: portableValueSchema(m.input), output: portableValueSchema(m.output) })),
});
}
return `// Generated ${remote ? "remote" : "portable"} bindings. Regenerate from the checked capability schema; do not edit.\nimport { define${mode}Registry, type ${mode}Export, type PreparedChange, type ManagedReference, type ExactReference, type ${remote ? "ServerMutationOptions" : "MutationKey"} } from ${q(options.runtimeModule ?? "@quixos/camino-replica-core")};\nexport const target = ${q(options.target)};\nexport type Contexts = { ${contexts.join(";\n")} };\nexport type ${mode}Implementation = { ${implementations.join(";\n")} };\nexport const declarations = ${JSON.stringify(descriptors, null, 2)} as const satisfies readonly ${mode}Export[];\nexport function createRegistry(handlers: ${mode}Implementation) { const installed = { ...handlers }; return define${mode}Registry(declarations, { ${adapters.join(",\n")} }); }\n`;
const groups = new Map<string, typeof entries>();
for (const entry of entries) {
if (!entry.application) continue;
const template = pkg.genericExports?.find((item) => item.id === entry.application!.exportId);
if (!template) throw new PortableBindingError(entry.id, "Missing generic export template");
groups.set(template.displayName, [...(groups.get(template.displayName) ?? []), entry]);
}
const generic = [...groups].map(([name, applications]) => {
contexts.push(
`readonly ${q(name)}: ${applications.map((entry) => `Contexts[${q(entry.displayName)}]`).join(" | ")}`,
);
const type = applications
.map(
(entry) =>
`((context: Contexts[${q(entry.displayName)}]) => ${tsType(entry.outputType)} | Promise<${tsType(entry.outputType)}>)`,
)
.join(" & ");
const handlers = applications
.map((entry) => `${q(entry.displayName)}: (context: Contexts[${q(entry.displayName)}]) => handler(context)`)
.join(",");
return `${q(name)}: (handler: ${type}) => ({${handlers}})`;
});
return `// Generated ${remote ? "remote" : "portable"} bindings. Regenerate from the checked capability schema; do not edit.\nimport { define${mode}Registry, type ${mode}Export, type PreparedChange, type ManagedReference, type ExactReference, type ${remote ? "ServerMutationOptions" : "MutationKey"} } from ${q(options.runtimeModule ?? "@quixos/camino-replica-core")};\nexport const target = ${q(options.target)};\nexport type Contexts = { ${contexts.join(";\n")} };\nexport type ${mode}Implementation = { ${implementations.join(";\n")} };\nexport const declarations = ${JSON.stringify(descriptors, null, 2)} as const satisfies readonly ${mode}Export[];\nexport const generic = { ${generic.join(",\n")} };\nexport function createRegistry(handlers: ${mode}Implementation) { const installed = { ...handlers }; return define${mode}Registry(declarations, { ${adapters.join(",\n")} }); }\n`;
}