Host workspace repositories on Central Gitea
This commit is contained in:
+273
-345
File diff suppressed because one or more lines are too long
+143
-843
File diff suppressed because one or more lines are too long
@@ -1,684 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import protobuf from "protobufjs";
|
||||
import {
|
||||
compileCaminoSchema,
|
||||
loadCaminoSchemaRoot,
|
||||
} from "./schema-compiler.js";
|
||||
import type {
|
||||
ClassSchema,
|
||||
FieldSchema,
|
||||
FunctionRef,
|
||||
InterfaceImplementation,
|
||||
TypeRef,
|
||||
} from "./schema-ir.js";
|
||||
|
||||
const usage = (): never => {
|
||||
console.error(
|
||||
"Usage: camino-codegen-ts-runtime [--react-only] <class-schema.camino.proto> <out-dir> [implementation-import]",
|
||||
);
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
const required = (value: string | undefined) => value ?? usage();
|
||||
|
||||
const stringLiteral = (value: string) => JSON.stringify(value);
|
||||
|
||||
const upperFirst = (value: string) =>
|
||||
value.length === 0 ? value : `${value[0]?.toUpperCase()}${value.slice(1)}`;
|
||||
|
||||
const lowerFirst = (value: string) =>
|
||||
value.length === 0 ? value : `${value[0]?.toLowerCase()}${value.slice(1)}`;
|
||||
|
||||
const camel = (value: string) =>
|
||||
value
|
||||
.split(/[^a-zA-Z0-9]+/)
|
||||
.filter(Boolean)
|
||||
.map((part, index) =>
|
||||
index === 0 ? lowerFirst(part) : upperFirst(lowerFirst(part)),
|
||||
)
|
||||
.join("");
|
||||
|
||||
const isIdentifier = (value: string) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
||||
|
||||
const classId = (schema: ClassSchema) =>
|
||||
`${schema.id.namespace}:${schema.id.name}:${schema.id.version}:${
|
||||
schema.id.hash ?? ""
|
||||
}`;
|
||||
|
||||
const symbolId = (value: { namespace: string; name: string; version: string; hash?: string }) =>
|
||||
`${value.namespace}:${value.name}:${value.version}:${value.hash ?? ""}`;
|
||||
|
||||
const normalizedProtoType = (value: string) => value.replace(/^\./, "");
|
||||
|
||||
const declarationName = (value: protobuf.Type | protobuf.Enum) => value.name;
|
||||
|
||||
const tsTypeForTypeRef = (
|
||||
type: TypeRef,
|
||||
root?: protobuf.Root,
|
||||
): string => {
|
||||
if (type.enumValues && type.enumValues.length > 0) {
|
||||
return type.enumValues.map(stringLiteral).join(" | ");
|
||||
}
|
||||
if (type.symbol) {
|
||||
return `ObjectRef<${stringLiteral(symbolId(type.symbol))}>`;
|
||||
}
|
||||
const protoType = normalizedProtoType(type.protoType);
|
||||
switch (protoType) {
|
||||
case "string":
|
||||
case "google.protobuf.StringValue":
|
||||
return "string";
|
||||
case "bool":
|
||||
case "google.protobuf.BoolValue":
|
||||
return "boolean";
|
||||
case "double":
|
||||
case "float":
|
||||
case "google.protobuf.DoubleValue":
|
||||
case "google.protobuf.FloatValue":
|
||||
case "int32":
|
||||
case "sint32":
|
||||
case "sfixed32":
|
||||
case "uint32":
|
||||
case "fixed32":
|
||||
case "int64":
|
||||
case "sint64":
|
||||
case "sfixed64":
|
||||
case "uint64":
|
||||
case "fixed64":
|
||||
case "google.protobuf.Int32Value":
|
||||
case "google.protobuf.UInt32Value":
|
||||
case "google.protobuf.Int64Value":
|
||||
case "google.protobuf.UInt64Value":
|
||||
return "number";
|
||||
case "bytes":
|
||||
case "google.protobuf.BytesValue":
|
||||
return "Uint8Array";
|
||||
default:
|
||||
if (protoType === "google.protobuf.Empty") {
|
||||
return "Record<string, never>";
|
||||
}
|
||||
try {
|
||||
const reflected = root?.lookup(protoType);
|
||||
if (reflected instanceof protobuf.Type || reflected instanceof protobuf.Enum) {
|
||||
return declarationName(reflected);
|
||||
}
|
||||
} catch {
|
||||
// Unknown imported message types remain opaque at this codegen boundary.
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
const tsTypeForField = (field: FieldSchema, root?: protobuf.Root): string =>
|
||||
tsTypeForTypeRef(field.type, root);
|
||||
|
||||
const tsValueTypeForField = (field: FieldSchema, root?: protobuf.Root) =>
|
||||
field.repeated ? `${tsTypeForField(field, root)}[]` : tsTypeForField(field, root);
|
||||
|
||||
const tsFieldApiType = (field: FieldSchema, root?: protobuf.Root) =>
|
||||
field.conflict === "crdt"
|
||||
? `CrdtField<${tsValueTypeForField(field, root)}>`
|
||||
: `Field<${tsValueTypeForField(field, root)}>`;
|
||||
|
||||
const functionExportName = (fn: FunctionRef, fallback: string) => {
|
||||
if (isIdentifier(fn.symbol)) {
|
||||
return fn.symbol;
|
||||
}
|
||||
const fallbackName = camel(fallback);
|
||||
if (isIdentifier(fallbackName)) {
|
||||
return fallbackName;
|
||||
}
|
||||
throw new Error(`Cannot generate TS export name for function ${fn.symbol}`);
|
||||
};
|
||||
|
||||
const generatedWarning = `// @generated by camino-codegen-ts-runtime. Do not edit.\n`;
|
||||
|
||||
const scalarTsType = (field: protobuf.Field, root: protobuf.Root): string => {
|
||||
const primitive = tsTypeForTypeRef({ protoType: field.type }, root);
|
||||
if (primitive !== "unknown") {
|
||||
return primitive;
|
||||
}
|
||||
const resolved = field.resolvedType;
|
||||
if (resolved instanceof protobuf.Type || resolved instanceof protobuf.Enum) {
|
||||
return declarationName(resolved);
|
||||
}
|
||||
return "unknown";
|
||||
};
|
||||
|
||||
const collectProtoDeclarations = (
|
||||
root: protobuf.Root,
|
||||
types: TypeRef[],
|
||||
) => {
|
||||
const declarations = new Map<string, protobuf.Type | protobuf.Enum>();
|
||||
const visit = (value: protobuf.Type | protobuf.Enum) => {
|
||||
const key = value.fullName;
|
||||
if (declarations.has(key)) {
|
||||
return;
|
||||
}
|
||||
declarations.set(key, value);
|
||||
if (value instanceof protobuf.Type) {
|
||||
for (const field of value.fieldsArray) {
|
||||
if (
|
||||
field.resolvedType instanceof protobuf.Type ||
|
||||
field.resolvedType instanceof protobuf.Enum
|
||||
) {
|
||||
visit(field.resolvedType);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for (const type of types) {
|
||||
if (type.symbol || !type.protoType) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
const reflected = root.lookup(normalizedProtoType(type.protoType));
|
||||
if (reflected instanceof protobuf.Type || reflected instanceof protobuf.Enum) {
|
||||
visit(reflected);
|
||||
}
|
||||
} catch {
|
||||
// Opaque imported types are represented as unknown by the generated API.
|
||||
}
|
||||
}
|
||||
return [...declarations.values()]
|
||||
.map((value) => {
|
||||
if (value instanceof protobuf.Enum) {
|
||||
return `export type ${declarationName(value)} = ${Object.keys(value.values)
|
||||
.map(stringLiteral)
|
||||
.join(" | ")};`;
|
||||
}
|
||||
const fields = value.fieldsArray.map((field) => {
|
||||
const fieldType = scalarTsType(field, root);
|
||||
const valueType = field.map
|
||||
? `Record<string, ${fieldType}>`
|
||||
: field.repeated
|
||||
? `${fieldType}[]`
|
||||
: fieldType;
|
||||
return ` ${JSON.stringify(field.name)}${field.optional ? "?" : ""}: ${valueType};`;
|
||||
});
|
||||
return `export type ${declarationName(value)} = {\n${fields.join("\n")}\n};`;
|
||||
})
|
||||
.join("\n\n");
|
||||
};
|
||||
|
||||
type FunctionSpec = {
|
||||
exportName: string;
|
||||
symbol: string;
|
||||
operation?: string;
|
||||
packageNamespace: string;
|
||||
packageName: string;
|
||||
field?: {
|
||||
name: string;
|
||||
type: string;
|
||||
storage: string;
|
||||
conflict: string;
|
||||
};
|
||||
};
|
||||
|
||||
const fieldTypeId = (field: FieldSchema) =>
|
||||
field.type.symbol ? symbolId(field.type.symbol) : field.type.protoType;
|
||||
|
||||
const crdtStorageTypeId = (field: FieldSchema) =>
|
||||
field.type.protoType ||
|
||||
(field.type.symbol
|
||||
? `${field.type.symbol.namespace}.${field.type.symbol.name}`
|
||||
: fieldTypeId(field));
|
||||
|
||||
const fieldStorageId = (field: FieldSchema) =>
|
||||
field.ops && field.storage.kind === "stored" ? "derived" : field.storage.kind;
|
||||
|
||||
const interfaceTypeName = (implementation: InterfaceImplementation) =>
|
||||
`${implementation.interface.name}Ref`;
|
||||
|
||||
const renderInterfaceRefTypes = (schema: ClassSchema) =>
|
||||
schema.implements
|
||||
.map((implementation) => {
|
||||
const typeParams = implementation.typeBindings.map((binding) => binding.name);
|
||||
const generic =
|
||||
typeParams.length > 0 ? `<${typeParams.join(", ")}>` : "";
|
||||
const bindings =
|
||||
typeParams.length > 0
|
||||
? typeParams
|
||||
.map((param) => ` readonly ${param}: ${param};`)
|
||||
.join("\n")
|
||||
: " readonly value: unknown;";
|
||||
return `export type ${interfaceTypeName(implementation)}${generic} = ObjectRef<string> & {
|
||||
readonly $caminoInterfaces: {
|
||||
readonly ${stringLiteral(symbolId(implementation.interface))}: {
|
||||
${bindings}
|
||||
};
|
||||
};
|
||||
};`;
|
||||
})
|
||||
.join("\n\n");
|
||||
|
||||
const interfaceMixins = (schema: ClassSchema, root: protobuf.Root) =>
|
||||
schema.implements.map((implementation) => {
|
||||
const typeArgs = implementation.typeBindings.map((binding) =>
|
||||
tsTypeForTypeRef(binding.type, root),
|
||||
);
|
||||
return `${interfaceTypeName(implementation)}${
|
||||
typeArgs.length > 0 ? `<${typeArgs.join(", ")}>` : ""
|
||||
}`;
|
||||
});
|
||||
|
||||
const operationFunctionSpecs = (schema: ClassSchema): FunctionSpec[] =>
|
||||
schema.fields.flatMap((field) => {
|
||||
const serviceName = field.ops?.service.replace(/^\./, "");
|
||||
if (!serviceName) {
|
||||
return [];
|
||||
}
|
||||
const service = schema.operationServices.find(
|
||||
(candidate) => candidate.fullName === serviceName,
|
||||
);
|
||||
if (!service) {
|
||||
throw new Error(
|
||||
`${schema.id.name}.${field.name} points to missing operation service ${field.ops?.service}`,
|
||||
);
|
||||
}
|
||||
return service.operations.map((operation) => ({
|
||||
exportName: functionExportName(
|
||||
operation.function,
|
||||
`${field.name}_${operation.name}`,
|
||||
),
|
||||
symbol: operation.function.symbol,
|
||||
...(operation.function.operation
|
||||
? { operation: operation.function.operation }
|
||||
: {}),
|
||||
packageNamespace: operation.function.packageNamespace,
|
||||
packageName: operation.function.packageName,
|
||||
field: {
|
||||
name: field.name,
|
||||
type: fieldTypeId(field),
|
||||
storage: fieldStorageId(field),
|
||||
conflict: field.conflict,
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
const renderRuntime = (schema: ClassSchema, root: protobuf.Root) => {
|
||||
const className = schema.id.name;
|
||||
const objectTypeName = `${className}Object`;
|
||||
const refTypeName = `${className}Ref`;
|
||||
const contextTypeName = `${className}Context`;
|
||||
const implementationTypeName = `${className}Implementation`;
|
||||
const serveName = `serve${className}Runtime`;
|
||||
const createObjectName = `create${className}Object`;
|
||||
const interfaceRefTypes = renderInterfaceRefTypes(schema);
|
||||
const refType =
|
||||
[ `ObjectRef<${stringLiteral(classId(schema))}>`, ...interfaceMixins(schema, root)]
|
||||
.join(" & ");
|
||||
const edgeFields = new Set(schema.edges.map((edge) => edge.sourceField));
|
||||
const writableFields = schema.fields.filter(
|
||||
(field) =>
|
||||
field.storage.kind === "stored" &&
|
||||
!field.ops &&
|
||||
!edgeFields.has(field.name),
|
||||
);
|
||||
const functionSpecs = [
|
||||
...(schema.constructorSpec
|
||||
? [
|
||||
{
|
||||
exportName: functionExportName(
|
||||
schema.constructorSpec.function,
|
||||
"constructor",
|
||||
),
|
||||
symbol: schema.constructorSpec.function.symbol,
|
||||
...(schema.constructorSpec.function.operation
|
||||
? { operation: schema.constructorSpec.function.operation }
|
||||
: {}),
|
||||
packageNamespace: schema.constructorSpec.function.packageNamespace,
|
||||
packageName: schema.constructorSpec.function.packageName,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...schema.methods.map((method) => ({
|
||||
exportName: functionExportName(method.function, method.name),
|
||||
symbol: method.function.symbol,
|
||||
...(method.function.operation ? { operation: method.function.operation } : {}),
|
||||
packageNamespace: method.function.packageNamespace,
|
||||
packageName: method.function.packageName,
|
||||
})),
|
||||
...schema.fields.flatMap((field) =>
|
||||
field.storage.resolver
|
||||
? [
|
||||
{
|
||||
exportName: functionExportName(field.storage.resolver, field.name),
|
||||
symbol: field.storage.resolver.symbol,
|
||||
...(field.storage.resolver.operation
|
||||
? { operation: field.storage.resolver.operation }
|
||||
: {}),
|
||||
packageNamespace: field.storage.resolver.packageNamespace,
|
||||
packageName: field.storage.resolver.packageName,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
),
|
||||
...operationFunctionSpecs(schema),
|
||||
];
|
||||
const firstFunction = functionSpecs[0];
|
||||
if (!firstFunction) {
|
||||
throw new Error(`${schema.id.name} has no runtime functions to generate`);
|
||||
}
|
||||
const mixedPackage = functionSpecs.find(
|
||||
(spec) =>
|
||||
spec.packageNamespace !== firstFunction.packageNamespace ||
|
||||
spec.packageName !== firstFunction.packageName,
|
||||
);
|
||||
if (mixedPackage) {
|
||||
throw new Error(
|
||||
`${schema.id.name} points to multiple packages; v0 TS runtime generation expects one package`,
|
||||
);
|
||||
}
|
||||
|
||||
return `${generatedWarning}import {
|
||||
type CaminoClient,
|
||||
createCrdtField,
|
||||
createField,
|
||||
type CrdtField,
|
||||
type Field,
|
||||
type FieldOperation,
|
||||
type InvokeRequest,
|
||||
objectRef,
|
||||
type ObjectRef,
|
||||
type RuntimeHandler,
|
||||
serveQuixosPackageRuntime,
|
||||
} from "@quixos/camino-package-runtime";
|
||||
|
||||
${collectProtoDeclarations(root, [
|
||||
...writableFields.map((field) => field.type),
|
||||
...schema.implements.flatMap((entry) =>
|
||||
entry.typeBindings.map((binding) => binding.type),
|
||||
),
|
||||
])}
|
||||
|
||||
${interfaceRefTypes ? `${interfaceRefTypes}\n\n` : ""}export type ${refTypeName} = ${refType};
|
||||
|
||||
export type ${objectTypeName} = {
|
||||
id: ${refTypeName};
|
||||
${writableFields
|
||||
.map(
|
||||
(field) =>
|
||||
` ${camel(field.name)}: ${tsFieldApiType(field, root)};`,
|
||||
)
|
||||
.join("\n")}
|
||||
};
|
||||
|
||||
export type ${contextTypeName} = {
|
||||
object: ${objectTypeName};
|
||||
camino: CaminoClient;
|
||||
request: InvokeRequest;
|
||||
};
|
||||
|
||||
export type ${implementationTypeName} = {
|
||||
${functionSpecs
|
||||
.map((spec) =>
|
||||
spec.operation
|
||||
? ` ${spec.exportName}: FieldOperation<${contextTypeName}>;`
|
||||
: ` ${spec.exportName}: RuntimeHandler<${contextTypeName}>;`,
|
||||
)
|
||||
.filter((line, index, lines) => lines.indexOf(line) === index)
|
||||
.join("\n")}
|
||||
};
|
||||
|
||||
const packageNamespace = ${stringLiteral(firstFunction.packageNamespace)};
|
||||
const packageName = ${stringLiteral(firstFunction.packageName)};
|
||||
const runtimeProtocolVersion = ${stringLiteral("camino-orch-v0")};
|
||||
|
||||
const functions = [
|
||||
${functionSpecs
|
||||
.map(
|
||||
(spec) =>
|
||||
` { exportName: ${stringLiteral(spec.exportName)}, symbol: ${stringLiteral(spec.symbol)}${
|
||||
spec.operation ? `, operation: ${stringLiteral(spec.operation)}` : ""
|
||||
}${
|
||||
spec.field
|
||||
? `, field: { name: ${stringLiteral(spec.field.name)}, type: ${stringLiteral(spec.field.type)}, storage: ${stringLiteral(spec.field.storage)}, conflict: ${stringLiteral(spec.field.conflict)} }`
|
||||
: ""
|
||||
} },`,
|
||||
)
|
||||
.join("\n")}
|
||||
] as const;
|
||||
|
||||
export const ${createObjectName} = (
|
||||
camino: CaminoClient,
|
||||
objectId: string,
|
||||
): ${objectTypeName} => {
|
||||
const id = objectRef<${stringLiteral(classId(schema))}>(objectId) as ${refTypeName};
|
||||
return {
|
||||
id,
|
||||
${writableFields
|
||||
.map(
|
||||
(fieldSchema) =>
|
||||
fieldSchema.conflict === "crdt"
|
||||
? ` ${camel(fieldSchema.name)}: createCrdtField(camino, id, ${stringLiteral(fieldSchema.name)}, ${stringLiteral(crdtStorageTypeId(fieldSchema))}),`
|
||||
: ` ${camel(fieldSchema.name)}: createField(camino, id, ${stringLiteral(fieldSchema.name)}),`,
|
||||
)
|
||||
.join("\n")}
|
||||
};
|
||||
};
|
||||
|
||||
export const create${className}Context = (
|
||||
camino: CaminoClient,
|
||||
request: InvokeRequest,
|
||||
): ${contextTypeName} => ({
|
||||
object: ${createObjectName}(camino, request.objectId),
|
||||
camino,
|
||||
request,
|
||||
});
|
||||
|
||||
export const ${serveName} = (implementation: ${implementationTypeName}) => {
|
||||
serveQuixosPackageRuntime({
|
||||
packageNamespace,
|
||||
packageName,
|
||||
runtimeProtocolVersion,
|
||||
functions,
|
||||
implementation,
|
||||
createContext: create${className}Context,
|
||||
});
|
||||
};
|
||||
`;
|
||||
};
|
||||
|
||||
const implementationNamed = (schema: ClassSchema, name: string) =>
|
||||
schema.implements.find(
|
||||
(entry) =>
|
||||
entry.interface.namespace === "quixos.react" &&
|
||||
entry.interface.name === name,
|
||||
);
|
||||
|
||||
const requiredBinding = (
|
||||
implementation: InterfaceImplementation,
|
||||
name: string,
|
||||
) => {
|
||||
const binding = implementation.typeBindings.find((entry) => entry.name === name);
|
||||
if (!binding) {
|
||||
throw new Error(
|
||||
`${implementation.interface.name} implementation is missing ${name}`,
|
||||
);
|
||||
}
|
||||
return binding.type;
|
||||
};
|
||||
|
||||
const renderReactClient = (schema: ClassSchema, root: protobuf.Root) => {
|
||||
const react = implementationNamed(schema, "ReactComponent");
|
||||
const componentFor = implementationNamed(schema, "ReactComponentFor");
|
||||
if (!react || !componentFor) {
|
||||
return undefined;
|
||||
}
|
||||
const renderProps = requiredBinding(react, "RenderProps");
|
||||
const action = requiredBinding(react, "Action");
|
||||
const object = requiredBinding(componentFor, "Object");
|
||||
if (!object.symbol) {
|
||||
throw new Error(`${schema.id.name}.ReactComponentFor.Object must bind a class symbol`);
|
||||
}
|
||||
const edge = schema.edges.find((candidate) => candidate.sourceField === "for_object");
|
||||
if (!edge) {
|
||||
throw new Error(`${schema.id.name} must declare its ReactComponentFor edge`);
|
||||
}
|
||||
const componentEndpoint =
|
||||
edge.fromEndpoint.projection === "for_object"
|
||||
? edge.fromEndpoint
|
||||
: edge.toEndpoint.projection === "for_object"
|
||||
? edge.toEndpoint
|
||||
: undefined;
|
||||
const objectEndpoint =
|
||||
componentEndpoint === edge.fromEndpoint ? edge.toEndpoint : edge.fromEndpoint;
|
||||
if (!componentEndpoint || !objectEndpoint.projection) {
|
||||
throw new Error(`${schema.id.name}.for_object edge has no inverse projection`);
|
||||
}
|
||||
if (componentEndpoint.cardinality !== "exactly_one") {
|
||||
throw new Error(`${schema.id.name}.for_object must have exactly_one cardinality`);
|
||||
}
|
||||
if (
|
||||
!objectEndpoint.materialization ||
|
||||
symbolId(objectEndpoint.materialization.class) !== symbolId(schema.id)
|
||||
) {
|
||||
throw new Error(
|
||||
`${schema.id.name}.${objectEndpoint.projection} must materialize ${classId(schema)}`,
|
||||
);
|
||||
}
|
||||
|
||||
const className = schema.id.name;
|
||||
const componentName = className.endsWith("ReactComponent")
|
||||
? `${className.slice(0, -"ReactComponent".length)}Component`
|
||||
: className;
|
||||
const propsTypeName = `${componentName}Props`;
|
||||
const renderPropsType = tsTypeForTypeRef(renderProps, root);
|
||||
const actionType = tsTypeForTypeRef(action, root);
|
||||
const objectType = tsTypeForTypeRef(object, root);
|
||||
const declarations = collectProtoDeclarations(root, [renderProps, action]);
|
||||
|
||||
return `${generatedWarning}import {
|
||||
createReactComponentFor,
|
||||
type ReactComponentHostProps,
|
||||
type ObjectRef,
|
||||
} from "@quixos/camino-react-runtime";
|
||||
|
||||
${declarations}
|
||||
|
||||
export type ${propsTypeName} = {
|
||||
forObject: ${objectType};
|
||||
} & ${renderPropsType} & ReactComponentHostProps<${actionType}>;
|
||||
|
||||
export const ${componentName} = createReactComponentFor<
|
||||
${objectType},
|
||||
${renderPropsType},
|
||||
${actionType}
|
||||
>({
|
||||
componentClassId: ${stringLiteral(classId(schema))},
|
||||
projection: ${stringLiteral(objectEndpoint.projection)},
|
||||
});
|
||||
`;
|
||||
};
|
||||
|
||||
const reactRuntimeDeclaration = `${generatedWarning}declare module "@quixos/camino-react-runtime" {
|
||||
import type * as AutomergeNamespace from "@automerge/automerge";
|
||||
|
||||
export type ObjectRef<ClassId extends string> = string & {
|
||||
readonly $caminoClass: ClassId;
|
||||
};
|
||||
|
||||
export type LiveFieldProp<T> = {
|
||||
value: T;
|
||||
source: {
|
||||
objectId: string;
|
||||
fieldName: string;
|
||||
fieldType?: string;
|
||||
fieldStorage?: string;
|
||||
conflictStrategy?: string;
|
||||
revision?: string | number | bigint;
|
||||
};
|
||||
};
|
||||
|
||||
export type ReactComponentHostProps<Action> = {
|
||||
onAction?: (action: Action) => void;
|
||||
fallback?: unknown;
|
||||
className?: string;
|
||||
style?: Record<string, string | number | undefined>;
|
||||
onError?: (error: Error) => void;
|
||||
};
|
||||
|
||||
export type ReactComponentImplementationProps<CaminoProps, RenderProps, Action> = {
|
||||
camino: CaminoProps;
|
||||
render: RenderProps;
|
||||
dispatch: (action: Action) => void;
|
||||
};
|
||||
|
||||
export const createReactComponentFor: <
|
||||
ForObject extends ObjectRef<string>,
|
||||
RenderProps extends object,
|
||||
Action,
|
||||
>(config: {
|
||||
componentClassId: string;
|
||||
projection: string;
|
||||
}) => (props: {
|
||||
forObject: ForObject;
|
||||
} & RenderProps & ReactComponentHostProps<Action>) => any;
|
||||
|
||||
export const callObjectMethod: <Result = unknown>(
|
||||
object: ObjectRef<string>,
|
||||
methodName: string,
|
||||
input?: Record<string, unknown>,
|
||||
) => Promise<Result>;
|
||||
|
||||
export const h: (...args: any[]) => any;
|
||||
export const useLiveField: <T>(
|
||||
field: LiveFieldProp<T>,
|
||||
) => [T, (value: T) => void | Promise<void>];
|
||||
export const Automerge: typeof AutomergeNamespace;
|
||||
}
|
||||
`;
|
||||
|
||||
const renderServer = (schema: ClassSchema, implementationImport: string) => {
|
||||
const className = schema.id.name;
|
||||
return `${generatedWarning}import * as implementation from ${stringLiteral(implementationImport)};
|
||||
import { serve${className}Runtime } from "./${schema.id.namespace}.${className}.runtime.js";
|
||||
|
||||
serve${className}Runtime(implementation);
|
||||
`;
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
const reactOnly = process.argv[2] === "--react-only";
|
||||
const offset = reactOnly ? 1 : 0;
|
||||
const sourceFile = required(process.argv[2 + offset]);
|
||||
const outDir = required(process.argv[3 + offset]);
|
||||
const implementationImport = process.argv[4 + offset] ?? "../task.impl.js";
|
||||
const compiled = await compileCaminoSchema(sourceFile);
|
||||
const { root } = await loadCaminoSchemaRoot(sourceFile);
|
||||
if (compiled.classes.length !== 1) {
|
||||
throw new Error(
|
||||
`Expected exactly one Camino class in ${sourceFile}, found ${compiled.classes.length}`,
|
||||
);
|
||||
}
|
||||
const schema = compiled.classes[0];
|
||||
if (!schema) {
|
||||
throw new Error(`No Camino class found in ${sourceFile}`);
|
||||
}
|
||||
fs.mkdirSync(outDir, { recursive: true });
|
||||
const baseName = `${schema.id.namespace}.${schema.id.name}`;
|
||||
const reactClient = renderReactClient(schema, root);
|
||||
if (!reactOnly) {
|
||||
fs.writeFileSync(
|
||||
path.join(outDir, `${baseName}.runtime.ts`),
|
||||
renderRuntime(schema, root),
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(outDir, `${baseName}.server.ts`),
|
||||
renderServer(schema, implementationImport),
|
||||
);
|
||||
}
|
||||
if (reactClient) {
|
||||
fs.writeFileSync(path.join(outDir, `${baseName}.react.ts`), reactClient);
|
||||
fs.writeFileSync(
|
||||
path.join(outDir, "camino-react-runtime.d.ts"),
|
||||
reactRuntimeDeclaration,
|
||||
);
|
||||
} else if (reactOnly) {
|
||||
throw new Error(`${schema.id.name} does not implement ReactComponentFor`);
|
||||
}
|
||||
};
|
||||
|
||||
await main();
|
||||
+396
-1051
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,573 @@
|
||||
// @generated by protoc-gen-es v2.12.1 with parameter "target=ts,import_extension=js"
|
||||
// @generated from file quixos/orch.proto (package quixos.orch, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv2";
|
||||
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2";
|
||||
import type { CaminoObject, Value } from "../camino/api_pb.js";
|
||||
import { file_camino_api } from "../camino/api_pb.js";
|
||||
import type { PackageDescriptor } from "./package_pb.js";
|
||||
import { file_quixos_package } from "./package_pb.js";
|
||||
import type { CapabilityRef, PackageExportRef } from "./refs_pb.js";
|
||||
import { file_quixos_refs } from "./refs_pb.js";
|
||||
import type { DerivedDependency } from "./runtime_pb.js";
|
||||
import { file_quixos_runtime } from "./runtime_pb.js";
|
||||
import type { Message } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
* Describes the file quixos/orch.proto.
|
||||
*/
|
||||
export const file_quixos_orch: GenFile = /*@__PURE__*/
|
||||
fileDesc("ChFxdWl4b3Mvb3JjaC5wcm90bxILcXVpeG9zLm9yY2gipQEKFkNvbnN0cnVjdE9iamVjdFJlcXVlc3QSDwoHYXRvbV9pZBgBIAEoCRI9CgVpbnB1dBgCIAMoCzIuLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEiPwoXQ29uc3RydWN0T2JqZWN0UmVzcG9uc2USJAoGb2JqZWN0GAEgASgLMhQuY2FtaW5vLkNhbWlub09iamVjdCLUAQoXSW52b2tlQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI+CgVpbnB1dBgDIAMoCzIvLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0LklucHV0RW50cnkaOwoKSW5wdXRFbnRyeRILCgNrZXkYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWU6AjgBIpgBChhJbnZva2VDYXBhYmlsaXR5UmVzcG9uc2USFQoNaW52b2NhdGlvbl9pZBgBIAEoCRIrCgphY3RpdmF0aW9uGAIgASgLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbhIKCgJvaxgDIAEoCBIdCgZyZXN1bHQYBCABKAsyDS5jYW1pbm8uVmFsdWUSDQoFZXJyb3IYBSABKAki0gEKFldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QSKQoKY2FwYWJpbGl0eRgBIAEoCzIVLnF1aXhvcy5DYXBhYmlsaXR5UmVmEhEKCW9iamVjdF9pZBgCIAEoCRI9CgVpbnB1dBgDIAMoCzIuLnF1aXhvcy5vcmNoLldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QuSW5wdXRFbnRyeRo7CgpJbnB1dEVudHJ5EgsKA2tleRgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZToCOAEi4wEKFFdhdGNoQ2FwYWJpbGl0eUV2ZW50EhUKDWludm9jYXRpb25faWQYASABKAkSKwoKYWN0aXZhdGlvbhgCIAEoCzIXLnF1aXhvcy5vcmNoLkFjdGl2YXRpb24SEAoId2F0Y2hfaWQYAyABKAkSHAoFdmFsdWUYBCABKAsyDS5jYW1pbm8uVmFsdWUSNwoMZGVwZW5kZW5jaWVzGAUgAygLMiEucXVpeG9zLnJ1bnRpbWUuRGVyaXZlZERlcGVuZGVuY3kSDQoFZXJyb3IYBiABKAkSDwoHaW5pdGlhbBgHIAEoCCIVChNHZXRXb3Jrc3BhY2VSZXF1ZXN0ImcKFEdldFdvcmtzcGFjZVJlc3BvbnNlEhQKDHdvcmtzcGFjZV9pZBgBIAEoCRIdChV3b3Jrc3BhY2VfcmV2aXNpb25faWQYAiABKAkSGgoSc291cmNlX3Jvb3RfY29tbWl0GAMgASgJIhgKFkxpc3RBY3RpdmF0aW9uc1JlcXVlc3QiHwodTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1JlcXVlc3QiUAoeTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1Jlc3BvbnNlEi4KC2Rlc2NyaXB0b3JzGAEgAygLMhkucXVpeG9zLlBhY2thZ2VEZXNjcmlwdG9yIhwKGkxpc3RQYWNrYWdlUnVudGltZXNSZXF1ZXN0IlIKG0xpc3RQYWNrYWdlUnVudGltZXNSZXNwb25zZRIzCghydW50aW1lcxgBIAMoCzIhLnF1aXhvcy5vcmNoLlBhY2thZ2VSdW50aW1lU3RhdHVzIkcKF0xpc3RBY3RpdmF0aW9uc1Jlc3BvbnNlEiwKC2FjdGl2YXRpb25zGAEgAygLMhcucXVpeG9zLm9yY2guQWN0aXZhdGlvbiI/ChZDbG9zZUFjdGl2YXRpb25SZXF1ZXN0EhUKDWFjdGl2YXRpb25faWQYASABKAkSDgoGcmVhc29uGAIgASgJIkYKF0Nsb3NlQWN0aXZhdGlvblJlc3BvbnNlEisKCmFjdGl2YXRpb24YASABKAsyFy5xdWl4b3Mub3JjaC5BY3RpdmF0aW9uIusBCgpBY3RpdmF0aW9uEhUKDWFjdGl2YXRpb25faWQYASABKAkSKAoGZXhwb3J0GAIgASgLMhgucXVpeG9zLlBhY2thZ2VFeHBvcnRSZWYSEQoJb2JqZWN0X2lkGAMgASgJEg0KBXN0YXRlGAQgASgJEg4KBmRlbWFuZBgFIAEoDRIRCglvcGVuZWRfYXQYBiABKAkSFAoMbGFzdF91c2VkX2F0GAcgASgJEhgKEGlkbGVfZGVhZGxpbmVfYXQYCCABKAkSEQoJY2xvc2VkX2F0GAkgASgJEhQKDGNsb3NlX3JlYXNvbhgKIAEoCSKzAgoUUGFja2FnZVJ1bnRpbWVTdGF0dXMSEwoLcnVudGltZV9rZXkYASABKAkSGwoTcGFja2FnZV9yZXZpc2lvbl9pZBgCIAEoCRIZChFzb3VyY2VfcmVwb3NpdG9yeRgDIAEoCRIVCg1zb3VyY2VfY29tbWl0GAQgASgJEhQKDGJ1aWxkX3RhcmdldBgFIAEoCRITCgtzZXJ2ZXJfcGF0aBgGIAEoCRILCgNwaWQYByABKA0SDQoFc3RhdGUYCCABKAkSEgoKc3RhcnRlZF9hdBgJIAEoCRIZChFsYXN0X2hhbmRzaGFrZV9hdBgKIAEoCRIgChhydW50aW1lX3Byb3RvY29sX3ZlcnNpb24YCyABKAkSHwoXYWR2ZXJ0aXNlZF9leHBvcnRfY291bnQYDCABKA0ynwYKE09yY2hlc3RyYXRvclJ1bnRpbWUSXwoQSW52b2tlQ2FwYWJpbGl0eRIkLnF1aXhvcy5vcmNoLkludm9rZUNhcGFiaWxpdHlSZXF1ZXN0GiUucXVpeG9zLm9yY2guSW52b2tlQ2FwYWJpbGl0eVJlc3BvbnNlElsKD1dhdGNoQ2FwYWJpbGl0eRIjLnF1aXhvcy5vcmNoLldhdGNoQ2FwYWJpbGl0eVJlcXVlc3QaIS5xdWl4b3Mub3JjaC5XYXRjaENhcGFiaWxpdHlFdmVudDABElwKD0NvbnN0cnVjdE9iamVjdBIjLnF1aXhvcy5vcmNoLkNvbnN0cnVjdE9iamVjdFJlcXVlc3QaJC5xdWl4b3Mub3JjaC5Db25zdHJ1Y3RPYmplY3RSZXNwb25zZRJTCgxHZXRXb3Jrc3BhY2USIC5xdWl4b3Mub3JjaC5HZXRXb3Jrc3BhY2VSZXF1ZXN0GiEucXVpeG9zLm9yY2guR2V0V29ya3NwYWNlUmVzcG9uc2UScQoWTGlzdFBhY2thZ2VEZXNjcmlwdG9ycxIqLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlRGVzY3JpcHRvcnNSZXF1ZXN0GisucXVpeG9zLm9yY2guTGlzdFBhY2thZ2VEZXNjcmlwdG9yc1Jlc3BvbnNlEmgKE0xpc3RQYWNrYWdlUnVudGltZXMSJy5xdWl4b3Mub3JjaC5MaXN0UGFja2FnZVJ1bnRpbWVzUmVxdWVzdBooLnF1aXhvcy5vcmNoLkxpc3RQYWNrYWdlUnVudGltZXNSZXNwb25zZRJcCg9MaXN0QWN0aXZhdGlvbnMSIy5xdWl4b3Mub3JjaC5MaXN0QWN0aXZhdGlvbnNSZXF1ZXN0GiQucXVpeG9zLm9yY2guTGlzdEFjdGl2YXRpb25zUmVzcG9uc2USXAoPQ2xvc2VBY3RpdmF0aW9uEiMucXVpeG9zLm9yY2guQ2xvc2VBY3RpdmF0aW9uUmVxdWVzdBokLnF1aXhvcy5vcmNoLkNsb3NlQWN0aXZhdGlvblJlc3BvbnNlYgZwcm90bzM", [file_camino_api, file_quixos_package, file_quixos_refs, file_quixos_runtime]);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.ConstructObjectRequest
|
||||
*/
|
||||
export type ConstructObjectRequest = Message<"quixos.orch.ConstructObjectRequest"> & {
|
||||
/**
|
||||
* @generated from field: string atom_id = 1;
|
||||
*/
|
||||
atomId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: map<string, camino.Value> input = 2;
|
||||
*/
|
||||
input: { [key: string]: Value };
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.ConstructObjectRequest.
|
||||
* Use `create(ConstructObjectRequestSchema)` to create a new message.
|
||||
*/
|
||||
export const ConstructObjectRequestSchema: GenMessage<ConstructObjectRequest> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 0);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.ConstructObjectResponse
|
||||
*/
|
||||
export type ConstructObjectResponse = Message<"quixos.orch.ConstructObjectResponse"> & {
|
||||
/**
|
||||
* @generated from field: camino.CaminoObject object = 1;
|
||||
*/
|
||||
object?: CaminoObject | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.ConstructObjectResponse.
|
||||
* Use `create(ConstructObjectResponseSchema)` to create a new message.
|
||||
*/
|
||||
export const ConstructObjectResponseSchema: GenMessage<ConstructObjectResponse> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 1);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.InvokeCapabilityRequest
|
||||
*/
|
||||
export type InvokeCapabilityRequest = Message<"quixos.orch.InvokeCapabilityRequest"> & {
|
||||
/**
|
||||
* @generated from field: quixos.CapabilityRef capability = 1;
|
||||
*/
|
||||
capability?: CapabilityRef | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: string object_id = 2;
|
||||
*/
|
||||
objectId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: map<string, camino.Value> input = 3;
|
||||
*/
|
||||
input: { [key: string]: Value };
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.InvokeCapabilityRequest.
|
||||
* Use `create(InvokeCapabilityRequestSchema)` to create a new message.
|
||||
*/
|
||||
export const InvokeCapabilityRequestSchema: GenMessage<InvokeCapabilityRequest> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 2);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.InvokeCapabilityResponse
|
||||
*/
|
||||
export type InvokeCapabilityResponse = Message<"quixos.orch.InvokeCapabilityResponse"> & {
|
||||
/**
|
||||
* @generated from field: string invocation_id = 1;
|
||||
*/
|
||||
invocationId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: quixos.orch.Activation activation = 2;
|
||||
*/
|
||||
activation?: Activation | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: bool ok = 3;
|
||||
*/
|
||||
ok: boolean;
|
||||
|
||||
/**
|
||||
* @generated from field: camino.Value result = 4;
|
||||
*/
|
||||
result?: Value | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: string error = 5;
|
||||
*/
|
||||
error: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.InvokeCapabilityResponse.
|
||||
* Use `create(InvokeCapabilityResponseSchema)` to create a new message.
|
||||
*/
|
||||
export const InvokeCapabilityResponseSchema: GenMessage<InvokeCapabilityResponse> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 3);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.WatchCapabilityRequest
|
||||
*/
|
||||
export type WatchCapabilityRequest = Message<"quixos.orch.WatchCapabilityRequest"> & {
|
||||
/**
|
||||
* @generated from field: quixos.CapabilityRef capability = 1;
|
||||
*/
|
||||
capability?: CapabilityRef | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: string object_id = 2;
|
||||
*/
|
||||
objectId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: map<string, camino.Value> input = 3;
|
||||
*/
|
||||
input: { [key: string]: Value };
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.WatchCapabilityRequest.
|
||||
* Use `create(WatchCapabilityRequestSchema)` to create a new message.
|
||||
*/
|
||||
export const WatchCapabilityRequestSchema: GenMessage<WatchCapabilityRequest> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 4);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.WatchCapabilityEvent
|
||||
*/
|
||||
export type WatchCapabilityEvent = Message<"quixos.orch.WatchCapabilityEvent"> & {
|
||||
/**
|
||||
* @generated from field: string invocation_id = 1;
|
||||
*/
|
||||
invocationId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: quixos.orch.Activation activation = 2;
|
||||
*/
|
||||
activation?: Activation | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: string watch_id = 3;
|
||||
*/
|
||||
watchId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: camino.Value value = 4;
|
||||
*/
|
||||
value?: Value | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: repeated quixos.runtime.DerivedDependency dependencies = 5;
|
||||
*/
|
||||
dependencies: DerivedDependency[];
|
||||
|
||||
/**
|
||||
* @generated from field: string error = 6;
|
||||
*/
|
||||
error: string;
|
||||
|
||||
/**
|
||||
* @generated from field: bool initial = 7;
|
||||
*/
|
||||
initial: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.WatchCapabilityEvent.
|
||||
* Use `create(WatchCapabilityEventSchema)` to create a new message.
|
||||
*/
|
||||
export const WatchCapabilityEventSchema: GenMessage<WatchCapabilityEvent> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 5);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.GetWorkspaceRequest
|
||||
*/
|
||||
export type GetWorkspaceRequest = Message<"quixos.orch.GetWorkspaceRequest"> & {
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.GetWorkspaceRequest.
|
||||
* Use `create(GetWorkspaceRequestSchema)` to create a new message.
|
||||
*/
|
||||
export const GetWorkspaceRequestSchema: GenMessage<GetWorkspaceRequest> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 6);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.GetWorkspaceResponse
|
||||
*/
|
||||
export type GetWorkspaceResponse = Message<"quixos.orch.GetWorkspaceResponse"> & {
|
||||
/**
|
||||
* @generated from field: string workspace_id = 1;
|
||||
*/
|
||||
workspaceId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string workspace_revision_id = 2;
|
||||
*/
|
||||
workspaceRevisionId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string source_root_commit = 3;
|
||||
*/
|
||||
sourceRootCommit: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.GetWorkspaceResponse.
|
||||
* Use `create(GetWorkspaceResponseSchema)` to create a new message.
|
||||
*/
|
||||
export const GetWorkspaceResponseSchema: GenMessage<GetWorkspaceResponse> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 7);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.ListActivationsRequest
|
||||
*/
|
||||
export type ListActivationsRequest = Message<"quixos.orch.ListActivationsRequest"> & {
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.ListActivationsRequest.
|
||||
* Use `create(ListActivationsRequestSchema)` to create a new message.
|
||||
*/
|
||||
export const ListActivationsRequestSchema: GenMessage<ListActivationsRequest> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 8);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.ListPackageDescriptorsRequest
|
||||
*/
|
||||
export type ListPackageDescriptorsRequest = Message<"quixos.orch.ListPackageDescriptorsRequest"> & {
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.ListPackageDescriptorsRequest.
|
||||
* Use `create(ListPackageDescriptorsRequestSchema)` to create a new message.
|
||||
*/
|
||||
export const ListPackageDescriptorsRequestSchema: GenMessage<ListPackageDescriptorsRequest> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 9);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.ListPackageDescriptorsResponse
|
||||
*/
|
||||
export type ListPackageDescriptorsResponse = Message<"quixos.orch.ListPackageDescriptorsResponse"> & {
|
||||
/**
|
||||
* @generated from field: repeated quixos.PackageDescriptor descriptors = 1;
|
||||
*/
|
||||
descriptors: PackageDescriptor[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.ListPackageDescriptorsResponse.
|
||||
* Use `create(ListPackageDescriptorsResponseSchema)` to create a new message.
|
||||
*/
|
||||
export const ListPackageDescriptorsResponseSchema: GenMessage<ListPackageDescriptorsResponse> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 10);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.ListPackageRuntimesRequest
|
||||
*/
|
||||
export type ListPackageRuntimesRequest = Message<"quixos.orch.ListPackageRuntimesRequest"> & {
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.ListPackageRuntimesRequest.
|
||||
* Use `create(ListPackageRuntimesRequestSchema)` to create a new message.
|
||||
*/
|
||||
export const ListPackageRuntimesRequestSchema: GenMessage<ListPackageRuntimesRequest> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 11);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.ListPackageRuntimesResponse
|
||||
*/
|
||||
export type ListPackageRuntimesResponse = Message<"quixos.orch.ListPackageRuntimesResponse"> & {
|
||||
/**
|
||||
* @generated from field: repeated quixos.orch.PackageRuntimeStatus runtimes = 1;
|
||||
*/
|
||||
runtimes: PackageRuntimeStatus[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.ListPackageRuntimesResponse.
|
||||
* Use `create(ListPackageRuntimesResponseSchema)` to create a new message.
|
||||
*/
|
||||
export const ListPackageRuntimesResponseSchema: GenMessage<ListPackageRuntimesResponse> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 12);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.ListActivationsResponse
|
||||
*/
|
||||
export type ListActivationsResponse = Message<"quixos.orch.ListActivationsResponse"> & {
|
||||
/**
|
||||
* @generated from field: repeated quixos.orch.Activation activations = 1;
|
||||
*/
|
||||
activations: Activation[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.ListActivationsResponse.
|
||||
* Use `create(ListActivationsResponseSchema)` to create a new message.
|
||||
*/
|
||||
export const ListActivationsResponseSchema: GenMessage<ListActivationsResponse> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 13);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.CloseActivationRequest
|
||||
*/
|
||||
export type CloseActivationRequest = Message<"quixos.orch.CloseActivationRequest"> & {
|
||||
/**
|
||||
* @generated from field: string activation_id = 1;
|
||||
*/
|
||||
activationId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string reason = 2;
|
||||
*/
|
||||
reason: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.CloseActivationRequest.
|
||||
* Use `create(CloseActivationRequestSchema)` to create a new message.
|
||||
*/
|
||||
export const CloseActivationRequestSchema: GenMessage<CloseActivationRequest> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 14);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.CloseActivationResponse
|
||||
*/
|
||||
export type CloseActivationResponse = Message<"quixos.orch.CloseActivationResponse"> & {
|
||||
/**
|
||||
* @generated from field: quixos.orch.Activation activation = 1;
|
||||
*/
|
||||
activation?: Activation | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.CloseActivationResponse.
|
||||
* Use `create(CloseActivationResponseSchema)` to create a new message.
|
||||
*/
|
||||
export const CloseActivationResponseSchema: GenMessage<CloseActivationResponse> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 15);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.Activation
|
||||
*/
|
||||
export type Activation = Message<"quixos.orch.Activation"> & {
|
||||
/**
|
||||
* @generated from field: string activation_id = 1;
|
||||
*/
|
||||
activationId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: quixos.PackageExportRef export = 2;
|
||||
*/
|
||||
export?: PackageExportRef | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: string object_id = 3;
|
||||
*/
|
||||
objectId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string state = 4;
|
||||
*/
|
||||
state: string;
|
||||
|
||||
/**
|
||||
* @generated from field: uint32 demand = 5;
|
||||
*/
|
||||
demand: number;
|
||||
|
||||
/**
|
||||
* @generated from field: string opened_at = 6;
|
||||
*/
|
||||
openedAt: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string last_used_at = 7;
|
||||
*/
|
||||
lastUsedAt: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string idle_deadline_at = 8;
|
||||
*/
|
||||
idleDeadlineAt: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string closed_at = 9;
|
||||
*/
|
||||
closedAt: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string close_reason = 10;
|
||||
*/
|
||||
closeReason: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.Activation.
|
||||
* Use `create(ActivationSchema)` to create a new message.
|
||||
*/
|
||||
export const ActivationSchema: GenMessage<Activation> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 16);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.orch.PackageRuntimeStatus
|
||||
*/
|
||||
export type PackageRuntimeStatus = Message<"quixos.orch.PackageRuntimeStatus"> & {
|
||||
/**
|
||||
* @generated from field: string runtime_key = 1;
|
||||
*/
|
||||
runtimeKey: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string package_revision_id = 2;
|
||||
*/
|
||||
packageRevisionId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string source_repository = 3;
|
||||
*/
|
||||
sourceRepository: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string source_commit = 4;
|
||||
*/
|
||||
sourceCommit: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string build_target = 5;
|
||||
*/
|
||||
buildTarget: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string server_path = 6;
|
||||
*/
|
||||
serverPath: string;
|
||||
|
||||
/**
|
||||
* @generated from field: uint32 pid = 7;
|
||||
*/
|
||||
pid: number;
|
||||
|
||||
/**
|
||||
* @generated from field: string state = 8;
|
||||
*/
|
||||
state: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string started_at = 9;
|
||||
*/
|
||||
startedAt: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string last_handshake_at = 10;
|
||||
*/
|
||||
lastHandshakeAt: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string runtime_protocol_version = 11;
|
||||
*/
|
||||
runtimeProtocolVersion: string;
|
||||
|
||||
/**
|
||||
* @generated from field: uint32 advertised_export_count = 12;
|
||||
*/
|
||||
advertisedExportCount: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.orch.PackageRuntimeStatus.
|
||||
* Use `create(PackageRuntimeStatusSchema)` to create a new message.
|
||||
*/
|
||||
export const PackageRuntimeStatusSchema: GenMessage<PackageRuntimeStatus> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_orch, 17);
|
||||
|
||||
/**
|
||||
* @generated from service quixos.orch.OrchestratorRuntime
|
||||
*/
|
||||
export const OrchestratorRuntime: GenService<{
|
||||
/**
|
||||
* @generated from rpc quixos.orch.OrchestratorRuntime.InvokeCapability
|
||||
*/
|
||||
invokeCapability: {
|
||||
methodKind: "unary";
|
||||
input: typeof InvokeCapabilityRequestSchema;
|
||||
output: typeof InvokeCapabilityResponseSchema;
|
||||
},
|
||||
/**
|
||||
* @generated from rpc quixos.orch.OrchestratorRuntime.WatchCapability
|
||||
*/
|
||||
watchCapability: {
|
||||
methodKind: "server_streaming";
|
||||
input: typeof WatchCapabilityRequestSchema;
|
||||
output: typeof WatchCapabilityEventSchema;
|
||||
},
|
||||
/**
|
||||
* @generated from rpc quixos.orch.OrchestratorRuntime.ConstructObject
|
||||
*/
|
||||
constructObject: {
|
||||
methodKind: "unary";
|
||||
input: typeof ConstructObjectRequestSchema;
|
||||
output: typeof ConstructObjectResponseSchema;
|
||||
},
|
||||
/**
|
||||
* @generated from rpc quixos.orch.OrchestratorRuntime.GetWorkspace
|
||||
*/
|
||||
getWorkspace: {
|
||||
methodKind: "unary";
|
||||
input: typeof GetWorkspaceRequestSchema;
|
||||
output: typeof GetWorkspaceResponseSchema;
|
||||
},
|
||||
/**
|
||||
* @generated from rpc quixos.orch.OrchestratorRuntime.ListPackageDescriptors
|
||||
*/
|
||||
listPackageDescriptors: {
|
||||
methodKind: "unary";
|
||||
input: typeof ListPackageDescriptorsRequestSchema;
|
||||
output: typeof ListPackageDescriptorsResponseSchema;
|
||||
},
|
||||
/**
|
||||
* @generated from rpc quixos.orch.OrchestratorRuntime.ListPackageRuntimes
|
||||
*/
|
||||
listPackageRuntimes: {
|
||||
methodKind: "unary";
|
||||
input: typeof ListPackageRuntimesRequestSchema;
|
||||
output: typeof ListPackageRuntimesResponseSchema;
|
||||
},
|
||||
/**
|
||||
* @generated from rpc quixos.orch.OrchestratorRuntime.ListActivations
|
||||
*/
|
||||
listActivations: {
|
||||
methodKind: "unary";
|
||||
input: typeof ListActivationsRequestSchema;
|
||||
output: typeof ListActivationsResponseSchema;
|
||||
},
|
||||
/**
|
||||
* @generated from rpc quixos.orch.OrchestratorRuntime.CloseActivation
|
||||
*/
|
||||
closeActivation: {
|
||||
methodKind: "unary";
|
||||
input: typeof CloseActivationRequestSchema;
|
||||
output: typeof CloseActivationResponseSchema;
|
||||
},
|
||||
}> = /*@__PURE__*/
|
||||
serviceDesc(file_quixos_orch, 0);
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// @generated by protoc-gen-es v2.12.1 with parameter "target=ts,import_extension=js"
|
||||
// @generated from file quixos/package.proto (package quixos, syntax proto3)
|
||||
/* eslint-disable */
|
||||
|
||||
import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
|
||||
import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
|
||||
import type { Message } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
* Describes the file quixos/package.proto.
|
||||
*/
|
||||
export const file_quixos_package: GenFile = /*@__PURE__*/
|
||||
fileDesc("ChRxdWl4b3MvcGFja2FnZS5wcm90bxIGcXVpeG9zIo4BChFQYWNrYWdlRGVzY3JpcHRvchISCgpwYWNrYWdlX2lkGAEgASgJEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYAiABKAkSIAoYcnVudGltZV9wcm90b2NvbF92ZXJzaW9uGAMgASgJEiYKB2V4cG9ydHMYBCADKAsyFS5xdWl4b3MuUnVudGltZUV4cG9ydCI6Cg1SdW50aW1lRXhwb3J0EhEKCWV4cG9ydF9pZBgBIAEoCRIWCg5ydW50aW1lX3N5bWJvbBgCIAEoCWIGcHJvdG8z");
|
||||
|
||||
/**
|
||||
* @generated from message quixos.PackageDescriptor
|
||||
*/
|
||||
export type PackageDescriptor = Message<"quixos.PackageDescriptor"> & {
|
||||
/**
|
||||
* @generated from field: string package_id = 1;
|
||||
*/
|
||||
packageId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string package_revision_id = 2;
|
||||
*/
|
||||
packageRevisionId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string runtime_protocol_version = 3;
|
||||
*/
|
||||
runtimeProtocolVersion: string;
|
||||
|
||||
/**
|
||||
* @generated from field: repeated quixos.RuntimeExport exports = 4;
|
||||
*/
|
||||
exports: RuntimeExport[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.PackageDescriptor.
|
||||
* Use `create(PackageDescriptorSchema)` to create a new message.
|
||||
*/
|
||||
export const PackageDescriptorSchema: GenMessage<PackageDescriptor> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_package, 0);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.RuntimeExport
|
||||
*/
|
||||
export type RuntimeExport = Message<"quixos.RuntimeExport"> & {
|
||||
/**
|
||||
* @generated from field: string export_id = 1;
|
||||
*/
|
||||
exportId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string runtime_symbol = 2;
|
||||
*/
|
||||
runtimeSymbol: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.RuntimeExport.
|
||||
* Use `create(RuntimeExportSchema)` to create a new message.
|
||||
*/
|
||||
export const RuntimeExportSchema: GenMessage<RuntimeExport> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_package, 1);
|
||||
|
||||
+100
-25
@@ -10,42 +10,117 @@ import type { Message } from "@bufbuild/protobuf";
|
||||
* Describes the file quixos/refs.proto.
|
||||
*/
|
||||
export const file_quixos_refs: GenFile = /*@__PURE__*/
|
||||
fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zInYKC0Z1bmN0aW9uUmVmEhkKEXBhY2thZ2VfbmFtZXNwYWNlGAEgASgJEhQKDHBhY2thZ2VfbmFtZRgCIAEoCRIOCgZzeW1ib2wYAyABKAkSEwoLdmVyc2lvbl9yZWYYBCABKAkSEQoJb3BlcmF0aW9uGAUgASgJYgZwcm90bzM");
|
||||
fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zIkQKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCSJCChBQYWNrYWdlRXhwb3J0UmVmEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYASABKAkSEQoJZXhwb3J0X2lkGAIgASgJIroBChJJbmplY3RlZERlcGVuZGVuY3kSDwoHcG9ydF9pZBgBIAEoCRIXCg1zdGF0ZV9zbG90X2lkGAIgASgJSAASJgoEZWRnZRgDIAEoCzIWLnF1aXhvcy5FZGdlRGVwZW5kZW5jeUgAEigKHnJlY2VpdmVyX2ludGVyZmFjZV9yZXZpc2lvbl9pZBgEIAEoCUgAEh0KE2NvbnN0cnVjdG9yX2F0b21faWQYBSABKAlIAEIJCgdiaW5kaW5nIj0KDkVkZ2VEZXBlbmRlbmN5EhQKDGVkZ2VfdHlwZV9pZBgBIAEoCRIVCg1wcm9qZWN0aW9uX2lkGAIgASgJYgZwcm90bzM");
|
||||
|
||||
/**
|
||||
* @generated from message quixos.FunctionRef
|
||||
* @generated from message quixos.CapabilityRef
|
||||
*/
|
||||
export type FunctionRef = Message<"quixos.FunctionRef"> & {
|
||||
export type CapabilityRef = Message<"quixos.CapabilityRef"> & {
|
||||
/**
|
||||
* @generated from field: string package_namespace = 1;
|
||||
* @generated from field: string interface_revision_id = 1;
|
||||
*/
|
||||
packageNamespace: string;
|
||||
interfaceRevisionId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string package_name = 2;
|
||||
* @generated from field: string operation_id = 2;
|
||||
*/
|
||||
packageName: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string symbol = 3;
|
||||
*/
|
||||
symbol: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string version_ref = 4;
|
||||
*/
|
||||
versionRef: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string operation = 5;
|
||||
*/
|
||||
operation: string;
|
||||
operationId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.FunctionRef.
|
||||
* Use `create(FunctionRefSchema)` to create a new message.
|
||||
* Describes the message quixos.CapabilityRef.
|
||||
* Use `create(CapabilityRefSchema)` to create a new message.
|
||||
*/
|
||||
export const FunctionRefSchema: GenMessage<FunctionRef> = /*@__PURE__*/
|
||||
export const CapabilityRefSchema: GenMessage<CapabilityRef> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_refs, 0);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.PackageExportRef
|
||||
*/
|
||||
export type PackageExportRef = Message<"quixos.PackageExportRef"> & {
|
||||
/**
|
||||
* @generated from field: string package_revision_id = 1;
|
||||
*/
|
||||
packageRevisionId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string export_id = 2;
|
||||
*/
|
||||
exportId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.PackageExportRef.
|
||||
* Use `create(PackageExportRefSchema)` to create a new message.
|
||||
*/
|
||||
export const PackageExportRefSchema: GenMessage<PackageExportRef> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_refs, 1);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.InjectedDependency
|
||||
*/
|
||||
export type InjectedDependency = Message<"quixos.InjectedDependency"> & {
|
||||
/**
|
||||
* @generated from field: string port_id = 1;
|
||||
*/
|
||||
portId: string;
|
||||
|
||||
/**
|
||||
* @generated from oneof quixos.InjectedDependency.binding
|
||||
*/
|
||||
binding: {
|
||||
/**
|
||||
* @generated from field: string state_slot_id = 2;
|
||||
*/
|
||||
value: string;
|
||||
case: "stateSlotId";
|
||||
} | {
|
||||
/**
|
||||
* @generated from field: quixos.EdgeDependency edge = 3;
|
||||
*/
|
||||
value: EdgeDependency;
|
||||
case: "edge";
|
||||
} | {
|
||||
/**
|
||||
* @generated from field: string receiver_interface_revision_id = 4;
|
||||
*/
|
||||
value: string;
|
||||
case: "receiverInterfaceRevisionId";
|
||||
} | {
|
||||
/**
|
||||
* @generated from field: string constructor_atom_id = 5;
|
||||
*/
|
||||
value: string;
|
||||
case: "constructorAtomId";
|
||||
} | { case: undefined; value?: undefined };
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.InjectedDependency.
|
||||
* Use `create(InjectedDependencySchema)` to create a new message.
|
||||
*/
|
||||
export const InjectedDependencySchema: GenMessage<InjectedDependency> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_refs, 2);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.EdgeDependency
|
||||
*/
|
||||
export type EdgeDependency = Message<"quixos.EdgeDependency"> & {
|
||||
/**
|
||||
* @generated from field: string edge_type_id = 1;
|
||||
*/
|
||||
edgeTypeId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string projection_id = 2;
|
||||
*/
|
||||
projectionId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the message quixos.EdgeDependency.
|
||||
* Use `create(EdgeDependencySchema)` to create a new message.
|
||||
*/
|
||||
export const EdgeDependencySchema: GenMessage<EdgeDependency> = /*@__PURE__*/
|
||||
messageDesc(file_quixos_refs, 3);
|
||||
|
||||
|
||||
+25
-20
@@ -6,7 +6,7 @@ import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegen
|
||||
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2";
|
||||
import type { Value } from "../camino/api_pb.js";
|
||||
import { file_camino_api } from "../camino/api_pb.js";
|
||||
import type { FunctionRef } from "./refs_pb.js";
|
||||
import type { InjectedDependency, PackageExportRef } from "./refs_pb.js";
|
||||
import { file_quixos_refs } from "./refs_pb.js";
|
||||
import type { Message } from "@bufbuild/protobuf";
|
||||
|
||||
@@ -14,7 +14,7 @@ import type { Message } from "@bufbuild/protobuf";
|
||||
* Describes the file quixos/runtime.proto.
|
||||
*/
|
||||
export const file_quixos_runtime: GenFile = /*@__PURE__*/
|
||||
fileDesc("ChRxdWl4b3MvcnVudGltZS5wcm90bxIOcXVpeG9zLnJ1bnRpbWUiMQoQSGFuZHNoYWtlUmVxdWVzdBIdChVvcmNoX3Byb3RvY29sX3ZlcnNpb24YASABKAkijgEKEUhhbmRzaGFrZVJlc3BvbnNlEhkKEXBhY2thZ2VfbmFtZXNwYWNlGAEgASgJEhQKDHBhY2thZ2VfbmFtZRgCIAEoCRIgChhydW50aW1lX3Byb3RvY29sX3ZlcnNpb24YAyABKAkSJgoJZnVuY3Rpb25zGAQgAygLMhMucXVpeG9zLkZ1bmN0aW9uUmVmItYBCg1JbnZva2VSZXF1ZXN0EhUKDWludm9jYXRpb25faWQYASABKAkSJQoIZnVuY3Rpb24YAiABKAsyEy5xdWl4b3MuRnVuY3Rpb25SZWYSEQoJb2JqZWN0X2lkGAMgASgJEjcKBWlucHV0GAQgAygLMigucXVpeG9zLnJ1bnRpbWUuSW52b2tlUmVxdWVzdC5JbnB1dEVudHJ5GjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASJKCg5JbnZva2VSZXNwb25zZRIKCgJvaxgBIAEoCBIdCgZyZXN1bHQYAiABKAsyDS5jYW1pbm8uVmFsdWUSDQoFZXJyb3IYAyABKAki1AEKDFdhdGNoUmVxdWVzdBIVCg1pbnZvY2F0aW9uX2lkGAEgASgJEiUKCGZ1bmN0aW9uGAIgASgLMhMucXVpeG9zLkZ1bmN0aW9uUmVmEhEKCW9iamVjdF9pZBgDIAEoCRI2CgVpbnB1dBgEIAMoCzInLnF1aXhvcy5ydW50aW1lLldhdGNoUmVxdWVzdC5JbnB1dEVudHJ5GjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASJeChFEZXJpdmVkRGVwZW5kZW5jeRIMCgRraW5kGAEgASgJEhEKCW9iamVjdF9pZBgCIAEoCRISCgpmaWVsZF9uYW1lGAMgASgJEhQKDHNvdXJjZV9maWVsZBgEIAEoCSKVAQoKV2F0Y2hFdmVudBIQCgh3YXRjaF9pZBgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZRI3CgxkZXBlbmRlbmNpZXMYAyADKAsyIS5xdWl4b3MucnVudGltZS5EZXJpdmVkRGVwZW5kZW5jeRINCgVlcnJvchgEIAEoCRIPCgdpbml0aWFsGAUgASgIMvABCg5QYWNrYWdlUnVudGltZRJQCglIYW5kc2hha2USIC5xdWl4b3MucnVudGltZS5IYW5kc2hha2VSZXF1ZXN0GiEucXVpeG9zLnJ1bnRpbWUuSGFuZHNoYWtlUmVzcG9uc2USRwoGSW52b2tlEh0ucXVpeG9zLnJ1bnRpbWUuSW52b2tlUmVxdWVzdBoeLnF1aXhvcy5ydW50aW1lLkludm9rZVJlc3BvbnNlEkMKBVdhdGNoEhwucXVpeG9zLnJ1bnRpbWUuV2F0Y2hSZXF1ZXN0GhoucXVpeG9zLnJ1bnRpbWUuV2F0Y2hFdmVudDABYgZwcm90bzM", [file_camino_api, file_quixos_refs]);
|
||||
fileDesc("ChRxdWl4b3MvcnVudGltZS5wcm90bxIOcXVpeG9zLnJ1bnRpbWUiMQoQSGFuZHNoYWtlUmVxdWVzdBIdChVvcmNoX3Byb3RvY29sX3ZlcnNpb24YASABKAkiZgoRSGFuZHNoYWtlUmVzcG9uc2USGwoTcGFja2FnZV9yZXZpc2lvbl9pZBgBIAEoCRIgChhydW50aW1lX3Byb3RvY29sX3ZlcnNpb24YAiABKAkSEgoKZXhwb3J0X2lkcxgDIAMoCSKLAgoNSW52b2tlUmVxdWVzdBIVCg1pbnZvY2F0aW9uX2lkGAEgASgJEigKBmV4cG9ydBgCIAEoCzIYLnF1aXhvcy5QYWNrYWdlRXhwb3J0UmVmEhEKCW9iamVjdF9pZBgDIAEoCRI3CgVpbnB1dBgEIAMoCzIoLnF1aXhvcy5ydW50aW1lLkludm9rZVJlcXVlc3QuSW5wdXRFbnRyeRIwCgxkZXBlbmRlbmNpZXMYBSADKAsyGi5xdWl4b3MuSW5qZWN0ZWREZXBlbmRlbmN5GjsKCklucHV0RW50cnkSCwoDa2V5GAEgASgJEhwKBXZhbHVlGAIgASgLMg0uY2FtaW5vLlZhbHVlOgI4ASJKCg5JbnZva2VSZXNwb25zZRIKCgJvaxgBIAEoCBIdCgZyZXN1bHQYAiABKAsyDS5jYW1pbm8uVmFsdWUSDQoFZXJyb3IYAyABKAkiiQIKDFdhdGNoUmVxdWVzdBIVCg1pbnZvY2F0aW9uX2lkGAEgASgJEigKBmV4cG9ydBgCIAEoCzIYLnF1aXhvcy5QYWNrYWdlRXhwb3J0UmVmEhEKCW9iamVjdF9pZBgDIAEoCRI2CgVpbnB1dBgEIAMoCzInLnF1aXhvcy5ydW50aW1lLldhdGNoUmVxdWVzdC5JbnB1dEVudHJ5EjAKDGRlcGVuZGVuY2llcxgFIAMoCzIaLnF1aXhvcy5JbmplY3RlZERlcGVuZGVuY3kaOwoKSW5wdXRFbnRyeRILCgNrZXkYASABKAkSHAoFdmFsdWUYAiABKAsyDS5jYW1pbm8uVmFsdWU6AjgBImIKEURlcml2ZWREZXBlbmRlbmN5EgwKBGtpbmQYASABKAkSEQoJb2JqZWN0X2lkGAIgASgJEhUKDWF0dGFjaG1lbnRfaWQYAyABKAkSFQoNcHJvamVjdGlvbl9pZBgEIAEoCSKVAQoKV2F0Y2hFdmVudBIQCgh3YXRjaF9pZBgBIAEoCRIcCgV2YWx1ZRgCIAEoCzINLmNhbWluby5WYWx1ZRI3CgxkZXBlbmRlbmNpZXMYAyADKAsyIS5xdWl4b3MucnVudGltZS5EZXJpdmVkRGVwZW5kZW5jeRINCgVlcnJvchgEIAEoCRIPCgdpbml0aWFsGAUgASgIMvABCg5QYWNrYWdlUnVudGltZRJQCglIYW5kc2hha2USIC5xdWl4b3MucnVudGltZS5IYW5kc2hha2VSZXF1ZXN0GiEucXVpeG9zLnJ1bnRpbWUuSGFuZHNoYWtlUmVzcG9uc2USRwoGSW52b2tlEh0ucXVpeG9zLnJ1bnRpbWUuSW52b2tlUmVxdWVzdBoeLnF1aXhvcy5ydW50aW1lLkludm9rZVJlc3BvbnNlEkMKBVdhdGNoEhwucXVpeG9zLnJ1bnRpbWUuV2F0Y2hSZXF1ZXN0GhoucXVpeG9zLnJ1bnRpbWUuV2F0Y2hFdmVudDABYgZwcm90bzM", [file_camino_api, file_quixos_refs]);
|
||||
|
||||
/**
|
||||
* @generated from message quixos.runtime.HandshakeRequest
|
||||
@@ -38,24 +38,19 @@ export const HandshakeRequestSchema: GenMessage<HandshakeRequest> = /*@__PURE__*
|
||||
*/
|
||||
export type HandshakeResponse = Message<"quixos.runtime.HandshakeResponse"> & {
|
||||
/**
|
||||
* @generated from field: string package_namespace = 1;
|
||||
* @generated from field: string package_revision_id = 1;
|
||||
*/
|
||||
packageNamespace: string;
|
||||
packageRevisionId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string package_name = 2;
|
||||
*/
|
||||
packageName: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string runtime_protocol_version = 3;
|
||||
* @generated from field: string runtime_protocol_version = 2;
|
||||
*/
|
||||
runtimeProtocolVersion: string;
|
||||
|
||||
/**
|
||||
* @generated from field: repeated quixos.FunctionRef functions = 4;
|
||||
* @generated from field: repeated string export_ids = 3;
|
||||
*/
|
||||
functions: FunctionRef[];
|
||||
exportIds: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -75,9 +70,9 @@ export type InvokeRequest = Message<"quixos.runtime.InvokeRequest"> & {
|
||||
invocationId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: quixos.FunctionRef function = 2;
|
||||
* @generated from field: quixos.PackageExportRef export = 2;
|
||||
*/
|
||||
function?: FunctionRef | undefined;
|
||||
export?: PackageExportRef | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: string object_id = 3;
|
||||
@@ -88,6 +83,11 @@ export type InvokeRequest = Message<"quixos.runtime.InvokeRequest"> & {
|
||||
* @generated from field: map<string, camino.Value> input = 4;
|
||||
*/
|
||||
input: { [key: string]: Value };
|
||||
|
||||
/**
|
||||
* @generated from field: repeated quixos.InjectedDependency dependencies = 5;
|
||||
*/
|
||||
dependencies: InjectedDependency[];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -134,9 +134,9 @@ export type WatchRequest = Message<"quixos.runtime.WatchRequest"> & {
|
||||
invocationId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: quixos.FunctionRef function = 2;
|
||||
* @generated from field: quixos.PackageExportRef export = 2;
|
||||
*/
|
||||
function?: FunctionRef | undefined;
|
||||
export?: PackageExportRef | undefined;
|
||||
|
||||
/**
|
||||
* @generated from field: string object_id = 3;
|
||||
@@ -147,6 +147,11 @@ export type WatchRequest = Message<"quixos.runtime.WatchRequest"> & {
|
||||
* @generated from field: map<string, camino.Value> input = 4;
|
||||
*/
|
||||
input: { [key: string]: Value };
|
||||
|
||||
/**
|
||||
* @generated from field: repeated quixos.InjectedDependency dependencies = 5;
|
||||
*/
|
||||
dependencies: InjectedDependency[];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -171,14 +176,14 @@ export type DerivedDependency = Message<"quixos.runtime.DerivedDependency"> & {
|
||||
objectId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string field_name = 3;
|
||||
* @generated from field: string attachment_id = 3;
|
||||
*/
|
||||
fieldName: string;
|
||||
attachmentId: string;
|
||||
|
||||
/**
|
||||
* @generated from field: string source_field = 4;
|
||||
* @generated from field: string projection_id = 4;
|
||||
*/
|
||||
sourceField: string;
|
||||
projectionId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,973 +0,0 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import protobuf from "protobufjs";
|
||||
import type {
|
||||
Cardinality,
|
||||
ClassSchema,
|
||||
ConflictStrategy,
|
||||
FieldSchema,
|
||||
FieldStorage,
|
||||
FieldStorageKind,
|
||||
FunctionRef,
|
||||
InterfaceFieldContract,
|
||||
InterfaceImplementation,
|
||||
InterfaceSchema,
|
||||
MethodSchema,
|
||||
OperationSchema,
|
||||
OperationServiceSchema,
|
||||
MigrationSpec,
|
||||
SchemaCompileResult,
|
||||
SymbolRef,
|
||||
EdgeDirectionality,
|
||||
TypeRef,
|
||||
} from "./schema-ir.js";
|
||||
|
||||
type OptionBag = Record<string, unknown>;
|
||||
|
||||
const CLASS_OPTION = "(camino.class)";
|
||||
const INTERFACE_OPTION = "(camino.interface)";
|
||||
const IMPLEMENTS_OPTION = "(camino.implements)";
|
||||
const CONSTRUCTOR_OPTION = "(camino.constructor)";
|
||||
const METHOD_OPTION = "(camino.method)";
|
||||
const MIGRATION_OPTION = "(camino.migration)";
|
||||
const CONFLICT_OPTION = "(camino.conflict)";
|
||||
const EDGE_OPTION = "(camino.edge)";
|
||||
const FIELD_STORAGE_OPTION = "(camino.field_storage)";
|
||||
const FIELD_OPS_OPTION = "(camino.field_ops)";
|
||||
const INTERFACE_FIELD_OPTION = "(camino.interface_field)";
|
||||
const DISPLAY_LABEL_OPTION = "(camino.display_label)";
|
||||
const IMPL_OPTION = "(camino.impl)";
|
||||
const SCHEMA_NAMESPACE_OPTION = "(camino.schema_namespace)";
|
||||
const SCHEMA_VERSION_OPTION = "(camino.schema_version)";
|
||||
|
||||
const enumName = (value: unknown) =>
|
||||
String(value)
|
||||
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
||||
.replace(/-/g, "_")
|
||||
.toUpperCase();
|
||||
|
||||
const lowerEnumName = (value: unknown) => enumName(value).toLowerCase();
|
||||
|
||||
const getOption = (
|
||||
options: OptionBag | undefined,
|
||||
name: string,
|
||||
): unknown => {
|
||||
if (!options) {
|
||||
return undefined;
|
||||
}
|
||||
if (Object.hasOwn(options, name)) {
|
||||
return options[name];
|
||||
}
|
||||
const bareName = name.replace(/^\((.*)\)$/, "$1");
|
||||
if (Object.hasOwn(options, bareName)) {
|
||||
return options[bareName];
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const getParsedOptions = (
|
||||
reflection: protobuf.ReflectionObject,
|
||||
): OptionBag[] => {
|
||||
const parsedOptions = (reflection as unknown as { parsedOptions?: unknown })
|
||||
.parsedOptions;
|
||||
return Array.isArray(parsedOptions)
|
||||
? parsedOptions.filter(
|
||||
(option): option is OptionBag =>
|
||||
Boolean(option) && typeof option === "object" && !Array.isArray(option),
|
||||
)
|
||||
: [];
|
||||
};
|
||||
|
||||
const getReflectionOptions = (
|
||||
reflection: protobuf.ReflectionObject,
|
||||
name: string,
|
||||
): unknown[] => {
|
||||
const parsedValues = getParsedOptions(reflection).flatMap((option) => {
|
||||
const value = getOption(option, name);
|
||||
return value === undefined ? [] : [value];
|
||||
});
|
||||
if (parsedValues.length > 0) {
|
||||
return parsedValues;
|
||||
}
|
||||
const value = getOption(reflection.options, name);
|
||||
return value === undefined ? [] : [value];
|
||||
};
|
||||
|
||||
const getReflectionOption = (
|
||||
reflection: protobuf.ReflectionObject,
|
||||
name: string,
|
||||
): unknown => getReflectionOptions(reflection, name)[0];
|
||||
|
||||
const asObject = (value: unknown): OptionBag | undefined =>
|
||||
value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as OptionBag)
|
||||
: undefined;
|
||||
|
||||
const asArray = (value: unknown): unknown[] =>
|
||||
Array.isArray(value) ? value : value === undefined ? [] : [value];
|
||||
|
||||
const readString = (
|
||||
object: OptionBag | undefined,
|
||||
key: string,
|
||||
): string | undefined => {
|
||||
const value = object?.[key];
|
||||
return typeof value === "string" ? value : undefined;
|
||||
};
|
||||
|
||||
const readNumber = (
|
||||
object: OptionBag | undefined,
|
||||
key: string,
|
||||
): number | undefined => {
|
||||
const value = object?.[key];
|
||||
return typeof value === "number" && Number.isFinite(value)
|
||||
? value
|
||||
: undefined;
|
||||
};
|
||||
|
||||
const readBoolean = (
|
||||
object: OptionBag | undefined,
|
||||
key: string,
|
||||
): boolean | undefined => {
|
||||
const value = object?.[key];
|
||||
return typeof value === "boolean" ? value : undefined;
|
||||
};
|
||||
|
||||
const symbolRefFromOption = (
|
||||
value: unknown,
|
||||
fallback: SymbolRef,
|
||||
): SymbolRef => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
return fallback;
|
||||
}
|
||||
return {
|
||||
namespace: readString(object, "namespace") ?? fallback.namespace,
|
||||
name: readString(object, "name") ?? fallback.name,
|
||||
version: readString(object, "version") ?? fallback.version,
|
||||
...(readString(object, "hash")
|
||||
? { hash: readString(object, "hash") }
|
||||
: {}),
|
||||
};
|
||||
};
|
||||
|
||||
const typeRefFromOption = (
|
||||
value: unknown,
|
||||
fallbackVersion: string,
|
||||
): TypeRef | undefined => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
return undefined;
|
||||
}
|
||||
const symbol = asObject(object.symbol)
|
||||
? symbolRefFromOption(object.symbol, {
|
||||
namespace: "",
|
||||
name: "",
|
||||
version: fallbackVersion,
|
||||
})
|
||||
: undefined;
|
||||
const protoType = readString(object, "proto_type")?.replace(/^\./, "");
|
||||
const symbolProtoType =
|
||||
symbol?.namespace && symbol.name ? `${symbol.namespace}.${symbol.name}` : "";
|
||||
const resolvedProtoType = protoType ?? symbolProtoType;
|
||||
if (!resolvedProtoType) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
protoType: resolvedProtoType,
|
||||
...(symbol?.namespace && symbol.name ? { symbol } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
const interfaceFieldContractFromOption = (
|
||||
value: unknown,
|
||||
schemaVersion: string,
|
||||
): InterfaceFieldContract | undefined => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
return undefined;
|
||||
}
|
||||
const type = typeRefFromOption(object.type, schemaVersion);
|
||||
const refTargetTypeParam = readString(object, "ref_target_type_param");
|
||||
const edgeCardinality =
|
||||
object.edge_cardinality === undefined
|
||||
? undefined
|
||||
: cardinalityFromOption(object.edge_cardinality);
|
||||
return {
|
||||
required: readBoolean(object, "required") ?? false,
|
||||
readable: readBoolean(object, "readable") ?? false,
|
||||
writable: readBoolean(object, "writable") ?? false,
|
||||
watchable: readBoolean(object, "watchable") ?? false,
|
||||
...(readString(object, "type_param")
|
||||
? { typeParam: readString(object, "type_param") }
|
||||
: {}),
|
||||
...(type ? { type } : {}),
|
||||
...(refTargetTypeParam ? { refTargetTypeParam } : {}),
|
||||
...(edgeCardinality ? { edgeCardinality } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
const functionRefFromOption = (value: unknown): FunctionRef => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
throw new Error("Expected function ref option object");
|
||||
}
|
||||
const packageNamespace = readString(object, "package_namespace");
|
||||
const packageName = readString(object, "package_name");
|
||||
const symbol = readString(object, "symbol");
|
||||
if (!packageNamespace || !packageName || !symbol) {
|
||||
throw new Error("Function ref requires package_namespace, package_name, and symbol");
|
||||
}
|
||||
return {
|
||||
packageNamespace,
|
||||
packageName,
|
||||
symbol,
|
||||
...(readString(object, "operation")
|
||||
? { operation: readString(object, "operation") }
|
||||
: {}),
|
||||
...(readString(object, "version_ref")
|
||||
? { versionRef: readString(object, "version_ref") }
|
||||
: {}),
|
||||
};
|
||||
};
|
||||
|
||||
const conflictFromOption = (value: unknown): ConflictStrategy => {
|
||||
const normalized = enumName(value);
|
||||
if (!value || normalized === "CONFLICT_STRATEGY_UNSPECIFIED") {
|
||||
return "preserve_conflicts";
|
||||
}
|
||||
if (normalized === "REPLACE") {
|
||||
return "replace";
|
||||
}
|
||||
if (normalized === "PRESERVE_CONFLICTS") {
|
||||
return "preserve_conflicts";
|
||||
}
|
||||
if (normalized === "CRDT") {
|
||||
return "crdt";
|
||||
}
|
||||
throw new Error(`Unknown Camino conflict strategy: ${String(value)}`);
|
||||
};
|
||||
|
||||
const cardinalityFromOption = (value: unknown): Cardinality => {
|
||||
const normalized = lowerEnumName(value);
|
||||
if (!value || normalized === "cardinality_unspecified") {
|
||||
return "many";
|
||||
}
|
||||
if (
|
||||
normalized === "optional_one" ||
|
||||
normalized === "exactly_one" ||
|
||||
normalized === "many" ||
|
||||
normalized === "many_unique" ||
|
||||
normalized === "many_ordered" ||
|
||||
normalized === "many_unique_ordered"
|
||||
) {
|
||||
return normalized;
|
||||
}
|
||||
throw new Error(`Unknown Camino cardinality: ${String(value)}`);
|
||||
};
|
||||
|
||||
const fieldStorageKindFromOption = (value: unknown): FieldStorageKind => {
|
||||
if (value === 5) {
|
||||
return "static_final";
|
||||
}
|
||||
const normalized = lowerEnumName(value);
|
||||
if (!value || normalized === "field_storage_kind_unspecified") {
|
||||
return "stored";
|
||||
}
|
||||
if (
|
||||
normalized === "stored" ||
|
||||
normalized === "derived" ||
|
||||
normalized === "lazy" ||
|
||||
normalized === "external" ||
|
||||
normalized === "static_final"
|
||||
) {
|
||||
return normalized;
|
||||
}
|
||||
throw new Error(`Unknown Camino field storage kind: ${String(value)}`);
|
||||
};
|
||||
|
||||
const fieldStorageFromOption = (value: unknown): FieldStorage => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
return {
|
||||
kind: "stored",
|
||||
cache: false,
|
||||
};
|
||||
}
|
||||
const kind = fieldStorageKindFromOption(object.kind);
|
||||
const resolver = object.resolver === undefined
|
||||
? undefined
|
||||
: functionRefFromOption(object.resolver);
|
||||
if ((kind === "derived" || kind === "lazy" || kind === "external") && !resolver) {
|
||||
throw new Error(`${kind} field storage requires resolver`);
|
||||
}
|
||||
return {
|
||||
kind,
|
||||
...(resolver ? { resolver } : {}),
|
||||
cache: object.cache === true,
|
||||
};
|
||||
};
|
||||
|
||||
const fieldOpsFromOption = (value: unknown) => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
return undefined;
|
||||
}
|
||||
const implementation = enumName(object.implementation);
|
||||
if (implementation !== "SERVICE") {
|
||||
throw new Error(
|
||||
`Unsupported Camino field implementation: ${String(object.implementation)}`,
|
||||
);
|
||||
}
|
||||
const service = readString(object, "service");
|
||||
if (!service) {
|
||||
throw new Error("SERVICE field_ops requires service");
|
||||
}
|
||||
return {
|
||||
implementation: "service" as const,
|
||||
service,
|
||||
};
|
||||
};
|
||||
|
||||
const extractFileDefaults = (sourceFile: string) => {
|
||||
const text = fs.readFileSync(sourceFile, "utf8");
|
||||
const packageMatch = /^\s*package\s+([a-zA-Z0-9_.]+)\s*;/m.exec(text);
|
||||
const namespaceMatch =
|
||||
/^\s*option\s+\(camino\.schema_namespace\)\s*=\s*"([^"]+)"\s*;/m.exec(
|
||||
text,
|
||||
);
|
||||
const versionMatch =
|
||||
/^\s*option\s+\(camino\.schema_version\)\s*=\s*"([^"]+)"\s*;/m.exec(text);
|
||||
|
||||
return {
|
||||
packageName: packageMatch?.[1] ?? "",
|
||||
schemaNamespace: namespaceMatch?.[1] ?? packageMatch?.[1] ?? "",
|
||||
schemaVersion: versionMatch?.[1] ?? "1",
|
||||
};
|
||||
};
|
||||
|
||||
const protoSymbolFromReflection = (
|
||||
reflection: protobuf.ReflectionObject | null,
|
||||
fallbackVersion: string,
|
||||
): SymbolRef | undefined => {
|
||||
if (!reflection?.fullName) {
|
||||
return undefined;
|
||||
}
|
||||
const parts = reflection.fullName.replace(/^\./, "").split(".");
|
||||
const name = parts.pop();
|
||||
if (!name) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
namespace: parts.join("."),
|
||||
name,
|
||||
version: fallbackVersion,
|
||||
};
|
||||
};
|
||||
|
||||
const typeRefForField = (
|
||||
field: protobuf.Field,
|
||||
_schemaVersion: string,
|
||||
): TypeRef => {
|
||||
const enumValues =
|
||||
field.resolvedType instanceof protobuf.Enum
|
||||
? Object.entries(field.resolvedType.values)
|
||||
.filter(([_name, value]) => value !== 0)
|
||||
.map(([name]) => name)
|
||||
: undefined;
|
||||
return {
|
||||
protoType: field.type,
|
||||
...(enumValues ? { enumValues } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
const typeRefForType = (
|
||||
type: protobuf.Type | undefined,
|
||||
fallbackType: string,
|
||||
schemaVersion: string,
|
||||
): TypeRef => {
|
||||
const symbol = protoSymbolFromReflection(type ?? null, schemaVersion);
|
||||
return {
|
||||
protoType: type?.fullName?.replace(/^\./, "") ?? fallbackType,
|
||||
...(symbol ? { symbol } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
const fieldSchemaFromField = (
|
||||
field: protobuf.Field,
|
||||
schemaVersion: string,
|
||||
): FieldSchema => {
|
||||
const storage = fieldStorageFromOption(
|
||||
getReflectionOption(field, FIELD_STORAGE_OPTION),
|
||||
);
|
||||
const ops = fieldOpsFromOption(getReflectionOption(field, FIELD_OPS_OPTION));
|
||||
if (ops && storage.kind !== "stored" && storage.kind !== "static_final") {
|
||||
throw new Error(
|
||||
`Field ${field.fullName} cannot declare both field_ops and package-resolved storage`,
|
||||
);
|
||||
}
|
||||
if (storage.kind === "static_final" && !ops) {
|
||||
throw new Error(`Field ${field.fullName} with static_final storage requires field_ops`);
|
||||
}
|
||||
const interfaceContract = interfaceFieldContractFromOption(
|
||||
getReflectionOption(field, INTERFACE_FIELD_OPTION),
|
||||
schemaVersion,
|
||||
);
|
||||
return {
|
||||
name: field.name,
|
||||
tag: field.id,
|
||||
type: typeRefForField(field, schemaVersion),
|
||||
conflict: conflictFromOption(getReflectionOption(field, CONFLICT_OPTION)),
|
||||
repeated: field.repeated,
|
||||
optional: field.optional,
|
||||
storage,
|
||||
...(ops ? { ops } : {}),
|
||||
...(interfaceContract ? { interfaceContract } : {}),
|
||||
isDisplayLabel: getReflectionOption(field, DISPLAY_LABEL_OPTION) === true,
|
||||
};
|
||||
};
|
||||
|
||||
const isManyCardinality = (cardinality: Cardinality) =>
|
||||
cardinality === "many" ||
|
||||
cardinality === "many_unique" ||
|
||||
cardinality === "many_ordered" ||
|
||||
cardinality === "many_unique_ordered";
|
||||
|
||||
const materializationFromOption = (
|
||||
value: unknown,
|
||||
fallbackVersion: string,
|
||||
) => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
return undefined;
|
||||
}
|
||||
const classRef = symbolRefFromOption(object.class, {
|
||||
namespace: "",
|
||||
name: "",
|
||||
version: fallbackVersion,
|
||||
});
|
||||
if (!classRef.name) {
|
||||
throw new Error("Edge materialization requires class");
|
||||
}
|
||||
return {
|
||||
class: classRef,
|
||||
connectProjection: readString(object, "connect_projection") ?? "",
|
||||
};
|
||||
};
|
||||
|
||||
const endpointFromOption = (params: {
|
||||
option: unknown;
|
||||
fallbackClass?: SymbolRef;
|
||||
fallbackProjection: string;
|
||||
fallbackCardinality: Cardinality;
|
||||
fallbackVersion: string;
|
||||
}) => {
|
||||
const object = asObject(params.option);
|
||||
const classRef = asObject(object?.class)
|
||||
? symbolRefFromOption(object?.class, {
|
||||
namespace: "",
|
||||
name: "",
|
||||
version: params.fallbackVersion,
|
||||
})
|
||||
: params.fallbackClass;
|
||||
const interfaceRef = asObject(object?.interface)
|
||||
? symbolRefFromOption(object?.interface, {
|
||||
namespace: "",
|
||||
name: "",
|
||||
version: params.fallbackVersion,
|
||||
})
|
||||
: undefined;
|
||||
const projection = readString(object, "projection") ?? params.fallbackProjection;
|
||||
const cardinality = object?.cardinality === undefined
|
||||
? params.fallbackCardinality
|
||||
: cardinalityFromOption(object.cardinality);
|
||||
const materialization = materializationFromOption(
|
||||
object?.materialize,
|
||||
params.fallbackVersion,
|
||||
);
|
||||
if (!classRef?.name && !interfaceRef?.name) {
|
||||
throw new Error(`Edge endpoint ${projection} requires class or interface`);
|
||||
}
|
||||
return {
|
||||
...(classRef?.name ? { class: classRef } : {}),
|
||||
...(interfaceRef?.name ? { interface: interfaceRef } : {}),
|
||||
projection,
|
||||
cardinality,
|
||||
indexed: readBoolean(object, "indexed") ?? false,
|
||||
...(materialization ? { materialization } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
const symbolKey = (ref: SymbolRef | undefined) =>
|
||||
ref ? [ref.namespace, ref.name, ref.version, ref.hash ?? ""].join(":") : "";
|
||||
|
||||
const endpointRoleKey = (endpoint: ReturnType<typeof endpointFromOption>) =>
|
||||
[
|
||||
symbolKey(endpoint.class),
|
||||
symbolKey(endpoint.interface),
|
||||
endpoint.projection,
|
||||
endpoint.cardinality,
|
||||
].join("|");
|
||||
|
||||
const normalizeEdgeEndpoints = (params: {
|
||||
directionality: "directed" | "undirected";
|
||||
fromEndpoint: ReturnType<typeof endpointFromOption>;
|
||||
toEndpoint: ReturnType<typeof endpointFromOption>;
|
||||
}) => {
|
||||
if (params.directionality === "directed") {
|
||||
return {
|
||||
fromEndpoint: params.fromEndpoint,
|
||||
toEndpoint: params.toEndpoint,
|
||||
};
|
||||
}
|
||||
return endpointRoleKey(params.fromEndpoint) <= endpointRoleKey(params.toEndpoint)
|
||||
? {
|
||||
fromEndpoint: params.fromEndpoint,
|
||||
toEndpoint: params.toEndpoint,
|
||||
}
|
||||
: {
|
||||
fromEndpoint: params.toEndpoint,
|
||||
toEndpoint: params.fromEndpoint,
|
||||
};
|
||||
};
|
||||
|
||||
const symbolArrayFromOption = (
|
||||
value: unknown,
|
||||
defaults: ReturnType<typeof extractFileDefaults>,
|
||||
) =>
|
||||
asArray(value)
|
||||
.map((item) =>
|
||||
symbolRefFromOption(item, {
|
||||
namespace: defaults.schemaNamespace,
|
||||
name: "",
|
||||
version: defaults.schemaVersion,
|
||||
}),
|
||||
)
|
||||
.filter((symbol) => Boolean(symbol.name));
|
||||
|
||||
const isStringType = (type: TypeRef) =>
|
||||
type.protoType === "string" || type.protoType === "google.protobuf.StringValue";
|
||||
|
||||
const validateDisplayLabelFields = (
|
||||
type: protobuf.Type,
|
||||
fields: FieldSchema[],
|
||||
operationServices: OperationServiceSchema[],
|
||||
) => {
|
||||
const displayLabelFields = fields.filter((field) => field.isDisplayLabel);
|
||||
if (displayLabelFields.length > 1) {
|
||||
throw new Error(
|
||||
`Class ${type.fullName} declares multiple Camino display label fields`,
|
||||
);
|
||||
}
|
||||
const displayLabelField = displayLabelFields[0];
|
||||
if (!displayLabelField) {
|
||||
return;
|
||||
}
|
||||
if (!displayLabelField.ops) {
|
||||
if (!isStringType(displayLabelField.type)) {
|
||||
throw new Error(
|
||||
`Display label field ${type.fullName}.${displayLabelField.name} must have string type`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const serviceName = displayLabelField.ops.service.replace(/^\./, "");
|
||||
const getOperation = operationServices
|
||||
.find((service) => service.fullName === serviceName)
|
||||
?.operations.find((operation) => operation.name === "Get");
|
||||
if (!getOperation || !isStringType(getOperation.outputType)) {
|
||||
throw new Error(
|
||||
`Display label field ${type.fullName}.${displayLabelField.name} must resolve to string`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const typeBindingFromOption = (
|
||||
value: unknown,
|
||||
schemaVersion: string,
|
||||
) => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
return undefined;
|
||||
}
|
||||
const name = readString(object, "name");
|
||||
const type = typeRefFromOption(object.type, schemaVersion);
|
||||
if (!name || !type) {
|
||||
throw new Error("Interface type_binding requires name and type");
|
||||
}
|
||||
return { name, type };
|
||||
};
|
||||
|
||||
const interfaceImplementationFromOption = (
|
||||
value: unknown,
|
||||
defaults: ReturnType<typeof extractFileDefaults>,
|
||||
): InterfaceImplementation => {
|
||||
const object = asObject(value);
|
||||
if (!object) {
|
||||
throw new Error("Expected implements option object");
|
||||
}
|
||||
const interfaceId = symbolRefFromOption(object.interface, {
|
||||
namespace: defaults.schemaNamespace,
|
||||
name: "",
|
||||
version: defaults.schemaVersion,
|
||||
});
|
||||
if (!interfaceId.name) {
|
||||
throw new Error("implements option requires interface name");
|
||||
}
|
||||
return {
|
||||
interface: interfaceId,
|
||||
typeBindings: asArray(object.type_binding)
|
||||
.map((binding) => typeBindingFromOption(binding, defaults.schemaVersion))
|
||||
.filter((binding): binding is NonNullable<typeof binding> =>
|
||||
Boolean(binding),
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const serviceName = (service: protobuf.Service) =>
|
||||
service.fullName.replace(/^\./, "");
|
||||
|
||||
const operationFromMethod = (
|
||||
method: protobuf.Method,
|
||||
schemaVersion: string,
|
||||
): OperationSchema => {
|
||||
const fn = functionRefFromOption(getReflectionOption(method, IMPL_OPTION));
|
||||
const methodWithTypes = method as protobuf.Method & {
|
||||
resolvedRequestType?: protobuf.Type;
|
||||
resolvedResponseType?: protobuf.Type;
|
||||
};
|
||||
return {
|
||||
name: method.name,
|
||||
inputType: typeRefForType(
|
||||
methodWithTypes.resolvedRequestType,
|
||||
method.requestType,
|
||||
schemaVersion,
|
||||
),
|
||||
outputType: typeRefForType(
|
||||
methodWithTypes.resolvedResponseType,
|
||||
method.responseType,
|
||||
schemaVersion,
|
||||
),
|
||||
function: fn,
|
||||
};
|
||||
};
|
||||
|
||||
const operationServiceFromService = (
|
||||
service: protobuf.Service,
|
||||
schemaVersion: string,
|
||||
): OperationServiceSchema => ({
|
||||
name: service.name,
|
||||
fullName: serviceName(service),
|
||||
operations: service.methodsArray.map((method) =>
|
||||
operationFromMethod(method, schemaVersion),
|
||||
),
|
||||
});
|
||||
|
||||
const classSchemaFromType = (
|
||||
type: protobuf.Type,
|
||||
sourceFile: string,
|
||||
defaults: ReturnType<typeof extractFileDefaults>,
|
||||
operationServices: OperationServiceSchema[],
|
||||
): ClassSchema | undefined => {
|
||||
const classOption = asObject(getReflectionOption(type, CLASS_OPTION));
|
||||
if (!classOption) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const fallbackClassRef = {
|
||||
namespace: defaults.schemaNamespace,
|
||||
name: type.name,
|
||||
version: defaults.schemaVersion,
|
||||
};
|
||||
const classId = symbolRefFromOption(classOption.id, fallbackClassRef);
|
||||
const classVersion = readNumber(classOption, "version") ?? Number(classId.version);
|
||||
if (!Number.isInteger(classVersion) || classVersion <= 0) {
|
||||
throw new Error(`Class ${type.fullName} has invalid Camino class version`);
|
||||
}
|
||||
|
||||
const fields = type.fieldsArray.map((field) =>
|
||||
fieldSchemaFromField(field, defaults.schemaVersion),
|
||||
);
|
||||
validateDisplayLabelFields(type, fields, operationServices);
|
||||
const edges = type.fieldsArray.flatMap((field) => {
|
||||
const edgeOption = asObject(getReflectionOption(field, EDGE_OPTION));
|
||||
if (!edgeOption) {
|
||||
return [];
|
||||
}
|
||||
const legacyTargetClass = symbolRefFromOption(edgeOption.target, {
|
||||
namespace: defaults.schemaNamespace,
|
||||
name: "",
|
||||
version: defaults.schemaVersion,
|
||||
});
|
||||
const cardinality = cardinalityFromOption(edgeOption.cardinality);
|
||||
const declaredFromEndpoint = endpointFromOption({
|
||||
option: edgeOption.this_endpoint,
|
||||
fallbackClass: classId,
|
||||
fallbackProjection: field.name,
|
||||
fallbackCardinality: cardinality,
|
||||
fallbackVersion: defaults.schemaVersion,
|
||||
});
|
||||
const declaredToEndpoint = endpointFromOption({
|
||||
option: edgeOption.other_endpoint,
|
||||
fallbackClass: legacyTargetClass.name ? legacyTargetClass : undefined,
|
||||
fallbackProjection: readString(edgeOption, "inverse") ?? "",
|
||||
fallbackCardinality: "many",
|
||||
fallbackVersion: defaults.schemaVersion,
|
||||
});
|
||||
if (!declaredToEndpoint.projection) {
|
||||
throw new Error(
|
||||
`Edge field ${type.fullName}.${field.name} requires other_endpoint.projection or inverse`,
|
||||
);
|
||||
}
|
||||
const sourceProtoType = field.resolvedType?.fullName?.replace(/^\./, "");
|
||||
if (sourceProtoType !== "camino.Ref") {
|
||||
throw new Error(`Edge field ${type.fullName}.${field.name} must use camino.Ref`);
|
||||
}
|
||||
const isMany = isManyCardinality(declaredFromEndpoint.cardinality);
|
||||
if (isMany && !field.repeated) {
|
||||
throw new Error(`Edge field ${type.fullName}.${field.name} must be repeated for ${declaredFromEndpoint.cardinality}`);
|
||||
}
|
||||
if (!isMany && field.repeated) {
|
||||
throw new Error(`Edge field ${type.fullName}.${field.name} must not be repeated for ${declaredFromEndpoint.cardinality}`);
|
||||
}
|
||||
const directionality: EdgeDirectionality =
|
||||
edgeOption.undirected === true ? "undirected" : "directed";
|
||||
const { fromEndpoint, toEndpoint } = normalizeEdgeEndpoints({
|
||||
directionality,
|
||||
fromEndpoint: declaredFromEndpoint,
|
||||
toEndpoint: declaredToEndpoint,
|
||||
});
|
||||
const edgeId = symbolRefFromOption(edgeOption.id, {
|
||||
namespace: defaults.schemaNamespace,
|
||||
name: `${type.name}.${field.name}`,
|
||||
version: defaults.schemaVersion,
|
||||
});
|
||||
const fallbackToClass = toEndpoint.class ?? {
|
||||
namespace: "",
|
||||
name: "",
|
||||
version: "",
|
||||
};
|
||||
return [
|
||||
{
|
||||
id: edgeId,
|
||||
directionality,
|
||||
sourceField: fromEndpoint.projection,
|
||||
fromClass: fromEndpoint.class ?? classId,
|
||||
toClass: fallbackToClass,
|
||||
cardinality: fromEndpoint.cardinality,
|
||||
...(toEndpoint.projection
|
||||
? { inverse: toEndpoint.projection }
|
||||
: {}),
|
||||
fields: [],
|
||||
fromEndpoint,
|
||||
toEndpoint,
|
||||
declaringClass: classId,
|
||||
tags: symbolArrayFromOption(edgeOption.tag, defaults),
|
||||
implements: symbolArrayFromOption(edgeOption.implements, defaults),
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const methods: MethodSchema[] = getReflectionOptions(type, METHOD_OPTION)
|
||||
.map(asObject)
|
||||
.filter((option): option is OptionBag => Boolean(option))
|
||||
.map((option) => {
|
||||
const name = readString(option, "name");
|
||||
if (!name) {
|
||||
throw new Error(`Method option on ${type.fullName} requires name`);
|
||||
}
|
||||
return {
|
||||
name,
|
||||
function: functionRefFromOption(option.function),
|
||||
};
|
||||
});
|
||||
|
||||
const migrations: MigrationSpec[] = getReflectionOptions(type, MIGRATION_OPTION)
|
||||
.map(asObject)
|
||||
.filter((option): option is OptionBag => Boolean(option))
|
||||
.map((option) => {
|
||||
const fromVersion = readNumber(option, "from_version");
|
||||
const toVersion = readNumber(option, "to_version");
|
||||
if (!fromVersion || !toVersion) {
|
||||
throw new Error(`Migration option on ${type.fullName} requires versions`);
|
||||
}
|
||||
return {
|
||||
fromVersion,
|
||||
toVersion,
|
||||
function: functionRefFromOption(option.function),
|
||||
};
|
||||
});
|
||||
|
||||
const constructorOption = asObject(
|
||||
getReflectionOption(type, CONSTRUCTOR_OPTION),
|
||||
);
|
||||
const constructorSpec = constructorOption
|
||||
? { function: functionRefFromOption(constructorOption.function) }
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
id: classId,
|
||||
version: classVersion,
|
||||
fields,
|
||||
edges,
|
||||
methods,
|
||||
migrations,
|
||||
operationServices,
|
||||
implements: getReflectionOptions(type, IMPLEMENTS_OPTION).map((option) =>
|
||||
interfaceImplementationFromOption(option, defaults),
|
||||
),
|
||||
...(constructorSpec ? { constructorSpec } : {}),
|
||||
sourceFile,
|
||||
protoMessage: type.fullName,
|
||||
};
|
||||
};
|
||||
|
||||
const interfaceSchemaFromType = (
|
||||
type: protobuf.Type,
|
||||
sourceFile: string,
|
||||
defaults: ReturnType<typeof extractFileDefaults>,
|
||||
): InterfaceSchema | undefined => {
|
||||
const interfaceOption = asObject(getReflectionOption(type, INTERFACE_OPTION));
|
||||
if (!interfaceOption) {
|
||||
return undefined;
|
||||
}
|
||||
const classOption = asObject(getReflectionOption(type, CLASS_OPTION));
|
||||
if (classOption) {
|
||||
throw new Error(`${type.fullName} cannot be both a Camino class and interface`);
|
||||
}
|
||||
const fallbackInterfaceRef = {
|
||||
namespace: defaults.schemaNamespace,
|
||||
name: type.name,
|
||||
version: defaults.schemaVersion,
|
||||
};
|
||||
const interfaceId = symbolRefFromOption(
|
||||
interfaceOption.id,
|
||||
fallbackInterfaceRef,
|
||||
);
|
||||
const interfaceVersion =
|
||||
readNumber(interfaceOption, "version") ?? Number(interfaceId.version);
|
||||
if (!Number.isInteger(interfaceVersion) || interfaceVersion <= 0) {
|
||||
throw new Error(`Interface ${type.fullName} has invalid Camino interface version`);
|
||||
}
|
||||
return {
|
||||
id: interfaceId,
|
||||
version: interfaceVersion,
|
||||
fields: type.fieldsArray.map((field) =>
|
||||
fieldSchemaFromField(field, defaults.schemaVersion),
|
||||
),
|
||||
sourceFile,
|
||||
protoMessage: type.fullName,
|
||||
typeParameters: asArray(interfaceOption.type_parameter)
|
||||
.map((entry) => String(entry).trim())
|
||||
.filter(Boolean),
|
||||
};
|
||||
};
|
||||
|
||||
const walkTypes = (
|
||||
namespace: protobuf.NamespaceBase,
|
||||
visit: (type: protobuf.Type) => void,
|
||||
) => {
|
||||
for (const nested of namespace.nestedArray) {
|
||||
if (nested instanceof protobuf.Type) {
|
||||
visit(nested);
|
||||
walkTypes(nested, visit);
|
||||
} else if (nested instanceof protobuf.Namespace) {
|
||||
walkTypes(nested, visit);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const walkServices = (
|
||||
namespace: protobuf.NamespaceBase,
|
||||
visit: (service: protobuf.Service) => void,
|
||||
) => {
|
||||
for (const nested of namespace.nestedArray) {
|
||||
if (nested instanceof protobuf.Service) {
|
||||
visit(nested);
|
||||
} else if (nested instanceof protobuf.Namespace) {
|
||||
walkServices(nested, visit);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const loadCaminoSchemaRoot = async (
|
||||
sourceFile: string,
|
||||
): Promise<{ absoluteSourceFile: string; root: protobuf.Root }> => {
|
||||
const absoluteSourceFile = path.resolve(sourceFile);
|
||||
const root = new protobuf.Root();
|
||||
const envIncludeDirs = [
|
||||
process.env.QUIXOS_PROTO_PATH,
|
||||
process.env.CAMINO_PROTO_PATH,
|
||||
]
|
||||
.filter((value): value is string => Boolean(value))
|
||||
.join(path.delimiter)
|
||||
.split(path.delimiter)
|
||||
.map((entry) => entry.trim())
|
||||
.filter(Boolean)
|
||||
.map((entry) => path.resolve(entry));
|
||||
const includeDirs = [
|
||||
path.dirname(absoluteSourceFile),
|
||||
path.resolve("../../quixos-protocol/proto"),
|
||||
path.resolve("quixos-protocol/proto"),
|
||||
path.resolve("proto"),
|
||||
...envIncludeDirs,
|
||||
];
|
||||
root.resolvePath = (origin, target) => {
|
||||
if (path.isAbsolute(target) && fs.existsSync(target)) {
|
||||
return target;
|
||||
}
|
||||
const originDir = origin ? path.dirname(origin) : undefined;
|
||||
const candidates = [
|
||||
...(originDir ? [path.resolve(originDir, target)] : []),
|
||||
...includeDirs.map((dir) => path.resolve(dir, target)),
|
||||
];
|
||||
const found = candidates.find((candidate) => fs.existsSync(candidate));
|
||||
return found ?? target;
|
||||
};
|
||||
|
||||
await root.load(absoluteSourceFile, { keepCase: true });
|
||||
root.resolveAll();
|
||||
|
||||
return { absoluteSourceFile, root };
|
||||
};
|
||||
|
||||
export const compileCaminoSchema = async (
|
||||
sourceFile: string,
|
||||
): Promise<SchemaCompileResult> => {
|
||||
const { absoluteSourceFile, root } = await loadCaminoSchemaRoot(sourceFile);
|
||||
const defaults = extractFileDefaults(absoluteSourceFile);
|
||||
|
||||
const operationServices: OperationServiceSchema[] = [];
|
||||
walkServices(root, (service) => {
|
||||
operationServices.push(
|
||||
operationServiceFromService(service, defaults.schemaVersion),
|
||||
);
|
||||
});
|
||||
|
||||
const classes: ClassSchema[] = [];
|
||||
const interfaces: InterfaceSchema[] = [];
|
||||
walkTypes(root, (type) => {
|
||||
const interfaceSchema = interfaceSchemaFromType(
|
||||
type,
|
||||
absoluteSourceFile,
|
||||
defaults,
|
||||
);
|
||||
if (interfaceSchema) {
|
||||
interfaces.push(interfaceSchema);
|
||||
}
|
||||
const classSchema = classSchemaFromType(
|
||||
type,
|
||||
absoluteSourceFile,
|
||||
defaults,
|
||||
operationServices,
|
||||
);
|
||||
if (classSchema) {
|
||||
classes.push(classSchema);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
sourceFile: absoluteSourceFile,
|
||||
classes,
|
||||
interfaces,
|
||||
};
|
||||
};
|
||||
@@ -1,174 +0,0 @@
|
||||
export type SymbolRef = {
|
||||
namespace: string;
|
||||
name: string;
|
||||
version: string;
|
||||
hash?: string;
|
||||
};
|
||||
|
||||
export type FunctionRef = {
|
||||
packageNamespace: string;
|
||||
packageName: string;
|
||||
symbol: string;
|
||||
operation?: string;
|
||||
versionRef?: string;
|
||||
};
|
||||
|
||||
export type ConflictStrategy =
|
||||
| "replace"
|
||||
| "preserve_conflicts"
|
||||
| "crdt";
|
||||
|
||||
export type Cardinality =
|
||||
| "optional_one"
|
||||
| "exactly_one"
|
||||
| "many"
|
||||
| "many_unique"
|
||||
| "many_ordered"
|
||||
| "many_unique_ordered";
|
||||
|
||||
export type EdgeDirectionality = "directed" | "undirected";
|
||||
|
||||
export type EdgeMaterialization = {
|
||||
class: SymbolRef;
|
||||
connectProjection: string;
|
||||
};
|
||||
|
||||
export type FieldStorageKind =
|
||||
| "stored"
|
||||
| "derived"
|
||||
| "lazy"
|
||||
| "external"
|
||||
| "static_final";
|
||||
|
||||
export type FieldStorage = {
|
||||
kind: FieldStorageKind;
|
||||
resolver?: FunctionRef;
|
||||
cache: boolean;
|
||||
};
|
||||
|
||||
export type FieldOps = {
|
||||
implementation: "service";
|
||||
service: string;
|
||||
};
|
||||
|
||||
export type TypeRef = {
|
||||
protoType: string;
|
||||
symbol?: SymbolRef;
|
||||
enumValues?: string[];
|
||||
};
|
||||
|
||||
export type TypeBinding = {
|
||||
name: string;
|
||||
type: TypeRef;
|
||||
};
|
||||
|
||||
export type InterfaceFieldContract = {
|
||||
required: boolean;
|
||||
readable: boolean;
|
||||
writable: boolean;
|
||||
watchable: boolean;
|
||||
typeParam?: string;
|
||||
type?: TypeRef;
|
||||
refTargetTypeParam?: string;
|
||||
edgeCardinality?: Cardinality;
|
||||
};
|
||||
|
||||
export type InterfaceImplementation = {
|
||||
interface: SymbolRef;
|
||||
typeBindings: TypeBinding[];
|
||||
};
|
||||
|
||||
export type FieldSchema = {
|
||||
name: string;
|
||||
tag: number;
|
||||
type: TypeRef;
|
||||
conflict: ConflictStrategy;
|
||||
repeated: boolean;
|
||||
optional: boolean;
|
||||
storage: FieldStorage;
|
||||
ops?: FieldOps;
|
||||
interfaceContract?: InterfaceFieldContract;
|
||||
isDisplayLabel: boolean;
|
||||
};
|
||||
|
||||
export type EdgeEndpointSchema = {
|
||||
class?: SymbolRef;
|
||||
interface?: SymbolRef;
|
||||
projection: string;
|
||||
cardinality: Cardinality;
|
||||
indexed: boolean;
|
||||
materialization?: EdgeMaterialization;
|
||||
};
|
||||
|
||||
export type EdgeSchema = {
|
||||
id: SymbolRef;
|
||||
directionality: EdgeDirectionality;
|
||||
sourceField: string;
|
||||
fromClass: SymbolRef;
|
||||
toClass: SymbolRef;
|
||||
cardinality: Cardinality;
|
||||
inverse?: string;
|
||||
fields: FieldSchema[];
|
||||
fromEndpoint: EdgeEndpointSchema;
|
||||
toEndpoint: EdgeEndpointSchema;
|
||||
declaringClass: SymbolRef;
|
||||
tags: SymbolRef[];
|
||||
implements: SymbolRef[];
|
||||
};
|
||||
|
||||
export type MethodSchema = {
|
||||
name: string;
|
||||
function: FunctionRef;
|
||||
};
|
||||
|
||||
export type MigrationSpec = {
|
||||
fromVersion: number;
|
||||
toVersion: number;
|
||||
function: FunctionRef;
|
||||
};
|
||||
|
||||
export type ConstructorSpec = {
|
||||
function: FunctionRef;
|
||||
};
|
||||
|
||||
export type OperationSchema = {
|
||||
name: string;
|
||||
inputType: TypeRef;
|
||||
outputType: TypeRef;
|
||||
function: FunctionRef;
|
||||
};
|
||||
|
||||
export type OperationServiceSchema = {
|
||||
name: string;
|
||||
fullName: string;
|
||||
operations: OperationSchema[];
|
||||
};
|
||||
|
||||
export type ClassSchema = {
|
||||
id: SymbolRef;
|
||||
version: number;
|
||||
fields: FieldSchema[];
|
||||
edges: EdgeSchema[];
|
||||
methods: MethodSchema[];
|
||||
migrations: MigrationSpec[];
|
||||
operationServices: OperationServiceSchema[];
|
||||
implements: InterfaceImplementation[];
|
||||
constructorSpec?: ConstructorSpec;
|
||||
sourceFile: string;
|
||||
protoMessage: string;
|
||||
};
|
||||
|
||||
export type InterfaceSchema = {
|
||||
id: SymbolRef;
|
||||
version: number;
|
||||
fields: FieldSchema[];
|
||||
sourceFile: string;
|
||||
protoMessage: string;
|
||||
typeParameters: string[];
|
||||
};
|
||||
|
||||
export type SchemaCompileResult = {
|
||||
sourceFile: string;
|
||||
classes: ClassSchema[];
|
||||
interfaces: InterfaceSchema[];
|
||||
};
|
||||
Reference in New Issue
Block a user