@rocicorp/zero 1.11.0-canary.37 → 1.11.0-canary.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  var package_default = {
2
2
  name: "@rocicorp/zero",
3
- version: "1.11.0-canary.37",
3
+ version: "1.11.0-canary.38",
4
4
  description: "Zero is a web framework for serverless web development.",
5
5
  homepage: "https://zero.rocicorp.dev",
6
6
  bugs: { "url": "https://bugs.rocicorp.dev" },
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.11.0-canary.37\",\n \"description\": \"Zero is a web framework for serverless web development.\",\n \"homepage\": \"https://zero.rocicorp.dev\",\n \"bugs\": {\n \"url\": \"https://bugs.rocicorp.dev\"\n },\n \"license\": \"Apache-2.0\",\n \"author\": \"Rocicorp, Inc.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/rocicorp/mono.git\",\n \"directory\": \"packages/zero\"\n },\n \"bin\": {\n \"analyze-query\": \"./out/zero/src/analyze-query.js\",\n \"ast-to-zql\": \"./out/zero/src/ast-to-zql.js\",\n \"transform-query\": \"./out/zero/src/transform-query.js\",\n \"zero-build-schema\": \"./out/zero/src/build-schema.js\",\n \"zero-cache\": \"./out/zero/src/cli.js\",\n \"zero-cache-dev\": \"./out/zero/src/zero-cache-dev.js\",\n \"zero-deploy-permissions\": \"./out/zero/src/deploy-permissions.js\",\n \"zero-out\": \"./out/zero/src/zero-out.js\"\n },\n \"files\": [\n \"out\",\n \"!*.tsbuildinfo\"\n ],\n \"type\": \"module\",\n \"main\": \"out/zero/src/zero.js\",\n \"module\": \"out/zero/src/zero.js\",\n \"types\": \"out/zero/src/zero.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./out/zero/src/zero.d.ts\",\n \"default\": \"./out/zero/src/zero.js\"\n },\n \"./analyze\": {\n \"types\": \"./out/zero/src/analyze.d.ts\",\n \"default\": \"./out/zero/src/analyze.js\"\n },\n \"./bindings\": {\n \"types\": \"./out/zero/src/bindings.d.ts\",\n \"default\": \"./out/zero/src/bindings.js\"\n },\n \"./change-protocol/v0\": {\n \"types\": \"./out/zero/src/change-protocol/v0.d.ts\",\n \"default\": \"./out/zero/src/change-protocol/v0.js\"\n },\n \"./expo-sqlite\": {\n \"types\": \"./out/zero/src/expo-sqlite.d.ts\",\n \"default\": \"./out/zero/src/expo-sqlite.js\"\n },\n \"./op-sqlite\": {\n \"types\": \"./out/zero/src/op-sqlite.d.ts\",\n \"default\": \"./out/zero/src/op-sqlite.js\"\n },\n \"./pg\": {\n \"types\": \"./out/zero/src/pg.d.ts\",\n \"default\": \"./out/zero/src/pg.js\"\n },\n \"./react\": {\n \"types\": \"./out/zero/src/react.d.ts\",\n \"default\": \"./out/zero/src/react.js\"\n },\n \"./react-native\": {\n \"types\": \"./out/zero/src/react-native.d.ts\",\n \"default\": \"./out/zero/src/react-native.js\"\n },\n \"./server\": {\n \"types\": \"./out/zero/src/server.d.ts\",\n \"default\": \"./out/zero/src/server.js\"\n },\n \"./server/adapters/drizzle\": {\n \"types\": \"./out/zero/src/adapters/drizzle.d.ts\",\n \"default\": \"./out/zero/src/adapters/drizzle.js\"\n },\n \"./server/adapters/kysely\": {\n \"types\": \"./out/zero/src/adapters/kysely.d.ts\",\n \"default\": \"./out/zero/src/adapters/kysely.js\"\n },\n \"./server/adapters/prisma\": {\n \"types\": \"./out/zero/src/adapters/prisma.d.ts\",\n \"default\": \"./out/zero/src/adapters/prisma.js\"\n },\n \"./server/adapters/pg\": {\n \"types\": \"./out/zero/src/adapters/pg.d.ts\",\n \"default\": \"./out/zero/src/adapters/pg.js\"\n },\n \"./server/adapters/postgresjs\": {\n \"types\": \"./out/zero/src/adapters/postgresjs.d.ts\",\n \"default\": \"./out/zero/src/adapters/postgresjs.js\"\n },\n \"./solid\": {\n \"types\": \"./out/zero/src/solid.d.ts\",\n \"default\": \"./out/zero/src/solid.js\"\n },\n \"./sqlite\": {\n \"types\": \"./out/zero/src/sqlite.d.ts\",\n \"default\": \"./out/zero/src/sqlite.js\"\n },\n \"./zqlite\": {\n \"types\": \"./out/zero/src/zqlite.d.ts\",\n \"default\": \"./out/zero/src/zqlite.js\"\n }\n },\n \"scripts\": {\n \"build\": \"node --experimental-strip-types --no-warnings tool/build.ts\",\n \"build:watch\": \"node --experimental-strip-types --no-warnings tool/build.ts --watch\",\n \"check-types\": \"tsc -p tsconfig.client.json && tsc -p tsconfig.server.json\",\n \"check-types:client:watch\": \"tsc -p tsconfig.client.json --watch\",\n \"check-types:server:watch\": \"tsc -p tsconfig.server.json --watch\",\n \"format\": \"oxfmt .\",\n \"check-format\": \"oxfmt --check .\",\n \"lint\": \"oxlint --quiet --config ../../oxlint.config.ts src/\",\n \"docs\": \"node --experimental-strip-types --no-warnings tool/generate-docs.ts\",\n \"docs:server\": \"node --watch --experimental-strip-types --no-warnings tool/generate-docs.ts --server\",\n \"fmt\": \"oxfmt .\",\n \"check-fmt\": \"oxfmt --check .\"\n },\n \"dependencies\": {\n \"@badrap/valita\": \"0.5.5\",\n \"@databases/escape-identifier\": \"^1.0.3\",\n \"@databases/sql\": \"^3.3.0\",\n \"@dotenvx/dotenvx\": \"^1.39.0\",\n \"@drdgvhbh/postgres-error-codes\": \"^0.0.6\",\n \"@fastify/cors\": \"^10.0.0\",\n \"@fastify/websocket\": \"^11.0.0\",\n \"@google-cloud/precise-date\": \"^4.0.0\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/api-logs\": \"^0.218.0\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.76.0\",\n \"@opentelemetry/exporter-metrics-otlp-http\": \"^0.218.0\",\n \"@opentelemetry/resources\": \"^2.7.1\",\n \"@opentelemetry/sdk-metrics\": \"^2.7.1\",\n \"@opentelemetry/sdk-node\": \"^0.218.0\",\n \"@opentelemetry/sdk-trace-node\": \"^2.7.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.41.1\",\n \"@postgresql-typed/oids\": \"^0.2.0\",\n \"@rocicorp/lock\": \"^1.0.4\",\n \"@rocicorp/logger\": \"^6.1.0\",\n \"@rocicorp/resolver\": \"^1.0.2\",\n \"@rocicorp/zero-sqlite3\": \"^1.1.5\",\n \"@standard-schema/spec\": \"^1.0.0\",\n \"@types/basic-auth\": \"^1.1.8\",\n \"@types/ws\": \"^8.5.12\",\n \"basic-auth\": \"^2.0.1\",\n \"chalk-template\": \"^1.1.0\",\n \"chokidar\": \"^4.0.1\",\n \"cloudevents\": \"^10.0.0\",\n \"command-line-args\": \"^6.0.1\",\n \"command-line-usage\": \"^7.0.3\",\n \"compare-utf8\": \"^0.2.3\",\n \"defu\": \"^6.1.4\",\n \"eventemitter3\": \"^5.0.1\",\n \"fastify\": \"^5.0.0\",\n \"is-in-subnet\": \"^4.0.1\",\n \"jose\": \"^5.9.3\",\n \"json-custom-numbers\": \"^3.1.1\",\n \"kasi\": \"^1.1.0\",\n \"nanoid\": \"^5.1.2\",\n \"oxfmt\": \"^0.65.0\",\n \"parse-prometheus-text-format\": \"^1.1.1\",\n \"pg-format\": \"npm:pg-format-fix@^1.0.5\",\n \"postgres\": \"3.4.7\",\n \"semver\": \"^7.5.4\",\n \"url-pattern\": \"^1.0.3\",\n \"urlpattern-polyfill\": \"^10.1.0\",\n \"ws\": \"^8.18.1\"\n },\n \"devDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"analyze-query\": \"workspace:*\",\n \"ast-to-zql\": \"workspace:*\",\n \"expo-sqlite\": \">=15\",\n \"oxc-parser\": \"^0.129.0\",\n \"replicache\": \"workspace:*\",\n \"shared\": \"workspace:*\",\n \"syncpack\": \"^14.3.0\",\n \"typedoc\": \"^0.28.17\",\n \"typescript\": \"~7.0.2\",\n \"vite\": \"^8.0.13\",\n \"vitest\": \"^5.0.0\",\n \"zero-cache\": \"workspace:*\",\n \"zero-client\": \"workspace:*\",\n \"zero-pg\": \"workspace:*\",\n \"zero-react\": \"workspace:*\",\n \"zero-server\": \"workspace:*\",\n \"zero-solid\": \"workspace:*\",\n \"zqlite\": \"workspace:*\"\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"packageManager\": \"pnpm@11.11.0\"\n}\n"],"mappings":""}
1
+ {"version":3,"file":"package.js","names":[],"sources":["../../package.json"],"sourcesContent":["{\n \"name\": \"@rocicorp/zero\",\n \"version\": \"1.11.0-canary.38\",\n \"description\": \"Zero is a web framework for serverless web development.\",\n \"homepage\": \"https://zero.rocicorp.dev\",\n \"bugs\": {\n \"url\": \"https://bugs.rocicorp.dev\"\n },\n \"license\": \"Apache-2.0\",\n \"author\": \"Rocicorp, Inc.\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/rocicorp/mono.git\",\n \"directory\": \"packages/zero\"\n },\n \"bin\": {\n \"analyze-query\": \"./out/zero/src/analyze-query.js\",\n \"ast-to-zql\": \"./out/zero/src/ast-to-zql.js\",\n \"transform-query\": \"./out/zero/src/transform-query.js\",\n \"zero-build-schema\": \"./out/zero/src/build-schema.js\",\n \"zero-cache\": \"./out/zero/src/cli.js\",\n \"zero-cache-dev\": \"./out/zero/src/zero-cache-dev.js\",\n \"zero-deploy-permissions\": \"./out/zero/src/deploy-permissions.js\",\n \"zero-out\": \"./out/zero/src/zero-out.js\"\n },\n \"files\": [\n \"out\",\n \"!*.tsbuildinfo\"\n ],\n \"type\": \"module\",\n \"main\": \"out/zero/src/zero.js\",\n \"module\": \"out/zero/src/zero.js\",\n \"types\": \"out/zero/src/zero.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./out/zero/src/zero.d.ts\",\n \"default\": \"./out/zero/src/zero.js\"\n },\n \"./analyze\": {\n \"types\": \"./out/zero/src/analyze.d.ts\",\n \"default\": \"./out/zero/src/analyze.js\"\n },\n \"./bindings\": {\n \"types\": \"./out/zero/src/bindings.d.ts\",\n \"default\": \"./out/zero/src/bindings.js\"\n },\n \"./change-protocol/v0\": {\n \"types\": \"./out/zero/src/change-protocol/v0.d.ts\",\n \"default\": \"./out/zero/src/change-protocol/v0.js\"\n },\n \"./expo-sqlite\": {\n \"types\": \"./out/zero/src/expo-sqlite.d.ts\",\n \"default\": \"./out/zero/src/expo-sqlite.js\"\n },\n \"./op-sqlite\": {\n \"types\": \"./out/zero/src/op-sqlite.d.ts\",\n \"default\": \"./out/zero/src/op-sqlite.js\"\n },\n \"./pg\": {\n \"types\": \"./out/zero/src/pg.d.ts\",\n \"default\": \"./out/zero/src/pg.js\"\n },\n \"./react\": {\n \"types\": \"./out/zero/src/react.d.ts\",\n \"default\": \"./out/zero/src/react.js\"\n },\n \"./react-native\": {\n \"types\": \"./out/zero/src/react-native.d.ts\",\n \"default\": \"./out/zero/src/react-native.js\"\n },\n \"./server\": {\n \"types\": \"./out/zero/src/server.d.ts\",\n \"default\": \"./out/zero/src/server.js\"\n },\n \"./server/adapters/drizzle\": {\n \"types\": \"./out/zero/src/adapters/drizzle.d.ts\",\n \"default\": \"./out/zero/src/adapters/drizzle.js\"\n },\n \"./server/adapters/kysely\": {\n \"types\": \"./out/zero/src/adapters/kysely.d.ts\",\n \"default\": \"./out/zero/src/adapters/kysely.js\"\n },\n \"./server/adapters/prisma\": {\n \"types\": \"./out/zero/src/adapters/prisma.d.ts\",\n \"default\": \"./out/zero/src/adapters/prisma.js\"\n },\n \"./server/adapters/pg\": {\n \"types\": \"./out/zero/src/adapters/pg.d.ts\",\n \"default\": \"./out/zero/src/adapters/pg.js\"\n },\n \"./server/adapters/postgresjs\": {\n \"types\": \"./out/zero/src/adapters/postgresjs.d.ts\",\n \"default\": \"./out/zero/src/adapters/postgresjs.js\"\n },\n \"./solid\": {\n \"types\": \"./out/zero/src/solid.d.ts\",\n \"default\": \"./out/zero/src/solid.js\"\n },\n \"./sqlite\": {\n \"types\": \"./out/zero/src/sqlite.d.ts\",\n \"default\": \"./out/zero/src/sqlite.js\"\n },\n \"./zqlite\": {\n \"types\": \"./out/zero/src/zqlite.d.ts\",\n \"default\": \"./out/zero/src/zqlite.js\"\n }\n },\n \"scripts\": {\n \"build\": \"node --experimental-strip-types --no-warnings tool/build.ts\",\n \"build:watch\": \"node --experimental-strip-types --no-warnings tool/build.ts --watch\",\n \"check-types\": \"tsc -p tsconfig.client.json && tsc -p tsconfig.server.json\",\n \"check-types:client:watch\": \"tsc -p tsconfig.client.json --watch\",\n \"check-types:server:watch\": \"tsc -p tsconfig.server.json --watch\",\n \"format\": \"oxfmt .\",\n \"check-format\": \"oxfmt --check .\",\n \"lint\": \"oxlint --quiet --config ../../oxlint.config.ts src/\",\n \"docs\": \"node --experimental-strip-types --no-warnings tool/generate-docs.ts\",\n \"docs:server\": \"node --watch --experimental-strip-types --no-warnings tool/generate-docs.ts --server\",\n \"fmt\": \"oxfmt .\",\n \"check-fmt\": \"oxfmt --check .\"\n },\n \"dependencies\": {\n \"@badrap/valita\": \"0.5.5\",\n \"@databases/escape-identifier\": \"^1.0.3\",\n \"@databases/sql\": \"^3.3.0\",\n \"@dotenvx/dotenvx\": \"^1.39.0\",\n \"@drdgvhbh/postgres-error-codes\": \"^0.0.6\",\n \"@fastify/cors\": \"^10.0.0\",\n \"@fastify/websocket\": \"^11.0.0\",\n \"@google-cloud/precise-date\": \"^4.0.0\",\n \"@opentelemetry/api\": \"^1.9.0\",\n \"@opentelemetry/api-logs\": \"^0.218.0\",\n \"@opentelemetry/auto-instrumentations-node\": \"^0.76.0\",\n \"@opentelemetry/exporter-metrics-otlp-http\": \"^0.218.0\",\n \"@opentelemetry/resources\": \"^2.7.1\",\n \"@opentelemetry/sdk-metrics\": \"^2.7.1\",\n \"@opentelemetry/sdk-node\": \"^0.218.0\",\n \"@opentelemetry/sdk-trace-node\": \"^2.7.1\",\n \"@opentelemetry/semantic-conventions\": \"^1.41.1\",\n \"@postgresql-typed/oids\": \"^0.2.0\",\n \"@rocicorp/lock\": \"^1.0.4\",\n \"@rocicorp/logger\": \"^6.1.0\",\n \"@rocicorp/resolver\": \"^1.0.2\",\n \"@rocicorp/zero-sqlite3\": \"^1.1.5\",\n \"@standard-schema/spec\": \"^1.0.0\",\n \"@types/basic-auth\": \"^1.1.8\",\n \"@types/ws\": \"^8.5.12\",\n \"basic-auth\": \"^2.0.1\",\n \"chalk-template\": \"^1.1.0\",\n \"chokidar\": \"^4.0.1\",\n \"cloudevents\": \"^10.0.0\",\n \"command-line-args\": \"^6.0.1\",\n \"command-line-usage\": \"^7.0.3\",\n \"compare-utf8\": \"^0.2.3\",\n \"defu\": \"^6.1.4\",\n \"eventemitter3\": \"^5.0.1\",\n \"fastify\": \"^5.0.0\",\n \"is-in-subnet\": \"^4.0.1\",\n \"jose\": \"^5.9.3\",\n \"json-custom-numbers\": \"^3.1.1\",\n \"kasi\": \"^1.1.0\",\n \"nanoid\": \"^5.1.2\",\n \"oxfmt\": \"^0.65.0\",\n \"parse-prometheus-text-format\": \"^1.1.1\",\n \"pg-format\": \"npm:pg-format-fix@^1.0.5\",\n \"postgres\": \"3.4.7\",\n \"semver\": \"^7.5.4\",\n \"url-pattern\": \"^1.0.3\",\n \"urlpattern-polyfill\": \"^10.1.0\",\n \"ws\": \"^8.18.1\"\n },\n \"devDependencies\": {\n \"@op-engineering/op-sqlite\": \">=15\",\n \"analyze-query\": \"workspace:*\",\n \"ast-to-zql\": \"workspace:*\",\n \"expo-sqlite\": \">=15\",\n \"oxc-parser\": \"^0.129.0\",\n \"replicache\": \"workspace:*\",\n \"shared\": \"workspace:*\",\n \"syncpack\": \"^14.3.0\",\n \"typedoc\": \"^0.28.17\",\n \"typescript\": \"~7.0.2\",\n \"vite\": \"^8.0.13\",\n \"vitest\": \"^5.0.0\",\n \"zero-cache\": \"workspace:*\",\n \"zero-client\": \"workspace:*\",\n \"zero-pg\": \"workspace:*\",\n \"zero-react\": \"workspace:*\",\n \"zero-server\": \"workspace:*\",\n \"zero-solid\": \"workspace:*\",\n \"zqlite\": \"workspace:*\"\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"packageManager\": \"pnpm@11.11.0\"\n}\n"],"mappings":""}
@@ -1,4 +1,5 @@
1
1
  import type { LogContext } from '@rocicorp/logger';
2
+ import type { AnalyzeQueryResult } from '../../../../zero-protocol/src/analyze-query-result.ts';
2
3
  import type { QueryServerMetrics } from '../../../../zero-protocol/src/inspect-down.ts';
3
4
  import { type UnparsedInspectUpBody } from '../../../../zero-protocol/src/inspect-up.ts';
4
5
  import type { NormalizedZeroConfig } from '../../config/normalize.ts';
@@ -8,6 +9,15 @@ import type { ConnectionContext } from './connection-context-manager.ts';
8
9
  import type { CVRStore } from './cvr-store.ts';
9
10
  import type { CVRSnapshot } from './cvr.ts';
10
11
  export declare function handleInspect(lc: LogContext, body: UnparsedInspectUpBody, cvr: CVRSnapshot, client: ClientHandler, inspectorDelegate: InspectorDelegate, clientGroupID: string, authOwner: object, cvrStore: CVRStore, config: NormalizedZeroConfig, ctx: ConnectionContext): Promise<void>;
12
+ /**
13
+ * Removes the planner's `filter` nodes from `joinPlans` for clients before
14
+ * protocol 53, which added that node type. 1.9 and 1.10 clients fail to parse
15
+ * a node type they don't know, and the failed parse puts the client in its
16
+ * error state.
17
+ *
18
+ * @visibleForTesting
19
+ */
20
+ export declare function analyzeResultForProtocol(result: AnalyzeQueryResult, protocolVersion: number): AnalyzeQueryResult;
11
21
  /**
12
22
  * Converts per-query server metrics to the appropriate wire format based on the
13
23
  * client's protocol version.
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-handler.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/inspect-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAKjD,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AAGrD,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,2BAA2B,CAAC;AAMpE,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,oCAAoC,CAAC;AAE1E,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,UAAU,CAAC;AAE1C,wBAAsB,aAAa,CACjC,EAAE,EAAE,UAAU,EACd,IAAI,EAAE,qBAAqB,EAC3B,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,aAAa,EACrB,iBAAiB,EAAE,iBAAiB,EACpC,aAAa,EAAE,MAAM,EAGrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,oBAAoB,EAC5B,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,IAAI,CAAC,CAiJf;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,GAAG,IAAI,EAClC,eAAe,EAAE,MAAM,GACtB,kBAAkB,GAAG,IAAI,CAmB3B"}
1
+ {"version":3,"file":"inspect-handler.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/inspect-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAKjD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,uDAAuD,CAAC;AAC9F,OAAO,KAAK,EACV,kBAAkB,EAEnB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AAGrD,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,2BAA2B,CAAC;AAMpE,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,oCAAoC,CAAC;AAE1E,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,UAAU,CAAC;AAE1C,wBAAsB,aAAa,CACjC,EAAE,EAAE,UAAU,EACd,IAAI,EAAE,qBAAqB,EAC3B,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,aAAa,EACrB,iBAAiB,EAAE,iBAAiB,EACpC,aAAa,EAAE,MAAM,EAGrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,oBAAoB,EAC5B,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,IAAI,CAAC,CAiJf;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,kBAAkB,EAC1B,eAAe,EAAE,MAAM,GACtB,kBAAkB,CAUpB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,kBAAkB,GAAG,IAAI,EAClC,eAAe,EAAE,MAAM,GACtB,kBAAkB,GAAG,IAAI,CAmB3B"}
@@ -85,7 +85,7 @@ async function handleInspect(lc, body, cvr, client, inspectorDelegate, clientGro
85
85
  client.sendInspectResponse(lc, {
86
86
  op: "analyze-query",
87
87
  id: body.id,
88
- value: result
88
+ value: analyzeResultForProtocol(result, ctx.protocolVersion)
89
89
  });
90
90
  break;
91
91
  }
@@ -101,6 +101,21 @@ async function handleInspect(lc, body, cvr, client, inspectorDelegate, clientGro
101
101
  }
102
102
  }
103
103
  /**
104
+ * Removes the planner's `filter` nodes from `joinPlans` for clients before
105
+ * protocol 53, which added that node type. 1.9 and 1.10 clients fail to parse
106
+ * a node type they don't know, and the failed parse puts the client in its
107
+ * error state.
108
+ *
109
+ * @visibleForTesting
110
+ */
111
+ function analyzeResultForProtocol(result, protocolVersion) {
112
+ if (protocolVersion >= 53 || result.joinPlans === void 0) return result;
113
+ return {
114
+ ...result,
115
+ joinPlans: result.joinPlans.filter((event) => !("nodeType" in event && event.nodeType === "filter"))
116
+ };
117
+ }
118
+ /**
104
119
  * Converts per-query server metrics to the appropriate wire format based on the
105
120
  * client's protocol version.
106
121
  *
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-handler.js","names":[],"sources":["../../../../../../zero-cache/src/services/view-syncer/inspect-handler.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {unreachable} from '../../../../shared/src/asserts.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport {TDigest} from '../../../../shared/src/tdigest.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport type {\n QueryServerMetrics,\n ServerMetrics,\n} from '../../../../zero-protocol/src/inspect-down.ts';\nimport {\n inspectAnalyzeQueryUpSchema,\n type UnparsedInspectUpBody,\n} from '../../../../zero-protocol/src/inspect-up.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {loadPermissions} from '../../auth/load-permissions.ts';\nimport type {NormalizedZeroConfig} from '../../config/normalize.ts';\nimport {\n getServerVersion,\n isAdminPasswordValid,\n} from '../../config/zero-config.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport type {InspectorDelegate} from '../../server/inspector-delegate.ts';\nimport {analyzeQuery} from '../analyze.ts';\nimport type {ClientHandler} from './client-handler.ts';\nimport type {ConnectionContext} from './connection-context-manager.ts';\nimport type {CVRStore} from './cvr-store.ts';\nimport type {CVRSnapshot} from './cvr.ts';\n\nexport async function handleInspect(\n lc: LogContext,\n body: UnparsedInspectUpBody,\n cvr: CVRSnapshot,\n client: ClientHandler,\n inspectorDelegate: InspectorDelegate,\n clientGroupID: string,\n // The service handling the request, on whose behalf authentication is\n // recorded (see InspectorDelegate.clearAuthenticated).\n authOwner: object,\n cvrStore: CVRStore,\n config: NormalizedZeroConfig,\n ctx: ConnectionContext,\n): Promise<void> {\n // Check if the client is already authenticated. We only authenticate the clientGroup\n // once per \"worker\".\n if (\n body.op !== 'authenticate' &&\n !inspectorDelegate.isAuthenticated(clientGroupID)\n ) {\n lc.info?.(\n 'Client not authenticated to access the inspector protocol. Sending authentication challenge',\n );\n client.sendInspectResponse(lc, {\n op: 'authenticated',\n id: body.id,\n value: false,\n });\n return;\n }\n\n try {\n switch (body.op) {\n case 'queries': {\n const queryRows = await cvrStore.inspectQueries(\n lc,\n cvr.ttlClock,\n body.clientID,\n );\n\n // Enhance query rows with server-side materialization metrics\n const enhancedRows = queryRows.map(row => ({\n ...row,\n ast: row.ast ?? inspectorDelegate.getASTForQuery(row.queryID) ?? null,\n metrics: metricsForProtocol(\n inspectorDelegate.getMetricsJSONForQuery(row.queryID),\n ctx.protocolVersion,\n ),\n }));\n\n client.sendInspectResponse(lc, {\n op: 'queries',\n id: body.id,\n value: enhancedRows,\n });\n break;\n }\n\n case 'metrics': {\n client.sendInspectResponse(lc, {\n op: 'metrics',\n id: body.id,\n value: inspectorDelegate.getMetricsJSON(),\n });\n break;\n }\n\n case 'version':\n client.sendInspectResponse(lc, {\n op: 'version',\n id: body.id,\n value: getServerVersion(config),\n });\n break;\n\n case 'authenticate': {\n const password = body.value;\n const ok = isAdminPasswordValid(lc, config, password);\n if (ok) {\n inspectorDelegate.setAuthenticated(clientGroupID, authOwner);\n } else {\n inspectorDelegate.clearAuthenticated(clientGroupID);\n }\n\n client.sendInspectResponse(lc, {\n op: 'authenticated',\n id: body.id,\n value: ok,\n });\n\n break;\n }\n\n case 'analyze-query': {\n const parsedBody = v.parse(body, inspectAnalyzeQueryUpSchema);\n let ast = parsedBody.ast ?? parsedBody.value;\n let legacyQuery = true;\n\n if (parsedBody.name && parsedBody.args) {\n // Get the AST from the API server by transforming the named query\n ast = await inspectorDelegate.transformCustomQuery(\n parsedBody.name,\n parsedBody.args,\n ctx,\n );\n legacyQuery = false;\n }\n\n if (ast === undefined) {\n throw new Error(\n 'AST is required for analyze-query operation. Either provide an AST directly or ensure custom query transformation is configured.',\n );\n }\n\n let permissions;\n if (legacyQuery) {\n using db = new Database(lc, config.replica.file);\n const dbRunner = new StatementRunner(db);\n const loaded = loadPermissions(lc, dbRunner, config.app.id, config);\n if (loaded.permissions) {\n permissions = loaded.permissions;\n } else {\n lc.info?.(\n 'No permissions loaded; analyze-query will run without applying permissions.',\n );\n }\n }\n\n const result = await analyzeQuery(\n lc,\n config,\n must(cvr.clientSchema),\n ast,\n parsedBody.options?.syncedRows,\n parsedBody.options?.vendedRows,\n permissions,\n ctx.auth?.type === 'jwt' ? ctx.auth : undefined,\n parsedBody.options?.joinPlans,\n );\n client.sendInspectResponse(lc, {\n op: 'analyze-query',\n id: body.id,\n value: result,\n });\n break;\n }\n\n default:\n unreachable(body);\n }\n } catch (e) {\n lc.warn?.('Error handling inspect message', e);\n client.sendInspectResponse(lc, {\n op: 'error',\n id: body.id,\n value: (e as Error).message,\n });\n }\n}\n\n/**\n * Converts per-query server metrics to the appropriate wire format based on the\n * client's protocol version.\n *\n * Protocol >= 51: new format — `query-hydration-server-ms` (plain number) +\n * `query-update-server` (TDigest).\n * Protocol < 51: old format — `query-materialization-server` (TDigest) +\n * `query-update-server` (TDigest). The scalar hydration time is wrapped into a\n * one-point TDigest for backward compatibility.\n *\n * @visibleForTesting\n */\nexport function metricsForProtocol(\n metrics: QueryServerMetrics | null,\n protocolVersion: number,\n): QueryServerMetrics | null {\n if (protocolVersion >= 51 || metrics === null) {\n return metrics;\n }\n // Backward compat: wrap the scalar hydration ms into a one-point TDigest\n // under the old field name so that 1.5 clients can parse the response.\n const hydrateDigest = new TDigest();\n const hydrateMs = metrics['query-hydration-server-ms'];\n if (hydrateMs !== undefined) {\n hydrateDigest.add(hydrateMs);\n }\n const legacyMetrics: ServerMetrics = {\n 'query-materialization-server': hydrateDigest.toJSON(),\n 'query-update-server': metrics['query-update-server'],\n };\n // Cast to QueryServerMetrics: this is intentional — for old-protocol clients\n // we send the legacy ServerMetrics wire shape under the QueryServerMetrics type\n // to satisfy TypeScript while preserving backward compatibility.\n return legacyMetrics as unknown as QueryServerMetrics;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"inspect-handler.js","names":[],"sources":["../../../../../../zero-cache/src/services/view-syncer/inspect-handler.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {unreachable} from '../../../../shared/src/asserts.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport {TDigest} from '../../../../shared/src/tdigest.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport type {AnalyzeQueryResult} from '../../../../zero-protocol/src/analyze-query-result.ts';\nimport type {\n QueryServerMetrics,\n ServerMetrics,\n} from '../../../../zero-protocol/src/inspect-down.ts';\nimport {\n inspectAnalyzeQueryUpSchema,\n type UnparsedInspectUpBody,\n} from '../../../../zero-protocol/src/inspect-up.ts';\nimport {Database} from '../../../../zqlite/src/db.ts';\nimport {loadPermissions} from '../../auth/load-permissions.ts';\nimport type {NormalizedZeroConfig} from '../../config/normalize.ts';\nimport {\n getServerVersion,\n isAdminPasswordValid,\n} from '../../config/zero-config.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport type {InspectorDelegate} from '../../server/inspector-delegate.ts';\nimport {analyzeQuery} from '../analyze.ts';\nimport type {ClientHandler} from './client-handler.ts';\nimport type {ConnectionContext} from './connection-context-manager.ts';\nimport type {CVRStore} from './cvr-store.ts';\nimport type {CVRSnapshot} from './cvr.ts';\n\nexport async function handleInspect(\n lc: LogContext,\n body: UnparsedInspectUpBody,\n cvr: CVRSnapshot,\n client: ClientHandler,\n inspectorDelegate: InspectorDelegate,\n clientGroupID: string,\n // The service handling the request, on whose behalf authentication is\n // recorded (see InspectorDelegate.clearAuthenticated).\n authOwner: object,\n cvrStore: CVRStore,\n config: NormalizedZeroConfig,\n ctx: ConnectionContext,\n): Promise<void> {\n // Check if the client is already authenticated. We only authenticate the clientGroup\n // once per \"worker\".\n if (\n body.op !== 'authenticate' &&\n !inspectorDelegate.isAuthenticated(clientGroupID)\n ) {\n lc.info?.(\n 'Client not authenticated to access the inspector protocol. Sending authentication challenge',\n );\n client.sendInspectResponse(lc, {\n op: 'authenticated',\n id: body.id,\n value: false,\n });\n return;\n }\n\n try {\n switch (body.op) {\n case 'queries': {\n const queryRows = await cvrStore.inspectQueries(\n lc,\n cvr.ttlClock,\n body.clientID,\n );\n\n // Enhance query rows with server-side materialization metrics\n const enhancedRows = queryRows.map(row => ({\n ...row,\n ast: row.ast ?? inspectorDelegate.getASTForQuery(row.queryID) ?? null,\n metrics: metricsForProtocol(\n inspectorDelegate.getMetricsJSONForQuery(row.queryID),\n ctx.protocolVersion,\n ),\n }));\n\n client.sendInspectResponse(lc, {\n op: 'queries',\n id: body.id,\n value: enhancedRows,\n });\n break;\n }\n\n case 'metrics': {\n client.sendInspectResponse(lc, {\n op: 'metrics',\n id: body.id,\n value: inspectorDelegate.getMetricsJSON(),\n });\n break;\n }\n\n case 'version':\n client.sendInspectResponse(lc, {\n op: 'version',\n id: body.id,\n value: getServerVersion(config),\n });\n break;\n\n case 'authenticate': {\n const password = body.value;\n const ok = isAdminPasswordValid(lc, config, password);\n if (ok) {\n inspectorDelegate.setAuthenticated(clientGroupID, authOwner);\n } else {\n inspectorDelegate.clearAuthenticated(clientGroupID);\n }\n\n client.sendInspectResponse(lc, {\n op: 'authenticated',\n id: body.id,\n value: ok,\n });\n\n break;\n }\n\n case 'analyze-query': {\n const parsedBody = v.parse(body, inspectAnalyzeQueryUpSchema);\n let ast = parsedBody.ast ?? parsedBody.value;\n let legacyQuery = true;\n\n if (parsedBody.name && parsedBody.args) {\n // Get the AST from the API server by transforming the named query\n ast = await inspectorDelegate.transformCustomQuery(\n parsedBody.name,\n parsedBody.args,\n ctx,\n );\n legacyQuery = false;\n }\n\n if (ast === undefined) {\n throw new Error(\n 'AST is required for analyze-query operation. Either provide an AST directly or ensure custom query transformation is configured.',\n );\n }\n\n let permissions;\n if (legacyQuery) {\n using db = new Database(lc, config.replica.file);\n const dbRunner = new StatementRunner(db);\n const loaded = loadPermissions(lc, dbRunner, config.app.id, config);\n if (loaded.permissions) {\n permissions = loaded.permissions;\n } else {\n lc.info?.(\n 'No permissions loaded; analyze-query will run without applying permissions.',\n );\n }\n }\n\n const result = await analyzeQuery(\n lc,\n config,\n must(cvr.clientSchema),\n ast,\n parsedBody.options?.syncedRows,\n parsedBody.options?.vendedRows,\n permissions,\n ctx.auth?.type === 'jwt' ? ctx.auth : undefined,\n parsedBody.options?.joinPlans,\n );\n client.sendInspectResponse(lc, {\n op: 'analyze-query',\n id: body.id,\n value: analyzeResultForProtocol(result, ctx.protocolVersion),\n });\n break;\n }\n\n default:\n unreachable(body);\n }\n } catch (e) {\n lc.warn?.('Error handling inspect message', e);\n client.sendInspectResponse(lc, {\n op: 'error',\n id: body.id,\n value: (e as Error).message,\n });\n }\n}\n\n/**\n * Removes the planner's `filter` nodes from `joinPlans` for clients before\n * protocol 53, which added that node type. 1.9 and 1.10 clients fail to parse\n * a node type they don't know, and the failed parse puts the client in its\n * error state.\n *\n * @visibleForTesting\n */\nexport function analyzeResultForProtocol(\n result: AnalyzeQueryResult,\n protocolVersion: number,\n): AnalyzeQueryResult {\n if (protocolVersion >= 53 || result.joinPlans === undefined) {\n return result;\n }\n return {\n ...result,\n joinPlans: result.joinPlans.filter(\n event => !('nodeType' in event && event.nodeType === 'filter'),\n ),\n };\n}\n\n/**\n * Converts per-query server metrics to the appropriate wire format based on the\n * client's protocol version.\n *\n * Protocol >= 51: new format — `query-hydration-server-ms` (plain number) +\n * `query-update-server` (TDigest).\n * Protocol < 51: old format — `query-materialization-server` (TDigest) +\n * `query-update-server` (TDigest). The scalar hydration time is wrapped into a\n * one-point TDigest for backward compatibility.\n *\n * @visibleForTesting\n */\nexport function metricsForProtocol(\n metrics: QueryServerMetrics | null,\n protocolVersion: number,\n): QueryServerMetrics | null {\n if (protocolVersion >= 51 || metrics === null) {\n return metrics;\n }\n // Backward compat: wrap the scalar hydration ms into a one-point TDigest\n // under the old field name so that 1.5 clients can parse the response.\n const hydrateDigest = new TDigest();\n const hydrateMs = metrics['query-hydration-server-ms'];\n if (hydrateMs !== undefined) {\n hydrateDigest.add(hydrateMs);\n }\n const legacyMetrics: ServerMetrics = {\n 'query-materialization-server': hydrateDigest.toJSON(),\n 'query-update-server': metrics['query-update-server'],\n };\n // Cast to QueryServerMetrics: this is intentional — for old-protocol clients\n // we send the legacy ServerMetrics wire shape under the QueryServerMetrics type\n // to satisfy TypeScript while preserving backward compatibility.\n return legacyMetrics as unknown as QueryServerMetrics;\n}\n"],"mappings":";;;;;;;;;;;;AA6BA,eAAsB,cACpB,IACA,MACA,KACA,QACA,mBACA,eAGA,WACA,UACA,QACA,KACe;CAGf,IACE,KAAK,OAAO,kBACZ,CAAC,kBAAkB,gBAAgB,aAAa,GAChD;EACA,GAAG,OACD,6FACF;EACA,OAAO,oBAAoB,IAAI;GAC7B,IAAI;GACJ,IAAI,KAAK;GACT,OAAO;EACT,CAAC;EACD;CACF;CAEA,IAAI;EACF,QAAQ,KAAK,IAAb;GACE,KAAK,WAAW;IAQd,MAAM,gBAAe,MAPG,SAAS,eAC/B,IACA,IAAI,UACJ,KAAK,QACP,GAG+B,KAAI,SAAQ;KACzC,GAAG;KACH,KAAK,IAAI,OAAO,kBAAkB,eAAe,IAAI,OAAO,KAAK;KACjE,SAAS,mBACP,kBAAkB,uBAAuB,IAAI,OAAO,GACpD,IAAI,eACN;IACF,EAAE;IAEF,OAAO,oBAAoB,IAAI;KAC7B,IAAI;KACJ,IAAI,KAAK;KACT,OAAO;IACT,CAAC;IACD;GACF;GAEA,KAAK;IACH,OAAO,oBAAoB,IAAI;KAC7B,IAAI;KACJ,IAAI,KAAK;KACT,OAAO,kBAAkB,eAAe;IAC1C,CAAC;IACD;GAGF,KAAK;IACH,OAAO,oBAAoB,IAAI;KAC7B,IAAI;KACJ,IAAI,KAAK;KACT,OAAO,iBAAiB,MAAM;IAChC,CAAC;IACD;GAEF,KAAK,gBAAgB;IACnB,MAAM,WAAW,KAAK;IACtB,MAAM,KAAK,qBAAqB,IAAI,QAAQ,QAAQ;IACpD,IAAI,IACF,kBAAkB,iBAAiB,eAAe,SAAS;SAE3D,kBAAkB,mBAAmB,aAAa;IAGpD,OAAO,oBAAoB,IAAI;KAC7B,IAAI;KACJ,IAAI,KAAK;KACT,OAAO;IACT,CAAC;IAED;GACF;GAEA,KAAK,iBAAiB;IACpB,MAAM,aAAa,MAAQ,MAAM,2BAA2B;IAC5D,IAAI,MAAM,WAAW,OAAO,WAAW;IACvC,IAAI,cAAc;IAElB,IAAI,WAAW,QAAQ,WAAW,MAAM;KAEtC,MAAM,MAAM,kBAAkB,qBAC5B,WAAW,MACX,WAAW,MACX,GACF;KACA,cAAc;IAChB;IAEA,IAAI,QAAQ,KAAA,GACV,MAAM,IAAI,MACR,kIACF;IAGF,IAAI;IACJ,IAAI,aAAa,IAAA;;KAGf,MAAM,SAAS,gBAAgB,IAAI,IADd,gBAAA,YAAA,EADV,IAAI,SAAS,IAAI,OAAO,QAAQ,IAAI,CACV,CACF,GAAU,OAAO,IAAI,IAAI,MAAM;KAClE,IAAI,OAAO,aACT,cAAc,OAAO;UAErB,GAAG,OACD,6EACF;;;;;;IAIJ,MAAM,SAAS,MAAM,aACnB,IACA,QACA,KAAK,IAAI,YAAY,GACrB,KACA,WAAW,SAAS,YACpB,WAAW,SAAS,YACpB,aACA,IAAI,MAAM,SAAS,QAAQ,IAAI,OAAO,KAAA,GACtC,WAAW,SAAS,SACtB;IACA,OAAO,oBAAoB,IAAI;KAC7B,IAAI;KACJ,IAAI,KAAK;KACT,OAAO,yBAAyB,QAAQ,IAAI,eAAe;IAC7D,CAAC;IACD;GACF;GAEA,SACE,YAAY,IAAI;EACpB;CACF,SAAS,GAAG;EACV,GAAG,OAAO,kCAAkC,CAAC;EAC7C,OAAO,oBAAoB,IAAI;GAC7B,IAAI;GACJ,IAAI,KAAK;GACT,OAAQ,EAAY;EACtB,CAAC;CACH;AACF;;;;;;;;;AAUA,SAAgB,yBACd,QACA,iBACoB;CACpB,IAAI,mBAAmB,MAAM,OAAO,cAAc,KAAA,GAChD,OAAO;CAET,OAAO;EACL,GAAG;EACH,WAAW,OAAO,UAAU,QAC1B,UAAS,EAAE,cAAc,SAAS,MAAM,aAAa,SACvD;CACF;AACF;;;;;;;;;;;;;AAcA,SAAgB,mBACd,SACA,iBAC2B;CAC3B,IAAI,mBAAmB,MAAM,YAAY,MACvC,OAAO;CAIT,MAAM,gBAAgB,IAAI,QAAQ;CAClC,MAAM,YAAY,QAAQ;CAC1B,IAAI,cAAc,KAAA,GAChB,cAAc,IAAI,SAAS;CAS7B,OAAO;EANL,gCAAgC,cAAc,OAAO;EACrD,uBAAuB,QAAQ;CAK1B;AACT"}
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * The current version of Zero.
4
4
  */
5
- var version = "1.11.0-canary.37";
5
+ var version = "1.11.0-canary.38";
6
6
  //#endregion
7
7
  export { version };
8
8
 
@@ -59,6 +59,25 @@ export declare const correlatedSubquerySchemaOmitSubquery: v.ObjectType<Readonly
59
59
  }>, undefined>;
60
60
  export declare const correlatedSubquerySchema: v.Type<CorrelatedSubquery>;
61
61
  export declare const astSchema: v.Type<AST>;
62
+ /**
63
+ * The maximum nesting depth of an AST sent by a client, counting and/or
64
+ * conditions, correlated subqueries and related subqueries. Parsing and the
65
+ * AST visitors in zero-cache are recursive, so a single deeply nested AST can
66
+ * otherwise overflow the stack or burn seconds of CPU. Realistic queries,
67
+ * permission rules included, are less than 10 levels deep.
68
+ */
69
+ export declare const MAX_AST_DEPTH = 50;
70
+ /**
71
+ * Returns whether the unparsed `ast` is nested deeper than `maxDepth`.
72
+ */
73
+ export declare function exceedsASTDepth(ast: unknown, maxDepth?: number): boolean;
74
+ /**
75
+ * {@link astSchema} for ASTs sent by clients, which rejects ASTs nested deeper
76
+ * than {@link MAX_AST_DEPTH} before parsing them. ASTs the server stored itself
77
+ * (e.g. in the CVR) are parsed with {@link astSchema} so that ones stored
78
+ * before the limit existed can still be read.
79
+ */
80
+ export declare const depthBoundedAstSchema: v.Type<AST>;
62
81
  export type Bound = {
63
82
  row: Row;
64
83
  exclusive: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../../../zero-protocol/src/ast.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../../../zero-protocol/src/ast.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { assert } from "../../shared/src/asserts.js";
2
2
  import { literalUnion, readonly, readonlyArray, readonlyObject, valita_exports } from "../../shared/src/valita.js";
3
3
  import { getOrInsertComputed } from "../../shared/src/map.js";
4
+ import { isPlainObject } from "../../shared/src/deep-merge.js";
4
5
  import { must } from "../../shared/src/must.js";
5
6
  import { rowSchema } from "./data.js";
6
7
  import { compareUTF8 } from "compare-utf8";
@@ -103,6 +104,31 @@ var astSchema = readonlyObject({
103
104
  exclusive: valita_exports.boolean()
104
105
  }).optional()
105
106
  });
107
+ /**
108
+ * Returns whether the unparsed `ast` is nested deeper than `maxDepth`.
109
+ */
110
+ function exceedsASTDepth(ast, maxDepth = 50) {
111
+ return astExceedsDepth(ast, 0, maxDepth);
112
+ }
113
+ function astExceedsDepth(ast, depth, maxDepth) {
114
+ if (depth > maxDepth) return true;
115
+ if (!isPlainObject(ast)) return false;
116
+ const { where, related } = ast;
117
+ return conditionExceedsDepth(where, depth, maxDepth) || Array.isArray(related) && related.some((r) => isPlainObject(r) && astExceedsDepth(r.subquery, depth + 1, maxDepth));
118
+ }
119
+ function conditionExceedsDepth(cond, depth, maxDepth) {
120
+ if (depth > maxDepth) return true;
121
+ if (!isPlainObject(cond)) return false;
122
+ const { conditions, related } = cond;
123
+ return Array.isArray(conditions) && conditions.some((c) => conditionExceedsDepth(c, depth + 1, maxDepth)) || isPlainObject(related) && astExceedsDepth(related.subquery, depth + 1, maxDepth);
124
+ }
125
+ /**
126
+ * {@link astSchema} for ASTs sent by clients, which rejects ASTs nested deeper
127
+ * than {@link MAX_AST_DEPTH} before parsing them. ASTs the server stored itself
128
+ * (e.g. in the CVR) are parsed with {@link astSchema} so that ones stored
129
+ * before the limit existed can still be read.
130
+ */
131
+ var depthBoundedAstSchema = valita_exports.unknown().chain((value, options) => exceedsASTDepth(value) ? valita_exports.err(`AST exceeds the maximum depth of 50`) : astSchema.try(value, options));
106
132
  function transformAST(ast, transform) {
107
133
  const { tableName, columnName } = transform;
108
134
  const colName = (c) => columnName(ast.table, c);
@@ -440,6 +466,6 @@ function cmpOptionalBool(a, b) {
440
466
  return toNum(a) - toNum(b);
441
467
  }
442
468
  //#endregion
443
- export { SUBQ_PREFIX, astSchema, compoundKeySchema, conditionSchema, insertRelated, mapAST, mapCondition, normalizeAST, normalizeCondition, normalizedRelated, orderingSchema, planIdSymbol, tableAST, toStaticParam };
469
+ export { SUBQ_PREFIX, astSchema, compoundKeySchema, conditionSchema, depthBoundedAstSchema, insertRelated, mapAST, mapCondition, normalizeAST, normalizeCondition, normalizedRelated, orderingSchema, planIdSymbol, tableAST, toStaticParam };
444
470
 
445
471
  //# sourceMappingURL=ast.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ast.js","names":[],"sources":["../../../../zero-protocol/src/ast.ts"],"sourcesContent":["/**\n * Wire-format representation of the zql AST interface.\n *\n * `v.Type<...>` types are explicitly declared to facilitate Typescript verification\n * that the schemas satisfy the zql type definitions. (Incidentally, explicit types\n * are also required for recursive schema definitions.)\n */\n\nimport {compareUTF8} from 'compare-utf8';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {getOrInsertComputed} from '../../shared/src/map.ts';\nimport {must} from '../../shared/src/must.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport type {NameMapper} from '../../zero-types/src/name-mapper.ts';\nimport {rowSchema, type Row} from './data.ts';\n\nexport const SUBQ_PREFIX = 'zsubq_';\n\nexport const selectorSchema = v.string();\nexport const toStaticParam = Symbol();\nexport const planIdSymbol = Symbol('planId');\n\nconst orderingElementSchema = v.readonly(\n v.tuple([selectorSchema, v.literalUnion('asc', 'desc')]),\n);\n\nexport const orderingSchema = v.readonlyArray(orderingElementSchema);\nexport type System = 'permissions' | 'client' | 'test';\n\nexport const primitiveSchema = v.union(\n v.string(),\n v.number(),\n v.boolean(),\n v.null(),\n);\n\nexport const equalityOpsSchema = v.literalUnion('=', '!=', 'IS', 'IS NOT');\n\nexport const orderOpsSchema = v.literalUnion('<', '>', '<=', '>=');\n\nexport const likeOpsSchema = v.literalUnion(\n 'LIKE',\n 'NOT LIKE',\n 'ILIKE',\n 'NOT ILIKE',\n);\n\nexport const inOpsSchema = v.literalUnion('IN', 'NOT IN');\n\nexport const simpleOperatorSchema = v.union(\n equalityOpsSchema,\n orderOpsSchema,\n likeOpsSchema,\n inOpsSchema,\n);\n\nconst literalReferenceSchema: v.Type<LiteralReference> = v.readonlyObject({\n type: v.literal('literal'),\n value: v.union(\n v.string(),\n v.number(),\n v.boolean(),\n v.null(),\n v.readonlyArray(v.union(v.string(), v.number(), v.boolean())),\n ),\n});\nconst columnReferenceSchema: v.Type<ColumnReference> = v.readonlyObject({\n type: v.literal('column'),\n name: v.string(),\n});\n\n/**\n * A parameter is a value that is not known at the time the query is written\n * and is resolved at runtime.\n *\n * Static parameters refer to something provided by the caller.\n * Static parameters are injected when the query pipeline is built from the AST\n * and do not change for the life of that pipeline.\n *\n * An example static parameter is the current authentication data.\n * When a user is authenticated, queries on the server have access\n * to the user's authentication data in order to evaluate authorization rules.\n * Authentication data doesn't change over the life of a query as a change\n * in auth data would represent a log-in / log-out of the user.\n *\n * AncestorParameters refer to rows encountered while running the query.\n * They are used by subqueries to refer to rows emitted by parent queries.\n */\nconst parameterReferenceSchema = v.readonlyObject({\n type: v.literal('static'),\n // The \"namespace\" of the injected parameter.\n // Write authorization will send the value of a row\n // prior to the mutation being run (preMutationRow).\n // Read and write authorization will both send the\n // current authentication data (authData).\n anchor: v.literalUnion('authData', 'preMutationRow'),\n field: v.union(v.string(), v.array(v.string())),\n});\n\nconst conditionValueSchema = v.union(\n literalReferenceSchema,\n columnReferenceSchema,\n parameterReferenceSchema,\n);\n\nexport type Parameter = v.Infer<typeof parameterReferenceSchema>;\n\nexport const simpleConditionSchema: v.Type<SimpleCondition> = v.readonlyObject({\n type: v.literal('simple'),\n op: simpleOperatorSchema,\n left: conditionValueSchema,\n right: v.union(parameterReferenceSchema, literalReferenceSchema),\n});\n\ntype ConditionValue = v.Infer<typeof conditionValueSchema>;\n\nexport const correlatedSubqueryConditionOperatorSchema: v.Type<CorrelatedSubqueryConditionOperator> =\n v.literalUnion('EXISTS', 'NOT EXISTS');\n\nexport const correlatedSubqueryConditionSchema: v.Type<CorrelatedSubqueryCondition> =\n v.readonlyObject({\n type: v.literal('correlatedSubquery'),\n related: v.lazy(() => correlatedSubquerySchema),\n op: correlatedSubqueryConditionOperatorSchema,\n flip: v.boolean().optional(),\n scalar: v.boolean().optional(),\n });\n\nexport const conditionSchema: v.Type<Condition> = v.union(\n simpleConditionSchema,\n v.lazy(() => conjunctionSchema),\n v.lazy(() => disjunctionSchema),\n correlatedSubqueryConditionSchema,\n);\n\nconst conjunctionSchema: v.Type<Conjunction> = v.readonlyObject({\n type: v.literal('and'),\n conditions: v.readonlyArray(conditionSchema),\n});\n\nconst disjunctionSchema: v.Type<Disjunction> = v.readonlyObject({\n type: v.literal('or'),\n conditions: v.readonlyArray(conditionSchema),\n});\n\nexport type CompoundKey = readonly [string, ...string[]];\n\nfunction mustCompoundKey(field: readonly string[]): CompoundKey {\n assert(\n Array.isArray(field) && field.length >= 1,\n 'Expected non-empty array for compound key',\n );\n return field as unknown as CompoundKey;\n}\n\nexport const compoundKeySchema: v.Type<CompoundKey> = v.readonly(\n // oxlint-disable-next-line e18e/prefer-spread-syntax\n v.tuple([v.string()]).concat(v.array(v.string())),\n);\n\nconst correlationSchema = v.readonlyObject({\n parentField: compoundKeySchema,\n childField: compoundKeySchema,\n});\n\n// Split out so that its inferred type can be checked against\n// Omit<CorrelatedSubquery, 'correlation'> in ast-type-test.ts.\n// The mutually-recursive reference of the 'other' field to astSchema\n// is the only thing added in v.lazy. The v.lazy is necessary due to the\n// mutually-recursive types, but v.lazy prevents inference of the resulting\n// type.\nexport const correlatedSubquerySchemaOmitSubquery = v.readonlyObject({\n correlation: correlationSchema,\n hidden: v.boolean().optional(),\n system: v.literalUnion('permissions', 'client', 'test').optional(),\n});\n\nexport const correlatedSubquerySchema: v.Type<CorrelatedSubquery> =\n correlatedSubquerySchemaOmitSubquery.extend({\n subquery: v.lazy(() => astSchema),\n });\n\nexport const astSchema: v.Type<AST> = v.readonlyObject({\n schema: v.string().optional(),\n table: v.string(),\n alias: v.string().optional(),\n where: conditionSchema.optional(),\n related: v.readonlyArray(correlatedSubquerySchema).optional(),\n limit: v.number().optional(),\n orderBy: orderingSchema.optional(),\n start: v\n .object({\n row: rowSchema,\n exclusive: v.boolean(),\n })\n .optional(),\n});\n\nexport type Bound = {\n row: Row;\n exclusive: boolean;\n};\n\n/**\n * As in SQL you can have multiple orderings. We don't currently\n * support ordering on anything other than the root query.\n */\nexport type OrderPart = readonly [field: string, direction: 'asc' | 'desc'];\nexport type Ordering = readonly OrderPart[];\n\nexport type SimpleOperator = EqualityOps | OrderOps | LikeOps | InOps;\nexport type EqualityOps = '=' | '!=' | 'IS' | 'IS NOT';\nexport type OrderOps = '<' | '>' | '<=' | '>=';\nexport type LikeOps = 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE';\nexport type InOps = 'IN' | 'NOT IN';\n\nexport type AST = {\n readonly schema?: string | undefined;\n readonly table: string;\n\n // A query would be aliased if the AST is a subquery.\n // e.g., when two subqueries select from the same table\n // they need an alias to differentiate them.\n // `SELECT\n // [SELECT * FROM issue WHERE issue.id = outer.parentId] AS parent\n // [SELECT * FROM issue WHERE issue.parentId = outer.id] AS children\n // FROM issue as outer`\n readonly alias?: string | undefined;\n\n // `select` is missing given we return all columns for now.\n\n // The PipelineBuilder will pick what to use to correlate\n // a subquery with a parent query. It can choose something from the\n // where conditions or choose the _first_ `related` entry.\n // Choosing the first `related` entry is almost always the best choice if\n // one exists.\n readonly where?: Condition | undefined;\n\n readonly related?: readonly CorrelatedSubquery[] | undefined;\n readonly start?: Bound | undefined;\n readonly limit?: number | undefined;\n readonly orderBy?: Ordering | undefined;\n};\n\nexport type Correlation = {\n readonly parentField: CompoundKey;\n readonly childField: CompoundKey;\n};\n\nexport type CorrelatedSubquery = {\n /**\n * Only equality correlation are supported for now.\n * E.g., direct foreign key relationships.\n */\n readonly correlation: Correlation;\n readonly subquery: AST;\n readonly system?: System | undefined;\n // If a hop in the subquery chain should be hidden from the output view.\n // A common example is junction edges. The query API provides the illusion\n // that they don't exist: `issue.related('labels')` instead of `issue.related('issue_labels').related('labels')`.\n // To maintain this illusion, the junction edge should be hidden.\n // When `hidden` is set to true, this hop will not be included in the output view\n // but its children will be.\n readonly hidden?: boolean | undefined;\n};\n\nexport type ValuePosition = LiteralReference | Parameter | ColumnReference;\n\nexport type ColumnReference = {\n readonly type: 'column';\n /**\n * Not a path yet as we're currently not allowing\n * comparisons across tables. This will need to\n * be a path through the tree in the near future.\n */\n readonly name: string;\n};\n\nexport type LiteralReference = {\n readonly type: 'literal';\n readonly value: LiteralValue;\n};\n\nexport type LiteralValue =\n | string\n | number\n | boolean\n | null\n | ReadonlyArray<string | number | boolean>;\n\n/**\n * Starting only with SimpleCondition for now.\n * ivm1 supports Conjunctions and Disjunctions.\n * We'll support them in the future.\n */\nexport type Condition =\n | SimpleCondition\n | Conjunction\n | Disjunction\n | CorrelatedSubqueryCondition;\n\nexport type SimpleCondition = {\n readonly type: 'simple';\n readonly op: SimpleOperator;\n readonly left: ValuePosition;\n\n /**\n * `null` is absent since we do not have an `IS` or `IS NOT`\n * operator defined and `null != null` in SQL.\n */\n readonly right: Exclude<ValuePosition, ColumnReference>;\n};\n\nexport type Conjunction = {\n type: 'and';\n conditions: readonly Condition[];\n};\n\nexport type Disjunction = {\n type: 'or';\n conditions: readonly Condition[];\n};\n\nexport type CorrelatedSubqueryCondition = {\n type: 'correlatedSubquery';\n related: CorrelatedSubquery;\n op: CorrelatedSubqueryConditionOperator;\n flip?: boolean | undefined;\n scalar?: boolean | undefined;\n [planIdSymbol]?: number | undefined;\n};\n\nexport type CorrelatedSubqueryConditionOperator = 'EXISTS' | 'NOT EXISTS';\n\ninterface ASTTransform {\n tableName(orig: string): string;\n columnName(origTable: string, origColumn: string): string;\n}\n\nfunction transformAST(ast: AST, transform: ASTTransform): Required<AST> {\n // Name mapping functions (e.g. to server names)\n const {tableName, columnName} = transform;\n const colName = (c: string) => columnName(ast.table, c);\n const key = (table: string, k: CompoundKey) => {\n const serverKey = k.map(col => columnName(table, col));\n return mustCompoundKey(serverKey);\n };\n\n const transformed = {\n schema: ast.schema,\n table: tableName(ast.table),\n alias: ast.alias,\n where: ast.where\n ? transformWhere(ast.where, ast.table, transform)\n : undefined,\n related: ast.related?.map(\n r =>\n ({\n correlation: {\n parentField: key(ast.table, r.correlation.parentField),\n childField: key(r.subquery.table, r.correlation.childField),\n },\n hidden: r.hidden,\n subquery: transformAST(r.subquery, transform),\n system: r.system,\n }) satisfies Required<CorrelatedSubquery>,\n ),\n start: ast.start\n ? {\n ...ast.start,\n row: Object.fromEntries(\n Object.entries(ast.start.row).map(([col, val]) => [\n colName(col),\n val,\n ]),\n ),\n }\n : undefined,\n limit: ast.limit,\n orderBy: ast.orderBy?.map(([col, dir]) => [colName(col), dir] as const),\n };\n\n return transformed;\n}\n\nfunction transformWhere(\n where: Condition,\n table: string,\n transform: ASTTransform,\n): Condition {\n // Name mapping functions (e.g. to server names)\n const {columnName} = transform;\n const condValue = (c: ConditionValue) =>\n c.type !== 'column' ? c : {...c, name: columnName(table, c.name)};\n const key = (table: string, k: CompoundKey) => {\n const serverKey = k.map(col => columnName(table, col));\n return mustCompoundKey(serverKey);\n };\n\n if (where.type === 'simple') {\n return {...where, left: condValue(where.left)};\n } else if (where.type === 'correlatedSubquery') {\n const {correlation, subquery} = where.related;\n return {\n ...where,\n related: {\n ...where.related,\n correlation: {\n parentField: key(table, correlation.parentField),\n childField: key(subquery.table, correlation.childField),\n },\n subquery: transformAST(subquery, transform),\n },\n };\n }\n\n return {\n type: where.type,\n conditions: where.conditions.map(c => transformWhere(c, table, transform)),\n };\n}\n\ndeclare const normalizedTag: unique symbol;\n\n/**\n * An {@link AST} in its normalized form: `related` is sorted, `where` is\n * flattened and sorted, and every field is present, in a fixed order. Two ASTs\n * that describe the same query have the same JSON encoding, and thus the same\n * hash, once normalized.\n *\n * The tag only exists in the type, so the only way to get one is from\n * {@link normalizeAST}, {@link normalizedAST} or {@link tableAST}. Spreading\n * one keeps the tag, which is what lets a query builder derive a normalized\n * AST from another one by replacing a field it knows to be safe.\n */\nexport type NormalizedAST = Required<AST> & {readonly [normalizedTag]: true};\n\nfunction asNormalized(ast: Required<AST>): NormalizedAST {\n return ast as NormalizedAST;\n}\n\nconst normalizeCache = new WeakMap<AST, NormalizedAST>();\n\nexport function normalizeAST(ast: AST): NormalizedAST {\n return getOrInsertComputed(normalizeCache, ast, normalizeASTUncached);\n}\n\nfunction normalizeASTUncached(ast: AST): NormalizedAST {\n // normalizedAST() normalizes a single level, so normalize the subqueries\n // first.\n const {where, related} = ast;\n return normalizedAST({\n ...ast,\n where: where && normalizeSubqueries(where),\n related: related?.map(r =>\n normalizedRelated({...r, subquery: normalizeAST(r.subquery)}),\n ),\n });\n}\n\n/**\n * Normalizes the ASTs of the correlated subqueries of `cond`. The condition\n * itself is normalized by {@link normalizeCondition}.\n */\nfunction normalizeSubqueries(cond: Condition): Condition {\n switch (cond.type) {\n case 'simple':\n return cond;\n case 'correlatedSubquery':\n return {\n ...cond,\n related: {\n ...cond.related,\n subquery: normalizeAST(cond.related.subquery),\n },\n };\n default:\n return {\n type: cond.type,\n conditions: cond.conditions.map(normalizeSubqueries),\n };\n }\n}\n\n/**\n * Normalizes a single level of an AST, assuming that the ASTs of its\n * subqueries (i.e. those in `related` and in correlated subquery conditions)\n * are already normalized and that the `related` entries have the shape that\n * {@link normalizedRelated} gives them.\n *\n * This lets a query builder keep its AST normalized as it builds it up\n * instead of normalizing the whole tree afterwards. A builder that knows\n * which of the rules a step can break at all is better off applying just\n * those (see {@link tableAST}, {@link insertRelated} and\n * {@link normalizeCondition}).\n */\nexport function normalizedAST(ast: AST): NormalizedAST {\n const {schema, table, alias, where, related, start, limit, orderBy} = ast;\n // Every field is written, in the same order, so that all normalized ASTs\n // have the same shape (one hidden class) and the same JSON encoding (and\n // thus the same hash) no matter how they were put together. The fields that\n // are undefined are dropped by JSON.stringify() anyway.\n return asNormalized({\n schema,\n table,\n alias,\n where: where === undefined ? undefined : normalizeCondition(where),\n related: related === undefined ? undefined : normalizeRelated(related),\n start,\n limit,\n orderBy,\n });\n}\n\n/**\n * The normalized AST that selects a whole table. Spreading it (or any other\n * normalized AST) and replacing a field keeps the field order, since a\n * normalized AST has every field.\n */\nexport function tableAST(\n table: string,\n alias?: string | undefined,\n): NormalizedAST {\n return asNormalized({\n schema: undefined,\n table,\n alias,\n where: undefined,\n related: undefined,\n start: undefined,\n limit: undefined,\n orderBy: undefined,\n });\n}\n\n/**\n * Adds `subquery` to the `related` of a normalized AST, at the position that\n * keeps it sorted.\n */\nexport function insertRelated(\n related: readonly CorrelatedSubquery[] | undefined,\n subquery: CorrelatedSubquery,\n): readonly CorrelatedSubquery[] {\n const normalized = normalizedRelated(subquery);\n if (related === undefined) {\n return [normalized];\n }\n // Sorting is stable, so an entry goes after the ones it compares equal to.\n let i = related.length;\n while (i > 0 && cmpRelated(related[i - 1], normalized) > 0) {\n i--;\n }\n return related.toSpliced(i, 0, normalized);\n}\n\n// Conjunctions and disjunctions that are known to be normalized. The query\n// builder rebuilds its AST for every step, so this keeps the conditions that\n// did not change from being normalized over and over again.\nconst normalizedConditions = new WeakSet<Condition>();\n\nfunction normalizeRelated(\n related: readonly CorrelatedSubquery[],\n): readonly CorrelatedSubquery[] {\n for (let i = 1; i < related.length; i++) {\n if (cmpRelated(related[i - 1], related[i]) > 0) {\n return related.toSorted(cmpRelated);\n }\n }\n return related;\n}\n\n/**\n * Gives a correlated subquery the shape that a normalized AST has: every\n * field, in a fixed order (see {@link normalizedAST}). Its `subquery` must\n * already be normalized.\n */\nexport function normalizedRelated(\n related: CorrelatedSubquery,\n): Required<CorrelatedSubquery> {\n const {correlation, hidden, subquery, system} = related;\n return {\n correlation: {\n parentField: correlation.parentField,\n childField: correlation.childField,\n },\n hidden,\n subquery,\n system,\n };\n}\n\nfunction normalizeValuePosition<T extends ValuePosition>(v: T): T {\n switch (v.type) {\n case 'literal':\n return {type: 'literal', value: v.value} as T;\n case 'column':\n return {type: 'column', name: v.name} as T;\n default:\n return {type: 'static', anchor: v.anchor, field: v.field} as T;\n }\n}\n\n/**\n * Normalizes a condition, assuming that the ASTs of any correlated subqueries\n * it contains are already normalized.\n *\n * Like {@link normalizedAST}, this rebuilds every node with its fields in a\n * fixed order, so that structurally equal conditions have the same JSON\n * encoding (and thus the same hash) no matter how they were put together.\n * That includes a round trip through Postgres, whose jsonb type reorders\n * object keys: without the rebuild, every query record reloaded from the CVR\n * re-hashed to a different transformationHash than was stored, making it look\n * changed and re-execute on every view-syncer restart.\n */\nexport function normalizeCondition(cond: Condition): Condition {\n if (normalizedConditions.has(cond)) {\n return cond;\n }\n if (cond.type === 'simple') {\n const normalized: Condition = {\n type: 'simple',\n op: cond.op,\n left: normalizeValuePosition(cond.left),\n right: normalizeValuePosition(cond.right),\n };\n normalizedConditions.add(normalized);\n return normalized;\n }\n if (cond.type === 'correlatedSubquery') {\n const normalized: Condition = {\n type: 'correlatedSubquery',\n related: normalizedRelated(cond.related),\n op: cond.op,\n flip: cond.flip,\n scalar: cond.scalar,\n };\n normalizedConditions.add(normalized);\n return normalized;\n }\n\n // Flatten the conditions of nested conjunctions of the same type and sort\n // them. The nested conditions are normalized (and thus flattened and sorted)\n // first.\n const conditions: Condition[] = [];\n for (const c of cond.conditions) {\n const n = normalizeCondition(c);\n if (n.type === cond.type) {\n conditions.push(...n.conditions);\n } else {\n conditions.push(n);\n }\n }\n\n // A singleton conjunction is the same as the condition itself. Empty\n // conjunctions, on the other hand, are meaningful: an empty 'and' is always\n // true and an empty 'or' is always false.\n if (conditions.length === 1) {\n return conditions[0];\n }\n conditions.sort(cmpCondition);\n const normalized: Condition = {type: cond.type, conditions};\n normalizedConditions.add(normalized);\n return normalized;\n}\n\n/**\n * Maps the table and column names of `ast`. The result is not a\n * {@link NormalizedAST} even if `ast` was normalized: the names it sorts by\n * are the ones that changed.\n */\nexport function mapAST(ast: AST, mapper: NameMapper) {\n return transformAST(ast, {\n tableName: table => mapper.tableName(table),\n columnName: (table, col) => mapper.columnName(table, col),\n });\n}\n\nexport function mapCondition(\n cond: Condition,\n table: string,\n mapper: NameMapper,\n) {\n return transformWhere(cond, table, {\n tableName: table => mapper.tableName(table),\n columnName: (table, col) => mapper.columnName(table, col),\n });\n}\n\nfunction cmpCondition(a: Condition, b: Condition): number {\n if (a.type === 'simple') {\n if (b.type !== 'simple') {\n return -1; // Order SimpleConditions first\n }\n\n return (\n compareValuePosition(a.left, b.left) ||\n compareUTF8MaybeNull(a.op, b.op) ||\n compareValuePosition(a.right, b.right)\n );\n }\n\n if (b.type === 'simple') {\n return 1; // Order SimpleConditions first\n }\n\n if (a.type === 'correlatedSubquery') {\n if (b.type !== 'correlatedSubquery') {\n return -1; // Order subquery before conjuctions/disjuctions\n }\n return (\n cmpRelated(a.related, b.related) ||\n compareUTF8MaybeNull(a.op, b.op) ||\n cmpOptionalBool(a.flip, b.flip) ||\n cmpOptionalBool(a.scalar, b.scalar)\n );\n }\n if (b.type === 'correlatedSubquery') {\n return -1; // Order correlatedSubquery before conjuctions/disjuctions\n }\n\n const val = compareUTF8MaybeNull(a.type, b.type);\n if (val !== 0) {\n return val;\n }\n for (\n let l = 0, r = 0;\n l < a.conditions.length && r < b.conditions.length;\n l++, r++\n ) {\n const val = cmpCondition(a.conditions[l], b.conditions[r]);\n if (val !== 0) {\n return val;\n }\n }\n // prefixes first\n return a.conditions.length - b.conditions.length;\n}\n\nfunction compareValuePosition(a: ValuePosition, b: ValuePosition): number {\n if (a.type !== b.type) {\n return compareUTF8(a.type, b.type);\n }\n switch (a.type) {\n case 'literal':\n assert(b.type === 'literal', 'Expected literal type for comparison');\n return cmpLiteralValue(a.value, b.value);\n case 'column':\n assert(b.type === 'column', 'Expected column type for comparison');\n return compareUTF8(a.name, b.name);\n case 'static':\n assert(b.type === 'static', 'Expected static type for comparison');\n // A field is a string or a path of strings, which cmpLiteralValue()\n // tells apart.\n return (\n compareUTF8(a.anchor, b.anchor) || cmpLiteralValue(a.field, b.field)\n );\n }\n}\n\n// null < boolean < number < string < array. Ordering values of different\n// types by their string form would make distinct values compare equal (['a',\n// 'b'] and 'a,b', or 1 and '1'), which would leave their order up to the\n// order they were written in, and with it the hash of the query.\nconst LITERAL_VALUE_TYPES = ['object', 'boolean', 'number', 'string'];\n\nfunction literalValueType(value: LiteralValue): number {\n return Array.isArray(value)\n ? LITERAL_VALUE_TYPES.length\n : LITERAL_VALUE_TYPES.indexOf(typeof value);\n}\n\nfunction cmpLiteralValue(a: LiteralValue, b: LiteralValue): number {\n const type = literalValueType(a) - literalValueType(b);\n if (type !== 0) {\n return type;\n }\n\n if (Array.isArray(a)) {\n assert(Array.isArray(b), 'Expected array for comparison');\n for (let i = 0; i < a.length && i < b.length; i++) {\n const val = cmpLiteralValue(a[i], b[i]);\n if (val !== 0) {\n return val;\n }\n }\n // prefixes first\n return a.length - b.length;\n }\n\n switch (typeof a) {\n case 'string':\n assert(typeof b === 'string', 'Expected string for comparison');\n return compareUTF8(a, b);\n case 'number':\n assert(typeof b === 'number', 'Expected number for comparison');\n return a < b ? -1 : a > b ? 1 : 0;\n case 'boolean':\n assert(typeof b === 'boolean', 'Expected boolean for comparison');\n return Number(a) - Number(b);\n default:\n return 0; // null\n }\n}\n\nfunction cmpRelated(a: CorrelatedSubquery, b: CorrelatedSubquery): number {\n return compareUTF8(must(a.subquery.alias), must(b.subquery.alias));\n}\n\nfunction compareUTF8MaybeNull(a: string | null, b: string | null): number {\n if (a !== null && b !== null) {\n return compareUTF8(a, b);\n }\n if (b !== null) {\n return -1;\n }\n if (a !== null) {\n return 1;\n }\n return 0;\n}\n\nfunction cmpOptionalBool(\n a: boolean | undefined,\n b: boolean | undefined,\n): number {\n // undefined < false < true\n const toNum = (v: boolean | undefined) => (v === undefined ? 0 : v ? 2 : 1);\n return toNum(a) - toNum(b);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ast.js","names":[],"sources":["../../../../zero-protocol/src/ast.ts"],"sourcesContent":["/**\n * Wire-format representation of the zql AST interface.\n *\n * `v.Type<...>` types are explicitly declared to facilitate Typescript verification\n * that the schemas satisfy the zql type definitions. (Incidentally, explicit types\n * are also required for recursive schema definitions.)\n */\n\nimport {compareUTF8} from 'compare-utf8';\nimport {assert} from '../../shared/src/asserts.ts';\nimport {isPlainObject} from '../../shared/src/deep-merge.ts';\nimport {getOrInsertComputed} from '../../shared/src/map.ts';\nimport {must} from '../../shared/src/must.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport type {NameMapper} from '../../zero-types/src/name-mapper.ts';\nimport {rowSchema, type Row} from './data.ts';\n\nexport const SUBQ_PREFIX = 'zsubq_';\n\nexport const selectorSchema = v.string();\nexport const toStaticParam = Symbol();\nexport const planIdSymbol = Symbol('planId');\n\nconst orderingElementSchema = v.readonly(\n v.tuple([selectorSchema, v.literalUnion('asc', 'desc')]),\n);\n\nexport const orderingSchema = v.readonlyArray(orderingElementSchema);\nexport type System = 'permissions' | 'client' | 'test';\n\nexport const primitiveSchema = v.union(\n v.string(),\n v.number(),\n v.boolean(),\n v.null(),\n);\n\nexport const equalityOpsSchema = v.literalUnion('=', '!=', 'IS', 'IS NOT');\n\nexport const orderOpsSchema = v.literalUnion('<', '>', '<=', '>=');\n\nexport const likeOpsSchema = v.literalUnion(\n 'LIKE',\n 'NOT LIKE',\n 'ILIKE',\n 'NOT ILIKE',\n);\n\nexport const inOpsSchema = v.literalUnion('IN', 'NOT IN');\n\nexport const simpleOperatorSchema = v.union(\n equalityOpsSchema,\n orderOpsSchema,\n likeOpsSchema,\n inOpsSchema,\n);\n\nconst literalReferenceSchema: v.Type<LiteralReference> = v.readonlyObject({\n type: v.literal('literal'),\n value: v.union(\n v.string(),\n v.number(),\n v.boolean(),\n v.null(),\n v.readonlyArray(v.union(v.string(), v.number(), v.boolean())),\n ),\n});\nconst columnReferenceSchema: v.Type<ColumnReference> = v.readonlyObject({\n type: v.literal('column'),\n name: v.string(),\n});\n\n/**\n * A parameter is a value that is not known at the time the query is written\n * and is resolved at runtime.\n *\n * Static parameters refer to something provided by the caller.\n * Static parameters are injected when the query pipeline is built from the AST\n * and do not change for the life of that pipeline.\n *\n * An example static parameter is the current authentication data.\n * When a user is authenticated, queries on the server have access\n * to the user's authentication data in order to evaluate authorization rules.\n * Authentication data doesn't change over the life of a query as a change\n * in auth data would represent a log-in / log-out of the user.\n *\n * AncestorParameters refer to rows encountered while running the query.\n * They are used by subqueries to refer to rows emitted by parent queries.\n */\nconst parameterReferenceSchema = v.readonlyObject({\n type: v.literal('static'),\n // The \"namespace\" of the injected parameter.\n // Write authorization will send the value of a row\n // prior to the mutation being run (preMutationRow).\n // Read and write authorization will both send the\n // current authentication data (authData).\n anchor: v.literalUnion('authData', 'preMutationRow'),\n field: v.union(v.string(), v.array(v.string())),\n});\n\nconst conditionValueSchema = v.union(\n literalReferenceSchema,\n columnReferenceSchema,\n parameterReferenceSchema,\n);\n\nexport type Parameter = v.Infer<typeof parameterReferenceSchema>;\n\nexport const simpleConditionSchema: v.Type<SimpleCondition> = v.readonlyObject({\n type: v.literal('simple'),\n op: simpleOperatorSchema,\n left: conditionValueSchema,\n right: v.union(parameterReferenceSchema, literalReferenceSchema),\n});\n\ntype ConditionValue = v.Infer<typeof conditionValueSchema>;\n\nexport const correlatedSubqueryConditionOperatorSchema: v.Type<CorrelatedSubqueryConditionOperator> =\n v.literalUnion('EXISTS', 'NOT EXISTS');\n\nexport const correlatedSubqueryConditionSchema: v.Type<CorrelatedSubqueryCondition> =\n v.readonlyObject({\n type: v.literal('correlatedSubquery'),\n related: v.lazy(() => correlatedSubquerySchema),\n op: correlatedSubqueryConditionOperatorSchema,\n flip: v.boolean().optional(),\n scalar: v.boolean().optional(),\n });\n\nexport const conditionSchema: v.Type<Condition> = v.union(\n simpleConditionSchema,\n v.lazy(() => conjunctionSchema),\n v.lazy(() => disjunctionSchema),\n correlatedSubqueryConditionSchema,\n);\n\nconst conjunctionSchema: v.Type<Conjunction> = v.readonlyObject({\n type: v.literal('and'),\n conditions: v.readonlyArray(conditionSchema),\n});\n\nconst disjunctionSchema: v.Type<Disjunction> = v.readonlyObject({\n type: v.literal('or'),\n conditions: v.readonlyArray(conditionSchema),\n});\n\nexport type CompoundKey = readonly [string, ...string[]];\n\nfunction mustCompoundKey(field: readonly string[]): CompoundKey {\n assert(\n Array.isArray(field) && field.length >= 1,\n 'Expected non-empty array for compound key',\n );\n return field as unknown as CompoundKey;\n}\n\nexport const compoundKeySchema: v.Type<CompoundKey> = v.readonly(\n // oxlint-disable-next-line e18e/prefer-spread-syntax\n v.tuple([v.string()]).concat(v.array(v.string())),\n);\n\nconst correlationSchema = v.readonlyObject({\n parentField: compoundKeySchema,\n childField: compoundKeySchema,\n});\n\n// Split out so that its inferred type can be checked against\n// Omit<CorrelatedSubquery, 'correlation'> in ast-type-test.ts.\n// The mutually-recursive reference of the 'other' field to astSchema\n// is the only thing added in v.lazy. The v.lazy is necessary due to the\n// mutually-recursive types, but v.lazy prevents inference of the resulting\n// type.\nexport const correlatedSubquerySchemaOmitSubquery = v.readonlyObject({\n correlation: correlationSchema,\n hidden: v.boolean().optional(),\n system: v.literalUnion('permissions', 'client', 'test').optional(),\n});\n\nexport const correlatedSubquerySchema: v.Type<CorrelatedSubquery> =\n correlatedSubquerySchemaOmitSubquery.extend({\n subquery: v.lazy(() => astSchema),\n });\n\nexport const astSchema: v.Type<AST> = v.readonlyObject({\n schema: v.string().optional(),\n table: v.string(),\n alias: v.string().optional(),\n where: conditionSchema.optional(),\n related: v.readonlyArray(correlatedSubquerySchema).optional(),\n limit: v.number().optional(),\n orderBy: orderingSchema.optional(),\n start: v\n .object({\n row: rowSchema,\n exclusive: v.boolean(),\n })\n .optional(),\n});\n\n/**\n * The maximum nesting depth of an AST sent by a client, counting and/or\n * conditions, correlated subqueries and related subqueries. Parsing and the\n * AST visitors in zero-cache are recursive, so a single deeply nested AST can\n * otherwise overflow the stack or burn seconds of CPU. Realistic queries,\n * permission rules included, are less than 10 levels deep.\n */\nexport const MAX_AST_DEPTH = 50;\n\n/**\n * Returns whether the unparsed `ast` is nested deeper than `maxDepth`.\n */\nexport function exceedsASTDepth(\n ast: unknown,\n maxDepth = MAX_AST_DEPTH,\n): boolean {\n return astExceedsDepth(ast, 0, maxDepth);\n}\n\n// Every step down increases the depth, except the one from an AST into its\n// where clause, so the recursion stops within 2 * maxDepth steps and cannot\n// overflow the stack.\nfunction astExceedsDepth(\n ast: unknown,\n depth: number,\n maxDepth: number,\n): boolean {\n if (depth > maxDepth) {\n return true;\n }\n if (!isPlainObject(ast)) {\n return false;\n }\n const {where, related} = ast;\n return (\n conditionExceedsDepth(where, depth, maxDepth) ||\n (Array.isArray(related) &&\n related.some(\n r =>\n isPlainObject(r) && astExceedsDepth(r.subquery, depth + 1, maxDepth),\n ))\n );\n}\n\nfunction conditionExceedsDepth(\n cond: unknown,\n depth: number,\n maxDepth: number,\n): boolean {\n if (depth > maxDepth) {\n return true;\n }\n if (!isPlainObject(cond)) {\n return false;\n }\n const {conditions, related} = cond;\n return (\n (Array.isArray(conditions) &&\n conditions.some(c => conditionExceedsDepth(c, depth + 1, maxDepth))) ||\n (isPlainObject(related) &&\n astExceedsDepth(related.subquery, depth + 1, maxDepth))\n );\n}\n\n/**\n * {@link astSchema} for ASTs sent by clients, which rejects ASTs nested deeper\n * than {@link MAX_AST_DEPTH} before parsing them. ASTs the server stored itself\n * (e.g. in the CVR) are parsed with {@link astSchema} so that ones stored\n * before the limit existed can still be read.\n */\nexport const depthBoundedAstSchema: v.Type<AST> = v\n .unknown()\n .chain((value, options) =>\n exceedsASTDepth(value)\n ? v.err(`AST exceeds the maximum depth of ${MAX_AST_DEPTH}`)\n : astSchema.try(value, options),\n );\n\nexport type Bound = {\n row: Row;\n exclusive: boolean;\n};\n\n/**\n * As in SQL you can have multiple orderings. We don't currently\n * support ordering on anything other than the root query.\n */\nexport type OrderPart = readonly [field: string, direction: 'asc' | 'desc'];\nexport type Ordering = readonly OrderPart[];\n\nexport type SimpleOperator = EqualityOps | OrderOps | LikeOps | InOps;\nexport type EqualityOps = '=' | '!=' | 'IS' | 'IS NOT';\nexport type OrderOps = '<' | '>' | '<=' | '>=';\nexport type LikeOps = 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE';\nexport type InOps = 'IN' | 'NOT IN';\n\nexport type AST = {\n readonly schema?: string | undefined;\n readonly table: string;\n\n // A query would be aliased if the AST is a subquery.\n // e.g., when two subqueries select from the same table\n // they need an alias to differentiate them.\n // `SELECT\n // [SELECT * FROM issue WHERE issue.id = outer.parentId] AS parent\n // [SELECT * FROM issue WHERE issue.parentId = outer.id] AS children\n // FROM issue as outer`\n readonly alias?: string | undefined;\n\n // `select` is missing given we return all columns for now.\n\n // The PipelineBuilder will pick what to use to correlate\n // a subquery with a parent query. It can choose something from the\n // where conditions or choose the _first_ `related` entry.\n // Choosing the first `related` entry is almost always the best choice if\n // one exists.\n readonly where?: Condition | undefined;\n\n readonly related?: readonly CorrelatedSubquery[] | undefined;\n readonly start?: Bound | undefined;\n readonly limit?: number | undefined;\n readonly orderBy?: Ordering | undefined;\n};\n\nexport type Correlation = {\n readonly parentField: CompoundKey;\n readonly childField: CompoundKey;\n};\n\nexport type CorrelatedSubquery = {\n /**\n * Only equality correlation are supported for now.\n * E.g., direct foreign key relationships.\n */\n readonly correlation: Correlation;\n readonly subquery: AST;\n readonly system?: System | undefined;\n // If a hop in the subquery chain should be hidden from the output view.\n // A common example is junction edges. The query API provides the illusion\n // that they don't exist: `issue.related('labels')` instead of `issue.related('issue_labels').related('labels')`.\n // To maintain this illusion, the junction edge should be hidden.\n // When `hidden` is set to true, this hop will not be included in the output view\n // but its children will be.\n readonly hidden?: boolean | undefined;\n};\n\nexport type ValuePosition = LiteralReference | Parameter | ColumnReference;\n\nexport type ColumnReference = {\n readonly type: 'column';\n /**\n * Not a path yet as we're currently not allowing\n * comparisons across tables. This will need to\n * be a path through the tree in the near future.\n */\n readonly name: string;\n};\n\nexport type LiteralReference = {\n readonly type: 'literal';\n readonly value: LiteralValue;\n};\n\nexport type LiteralValue =\n | string\n | number\n | boolean\n | null\n | ReadonlyArray<string | number | boolean>;\n\n/**\n * Starting only with SimpleCondition for now.\n * ivm1 supports Conjunctions and Disjunctions.\n * We'll support them in the future.\n */\nexport type Condition =\n | SimpleCondition\n | Conjunction\n | Disjunction\n | CorrelatedSubqueryCondition;\n\nexport type SimpleCondition = {\n readonly type: 'simple';\n readonly op: SimpleOperator;\n readonly left: ValuePosition;\n\n /**\n * `null` is absent since we do not have an `IS` or `IS NOT`\n * operator defined and `null != null` in SQL.\n */\n readonly right: Exclude<ValuePosition, ColumnReference>;\n};\n\nexport type Conjunction = {\n type: 'and';\n conditions: readonly Condition[];\n};\n\nexport type Disjunction = {\n type: 'or';\n conditions: readonly Condition[];\n};\n\nexport type CorrelatedSubqueryCondition = {\n type: 'correlatedSubquery';\n related: CorrelatedSubquery;\n op: CorrelatedSubqueryConditionOperator;\n flip?: boolean | undefined;\n scalar?: boolean | undefined;\n [planIdSymbol]?: number | undefined;\n};\n\nexport type CorrelatedSubqueryConditionOperator = 'EXISTS' | 'NOT EXISTS';\n\ninterface ASTTransform {\n tableName(orig: string): string;\n columnName(origTable: string, origColumn: string): string;\n}\n\nfunction transformAST(ast: AST, transform: ASTTransform): Required<AST> {\n // Name mapping functions (e.g. to server names)\n const {tableName, columnName} = transform;\n const colName = (c: string) => columnName(ast.table, c);\n const key = (table: string, k: CompoundKey) => {\n const serverKey = k.map(col => columnName(table, col));\n return mustCompoundKey(serverKey);\n };\n\n const transformed = {\n schema: ast.schema,\n table: tableName(ast.table),\n alias: ast.alias,\n where: ast.where\n ? transformWhere(ast.where, ast.table, transform)\n : undefined,\n related: ast.related?.map(\n r =>\n ({\n correlation: {\n parentField: key(ast.table, r.correlation.parentField),\n childField: key(r.subquery.table, r.correlation.childField),\n },\n hidden: r.hidden,\n subquery: transformAST(r.subquery, transform),\n system: r.system,\n }) satisfies Required<CorrelatedSubquery>,\n ),\n start: ast.start\n ? {\n ...ast.start,\n row: Object.fromEntries(\n Object.entries(ast.start.row).map(([col, val]) => [\n colName(col),\n val,\n ]),\n ),\n }\n : undefined,\n limit: ast.limit,\n orderBy: ast.orderBy?.map(([col, dir]) => [colName(col), dir] as const),\n };\n\n return transformed;\n}\n\nfunction transformWhere(\n where: Condition,\n table: string,\n transform: ASTTransform,\n): Condition {\n // Name mapping functions (e.g. to server names)\n const {columnName} = transform;\n const condValue = (c: ConditionValue) =>\n c.type !== 'column' ? c : {...c, name: columnName(table, c.name)};\n const key = (table: string, k: CompoundKey) => {\n const serverKey = k.map(col => columnName(table, col));\n return mustCompoundKey(serverKey);\n };\n\n if (where.type === 'simple') {\n return {...where, left: condValue(where.left)};\n } else if (where.type === 'correlatedSubquery') {\n const {correlation, subquery} = where.related;\n return {\n ...where,\n related: {\n ...where.related,\n correlation: {\n parentField: key(table, correlation.parentField),\n childField: key(subquery.table, correlation.childField),\n },\n subquery: transformAST(subquery, transform),\n },\n };\n }\n\n return {\n type: where.type,\n conditions: where.conditions.map(c => transformWhere(c, table, transform)),\n };\n}\n\ndeclare const normalizedTag: unique symbol;\n\n/**\n * An {@link AST} in its normalized form: `related` is sorted, `where` is\n * flattened and sorted, and every field is present, in a fixed order. Two ASTs\n * that describe the same query have the same JSON encoding, and thus the same\n * hash, once normalized.\n *\n * The tag only exists in the type, so the only way to get one is from\n * {@link normalizeAST}, {@link normalizedAST} or {@link tableAST}. Spreading\n * one keeps the tag, which is what lets a query builder derive a normalized\n * AST from another one by replacing a field it knows to be safe.\n */\nexport type NormalizedAST = Required<AST> & {readonly [normalizedTag]: true};\n\nfunction asNormalized(ast: Required<AST>): NormalizedAST {\n return ast as NormalizedAST;\n}\n\nconst normalizeCache = new WeakMap<AST, NormalizedAST>();\n\nexport function normalizeAST(ast: AST): NormalizedAST {\n return getOrInsertComputed(normalizeCache, ast, normalizeASTUncached);\n}\n\nfunction normalizeASTUncached(ast: AST): NormalizedAST {\n // normalizedAST() normalizes a single level, so normalize the subqueries\n // first.\n const {where, related} = ast;\n return normalizedAST({\n ...ast,\n where: where && normalizeSubqueries(where),\n related: related?.map(r =>\n normalizedRelated({...r, subquery: normalizeAST(r.subquery)}),\n ),\n });\n}\n\n/**\n * Normalizes the ASTs of the correlated subqueries of `cond`. The condition\n * itself is normalized by {@link normalizeCondition}.\n */\nfunction normalizeSubqueries(cond: Condition): Condition {\n switch (cond.type) {\n case 'simple':\n return cond;\n case 'correlatedSubquery':\n return {\n ...cond,\n related: {\n ...cond.related,\n subquery: normalizeAST(cond.related.subquery),\n },\n };\n default:\n return {\n type: cond.type,\n conditions: cond.conditions.map(normalizeSubqueries),\n };\n }\n}\n\n/**\n * Normalizes a single level of an AST, assuming that the ASTs of its\n * subqueries (i.e. those in `related` and in correlated subquery conditions)\n * are already normalized and that the `related` entries have the shape that\n * {@link normalizedRelated} gives them.\n *\n * This lets a query builder keep its AST normalized as it builds it up\n * instead of normalizing the whole tree afterwards. A builder that knows\n * which of the rules a step can break at all is better off applying just\n * those (see {@link tableAST}, {@link insertRelated} and\n * {@link normalizeCondition}).\n */\nexport function normalizedAST(ast: AST): NormalizedAST {\n const {schema, table, alias, where, related, start, limit, orderBy} = ast;\n // Every field is written, in the same order, so that all normalized ASTs\n // have the same shape (one hidden class) and the same JSON encoding (and\n // thus the same hash) no matter how they were put together. The fields that\n // are undefined are dropped by JSON.stringify() anyway.\n return asNormalized({\n schema,\n table,\n alias,\n where: where === undefined ? undefined : normalizeCondition(where),\n related: related === undefined ? undefined : normalizeRelated(related),\n start,\n limit,\n orderBy,\n });\n}\n\n/**\n * The normalized AST that selects a whole table. Spreading it (or any other\n * normalized AST) and replacing a field keeps the field order, since a\n * normalized AST has every field.\n */\nexport function tableAST(\n table: string,\n alias?: string | undefined,\n): NormalizedAST {\n return asNormalized({\n schema: undefined,\n table,\n alias,\n where: undefined,\n related: undefined,\n start: undefined,\n limit: undefined,\n orderBy: undefined,\n });\n}\n\n/**\n * Adds `subquery` to the `related` of a normalized AST, at the position that\n * keeps it sorted.\n */\nexport function insertRelated(\n related: readonly CorrelatedSubquery[] | undefined,\n subquery: CorrelatedSubquery,\n): readonly CorrelatedSubquery[] {\n const normalized = normalizedRelated(subquery);\n if (related === undefined) {\n return [normalized];\n }\n // Sorting is stable, so an entry goes after the ones it compares equal to.\n let i = related.length;\n while (i > 0 && cmpRelated(related[i - 1], normalized) > 0) {\n i--;\n }\n return related.toSpliced(i, 0, normalized);\n}\n\n// Conjunctions and disjunctions that are known to be normalized. The query\n// builder rebuilds its AST for every step, so this keeps the conditions that\n// did not change from being normalized over and over again.\nconst normalizedConditions = new WeakSet<Condition>();\n\nfunction normalizeRelated(\n related: readonly CorrelatedSubquery[],\n): readonly CorrelatedSubquery[] {\n for (let i = 1; i < related.length; i++) {\n if (cmpRelated(related[i - 1], related[i]) > 0) {\n return related.toSorted(cmpRelated);\n }\n }\n return related;\n}\n\n/**\n * Gives a correlated subquery the shape that a normalized AST has: every\n * field, in a fixed order (see {@link normalizedAST}). Its `subquery` must\n * already be normalized.\n */\nexport function normalizedRelated(\n related: CorrelatedSubquery,\n): Required<CorrelatedSubquery> {\n const {correlation, hidden, subquery, system} = related;\n return {\n correlation: {\n parentField: correlation.parentField,\n childField: correlation.childField,\n },\n hidden,\n subquery,\n system,\n };\n}\n\nfunction normalizeValuePosition<T extends ValuePosition>(v: T): T {\n switch (v.type) {\n case 'literal':\n return {type: 'literal', value: v.value} as T;\n case 'column':\n return {type: 'column', name: v.name} as T;\n default:\n return {type: 'static', anchor: v.anchor, field: v.field} as T;\n }\n}\n\n/**\n * Normalizes a condition, assuming that the ASTs of any correlated subqueries\n * it contains are already normalized.\n *\n * Like {@link normalizedAST}, this rebuilds every node with its fields in a\n * fixed order, so that structurally equal conditions have the same JSON\n * encoding (and thus the same hash) no matter how they were put together.\n * That includes a round trip through Postgres, whose jsonb type reorders\n * object keys: without the rebuild, every query record reloaded from the CVR\n * re-hashed to a different transformationHash than was stored, making it look\n * changed and re-execute on every view-syncer restart.\n */\nexport function normalizeCondition(cond: Condition): Condition {\n if (normalizedConditions.has(cond)) {\n return cond;\n }\n if (cond.type === 'simple') {\n const normalized: Condition = {\n type: 'simple',\n op: cond.op,\n left: normalizeValuePosition(cond.left),\n right: normalizeValuePosition(cond.right),\n };\n normalizedConditions.add(normalized);\n return normalized;\n }\n if (cond.type === 'correlatedSubquery') {\n const normalized: Condition = {\n type: 'correlatedSubquery',\n related: normalizedRelated(cond.related),\n op: cond.op,\n flip: cond.flip,\n scalar: cond.scalar,\n };\n normalizedConditions.add(normalized);\n return normalized;\n }\n\n // Flatten the conditions of nested conjunctions of the same type and sort\n // them. The nested conditions are normalized (and thus flattened and sorted)\n // first.\n const conditions: Condition[] = [];\n for (const c of cond.conditions) {\n const n = normalizeCondition(c);\n if (n.type === cond.type) {\n conditions.push(...n.conditions);\n } else {\n conditions.push(n);\n }\n }\n\n // A singleton conjunction is the same as the condition itself. Empty\n // conjunctions, on the other hand, are meaningful: an empty 'and' is always\n // true and an empty 'or' is always false.\n if (conditions.length === 1) {\n return conditions[0];\n }\n conditions.sort(cmpCondition);\n const normalized: Condition = {type: cond.type, conditions};\n normalizedConditions.add(normalized);\n return normalized;\n}\n\n/**\n * Maps the table and column names of `ast`. The result is not a\n * {@link NormalizedAST} even if `ast` was normalized: the names it sorts by\n * are the ones that changed.\n */\nexport function mapAST(ast: AST, mapper: NameMapper) {\n return transformAST(ast, {\n tableName: table => mapper.tableName(table),\n columnName: (table, col) => mapper.columnName(table, col),\n });\n}\n\nexport function mapCondition(\n cond: Condition,\n table: string,\n mapper: NameMapper,\n) {\n return transformWhere(cond, table, {\n tableName: table => mapper.tableName(table),\n columnName: (table, col) => mapper.columnName(table, col),\n });\n}\n\nfunction cmpCondition(a: Condition, b: Condition): number {\n if (a.type === 'simple') {\n if (b.type !== 'simple') {\n return -1; // Order SimpleConditions first\n }\n\n return (\n compareValuePosition(a.left, b.left) ||\n compareUTF8MaybeNull(a.op, b.op) ||\n compareValuePosition(a.right, b.right)\n );\n }\n\n if (b.type === 'simple') {\n return 1; // Order SimpleConditions first\n }\n\n if (a.type === 'correlatedSubquery') {\n if (b.type !== 'correlatedSubquery') {\n return -1; // Order subquery before conjuctions/disjuctions\n }\n return (\n cmpRelated(a.related, b.related) ||\n compareUTF8MaybeNull(a.op, b.op) ||\n cmpOptionalBool(a.flip, b.flip) ||\n cmpOptionalBool(a.scalar, b.scalar)\n );\n }\n if (b.type === 'correlatedSubquery') {\n return -1; // Order correlatedSubquery before conjuctions/disjuctions\n }\n\n const val = compareUTF8MaybeNull(a.type, b.type);\n if (val !== 0) {\n return val;\n }\n for (\n let l = 0, r = 0;\n l < a.conditions.length && r < b.conditions.length;\n l++, r++\n ) {\n const val = cmpCondition(a.conditions[l], b.conditions[r]);\n if (val !== 0) {\n return val;\n }\n }\n // prefixes first\n return a.conditions.length - b.conditions.length;\n}\n\nfunction compareValuePosition(a: ValuePosition, b: ValuePosition): number {\n if (a.type !== b.type) {\n return compareUTF8(a.type, b.type);\n }\n switch (a.type) {\n case 'literal':\n assert(b.type === 'literal', 'Expected literal type for comparison');\n return cmpLiteralValue(a.value, b.value);\n case 'column':\n assert(b.type === 'column', 'Expected column type for comparison');\n return compareUTF8(a.name, b.name);\n case 'static':\n assert(b.type === 'static', 'Expected static type for comparison');\n // A field is a string or a path of strings, which cmpLiteralValue()\n // tells apart.\n return (\n compareUTF8(a.anchor, b.anchor) || cmpLiteralValue(a.field, b.field)\n );\n }\n}\n\n// null < boolean < number < string < array. Ordering values of different\n// types by their string form would make distinct values compare equal (['a',\n// 'b'] and 'a,b', or 1 and '1'), which would leave their order up to the\n// order they were written in, and with it the hash of the query.\nconst LITERAL_VALUE_TYPES = ['object', 'boolean', 'number', 'string'];\n\nfunction literalValueType(value: LiteralValue): number {\n return Array.isArray(value)\n ? LITERAL_VALUE_TYPES.length\n : LITERAL_VALUE_TYPES.indexOf(typeof value);\n}\n\nfunction cmpLiteralValue(a: LiteralValue, b: LiteralValue): number {\n const type = literalValueType(a) - literalValueType(b);\n if (type !== 0) {\n return type;\n }\n\n if (Array.isArray(a)) {\n assert(Array.isArray(b), 'Expected array for comparison');\n for (let i = 0; i < a.length && i < b.length; i++) {\n const val = cmpLiteralValue(a[i], b[i]);\n if (val !== 0) {\n return val;\n }\n }\n // prefixes first\n return a.length - b.length;\n }\n\n switch (typeof a) {\n case 'string':\n assert(typeof b === 'string', 'Expected string for comparison');\n return compareUTF8(a, b);\n case 'number':\n assert(typeof b === 'number', 'Expected number for comparison');\n return a < b ? -1 : a > b ? 1 : 0;\n case 'boolean':\n assert(typeof b === 'boolean', 'Expected boolean for comparison');\n return Number(a) - Number(b);\n default:\n return 0; // null\n }\n}\n\nfunction cmpRelated(a: CorrelatedSubquery, b: CorrelatedSubquery): number {\n return compareUTF8(must(a.subquery.alias), must(b.subquery.alias));\n}\n\nfunction compareUTF8MaybeNull(a: string | null, b: string | null): number {\n if (a !== null && b !== null) {\n return compareUTF8(a, b);\n }\n if (b !== null) {\n return -1;\n }\n if (a !== null) {\n return 1;\n }\n return 0;\n}\n\nfunction cmpOptionalBool(\n a: boolean | undefined,\n b: boolean | undefined,\n): number {\n // undefined < false < true\n const toNum = (v: boolean | undefined) => (v === undefined ? 0 : v ? 2 : 1);\n return toNum(a) - toNum(b);\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { readonlyArray, valita_exports } from "../../shared/src/valita.js";
2
2
  import { jsonSchema } from "../../shared/src/json-schema.js";
3
- import { astSchema } from "./ast.js";
3
+ import { depthBoundedAstSchema } from "./ast.js";
4
4
  //#region ../zero-protocol/src/inspect-up.ts
5
5
  var inspectUpBase = valita_exports.object({ id: valita_exports.string() });
6
6
  var inspectQueriesUpBodySchema = inspectUpBase.extend({
@@ -21,9 +21,9 @@ var analyzeQueryOptionsSchema = valita_exports.object({
21
21
  var inspectAnalyzeQueryUpSchema = inspectUpBase.extend({
22
22
  op: valita_exports.literal("analyze-query"),
23
23
  /** @deprecated Use {@linkcode ast} instead */
24
- value: astSchema.optional(),
24
+ value: depthBoundedAstSchema.optional(),
25
25
  options: analyzeQueryOptionsSchema.optional(),
26
- ast: astSchema.optional(),
26
+ ast: depthBoundedAstSchema.optional(),
27
27
  name: valita_exports.string().optional(),
28
28
  args: readonlyArray(jsonSchema).optional()
29
29
  });
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-up.js","names":[],"sources":["../../../../zero-protocol/src/inspect-up.ts"],"sourcesContent":["import {jsonSchema} from '../../shared/src/json-schema.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {astSchema} from './ast.ts';\n\nconst inspectUpBase = v.object({\n id: v.string(),\n});\n\nconst inspectQueriesUpBodySchema = inspectUpBase.extend({\n op: v.literal('queries'),\n clientID: v.string().optional(),\n});\n\nexport type InspectQueriesUpBody = v.Infer<typeof inspectQueriesUpBodySchema>;\n\nconst inspectMetricsUpSchema = inspectUpBase.extend({\n op: v.literal('metrics'),\n});\n\nexport type InspectMetricsUpBody = v.Infer<typeof inspectMetricsUpSchema>;\n\nconst inspectVersionUpSchema = inspectUpBase.extend({\n op: v.literal('version'),\n});\n\nexport type InspectVersionUpBody = v.Infer<typeof inspectVersionUpSchema>;\n\nexport const inspectAuthenticateUpSchema = inspectUpBase.extend({\n op: v.literal('authenticate'),\n value: v.string(),\n});\n\nexport type InspectAuthenticateUpBody = v.Infer<\n typeof inspectAuthenticateUpSchema\n>;\n\nconst analyzeQueryOptionsSchema = v.object({\n vendedRows: v.boolean().optional(),\n syncedRows: v.boolean().optional(),\n joinPlans: v.boolean().optional(),\n});\n\nexport type AnalyzeQueryOptions = v.Infer<typeof analyzeQueryOptionsSchema>;\n\nexport const inspectAnalyzeQueryUpSchema = inspectUpBase.extend({\n op: v.literal('analyze-query'),\n /** @deprecated Use {@linkcode ast} instead */\n value: astSchema.optional(),\n options: analyzeQueryOptionsSchema.optional(),\n ast: astSchema.optional(),\n name: v.string().optional(),\n args: v.readonlyArray(jsonSchema).optional(),\n});\n\nconst unparsedInspectAnalyzeQueryUpSchema = inspectUpBase.extend({\n op: v.literal('analyze-query'),\n /** @deprecated Use {@linkcode ast} instead */\n value: v.unknown().optional(),\n options: analyzeQueryOptionsSchema.optional(),\n ast: v.unknown().optional(),\n name: v.string().optional(),\n args: v.readonlyArray(jsonSchema).optional(),\n});\n\nexport type InspectAnalyzeQueryUpBody = v.Infer<\n typeof inspectAnalyzeQueryUpSchema\n>;\n\nconst inspectUpBodySchema = v.union(\n inspectQueriesUpBodySchema,\n inspectMetricsUpSchema,\n inspectVersionUpSchema,\n inspectAuthenticateUpSchema,\n inspectAnalyzeQueryUpSchema,\n);\n\nexport const inspectUpMessageSchema = v.tuple([\n v.literal('inspect'),\n inspectUpBodySchema,\n]);\n\nconst unparsedInspectUpBodySchema = v.union(\n inspectQueriesUpBodySchema,\n inspectMetricsUpSchema,\n inspectVersionUpSchema,\n inspectAuthenticateUpSchema,\n unparsedInspectAnalyzeQueryUpSchema,\n);\n\nexport const unparsedInspectUpMessageSchema = v.tuple([\n v.literal('inspect'),\n unparsedInspectUpBodySchema,\n]);\n\nexport type InspectUpMessage = v.Infer<typeof inspectUpMessageSchema>;\n\nexport type InspectUpBody = v.Infer<typeof inspectUpBodySchema>;\n\nexport type UnparsedInspectUpMessage = v.Infer<\n typeof unparsedInspectUpMessageSchema\n>;\n\nexport type UnparsedInspectUpBody = v.Infer<typeof unparsedInspectUpBodySchema>;\n"],"mappings":";;;;AAIA,IAAM,gBAAgB,eAAE,OAAO,EAC7B,IAAI,eAAE,OAAO,EACf,CAAC;AAED,IAAM,6BAA6B,cAAc,OAAO;CACtD,IAAI,eAAE,QAAQ,SAAS;CACvB,UAAU,eAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AAID,IAAM,yBAAyB,cAAc,OAAO,EAClD,IAAI,eAAE,QAAQ,SAAS,EACzB,CAAC;AAID,IAAM,yBAAyB,cAAc,OAAO,EAClD,IAAI,eAAE,QAAQ,SAAS,EACzB,CAAC;AAID,IAAa,8BAA8B,cAAc,OAAO;CAC9D,IAAI,eAAE,QAAQ,cAAc;CAC5B,OAAO,eAAE,OAAO;AAClB,CAAC;AAMD,IAAM,4BAA4B,eAAE,OAAO;CACzC,YAAY,eAAE,QAAQ,EAAE,SAAS;CACjC,YAAY,eAAE,QAAQ,EAAE,SAAS;CACjC,WAAW,eAAE,QAAQ,EAAE,SAAS;AAClC,CAAC;AAID,IAAa,8BAA8B,cAAc,OAAO;CAC9D,IAAI,eAAE,QAAQ,eAAe;;CAE7B,OAAO,UAAU,SAAS;CAC1B,SAAS,0BAA0B,SAAS;CAC5C,KAAK,UAAU,SAAS;CACxB,MAAM,eAAE,OAAO,EAAE,SAAS;CAC1B,MAAM,cAAgB,UAAU,EAAE,SAAS;AAC7C,CAAC;AAED,IAAM,sCAAsC,cAAc,OAAO;CAC/D,IAAI,eAAE,QAAQ,eAAe;;CAE7B,OAAO,eAAE,QAAQ,EAAE,SAAS;CAC5B,SAAS,0BAA0B,SAAS;CAC5C,KAAK,eAAE,QAAQ,EAAE,SAAS;CAC1B,MAAM,eAAE,OAAO,EAAE,SAAS;CAC1B,MAAM,cAAgB,UAAU,EAAE,SAAS;AAC7C,CAAC;AAMD,IAAM,sBAAsB,eAAE,MAC5B,4BACA,wBACA,wBACA,6BACA,2BACF;AAEA,IAAa,yBAAyB,eAAE,MAAM,CAC5C,eAAE,QAAQ,SAAS,GACnB,mBACF,CAAC;AAED,IAAM,8BAA8B,eAAE,MACpC,4BACA,wBACA,wBACA,6BACA,mCACF;AAEA,IAAa,iCAAiC,eAAE,MAAM,CACpD,eAAE,QAAQ,SAAS,GACnB,2BACF,CAAC"}
1
+ {"version":3,"file":"inspect-up.js","names":[],"sources":["../../../../zero-protocol/src/inspect-up.ts"],"sourcesContent":["import {jsonSchema} from '../../shared/src/json-schema.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {depthBoundedAstSchema} from './ast.ts';\n\nconst inspectUpBase = v.object({\n id: v.string(),\n});\n\nconst inspectQueriesUpBodySchema = inspectUpBase.extend({\n op: v.literal('queries'),\n clientID: v.string().optional(),\n});\n\nexport type InspectQueriesUpBody = v.Infer<typeof inspectQueriesUpBodySchema>;\n\nconst inspectMetricsUpSchema = inspectUpBase.extend({\n op: v.literal('metrics'),\n});\n\nexport type InspectMetricsUpBody = v.Infer<typeof inspectMetricsUpSchema>;\n\nconst inspectVersionUpSchema = inspectUpBase.extend({\n op: v.literal('version'),\n});\n\nexport type InspectVersionUpBody = v.Infer<typeof inspectVersionUpSchema>;\n\nexport const inspectAuthenticateUpSchema = inspectUpBase.extend({\n op: v.literal('authenticate'),\n value: v.string(),\n});\n\nexport type InspectAuthenticateUpBody = v.Infer<\n typeof inspectAuthenticateUpSchema\n>;\n\nconst analyzeQueryOptionsSchema = v.object({\n vendedRows: v.boolean().optional(),\n syncedRows: v.boolean().optional(),\n joinPlans: v.boolean().optional(),\n});\n\nexport type AnalyzeQueryOptions = v.Infer<typeof analyzeQueryOptionsSchema>;\n\nexport const inspectAnalyzeQueryUpSchema = inspectUpBase.extend({\n op: v.literal('analyze-query'),\n /** @deprecated Use {@linkcode ast} instead */\n value: depthBoundedAstSchema.optional(),\n options: analyzeQueryOptionsSchema.optional(),\n ast: depthBoundedAstSchema.optional(),\n name: v.string().optional(),\n args: v.readonlyArray(jsonSchema).optional(),\n});\n\nconst unparsedInspectAnalyzeQueryUpSchema = inspectUpBase.extend({\n op: v.literal('analyze-query'),\n /** @deprecated Use {@linkcode ast} instead */\n value: v.unknown().optional(),\n options: analyzeQueryOptionsSchema.optional(),\n ast: v.unknown().optional(),\n name: v.string().optional(),\n args: v.readonlyArray(jsonSchema).optional(),\n});\n\nexport type InspectAnalyzeQueryUpBody = v.Infer<\n typeof inspectAnalyzeQueryUpSchema\n>;\n\nconst inspectUpBodySchema = v.union(\n inspectQueriesUpBodySchema,\n inspectMetricsUpSchema,\n inspectVersionUpSchema,\n inspectAuthenticateUpSchema,\n inspectAnalyzeQueryUpSchema,\n);\n\nexport const inspectUpMessageSchema = v.tuple([\n v.literal('inspect'),\n inspectUpBodySchema,\n]);\n\nconst unparsedInspectUpBodySchema = v.union(\n inspectQueriesUpBodySchema,\n inspectMetricsUpSchema,\n inspectVersionUpSchema,\n inspectAuthenticateUpSchema,\n unparsedInspectAnalyzeQueryUpSchema,\n);\n\nexport const unparsedInspectUpMessageSchema = v.tuple([\n v.literal('inspect'),\n unparsedInspectUpBodySchema,\n]);\n\nexport type InspectUpMessage = v.Infer<typeof inspectUpMessageSchema>;\n\nexport type InspectUpBody = v.Infer<typeof inspectUpBodySchema>;\n\nexport type UnparsedInspectUpMessage = v.Infer<\n typeof unparsedInspectUpMessageSchema\n>;\n\nexport type UnparsedInspectUpBody = v.Infer<typeof unparsedInspectUpBodySchema>;\n"],"mappings":";;;;AAIA,IAAM,gBAAgB,eAAE,OAAO,EAC7B,IAAI,eAAE,OAAO,EACf,CAAC;AAED,IAAM,6BAA6B,cAAc,OAAO;CACtD,IAAI,eAAE,QAAQ,SAAS;CACvB,UAAU,eAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AAID,IAAM,yBAAyB,cAAc,OAAO,EAClD,IAAI,eAAE,QAAQ,SAAS,EACzB,CAAC;AAID,IAAM,yBAAyB,cAAc,OAAO,EAClD,IAAI,eAAE,QAAQ,SAAS,EACzB,CAAC;AAID,IAAa,8BAA8B,cAAc,OAAO;CAC9D,IAAI,eAAE,QAAQ,cAAc;CAC5B,OAAO,eAAE,OAAO;AAClB,CAAC;AAMD,IAAM,4BAA4B,eAAE,OAAO;CACzC,YAAY,eAAE,QAAQ,EAAE,SAAS;CACjC,YAAY,eAAE,QAAQ,EAAE,SAAS;CACjC,WAAW,eAAE,QAAQ,EAAE,SAAS;AAClC,CAAC;AAID,IAAa,8BAA8B,cAAc,OAAO;CAC9D,IAAI,eAAE,QAAQ,eAAe;;CAE7B,OAAO,sBAAsB,SAAS;CACtC,SAAS,0BAA0B,SAAS;CAC5C,KAAK,sBAAsB,SAAS;CACpC,MAAM,eAAE,OAAO,EAAE,SAAS;CAC1B,MAAM,cAAgB,UAAU,EAAE,SAAS;AAC7C,CAAC;AAED,IAAM,sCAAsC,cAAc,OAAO;CAC/D,IAAI,eAAE,QAAQ,eAAe;;CAE7B,OAAO,eAAE,QAAQ,EAAE,SAAS;CAC5B,SAAS,0BAA0B,SAAS;CAC5C,KAAK,eAAE,QAAQ,EAAE,SAAS;CAC1B,MAAM,eAAE,OAAO,EAAE,SAAS;CAC1B,MAAM,cAAgB,UAAU,EAAE,SAAS;AAC7C,CAAC;AAMD,IAAM,sBAAsB,eAAE,MAC5B,4BACA,wBACA,wBACA,6BACA,2BACF;AAEA,IAAa,yBAAyB,eAAE,MAAM,CAC5C,eAAE,QAAQ,SAAS,GACnB,mBACF,CAAC;AAED,IAAM,8BAA8B,eAAE,MACpC,4BACA,wBACA,wBACA,6BACA,mCACF;AAEA,IAAa,iCAAiC,eAAE,MAAM,CACpD,eAAE,QAAQ,SAAS,GACnB,2BACF,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { readonly, valita_exports } from "../../shared/src/valita.js";
2
2
  import { jsonSchema } from "../../shared/src/json-schema.js";
3
- import { astSchema } from "./ast.js";
3
+ import { depthBoundedAstSchema } from "./ast.js";
4
4
  //#region ../zero-protocol/src/queries-patch.ts
5
5
  var putOpSchema = valita_exports.object({
6
6
  op: valita_exports.literal("put"),
@@ -8,7 +8,7 @@ var putOpSchema = valita_exports.object({
8
8
  ttl: valita_exports.number().optional()
9
9
  });
10
10
  var upPutOpSchema = putOpSchema.extend({
11
- ast: astSchema.optional(),
11
+ ast: depthBoundedAstSchema.optional(),
12
12
  name: valita_exports.string().optional(),
13
13
  args: readonly(valita_exports.array(jsonSchema)).optional()
14
14
  });
@@ -1 +1 @@
1
- {"version":3,"file":"queries-patch.js","names":[],"sources":["../../../../zero-protocol/src/queries-patch.ts"],"sourcesContent":["import {jsonSchema} from '../../shared/src/json-schema.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {astSchema} from './ast.ts';\n\nexport const putOpSchema = v.object({\n op: v.literal('put'),\n hash: v.string(),\n ttl: v.number().optional(),\n});\n\nexport const upPutOpSchema = putOpSchema.extend({\n // All fields are optional in this transitional period.\n // - ast is filled in for client queries\n // - name and args are filled in for custom queries\n ast: astSchema.optional(),\n name: v.string().optional(),\n args: v.readonly(v.array(jsonSchema)).optional(),\n});\n\nconst delOpSchema = v.object({\n op: v.literal('del'),\n hash: v.string(),\n});\n\nconst clearOpSchema = v.object({\n op: v.literal('clear'),\n});\n\nconst patchOpSchema = v.union(putOpSchema, delOpSchema, clearOpSchema);\nconst upPatchOpSchema = v.union(upPutOpSchema, delOpSchema, clearOpSchema);\n\nexport const queriesPatchSchema = v.array(patchOpSchema);\nexport const upQueriesPatchSchema = v.array(upPatchOpSchema);\n\nexport type QueriesPutOp = v.Infer<typeof putOpSchema>;\nexport type QueriesDelOp = v.Infer<typeof delOpSchema>;\nexport type QueriesClearOp = v.Infer<typeof clearOpSchema>;\nexport type QueriesPatchOp = v.Infer<typeof patchOpSchema>;\nexport type UpQueriesPatchOp = v.Infer<typeof upPatchOpSchema>;\nexport type QueriesPatch = v.Infer<typeof queriesPatchSchema>;\nexport type UpQueriesPatch = v.Infer<typeof upQueriesPatchSchema>;\n"],"mappings":";;;;AAIA,IAAa,cAAc,eAAE,OAAO;CAClC,IAAI,eAAE,QAAQ,KAAK;CACnB,MAAM,eAAE,OAAO;CACf,KAAK,eAAE,OAAO,EAAE,SAAS;AAC3B,CAAC;AAED,IAAa,gBAAgB,YAAY,OAAO;CAI9C,KAAK,UAAU,SAAS;CACxB,MAAM,eAAE,OAAO,EAAE,SAAS;CAC1B,MAAM,SAAW,eAAE,MAAM,UAAU,CAAC,EAAE,SAAS;AACjD,CAAC;AAED,IAAM,cAAc,eAAE,OAAO;CAC3B,IAAI,eAAE,QAAQ,KAAK;CACnB,MAAM,eAAE,OAAO;AACjB,CAAC;AAED,IAAM,gBAAgB,eAAE,OAAO,EAC7B,IAAI,eAAE,QAAQ,OAAO,EACvB,CAAC;AAED,IAAM,gBAAgB,eAAE,MAAM,aAAa,aAAa,aAAa;AACrE,IAAM,kBAAkB,eAAE,MAAM,eAAe,aAAa,aAAa;AAEzE,IAAa,qBAAqB,eAAE,MAAM,aAAa;AACvD,IAAa,uBAAuB,eAAE,MAAM,eAAe"}
1
+ {"version":3,"file":"queries-patch.js","names":[],"sources":["../../../../zero-protocol/src/queries-patch.ts"],"sourcesContent":["import {jsonSchema} from '../../shared/src/json-schema.ts';\nimport * as v from '../../shared/src/valita.ts';\nimport {depthBoundedAstSchema} from './ast.ts';\n\nexport const putOpSchema = v.object({\n op: v.literal('put'),\n hash: v.string(),\n ttl: v.number().optional(),\n});\n\nexport const upPutOpSchema = putOpSchema.extend({\n // All fields are optional in this transitional period.\n // - ast is filled in for client queries\n // - name and args are filled in for custom queries\n ast: depthBoundedAstSchema.optional(),\n name: v.string().optional(),\n args: v.readonly(v.array(jsonSchema)).optional(),\n});\n\nconst delOpSchema = v.object({\n op: v.literal('del'),\n hash: v.string(),\n});\n\nconst clearOpSchema = v.object({\n op: v.literal('clear'),\n});\n\nconst patchOpSchema = v.union(putOpSchema, delOpSchema, clearOpSchema);\nconst upPatchOpSchema = v.union(upPutOpSchema, delOpSchema, clearOpSchema);\n\nexport const queriesPatchSchema = v.array(patchOpSchema);\nexport const upQueriesPatchSchema = v.array(upPatchOpSchema);\n\nexport type QueriesPutOp = v.Infer<typeof putOpSchema>;\nexport type QueriesDelOp = v.Infer<typeof delOpSchema>;\nexport type QueriesClearOp = v.Infer<typeof clearOpSchema>;\nexport type QueriesPatchOp = v.Infer<typeof patchOpSchema>;\nexport type UpQueriesPatchOp = v.Infer<typeof upPatchOpSchema>;\nexport type QueriesPatch = v.Infer<typeof queriesPatchSchema>;\nexport type UpQueriesPatch = v.Infer<typeof upQueriesPatchSchema>;\n"],"mappings":";;;;AAIA,IAAa,cAAc,eAAE,OAAO;CAClC,IAAI,eAAE,QAAQ,KAAK;CACnB,MAAM,eAAE,OAAO;CACf,KAAK,eAAE,OAAO,EAAE,SAAS;AAC3B,CAAC;AAED,IAAa,gBAAgB,YAAY,OAAO;CAI9C,KAAK,sBAAsB,SAAS;CACpC,MAAM,eAAE,OAAO,EAAE,SAAS;CAC1B,MAAM,SAAW,eAAE,MAAM,UAAU,CAAC,EAAE,SAAS;AACjD,CAAC;AAED,IAAM,cAAc,eAAE,OAAO;CAC3B,IAAI,eAAE,QAAQ,KAAK;CACnB,MAAM,eAAE,OAAO;AACjB,CAAC;AAED,IAAM,gBAAgB,eAAE,OAAO,EAC7B,IAAI,eAAE,QAAQ,OAAO,EACvB,CAAC;AAED,IAAM,gBAAgB,eAAE,MAAM,aAAa,aAAa,aAAa;AACrE,IAAM,kBAAkB,eAAE,MAAM,eAAe,aAAa,aAAa;AAEzE,IAAa,qBAAqB,eAAE,MAAM,aAAa;AACvD,IAAa,uBAAuB,eAAE,MAAM,eAAe"}
@@ -1,6 +1,6 @@
1
+ import { deepMerge, isPlainObject } from "../../../shared/src/deep-merge.js";
1
2
  import { must } from "../../../shared/src/must.js";
2
3
  import { asQueryInternals } from "./query-internals.js";
3
- import { deepMerge, isPlainObject } from "../../../shared/src/deep-merge.js";
4
4
  import { getValueAtPath } from "../../../shared/src/object-traversal.js";
5
5
  import { validateInput } from "./validate-input.js";
6
6
  //#region ../zql/src/query/query-registry.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocicorp/zero",
3
- "version": "1.11.0-canary.37",
3
+ "version": "1.11.0-canary.38",
4
4
  "description": "Zero is a web framework for serverless web development.",
5
5
  "homepage": "https://zero.rocicorp.dev",
6
6
  "bugs": {