diff --git a/src/execution-world/query-document.ts b/src/execution-world/query-document.ts index 08509d1..a897ab8 100644 --- a/src/execution-world/query-document.ts +++ b/src/execution-world/query-document.ts @@ -12,6 +12,7 @@ export interface QueryDocument { readonly document: string; readonly operation: string; readonly objectRoot: boolean; + readonly views?: readonly { readonly atom: string; readonly interface: string }[]; } /** Runtime query documents use the same language, nominal contracts, linking * and interpreter as packaged queries. They introduce no resources or code. */ @@ -27,6 +28,21 @@ export async function compilePublicQuery(plan: ExecutionPlan, request: QueryDocu ) throw Error("QUERY_DOCUMENT_LIMIT"); const id = "public-query:" + hexDigest(request); + const views = request.views ?? []; + if (!Array.isArray(views) || views.length > 16 || new Set(views.map((v) => v.atom)).size !== views.length) + throw Error("QUERY_VIEW_LIMIT"); + for (const view of views) { + if ( + !view || + Object.keys(view).sort().join(",") !== "atom,interface" || + typeof view.atom !== "string" || + typeof view.interface !== "string" || + view.atom.length > 2048 || + view.interface.length > 2048 || + !plan.definition.workspace.interfaceImports.some((i) => i.revisionId === view.interface) + ) + throw Error("QUERY_VIEW_INVALID"); + } const checked = await compileQuery( { id, @@ -38,7 +54,10 @@ export async function compilePublicQuery(plan: ExecutionPlan, request: QueryDocu document: "request.graphql", operation: request.operation, fragments: [], - views: [], + views: views.map((view) => ({ + atomId: capabilityId.atom(view.atom), + interfaceRevisionId: capabilityId.interfaceRevision(view.interface), + })), allowances: [], watch: false, budgets: {