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,2 +1,2 @@
1
- import{zid as e,zodToConvex as t}from"convex-helpers/server/zod4";import{z as n}from"zod";const r=/* @__PURE__ */ new Map;u(`object`,n.ZodObject),u(`array`,n.ZodArray),u(`optional`,n.ZodOptional),u(`exactOptional`,n.ZodExactOptional),u(`nullable`,n.ZodNullable),u(`nonoptional`,n.ZodNonOptional),u(`union`,n.ZodUnion),u(`discriminatedUnion`,n.ZodDiscriminatedUnion),u(`tuple`,n.ZodTuple),u(`record`,n.ZodRecord),u(`string`,n.ZodString),u(`number`,n.ZodNumber),u(`boolean`,n.ZodBoolean),u(`bigint`,n.ZodBigInt),u(`null`,n.ZodNull),u(`never`,n.ZodNever),u(`literal`,n.ZodLiteral),u(`enum`,n.ZodEnum),u(`custom`,n.ZodCustom),u(`minLength`,n.core.$ZodCheckMinLength),u(`maxLength`,n.core.$ZodCheckMaxLength),u(`length`,n.core.$ZodCheckLengthEquals),u(`lessThan`,n.core.$ZodCheckLessThan),u(`greaterThan`,n.core.$ZodCheckGreaterThan),u(`multipleOf`,n.core.$ZodCheckMultipleOf),u(`checkNumberFormat`,n.core.$ZodCheckNumberFormat),u(`checkBigintFormat`,n.core.$ZodCheckBigIntFormat),u(`stringFormat`,n.core.$ZodCheckStringFormat),u(`regex`,n.core.$ZodCheckRegex),u(`lowercase`,n.core.$ZodCheckLowerCase),u(`uppercase`,n.core.$ZodCheckUpperCase),u(`includes`,n.core.$ZodCheckIncludes),u(`startsWith`,n.core.$ZodCheckStartsWith),u(`endsWith`,n.core.$ZodCheckEndsWith),u(`property`,n.core.$ZodCheckProperty),u(`properties`,n.core.$ZodCheckProperties),u(`numberFormat`,n.ZodNumberFormat),u(`bigintFormat`,n.ZodBigIntFormat),u(`coreEmail`,n.core.$ZodEmail),u(`coreGUID`,n.core.$ZodGUID),u(`coreUUID`,n.core.$ZodUUID),u(`coreURL`,n.core.$ZodURL),u(`coreEmoji`,n.core.$ZodEmoji),u(`coreNanoID`,n.core.$ZodNanoID),u(`coreCUID`,n.core.$ZodCUID),u(`coreCUID2`,n.core.$ZodCUID2),u(`coreULID`,n.core.$ZodULID),u(`coreXID`,n.core.$ZodXID),u(`coreKSUID`,n.core.$ZodKSUID),u(`coreIPv4`,n.core.$ZodIPv4),u(`coreIPv6`,n.core.$ZodIPv6),u(`coreMAC`,n.core.$ZodMAC),u(`coreCIDRv4`,n.core.$ZodCIDRv4),u(`coreCIDRv6`,n.core.$ZodCIDRv6),u(`coreBase64`,n.core.$ZodBase64),u(`coreBase64URL`,n.core.$ZodBase64URL),u(`coreE164`,n.core.$ZodE164),u(`coreJWT`,n.core.$ZodJWT),u(`coreISODateTime`,n.core.$ZodISODateTime),u(`coreISODate`,n.core.$ZodISODate),u(`coreISOTime`,n.core.$ZodISOTime),u(`coreISODuration`,n.core.$ZodISODuration),u(`coreCreditCard`,n.core.$ZodCreditCard),u(`coreIBAN`,n.core.$ZodIBAN),u(`coreCustomStringFormat`,n.core.$ZodCustomStringFormat),u(`email`,n.ZodEmail),u(`guid`,n.ZodGUID),u(`uuid`,n.ZodUUID),u(`url`,n.ZodURL),u(`emoji`,n.ZodEmoji),u(`nanoid`,n.ZodNanoID),u(`cuid`,n.ZodCUID),u(`cuid2`,n.ZodCUID2),u(`ulid`,n.ZodULID),u(`xid`,n.ZodXID),u(`ksuid`,n.ZodKSUID),u(`ipv4`,n.ZodIPv4),u(`ipv6`,n.ZodIPv6),u(`mac`,n.ZodMAC),u(`cidrv4`,n.ZodCIDRv4),u(`cidrv6`,n.ZodCIDRv6),u(`base64`,n.ZodBase64),u(`base64url`,n.ZodBase64URL),u(`e164`,n.ZodE164),u(`jwt`,n.ZodJWT),u(`isoDateTime`,n.ZodISODateTime),u(`isoDate`,n.ZodISODate),u(`isoTime`,n.ZodISOTime),u(`isoDuration`,n.ZodISODuration),u(`creditCard`,n.ZodCreditCard),u(`iban`,n.ZodIBAN),u(`customStringFormat`,n.ZodCustomStringFormat);const i=[...r.entries()].reverse();function a(e){let t=/* @__PURE__ */ new WeakMap,r=/* @__PURE__ */ new WeakSet,a=0;function o(e,s){if(e===null||Object(e)!==e||e instanceof Function)return Object.freeze({kind:`value`,value:e});let c=e;if(r.has(c))throw Error(`Unsupported cyclic DTO schema`);let u=t.get(c);if(u)return u;if(s>64||++a>8192)throw Error(`DTO schema graph budget exceeded`);r.add(c);let d;if(e instanceof RegExp)d={kind:`regexp`,source:e.source,flags:e.flags};else if(e instanceof n.core.$ZodType||e instanceof n.core.$ZodCheck){if(e instanceof n.core.$ZodCheck&&e._zod.def.check===`custom`&&!(e instanceof n.ZodCustom))throw Error(`Unsupported opaque DTO check/superRefine; use .refine() instead`);let t=i.find(([,t])=>t.matches(e));if(!t)throw Error(`Unsupported DTO schema or check`);let r;if(e instanceof n.ZodCustom){let t=l(e);t.kind===`id`&&(r=t.tableName)}let a=e instanceof n.ZodObject?{...e._zod.def,shape:e.shape}:e._zod.def;d={kind:`node`,constructor:t[0],definition:o(a,s+1),id:r}}else if(Array.isArray(e))d={kind:`array`,items:Object.freeze(e.map(e=>o(e,s+1)))};else{if(Object.hasOwn(c,`_zod`))throw Error(`Unsupported opaque DTO check/superRefine; use .refine() instead`);if(Object.getPrototypeOf(e)!==Object.prototype&&Object.getPrototypeOf(e)!==null)throw Error(`Unsupported DTO definition object`);let t=[];for(let e of Reflect.ownKeys(c)){if(String(e)!==e)throw Error(`Unsupported DTO definition symbol`);let n=Object.getOwnPropertyDescriptor(c,e);if(!(`value`in n))throw Error(`Unsupported DTO schema accessor`);t.push(Object.freeze([e,o(n.value,s+1)]))}d={kind:`record`,entries:Object.freeze(t)}}return r.delete(c),Object.freeze(d),t.set(c,d),d}return Object.freeze({root:o(e,0)})}const o=/* @__PURE__ */ new WeakMap;function s(t){let n=o.get(t);if(n)return n;let i;switch(t.kind){case`value`:i=()=>t.value;break;case`regexp`:i=()=>new RegExp(t.source,t.flags);break;case`array`:{let e=t.items.map(s);i=()=>e.map(e=>e());break}case`record`:{let e=t.entries.map(([e,t])=>[e,s(t)]);i=()=>Object.fromEntries(e.map(([e,t])=>[e,t()]));break}case`node`:{let n=s(t.definition);if(t.id!==void 0){let r=t.id;i=()=>{let t=n(),i=e(r);if(t instanceof Object&&`checks`in t){let e=t.checks;if(Array.isArray(e))return i.check(...e)}return i}}else{let e=r.get(t.constructor);i=()=>e.create(n())}break}}return o.set(t,i),i}function c(e){let t=s(e.root)();if(!(t instanceof n.ZodType))throw Error(`Expected classic DTO schema`);return t}function l(e){return t(e)}function u(e,t){t!==void 0&&r.set(e,{matches:e=>e instanceof t,create:e=>new t(e)})}export{a as captureDto,c as materializeDto};
1
+ import{zodToConvex as e}from"../zod-convex.mjs";import{zid as t}from"convex-helpers/server/zod4";import{z as n}from"zod";const r=/* @__PURE__ */ new Map;u(`object`,n.ZodObject),u(`array`,n.ZodArray),u(`optional`,n.ZodOptional),u(`exactOptional`,n.ZodExactOptional),u(`nullable`,n.ZodNullable),u(`nonoptional`,n.ZodNonOptional),u(`union`,n.ZodUnion),u(`discriminatedUnion`,n.ZodDiscriminatedUnion),u(`tuple`,n.ZodTuple),u(`record`,n.ZodRecord),u(`string`,n.ZodString),u(`number`,n.ZodNumber),u(`boolean`,n.ZodBoolean),u(`bigint`,n.ZodBigInt),u(`null`,n.ZodNull),u(`never`,n.ZodNever),u(`literal`,n.ZodLiteral),u(`enum`,n.ZodEnum),u(`custom`,n.ZodCustom),u(`minLength`,n.core.$ZodCheckMinLength),u(`maxLength`,n.core.$ZodCheckMaxLength),u(`length`,n.core.$ZodCheckLengthEquals),u(`lessThan`,n.core.$ZodCheckLessThan),u(`greaterThan`,n.core.$ZodCheckGreaterThan),u(`multipleOf`,n.core.$ZodCheckMultipleOf),u(`checkNumberFormat`,n.core.$ZodCheckNumberFormat),u(`checkBigintFormat`,n.core.$ZodCheckBigIntFormat),u(`stringFormat`,n.core.$ZodCheckStringFormat),u(`regex`,n.core.$ZodCheckRegex),u(`lowercase`,n.core.$ZodCheckLowerCase),u(`uppercase`,n.core.$ZodCheckUpperCase),u(`includes`,n.core.$ZodCheckIncludes),u(`startsWith`,n.core.$ZodCheckStartsWith),u(`endsWith`,n.core.$ZodCheckEndsWith),u(`property`,n.core.$ZodCheckProperty),u(`properties`,n.core.$ZodCheckProperties),u(`numberFormat`,n.ZodNumberFormat),u(`bigintFormat`,n.ZodBigIntFormat),u(`coreEmail`,n.core.$ZodEmail),u(`coreGUID`,n.core.$ZodGUID),u(`coreUUID`,n.core.$ZodUUID),u(`coreURL`,n.core.$ZodURL),u(`coreEmoji`,n.core.$ZodEmoji),u(`coreNanoID`,n.core.$ZodNanoID),u(`coreCUID`,n.core.$ZodCUID),u(`coreCUID2`,n.core.$ZodCUID2),u(`coreULID`,n.core.$ZodULID),u(`coreXID`,n.core.$ZodXID),u(`coreKSUID`,n.core.$ZodKSUID),u(`coreIPv4`,n.core.$ZodIPv4),u(`coreIPv6`,n.core.$ZodIPv6),u(`coreMAC`,n.core.$ZodMAC),u(`coreCIDRv4`,n.core.$ZodCIDRv4),u(`coreCIDRv6`,n.core.$ZodCIDRv6),u(`coreBase64`,n.core.$ZodBase64),u(`coreBase64URL`,n.core.$ZodBase64URL),u(`coreE164`,n.core.$ZodE164),u(`coreJWT`,n.core.$ZodJWT),u(`coreISODateTime`,n.core.$ZodISODateTime),u(`coreISODate`,n.core.$ZodISODate),u(`coreISOTime`,n.core.$ZodISOTime),u(`coreISODuration`,n.core.$ZodISODuration),u(`coreCreditCard`,n.core.$ZodCreditCard),u(`coreIBAN`,n.core.$ZodIBAN),u(`coreCustomStringFormat`,n.core.$ZodCustomStringFormat),u(`email`,n.ZodEmail),u(`guid`,n.ZodGUID),u(`uuid`,n.ZodUUID),u(`url`,n.ZodURL),u(`emoji`,n.ZodEmoji),u(`nanoid`,n.ZodNanoID),u(`cuid`,n.ZodCUID),u(`cuid2`,n.ZodCUID2),u(`ulid`,n.ZodULID),u(`xid`,n.ZodXID),u(`ksuid`,n.ZodKSUID),u(`ipv4`,n.ZodIPv4),u(`ipv6`,n.ZodIPv6),u(`mac`,n.ZodMAC),u(`cidrv4`,n.ZodCIDRv4),u(`cidrv6`,n.ZodCIDRv6),u(`base64`,n.ZodBase64),u(`base64url`,n.ZodBase64URL),u(`e164`,n.ZodE164),u(`jwt`,n.ZodJWT),u(`isoDateTime`,n.ZodISODateTime),u(`isoDate`,n.ZodISODate),u(`isoTime`,n.ZodISOTime),u(`isoDuration`,n.ZodISODuration),u(`creditCard`,n.ZodCreditCard),u(`iban`,n.ZodIBAN),u(`customStringFormat`,n.ZodCustomStringFormat);const i=[...r.entries()].reverse();function a(e){let t=/* @__PURE__ */ new WeakMap,r=/* @__PURE__ */ new WeakSet,a=0;function o(e,s){if(e===null||Object(e)!==e||e instanceof Function)return Object.freeze({kind:`value`,value:e});let c=e;if(r.has(c))throw Error(`Unsupported cyclic DTO schema`);let u=t.get(c);if(u)return u;if(s>64||++a>8192)throw Error(`DTO schema graph budget exceeded`);r.add(c);let d;if(e instanceof RegExp)d={kind:`regexp`,source:e.source,flags:e.flags};else if(e instanceof n.core.$ZodType||e instanceof n.core.$ZodCheck){if(e instanceof n.core.$ZodCheck&&e._zod.def.check===`custom`&&!(e instanceof n.ZodCustom))throw Error(`Unsupported opaque DTO check/superRefine; use .refine() instead`);let t=i.find(([,t])=>t.matches(e));if(!t)throw Error(`Unsupported DTO schema or check`);let r;if(e instanceof n.ZodCustom){let t=l(e);t.kind===`id`&&(r=t.tableName)}let a=e instanceof n.ZodObject?{...e._zod.def,shape:e.shape}:e._zod.def;d={kind:`node`,constructor:t[0],definition:o(a,s+1),id:r}}else if(Array.isArray(e))d={kind:`array`,items:Object.freeze(e.map(e=>o(e,s+1)))};else{if(Object.hasOwn(c,`_zod`))throw Error(`Unsupported opaque DTO check/superRefine; use .refine() instead`);if(Object.getPrototypeOf(e)!==Object.prototype&&Object.getPrototypeOf(e)!==null)throw Error(`Unsupported DTO definition object`);let t=[];for(let e of Reflect.ownKeys(c)){if(String(e)!==e)throw Error(`Unsupported DTO definition symbol`);let n=Object.getOwnPropertyDescriptor(c,e);if(!(`value`in n))throw Error(`Unsupported DTO schema accessor`);t.push(Object.freeze([e,o(n.value,s+1)]))}d={kind:`record`,entries:Object.freeze(t)}}return r.delete(c),Object.freeze(d),t.set(c,d),d}return Object.freeze({root:o(e,0)})}const o=/* @__PURE__ */ new WeakMap;function s(e){let n=o.get(e);if(n)return n;let i;switch(e.kind){case`value`:i=()=>e.value;break;case`regexp`:i=()=>new RegExp(e.source,e.flags);break;case`array`:{let t=e.items.map(s);i=()=>t.map(e=>e());break}case`record`:{let t=e.entries.map(([e,t])=>[e,s(t)]);i=()=>Object.fromEntries(t.map(([e,t])=>[e,t()]));break}case`node`:{let n=s(e.definition);if(e.id!==void 0){let r=e.id;i=()=>{let e=n(),i=t(r);if(e instanceof Object&&`checks`in e){let t=e.checks;if(Array.isArray(t))return i.check(...t)}return i}}else{let t=r.get(e.constructor);i=()=>t.create(n())}break}}return o.set(e,i),i}function c(e){let t=s(e.root)();if(!(t instanceof n.ZodType))throw Error(`Expected classic DTO schema`);return t}function l(t){return e(t)}function u(e,t){t!==void 0&&r.set(e,{matches:e=>e instanceof t,create:e=>new t(e)})}export{a as captureDto,c as materializeDto};
2
2
  //# sourceMappingURL=schema-snapshot.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-snapshot.mjs","names":["constructors","register","z","dispatch","captureDto","seen","active","nodes","capture","value","object","cached","depth","recipe","entry","constructor","id","native","nativeValidator","definition","child","entries","key","descriptor","schema","factories","compile","factory","items","item","restored","result","zid","checks","materializeDto","zodToConvex","Constructor","name","node"],"sources":["../../src/querying/schema-snapshot.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { GenericValidator } from 'convex/values'\nimport { zid, zodToConvex } from 'convex-helpers/server/zod4'\n\n// Recipes contain semantic definitions only. No source parser, constructor,\n// parent, hooks or lazy caches survive registration.\ntype Recipe =\n\t| { readonly kind: 'value'; readonly value: unknown }\n\t| { readonly kind: 'array'; readonly items: readonly Recipe[] }\n\t| { readonly kind: 'record'; readonly entries: readonly (readonly [string, Recipe])[] }\n\t| { readonly kind: 'regexp'; readonly source: string; readonly flags: string }\n\t| {\n\t\t\treadonly kind: 'node'\n\t\t\treadonly constructor: string\n\t\t\treadonly definition: Recipe\n\t\t\treadonly id?: string\n\t }\n\nexport interface DtoRecipe<Schema extends z.ZodType = z.ZodType> {\n\treadonly schemaType?: Schema\n\treadonly root: Recipe\n}\n\ntype Node = z.core.$ZodType | z.core.$ZodCheck\nconst constructors = new Map<\n\tstring,\n\t{\n\t\tmatches(node: Node): boolean\n\t\t// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Only recipe-restored semantic definitions enter the selected installed constructor.\n\t\tcreate(definition: unknown): Node\n\t}\n>()\n// Base classes precede specialized classes so the most specific installed\n// constructor wins. Never consult a caller's _zod.constr or constructor property.\nregister('object', z.ZodObject)\nregister('array', z.ZodArray)\nregister('optional', z.ZodOptional)\nregister('exactOptional', z.ZodExactOptional)\nregister('nullable', z.ZodNullable)\nregister('nonoptional', z.ZodNonOptional)\nregister('union', z.ZodUnion)\nregister('discriminatedUnion', z.ZodDiscriminatedUnion)\nregister('tuple', z.ZodTuple)\nregister('record', z.ZodRecord)\nregister('string', z.ZodString)\nregister('number', z.ZodNumber)\nregister('boolean', z.ZodBoolean)\nregister('bigint', z.ZodBigInt)\nregister('null', z.ZodNull)\nregister('never', z.ZodNever)\nregister('literal', z.ZodLiteral)\nregister('enum', z.ZodEnum)\nregister('custom', z.ZodCustom)\nregister('minLength', z.core.$ZodCheckMinLength)\nregister('maxLength', z.core.$ZodCheckMaxLength)\nregister('length', z.core.$ZodCheckLengthEquals)\nregister('lessThan', z.core.$ZodCheckLessThan)\nregister('greaterThan', z.core.$ZodCheckGreaterThan)\nregister('multipleOf', z.core.$ZodCheckMultipleOf)\nregister('checkNumberFormat', z.core.$ZodCheckNumberFormat)\nregister('checkBigintFormat', z.core.$ZodCheckBigIntFormat)\nregister('stringFormat', z.core.$ZodCheckStringFormat)\nregister('regex', z.core.$ZodCheckRegex)\nregister('lowercase', z.core.$ZodCheckLowerCase)\nregister('uppercase', z.core.$ZodCheckUpperCase)\nregister('includes', z.core.$ZodCheckIncludes)\nregister('startsWith', z.core.$ZodCheckStartsWith)\nregister('endsWith', z.core.$ZodCheckEndsWith)\nregister('property', z.core.$ZodCheckProperty)\nregister('properties', z.core.$ZodCheckProperties)\nregister('numberFormat', z.ZodNumberFormat)\nregister('bigintFormat', z.ZodBigIntFormat)\n// Format schemas are also checks; preserve their implicit checks, including\n// URL/JWT validation which cannot be represented by a regex alone.\nregister('coreEmail', z.core.$ZodEmail)\nregister('coreGUID', z.core.$ZodGUID)\nregister('coreUUID', z.core.$ZodUUID)\nregister('coreURL', z.core.$ZodURL)\nregister('coreEmoji', z.core.$ZodEmoji)\nregister('coreNanoID', z.core.$ZodNanoID)\nregister('coreCUID', z.core.$ZodCUID)\nregister('coreCUID2', z.core.$ZodCUID2)\nregister('coreULID', z.core.$ZodULID)\nregister('coreXID', z.core.$ZodXID)\nregister('coreKSUID', z.core.$ZodKSUID)\nregister('coreIPv4', z.core.$ZodIPv4)\nregister('coreIPv6', z.core.$ZodIPv6)\nregister('coreMAC', z.core.$ZodMAC)\nregister('coreCIDRv4', z.core.$ZodCIDRv4)\nregister('coreCIDRv6', z.core.$ZodCIDRv6)\nregister('coreBase64', z.core.$ZodBase64)\nregister('coreBase64URL', z.core.$ZodBase64URL)\nregister('coreE164', z.core.$ZodE164)\nregister('coreJWT', z.core.$ZodJWT)\nregister('coreISODateTime', z.core.$ZodISODateTime)\nregister('coreISODate', z.core.$ZodISODate)\nregister('coreISOTime', z.core.$ZodISOTime)\nregister('coreISODuration', z.core.$ZodISODuration)\nregister('coreCreditCard', z.core.$ZodCreditCard)\nregister('coreIBAN', z.core.$ZodIBAN)\nregister('coreCustomStringFormat', z.core.$ZodCustomStringFormat)\nregister('email', z.ZodEmail)\nregister('guid', z.ZodGUID)\nregister('uuid', z.ZodUUID)\nregister('url', z.ZodURL)\nregister('emoji', z.ZodEmoji)\nregister('nanoid', z.ZodNanoID)\nregister('cuid', z.ZodCUID)\nregister('cuid2', z.ZodCUID2)\nregister('ulid', z.ZodULID)\nregister('xid', z.ZodXID)\nregister('ksuid', z.ZodKSUID)\nregister('ipv4', z.ZodIPv4)\nregister('ipv6', z.ZodIPv6)\nregister('mac', z.ZodMAC)\nregister('cidrv4', z.ZodCIDRv4)\nregister('cidrv6', z.ZodCIDRv6)\nregister('base64', z.ZodBase64)\nregister('base64url', z.ZodBase64URL)\nregister('e164', z.ZodE164)\nregister('jwt', z.ZodJWT)\nregister('isoDateTime', z.ZodISODateTime)\nregister('isoDate', z.ZodISODate)\nregister('isoTime', z.ZodISOTime)\nregister('isoDuration', z.ZodISODuration)\nregister('creditCard', z.ZodCreditCard)\nregister('iban', z.ZodIBAN)\nregister('customStringFormat', z.ZodCustomStringFormat)\nconst dispatch = [...constructors.entries()].reverse()\n\nexport function captureDto<Schema extends z.ZodType>(schema: Schema): DtoRecipe<Schema> {\n\tconst seen = new WeakMap<object, Recipe>()\n\tconst active = new WeakSet<object>()\n\tlet nodes = 0\n\t// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Recursively decode preflighted Zod definitions into owned recipes.\n\tfunction capture(value: unknown, depth: number): Recipe {\n\t\tif (value === null || Object(value) !== value || value instanceof Function)\n\t\t\treturn Object.freeze({ kind: 'value', value })\n\t\t// SAFETY: the boxing equality above excludes primitives.\n\t\tconst object = value as object\n\t\tif (active.has(object)) throw new Error('Unsupported cyclic DTO schema')\n\t\tconst cached = seen.get(object)\n\t\tif (cached) return cached\n\t\tif (depth > 64 || ++nodes > 8192) throw new Error('DTO schema graph budget exceeded')\n\t\tactive.add(object)\n\t\tlet recipe: Recipe\n\t\tif (value instanceof RegExp) {\n\t\t\trecipe = { kind: 'regexp', source: value.source, flags: value.flags }\n\t\t} else if (value instanceof z.core.$ZodType || value instanceof z.core.$ZodCheck) {\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!(value instanceof z.ZodCustom)\n\t\t\t)\n\t\t\t\tthrow new Error('Unsupported opaque DTO check/superRefine; use .refine() instead')\n\t\t\tconst entry = dispatch.find(([, constructor]) => constructor.matches(value))\n\t\t\tif (!entry) throw new Error('Unsupported DTO schema or check')\n\t\t\tlet id: string | undefined\n\t\t\tif (value instanceof z.ZodCustom) {\n\t\t\t\tconst native = nativeValidator(value)\n\t\t\t\tif (native.kind === 'id') id = native.tableName\n\t\t\t}\n\t\t\tconst definition =\n\t\t\t\tvalue instanceof z.ZodObject\n\t\t\t\t\t? // oxlint-disable-next-line anti-slop/no-shape-in-symbol-names -- The installed Zod object definition requires this exact property.\n\t\t\t\t\t\t{ ...value._zod.def, shape: value.shape }\n\t\t\t\t\t: value._zod.def\n\t\t\trecipe = {\n\t\t\t\tkind: 'node',\n\t\t\t\tconstructor: entry[0],\n\t\t\t\tdefinition: capture(definition, depth + 1),\n\t\t\t\tid,\n\t\t\t}\n\t\t} else if (Array.isArray(value)) {\n\t\t\trecipe = {\n\t\t\t\tkind: 'array',\n\t\t\t\titems: Object.freeze(value.map((child) => capture(child, depth + 1))),\n\t\t\t}\n\t\t} else {\n\t\t\tif (Object.hasOwn(object, '_zod'))\n\t\t\t\tthrow new Error('Unsupported opaque DTO check/superRefine; use .refine() instead')\n\t\t\tif (\n\t\t\t\tObject.getPrototypeOf(value) !== Object.prototype &&\n\t\t\t\tObject.getPrototypeOf(value) !== null\n\t\t\t)\n\t\t\t\tthrow new Error('Unsupported DTO definition object')\n\t\t\tconst entries: (readonly [string, Recipe])[] = []\n\t\t\tfor (const key of Reflect.ownKeys(object)) {\n\t\t\t\tif (String(key) !== key) throw new Error('Unsupported DTO definition symbol')\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, key)!\n\t\t\t\tif (!('value' in descriptor)) throw new Error('Unsupported DTO schema accessor')\n\t\t\t\tentries.push(Object.freeze([key, capture(descriptor.value, depth + 1)]))\n\t\t\t}\n\t\t\trecipe = { kind: 'record', entries: Object.freeze(entries) }\n\t\t}\n\t\tactive.delete(object)\n\t\tObject.freeze(recipe)\n\t\tseen.set(object, recipe)\n\t\treturn recipe\n\t}\n\treturn Object.freeze({ root: capture(schema, 0) })\n}\n\n// Factories share immutable instructions only. Every occurrence invokes its factory\n// again, so shared recipe nodes never share mutable materialized definitions.\ntype Factory = () => unknown\nconst factories = new WeakMap<Recipe, Factory>()\n\nfunction compile(recipe: Recipe): Factory {\n\tconst cached = factories.get(recipe)\n\tif (cached) return cached\n\tlet factory: Factory\n\tswitch (recipe.kind) {\n\t\tcase 'value':\n\t\t\tfactory = () => recipe.value\n\t\t\tbreak\n\t\tcase 'regexp':\n\t\t\tfactory = () => new RegExp(recipe.source, recipe.flags)\n\t\t\tbreak\n\t\tcase 'array': {\n\t\t\tconst items = recipe.items.map(compile)\n\t\t\tfactory = () => items.map((item) => item())\n\t\t\tbreak\n\t\t}\n\t\tcase 'record': {\n\t\t\tconst entries = recipe.entries.map(([key, child]) => [key, compile(child)] as const)\n\t\t\tfactory = () => Object.fromEntries(entries.map(([key, child]) => [key, child()]))\n\t\t\tbreak\n\t\t}\n\t\tcase 'node': {\n\t\t\tconst definition = compile(recipe.definition)\n\t\t\tif (recipe.id !== undefined) {\n\t\t\t\tconst id = recipe.id\n\t\t\t\tfactory = () => {\n\t\t\t\t\tconst restored = definition()\n\t\t\t\t\tconst result = zid(id)\n\t\t\t\t\t// The new zid is registered with convex-helpers. Added refinements are\n\t\t\t\t\t// reconstructed independently, never inherited via _zod.parent.\n\t\t\t\t\tif (restored instanceof Object && 'checks' in restored) {\n\t\t\t\t\t\tconst checks = restored.checks\n\t\t\t\t\t\tif (Array.isArray(checks)) return result.check(...checks)\n\t\t\t\t\t}\n\t\t\t\t\treturn result\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst constructor = constructors.get(recipe.constructor)!\n\t\t\t\tfactory = () => constructor.create(definition())\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\tfactories.set(recipe, factory)\n\treturn factory\n}\n\nexport function materializeDto<Schema extends z.ZodType>(recipe: DtoRecipe<Schema>): Schema {\n\tconst result = compile(recipe.root)()\n\tif (!(result instanceof z.ZodType)) throw new Error('Expected classic DTO schema')\n\t// SAFETY: the recipe preserves the captured schema constructor and definition.\n\treturn result as Schema\n}\n\nfunction nativeValidator(schema: z.ZodType): GenericValidator {\n\treturn zodToConvex(schema)\n}\n\nfunction register<T extends Node>(\n\tname: string,\n\tConstructor: z.core.$constructor<T> | undefined,\n): void {\n\tif (Constructor === undefined) return\n\tconstructors.set(name, {\n\t\tmatches: (node) => node instanceof Constructor,\n\t\tcreate: (definition) => {\n\t\t\t// SAFETY: capture selected this installed constructor and recursively copied\n\t\t\t// its own semantic definition; materialization restores every child first.\n\t\t\treturn new Constructor(definition as T['_zod']['def'])\n\t\t},\n\t})\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"schema-snapshot.mjs","names":["zodToConvex","zodToConvex$1","constructors","register","z","dispatch","captureDto","seen","active","nodes","capture","value","object","cached","depth","recipe","entry","constructor","id","native","nativeValidator","definition","child","entries","key","descriptor","schema","factories","compile","factory","items","item","restored","result","zid","checks","materializeDto","Constructor","name","node"],"sources":["../../src/querying/schema-snapshot.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { GenericValidator } from 'convex/values'\nimport { zid } from 'convex-helpers/server/zod4'\nimport { zodToConvex } from '../zod-convex'\n\n// Recipes contain semantic definitions only. No source parser, constructor,\n// parent, hooks or lazy caches survive registration.\ntype Recipe =\n\t| { readonly kind: 'value'; readonly value: unknown }\n\t| { readonly kind: 'array'; readonly items: readonly Recipe[] }\n\t| { readonly kind: 'record'; readonly entries: readonly (readonly [string, Recipe])[] }\n\t| { readonly kind: 'regexp'; readonly source: string; readonly flags: string }\n\t| {\n\t\t\treadonly kind: 'node'\n\t\t\treadonly constructor: string\n\t\t\treadonly definition: Recipe\n\t\t\treadonly id?: string\n\t }\n\nexport interface DtoRecipe<Schema extends z.ZodType = z.ZodType> {\n\treadonly schemaType?: Schema\n\treadonly root: Recipe\n}\n\ntype Node = z.core.$ZodType | z.core.$ZodCheck\nconst constructors = new Map<\n\tstring,\n\t{\n\t\tmatches(node: Node): boolean\n\t\t// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Only recipe-restored semantic definitions enter the selected installed constructor.\n\t\tcreate(definition: unknown): Node\n\t}\n>()\n// Base classes precede specialized classes so the most specific installed\n// constructor wins. Never consult a caller's _zod.constr or constructor property.\nregister('object', z.ZodObject)\nregister('array', z.ZodArray)\nregister('optional', z.ZodOptional)\nregister('exactOptional', z.ZodExactOptional)\nregister('nullable', z.ZodNullable)\nregister('nonoptional', z.ZodNonOptional)\nregister('union', z.ZodUnion)\nregister('discriminatedUnion', z.ZodDiscriminatedUnion)\nregister('tuple', z.ZodTuple)\nregister('record', z.ZodRecord)\nregister('string', z.ZodString)\nregister('number', z.ZodNumber)\nregister('boolean', z.ZodBoolean)\nregister('bigint', z.ZodBigInt)\nregister('null', z.ZodNull)\nregister('never', z.ZodNever)\nregister('literal', z.ZodLiteral)\nregister('enum', z.ZodEnum)\nregister('custom', z.ZodCustom)\nregister('minLength', z.core.$ZodCheckMinLength)\nregister('maxLength', z.core.$ZodCheckMaxLength)\nregister('length', z.core.$ZodCheckLengthEquals)\nregister('lessThan', z.core.$ZodCheckLessThan)\nregister('greaterThan', z.core.$ZodCheckGreaterThan)\nregister('multipleOf', z.core.$ZodCheckMultipleOf)\nregister('checkNumberFormat', z.core.$ZodCheckNumberFormat)\nregister('checkBigintFormat', z.core.$ZodCheckBigIntFormat)\nregister('stringFormat', z.core.$ZodCheckStringFormat)\nregister('regex', z.core.$ZodCheckRegex)\nregister('lowercase', z.core.$ZodCheckLowerCase)\nregister('uppercase', z.core.$ZodCheckUpperCase)\nregister('includes', z.core.$ZodCheckIncludes)\nregister('startsWith', z.core.$ZodCheckStartsWith)\nregister('endsWith', z.core.$ZodCheckEndsWith)\nregister('property', z.core.$ZodCheckProperty)\nregister('properties', z.core.$ZodCheckProperties)\nregister('numberFormat', z.ZodNumberFormat)\nregister('bigintFormat', z.ZodBigIntFormat)\n// Format schemas are also checks; preserve their implicit checks, including\n// URL/JWT validation which cannot be represented by a regex alone.\nregister('coreEmail', z.core.$ZodEmail)\nregister('coreGUID', z.core.$ZodGUID)\nregister('coreUUID', z.core.$ZodUUID)\nregister('coreURL', z.core.$ZodURL)\nregister('coreEmoji', z.core.$ZodEmoji)\nregister('coreNanoID', z.core.$ZodNanoID)\nregister('coreCUID', z.core.$ZodCUID)\nregister('coreCUID2', z.core.$ZodCUID2)\nregister('coreULID', z.core.$ZodULID)\nregister('coreXID', z.core.$ZodXID)\nregister('coreKSUID', z.core.$ZodKSUID)\nregister('coreIPv4', z.core.$ZodIPv4)\nregister('coreIPv6', z.core.$ZodIPv6)\nregister('coreMAC', z.core.$ZodMAC)\nregister('coreCIDRv4', z.core.$ZodCIDRv4)\nregister('coreCIDRv6', z.core.$ZodCIDRv6)\nregister('coreBase64', z.core.$ZodBase64)\nregister('coreBase64URL', z.core.$ZodBase64URL)\nregister('coreE164', z.core.$ZodE164)\nregister('coreJWT', z.core.$ZodJWT)\nregister('coreISODateTime', z.core.$ZodISODateTime)\nregister('coreISODate', z.core.$ZodISODate)\nregister('coreISOTime', z.core.$ZodISOTime)\nregister('coreISODuration', z.core.$ZodISODuration)\nregister('coreCreditCard', z.core.$ZodCreditCard)\nregister('coreIBAN', z.core.$ZodIBAN)\nregister('coreCustomStringFormat', z.core.$ZodCustomStringFormat)\nregister('email', z.ZodEmail)\nregister('guid', z.ZodGUID)\nregister('uuid', z.ZodUUID)\nregister('url', z.ZodURL)\nregister('emoji', z.ZodEmoji)\nregister('nanoid', z.ZodNanoID)\nregister('cuid', z.ZodCUID)\nregister('cuid2', z.ZodCUID2)\nregister('ulid', z.ZodULID)\nregister('xid', z.ZodXID)\nregister('ksuid', z.ZodKSUID)\nregister('ipv4', z.ZodIPv4)\nregister('ipv6', z.ZodIPv6)\nregister('mac', z.ZodMAC)\nregister('cidrv4', z.ZodCIDRv4)\nregister('cidrv6', z.ZodCIDRv6)\nregister('base64', z.ZodBase64)\nregister('base64url', z.ZodBase64URL)\nregister('e164', z.ZodE164)\nregister('jwt', z.ZodJWT)\nregister('isoDateTime', z.ZodISODateTime)\nregister('isoDate', z.ZodISODate)\nregister('isoTime', z.ZodISOTime)\nregister('isoDuration', z.ZodISODuration)\nregister('creditCard', z.ZodCreditCard)\nregister('iban', z.ZodIBAN)\nregister('customStringFormat', z.ZodCustomStringFormat)\nconst dispatch = [...constructors.entries()].reverse()\n\nexport function captureDto<Schema extends z.ZodType>(schema: Schema): DtoRecipe<Schema> {\n\tconst seen = new WeakMap<object, Recipe>()\n\tconst active = new WeakSet<object>()\n\tlet nodes = 0\n\t// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Recursively decode preflighted Zod definitions into owned recipes.\n\tfunction capture(value: unknown, depth: number): Recipe {\n\t\tif (value === null || Object(value) !== value || value instanceof Function)\n\t\t\treturn Object.freeze({ kind: 'value', value })\n\t\t// SAFETY: the boxing equality above excludes primitives.\n\t\tconst object = value as object\n\t\tif (active.has(object)) throw new Error('Unsupported cyclic DTO schema')\n\t\tconst cached = seen.get(object)\n\t\tif (cached) return cached\n\t\tif (depth > 64 || ++nodes > 8192) throw new Error('DTO schema graph budget exceeded')\n\t\tactive.add(object)\n\t\tlet recipe: Recipe\n\t\tif (value instanceof RegExp) {\n\t\t\trecipe = { kind: 'regexp', source: value.source, flags: value.flags }\n\t\t} else if (value instanceof z.core.$ZodType || value instanceof z.core.$ZodCheck) {\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!(value instanceof z.ZodCustom)\n\t\t\t)\n\t\t\t\tthrow new Error('Unsupported opaque DTO check/superRefine; use .refine() instead')\n\t\t\tconst entry = dispatch.find(([, constructor]) => constructor.matches(value))\n\t\t\tif (!entry) throw new Error('Unsupported DTO schema or check')\n\t\t\tlet id: string | undefined\n\t\t\tif (value instanceof z.ZodCustom) {\n\t\t\t\tconst native = nativeValidator(value)\n\t\t\t\tif (native.kind === 'id') id = native.tableName\n\t\t\t}\n\t\t\tconst definition =\n\t\t\t\tvalue instanceof z.ZodObject\n\t\t\t\t\t? // oxlint-disable-next-line anti-slop/no-shape-in-symbol-names -- The installed Zod object definition requires this exact property.\n\t\t\t\t\t\t{ ...value._zod.def, shape: value.shape }\n\t\t\t\t\t: value._zod.def\n\t\t\trecipe = {\n\t\t\t\tkind: 'node',\n\t\t\t\tconstructor: entry[0],\n\t\t\t\tdefinition: capture(definition, depth + 1),\n\t\t\t\tid,\n\t\t\t}\n\t\t} else if (Array.isArray(value)) {\n\t\t\trecipe = {\n\t\t\t\tkind: 'array',\n\t\t\t\titems: Object.freeze(value.map((child) => capture(child, depth + 1))),\n\t\t\t}\n\t\t} else {\n\t\t\tif (Object.hasOwn(object, '_zod'))\n\t\t\t\tthrow new Error('Unsupported opaque DTO check/superRefine; use .refine() instead')\n\t\t\tif (\n\t\t\t\tObject.getPrototypeOf(value) !== Object.prototype &&\n\t\t\t\tObject.getPrototypeOf(value) !== null\n\t\t\t)\n\t\t\t\tthrow new Error('Unsupported DTO definition object')\n\t\t\tconst entries: (readonly [string, Recipe])[] = []\n\t\t\tfor (const key of Reflect.ownKeys(object)) {\n\t\t\t\tif (String(key) !== key) throw new Error('Unsupported DTO definition symbol')\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, key)!\n\t\t\t\tif (!('value' in descriptor)) throw new Error('Unsupported DTO schema accessor')\n\t\t\t\tentries.push(Object.freeze([key, capture(descriptor.value, depth + 1)]))\n\t\t\t}\n\t\t\trecipe = { kind: 'record', entries: Object.freeze(entries) }\n\t\t}\n\t\tactive.delete(object)\n\t\tObject.freeze(recipe)\n\t\tseen.set(object, recipe)\n\t\treturn recipe\n\t}\n\treturn Object.freeze({ root: capture(schema, 0) })\n}\n\n// Factories share immutable instructions only. Every occurrence invokes its factory\n// again, so shared recipe nodes never share mutable materialized definitions.\ntype Factory = () => unknown\nconst factories = new WeakMap<Recipe, Factory>()\n\nfunction compile(recipe: Recipe): Factory {\n\tconst cached = factories.get(recipe)\n\tif (cached) return cached\n\tlet factory: Factory\n\tswitch (recipe.kind) {\n\t\tcase 'value':\n\t\t\tfactory = () => recipe.value\n\t\t\tbreak\n\t\tcase 'regexp':\n\t\t\tfactory = () => new RegExp(recipe.source, recipe.flags)\n\t\t\tbreak\n\t\tcase 'array': {\n\t\t\tconst items = recipe.items.map(compile)\n\t\t\tfactory = () => items.map((item) => item())\n\t\t\tbreak\n\t\t}\n\t\tcase 'record': {\n\t\t\tconst entries = recipe.entries.map(([key, child]) => [key, compile(child)] as const)\n\t\t\tfactory = () => Object.fromEntries(entries.map(([key, child]) => [key, child()]))\n\t\t\tbreak\n\t\t}\n\t\tcase 'node': {\n\t\t\tconst definition = compile(recipe.definition)\n\t\t\tif (recipe.id !== undefined) {\n\t\t\t\tconst id = recipe.id\n\t\t\t\tfactory = () => {\n\t\t\t\t\tconst restored = definition()\n\t\t\t\t\tconst result = zid(id)\n\t\t\t\t\t// The new zid is registered with convex-helpers. Added refinements are\n\t\t\t\t\t// reconstructed independently, never inherited via _zod.parent.\n\t\t\t\t\tif (restored instanceof Object && 'checks' in restored) {\n\t\t\t\t\t\tconst checks = restored.checks\n\t\t\t\t\t\tif (Array.isArray(checks)) return result.check(...checks)\n\t\t\t\t\t}\n\t\t\t\t\treturn result\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst constructor = constructors.get(recipe.constructor)!\n\t\t\t\tfactory = () => constructor.create(definition())\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n\tfactories.set(recipe, factory)\n\treturn factory\n}\n\nexport function materializeDto<Schema extends z.ZodType>(recipe: DtoRecipe<Schema>): Schema {\n\tconst result = compile(recipe.root)()\n\tif (!(result instanceof z.ZodType)) throw new Error('Expected classic DTO schema')\n\t// SAFETY: the recipe preserves the captured schema constructor and definition.\n\treturn result as Schema\n}\n\nfunction nativeValidator(schema: z.ZodType): GenericValidator {\n\treturn zodToConvex(schema)\n}\n\nfunction register<T extends Node>(\n\tname: string,\n\tConstructor: z.core.$constructor<T> | undefined,\n): void {\n\tif (Constructor === undefined) return\n\tconstructors.set(name, {\n\t\tmatches: (node) => node instanceof Constructor,\n\t\tcreate: (definition) => {\n\t\t\t// SAFETY: capture selected this installed constructor and recursively copied\n\t\t\t// its own semantic definition; materialization restores every child first.\n\t\t\treturn new Constructor(definition as T['_zod']['def'])\n\t\t},\n\t})\n}\n"],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { FilterAst, FilterScalar } from "./shared/ast.mjs";
2
+ import { FieldRange, IndexExpansion, NativeRange, QueryIndex } from "./filters.mjs";
3
+ import { EnginePaginationResult } from "../zod-table.mjs";
4
+ import { SearchIndexMetadata } from "../relations.mjs";
5
+ import { ManagedReadRequest } from "./security.mjs";
6
+ import { QueryInput, StoredConstraint, createPlanner } from "./planner.mjs";
7
+ import { CursorBinding, createCursorCodec } from "./cursors.mjs";
8
+ import { GenericDataModel, GenericDocument } from "convex/server";
9
+ import { Value } from "convex/values";
10
+ //#region src/querying/search.d.ts
11
+ export type SearchErrorCode = 'SEARCH_TEXT_REQUIRED' | 'SEARCH_END_CURSOR_UNSUPPORTED' | 'SEARCH_ORDER_UNSUPPORTED' | 'SEARCH_RELATION_UNSUPPORTED' | 'SEARCH_OPTIONS_UNSUPPORTED' | 'SEARCH_PROTOCOL_UNSUPPORTED';
12
+ export declare class SearchError extends Error {
13
+ readonly code: SearchErrorCode;
14
+ constructor(code: SearchErrorCode);
15
+ }
16
+ export type SearchPaginationResult<Row> = Omit<EnginePaginationResult<Row>, 'splitCursor' | 'pageStatus'> & {
17
+ paginationMode: 'native-search';
18
+ splitCursor: null;
19
+ pageStatus: null;
20
+ };
21
+ export interface SearchInput {
22
+ numItems: number;
23
+ cursor: string | null;
24
+ id?: number;
25
+ scanLimit?: number;
26
+ filters?: QueryInput['filters'];
27
+ }
28
+ /** Search compilation deliberately supplies no browse indexes or expansion directives. */
29
+ export declare function planSearch(planner: ReturnType<typeof createPlanner>, table: string, index: string, text: string, input: SearchInput, constraints: readonly StoredConstraint[]): {
30
+ plan: {
31
+ expansion: IndexExpansion | null;
32
+ sets: ReadonlyMap<string, FilterScalar[]>;
33
+ residual: FilterAst;
34
+ bindings: ReadonlyMap<string, FilterScalar>;
35
+ ranges: ReadonlyMap<string, FieldRange>;
36
+ range: NativeRange | null;
37
+ unsatisfiable: boolean;
38
+ index: QueryIndex | null;
39
+ prefix: readonly {
40
+ field: string;
41
+ value: FilterScalar;
42
+ }[];
43
+ clientIdentity: Value;
44
+ serverIdentity: Value;
45
+ args: {
46
+ cursor: string | null;
47
+ endCursor?: string | null | undefined;
48
+ id?: number | undefined;
49
+ onEmptyBudget?: "split" | undefined;
50
+ maximumRowsRead?: number | undefined;
51
+ maximumBytesRead?: number | undefined;
52
+ filters?: unknown;
53
+ order?: "asc" | "desc" | undefined;
54
+ numItems: number;
55
+ };
56
+ };
57
+ text: string;
58
+ metadata: SearchIndexMetadata;
59
+ scanLimit: number | undefined;
60
+ equalities: {
61
+ field: string;
62
+ value: string | number | bigint | boolean;
63
+ }[];
64
+ };
65
+ type SearchPlan = ReturnType<typeof planSearch>;
66
+ /** One complete native window. No result token is minted until all descendants finish. */
67
+ export declare function executeSearch(request: ManagedReadRequest<GenericDataModel>, table: string, search: SearchPlan, codec: ReturnType<typeof createCursorCodec>, binding: CursorBinding, maxPageSize: number, complete: (document: GenericDocument) => Promise<Record<string, Value> | null>): Promise<SearchPaginationResult<Record<string, Value>>>;
68
+ //#endregion
69
+ //# sourceMappingURL=search.d.mts.map
@@ -0,0 +1,2 @@
1
+ import"./filters.mjs";import{CursorError as e}from"./cursors.mjs";import{rethrowQueryError as t}from"./execution.mjs";import{z as n}from"zod";var r=class extends Error{code;constructor(e){super(e),this.code=e,this.name=`SearchError`}};const i=n.strictObject({numItems:n.number().int().positive(),cursor:n.string().nullable(),id:n.number().optional(),scanLimit:n.number().int().positive().max(2**53-1).optional(),filters:n.any().optional(),endCursor:n.null().optional()}),a=n.looseObject({endCursor:n.any().optional(),order:n.any().optional(),maximumRowsRead:n.any().optional(),maximumBytesRead:n.any().optional(),onEmptyBudget:n.any().optional()}),o=n.object({page:n.array(n.any()),isDone:n.boolean(),continueCursor:n.string(),splitCursor:n.null().optional(),pageStatus:n.null().optional(),completeness:n.literal(`complete`).optional()});function s(e,t,o,s,c,l){if(!n.string().safeParse(s).success||!s.trim())throw new r(`SEARCH_TEXT_REQUIRED`);let u=a.safeParse(c);if(!u.success)throw new r(`SEARCH_OPTIONS_UNSUPPORTED`);let d=u.data;if(d.endCursor!=null)throw new r(`SEARCH_END_CURSOR_UNSUPPORTED`);if(Object.hasOwn(d,`order`))throw new r(`SEARCH_ORDER_UNSUPPORTED`);if([`maximumRowsRead`,`maximumBytesRead`,`onEmptyBudget`].some(e=>Object.hasOwn(d,e)))throw new r(`SEARCH_OPTIONS_UNSUPPORTED`);let f=i.safeParse(c);if(!f.success)throw new r(`SEARCH_OPTIONS_UNSUPPORTED`);let p=e.metadata.tables[t]?.searchIndexes.find(e=>e.name===o&&!e.staged);if(!p)throw new r(`SEARCH_OPTIONS_UNSUPPORTED`);let{scanLimit:m,endCursor:h,...g}=f.data,_=e.plan(t,{...g,numItems:Math.min(g.numItems,100)},[],l,void 0,`relation`),v={..._,args:{..._.args,numItems:g.numItems}},y=/* @__PURE__ */ new Map;function b(e){if(e.kind===`and`)for(let t of e.children)b(t);else e.kind===`scalar`&&e.operator===`eq`&&!Array.isArray(e.value)&&y.set(e.field,e.value)}return b(v.residual),{plan:v,text:s.trim(),metadata:p,scanLimit:m,equalities:p.filterFields.filter(e=>y.has(e)).map(e=>({field:e,value:y.get(e)}))}}const c=n.strictObject({v:n.literal(1),mode:n.literal(`search`),nativeCursor:n.string().nullable(),seen:n.number().int().nonnegative().max(2**53-1)});async function l(n,i,a,s,l,u,d){let f={v:1,mode:`search`,nativeCursor:null,seen:0};if(a.plan.args.cursor!==null)try{f=c.parse(JSON.parse(s.open(a.plan.args.cursor,l)))}catch{throw new e}let p=a.scanLimit,m=p!==void 0&&f.seen>=p,h=(e,t,n,r)=>({page:e,isDone:r,continueCursor:s.seal(JSON.stringify({v:1,mode:`search`,nativeCursor:t,seen:n}),l),completeness:p!==void 0&&n>=p?`result-cap`:`complete`,paginationMode:`native-search`,splitCursor:null,pageStatus:null});if(m||a.plan.unsatisfiable)return h([],f.nativeCursor,f.seen,!0);try{let e={cursor:f.nativeCursor,numItems:Math.min(a.plan.args.numItems,u,n.budgets.searchCandidates,p===void 0?1/0:p-f.seen),id:a.plan.args.id},t=await n.search(i,a.metadata,a.text,a.equalities,e);if(!o.safeParse(t).success||!t.isDone&&t.continueCursor===f.nativeCursor)throw new r(`SEARCH_PROTOCOL_UNSUPPORTED`);let s=f.seen+t.page.length;if(!Number.isSafeInteger(s))throw new r(`SEARCH_PROTOCOL_UNSUPPORTED`);let c=[];for(let e of t.page){let t=await d(e);t!==null&&c.push(t)}return h(c,t.continueCursor,s,t.isDone||p!==void 0&&s>=p)}catch(e){if(e instanceof r)throw e;t(e)}}export{r as SearchError,l as executeSearch,s as planSearch};
2
+ //# sourceMappingURL=search.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.mjs","names":["SearchError","code","searchInput","z","optionEnvelope","nativePage","planSearch","text","envelope","input","raw","key","parsed","metadata","planner","table","candidate","index","_endCursor","args","planned","constraints","plan","values","equalities","ast","child","field","payload","executeSearch","start","search","codec","binding","CursorError","cap","terminal","finish","seen","options","maxPageSize","request","result","page","document","projected","complete","error","rethrowQueryError"],"sources":["../../src/querying/search.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { createPlanner, QueryInput, StoredConstraint } from './planner'\nimport type { FilterAst, FilterScalar } from './filters'\nimport { MAX_PAGE_SIZE } from './filters'\n\nexport type SearchErrorCode =\n\t| 'SEARCH_TEXT_REQUIRED'\n\t| 'SEARCH_END_CURSOR_UNSUPPORTED'\n\t| 'SEARCH_ORDER_UNSUPPORTED'\n\t| 'SEARCH_RELATION_UNSUPPORTED'\n\t| 'SEARCH_OPTIONS_UNSUPPORTED'\n\t| 'SEARCH_PROTOCOL_UNSUPPORTED'\nexport class SearchError extends Error {\n\tconstructor(readonly code: SearchErrorCode) {\n\t\tsuper(code)\n\t\tthis.name = 'SearchError'\n\t}\n}\nexport type SearchPaginationResult<Row> = Omit<\n\timport('../zod-table').EnginePaginationResult<Row>,\n\t'splitCursor' | 'pageStatus'\n> & { paginationMode: 'native-search'; splitCursor: null; pageStatus: null }\nexport interface SearchInput {\n\tnumItems: number\n\tcursor: string | null\n\tid?: number\n\tscanLimit?: number\n\tfilters?: QueryInput['filters']\n}\nconst searchInput = z.strictObject({\n\tnumItems: z.number().int().positive(),\n\tcursor: z.string().nullable(),\n\tid: z.number().optional(),\n\tscanLimit: z.number().int().positive().max(Number.MAX_SAFE_INTEGER).optional(),\n\tfilters: z.any().optional(),\n\tendCursor: z.null().optional(),\n})\nconst optionEnvelope = z.looseObject({\n\tendCursor: z.any().optional(),\n\torder: z.any().optional(),\n\tmaximumRowsRead: z.any().optional(),\n\tmaximumBytesRead: z.any().optional(),\n\tonEmptyBudget: z.any().optional(),\n})\nconst nativePage = z.object({\n\tpage: z.array(z.any()),\n\tisDone: z.boolean(),\n\tcontinueCursor: z.string(),\n\tsplitCursor: z.null().optional(),\n\tpageStatus: z.null().optional(),\n\tcompleteness: z.literal('complete').optional(),\n})\n\n/** Search compilation deliberately supplies no browse indexes or expansion directives. */\nexport function planSearch(\n\tplanner: ReturnType<typeof createPlanner>,\n\ttable: string,\n\tindex: string,\n\ttext: string,\n\tinput: SearchInput,\n\tconstraints: readonly StoredConstraint[],\n) {\n\tif (!z.string().safeParse(text).success || !text.trim())\n\t\tthrow new SearchError('SEARCH_TEXT_REQUIRED')\n\tconst envelope = optionEnvelope.safeParse(input)\n\tif (!envelope.success) throw new SearchError('SEARCH_OPTIONS_UNSUPPORTED')\n\tconst raw = envelope.data\n\tif (raw.endCursor != null) throw new SearchError('SEARCH_END_CURSOR_UNSUPPORTED')\n\tif (Object.hasOwn(raw, 'order')) throw new SearchError('SEARCH_ORDER_UNSUPPORTED')\n\tif (\n\t\t['maximumRowsRead', 'maximumBytesRead', 'onEmptyBudget'].some((key) => Object.hasOwn(raw, key))\n\t)\n\t\tthrow new SearchError('SEARCH_OPTIONS_UNSUPPORTED')\n\tconst parsed = searchInput.safeParse(input)\n\tif (!parsed.success) throw new SearchError('SEARCH_OPTIONS_UNSUPPORTED')\n\tconst metadata = planner.metadata.tables[table]?.searchIndexes.find(\n\t\t(candidate) => candidate.name === index && !candidate.staged,\n\t)\n\tif (!metadata) throw new SearchError('SEARCH_OPTIONS_UNSUPPORTED')\n\tconst { scanLimit, endCursor: _endCursor, ...args } = parsed.data\n\t// Relation planning with no ordering uses the existing grammar with no browse index selection.\n\t// The shared filter grammar enforces browse page limits; search owns a soft target.\n\tconst planned = planner.plan(\n\t\ttable,\n\t\t{ ...args, numItems: Math.min(args.numItems, MAX_PAGE_SIZE) },\n\t\t[],\n\t\tconstraints,\n\t\tundefined,\n\t\t'relation',\n\t)\n\tconst plan = { ...planned, args: { ...planned.args, numItems: args.numItems } }\n\tconst values = new Map<string, FilterScalar>()\n\tfunction equalities(ast: FilterAst): void {\n\t\tif (ast.kind === 'and') for (const child of ast.children) equalities(child)\n\t\telse if (ast.kind === 'scalar' && ast.operator === 'eq' && !Array.isArray(ast.value))\n\t\t\tvalues.set(ast.field, ast.value)\n\t}\n\tequalities(plan.residual)\n\treturn {\n\t\tplan,\n\t\ttext: text.trim(),\n\t\tmetadata,\n\t\tscanLimit,\n\t\tequalities: metadata.filterFields\n\t\t\t.filter((field) => values.has(field))\n\t\t\t.map((field) => ({ field, value: values.get(field)! })),\n\t}\n}\n\nimport type { GenericDataModel, GenericDocument } from 'convex/server'\nimport type { Value } from 'convex/values'\nimport { CursorError, type CursorBinding, type createCursorCodec } from './cursors'\nimport type { ManagedReadRequest } from './security'\nimport { rethrowQueryError } from './execution'\n\nconst payload = z.strictObject({\n\tv: z.literal(1),\n\tmode: z.literal('search'),\n\tnativeCursor: z.string().nullable(),\n\tseen: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),\n})\ntype SearchPlan = ReturnType<typeof planSearch>\n/** One complete native window. No result token is minted until all descendants finish. */\nexport async function executeSearch(\n\trequest: ManagedReadRequest<GenericDataModel>,\n\ttable: string,\n\tsearch: SearchPlan,\n\tcodec: ReturnType<typeof createCursorCodec>,\n\tbinding: CursorBinding,\n\tmaxPageSize: number,\n\tcomplete: (document: GenericDocument) => Promise<Record<string, Value> | null>,\n): Promise<SearchPaginationResult<Record<string, Value>>> {\n\tlet start: z.output<typeof payload> = {\n\t\tv: 1,\n\t\tmode: 'search',\n\t\tnativeCursor: null,\n\t\tseen: 0,\n\t}\n\tif (search.plan.args.cursor !== null) {\n\t\ttry {\n\t\t\tstart = payload.parse(JSON.parse(codec.open(search.plan.args.cursor, binding)))\n\t\t} catch {\n\t\t\tthrow new CursorError()\n\t\t}\n\t}\n\tconst cap = search.scanLimit\n\tconst terminal = cap !== undefined && start.seen >= cap\n\tconst finish = (\n\t\tpage: Record<string, Value>[],\n\t\tnativeCursor: string | null,\n\t\tseen: number,\n\t\tisDone: boolean,\n\t): SearchPaginationResult<Record<string, Value>> => ({\n\t\tpage,\n\t\tisDone,\n\t\tcontinueCursor: codec.seal(\n\t\t\tJSON.stringify({ v: 1, mode: 'search', nativeCursor, seen }),\n\t\t\tbinding,\n\t\t),\n\t\tcompleteness: cap !== undefined && seen >= cap ? 'result-cap' : 'complete',\n\t\tpaginationMode: 'native-search',\n\t\tsplitCursor: null,\n\t\tpageStatus: null,\n\t})\n\tif (terminal || search.plan.unsatisfiable) return finish([], start.nativeCursor, start.seen, true)\n\ttry {\n\t\tconst options = {\n\t\t\tcursor: start.nativeCursor,\n\t\t\tnumItems: Math.min(\n\t\t\t\tsearch.plan.args.numItems,\n\t\t\t\tmaxPageSize,\n\t\t\t\trequest.budgets.searchCandidates,\n\t\t\t\tcap === undefined ? Infinity : cap - start.seen,\n\t\t\t),\n\t\t\tid: search.plan.args.id,\n\t\t}\n\t\tconst result = await request.search(\n\t\t\ttable,\n\t\t\tsearch.metadata,\n\t\t\tsearch.text,\n\t\t\tsearch.equalities,\n\t\t\toptions,\n\t\t)\n\t\tif (!nativePage.safeParse(result).success) throw new SearchError('SEARCH_PROTOCOL_UNSUPPORTED')\n\t\tif (!result.isDone && result.continueCursor === start.nativeCursor)\n\t\t\tthrow new SearchError('SEARCH_PROTOCOL_UNSUPPORTED')\n\t\tconst seen = start.seen + result.page.length\n\t\tif (!Number.isSafeInteger(seen)) throw new SearchError('SEARCH_PROTOCOL_UNSUPPORTED')\n\t\tconst page: Record<string, Value>[] = []\n\t\tfor (const document of result.page) {\n\t\t\tconst projected = await complete(document)\n\t\t\tif (projected !== null) page.push(projected)\n\t\t}\n\t\treturn finish(\n\t\t\tpage,\n\t\t\tresult.continueCursor,\n\t\t\tseen,\n\t\t\tresult.isDone || (cap !== undefined && seen >= cap),\n\t\t)\n\t} catch (error) {\n\t\tif (error instanceof SearchError) throw error\n\t\trethrowQueryError(error)\n\t}\n}\n"],"mappings":"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"}
@@ -1,5 +1,8 @@
1
+ import { FilterScalar } from "./shared/ast.mjs";
2
+ import "./filters.mjs";
3
+ import { SearchIndexMetadata } from "../relations.mjs";
1
4
  import { Rules } from "../tenancy.mjs";
2
- import { GenericDataModel, GenericDatabaseReader, GenericDocument, QueryInitializer } from "convex/server";
5
+ import { GenericDataModel, GenericDatabaseReader, GenericDocument, PaginationOptions, PaginationResult, QueryInitializer } from "convex/server";
3
6
  //#region src/querying/security.d.ts
4
7
  export declare const MAX_DOCUMENT_BYTES: number;
5
8
  /** Additive context supplied to existing read/insert/modify rules on BOTH paths.
@@ -19,6 +22,7 @@ export interface ManagedScope {
19
22
  readonly role: string | null;
20
23
  }
21
24
  export interface ManagedBudgets {
25
+ searchCandidates: number;
22
26
  readOperations: number;
23
27
  indexRanges: number;
24
28
  rawCandidates: number;
@@ -61,8 +65,16 @@ export interface ManagedReadRequest<DM extends GenericDataModel> {
61
65
  };
62
66
  readonly budgets: Readonly<ManagedBudgets>;
63
67
  readonly counters: ManagedCounters;
68
+ /** Only the private search operation enables atomic descendant completion. */
69
+ readonly atomicCompletion: boolean;
70
+ search(table: string, index: SearchIndexMetadata, text: string, equalities: readonly {
71
+ field: string;
72
+ value: FilterScalar;
73
+ }[], options: PaginationOptions): Promise<PaginationResult<GenericDocument>>;
64
74
  /** Future native leaf adapter reserves BEFORE every actual next/get, not an outer stream. */
65
75
  reserveLeaf(): LeafReservation;
76
+ /** Only raw leaf reservation failures from this request can be resumed by the executor. */
77
+ leafBudgetFailure(error: ManagedReadError): 'row-budget' | 'byte-budget' | undefined;
66
78
  openRange(): void;
67
79
  expand(depth: number, count?: number): void;
68
80
  /** Raw candidate visibility for the private executor; every leaf is metered.
@@ -97,7 +109,12 @@ export type ManagedQueryContext<DM extends GenericDataModel> = {
97
109
  /** Central construction, then one shared request per engine invocation.
98
110
  * Requests may lower, never raise ceilings. Unknown/native contexts fail closed.
99
111
  */
100
- export declare function createManagedSecurity<DM extends GenericDataModel = GenericDataModel>(config: ManagedSecurityConfig<DM>): <Ctx extends ManagedQueryContext<DM>>(ctx: Ctx, lower?: Partial<ManagedBudgets>) => ManagedReadRequest<DM>;
112
+ export declare function createManagedSecurity<DM extends GenericDataModel = GenericDataModel>(config: ManagedSecurityConfig<DM>): (<Ctx extends ManagedQueryContext<DM>>(ctx: Ctx, lower?: Partial<ManagedBudgets>) => ManagedReadRequest<DM>) & {
113
+ /** Scope-only admission for public cursors. Never returns the registered reader. */
114
+ cursorScope(ctx: ManagedQueryContext<DM>): ManagedScope & {
115
+ readonly policyVersion: string;
116
+ };
117
+ };
101
118
  /** Ordinary rule invocations share a policy-only meter. Ordinary db reads stay
102
119
  * unmetered by engine ceilings; supplied rule dependencies never bypass policy.
103
120
  * Mutation insert/modify receive the same supplied contract as read callbacks.
@@ -1,2 +1,2 @@
1
- import{getDocumentSize as e}from"convex/values";const t=1048576,n=Object.freeze({readOperations:4096,indexRanges:1024,rawCandidates:8192,documentBytes:16*t,fanout:1024,depth:8,memoEntries:4096});var r=class extends Error{code;constructor(e){super(e),this.code=e,this.name=`ManagedReadError`}};const i=/* @__PURE__ */ new WeakMap;function a(e,t,n){let r=Object.freeze({get:t.get.bind(t),query:e=>c(t.query(e)),normalizeId:t.normalizeId.bind(t),system:Object.freeze({get:t.system.get.bind(t.system),query:e=>c(t.system.query(e)),normalizeId:t.system.normalizeId.bind(t.system)})});return i.set(r,{reader:e,...u(n)}),r}function o(e){if(!e.policyVersion||!e.tables.length||new Set(e.tables).size!==e.tables.length||e.tables.some(e=>!e||e.startsWith(`_`)))throw Error(`Invalid managed security configuration`);let t=new Set(e.tables);l(e.budgets);let a=Object.freeze({...n,...e.budgets}),o=e.policyVersion,s=e.trustedAdapter;return(e,n)=>{let c=i.get(e.db),f=c?void 0:s?.(e);if(!c&&!f)throw new r(`UNMANAGED_QUERY_CONTEXT`);return d(c??{...f,...u(f)},t,l(n,a),o)}}function s(e,t,r){let i=d({reader:e,...u({rules:t,defaultPolicy:r,scope:{mode:`trusted`,principal:null,organization:null,tenant:null,role:null}})},null,n,`ordinary-policy`,!1),a={};for(let e of Object.keys(t)){let n=t[e],r={};n?.read&&(r.read=(t,n)=>i.authorize(e,n)),n?.insert&&(r.insert=(e,t)=>n.insert({db:i.db},t)),n?.modify&&(r.modify=(e,t)=>n.modify({db:i.db},t)),a[e]=r}return a}function c(e){return Object.freeze({fullTableScan:()=>c(e.fullTableScan()),withIndex:(...t)=>c(e.withIndex(...t)),withSearchIndex:(...t)=>c(e.withSearchIndex(...t)),filter:(...t)=>c(e.filter(...t)),order:(...t)=>c(e.order(...t)),paginate:e.paginate.bind(e),collect:e.collect.bind(e),take:e.take.bind(e),first:e.first.bind(e),unique:e.unique.bind(e),[Symbol.asyncIterator]:()=>{let t=e[Symbol.asyncIterator](),n={next:t.next.bind(t)};return t.return&&(n.return=t.return.bind(t)),t.throw&&(n.throw=t.throw.bind(t)),Object.freeze(n)}})}function l(e={},t=n){for(let[t,r]of Object.entries(e))if(!Object.hasOwn(n,t)||!Number.isSafeInteger(r)||r<=0)throw Error(`Invalid managed read budgets`);return Object.freeze({readOperations:Math.min(t.readOperations,e.readOperations??t.readOperations),indexRanges:Math.min(t.indexRanges,e.indexRanges??t.indexRanges),rawCandidates:Math.min(t.rawCandidates,e.rawCandidates??t.rawCandidates),documentBytes:Math.min(t.documentBytes,e.documentBytes??t.documentBytes),fanout:Math.min(t.fanout,e.fanout??t.fanout),depth:Math.min(t.depth,e.depth??t.depth),memoEntries:Math.min(t.memoEntries,e.memoEntries??t.memoEntries)})}function u(e){let t=Object.fromEntries(Object.entries(e.rules).map(([e,t])=>[e,Object.freeze({...t})]));return Object.freeze({scope:Object.freeze({...e.scope}),rules:Object.freeze(t),defaultPolicy:e.defaultPolicy})}function d(n,i,a,o,s=!0){let c={readOperations:0,indexRanges:0,rawCandidates:0,documentBytesObserved:0,documentBytesReserved:0,fanout:0,memoEntries:0},l=Object.freeze({get readOperations(){return c.readOperations},get indexRanges(){return c.indexRanges},get rawCandidates(){return c.rawCandidates},get documentBytesObserved(){return c.documentBytesObserved},get documentBytesReserved(){return c.documentBytesReserved},get fanout(){return c.fanout},get memoEntries(){return c.memoEntries}}),u=/* @__PURE__ */ new Map,d=0,f=0,p=()=>{throw new r(`MANAGED_READ_BUDGET`)},m=e=>{if(e.startsWith(`_`)||i&&!i.has(e))throw new r(`UNSUPPORTED_MANAGED_READ`)},h=()=>{c.indexRanges>=a.indexRanges&&p(),c.indexRanges++},g=()=>{(c.readOperations>=a.readOperations||c.rawCandidates+f>=a.rawCandidates||c.documentBytesObserved+c.documentBytesReserved+1048576>a.documentBytes)&&p(),c.readOperations++,f++,c.documentBytesReserved+=t;let n=!1;return{settle(r){if(n)throw Error(`Leaf reservation already settled`);if(n=!0,f--,c.documentBytesReserved-=t,r){c.rawCandidates++;let t=e(r);c.documentBytesObserved+=t,t>1048576&&p()}}}},_=(e,t)=>JSON.stringify([e,t]),v=(e,t)=>{if(t.includes(e))throw new r(`POLICY_RECURSION`);t.length>=a.depth&&p()};async function y(e,t,i=[]){m(e);let a=t._id;if(!n.reader.normalizeId(e,a))throw new r(`UNSUPPORTED_MANAGED_READ`);let o=_(e,a);v(o,i);let s=n.rules[e]?.read;return s?s(Object.freeze({db:S([...i,o])}),t):n.defaultPolicy===`allow`}async function b(e,t,r){m(e);let i=_(e,t);if(v(i,r),u.has(i))return u.get(i);s&&c.memoEntries>=a.memoEntries&&p(),s&&(d++,c.memoEntries=u.size+d);try{h();let a=g(),o;try{o=await n.reader.get(e,t)}catch(e){throw a.settle(null),e}a.settle(o);let c=o&&await y(e,o,r)?o:null;return s&&u.set(i,c),c}finally{s&&(d--,c.memoEntries=u.size+d)}}function x(e,t,n,i){function o(){throw new r(`UNSUPPORTED_MANAGED_READ`)}async function*s(){h();let r;try{for(;;){let a=g(),o;try{r??=t[Symbol.asyncIterator](),o=await r.next()}catch(e){throw a.settle(null),e}if(a.settle(o.done?null:o.value),o.done)return;(!i||await y(e,o.value,n))&&(yield o.value)}}finally{await r?.return?.()}}async function c(e){if(!Number.isSafeInteger(e)||e<0||e>a.rawCandidates)throw new r(`MANAGED_READ_BUDGET`);let t=[];if(e===0)return t;for await(let n of s())if(t.push(n),t.length===e)break;return t}return Object.freeze({fullTableScan:()=>x(e,t.fullTableScan(),n,i),withIndex:(...r)=>x(e,t.withIndex(...r),n,i),order:(...r)=>x(e,t.order(...r),n,i),filter:o,withSearchIndex:o,paginate:o,collect:o,take:c,first:async()=>(await c(1))[0]??null,unique:async()=>{let e=await c(2);if(e.length>1)throw Error(`Query is not unique`);return e[0]??null},[Symbol.asyncIterator]:s})}function S(e){let t=()=>{throw new r(`UNSUPPORTED_MANAGED_READ`)};return Object.freeze({get:async(t,r)=>{if(r!==void 0)return b(t,r,e);let a=[...i??new Set(Object.keys(n.rules))].find(e=>n.reader.normalizeId(e,t));return a?b(a,t,e):null},query:t=>(m(t),x(t,n.reader.query(t),e,!0)),normalizeId:(e,t)=>(m(e),n.reader.normalizeId(e,t)),system:Object.freeze({get:t,query:t,normalizeId:t})})}return Object.freeze({db:S([]),scope:Object.freeze({...n.scope,policyVersion:o}),budgets:a,counters:l,reserveLeaf:g,openRange:h,expand(e,t=1){(!Number.isSafeInteger(e)||e<0||e>a.depth||!Number.isSafeInteger(t)||t<0||c.fanout+t>a.fanout)&&p(),c.fanout+=t},leafQuery:e=>(m(e),x(e,n.reader.query(e),[],!1)),authorize:(e,t)=>y(e,t)})}export{t as MAX_DOCUMENT_BYTES,r as ManagedReadError,o as createManagedSecurity,a as registerQueryReader,s as suppliedPolicyRules};
1
+ import{getDocumentSize as e}from"convex/values";const t=1048576,n=Object.freeze({searchCandidates:100,readOperations:4096,indexRanges:1024,rawCandidates:8192,documentBytes:16*t,fanout:1024,depth:8,memoEntries:4096});var r=class extends Error{code;constructor(e){super(e),this.code=e,this.name=`ManagedReadError`}};const i=/* @__PURE__ */ new WeakMap;function a(e,t,n){let r=Object.freeze({get:t.get.bind(t),query:e=>c(t.query(e)),normalizeId:t.normalizeId.bind(t),system:Object.freeze({get:t.system.get.bind(t.system),query:e=>c(t.system.query(e)),normalizeId:t.system.normalizeId.bind(t.system)})});return i.set(r,{reader:e,...u(n)}),r}function o(e){if(!e.policyVersion||!e.tables.length||new Set(e.tables).size!==e.tables.length||e.tables.some(e=>!e||e.startsWith(`_`)))throw Error(`Invalid managed security configuration`);let t=new Set(e.tables);l(e.budgets);let a=Object.freeze({...n,...e.budgets}),o=e.policyVersion,s=e.trustedAdapter;function c(e){let t=i.get(e.db),n=t?void 0:s?.(e);if(!t&&!n)throw new r(`UNMANAGED_QUERY_CONTEXT`);return t??{...n,...u(n)}}function f(e,n){return d(c(e),t,l(n,a),o)}return Object.assign(f,{cursorScope(e){if(!e?.db||[`insert`,`patch`,`replace`,`delete`].some(t=>t in e.db))throw new r(`UNMANAGED_QUERY_CONTEXT`);return Object.freeze({...c(e).scope,policyVersion:o})}})}function s(e,t,r){let i=d({reader:e,...u({rules:t,defaultPolicy:r,scope:{mode:`trusted`,principal:null,organization:null,tenant:null,role:null}})},null,n,`ordinary-policy`,!1),a={};for(let e of Object.keys(t)){let n=t[e],r={};n?.read&&(r.read=(t,n)=>i.authorize(e,n)),n?.insert&&(r.insert=(e,t)=>n.insert({db:i.db},t)),n?.modify&&(r.modify=(e,t)=>n.modify({db:i.db},t)),a[e]=r}return a}function c(e){return Object.freeze({fullTableScan:()=>c(e.fullTableScan()),withIndex:(...t)=>c(e.withIndex(...t)),withSearchIndex:(...t)=>c(e.withSearchIndex(...t)),filter:(...t)=>c(e.filter(...t)),order:(...t)=>c(e.order(...t)),paginate:e.paginate.bind(e),collect:e.collect.bind(e),take:e.take.bind(e),first:e.first.bind(e),unique:e.unique.bind(e),[Symbol.asyncIterator]:()=>{let t=e[Symbol.asyncIterator](),n={next:t.next.bind(t)};return t.return&&(n.return=t.return.bind(t)),t.throw&&(n.throw=t.throw.bind(t)),Object.freeze(n)}})}function l(e={},t=n){for(let[t,r]of Object.entries(e))if(!Object.hasOwn(n,t)||!Number.isSafeInteger(r)||r<=0)throw Error(`Invalid managed read budgets`);return Object.freeze({searchCandidates:Math.min(t.searchCandidates,e.searchCandidates??t.searchCandidates),readOperations:Math.min(t.readOperations,e.readOperations??t.readOperations),indexRanges:Math.min(t.indexRanges,e.indexRanges??t.indexRanges),rawCandidates:Math.min(t.rawCandidates,e.rawCandidates??t.rawCandidates),documentBytes:Math.min(t.documentBytes,e.documentBytes??t.documentBytes),fanout:Math.min(t.fanout,e.fanout??t.fanout),depth:Math.min(t.depth,e.depth??t.depth),memoEntries:Math.min(t.memoEntries,e.memoEntries??t.memoEntries)})}function u(e){let t=Object.fromEntries(Object.entries(e.rules).map(([e,t])=>[e,Object.freeze({...t})]));return Object.freeze({scope:Object.freeze({...e.scope}),rules:Object.freeze(t),defaultPolicy:e.defaultPolicy})}function d(n,i,a,o,s=!0){let c={readOperations:0,indexRanges:0,rawCandidates:0,documentBytesObserved:0,documentBytesReserved:0,fanout:0,memoEntries:0},l=Object.freeze({get readOperations(){return c.readOperations},get indexRanges(){return c.indexRanges},get rawCandidates(){return c.rawCandidates},get documentBytesObserved(){return c.documentBytesObserved},get documentBytesReserved(){return c.documentBytesReserved},get fanout(){return c.fanout},get memoEntries(){return c.memoEntries}}),u=!1,d={rawCandidates:0,documentBytes:0},f=/* @__PURE__ */ new Map,p=0,m=0,h=/* @__PURE__ */ new WeakMap,g=()=>{if(c.readOperations>=a.readOperations||c.rawCandidates+m>=a.rawCandidates)return`row-budget`;if(c.documentBytesObserved+c.documentBytesReserved+1048576>a.documentBytes)return`byte-budget`},_=()=>{throw new r(`MANAGED_READ_BUDGET`)},v=e=>{if(e.startsWith(`_`)||i&&!i.has(e))throw new r(`UNSUPPORTED_MANAGED_READ`)},y=()=>{c.indexRanges>=a.indexRanges&&_(),c.indexRanges++},b=()=>{g()&&_(),c.readOperations++,m++,c.documentBytesReserved+=t;let n=!1;return{settle(r){if(n)throw Error(`Leaf reservation already settled`);if(n=!0,m--,c.documentBytesReserved-=t,r){c.rawCandidates++;let t=e(r);c.documentBytesObserved+=t,t>1048576&&_()}}}},x=(e,t)=>JSON.stringify([e,t]),S=(e,t)=>{if(t.includes(e))throw new r(`POLICY_RECURSION`);t.length>=a.depth&&_()};async function C(e,t,i=[]){v(e);let a=t._id;if(!n.reader.normalizeId(e,a))throw new r(`UNSUPPORTED_MANAGED_READ`);let o=x(e,a);S(o,i);let s=n.rules[e]?.read;return s?s(Object.freeze({db:E([...i,o])}),t):n.defaultPolicy===`allow`}async function w(e,t,r){v(e);let i=x(e,t);if(S(i,r),f.has(i))return f.get(i);s&&c.memoEntries>=a.memoEntries&&_(),s&&(p++,c.memoEntries=f.size+p);try{y();let a=b(),o;try{o=await n.reader.get(e,t)}catch(e){throw a.settle(null),e}a.settle(o);let c=o&&await C(e,o,r)?o:null;return s&&f.set(i,c),c}finally{s&&(p--,c.memoEntries=f.size+p)}}function T(e,t,n,i){function o(){throw new r(`UNSUPPORTED_MANAGED_READ`)}async function*s(){y();let a;try{for(;;){let o=!i&&g();if(o){let e=new r(`MANAGED_READ_BUDGET`);throw h.set(e,o),e}let s=b(),c;try{a??=t[Symbol.asyncIterator](),c=await a.next()}catch(e){throw s.settle(null),e}if(s.settle(c.done?null:c.value),c.done)return;(!i||await C(e,c.value,n))&&(yield c.value)}}finally{await a?.return?.()}}async function c(e){if(!Number.isSafeInteger(e)||e<0||e>a.rawCandidates)throw new r(`MANAGED_READ_BUDGET`);let t=[];if(e===0)return t;for await(let n of s())if(t.push(n),t.length===e)break;return t}return Object.freeze({fullTableScan:()=>T(e,t.fullTableScan(),n,i),withIndex:(...r)=>T(e,t.withIndex(...r),n,i),order:(...r)=>T(e,t.order(...r),n,i),filter:o,withSearchIndex:o,paginate:o,collect:o,take:c,first:async()=>(await c(1))[0]??null,unique:async()=>{let e=await c(2);if(e.length>1)throw Error(`Query is not unique`);return e[0]??null},[Symbol.asyncIterator]:s})}function E(e){let t=()=>{throw new r(`UNSUPPORTED_MANAGED_READ`)};return Object.freeze({get:async(t,r)=>{if(r!==void 0)return w(t,r,e);let a=[...i??new Set(Object.keys(n.rules))].find(e=>n.reader.normalizeId(e,t));return a?w(a,t,e):null},query:t=>(v(t),T(t,n.reader.query(t),e,!0)),normalizeId:(e,t)=>(v(e),n.reader.normalizeId(e,t)),system:Object.freeze({get:t,query:t,normalizeId:t})})}return Object.freeze({db:E([]),scope:Object.freeze({...n.scope,policyVersion:o}),budgets:a,counters:l,get atomicCompletion(){return u},async search(t,i,o,s,l){if(v(t),u)throw new r(`UNSUPPORTED_MANAGED_READ`);u=!0,c.readOperations>=a.readOperations&&_(),y(),c.readOperations++;let f=await n.reader.query(t).withSearchIndex(i.name,e=>{let t=e.search(i.searchField,o);for(let{field:e,value:n}of s)t=t.eq(e,n);return t}).paginate(l);d.rawCandidates+=f.page.length;for(let t of f.page)d.documentBytes+=e(t);return f},reserveLeaf:b,leafBudgetFailure:e=>h.get(e),openRange:y,expand(e,t=1){(!Number.isSafeInteger(e)||e<0||e>a.depth||!Number.isSafeInteger(t)||t<0||c.fanout+t>a.fanout)&&_(),c.fanout+=t},leafQuery:e=>(v(e),T(e,n.reader.query(e),[],!1)),authorize:(e,t)=>C(e,t)})}export{t as MAX_DOCUMENT_BYTES,r as ManagedReadError,o as createManagedSecurity,a as registerQueryReader,s as suppliedPolicyRules};
2
2
  //# sourceMappingURL=security.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"security.mjs","names":["MAX_DOCUMENT_BYTES","defaultBudgets","ManagedReadError","code","capabilities","registerQueryReader","facade","ordinary","ordinaryQuery","table","raw","snapshot","authority","createManagedSecurity","config","tables","limits","central","policyVersion","trustedAdapter","registered","ctx","adapted","request","lower","suppliedPolicyRules","session","result","rules","operations","wrapped","doc","source","args","iterator","key","value","overrides","counts","view","memo","pendingMemo","pendingCandidates","fail","assertTable","openRange","budgets","reserveLeaf","settled","document","size","getDocumentSize","keyOf","id","checkCycle","ancestors","authorize","cap","rule","reader","get","memoize","reservation","error","query","unsupported","iterate","next","authorized","take","n","docs","blocked","arg1","arg0","name","depth","count"],"sources":["../../src/querying/security.ts"],"sourcesContent":["/** Internal managed-read contracts for the relational executor. No root/package export. */\nimport type {\n\tGenericDataModel,\n\tGenericDatabaseReader,\n\tGenericDocument,\n\tGenericTableInfo,\n\tQueryInitializer,\n} from 'convex/server'\nimport { getDocumentSize, type GenericId } from 'convex/values'\nimport type { Rules } from '../tenancy'\n\nexport const MAX_DOCUMENT_BYTES = 1024 * 1024\n\n/** Additive context supplied to existing read/insert/modify rules on BOTH paths.\n * Reads through db are authorized and bounded. collect, native paginate/filter,\n * search, and system reads fail closed; use get, take/first/unique, or iteration.\n * Trusted server callbacks can close\n * over other readers; arbitrary captured JavaScript cannot be sandboxed here.\n */\nexport interface SecurityPolicyContext<DM extends GenericDataModel> {\n\treadonly db: GenericDatabaseReader<DM>\n}\n\nexport interface ManagedScope {\n\treadonly mode: 'authenticated' | 'system' | 'trusted'\n\treadonly principal: string | null\n\treadonly organization: string | null\n\treadonly tenant: string | null\n\treadonly role: string | null\n}\n\nexport interface ManagedBudgets {\n\treadOperations: number\n\tindexRanges: number\n\trawCandidates: number\n\tdocumentBytes: number\n\tfanout: number\n\tdepth: number\n\tmemoEntries: number\n}\n\n/** Finite starting ceilings; U5/U6 adversarial workload evidence must tune them.\n * Document payload accounting is NOT Convex storage/index/prefetch I/O accounting.\n */\nconst defaultBudgets: Readonly<ManagedBudgets> = Object.freeze({\n\treadOperations: 4096,\n\tindexRanges: 1024,\n\trawCandidates: 8192,\n\tdocumentBytes: 16 * MAX_DOCUMENT_BYTES,\n\tfanout: 1024,\n\tdepth: 8,\n\tmemoEntries: 4096,\n})\n\nexport class ManagedReadError extends Error {\n\tconstructor(\n\t\treadonly code:\n\t\t\t| 'UNMANAGED_QUERY_CONTEXT'\n\t\t\t| 'MANAGED_READ_BUDGET'\n\t\t\t| 'POLICY_RECURSION'\n\t\t\t| 'UNSUPPORTED_MANAGED_READ',\n\t) {\n\t\tsuper(code)\n\t\tthis.name = 'ManagedReadError'\n\t}\n}\n\ninterface Authority<DM extends GenericDataModel> {\n\tscope: ManagedScope\n\trules: Rules<SecurityPolicyContext<DM>, DM>\n\tdefaultPolicy: 'allow' | 'deny'\n}\ninterface Capability<DM extends GenericDataModel> extends Authority<DM> {\n\treader: GenericDatabaseReader<DM>\n}\n// Type erasure stays inside the private identity map; registration retains native DM.\nconst capabilities = new WeakMap<object, Capability<any>>()\n\n/** Unique closure-only ordinary facade: helper implementation fields never leak.\n * Ordinary operations preserve their native/helper behavior and receive no new\n * engine ceilings. Register only from query constructors, never mutations/actions.\n */\nexport function registerQueryReader<DM extends GenericDataModel>(\n\traw: GenericDatabaseReader<DM>,\n\tordinary: GenericDatabaseReader<DM>,\n\tauthority: Authority<DM>,\n): GenericDatabaseReader<DM> {\n\t// SAFETY: all base-reader methods are bound forwards; the new identity hides helper fields.\n\tconst facade: GenericDatabaseReader<DM> = Object.freeze({\n\t\tget: ordinary.get.bind(ordinary),\n\t\tquery: <Table extends Parameters<typeof ordinary.query>[0]>(table: Table) =>\n\t\t\tordinaryQuery(ordinary.query(table)),\n\t\tnormalizeId: ordinary.normalizeId.bind(ordinary),\n\t\tsystem: Object.freeze({\n\t\t\tget: ordinary.system.get.bind(ordinary.system),\n\t\t\tquery: <Table extends Parameters<typeof ordinary.system.query>[0]>(table: Table) =>\n\t\t\t\tordinaryQuery(ordinary.system.query(table)),\n\t\t\tnormalizeId: ordinary.system.normalizeId.bind(ordinary.system),\n\t\t}),\n\t})\n\t// SAFETY: capabilities are retrieved using the same facade with its native DM.\n\tcapabilities.set(facade, { reader: raw, ...snapshot(authority) })\n\treturn facade\n}\n\nexport interface ManagedCounters {\n\treadonly readOperations: number\n\treadonly indexRanges: number\n\treadonly rawCandidates: number\n\treadonly documentBytesObserved: number\n\treadonly documentBytesReserved: number\n\treadonly fanout: number\n\treadonly memoEntries: number\n}\nexport interface LeafReservation {\n\t/** Settle/refund exactly once, including missing/error results (null). */\n\tsettle(document: GenericDocument | null): void\n}\nexport interface ManagedReadRequest<DM extends GenericDataModel> {\n\treadonly db: GenericDatabaseReader<DM>\n\treadonly scope: ManagedScope & { readonly policyVersion: string }\n\treadonly budgets: Readonly<ManagedBudgets>\n\treadonly counters: ManagedCounters\n\t/** Future native leaf adapter reserves BEFORE every actual next/get, not an outer stream. */\n\treserveLeaf(): LeafReservation\n\topenRange(): void\n\texpand(depth: number, count?: number): void\n\t/** Raw candidate visibility for the private executor; every leaf is metered.\n\t * Its iterator reserves each next internally; do not add an outer reservation.\n\t * Eligibility/authorization must complete before its key is eligible to advance.\n\t */\n\tleafQuery(table: string): QueryInitializer<any>\n\tauthorize(table: string, document: GenericDocument): Promise<boolean>\n}\n\nexport interface ManagedSecurityConfig<DM extends GenericDataModel> {\n\t/** Entire registry: parent/junction/target/policy dependencies share one request. */\n\ttables: readonly string[]\n\tpolicyVersion: string\n\tbudgets?: Partial<ManagedBudgets>\n\t/** Central server trust assertion. Never inspect third-party wrapper fields.\n\t * The adapter must attest a QUERY transaction reader and the exact effective\n\t * composed policy and immutable scope. It assumes responsibility for that claim.\n\t */\n\ttrustedAdapter?: (\n\t\tctx: ManagedQueryContext<DM>,\n\t) => (Authority<DM> & { reader: GenericDatabaseReader<DM> }) | null\n}\n\n/** Native writer/action contexts are not accepted by the engine contract. */\nexport type ManagedQueryContext<DM extends GenericDataModel> = {\n\tdb: GenericDatabaseReader<DM> & { insert?: never; patch?: never; replace?: never; delete?: never }\n}\n\n/** Central construction, then one shared request per engine invocation.\n * Requests may lower, never raise ceilings. Unknown/native contexts fail closed.\n */\nexport function createManagedSecurity<DM extends GenericDataModel = GenericDataModel>(\n\tconfig: ManagedSecurityConfig<DM>,\n) {\n\tif (\n\t\t!config.policyVersion ||\n\t\t!config.tables.length ||\n\t\tnew Set(config.tables).size !== config.tables.length ||\n\t\tconfig.tables.some((table) => !table || table.startsWith('_'))\n\t)\n\t\tthrow new Error('Invalid managed security configuration')\n\tconst tables = new Set(config.tables)\n\t// Central values may exceed starting defaults; these are application-owned ceilings.\n\tlimits(config.budgets)\n\tconst central = Object.freeze({ ...defaultBudgets, ...config.budgets })\n\tconst policyVersion = config.policyVersion\n\tconst trustedAdapter = config.trustedAdapter\n\treturn <Ctx extends ManagedQueryContext<DM>>(\n\t\tctx: Ctx,\n\t\tlower?: Partial<ManagedBudgets>,\n\t): ManagedReadRequest<DM> => {\n\t\t// SAFETY: identity is registered privately by the query constructor for this DM.\n\t\tconst registered = capabilities.get(ctx.db) as Capability<DM> | undefined\n\t\tconst adapted = registered ? undefined : trustedAdapter?.(ctx)\n\t\tif (!registered && !adapted) throw new ManagedReadError('UNMANAGED_QUERY_CONTEXT')\n\t\tconst cap = registered ?? { ...adapted!, ...snapshot(adapted!) }\n\t\treturn request(cap, tables, limits(lower, central), policyVersion)\n\t}\n}\n\n/** Ordinary rule invocations share a policy-only meter. Ordinary db reads stay\n * unmetered by engine ceilings; supplied rule dependencies never bypass policy.\n * Mutation insert/modify receive the same supplied contract as read callbacks.\n */\nexport function suppliedPolicyRules<DM extends GenericDataModel>(\n\traw: GenericDatabaseReader<DM>,\n\trules: Rules<SecurityPolicyContext<DM>, DM>,\n\tdefaultPolicy: 'allow' | 'deny',\n): Rules<SecurityPolicyContext<DM>, DM> {\n\tconst cap = {\n\t\treader: raw,\n\t\t...snapshot({\n\t\t\trules,\n\t\t\tdefaultPolicy,\n\t\t\tscope: { mode: 'trusted', principal: null, organization: null, tenant: null, role: null },\n\t\t}),\n\t}\n\t// Mutations can change dependencies between callbacks; never memoize ordinary\n\t// policy reads across writes. The shared policy meter still bounds all calls.\n\tconst session = request(cap, null, defaultBudgets, 'ordinary-policy', false)\n\tconst result: Rules<SecurityPolicyContext<DM>, DM> = {}\n\tfor (const table of Object.keys(rules)) {\n\t\tconst operations = rules[table]\n\t\tconst wrapped: NonNullable<typeof operations> = {}\n\t\tif (operations?.read) wrapped.read = (_ctx, doc) => session.authorize(table, doc)\n\t\tif (operations?.insert)\n\t\t\twrapped.insert = (_ctx, doc) => operations.insert!({ db: session.db }, doc)\n\t\tif (operations?.modify)\n\t\t\twrapped.modify = (_ctx, doc) => operations.modify!({ db: session.db }, doc)\n\t\t// SAFETY: the keys originated from this same Rules map.\n\t\tresult[table as keyof typeof result] = wrapped\n\t}\n\treturn result\n}\n\n/** Forward only native query methods, never the RLS helper's unfiltered fields.\n * Ordinary consumption retains its existing policy and has no engine ceilings.\n */\nfunction ordinaryQuery<T extends GenericTableInfo>(\n\tsource: QueryInitializer<T>,\n): QueryInitializer<T> {\n\t// SAFETY: native fluent methods retain the same table metadata; ordered results\n\t// only expose methods the native/helper source itself can successfully invoke.\n\treturn Object.freeze({\n\t\tfullTableScan: () => ordinaryQuery(source.fullTableScan() as QueryInitializer<T>),\n\t\twithIndex: (...args: Parameters<typeof source.withIndex>) =>\n\t\t\tordinaryQuery(source.withIndex(...args) as QueryInitializer<T>),\n\t\twithSearchIndex: (...args: Parameters<typeof source.withSearchIndex>) =>\n\t\t\tordinaryQuery(source.withSearchIndex(...args) as QueryInitializer<T>),\n\t\tfilter: (...args: Parameters<typeof source.filter>) =>\n\t\t\tordinaryQuery(source.filter(...args) as QueryInitializer<T>),\n\t\torder: (...args: Parameters<typeof source.order>) =>\n\t\t\tordinaryQuery(source.order(...args) as QueryInitializer<T>),\n\t\tpaginate: source.paginate.bind(source),\n\t\tcollect: source.collect.bind(source),\n\t\ttake: source.take.bind(source),\n\t\tfirst: source.first.bind(source),\n\t\tunique: source.unique.bind(source),\n\t\t[Symbol.asyncIterator]: () => {\n\t\t\tconst iterator = source[Symbol.asyncIterator]()\n\t\t\tconst facade: typeof iterator = {\n\t\t\t\tnext: iterator.next.bind(iterator),\n\t\t\t}\n\t\t\tif (iterator.return) facade.return = iterator.return.bind(iterator)\n\t\t\tif (iterator.throw) facade.throw = iterator.throw.bind(iterator)\n\t\t\treturn Object.freeze(facade)\n\t\t},\n\t}) as QueryInitializer<T>\n}\n\nfunction limits(\n\toverrides: Partial<ManagedBudgets> = {},\n\tcentral = defaultBudgets,\n): Readonly<ManagedBudgets> {\n\tfor (const [key, value] of Object.entries(overrides)) {\n\t\tif (!Object.hasOwn(defaultBudgets, key) || !Number.isSafeInteger(value) || value <= 0)\n\t\t\tthrow new Error('Invalid managed read budgets')\n\t}\n\treturn Object.freeze({\n\t\treadOperations: Math.min(\n\t\t\tcentral.readOperations,\n\t\t\toverrides.readOperations ?? central.readOperations,\n\t\t),\n\t\tindexRanges: Math.min(central.indexRanges, overrides.indexRanges ?? central.indexRanges),\n\t\trawCandidates: Math.min(\n\t\t\tcentral.rawCandidates,\n\t\t\toverrides.rawCandidates ?? central.rawCandidates,\n\t\t),\n\t\tdocumentBytes: Math.min(\n\t\t\tcentral.documentBytes,\n\t\t\toverrides.documentBytes ?? central.documentBytes,\n\t\t),\n\t\tfanout: Math.min(central.fanout, overrides.fanout ?? central.fanout),\n\t\tdepth: Math.min(central.depth, overrides.depth ?? central.depth),\n\t\tmemoEntries: Math.min(central.memoEntries, overrides.memoEntries ?? central.memoEntries),\n\t})\n}\n\nfunction snapshot<DM extends GenericDataModel>(authority: Authority<DM>): Authority<DM> {\n\tconst rules = Object.fromEntries(\n\t\tObject.entries(authority.rules).map(([table, rules]) => [table, Object.freeze({ ...rules })]),\n\t)\n\treturn Object.freeze({\n\t\tscope: Object.freeze({ ...authority.scope }),\n\t\t// SAFETY: only the table keys and operation callbacks of Rules were copied.\n\t\trules: Object.freeze(rules) as Rules<SecurityPolicyContext<DM>, DM>,\n\t\tdefaultPolicy: authority.defaultPolicy,\n\t})\n}\n\nfunction request<DM extends GenericDataModel>(\n\tcap: Capability<DM>,\n\ttables: ReadonlySet<string> | null,\n\tbudgets: Readonly<ManagedBudgets>,\n\tpolicyVersion: string,\n\tmemoize = true,\n): ManagedReadRequest<DM> {\n\tconst counts = {\n\t\treadOperations: 0,\n\t\tindexRanges: 0,\n\t\trawCandidates: 0,\n\t\tdocumentBytesObserved: 0,\n\t\tdocumentBytesReserved: 0,\n\t\tfanout: 0,\n\t\tmemoEntries: 0,\n\t}\n\tconst view: ManagedCounters = Object.freeze({\n\t\tget readOperations() {\n\t\t\treturn counts.readOperations\n\t\t},\n\t\tget indexRanges() {\n\t\t\treturn counts.indexRanges\n\t\t},\n\t\tget rawCandidates() {\n\t\t\treturn counts.rawCandidates\n\t\t},\n\t\tget documentBytesObserved() {\n\t\t\treturn counts.documentBytesObserved\n\t\t},\n\t\tget documentBytesReserved() {\n\t\t\treturn counts.documentBytesReserved\n\t\t},\n\t\tget fanout() {\n\t\t\treturn counts.fanout\n\t\t},\n\t\tget memoEntries() {\n\t\t\treturn counts.memoEntries\n\t\t},\n\t})\n\tconst memo = new Map<string, GenericDocument | null>()\n\tlet pendingMemo = 0\n\tlet pendingCandidates = 0\n\tconst fail = (): never => {\n\t\tthrow new ManagedReadError('MANAGED_READ_BUDGET')\n\t}\n\tconst assertTable = (table: string) => {\n\t\tif (table.startsWith('_') || (tables && !tables.has(table)))\n\t\t\tthrow new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t}\n\tconst openRange = () => {\n\t\tif (counts.indexRanges >= budgets.indexRanges) fail()\n\t\tcounts.indexRanges++\n\t}\n\tconst reserveLeaf = (): LeafReservation => {\n\t\tif (\n\t\t\tcounts.readOperations >= budgets.readOperations ||\n\t\t\tcounts.rawCandidates + pendingCandidates >= budgets.rawCandidates ||\n\t\t\tcounts.documentBytesObserved + counts.documentBytesReserved + MAX_DOCUMENT_BYTES >\n\t\t\t\tbudgets.documentBytes\n\t\t)\n\t\t\tfail()\n\t\tcounts.readOperations++\n\t\tpendingCandidates++\n\t\tcounts.documentBytesReserved += MAX_DOCUMENT_BYTES\n\t\tlet settled = false\n\t\treturn {\n\t\t\tsettle(document) {\n\t\t\t\tif (settled) throw new Error('Leaf reservation already settled')\n\t\t\t\tsettled = true\n\t\t\t\tpendingCandidates--\n\t\t\t\tcounts.documentBytesReserved -= MAX_DOCUMENT_BYTES\n\t\t\t\tif (document) {\n\t\t\t\t\tcounts.rawCandidates++\n\t\t\t\t\tconst size = getDocumentSize(document)\n\t\t\t\t\tcounts.documentBytesObserved += size\n\t\t\t\t\tif (size > MAX_DOCUMENT_BYTES) fail()\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t}\n\tconst keyOf = (table: string, id: string) => JSON.stringify([table, id])\n\tconst checkCycle = (key: string, ancestors: readonly string[]) => {\n\t\tif (ancestors.includes(key)) throw new ManagedReadError('POLICY_RECURSION')\n\t\tif (ancestors.length >= budgets.depth) fail()\n\t}\n\tasync function authorize(\n\t\ttable: string,\n\t\tdoc: GenericDocument,\n\t\tancestors: readonly string[] = [],\n\t): Promise<boolean> {\n\t\tassertTable(table)\n\t\t// SAFETY: native documents carry a string system ID; normalizeId additionally verifies the declared table.\n\t\tconst id = doc._id as GenericId<string>\n\t\tif (!cap.reader.normalizeId(table, id)) throw new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t\tconst key = keyOf(table, id)\n\t\tcheckCycle(key, ancestors)\n\t\tconst rule = cap.rules[table]?.read\n\t\treturn rule\n\t\t\t? rule(Object.freeze({ db: reader([...ancestors, key]) }), doc)\n\t\t\t: cap.defaultPolicy === 'allow'\n\t}\n\tasync function get(\n\t\ttable: string,\n\t\tid: string,\n\t\tancestors: readonly string[],\n\t): Promise<GenericDocument | null> {\n\t\tassertTable(table)\n\t\tconst key = keyOf(table, id)\n\t\tcheckCycle(key, ancestors) // BEFORE consulting memo: active policy cannot await itself.\n\t\tif (memo.has(key)) return memo.get(key)!\n\t\tif (memoize && counts.memoEntries >= budgets.memoEntries) fail()\n\t\t// Completed results only: independent concurrent branches cannot deadlock\n\t\t// through mutually pending memo promises. Concurrent duplicates may fetch twice.\n\t\tif (memoize) {\n\t\t\tpendingMemo++\n\t\t\tcounts.memoEntries = memo.size + pendingMemo\n\t\t}\n\t\ttry {\n\t\t\topenRange()\n\t\t\tconst reservation = reserveLeaf()\n\t\t\tlet doc: GenericDocument | null\n\t\t\ttry {\n\t\t\t\t// SAFETY: IDs come from native readers or caller-branded IDs, with explicit table identity.\n\t\t\t\tdoc = await cap.reader.get(table, id as GenericId<string>)\n\t\t\t} catch (error) {\n\t\t\t\treservation.settle(null)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\treservation.settle(doc)\n\t\t\tconst result = doc && (await authorize(table, doc, ancestors)) ? doc : null\n\t\t\tif (memoize) memo.set(key, result)\n\t\t\treturn result\n\t\t} finally {\n\t\t\tif (memoize) {\n\t\t\t\tpendingMemo--\n\t\t\t\tcounts.memoEntries = memo.size + pendingMemo\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction query(\n\t\ttable: string,\n\t\tsource: QueryInitializer<any>,\n\t\tancestors: readonly string[],\n\t\tauthorized: boolean,\n\t): QueryInitializer<any> {\n\t\tfunction unsupported(): never {\n\t\t\tthrow new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t\t}\n\t\tasync function* iterate() {\n\t\t\topenRange()\n\t\t\tlet iterator: AsyncIterator<GenericDocument> | undefined\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst reservation = reserveLeaf()\n\t\t\t\t\tlet next: IteratorResult<GenericDocument>\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Native iterator construction starts the query. Reserve before\n\t\t\t\t\t\t// both initialization and next; every later next reserves anew.\n\t\t\t\t\t\titerator ??= source[Symbol.asyncIterator]()\n\t\t\t\t\t\tnext = await iterator.next()\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\treservation.settle(null)\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t\treservation.settle(next.done ? null : next.value)\n\t\t\t\t\tif (next.done) return\n\t\t\t\t\tif (!authorized || (await authorize(table, next.value, ancestors))) yield next.value\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tawait iterator?.return?.()\n\t\t\t}\n\t\t}\n\t\tasync function take(n: number) {\n\t\t\tif (!Number.isSafeInteger(n) || n < 0 || n > budgets.rawCandidates)\n\t\t\t\tthrow new ManagedReadError('MANAGED_READ_BUDGET')\n\t\t\tconst docs: GenericDocument[] = []\n\t\t\tif (n === 0) return docs\n\t\t\tfor await (const doc of iterate()) {\n\t\t\t\tdocs.push(doc)\n\t\t\t\tif (docs.length === n) break\n\t\t\t}\n\t\t\treturn docs\n\t\t}\n\t\t// SAFETY: forwarding preserves native document/index types; only consumers are replaced.\n\t\treturn Object.freeze({\n\t\t\tfullTableScan: () =>\n\t\t\t\tquery(table, source.fullTableScan() as QueryInitializer<any>, ancestors, authorized),\n\t\t\twithIndex: (...args: Parameters<typeof source.withIndex>) =>\n\t\t\t\tquery(table, source.withIndex(...args) as QueryInitializer<any>, ancestors, authorized),\n\t\t\torder: (...args: Parameters<typeof source.order>) =>\n\t\t\t\tquery(table, source.order(...args) as QueryInitializer<any>, ancestors, authorized),\n\t\t\t// Native filters/search/pagination may scan/prefetch hidden rows. They\n\t\t\t// cannot prove per-leaf reservation via public APIs; reject on managed readers.\n\t\t\tfilter: unsupported,\n\t\t\twithSearchIndex: unsupported,\n\t\t\tpaginate: unsupported,\n\t\t\tcollect: unsupported,\n\t\t\ttake,\n\t\t\tfirst: async () => (await take(1))[0] ?? null,\n\t\t\tunique: async () => {\n\t\t\t\tconst docs = await take(2)\n\t\t\t\tif (docs.length > 1) throw new Error('Query is not unique')\n\t\t\t\treturn docs[0] ?? null\n\t\t\t},\n\t\t\t[Symbol.asyncIterator]: iterate,\n\t\t}) as QueryInitializer<any>\n\t}\n\tfunction reader(ancestors: readonly string[]): GenericDatabaseReader<any> {\n\t\tconst blocked = () => {\n\t\t\tthrow new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t\t}\n\t\t// SAFETY: normalizeId retains the requested table brand; query forwarding retains native table metadata.\n\t\treturn Object.freeze({\n\t\t\tget: async (arg0: string, arg1?: string) => {\n\t\t\t\tif (arg1 !== undefined) return get(arg0, arg1, ancestors)\n\t\t\t\t// Resolve only from the explicit registry (or known policy tables for\n\t\t\t\t// ordinary policy callbacks). Never raw-get an unrecognized ID.\n\t\t\t\tconst table = [...(tables ?? new Set(Object.keys(cap.rules)))].find((name) =>\n\t\t\t\t\tcap.reader.normalizeId(name, arg0),\n\t\t\t\t)\n\t\t\t\treturn table ? get(table, arg0, ancestors) : null\n\t\t\t},\n\t\t\tquery: (table: string) => {\n\t\t\t\tassertTable(table)\n\t\t\t\treturn query(table, cap.reader.query(table), ancestors, true)\n\t\t\t},\n\t\t\tnormalizeId: (table: string, id: string) => {\n\t\t\t\tassertTable(table)\n\t\t\t\treturn cap.reader.normalizeId(table, id)\n\t\t\t},\n\t\t\tsystem: Object.freeze({ get: blocked, query: blocked, normalizeId: blocked }),\n\t\t}) as GenericDatabaseReader<any>\n\t}\n\treturn Object.freeze({\n\t\tdb: reader([]),\n\t\tscope: Object.freeze({ ...cap.scope, policyVersion }),\n\t\tbudgets,\n\t\tcounters: view,\n\t\treserveLeaf,\n\t\topenRange,\n\t\texpand(depth: number, count = 1) {\n\t\t\tif (\n\t\t\t\t!Number.isSafeInteger(depth) ||\n\t\t\t\tdepth < 0 ||\n\t\t\t\tdepth > budgets.depth ||\n\t\t\t\t!Number.isSafeInteger(count) ||\n\t\t\t\tcount < 0 ||\n\t\t\t\tcounts.fanout + count > budgets.fanout\n\t\t\t)\n\t\t\t\tfail()\n\t\t\tcounts.fanout += count\n\t\t},\n\t\tleafQuery: (table: string) => {\n\t\t\tassertTable(table)\n\t\t\treturn query(table, cap.reader.query(table), [], false)\n\t\t},\n\t\tauthorize: (table: string, doc: GenericDocument) => authorize(table, doc),\n\t})\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"security.mjs","names":["MAX_DOCUMENT_BYTES","defaultBudgets","ManagedReadError","code","capabilities","registerQueryReader","facade","ordinary","ordinaryQuery","table","raw","snapshot","authority","createManagedSecurity","config","tables","limits","central","policyVersion","trustedAdapter","admit","registered","ctx","adapted","managed","request","lower","key","suppliedPolicyRules","session","result","rules","operations","wrapped","doc","source","args","iterator","value","overrides","counts","view","searchUsed","searchCounts","memo","pendingMemo","pendingCandidates","leafFailures","leafLimit","budgets","fail","assertTable","openRange","reserveLeaf","settled","document","size","getDocumentSize","keyOf","id","checkCycle","ancestors","authorize","cap","rule","reader","get","memoize","reservation","error","query","unsupported","iterate","reason","authorized","next","take","n","docs","blocked","arg1","arg0","name","index","filter","q","text","equalities","field","options","depth","count"],"sources":["../../src/querying/security.ts"],"sourcesContent":["/** Internal managed-read contracts for the relational executor. No root/package export. */\nimport type {\n\tGenericDataModel,\n\tGenericDatabaseReader,\n\tGenericDocument,\n\tGenericTableInfo,\n\tQueryInitializer,\n} from 'convex/server'\nimport { getDocumentSize, type GenericId } from 'convex/values'\nimport type { SearchIndexMetadata } from '../relations'\nimport type { PaginationOptions, PaginationResult } from 'convex/server'\nimport type { FilterScalar } from './filters'\nimport type { Rules } from '../tenancy'\n\nexport const MAX_DOCUMENT_BYTES = 1024 * 1024\n\n/** Additive context supplied to existing read/insert/modify rules on BOTH paths.\n * Reads through db are authorized and bounded. collect, native paginate/filter,\n * search, and system reads fail closed; use get, take/first/unique, or iteration.\n * Trusted server callbacks can close\n * over other readers; arbitrary captured JavaScript cannot be sandboxed here.\n */\nexport interface SecurityPolicyContext<DM extends GenericDataModel> {\n\treadonly db: GenericDatabaseReader<DM>\n}\n\nexport interface ManagedScope {\n\treadonly mode: 'authenticated' | 'system' | 'trusted'\n\treadonly principal: string | null\n\treadonly organization: string | null\n\treadonly tenant: string | null\n\treadonly role: string | null\n}\n\nexport interface ManagedBudgets {\n\tsearchCandidates: number\n\treadOperations: number\n\tindexRanges: number\n\trawCandidates: number\n\tdocumentBytes: number\n\tfanout: number\n\tdepth: number\n\tmemoEntries: number\n}\n\n/** Finite starting ceilings; U5/U6 adversarial workload evidence must tune them.\n * Document payload accounting is NOT Convex storage/index/prefetch I/O accounting.\n */\nconst defaultBudgets: Readonly<ManagedBudgets> = Object.freeze({\n\tsearchCandidates: 100,\n\treadOperations: 4096,\n\tindexRanges: 1024,\n\trawCandidates: 8192,\n\tdocumentBytes: 16 * MAX_DOCUMENT_BYTES,\n\tfanout: 1024,\n\tdepth: 8,\n\tmemoEntries: 4096,\n})\n\nexport class ManagedReadError extends Error {\n\tconstructor(\n\t\treadonly code:\n\t\t\t| 'UNMANAGED_QUERY_CONTEXT'\n\t\t\t| 'MANAGED_READ_BUDGET'\n\t\t\t| 'POLICY_RECURSION'\n\t\t\t| 'UNSUPPORTED_MANAGED_READ',\n\t) {\n\t\tsuper(code)\n\t\tthis.name = 'ManagedReadError'\n\t}\n}\n\ninterface Authority<DM extends GenericDataModel> {\n\tscope: ManagedScope\n\trules: Rules<SecurityPolicyContext<DM>, DM>\n\tdefaultPolicy: 'allow' | 'deny'\n}\ninterface Capability<DM extends GenericDataModel> extends Authority<DM> {\n\treader: GenericDatabaseReader<DM>\n}\n// Type erasure stays inside the private identity map; registration retains native DM.\nconst capabilities = new WeakMap<object, Capability<any>>()\n\n/** Unique closure-only ordinary facade: helper implementation fields never leak.\n * Ordinary operations preserve their native/helper behavior and receive no new\n * engine ceilings. Register only from query constructors, never mutations/actions.\n */\nexport function registerQueryReader<DM extends GenericDataModel>(\n\traw: GenericDatabaseReader<DM>,\n\tordinary: GenericDatabaseReader<DM>,\n\tauthority: Authority<DM>,\n): GenericDatabaseReader<DM> {\n\t// SAFETY: all base-reader methods are bound forwards; the new identity hides helper fields.\n\tconst facade: GenericDatabaseReader<DM> = Object.freeze({\n\t\tget: ordinary.get.bind(ordinary),\n\t\tquery: <Table extends Parameters<typeof ordinary.query>[0]>(table: Table) =>\n\t\t\tordinaryQuery(ordinary.query(table)),\n\t\tnormalizeId: ordinary.normalizeId.bind(ordinary),\n\t\tsystem: Object.freeze({\n\t\t\tget: ordinary.system.get.bind(ordinary.system),\n\t\t\tquery: <Table extends Parameters<typeof ordinary.system.query>[0]>(table: Table) =>\n\t\t\t\tordinaryQuery(ordinary.system.query(table)),\n\t\t\tnormalizeId: ordinary.system.normalizeId.bind(ordinary.system),\n\t\t}),\n\t})\n\t// SAFETY: capabilities are retrieved using the same facade with its native DM.\n\tcapabilities.set(facade, { reader: raw, ...snapshot(authority) })\n\treturn facade\n}\n\nexport interface ManagedCounters {\n\treadonly readOperations: number\n\treadonly indexRanges: number\n\treadonly rawCandidates: number\n\treadonly documentBytesObserved: number\n\treadonly documentBytesReserved: number\n\treadonly fanout: number\n\treadonly memoEntries: number\n}\nexport interface LeafReservation {\n\t/** Settle/refund exactly once, including missing/error results (null). */\n\tsettle(document: GenericDocument | null): void\n}\nexport interface ManagedReadRequest<DM extends GenericDataModel> {\n\treadonly db: GenericDatabaseReader<DM>\n\treadonly scope: ManagedScope & { readonly policyVersion: string }\n\treadonly budgets: Readonly<ManagedBudgets>\n\treadonly counters: ManagedCounters\n\t/** Only the private search operation enables atomic descendant completion. */\n\treadonly atomicCompletion: boolean\n\tsearch(\n\t\ttable: string,\n\t\tindex: SearchIndexMetadata,\n\t\ttext: string,\n\t\tequalities: readonly { field: string; value: FilterScalar }[],\n\t\toptions: PaginationOptions,\n\t): Promise<PaginationResult<GenericDocument>>\n\t/** Future native leaf adapter reserves BEFORE every actual next/get, not an outer stream. */\n\treserveLeaf(): LeafReservation\n\t/** Only raw leaf reservation failures from this request can be resumed by the executor. */\n\tleafBudgetFailure(error: ManagedReadError): 'row-budget' | 'byte-budget' | undefined\n\topenRange(): void\n\texpand(depth: number, count?: number): void\n\t/** Raw candidate visibility for the private executor; every leaf is metered.\n\t * Its iterator reserves each next internally; do not add an outer reservation.\n\t * Eligibility/authorization must complete before its key is eligible to advance.\n\t */\n\tleafQuery(table: string): QueryInitializer<any>\n\tauthorize(table: string, document: GenericDocument): Promise<boolean>\n}\n\nexport interface ManagedSecurityConfig<DM extends GenericDataModel> {\n\t/** Entire registry: parent/junction/target/policy dependencies share one request. */\n\ttables: readonly string[]\n\tpolicyVersion: string\n\tbudgets?: Partial<ManagedBudgets>\n\t/** Central server trust assertion. Never inspect third-party wrapper fields.\n\t * The adapter must attest a QUERY transaction reader and the exact effective\n\t * composed policy and immutable scope. It assumes responsibility for that claim.\n\t */\n\ttrustedAdapter?: (\n\t\tctx: ManagedQueryContext<DM>,\n\t) => (Authority<DM> & { reader: GenericDatabaseReader<DM> }) | null\n}\n\n/** Native writer/action contexts are not accepted by the engine contract. */\nexport type ManagedQueryContext<DM extends GenericDataModel> = {\n\tdb: GenericDatabaseReader<DM> & {\n\t\tinsert?: never\n\t\tpatch?: never\n\t\treplace?: never\n\t\tdelete?: never\n\t}\n}\n\n/** Central construction, then one shared request per engine invocation.\n * Requests may lower, never raise ceilings. Unknown/native contexts fail closed.\n */\nexport function createManagedSecurity<DM extends GenericDataModel = GenericDataModel>(\n\tconfig: ManagedSecurityConfig<DM>,\n) {\n\tif (\n\t\t!config.policyVersion ||\n\t\t!config.tables.length ||\n\t\tnew Set(config.tables).size !== config.tables.length ||\n\t\tconfig.tables.some((table) => !table || table.startsWith('_'))\n\t)\n\t\tthrow new Error('Invalid managed security configuration')\n\tconst tables = new Set(config.tables)\n\t// Central values may exceed starting defaults; these are application-owned ceilings.\n\tlimits(config.budgets)\n\tconst central = Object.freeze({ ...defaultBudgets, ...config.budgets })\n\tconst policyVersion = config.policyVersion\n\tconst trustedAdapter = config.trustedAdapter\n\tfunction admit(ctx: ManagedQueryContext<DM>): Capability<DM> {\n\t\t// SAFETY: identity is registered privately by the query constructor for this DM.\n\t\tconst registered = capabilities.get(ctx.db) as Capability<DM> | undefined\n\t\tconst adapted = registered ? undefined : trustedAdapter?.(ctx)\n\t\tif (!registered && !adapted) throw new ManagedReadError('UNMANAGED_QUERY_CONTEXT')\n\t\treturn registered ?? { ...adapted!, ...snapshot(adapted!) }\n\t}\n\tfunction managed<Ctx extends ManagedQueryContext<DM>>(\n\t\tctx: Ctx,\n\t\tlower?: Partial<ManagedBudgets>,\n\t): ManagedReadRequest<DM> {\n\t\treturn request(admit(ctx), tables, limits(lower, central), policyVersion)\n\t}\n\treturn Object.assign(managed, {\n\t\t/** Scope-only admission for public cursors. Never returns the registered reader. */\n\t\tcursorScope(ctx: ManagedQueryContext<DM>): ManagedScope & { readonly policyVersion: string } {\n\t\t\tif (!ctx?.db || ['insert', 'patch', 'replace', 'delete'].some((key) => key in ctx.db))\n\t\t\t\tthrow new ManagedReadError('UNMANAGED_QUERY_CONTEXT')\n\t\t\treturn Object.freeze({ ...admit(ctx).scope, policyVersion })\n\t\t},\n\t})\n}\n\n/** Ordinary rule invocations share a policy-only meter. Ordinary db reads stay\n * unmetered by engine ceilings; supplied rule dependencies never bypass policy.\n * Mutation insert/modify receive the same supplied contract as read callbacks.\n */\nexport function suppliedPolicyRules<DM extends GenericDataModel>(\n\traw: GenericDatabaseReader<DM>,\n\trules: Rules<SecurityPolicyContext<DM>, DM>,\n\tdefaultPolicy: 'allow' | 'deny',\n): Rules<SecurityPolicyContext<DM>, DM> {\n\tconst cap = {\n\t\treader: raw,\n\t\t...snapshot({\n\t\t\trules,\n\t\t\tdefaultPolicy,\n\t\t\tscope: {\n\t\t\t\tmode: 'trusted',\n\t\t\t\tprincipal: null,\n\t\t\t\torganization: null,\n\t\t\t\ttenant: null,\n\t\t\t\trole: null,\n\t\t\t},\n\t\t}),\n\t}\n\t// Mutations can change dependencies between callbacks; never memoize ordinary\n\t// policy reads across writes. The shared policy meter still bounds all calls.\n\tconst session = request(cap, null, defaultBudgets, 'ordinary-policy', false)\n\tconst result: Rules<SecurityPolicyContext<DM>, DM> = {}\n\tfor (const table of Object.keys(rules)) {\n\t\tconst operations = rules[table]\n\t\tconst wrapped: NonNullable<typeof operations> = {}\n\t\tif (operations?.read) wrapped.read = (_ctx, doc) => session.authorize(table, doc)\n\t\tif (operations?.insert)\n\t\t\twrapped.insert = (_ctx, doc) => operations.insert!({ db: session.db }, doc)\n\t\tif (operations?.modify)\n\t\t\twrapped.modify = (_ctx, doc) => operations.modify!({ db: session.db }, doc)\n\t\t// SAFETY: the keys originated from this same Rules map.\n\t\tresult[table as keyof typeof result] = wrapped\n\t}\n\treturn result\n}\n\n/** Forward only native query methods, never the RLS helper's unfiltered fields.\n * Ordinary consumption retains its existing policy and has no engine ceilings.\n */\nfunction ordinaryQuery<T extends GenericTableInfo>(\n\tsource: QueryInitializer<T>,\n): QueryInitializer<T> {\n\t// SAFETY: native fluent methods retain the same table metadata; ordered results\n\t// only expose methods the native/helper source itself can successfully invoke.\n\treturn Object.freeze({\n\t\tfullTableScan: () => ordinaryQuery(source.fullTableScan() as QueryInitializer<T>),\n\t\twithIndex: (...args: Parameters<typeof source.withIndex>) =>\n\t\t\tordinaryQuery(source.withIndex(...args) as QueryInitializer<T>),\n\t\twithSearchIndex: (...args: Parameters<typeof source.withSearchIndex>) =>\n\t\t\tordinaryQuery(source.withSearchIndex(...args) as QueryInitializer<T>),\n\t\tfilter: (...args: Parameters<typeof source.filter>) =>\n\t\t\tordinaryQuery(source.filter(...args) as QueryInitializer<T>),\n\t\torder: (...args: Parameters<typeof source.order>) =>\n\t\t\tordinaryQuery(source.order(...args) as QueryInitializer<T>),\n\t\tpaginate: source.paginate.bind(source),\n\t\tcollect: source.collect.bind(source),\n\t\ttake: source.take.bind(source),\n\t\tfirst: source.first.bind(source),\n\t\tunique: source.unique.bind(source),\n\t\t[Symbol.asyncIterator]: () => {\n\t\t\tconst iterator = source[Symbol.asyncIterator]()\n\t\t\tconst facade: typeof iterator = {\n\t\t\t\tnext: iterator.next.bind(iterator),\n\t\t\t}\n\t\t\tif (iterator.return) facade.return = iterator.return.bind(iterator)\n\t\t\tif (iterator.throw) facade.throw = iterator.throw.bind(iterator)\n\t\t\treturn Object.freeze(facade)\n\t\t},\n\t}) as QueryInitializer<T>\n}\n\nfunction limits(\n\toverrides: Partial<ManagedBudgets> = {},\n\tcentral = defaultBudgets,\n): Readonly<ManagedBudgets> {\n\tfor (const [key, value] of Object.entries(overrides)) {\n\t\tif (!Object.hasOwn(defaultBudgets, key) || !Number.isSafeInteger(value) || value <= 0)\n\t\t\tthrow new Error('Invalid managed read budgets')\n\t}\n\treturn Object.freeze({\n\t\tsearchCandidates: Math.min(\n\t\t\tcentral.searchCandidates,\n\t\t\toverrides.searchCandidates ?? central.searchCandidates,\n\t\t),\n\t\treadOperations: Math.min(\n\t\t\tcentral.readOperations,\n\t\t\toverrides.readOperations ?? central.readOperations,\n\t\t),\n\t\tindexRanges: Math.min(central.indexRanges, overrides.indexRanges ?? central.indexRanges),\n\t\trawCandidates: Math.min(\n\t\t\tcentral.rawCandidates,\n\t\t\toverrides.rawCandidates ?? central.rawCandidates,\n\t\t),\n\t\tdocumentBytes: Math.min(\n\t\t\tcentral.documentBytes,\n\t\t\toverrides.documentBytes ?? central.documentBytes,\n\t\t),\n\t\tfanout: Math.min(central.fanout, overrides.fanout ?? central.fanout),\n\t\tdepth: Math.min(central.depth, overrides.depth ?? central.depth),\n\t\tmemoEntries: Math.min(central.memoEntries, overrides.memoEntries ?? central.memoEntries),\n\t})\n}\n\nfunction snapshot<DM extends GenericDataModel>(authority: Authority<DM>): Authority<DM> {\n\tconst rules = Object.fromEntries(\n\t\tObject.entries(authority.rules).map(([table, rules]) => [table, Object.freeze({ ...rules })]),\n\t)\n\treturn Object.freeze({\n\t\tscope: Object.freeze({ ...authority.scope }),\n\t\t// SAFETY: only the table keys and operation callbacks of Rules were copied.\n\t\trules: Object.freeze(rules) as Rules<SecurityPolicyContext<DM>, DM>,\n\t\tdefaultPolicy: authority.defaultPolicy,\n\t})\n}\n\nfunction request<DM extends GenericDataModel>(\n\tcap: Capability<DM>,\n\ttables: ReadonlySet<string> | null,\n\tbudgets: Readonly<ManagedBudgets>,\n\tpolicyVersion: string,\n\tmemoize = true,\n): ManagedReadRequest<DM> {\n\tconst counts = {\n\t\treadOperations: 0,\n\t\tindexRanges: 0,\n\t\trawCandidates: 0,\n\t\tdocumentBytesObserved: 0,\n\t\tdocumentBytesReserved: 0,\n\t\tfanout: 0,\n\t\tmemoEntries: 0,\n\t}\n\tconst view: ManagedCounters = Object.freeze({\n\t\tget readOperations() {\n\t\t\treturn counts.readOperations\n\t\t},\n\t\tget indexRanges() {\n\t\t\treturn counts.indexRanges\n\t\t},\n\t\tget rawCandidates() {\n\t\t\treturn counts.rawCandidates\n\t\t},\n\t\tget documentBytesObserved() {\n\t\t\treturn counts.documentBytesObserved\n\t\t},\n\t\tget documentBytesReserved() {\n\t\t\treturn counts.documentBytesReserved\n\t\t},\n\t\tget fanout() {\n\t\t\treturn counts.fanout\n\t\t},\n\t\tget memoEntries() {\n\t\t\treturn counts.memoEntries\n\t\t},\n\t})\n\tlet searchUsed = false\n\tconst searchCounts = { rawCandidates: 0, documentBytes: 0 }\n\tconst memo = new Map<string, GenericDocument | null>()\n\tlet pendingMemo = 0\n\tlet pendingCandidates = 0\n\tconst leafFailures = new WeakMap<ManagedReadError, 'row-budget' | 'byte-budget'>()\n\tconst leafLimit = () => {\n\t\tif (\n\t\t\tcounts.readOperations >= budgets.readOperations ||\n\t\t\tcounts.rawCandidates + pendingCandidates >= budgets.rawCandidates\n\t\t)\n\t\t\treturn 'row-budget'\n\t\tif (\n\t\t\tcounts.documentBytesObserved + counts.documentBytesReserved + MAX_DOCUMENT_BYTES >\n\t\t\tbudgets.documentBytes\n\t\t)\n\t\t\treturn 'byte-budget'\n\t\treturn undefined\n\t}\n\tconst fail = (): never => {\n\t\tthrow new ManagedReadError('MANAGED_READ_BUDGET')\n\t}\n\tconst assertTable = (table: string) => {\n\t\tif (table.startsWith('_') || (tables && !tables.has(table)))\n\t\t\tthrow new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t}\n\tconst openRange = () => {\n\t\tif (counts.indexRanges >= budgets.indexRanges) fail()\n\t\tcounts.indexRanges++\n\t}\n\tconst reserveLeaf = (): LeafReservation => {\n\t\tif (leafLimit()) fail()\n\t\tcounts.readOperations++\n\t\tpendingCandidates++\n\t\tcounts.documentBytesReserved += MAX_DOCUMENT_BYTES\n\t\tlet settled = false\n\t\treturn {\n\t\t\tsettle(document) {\n\t\t\t\tif (settled) throw new Error('Leaf reservation already settled')\n\t\t\t\tsettled = true\n\t\t\t\tpendingCandidates--\n\t\t\t\tcounts.documentBytesReserved -= MAX_DOCUMENT_BYTES\n\t\t\t\tif (document) {\n\t\t\t\t\tcounts.rawCandidates++\n\t\t\t\t\tconst size = getDocumentSize(document)\n\t\t\t\t\tcounts.documentBytesObserved += size\n\t\t\t\t\tif (size > MAX_DOCUMENT_BYTES) fail()\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t}\n\tconst keyOf = (table: string, id: string) => JSON.stringify([table, id])\n\tconst checkCycle = (key: string, ancestors: readonly string[]) => {\n\t\tif (ancestors.includes(key)) throw new ManagedReadError('POLICY_RECURSION')\n\t\tif (ancestors.length >= budgets.depth) fail()\n\t}\n\tasync function authorize(\n\t\ttable: string,\n\t\tdoc: GenericDocument,\n\t\tancestors: readonly string[] = [],\n\t): Promise<boolean> {\n\t\tassertTable(table)\n\t\t// SAFETY: native documents carry a string system ID; normalizeId additionally verifies the declared table.\n\t\tconst id = doc._id as GenericId<string>\n\t\tif (!cap.reader.normalizeId(table, id)) throw new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t\tconst key = keyOf(table, id)\n\t\tcheckCycle(key, ancestors)\n\t\tconst rule = cap.rules[table]?.read\n\t\treturn rule\n\t\t\t? rule(Object.freeze({ db: reader([...ancestors, key]) }), doc)\n\t\t\t: cap.defaultPolicy === 'allow'\n\t}\n\tasync function get(\n\t\ttable: string,\n\t\tid: string,\n\t\tancestors: readonly string[],\n\t): Promise<GenericDocument | null> {\n\t\tassertTable(table)\n\t\tconst key = keyOf(table, id)\n\t\tcheckCycle(key, ancestors) // BEFORE consulting memo: active policy cannot await itself.\n\t\tif (memo.has(key)) return memo.get(key)!\n\t\tif (memoize && counts.memoEntries >= budgets.memoEntries) fail()\n\t\t// Completed results only: independent concurrent branches cannot deadlock\n\t\t// through mutually pending memo promises. Concurrent duplicates may fetch twice.\n\t\tif (memoize) {\n\t\t\tpendingMemo++\n\t\t\tcounts.memoEntries = memo.size + pendingMemo\n\t\t}\n\t\ttry {\n\t\t\topenRange()\n\t\t\tconst reservation = reserveLeaf()\n\t\t\tlet doc: GenericDocument | null\n\t\t\ttry {\n\t\t\t\t// SAFETY: IDs come from native readers or caller-branded IDs, with explicit table identity.\n\t\t\t\tdoc = await cap.reader.get(table, id as GenericId<string>)\n\t\t\t} catch (error) {\n\t\t\t\treservation.settle(null)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\treservation.settle(doc)\n\t\t\tconst result = doc && (await authorize(table, doc, ancestors)) ? doc : null\n\t\t\tif (memoize) memo.set(key, result)\n\t\t\treturn result\n\t\t} finally {\n\t\t\tif (memoize) {\n\t\t\t\tpendingMemo--\n\t\t\t\tcounts.memoEntries = memo.size + pendingMemo\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction query(\n\t\ttable: string,\n\t\tsource: QueryInitializer<any>,\n\t\tancestors: readonly string[],\n\t\tauthorized: boolean,\n\t): QueryInitializer<any> {\n\t\tfunction unsupported(): never {\n\t\t\tthrow new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t\t}\n\t\tasync function* iterate() {\n\t\t\topenRange()\n\t\t\tlet iterator: AsyncIterator<GenericDocument> | undefined\n\t\t\ttry {\n\t\t\t\twhile (true) {\n\t\t\t\t\t// Mark only this raw leaf's pre-fetch reservation, never native or policy errors.\n\t\t\t\t\tconst reason = !authorized && leafLimit()\n\t\t\t\t\tif (reason) {\n\t\t\t\t\t\tconst error = new ManagedReadError('MANAGED_READ_BUDGET')\n\t\t\t\t\t\tleafFailures.set(error, reason)\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t\tconst reservation = reserveLeaf()\n\t\t\t\t\tlet next: IteratorResult<GenericDocument>\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Native iterator construction starts the query. Reserve before\n\t\t\t\t\t\t// both initialization and next; every later next reserves anew.\n\t\t\t\t\t\titerator ??= source[Symbol.asyncIterator]()\n\t\t\t\t\t\tnext = await iterator.next()\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\treservation.settle(null)\n\t\t\t\t\t\tthrow error\n\t\t\t\t\t}\n\t\t\t\t\treservation.settle(next.done ? null : next.value)\n\t\t\t\t\tif (next.done) return\n\t\t\t\t\tif (!authorized || (await authorize(table, next.value, ancestors))) yield next.value\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tawait iterator?.return?.()\n\t\t\t}\n\t\t}\n\t\tasync function take(n: number) {\n\t\t\tif (!Number.isSafeInteger(n) || n < 0 || n > budgets.rawCandidates)\n\t\t\t\tthrow new ManagedReadError('MANAGED_READ_BUDGET')\n\t\t\tconst docs: GenericDocument[] = []\n\t\t\tif (n === 0) return docs\n\t\t\tfor await (const doc of iterate()) {\n\t\t\t\tdocs.push(doc)\n\t\t\t\tif (docs.length === n) break\n\t\t\t}\n\t\t\treturn docs\n\t\t}\n\t\t// SAFETY: forwarding preserves native document/index types; only consumers are replaced.\n\t\treturn Object.freeze({\n\t\t\tfullTableScan: () =>\n\t\t\t\tquery(table, source.fullTableScan() as QueryInitializer<any>, ancestors, authorized),\n\t\t\twithIndex: (...args: Parameters<typeof source.withIndex>) =>\n\t\t\t\tquery(table, source.withIndex(...args) as QueryInitializer<any>, ancestors, authorized),\n\t\t\torder: (...args: Parameters<typeof source.order>) =>\n\t\t\t\tquery(table, source.order(...args) as QueryInitializer<any>, ancestors, authorized),\n\t\t\t// Native filters/search/pagination may scan/prefetch hidden rows. They\n\t\t\t// cannot prove per-leaf reservation via public APIs; reject on managed readers.\n\t\t\tfilter: unsupported,\n\t\t\twithSearchIndex: unsupported,\n\t\t\tpaginate: unsupported,\n\t\t\tcollect: unsupported,\n\t\t\ttake,\n\t\t\tfirst: async () => (await take(1))[0] ?? null,\n\t\t\tunique: async () => {\n\t\t\t\tconst docs = await take(2)\n\t\t\t\tif (docs.length > 1) throw new Error('Query is not unique')\n\t\t\t\treturn docs[0] ?? null\n\t\t\t},\n\t\t\t[Symbol.asyncIterator]: iterate,\n\t\t}) as QueryInitializer<any>\n\t}\n\tfunction reader(ancestors: readonly string[]): GenericDatabaseReader<any> {\n\t\tconst blocked = () => {\n\t\t\tthrow new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t\t}\n\t\t// SAFETY: normalizeId retains the requested table brand; query forwarding retains native table metadata.\n\t\treturn Object.freeze({\n\t\t\tget: async (arg0: string, arg1?: string) => {\n\t\t\t\tif (arg1 !== undefined) return get(arg0, arg1, ancestors)\n\t\t\t\t// Resolve only from the explicit registry (or known policy tables for\n\t\t\t\t// ordinary policy callbacks). Never raw-get an unrecognized ID.\n\t\t\t\tconst table = [...(tables ?? new Set(Object.keys(cap.rules)))].find((name) =>\n\t\t\t\t\tcap.reader.normalizeId(name, arg0),\n\t\t\t\t)\n\t\t\t\treturn table ? get(table, arg0, ancestors) : null\n\t\t\t},\n\t\t\tquery: (table: string) => {\n\t\t\t\tassertTable(table)\n\t\t\t\treturn query(table, cap.reader.query(table), ancestors, true)\n\t\t\t},\n\t\t\tnormalizeId: (table: string, id: string) => {\n\t\t\t\tassertTable(table)\n\t\t\t\treturn cap.reader.normalizeId(table, id)\n\t\t\t},\n\t\t\tsystem: Object.freeze({\n\t\t\t\tget: blocked,\n\t\t\t\tquery: blocked,\n\t\t\t\tnormalizeId: blocked,\n\t\t\t}),\n\t\t}) as GenericDatabaseReader<any>\n\t}\n\treturn Object.freeze({\n\t\tdb: reader([]),\n\t\tscope: Object.freeze({ ...cap.scope, policyVersion }),\n\t\tbudgets,\n\t\tcounters: view,\n\t\tget atomicCompletion() {\n\t\t\treturn searchUsed\n\t\t},\n\t\tasync search(\n\t\t\ttable: string,\n\t\t\tindex: SearchIndexMetadata,\n\t\t\ttext: string,\n\t\t\tequalities: readonly { field: string; value: FilterScalar }[],\n\t\t\toptions: PaginationOptions,\n\t\t) {\n\t\t\tassertTable(table)\n\t\t\tif (searchUsed) throw new ManagedReadError('UNSUPPORTED_MANAGED_READ')\n\t\t\tsearchUsed = true\n\t\t\tif (counts.readOperations >= budgets.readOperations) fail()\n\t\t\topenRange()\n\t\t\tcounts.readOperations++\n\t\t\t// SAFETY: registered immutable metadata admits the native search field and equality fields.\n\t\t\tconst source: QueryInitializer<any> = cap.reader.query(table)\n\t\t\tconst result = await source\n\t\t\t\t.withSearchIndex(index.name, (q) => {\n\t\t\t\t\tlet filter = q.search(index.searchField, text)\n\t\t\t\t\tfor (const { field, value } of equalities) filter = filter.eq(field, value)\n\t\t\t\t\treturn filter\n\t\t\t\t})\n\t\t\t\t.paginate(options)\n\t\t\tsearchCounts.rawCandidates += result.page.length\n\t\t\tfor (const document of result.page) searchCounts.documentBytes += getDocumentSize(document)\n\t\t\treturn result\n\t\t},\n\t\treserveLeaf,\n\t\tleafBudgetFailure: (error: ManagedReadError) => leafFailures.get(error),\n\t\topenRange,\n\t\texpand(depth: number, count = 1) {\n\t\t\tif (\n\t\t\t\t!Number.isSafeInteger(depth) ||\n\t\t\t\tdepth < 0 ||\n\t\t\t\tdepth > budgets.depth ||\n\t\t\t\t!Number.isSafeInteger(count) ||\n\t\t\t\tcount < 0 ||\n\t\t\t\tcounts.fanout + count > budgets.fanout\n\t\t\t)\n\t\t\t\tfail()\n\t\t\tcounts.fanout += count\n\t\t},\n\t\tleafQuery: (table: string) => {\n\t\t\tassertTable(table)\n\t\t\treturn query(table, cap.reader.query(table), [], false)\n\t\t},\n\t\tauthorize: (table: string, doc: GenericDocument) => authorize(table, doc),\n\t})\n}\n"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ //#region src/querying/shared/ast.d.ts
2
+ export type FilterScalar = string | number | bigint | boolean | null;
3
+ export type FilterOperator = 'eq' | 'in' | 'gt' | 'gte' | 'lt' | 'lte' | 'exists';
4
+ export type FilterAst = {
5
+ kind: 'and' | 'or';
6
+ children: FilterAst[];
7
+ } | {
8
+ kind: 'not';
9
+ child: FilterAst;
10
+ } | {
11
+ kind: 'variant';
12
+ discriminator: string;
13
+ tag: string;
14
+ child: FilterAst;
15
+ } | {
16
+ kind: 'scalar';
17
+ field: string;
18
+ operator: FilterOperator;
19
+ value: FilterScalar | FilterScalar[];
20
+ } | {
21
+ kind: 'relation';
22
+ name: string;
23
+ mode: 'one' | 'some' | 'none';
24
+ predicate: FilterAst | null;
25
+ };
26
+ export declare function valueEqual(left: FilterScalar, right: FilterScalar): boolean;
27
+ //#endregion
28
+ //# sourceMappingURL=ast.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{compareValues as e}from"convex/values";function t(t,n){return e(t,n)===0}export{t as valueEqual};
2
+ //# sourceMappingURL=ast.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.mjs","names":["valueEqual","compareValues","left","right"],"sources":["../../../src/querying/shared/ast.ts"],"sourcesContent":["import { compareValues } from 'convex/values'\nexport type FilterScalar = string | number | bigint | boolean | null\nexport type FilterOperator = 'eq' | 'in' | 'gt' | 'gte' | 'lt' | 'lte' | 'exists'\nexport type FilterAst =\n\t| { kind: 'and' | 'or'; children: FilterAst[] }\n\t| { kind: 'not'; child: FilterAst }\n\t| { kind: 'variant'; discriminator: string; tag: string; child: FilterAst }\n\t| {\n\t\t\tkind: 'scalar'\n\t\t\tfield: string\n\t\t\toperator: FilterOperator\n\t\t\tvalue: FilterScalar | FilterScalar[]\n\t }\n\t| { kind: 'relation'; name: string; mode: 'one' | 'some' | 'none'; predicate: FilterAst | null }\n\nexport function valueEqual(left: FilterScalar, right: FilterScalar): boolean {\n\treturn compareValues(left, right) === 0\n}\n"],"mappings":"8CAeA,SAAgBA,EAAW,EAAoB,EAA8B,CAC5E,OAAOC,EAAcC,EAAMC,CAAK,IAAM,CACvC"}