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" ;
2026-09-20 04:55:18 -07:00
import type { QuerySelection } from "../query/types.js" ;
const conditional = ( selections : readonly QuerySelection []) : boolean =>
selections . some (( selection ) => selection . conditions . length > 0 || conditional ( selection . selection ));
2026-09-20 01:49:56 -07:00
/** 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-21 00:10:45 -07:00
const serverProjections = new Map < string , string [] >();
2026-09-20 04:55:18 -07:00
const results = 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 ;
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-21 00:10:45 -07:00
const addResult = () => {
2026-09-20 04:55:18 -07:00
if ( conditional ( query . query . checked . selection )) {
unavailable . push ({ key : query.id , reason : "CONDITIONAL_RESULT_DECODER_UNSUPPORTED" });
2026-09-21 00:10:45 -07:00
return ;
2026-09-20 04:55:18 -07:00
}
const decoders = results . get ( pkg . displayName ) ?? [];
decoders . push (
` ${ JSON . stringify ( declaration . displayName ) } : (data: Json): ${ tsType ( query . query . checked . output ) } => decodeArgument( ${ JSON . stringify ( portableValueSchema ( query . query . checked . output )) } , { codec: "camino-value-v1", usage: "argument", value: data }, { workspace: workspaceId( ${ JSON . stringify ( workspace . workspaceId ) } ), limits: { bytes: ${ declaration . budgets . resultBytes + 128 } , nodes: 100000, depth: 64 } }) as ${ tsType ( query . query . checked . output ) } ` ,
);
results . set ( pkg . displayName , decoders );
2026-09-21 00:10:45 -07:00
};
if ( ! declaration . placement ) {
const operations = query . operations . map (
( key ) => plan . definition . operations . find (( operation ) => operation . key === key ) ! ,
);
if (
operations . some (
( operation ) => operation . execution . kind !== "snapshot" || ! operation . execution . targets . includes ( "server" ),
2026-09-22 15:31:42 -07:00
)
2026-09-21 00:10:45 -07:00
) {
unavailable . push ({ key : query.id , reason : "QUERY_NOT_SNAPSHOT_PROJECTION" });
continue ;
}
const list = serverProjections . get ( pkg . displayName ) ?? [];
list . push (
JSON . stringify ( declaration . displayName ) +
": " +
JSON . stringify ({
kind : "server-projection" ,
id : query.id ,
plan : plan.digest ,
root : declaration.root.interface ,
rootKind : declaration.root.kind ,
}) +
" as const satisfies ServerProjection<" +
JSON . stringify ( declaration . root . interface ) +
", " +
JSON . stringify ( declaration . root . kind ) +
">" ,
);
serverProjections . set ( pkg . displayName , list );
addResult ();
continue ;
}
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 );
addResult ();
2026-09-20 03:44:49 -07:00
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-21 00:10:45 -07:00
return `// Generated application descriptors. Regenerate; do not edit. \ nimport { defineOperationDescriptor, decodeArgument, workspaceId, type Json, type PreparedChange, type ManagedReference, type ReplicaProjection, type ServerProjection, 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 serverProjections = { ${ groups ( serverProjections ) } } as const; \ nexport const results = { ${ groups ( results ) } } as const; \ nexport const unavailable = ${ JSON . stringify ( unavailable ) } as const; \ n` ;
2026-09-20 01:49:56 -07:00
}