Make local graph execution optional across composed packages
This commit is contained in:
+19
-14
@@ -1,3 +1,4 @@
|
||||
import { standardNativeBackends, type NativeExecutionBackend } from "./native-backends.js";
|
||||
import type {
|
||||
WorkspaceRevision,
|
||||
ExecutionContract,
|
||||
@@ -45,7 +46,7 @@ export interface PlannedOperation {
|
||||
operationId: string;
|
||||
scope: "object" | "class";
|
||||
execution: ExecutionContract;
|
||||
/** Installed implementation closure; the public execution contract above remains required. */
|
||||
/** Targets available for this complete installed implementation/dependency closure. */
|
||||
availableTargets: string[];
|
||||
input: ValueType;
|
||||
output: ValueType;
|
||||
@@ -171,7 +172,10 @@ function checkValue(type: ValueType, path: string, allowChange = false): void {
|
||||
}
|
||||
|
||||
/** Compile declarations into a closed dispatch/dependency graph before artifact selection. */
|
||||
export function compileExecutionPlan(input: WorkspaceRevision): ExecutionPlan {
|
||||
export function compileExecutionPlan(
|
||||
input: WorkspaceRevision,
|
||||
backends: readonly NativeExecutionBackend[] = standardNativeBackends,
|
||||
): ExecutionPlan {
|
||||
const workspace = structuredClone(input);
|
||||
const issues = validateWorkspaceRevision(workspace);
|
||||
if (issues.length)
|
||||
@@ -311,13 +315,6 @@ export function compileExecutionPlan(input: WorkspaceRevision): ExecutionPlan {
|
||||
path.join(" -> "),
|
||||
"Execution effect is not allowed by the root contract",
|
||||
);
|
||||
for (const target of requested.targets)
|
||||
if (!node.execution.targets.includes(target))
|
||||
throw new ExecutionPlanError(
|
||||
"MISSING_EXECUTION_TARGET",
|
||||
path.join(" -> "),
|
||||
`Dependency does not provide ${target}`,
|
||||
);
|
||||
for (const dependency of node.dependencies) {
|
||||
if (dependency.kind === "operation")
|
||||
walk(dependency.operation, [...path, dependency.port, dependency.operation]);
|
||||
@@ -352,9 +349,10 @@ export function compileExecutionPlan(input: WorkspaceRevision): ExecutionPlan {
|
||||
const provider =
|
||||
binding.kind === "package"
|
||||
? packages.get(binding.packageRevisionId)!.exports.find((entry) => entry.id === binding.exportId)!.execution
|
||||
: binding.kind === "lifecycle" || (binding.kind === "subscription" && binding.primitive !== "status")
|
||||
? { kind: "transaction" as const, targets: ["server" as const] }
|
||||
: { kind: node.execution.kind, targets: ["browser" as const, "server" as const] };
|
||||
: {
|
||||
kind: node.execution.kind,
|
||||
targets: backends.filter((backend) => backend.supports(binding)).map((backend) => backend.target),
|
||||
};
|
||||
if (provider && provider.kind !== "remote") node.availableTargets = [...provider.targets].sort();
|
||||
}
|
||||
let targetsChanged = true;
|
||||
@@ -382,6 +380,13 @@ export function compileExecutionPlan(input: WorkspaceRevision): ExecutionPlan {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const node of operationMap.values())
|
||||
if (node.execution.kind !== "remote" && !node.availableTargets.includes("server"))
|
||||
throw new ExecutionPlanError(
|
||||
"MISSING_SERVER_IMPLEMENTATION",
|
||||
node.key,
|
||||
"Every graph operation requires an authoritative implementation across its dependency closure",
|
||||
);
|
||||
const plannedQueries: PlannedQuery[] = queries.map((query) => ({
|
||||
id: queryKey(query.packageRevisionId, query.checked.declaration.id),
|
||||
query,
|
||||
@@ -515,11 +520,11 @@ export function compileExecutionPlan(input: WorkspaceRevision): ExecutionPlan {
|
||||
source.admittedOperations.push(...query.operations);
|
||||
for (const operation of query.operations) {
|
||||
const node = operationMap.get(operation)!;
|
||||
if (node.execution.kind !== "snapshot" || !node.execution.targets.includes("browser"))
|
||||
if (node.execution.kind !== "snapshot" || !node.availableTargets.some((target) => target !== "server"))
|
||||
throw new ExecutionPlanError(
|
||||
"NONPORTABLE_QUERY_FIELD",
|
||||
`${query.id}/${operation}`,
|
||||
"Local query getter must provide browser snapshot execution",
|
||||
"Local query getter needs an installed local snapshot implementation",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user