2026-09-21 11:23:26 -07:00
import type {
InterfaceRevision ,
InterfaceOperation ,
ExecutionContract ,
PackageRevision ,
} from "../capability-model/types.js" ;
import { canonicalJson } from "../capability-model/evolution.js" ;
import { portableValueSchema , tsType } from "../bindings/portable.js" ;
import { type ExecutionPlan , resolvePlannedOperation , hexDigest , ExecutionPlanError } from "./plan.js" ;
2026-09-25 11:30:37 -07:00
import { moduleTypeContext } from "./module-contracts.js" ;
2026-09-21 11:23:26 -07:00
/** Public shape only: no slot inventory, implementation binding, or workspace identity. */
export interface PublicOperationContract {
interface : string ;
operation : string ;
scope : "object" | "class" ;
execution : ExecutionContract ;
input : unknown ;
output : unknown ;
}
export function publicOperationContract (
iface : InterfaceRevision ,
operation : InterfaceOperation ,
) : PublicOperationContract {
if ( iface . template || operation . mode !== "call" || ! iface . members . some (( m ) => m . operations . includes ( operation )))
throw new ExecutionPlanError (
"UNSUPPORTED_CLIENT_CONTRACT" ,
iface . revisionId ,
"Expected a closed interface call operation" ,
);
const execution = operation . execution ?? { kind : "remote" };
return {
interface : iface . revisionId ,
operation : operation.id ,
scope : operation.scope ?? "object" ,
execution : execution.kind === "remote" ? execution : { ... execution , targets : [... execution . targets ]. sort () },
input : portableValueSchema ( operation . inputType ),
output : portableValueSchema ( operation . outputType ),
};
}
/** Resolve a public contract to internal dispatch. This does not authorize the receiver. */
export function linkInterfaceOperation ( plan : ExecutionPlan , atom : string , contract : PublicOperationContract ) {
if ( hexDigest ( plan . definition ) !== plan . digest )
throw new ExecutionPlanError ( "INVALID_PLAN" , atom , "Invalid execution plan digest" );
const iface = plan . definition . workspace . interfaceImports . find (( i ) => i . revisionId === contract . interface );
const operation = iface ? . members . flatMap (( m ) => m . operations ). find (( o ) => o . id === contract . operation );
if ( ! iface || ! operation || canonicalJson ( publicOperationContract ( iface , operation )) !== canonicalJson ( contract ))
throw new ExecutionPlanError (
"CLIENT_CONTRACT_MISMATCH" ,
` ${ contract . interface } / ${ contract . operation } ` ,
"Installed interface differs from the imported operation contract" ,
);
return resolvePlannedOperation ( plan , atom , contract . interface , contract . operation );
}
export interface PublicQueryContract {
package : string ;
query : string ;
definitionDigest : string ;
root : { kind : "object" | "workspace-interface" ; interface : string };
placement : "server" | "replica" | "local" ;
sourceQuery? : string ;
input : unknown ;
output : unknown ;
}
export function publicQueryContract ( pkg : PackageRevision , queryId : string ) : PublicQueryContract {
const query = pkg . checkedQueries ? . find (( q ) => q . declaration . id === queryId );
if ( ! query )
throw new ExecutionPlanError ( "UNCHECKED_QUERY" , ` ${ pkg . revisionId } / ${ queryId } ` , "Expected a checked package query" );
const placement = query . declaration . placement ;
return {
package : pkg . revisionId ,
query : queryId ,
definitionDigest : query.definitionDigest ,
root : query.declaration.root ,
placement : placement?.kind ?? "server" ,
...( placement ? . kind === "local" ? { sourceQuery : placement.sourceQueryId } : {}),
input : portableValueSchema ( query . variables ),
output : portableValueSchema ( query . output ),
};
}
export function linkPackageQuery ( plan : ExecutionPlan , contract : PublicQueryContract ) {
if ( hexDigest ( plan . definition ) !== plan . digest )
throw new ExecutionPlanError ( "INVALID_PLAN" , contract . query , "Invalid execution plan digest" );
const pkg = plan . definition . workspace . packageImports . find (( p ) => p . revisionId === contract . package );
if ( ! pkg || canonicalJson ( publicQueryContract ( pkg , contract . query )) !== canonicalJson ( contract ))
throw new ExecutionPlanError (
"CLIENT_QUERY_MISMATCH" ,
` ${ contract . package } / ${ contract . query } ` ,
"Installed query differs from the imported query contract" ,
);
const query = plan . definition . queries . find (
( q ) => q . query . packageRevisionId === contract . package && q . query . checked . declaration . id === contract . query ,
);
if ( ! query ) throw new ExecutionPlanError ( "UNINSTALLED_QUERY" , contract . query , "No installed query binding" );
return query ;
}
/** Generate only the explicitly imported interfaces. No concrete atom inventory is needed. */
export function generateInterfaceClientBindings (
imports : Readonly < Record < string , InterfaceRevision >>,
runtimeModule = "@quixos/camino-replica-core" ,
2026-09-22 16:19:05 -07:00
moduleProps ?: ( interfaceId : string , memberId : string ) => string ,
2026-09-21 11:23:26 -07:00
) : string {
const entries = Object . entries ( imports ). map (([ alias , iface ]) => {
if ( iface . template )
throw new ExecutionPlanError (
"OPEN_CLIENT_CONTRACT" ,
alias ,
"Specialize the interface before generating a client" ,
);
const members = iface . members . map (( member ) => {
2026-09-22 16:19:05 -07:00
if ( member . kind === "module" && member . subject ? . kind === "interface" ) {
const subject = member . subject . interfaceRevisionId ;
2026-09-25 11:30:37 -07:00
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 , ... moduleTypeContext ( iface ) } )})` ;
2026-09-22 16:19:05 -07:00
}
2026-09-21 11:23:26 -07:00
const operations = member . operations
. filter (( op ) => op . mode === "call" )
. map (
( op ) =>
2026-09-21 14:03:14 -07:00
` ${ JSON . stringify ( op . displayName ) } : defineInterfaceOperation< ${ tsType ( op . inputType ) } , ${ tsType ( op . outputType ) } , ${ JSON . stringify ( publicOperationContract ( iface , op ). execution ) } >( ${ JSON . stringify ( publicOperationContract ( iface , op )) } )` ,
2026-09-21 11:23:26 -07:00
);
return ` ${ JSON . stringify ( member . displayName ) } : { ${ operations . join ( ",\n" ) } }` ;
});
return ` ${ JSON . stringify ( alias ) } : { ${ members . join ( ",\n" ) } }` ;
});
2026-09-22 16:19:05 -07:00
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` ;
2026-09-21 11:23:26 -07:00
}
2026-09-21 14:03:14 -07:00
export function generatePackageQueryClientBindings (
pkg : PackageRevision ,
runtimeModule = "@quixos/camino-replica-core" ,
2026-09-22 15:41:27 -07:00
packages : readonly PackageRevision [] = [ pkg ],
2026-09-21 14:03:14 -07:00
) : string {
2026-09-22 15:41:27 -07:00
const queries = ( pkg . checkedQueries ?? [])
. filter (( query ) => ! query . declaration . fragment )
. map (
( query ) =>
` ${ JSON . stringify ( query . declaration . displayName ) } : definePackageQuery< ${ tsType ( query . variables ) } , ${ tsType ( query . output ) } , ${ JSON . stringify ( publicQueryContract ( pkg , query . declaration . id ). placement ) } >( ${ JSON . stringify ( publicQueryContract ( pkg , query . declaration . id )) } )` ,
);
const emitFragment = ( provider : PackageRevision , id : string ) => {
const query = provider . checkedQueries ? . find (( query ) => query . declaration . id === id );
if (
! query ? . declaration . fragment ||
query . declaration . fragment . admission ||
query . declaration . placement ? . kind !== "local" ||
query . output . kind !== "record" ||
! query . output . fields . root
)
throw new ExecutionPlanError ( "UNCHECKED_FRAGMENT" , id , "Expected a checked local fragment export" );
const output = query . output . fields . root ;
const descriptor = {
package : provider . revisionId ,
fragment : id ,
digest : query.definitionDigest ,
subject : query.declaration.root.interface ,
input : portableValueSchema ( query . variables ),
output : portableValueSchema ( output ),
admission : publicQueryContract ( provider , query . declaration . placement . sourceQueryId ),
view : publicQueryContract ( provider , id ),
};
return `definePackageFragment< ${ tsType ( query . variables ) } , ${ tsType ( output ) } , ${ JSON . stringify ( query . declaration . root . interface ) } >( ${ JSON . stringify ( descriptor ) } )` ;
};
const fragments = ( pkg . checkedQueries ?? [])
. filter (( query ) => query . declaration . fragment && ! query . declaration . fragment . admission )
. map (( query ) => ` ${ JSON . stringify ( query . declaration . displayName ) } : ${ emitFragment ( pkg , query . declaration . id ) } ` );
const imports = new Map < string , Map < string , string >>();
for ( const query of pkg . queries ?? [])
for ( const imported of query . importedFragments ?? []) {
if ( imported . packageRevisionId === pkg . revisionId ) continue ;
const provider = packages . find (( provider ) => provider . revisionId === imported . packageRevisionId );
const name = provider ? . queries ? . find (( query ) => query . id === imported . fragmentId ) ? . displayName ;
if ( ! provider || ! name )
throw new ExecutionPlanError ( "UNCHECKED_FRAGMENT" , imported . fragmentId , "Missing imported fragment provider" );
const alias = imported . packageAlias ?? provider . displayName ;
if ( pkg . queries ? . some (( query ) => query . fragment && query . displayName === alias ))
throw new ExecutionPlanError (
"FRAGMENT_ALIAS_COLLISION" ,
alias ,
"Imported fragment namespace conflicts with a local fragment export" ,
);
const entries = imports . get ( alias ) ?? new Map < string , string >();
entries . set ( name , emitFragment ( provider , imported . fragmentId ));
imports . set ( alias , entries );
}
for ( const [ alias , entries ] of imports )
fragments . push (
` ${ JSON . stringify ( alias ) } : { ${ [... entries ]. map (([ name , value ]) => ` ${ JSON . stringify ( name ) } : ${ value } ` ). join ( "," ) } }` ,
);
return `// Generated from checked package query contracts. Regenerate; do not edit. \ nimport { definePackageQuery, definePackageFragment, type ManagedReference } from ${ JSON . stringify ( runtimeModule ) } ; \ nexport const queries = { ${ queries . join ( ",\n" ) } } as const; \ nexport const fragments = { ${ fragments . join ( ",\n" ) } } as const; \ n` ;
2026-09-21 14:03:14 -07:00
}
2026-09-21 15:24:05 -07:00
/** Receipt-covered bindings expose the package's imports, component subjects and
* declared queries, never the workspace's complete atom/interface inventory. */
export function generateComponentClientBindings ( plan : ExecutionPlan , packageRevision : string ) : string {
const pkg = plan . definition . workspace . packageImports . find (( pkg ) => pkg . revisionId === packageRevision );
2026-09-22 13:16:23 -07:00
const components = plan . definition . packages . find (( pkg ) => pkg . revision === packageRevision ) ? . components ;
2026-09-22 13:51:32 -07:00
const modules = plan . definition . packages . find (( pkg ) => pkg . revision === packageRevision ) ? . modules ?? [];
2026-09-22 13:16:23 -07:00
if ( ! pkg || ! components ? . length )
2026-09-21 15:24:05 -07:00
throw new ExecutionPlanError ( "NO_COMPONENT_CONTRACT" , packageRevision , "Package declares no component entries" );
const byId = new Map ( plan . definition . workspace . interfaceImports . map (( iface ) => [ iface . revisionId as string , iface ]));
const find = ( id : string ) => {
const contract = byId . get ( id );
if ( ! contract || contract . template )
throw new ExecutionPlanError ( "OPEN_CLIENT_CONTRACT" , id , "Component contracts must be closed" );
return contract ;
};
const imports = Object . fromEntries (
Object . entries ( pkg . clientInterfaces ?? {}). map (([ alias , id ]) => [ alias , find ( id )]),
);
2026-09-22 13:16:23 -07:00
const subjects = Object . fromEntries ( components . map (( component ) => [ component . displayName , find ( component . subject )]));
2026-09-22 16:19:05 -07:00
const props = ( iface : string , member : string ) =>
`ExtraModuleProps< ${ JSON . stringify ( JSON . stringify ([ iface , member ])) } >` ;
2026-09-25 12:11:01 -07:00
// Preserve closed type arguments for the artifact consumer. Interpretation of
// a particular module contract belongs to that consumer, not this compiler.
2026-09-25 12:26:34 -07:00
const moduleArguments = ( iface : InterfaceRevision ) =>
`[ ${ ( iface . application ? . arguments ?? [])
. map (( argument ) => {
if ( argument . kind === "value" ) return tsType ( argument . type );
const target = argument . target ;
const reference =
target . kind === "atom"
? `ManagedReference<"atom", ${ JSON . stringify ( target . atomId ) } >`
: `ManagedReference<"interface", ${ JSON . stringify ( target . interfaceRevisionId ) } >` ;
const fields =
target . kind === "interface"
? find ( target . interfaceRevisionId ). members . flatMap (( member ) => {
if (( member . kind !== "value" && member . kind !== "relationship" ) || ! member . queryRead ) return [];
const getter = member . operations . find (
( operation ) => operation . displayName === ( member . kind === "value" ? "get" : "resolve" ),
);
return getter ? [ `readonly ${ JSON . stringify ( member . displayName ) } : ${ tsType ( getter . outputType ) } ` ] : [];
} )
: [];
return ` { readonly reference : $ { reference }; readonly values : { $ { fields . join ( ";" )}}} `;
})
.join(",")}]` ;
2026-09-22 16:19:05 -07:00
const interfaces = generateInterfaceClientBindings ( imports , "@quixos/camino-react" , props );
const subjectBindings = generateInterfaceClientBindings ( subjects , "@quixos/camino-react" , props )
2026-09-21 15:24:05 -07:00
. split ( "\n" )
. filter (( line ) => ! line . startsWith ( "import " ))
. join ( "\n" )
. replace ( "export const interfaces =" , "export const subjects =" );
2026-09-22 15:41:27 -07:00
const queries = generatePackageQueryClientBindings (
pkg ,
"@quixos/camino-react" ,
plan . definition . workspace . packageImports ,
)
2026-09-21 15:24:05 -07:00
. split ( "\n" )
. filter (( line ) => ! line . startsWith ( "import " ))
. join ( "\n" );
return (
interfaces +
2026-09-27 16:34:53 -07:00
'\nimport {createObjectRenderer,definePackageQuery,definePackageFragment,type ComponentType,type ComponentProps,type PreparedPresentation} from "@quixos/camino-react";\n' +
2026-09-21 15:24:05 -07:00
subjectBindings +
"\n" +
queries +
2026-09-22 16:19:05 -07:00
` \ 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` +
2026-09-22 13:51:32 -07:00
"\nexport interface ModuleProps {}\n" +
"export type ExtraModuleProps<K extends string> = K extends keyof ModuleProps ? ModuleProps[K] : {};\n" +
"export interface Modules {\n" +
2026-09-22 13:16:23 -07:00
components
2026-09-22 13:51:32 -07:00
. map (( component ) => {
const module = modules . find (( module ) => module . id === component . id ) ! ;
const key = JSON . stringify ([ module . interfaceRevisionId , module . memberId ]);
2026-09-27 16:34:53 -07:00
const artifact = pkg . buildArtifacts ? .[ "org.quixos.react.preparation/1" ] as
| import ( "../react-build/declarations.js" ). ReactPreparationArtifact
| undefined ;
const preparation = artifact ? . modules . find (( entry ) => entry . module === module . id );
const composition = pkg . queryCompositions ? . find (( entry ) => entry . id === preparation ? . composition );
if ( ! preparation || ! composition )
throw new ExecutionPlanError ( "MISSING_PRESENTATION_INPUTS" , module . id , "Declare inputs in quixos.react.json" );
const children = preparation . children . map (( child ) => {
let extra = "{}" ;
if ( child . role ) {
const iface = find ( child . role . interface );
const member = iface . members . find (
( entry ) => entry . id === child . role ! . member || entry . displayName === child . role ! . member ,
) ! ;
extra = props ( iface . revisionId , member . id );
}
const handle = `PreparedPresentation< ${ JSON . stringify ( child . subject ) } , ${ extra } >` ;
return `readonly ${ JSON . stringify ( child . name ) } : ${ child . each ? `readonly ${ handle } []` : child . with || child . when ? ` ${ handle } | null` : handle } ` ;
});
const input = ` ${ tsType ( composition . output ) } & {readonly children: { ${ children . join ( ";" ) } }}` ;
return ` ${ JSON . stringify ( component . displayName ) } : ComponentType<ComponentProps< ${ JSON . stringify ( component . subject ) } , ${ JSON . stringify ( module . contract ) } , ${ moduleArguments ( find ( module . interfaceRevisionId )) } , ${ input } > & ExtraModuleProps< ${ JSON . stringify ( key ) } >>;` ;
2026-09-22 13:51:32 -07:00
})
2026-09-21 15:24:05 -07:00
. join ( "\n" ) +
"\n}\n"
);
}
export function componentAssetDeclarations () : string {
return (
"// Generated component asset modules. Regenerate; do not edit.\n" +
[ "svg" , "png" , "jpg" , "jpeg" , "gif" , "webp" , "avif" , "woff" , "woff2" , "ttf" , "ico" ]
. map (( extension ) => `declare module "*. ${ extension } " { const value: string; export default value; }` )
. join ( "\n" ) +
'\ndeclare module "*.css";\n'
);
}