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
@@ -0,0 +1,104 @@
1
+ import { z } from "zod";
2
+ import { GenericId, GenericValidator, ValidatorJSON, Value } from "convex/values";
3
+ //#region src/querying/shared/contract.d.ts
4
+ export declare function sharedNativeValidator(schema: z.core.$ZodType): GenericValidator | undefined;
5
+ type RequiredSharedField<V extends GenericValidator> = V extends {
6
+ kind: 'string';
7
+ } ? z.ZodString : V extends {
8
+ kind: 'float64';
9
+ } ? z.ZodNumber : V extends {
10
+ kind: 'int64';
11
+ } ? z.ZodBigInt : V extends {
12
+ kind: 'boolean';
13
+ } ? z.ZodBoolean : V extends {
14
+ kind: 'null';
15
+ } ? z.ZodNull : V extends {
16
+ kind: 'literal';
17
+ value: infer L extends string | number | bigint | boolean;
18
+ } ? z.ZodLiteral<L> : V extends {
19
+ kind: 'id';
20
+ } ? z.ZodCustom<Extract<V['type'], GenericId<string>>, string> : V extends {
21
+ kind: 'union';
22
+ members: [];
23
+ } ? z.ZodUnion<[]> : V extends {
24
+ kind: 'union';
25
+ members: [infer A extends GenericValidator, ...infer R extends GenericValidator[]];
26
+ } ? z.ZodUnion<readonly [SharedField<A>, ...{ [K in keyof R]: SharedField<R[K]>; }]> : V extends {
27
+ kind: 'union';
28
+ members: (infer E extends GenericValidator)[];
29
+ } ? [GenericValidator] extends [E] ? z.ZodUnion<readonly z.core.SomeType[]> : z.ZodUnion<readonly SharedField<E>[]> : never;
30
+ export type SharedField<V extends GenericValidator> = V extends {
31
+ isOptional: 'optional';
32
+ } ? z.ZodOptional<RequiredSharedField<V>> : RequiredSharedField<V>;
33
+ type FieldSchemas<F extends Record<string, GenericValidator>> = { [K in keyof F]: SharedField<F[K]>; };
34
+ type FilterSide = 'input' | 'output';
35
+ type InputValue<V> = V extends GenericId<string> ? string : V;
36
+ type Scalar<V extends GenericValidator, S extends FilterSide> = S extends 'input' ? InputValue<Exclude<V['type'], undefined>> : Exclude<V['type'], undefined>;
37
+ type Ordered<V extends GenericValidator> = [GenericValidator] extends [V] ? false : V extends {
38
+ kind: 'string' | 'float64' | 'int64';
39
+ } ? true : V extends {
40
+ kind: 'literal';
41
+ } ? Exclude<V['type'], undefined> extends string | number | bigint ? true : false : V extends {
42
+ kind: 'union';
43
+ members: infer M extends GenericValidator[];
44
+ } ? false extends Ordered<M[number]> ? false : true : false;
45
+ type Predicate<V extends GenericValidator, S extends FilterSide> = Scalar<V, S> | ({
46
+ eq?: Scalar<V, S>;
47
+ in?: Scalar<V, S>[];
48
+ } & (Ordered<V> extends true ? {
49
+ gt?: Scalar<V, S>;
50
+ gte?: Scalar<V, S>;
51
+ lt?: Scalar<V, S>;
52
+ lte?: Scalar<V, S>;
53
+ } : {}) & (V['isOptional'] extends 'optional' ? {
54
+ exists?: boolean;
55
+ } : {}));
56
+ type Fields<F extends Record<string, GenericValidator>, S extends FilterSide> = { [K in keyof F]?: Predicate<F[K], S>; };
57
+ type Tail<D extends 1[]> = D extends [1, ...infer R extends 1[]] ? R : [];
58
+ export type SharedFilters<F extends Record<string, GenericValidator>, S extends FilterSide = 'output', D extends 1[] = [1, 1, 1, 1]> = Omit<Fields<F, S>, 'and' | 'or' | 'not' | 'fields'> & {
59
+ fields?: Fields<F, S>;
60
+ } & (D extends [] ? {} : {
61
+ and?: SharedFilters<F, S, Tail<D>>[];
62
+ or?: SharedFilters<F, S, Tail<D>>[];
63
+ not?: SharedFilters<F, S, Tail<D>>;
64
+ });
65
+ export interface FilterDescriptor {
66
+ field: string;
67
+ kind: 'string' | 'number' | 'bigint' | 'boolean' | 'null' | 'id' | 'enum' | 'union';
68
+ optional: boolean;
69
+ nullable: boolean;
70
+ values?: readonly (string | number | bigint | boolean)[];
71
+ idTables: readonly string[];
72
+ operators: readonly string[];
73
+ members?: readonly FilterDescriptor[];
74
+ }
75
+ export interface FilterContract<F extends Record<string, GenericValidator>> {
76
+ readonly fields: FieldSchemas<F>;
77
+ readonly native: Readonly<Record<string, {
78
+ json: ValidatorJSON;
79
+ optional: boolean;
80
+ }>>;
81
+ readonly schema: z.ZodType<SharedFilters<F>, SharedFilters<F, 'input'>>;
82
+ describe(): readonly FilterDescriptor[];
83
+ evaluate(filters: SharedFilters<F, 'input'>, document: Record<string, Value | undefined>, accessible?: ReadonlySet<string>): boolean | 'unknown';
84
+ readonly searchParam: {
85
+ encode(value: SharedFilters<F, 'input'>): {
86
+ success: true;
87
+ value: string;
88
+ } | {
89
+ success: false;
90
+ error: string;
91
+ };
92
+ decode(value: string): {
93
+ success: true;
94
+ value: SharedFilters<F>;
95
+ } | {
96
+ success: false;
97
+ error: string;
98
+ };
99
+ };
100
+ }
101
+ /** Scalar-only contracts explicitly reject objects, arrays, relations and variants. */
102
+ export declare function defineFilterContract<const F extends Record<string, GenericValidator>>(input: F): FilterContract<F>;
103
+ //#endregion
104
+ //# sourceMappingURL=contract.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{boundedFilterSchema as e,normalizeFilters as t,scalarPredicateFromSchema as n}from"./filters.mjs";import{evaluateFilter as r}from"./evaluate.mjs";import{z as i}from"zod";import{convexToJson as a,jsonToConvex as o,v as s}from"convex/values";const c=/* @__PURE__ */ new WeakMap,l=/* @__PURE__ */ new WeakMap;function u(e){let t=c.get(e)??(e instanceof i.core.$ZodCustom?l.get(e._zod.def.fn):void 0);return t?v(t):void 0}function d(i){let s={},c={},l={},u=[];for(let[e,t]of Object.entries(i)){if([`__proto__`,`constructor`,`prototype`].includes(e))throw Error(`Unsupported filter field`);let r=f(t);s[e]=t.isOptional===`optional`?r.optional():r;let i=[`eq`,`in`];p(t)&&i.push(`gt`,`gte`,`lt`,`lte`),t.isOptional===`optional`&&i.push(`exists`),c[e]=n(r,p(t),t.isOptional===`optional`).optional(),l[e]={json:_(t),optional:t.isOptional===`optional`},u.push(m(e,t,i))}let d=e(c);return Object.freeze({fields:Object.freeze(s),native:y(l),schema:d,describe:()=>structuredClone(u),evaluate:(e,n,i)=>r(t(d.parse(e)),n,i),searchParam:Object.freeze({encode:e=>{try{if(!b(e))throw Error(`URL size exceeded`);let t=d.parse(e),n=JSON.stringify({v:1,filters:h(a(t))});if(n.length>32768)throw Error(`URL size exceeded`);return{success:!0,value:n}}catch{return{success:!1,error:`Invalid filters`}}},decode:e=>{try{if(e.length>32768)throw Error(`URL size exceeded`);let t=JSON.parse(e);if(!t||t.v!==1||Object.keys(t).sort().join(`,`)!==`filters,v`)throw Error(`Unsupported URL version`);return g(t.filters),{success:!0,value:d.parse(o(t.filters))}}catch{return{success:!1,error:`Invalid filter URL`}}}})})}function f(e){let t;switch(e.kind){case`string`:t=i.string();break;case`float64`:t=i.number();break;case`int64`:t=i.bigint().min(-(1n<<63n)).max((1n<<63n)-1n);break;case`boolean`:t=i.boolean();break;case`null`:t=i.null();break;case`literal`:t=i.literal(e.value);break;case`id`:t=i.custom(e=>i.string().safeParse(e).success);break;case`union`:t=i.union(e.members.map(f));break;default:throw Error(`Unsupported shared scalar kind "${e.kind}"; relations and variants require a server contract`)}let n=v(e,!1);return c.set(t,n),e.kind===`id`&&t instanceof i.core.$ZodCustom&&l.set(t._zod.def.fn,n),t}function p(e){return[`string`,`float64`,`int64`].includes(e.kind)||e.kind===`literal`&&i.union([i.string(),i.number(),i.bigint()]).safeParse(e.value).success||e.kind===`union`&&e.members.every(p)}function m(e,t,n){let r=t.kind===`union`?t.members.map(t=>m(e,t,n)):void 0,i=r?.every(e=>e.kind===`enum`);return{field:e,kind:t.kind===`float64`?`number`:t.kind===`int64`?`bigint`:t.kind===`literal`||i?`enum`:t.kind,optional:t.isOptional===`optional`,nullable:t.kind===`null`||!!r?.some(e=>e.nullable),values:t.kind===`literal`?[t.value]:i?r.flatMap(e=>e.values??[]):void 0,idTables:t.kind===`id`?[t.tableName]:r?.flatMap(e=>e.idTables)??[],operators:n,members:r}}function h(e){if(Array.isArray(e))return e.map(h);if(e&&typeof e==`object`){let t=e;return Object.fromEntries(Object.keys(t).sort().map(e=>[e,h(t[e])]))}return e}function g(e,t=0,n={nodes:0}){if(t>16||++n.nodes>2048)throw Error(`URL budget exceeded`);if(e&&typeof e==`object`)for(let r of Object.values(e))g(r,t+1,n)}function _(e){return e.json}function v(e,t=!0){let n;switch(e.kind){case`id`:n=s.id(e.tableName);break;case`string`:n=s.string();break;case`float64`:n=s.float64();break;case`int64`:n=s.int64();break;case`null`:n=s.null();break;case`boolean`:n=s.boolean();break;case`literal`:n=s.literal(e.value);break;case`union`:n=s.union(...e.members.map(e=>v(e)));break;default:throw Error(`Unsupported shared scalar`)}return t&&e.isOptional===`optional`?s.optional(n):n}function y(e){if(e&&typeof e==`object`){for(let t of Object.values(e))y(t);Object.freeze(e)}return e}function b(e){let t=[e],n=0,r=0;for(;t.length;){let e=t.pop();if(++r>512||typeof e==`string`&&(n+=e.length,n>32768))return!1;if(Object(e)!==e)continue;let i=e,a=Reflect.ownKeys(i);if(a.length+r+t.length>512)return!1;for(let e of a){if(Array.isArray(i)&&e===`length`)continue;let r=Object.getOwnPropertyDescriptor(i,e);if(!r||!(`value`in r)||(n+=String(e).length,n>32768))return!1;t.push(r.value)}}return!0}export{d as defineFilterContract,u as sharedNativeValidator};
2
+ //# sourceMappingURL=contract.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.mjs","names":["nativeSchemas","nativeIdPredicates","sharedNativeValidator","validator","schema","z","cloneNative","defineFilterContract","fields","predicates","native","descriptors","field","input","scalar","scalarSchema","operators","ordered","scalarPredicateFromSchema","nativeJson","describe","boundedFilterSchema","freezeMetadata","evaluateFilter","normalizeFilters","filters","document","accessible","withinUrlSize","value","parsed","encoded","canonical","convexToJson","envelope","guardJson","jsonToConvex","result","children","v","literals","c","object","k","depth","state","child","member","optional","pending","size","nodes","current","keys","key","descriptor"],"sources":["../../../src/querying/shared/contract.ts"],"sourcesContent":["import { z } from 'zod'\nimport {\n\tconvexToJson,\n\tjsonToConvex,\n\tv,\n\ttype GenericId,\n\ttype JSONValue,\n\ttype ValidatorJSON,\n\ttype GenericValidator,\n\ttype Value,\n} from 'convex/values'\nimport {\n\tboundedFilterSchema,\n\tnormalizeFilters,\n\tscalarPredicateFromSchema,\n\ttype FilterTree,\n} from './filters'\nimport { evaluateFilter } from './evaluate'\n\n// Metadata only: no parser callbacks or server state cross this boundary.\nconst nativeSchemas = new WeakMap<z.core.$ZodType, GenericValidator>()\n// Zod preserves a custom predicate through clone/describe/meta/refine. Associate\n// ID metadata with that private predicate too, so those derivations stay native IDs.\nconst nativeIdPredicates = new WeakMap<z.core.$ZodCustom['_zod']['def']['fn'], GenericValidator>()\nexport function sharedNativeValidator(schema: z.core.$ZodType): GenericValidator | undefined {\n\tconst validator =\n\t\tnativeSchemas.get(schema) ??\n\t\t(schema instanceof z.core.$ZodCustom ? nativeIdPredicates.get(schema._zod.def.fn) : undefined)\n\treturn validator ? cloneNative(validator) : undefined\n}\ntype RequiredSharedField<V extends GenericValidator> = V extends { kind: 'string' }\n\t? z.ZodString\n\t: V extends { kind: 'float64' }\n\t\t? z.ZodNumber\n\t\t: V extends { kind: 'int64' }\n\t\t\t? z.ZodBigInt\n\t\t\t: V extends { kind: 'boolean' }\n\t\t\t\t? z.ZodBoolean\n\t\t\t\t: V extends { kind: 'null' }\n\t\t\t\t\t? z.ZodNull\n\t\t\t\t\t: V extends { kind: 'literal'; value: infer L extends string | number | bigint | boolean }\n\t\t\t\t\t\t? z.ZodLiteral<L>\n\t\t\t\t\t\t: V extends { kind: 'id' }\n\t\t\t\t\t\t\t? z.ZodCustom<Extract<V['type'], GenericId<string>>, string>\n\t\t\t\t\t\t\t: V extends { kind: 'union'; members: [] }\n\t\t\t\t\t\t\t\t? z.ZodUnion<[]>\n\t\t\t\t\t\t\t\t: V extends {\n\t\t\t\t\t\t\t\t\t\t\tkind: 'union'\n\t\t\t\t\t\t\t\t\t\t\tmembers: [\n\t\t\t\t\t\t\t\t\t\t\t\tinfer A extends GenericValidator,\n\t\t\t\t\t\t\t\t\t\t\t\t...infer R extends GenericValidator[],\n\t\t\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t\t\t? z.ZodUnion<readonly [SharedField<A>, ...{ [K in keyof R]: SharedField<R[K]> }]>\n\t\t\t\t\t\t\t\t\t: V extends { kind: 'union'; members: (infer E extends GenericValidator)[] }\n\t\t\t\t\t\t\t\t\t\t? [GenericValidator] extends [E]\n\t\t\t\t\t\t\t\t\t\t\t? z.ZodUnion<readonly z.core.SomeType[]>\n\t\t\t\t\t\t\t\t\t\t\t: z.ZodUnion<readonly SharedField<E>[]>\n\t\t\t\t\t\t\t\t\t\t: never\nexport type SharedField<V extends GenericValidator> = V extends { isOptional: 'optional' }\n\t? z.ZodOptional<RequiredSharedField<V>>\n\t: RequiredSharedField<V>\ntype FieldSchemas<F extends Record<string, GenericValidator>> = {\n\t[K in keyof F]: SharedField<F[K]>\n}\ntype FilterSide = 'input' | 'output'\ntype InputValue<V> = V extends GenericId<string> ? string : V\ntype Scalar<V extends GenericValidator, S extends FilterSide> = S extends 'input'\n\t? InputValue<Exclude<V['type'], undefined>>\n\t: Exclude<V['type'], undefined>\ntype Ordered<V extends GenericValidator> = [GenericValidator] extends [V]\n\t? false\n\t: V extends { kind: 'string' | 'float64' | 'int64' }\n\t\t? true\n\t\t: V extends { kind: 'literal' }\n\t\t\t? Exclude<V['type'], undefined> extends string | number | bigint\n\t\t\t\t? true\n\t\t\t\t: false\n\t\t\t: V extends { kind: 'union'; members: infer M extends GenericValidator[] }\n\t\t\t\t? false extends Ordered<M[number]>\n\t\t\t\t\t? false\n\t\t\t\t\t: true\n\t\t\t\t: false\ntype Predicate<V extends GenericValidator, S extends FilterSide> =\n\t| Scalar<V, S>\n\t| ({ eq?: Scalar<V, S>; in?: Scalar<V, S>[] } & (Ordered<V> extends true\n\t\t\t? { gt?: Scalar<V, S>; gte?: Scalar<V, S>; lt?: Scalar<V, S>; lte?: Scalar<V, S> }\n\t\t\t: {}) &\n\t\t\t(V['isOptional'] extends 'optional' ? { exists?: boolean } : {}))\ntype Fields<F extends Record<string, GenericValidator>, S extends FilterSide> = {\n\t[K in keyof F]?: Predicate<F[K], S>\n}\ntype Tail<D extends 1[]> = D extends [1, ...infer R extends 1[]] ? R : []\nexport type SharedFilters<\n\tF extends Record<string, GenericValidator>,\n\tS extends FilterSide = 'output',\n\tD extends 1[] = [1, 1, 1, 1],\n> = Omit<Fields<F, S>, 'and' | 'or' | 'not' | 'fields'> & { fields?: Fields<F, S> } & (D extends []\n\t\t? {}\n\t\t: {\n\t\t\t\tand?: SharedFilters<F, S, Tail<D>>[]\n\t\t\t\tor?: SharedFilters<F, S, Tail<D>>[]\n\t\t\t\tnot?: SharedFilters<F, S, Tail<D>>\n\t\t\t})\nexport interface FilterDescriptor {\n\tfield: string\n\tkind: 'string' | 'number' | 'bigint' | 'boolean' | 'null' | 'id' | 'enum' | 'union'\n\toptional: boolean\n\tnullable: boolean\n\tvalues?: readonly (string | number | bigint | boolean)[]\n\tidTables: readonly string[]\n\toperators: readonly string[]\n\tmembers?: readonly FilterDescriptor[]\n}\nexport interface FilterContract<F extends Record<string, GenericValidator>> {\n\treadonly fields: FieldSchemas<F>\n\treadonly native: Readonly<Record<string, { json: ValidatorJSON; optional: boolean }>>\n\treadonly schema: z.ZodType<SharedFilters<F>, SharedFilters<F, 'input'>>\n\tdescribe(): readonly FilterDescriptor[]\n\tevaluate(\n\t\tfilters: SharedFilters<F, 'input'>,\n\t\tdocument: Record<string, Value | undefined>,\n\t\taccessible?: ReadonlySet<string>,\n\t): boolean | 'unknown'\n\treadonly searchParam: {\n\t\tencode(\n\t\t\tvalue: SharedFilters<F, 'input'>,\n\t\t): { success: true; value: string } | { success: false; error: string }\n\t\tdecode(\n\t\t\tvalue: string,\n\t\t): { success: true; value: SharedFilters<F> } | { success: false; error: string }\n\t}\n}\n\n/** Scalar-only contracts explicitly reject objects, arrays, relations and variants. */\nexport function defineFilterContract<const F extends Record<string, GenericValidator>>(\n\tinput: F,\n): FilterContract<F> {\n\ttype Schemas = Record<string, z.ZodType>\n\tconst fields: Schemas = {},\n\t\tpredicates: Record<string, z.ZodType> = {}\n\tconst native: Record<string, { json: ValidatorJSON; optional: boolean }> = {}\n\tconst descriptors: FilterDescriptor[] = []\n\tfor (const [field, validator] of Object.entries(input)) {\n\t\tif (['__proto__', 'constructor', 'prototype'].includes(field))\n\t\t\tthrow new Error('Unsupported filter field')\n\t\tconst scalar = scalarSchema(validator)\n\t\tfields[field] = validator.isOptional === 'optional' ? scalar.optional() : scalar\n\t\tconst operators = ['eq', 'in']\n\t\tif (ordered(validator)) operators.push('gt', 'gte', 'lt', 'lte')\n\t\tif (validator.isOptional === 'optional') operators.push('exists')\n\t\tpredicates[field] = scalarPredicateFromSchema(\n\t\t\tscalar,\n\t\t\tordered(validator),\n\t\t\tvalidator.isOptional === 'optional',\n\t\t).optional()\n\t\tnative[field] = { json: nativeJson(validator), optional: validator.isOptional === 'optional' }\n\t\tdescriptors.push(describe(field, validator, operators))\n\t}\n\t// SAFETY: every selected native scalar generates precisely the mapped predicate grammar.\n\tconst schema = boundedFilterSchema(predicates) as z.ZodType<\n\t\tSharedFilters<F>,\n\t\tSharedFilters<F, 'input'>\n\t>\n\tconst encode = (value: SharedFilters<F, 'input'>) => {\n\t\t// SAFETY: bounded scalar schema outputs contain only Convex scalar values and containers.\n\t\ttry {\n\t\t\t// SAFETY: the input boundary inspects descriptors before parsing or serializing.\n\t\t\tif (!withinUrlSize(value as FilterTree)) throw new Error('URL size exceeded')\n\t\t\tconst parsed = schema.parse(value)\n\t\t\t// SAFETY: bounded schema output contains only Convex values.\n\t\t\tconst encoded = JSON.stringify({ v: 1, filters: canonical(convexToJson(parsed as Value)) })\n\t\t\tif (encoded.length > 32768) throw new Error('URL size exceeded')\n\t\t\treturn { success: true as const, value: encoded }\n\t\t} catch {\n\t\t\treturn { success: false as const, error: 'Invalid filters' }\n\t\t}\n\t}\n\tconst decode = (value: string) => {\n\t\ttry {\n\t\t\tif (value.length > 32768) throw new Error('URL size exceeded')\n\t\t\tconst envelope = JSON.parse(value)\n\t\t\tif (!envelope || envelope.v !== 1 || Object.keys(envelope).sort().join(',') !== 'filters,v')\n\t\t\t\tthrow new Error('Unsupported URL version')\n\t\t\tguardJson(envelope.filters)\n\t\t\tconst parsed = schema.parse(jsonToConvex(envelope.filters))\n\t\t\treturn { success: true as const, value: parsed }\n\t\t} catch {\n\t\t\treturn { success: false as const, error: 'Invalid filter URL' }\n\t\t}\n\t}\n\treturn Object.freeze({\n\t\t// SAFETY: fields were generated from their corresponding native validator types.\n\t\tfields: Object.freeze(fields) as FieldSchemas<F>,\n\t\tnative: freezeMetadata(native),\n\t\tschema,\n\t\tdescribe: () => structuredClone(descriptors),\n\t\t// SAFETY: the bounded scalar schema validates the tree before normalization.\n\t\tevaluate: (\n\t\t\tfilters: SharedFilters<F, 'input'>,\n\t\t\tdocument: Record<string, Value | undefined>,\n\t\t\taccessible?: ReadonlySet<string>,\n\t\t) =>\n\t\t\tevaluateFilter(normalizeFilters(schema.parse(filters) as FilterTree), document, accessible),\n\t\tsearchParam: Object.freeze({ encode, decode }),\n\t})\n}\nfunction scalarSchema(validator: GenericValidator): z.ZodType {\n\tlet result: z.ZodType\n\tswitch (validator.kind) {\n\t\tcase 'string':\n\t\t\tresult = z.string()\n\t\t\tbreak\n\t\tcase 'float64':\n\t\t\tresult = z.number()\n\t\t\tbreak\n\t\tcase 'int64':\n\t\t\tresult = z\n\t\t\t\t.bigint()\n\t\t\t\t.min(-(1n << 63n))\n\t\t\t\t.max((1n << 63n) - 1n)\n\t\t\tbreak\n\t\tcase 'boolean':\n\t\t\tresult = z.boolean()\n\t\t\tbreak\n\t\tcase 'null':\n\t\t\tresult = z.null()\n\t\t\tbreak\n\t\tcase 'literal':\n\t\t\tresult = z.literal(validator.value)\n\t\t\tbreak\n\t\tcase 'id':\n\t\t\tresult = z.custom<string>((value) => z.string().safeParse(value).success)\n\t\t\tbreak\n\t\tcase 'union':\n\t\t\tresult = z.union(validator.members.map(scalarSchema))\n\t\t\tbreak\n\t\tdefault:\n\t\t\tthrow new Error(\n\t\t\t\t`Unsupported shared scalar kind \"${validator.kind}\"; relations and variants require a server contract`,\n\t\t\t)\n\t}\n\t// Capture immutable scalar metadata. Binding and conversion never consult mutable callers.\n\tconst native = cloneNative(validator, false)\n\tnativeSchemas.set(result, native)\n\tif (validator.kind === 'id' && result instanceof z.core.$ZodCustom)\n\t\tnativeIdPredicates.set(result._zod.def.fn, native)\n\treturn result\n}\nfunction ordered(validator: GenericValidator): boolean {\n\treturn (\n\t\t['string', 'float64', 'int64'].includes(validator.kind) ||\n\t\t(validator.kind === 'literal' &&\n\t\t\tz.union([z.string(), z.number(), z.bigint()]).safeParse(validator.value).success) ||\n\t\t(validator.kind === 'union' && validator.members.every(ordered))\n\t)\n}\nfunction describe(\n\tfield: string,\n\tvalidator: GenericValidator,\n\toperators: string[],\n): FilterDescriptor {\n\tconst children =\n\t\tvalidator.kind === 'union'\n\t\t\t? validator.members.map((v) => describe(field, v, operators))\n\t\t\t: undefined\n\tconst literals = children?.every((c) => c.kind === 'enum')\n\tconst kind =\n\t\tvalidator.kind === 'float64'\n\t\t\t? 'number'\n\t\t\t: validator.kind === 'int64'\n\t\t\t\t? 'bigint'\n\t\t\t\t: validator.kind === 'literal'\n\t\t\t\t\t? 'enum'\n\t\t\t\t\t: literals\n\t\t\t\t\t\t? 'enum'\n\t\t\t\t\t\t: validator.kind\n\t// SAFETY: unsupported native kinds were rejected while generating scalar schemas.\n\treturn {\n\t\tfield,\n\t\tkind: kind as FilterDescriptor['kind'],\n\t\toptional: validator.isOptional === 'optional',\n\t\tnullable: validator.kind === 'null' || !!children?.some((c) => c.nullable),\n\t\tvalues:\n\t\t\tvalidator.kind === 'literal'\n\t\t\t\t? [validator.value]\n\t\t\t\t: literals\n\t\t\t\t\t? children!.flatMap((c) => c.values ?? [])\n\t\t\t\t\t: undefined,\n\t\tidTables:\n\t\t\tvalidator.kind === 'id'\n\t\t\t\t? [validator.tableName]\n\t\t\t\t: (children?.flatMap((c) => c.idTables) ?? []),\n\t\toperators,\n\t\tmembers: children,\n\t}\n}\n// oxlint-disable-next-line anti-slop/no-runtime-typeof -- Serialized Convex JSON contains only validated JSON containers and scalars.\nfunction canonical(value: JSONValue): JSONValue {\n\tif (Array.isArray(value)) return value.map(canonical)\n\t// SAFETY: arrays were handled; the remaining JSON object supports string-key lookup.\n\t// oxlint-disable-next-line anti-slop/no-runtime-typeof -- Traverse JSON containers before canonical encoding.\n\tif (value && typeof value === 'object') {\n\t\t// SAFETY: arrays were handled, leaving a JSON object with string keys.\n\t\tconst object = value as Record<string, JSONValue>\n\t\treturn Object.fromEntries(\n\t\t\tObject.keys(object)\n\t\t\t\t.sort()\n\t\t\t\t.map((k) => [k, canonical(object[k])]),\n\t\t)\n\t}\n\treturn value\n}\n// oxlint-disable-next-line anti-slop/no-runtime-typeof -- Bound untrusted JSON before Convex decoding or recursive schema validation.\nfunction guardJson(value: JSONValue, depth = 0, state = { nodes: 0 }): void {\n\tif (depth > 16 || ++state.nodes > 2048) throw new Error('URL budget exceeded')\n\t// oxlint-disable-next-line anti-slop/no-runtime-typeof -- Traverse only JSON containers or owned metadata; no domain narrowing occurs.\n\tif (value && typeof value === 'object')\n\t\tfor (const child of Object.values(value)) guardJson(child, depth + 1, state)\n}\n\nfunction nativeJson(validator: GenericValidator): ValidatorJSON {\n\t// SAFETY: native scalar validators expose json at runtime, stripped from declarations.\n\treturn (validator as GenericValidator & { json: ValidatorJSON }).json\n}\nfunction cloneNative(validator: GenericValidator, optional = true): GenericValidator {\n\tlet result: GenericValidator\n\tswitch (validator.kind) {\n\t\tcase 'id':\n\t\t\tresult = v.id(validator.tableName)\n\t\t\tbreak\n\t\tcase 'string':\n\t\t\tresult = v.string()\n\t\t\tbreak\n\t\tcase 'float64':\n\t\t\tresult = v.float64()\n\t\t\tbreak\n\t\tcase 'int64':\n\t\t\tresult = v.int64()\n\t\t\tbreak\n\t\tcase 'null':\n\t\t\tresult = v.null()\n\t\t\tbreak\n\t\tcase 'boolean':\n\t\t\tresult = v.boolean()\n\t\t\tbreak\n\t\tcase 'literal':\n\t\t\tresult = v.literal(validator.value)\n\t\t\tbreak\n\t\tcase 'union':\n\t\t\tresult = v.union(...validator.members.map((member) => cloneNative(member)))\n\t\t\tbreak\n\t\tdefault:\n\t\t\tthrow new Error('Unsupported shared scalar')\n\t}\n\treturn optional && validator.isOptional === 'optional' ? v.optional(result) : result\n}\n\nfunction freezeMetadata<T>(value: T): T {\n\t// oxlint-disable-next-line anti-slop/no-runtime-typeof -- Traverse only JSON containers or owned metadata; no domain narrowing occurs.\n\tif (value && typeof value === 'object') {\n\t\tfor (const child of Object.values(value)) freezeMetadata(child)\n\t\tObject.freeze(value)\n\t}\n\treturn value\n}\n\nfunction withinUrlSize(value: FilterTree): boolean {\n\tconst pending = [value]\n\tlet size = 0,\n\t\tnodes = 0\n\twhile (pending.length) {\n\t\tconst current = pending.pop()\n\t\tif (++nodes > 512) return false\n\t\t// oxlint-disable-next-line anti-slop/no-runtime-typeof -- Count raw scalar text before any serialization allocation.\n\t\tif (typeof current === 'string') {\n\t\t\tsize += current.length\n\t\t\tif (size > 32768) return false\n\t\t}\n\t\tif (Object(current) !== current) continue\n\t\t// SAFETY: boxing excluded null and primitives; inspect data descriptors without invoking getters.\n\t\tconst object = current as object\n\t\tconst keys = Reflect.ownKeys(object)\n\t\tif (keys.length + nodes + pending.length > 512) return false\n\t\tfor (const key of keys) {\n\t\t\tif (Array.isArray(object) && key === 'length') continue\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, key)\n\t\t\tif (!descriptor || !('value' in descriptor)) return false\n\t\t\tsize += String(key).length\n\t\t\tif (size > 32768) return false\n\t\t\tpending.push(descriptor.value)\n\t\t}\n\t}\n\treturn true\n}\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { FilterAst } from "./ast.mjs";
2
+ import { Value } from "convex/values";
3
+ //#region src/querying/shared/evaluate.d.ts
4
+ /** Native scalar ordering/equality, including missing vs null, without coercion. */
5
+ export declare function evaluateFilter(ast: FilterAst, document: Record<string, Value | undefined>, accessible?: ReadonlySet<string>): boolean | 'unknown';
6
+ //#endregion
7
+ //# sourceMappingURL=evaluate.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{compareValues as e}from"convex/values";function t(n,r,i){switch(n.kind){case`and`:{let e=!1;for(let a of n.children){let n=t(a,r,i);if(n===!1)return!1;n===`unknown`&&(e=!0)}return!e||`unknown`}case`or`:{let e=!1;for(let a of n.children){let n=t(a,r,i);if(n===!0)return!0;n===`unknown`&&(e=!0)}return e?`unknown`:!1}case`variant`:return t({kind:`and`,children:[{kind:`scalar`,field:n.discriminator,operator:`eq`,value:n.tag},n.child]},r,i);case`not`:{let e=t(n.child,r,i);return e===`unknown`?e:!e}case`relation`:if(!i)throw Error(`Relation execution requires U6`);return`unknown`;case`scalar`:{if(i&&!i.has(n.field))return`unknown`;let t=r[n.field];if(n.operator===`exists`)return t!==void 0===n.value;if(n.operator===`in`)return Array.isArray(n.value)&&n.value.some(n=>e(t,n)===0);if(Array.isArray(n.value))throw Error(`Invalid scalar predicate`);let a=e(t,n.value);switch(n.operator){case`eq`:return a===0;case`gt`:return a>0;case`gte`:return a>=0;case`lt`:return a<0;case`lte`:return a<=0}}}}export{t as evaluateFilter};
2
+ //# sourceMappingURL=evaluate.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.mjs","names":["evaluateFilter","ast","unknown","child","value","document","accessible","actual","compareValues","compared"],"sources":["../../../src/querying/shared/evaluate.ts"],"sourcesContent":["import { compareValues, type Value } from 'convex/values'\nimport type { FilterAst } from './ast'\n/** Native scalar ordering/equality, including missing vs null, without coercion. */\nexport function evaluateFilter(\n\tast: FilterAst,\n\tdocument: Record<string, Value | undefined>,\n\taccessible?: ReadonlySet<string>,\n): boolean | 'unknown' {\n\tswitch (ast.kind) {\n\t\tcase 'and': {\n\t\t\tlet unknown = false\n\t\t\tfor (const child of ast.children) {\n\t\t\t\tconst value = evaluateFilter(child, document, accessible)\n\t\t\t\tif (value === false) return false\n\t\t\t\tif (value === 'unknown') unknown = true\n\t\t\t}\n\t\t\treturn unknown ? 'unknown' : true\n\t\t}\n\t\tcase 'or': {\n\t\t\tlet unknown = false\n\t\t\tfor (const child of ast.children) {\n\t\t\t\tconst value = evaluateFilter(child, document, accessible)\n\t\t\t\tif (value === true) return true\n\t\t\t\tif (value === 'unknown') unknown = true\n\t\t\t}\n\t\t\treturn unknown ? 'unknown' : false\n\t\t}\n\t\tcase 'variant':\n\t\t\treturn evaluateFilter(\n\t\t\t\t{\n\t\t\t\t\tkind: 'and',\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{ kind: 'scalar', field: ast.discriminator, operator: 'eq', value: ast.tag },\n\t\t\t\t\t\tast.child,\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tdocument,\n\t\t\t\taccessible,\n\t\t\t)\n\t\tcase 'not': {\n\t\t\tconst value = evaluateFilter(ast.child, document, accessible)\n\t\t\treturn value === 'unknown' ? value : !value\n\t\t}\n\t\tcase 'relation':\n\t\t\tif (!accessible) throw new Error('Relation execution requires U6')\n\t\t\treturn 'unknown'\n\t\tcase 'scalar': {\n\t\t\tif (accessible && !accessible.has(ast.field)) return 'unknown'\n\t\t\tconst actual = document[ast.field]\n\t\t\tif (ast.operator === 'exists') return (actual !== undefined) === ast.value\n\t\t\tif (ast.operator === 'in')\n\t\t\t\treturn (\n\t\t\t\t\tArray.isArray(ast.value) && ast.value.some((value) => compareValues(actual, value) === 0)\n\t\t\t\t)\n\t\t\tif (Array.isArray(ast.value)) throw new Error('Invalid scalar predicate')\n\t\t\tconst compared = compareValues(actual, ast.value)\n\t\t\tswitch (ast.operator) {\n\t\t\t\tcase 'eq':\n\t\t\t\t\treturn compared === 0\n\t\t\t\tcase 'gt':\n\t\t\t\t\treturn compared > 0\n\t\t\t\tcase 'gte':\n\t\t\t\t\treturn compared >= 0\n\t\t\t\tcase 'lt':\n\t\t\t\t\treturn compared < 0\n\t\t\t\tcase 'lte':\n\t\t\t\t\treturn compared <= 0\n\t\t\t}\n\t\t}\n\t}\n}\n"],"mappings":"8CAGA,SAAgBA,EACf,EACA,EACA,EACsB,CACtB,OAAQC,EAAI,KAAZ,CACC,IAAK,MAAO,CACX,IAAIC,EAAU,GACd,IAAK,IAAMC,KAASF,EAAI,SAAU,CACjC,IAAMG,EAAQJ,EAAeG,EAAOE,EAAUC,CAAU,EACxD,GAAIF,IAAU,GAAO,MAAO,GACxBA,IAAU,YAAW,EAAU,GACpC,CACA,MAAO,IAAU,SAClB,CACA,IAAK,KAAM,CACV,IAAIF,EAAU,GACd,IAAK,IAAMC,KAASF,EAAI,SAAU,CACjC,IAAMG,EAAQJ,EAAeG,EAAOE,EAAUC,CAAU,EACxD,GAAIF,IAAU,GAAM,MAAO,GACvBA,IAAU,YAAW,EAAU,GACpC,CACA,OAAOF,EAAU,UAAY,EAC9B,CACA,IAAK,UACJ,OAAOF,EACN,CACC,KAAM,MACN,SAAU,CACT,CAAE,KAAM,SAAU,MAAOC,EAAI,cAAe,SAAU,KAAM,MAAOA,EAAI,GAAI,EAC3EA,EAAI,KACL,CACD,EACAI,EACAC,CACD,EACD,IAAK,MAAO,CACX,IAAMF,EAAQJ,EAAeC,EAAI,MAAOI,EAAUC,CAAU,EAC5D,OAAOF,IAAU,UAAYA,EAAQ,CAACA,CACvC,CACA,IAAK,WACJ,GAAI,CAACE,EAAY,MAAU,MAAM,gCAAgC,EACjE,MAAO,UACR,IAAK,SAAU,CACd,GAAIA,GAAc,CAACA,EAAW,IAAIL,EAAI,KAAK,EAAG,MAAO,UACrD,IAAMM,EAASF,EAASJ,EAAI,OAC5B,GAAIA,EAAI,WAAa,SAAU,OAAQM,IAAW,IAAA,KAAeN,EAAI,MACrE,GAAIA,EAAI,WAAa,KACpB,OACC,MAAM,QAAQA,EAAI,KAAK,GAAKA,EAAI,MAAM,KAAM,GAAUO,EAAcD,EAAQH,CAAK,IAAM,CAAC,EAE1F,GAAI,MAAM,QAAQH,EAAI,KAAK,EAAG,MAAU,MAAM,0BAA0B,EACxE,IAAMQ,EAAWD,EAAcD,EAAQN,EAAI,KAAK,EAChD,OAAQA,EAAI,SAAZ,CACC,IAAK,KACJ,OAAOQ,IAAa,EACrB,IAAK,KACJ,OAAOA,EAAW,EACnB,IAAK,MACJ,OAAOA,GAAY,EACpB,IAAK,KACJ,OAAOA,EAAW,EACnB,IAAK,MACJ,OAAOA,GAAY,CACrB,CACD,CACD,CACD"}
@@ -0,0 +1,31 @@
1
+ import { FilterAst } from "./ast.mjs";
2
+ import { z } from "zod";
3
+ //#region src/querying/shared/filters.d.ts
4
+ export declare const MAX_FILTER_DEPTH = 4;
5
+ export declare const MAX_FILTER_NODES = 256;
6
+ export declare const MAX_FILTER_IN_VALUES = 100;
7
+ export type FieldSchemas = Record<string, z.ZodType>;
8
+ export type FilterTree = string | number | bigint | boolean | null | undefined | FilterTree[] | {
9
+ [key: string]: FilterTree;
10
+ };
11
+ /** Each boolean child and relation target expression consumes one of four edges.
12
+ * some/none wrappers and fields namespaces consume nodes, but no extra depth.
13
+ */
14
+ export interface FilterGrammar {
15
+ fields: FieldSchemas;
16
+ variants?: {
17
+ discriminator: string;
18
+ options: Record<string, FilterGrammar>;
19
+ };
20
+ relations: Record<string, {
21
+ cardinality: 'one' | 'many';
22
+ target: FilterGrammar;
23
+ }>;
24
+ }
25
+ export declare function relationFilterSchema(grammar: FilterGrammar, cache?: WeakMap<FilterGrammar, Map<number, z.ZodObject<z.core.$ZodLooseShape, z.core.$strip>>>): z.ZodType;
26
+ export declare function paginationGrammar(schema: z.ZodType): FilterGrammar | undefined;
27
+ export declare function normalizeFilters(value: FilterTree, grammar?: FilterGrammar): FilterAst;
28
+ export declare function scalarPredicateFromSchema(scalar: z.ZodType, range: boolean, optional: boolean): z.ZodType;
29
+ export declare function boundedFilterSchema(predicates: FieldSchemas): z.ZodType;
30
+ //#endregion
31
+ //# sourceMappingURL=filters.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{z as e}from"zod";const t=4,n=256,r=100,i=/* @__PURE__ */ new WeakMap,a=/* @__PURE__ */ new WeakMap,o=/* @__PURE__ */ new WeakMap,s=e.core.$constructor(`BoundedFilterObject`,(t,n)=>{e.ZodObject.init(t,n);let r=t._zod.parse,o=n.shape.fields,s=o instanceof e.ZodOptional?o.unwrap():void 0,c=s instanceof e.ZodObject?Object.keys(s.shape):Object.keys(n.shape),l={variants:a.get(n.shape.variant),fields:Object.fromEntries(c.map(e=>[e,n.shape[e]])),relations:Object.fromEntries(Object.entries(n.shape).flatMap(([e,t])=>{let n=i.get(t);return n?[[e,n]]:[]}))};t._zod.parse=(e,t)=>m(e.value,l)?r(e,t):(e.issues.push({code:`custom`,input:e.value,message:`Unsupported filter layout or depth/node budget exceeded`}),e)});function c(e,t=/* @__PURE__ */ new WeakMap){let n=new s(p(e,0,t)._zod.def);return o.set(n,e),n}function l(t){if(!(t instanceof e.ZodObject))return;let n=t.shape.filters;if(!(n instanceof e.ZodOptional))return;let r=n.unwrap(),s=o.get(r);if(s)return s;if(r instanceof e.ZodObject)return{fields:r.shape,variants:a.get(r.shape.variant),relations:Object.fromEntries(Object.entries(r.shape).flatMap(([e,t])=>{let n=i.get(t);return n?[[e,n]]:[]}))}}function u(e,t){let n=[];if(!e)return{kind:`and`,children:n};let r=e;for(let[e,i]of Object.entries(r))if(i!==void 0){if(e===`and`||e===`or`)n.push({kind:e,children:i.map(e=>u(e,t))});else if(e===`variant`&&t?.variants){let e=i;n.push({kind:`variant`,discriminator:t.variants.discriminator,tag:e.tag,child:u(e.filters,t.variants.options[e.tag])})}else if(e===`not`)n.push({kind:`not`,child:u(i,t)});else if(e===`fields`)for(let[e,t]of Object.entries(i))n.push(...h(e,t));else if(t?.relations[e]){let r=t.relations[e];if(r.cardinality===`one`)n.push({kind:`relation`,name:e,mode:`one`,predicate:i===null?null:u(i,r.target)});else{let t=i;n.push({kind:`relation`,name:e,mode:t.some===void 0?`none`:`some`,predicate:u(t.some??t.none,r.target)})}}else n.push(...h(e,i))}return{kind:`and`,children:n}}function d(t,n,r){let i=e.object({eq:t.optional(),in:e.array(t).max(100).optional()}),a=n?i.extend({gt:t.optional(),gte:t.optional(),lt:t.optional(),lte:t.optional()}):i,o=r?a.extend({exists:e.boolean().optional()}):a;return e.union([t,o.strict().refine(e=>Object.values(e).some(e=>e!==void 0),`At least one operator is required`)])}function f(e){return c({fields:e,relations:{}})}function p(t,n,r=/* @__PURE__ */ new WeakMap){let o=r.get(t)?.get(n);if(o)return o;let s=t.fields,c=Object.fromEntries(Object.entries(s).filter(([e])=>![`and`,`or`,`not`,`fields`,...t.variants?[`variant`]:[]].includes(e))),l={};for(let[a,o]of Object.entries(t.relations)){if(n===4)continue;let t=p(o.target,n+1,r);l[a]=(o.cardinality===`one`?t.nullable():e.union([e.object({some:t}).strict(),e.object({none:t}).strict()])).optional(),i.set(l[a],o)}if(t.variants&&n<4){let i=Object.entries(t.variants.options).map(([t,i])=>e.strictObject({tag:e.literal(t),filters:p(i,n+1,r)}));i.length&&(l.variant=e.union(i).optional(),a.set(l.variant,t.variants))}let u=e.object({...c,...l,fields:e.object(s).strict().optional()}).strict(),d=n===4?void 0:p(t,n+1,r),f=d?u.extend({and:e.array(d).min(1).max(256).optional(),or:e.array(d).min(1).max(256).optional(),not:d.optional()}):u,m=r.get(t);return m||(m=/* @__PURE__ */ new Map,r.set(t,m)),m.set(n,f),f}function m(t,n){let r=[{value:t,depth:0,context:`expression`,grammar:n}],i=0;for(;r.length;){let t=r.pop();if(++i>256||t.depth>4)return!1;if(Object(t.value)!==t.value)continue;let n=t.value,a=Array.isArray(n)?n:void 0,o=Object.getPrototypeOf(n);if((a?o!==Array.prototype:o!==Object.prototype&&o!==null)||a&&a.length+i+r.length>256)return!1;let s=Reflect.ownKeys(n);if(s.length-+!!a+i+r.length>256||a&&s.length!==a.length+1)return!1;let c;switch(t.context){case`expression`:c=[...Object.keys(t.grammar.fields),...Object.keys(t.grammar.relations),`and`,`or`,`not`,`fields`,...t.grammar.variants?[`variant`]:[]];break;case`variant`:c=[`tag`,`filters`];break;case`fields`:c=Object.keys(t.grammar.fields);break;case`predicate`:c=[`eq`,`in`,`gt`,`gte`,`lt`,`lte`,`exists`];break;case`many`:c=[`some`,`none`];break;default:c=[]}for(let e of c)if(!Object.hasOwn(n,e)&&e in n)return!1;for(let i of s){if(a&&i===`length`)continue;let o=Object.getOwnPropertyDescriptor(n,i),s=String(i);if(!o.enumerable||!(`value`in o)||s!==i||a&&(!/^(0|[1-9]\d*)$/.test(s)||Number(s)>=a.length))return!1;let c=`value`,l=t.depth,u=t.grammar;if(t.context===`expression`){if(c=`predicate`,s===`variant`&&t.grammar.variants)c=`variant`,l++;else if(s===`fields`)c=`fields`;else if(s===`and`||s===`or`)c=`composition`,l++;else if(s===`not`)c=`expression`,l++;else if(t.grammar.relations[s]){let e=t.grammar.relations[s];c=e.cardinality===`one`?`expression`:`many`,u=e.target,l++}}else if(t.context===`variant`&&s===`filters`){let r=Object.getOwnPropertyDescriptor(n,`tag`);if(!r||!(`value`in r)||!e.string().safeParse(r.value).success||!Object.hasOwn(t.grammar.variants?.options??{},r.value))return!1;c=`expression`,u=t.grammar.variants.options[String(r.value)]}else t.context===`fields`?c=`predicate`:(t.context===`composition`||t.context===`many`)&&(c=`expression`);r.push({value:o.value,depth:l,context:c,grammar:u})}}return!0}function h(e,t){return t===void 0?[]:Object(t)===t?Object.entries(t).filter(([,e])=>e!==void 0).map(([t,n])=>({kind:`scalar`,field:e,operator:t,value:n})):[{kind:`scalar`,field:e,operator:`eq`,value:t}]}export{t as MAX_FILTER_DEPTH,r as MAX_FILTER_IN_VALUES,n as MAX_FILTER_NODES,f as boundedFilterSchema,u as normalizeFilters,l as paginationGrammar,c as relationFilterSchema,d as scalarPredicateFromSchema};
2
+ //# sourceMappingURL=filters.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filters.mjs","names":["MAX_FILTER_DEPTH","MAX_FILTER_NODES","MAX_FILTER_IN_VALUES","relationPredicates","variantPredicates","filterGrammars","BoundedFilterObject","z","inst","def","parse","namespace","namespaceObject","selectedKeys","grammar","key","schema","relation","withinFilterBudget","payload","ctx","relationFilterSchema","filterNodeSchema","cache","paginationGrammar","filters","root","cached","name","predicate","normalizeFilters","children","value","expression","child","scoped","field","scalar","normalizeScalar","target","scalarPredicateFromSchema","equality","ranged","range","existence","optional","entry","boundedFilterSchema","predicates","depth","direct","relations","options","tag","branch","node","result","depths","pending","nodes","object","array","prototype","keys","consumed","descriptor","context","operator"],"sources":["../../../src/querying/shared/filters.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { FilterAst, FilterScalar, FilterOperator } from './ast'\nexport const MAX_FILTER_DEPTH = 4\nexport const MAX_FILTER_NODES = 256\nexport const MAX_FILTER_IN_VALUES = 100\nexport type FieldSchemas = Record<string, z.ZodType>\nexport type FilterTree =\n\t| string\n\t| number\n\t| bigint\n\t| boolean\n\t| null\n\t| undefined\n\t| FilterTree[]\n\t| { [key: string]: FilterTree }\n\n// Compose Zod's exported core constructor with its ordinary object initializer.\n// Clones use this constructor again, preserving preflight without replacing the\n// converter-recognized object definition or any native scalar/ID validators.\nconst relationPredicates = new WeakMap<\n\tz.core.$ZodType,\n\t{ cardinality: 'one' | 'many'; target: FilterGrammar }\n>()\nconst variantPredicates = new WeakMap<z.core.$ZodType, NonNullable<FilterGrammar['variants']>>()\nconst filterGrammars = new WeakMap<z.core.$ZodType, FilterGrammar>()\n\nconst BoundedFilterObject = z.core.$constructor<z.ZodObject>('BoundedFilterObject', (inst, def) => {\n\tz.ZodObject.init(inst, def)\n\tconst parse = inst._zod.parse\n\tconst namespace = def.shape.fields\n\tconst namespaceObject = namespace instanceof z.ZodOptional ? namespace.unwrap() : undefined\n\tconst selectedKeys =\n\t\tnamespaceObject instanceof z.ZodObject\n\t\t\t? Object.keys(namespaceObject.shape)\n\t\t\t: Object.keys(def.shape)\n\tconst grammar: FilterGrammar = {\n\t\tvariants: variantPredicates.get(def.shape.variant),\n\t\tfields: Object.fromEntries(selectedKeys.map((key) => [key, def.shape[key]])),\n\t\trelations: Object.fromEntries(\n\t\t\tObject.entries(def.shape).flatMap(([key, schema]) => {\n\t\t\t\tconst relation = relationPredicates.get(schema)\n\t\t\t\treturn relation ? [[key, relation]] : []\n\t\t\t}),\n\t\t),\n\t}\n\t// Zod refinements run after parsing. Guard parse itself so both the deferred\n\t// no-check run and the refinement run retain the same pre-child boundary.\n\tinst._zod.parse = (payload, ctx) => {\n\t\t// SAFETY: preflight examines layout and budgets only; Zod still validates values.\n\t\tif (!withinFilterBudget(payload.value as FilterTree, grammar)) {\n\t\t\tpayload.issues.push({\n\t\t\t\tcode: 'custom',\n\t\t\t\tinput: payload.value,\n\t\t\t\tmessage: 'Unsupported filter layout or depth/node budget exceeded',\n\t\t\t})\n\t\t\treturn payload\n\t\t}\n\t\treturn parse(payload, ctx)\n\t}\n})\n\n/** Each boolean child and relation target expression consumes one of four edges.\n * some/none wrappers and fields namespaces consume nodes, but no extra depth.\n */\nexport interface FilterGrammar {\n\tfields: FieldSchemas\n\tvariants?: { discriminator: string; options: Record<string, FilterGrammar> }\n\trelations: Record<string, { cardinality: 'one' | 'many'; target: FilterGrammar }>\n}\n\nexport function relationFilterSchema(\n\tgrammar: FilterGrammar,\n\tcache = new WeakMap<FilterGrammar, Map<number, z.ZodObject>>(),\n): z.ZodType {\n\tconst schema = new BoundedFilterObject(filterNodeSchema(grammar, 0, cache)._zod.def)\n\tfilterGrammars.set(schema, grammar)\n\treturn schema\n}\n\nexport function paginationGrammar(schema: z.ZodType): FilterGrammar | undefined {\n\tif (!(schema instanceof z.ZodObject)) return undefined\n\tconst filters = schema.shape.filters\n\tif (!(filters instanceof z.ZodOptional)) return undefined\n\tconst root = filters.unwrap()\n\tconst cached = filterGrammars.get(root)\n\tif (cached) return cached\n\tif (!(root instanceof z.ZodObject)) return undefined\n\treturn {\n\t\tfields: root.shape,\n\t\tvariants: variantPredicates.get(root.shape.variant),\n\t\trelations: Object.fromEntries(\n\t\t\tObject.entries(root.shape).flatMap(([name, predicate]) => {\n\t\t\t\t// SAFETY: object shapes contain Zod schemas; metadata only recognizes predicates created by our grammar.\n\t\t\t\tconst relation = relationPredicates.get(predicate as z.core.$ZodType)\n\t\t\t\treturn relation ? [[name, relation]] : []\n\t\t\t}),\n\t\t),\n\t}\n}\nexport function normalizeFilters(value: FilterTree, grammar?: FilterGrammar): FilterAst {\n\tconst children: FilterAst[] = []\n\tif (!value) return { kind: 'and', children }\n\t// SAFETY: the caller parsed a strict filter object; its grammar has no array/primitive expression.\n\tconst expression = value as Record<string, FilterTree>\n\tfor (const [name, predicate] of Object.entries(expression)) {\n\t\tif (predicate === undefined) continue\n\t\tif (name === 'and' || name === 'or') {\n\t\t\t// SAFETY: boolean composition is validated as an array of expressions.\n\t\t\tchildren.push({\n\t\t\t\tkind: name,\n\t\t\t\tchildren: (predicate as FilterTree[]).map((child) => normalizeFilters(child, grammar)),\n\t\t\t})\n\t\t} else if (name === 'variant' && grammar?.variants) {\n\t\t\t// SAFETY: strict branch grammar validates the literal tag and its selected target filters.\n\t\t\tconst scoped = predicate as { tag: string; filters: FilterTree }\n\t\t\tchildren.push({\n\t\t\t\tkind: 'variant',\n\t\t\t\tdiscriminator: grammar.variants.discriminator,\n\t\t\t\ttag: scoped.tag,\n\t\t\t\tchild: normalizeFilters(scoped.filters, grammar.variants.options[scoped.tag]),\n\t\t\t})\n\t\t} else if (name === 'not')\n\t\t\tchildren.push({ kind: 'not', child: normalizeFilters(predicate, grammar) })\n\t\telse if (name === 'fields') {\n\t\t\t// SAFETY: fields is a strict selected scalar namespace.\n\t\t\tfor (const [field, scalar] of Object.entries(predicate as Record<string, FilterTree>))\n\t\t\t\tchildren.push(...normalizeScalar(field, scalar))\n\t\t} else if (grammar?.relations[name]) {\n\t\t\tconst relation = grammar.relations[name]\n\t\t\tif (relation.cardinality === 'one')\n\t\t\t\tchildren.push({\n\t\t\t\t\tkind: 'relation',\n\t\t\t\t\tname,\n\t\t\t\t\tmode: 'one',\n\t\t\t\t\tpredicate: predicate === null ? null : normalizeFilters(predicate, relation.target),\n\t\t\t\t})\n\t\t\telse {\n\t\t\t\t// SAFETY: many predicates validate as exactly one some/none target expression.\n\t\t\t\tconst target = predicate as { some?: FilterTree; none?: FilterTree }\n\t\t\t\tchildren.push({\n\t\t\t\t\tkind: 'relation',\n\t\t\t\t\tname,\n\t\t\t\t\tmode: target.some === undefined ? 'none' : 'some',\n\t\t\t\t\tpredicate: normalizeFilters(target.some ?? target.none, relation.target),\n\t\t\t\t})\n\t\t\t}\n\t\t} else children.push(...normalizeScalar(name, predicate))\n\t}\n\treturn { kind: 'and', children }\n}\nexport function scalarPredicateFromSchema(\n\tscalar: z.ZodType,\n\trange: boolean,\n\toptional: boolean,\n): z.ZodType {\n\tconst equality = z.object({\n\t\teq: scalar.optional(),\n\t\tin: z.array(scalar).max(MAX_FILTER_IN_VALUES).optional(),\n\t})\n\tconst ranged = range\n\t\t? equality.extend({\n\t\t\t\tgt: scalar.optional(),\n\t\t\t\tgte: scalar.optional(),\n\t\t\t\tlt: scalar.optional(),\n\t\t\t\tlte: scalar.optional(),\n\t\t\t})\n\t\t: equality\n\tconst existence = optional ? ranged.extend({ exists: z.boolean().optional() }) : ranged\n\treturn z.union([\n\t\tscalar,\n\t\texistence\n\t\t\t.strict()\n\t\t\t.refine(\n\t\t\t\t(value) => Object.values(value).some((entry) => entry !== undefined),\n\t\t\t\t'At least one operator is required',\n\t\t\t),\n\t])\n}\n\nexport function boundedFilterSchema(predicates: FieldSchemas): z.ZodType {\n\treturn relationFilterSchema({ fields: predicates, relations: {} })\n}\n\nfunction filterNodeSchema(\n\tgrammar: FilterGrammar,\n\tdepth: number,\n\tcache = new WeakMap<FilterGrammar, Map<number, z.ZodObject>>(),\n): z.ZodObject {\n\tconst cached = cache.get(grammar)?.get(depth)\n\tif (cached) return cached\n\tconst predicates = grammar.fields\n\tconst direct = Object.fromEntries(\n\t\tObject.entries(predicates).filter(\n\t\t\t([key]) =>\n\t\t\t\t!['and', 'or', 'not', 'fields', ...(grammar.variants ? ['variant'] : [])].includes(key),\n\t\t),\n\t)\n\tconst relations: FieldSchemas = {}\n\tfor (const [name, relation] of Object.entries(grammar.relations)) {\n\t\tif (depth === MAX_FILTER_DEPTH) continue\n\t\tconst target = filterNodeSchema(relation.target, depth + 1, cache)\n\t\trelations[name] = (\n\t\t\trelation.cardinality === 'one'\n\t\t\t\t? target.nullable()\n\t\t\t\t: z.union([z.object({ some: target }).strict(), z.object({ none: target }).strict()])\n\t\t).optional()\n\t\trelationPredicates.set(relations[name], relation)\n\t}\n\tif (grammar.variants && depth < MAX_FILTER_DEPTH) {\n\t\tconst options = Object.entries(grammar.variants.options).map(([tag, branch]) =>\n\t\t\tz.strictObject({ tag: z.literal(tag), filters: filterNodeSchema(branch, depth + 1, cache) }),\n\t\t)\n\t\tif (options.length) {\n\t\t\trelations.variant = z.union(options).optional()\n\t\t\tvariantPredicates.set(relations.variant, grammar.variants)\n\t\t}\n\t}\n\tconst node = z\n\t\t.object({ ...direct, ...relations, fields: z.object(predicates).strict().optional() })\n\t\t.strict()\n\tconst child = depth === MAX_FILTER_DEPTH ? undefined : filterNodeSchema(grammar, depth + 1, cache)\n\tconst result = child\n\t\t? node.extend({\n\t\t\t\tand: z.array(child).min(1).max(MAX_FILTER_NODES).optional(),\n\t\t\t\tor: z.array(child).min(1).max(MAX_FILTER_NODES).optional(),\n\t\t\t\tnot: child.optional(),\n\t\t\t})\n\t\t: node\n\tlet depths = cache.get(grammar)\n\tif (!depths) {\n\t\tdepths = new Map()\n\t\tcache.set(grammar, depths)\n\t}\n\tdepths.set(depth, result)\n\treturn result\n}\n\nfunction withinFilterBudget(value: FilterTree, grammar: FilterGrammar): boolean {\n\ttype Context =\n\t\t| 'expression'\n\t\t| 'fields'\n\t\t| 'predicate'\n\t\t| 'composition'\n\t\t| 'many'\n\t\t| 'variant'\n\t\t| 'value'\n\tinterface Entry {\n\t\tvalue: FilterTree\n\t\tdepth: number\n\t\tcontext: Context\n\t\tgrammar: FilterGrammar\n\t}\n\tconst pending: Entry[] = [{ value, depth: 0, context: 'expression', grammar }]\n\tlet nodes = 0\n\twhile (pending.length) {\n\t\tconst entry = pending.pop()!\n\t\tif (++nodes > MAX_FILTER_NODES || entry.depth > MAX_FILTER_DEPTH) return false\n\t\tif (Object(entry.value) !== entry.value) continue\n\t\t// SAFETY: boxing excludes null and primitives; descriptors below avoid invoking getters.\n\t\tconst object = entry.value as FilterTree[] | Record<string, FilterTree>\n\t\tconst array = Array.isArray(object) ? object : undefined\n\t\tconst prototype = Object.getPrototypeOf(object)\n\t\tif (\n\t\t\tarray ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null\n\t\t)\n\t\t\treturn false\n\t\tif (array && array.length + nodes + pending.length > MAX_FILTER_NODES) return false\n\t\tconst keys = Reflect.ownKeys(object)\n\t\tif (\n\t\t\tkeys.length - (array ? 1 : 0) + nodes + pending.length > MAX_FILTER_NODES ||\n\t\t\t(array && keys.length !== array.length + 1)\n\t\t)\n\t\t\treturn false\n\t\tlet consumed: string[]\n\t\tswitch (entry.context) {\n\t\t\tcase 'expression':\n\t\t\t\tconsumed = [\n\t\t\t\t\t...Object.keys(entry.grammar.fields),\n\t\t\t\t\t...Object.keys(entry.grammar.relations),\n\t\t\t\t\t'and',\n\t\t\t\t\t'or',\n\t\t\t\t\t'not',\n\t\t\t\t\t'fields',\n\t\t\t\t\t...(entry.grammar.variants ? ['variant'] : []),\n\t\t\t\t]\n\t\t\t\tbreak\n\t\t\tcase 'variant':\n\t\t\t\tconsumed = ['tag', 'filters']\n\t\t\t\tbreak\n\t\t\tcase 'fields':\n\t\t\t\tconsumed = Object.keys(entry.grammar.fields)\n\t\t\t\tbreak\n\t\t\tcase 'predicate':\n\t\t\t\tconsumed = ['eq', 'in', 'gt', 'gte', 'lt', 'lte', 'exists']\n\t\t\t\tbreak\n\t\t\tcase 'many':\n\t\t\t\tconsumed = ['some', 'none']\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\tconsumed = []\n\t\t}\n\t\tfor (const key of consumed) if (!Object.hasOwn(object, key) && key in object) return false\n\t\tfor (const key of keys) {\n\t\t\tif (array && key === 'length') continue\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, key)!\n\t\t\tconst name = String(key)\n\t\t\tif (!descriptor.enumerable || !('value' in descriptor) || name !== key) return false\n\t\t\tif (array && (!/^(0|[1-9]\\d*)$/.test(name) || Number(name) >= array.length)) return false\n\t\t\tlet context: Context = 'value'\n\t\t\tlet depth = entry.depth\n\t\t\tlet target = entry.grammar\n\t\t\tif (entry.context === 'expression') {\n\t\t\t\tcontext = 'predicate'\n\t\t\t\tif (name === 'variant' && entry.grammar.variants) {\n\t\t\t\t\tcontext = 'variant'\n\t\t\t\t\tdepth++\n\t\t\t\t} else if (name === 'fields') context = 'fields'\n\t\t\t\telse if (name === 'and' || name === 'or') {\n\t\t\t\t\tcontext = 'composition'\n\t\t\t\t\tdepth++\n\t\t\t\t} else if (name === 'not') {\n\t\t\t\t\tcontext = 'expression'\n\t\t\t\t\tdepth++\n\t\t\t\t} else if (entry.grammar.relations[name]) {\n\t\t\t\t\tconst relation = entry.grammar.relations[name]\n\t\t\t\t\tcontext = relation.cardinality === 'one' ? 'expression' : 'many'\n\t\t\t\t\ttarget = relation.target\n\t\t\t\t\tdepth++\n\t\t\t\t}\n\t\t\t} else if (entry.context === 'variant' && name === 'filters') {\n\t\t\t\tconst tag = Object.getOwnPropertyDescriptor(object, 'tag')\n\t\t\t\tif (\n\t\t\t\t\t!tag ||\n\t\t\t\t\t!('value' in tag) ||\n\t\t\t\t\t!z.string().safeParse(tag.value).success ||\n\t\t\t\t\t!Object.hasOwn(entry.grammar.variants?.options ?? {}, tag.value)\n\t\t\t\t)\n\t\t\t\t\treturn false\n\t\t\t\tcontext = 'expression'\n\t\t\t\ttarget = entry.grammar.variants!.options[String(tag.value)]\n\t\t\t} else if (entry.context === 'fields') context = 'predicate'\n\t\t\telse if (entry.context === 'composition' || entry.context === 'many') context = 'expression'\n\t\t\tpending.push({ value: descriptor.value, depth, context, grammar: target })\n\t\t}\n\t}\n\treturn true\n}\nfunction normalizeScalar(field: string, predicate: FilterTree): FilterAst[] {\n\tif (predicate === undefined) return []\n\tif (Object(predicate) !== predicate) {\n\t\t// SAFETY: native scalar grammar excludes object/array values and preserves branded ID strings.\n\t\treturn [{ kind: 'scalar', field, operator: 'eq', value: predicate as FilterScalar }]\n\t}\n\t// SAFETY: only selected supported scalar operator objects survive validation.\n\treturn Object.entries(predicate as Record<FilterOperator, FilterScalar | FilterScalar[]>)\n\t\t.filter(([, value]) => value !== undefined)\n\t\t.map(([operator, value]) => ({\n\t\t\tkind: 'scalar',\n\t\t\tfield,\n\t\t\toperator: operator as FilterOperator,\n\t\t\tvalue,\n\t\t}))\n}\n"],"mappings":"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"}
@@ -1,9 +1,13 @@
1
- import { ManagedBudgets, ManagedQueryContext, ManagedSecurityConfig } from "./querying/security.mjs";
2
1
  import { IndexCondition, NativePagination } from "./querying/filters.mjs";
3
- import { RelationDeclarations, RelationFilterSelection, RelationFilters, RelationQueryRow, RelationRegistry, RelationSelection, RelationTables } from "./relations.mjs";
4
- import { CursorCodecConfig } from "./querying/cursors.mjs";
5
- import { DataModelFromSchemaDefinition, GenericSchema, PaginationResult, SchemaDefinition } from "convex/server";
6
- import { GenericId } from "convex/values";
2
+ import { EnginePaginationResult } from "./zod-table.mjs";
3
+ import { ExactGroupSelection, FieldGroupRequest, RelationDeclarations, RelationFilterSelection, RelationFilters, RelationGroupSelection, RelationQueryRow, RelationRegistry, RelationSelection, RelationTables } from "./relations.mjs";
4
+ import { ManagedBudgets, ManagedQueryContext, ManagedScope, ManagedSecurityConfig } from "./querying/security.mjs";
5
+ import { CursorCodecConfig, CursorError, ScopedCursorCodec, ScopedCursorOptions } from "./querying/cursors.mjs";
6
+ import { SearchError, SearchPaginationResult } from "./querying/search.mjs";
7
+ import { queryFailureContract } from "./querying/failures.mjs";
8
+ import { DataModelFromSchemaDefinition, GenericDatabaseReader, GenericSchema, SchemaDefinition } from "convex/server";
9
+ import { z } from "zod";
10
+ import { GenericId, Value } from "convex/values";
7
11
  //#region src/querying.d.ts
8
12
  type FullMask<S> = { [K in keyof S]-?: NonNullable<S[K]> extends true ? true : FullMask<Exclude<NonNullable<S[K]>, true>>; };
9
13
  type Paths<D extends RelationDeclarations, T extends string, L extends readonly 1[] = [1, 1, 1, 1]> = L extends readonly [1, ...infer Rest extends 1[]] ? { [K in keyof D[T] & string]: (D[T][K]['cardinality'] extends 'many' ? K : never) | `${K}.${Paths<D, D[T][K]['target'], Rest>}`; }[keyof D[T] & string] : never;
@@ -15,19 +19,34 @@ type EngineArgs<Tables extends RelationTables, D extends RelationDeclarations, T
15
19
  order?: 'asc' | 'desc';
16
20
  };
17
21
  /** Typed declarative chain returned by the engine; named for consumer declaration emission. */
18
- export interface TableQuery<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S = {}, L extends readonly 1[] = [1, 1, 1, 1], Scope extends string = never> {
19
- when(value: IndexCondition['value'], index: string): TableQuery<Tables, D, T, S, L, Scope>;
20
- where(spec: NonNullable<EngineArgs<Tables, D, T>['filters']>): TableQuery<Tables, D, T, S, L, Scope>;
21
- with<const Selection extends RelationSelection<Tables, D, T, L>>(selection: Selection & { [K in keyof Selection]: K extends keyof RelationSelection<Tables, D, T, L> ? Selection[K] : never; }): TableQuery<Tables, D, T, Selection, L, Scope>;
22
- relation<const P extends Paths<D, Extract<T, string>>>(parent: GenericId<Tables[T]['tableName']>, path: P): Omit<TableQuery<Tables, D, Extract<PathTarget<D, Extract<T, string>, P>, keyof Tables>, {}, RemainingDepth<P, L>, PathScope<D, Extract<T, string>, P>>, 'relation'>;
23
- paginate(args: EngineArgs<Tables, D, T>): Promise<PaginationResult<RelationQueryRow<Tables, D, T, S, Scope>>>;
22
+ export interface TableQuery<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S = {}, L extends readonly 1[] = [1, 1, 1, 1], Scope extends string = never, Schema extends SchemaDefinition<GenericSchema, boolean> = SchemaDefinition<GenericSchema, boolean>, G = {}, Root extends boolean = true> {
23
+ search: Root extends true ? (index: Extract<keyof DataModelFromSchemaDefinition<Schema>[Extract<T, string>]['searchIndexes'], string>, text: string) => SearchQuery<Tables, D, T, S, L, Scope, Schema, G> : never;
24
+ include<const Groups extends FieldGroupRequest<Tables[T]>>(groups: Groups & Record<Exclude<keyof Groups, keyof FieldGroupRequest<Tables[T]>>, never>): TableQuery<Tables, D, T, S, L, Scope, Schema, Omit<G, 'fieldGroups'> & {
25
+ fieldGroups: Groups;
26
+ }, Root>;
27
+ orderBy(index: Exclude<Extract<keyof DataModelFromSchemaDefinition<Schema>[Extract<T, string>]['indexes'], string>, 'by_id' | 'by_creation_time'>): TableQuery<Tables, D, T, S, L, Scope, Schema, G, Root>;
28
+ when(value: IndexCondition['value'], index: string): TableQuery<Tables, D, T, S, L, Scope, Schema, G, Root>;
29
+ where(spec: NonNullable<EngineArgs<Tables, D, T>['filters']>): TableQuery<Tables, D, T, S, L, Scope, Schema, G, Root>;
30
+ with<const Selection extends RelationSelection<Tables, D, T, L>, const Groups extends RelationGroupSelection<Tables, D, T, L> = {}>(selection: Selection & { [K in keyof Selection]: K extends keyof RelationSelection<Tables, D, T, L> ? Selection[K] : never; }, groups?: ExactGroupSelection<Tables, D, T, Groups>): TableQuery<Tables, D, T, Selection, L, Scope, Schema, Omit<G, keyof Groups> & Groups, Root>;
31
+ relation<const P extends Paths<D, Extract<T, string>>>(parent: GenericId<Tables[T]['tableName']>, path: P): Omit<TableQuery<Tables, D, Extract<PathTarget<D, Extract<T, string>, P>, keyof Tables>, {}, RemainingDepth<P, L>, PathScope<D, Extract<T, string>, P>, Schema, {}, false>, 'relation'>;
32
+ paginate(args: EngineArgs<Tables, D, T>): Promise<EnginePaginationResult<RelationQueryRow<Tables, D, T, S, Scope, G>>>;
33
+ }
34
+ export interface SearchQuery<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S = {}, L extends readonly 1[] = [1, 1, 1, 1], Scope extends string = never, Schema extends SchemaDefinition<GenericSchema, boolean> = SchemaDefinition<GenericSchema, boolean>, G = {}> {
35
+ include<const Groups extends FieldGroupRequest<Tables[T]>>(groups: Groups & Record<Exclude<keyof Groups, keyof FieldGroupRequest<Tables[T]>>, never>): SearchQuery<Tables, D, T, S, L, Scope, Schema, Omit<G, 'fieldGroups'> & {
36
+ fieldGroups: Groups;
37
+ }>;
38
+ where(spec: NonNullable<EngineArgs<Tables, D, T>['filters']>): SearchQuery<Tables, D, T, S, L, Scope, Schema, G>;
39
+ with<const Selection extends RelationSelection<Tables, D, T, L>, const Groups extends RelationGroupSelection<Tables, D, T, L> = {}>(selection: Selection & { [K in keyof Selection]: K extends keyof RelationSelection<Tables, D, T, L> ? Selection[K] : never; }, groups?: ExactGroupSelection<Tables, D, T, Groups>): SearchQuery<Tables, D, T, Selection, L, Scope, Schema, Omit<G, keyof Groups> & Groups>;
40
+ paginate(args: Omit<EngineArgs<Tables, D, T>, 'order' | 'endCursor' | 'maximumRowsRead' | 'maximumBytesRead' | 'onEmptyBudget'> & {
41
+ scanLimit?: number;
42
+ }): Promise<SearchPaginationResult<RelationQueryRow<Tables, D, T, S, Scope, G>>>;
24
43
  }
25
44
  export interface QueryEngineDeclaration<Schema extends SchemaDefinition<GenericSchema, boolean>, Tables extends RelationTables, D extends RelationDeclarations> {
26
45
  schema: Schema;
27
46
  relations: RelationRegistry<Tables, D>;
28
47
  }
29
48
  /** Advanced server configuration, separate from the normal schema/relations declaration. */
30
- export interface QueryEngineOptions<Schema extends SchemaDefinition<GenericSchema, boolean>> {
49
+ export interface QueryEngineOptions<Schema extends SchemaDefinition<GenericSchema, boolean>, Tables extends RelationTables = RelationTables> {
31
50
  /** Explicit codecs validate at creation. Otherwise environment keys load at first paginate. */
32
51
  cursor?: CursorCodecConfig;
33
52
  budgets?: Partial<ManagedBudgets>;
@@ -35,20 +54,32 @@ export interface QueryEngineOptions<Schema extends SchemaDefinition<GenericSchem
35
54
  policyVersion?: string;
36
55
  engineVersion?: string;
37
56
  trustedAdapter?: ManagedSecurityConfig<DataModelFromSchemaDefinition<Schema>>['trustedAdapter'];
57
+ fieldGroups?: { [T in keyof Tables]?: { [G in keyof NonNullable<Tables[T]['fieldGroups']>]?: (ctx: FieldGroupPolicyContext<Schema>) => boolean | Promise<boolean>; }; };
58
+ }
59
+ export interface FieldGroupPolicyContext<Schema extends SchemaDefinition<GenericSchema, boolean>> {
60
+ readonly db: GenericDatabaseReader<DataModelFromSchemaDefinition<Schema>>;
61
+ readonly scope: ManagedScope;
62
+ }
63
+ export declare class FieldGroupError extends Error {
64
+ readonly code = "FIELD_GROUP_DENIED";
65
+ constructor();
38
66
  }
39
67
  /** @deprecated Use QueryEngineDeclaration and optional QueryEngineOptions separately. */
40
- export interface QueryEngineConfig<Schema extends SchemaDefinition<GenericSchema, boolean>, Tables extends RelationTables, D extends RelationDeclarations> extends QueryEngineDeclaration<Schema, Tables, D>, QueryEngineOptions<Schema> {
68
+ export interface QueryEngineConfig<Schema extends SchemaDefinition<GenericSchema, boolean>, Tables extends RelationTables, D extends RelationDeclarations> extends QueryEngineDeclaration<Schema, Tables, D>, QueryEngineOptions<Schema, Tables> {
41
69
  cursor: CursorCodecConfig;
42
70
  }
43
71
  type QueryEngine<Schema extends SchemaDefinition<GenericSchema, boolean>, Tables extends RelationTables, D extends RelationDeclarations> = {
44
- (ctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>): { [T in keyof Tables]: TableQuery<Tables, D, T>; };
72
+ (ctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>): { [T in keyof Tables]: TableQuery<Tables, D, T, {}, [1, 1, 1, 1], never, Schema>; };
73
+ /** Opens prove integrity only; native consumers must enforce current row authorization. */
74
+ cursorCodec<S extends z.ZodType<Value>>(ctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>, options: ScopedCursorOptions<S>): ScopedCursorCodec<S>;
45
75
  tables: RelationRegistry<Tables, D>['tables'];
46
76
  };
47
77
  /** Central facade. Endpoint chains carry declarative constraints and explicit relationships. */
48
- export declare function createQueryEngine<Schema extends SchemaDefinition<GenericSchema, boolean>, const Tables extends RelationTables, const D extends RelationDeclarations>(config: QueryEngineDeclaration<Schema, Tables, D>, options?: QueryEngineOptions<Schema>): QueryEngine<Schema, Tables, D>;
78
+ export declare function createQueryEngine<Schema extends SchemaDefinition<GenericSchema, boolean>, const Tables extends RelationTables, const D extends RelationDeclarations>(config: QueryEngineDeclaration<Schema, Tables, D>, options?: QueryEngineOptions<Schema, Tables>): QueryEngine<Schema, Tables, D>;
49
79
  /** @deprecated Pass advanced fields in the optional second argument. */
50
- export declare function createQueryEngine<Schema extends SchemaDefinition<GenericSchema, boolean>, const Tables extends RelationTables, const D extends RelationDeclarations>(config: QueryEngineDeclaration<Schema, Tables, D> & QueryEngineOptions<Schema> & {
80
+ export declare function createQueryEngine<Schema extends SchemaDefinition<GenericSchema, boolean>, const Tables extends RelationTables, const D extends RelationDeclarations>(config: QueryEngineDeclaration<Schema, Tables, D> & QueryEngineOptions<Schema, Tables> & {
51
81
  cursor: CursorCodecConfig;
52
82
  }): QueryEngine<Schema, Tables, D>;
53
83
  //#endregion
84
+ export { CursorError, type ScopedCursorCodec, type ScopedCursorOptions, SearchError, type SearchPaginationResult, queryFailureContract };
54
85
  //# sourceMappingURL=querying.d.mts.map
package/dist/querying.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{createManagedSecurity as e}from"./querying/security.mjs";import{createPlanner as t}from"./querying/planner.mjs";import{createCursorCodec as n,createEnvironmentCursorCodec as r}from"./querying/cursors.mjs";import{assertRelationshipDepth as i,relationshipExecutor as a}from"./querying/relationships.mjs";import{executeQuery as o}from"./querying/execution.mjs";function s(s,c){let{relations:l}=s,u={...s,...c},d=t(s.schema,l),f=d.streamSchema,p=u.cursor===void 0?void 0:n(u.cursor),m=u.maxPageSize??100;if(!Number.isSafeInteger(m)||m<=0||m>100)throw Error(`Invalid central page size`);let h=u.engineVersion??`scalar-1`,g=u.policyVersion??`1`,_,v=e({tables:Object.keys(l.tables),policyVersion:g,budgets:u.budgets,trustedAdapter:u.trustedAdapter});function y(e){let t=v(e);function n(e,s=[],c=[],u={},v){return Object.freeze({when:(t,r)=>n(e,[...s,{value:t,index:r}],c,u,v),where:t=>n(e,s,[...c,t],u,v),with:t=>n(e,s,c,t,v),relation:(t,r)=>{let i=r.split(`.`);if(!i.length||i.length>4)throw Error(`INVALID_RELATION`);let a=e;for(let e of i){let t=d.metadata.declarations[a]?.[e];if(!t)throw Error(`INVALID_RELATION`);a=t.target}return n(a,s,c,{},{table:e,parent:t,path:i})},async paginate(n){let y=p??=r();d.select(e,u),i(u,v?.path.length??0);let b=d.plan(e,n,v?[]:s,c);if(b.args.numItems>m)throw Error(`Page size exceeds central ceiling`);b.args.maximumRowsRead=Math.min(b.args.maximumRowsRead??t.budgets.rawCandidates,t.budgets.rawCandidates),b.args.maximumBytesRead=Math.min(b.args.maximumBytesRead??t.budgets.documentBytes,t.budgets.documentBytes),_??=Array.from(new Uint8Array(await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(l.identity))),e=>e.toString(16).padStart(2,`0`)).join(``);let x={table:v?.table??e,index:b.index?.name??`by_creation_time`,order:b.args.order??`asc`,clientFilters:b.clientIdentity,serverFilters:{predicates:b.serverIdentity,selection:u,scope:{...t.scope}},relationPath:[],principal:JSON.stringify(t.scope),tenant:t.scope.tenant,policyVersion:g,engineVersion:h,registryVersion:_},S=a(f,t,d,y,x);return v?await S.continuation(v.table,v.parent,v.path,u,b.args,s,c):await o(f,t,e,b,d,y,x,async(t,n)=>!n||!await S.matches(e,t,b.residual)?null:S.output(e,t,u,b.args))}})}return Object.freeze(Object.fromEntries(Object.keys(l.tables).map(e=>[e,n(e)])))}return Object.assign(y,{tables:l.tables})}export{s as createQueryEngine};
1
+ import{ManagedReadError as e,createManagedSecurity as t}from"./querying/security.mjs";import{createPlanner as n}from"./querying/planner.mjs";import{CursorError as r,createCursorCodec as i,createEnvironmentCursorCodec as a,createScopedCursorCodec as o}from"./querying/cursors.mjs";import{SearchError as s,executeSearch as c,planSearch as l}from"./querying/search.mjs";import{assertRelationshipDepth as u,relationshipExecutor as d}from"./querying/relationships.mjs";import{executeQuery as f}from"./querying/execution.mjs";import{queryFailureContract as p}from"./querying/failures.mjs";import{z as m}from"zod";const h={fieldGroups:{},relations:{}};var g=class extends Error{code=`FIELD_GROUP_DENIED`;constructor(){super(`FIELD_GROUP_DENIED`),this.name=`FieldGroupError`}};function _(r,p){let{relations:_}=r,y={...r,...p},b=n(r.schema,_),x=b.streamSchema,S=/* @__PURE__ */ new Map;for(let[e,t]of Object.entries(y.fieldGroups??{})){if(!Object.hasOwn(b.metadata.tables,e))throw Error(`Unknown field group policy table`);for(let[n,r]of Object.entries(t??{})){if(!Object.hasOwn(b.metadata.tables[e].fieldGroups,n)||!(r instanceof Function))throw Error(`Unknown field group policy`);S.set(JSON.stringify([e,n]),r)}}let C=y.cursor===void 0?void 0:i(y.cursor),w=y.maxPageSize??100;if(!Number.isSafeInteger(w)||w<=0||w>100)throw Error(`Invalid central page size`);let T=y.engineVersion??`scalar-1`,E=y.policyVersion??`1`,D,O=t({tables:Object.keys(_.tables),policyVersion:E,budgets:y.budgets,trustedAdapter:y.trustedAdapter});function k(t){let n=O(t),r=/* @__PURE__ */ new Map;async function i(t,a){let o={};for(let[i,s]of Object.entries(a.fieldGroups??{})){let a=JSON.stringify([t,i]),c=r.get(a);if(c||(c=Promise.resolve().then(async()=>{try{return await S.get(a)?.(Object.freeze({db:n.db,scope:n.scope}))===!0}catch(t){throw t instanceof e?t:new g}}),r.set(a,c)),o[i]={mode:s,allowed:await c},s===`required`&&!o[i].allowed)throw new g}let s={};for(let[e,n]of Object.entries(a.relations??{}))s[e]=await i(b.metadata.declarations[t][e].target,n);return{fieldGroups:o,relations:s}}function o(e,t=[],r=[],p={},y,S,O={},k){return Object.freeze({include:n=>o(e,t,r,p,y,S,b.groups(e,{...O,fieldGroups:n}),k),orderBy:n=>{if(k)throw new s(`SEARCH_ORDER_UNSUPPORTED`);if(!m.string().safeParse(n).success)throw Error(`Unknown ordering index`);return o(e,t,r,p,y,n,O,k)},when:(n,i)=>{if(k&&n!=null)throw new s(`SEARCH_ORDER_UNSUPPORTED`);return o(e,[...t,{value:n,index:i}],r,p,y,S,O,k)},where:n=>o(e,t,[...r,n],p,y,S,O,k),with:(n,i={})=>o(e,t,r,n,y,S,b.groups(e,{...O,...i}),k),search:(n,i)=>{if(y)throw new s(`SEARCH_RELATION_UNSUPPORTED`);if(S!==void 0||t.some(({value:e})=>e!=null))throw new s(`SEARCH_ORDER_UNSUPPORTED`);if(k)throw new s(`SEARCH_OPTIONS_UNSUPPORTED`);return o(e,t,r,p,y,S,O,{index:n,text:i})},relation:(n,i)=>{if(k)throw new s(`SEARCH_RELATION_UNSUPPORTED`);let a=i.split(`.`);if(!a.length||a.length>4)throw Error(`INVALID_RELATION`);let c=e;for(let e of a){let t=b.metadata.declarations[c]?.[e];if(!t)throw Error(`INVALID_RELATION`);c=t.target}return o(c,t,r,{},{table:e,parent:n,path:a},S)},async paginate(o){let s=C??=a();b.select(e,p),u(p,y?.path.length??0);let m=k?l(b,e,k.index,k.text,o,r):void 0,A=m?.plan??b.plan(e,o,y?[]:t,r,S,y?`relation`:`root`);if(!m&&A.args.numItems>w)throw Error(`Page size exceeds central ceiling`);let j=await i(e,b.groups(e,O)),M={at(e){return e.slice(y?.path.length??0).reduce((e,t)=>e.relations[t]??h,j)},allowed(e){return Object.entries(this.at(e).fieldGroups).filter(([,e])=>e.allowed).map(([e])=>e)},checkOrder(e,t,n){for(let r of t)N(e,r,n?this.at(n):h)}};function N(e,t,n){for(let[r,i]of Object.entries(b.metadata.tables[e].fieldGroups))if(i.includes(t.split(`.`)[0])&&n.fieldGroups[r]?.allowed!==!0)throw new g}function P(e,t,n){if(t.kind===`scalar`)N(e,t.field,n);else if(t.kind===`variant`)N(e,t.discriminator,n),P(e,t.child,n);else if(t.kind===`not`)P(e,t.child,n);else if(t.kind===`and`||t.kind===`or`)for(let r of t.children)P(e,r,n);else t.kind===`relation`&&t.predicate&&P(b.metadata.declarations[e][t.name].target,t.predicate,n.relations[t.name]??h)}if(A.residual.kind!==`and`)throw Error(`Invalid compiled filter root`);P(e,A.residual.children[0],j),m&&N(e,m.metadata.searchField,j);let F=S??t.find(e=>e.value!=null)?.index;if(!m&&F!==void 0)for(let t of b.metadata.tables[e].indexes.find(e=>e.name===F)?.fields??[])N(e,t,j);else if(!m&&!y&&A.index)for(let t of A.index.fields.slice(A.prefix.length))N(e,t,j);A.args.maximumRowsRead=Math.min(A.args.maximumRowsRead??n.budgets.rawCandidates,n.budgets.rawCandidates),A.args.maximumBytesRead=Math.min(A.args.maximumBytesRead??n.budgets.documentBytes,n.budgets.documentBytes),D??=Array.from(new Uint8Array(await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(_.identity))),e=>e.toString(16).padStart(2,`0`)).join(``);let I={};v(j)&&(I.fieldGroups=j);let L={predicates:A.serverIdentity,selection:p,...I,scope:{...n.scope}};m&&(L.search={mode:`search`,text:m.text,index:{...m.metadata,filterFields:[...m.metadata.filterFields]},equalities:m.equalities,scanLimit:m.scanLimit??null});let R={table:y?.table??e,index:m?.metadata.name??A.index?.name??`by_creation_time`,order:A.args.order??`asc`,clientFilters:A.clientIdentity,serverFilters:L,relationPath:[],principal:JSON.stringify(n.scope),tenant:n.scope.tenant,policyVersion:E,engineVersion:T,registryVersion:D},z=n,B=d(x,z,b,s,R,M);return B.preflight(e,p,A.args,y?.path??[]),m?await c(z,e,m,s,R,w,async t=>{let r=t;return!await n.authorize(e,t)||!await B.matches(e,r,A.residual)?null:B.output(e,r,p,A.args)}):y?await B.continuation(y.table,y.parent,y.path,p,A.args,t,r,S):await f(x,n,e,A,b,s,R,async(t,n)=>!n||!await B.matches(e,t,A.residual)?null:B.output(e,t,p,A.args))}})}return Object.freeze(Object.fromEntries(Object.keys(_.tables).map(e=>[e,o(e)])))}return Object.assign(k,{tables:_.tables,cursorCodec(e,t){let n=O.cursorScope(e);return C??=a(),o(C.custom,n,t)}})}function v(e){return Object.keys(e.fieldGroups).length>0||Object.values(e.relations).some(v)}export{r as CursorError,g as FieldGroupError,s as SearchError,_ as createQueryEngine,p as queryFailureContract};
2
2
  //# sourceMappingURL=querying.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"querying.mjs","names":["executorRequest","createQueryEngine","config","settings","options","planner","createPlanner","relations","schema","cursorCodec","createCursorCodec","maxPageSize","engineVersion","policyVersion","registryDigest","security","createManagedSecurity","querying","request","ctx","tableQuery","table","conditions","constraints","selection","route","spec","selected","path","declaredPath","target","name","edge","codec","createEnvironmentCursorCodec","assertRelationshipDepth","plan","input","byte","binding","executor","relationshipExecutor","executeQuery","permitted","row"],"sources":["../src/querying.ts"],"sourcesContent":["import type {\n\tGenericSchema,\n\tSchemaDefinition,\n\tDataModelFromSchemaDefinition,\n\tPaginationResult,\n} from 'convex/server'\nimport type { GenericId } from 'convex/values'\nimport type {\n\tRelationTables,\n\tRelationDeclarations,\n\tRelationRegistry,\n\tRelationQueryRow,\n\tRelationSelection,\n\tRelationFilters,\n\tRelationFilterSelection,\n} from './relations'\nimport { createPlanner, type QueryInput, type StoredConstraint } from './querying/planner'\nimport { executeQuery, type ExecutionRequest } from './querying/execution'\nimport {\n\trelationshipExecutor,\n\tassertRelationshipDepth,\n\ttype OutputSelection,\n\ttype RelationDocument,\n} from './querying/relationships'\nimport {\n\tcreateCursorCodec,\n\tcreateEnvironmentCursorCodec,\n\ttype CursorCodecConfig,\n\ttype CursorBinding,\n} from './querying/cursors'\nimport {\n\tcreateManagedSecurity,\n\ttype ManagedSecurityConfig,\n\ttype ManagedQueryContext,\n\ttype ManagedBudgets,\n} from './querying/security'\nimport type { IndexCondition, NativePagination } from './querying/filters'\n\ntype FullMask<S> = {\n\t[K in keyof S]-?: NonNullable<S[K]> extends true\n\t\t? true\n\t\t: FullMask<Exclude<NonNullable<S[K]>, true>>\n}\ntype Paths<\n\tD extends RelationDeclarations,\n\tT extends string,\n\tL extends readonly 1[] = [1, 1, 1, 1],\n> = L extends readonly [1, ...infer Rest extends 1[]]\n\t? {\n\t\t\t[K in keyof D[T] & string]:\n\t\t\t\t| (D[T][K]['cardinality'] extends 'many' ? K : never)\n\t\t\t\t| `${K}.${Paths<D, D[T][K]['target'], Rest>}`\n\t\t}[keyof D[T] & string]\n\t: never\ntype PathTarget<\n\tD extends RelationDeclarations,\n\tT extends string,\n\tP extends string,\n> = P extends `${infer Head}.${infer Rest}`\n\t? PathTarget<D, D[T][Head]['target'], Rest>\n\t: D[T][P]['target']\ntype PathScope<\n\tD extends RelationDeclarations,\n\tT extends string,\n\tP extends string,\n> = P extends `${infer Head}.${infer Rest}`\n\t? PathScope<D, D[T][Head]['target'], Rest>\n\t: Extract<NonNullable<D[T][P]['targetGuard']>['tag'], string>\ntype RemainingDepth<P extends string, L extends readonly 1[]> = L extends readonly [\n\t1,\n\t...infer Rest extends 1[],\n]\n\t? P extends `${string}.${infer Tail}`\n\t\t? RemainingDepth<Tail, Rest>\n\t\t: Rest\n\t: []\ntype EngineArgs<\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n\tT extends keyof Tables,\n> = NativePagination & {\n\tfilters?: RelationFilters<Tables, D, T, FullMask<RelationFilterSelection<Tables, D, T>>>\n\torder?: 'asc' | 'desc'\n}\n/** Typed declarative chain returned by the engine; named for consumer declaration emission. */\nexport interface TableQuery<\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n\tT extends keyof Tables,\n\tS = {},\n\tL extends readonly 1[] = [1, 1, 1, 1],\n\tScope extends string = never,\n> {\n\twhen(value: IndexCondition['value'], index: string): TableQuery<Tables, D, T, S, L, Scope>\n\twhere(\n\t\tspec: NonNullable<EngineArgs<Tables, D, T>['filters']>,\n\t): TableQuery<Tables, D, T, S, L, Scope>\n\twith<const Selection extends RelationSelection<Tables, D, T, L>>(\n\t\tselection: Selection & {\n\t\t\t[K in keyof Selection]: K extends keyof RelationSelection<Tables, D, T, L>\n\t\t\t\t? Selection[K]\n\t\t\t\t: never\n\t\t},\n\t): TableQuery<Tables, D, T, Selection, L, Scope>\n\trelation<const P extends Paths<D, Extract<T, string>>>(\n\t\tparent: GenericId<Tables[T]['tableName']>,\n\t\tpath: P,\n\t): Omit<\n\t\tTableQuery<\n\t\t\tTables,\n\t\t\tD,\n\t\t\tExtract<PathTarget<D, Extract<T, string>, P>, keyof Tables>,\n\t\t\t{},\n\t\t\tRemainingDepth<P, L>,\n\t\t\tPathScope<D, Extract<T, string>, P>\n\t\t>,\n\t\t'relation'\n\t>\n\tpaginate(\n\t\targs: EngineArgs<Tables, D, T>,\n\t): Promise<PaginationResult<RelationQueryRow<Tables, D, T, S, Scope>>>\n}\nexport interface QueryEngineDeclaration<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n> {\n\tschema: Schema\n\trelations: RelationRegistry<Tables, D>\n}\n/** Advanced server configuration, separate from the normal schema/relations declaration. */\nexport interface QueryEngineOptions<Schema extends SchemaDefinition<GenericSchema, boolean>> {\n\t/** Explicit codecs validate at creation. Otherwise environment keys load at first paginate. */\n\tcursor?: CursorCodecConfig\n\tbudgets?: Partial<ManagedBudgets>\n\tmaxPageSize?: number\n\tpolicyVersion?: string\n\tengineVersion?: string\n\ttrustedAdapter?: ManagedSecurityConfig<DataModelFromSchemaDefinition<Schema>>['trustedAdapter']\n}\n\n/** @deprecated Use QueryEngineDeclaration and optional QueryEngineOptions separately. */\nexport interface QueryEngineConfig<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n>\n\textends QueryEngineDeclaration<Schema, Tables, D>, QueryEngineOptions<Schema> {\n\tcursor: CursorCodecConfig\n}\n\ntype QueryEngine<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n> = {\n\t(ctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>): {\n\t\t[T in keyof Tables]: TableQuery<Tables, D, T>\n\t}\n\ttables: RelationRegistry<Tables, D>['tables']\n}\n\n/** Central facade. Endpoint chains carry declarative constraints and explicit relationships. */\nexport function createQueryEngine<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tconst Tables extends RelationTables,\n\tconst D extends RelationDeclarations,\n>(\n\tconfig: QueryEngineDeclaration<Schema, Tables, D>,\n\toptions?: QueryEngineOptions<Schema>,\n): QueryEngine<Schema, Tables, D>\n/** @deprecated Pass advanced fields in the optional second argument. */\nexport function createQueryEngine<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tconst Tables extends RelationTables,\n\tconst D extends RelationDeclarations,\n>(\n\tconfig: QueryEngineDeclaration<Schema, Tables, D> &\n\t\tQueryEngineOptions<Schema> & { cursor: CursorCodecConfig },\n): QueryEngine<Schema, Tables, D>\nexport function createQueryEngine<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tconst Tables extends RelationTables,\n\tconst D extends RelationDeclarations,\n>(\n\tconfig: QueryEngineDeclaration<Schema, Tables, D> & QueryEngineOptions<Schema>,\n\toptions?: QueryEngineOptions<Schema>,\n) {\n\tconst { relations } = config\n\t// Retain released one-argument calls; a second argument overrides legacy fields.\n\tconst settings = { ...config, ...options }\n\tconst planner = createPlanner(config.schema, relations)\n\tconst schema = planner.streamSchema\n\tlet cursorCodec = settings.cursor === undefined ? undefined : createCursorCodec(settings.cursor)\n\tconst maxPageSize = settings.maxPageSize ?? 100\n\tif (!Number.isSafeInteger(maxPageSize) || maxPageSize <= 0 || maxPageSize > 100)\n\t\tthrow new Error('Invalid central page size')\n\tconst engineVersion = settings.engineVersion ?? 'scalar-1'\n\tconst policyVersion = settings.policyVersion ?? '1'\n\t// Bind the full immutable identity through a collision-resistant digest so\n\t// real application registries fit the codec's bounded AAD.\n\tlet registryDigest: string | undefined\n\tconst security = createManagedSecurity<DataModelFromSchemaDefinition<Schema>>({\n\t\ttables: Object.keys(relations.tables),\n\t\tpolicyVersion,\n\t\tbudgets: settings.budgets,\n\t\ttrustedAdapter: settings.trustedAdapter,\n\t})\n\tfunction querying(ctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>) {\n\t\tconst request = security(ctx)\n\t\tfunction tableQuery(\n\t\t\ttable: string,\n\t\t\tconditions: readonly IndexCondition[] = [],\n\t\t\tconstraints: readonly StoredConstraint[] = [],\n\t\t\tselection: OutputSelection = {},\n\t\t\troute?: { table: string; parent: string; path: string[] },\n\t\t) {\n\t\t\treturn Object.freeze({\n\t\t\t\twhen: (value: IndexCondition['value'], index: string) =>\n\t\t\t\t\ttableQuery(table, [...conditions, { value, index }], constraints, selection, route),\n\t\t\t\twhere: (spec: StoredConstraint) =>\n\t\t\t\t\ttableQuery(table, conditions, [...constraints, spec], selection, route),\n\t\t\t\twith: (selected: OutputSelection) =>\n\t\t\t\t\ttableQuery(table, conditions, constraints, selected, route),\n\t\t\t\trelation: (parent: string, declaredPath: string) => {\n\t\t\t\t\tconst path = declaredPath.split('.')\n\t\t\t\t\tif (!path.length || path.length > 4) throw new Error('INVALID_RELATION')\n\t\t\t\t\tlet target = table\n\t\t\t\t\tfor (const name of path) {\n\t\t\t\t\t\tconst edge = planner.metadata.declarations[target]?.[name]\n\t\t\t\t\t\tif (!edge) throw new Error('INVALID_RELATION')\n\t\t\t\t\t\ttarget = edge.target\n\t\t\t\t\t}\n\t\t\t\t\treturn tableQuery(target, conditions, constraints, {}, { table, parent, path })\n\t\t\t\t},\n\t\t\t\tasync paginate(input: QueryInput) {\n\t\t\t\t\t// Resolve once per global engine, before any native query or policy reads.\n\t\t\t\t\tconst codec = (cursorCodec ??= createEnvironmentCursorCodec())\n\t\t\t\t\tplanner.select(table, selection)\n\t\t\t\t\tassertRelationshipDepth(selection, route?.path.length ?? 0)\n\t\t\t\t\tconst plan = planner.plan(table, input, route ? [] : conditions, constraints)\n\t\t\t\t\tif (plan.args.numItems > maxPageSize) throw new Error('Page size exceeds central ceiling')\n\t\t\t\t\t// Native root limits stay native; lowering those limits cannot raise\n\t\t\t\t\t// the independent shared request meter.\n\t\t\t\t\tplan.args.maximumRowsRead = Math.min(\n\t\t\t\t\t\tplan.args.maximumRowsRead ?? request.budgets.rawCandidates,\n\t\t\t\t\t\trequest.budgets.rawCandidates,\n\t\t\t\t\t)\n\t\t\t\t\tplan.args.maximumBytesRead = Math.min(\n\t\t\t\t\t\tplan.args.maximumBytesRead ?? request.budgets.documentBytes,\n\t\t\t\t\t\trequest.budgets.documentBytes,\n\t\t\t\t\t)\n\t\t\t\t\tregistryDigest ??= Array.from(\n\t\t\t\t\t\tnew Uint8Array(\n\t\t\t\t\t\t\tawait crypto.subtle.digest('SHA-256', new TextEncoder().encode(relations.identity)),\n\t\t\t\t\t\t),\n\t\t\t\t\t\t(byte) => byte.toString(16).padStart(2, '0'),\n\t\t\t\t\t).join('')\n\t\t\t\t\t// SAFETY: selection has passed registry admission before cursor binding.\n\t\t\t\t\tconst binding: CursorBinding = {\n\t\t\t\t\t\ttable: route?.table ?? table,\n\t\t\t\t\t\tindex: plan.index?.name ?? 'by_creation_time',\n\t\t\t\t\t\torder: plan.args.order ?? 'asc',\n\t\t\t\t\t\tclientFilters: plan.clientIdentity,\n\t\t\t\t\t\t// Include output selection and the complete immutable scope in trusted identity.\n\t\t\t\t\t\tserverFilters: {\n\t\t\t\t\t\t\tpredicates: plan.serverIdentity,\n\t\t\t\t\t\t\tselection: selection as import('convex/values').Value,\n\t\t\t\t\t\t\tscope: { ...request.scope },\n\t\t\t\t\t\t},\n\t\t\t\t\t\trelationPath: [],\n\t\t\t\t\t\tprincipal: JSON.stringify(request.scope),\n\t\t\t\t\t\ttenant: request.scope.tenant,\n\t\t\t\t\t\tpolicyVersion,\n\t\t\t\t\t\tengineVersion,\n\t\t\t\t\t\tregistryVersion: registryDigest,\n\t\t\t\t\t}\n\t\t\t\t\t// The executor accepts registry-selected native tables, rather than a static DM key.\n\t\t\t\t\tconst executorRequest: unknown = request\n\t\t\t\t\t// SAFETY: only native DM types are erased at this private executor boundary.\n\t\t\t\t\tconst executor = relationshipExecutor(\n\t\t\t\t\t\tschema,\n\t\t\t\t\t\texecutorRequest as ExecutionRequest,\n\t\t\t\t\t\tplanner,\n\t\t\t\t\t\tcodec,\n\t\t\t\t\t\tbinding,\n\t\t\t\t\t)\n\t\t\t\t\tconst result = route\n\t\t\t\t\t\t? await executor.continuation(\n\t\t\t\t\t\t\t\troute.table,\n\t\t\t\t\t\t\t\troute.parent,\n\t\t\t\t\t\t\t\troute.path,\n\t\t\t\t\t\t\t\tselection,\n\t\t\t\t\t\t\t\tplan.args,\n\t\t\t\t\t\t\t\tconditions,\n\t\t\t\t\t\t\t\tconstraints,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: await executeQuery(\n\t\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\t\ttable,\n\t\t\t\t\t\t\t\tplan,\n\t\t\t\t\t\t\t\tplanner,\n\t\t\t\t\t\t\t\tcodec,\n\t\t\t\t\t\t\t\tbinding,\n\t\t\t\t\t\t\t\tasync (row, permitted) => {\n\t\t\t\t\t\t\t\t\t// SAFETY: metered native stream rows contain the validated system fields.\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t!permitted ||\n\t\t\t\t\t\t\t\t\t\t!(await executor.matches(table, row as RelationDocument, plan.residual))\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t\t\t\t// SAFETY: the same native row is authorized and matches the declared predicates.\n\t\t\t\t\t\t\t\t\treturn executor.output(table, row as RelationDocument, selection, plan.args)\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t)\n\t\t\t\t\t// SAFETY: the private executor validated and projected every row against\n\t\t\t\t\t// this registry's DTO and selected edges before assembling the page.\n\t\t\t\t\treturn result as PaginationResult<\n\t\t\t\t\t\tRelationQueryRow<Tables, D, keyof Tables, OutputSelection>\n\t\t\t\t\t>\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\t// SAFETY: each key comes from the exact validated registry; the planner\n\t\t// validates all input and projection while mapped types retain table brands.\n\t\treturn Object.freeze(\n\t\t\tObject.fromEntries(Object.keys(relations.tables).map((table) => [table, tableQuery(table)])),\n\t\t) as { [T in keyof Tables]: TableQuery<Tables, D, T> }\n\t}\n\treturn Object.assign(querying, { tables: relations.tables })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"querying.mjs","names":["executorRequest","emptyGroups","FieldGroupError","createQueryEngine","config","settings","options","planner","createPlanner","relations","schema","policies","table","definitions","name","policy","cursorCodec","createCursorCodec","maxPageSize","engineVersion","policyVersion","registryDigest","security","createManagedSecurity","querying","request","ctx","decisions","resolveGroups","fieldGroups","mode","groups","key","decision","error","ManagedReadError","nested","selection","tableQuery","conditions","constraints","route","ordering","search","SearchError","z","index","value","spec","selected","requested","path","declaredPath","target","edge","codec","createEnvironmentCursorCodec","assertRelationshipDepth","searchPlan","planSearch","input","plan","resolved","groupAccess","node","field","fields","checkField","checkClient","ast","child","sortIndex","condition","byte","groupBinding","hasGroups","serverFilters","binding","executionRequest","executor","relationshipExecutor","executeSearch","document","row","executeQuery","permitted","scope","createScopedCursorCodec","CursorError","queryFailureContract"],"sources":["../src/querying.ts"],"sourcesContent":["import type { GenericSchema, SchemaDefinition, DataModelFromSchemaDefinition } from 'convex/server'\nimport type { GenericId } from 'convex/values'\nimport type { EnginePaginationResult } from './zod-table'\nimport { z } from 'zod'\nimport type {\n\tRelationTables,\n\tRelationDeclarations,\n\tRelationRegistry,\n\tRelationQueryRow,\n\tRelationSelection,\n\tRelationFilters,\n\tRelationFilterSelection,\n\tFieldGroupRequest,\n\tRelationGroupSelection,\n\tGroupSelection,\n\tExactGroupSelection,\n} from './relations'\nimport { createPlanner, type QueryInput, type StoredConstraint } from './querying/planner'\nimport { executeQuery, type ExecutionRequest } from './querying/execution'\nimport {\n\trelationshipExecutor,\n\tassertRelationshipDepth,\n\ttype OutputSelection,\n\ttype RelationDocument,\n\ttype GroupAccess,\n\ttype ResolvedGroups,\n} from './querying/relationships'\nimport {\n\tcreateCursorCodec,\n\tcreateScopedCursorCodec,\n\ttype ScopedCursorOptions,\n\ttype ScopedCursorCodec,\n\tcreateEnvironmentCursorCodec,\n\ttype CursorCodecConfig,\n\ttype CursorBinding,\n} from './querying/cursors'\nimport {\n\tcreateManagedSecurity,\n\ttype ManagedSecurityConfig,\n\ttype ManagedQueryContext,\n\ttype ManagedBudgets,\n\ttype ManagedScope,\n\tManagedReadError,\n} from './querying/security'\nimport type { FilterAst, IndexCondition, NativePagination } from './querying/filters'\nimport type { GenericDatabaseReader } from 'convex/server'\nimport type { Value } from 'convex/values'\n\nimport { planSearch, executeSearch, SearchError } from './querying/search'\nexport { SearchError } from './querying/search'\nexport type { SearchPaginationResult } from './querying/search'\nexport { queryFailureContract } from './querying/failures'\nexport { CursorError } from './querying/cursors'\nexport type { ScopedCursorOptions, ScopedCursorCodec } from './querying/cursors'\n\nconst emptyGroups: ResolvedGroups = { fieldGroups: {}, relations: {} }\n\ntype FullMask<S> = {\n\t[K in keyof S]-?: NonNullable<S[K]> extends true\n\t\t? true\n\t\t: FullMask<Exclude<NonNullable<S[K]>, true>>\n}\ntype Paths<\n\tD extends RelationDeclarations,\n\tT extends string,\n\tL extends readonly 1[] = [1, 1, 1, 1],\n> = L extends readonly [1, ...infer Rest extends 1[]]\n\t? {\n\t\t\t[K in keyof D[T] & string]:\n\t\t\t\t| (D[T][K]['cardinality'] extends 'many' ? K : never)\n\t\t\t\t| `${K}.${Paths<D, D[T][K]['target'], Rest>}`\n\t\t}[keyof D[T] & string]\n\t: never\ntype PathTarget<\n\tD extends RelationDeclarations,\n\tT extends string,\n\tP extends string,\n> = P extends `${infer Head}.${infer Rest}`\n\t? PathTarget<D, D[T][Head]['target'], Rest>\n\t: D[T][P]['target']\ntype PathScope<\n\tD extends RelationDeclarations,\n\tT extends string,\n\tP extends string,\n> = P extends `${infer Head}.${infer Rest}`\n\t? PathScope<D, D[T][Head]['target'], Rest>\n\t: Extract<NonNullable<D[T][P]['targetGuard']>['tag'], string>\ntype RemainingDepth<P extends string, L extends readonly 1[]> = L extends readonly [\n\t1,\n\t...infer Rest extends 1[],\n]\n\t? P extends `${string}.${infer Tail}`\n\t\t? RemainingDepth<Tail, Rest>\n\t\t: Rest\n\t: []\ntype EngineArgs<\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n\tT extends keyof Tables,\n> = NativePagination & {\n\tfilters?: RelationFilters<Tables, D, T, FullMask<RelationFilterSelection<Tables, D, T>>>\n\torder?: 'asc' | 'desc'\n}\n/** Typed declarative chain returned by the engine; named for consumer declaration emission. */\nexport interface TableQuery<\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n\tT extends keyof Tables,\n\tS = {},\n\tL extends readonly 1[] = [1, 1, 1, 1],\n\tScope extends string = never,\n\tSchema extends SchemaDefinition<GenericSchema, boolean> = SchemaDefinition<\n\t\tGenericSchema,\n\t\tboolean\n\t>,\n\tG = {},\n\tRoot extends boolean = true,\n> {\n\tsearch: Root extends true\n\t\t? (\n\t\t\t\tindex: Extract<\n\t\t\t\t\tkeyof DataModelFromSchemaDefinition<Schema>[Extract<T, string>]['searchIndexes'],\n\t\t\t\t\tstring\n\t\t\t\t>,\n\t\t\t\ttext: string,\n\t\t\t) => SearchQuery<Tables, D, T, S, L, Scope, Schema, G>\n\t\t: never\n\tinclude<const Groups extends FieldGroupRequest<Tables[T]>>(\n\t\tgroups: Groups & Record<Exclude<keyof Groups, keyof FieldGroupRequest<Tables[T]>>, never>,\n\t): TableQuery<\n\t\tTables,\n\t\tD,\n\t\tT,\n\t\tS,\n\t\tL,\n\t\tScope,\n\t\tSchema,\n\t\tOmit<G, 'fieldGroups'> & { fieldGroups: Groups },\n\t\tRoot\n\t>\n\torderBy(\n\t\tindex: Exclude<\n\t\t\tExtract<keyof DataModelFromSchemaDefinition<Schema>[Extract<T, string>]['indexes'], string>,\n\t\t\t'by_id' | 'by_creation_time'\n\t\t>,\n\t): TableQuery<Tables, D, T, S, L, Scope, Schema, G, Root>\n\twhen(\n\t\tvalue: IndexCondition['value'],\n\t\tindex: string,\n\t): TableQuery<Tables, D, T, S, L, Scope, Schema, G, Root>\n\twhere(\n\t\tspec: NonNullable<EngineArgs<Tables, D, T>['filters']>,\n\t): TableQuery<Tables, D, T, S, L, Scope, Schema, G, Root>\n\twith<\n\t\tconst Selection extends RelationSelection<Tables, D, T, L>,\n\t\tconst Groups extends RelationGroupSelection<Tables, D, T, L> = {},\n\t>(\n\t\tselection: Selection & {\n\t\t\t[K in keyof Selection]: K extends keyof RelationSelection<Tables, D, T, L>\n\t\t\t\t? Selection[K]\n\t\t\t\t: never\n\t\t},\n\t\tgroups?: ExactGroupSelection<Tables, D, T, Groups>,\n\t): TableQuery<Tables, D, T, Selection, L, Scope, Schema, Omit<G, keyof Groups> & Groups, Root>\n\trelation<const P extends Paths<D, Extract<T, string>>>(\n\t\tparent: GenericId<Tables[T]['tableName']>,\n\t\tpath: P,\n\t): Omit<\n\t\tTableQuery<\n\t\t\tTables,\n\t\t\tD,\n\t\t\tExtract<PathTarget<D, Extract<T, string>, P>, keyof Tables>,\n\t\t\t{},\n\t\t\tRemainingDepth<P, L>,\n\t\t\tPathScope<D, Extract<T, string>, P>,\n\t\t\tSchema,\n\t\t\t{},\n\t\t\tfalse\n\t\t>,\n\t\t'relation'\n\t>\n\tpaginate(\n\t\targs: EngineArgs<Tables, D, T>,\n\t): Promise<EnginePaginationResult<RelationQueryRow<Tables, D, T, S, Scope, G>>>\n}\n\nexport interface SearchQuery<\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n\tT extends keyof Tables,\n\tS = {},\n\tL extends readonly 1[] = [1, 1, 1, 1],\n\tScope extends string = never,\n\tSchema extends SchemaDefinition<GenericSchema, boolean> = SchemaDefinition<\n\t\tGenericSchema,\n\t\tboolean\n\t>,\n\tG = {},\n> {\n\tinclude<const Groups extends FieldGroupRequest<Tables[T]>>(\n\t\tgroups: Groups & Record<Exclude<keyof Groups, keyof FieldGroupRequest<Tables[T]>>, never>,\n\t): SearchQuery<\n\t\tTables,\n\t\tD,\n\t\tT,\n\t\tS,\n\t\tL,\n\t\tScope,\n\t\tSchema,\n\t\tOmit<G, 'fieldGroups'> & { fieldGroups: Groups }\n\t>\n\twhere(\n\t\tspec: NonNullable<EngineArgs<Tables, D, T>['filters']>,\n\t): SearchQuery<Tables, D, T, S, L, Scope, Schema, G>\n\twith<\n\t\tconst Selection extends RelationSelection<Tables, D, T, L>,\n\t\tconst Groups extends RelationGroupSelection<Tables, D, T, L> = {},\n\t>(\n\t\tselection: Selection & {\n\t\t\t[K in keyof Selection]: K extends keyof RelationSelection<Tables, D, T, L>\n\t\t\t\t? Selection[K]\n\t\t\t\t: never\n\t\t},\n\t\tgroups?: ExactGroupSelection<Tables, D, T, Groups>,\n\t): SearchQuery<Tables, D, T, Selection, L, Scope, Schema, Omit<G, keyof Groups> & Groups>\n\tpaginate(\n\t\targs: Omit<\n\t\t\tEngineArgs<Tables, D, T>,\n\t\t\t'order' | 'endCursor' | 'maximumRowsRead' | 'maximumBytesRead' | 'onEmptyBudget'\n\t\t> & { scanLimit?: number },\n\t): Promise<\n\t\timport('./querying/search').SearchPaginationResult<RelationQueryRow<Tables, D, T, S, Scope, G>>\n\t>\n}\nexport interface QueryEngineDeclaration<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n> {\n\tschema: Schema\n\trelations: RelationRegistry<Tables, D>\n}\n/** Advanced server configuration, separate from the normal schema/relations declaration. */\nexport interface QueryEngineOptions<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tTables extends RelationTables = RelationTables,\n> {\n\t/** Explicit codecs validate at creation. Otherwise environment keys load at first paginate. */\n\tcursor?: CursorCodecConfig\n\tbudgets?: Partial<ManagedBudgets>\n\tmaxPageSize?: number\n\tpolicyVersion?: string\n\tengineVersion?: string\n\ttrustedAdapter?: ManagedSecurityConfig<DataModelFromSchemaDefinition<Schema>>['trustedAdapter']\n\tfieldGroups?: {\n\t\t[T in keyof Tables]?: {\n\t\t\t[G in keyof NonNullable<Tables[T]['fieldGroups']>]?: (\n\t\t\t\tctx: FieldGroupPolicyContext<Schema>,\n\t\t\t) => boolean | Promise<boolean>\n\t\t}\n\t}\n}\nexport interface FieldGroupPolicyContext<Schema extends SchemaDefinition<GenericSchema, boolean>> {\n\treadonly db: GenericDatabaseReader<DataModelFromSchemaDefinition<Schema>>\n\treadonly scope: ManagedScope\n}\nexport class FieldGroupError extends Error {\n\treadonly code = 'FIELD_GROUP_DENIED'\n\tconstructor() {\n\t\tsuper('FIELD_GROUP_DENIED')\n\t\tthis.name = 'FieldGroupError'\n\t}\n}\n\n/** @deprecated Use QueryEngineDeclaration and optional QueryEngineOptions separately. */\nexport interface QueryEngineConfig<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n>\n\textends QueryEngineDeclaration<Schema, Tables, D>, QueryEngineOptions<Schema, Tables> {\n\tcursor: CursorCodecConfig\n}\n\ntype QueryEngine<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tTables extends RelationTables,\n\tD extends RelationDeclarations,\n> = {\n\t(ctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>): {\n\t\t[T in keyof Tables]: TableQuery<Tables, D, T, {}, [1, 1, 1, 1], never, Schema>\n\t}\n\t/** Opens prove integrity only; native consumers must enforce current row authorization. */\n\tcursorCodec<S extends z.ZodType<Value>>(\n\t\tctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>,\n\t\toptions: ScopedCursorOptions<S>,\n\t): ScopedCursorCodec<S>\n\ttables: RelationRegistry<Tables, D>['tables']\n}\n\n/** Central facade. Endpoint chains carry declarative constraints and explicit relationships. */\nexport function createQueryEngine<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tconst Tables extends RelationTables,\n\tconst D extends RelationDeclarations,\n>(\n\tconfig: QueryEngineDeclaration<Schema, Tables, D>,\n\toptions?: QueryEngineOptions<Schema, Tables>,\n): QueryEngine<Schema, Tables, D>\n/** @deprecated Pass advanced fields in the optional second argument. */\nexport function createQueryEngine<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tconst Tables extends RelationTables,\n\tconst D extends RelationDeclarations,\n>(\n\tconfig: QueryEngineDeclaration<Schema, Tables, D> &\n\t\tQueryEngineOptions<Schema, Tables> & { cursor: CursorCodecConfig },\n): QueryEngine<Schema, Tables, D>\nexport function createQueryEngine<\n\tSchema extends SchemaDefinition<GenericSchema, boolean>,\n\tconst Tables extends RelationTables,\n\tconst D extends RelationDeclarations,\n>(\n\tconfig: QueryEngineDeclaration<Schema, Tables, D> & QueryEngineOptions<Schema, Tables>,\n\toptions?: QueryEngineOptions<Schema, Tables>,\n) {\n\tconst { relations } = config\n\t// Retain released one-argument calls; a second argument overrides legacy fields.\n\tconst settings = { ...config, ...options }\n\tconst planner = createPlanner(config.schema, relations)\n\tconst schema = planner.streamSchema\n\t// Copy callback references once: later option mutation cannot replace engine authority.\n\tconst policies = new Map<\n\t\tstring,\n\t\t(ctx: FieldGroupPolicyContext<Schema>) => boolean | Promise<boolean>\n\t>()\n\tfor (const [table, definitions] of Object.entries(settings.fieldGroups ?? {})) {\n\t\tif (!Object.hasOwn(planner.metadata.tables, table))\n\t\t\tthrow new Error('Unknown field group policy table')\n\t\tfor (const [name, policy] of Object.entries(definitions ?? {})) {\n\t\t\tif (\n\t\t\t\t!Object.hasOwn(planner.metadata.tables[table].fieldGroups, name) ||\n\t\t\t\t!(policy instanceof Function)\n\t\t\t)\n\t\t\t\tthrow new Error('Unknown field group policy')\n\t\t\t// SAFETY: the public mapped options require this policy signature; the function check also rejects malformed JS callers.\n\t\t\tpolicies.set(\n\t\t\t\tJSON.stringify([table, name]),\n\t\t\t\tpolicy as (ctx: FieldGroupPolicyContext<Schema>) => boolean | Promise<boolean>,\n\t\t\t)\n\t\t}\n\t}\n\tlet cursorCodec = settings.cursor === undefined ? undefined : createCursorCodec(settings.cursor)\n\tconst maxPageSize = settings.maxPageSize ?? 100\n\tif (!Number.isSafeInteger(maxPageSize) || maxPageSize <= 0 || maxPageSize > 100)\n\t\tthrow new Error('Invalid central page size')\n\tconst engineVersion = settings.engineVersion ?? 'scalar-1'\n\tconst policyVersion = settings.policyVersion ?? '1'\n\t// Bind the full immutable identity through a collision-resistant digest so\n\t// real application registries fit the codec's bounded AAD.\n\tlet registryDigest: string | undefined\n\tconst security = createManagedSecurity<DataModelFromSchemaDefinition<Schema>>({\n\t\ttables: Object.keys(relations.tables),\n\t\tpolicyVersion,\n\t\tbudgets: settings.budgets,\n\t\ttrustedAdapter: settings.trustedAdapter,\n\t})\n\tfunction querying(ctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>) {\n\t\tconst request = security(ctx)\n\t\tconst decisions = new Map<string, Promise<boolean>>()\n\t\tasync function resolveGroups(table: string, groups: GroupSelection): Promise<ResolvedGroups> {\n\t\t\tconst fieldGroups: ResolvedGroups['fieldGroups'] = {}\n\t\t\tfor (const [name, mode] of Object.entries(groups.fieldGroups ?? {})) {\n\t\t\t\tconst key = JSON.stringify([table, name])\n\t\t\t\tlet decision = decisions.get(key)\n\t\t\t\tif (!decision) {\n\t\t\t\t\tdecision = Promise.resolve().then(async () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t(await policies.get(key)?.(\n\t\t\t\t\t\t\t\t\tObject.freeze({ db: request.db, scope: request.scope }),\n\t\t\t\t\t\t\t\t)) === true\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tif (error instanceof ManagedReadError) throw error\n\t\t\t\t\t\t\tthrow new FieldGroupError()\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t\tdecisions.set(key, decision)\n\t\t\t\t}\n\t\t\t\tfieldGroups[name] = { mode, allowed: await decision }\n\t\t\t\tif (mode === 'required' && !fieldGroups[name].allowed) throw new FieldGroupError()\n\t\t\t}\n\t\t\tconst nested: ResolvedGroups['relations'] = {}\n\t\t\tfor (const [name, selection] of Object.entries(groups.relations ?? {}))\n\t\t\t\tnested[name] = await resolveGroups(\n\t\t\t\t\tplanner.metadata.declarations[table][name].target,\n\t\t\t\t\tselection,\n\t\t\t\t)\n\t\t\treturn { fieldGroups, relations: nested }\n\t\t}\n\t\tfunction tableQuery(\n\t\t\ttable: string,\n\t\t\tconditions: readonly IndexCondition[] = [],\n\t\t\tconstraints: readonly StoredConstraint[] = [],\n\t\t\tselection: OutputSelection = {},\n\t\t\troute?: { table: string; parent: string; path: string[] },\n\t\t\tordering?: string,\n\t\t\tgroups: GroupSelection = {},\n\t\t\tsearch?: { index: string; text: string },\n\t\t) {\n\t\t\treturn Object.freeze({\n\t\t\t\tinclude: (fieldGroups: GroupSelection['fieldGroups']) =>\n\t\t\t\t\ttableQuery(\n\t\t\t\t\t\ttable,\n\t\t\t\t\t\tconditions,\n\t\t\t\t\t\tconstraints,\n\t\t\t\t\t\tselection,\n\t\t\t\t\t\troute,\n\t\t\t\t\t\tordering,\n\t\t\t\t\t\tplanner.groups(table, { ...groups, fieldGroups }),\n\t\t\t\t\t\tsearch,\n\t\t\t\t\t),\n\t\t\t\torderBy: (index: string) => {\n\t\t\t\t\tif (search) throw new SearchError('SEARCH_ORDER_UNSUPPORTED')\n\t\t\t\t\tif (!z.string().safeParse(index).success) throw new Error('Unknown ordering index')\n\t\t\t\t\treturn tableQuery(table, conditions, constraints, selection, route, index, groups, search)\n\t\t\t\t},\n\t\t\t\twhen: (value: IndexCondition['value'], index: string) => {\n\t\t\t\t\tif (search && value != null) throw new SearchError('SEARCH_ORDER_UNSUPPORTED')\n\t\t\t\t\treturn tableQuery(\n\t\t\t\t\t\ttable,\n\t\t\t\t\t\t[...conditions, { value, index }],\n\t\t\t\t\t\tconstraints,\n\t\t\t\t\t\tselection,\n\t\t\t\t\t\troute,\n\t\t\t\t\t\tordering,\n\t\t\t\t\t\tgroups,\n\t\t\t\t\t\tsearch,\n\t\t\t\t\t)\n\t\t\t\t},\n\t\t\t\twhere: (spec: StoredConstraint) =>\n\t\t\t\t\ttableQuery(\n\t\t\t\t\t\ttable,\n\t\t\t\t\t\tconditions,\n\t\t\t\t\t\t[...constraints, spec],\n\t\t\t\t\t\tselection,\n\t\t\t\t\t\troute,\n\t\t\t\t\t\tordering,\n\t\t\t\t\t\tgroups,\n\t\t\t\t\t\tsearch,\n\t\t\t\t\t),\n\t\t\t\twith: (selected: OutputSelection, requested: GroupSelection = {}) =>\n\t\t\t\t\ttableQuery(\n\t\t\t\t\t\ttable,\n\t\t\t\t\t\tconditions,\n\t\t\t\t\t\tconstraints,\n\t\t\t\t\t\tselected,\n\t\t\t\t\t\troute,\n\t\t\t\t\t\tordering,\n\t\t\t\t\t\tplanner.groups(table, { ...groups, ...requested }),\n\t\t\t\t\t\tsearch,\n\t\t\t\t\t),\n\t\t\t\tsearch: (index: string, text: string) => {\n\t\t\t\t\tif (route) throw new SearchError('SEARCH_RELATION_UNSUPPORTED')\n\t\t\t\t\tif (ordering !== undefined || conditions.some(({ value }) => value != null))\n\t\t\t\t\t\tthrow new SearchError('SEARCH_ORDER_UNSUPPORTED')\n\t\t\t\t\tif (search) throw new SearchError('SEARCH_OPTIONS_UNSUPPORTED')\n\t\t\t\t\treturn tableQuery(table, conditions, constraints, selection, route, ordering, groups, {\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\ttext,\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\trelation: (parent: string, declaredPath: string) => {\n\t\t\t\t\tif (search) throw new SearchError('SEARCH_RELATION_UNSUPPORTED')\n\t\t\t\t\tconst path = declaredPath.split('.')\n\t\t\t\t\tif (!path.length || path.length > 4) throw new Error('INVALID_RELATION')\n\t\t\t\t\tlet target = table\n\t\t\t\t\tfor (const name of path) {\n\t\t\t\t\t\tconst edge = planner.metadata.declarations[target]?.[name]\n\t\t\t\t\t\tif (!edge) throw new Error('INVALID_RELATION')\n\t\t\t\t\t\ttarget = edge.target\n\t\t\t\t\t}\n\t\t\t\t\treturn tableQuery(target, conditions, constraints, {}, { table, parent, path }, ordering)\n\t\t\t\t},\n\t\t\t\tasync paginate(input: QueryInput) {\n\t\t\t\t\t// Resolve once per global engine, before any native query or policy reads.\n\t\t\t\t\tconst codec = (cursorCodec ??= createEnvironmentCursorCodec())\n\t\t\t\t\tplanner.select(table, selection)\n\t\t\t\t\tassertRelationshipDepth(selection, route?.path.length ?? 0)\n\t\t\t\t\tconst searchPlan = search\n\t\t\t\t\t\t? planSearch(\n\t\t\t\t\t\t\t\tplanner,\n\t\t\t\t\t\t\t\ttable,\n\t\t\t\t\t\t\t\tsearch.index,\n\t\t\t\t\t\t\t\tsearch.text,\n\t\t\t\t\t\t\t\tinput,\n\t\t\t\t\t\t\t\tconstraints,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: undefined\n\t\t\t\t\tconst plan =\n\t\t\t\t\t\tsearchPlan?.plan ??\n\t\t\t\t\t\tplanner.plan(\n\t\t\t\t\t\t\ttable,\n\t\t\t\t\t\t\tinput,\n\t\t\t\t\t\t\troute ? [] : conditions,\n\t\t\t\t\t\t\tconstraints,\n\t\t\t\t\t\t\tordering,\n\t\t\t\t\t\t\troute ? 'relation' : 'root',\n\t\t\t\t\t\t)\n\t\t\t\t\tif (!searchPlan && plan.args.numItems > maxPageSize)\n\t\t\t\t\t\tthrow new Error('Page size exceeds central ceiling')\n\t\t\t\t\tconst resolved = await resolveGroups(table, planner.groups(table, groups))\n\t\t\t\t\tconst groupAccess: GroupAccess = {\n\t\t\t\t\t\tat(path) {\n\t\t\t\t\t\t\treturn path\n\t\t\t\t\t\t\t\t.slice(route?.path.length ?? 0)\n\t\t\t\t\t\t\t\t.reduce((node, name) => node.relations[name] ?? emptyGroups, resolved)\n\t\t\t\t\t\t},\n\t\t\t\t\t\tallowed(path) {\n\t\t\t\t\t\t\treturn Object.entries(this.at(path).fieldGroups)\n\t\t\t\t\t\t\t\t.filter(([, decision]) => decision.allowed)\n\t\t\t\t\t\t\t\t.map(([name]) => name)\n\t\t\t\t\t\t},\n\t\t\t\t\t\tcheckOrder(table, fields, path) {\n\t\t\t\t\t\t\tfor (const field of fields)\n\t\t\t\t\t\t\t\tcheckField(table, field, path ? this.at(path) : emptyGroups)\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t\tfunction checkField(table: string, field: string, groups: ResolvedGroups) {\n\t\t\t\t\t\tfor (const [name, fields] of Object.entries(planner.metadata.tables[table].fieldGroups))\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tfields.includes(field.split('.')[0]) &&\n\t\t\t\t\t\t\t\tgroups.fieldGroups[name]?.allowed !== true\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tthrow new FieldGroupError()\n\t\t\t\t\t}\n\t\t\t\t\tfunction checkClient(table: string, ast: FilterAst, groups: ResolvedGroups): void {\n\t\t\t\t\t\tif (ast.kind === 'scalar') checkField(table, ast.field, groups)\n\t\t\t\t\t\telse if (ast.kind === 'variant') {\n\t\t\t\t\t\t\tcheckField(table, ast.discriminator, groups)\n\t\t\t\t\t\t\tcheckClient(table, ast.child, groups)\n\t\t\t\t\t\t} else if (ast.kind === 'not') checkClient(table, ast.child, groups)\n\t\t\t\t\t\telse if (ast.kind === 'and' || ast.kind === 'or')\n\t\t\t\t\t\t\tfor (const child of ast.children) checkClient(table, child, groups)\n\t\t\t\t\t\telse if (ast.kind === 'relation' && ast.predicate)\n\t\t\t\t\t\t\tcheckClient(\n\t\t\t\t\t\t\t\tplanner.metadata.declarations[table][ast.name].target,\n\t\t\t\t\t\t\t\tast.predicate,\n\t\t\t\t\t\t\t\tgroups.relations[ast.name] ?? emptyGroups,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t}\n\t\t\t\t\t// Inspect the whole client tree independently of execution/contradiction short circuits.\n\t\t\t\t\tif (plan.residual.kind !== 'and') throw new Error('Invalid compiled filter root')\n\t\t\t\t\tcheckClient(table, plan.residual.children[0], resolved)\n\t\t\t\t\tif (searchPlan) checkField(table, searchPlan.metadata.searchField, resolved)\n\t\t\t\t\tconst sortIndex =\n\t\t\t\t\t\tordering ?? conditions.find((condition) => condition.value != null)?.index\n\t\t\t\t\tif (!searchPlan && sortIndex !== undefined)\n\t\t\t\t\t\tfor (const field of planner.metadata.tables[table].indexes.find(\n\t\t\t\t\t\t\t(index) => index.name === sortIndex,\n\t\t\t\t\t\t)?.fields ?? [])\n\t\t\t\t\t\t\tcheckField(table, field, resolved)\n\t\t\t\t\telse if (!searchPlan && !route && plan.index)\n\t\t\t\t\t\tfor (const field of plan.index.fields.slice(plan.prefix.length))\n\t\t\t\t\t\t\tcheckField(table, field, resolved)\n\t\t\t\t\t// Native root limits stay native; lowering those limits cannot raise\n\t\t\t\t\t// the independent shared request meter.\n\t\t\t\t\tplan.args.maximumRowsRead = Math.min(\n\t\t\t\t\t\tplan.args.maximumRowsRead ?? request.budgets.rawCandidates,\n\t\t\t\t\t\trequest.budgets.rawCandidates,\n\t\t\t\t\t)\n\t\t\t\t\tplan.args.maximumBytesRead = Math.min(\n\t\t\t\t\t\tplan.args.maximumBytesRead ?? request.budgets.documentBytes,\n\t\t\t\t\t\trequest.budgets.documentBytes,\n\t\t\t\t\t)\n\t\t\t\t\tregistryDigest ??= Array.from(\n\t\t\t\t\t\tnew Uint8Array(\n\t\t\t\t\t\t\tawait crypto.subtle.digest('SHA-256', new TextEncoder().encode(relations.identity)),\n\t\t\t\t\t\t),\n\t\t\t\t\t\t(byte) => byte.toString(16).padStart(2, '0'),\n\t\t\t\t\t).join('')\n\t\t\t\t\tconst groupBinding: Record<string, Value> = {}\n\t\t\t\t\tif (hasGroups(resolved)) groupBinding.fieldGroups = resolved\n\t\t\t\t\t// SAFETY: selection has passed registry admission before cursor binding.\n\t\t\t\t\tconst serverFilters: CursorBinding['serverFilters'] = {\n\t\t\t\t\t\tpredicates: plan.serverIdentity,\n\t\t\t\t\t\tselection: selection as import('convex/values').Value,\n\t\t\t\t\t\t...groupBinding,\n\t\t\t\t\t\tscope: { ...request.scope },\n\t\t\t\t\t}\n\t\t\t\t\tif (searchPlan) serverFilters.search = {\n\t\t\t\t\t\tmode: 'search', text: searchPlan.text,\n\t\t\t\t\t\tindex: {...searchPlan.metadata, filterFields: [...searchPlan.metadata.filterFields]},\n\t\t\t\t\t\tequalities: searchPlan.equalities, scanLimit: searchPlan.scanLimit ?? null,\n\t\t\t\t\t}\n\t\t\t\t\tconst binding: CursorBinding = {\n\t\t\t\t\t\ttable: route?.table ?? table,\n\t\t\t\t\t\tindex: searchPlan?.metadata.name ?? plan.index?.name ?? 'by_creation_time',\n\t\t\t\t\t\torder: plan.args.order ?? 'asc',\n\t\t\t\t\t\tclientFilters: plan.clientIdentity,\n\t\t\t\t\t\t// Include output selection and the complete immutable scope in trusted identity.\n\t\t\t\t\t\tserverFilters,\n\t\t\t\t\t\trelationPath: [],\n\t\t\t\t\t\tprincipal: JSON.stringify(request.scope),\n\t\t\t\t\t\ttenant: request.scope.tenant,\n\t\t\t\t\t\tpolicyVersion,\n\t\t\t\t\t\tengineVersion,\n\t\t\t\t\t\tregistryVersion: registryDigest,\n\t\t\t\t\t}\n\t\t\t\t\t// The executor accepts registry-selected native tables, rather than a static DM key.\n\t\t\t\t\tconst executorRequest: unknown = request\n\t\t\t\t\t// SAFETY: only native DM types are erased at this private executor boundary.\n\t\t\t\t\tconst executionRequest = executorRequest as ExecutionRequest\n\t\t\t\t\tconst executor = relationshipExecutor(\n\t\t\t\t\t\tschema,\n\t\t\t\t\t\texecutionRequest,\n\t\t\t\t\t\tplanner,\n\t\t\t\t\t\tcodec,\n\t\t\t\t\t\tbinding,\n\t\t\t\t\t\tgroupAccess,\n\t\t\t\t\t)\n\t\t\t\t\texecutor.preflight(table, selection, plan.args, route?.path ?? [])\n\t\t\t\t\tconst result = searchPlan\n\t\t\t\t\t\t? await executeSearch(\n\t\t\t\t\t\t\t\texecutionRequest,\n\t\t\t\t\t\t\t\ttable,\n\t\t\t\t\t\t\t\tsearchPlan,\n\t\t\t\t\t\t\t\tcodec,\n\t\t\t\t\t\t\t\tbinding,\n\t\t\t\t\t\t\t\tmaxPageSize,\n\t\t\t\t\t\t\t\tasync (row) => {\n\t\t\t\t\t\t\t\t\t// SAFETY: native search returns system fields from the admitted registry table.\n\t\t\t\t\t\t\t\t\tconst document = row as RelationDocument\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t!(await request.authorize(table, row)) ||\n\t\t\t\t\t\t\t\t\t\t!(await executor.matches(table, document, plan.residual))\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t\t\t\treturn executor.output(table, document, selection, plan.args)\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: route\n\t\t\t\t\t\t\t? await executor.continuation(\n\t\t\t\t\t\t\t\t\troute.table,\n\t\t\t\t\t\t\t\t\troute.parent,\n\t\t\t\t\t\t\t\t\troute.path,\n\t\t\t\t\t\t\t\t\tselection,\n\t\t\t\t\t\t\t\t\tplan.args,\n\t\t\t\t\t\t\t\t\tconditions,\n\t\t\t\t\t\t\t\t\tconstraints,\n\t\t\t\t\t\t\t\t\tordering,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: await executeQuery(\n\t\t\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\t\t\trequest,\n\t\t\t\t\t\t\t\t\ttable,\n\t\t\t\t\t\t\t\t\tplan,\n\t\t\t\t\t\t\t\t\tplanner,\n\t\t\t\t\t\t\t\t\tcodec,\n\t\t\t\t\t\t\t\t\tbinding,\n\t\t\t\t\t\t\t\t\tasync (row, permitted) => {\n\t\t\t\t\t\t\t\t\t\t// SAFETY: metered native stream rows contain the validated system fields.\n\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t!permitted ||\n\t\t\t\t\t\t\t\t\t\t\t!(await executor.matches(table, row as RelationDocument, plan.residual))\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\treturn null\n\t\t\t\t\t\t\t\t\t\t// SAFETY: the same native row is authorized and matches the declared predicates.\n\t\t\t\t\t\t\t\t\t\treturn executor.output(table, row as RelationDocument, selection, plan.args)\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t// SAFETY: the private executor validated and projected every row against\n\t\t\t\t\t// this registry's DTO and selected edges before assembling the page.\n\t\t\t\t\treturn result as EnginePaginationResult<\n\t\t\t\t\t\tRelationQueryRow<Tables, D, keyof Tables, OutputSelection>\n\t\t\t\t\t>\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\t// SAFETY: each key comes from the exact validated registry; the planner\n\t\t// validates all input and projection while mapped types retain table brands.\n\t\treturn Object.freeze(\n\t\t\tObject.fromEntries(Object.keys(relations.tables).map((table) => [table, tableQuery(table)])),\n\t\t) as { [T in keyof Tables]: TableQuery<Tables, D, T, {}, [1, 1, 1, 1], never, Schema> }\n\t}\n\treturn Object.assign(querying, {\n\t\ttables: relations.tables,\n\t\tcursorCodec<S extends z.ZodType<Value>>(\n\t\t\tctx: ManagedQueryContext<DataModelFromSchemaDefinition<Schema>>,\n\t\t\toptions: ScopedCursorOptions<S>,\n\t\t): ScopedCursorCodec<S> {\n\t\t\t// Admission precedes lazy key loading and all schema/codec operations.\n\t\t\tconst scope = security.cursorScope(ctx)\n\t\t\tcursorCodec ??= createEnvironmentCursorCodec()\n\t\t\treturn createScopedCursorCodec(cursorCodec.custom, scope, options)\n\t\t},\n\t})\n}\n\nfunction hasGroups(groups: ResolvedGroups): boolean {\n\treturn (\n\t\tObject.keys(groups.fieldGroups).length > 0 || Object.values(groups.relations).some(hasGroups)\n\t)\n}\n"],"mappings":"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"}