Add Camino service-backed custom fields
This commit is contained in:
+52
-6
@@ -34,6 +34,7 @@ export type CaminoClient = Client<typeof CaminoService>;
|
||||
export type { InvokeRequest, Value };
|
||||
|
||||
export type Field<T> = {
|
||||
get(): Promise<T | undefined>;
|
||||
set(value: T): Promise<void>;
|
||||
};
|
||||
|
||||
@@ -41,9 +42,25 @@ export type RuntimeHandler<Context> = (
|
||||
context: Context,
|
||||
) => Promise<unknown> | unknown;
|
||||
|
||||
export type FieldOperation<Context> = {
|
||||
get?: RuntimeHandler<Context>;
|
||||
set?: RuntimeHandler<Context>;
|
||||
watchStart?: RuntimeHandler<Context>;
|
||||
watchStop?: RuntimeHandler<Context>;
|
||||
};
|
||||
|
||||
export const fieldOps = <Context>(
|
||||
operation: FieldOperation<Context>,
|
||||
): FieldOperation<Context> => operation;
|
||||
|
||||
export const derivedWithDeps = <Context>(operation: {
|
||||
get: RuntimeHandler<Context>;
|
||||
}): FieldOperation<Context> => fieldOps(operation);
|
||||
|
||||
export type RuntimeFunctionSpec<ExportName extends string = string> = {
|
||||
exportName: ExportName;
|
||||
symbol: string;
|
||||
operation?: string;
|
||||
};
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
@@ -203,6 +220,10 @@ export const createField = <T>(
|
||||
objectId: string,
|
||||
fieldName: string,
|
||||
): Field<T> => ({
|
||||
async get() {
|
||||
const response = await camino.getObject({ objectId });
|
||||
return protoValueToJs(response.object?.fields[fieldName]) as T | undefined;
|
||||
},
|
||||
async set(value) {
|
||||
await camino.setField({
|
||||
objectId,
|
||||
@@ -221,7 +242,9 @@ export const serveQuixosPackageRuntime = <
|
||||
runtimeProtocolVersion: string;
|
||||
functions: Spec;
|
||||
implementation: {
|
||||
[Name in Spec[number]["exportName"]]: RuntimeHandler<Context>;
|
||||
[Name in Spec[number]["exportName"]]:
|
||||
| RuntimeHandler<Context>
|
||||
| FieldOperation<Context>;
|
||||
};
|
||||
createContext: (camino: CaminoClient, request: InvokeRequest) => Context;
|
||||
}) => {
|
||||
@@ -242,6 +265,7 @@ export const serveQuixosPackageRuntime = <
|
||||
packageNamespace: params.packageNamespace,
|
||||
packageName: params.packageName,
|
||||
symbol: entry.symbol,
|
||||
operation: entry.operation ?? "",
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -261,19 +285,41 @@ export const serveQuixosPackageRuntime = <
|
||||
try {
|
||||
const symbol = request.function?.symbol ?? "";
|
||||
const spec = params.functions.find(
|
||||
(entry) => entry.symbol === symbol,
|
||||
(entry) =>
|
||||
entry.symbol === symbol &&
|
||||
(entry.operation ?? "") === (request.function?.operation ?? ""),
|
||||
);
|
||||
if (!spec) {
|
||||
throw new Error(
|
||||
`Unknown ${params.packageName} function: ${symbol}`,
|
||||
`Unknown ${params.packageName} function: ${symbol}${
|
||||
request.function?.operation
|
||||
? `.${request.function.operation}`
|
||||
: ""
|
||||
}`,
|
||||
);
|
||||
}
|
||||
const runtimeFunction = (
|
||||
params.implementation as Record<string, RuntimeHandler<Context>>
|
||||
const implementationExport = (
|
||||
params.implementation as Record<
|
||||
string,
|
||||
RuntimeHandler<Context> | FieldOperation<Context>
|
||||
>
|
||||
)[spec.exportName];
|
||||
const runtimeFunction =
|
||||
spec.operation && typeof implementationExport === "object"
|
||||
? implementationExport[spec.operation as keyof FieldOperation<Context>]
|
||||
: implementationExport;
|
||||
if (!runtimeFunction) {
|
||||
throw new Error(
|
||||
`Missing ${params.packageName} implementation export: ${spec.exportName}`,
|
||||
`Missing ${params.packageName} implementation export: ${spec.exportName}${
|
||||
spec.operation ? `.${spec.operation}` : ""
|
||||
}`,
|
||||
);
|
||||
}
|
||||
if (typeof runtimeFunction !== "function") {
|
||||
throw new Error(
|
||||
`${params.packageName} implementation export is not callable: ${spec.exportName}${
|
||||
spec.operation ? `.${spec.operation}` : ""
|
||||
}`,
|
||||
);
|
||||
}
|
||||
return create(InvokeResponseSchema, {
|
||||
|
||||
Reference in New Issue
Block a user