2026-09-20 01:49:56 -07:00
import { hexDigest , type ExecutionPlan } from "../execution-world/plan.js" ;
import { resultInterfaces } from "../execution-world/projections.js" ;
import { portableValueSchema , tsType , PortableBindingError } from "./portable.js" ;
/** Closed-world app descriptors. Handler bindings and application acquisition share the same public identities. */
export function generatePortableClientBindings (
plan : ExecutionPlan ,
options : { target : string ; runtimeModule? : string },
) : string {
if ( hexDigest ( plan . definition ) !== plan . digest ) throw new PortableBindingError ( "client" , "Invalid plan digest" );
const workspace = plan . definition . workspace ,
atoms = new Map < string , string [] >(),
unavailable : { key : string ; reason : string }[] = [];
const seen = new Set < string >();
for ( const operation of plan . definition . operations ) {
if ( operation . execution . kind === "remote" || ! operation . execution . targets . includes ( options . target )) {
unavailable . push ({ key : operation.key , reason : "OPERATION_NOT_PORTABLE" });
continue ;
}
let input : string , output : string ;
try {
input = tsType ( operation . input );
output = tsType ( operation . output );
} catch ( error ) {
if ( ! ( error instanceof PortableBindingError )) throw error ;
unavailable . push ({ key : operation.key , reason : "UNSUPPORTED_OPERATION_CODEC" });
continue ;
}
const atom = workspace . atoms . find (( a ) => a . id === operation . atomId ) ! ;
const iface = workspace . interfaceImports . find (( i ) => i . revisionId === operation . interfaceRevisionId ) ! ;
const member = iface . members . find (( m ) => m . operations . some (( o ) => o . id === operation . operationId )) ! ;
const facet = member . operations . find (( o ) => o . id === operation . operationId ) ! ;
const name = ` ${ iface . displayName } . ${ member . displayName } . ${ facet . displayName } ` ;
const alias = JSON . stringify ([ atom . displayName , name ]);
if ( seen . has ( alias )) throw new PortableBindingError ( alias , "Ambiguous application descriptor alias" );
seen . add ( alias );
const roots = resultInterfaces ( plan , operation . key );
const descriptor = {
key : operation.key ,
plan : plan.digest ,
effect : operation.execution.kind ,
input : portableValueSchema ( operation . input ),
output : portableValueSchema ( operation . output ),
resultInterfaces : roots ,
};
const list = atoms . get ( atom . displayName ) ?? [];
list . push (
` ${ JSON . stringify ( name ) } : defineOperationDescriptor< ${ input } , ${ output } , ${ roots . map (( r ) => JSON . stringify ( r )). join ( " | " ) || "never" } , ${ JSON . stringify ( operation . execution . kind ) } >( ${ JSON . stringify ( descriptor ) } )` ,
);
atoms . set ( atom . displayName , list );
}
const queries = new Map < string , string [] >();
2026-09-20 03:44:49 -07:00
const views = new Map < string , string [] >();
2026-09-20 01:49:56 -07:00
for ( const query of plan . definition . queries ) {
const declaration = query . query . checked . declaration ;
2026-09-20 03:44:49 -07:00
if ( ! declaration . placement ) continue ;
2026-09-20 01:49:56 -07:00
const pkg = workspace . packageImports . find (( p ) => p . revisionId === query . query . packageRevisionId ) ! ;
const alias = JSON . stringify ([ pkg . displayName , declaration . displayName ]);
if ( seen . has ( `query: ${ alias } ` )) throw new PortableBindingError ( alias , "Ambiguous query alias" );
seen . add ( `query: ${ alias } ` );
2026-09-20 03:44:49 -07:00
if ( declaration . placement . kind === "local" ) {
const list = views . get ( pkg . displayName ) ?? [];
list . push (
` ${ JSON . stringify ( declaration . displayName ) } : ${ JSON . stringify ({ id : query.id , plan : plan.digest , source : JSON.stringify ([ query . query . packageRevisionId , declaration . placement . sourceQueryId ]) } )} as const satisfies LocalQueryDescriptor` ,
);
views . set ( pkg . displayName , list );
continue ;
}
2026-09-20 01:49:56 -07:00
const list = queries . get ( pkg . displayName ) ?? [];
list . push (
` ${ JSON . stringify ( declaration . displayName ) } : { id: ${ JSON . stringify ( query . id ) } , plan: ${ JSON . stringify ( plan . digest ) } , root: ${ JSON . stringify ( declaration . root . interface ) } , rootKind: ${ JSON . stringify ( declaration . root . kind ) } } as const satisfies ReplicaProjection< ${ JSON . stringify ( declaration . root . interface ) } , ${ JSON . stringify ( declaration . root . kind ) } >` ,
);
queries . set ( pkg . displayName , list );
}
const groups = ( entries : Map < string , string [] >) =>
[... entries ]. map (([ name , values ]) => ` ${ JSON . stringify ( name ) } : { ${ values . join ( ",\n" ) } }` ). join ( ",\n" );
2026-09-20 03:44:49 -07:00
return `// Generated application descriptors. Regenerate; do not edit. \ nimport { defineOperationDescriptor, type ManagedReference, type ReplicaProjection, type LocalQueryDescriptor } from ${ JSON . stringify ( options . runtimeModule ?? "@quixos/camino-replica-core" ) } ; \ nexport const planDigest = ${ JSON . stringify ( plan . digest ) } ; \ nexport const operations = { ${ groups ( atoms ) } } as const; \ nexport const queries = { ${ groups ( queries ) } } as const; \ nexport const views = { ${ groups ( views ) } } as const; \ nexport const unavailable = ${ JSON . stringify ( unavailable ) } as const; \ n` ;
2026-09-20 01:49:56 -07:00
}