Build reusable React component hosting and typed fragment composition

This commit is contained in:
Timothy J. Aveni
2026-09-22 16:46:33 -07:00
parent a8869e4545
commit b8571d054b
4 changed files with 65 additions and 4 deletions
+21 -4
View File
@@ -99,6 +99,7 @@ export function linkPackageQuery(plan: ExecutionPlan, contract: PublicQueryContr
export function generateInterfaceClientBindings(
imports: Readonly<Record<string, InterfaceRevision>>,
runtimeModule = "@quixos/camino-replica-core",
moduleProps?: (interfaceId: string, memberId: string) => string,
): string {
const entries = Object.entries(imports).map(([alias, iface]) => {
if (iface.template)
@@ -108,6 +109,10 @@ export function generateInterfaceClientBindings(
"Specialize the interface before generating a client",
);
const members = iface.members.map((member) => {
if (member.kind === "module" && member.subject?.kind === "interface") {
const subject = member.subject.interfaceRevisionId;
return `${JSON.stringify(member.displayName)}: defineModuleMember<${JSON.stringify(subject)}, ${moduleProps?.(iface.revisionId, member.id) ?? "{}"}>(${JSON.stringify({ interface: iface.revisionId, member: member.id, subject, contract: member.contract })})`;
}
const operations = member.operations
.filter((op) => op.mode === "call")
.map(
@@ -118,7 +123,7 @@ export function generateInterfaceClientBindings(
});
return `${JSON.stringify(alias)}: {${members.join(",\n")}}`;
});
return `// Generated from imported interface contracts. Regenerate; do not edit.\nimport { defineInterfaceOperation, type PreparedChange, type ManagedReference } from ${JSON.stringify(runtimeModule)};\nexport const interfaces = {${entries.join(",\n")}} as const;\n`;
return `// Generated from imported interface contracts. Regenerate; do not edit.\nimport { defineModuleMember, defineInterfaceOperation, type PreparedChange, type ManagedReference } from ${JSON.stringify(runtimeModule)};\nexport const interfaces = {${entries.join(",\n")}} as const;\n`;
}
export function generatePackageQueryClientBindings(
@@ -203,8 +208,10 @@ export function generateComponentClientBindings(plan: ExecutionPlan, packageRevi
Object.entries(pkg.clientInterfaces ?? {}).map(([alias, id]) => [alias, find(id)]),
);
const subjects = Object.fromEntries(components.map((component) => [component.displayName, find(component.subject)]));
const interfaces = generateInterfaceClientBindings(imports, "@quixos/camino-react");
const subjectBindings = generateInterfaceClientBindings(subjects, "@quixos/camino-react")
const props = (iface: string, member: string) =>
`ExtraModuleProps<${JSON.stringify(JSON.stringify([iface, member]))}>`;
const interfaces = generateInterfaceClientBindings(imports, "@quixos/camino-react", props);
const subjectBindings = generateInterfaceClientBindings(subjects, "@quixos/camino-react", props)
.split("\n")
.filter((line) => !line.startsWith("import "))
.join("\n")
@@ -219,10 +226,20 @@ export function generateComponentClientBindings(plan: ExecutionPlan, packageRevi
.join("\n");
return (
interfaces +
'\nimport {definePackageQuery,definePackageFragment,type ComponentType,type ComponentProps} from "@quixos/camino-react";\n' +
'\nimport {createObjectRenderer,definePackageQuery,definePackageFragment,type ComponentType,type ComponentProps} from "@quixos/camino-react";\n' +
subjectBindings +
"\n" +
queries +
`\nexport const providers = {${Object.entries(pkg.clientPackages ?? {})
.map(([alias, id]) => {
const imported = plan.definition.workspace.packageImports.find((entry) => entry.revisionId === id);
if (!imported) throw new ExecutionPlanError("UNINSTALLED_PACKAGE", id, "Missing imported module provider");
return `${JSON.stringify(alias)}:{${(imported.modules ?? []).map((module) => `${JSON.stringify(module.displayName)}:${JSON.stringify({ packageRevision: id, id: module.id })}`).join(",")}}`;
})
.join(",")}} as const;\n` +
`\nexport const renderers = {${Object.entries(imports)
.map(([name, iface]) => `${JSON.stringify(name)}:createObjectRenderer(${JSON.stringify(iface.revisionId)})`)
.join(",\n")}} as const;\n` +
"\nexport interface ModuleProps {}\n" +
"export type ExtraModuleProps<K extends string> = K extends keyof ModuleProps ? ModuleProps[K] : {};\n" +
"export interface Modules {\n" +