cvx-kit 0.1.20 → 0.1.21

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.
Files changed (79) hide show
  1. package/README.md +40 -2
  2. package/dist/errors.d.mts +3 -2
  3. package/dist/errors.mjs +1 -1
  4. package/dist/errors.mjs.map +1 -1
  5. package/dist/filters.d.mts +4 -0
  6. package/dist/filters.mjs +1 -0
  7. package/dist/index.d.mts +3 -3
  8. package/dist/modules/contracts/errors.d.mts +218 -0
  9. package/dist/modules/contracts/errors.mjs +1 -1
  10. package/dist/modules/contracts/errors.mjs.map +1 -1
  11. package/dist/modules/effect/crud.d.mts +28 -0
  12. package/dist/querying/cursors.d.mts +30 -4
  13. package/dist/querying/cursors.mjs +1 -1
  14. package/dist/querying/cursors.mjs.map +1 -1
  15. package/dist/querying/execution.d.mts +14 -3
  16. package/dist/querying/execution.mjs +1 -1
  17. package/dist/querying/execution.mjs.map +1 -1
  18. package/dist/querying/failures.d.mts +13 -0
  19. package/dist/querying/failures.mjs +2 -0
  20. package/dist/querying/failures.mjs.map +1 -0
  21. package/dist/querying/filters.d.mts +39 -45
  22. package/dist/querying/filters.mjs +1 -1
  23. package/dist/querying/filters.mjs.map +1 -1
  24. package/dist/querying/planner.d.mts +11 -5
  25. package/dist/querying/planner.mjs +1 -1
  26. package/dist/querying/planner.mjs.map +1 -1
  27. package/dist/querying/relationships.d.mts +21 -4
  28. package/dist/querying/relationships.mjs +1 -1
  29. package/dist/querying/relationships.mjs.map +1 -1
  30. package/dist/querying/schema-snapshot.mjs +1 -1
  31. package/dist/querying/schema-snapshot.mjs.map +1 -1
  32. package/dist/querying/search.d.mts +69 -0
  33. package/dist/querying/search.mjs +2 -0
  34. package/dist/querying/search.mjs.map +1 -0
  35. package/dist/querying/security.d.mts +19 -2
  36. package/dist/querying/security.mjs +1 -1
  37. package/dist/querying/security.mjs.map +1 -1
  38. package/dist/querying/shared/ast.d.mts +28 -0
  39. package/dist/querying/shared/ast.mjs +2 -0
  40. package/dist/querying/shared/ast.mjs.map +1 -0
  41. package/dist/querying/shared/contract.d.mts +104 -0
  42. package/dist/querying/shared/contract.mjs +2 -0
  43. package/dist/querying/shared/contract.mjs.map +1 -0
  44. package/dist/querying/shared/evaluate.d.mts +7 -0
  45. package/dist/querying/shared/evaluate.mjs +2 -0
  46. package/dist/querying/shared/evaluate.mjs.map +1 -0
  47. package/dist/querying/shared/filters.d.mts +31 -0
  48. package/dist/querying/shared/filters.mjs +2 -0
  49. package/dist/querying/shared/filters.mjs.map +1 -0
  50. package/dist/querying.d.mts +47 -16
  51. package/dist/querying.mjs +1 -1
  52. package/dist/querying.mjs.map +1 -1
  53. package/dist/react/failures.d.mts +23 -0
  54. package/dist/react/failures.mjs +2 -0
  55. package/dist/react/failures.mjs.map +1 -0
  56. package/dist/react/optimistic.d.mts +47 -0
  57. package/dist/react/optimistic.mjs +2 -0
  58. package/dist/react/optimistic.mjs.map +1 -0
  59. package/dist/react/pagination-state.d.mts +40 -0
  60. package/dist/react/pagination-state.mjs +2 -0
  61. package/dist/react/pagination-state.mjs.map +1 -0
  62. package/dist/react/use-command.d.mts +23 -0
  63. package/dist/react/use-command.mjs +2 -0
  64. package/dist/react/use-command.mjs.map +1 -0
  65. package/dist/react/use-paginated-list.d.mts +32 -0
  66. package/dist/react/use-paginated-list.mjs +2 -0
  67. package/dist/react/use-paginated-list.mjs.map +1 -0
  68. package/dist/react.d.mts +6 -0
  69. package/dist/react.mjs +1 -0
  70. package/dist/relations-public.d.mts +2 -2
  71. package/dist/relations.d.mts +62 -7
  72. package/dist/relations.mjs +1 -1
  73. package/dist/relations.mjs.map +1 -1
  74. package/dist/zod-convex.mjs +1 -1
  75. package/dist/zod-convex.mjs.map +1 -1
  76. package/dist/zod-table.d.mts +15 -1
  77. package/dist/zod-table.mjs +1 -1
  78. package/dist/zod-table.mjs.map +1 -1
  79. package/package.json +21 -4
@@ -1 +1 @@
1
- {"version":3,"file":"cursors.mjs","names":["CursorError","CursorConfigurationError","bounds","maxPlaintextBytes","encoder","decoder","identifier","createEnvironmentCursorCodec","encoded","currentKeyId","parsed","createCursorCodec","id","key","hexToBytes","version","keys","config","entries","raw","payload","cipher","aessiv","aad","binding","bytesToHex","token","parts","keyId","plaintext","json","checkDescriptors","ancestors","nodes","visit","depth","current","array","names","name","descriptor","value","field","table","principal","policyVersion","engineVersion","registryVersion","order","part","canonicalConvexBytes"],"sources":["../../src/querying/cursors.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-runtime-typeof, anti-slop/no-unknown-parameters -- Cursor transport and canonical values are explicit validation boundaries. */\nimport { aessiv } from '@noble/ciphers/aes.js'\nimport { bytesToHex, hexToBytes } from '@noble/ciphers/utils.js'\nimport type { Value } from 'convex/values'\nimport { canonicalConvexBytes } from '../modules/contracts/idempotency'\n\n/** Private engine contract. Bindings must come from trusted normalized engine state, never query args. */\nexport interface CursorBinding {\n\treadonly table: string\n\treadonly index?: string | null\n\treadonly order: 'asc' | 'desc'\n\treadonly clientFilters: Value\n\treadonly serverFilters: Value\n\treadonly relationPath: readonly string[]\n\treadonly parent?: string | null\n\treadonly principal: string\n\treadonly tenant?: string | null\n\treadonly policyVersion: string\n\treadonly engineVersion: string\n\treadonly registryVersion: string\n\t/** Deliberately excluded from authenticated identity. */\n\treadonly pageSize?: number\n}\nexport interface CursorCodecConfig {\n\treadonly version: string\n\treadonly currentKeyId: string\n\treadonly keys: Readonly<Record<string, Uint8Array>>\n}\nexport class CursorError extends Error {\n\treadonly _tag = 'CursorError'\n\treadonly code = 'invalid-cursor'\n\tconstructor() {\n\t\tsuper('Invalid cursor')\n\t\tthis.name = 'CursorError'\n\t}\n}\nexport class CursorConfigurationError extends Error {\n\treadonly _tag = 'CursorConfigurationError'\n\tconstructor() {\n\t\tsuper('Invalid cursor server configuration')\n\t\tthis.name = 'CursorConfigurationError'\n\t}\n}\n\nconst bounds = Object.freeze({\n\tmaxDepth: 24,\n\tmaxNodes: 2048,\n\tmaxBytes: 16384,\n\tmaxArrayLength: 512,\n\tmaxObjectFields: 128,\n})\nconst maxPlaintextBytes = 8192\n// JSON string encoding preserves even lone UTF-16 surrogates without lossy UTF-8 replacement.\nconst maxPayloadBytes = maxPlaintextBytes * 6 + 2\nconst maxCiphertextBytes = maxPayloadBytes + 16\nconst maxTokenLength = maxCiphertextBytes * 2 + 70\nconst encoder = new TextEncoder()\nconst decoder = new TextDecoder('utf-8', { fatal: true })\nconst identifier = /^[A-Za-z0-9_-]{1,32}$/\n\n/** Private lazy server configuration. Call only at the first pagination boundary. */\nexport function createEnvironmentCursorCodec() {\n\ttry {\n\t\tconst encoded = process.env.CVX_QUERY_CURSOR_KEYS_JSON\n\t\tconst currentKeyId = process.env.CVX_QUERY_CURSOR_CURRENT_KEY_ID\n\t\tif (!encoded || !currentKeyId) throw new CursorConfigurationError()\n\t\tconst parsed: unknown = JSON.parse(encoded)\n\t\tif (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))\n\t\t\tthrow new CursorConfigurationError()\n\t\tconst keys = Object.fromEntries(\n\t\t\tObject.entries(parsed).map(([id, key]) => {\n\t\t\t\tif (typeof key !== 'string' || !/^[0-9a-fA-F]{128}$/.test(key))\n\t\t\t\t\tthrow new CursorConfigurationError()\n\t\t\t\treturn [id, hexToBytes(key)]\n\t\t\t}),\n\t\t)\n\t\treturn createCursorCodec({ version: '1', currentKeyId, keys })\n\t} catch {\n\t\t// Parsing/runtime failures must never expose key material or environment values.\n\t\tthrow new CursorConfigurationError()\n\t}\n}\n\n/**\n * Deterministic RFC 5297 AES-SIV: equal plaintext and binding leak equality.\n * One navigation-boundary family permits native split/continue tokens in start/end\n * slots. Relation identity remains in the binding. No nonce/randomness or plaintext fallback. Opening is not authorization: the engine\n * must recheck current policy on every future request, including nested continuations.\n */\nexport function createCursorCodec(config: CursorCodecConfig) {\n\tlet version: string, currentKeyId: string\n\tconst keys = new Map<string, Uint8Array>()\n\ttry {\n\t\tversion = config.version\n\t\tcurrentKeyId = config.currentKeyId\n\t\tif (\n\t\t\ttypeof version !== 'string' ||\n\t\t\ttypeof currentKeyId !== 'string' ||\n\t\t\t!identifier.test(version) ||\n\t\t\t!identifier.test(currentKeyId)\n\t\t)\n\t\t\tthrow new CursorConfigurationError()\n\t\tconst entries = Object.entries(config.keys)\n\t\tif (!entries.length) throw new CursorConfigurationError()\n\t\tfor (const [id, key] of entries) {\n\t\t\tif (!identifier.test(id) || !(key instanceof Uint8Array) || key.byteLength !== 64)\n\t\t\t\tthrow new CursorConfigurationError()\n\t\t\tkeys.set(id, Uint8Array.from(key))\n\t\t}\n\t\tif (!keys.has(currentKeyId)) throw new CursorConfigurationError()\n\t} catch {\n\t\tthrow new CursorConfigurationError()\n\t}\n\treturn Object.freeze({\n\t\tseal(raw: string, binding: CursorBinding): string {\n\t\t\ttry {\n\t\t\t\tif (\n\t\t\t\t\ttypeof raw !== 'string' ||\n\t\t\t\t\traw.length > maxPlaintextBytes ||\n\t\t\t\t\tencoder.encode(raw).length > maxPlaintextBytes\n\t\t\t\t)\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\tconst payload = encoder.encode(JSON.stringify(raw))\n\t\t\t\tconst cipher = aessiv(keys.get(currentKeyId)!, aad(version, currentKeyId, binding))\n\t\t\t\treturn `pc.${version}.${currentKeyId}.${bytesToHex(cipher.encrypt(payload))}`\n\t\t\t} catch {\n\t\t\t\tthrow new CursorError()\n\t\t\t}\n\t\t},\n\t\topen(token: string, binding: CursorBinding): string {\n\t\t\ttry {\n\t\t\t\tif (typeof token !== 'string' || token.length > maxTokenLength) throw new CursorError()\n\t\t\t\tconst parts = token.split('.')\n\t\t\t\tif (\n\t\t\t\t\tparts.length !== 4 ||\n\t\t\t\t\tparts[0] !== 'pc' ||\n\t\t\t\t\tparts[1] !== version ||\n\t\t\t\t\t!identifier.test(parts[2]!)\n\t\t\t\t)\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\tconst keyId = parts[2]!,\n\t\t\t\t\tencoded = parts[3]!,\n\t\t\t\t\tkey = keys.get(keyId)\n\t\t\t\tif (\n\t\t\t\t\t!key ||\n\t\t\t\t\tencoded.length < 36 ||\n\t\t\t\t\tencoded.length > maxCiphertextBytes * 2 ||\n\t\t\t\t\tencoded.length % 2 ||\n\t\t\t\t\t!/^[0-9a-f]+$/.test(encoded)\n\t\t\t\t)\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\tconst cipher = aessiv(key, aad(version, keyId, binding))\n\t\t\t\tconst plaintext = cipher.decrypt(hexToBytes(encoded))\n\t\t\t\tif (plaintext.length > maxPayloadBytes) throw new CursorError()\n\t\t\t\tconst json = decoder.decode(plaintext)\n\t\t\t\tconst raw: unknown = JSON.parse(json)\n\t\t\t\tif (\n\t\t\t\t\ttypeof raw !== 'string' ||\n\t\t\t\t\traw.length > maxPlaintextBytes ||\n\t\t\t\t\tencoder.encode(raw).length > maxPlaintextBytes ||\n\t\t\t\t\tJSON.stringify(raw) !== json\n\t\t\t\t)\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\treturn raw\n\t\t\t} catch {\n\t\t\t\tthrow new CursorError()\n\t\t\t}\n\t\t},\n\t})\n}\n\n/** Reject accessor-bearing arrays/dictionaries before the shared canonical encoder reads values. */\nfunction checkDescriptors(value: unknown): void {\n\tconst ancestors = new Set<object>()\n\tlet nodes = 0\n\tfunction visit(current: unknown, depth: number): void {\n\t\tif (++nodes > bounds.maxNodes || depth > bounds.maxDepth) throw new CursorError()\n\t\tif (current === null || typeof current !== 'object' || current instanceof ArrayBuffer) return\n\t\tif (ancestors.has(current)) throw new CursorError()\n\t\tconst array = Array.isArray(current)\n\t\tif (array && Object.getPrototypeOf(current) !== Array.prototype) throw new CursorError()\n\t\tif (\n\t\t\t!array &&\n\t\t\tObject.getPrototypeOf(current) !== Object.prototype &&\n\t\t\tObject.getPrototypeOf(current) !== null\n\t\t)\n\t\t\tthrow new CursorError()\n\t\tif (Object.getOwnPropertySymbols(current).length) throw new CursorError()\n\t\tconst names = Object.getOwnPropertyNames(current)\n\t\tif (names.length > (array ? bounds.maxArrayLength + 1 : bounds.maxObjectFields))\n\t\t\tthrow new CursorError()\n\t\tancestors.add(current)\n\t\ttry {\n\t\t\tfor (const name of names) {\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(current, name)!\n\t\t\t\tif (!('value' in descriptor)) throw new CursorError()\n\t\t\t\tif (array && name === 'length') {\n\t\t\t\t\tif (descriptor.value > bounds.maxArrayLength) throw new CursorError()\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\t!descriptor.enumerable ||\n\t\t\t\t\t(array && (!/^(0|[1-9][0-9]*)$/.test(name) || Number(name) >= current.length))\n\t\t\t\t)\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\tvisit(descriptor.value, depth + 1)\n\t\t\t}\n\t\t} finally {\n\t\t\tancestors.delete(current)\n\t\t}\n\t}\n\tvisit(value, 0)\n}\nfunction aad(version: string, keyId: string, binding: CursorBinding): Uint8Array {\n\tcheckDescriptors(binding)\n\tif (binding.clientFilters === undefined || binding.serverFilters === undefined)\n\t\tthrow new CursorError()\n\tconst { table, order, principal, policyVersion, engineVersion, registryVersion } = binding\n\tfor (const field of [table, principal, policyVersion, engineVersion, registryVersion])\n\t\tif (typeof field !== 'string' || !field.length) throw new CursorError()\n\tif (order !== 'asc' && order !== 'desc') throw new CursorError()\n\tfor (const field of [binding.index, binding.parent, binding.tenant])\n\t\tif (field != null && typeof field !== 'string') throw new CursorError()\n\tif (\n\t\t!Array.isArray(binding.relationPath) ||\n\t\tbinding.relationPath.some((part) => typeof part !== 'string')\n\t)\n\t\tthrow new CursorError()\n\treturn encoder.encode(\n\t\tcanonicalConvexBytes(\n\t\t\t{\n\t\t\t\tdomain: 'cvx-query-cursor',\n\t\t\t\tversion,\n\t\t\t\tkeyId,\n\t\t\t\ttable,\n\t\t\t\tindex: binding.index ?? null,\n\t\t\t\torder,\n\t\t\t\tclientFilters: binding.clientFilters,\n\t\t\t\tserverFilters: binding.serverFilters,\n\t\t\t\trelationPath: binding.relationPath,\n\t\t\t\tparent: binding.parent ?? null,\n\t\t\t\tprincipal,\n\t\t\t\ttenant: binding.tenant ?? null,\n\t\t\t\tpolicyVersion,\n\t\t\t\tengineVersion,\n\t\t\t\tregistryVersion,\n\t\t\t},\n\t\t\tbounds,\n\t\t),\n\t)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cursors.mjs","names":["CursorError","CursorConfigurationError","bounds","maxPlaintextBytes","encoder","decoder","identifier","createEnvironmentCursorCodec","encoded","currentKeyId","parsed","createCursorCodec","id","key","hexToBytes","version","keys","config","entries","transport","raw","payload","cipher","aessiv","aad","binding","namespace","bytesToHex","token","parts","keyId","plaintext","json","createScopedCursorCodec","checkDescriptors","options","scope","jsonToValue","canonicalConvexBytes","parse","synchronousCursorParser","encode","value","validate","copies","active","attempts","synchronous","result","attempt","copy","args","z","descriptors","definition","Constructor","node","child","descriptor","getter","get","owned","schema","depth","item","jsonToConvex","ancestors","nodes","visit","current","array","names","name","field","table","principal","policyVersion","engineVersion","registryVersion","order","part"],"sources":["../../src/querying/cursors.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-runtime-typeof, anti-slop/no-unknown-parameters -- Cursor transport and canonical values are explicit validation boundaries. */\nimport { aessiv } from '@noble/ciphers/aes.js'\nimport { bytesToHex, hexToBytes } from '@noble/ciphers/utils.js'\nimport { jsonToConvex, type Value, type JSONValue } from 'convex/values'\nimport { z } from 'zod'\nimport type { ManagedScope } from './security'\nimport { canonicalConvexBytes } from '../modules/contracts/idempotency'\n\n/** Private engine contract. Bindings must come from trusted normalized engine state, never query args. */\nexport interface CursorBinding {\n\treadonly table: string\n\treadonly index?: string | null\n\treadonly order: 'asc' | 'desc'\n\treadonly clientFilters: Value\n\treadonly serverFilters: Value\n\treadonly relationPath: readonly string[]\n\treadonly parent?: string | null\n\treadonly principal: string\n\treadonly tenant?: string | null\n\treadonly policyVersion: string\n\treadonly engineVersion: string\n\treadonly registryVersion: string\n\t/** Deliberately excluded from authenticated identity. */\n\treadonly pageSize?: number\n}\nexport interface CursorCodecConfig {\n\treadonly version: string\n\treadonly currentKeyId: string\n\treadonly keys: Readonly<Record<string, Uint8Array>>\n}\nexport class CursorError extends Error {\n\treadonly _tag = 'CursorError'\n\treadonly code = 'invalid-cursor'\n\tconstructor() {\n\t\tsuper('Invalid cursor')\n\t\tthis.name = 'CursorError'\n\t}\n}\nexport class CursorConfigurationError extends Error {\n\treadonly _tag = 'CursorConfigurationError'\n\tconstructor() {\n\t\tsuper('Invalid cursor server configuration')\n\t\tthis.name = 'CursorConfigurationError'\n\t}\n}\n\nconst bounds = Object.freeze({\n\tmaxDepth: 24,\n\tmaxNodes: 2048,\n\tmaxBytes: 16384,\n\tmaxArrayLength: 512,\n\tmaxObjectFields: 128,\n})\nconst maxPlaintextBytes = 8192\n// JSON string encoding preserves even lone UTF-16 surrogates without lossy UTF-8 replacement.\nconst maxPayloadBytes = maxPlaintextBytes * 6 + 2\nconst maxCiphertextBytes = maxPayloadBytes + 16\nconst maxTokenLength = maxCiphertextBytes * 2 + 70\nconst encoder = new TextEncoder()\nconst decoder = new TextDecoder('utf-8', { fatal: true })\nconst identifier = /^[A-Za-z0-9_-]{1,32}$/\n\n/** Private lazy server configuration. Call only at the first pagination boundary. */\nexport function createEnvironmentCursorCodec() {\n\ttry {\n\t\tconst encoded = process.env.CVX_QUERY_CURSOR_KEYS_JSON\n\t\tconst currentKeyId = process.env.CVX_QUERY_CURSOR_CURRENT_KEY_ID\n\t\tif (!encoded || !currentKeyId) throw new CursorConfigurationError()\n\t\tconst parsed: unknown = JSON.parse(encoded)\n\t\tif (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))\n\t\t\tthrow new CursorConfigurationError()\n\t\tconst keys = Object.fromEntries(\n\t\t\tObject.entries(parsed).map(([id, key]) => {\n\t\t\t\tif (typeof key !== 'string' || !/^[0-9a-fA-F]{128}$/.test(key))\n\t\t\t\t\tthrow new CursorConfigurationError()\n\t\t\t\treturn [id, hexToBytes(key)]\n\t\t\t}),\n\t\t)\n\t\treturn createCursorCodec({ version: '1', currentKeyId, keys })\n\t} catch {\n\t\t// Parsing/runtime failures must never expose key material or environment values.\n\t\tthrow new CursorConfigurationError()\n\t}\n}\n\n/**\n * Deterministic RFC 5297 AES-SIV: equal plaintext and binding leak equality.\n * One navigation-boundary family permits native split/continue tokens in start/end\n * slots. Relation identity remains in the binding. No nonce/randomness or plaintext fallback. Opening is not authorization: the engine\n * must recheck current policy on every future request, including nested continuations.\n */\nexport function createCursorCodec(config: CursorCodecConfig) {\n\tlet version: string, currentKeyId: string\n\tconst keys = new Map<string, Uint8Array>()\n\ttry {\n\t\tversion = config.version\n\t\tcurrentKeyId = config.currentKeyId\n\t\tif (\n\t\t\ttypeof version !== 'string' ||\n\t\t\ttypeof currentKeyId !== 'string' ||\n\t\t\t!identifier.test(version) ||\n\t\t\t!identifier.test(currentKeyId)\n\t\t)\n\t\t\tthrow new CursorConfigurationError()\n\t\tconst entries = Object.entries(config.keys)\n\t\tif (!entries.length) throw new CursorConfigurationError()\n\t\tfor (const [id, key] of entries) {\n\t\t\tif (!identifier.test(id) || !(key instanceof Uint8Array) || key.byteLength !== 64)\n\t\t\t\tthrow new CursorConfigurationError()\n\t\t\tkeys.set(id, Uint8Array.from(key))\n\t\t}\n\t\tif (!keys.has(currentKeyId)) throw new CursorConfigurationError()\n\t} catch {\n\t\tthrow new CursorConfigurationError()\n\t}\n\tfunction transport(namespace: 'pc' | 'cc') {\n\t\treturn Object.freeze({\n\t\t\tseal(raw: string, binding: CursorBinding): string {\n\t\t\t\ttry {\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof raw !== 'string' ||\n\t\t\t\t\t\traw.length > maxPlaintextBytes ||\n\t\t\t\t\t\tencoder.encode(raw).length > maxPlaintextBytes\n\t\t\t\t\t)\n\t\t\t\t\t\tthrow new CursorError()\n\t\t\t\t\tconst payload = encoder.encode(JSON.stringify(raw))\n\t\t\t\t\tconst cipher = aessiv(\n\t\t\t\t\t\tkeys.get(currentKeyId)!,\n\t\t\t\t\t\taad(version, currentKeyId, binding, namespace),\n\t\t\t\t\t)\n\t\t\t\t\treturn `${namespace}.${version}.${currentKeyId}.${bytesToHex(cipher.encrypt(payload))}`\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\t}\n\t\t\t},\n\t\t\topen(token: string, binding: CursorBinding): string {\n\t\t\t\ttry {\n\t\t\t\t\tif (typeof token !== 'string' || token.length > maxTokenLength) throw new CursorError()\n\t\t\t\t\tconst parts = token.split('.')\n\t\t\t\t\tif (\n\t\t\t\t\t\tparts.length !== 4 ||\n\t\t\t\t\t\tparts[0] !== namespace ||\n\t\t\t\t\t\tparts[1] !== version ||\n\t\t\t\t\t\t!identifier.test(parts[2]!)\n\t\t\t\t\t)\n\t\t\t\t\t\tthrow new CursorError()\n\t\t\t\t\tconst keyId = parts[2]!,\n\t\t\t\t\t\tencoded = parts[3]!,\n\t\t\t\t\t\tkey = keys.get(keyId)\n\t\t\t\t\tif (\n\t\t\t\t\t\t!key ||\n\t\t\t\t\t\tencoded.length < 36 ||\n\t\t\t\t\t\tencoded.length > maxCiphertextBytes * 2 ||\n\t\t\t\t\t\tencoded.length % 2 ||\n\t\t\t\t\t\t!/^[0-9a-f]+$/.test(encoded)\n\t\t\t\t\t)\n\t\t\t\t\t\tthrow new CursorError()\n\t\t\t\t\tconst cipher = aessiv(key, aad(version, keyId, binding, namespace))\n\t\t\t\t\tconst plaintext = cipher.decrypt(hexToBytes(encoded))\n\t\t\t\t\tif (plaintext.length > maxPayloadBytes) throw new CursorError()\n\t\t\t\t\tconst json = decoder.decode(plaintext)\n\t\t\t\t\tconst raw: unknown = JSON.parse(json)\n\t\t\t\t\tif (\n\t\t\t\t\t\ttypeof raw !== 'string' ||\n\t\t\t\t\t\traw.length > maxPlaintextBytes ||\n\t\t\t\t\t\tencoder.encode(raw).length > maxPlaintextBytes ||\n\t\t\t\t\t\tJSON.stringify(raw) !== json\n\t\t\t\t\t)\n\t\t\t\t\t\tthrow new CursorError()\n\t\t\t\t\treturn raw\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t}\n\treturn Object.freeze({ ...transport('pc'), custom: transport('cc') })\n}\n\n/** Server-derived binding supplements managed scope; opening never grants row access. */\nexport interface ScopedCursorOptions<S extends z.ZodType<Value>> {\n\treadonly domain: string\n\treadonly bind: Value\n\t/** Synchronous schema, applied on seal AND open. Outputs must be bounded Convex values. */\n\treadonly schema: S\n}\n/** Integrity only: consumers must recheck current authorization on every request. */\nexport interface ScopedCursorCodec<S extends z.ZodType<Value>> {\n\tseal(payload: z.input<S>): string\n\topen(token: string): z.output<S>\n}\n\n/** Internal construction uses the configured engine's already captured key ring. */\nexport function createScopedCursorCodec<S extends z.ZodType<Value>>(\n\ttransport: ReturnType<typeof createCursorCodec>['custom'],\n\tscope: ManagedScope & { readonly policyVersion: string },\n\toptions: ScopedCursorOptions<S>,\n): ScopedCursorCodec<S> {\n\ttry {\n\t\tcheckDescriptors(options.bind)\n\t\tif (typeof options.domain !== 'string' || !options.domain.length || options.domain.length > 256)\n\t\t\tthrow new CursorError()\n\t\t// Snapshot bind bytes before returning: later caller mutation cannot change identity.\n\t\tconst binding: CursorBinding = {\n\t\t\ttable: options.domain,\n\t\t\torder: 'asc',\n\t\t\tprincipal: 'custom',\n\t\t\tpolicyVersion: scope.policyVersion,\n\t\t\tengineVersion: 'custom-1',\n\t\t\tregistryVersion: 'custom-1',\n\t\t\trelationPath: [],\n\t\t\tclientFilters: jsonToValue(JSON.parse(canonicalConvexBytes(options.bind, bounds))),\n\t\t\tserverFilters: { ...scope },\n\t\t}\n\t\t// Validate the combined identity even before any seal/open call.\n\t\taad('1', 'validation', binding, 'cc')\n\t\tconst parse = synchronousCursorParser(options.schema)\n\t\tfunction encode(value: unknown): string {\n\t\t\tcheckDescriptors(value)\n\t\t\treturn canonicalConvexBytes(value, { ...bounds, maxBytes: maxPlaintextBytes })\n\t\t}\n\t\tfunction validate(value: unknown): z.output<S> {\n\t\t\tencode(value)\n\t\t\tconst parsed = parse(value)\n\t\t\tencode(parsed)\n\t\t\treturn parsed\n\t\t}\n\t\treturn Object.freeze({\n\t\t\tseal(payload: z.input<S>): string {\n\t\t\t\ttry {\n\t\t\t\t\t// Validate output too, but retain input bytes so open applies transforms once.\n\t\t\t\t\tvalidate(payload)\n\t\t\t\t\treturn transport.seal(encode(payload), binding)\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\t}\n\t\t\t},\n\t\t\topen(token: string): z.output<S> {\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = transport.open(token, binding)\n\t\t\t\t\tconst value = jsonToValue(JSON.parse(raw))\n\t\t\t\t\tif (encode(value) !== raw) throw new CursorError()\n\t\t\t\t\treturn validate(value)\n\t\t\t\t} catch {\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t} catch {\n\t\tthrow new CursorError()\n\t}\n}\n\n/**\n * Zod's sync parser throws AFTER starting async callbacks, losing their promises.\n * Rebuild an owned graph so callback results are contained before Zod sees them.\n * Uses Zod 4's definition/constructor seam (also used by its clone utility).\n */\n/* oxlint-disable anti-slop/no-unknown-returns, anti-slop/no-known-value-widening -- The private walker preserves heterogeneous Zod definitions and callback results until their installed constructor restores the schema contract. */\nfunction synchronousCursorParser<S extends z.ZodType>(schema: S): (value: unknown) => z.output<S> {\n\tconst copies = new WeakMap<object, unknown>()\n\tconst active = new WeakSet<object>()\n\tconst attempts = new Set<{ asynchronous: boolean }>()\n\tfunction synchronous(result: unknown): unknown {\n\t\tif (\n\t\t\tresult !== null &&\n\t\t\t(typeof result === 'object' || typeof result === 'function') &&\n\t\t\t'then' in result &&\n\t\t\ttypeof result.then === 'function'\n\t\t) {\n\t\t\tfor (const attempt of attempts) attempt.asynchronous = true\n\t\t\t// Attach before throwing, including foreign promises and ordinary functions\n\t\t\t// returning promises. Never propagate the callback's rejection details.\n\t\t\tvoid Promise.resolve(result).catch(() => {})\n\t\t\tthrow new CursorError()\n\t\t}\n\t\treturn result\n\t}\n\tfunction copy(value: unknown): unknown {\n\t\tif (typeof value === 'function') {\n\t\t\treturn function (this: unknown, ...args: unknown[]) {\n\t\t\t\tconst result = synchronous(value.apply(this, args))\n\t\t\t\t// Lazy schemas resolve at parse time; their children need the same boundary.\n\t\t\t\treturn result instanceof z.core.$ZodType ? copy(result) : result\n\t\t\t}\n\t\t}\n\t\tif (value === null || typeof value !== 'object') return value\n\t\tif (copies.has(value)) return copies.get(value)\n\t\tif (active.has(value)) throw new CursorError()\n\t\tactive.add(value)\n\t\tlet result: unknown\n\t\tif (value instanceof z.core.$ZodType || value instanceof z.core.$ZodCheck) {\n\t\t\tconst descriptors = Object.getOwnPropertyDescriptors(value._zod.def)\n\t\t\t// A previously parsed lazy schema caches its resolved graph here. Rebuild\n\t\t\t// it through the guarded getter so recursive references resolve to our copy.\n\t\t\tif ('type' in value._zod.def && value._zod.def.type === 'lazy')\n\t\t\t\tdelete descriptors._cachedInner\n\t\t\tconst definition = copy(Object.create(Object.getPrototypeOf(value._zod.def), descriptors))\n\t\t\t// Zod's check typings omit constr, but $constructor installs it on both\n\t\t\t// checks and schemas in the supported Zod 4 peers.\n\t\t\t// SAFETY: the installed constructor reconstructs the same schema/check kind.\n\t\t\tconst Constructor = (\n\t\t\t\tvalue._zod as {\n\t\t\t\t\tconstr: new (definition: unknown) => z.core.$ZodType | z.core.$ZodCheck\n\t\t\t\t}\n\t\t\t).constr\n\t\t\tconst node = new Constructor(definition)\n\t\t\tif (node instanceof z.core.$ZodType && node._zod.def.type === 'promise') {\n\t\t\t\t// Promise schemas are intrinsically async, even with a synchronous child.\n\t\t\t\t// Reject before Zod schedules that child outside this sync boundary.\n\t\t\t\tnode._zod.parse = node._zod.run = () => {\n\t\t\t\t\tfor (const attempt of attempts) attempt.asynchronous = true\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (\n\t\t\t\tvalue instanceof z.core.$ZodCheck &&\n\t\t\t\tvalue._zod.def.check === 'custom' &&\n\t\t\t\t!('type' in value._zod.def)\n\t\t\t) {\n\t\t\t\tif (!(node instanceof z.core.$ZodCheck)) throw new CursorError()\n\t\t\t\t// superRefine/check store their callback on the node, not in its definition.\n\t\t\t\t// SAFETY: copy wraps the original callback without changing its arguments or sync result.\n\t\t\t\tnode._zod.check = copy(value._zod.check) as typeof value._zod.check\n\t\t\t}\n\t\t\tresult = node\n\t\t} else if (Array.isArray(value)) {\n\t\t\tresult = value.map((child) => copy(child))\n\t\t} else if (\n\t\t\tObject.getPrototypeOf(value) === Object.prototype ||\n\t\t\tObject.getPrototypeOf(value) === null\n\t\t) {\n\t\t\t// Defaults/prefaults use getters to invoke callbacks per parse. Keep them\n\t\t\t// lazy, while guarding their results just like definition callbacks.\n\t\t\tconst descriptors = Object.getOwnPropertyDescriptors(value)\n\t\t\tfor (const descriptor of Object.values(descriptors)) {\n\t\t\t\tif ('value' in descriptor) descriptor.value = copy(descriptor.value)\n\t\t\t\telse if (descriptor.get) {\n\t\t\t\t\tconst getter = descriptor.get\n\t\t\t\t\tconst get = () => copy(synchronous(getter.call(value)))\n\t\t\t\t\t// Zod object constructors reuse the raw shape behind this getter.\n\t\t\t\t\tif ('raw' in getter) Object.assign(get, { raw: copy(getter.raw) })\n\t\t\t\t\tdescriptor.get = get\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult = Object.create(Object.getPrototypeOf(value), descriptors)\n\t\t} else {\n\t\t\t// RegExp and other literal definition values are not parser nodes.\n\t\t\tresult = value\n\t\t}\n\t\tactive.delete(value)\n\t\tcopies.set(value, result)\n\t\treturn result\n\t}\n\t// SAFETY: reconstruction preserves the root schema's input/output contract.\n\tconst owned = copy(schema) as S\n\treturn (value) => {\n\t\tconst attempt = { asynchronous: false }\n\t\tattempts.add(attempt)\n\t\ttry {\n\t\t\tconst parsed = owned.parse(value)\n\t\t\t// A catch/fallback schema may swallow the thrown boundary error.\n\t\t\tif (attempt.asynchronous) throw new CursorError()\n\t\t\treturn parsed\n\t\t} finally {\n\t\t\tattempts.delete(attempt)\n\t\t}\n\t}\n}\n/* oxlint-enable anti-slop/no-unknown-returns, anti-slop/no-known-value-widening */\n\n/** Preserve own __proto__ fields; SDK scalar conversion handles integer/binary/float tags. */\nfunction jsonToValue(value: JSONValue, depth = 0): Value {\n\tif (depth > bounds.maxDepth) throw new CursorError()\n\tif (Array.isArray(value)) return value.map((item) => jsonToValue(item, depth + 1))\n\tif (value !== null && typeof value === 'object') {\n\t\tconst entries = Object.entries(value)\n\t\tif (entries.some(([key]) => key.startsWith('$'))) return jsonToConvex(value)\n\t\treturn Object.fromEntries(entries.map(([key, item]) => [key, jsonToValue(item, depth + 1)]))\n\t}\n\treturn jsonToConvex(value)\n}\n\n/** Reject accessor-bearing arrays/dictionaries before the shared canonical encoder reads values. */\nfunction checkDescriptors(value: unknown): void {\n\tconst ancestors = new Set<object>()\n\tlet nodes = 0\n\tfunction visit(current: unknown, depth: number): void {\n\t\tif (++nodes > bounds.maxNodes || depth > bounds.maxDepth) throw new CursorError()\n\t\tif (current === null || typeof current !== 'object') return\n\t\tif (current instanceof ArrayBuffer) {\n\t\t\tif (\n\t\t\t\tObject.getPrototypeOf(current) !== ArrayBuffer.prototype ||\n\t\t\t\tObject.getOwnPropertyNames(current).length ||\n\t\t\t\tObject.getOwnPropertySymbols(current).length\n\t\t\t)\n\t\t\t\tthrow new CursorError()\n\t\t\treturn\n\t\t}\n\t\tif (ancestors.has(current)) throw new CursorError()\n\t\tconst array = Array.isArray(current)\n\t\tif (array && Object.getPrototypeOf(current) !== Array.prototype) throw new CursorError()\n\t\tif (\n\t\t\t!array &&\n\t\t\tObject.getPrototypeOf(current) !== Object.prototype &&\n\t\t\tObject.getPrototypeOf(current) !== null\n\t\t)\n\t\t\tthrow new CursorError()\n\t\tif (Object.getOwnPropertySymbols(current).length) throw new CursorError()\n\t\tconst names = Object.getOwnPropertyNames(current)\n\t\tif (names.length > (array ? bounds.maxArrayLength + 1 : bounds.maxObjectFields))\n\t\t\tthrow new CursorError()\n\t\tancestors.add(current)\n\t\ttry {\n\t\t\tfor (const name of names) {\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(current, name)!\n\t\t\t\tif (!('value' in descriptor)) throw new CursorError()\n\t\t\t\tif (array && name === 'length') {\n\t\t\t\t\tif (descriptor.value > bounds.maxArrayLength) throw new CursorError()\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\t!descriptor.enumerable ||\n\t\t\t\t\t(array && (!/^(0|[1-9][0-9]*)$/.test(name) || Number(name) >= current.length))\n\t\t\t\t)\n\t\t\t\t\tthrow new CursorError()\n\t\t\t\tvisit(descriptor.value, depth + 1)\n\t\t\t}\n\t\t} finally {\n\t\t\tancestors.delete(current)\n\t\t}\n\t}\n\tvisit(value, 0)\n}\nfunction aad(\n\tversion: string,\n\tkeyId: string,\n\tbinding: CursorBinding,\n\tnamespace: 'pc' | 'cc',\n): Uint8Array {\n\tcheckDescriptors(binding)\n\tif (binding.clientFilters === undefined || binding.serverFilters === undefined)\n\t\tthrow new CursorError()\n\tconst { table, order, principal, policyVersion, engineVersion, registryVersion } = binding\n\tfor (const field of [table, principal, policyVersion, engineVersion, registryVersion])\n\t\tif (typeof field !== 'string' || !field.length) throw new CursorError()\n\tif (order !== 'asc' && order !== 'desc') throw new CursorError()\n\tfor (const field of [binding.index, binding.parent, binding.tenant])\n\t\tif (field != null && typeof field !== 'string') throw new CursorError()\n\tif (\n\t\t!Array.isArray(binding.relationPath) ||\n\t\tbinding.relationPath.some((part) => typeof part !== 'string')\n\t)\n\t\tthrow new CursorError()\n\treturn encoder.encode(\n\t\tcanonicalConvexBytes(\n\t\t\t{\n\t\t\t\tdomain: namespace === 'pc' ? 'cvx-query-cursor' : 'cvx-custom-cursor',\n\t\t\t\tversion,\n\t\t\t\tkeyId,\n\t\t\t\ttable,\n\t\t\t\tindex: binding.index ?? null,\n\t\t\t\torder,\n\t\t\t\tclientFilters: binding.clientFilters,\n\t\t\t\tserverFilters: binding.serverFilters,\n\t\t\t\trelationPath: binding.relationPath,\n\t\t\t\tparent: binding.parent ?? null,\n\t\t\t\tprincipal,\n\t\t\t\ttenant: binding.tenant ?? null,\n\t\t\t\tpolicyVersion,\n\t\t\t\tengineVersion,\n\t\t\t\tregistryVersion,\n\t\t\t},\n\t\t\tbounds,\n\t\t),\n\t)\n}\n"],"mappings":"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"}
@@ -1,8 +1,10 @@
1
+ import { FilterScalar } from "./shared/ast.mjs";
2
+ import { NativePagination, NativeRange } from "./filters.mjs";
3
+ import { PageCompleteness } from "../zod-table.mjs";
1
4
  import { ManagedReadRequest } from "./security.mjs";
2
- import { NativePagination } from "./filters.mjs";
3
- import { CursorBinding, createCursorCodec } from "./cursors.mjs";
4
5
  import { createPlanner } from "./planner.mjs";
5
- import { GenericDataModel, GenericDatabaseReader, GenericSchema, SchemaDefinition } from "convex/server";
6
+ import { CursorBinding, createCursorCodec } from "./cursors.mjs";
7
+ import { GenericDataModel, GenericDatabaseReader, GenericSchema, IndexRangeBuilder, SchemaDefinition } from "convex/server";
6
8
  import { Value } from "convex/values";
7
9
  import { QueryStream } from "convex-helpers/server/stream";
8
10
  //#region src/querying/execution.d.ts
@@ -17,6 +19,8 @@ export declare function executeQuery(schema: SchemaDefinition<GenericSchema, boo
17
19
  isDone: boolean;
18
20
  splitCursor?: import("convex/server").Cursor | null;
19
21
  pageStatus?: "SplitRecommended" | "SplitRequired" | null;
22
+ paginationMode?: 'native-search';
23
+ completeness: PageCompleteness;
20
24
  continueCursor: string;
21
25
  }>;
22
26
  export declare function executeStream(schema: SchemaDefinition<GenericSchema, boolean>, request: Request, table: string, plan: Plan, planner: ReturnType<typeof createPlanner>, codec: Codec, binding: CursorBinding, args: NativePagination, complete?: (document: Record<string, Value>, permitted: boolean) => Promise<Record<string, Value> | null>, seal?: (raw: string) => string, transform?: (source: QueryStream<Record<string, Value>>, db: GenericDatabaseReader<any>) => QueryStream<Record<string, Value>>, authorizationTable?: string): Promise<{
@@ -24,7 +28,14 @@ export declare function executeStream(schema: SchemaDefinition<GenericSchema, bo
24
28
  isDone: boolean;
25
29
  splitCursor?: import("convex/server").Cursor | null;
26
30
  pageStatus?: "SplitRecommended" | "SplitRequired" | null;
31
+ paginationMode?: 'native-search';
32
+ completeness: PageCompleteness;
27
33
  continueCursor: string;
28
34
  }>;
35
+ /** Private adapter shared by root and relationship streams; the planner owns admission. */
36
+ export declare function nativeIndexRange(q: IndexRangeBuilder<any, string[], number>, prefix: readonly {
37
+ field: string;
38
+ value: FilterScalar;
39
+ }[], bounds: NativeRange | null): import('convex/server').IndexRange;
29
40
  //#endregion
30
41
  //# sourceMappingURL=execution.d.mts.map
@@ -1,2 +1,2 @@
1
- import{ManagedReadError as e}from"./security.mjs";import{CursorError as t}from"./cursors.mjs";import{RelationshipError as n}from"./relationships.mjs";import{EmptyStream as r,QueryStream as i,stream as a}from"convex-helpers/server/stream";function o(r){throw r instanceof e||r instanceof t||r instanceof n?r:Error(`Query execution failed`)}async function s(e,t,n,r,i,a,o,s){return c(e,t,n,r,i,a,o,{...r.args,cursor:r.args.cursor===null?null:a.open(r.args.cursor,o),endCursor:r.args.endCursor==null?r.args.endCursor:a.open(r.args.endCursor,o)},s)}async function c(e,t,n,i,s,c,u,d,p,m=e=>c.seal(e,u),h,g=n){let _=l(t,s);try{let o=a(_.db,e).query(n),c=(i.index?o.withIndex(i.index.name,e=>{let t=e;for(let{field:e,value:n}of i.prefix)t=t.eq(e,n);return t}):o).order(i.args.order??`asc`),l=h?h(c,_.db):c,u=i.unsatisfiable?await new r(l.getOrder(),l.getIndexFields(),l.getEqualityIndexFilter()).paginate(d):await new f(l,t,g,i,s,{completed:[],stopped:!1},p).paginate(d),v={...u,continueCursor:m(u.continueCursor)};return u.splitCursor!=null&&(v.splitCursor=m(u.splitCursor)),v}catch(e){o(e)}finally{await _.close()}}function l(e,t){let n=/* @__PURE__ */ new Set;function r(e,i){return new Proxy({},{get(a,o){let s=i;if(o===`withIndex`&&`withIndex`in s)return(...t)=>{let n=s.withIndex;return r(e,n.apply(s,t))};if(o===`order`&&`order`in s)return(...t)=>{let n=s.order;return r(e,n.apply(s,t))};if(o===Symbol.asyncIterator)return()=>{let r=s[Symbol.asyncIterator]();return n.add(r),{next:()=>(t.beforeLeaf(e),r.next())}};throw Error(`Unsupported private query operation`)}})}return{db:{query:n=>(t.beforeLeaf(n),r(n,e.leafQuery(n)))},async close(){let e=!1;for(let t of n)try{await t.return?.()}catch{e=!0}if(n.clear(),e)throw Error(`Query execution failed`)}}}function u(e){let t=e.counters,n=e.budgets;return t.readOperations<n.readOperations&&t.rawCandidates<n.rawCandidates&&t.documentBytesObserved+t.documentBytesReserved+1048576<=n.documentBytes}var d=class extends i{entry;source;constructor(e,t){super(),this.entry=e,this.source=t}getOrder(){return this.source.getOrder()}getIndexFields(){return this.source.getIndexFields()}getEqualityIndexFilter(){return this.source.getEqualityIndexFilter()}narrow(e){if(e.lowerBound.length||e.upperBound.length||!e.lowerBoundInclusive||!e.upperBoundInclusive)throw Error(`Invalid cursor encoder range`);return this}async*iterWithKeys(){yield[{},this.entry[1],this.entry[2]]}},f=class t extends i{source;request;table;plan;planner;progress;complete;constructor(e,t,n,r,i,a,o){super(),this.source=e,this.request=t,this.table=n,this.plan=r,this.planner=i,this.progress=a,this.complete=o}getOrder(){return this.source.getOrder()}getIndexFields(){return this.source.getIndexFields()}getEqualityIndexFilter(){return this.source.getEqualityIndexFilter()}narrow(e){return new t(this.source.narrow(e),this.request,this.table,this.plan,this.planner,this.progress,this.complete)}async*iterWithKeys(){let t=this.source.iterWithKeys(!0)[Symbol.asyncIterator]();try{for(;;){if(!u(this.request)){if(!this.progress.completed.length)throw new e(`MANAGED_READ_BUDGET`);this.progress.stopped=!0;return}let n,r=this.request.counters.rawCandidates;try{n=await t.next()}catch(t){if(t instanceof e&&t.code===`MANAGED_READ_BUDGET`&&this.progress.completed.length&&this.request.counters.rawCandidates===r){this.progress.stopped=!0;return}throw t}if(n.done)return;let[i,a,o]=n.value,s=null;if(i){let e=await this.request.authorize(this.table,i);s=this.complete?await this.complete(i,e):this.planner.complete(this.table,i,e,this.plan.residual)}let c=[s,a,o];this.progress.completed.push(c),u(this.request)||(this.progress.stopped=!0),yield c}}finally{await t.return?.()}}async paginate(t){let n=await super.paginate(t);if(!this.progress.stopped)return n;let r=this.progress.completed;if(!r.length)throw new e(`MANAGED_READ_BUDGET`);let i=async e=>(await new d(e,this.source).paginate({numItems:1,cursor:null})).continueCursor;return{...n,isDone:!1,pageStatus:`SplitRequired`,continueCursor:await i(r.at(-1)),splitCursor:await i(r[Math.floor((r.length-1)/2)])}}};export{s as executeQuery,c as executeStream,o as rethrowQueryError};
1
+ import{ManagedReadError as e}from"./security.mjs";import{rangeForIndex as t}from"./filters.mjs";import{CursorError as n}from"./cursors.mjs";import{SearchError as r}from"./search.mjs";import{RelationshipError as i}from"./relationships.mjs";import{EmptyStream as a,QueryStream as o,getIndexFields as s,mergedStream as c,stream as l}from"convex-helpers/server/stream";function u(t){throw t instanceof r||t instanceof e||t instanceof n||t instanceof i?t:Error(`Query execution failed`)}async function d(e,t,n,r,i,a,o,s){return f(e,t,n,r,i,a,o,{...r.args,cursor:r.args.cursor===null?null:a.open(r.args.cursor,o),endCursor:r.args.endCursor==null?r.args.endCursor:a.open(r.args.endCursor,o)},s)}async function f(e,n,r,i,o,d,f,h,g,v=e=>d.seal(e,f),y,b=r){let x=m(n,o),S={completed:[]};try{let u=e,d=l(x.db,u).query(r),f=i.index?d.withIndex(i.index.name,e=>p(e,i.prefix,i.range)):d,m=i.args.order??`asc`,C=i.expansion,w=C&&i.index&&!i.unsatisfiable?c(C.values.map(e=>{let n=[...i.prefix,{field:C.field,value:e}];return d.withIndex(i.index.name,e=>p(e,n,t(i.index,n,i.ranges))).order(m)}),C.comparator===`full-index`?s(r,i.index.name,u):s(r,i.index.name,u).slice(i.prefix.length+1)):f.order(m),T=y?y(w,x.db):w,E=i.unsatisfiable?await new a(T.getOrder(),T.getIndexFields(),T.getEqualityIndexFilter()).paginate(h):await new _(T,n,b,i,o,S,g).paginate(h),D={...E,completeness:E.completeness??`complete`,continueCursor:v(E.continueCursor)};return E.splitCursor!=null&&(D.splitCursor=v(E.splitCursor)),D}catch(e){u(e)}finally{await x.close()}}function p(e,t,n){let r=e;for(let{field:e,value:n}of t)r=r.eq(e,n);let i=r;if(n?.lower){let{field:e,lower:t}=n;i=t.inclusive?r.gte(e,t.value):r.gt(e,t.value)}if(n?.upper){let{field:e,upper:t}=n;return t.inclusive?i.lte(e,t.value):i.lt(e,t.value)}return i}function m(e,t){let n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Set;function i(e,a){return new Proxy({},{get(o,s){let c=a;if(s===`withIndex`&&`withIndex`in c)return(...t)=>{let n=c.withIndex;return i(e,n.apply(c,t))};if(s===`order`&&`order`in c)return(...t)=>{let n=c.order;return i(e,n.apply(c,t))};if(s===Symbol.asyncIterator)return()=>{let i=c[Symbol.asyncIterator]();return n.add(i),{next:()=>{t.beforeLeaf(e);let n=i.next();return r.add(n),n.then(()=>r.delete(n),()=>r.delete(n)),n}}};throw Error(`Unsupported private query operation`)}})}return{db:{query:n=>(t.beforeLeaf(n),i(n,e.leafQuery(n)))},async close(){await Promise.allSettled(r);let e=!1;for(let t of n)try{await t.return?.()}catch{e=!0}if(n.clear(),e)throw Error(`Query execution failed`)}}}function h(e){let t=e.counters,n=e.budgets;if(t.readOperations>=n.readOperations||t.rawCandidates>=n.rawCandidates)return`row-budget`;if(t.documentBytesObserved+t.documentBytesReserved+1048576>n.documentBytes)return`byte-budget`}var g=class extends o{entry;source;constructor(e,t){super(),this.entry=e,this.source=t}getOrder(){return this.source.getOrder()}getIndexFields(){return this.source.getIndexFields()}getEqualityIndexFilter(){return this.source.getEqualityIndexFilter()}narrow(e){if(e.lowerBound.length||e.upperBound.length||!e.lowerBoundInclusive||!e.upperBoundInclusive)throw Error(`Invalid cursor encoder range`);return this}async*iterWithKeys(){yield[{},this.entry[1],this.entry[2]]}},_=class t extends o{source;request;table;plan;planner;progress;complete;constructor(e,t,n,r,i,a,o){super(),this.source=e,this.request=t,this.table=n,this.plan=r,this.planner=i,this.progress=a,this.complete=o}getOrder(){return this.source.getOrder()}getIndexFields(){return this.source.getIndexFields()}getEqualityIndexFilter(){return this.source.getEqualityIndexFilter()}narrow(e){return new t(this.source.narrow(e),this.request,this.table,this.plan,this.planner,this.progress,this.complete)}async*iterWithKeys(){let t=this.source.iterWithKeys(!0)[Symbol.asyncIterator]();try{for(;;){let n=h(this.request);if(n){if(!this.progress.completed.length)throw new e(`MANAGED_READ_BUDGET`);this.progress.stopReason=n;return}let r,i=this.request.counters.rawCandidates;try{r=await t.next()}catch(t){if(t instanceof e&&t.code===`MANAGED_READ_BUDGET`&&this.request.leafBudgetFailure(t)&&this.progress.completed.length&&this.request.counters.rawCandidates===i){this.progress.stopReason=this.request.leafBudgetFailure(t);return}throw t}if(r.done)return;let[a,o,s]=r.value,c=null;if(a){let e=await this.request.authorize(this.table,a);c=this.complete?await this.complete(a,e):this.planner.complete(this.table,a,e,this.plan.residual)}let l=[c,o,s];this.progress.completed.push(l),yield l}}finally{await t.return?.()}}async paginate(t){let n=await super.paginate(t),r=this.progress.completed,i=async e=>(await new g(e,this.source).paginate({numItems:1,cursor:null})).continueCursor,a=t.endCursor?!!r.length&&await i(r.at(-1))===t.endCursor:n.page.length>=t.numItems;if(this.request.atomicCompletion&&(this.progress.stopReason&&!a||n.pageStatus===`SplitRequired`&&!a))throw new e(`MANAGED_READ_BUDGET`);if(!this.progress.stopReason)return{...n,completeness:n.pageStatus===`SplitRequired`&&!a?`native-limit`:`complete`};if(!r.length)throw new e(`MANAGED_READ_BUDGET`);let o=await i(r.at(-1));return{...n,completeness:a?`complete`:this.progress.stopReason,isDone:!1,pageStatus:`SplitRequired`,continueCursor:o,splitCursor:await i(r[Math.floor((r.length-1)/2)])}}};export{d as executeQuery,f as executeStream,p as nativeIndexRange,u as rethrowQueryError};
2
2
  //# sourceMappingURL=execution.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"execution.mjs","names":["rethrowQueryError","error","ManagedReadError","CursorError","RelationshipError","executeQuery","executeStream","schema","request","table","plan","planner","codec","binding","complete","raw","leaves","leafReader","base","stream","ordered","range","q","field","value","source","transform","result","EmptyStream","args","EligibleStream","authorizationTable","protectedResult","seal","active","wrap","target","key","withIndex","order","iterator","failed","canFetch","c","b","CapturedKey","QueryStream","entry","bounds","progress","next","candidatesBefore","document","bytes","output","permitted","completed","encode"],"sources":["../../src/querying/execution.ts"],"sourcesContent":["import {\n\tEmptyStream,\n\tQueryStream,\n\tstream,\n\ttype IndexBounds,\n\ttype IndexKey,\n} from 'convex-helpers/server/stream'\nimport type {\n\tGenericDatabaseReader,\n\tGenericDataModel,\n\tGenericDocument,\n\tQueryInitializer,\n\tSchemaDefinition,\n\tGenericSchema,\n\tPaginationResult,\n\tTableDefinition,\n\tIndexRangeBuilder,\n} from 'convex/server'\nimport type { Value } from 'convex/values'\nimport type { createPlanner } from './planner'\nimport { MAX_DOCUMENT_BYTES, ManagedReadError, type ManagedReadRequest } from './security'\nimport { CursorError, type CursorBinding, type createCursorCodec } from './cursors'\nimport type { NativePagination } from './filters'\nimport { RelationshipError } from './relationships'\n\ntype Entry = [Record<string, Value> | null, IndexKey, number]\ntype Plan = ReturnType<ReturnType<typeof createPlanner>['plan']>\ntype Codec = ReturnType<typeof createCursorCodec>\nexport type ExecutionRequest = ManagedReadRequest<GenericDataModel>\ntype Request = Omit<ExecutionRequest, 'db'>\ntype ExecutionSchema = SchemaDefinition<\n\tRecord<string, TableDefinition<any, Record<string, string[]>>>,\n\tboolean\n>\n\n/** Private shared boundary: only the established fixed typed errors are public. */\n// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Thrown values enter this error boundary untrusted; the class checks below admit only the fixed public error contracts.\nexport function rethrowQueryError(error: unknown): never {\n\tif (\n\t\terror instanceof ManagedReadError ||\n\t\terror instanceof CursorError ||\n\t\terror instanceof RelationshipError\n\t)\n\t\tthrow error\n\t// Native/policy errors may contain traversal values or structured private data.\n\tthrow new Error('Query execution failed')\n}\n\nexport async function executeQuery(\n\tschema: SchemaDefinition<GenericSchema, boolean>,\n\trequest: Request,\n\ttable: string,\n\tplan: Plan,\n\tplanner: ReturnType<typeof createPlanner>,\n\tcodec: Codec,\n\tbinding: CursorBinding,\n\tcomplete?: (\n\t\tdocument: Record<string, Value>,\n\t\tpermitted: boolean,\n\t) => Promise<Record<string, Value> | null>,\n) {\n\t// Authenticate BOTH navigation slots before constructing or consuming native queries.\n\tconst args = {\n\t\t...plan.args,\n\t\tcursor: plan.args.cursor === null ? null : codec.open(plan.args.cursor, binding),\n\t\tendCursor:\n\t\t\tplan.args.endCursor == null ? plan.args.endCursor : codec.open(plan.args.endCursor, binding),\n\t}\n\treturn executeStream(schema, request, table, plan, planner, codec, binding, args, complete)\n}\n\nexport async function executeStream(\n\tschema: SchemaDefinition<GenericSchema, boolean>,\n\trequest: Request,\n\ttable: string,\n\tplan: Plan,\n\tplanner: ReturnType<typeof createPlanner>,\n\tcodec: Codec,\n\tbinding: CursorBinding,\n\targs: NativePagination,\n\tcomplete?: (\n\t\tdocument: Record<string, Value>,\n\t\tpermitted: boolean,\n\t) => Promise<Record<string, Value> | null>,\n\tseal: (raw: string) => string = (raw) => codec.seal(raw, binding),\n\ttransform?: (\n\t\tsource: QueryStream<Record<string, Value>>,\n\t\tdb: GenericDatabaseReader<any>,\n\t) => QueryStream<Record<string, Value>>,\n\tauthorizationTable = table,\n) {\n\tconst leaves = leafReader(request, planner)\n\ttry {\n\t\t// SAFETY: runtime ownership/index validation precedes this dynamic table\n\t\t// adapter. Public generics retain the original application's schema.\n\t\tconst base = stream(leaves.db, schema as ExecutionSchema).query(table)\n\t\tconst selected = plan.index\n\t\t\t? base.withIndex(plan.index.name, (q) => {\n\t\t\t\t\t// SAFETY: every equality is a validated consecutive native prefix.\n\t\t\t\t\tlet range = q as IndexRangeBuilder<any, string[], number>\n\t\t\t\t\tfor (const { field, value } of plan.prefix) {\n\t\t\t\t\t\t// SAFETY: native eq returns the next builder; runtime prefix length\n\t\t\t\t\t\t// is validated even though this dynamic adapter erases tuple lengths.\n\t\t\t\t\t\trange = range.eq(field, value) as IndexRangeBuilder<any, string[], number>\n\t\t\t\t\t}\n\t\t\t\t\treturn range\n\t\t\t\t})\n\t\t\t: base\n\t\tconst ordered = selected.order(plan.args.order ?? 'asc')\n\t\tconst source = transform ? transform(ordered, leaves.db) : ordered\n\t\tconst result = plan.unsatisfiable\n\t\t\t? await new EmptyStream<Record<string, Value>>(\n\t\t\t\t\tsource.getOrder(),\n\t\t\t\t\tsource.getIndexFields(),\n\t\t\t\t\tsource.getEqualityIndexFilter(),\n\t\t\t\t).paginate(args)\n\t\t\t: await new EligibleStream(\n\t\t\t\t\tsource,\n\t\t\t\t\trequest,\n\t\t\t\t\tauthorizationTable,\n\t\t\t\t\tplan,\n\t\t\t\t\tplanner,\n\t\t\t\t\t{\n\t\t\t\t\t\tcompleted: [],\n\t\t\t\t\t\tstopped: false,\n\t\t\t\t\t},\n\t\t\t\t\tcomplete,\n\t\t\t\t).paginate(args)\n\t\tconst protectedResult = {\n\t\t\t...result,\n\t\t\tcontinueCursor: seal(result.continueCursor),\n\t\t}\n\t\tif (result.splitCursor != null) protectedResult.splitCursor = seal(result.splitCursor)\n\t\treturn protectedResult\n\t} catch (error) {\n\t\trethrowQueryError(error)\n\t} finally {\n\t\tawait leaves.close()\n\t}\n}\n\n/** Retain the actual metered leaf, since the helper's public key iterator does\n * not forward return(). This private reader only constructs raw metered queries.\n */\nfunction leafReader(request: Request, planner: ReturnType<typeof createPlanner>) {\n\tconst active = new Set<AsyncIterator<GenericDocument>>()\n\tfunction wrap<Source extends AsyncIterable<GenericDocument>>(\n\t\ttable: string,\n\t\tsource: Source,\n\t): Source {\n\t\t// SAFETY: the empty proxy shell is private; supported methods forward to the real native source below.\n\t\treturn new Proxy({} as Source, {\n\t\t\tget(_target, key) {\n\t\t\t\tconst target = source\n\t\t\t\tif (key === 'withIndex' && 'withIndex' in target)\n\t\t\t\t\treturn (...args: Parameters<QueryInitializer<any>['withIndex']>) => {\n\t\t\t\t\t\t// SAFETY: the private facade forwards an existing native index constructor only.\n\t\t\t\t\t\tconst withIndex = target.withIndex as QueryInitializer<any>['withIndex']\n\t\t\t\t\t\treturn wrap(table, withIndex.apply(target, args))\n\t\t\t\t\t}\n\t\t\t\tif (key === 'order' && 'order' in target)\n\t\t\t\t\treturn (...args: Parameters<QueryInitializer<any>['order']>) => {\n\t\t\t\t\t\t// SAFETY: the private facade forwards the existing native order method only.\n\t\t\t\t\t\tconst order = target.order as QueryInitializer<any>['order']\n\t\t\t\t\t\treturn wrap(table, order.apply(target, args))\n\t\t\t\t\t}\n\t\t\t\tif (key === Symbol.asyncIterator)\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tconst iterator = target[Symbol.asyncIterator]()\n\t\t\t\t\t\tactive.add(iterator)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tnext: () => {\n\t\t\t\t\t\t\t\tplanner.beforeLeaf(table)\n\t\t\t\t\t\t\t\treturn iterator.next()\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tthrow new Error('Unsupported private query operation')\n\t\t\t},\n\t\t})\n\t}\n\n\t// SAFETY: stream() uses only query to construct the indexed stream. The\n\t// request's authorized reader handles policy gets separately; never publish this facade.\n\tconst db = {\n\t\tquery: (table: string) => {\n\t\t\tplanner.beforeLeaf(table)\n\t\t\treturn wrap(table, request.leafQuery(table))\n\t\t},\n\t} as GenericDatabaseReader<any>\n\treturn {\n\t\tdb,\n\t\tasync close() {\n\t\t\tlet failed = false\n\t\t\tfor (const iterator of active) {\n\t\t\t\ttry {\n\t\t\t\t\tawait iterator.return?.()\n\t\t\t\t} catch {\n\t\t\t\t\tfailed = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tactive.clear()\n\t\t\tif (failed) throw new Error('Query execution failed')\n\t\t},\n\t}\n}\n\nfunction canFetch(request: Request): boolean {\n\tconst c = request.counters,\n\t\tb = request.budgets\n\treturn (\n\t\tc.readOperations < b.readOperations &&\n\t\tc.rawCandidates < b.rawCandidates &&\n\t\tc.documentBytesObserved + c.documentBytesReserved + MAX_DOCUMENT_BYTES <= b.documentBytes\n\t)\n}\n\n/** Encoder-only use of public native pagination; no private cursor wire format,\n * artificial bandwidth, lookahead, or database read.\n */\nclass CapturedKey extends QueryStream<object> {\n\tconstructor(\n\t\tprivate readonly entry: Entry,\n\t\tprivate readonly source: QueryStream<Record<string, Value>>,\n\t) {\n\t\tsuper()\n\t}\n\tgetOrder() {\n\t\treturn this.source.getOrder()\n\t}\n\tgetIndexFields() {\n\t\treturn this.source.getIndexFields()\n\t}\n\tgetEqualityIndexFilter() {\n\t\treturn this.source.getEqualityIndexFilter()\n\t}\n\tnarrow(bounds: IndexBounds) {\n\t\tif (\n\t\t\tbounds.lowerBound.length ||\n\t\t\tbounds.upperBound.length ||\n\t\t\t!bounds.lowerBoundInclusive ||\n\t\t\t!bounds.upperBoundInclusive\n\t\t)\n\t\t\tthrow new Error('Invalid cursor encoder range')\n\t\treturn this\n\t}\n\tasync *iterWithKeys(): AsyncGenerator<[object, IndexKey, number], undefined> {\n\t\tyield [{}, this.entry[1], this.entry[2]]\n\t}\n}\n\ninterface Progress {\n\tcompleted: Entry[]\n\tstopped: boolean\n}\nclass EligibleStream extends QueryStream<Record<string, Value>> {\n\tconstructor(\n\t\tprivate readonly source: QueryStream<Record<string, Value>>,\n\t\tprivate readonly request: Request,\n\t\tprivate readonly table: string,\n\t\tprivate readonly plan: Plan,\n\t\tprivate readonly planner: ReturnType<typeof createPlanner>,\n\t\tprivate readonly progress: Progress,\n\t\tprivate readonly complete?: (\n\t\t\tdocument: Record<string, Value>,\n\t\t\tpermitted: boolean,\n\t\t) => Promise<Record<string, Value> | null>,\n\t) {\n\t\tsuper()\n\t}\n\tgetOrder() {\n\t\treturn this.source.getOrder()\n\t}\n\tgetIndexFields() {\n\t\treturn this.source.getIndexFields()\n\t}\n\tgetEqualityIndexFilter() {\n\t\treturn this.source.getEqualityIndexFilter()\n\t}\n\tnarrow(bounds: IndexBounds): QueryStream<Record<string, Value>> {\n\t\treturn new EligibleStream(\n\t\t\tthis.source.narrow(bounds),\n\t\t\tthis.request,\n\t\t\tthis.table,\n\t\t\tthis.plan,\n\t\t\tthis.planner,\n\t\t\tthis.progress,\n\t\t\tthis.complete,\n\t\t)\n\t}\n\tasync *iterWithKeys(): AsyncGenerator<Entry, undefined> {\n\t\t// Always request actual root bandwidth, even without a native byte option.\n\t\tconst iterator = this.source.iterWithKeys(true)[Symbol.asyncIterator]()\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tif (!canFetch(this.request)) {\n\t\t\t\t\tif (!this.progress.completed.length) throw new ManagedReadError('MANAGED_READ_BUDGET')\n\t\t\t\t\tthis.progress.stopped = true\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet next: IteratorResult<Entry>\n\t\t\t\tconst candidatesBefore = this.request.counters.rawCandidates\n\t\t\t\ttry {\n\t\t\t\t\tnext = await iterator.next()\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// A reservation failure BEFORE the next root is safe to stop at\n\t\t\t\t\t// completed progress. Authorization errors below are never partialized.\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof ManagedReadError &&\n\t\t\t\t\t\terror.code === 'MANAGED_READ_BUDGET' &&\n\t\t\t\t\t\tthis.progress.completed.length &&\n\t\t\t\t\t\tthis.request.counters.rawCandidates === candidatesBefore\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.progress.stopped = true\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\tif (next.done) return\n\t\t\t\tconst [document, key, bytes] = next.value\n\t\t\t\tlet output: Record<string, Value> | null = null\n\t\t\t\tif (document) {\n\t\t\t\t\t// SAFETY: metered native stream documents contain their system IDs.\n\t\t\t\t\tconst permitted = await this.request.authorize(this.table, document as GenericDocument)\n\t\t\t\t\t// SAFETY: the registry DTO validates declared public native values only.\n\t\t\t\t\toutput = this.complete\n\t\t\t\t\t\t? await this.complete(document, permitted)\n\t\t\t\t\t\t: (this.planner.complete(this.table, document, permitted, this.plan.residual) as Record<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\tValue\n\t\t\t\t\t\t\t> | null)\n\t\t\t\t}\n\t\t\t\t// Complete policy, residual, and required DTO before recording the key.\n\t\t\t\tconst entry: Entry = [output, key, bytes]\n\t\t\t\tthis.progress.completed.push(entry)\n\t\t\t\tif (!canFetch(this.request)) this.progress.stopped = true\n\t\t\t\tyield entry\n\t\t\t}\n\t\t} finally {\n\t\t\tawait iterator.return?.()\n\t\t}\n\t}\n\toverride async paginate(\n\t\targs: NativePagination,\n\t): Promise<PaginationResult<Record<string, Value>>> {\n\t\tconst result = await super.paginate(args)\n\t\tif (!this.progress.stopped) return result\n\t\tconst completed = this.progress.completed\n\t\tif (!completed.length) throw new ManagedReadError('MANAGED_READ_BUDGET')\n\t\tconst encode = async (entry: Entry) =>\n\t\t\t(await new CapturedKey(entry, this.source).paginate({ numItems: 1, cursor: null }))\n\t\t\t\t.continueCursor\n\t\treturn {\n\t\t\t...result,\n\t\t\tisDone: false,\n\t\t\tpageStatus: 'SplitRequired',\n\t\t\tcontinueCursor: await encode(completed.at(-1)!),\n\t\t\tsplitCursor: await encode(completed[Math.floor((completed.length - 1) / 2)]),\n\t\t}\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"execution.mjs","names":["rethrowQueryError","error","SearchError","ManagedReadError","CursorError","RelationshipError","executeQuery","executeStream","schema","request","table","plan","planner","codec","binding","complete","raw","leaves","leafReader","progress","nativeSchema","base","stream","selected","nativeIndexRange","q","order","expansion","ordered","mergedStream","prefix","rangeForIndex","getIndexFields","source","transform","result","EmptyStream","args","EligibleStream","authorizationTable","protectedResult","seal","range","field","value","bounded","bounds","lower","upper","active","pending","wrap","target","key","withIndex","iterator","next","failed","fetchStopReason","c","b","CapturedKey","QueryStream","entry","reason","candidatesBefore","document","bytes","output","permitted","completed","encode","fulfilled","continuation"],"sources":["../../src/querying/execution.ts"],"sourcesContent":["import {\n\tEmptyStream,\n\tmergedStream,\n\tgetIndexFields,\n\tQueryStream,\n\tstream,\n\ttype IndexBounds,\n\ttype IndexKey,\n} from 'convex-helpers/server/stream'\nimport type {\n\tGenericDatabaseReader,\n\tGenericDataModel,\n\tGenericDocument,\n\tQueryInitializer,\n\tSchemaDefinition,\n\tGenericSchema,\n\tTableDefinition,\n\tIndexRangeBuilder,\n} from 'convex/server'\nimport type { Value } from 'convex/values'\nimport type { createPlanner } from './planner'\nimport { MAX_DOCUMENT_BYTES, ManagedReadError, type ManagedReadRequest } from './security'\nimport { CursorError, type CursorBinding, type createCursorCodec } from './cursors'\nimport {\n\trangeForIndex,\n\ttype NativePagination,\n\ttype NativeRange,\n\ttype FilterScalar,\n} from './filters'\nimport { SearchError } from './search'\nimport { RelationshipError } from './relationships'\nimport type { EnginePaginationResult, PageCompleteness } from '../zod-table'\n\ntype Entry = [Record<string, Value> | null, IndexKey, number]\ntype Plan = ReturnType<ReturnType<typeof createPlanner>['plan']>\ntype Codec = ReturnType<typeof createCursorCodec>\nexport type ExecutionRequest = ManagedReadRequest<GenericDataModel>\ntype Request = Omit<ExecutionRequest, 'db'>\ntype ExecutionSchema = SchemaDefinition<\n\tRecord<string, TableDefinition<any, Record<string, string[]>>>,\n\tboolean\n>\n\n/** Private shared boundary: only the established fixed typed errors are public. */\n// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Thrown values enter this error boundary untrusted; the class checks below admit only the fixed public error contracts.\nexport function rethrowQueryError(error: unknown): never {\n\tif (\n\t\terror instanceof SearchError ||\n\t\terror instanceof ManagedReadError ||\n\t\terror instanceof CursorError ||\n\t\terror instanceof RelationshipError\n\t)\n\t\tthrow error\n\t// Native/policy errors may contain traversal values or structured private data.\n\tthrow new Error('Query execution failed')\n}\n\nexport async function executeQuery(\n\tschema: SchemaDefinition<GenericSchema, boolean>,\n\trequest: Request,\n\ttable: string,\n\tplan: Plan,\n\tplanner: ReturnType<typeof createPlanner>,\n\tcodec: Codec,\n\tbinding: CursorBinding,\n\tcomplete?: (\n\t\tdocument: Record<string, Value>,\n\t\tpermitted: boolean,\n\t) => Promise<Record<string, Value> | null>,\n) {\n\t// Authenticate BOTH navigation slots before constructing or consuming native queries.\n\tconst args = {\n\t\t...plan.args,\n\t\tcursor: plan.args.cursor === null ? null : codec.open(plan.args.cursor, binding),\n\t\tendCursor:\n\t\t\tplan.args.endCursor == null ? plan.args.endCursor : codec.open(plan.args.endCursor, binding),\n\t}\n\treturn executeStream(schema, request, table, plan, planner, codec, binding, args, complete)\n}\n\nexport async function executeStream(\n\tschema: SchemaDefinition<GenericSchema, boolean>,\n\trequest: Request,\n\ttable: string,\n\tplan: Plan,\n\tplanner: ReturnType<typeof createPlanner>,\n\tcodec: Codec,\n\tbinding: CursorBinding,\n\targs: NativePagination,\n\tcomplete?: (\n\t\tdocument: Record<string, Value>,\n\t\tpermitted: boolean,\n\t) => Promise<Record<string, Value> | null>,\n\tseal: (raw: string) => string = (raw) => codec.seal(raw, binding),\n\ttransform?: (\n\t\tsource: QueryStream<Record<string, Value>>,\n\t\tdb: GenericDatabaseReader<any>,\n\t) => QueryStream<Record<string, Value>>,\n\tauthorizationTable = table,\n) {\n\tconst leaves = leafReader(request, planner)\n\tconst progress: Progress = { completed: [] }\n\ttry {\n\t\t// SAFETY: runtime ownership/index validation precedes this dynamic table\n\t\t// adapter. Public generics retain the original application's schema.\n\t\tconst nativeSchema = schema as ExecutionSchema\n\t\tconst base = stream(leaves.db, nativeSchema).query(table)\n\t\tconst selected = plan.index\n\t\t\t? base.withIndex(plan.index.name, (q) => nativeIndexRange(q, plan.prefix, plan.range))\n\t\t\t: base\n\t\tconst order = plan.args.order ?? 'asc'\n\t\tconst expansion = plan.expansion\n\t\tconst ordered =\n\t\t\texpansion && plan.index && !plan.unsatisfiable\n\t\t\t\t? mergedStream(\n\t\t\t\t\t\texpansion.values.map((value) => {\n\t\t\t\t\t\t\tconst prefix = [...plan.prefix, { field: expansion.field, value }]\n\t\t\t\t\t\t\t// SAFETY: each stream binds the same admitted index at one consecutive position.\n\t\t\t\t\t\t\treturn base\n\t\t\t\t\t\t\t\t.withIndex(plan.index!.name, (q) =>\n\t\t\t\t\t\t\t\t\tnativeIndexRange(q, prefix, rangeForIndex(plan.index!, prefix, plan.ranges)),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.order(order)\n\t\t\t\t\t\t}),\n\t\t\t\t\t\texpansion.comparator === 'full-index'\n\t\t\t\t\t\t\t? getIndexFields(table, plan.index.name, nativeSchema)\n\t\t\t\t\t\t\t: getIndexFields(table, plan.index.name, nativeSchema).slice(plan.prefix.length + 1),\n\t\t\t\t\t)\n\t\t\t\t: selected.order(order)\n\t\tconst source = transform ? transform(ordered, leaves.db) : ordered\n\t\tconst result: EnginePaginationResult<Record<string, Value>> = plan.unsatisfiable\n\t\t\t? await new EmptyStream<Record<string, Value>>(\n\t\t\t\t\tsource.getOrder(),\n\t\t\t\t\tsource.getIndexFields(),\n\t\t\t\t\tsource.getEqualityIndexFilter(),\n\t\t\t\t).paginate(args)\n\t\t\t: await new EligibleStream(\n\t\t\t\t\tsource,\n\t\t\t\t\trequest,\n\t\t\t\t\tauthorizationTable,\n\t\t\t\t\tplan,\n\t\t\t\t\tplanner,\n\t\t\t\t\tprogress,\n\t\t\t\t\tcomplete,\n\t\t\t\t).paginate(args)\n\t\tconst protectedResult = {\n\t\t\t...result,\n\t\t\tcompleteness: result.completeness ?? 'complete',\n\t\t\tcontinueCursor: seal(result.continueCursor),\n\t\t}\n\t\tif (result.splitCursor != null) protectedResult.splitCursor = seal(result.splitCursor)\n\t\treturn protectedResult\n\t} catch (error) {\n\t\trethrowQueryError(error)\n\t} finally {\n\t\tawait leaves.close()\n\t}\n}\n\n/** Private adapter shared by root and relationship streams; the planner owns admission. */\nexport function nativeIndexRange(\n\tq: IndexRangeBuilder<any, string[], number>,\n\tprefix: readonly { field: string; value: FilterScalar }[],\n\tbounds: NativeRange | null,\n): import('convex/server').IndexRange {\n\tlet range = q\n\tfor (const { field, value } of prefix) {\n\t\t// SAFETY: every equality advances the validated consecutive native prefix.\n\t\trange = range.eq(field, value) as IndexRangeBuilder<any, string[], number>\n\t}\n\t// SAFETY: an equality builder also admits upper bounds; lower methods retain that interface.\n\tlet bounded = range as ReturnType<typeof range.gte>\n\tif (bounds?.lower) {\n\t\tconst { field, lower } = bounds\n\t\tbounded = lower.inclusive ? range.gte(field, lower.value) : range.gt(field, lower.value)\n\t}\n\tif (bounds?.upper) {\n\t\tconst { field, upper } = bounds\n\t\treturn upper.inclusive ? bounded.lte(field, upper.value) : bounded.lt(field, upper.value)\n\t}\n\treturn bounded\n}\n\n/** Retain the actual metered leaf, since the helper's public key iterator does\n * not forward return(). This private reader only constructs raw metered queries.\n */\nfunction leafReader(request: Request, planner: ReturnType<typeof createPlanner>) {\n\tconst active = new Set<AsyncIterator<GenericDocument>>()\n\tconst pending = new Set<Promise<IteratorResult<GenericDocument>>>()\n\tfunction wrap<Source extends AsyncIterable<GenericDocument>>(\n\t\ttable: string,\n\t\tsource: Source,\n\t): Source {\n\t\t// SAFETY: the empty proxy shell is private; supported methods forward to the real native source below.\n\t\treturn new Proxy({} as Source, {\n\t\t\tget(_target, key) {\n\t\t\t\tconst target = source\n\t\t\t\tif (key === 'withIndex' && 'withIndex' in target)\n\t\t\t\t\treturn (...args: Parameters<QueryInitializer<any>['withIndex']>) => {\n\t\t\t\t\t\t// SAFETY: the private facade forwards an existing native index constructor only.\n\t\t\t\t\t\tconst withIndex = target.withIndex as QueryInitializer<any>['withIndex']\n\t\t\t\t\t\treturn wrap(table, withIndex.apply(target, args))\n\t\t\t\t\t}\n\t\t\t\tif (key === 'order' && 'order' in target)\n\t\t\t\t\treturn (...args: Parameters<QueryInitializer<any>['order']>) => {\n\t\t\t\t\t\t// SAFETY: the private facade forwards the existing native order method only.\n\t\t\t\t\t\tconst order = target.order as QueryInitializer<any>['order']\n\t\t\t\t\t\treturn wrap(table, order.apply(target, args))\n\t\t\t\t\t}\n\t\t\t\tif (key === Symbol.asyncIterator)\n\t\t\t\t\treturn () => {\n\t\t\t\t\t\tconst iterator = target[Symbol.asyncIterator]()\n\t\t\t\t\t\tactive.add(iterator)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tnext: () => {\n\t\t\t\t\t\t\t\tplanner.beforeLeaf(table)\n\t\t\t\t\t\t\t\tconst next = iterator.next()\n\t\t\t\t\t\t\t\tpending.add(next)\n\t\t\t\t\t\t\t\tvoid next.then(\n\t\t\t\t\t\t\t\t\t() => pending.delete(next),\n\t\t\t\t\t\t\t\t\t() => pending.delete(next),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\treturn next\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tthrow new Error('Unsupported private query operation')\n\t\t\t},\n\t\t})\n\t}\n\n\t// SAFETY: stream() uses only query to construct the indexed stream. The\n\t// request's authorized reader handles policy gets separately; never publish this facade.\n\tconst db = {\n\t\tquery: (table: string) => {\n\t\t\tplanner.beforeLeaf(table)\n\t\t\treturn wrap(table, request.leafQuery(table))\n\t\t},\n\t} as GenericDatabaseReader<any>\n\treturn {\n\t\tdb,\n\t\tasync close() {\n\t\t\tawait Promise.allSettled(pending)\n\t\t\tlet failed = false\n\t\t\tfor (const iterator of active) {\n\t\t\t\ttry {\n\t\t\t\t\tawait iterator.return?.()\n\t\t\t\t} catch {\n\t\t\t\t\tfailed = true\n\t\t\t\t}\n\t\t\t}\n\t\t\tactive.clear()\n\t\t\tif (failed) throw new Error('Query execution failed')\n\t\t},\n\t}\n}\n\nfunction fetchStopReason(request: Request): 'row-budget' | 'byte-budget' | undefined {\n\tconst c = request.counters,\n\t\tb = request.budgets\n\t// Row checks precede byte reservation, matching the managed leaf admission order.\n\tif (c.readOperations >= b.readOperations || c.rawCandidates >= b.rawCandidates)\n\t\treturn 'row-budget'\n\tif (c.documentBytesObserved + c.documentBytesReserved + MAX_DOCUMENT_BYTES > b.documentBytes)\n\t\treturn 'byte-budget'\n\treturn undefined\n}\n\n/** Encoder-only use of public native pagination; no private cursor wire format,\n * artificial bandwidth, lookahead, or database read.\n */\nclass CapturedKey extends QueryStream<object> {\n\tconstructor(\n\t\tprivate readonly entry: Entry,\n\t\tprivate readonly source: QueryStream<Record<string, Value>>,\n\t) {\n\t\tsuper()\n\t}\n\tgetOrder() {\n\t\treturn this.source.getOrder()\n\t}\n\tgetIndexFields() {\n\t\treturn this.source.getIndexFields()\n\t}\n\tgetEqualityIndexFilter() {\n\t\treturn this.source.getEqualityIndexFilter()\n\t}\n\tnarrow(bounds: IndexBounds) {\n\t\tif (\n\t\t\tbounds.lowerBound.length ||\n\t\t\tbounds.upperBound.length ||\n\t\t\t!bounds.lowerBoundInclusive ||\n\t\t\t!bounds.upperBoundInclusive\n\t\t)\n\t\t\tthrow new Error('Invalid cursor encoder range')\n\t\treturn this\n\t}\n\tasync *iterWithKeys(): AsyncGenerator<[object, IndexKey, number], undefined> {\n\t\tyield [{}, this.entry[1], this.entry[2]]\n\t}\n}\n\ninterface Progress {\n\tcompleted: Entry[]\n\tstopReason?: PageCompleteness\n}\nclass EligibleStream extends QueryStream<Record<string, Value>> {\n\tconstructor(\n\t\tprivate readonly source: QueryStream<Record<string, Value>>,\n\t\tprivate readonly request: Request,\n\t\tprivate readonly table: string,\n\t\tprivate readonly plan: Plan,\n\t\tprivate readonly planner: ReturnType<typeof createPlanner>,\n\t\tprivate readonly progress: Progress,\n\t\tprivate readonly complete?: (\n\t\t\tdocument: Record<string, Value>,\n\t\t\tpermitted: boolean,\n\t\t) => Promise<Record<string, Value> | null>,\n\t) {\n\t\tsuper()\n\t}\n\tgetOrder() {\n\t\treturn this.source.getOrder()\n\t}\n\tgetIndexFields() {\n\t\treturn this.source.getIndexFields()\n\t}\n\tgetEqualityIndexFilter() {\n\t\treturn this.source.getEqualityIndexFilter()\n\t}\n\tnarrow(bounds: IndexBounds): QueryStream<Record<string, Value>> {\n\t\treturn new EligibleStream(\n\t\t\tthis.source.narrow(bounds),\n\t\t\tthis.request,\n\t\t\tthis.table,\n\t\t\tthis.plan,\n\t\t\tthis.planner,\n\t\t\tthis.progress,\n\t\t\tthis.complete,\n\t\t)\n\t}\n\tasync *iterWithKeys(): AsyncGenerator<Entry, undefined> {\n\t\t// Always request actual root bandwidth, even without a native byte option.\n\t\tconst iterator = this.source.iterWithKeys(true)[Symbol.asyncIterator]()\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst reason = fetchStopReason(this.request)\n\t\t\t\tif (reason) {\n\t\t\t\t\tif (!this.progress.completed.length) throw new ManagedReadError('MANAGED_READ_BUDGET')\n\t\t\t\t\tthis.progress.stopReason = reason\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet next: IteratorResult<Entry>\n\t\t\t\tconst candidatesBefore = this.request.counters.rawCandidates\n\t\t\t\ttry {\n\t\t\t\t\tnext = await iterator.next()\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// A reservation failure BEFORE the next root is safe to stop at\n\t\t\t\t\t// completed progress. Authorization errors below are never partialized.\n\t\t\t\t\tif (\n\t\t\t\t\t\terror instanceof ManagedReadError &&\n\t\t\t\t\t\terror.code === 'MANAGED_READ_BUDGET' &&\n\t\t\t\t\t\tthis.request.leafBudgetFailure(error) &&\n\t\t\t\t\t\tthis.progress.completed.length &&\n\t\t\t\t\t\tthis.request.counters.rawCandidates === candidatesBefore\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.progress.stopReason = this.request.leafBudgetFailure(error)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\tif (next.done) return\n\t\t\t\tconst [document, key, bytes] = next.value\n\t\t\t\tlet output: Record<string, Value> | null = null\n\t\t\t\tif (document) {\n\t\t\t\t\t// SAFETY: metered native stream documents contain their system IDs.\n\t\t\t\t\tconst permitted = await this.request.authorize(this.table, document as GenericDocument)\n\t\t\t\t\t// SAFETY: the registry DTO validates declared public native values only.\n\t\t\t\t\toutput = this.complete\n\t\t\t\t\t\t? await this.complete(document, permitted)\n\t\t\t\t\t\t: (this.planner.complete(this.table, document, permitted, this.plan.residual) as Record<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\tValue\n\t\t\t\t\t\t\t> | null)\n\t\t\t\t}\n\t\t\t\t// Complete policy, residual, and required DTO before recording the key.\n\t\t\t\tconst entry: Entry = [output, key, bytes]\n\t\t\t\tthis.progress.completed.push(entry)\n\t\t\t\tyield entry\n\t\t\t}\n\t\t} finally {\n\t\t\tawait iterator.return?.()\n\t\t}\n\t}\n\toverride async paginate(\n\t\targs: NativePagination,\n\t): Promise<EnginePaginationResult<Record<string, Value>>> {\n\t\tconst result = await super.paginate(args)\n\t\tconst completed = this.progress.completed\n\t\tconst encode = async (entry: Entry) =>\n\t\t\t(\n\t\t\t\tawait new CapturedKey(entry, this.source).paginate({\n\t\t\t\t\tnumItems: 1,\n\t\t\t\t\tcursor: null,\n\t\t\t\t})\n\t\t\t).continueCursor\n\t\tconst fulfilled = args.endCursor\n\t\t\t? !!completed.length && (await encode(completed.at(-1)!)) === args.endCursor\n\t\t\t: result.page.length >= args.numItems\n\t\tif (\n\t\t\tthis.request.atomicCompletion &&\n\t\t\t((this.progress.stopReason && !fulfilled) ||\n\t\t\t\t(result.pageStatus === 'SplitRequired' && !fulfilled))\n\t\t)\n\t\t\tthrow new ManagedReadError('MANAGED_READ_BUDGET')\n\t\tif (!this.progress.stopReason)\n\t\t\treturn {\n\t\t\t\t...result,\n\t\t\t\t// A helper limit can coincide with the requested final row. That page\n\t\t\t\t// is fulfilled; preserve the native split/isDone/cursor metadata separately.\n\t\t\t\tcompleteness:\n\t\t\t\t\tresult.pageStatus === 'SplitRequired' && !fulfilled ? 'native-limit' : 'complete',\n\t\t\t}\n\t\tif (!completed.length) throw new ManagedReadError('MANAGED_READ_BUDGET')\n\t\tconst continuation = await encode(completed.at(-1)!)\n\t\treturn {\n\t\t\t...result,\n\t\t\tcompleteness: fulfilled ? 'complete' : this.progress.stopReason,\n\t\t\tisDone: false,\n\t\t\tpageStatus: 'SplitRequired',\n\t\t\tcontinueCursor: continuation,\n\t\t\tsplitCursor: await encode(completed[Math.floor((completed.length - 1) / 2)]),\n\t\t}\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { queryErrors } from "../modules/contracts/errors.mjs";
2
+ //#region src/querying/failures.d.ts
3
+ /**
4
+ * Explicit endpoint adapter for the query.errors policy in createEffectAuthFunctions.
5
+ * Promise handlers must use Effect.tryPromise({ try: () => engine(ctx).table.paginate(args), catch: error => error })
6
+ * so native failures enter the expected-error channel; ordinary throws/rejections remain defects.
7
+ * Ordinary authQuery handlers can throw new ConvexError(queryFailureContract.project(error)) in their catch.
8
+ * Do not throw an already-transported ConvexError inside an Effect builder with a different errors policy:
9
+ * that policy intentionally normalizes foreign failures. Direct engine callers keep their native errors.
10
+ */
11
+ export declare const queryFailureContract: typeof queryErrors;
12
+ //#endregion
13
+ //# sourceMappingURL=failures.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{queryErrors as e}from"../modules/contracts/errors.mjs";import{isQueryFanoutError as t}from"./filters.mjs";import{CursorError as n}from"./cursors.mjs";import{SearchError as r}from"./search.mjs";import{FieldGroupError as i}from"../querying.mjs";const a={...e,project(a){try{return a instanceof r?e.project(e.create(a.code,{})):a instanceof n?e.project(e.create(`invalid-cursor`,{})):a instanceof i?e.project(e.create(`FIELD_GROUP_DENIED`,{})):t(a)?e.project(e.create(`QUERY_FANOUT`,{})):e.project(a)}catch{return{_tag:`UnknownFailure`,version:1}}}};export{a as queryFailureContract};
2
+ //# sourceMappingURL=failures.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failures.mjs","names":["queryFailureContract","queryErrors","error","SearchError","CursorError","FieldGroupError","isQueryFanoutError"],"sources":["../../src/querying/failures.ts"],"sourcesContent":["import { queryErrors } from '../modules/contracts/errors'\nimport { SearchError } from './search'\nimport { CursorError } from './cursors'\nimport { FieldGroupError } from '../querying'\nimport { isQueryFanoutError } from './filters'\n\n/**\n * Explicit endpoint adapter for the query.errors policy in createEffectAuthFunctions.\n * Promise handlers must use Effect.tryPromise({ try: () => engine(ctx).table.paginate(args), catch: error => error })\n * so native failures enter the expected-error channel; ordinary throws/rejections remain defects.\n * Ordinary authQuery handlers can throw new ConvexError(queryFailureContract.project(error)) in their catch.\n * Do not throw an already-transported ConvexError inside an Effect builder with a different errors policy:\n * that policy intentionally normalizes foreign failures. Direct engine callers keep their native errors.\n */\nexport const queryFailureContract: typeof queryErrors = {\n\t...queryErrors,\n\tproject(error) {\n\t\ttry {\n\t\t\tif (error instanceof SearchError)\n\t\t\t\treturn queryErrors.project(queryErrors.create(error.code, {}))\n\t\t\tif (error instanceof CursorError)\n\t\t\t\treturn queryErrors.project(queryErrors.create('invalid-cursor', {}))\n\t\t\tif (error instanceof FieldGroupError)\n\t\t\t\treturn queryErrors.project(queryErrors.create('FIELD_GROUP_DENIED', {}))\n\t\t\tif (isQueryFanoutError(error))\n\t\t\t\treturn queryErrors.project(queryErrors.create('QUERY_FANOUT', {}))\n\t\t\treturn queryErrors.project(error)\n\t\t} catch {\n\t\t\treturn { _tag: 'UnknownFailure', version: 1 }\n\t\t}\n\t},\n}\n"],"mappings":"0PAcA,MAAaA,EAA2C,CACvD,GAAGC,EACH,QAAQ,EAAO,CACd,GAAI,CASH,OARIC,aAAiBC,EACbF,EAAY,QAAQA,EAAY,OAAOC,EAAM,KAAM,CAAC,CAAC,CAAC,EAC1DA,aAAiBE,EACbH,EAAY,QAAQA,EAAY,OAAO,iBAAkB,CAAC,CAAC,CAAC,EAChEC,aAAiBG,EACbJ,EAAY,QAAQA,EAAY,OAAO,qBAAsB,CAAC,CAAC,CAAC,EACpEK,EAAmBJ,CAAK,EACpBD,EAAY,QAAQA,EAAY,OAAO,eAAgB,CAAC,CAAC,CAAC,EAC3DA,EAAY,QAAQC,CAAK,CACjC,MAAQ,CACP,MAAO,CAAE,KAAM,iBAAkB,QAAS,CAAE,CAC7C,CACD,CACD"}
@@ -1,13 +1,11 @@
1
+ import { FilterAst, FilterOperator, FilterScalar } from "./shared/ast.mjs";
2
+ import { FieldSchemas, FilterGrammar, MAX_FILTER_DEPTH, MAX_FILTER_IN_VALUES, MAX_FILTER_NODES, relationFilterSchema } from "./shared/filters.mjs";
1
3
  import { ConvexValidatorFromZod } from "convex-helpers/server/zod4";
2
4
  import { z } from "zod";
3
5
  import { GenericId, GenericValidator } from "convex/values";
4
6
  //#region src/querying/filters.d.ts
5
7
  /** Shared hard ceilings; the execution engine may impose lower budgets. */
6
8
  export declare const MAX_PAGE_SIZE = 100;
7
- export declare const MAX_FILTER_DEPTH = 4;
8
- export declare const MAX_FILTER_NODES = 256;
9
- export declare const MAX_FILTER_IN_VALUES = 100;
10
- export type FieldSchemas = Record<string, z.ZodType>;
11
9
  type NativeField<Schema extends z.ZodType> = ConvexValidatorFromZod<Schema, 'required'>;
12
10
  type ScalarKind = 'id' | 'string' | 'float64' | 'int64' | 'boolean' | 'null' | 'literal';
13
11
  type SupportedNative<Validator extends GenericValidator> = Validator extends {
@@ -57,6 +55,7 @@ export declare const nativePagination: z.ZodObject<{
57
55
  cursor: z.ZodUnion<readonly [z.ZodString, z.ZodNull]>;
58
56
  endCursor: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>;
59
57
  id: z.ZodOptional<z.ZodNumber>;
58
+ onEmptyBudget: z.ZodOptional<z.ZodLiteral<"split">>;
60
59
  numItems: z.ZodNumber;
61
60
  maximumRowsRead: z.ZodOptional<z.ZodNumber>;
62
61
  maximumBytesRead: z.ZodOptional<z.ZodNumber>;
@@ -76,45 +75,6 @@ export type ScalarPaginationSchema<Fields extends FieldSchemas, Selection> = Pag
76
75
  */
77
76
  export declare function scalarPaginationSchema<Fields extends FieldSchemas, const Selection extends ScalarSelection<Fields>>(validators: Record<string, GenericValidator>, selection: ExactScalarSelection<Fields, Selection>): ScalarPaginationSchema<Fields, Selection>;
78
77
  export declare function scalarPredicateSchema(validator: GenericValidator): z.ZodType;
79
- /** Each boolean child and relation target expression consumes one of four edges.
80
- * some/none wrappers and fields namespaces consume nodes, but no extra depth.
81
- */
82
- export interface FilterGrammar {
83
- fields: FieldSchemas;
84
- variants?: {
85
- discriminator: string;
86
- options: Record<string, FilterGrammar>;
87
- };
88
- relations: Record<string, {
89
- cardinality: 'one' | 'many';
90
- target: FilterGrammar;
91
- }>;
92
- }
93
- export declare function relationFilterSchema(grammar: FilterGrammar, cache?: WeakMap<FilterGrammar, Map<number, z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>>): z.ZodType;
94
- export type FilterScalar = string | number | bigint | boolean | null;
95
- export type FilterOperator = 'eq' | 'in' | 'gt' | 'gte' | 'lt' | 'lte' | 'exists';
96
- export type FilterAst = {
97
- kind: 'and' | 'or';
98
- children: FilterAst[];
99
- } | {
100
- kind: 'not';
101
- child: FilterAst;
102
- } | {
103
- kind: 'variant';
104
- discriminator: string;
105
- tag: string;
106
- child: FilterAst;
107
- } | {
108
- kind: 'scalar';
109
- field: string;
110
- operator: FilterOperator;
111
- value: FilterScalar | FilterScalar[];
112
- } | {
113
- kind: 'relation';
114
- name: string;
115
- mode: 'one' | 'some' | 'none';
116
- predicate: FilterAst | null;
117
- };
118
78
  export interface QueryIndex {
119
79
  name: string;
120
80
  fields: readonly string[];
@@ -123,9 +83,30 @@ export interface IndexCondition {
123
83
  value: FilterScalar | undefined;
124
84
  index: string;
125
85
  }
86
+ export interface RangeBound {
87
+ value: FilterScalar;
88
+ inclusive: boolean;
89
+ }
90
+ export interface FieldRange {
91
+ lower?: RangeBound;
92
+ upper?: RangeBound;
93
+ }
94
+ export interface NativeRange extends FieldRange {
95
+ field: string;
96
+ }
97
+ export declare const MAX_INDEX_EXPANSION = 8;
98
+ export interface IndexExpansion {
99
+ field: string;
100
+ values: FilterScalar[];
101
+ comparator: 'tail' | 'full-index';
102
+ }
126
103
  export interface CompiledFilters {
104
+ expansion: IndexExpansion | null;
105
+ sets: ReadonlyMap<string, FilterScalar[]>;
127
106
  residual: FilterAst;
128
107
  bindings: ReadonlyMap<string, FilterScalar>;
108
+ ranges: ReadonlyMap<string, FieldRange>;
109
+ range: NativeRange | null;
129
110
  unsatisfiable: boolean;
130
111
  index: QueryIndex | null;
131
112
  prefix: readonly {
@@ -138,13 +119,26 @@ type FilterSpec<Schema extends z.ZodType> = z.input<Schema> extends {
138
119
  } ? Spec : never;
139
120
  export type ServerFilter<Fields extends FieldSchemas> = ScalarFilters<Fields, ScalarSelection<Fields>>;
140
121
  /** Validate first; where is independently validated and ANDed with client predicates.
141
- * OR remains a residual expression over one traversal, never multiple streams.
122
+ * Only guaranteed sets at one consecutive index position may expand.
142
123
  */
143
124
  export declare function compileFilters<Schema extends z.ZodType>(schema: Schema, input: z.input<Schema>, indexes: readonly QueryIndex[], conditions?: readonly IndexCondition[], where?: FilterSpec<Schema>): CompiledFilters;
144
125
  /** Internal planner boundary: retain the parsed arguments without parsing them again. */
145
- export declare function parseFilterPlan<Schema extends z.ZodType>(schema: Schema, input: z.input<Schema>, indexes: readonly QueryIndex[], conditions?: readonly IndexCondition[], where?: FilterSpec<Schema>): {
126
+ export declare function parseFilterPlan<Schema extends z.ZodType>(schema: Schema, input: z.input<Schema>, indexes: readonly QueryIndex[], conditions?: readonly IndexCondition[], where?: FilterSpec<Schema>, ordering?: string): {
146
127
  args: z.infer<Schema>;
147
128
  compiled: CompiledFilters;
148
129
  };
130
+ export declare function withinRange(value: FilterScalar, range: FieldRange): boolean;
131
+ /** Recompute against the actual stream prefix, including relationship lookup bindings. */
132
+ export declare function rangeForIndex(index: QueryIndex, prefix: readonly {
133
+ field: string;
134
+ value: FilterScalar;
135
+ }[], ranges: ReadonlyMap<string, FieldRange>): NativeRange | null;
136
+ /** Recompute for the actual lookup prefix on direct relationships, too. */
137
+ export declare function expansionForIndex(index: QueryIndex, prefix: readonly {
138
+ field: string;
139
+ value: FilterScalar;
140
+ }[], sets: ReadonlyMap<string, FilterScalar[]>, explicit: boolean): IndexExpansion | null;
141
+ export declare function isQueryFanoutError(error: unknown): boolean;
149
142
  //#endregion
143
+ export { type FieldSchemas, type FilterAst, type FilterGrammar, type FilterOperator, type FilterScalar, MAX_FILTER_DEPTH, MAX_FILTER_IN_VALUES, MAX_FILTER_NODES, relationFilterSchema };
150
144
  //# sourceMappingURL=filters.d.mts.map
@@ -1,2 +1,2 @@
1
- import{convexToZod as e}from"convex-helpers/server/zod4";import{paginationOptsValidator as t}from"convex/server";import{z as n}from"zod";import{compareValues as r}from"convex/values";const i=100,a=4,o=256,s=100,c=e(t),l=c.strict().extend({numItems:c.shape.numItems.int().positive().max(100),maximumRowsRead:c.shape.maximumRowsRead.unwrap().int().positive().optional(),maximumBytesRead:c.shape.maximumBytesRead.unwrap().int().positive().optional()});function u(e,t){let r={};for(let[n,i]of Object.entries(t)){if(i!==!0||!Object.hasOwn(e,n))throw Error(`Invalid scalar filter selection "${n}"`);r[n]=d(e[n]).optional()}let i=D(r);return l.extend({filters:i.optional(),order:n.enum([`asc`,`desc`]).optional()})}function d(t){T(t);let r=e(t).nonoptional(),i=n.object({eq:r.optional(),in:n.array(r).min(1).max(100).optional()}),a=E(t)?i.extend({gt:r.optional(),gte:r.optional(),lt:r.optional(),lte:r.optional()}):i,o=(t.isOptional===`optional`?a.extend({exists:n.boolean().optional()}):a).strict().refine(e=>Object.values(e).some(e=>e!==void 0),`At least one operator is required`);return n.union([r,o])}const f=/* @__PURE__ */ new WeakMap,p=/* @__PURE__ */ new WeakMap,m=/* @__PURE__ */ new WeakMap,h=n.core.$constructor(`BoundedFilterObject`,(e,t)=>{n.ZodObject.init(e,t);let r=e._zod.parse,i=t.shape.fields,a=i instanceof n.ZodOptional?i.unwrap():void 0,o=a instanceof n.ZodObject?Object.keys(a.shape):Object.keys(t.shape),s={variants:p.get(t.shape.variant),fields:Object.fromEntries(o.map(e=>[e,t.shape[e]])),relations:Object.fromEntries(Object.entries(t.shape).flatMap(([e,t])=>{let n=f.get(t);return n?[[e,n]]:[]}))};e._zod.parse=(e,t)=>k(e.value,s)?r(e,t):(e.issues.push({code:`custom`,input:e.value,message:`Unsupported filter layout or depth/node budget exceeded`}),e)});function g(e,t=/* @__PURE__ */ new WeakMap){let n=new h(O(e,0,t)._zod.def);return m.set(n,e),n}function _(e,t,n,r=[],i){return v(e,t,n,r,i).compiled}function v(e,t,n,r=[],i){let a=e.parse(t),o=a,s=i===void 0?void 0:e.parse({...o,filters:i}),c=y(e),l={kind:`and`,children:[b(o.filters,c),b(s?.filters,c)]},u=C(l),d=[...n].sort((e,t)=>e.name.localeCompare(t.name)||e.fields.join(`\0`).localeCompare(t.fields.join(`\0`))),f=r.find(e=>e.value!==null&&e.value!==void 0),p=null;if(f){if(p=d.find(e=>e.name===f.index)??null,!p||w(p,u.values).length===0)throw Error(`Explicit index "${f.index}" is incompatible with guaranteed filters`)}else{let e=0;for(let t of d){let n=w(t,u.values).length;n>e&&(p=t,e=n)}}return{args:a,compiled:{residual:l,bindings:u.values,unsatisfiable:u.impossible,index:p,prefix:p?w(p,u.values):[]}}}function y(e){if(!(e instanceof n.ZodObject))return;let t=e.shape.filters;if(!(t instanceof n.ZodOptional))return;let r=t.unwrap(),i=m.get(r);if(i)return i;if(r instanceof n.ZodObject)return{fields:r.shape,variants:p.get(r.shape.variant),relations:Object.fromEntries(Object.entries(r.shape).flatMap(([e,t])=>{let n=f.get(t);return n?[[e,n]]:[]}))}}function b(e,t){let n=[];if(!e)return{kind:`and`,children:n};let r=e;for(let[e,i]of Object.entries(r))if(i!==void 0){if(e===`and`||e===`or`)n.push({kind:e,children:i.map(e=>b(e,t))});else if(e===`variant`&&t?.variants){let e=i;n.push({kind:`variant`,discriminator:t.variants.discriminator,tag:e.tag,child:b(e.filters,t.variants.options[e.tag])})}else if(e===`not`)n.push({kind:`not`,child:b(i,t)});else if(e===`fields`)for(let[e,t]of Object.entries(i))n.push(...x(e,t));else if(t?.relations[e]){let r=t.relations[e];if(r.cardinality===`one`)n.push({kind:`relation`,name:e,mode:`one`,predicate:i===null?null:b(i,r.target)});else{let t=i;n.push({kind:`relation`,name:e,mode:t.some===void 0?`none`:`some`,predicate:b(t.some??t.none,r.target)})}}else n.push(...x(e,i))}return{kind:`and`,children:n}}function x(e,t){return t===void 0?[]:Object(t)===t?Object.entries(t).filter(([,e])=>e!==void 0).map(([t,n])=>({kind:`scalar`,field:e,operator:t,value:n})):[{kind:`scalar`,field:e,operator:`eq`,value:t}]}function S(e,t){return r(e,t)===0}function C(e){let t=/* @__PURE__ */ new Map;if(e.kind===`variant`)return C({kind:`and`,children:[{kind:`scalar`,field:e.discriminator,operator:`eq`,value:e.tag},e.child]});if(e.kind===`scalar`){e.operator===`eq`&&!Array.isArray(e.value)&&t.set(e.field,e.value);let n=Array.isArray(e.value)?e.value:void 0;return e.operator===`in`&&n&&n.every(e=>S(e,n[0]))&&t.set(e.field,n[0]),{values:t,impossible:!1}}if(e.kind===`not`||e.kind===`relation`)return{values:t,impossible:!1};let n=e.children.map(C);if(e.kind===`or`){let e=n.filter(e=>!e.impossible);for(let[n,r]of e[0]?.values??[])e.every(e=>e.values.has(n)&&S(e.values.get(n),r))&&t.set(n,r);return{values:t,impossible:e.every(e=>e.impossible)}}let r=n.some(e=>e.impossible);for(let e of n)for(let[n,i]of e.values)t.has(n)&&!S(t.get(n),i)&&(r=!0),t.set(n,i);return{values:t,impossible:r}}function w(e,t){let n=[];for(let r of e.fields){if(!t.has(r))break;n.push({field:r,value:t.get(r)})}return n}function T(e){switch(e.kind){case`id`:case`string`:case`float64`:case`int64`:case`boolean`:case`null`:case`literal`:return;case`union`:for(let t of e.members)T(t);return;default:throw Error(`Unsupported scalar filter kind "${e.kind}"`)}}function E(e){switch(e.kind){case`string`:case`float64`:case`int64`:return!0;case`literal`:return n.union([n.string(),n.number(),n.bigint()]).safeParse(e.value).success;case`union`:return e.members.every(E);default:return!1}}function D(e){return g({fields:e,relations:{}})}function O(e,t,r=/* @__PURE__ */ new WeakMap){let i=r.get(e)?.get(t);if(i)return i;let a=e.fields,o=Object.fromEntries(Object.entries(a).filter(([t])=>![`and`,`or`,`not`,`fields`,...e.variants?[`variant`]:[]].includes(t))),s={};for(let[i,a]of Object.entries(e.relations)){if(t===4)continue;let e=O(a.target,t+1,r);s[i]=(a.cardinality===`one`?e.nullable():n.union([n.object({some:e}).strict(),n.object({none:e}).strict()])).optional(),f.set(s[i],a)}if(e.variants&&t<4){let i=Object.entries(e.variants.options).map(([e,i])=>n.strictObject({tag:n.literal(e),filters:O(i,t+1,r)}));i.length&&(s.variant=n.union(i).optional(),p.set(s.variant,e.variants))}let c=n.object({...o,...s,fields:n.object(a).strict().optional()}).strict(),l=t===4?void 0:O(e,t+1,r),u=l?c.extend({and:n.array(l).min(1).max(256).optional(),or:n.array(l).min(1).max(256).optional(),not:l.optional()}):c,d=r.get(e);return d||(d=/* @__PURE__ */ new Map,r.set(e,d)),d.set(t,u),u}function k(e,t){let r=[{value:e,depth:0,context:`expression`,grammar:t}],i=0;for(;r.length;){let e=r.pop();if(++i>256||e.depth>4)return!1;if(Object(e.value)!==e.value)continue;let t=e.value,a=Array.isArray(t)?t:void 0,o=Object.getPrototypeOf(t);if((a?o!==Array.prototype:o!==Object.prototype&&o!==null)||a&&a.length+i+r.length>256)return!1;let s=Reflect.ownKeys(t);if(s.length-+!!a+i+r.length>256||a&&s.length!==a.length+1)return!1;let c;switch(e.context){case`expression`:c=[...Object.keys(e.grammar.fields),...Object.keys(e.grammar.relations),`and`,`or`,`not`,`fields`,...e.grammar.variants?[`variant`]:[]];break;case`variant`:c=[`tag`,`filters`];break;case`fields`:c=Object.keys(e.grammar.fields);break;case`predicate`:c=[`eq`,`in`,`gt`,`gte`,`lt`,`lte`,`exists`];break;case`many`:c=[`some`,`none`];break;default:c=[]}for(let e of c)if(!Object.hasOwn(t,e)&&e in t)return!1;for(let i of s){if(a&&i===`length`)continue;let o=Object.getOwnPropertyDescriptor(t,i),s=String(i);if(!o.enumerable||!(`value`in o)||s!==i||a&&(!/^(0|[1-9]\d*)$/.test(s)||Number(s)>=a.length))return!1;let c=`value`,l=e.depth,u=e.grammar;if(e.context===`expression`){if(c=`predicate`,s===`variant`&&e.grammar.variants)c=`variant`,l++;else if(s===`fields`)c=`fields`;else if(s===`and`||s===`or`)c=`composition`,l++;else if(s===`not`)c=`expression`,l++;else if(e.grammar.relations[s]){let t=e.grammar.relations[s];c=t.cardinality===`one`?`expression`:`many`,u=t.target,l++}}else if(e.context===`variant`&&s===`filters`){let r=Object.getOwnPropertyDescriptor(t,`tag`);if(!r||!(`value`in r)||!n.string().safeParse(r.value).success||!Object.hasOwn(e.grammar.variants?.options??{},r.value))return!1;c=`expression`,u=e.grammar.variants.options[String(r.value)]}else e.context===`fields`?c=`predicate`:(e.context===`composition`||e.context===`many`)&&(c=`expression`);r.push({value:o.value,depth:l,context:c,grammar:u})}}return!0}export{a as MAX_FILTER_DEPTH,s as MAX_FILTER_IN_VALUES,o as MAX_FILTER_NODES,i as MAX_PAGE_SIZE,_ as compileFilters,l as nativePagination,v as parseFilterPlan,g as relationFilterSchema,u as scalarPaginationSchema,d as scalarPredicateSchema};
1
+ import{MAX_FILTER_DEPTH as e,MAX_FILTER_IN_VALUES as t,MAX_FILTER_NODES as n,boundedFilterSchema as r,normalizeFilters as i,paginationGrammar as a,relationFilterSchema as o,scalarPredicateFromSchema as s}from"./shared/filters.mjs";import{valueEqual as c}from"./shared/ast.mjs";import{convexToZod as l}from"convex-helpers/server/zod4";import{paginationOptsValidator as u}from"convex/server";import{z as d}from"zod";import{compareValues as f}from"convex/values";const p=100,m=l(u),h=m.strict().extend({onEmptyBudget:d.literal(`split`).optional(),numItems:m.shape.numItems.int().positive().max(100),maximumRowsRead:m.shape.maximumRowsRead.unwrap().int().positive().optional(),maximumBytesRead:m.shape.maximumBytesRead.unwrap().int().positive().optional()});function g(e,t){let n={};for(let[r,i]of Object.entries(t)){if(i!==!0||!Object.hasOwn(e,r))throw Error(`Invalid scalar filter selection "${r}"`);n[r]=_(e[r]).optional()}let i=r(n);return h.extend({filters:i.optional(),order:d.enum([`asc`,`desc`]).optional()})}function _(e){M(e);let t=l(e).nonoptional();return s(t,N(e),e.isOptional===`optional`)}const v=8;function y(e,t,n,r=[],i){return b(e,t,n,r,i).compiled}function b(e,t,n,r=[],o,s){let l=e.parse(t),u=l,d=o===void 0?void 0:e.parse({...u,filters:o}),p=a(e),m={kind:`and`,children:[E(i(u.filters,p)),E(i(d?.filters,p))]},h=k(m),g=A(m),_=O(m);for(let[e,t]of _){let n=t.filter(t=>(!h.values.has(e)||c(t,h.values.get(e)))&&(!g.has(e)||x(t,g.get(e))));_.set(e,n),n.length||(h.impossible=!0)}for(let[e,t]of g){if(t.lower&&t.upper){let e=f(t.lower.value,t.upper.value);(e>0||e===0&&(!t.lower.inclusive||!t.upper.inclusive))&&(h.impossible=!0)}h.values.has(e)&&!x(h.values.get(e),t)&&(h.impossible=!0)}let v=[...n].sort((e,t)=>e.name.localeCompare(t.name)||e.fields.join(`\0`).localeCompare(t.fields.join(`\0`))),y=r.find(e=>e.value!==null&&e.value!==void 0),b=null;if(s!==void 0){if(y)throw Error(`orderBy cannot be combined with an active when selector`);if(b=v.find(e=>e.name===s)??null,!b)throw Error(`Unknown ordering index "${s}"`)}else if(y){if(b=v.find(e=>e.name===y.index)??null,!b||j(b,h.values).length===0)throw Error(`Explicit index "${y.index}" is incompatible with guaranteed filters`)}else{let e=0,t=!1;for(let n of v){let r=j(n,h.values),i=_.has(n.fields[r.length]),a=r.length+Number(i),o=g.has(n.fields[a]);(a>e||a===e&&o&&!t)&&(b=n,e=a,t=o)}}let w=b?j(b,h.values):[];return{args:l,compiled:{sets:_,expansion:b&&!h.impossible?C(b,w,_,s!==void 0||!!y):null,residual:m,bindings:h.values,ranges:g,range:b?S(b,j(b,h.values),g):null,unsatisfiable:h.impossible,index:b,prefix:b?j(b,h.values):[]}}}function x(e,t){let n=t.lower&&f(e,t.lower.value),r=t.upper&&f(e,t.upper.value);return(n===void 0||n>0||n===0&&t.lower.inclusive)&&(r===void 0||r<0||r===0&&t.upper.inclusive)}function S(e,t,n){let r=e.fields[t.length],i=n.get(r);return i?{field:r,...i}:null}function C(e,t,n,r){let i=e.fields[t.length],a=n.get(i);if(!a?.length)return null;if(a.length>8){if(r)return null;let e=/* @__PURE__ */ Error(`QUERY_FANOUT`);throw w.add(e),e}return{field:i,values:a,comparator:r?`full-index`:`tail`}}const w=/* @__PURE__ */ new WeakSet;function T(e){return e instanceof Error&&w.has(e)}function E(e){if(e.kind===`scalar`&&e.operator===`in`&&Array.isArray(e.value))return{...e,value:D(e.value)};if(e.kind===`and`||e.kind===`or`){let t=e.children.map(E),n=e=>{if(e.kind===`scalar`&&e.operator===`eq`&&!Array.isArray(e.value))return{field:e.field,value:e.value};if(e.kind===`and`&&e.children.length===1)return n(e.children[0])},r=t.map(n),i=r[0];return e.kind===`or`&&i&&r.every(e=>e?.field===i.field)?{kind:`scalar`,field:i.field,operator:`in`,value:D(r.map(e=>e.value))}:{...e,children:t}}return e.kind===`not`||e.kind===`variant`?{...e,child:E(e.child)}:e.kind===`relation`&&e.predicate?{...e,predicate:E(e.predicate)}:e}function D(e){return[...e].sort(f).filter((e,t,n)=>t===0||!c(e,n[t-1]))}function O(e,t=/* @__PURE__ */ new Map){if(e.kind===`and`)for(let n of e.children)O(n,t);else if(e.kind===`variant`)O(e.child,t);else if(e.kind===`scalar`&&e.operator===`in`&&Array.isArray(e.value)){let n=t.get(e.field);t.set(e.field,n?e.value.filter(e=>n.some(t=>c(e,t))):e.value)}return t}function k(e){let t=/* @__PURE__ */ new Map;if(e.kind===`variant`)return k({kind:`and`,children:[{kind:`scalar`,field:e.discriminator,operator:`eq`,value:e.tag},e.child]});if(e.kind===`scalar`){e.operator===`eq`&&!Array.isArray(e.value)&&t.set(e.field,e.value);let n=Array.isArray(e.value)?e.value:void 0;return e.operator===`in`&&n?.length&&n.every(e=>c(e,n[0]))&&t.set(e.field,n[0]),{values:t,impossible:e.operator===`in`&&n?.length===0}}if(e.kind===`not`||e.kind===`relation`)return{values:t,impossible:!1};let n=e.children.map(k);if(e.kind===`or`){let e=n.filter(e=>!e.impossible);for(let[n,r]of e[0]?.values??[])e.every(e=>e.values.has(n)&&c(e.values.get(n),r))&&t.set(n,r);return{values:t,impossible:e.every(e=>e.impossible)}}let r=n.some(e=>e.impossible);for(let e of n)for(let[n,i]of e.values)t.has(n)&&!c(t.get(n),i)&&(r=!0),t.set(n,i);return{values:t,impossible:r}}function A(e,t=/* @__PURE__ */ new Map){if(e.kind===`and`)for(let n of e.children)A(n,t);else if(e.kind===`variant`)A(e.child,t);else if(e.kind===`scalar`&&!Array.isArray(e.value)){let n=e.operator===`gt`||e.operator===`gte`,r=e.operator===`lt`||e.operator===`lte`;if(n||r){let r=t.get(e.field)??{},i=n?`lower`:`upper`,a={value:e.value,inclusive:e.operator===`gte`||e.operator===`lte`},o=r[i],s=o?f(a.value,o.value):0;(!o||(n?s>0:s<0)||s===0&&!a.inclusive)&&(r[i]=a),t.set(e.field,r)}}return t}function j(e,t){let n=[];for(let r of e.fields){if(!t.has(r))break;n.push({field:r,value:t.get(r)})}return n}function M(e){switch(e.kind){case`id`:case`string`:case`float64`:case`int64`:case`boolean`:case`null`:case`literal`:return;case`union`:for(let t of e.members)M(t);return;default:throw Error(`Unsupported scalar filter kind "${e.kind}"`)}}function N(e){switch(e.kind){case`string`:case`float64`:case`int64`:return!0;case`literal`:return d.union([d.string(),d.number(),d.bigint()]).safeParse(e.value).success;case`union`:return e.members.every(N);default:return!1}}export{e as MAX_FILTER_DEPTH,t as MAX_FILTER_IN_VALUES,n as MAX_FILTER_NODES,v as MAX_INDEX_EXPANSION,p as MAX_PAGE_SIZE,y as compileFilters,C as expansionForIndex,T as isQueryFanoutError,h as nativePagination,b as parseFilterPlan,S as rangeForIndex,o as relationFilterSchema,g as scalarPaginationSchema,_ as scalarPredicateSchema,x as withinRange};
2
2
  //# sourceMappingURL=filters.mjs.map