2026-07-11 23:01:51 -07:00
import http from "node:http" ;
2026-09-10 18:27:41 -07:00
import { readFileSync } from "node:fs" ;
import { createInvocationRegistry } from "./invocations.js" ;
import { isObjectReference , referenceFromWire , referenceToWire , assertReferenceFree , type QxObjectRef } from "./references.js" ;
2026-09-08 14:27:24 -07:00
export * from "./bindings.js" ;
2026-09-10 18:27:41 -07:00
export { relationshipMap , relationshipList , relationshipSet } from "./relationships.js" ;
2026-07-12 13:42:28 -07:00
import { AsyncLocalStorage } from "node:async_hooks" ;
2026-09-10 18:27:41 -07:00
import { createHmac , randomBytes , randomUUID , timingSafeEqual } from "node:crypto" ;
export { createMigrationContext , migrationObjectId , serveMigration , type MigrationContext , type MigrationInput , type MigrationOutput , type MigrationEdge } from "./migration.js" ;
2026-09-03 15:46:52 -07:00
import { create , equals } from "@bufbuild/protobuf" ;
import { Code , ConnectError , createClient , type Client , type ConnectRouter } from "@connectrpc/connect" ;
import { connectNodeAdapter , createConnectTransport } from "@connectrpc/connect-node" ;
2026-07-11 23:01:51 -07:00
import {
CaminoService ,
CrdtValueSchema ,
ListValueSchema ,
NullValueSchema ,
ObjectValueSchema ,
RefValueSchema ,
ValueSchema ,
type Value ,
} from "./camino/api_pb.js" ;
2026-09-03 15:46:52 -07:00
import { OrchestratorRuntime } from "./quixos/orch_pb.js" ;
2026-07-11 23:01:51 -07:00
import {
2026-07-12 14:04:21 -07:00
DerivedDependencySchema ,
2026-07-11 23:01:51 -07:00
HandshakeResponseSchema ,
InvokeResponseSchema ,
PackageRuntime ,
2026-07-12 14:04:21 -07:00
WatchEventSchema ,
2026-07-11 23:01:51 -07:00
} from "./quixos/runtime_pb.js" ;
2026-09-03 15:46:52 -07:00
import { CapabilityRefSchema } from "./quixos/refs_pb.js" ;
2026-07-11 23:01:51 -07:00
export type CaminoClient = Client < typeof CaminoService >;
2026-09-03 15:46:52 -07:00
export type OrchClient = Client < typeof OrchestratorRuntime >;
2026-07-11 23:01:51 -07:00
2026-09-03 15:46:52 -07:00
export type RuntimeDependency =
| { kind : "state" ; objectId : string ; attachmentId : string }
| { kind : "edge" ; objectId : string ; attachmentId : string ; projectionId : string };
2026-07-11 23:01:51 -07:00
2026-09-03 15:46:52 -07:00
type DependencyScope = {
dependencies : Map < string , RuntimeDependency >;
observe ?: ( dependency : RuntimeDependency ) => Promise < void >;
2026-07-12 13:42:28 -07:00
};
2026-09-03 15:46:52 -07:00
const dependencyKey = ( dependency : RuntimeDependency ) =>
` ${ dependency . kind } : ${ dependency . objectId } : ${ dependency . attachmentId } : ${
dependency . kind === "edge" ? dependency . projectionId : ""
} ` ;
const dependencyScope = new AsyncLocalStorage < DependencyScope >();
const recordDependency = async ( dependency : RuntimeDependency ) => {
const scope = dependencyScope . getStore ();
if ( ! scope ) return ;
const key = ` ${ dependency . kind } : ${ dependency . objectId } : ${ dependency . attachmentId } : ${
dependency . kind === "edge" ? dependency . projectionId : ""
} ` ;
scope . dependencies . set ( key , dependency );
await scope . observe ? .( dependency );
2026-07-12 13:42:28 -07:00
};
2026-09-03 15:46:52 -07:00
const bytesToBase64 = ( value : Uint8Array ) => Buffer . from ( value ). toString ( "base64" );
const base64ToBytes = ( value : string ) => Buffer . from ( value , "base64" );
2026-07-11 23:01:51 -07:00
const isRecord = ( value : unknown ) : value is Record < string , unknown > =>
Boolean ( value ) && typeof value === "object" && ! Array . isArray ( value );
2026-09-03 15:46:52 -07:00
const isWrappedValue = ( value : unknown ) : value is { $quixosValue : Value } =>
isRecord ( value ) && "$quixosValue" in value &&
isRecord ( value . $quixosValue ) && value . $quixosValue . $typeName === "camino.Value" ;
2026-07-11 23:01:51 -07:00
2026-09-10 18:27:41 -07:00
export const objectRef = ( reference : QxObjectRef ) => { referenceToWire ( reference ); return reference ; };
2026-09-03 15:46:52 -07:00
export const liveValue = ( value : Value ) => ({ $quixosValue : value });
2026-07-11 23:01:51 -07:00
2026-09-03 15:46:52 -07:00
export const jsToProtoValue = ( value : unknown ) : Value => {
2026-09-10 18:27:41 -07:00
if ( isObjectReference ( value )) return create ( ValueSchema , { kind : { case : "refValue" , value : create ( RefValueSchema , { objectId : referenceToWire ( value )})}});
2026-09-03 15:46:52 -07:00
if ( isWrappedValue ( value )) return value . $quixosValue ;
2026-07-11 23:01:51 -07:00
if ( value === null || value === undefined ) {
2026-09-03 15:46:52 -07:00
return create ( ValueSchema , { kind : { case : "nullValue" , value : create ( NullValueSchema , {}) } });
2026-07-11 23:01:51 -07:00
}
2026-09-03 15:46:52 -07:00
if ( typeof value === "boolean" ) return create ( ValueSchema , { kind : { case : "boolValue" , value } });
if ( typeof value === "number" ) return create ( ValueSchema , { kind : { case : "numberValue" , value } });
if ( typeof value === "bigint" ) return create ( ValueSchema , { kind : { case : "integerValue" , value : String ( value ) } });
if ( typeof value === "string" ) return create ( ValueSchema , { kind : { case : "stringValue" , value } });
if ( value instanceof Uint8Array ) return create ( ValueSchema , { kind : { case : "bytesValue" , value } });
2026-07-11 23:01:51 -07:00
if ( Array . isArray ( value )) {
return create ( ValueSchema , {
2026-09-03 15:46:52 -07:00
kind : { case : "listValue" , value : create ( ListValueSchema , { values : value.map ( jsToProtoValue ) }) },
2026-07-11 23:01:51 -07:00
});
}
2026-09-10 18:27:41 -07:00
if ( isRecord ( value ) && "$quixosRef" in value ) throw new Error ( "Raw ID wrappers are not object references" );
2026-09-03 15:46:52 -07:00
if ( isRecord ( value ) && typeof value . $quixosCrdtType === "string" &&
typeof value . $quixosCrdtPayload === "string" ) {
return create ( ValueSchema , {
kind : { case : "crdtValue" , value : create ( CrdtValueSchema , {
type : value . $quixosCrdtType ,
encoding : typeof value . $quixosCrdtEncoding === "string" ? value . $quixosCrdtEncoding : "base64" ,
payload : base64ToBytes ( value . $quixosCrdtPayload ),
}) },
});
}
if ( ! isRecord ( value )) throw new Error ( `Unsupported runtime value ${ typeof value } ` );
return create ( ValueSchema , {
kind : { case : "objectValue" , value : create ( ObjectValueSchema , {
fields : Object.fromEntries ( Object . entries ( value ). map (([ key , entry ]) => [ key , jsToProtoValue ( entry )])),
}) },
});
2026-07-11 23:01:51 -07:00
};
export const protoValueToJs = ( value : Value | undefined ) : unknown => {
switch ( value ? . kind . case ) {
case "nullValue" :
2026-09-03 15:46:52 -07:00
case undefined : return null ;
2026-07-11 23:01:51 -07:00
case "boolValue" :
case "numberValue" :
case "stringValue" :
2026-09-03 15:46:52 -07:00
case "integerValue" : return value . kind . value ;
case "bytesValue" : return bytesToBase64 ( value . kind . value );
2026-09-10 18:27:41 -07:00
case "refValue" : return referenceFromWire ( value . kind . value . objectId );
2026-09-03 15:46:52 -07:00
case "listValue" : return value . kind . value . values . map ( protoValueToJs );
case "objectValue" : return Object . fromEntries (
Object . entries ( value . kind . value . fields ). map (([ key , entry ]) => [ key , protoValueToJs ( entry )]),
);
case "crdtValue" : return {
$quixosCrdtType : value.kind.value.type ,
$quixosCrdtEncoding : value.kind.value.encoding ,
$quixosCrdtPayload : bytesToBase64 ( value . kind . value . payload ),
};
2026-07-11 23:01:51 -07:00
}
};
2026-09-03 15:46:52 -07:00
export const protoFieldsToJs = ( fields : Record < string , Value >) =>
Object . fromEntries ( Object . entries ( fields ). map (([ key , value ]) => [ key , protoValueToJs ( value )]));
2026-07-11 23:01:51 -07:00
2026-09-03 15:46:52 -07:00
export type StatePort < T = unknown > = {
slotId : string ;
get () : Promise < T >;
live () : Promise < ReturnType < typeof liveValue >>;
set ( value : T ) : Promise < void >;
2026-07-12 14:32:49 -07:00
};
2026-09-03 15:46:52 -07:00
export type EdgePort = {
edgeTypeId : string ;
projectionId : string ;
2026-09-10 18:27:41 -07:00
resolve () : Promise < QxObjectRef [] >;
connect ( target : QxObjectRef ) : Promise < void >;
disconnect ( target : QxObjectRef ) : Promise < void >;
collection () : Promise < RelationshipCollection >;
replace ( entries : RelationshipEntry [], expectedRevision : bigint ) : Promise < RelationshipCollection >;
2026-09-03 15:46:52 -07:00
};
2026-09-10 18:27:41 -07:00
export type RelationshipEntry < T extends QxObjectRef = QxObjectRef > = { edgeId? : string ; target : T ; key? : string | boolean | bigint };
export type RelationshipCollection < T extends QxObjectRef = QxObjectRef > = { revision : bigint ; entries : RelationshipEntry < T >[]};
2026-09-03 15:46:52 -07:00
export type InterfacePort = {
2026-09-10 18:27:41 -07:00
objectId : QxObjectRef ;
2026-09-03 15:46:52 -07:00
interfaceRevisionId : string ;
invoke ( operationId : string , input? : Record < string , unknown >) : Promise < unknown >;
2026-09-05 12:33:52 -07:00
live ( operationId : string , input? : Record < string , unknown >) : Promise < ReturnType < typeof liveValue >>;
2026-09-03 15:46:52 -07:00
};
export type ConstructorPort = {
atomId : string ;
2026-09-10 18:27:41 -07:00
construct ( input? : Record < string , unknown >) : Promise < QxObjectRef >;
2026-09-03 15:46:52 -07:00
};
export type RuntimePort = StatePort | EdgePort | InterfacePort | ConstructorPort ;
2026-07-12 14:32:49 -07:00
2026-09-03 15:46:52 -07:00
export type RuntimeContext = {
2026-09-10 18:27:41 -07:00
/** Cooperative cancellation. Completion is acknowledged only after the handler returns. */
signal? : AbortSignal ;
openSession ?: () => Promise < RuntimeSession >;
objectId : QxObjectRef ;
2026-09-03 15:46:52 -07:00
input : Record < string , unknown >;
inputProto : Record < string , Value >;
ports : ReadonlyMap < string , RuntimePort >;
state < T = unknown >( portId : string ) : StatePort < T >;
edge ( portId : string ) : EdgePort ;
interface ( portId : string ) : InterfacePort ;
constructor ( portId : string ) : ConstructorPort ;
};
2026-07-12 14:32:49 -07:00
2026-09-10 18:27:41 -07:00
export type RuntimeSession = {
id : string ;
run < T >( work : ( context : RuntimeContext ) => Promise < T >) : Promise < T >;
/** Close the external resource first, then close its host retention/session. */
close () : Promise < void >;
};
export class RuntimeAuthorityError extends Error {
readonly retryable : boolean ;
constructor ( message : string ) { super ( message ); this . name = "RuntimeAuthorityError" ; this . retryable = /WORKSPACE_FENCED|STALE_EPOCH/ . test ( message ); }
}
2026-09-03 15:46:52 -07:00
const targetForEdge = (
edge : { firstObjectId : string ; secondObjectId : string ; firstProjectionId : string },
projectionId : string ,
) => edge . firstProjectionId === projectionId ? edge.secondObjectId : edge.firstObjectId ;
2026-07-12 14:04:21 -07:00
2026-09-03 15:46:52 -07:00
export const createRuntimeContext = (
camino : CaminoClient ,
orch : OrchClient ,
request : RuntimeRequest ,
) : RuntimeContext => {
const ports = new Map < string , RuntimePort >();
for ( const dependency of request . dependencies ) {
switch ( dependency . binding . case ) {
case "stateSlotId" : {
const slotId = dependency . binding . value ;
2026-09-04 21:03:09 -07:00
const dependencyObjectId = dependency . objectId || request . objectId ;
2026-09-03 15:46:52 -07:00
const state : StatePort = {
slotId ,
async get () {
2026-09-04 21:03:09 -07:00
await recordDependency ({ kind : "state" , objectId : dependencyObjectId , attachmentId : slotId });
return protoValueToJs (( await camino . readState ({ objectId : dependencyObjectId , slotId })). value );
2026-09-03 15:46:52 -07:00
},
async live() {
2026-09-04 21:03:09 -07:00
await recordDependency ({ kind : "state" , objectId : dependencyObjectId , attachmentId : slotId });
const value = await camino . readState ({ objectId : dependencyObjectId , slotId });
2026-09-03 15:46:52 -07:00
if ( ! value . value ) throw new Error ( `State ${ slotId } returned no value` );
return liveValue ( value . value );
},
async set ( value ) {
2026-09-10 18:27:41 -07:00
assertReferenceFree ( isWrappedValue ( value ) ? protoValueToJs ( value . $quixosValue ) : value );
2026-09-04 21:03:09 -07:00
await camino . writeState ({ objectId : dependencyObjectId , slotId , value : jsToProtoValue ( value ) });
2026-09-03 15:46:52 -07:00
},
};
ports . set ( dependency . portId , state );
break ;
}
case "edge" : {
const { edgeTypeId , projectionId } = dependency . binding . value ;
2026-09-04 21:03:09 -07:00
const dependencyObjectId = dependency . objectId || request . objectId ;
2026-09-10 18:27:41 -07:00
const collectionResult = ( response : { revision : bigint ; entries : { edgeId : string ; targetObjectId : string ; key? : Value }[]}) : RelationshipCollection => ({ revision : response.revision ,
entries : response.entries.map (( entry ) => ({ edgeId : entry.edgeId , target : referenceFromWire ( entry . targetObjectId ),
...( entry . key ? { key : entry.key.kind.case === "integerValue" ? BigInt ( entry . key . kind . value ) : protoValueToJs ( entry . key ) as string | boolean } : {})}))});
2026-09-03 15:46:52 -07:00
const edge : EdgePort = {
edgeTypeId ,
projectionId ,
2026-09-10 18:27:41 -07:00
async collection() {
await recordDependency ({ kind : "edge" , objectId : dependencyObjectId , attachmentId : edgeTypeId , projectionId });
return collectionResult ( await camino . readCollection ({ objectId : dependencyObjectId , edgeTypeId , projectionId }));
},
async replace ( entries , expectedRevision ) {
return collectionResult ( await camino . replaceCollection ({ objectId : dependencyObjectId , edgeTypeId , projectionId , expectedRevision ,
entries : entries.map (( entry ) => {
assertReferenceFree ( entry . key );
return { edgeId : entry.edgeId ?? "" , targetObjectId : referenceToWire ( entry . target ), key : entry.key === undefined ? undefined : jsToProtoValue ( entry . key )};
})}));
},
2026-09-03 15:46:52 -07:00
async resolve() {
2026-09-04 21:03:09 -07:00
await recordDependency ({ kind : "edge" , objectId : dependencyObjectId , attachmentId : edgeTypeId , projectionId });
const result = await camino . resolveEdge ({ objectId : dependencyObjectId , edgeTypeId , projectionId });
2026-09-10 18:27:41 -07:00
return result . edges . map (( entry ) => referenceFromWire ( targetForEdge ( entry , projectionId )));
2026-09-03 15:46:52 -07:00
},
2026-09-10 18:27:41 -07:00
async connect ( target ) {
const targetObjectId = referenceToWire ( target );
2026-09-04 21:03:09 -07:00
await camino . connectEdge ({ objectId : dependencyObjectId , edgeTypeId , projectionId , targetObjectId });
2026-09-03 15:46:52 -07:00
},
2026-09-10 18:27:41 -07:00
async disconnect ( target ) {
const targetObjectId = referenceToWire ( target );
2026-09-08 14:27:24 -07:00
const result = await camino . resolveEdge ({ objectId : dependencyObjectId , edgeTypeId , projectionId });
for ( const entry of result . edges ) {
if ( targetForEdge ( entry , projectionId ) === targetObjectId ) await camino . disconnectEdge ({ edgeId : entry.id });
}
},
2026-09-03 15:46:52 -07:00
};
ports . set ( dependency . portId , edge );
break ;
}
2026-09-05 12:33:52 -07:00
case "interfaceRevisionId" : {
2026-09-03 15:46:52 -07:00
const interfaceRevisionId = dependency . binding . value ;
2026-09-05 12:33:52 -07:00
const dependencyObjectId = dependency . objectId || request . objectId ;
const invoke = async ( operationId : string , input : Record < string , unknown >) => {
const response = await orch . invokeCapability ({
capability : create ( CapabilityRefSchema , { interfaceRevisionId , operationId }),
objectId : dependencyObjectId ,
input : Object.fromEntries ( Object . entries ( input ). map (([ key , value ]) => [ key , jsToProtoValue ( value )])),
});
if ( ! response . ok ) throw new Error ( response . error || `Capability ${ operationId } failed` );
for ( const dependency of response . dependencies ) {
if ( dependency . kind === "state" ) {
await recordDependency ({
kind : "state" ,
objectId : dependency.objectId ,
attachmentId : dependency.attachmentId ,
});
} else if ( dependency . kind === "edge" ) {
await recordDependency ({
kind : "edge" ,
objectId : dependency.objectId ,
attachmentId : dependency.attachmentId ,
projectionId : dependency.projectionId ,
});
}
}
return response . result ;
};
2026-09-03 15:46:52 -07:00
const capability : InterfacePort = {
2026-09-10 18:27:41 -07:00
objectId : referenceFromWire ( dependencyObjectId ),
2026-09-03 15:46:52 -07:00
interfaceRevisionId ,
async invoke ( operationId , input = {}) {
2026-09-05 12:33:52 -07:00
return protoValueToJs ( await invoke ( operationId , input ));
},
async live ( operationId , input = {}) {
const value = await invoke ( operationId , input );
if ( ! value ) throw new Error ( `Capability ${ operationId } returned no value` );
return liveValue ( value );
2026-09-03 15:46:52 -07:00
},
};
ports . set ( dependency . portId , capability );
break ;
}
case "constructorAtomId" : {
const atomId = dependency . binding . value ;
const constructor : ConstructorPort = {
atomId ,
async construct ( input = {}) {
const response = await orch . constructObject ({
atomId ,
input : Object.fromEntries ( Object . entries ( input ). map (([ key , value ]) => [ key , jsToProtoValue ( value )])),
});
if ( ! response . object ) throw new Error ( `Constructor ${ atomId } returned no object` );
2026-09-10 18:27:41 -07:00
return referenceFromWire ( response . object . id );
2026-09-03 15:46:52 -07:00
},
};
ports . set ( dependency . portId , constructor );
}
}
2026-07-12 18:44:16 -07:00
}
2026-09-03 15:46:52 -07:00
const requirePort = < T extends RuntimePort >( portId : string , kind : string ) => {
const port = ports . get ( portId );
if ( ! port || ! ( kind in port )) throw new Error ( `Missing ${ kind } dependency port ${ portId } ` );
return port as T ;
};
2026-07-12 18:44:16 -07:00
return {
2026-09-10 18:27:41 -07:00
objectId : referenceFromWire ( request . objectId ),
2026-09-03 15:46:52 -07:00
input : protoFieldsToJs ( request . input ),
inputProto : request.input ,
ports ,
state : < T >( portId : string ) => requirePort < StatePort < T >>( portId , "slotId" ),
edge : ( portId : string ) => requirePort < EdgePort >( portId , "edgeTypeId" ),
interface : ( portId : string ) => requirePort < InterfacePort >( portId , "interfaceRevisionId" ),
constructor : ( portId : string ) => requirePort < ConstructorPort >( portId , "atomId" ),
2026-07-12 18:44:16 -07:00
};
};
2026-09-03 15:46:52 -07:00
export type RuntimeHandler = ( context : RuntimeContext ) => unknown | Promise < unknown >;
export type DerivedHandler = { kind : "derived" ; get : RuntimeHandler };
export const derived = ( get : RuntimeHandler ) : DerivedHandler => ({ kind : "derived" , get });
const isDerived = ( handler : RuntimeHandler | DerivedHandler ) : handler is DerivedHandler =>
typeof handler === "object" && handler . kind === "derived" ;
const evaluate = async (
handler : RuntimeHandler | DerivedHandler ,
context : RuntimeContext ,
observe ?: ( dependency : RuntimeDependency ) => Promise < void >,
2026-07-12 18:44:16 -07:00
) => {
2026-09-03 15:46:52 -07:00
const dependencies = new Map < string , RuntimeDependency >();
const result = await dependencyScope . run (
{ dependencies , observe },
() => isDerived ( handler ) ? handler . get ( context ) : handler ( context ),
);
return { value : jsToProtoValue ( result ), dependencies : [... dependencies . values ()] };
2026-07-12 18:44:16 -07:00
};
2026-09-03 15:46:52 -07:00
const protoDependencies = ( dependencies : RuntimeDependency []) => dependencies . map (( entry ) =>
create ( DerivedDependencySchema , {
kind : entry.kind ,
objectId : entry.objectId ,
attachmentId : entry.attachmentId ,
projectionId : entry.kind === "edge" ? entry . projectionId : "" ,
}));
2026-07-12 14:04:21 -07:00
2026-09-03 15:46:52 -07:00
export const createPackageRuntimeRoutes = ( config : {
packageRevisionId : string ;
exports : Record < string , RuntimeHandler | DerivedHandler >;
caminoUrl? : string ;
orchUrl? : string ;
}) => {
2026-09-10 18:27:41 -07:00
const invocations = createInvocationRegistry ();
2026-09-03 15:46:52 -07:00
const headers : Record < string , string > = {};
2026-09-10 18:27:41 -07:00
const processToken = process . env . CAMINO_RUNTIME_AUTH_TOKEN ?? ( process . env . CAMINO_RUNTIME_AUTH_TOKEN_FILE
? readFileSync ( process . env . CAMINO_RUNTIME_AUTH_TOKEN_FILE , "utf8" ). trim () : "" );
if ( processToken ) {
headers [ "x-camino-runtime-token" ] = processToken ;
2026-09-03 15:46:52 -07:00
} else if ( process . env . CAMINO_RUNTIME_AUTH_REQUIRED === "1" ) {
throw new Error ( "CAMINO_RUNTIME_AUTH_TOKEN is required" );
2026-07-12 14:04:21 -07:00
}
2026-09-03 15:46:52 -07:00
const camino = createClient ( CaminoService , createConnectTransport ({
baseUrl : config.caminoUrl ?? process . env . CAMINO_URL ?? "http://127.0.0.1:7310" ,
httpVersion : "1.1" ,
interceptors : headers [ "x-camino-runtime-token" ] ? [
( next ) => async ( request ) => {
request . header . set ( "x-camino-runtime-token" , headers [ "x-camino-runtime-token" ] ! );
return await next ( request );
},
] : [],
}));
const orch = createClient ( OrchestratorRuntime , createConnectTransport ({
baseUrl : config.orchUrl ?? process . env . QUIXOS_ORCH_URL ?? "http://127.0.0.1:7311" ,
httpVersion : "1.1" ,
}));
2026-07-12 14:04:21 -07:00
2026-09-10 18:27:41 -07:00
const authenticateInstance = ( header : Headers ) => {
if ( ! process . env . QUIXOS_RUNTIME_INSTANCE_ID ) return ; // standalone development ABI
const supplied = Buffer . from ( header . get ( "x-quixos-instance-token" ) ?? "" );
const expected = Buffer . from ( processToken );
if ( ! expected . length || supplied . length !== expected . length || ! timingSafeEqual ( supplied , expected )) {
throw new ConnectError ( "Invalid runtime instance credential" , Code . Unauthenticated );
}
};
const clientsFor = ( request : { context ?: { grant : string ; instanceId : string ; workspaceEpoch : string } }) => {
const context = request . context ;
if ( process . env . QUIXOS_RUNTIME_INSTANCE_ID && ( ! context ? . grant || context . instanceId !== process . env . QUIXOS_RUNTIME_INSTANCE_ID || ! context . workspaceEpoch )) {
throw new ConnectError ( "Managed invocation requires an exact instance and epoch grant" , Code . Unauthenticated );
}
if ( ! context ? . grant ) return { camino , orch };
const transport = ( url : string ) => createConnectTransport ({ baseUrl : url , httpVersion : "1.1" , interceptors : [( next ) => async ( call ) => {
call . header . set ( "x-quixos-invocation-grant" , context . grant );
call . header . set ( "x-camino-runtime-token" , processToken );
return next ( call );
}] });
return {
camino : createClient ( CaminoService , transport ( config . caminoUrl ?? process . env . CAMINO_URL ?? "http://127.0.0.1:7310" )),
orch : createClient ( OrchestratorRuntime , transport ( config . orchUrl ?? process . env . QUIXOS_ORCH_URL ?? "http://127.0.0.1:7311" )),
};
};
const runtimeControl = async < T >( operation : string , input : unknown ) : Promise < T > => {
const response = await fetch ( ` ${ config . caminoUrl ?? process . env . CAMINO_URL ?? "http://127.0.0.1:7310" } /__runtime/ ${ operation } ` , {
method : "POST" , headers : { "content-type" : "application/json" , "x-camino-runtime-token" : processToken }, body : JSON.stringify ( input ), signal : AbortSignal.timeout ( 10 _000 ),
});
const value = await response . json () as T & { error? : string };
if ( ! response . ok ) throw new RuntimeAuthorityError ( value . error ?? "Runtime authority request failed" );
return value ;
};
const attachSessions = ( runtimeContext : RuntimeContext , request : RuntimeRequest & { context ?: { grant : string ; instanceId : string ; workspaceEpoch : string ; ownerConformanceId? : string }}) => {
if ( ! request . context ? . grant || ! request . context . ownerConformanceId ) return ;
runtimeContext . openSession = async () => {
const ownerId = request . context ! . ownerConformanceId ! ;
const registration = { grant : request.context ! . grant , objectId : request.objectId , ownerId ,
sessionId : `session: ${ randomBytes ( 16 ). toString ( "hex" ) } ` , token : randomBytes ( 32 ). toString ( "base64url" ) };
const register = () => runtimeControl < { sessionId : string ; token : string } > ( "register-session" , registration );
const registered = await register (). catch (( error ) => {
// Retry a transport/lost-response failure with exactly the same identity.
// Admission/authority errors are definitive and must not be retried here.
if ( error instanceof RuntimeAuthorityError ) throw error ;
return register ();
});
let closed = false ;
return {
id : registered.sessionId ,
async run ( work ) {
if ( closed ) throw new RuntimeAuthorityError ( "SESSION_CLOSED" );
// Acquisition happens before user code. A fence failure can be retried
// by the caller without replaying a side-effecting callback.
const grant = await runtimeControl < { grant : string ; epoch : string ; instanceId : string ; invocationId : string ; bindingDigest : string } > ( "acquire-session" , registered );
const execution = invocations . begin ( grant . invocationId );
const sessionRequest = { ... request , context : { grant : grant.grant , instanceId : grant.instanceId , workspaceEpoch : grant.epoch } };
const clients = clientsFor ( sessionRequest );
const context = createRuntimeContext ( clients . camino , clients . orch , sessionRequest );
context . signal = execution . signal ;
try { return await work ( context ); }
finally {
execution . finish ();
await runtimeControl ( "complete-invocation" , { invocationId : grant.invocationId }). catch (( error ) => console . error ( "Session completion will be reconciled by the host" , error ));
}
},
async close() { await runtimeControl ( "close-session" , registered ); closed = true ; },
};
};
};
2026-09-03 15:46:52 -07:00
return ( router : ConnectRouter ) => router . service ( PackageRuntime , {
2026-09-10 18:27:41 -07:00
handshake : ( request ) => create ( HandshakeResponseSchema , {
2026-09-03 15:46:52 -07:00
packageRevisionId : config.packageRevisionId ,
runtimeProtocolVersion : "quixos-capabilities-v1" ,
exportIds : Object.keys ( config . exports ),
2026-09-10 18:27:41 -07:00
capabilities : [ "invocation-completion-v1" , "instance-authentication-v1" , "epoch-grants-v1" ],
instanceId : process.env.QUIXOS_RUNTIME_INSTANCE_ID ?? "" ,
authenticationProof : request.nonce && processToken ? createHmac ( "sha256" , processToken )
. update ( JSON . stringify ([ request . nonce , process . env . QUIXOS_RUNTIME_INSTANCE_ID ?? "" , config . packageRevisionId ]))
. digest ( "hex" ) : "" ,
2026-09-03 15:46:52 -07:00
}),
2026-09-10 18:27:41 -07:00
getInvocationStatus : ( request , context ) => {
authenticateInstance ( context . requestHeader );
return invocations . status ( request . invocationId );
},
cancelInvocation : ( request , context ) => {
authenticateInstance ( context . requestHeader );
return invocations . cancel ( request . invocationId );
},
invoke : async ( request , context ) => {
authenticateInstance ( context . requestHeader );
const { camino , orch } = clientsFor ( request );
2026-09-03 15:46:52 -07:00
const exportId = request . export ? . exportId ;
const handler = exportId ? config . exports [ exportId ] : undefined ;
if ( ! handler ) throw new ConnectError ( `Unknown export ${ exportId ?? "" } ` , Code . NotFound );
2026-09-10 18:27:41 -07:00
const execution = invocations . begin ( request . invocationId || ( process . env . QUIXOS_RUNTIME_INSTANCE_ID ? "" : randomUUID ()));
2026-09-03 15:46:52 -07:00
try {
2026-09-10 18:27:41 -07:00
const runtimeContext = createRuntimeContext ( camino , orch , request );
attachSessions ( runtimeContext , request );
runtimeContext . signal = AbortSignal . any ([ context . signal , execution . signal ]);
const result = await evaluate ( handler , runtimeContext );
execution . finish ();
2026-09-05 12:33:52 -07:00
return create ( InvokeResponseSchema , {
ok : true ,
result : result.value ,
dependencies : protoDependencies ( result . dependencies ),
});
2026-09-03 15:46:52 -07:00
} catch ( error ) {
2026-09-10 18:27:41 -07:00
execution . finish ( true );
2026-09-03 15:46:52 -07:00
return create ( InvokeResponseSchema , {
ok : false ,
error : error instanceof Error ? error.message : String ( error ),
});
2026-07-12 20:19:44 -07:00
}
},
2026-09-03 15:46:52 -07:00
watch : async function * ( request , context ) {
2026-09-10 18:27:41 -07:00
authenticateInstance ( context . requestHeader );
const { camino , orch } = clientsFor ( request );
2026-09-03 15:46:52 -07:00
const exportId = request . export ? . exportId ;
const handler = exportId ? config . exports [ exportId ] : undefined ;
if ( ! handler || ! isDerived ( handler )) {
throw new ConnectError ( `Export ${ exportId ?? "" } is not derived` , Code . FailedPrecondition );
}
2026-09-10 18:27:41 -07:00
const execution = invocations . begin ( request . invocationId || ( process . env . QUIXOS_RUNTIME_INSTANCE_ID ? "" : randomUUID ()));
const signal = AbortSignal . any ([ context . signal , execution . signal ]);
try {
2026-09-03 15:46:52 -07:00
const watchId = `watch: ${ randomUUID () } ` ;
const runtimeContext = createRuntimeContext ( camino , orch , request );
2026-09-10 18:27:41 -07:00
attachSessions ( runtimeContext , request );
runtimeContext . signal = signal ;
2026-09-03 15:46:52 -07:00
type WatchOutcome = { key : string ; done : boolean ; error? : unknown };
type Subscription = {
dependency : RuntimeDependency ;
controller : AbortController ;
next : Promise < WatchOutcome >;
waitNext : () => Promise < WatchOutcome >;
};
const subscriptions = new Map < string , Subscription >();
const establishing = new Map < string , Promise < void >>();
2026-09-05 12:33:52 -07:00
let subscriptionEpoch = 0 ;
2026-07-12 20:19:44 -07:00
2026-09-03 15:46:52 -07:00
const ensureSubscription = async ( dependency : RuntimeDependency ) => {
const key = dependencyKey ( dependency );
if ( subscriptions . has ( key )) return ;
const pending = establishing . get ( key );
if ( pending ) return await pending ;
const establish = ( async () => {
const controller = new AbortController ();
const stream = camino . watchObject (
2026-09-10 18:27:41 -07:00
{ objectId : dependency.objectId , includeSnapshot : true , attachmentIds : request.context?.grant ? [ dependency . attachmentId ] : [] },
2026-09-03 15:46:52 -07:00
{ signal : controller.signal },
)[ Symbol . asyncIterator ]();
try {
// Camino subscribes before producing the snapshot, so once this
// resolves the following state/edge read cannot race the stream.
const snapshot = await stream . next ();
if ( snapshot . done ) throw new Error ( `Dependency stream ${ key } ended during setup` );
const waitNext = () => stream . next (). then (
( result ) => ({ key , done : Boolean ( result . done ) }),
( error : unknown ) => ({ key , done : true , error }),
);
const subscription : Subscription = {
dependency ,
controller ,
waitNext ,
next : Promise.resolve ({ key , done : false }),
};
subscription . next = waitNext ();
subscriptions . set ( key , subscription );
2026-09-05 12:33:52 -07:00
subscriptionEpoch += 1 ;
2026-09-03 15:46:52 -07:00
} catch ( error ) {
controller . abort ();
throw error ;
}
})();
establishing . set ( key , establish );
try {
await establish ;
} finally {
establishing . delete ( key );
}
};
const abortAll = () => {
for ( const subscription of subscriptions . values ()) {
subscription . controller . abort ();
}
};
2026-09-10 18:27:41 -07:00
signal . addEventListener ( "abort" , abortAll , { once : true });
2026-09-03 15:46:52 -07:00
2026-09-05 12:33:52 -07:00
const evaluateWithStableSubscriptions = async () => {
// A direct state/edge port records its dependency before reading it,
// but a nested interface invocation can only report its transitive
// dependencies after that invocation returns. Once a new dependency
// stream is established, evaluate again so every read contributing to
// the emitted value happened after its stream became live.
for ( let pass = 0 ; pass < 32 ; pass += 1 ) {
const before = subscriptionEpoch ;
const result = await evaluate ( handler , runtimeContext , ensureSubscription );
if ( subscriptionEpoch === before ) return result ;
}
throw new Error ( "Derived dependency discovery did not stabilize after 32 passes" );
};
2026-09-10 18:27:41 -07:00
try {
2026-09-05 12:33:52 -07:00
let current = await evaluateWithStableSubscriptions ();
2026-09-03 15:46:52 -07:00
yield create ( WatchEventSchema , {
watchId ,
value : current.value ,
dependencies : protoDependencies ( current . dependencies ),
initial : true ,
});
const abort = new Promise < "abort" > (( resolve ) => {
2026-09-10 18:27:41 -07:00
if ( signal . aborted ) resolve ( "abort" );
else signal . addEventListener ( "abort" , () => resolve ( "abort" ), { once : true });
2026-09-03 15:46:52 -07:00
});
2026-09-10 18:27:41 -07:00
while ( ! signal . aborted ) {
2026-09-03 15:46:52 -07:00
if ( subscriptions . size === 0 ) {
await abort ;
break ;
}
const outcome = await Promise . race ([
...[... subscriptions . values ()]. map (( entry ) => entry . next ),
abort ,
]);
if ( outcome === "abort" ) break ;
const subscription = subscriptions . get ( outcome . key );
if ( ! subscription ) continue ;
if ( outcome . error ) throw outcome . error ;
if ( outcome . done ) throw new Error ( `Dependency stream ${ outcome . key } ended unexpectedly` );
subscription . next = subscription . waitNext ();
2026-09-05 12:33:52 -07:00
const updated = await evaluateWithStableSubscriptions ();
2026-09-03 15:46:52 -07:00
const active = new Set ( updated . dependencies . map ( dependencyKey ));
for ( const [ key , entry ] of subscriptions ) {
if ( ! active . has ( key )) {
entry . controller . abort ();
subscriptions . delete ( key );
}
}
if ( ! equals ( ValueSchema , current . value , updated . value )) {
yield create ( WatchEventSchema , {
watchId ,
value : updated.value ,
dependencies : protoDependencies ( updated . dependencies ),
2026-07-12 13:42:28 -07:00
});
}
2026-09-03 15:46:52 -07:00
current = updated ;
}
} finally {
2026-09-10 18:27:41 -07:00
signal . removeEventListener ( "abort" , abortAll );
2026-09-03 15:46:52 -07:00
abortAll ();
2026-07-12 13:42:28 -07:00
}
2026-09-10 18:27:41 -07:00
} finally { execution . finish (); }
2026-07-12 13:42:28 -07:00
},
});
2026-09-03 15:46:52 -07:00
};
2026-07-12 13:42:28 -07:00
2026-09-03 15:46:52 -07:00
export const servePackageRuntime = ( config : {
packageRevisionId : string ;
exports : Record < string , RuntimeHandler | DerivedHandler >;
2026-07-11 23:01:51 -07:00
}) => {
const host = process . env . QUIXOS_RUNTIME_HOST ?? "127.0.0.1" ;
const port = Number ( process . env . QUIXOS_RUNTIME_PORT ?? "0" );
2026-09-03 15:46:52 -07:00
const handler = connectNodeAdapter ({ routes : createPackageRuntimeRoutes ( config ) });
const server = http . createServer (( request , response ) => void handler ( request , response ));
server . listen ( port , host , () => console . log ( ` ${ config . packageRevisionId } listening on ${ host } : ${ port } ` ));
const shutdown = () => {
server . close (() => process . exit ( 0 ));
server . closeAllConnections ();
2026-07-12 14:32:49 -07:00
};
2026-09-03 15:46:52 -07:00
process . on ( "SIGTERM" , shutdown );
process . on ( "SIGINT" , shutdown );
return server ;
};
type RuntimeRequest = {
objectId : string ;
input : Record < string , Value >;
dependencies : import ( "./quixos/refs_pb.js" ). InjectedDependency [];
2026-07-11 23:01:51 -07:00
};