Implement progressive query admission, session boundaries and event-driven Studio observations
This commit is contained in:
@@ -20,6 +20,9 @@ export interface ReactModulePreparation {
|
||||
/** Public input type before workspace query lowering adds private projections. */
|
||||
input?: ValueType;
|
||||
children: ReactChildDeclaration[];
|
||||
/** Binds roots/arguments only. The ordinary checked Query Tree owns every
|
||||
* acquisition path; the React declaration does not repeat its descendants. */
|
||||
trees?: Pick<QueryCompositionStep, "name" | "query" | "root" | "arguments">[];
|
||||
}
|
||||
export interface ReactPreparationArtifact {
|
||||
/** Frontend queries belong to installed preparation, not the authored client API. */
|
||||
@@ -51,7 +54,7 @@ export function presentationDeclarations(
|
||||
};
|
||||
for (const [name, value] of Object.entries(modules)) {
|
||||
const declaration = object(value, `module ${name}`);
|
||||
if (Object.keys(declaration).some((key) => !["inputs", "children"].includes(key)))
|
||||
if (Object.keys(declaration).some((key) => !["inputs", "children", "trees"].includes(key)))
|
||||
throw Error(`${name}: unknown preparation field`);
|
||||
const module = pkg.modules?.find((entry) => entry.displayName === name);
|
||||
if (!module) throw Error(`React declaration: unknown module ${name}`);
|
||||
@@ -129,7 +132,29 @@ export function presentationDeclarations(
|
||||
...(role ? { role } : {}),
|
||||
};
|
||||
});
|
||||
artifact.modules.push({ module: module.id, composition, children: parsed });
|
||||
const trees = declaration.trees ?? [];
|
||||
if (!Array.isArray(trees) || trees.length > 16) throw Error(`${name}: trees must be a bounded array`);
|
||||
const treeNames = new Set<string>();
|
||||
const preparedTrees = trees.map((value) => {
|
||||
const tree = object(value, `${name} tree`) as unknown as NonNullable<ReactModulePreparation["trees"]>[number];
|
||||
if (
|
||||
Object.keys(tree).some((key) => !["name", "query", "root", "arguments"].includes(key)) ||
|
||||
!/^[A-Za-z_][A-Za-z0-9_]*$/.test(tree.name) ||
|
||||
treeNames.has(tree.name)
|
||||
)
|
||||
throw Error(`${name}: tree requires a unique name and checked root/arguments`);
|
||||
treeNames.add(tree.name);
|
||||
const query = pkg.queries?.find((entry) => entry.displayName === tree.query);
|
||||
if (!query || query.placement?.kind !== "replica")
|
||||
throw Error(`${name}.${tree.name}: requires a replica Query Tree`);
|
||||
return { ...tree, query: query.id };
|
||||
});
|
||||
artifact.modules.push({
|
||||
module: module.id,
|
||||
composition,
|
||||
children: parsed,
|
||||
...(preparedTrees.length ? { trees: preparedTrees } : {}),
|
||||
});
|
||||
}
|
||||
for (const module of pkg.modules ?? []) {
|
||||
const contract = interfaces.find((entry) => entry.revisionId === module.interfaceRevisionId);
|
||||
|
||||
Reference in New Issue
Block a user