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,23 @@
1
+ import { ErrorContract, ErrorDefinitions, UnknownFailure } from "../modules/contracts/errors.mjs";
2
+ //#region src/react/failures.d.ts
3
+ export type FailureContract = Pick<ErrorContract<ErrorDefinitions>, 'decode'>;
4
+ export type FailureOf<Contract extends FailureContract> = ReturnType<Contract['decode']>;
5
+ type DeclaredOf<Contract extends FailureContract> = Extract<FailureOf<Contract>, {
6
+ _tag: 'DeclaredFailure';
7
+ }>;
8
+ /** Extract ConvexError.data only. Contract validation owns the public envelope. */
9
+ export declare function decodeFailure<Contract extends FailureContract>(error: unknown, contract: Contract): FailureOf<Contract>;
10
+ type DeclaredHandlers<Contract extends FailureContract> = { [Code in DeclaredOf<Contract>['code']]: (failure: Code extends '_' ? FailureOf<Contract> : Extract<DeclaredOf<Contract>, {
11
+ code: Code;
12
+ }>) => unknown; };
13
+ export type FailureHandlers<Contract extends FailureContract> = DeclaredHandlers<Contract> | (Partial<DeclaredHandlers<Contract>> & {
14
+ _: (failure: FailureOf<Contract>) => unknown;
15
+ });
16
+ type HandlerResult<Handlers> = { [Key in keyof Handlers]: Handlers[Key] extends ((...args: never[]) => infer Result) ? Result : never; }[keyof Handlers];
17
+ /** Dispatch on code after validation. Without `_`, unknown errors return UnknownFailure. */
18
+ export declare function matchFailure<Contract extends FailureContract, const Handlers extends object>(error: unknown, contract: Contract, handlers: Partial<DeclaredHandlers<NoInfer<Contract>>> & {
19
+ _: (failure: FailureOf<NoInfer<Contract>>) => unknown;
20
+ } & Handlers & Record<Exclude<keyof Handlers, keyof DeclaredHandlers<Contract> | '_'>, never>): HandlerResult<Handlers>;
21
+ export declare function matchFailure<Contract extends FailureContract, const Handlers extends object>(error: unknown, contract: Contract, handlers: DeclaredHandlers<NoInfer<Contract>> & Handlers & Record<Exclude<keyof Handlers, keyof DeclaredHandlers<Contract>>, never>): HandlerResult<Handlers> | UnknownFailure;
22
+ //#endregion
23
+ //# sourceMappingURL=failures.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{ConvexError as e}from"convex/values";function t(t,n){let r={_tag:`UnknownFailure`,version:1};try{t instanceof e&&(r=n.decode(t.data))}catch{}return r}function n(e,n,r){let i=t(e,n),a=r,o=i._tag===`DeclaredFailure`&&Object.hasOwn(r,i.code)?a[i.code]:void 0;return o?o(i):Object.hasOwn(r,`_`)&&a._?a._(i):i}export{t as decodeFailure,n as matchFailure};
2
+ //# sourceMappingURL=failures.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failures.mjs","names":["decodeFailure","failure","error","ConvexError","contract","matchFailure","callbacks","handlers","handler"],"sources":["../../src/react/failures.ts"],"sourcesContent":["/* oxlint-disable anti-slop/no-unknown-parameters, anti-slop/no-unknown-returns -- Transport errors are untrusted; callback results are inferred independently. */\nimport { ConvexError } from 'convex/values'\nimport type { ErrorContract, ErrorDefinitions, UnknownFailure } from '../modules/contracts/errors'\n\nexport type FailureContract = Pick<ErrorContract<ErrorDefinitions>, 'decode'>\nexport type FailureOf<Contract extends FailureContract> = ReturnType<Contract['decode']>\ntype DeclaredOf<Contract extends FailureContract> = Extract<\n\tFailureOf<Contract>,\n\t{ _tag: 'DeclaredFailure' }\n>\n\n/** Extract ConvexError.data only. Contract validation owns the public envelope. */\nexport function decodeFailure<Contract extends FailureContract>(\n\terror: unknown,\n\tcontract: Contract,\n): FailureOf<Contract> {\n\tlet failure: ReturnType<FailureContract['decode']> = { _tag: 'UnknownFailure', version: 1 }\n\ttry {\n\t\tif (error instanceof ConvexError) failure = contract.decode(error.data)\n\t} catch {\n\t\t// Malformed proxies/getters and foreign errors never expose their diagnostics.\n\t}\n\t// SAFETY: the explicit contract owns its decode result; every error contract includes UnknownFailure.\n\treturn failure as FailureOf<Contract>\n}\n\ntype DeclaredHandlers<Contract extends FailureContract> = {\n\t[Code in DeclaredOf<Contract>['code']]: (\n\t\tfailure: Code extends '_' ? FailureOf<Contract> : Extract<DeclaredOf<Contract>, { code: Code }>,\n\t) => unknown\n}\nexport type FailureHandlers<Contract extends FailureContract> =\n\t| DeclaredHandlers<Contract>\n\t| (Partial<DeclaredHandlers<Contract>> & { _: (failure: FailureOf<Contract>) => unknown })\ntype HandlerResult<Handlers> = {\n\t[Key in keyof Handlers]: Handlers[Key] extends (...args: never[]) => infer Result ? Result : never\n}[keyof Handlers]\n\n/** Dispatch on code after validation. Without `_`, unknown errors return UnknownFailure. */\nexport function matchFailure<Contract extends FailureContract, const Handlers extends object>(\n\terror: unknown,\n\tcontract: Contract,\n\thandlers: Partial<DeclaredHandlers<NoInfer<Contract>>> & {\n\t\t_: (failure: FailureOf<NoInfer<Contract>>) => unknown\n\t} & Handlers &\n\t\tRecord<Exclude<keyof Handlers, keyof DeclaredHandlers<Contract> | '_'>, never>,\n): HandlerResult<Handlers>\nexport function matchFailure<Contract extends FailureContract, const Handlers extends object>(\n\terror: unknown,\n\tcontract: Contract,\n\thandlers: DeclaredHandlers<NoInfer<Contract>> &\n\t\tHandlers &\n\t\tRecord<Exclude<keyof Handlers, keyof DeclaredHandlers<Contract>>, never>,\n): HandlerResult<Handlers> | UnknownFailure\nexport function matchFailure<Contract extends FailureContract>(\n\terror: unknown,\n\tcontract: Contract,\n\thandlers: FailureHandlers<Contract>,\n): unknown {\n\tconst failure = decodeFailure(error, contract)\n\t// SAFETY: the checked declaration pairs each callback with its code; only the validated code selects it.\n\tconst callbacks = handlers as Record<\n\t\tstring,\n\t\t((failure: FailureOf<Contract>) => unknown) | undefined\n\t>\n\tconst handler =\n\t\tfailure._tag === 'DeclaredFailure' && Object.hasOwn(handlers, failure.code)\n\t\t\t? callbacks[failure.code]\n\t\t\t: undefined\n\treturn handler\n\t\t? handler(failure)\n\t\t: Object.hasOwn(handlers, '_') && callbacks._\n\t\t\t? callbacks._(failure)\n\t\t\t: failure\n}\n"],"mappings":"4CAYA,SAAgBA,EACf,EACA,EACsB,CACtB,IAAIC,EAAiD,CAAE,KAAM,iBAAkB,QAAS,CAAE,EAC1F,GAAI,CACCC,aAAiBC,IAAa,EAAUC,EAAS,OAAOF,EAAM,IAAI,EACvE,MAAQ,CAER,CAEA,OAAOD,CACR,CA8BA,SAAgBI,EACf,EACA,EACA,EACU,CACV,IAAMJ,EAAUD,EAAcE,EAAOE,CAAQ,EAEvCE,EAAYC,EAIZC,EACLP,EAAQ,OAAS,mBAAqB,OAAO,OAAOM,EAAUN,EAAQ,IAAI,EACvEK,EAAUL,EAAQ,MAClB,IAAA,GACJ,OAAOO,EACJA,EAAQP,CAAO,EACf,OAAO,OAAOM,EAAU,GAAG,GAAKD,EAAU,EACzCA,EAAU,EAAEL,CAAO,EACnBA,CACL"}
@@ -0,0 +1,47 @@
1
+ import { FilterAst } from "../querying/shared/ast.mjs";
2
+ import { FunctionArgs, FunctionReference, FunctionReturnType, PaginationOptions } from "convex/server";
3
+ import { Value } from "convex/values";
4
+ import { OptimisticLocalStore } from "convex/browser";
5
+ //#region src/react/optimistic.d.ts
6
+ type OptimisticQuery = FunctionReference<'query', 'public', {
7
+ paginationOpts: PaginationOptions;
8
+ }, {
9
+ page: Record<string, Value | undefined>[];
10
+ }>;
11
+ type RowOf<Query extends OptimisticQuery> = FunctionReturnType<Query>['page'][number];
12
+ type FieldOf<Query extends OptimisticQuery> = keyof RowOf<Query> & string;
13
+ export type OptimisticInterval = {
14
+ /** Bounds in declared sort order: lower exclusive, upper inclusive. Null attests an unbounded side. */
15
+ lower: readonly Value[] | null;
16
+ upper: readonly Value[] | null;
17
+ };
18
+ export type OptimisticOrder<Field extends string> = readonly {
19
+ field: Field;
20
+ direction: 'asc' | 'desc';
21
+ }[];
22
+ /** Shared server-owned semantics, never inferred from client filters or protected cursors. */
23
+ export type OptimisticListDescriptor<Query extends OptimisticQuery, Writable extends FieldOf<Query>, Id extends FieldOf<Query> = FieldOf<Query>> = {
24
+ id: Id;
25
+ writable: readonly Writable[];
26
+ /** Fields permitted by this args/session's output projection, including the ID. */
27
+ fields: (args: FunctionArgs<Query>) => readonly FieldOf<Query>[];
28
+ session: (args: FunctionArgs<Query>) => Value;
29
+ /** Known predicates may prove false even when other server logic remains undeclared. */
30
+ membership: (args: FunctionArgs<Query>) => {
31
+ predicate: FilterAst;
32
+ complete: boolean;
33
+ };
34
+ /** Complete, total server ordering, including tie breakers. Missing values remain unknown. */
35
+ order?: (args: FunctionArgs<Query>) => OptimisticOrder<FieldOf<Query>>;
36
+ /** An attested loaded interval, not a decoded cursor or a guessed first-page range. */
37
+ interval?: (args: FunctionArgs<Query>, page: FunctionReturnType<Query>) => OptimisticInterval | undefined;
38
+ };
39
+ export type OptimisticList<Query extends OptimisticQuery, Writable extends FieldOf<Query>, Id extends FieldOf<Query> = FieldOf<Query>> = {
40
+ patch: (store: OptimisticLocalStore, id: RowOf<Query>[Id], patch: Partial<Pick<RowOf<Query>, Writable>>) => void;
41
+ insert: (store: OptimisticLocalStore, row: RowOf<Query>) => void;
42
+ delete: (store: OptimisticLocalStore, id: RowOf<Query>[Id]) => void;
43
+ };
44
+ /** Call synchronously inside withOptimisticUpdate/useCommand. Convex owns replay and rollback. */
45
+ export declare function defineOptimisticList<Query extends OptimisticQuery, Writable extends FieldOf<Query>, Id extends FieldOf<Query>>(reference: Query, descriptor: OptimisticListDescriptor<Query, Writable, Id>): OptimisticList<Query, Writable, Id>;
46
+ //#endregion
47
+ //# sourceMappingURL=optimistic.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{evaluateFilter as e}from"../querying/shared/evaluate.mjs";import{compareValues as t,convexToJson as n}from"convex/values";function r(r,a){function o(o,s){let c=/* @__PURE__ */ new Map;for(let{args:e,value:t}of o.getAllQueries(r)){if(t===void 0)continue;let{paginationOpts:r,...i}=e,o=JSON.stringify(n([i,a.session(e)])),s=c.get(o)??[];s.push({args:e,value:t,rows:t.page}),c.set(o,s)}let l=s.kind===`insert`?s.row[a.id]:s.id,u=e=>t(e[a.id],l)===0;for(let l of c.values()){let c=l.flatMap(e=>e.rows.filter(u).map(t=>({entry:e,row:t})))[0],d,f=!1;if(s.kind===`insert`)c||(d=s.row);else if(s.kind===`patch`){for(let t of l){let n=new Set(a.fields(t.args));t.rows=t.rows.flatMap(r=>{if(!u(r))return[r];let i={...r};for(let e of a.writable)!Object.is(e,a.id)&&n.has(e)&&Object.hasOwn(r,e)&&Object.hasOwn(s.patch,e)&&(i[e]=s.patch[e]);let{predicate:o}=a.membership(t.args),c=new Set(Object.keys(r).filter(e=>n.has(e)));return e(o,i,c)===!1?[]:[i]})}if(c){let e=a.order?.(c.entry.args),n=c.entry.rows.find(u);n&&e?.length&&e.every(({field:e})=>Object.hasOwn(c.row,e)&&c.row[e]!==void 0&&a.fields(c.entry.args).includes(e))&&e.some(({field:e})=>t(c.row[e],n[e])!==0)&&(d=n)}}else for(let e of l)e.rows=e.rows.filter(e=>!u(e));if(d){let t=!1,n=l.flatMap(n=>{let r=new Set(a.fields(n.args)),o=n.value.page.find(u)?n.rows.find(u):d;if(!o)return[];let s=Object.fromEntries(Object.entries(o).filter(([e])=>r.has(e))),{predicate:c,complete:l}=a.membership(n.args),f=a.order?.(n.args),p=a.interval?.(n.args,n.value),m=new Set(Object.keys(s)),h=e(c,s,m);if(h===!1)return[];if(!m.has(a.id)||s[a.id]===void 0||!f?.length||!p||!f.every(({field:e})=>m.has(e)&&s[e]!==void 0))return t=!0,[];let g=f.map(({field:e})=>s[e]);return p.lower&&(p.lower.length!==f.length||i(g,p.lower,f)<=0)||p.upper&&(p.upper.length!==f.length||i(g,p.upper,f)>0)?[]:!l||h!==!0||!n.rows.every(e=>f.every(({field:t})=>r.has(t)&&Object.hasOwn(e,t)&&e[t]!==void 0))?(t=!0,[]):[{entry:n,projected:s,order:f}]});if(!t&&n.length===1){f=!0;let{entry:e,projected:t,order:r}=n[0];for(let e of l)e.rows=e.rows.filter(e=>!u(e));let a=e.rows.findIndex(e=>i(r.map(({field:e})=>t[e]),r.map(({field:t})=>e[t]),r)<0);e.rows=[...e.rows.slice(0,a<0?e.rows.length:a),t,...a<0?[]:e.rows.slice(a)]}}for(let e of l){let t=/* @__PURE__ */ new Set,i=e.rows.filter(e=>{if(!f&&(s.kind===`insert`||!u(e)))return!0;let r=JSON.stringify(n(e[a.id]??null));return!t.has(r)&&(t.add(r),!0)});i.length===e.value.page.length&&i.every((t,n)=>t===e.value.page[n])||o.setQuery(r,e.args,{...e.value,page:i})}}}return{patch:(e,t,n)=>o(e,{kind:`patch`,id:t,patch:n}),insert:(e,t)=>o(e,{kind:`insert`,row:t}),delete:(e,t)=>o(e,{kind:`delete`,id:t})}}function i(e,n,r){for(let i=0;i<r.length;i++){let a=t(e[i],n[i]);if(a)return r[i].direction===`asc`?a:-a}return 0}export{r as defineOptimisticList};
2
+ //# sourceMappingURL=optimistic.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimistic.mjs","names":["defineOptimisticList","apply","groups","store","reference","value","_pagination","rest","args","key","convexToJson","descriptor","group","id","change","matches","compareValues","row","source","entry","candidate","placed","fields","next","field","accessible","evaluateFilter","predicate","order","uncertainDestination","destinations","localCandidate","projected","interval","membership","compareKeys","complete","page","index","seen","rows","i","compared","left","right"],"sources":["../../src/react/optimistic.ts"],"sourcesContent":["import type { OptimisticLocalStore } from 'convex/browser'\nimport type {\n\tFunctionArgs,\n\tFunctionReference,\n\tFunctionReturnType,\n\tPaginationOptions,\n} from 'convex/server'\nimport { compareValues, convexToJson, type Value } from 'convex/values'\nimport { evaluateFilter } from '../querying/shared/evaluate'\nimport type { FilterAst } from '../querying/shared/ast'\n\ntype OptimisticQuery = FunctionReference<\n\t'query',\n\t'public',\n\t{ paginationOpts: PaginationOptions },\n\t{ page: Record<string, Value | undefined>[] }\n>\ntype RowOf<Query extends OptimisticQuery> = FunctionReturnType<Query>['page'][number]\ntype FieldOf<Query extends OptimisticQuery> = keyof RowOf<Query> & string\nexport type OptimisticInterval = {\n\t/** Bounds in declared sort order: lower exclusive, upper inclusive. Null attests an unbounded side. */\n\tlower: readonly Value[] | null\n\tupper: readonly Value[] | null\n}\nexport type OptimisticOrder<Field extends string> = readonly {\n\tfield: Field\n\tdirection: 'asc' | 'desc'\n}[]\n/** Shared server-owned semantics, never inferred from client filters or protected cursors. */\nexport type OptimisticListDescriptor<\n\tQuery extends OptimisticQuery,\n\tWritable extends FieldOf<Query>,\n\tId extends FieldOf<Query> = FieldOf<Query>,\n> = {\n\tid: Id\n\twritable: readonly Writable[]\n\t/** Fields permitted by this args/session's output projection, including the ID. */\n\tfields: (args: FunctionArgs<Query>) => readonly FieldOf<Query>[]\n\tsession: (args: FunctionArgs<Query>) => Value\n\t/** Known predicates may prove false even when other server logic remains undeclared. */\n\tmembership: (args: FunctionArgs<Query>) => { predicate: FilterAst; complete: boolean }\n\t/** Complete, total server ordering, including tie breakers. Missing values remain unknown. */\n\torder?: (args: FunctionArgs<Query>) => OptimisticOrder<FieldOf<Query>>\n\t/** An attested loaded interval, not a decoded cursor or a guessed first-page range. */\n\tinterval?: (\n\t\targs: FunctionArgs<Query>,\n\t\tpage: FunctionReturnType<Query>,\n\t) => OptimisticInterval | undefined\n}\nexport type OptimisticList<\n\tQuery extends OptimisticQuery,\n\tWritable extends FieldOf<Query>,\n\tId extends FieldOf<Query> = FieldOf<Query>,\n> = {\n\tpatch: (\n\t\tstore: OptimisticLocalStore,\n\t\tid: RowOf<Query>[Id],\n\t\tpatch: Partial<Pick<RowOf<Query>, Writable>>,\n\t) => void\n\tinsert: (store: OptimisticLocalStore, row: RowOf<Query>) => void\n\tdelete: (store: OptimisticLocalStore, id: RowOf<Query>[Id]) => void\n}\n\n/** Call synchronously inside withOptimisticUpdate/useCommand. Convex owns replay and rollback. */\nexport function defineOptimisticList<\n\tQuery extends OptimisticQuery,\n\tWritable extends FieldOf<Query>,\n\tId extends FieldOf<Query>,\n>(\n\treference: Query,\n\tdescriptor: OptimisticListDescriptor<Query, Writable, Id>,\n): OptimisticList<Query, Writable, Id> {\n\ttype Row = RowOf<Query>\n\ttype Change =\n\t\t| { kind: 'patch'; id: Row[Id]; patch: Partial<Pick<Row, Writable>> }\n\t\t| { kind: 'insert'; row: Row }\n\t\t| { kind: 'delete'; id: Row[Id] }\n\tfunction apply(store: OptimisticLocalStore, change: Change): void {\n\t\tconst groups = new Map<\n\t\t\tstring,\n\t\t\t{ args: FunctionArgs<Query>; value: FunctionReturnType<Query>; rows: Row[] }[]\n\t\t>()\n\t\tfor (const { args, value } of store.getAllQueries(reference)) {\n\t\t\tif (value === undefined) continue\n\t\t\tconst { paginationOpts: _pagination, ...rest } = args\n\t\t\t// SAFETY: Convex query arguments contain only Convex values; only pagination transport was omitted.\n\t\t\tconst key = JSON.stringify(\n\t\t\t\tconvexToJson([rest as Record<string, Value>, descriptor.session(args)]),\n\t\t\t)\n\t\t\tconst group = groups.get(key) ?? []\n\t\t\tgroup.push({ args, value, rows: value.page })\n\t\t\tgroups.set(key, group)\n\t\t}\n\t\tconst id = change.kind === 'insert' ? change.row[descriptor.id] : change.id\n\t\tconst matches = (row: Row) => compareValues(row[descriptor.id], id) === 0\n\t\tfor (const group of groups.values()) {\n\t\t\tconst source = group.flatMap((entry) =>\n\t\t\t\tentry.rows.filter(matches).map((row) => ({ entry, row })),\n\t\t\t)[0]\n\t\t\tlet candidate: Row | undefined\n\t\t\tlet placed = false\n\t\t\tif (change.kind === 'insert') {\n\t\t\t\tif (!source) candidate = change.row\n\t\t\t} else if (change.kind === 'patch') {\n\t\t\t\tfor (const entry of group) {\n\t\t\t\t\tconst fields = new Set(descriptor.fields(entry.args))\n\t\t\t\t\tentry.rows = entry.rows.flatMap((row) => {\n\t\t\t\t\t\tif (!matches(row)) return [row]\n\t\t\t\t\t\tconst next = { ...row }\n\t\t\t\t\t\tfor (const field of descriptor.writable) {\n\t\t\t\t\t\t\t// A patch cannot turn a hidden/absent output field into knowledge or expose an ID change.\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!Object.is(field, descriptor.id) &&\n\t\t\t\t\t\t\t\tfields.has(field) &&\n\t\t\t\t\t\t\t\tObject.hasOwn(row, field) &&\n\t\t\t\t\t\t\t\tObject.hasOwn(change.patch, field)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tnext[field] = change.patch[field]!\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst { predicate } = descriptor.membership(entry.args)\n\t\t\t\t\t\tconst accessible = new Set(Object.keys(row).filter((field) => fields.has(field)))\n\t\t\t\t\t\tif (evaluateFilter(predicate, next, accessible) === false) return []\n\t\t\t\t\t\treturn [next]\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tif (source) {\n\t\t\t\t\tconst order = descriptor.order?.(source.entry.args)\n\t\t\t\t\tconst next = source.entry.rows.find(matches)\n\t\t\t\t\t// Never infer rank from a field that was absent before the patch.\n\t\t\t\t\tif (\n\t\t\t\t\t\tnext &&\n\t\t\t\t\t\torder?.length &&\n\t\t\t\t\t\torder.every(\n\t\t\t\t\t\t\t({ field }) =>\n\t\t\t\t\t\t\t\tObject.hasOwn(source.row, field) &&\n\t\t\t\t\t\t\t\tsource.row[field] !== undefined &&\n\t\t\t\t\t\t\t\tdescriptor.fields(source.entry.args).includes(field),\n\t\t\t\t\t\t) &&\n\t\t\t\t\t\torder.some(({ field }) => compareValues(source.row[field], next[field]) !== 0)\n\t\t\t\t\t)\n\t\t\t\t\t\tcandidate = next\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (const entry of group) entry.rows = entry.rows.filter((row) => !matches(row))\n\t\t\t}\n\t\t\tif (candidate) {\n\t\t\t\tlet uncertainDestination = false\n\t\t\t\tconst destinations = group.flatMap((entry) => {\n\t\t\t\t\tconst fields = new Set(descriptor.fields(entry.args))\n\t\t\t\t\tconst existing = entry.value.page.find(matches)\n\t\t\t\t\t// An existing copy owns its field knowledge, including fields absent through redaction.\n\t\t\t\t\tconst localCandidate = existing ? entry.rows.find(matches) : candidate\n\t\t\t\t\tif (!localCandidate) return []\n\t\t\t\t\t// SAFETY: selecting only permitted DTO fields preserves their original values and never merges projections.\n\t\t\t\t\tconst projected = Object.fromEntries(\n\t\t\t\t\t\tObject.entries(localCandidate).filter(([field]) => fields.has(field)),\n\t\t\t\t\t) as Row\n\t\t\t\t\tconst { predicate, complete } = descriptor.membership(entry.args)\n\t\t\t\t\tconst order = descriptor.order?.(entry.args)\n\t\t\t\t\tconst interval = descriptor.interval?.(entry.args, entry.value)\n\t\t\t\t\tconst accessible = new Set(Object.keys(projected))\n\t\t\t\t\tconst membership = evaluateFilter(predicate, projected, accessible)\n\t\t\t\t\tif (membership === false) return []\n\t\t\t\t\tif (\n\t\t\t\t\t\t!accessible.has(descriptor.id) ||\n\t\t\t\t\t\tprojected[descriptor.id] === undefined ||\n\t\t\t\t\t\t!order?.length ||\n\t\t\t\t\t\t!interval ||\n\t\t\t\t\t\t!order.every(({ field }) => accessible.has(field) && projected[field] !== undefined)\n\t\t\t\t\t) {\n\t\t\t\t\t\tuncertainDestination = true\n\t\t\t\t\t\treturn []\n\t\t\t\t\t}\n\t\t\t\t\tconst key = order.map(({ field }) => projected[field]!)\n\t\t\t\t\tif (\n\t\t\t\t\t\t(interval.lower &&\n\t\t\t\t\t\t\t(interval.lower.length !== order.length ||\n\t\t\t\t\t\t\t\tcompareKeys(key, interval.lower, order) <= 0)) ||\n\t\t\t\t\t\t(interval.upper &&\n\t\t\t\t\t\t\t(interval.upper.length !== order.length ||\n\t\t\t\t\t\t\t\tcompareKeys(key, interval.upper, order) > 0))\n\t\t\t\t\t)\n\t\t\t\t\t\treturn []\n\t\t\t\t\tif (\n\t\t\t\t\t\t!complete ||\n\t\t\t\t\t\tmembership !== true ||\n\t\t\t\t\t\t!entry.rows.every((row) =>\n\t\t\t\t\t\t\torder.every(\n\t\t\t\t\t\t\t\t({ field }) =>\n\t\t\t\t\t\t\t\t\tfields.has(field) && Object.hasOwn(row, field) && row[field] !== undefined,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t) {\n\t\t\t\t\t\tuncertainDestination = true\n\t\t\t\t\t\treturn []\n\t\t\t\t\t}\n\t\t\t\t\treturn [{ entry, projected, order }]\n\t\t\t\t})\n\t\t\t\t// Overlapping parent/split subscriptions are not evidence of a unique destination.\n\t\t\t\tif (!uncertainDestination && destinations.length === 1) {\n\t\t\t\t\tplaced = true\n\t\t\t\t\tconst { entry, projected, order } = destinations[0]\n\t\t\t\t\tfor (const page of group) page.rows = page.rows.filter((row) => !matches(row))\n\t\t\t\t\tconst index = entry.rows.findIndex(\n\t\t\t\t\t\t(row) =>\n\t\t\t\t\t\t\tcompareKeys(\n\t\t\t\t\t\t\t\torder.map(({ field }) => projected[field]!),\n\t\t\t\t\t\t\t\torder.map(({ field }) => row[field]!),\n\t\t\t\t\t\t\t\torder,\n\t\t\t\t\t\t\t) < 0,\n\t\t\t\t\t)\n\t\t\t\t\tentry.rows = [\n\t\t\t\t\t\t...entry.rows.slice(0, index < 0 ? entry.rows.length : index),\n\t\t\t\t\t\tprojected,\n\t\t\t\t\t\t...(index < 0 ? [] : entry.rows.slice(index)),\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const entry of group) {\n\t\t\t\tconst seen = new Set<string>()\n\t\t\t\tconst rows = entry.rows.filter((row) => {\n\t\t\t\t\tif (!placed && (change.kind === 'insert' || !matches(row))) return true\n\t\t\t\t\tconst key = JSON.stringify(convexToJson(row[descriptor.id] ?? null))\n\t\t\t\t\tif (seen.has(key)) return false\n\t\t\t\t\tseen.add(key)\n\t\t\t\t\treturn true\n\t\t\t\t})\n\t\t\t\tif (\n\t\t\t\t\trows.length === entry.value.page.length &&\n\t\t\t\t\trows.every((row, i) => row === entry.value.page[i])\n\t\t\t\t)\n\t\t\t\t\tcontinue\n\t\t\t\tstore.setQuery(reference, entry.args, { ...entry.value, page: rows })\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tpatch: (store, id, patch) => apply(store, { kind: 'patch', id, patch }),\n\t\tinsert: (store, row) => apply(store, { kind: 'insert', row }),\n\t\tdelete: (store, id) => apply(store, { kind: 'delete', id }),\n\t}\n}\nfunction compareKeys(\n\tleft: readonly Value[],\n\tright: readonly Value[],\n\torder: OptimisticOrder<string>,\n): number {\n\tfor (let index = 0; index < order.length; index++) {\n\t\tconst compared = compareValues(left[index], right[index])\n\t\tif (compared) return order[index].direction === 'asc' ? compared : -compared\n\t}\n\treturn 0\n}\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ //#region src/react/pagination-state.d.ts
2
+ /** Pure interval controller. Keys include the epoch so late subscription results cannot enter a reset. */
3
+ export type ListPage = {
4
+ page: unknown[];
5
+ continueCursor: string;
6
+ isDone: boolean;
7
+ completeness?: string;
8
+ splitCursor?: string | null;
9
+ pageStatus?: 'SplitRecommended' | 'SplitRequired' | null;
10
+ paginationMode?: 'native-search';
11
+ };
12
+ type Interval<Page extends ListPage> = {
13
+ cursor: string | null;
14
+ endCursor?: string;
15
+ value?: Page;
16
+ children?: [string, string];
17
+ };
18
+ export type PaginationState<Page extends ListPage> = {
19
+ epoch: number;
20
+ identity: string;
21
+ restarted: boolean;
22
+ next: number;
23
+ order: string[];
24
+ intervals: Record<string, Interval<Page>>;
25
+ mode?: 'browse' | 'native-search';
26
+ error?: Error;
27
+ };
28
+ export declare function initialPagination<Page extends ListPage>(identity: string, epoch: number, skip: boolean, restarted?: boolean): PaginationState<Page>;
29
+ export declare function failPagination<Page extends ListPage>(state: PaginationState<Page>, error: Error): PaginationState<Page>;
30
+ export declare function reconcilePagination<Page extends ListPage>(state: PaginationState<Page>, results: Record<string, Page | Error | undefined>): PaginationState<Page>;
31
+ export declare function paginationView<Page extends ListPage>(state: PaginationState<Page>): {
32
+ rows: Page["page"][number][];
33
+ completeness: string | undefined;
34
+ isLoading: boolean;
35
+ isFetchingNextPage: boolean;
36
+ hasNextPage: boolean;
37
+ };
38
+ export declare function nextPagination<Page extends ListPage>(state: PaginationState<Page>): PaginationState<Page>;
39
+ //#endregion
40
+ //# sourceMappingURL=pagination-state.d.mts.map
@@ -0,0 +1,2 @@
1
+ function e(e,t,n,r=!1){let i=`${t}:0`;return{identity:e,epoch:t,restarted:r,next:1,order:n?[]:[i],intervals:n?{}:{[i]:{cursor:null}}}}function t(e,t){return{...e,order:[],intervals:{},error:t}}function n(e,n){if(e.error)return e;let r=!1,i={...e.intervals};for(let a of Object.keys(i)){let o=n[a];if(o instanceof Error)return t(e,o);o!==void 0&&o!==i[a].value&&(i[a]={...i[a],value:o},r=!0)}let a=i[e.order[0]]?.value,o=e.mode??(a?a.paginationMode??`browse`:void 0);for(let n of Object.values(i)){let r=n.value;if(r&&(r.paginationMode!==void 0&&r.paginationMode!==`native-search`||o!==void 0&&(r.paginationMode??`browse`)!==o||r.completeness===`searchSplitRequired`||o===`native-search`&&(r.pageStatus!=null||r.splitCursor!=null)))return t(e,/* @__PURE__ */ Error(`Invalid pagination protocol`))}let s=e.order,c=e.next;for(let n of e.order){let a=i[n],o=a.value;if(o){if(a.children)a.children.every(e=>i[e].value!==void 0)&&(s=s.flatMap(e=>e===n?a.children:[e]),delete i[n],r=!0);else if(o.pageStatus===`SplitRecommended`||o.pageStatus===`SplitRequired`){let s=o.splitCursor;if(!s||s===a.cursor||s===o.continueCursor||s===a.endCursor||o.continueCursor===a.cursor)return t(e,/* @__PURE__ */ Error(`Non-progressing pagination split`));let l=[`${e.epoch}:${c++}`,`${e.epoch}:${c++}`];i[n]={...a,children:l},i[l[0]]={cursor:a.cursor,endCursor:s},i[l[1]]={cursor:s,endCursor:a.endCursor??o.continueCursor},r=!0}else if(!o.isDone&&(!o.continueCursor||o.continueCursor===a.cursor))return t(e,/* @__PURE__ */ Error(`Non-progressing pagination cursor`))}}return r?{...e,mode:o,next:c,order:s,intervals:i}:e}function r(e){let t=[],n,r=!1;for(let i of e.order){let a=e.intervals[i];if(!a.value){r=!0;break}t.push(...a.value.page),n=a.value}let i=Object.values(e.intervals).some(e=>e.children!==void 0);return{rows:t,completeness:n?.completeness,isLoading:!e.error&&r&&n===void 0,isFetchingNextPage:!e.error&&(r&&n!==void 0||i),hasNextPage:!e.error&&!r&&!i&&n!==void 0&&!n.isDone}}function i(e){if(!r(e).hasNextPage)return e;let t=e.order[e.order.length-1],n=e.intervals[t],i=n.endCursor??n.value.continueCursor,a=`${e.epoch}:${e.next}`;return{...e,next:e.next+1,order:[...e.order,a],intervals:{...e.intervals,[t]:e.mode===`native-search`?n:{...n,endCursor:i},[a]:{cursor:i}}}}export{t as failPagination,e as initialPagination,i as nextPagination,r as paginationView,n as reconcilePagination};
2
+ //# sourceMappingURL=pagination-state.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination-state.mjs","names":["initialPagination","key","epoch","skip","failPagination","state","reconcilePagination","changed","intervals","value","results","first","mode","interval","order","next","child","item","split","children","paginationView","rows","latest","loading","splitting","nextPagination","lastKey","last","endCursor"],"sources":["../../src/react/pagination-state.ts"],"sourcesContent":["/** Pure interval controller. Keys include the epoch so late subscription results cannot enter a reset. */\nexport type ListPage = {\n\tpage: unknown[]\n\tcontinueCursor: string\n\tisDone: boolean\n\tcompleteness?: string\n\tsplitCursor?: string | null\n\tpageStatus?: 'SplitRecommended' | 'SplitRequired' | null\n\tpaginationMode?: 'native-search'\n}\ntype Interval<Page extends ListPage> = {\n\tcursor: string | null\n\tendCursor?: string\n\tvalue?: Page\n\tchildren?: [string, string]\n}\nexport type PaginationState<Page extends ListPage> = {\n\tepoch: number\n\tidentity: string\n\trestarted: boolean\n\tnext: number\n\torder: string[]\n\tintervals: Record<string, Interval<Page>>\n\tmode?: 'browse' | 'native-search'\n\terror?: Error\n}\nexport function initialPagination<Page extends ListPage>(\n\tidentity: string,\n\tepoch: number,\n\tskip: boolean,\n\trestarted = false,\n): PaginationState<Page> {\n\tconst key = `${epoch}:0`\n\treturn {\n\t\tidentity,\n\t\tepoch,\n\t\trestarted,\n\t\tnext: 1,\n\t\torder: skip ? [] : [key],\n\t\tintervals: skip ? {} : { [key]: { cursor: null } },\n\t}\n}\nexport function failPagination<Page extends ListPage>(\n\tstate: PaginationState<Page>,\n\terror: Error,\n): PaginationState<Page> {\n\treturn { ...state, order: [], intervals: {}, error }\n}\nexport function reconcilePagination<Page extends ListPage>(\n\tstate: PaginationState<Page>,\n\tresults: Record<string, Page | Error | undefined>,\n): PaginationState<Page> {\n\tif (state.error) return state\n\tlet changed = false\n\tconst intervals = { ...state.intervals }\n\tfor (const key of Object.keys(intervals)) {\n\t\tconst value = results[key]\n\t\tif (value instanceof Error) return failPagination(state, value)\n\t\tif (value !== undefined && value !== intervals[key].value) {\n\t\t\tintervals[key] = { ...intervals[key], value }\n\t\t\tchanged = true\n\t\t}\n\t}\n\t// The first result chooses the protocol for this epoch, including on reactive reruns.\n\tconst first = intervals[state.order[0]]?.value\n\tconst mode = state.mode ?? (first ? (first.paginationMode ?? 'browse') : undefined)\n\tfor (const interval of Object.values(intervals)) {\n\t\tconst value = interval.value\n\t\tif (!value) continue\n\t\tif (\n\t\t\t(value.paginationMode !== undefined && value.paginationMode !== 'native-search') ||\n\t\t\t(mode !== undefined && (value.paginationMode ?? 'browse') !== mode) ||\n\t\t\tvalue.completeness === 'searchSplitRequired' ||\n\t\t\t(mode === 'native-search' && (value.pageStatus != null || value.splitCursor != null))\n\t\t)\n\t\t\treturn failPagination(state, new Error('Invalid pagination protocol'))\n\t}\n\tlet order = state.order,\n\t\tnext = state.next\n\tfor (const key of state.order) {\n\t\tconst interval = intervals[key],\n\t\t\tvalue = interval.value\n\t\tif (!value) continue\n\t\tif (interval.children) {\n\t\t\tif (interval.children.every((child) => intervals[child].value !== undefined)) {\n\t\t\t\torder = order.flatMap((item) => (item === key ? interval.children! : [item]))\n\t\t\t\tdelete intervals[key]\n\t\t\t\tchanged = true\n\t\t\t}\n\t\t} else if (value.pageStatus === 'SplitRecommended' || value.pageStatus === 'SplitRequired') {\n\t\t\tconst split = value.splitCursor\n\t\t\tif (\n\t\t\t\t!split ||\n\t\t\t\tsplit === interval.cursor ||\n\t\t\t\tsplit === value.continueCursor ||\n\t\t\t\tsplit === interval.endCursor ||\n\t\t\t\tvalue.continueCursor === interval.cursor\n\t\t\t)\n\t\t\t\treturn failPagination(state, new Error('Non-progressing pagination split'))\n\t\t\tconst children: [string, string] = [`${state.epoch}:${next++}`, `${state.epoch}:${next++}`]\n\t\t\tintervals[key] = { ...interval, children }\n\t\t\tintervals[children[0]] = { cursor: interval.cursor, endCursor: split }\n\t\t\tintervals[children[1]] = {\n\t\t\t\tcursor: split,\n\t\t\t\tendCursor: interval.endCursor ?? value.continueCursor,\n\t\t\t}\n\t\t\tchanged = true\n\t\t} else if (\n\t\t\t!value.isDone &&\n\t\t\t(!value.continueCursor || value.continueCursor === interval.cursor)\n\t\t) {\n\t\t\treturn failPagination(state, new Error('Non-progressing pagination cursor'))\n\t\t}\n\t}\n\treturn changed ? { ...state, mode, next, order, intervals } : state\n}\nexport function paginationView<Page extends ListPage>(state: PaginationState<Page>) {\n\tconst rows: Page['page'][number][] = []\n\tlet latest: Page | undefined\n\tlet loading = false\n\tfor (const key of state.order) {\n\t\tconst interval = state.intervals[key]\n\t\tif (!interval.value) {\n\t\t\tloading = true\n\t\t\tbreak\n\t\t}\n\t\trows.push(...interval.value.page)\n\t\tlatest = interval.value\n\t}\n\tconst splitting = Object.values(state.intervals).some(\n\t\t(interval) => interval.children !== undefined,\n\t)\n\treturn {\n\t\trows,\n\t\tcompleteness: latest?.completeness,\n\t\tisLoading: !state.error && loading && latest === undefined,\n\t\tisFetchingNextPage: !state.error && ((loading && latest !== undefined) || splitting),\n\t\thasNextPage: !state.error && !loading && !splitting && latest !== undefined && !latest.isDone,\n\t}\n}\nexport function nextPagination<Page extends ListPage>(\n\tstate: PaginationState<Page>,\n): PaginationState<Page> {\n\tif (!paginationView(state).hasNextPage) return state\n\tconst lastKey = state.order[state.order.length - 1]\n\tconst last = state.intervals[lastKey]\n\tconst endCursor = last.endCursor ?? last.value!.continueCursor\n\tconst key = `${state.epoch}:${state.next}`\n\treturn {\n\t\t...state,\n\t\tnext: state.next + 1,\n\t\torder: [...state.order, key],\n\t\tintervals: {\n\t\t\t...state.intervals,\n\t\t\t// Fixed adjacent ranges keep reactive inserts/deletes from moving rows across a loaded boundary.\n\t\t\t// Native search windows are maintained by SDK journals; their original inputs stay immutable.\n\t\t\t[lastKey]: state.mode === 'native-search' ? last : { ...last, endCursor },\n\t\t\t[key]: { cursor: endCursor },\n\t\t},\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { FailureContract, FailureOf } from "./failures.mjs";
2
+ import { FunctionArgs, FunctionReference, FunctionReturnType, OptionalRestArgs } from "convex/server";
3
+ import { OptimisticUpdate } from "convex/browser";
4
+ //#region src/react/use-command.d.ts
5
+ export type CommandResult<Result, Contract extends FailureContract> = Readonly<{
6
+ ok: true;
7
+ value: Result;
8
+ }> | Readonly<{
9
+ ok: false;
10
+ failure: FailureOf<Contract>;
11
+ }>;
12
+ export type Command<Mutation extends FunctionReference<'mutation'>, Contract extends FailureContract> = ((...args: OptionalRestArgs<Mutation>) => Promise<CommandResult<FunctionReturnType<Mutation>, Contract>>) & {
13
+ readonly isPending: boolean;
14
+ /** The latest invocation's settled result; older concurrent completions cannot overwrite it. */
15
+ readonly result: CommandResult<FunctionReturnType<Mutation>, Contract> | undefined;
16
+ };
17
+ /** Explicit failures plus Convex-owned optimistic execution, replay and rollback. */
18
+ export declare function useCommand<Mutation extends FunctionReference<'mutation'>, Contract extends FailureContract, Update extends OptimisticUpdate<FunctionArgs<Mutation>> = OptimisticUpdate<FunctionArgs<Mutation>>>(reference: Mutation, options: {
19
+ errors: Contract;
20
+ optimisticUpdate?: Update & (ReturnType<Update> extends Promise<any> ? 'Optimistic update handlers must be synchronous' : {});
21
+ }): Command<Mutation, Contract>;
22
+ //#endregion
23
+ //# sourceMappingURL=use-command.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{decodeFailure as e}from"./failures.mjs";import{useCallback as t,useMemo as n,useRef as r,useState as i}from"react";import{useMutation as a}from"convex/react";function o(o,s){let c=a(o),{errors:l,optimisticUpdate:u}=s,d=n(()=>u?c.withOptimisticUpdate(u):c,[c,u]),[f,p]=i(0),[m,h]=i(),g=r(0),_=t(async(...t)=>{let n=++g.current;p(e=>e+1);let r;try{r={ok:!0,value:await d(...t)}}catch(t){r={ok:!1,failure:e(t,l)}}return p(e=>e-1),g.current===n&&h(r),r},[d,l]);return n(()=>Object.assign((...e)=>_(...e),{isPending:f>0,result:m}),[_,f,m])}export{o as useCommand};
2
+ //# sourceMappingURL=use-command.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-command.mjs","names":["useCommand","mutation","useMutation","reference","options","run","useMemo","optimisticUpdate","pending","setPending","useState","result","setResult","latest","useRef","execute","useCallback","args","invocation","count","settled","error","decodeFailure","errors"],"sources":["../../src/react/use-command.ts"],"sourcesContent":["import { useCallback, useMemo, useRef, useState } from 'react'\nimport { useMutation } from 'convex/react'\nimport type { OptimisticUpdate } from 'convex/browser'\nimport type {\n\tFunctionArgs,\n\tFunctionReference,\n\tFunctionReturnType,\n\tOptionalRestArgs,\n} from 'convex/server'\nimport { decodeFailure, type FailureContract, type FailureOf } from './failures'\n\nexport type CommandResult<Result, Contract extends FailureContract> =\n\t| Readonly<{ ok: true; value: Result }>\n\t| Readonly<{ ok: false; failure: FailureOf<Contract> }>\nexport type Command<\n\tMutation extends FunctionReference<'mutation'>,\n\tContract extends FailureContract,\n> = ((\n\t...args: OptionalRestArgs<Mutation>\n) => Promise<CommandResult<FunctionReturnType<Mutation>, Contract>>) & {\n\treadonly isPending: boolean\n\t/** The latest invocation's settled result; older concurrent completions cannot overwrite it. */\n\treadonly result: CommandResult<FunctionReturnType<Mutation>, Contract> | undefined\n}\n\n/** Explicit failures plus Convex-owned optimistic execution, replay and rollback. */\nexport function useCommand<\n\tMutation extends FunctionReference<'mutation'>,\n\tContract extends FailureContract,\n\tUpdate extends OptimisticUpdate<FunctionArgs<Mutation>> = OptimisticUpdate<\n\t\tFunctionArgs<Mutation>\n\t>,\n>(\n\treference: Mutation,\n\toptions: {\n\t\terrors: Contract\n\t\toptimisticUpdate?: Update &\n\t\t\t(ReturnType<Update> extends Promise<any>\n\t\t\t\t? 'Optimistic update handlers must be synchronous'\n\t\t\t\t: {})\n\t},\n): Command<Mutation, Contract> {\n\tconst mutation = useMutation(reference)\n\tconst { errors, optimisticUpdate } = options\n\t// Attach once per mutation/callback identity. Convex may invoke this callback repeatedly while pending.\n\tconst run = useMemo(\n\t\t() => (optimisticUpdate ? mutation.withOptimisticUpdate<Update>(optimisticUpdate) : mutation),\n\t\t[mutation, optimisticUpdate],\n\t)\n\tconst [pending, setPending] = useState(0)\n\tconst [result, setResult] = useState<CommandResult<FunctionReturnType<Mutation>, Contract>>()\n\tconst latest = useRef(0)\n\tconst execute = useCallback(\n\t\tasync (...args: OptionalRestArgs<Mutation>) => {\n\t\t\tconst invocation = ++latest.current\n\t\t\tsetPending((count) => count + 1)\n\t\t\tlet settled: CommandResult<FunctionReturnType<Mutation>, Contract>\n\t\t\ttry {\n\t\t\t\tsettled = { ok: true, value: await run(...args) }\n\t\t\t} catch (error) {\n\t\t\t\tsettled = { ok: false, failure: decodeFailure(error, errors) }\n\t\t\t}\n\t\t\tsetPending((count) => count - 1)\n\t\t\tif (latest.current === invocation) setResult(settled)\n\t\t\treturn settled\n\t\t},\n\t\t[run, errors],\n\t)\n\treturn useMemo(\n\t\t() =>\n\t\t\tObject.assign((...args: OptionalRestArgs<Mutation>) => execute(...args), {\n\t\t\t\tisPending: pending > 0,\n\t\t\t\tresult,\n\t\t\t}),\n\t\t[execute, pending, result],\n\t)\n}\n"],"mappings":"qKA0BA,SAAgBA,EAOf,EACA,EAO8B,CAC9B,IAAMC,EAAWC,EAAYC,CAAS,EAChC,CAAE,SAAQ,oBAAqBC,EAE/BC,EAAMC,MACJC,EAAmBN,EAAS,qBAA6BM,CAAgB,EAAIN,EACpF,CAACA,EAAUM,CAAgB,CAC5B,EACM,CAACC,EAASC,GAAcC,EAAS,CAAC,EAClC,CAACC,EAAQC,GAAaF,EAAgE,EACtFG,EAASC,EAAO,CAAC,EACjBC,EAAUC,EACf,MAAO,GAAGC,IAAqC,CAC9C,IAAMC,EAAa,EAAEL,EAAO,QAC5BJ,EAAY,GAAUU,EAAQ,CAAC,EAC/B,IAAIC,EACJ,GAAI,CACH,EAAU,CAAE,GAAI,GAAM,MAAO,MAAMf,EAAI,GAAGY,CAAI,CAAE,CACjD,OAASI,EAAO,CACf,EAAU,CAAE,GAAI,GAAO,QAASC,EAAcD,EAAOE,CAAM,CAAE,CAC9D,CAGA,OAFAd,EAAY,GAAUU,EAAQ,CAAC,EAC3BN,EAAO,UAAYK,GAAYN,EAAUQ,CAAO,EAC7CA,CACR,EACA,CAACf,EAAKkB,CAAM,CACb,EACA,OAAOjB,MAEL,OAAO,QAAQ,GAAGW,IAAqCF,EAAQ,GAAGE,CAAI,EAAG,CACxE,UAAWT,EAAU,EACrB,QACD,CAAC,EACF,CAACO,EAASP,EAASG,CAAM,CAC1B,CACD"}
@@ -0,0 +1,32 @@
1
+ import { queryErrors } from "../modules/contracts/errors.mjs";
2
+ import { FailureContract, FailureOf } from "./failures.mjs";
3
+ import { ListPage } from "./pagination-state.mjs";
4
+ import { FunctionArgs, FunctionReference, FunctionReturnType, PaginationOptions } from "convex/server";
5
+ import { Value } from "convex/values";
6
+ //#region src/react/use-paginated-list.d.ts
7
+ export type ListQueryReference = FunctionReference<'query', 'public', {
8
+ paginationOpts: PaginationOptions;
9
+ }, ListPage>;
10
+ export type PaginatedList<Query extends ListQueryReference, Contract extends FailureContract = typeof queryErrors> = {
11
+ rows: FunctionReturnType<Query>['page'];
12
+ isLoading: boolean;
13
+ hasNextPage: boolean;
14
+ isFetchingNextPage: boolean;
15
+ fetchNextPage: () => void;
16
+ resetKey: string;
17
+ completeness: FunctionReturnType<Query>['completeness'] | undefined;
18
+ failure: FailureOf<Contract> | undefined;
19
+ };
20
+ export type PaginatedListOptions<Contract extends FailureContract = typeof queryErrors> = {
21
+ /** Integer 1..100. Initial target for native search; browse uses fixed adjacent pages. */
22
+ pageSize: number;
23
+ onInvalidCursor?: 'restart' | 'throw';
24
+ /** Explicit server contract; generated references do not carry error metadata. Defaults to queryErrors. */
25
+ errors?: Contract;
26
+ /** Convex value identifying the current auth/scope/reset generation. Never a credential. */
27
+ resetIdentity?: Value;
28
+ };
29
+ /** Reactive engine-backed list: fixed browse ranges or SDK-journal search windows. Empty pages advance manually. */
30
+ export declare function usePaginatedList<Query extends ListQueryReference, Contract extends FailureContract = typeof queryErrors>(query: Query, args: Omit<FunctionArgs<Query>, 'paginationOpts'> | 'skip', options: PaginatedListOptions<Contract>): PaginatedList<Query, Contract>;
31
+ //#endregion
32
+ //# sourceMappingURL=use-paginated-list.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{queryErrors as e}from"../modules/contracts/errors.mjs";import{decodeFailure as t}from"./failures.mjs";import{initialPagination as n,nextPagination as r,paginationView as i,reconcilePagination as a}from"./pagination-state.mjs";import{getFunctionName as o}from"convex/server";import{convexToJson as s}from"convex/values";import{useMemo as c,useState as l}from"react";import{useQueries as u}from"convex/react";let d=0;function f(f,p,m){let{pageSize:h}=m;if(!Number.isInteger(h)||h<1||h>100)throw Error(`pageSize must be an integer from 1 to 100`);let g=p===`skip`,_=g?{}:p,v=JSON.stringify([o(f),s(_),s(m.resetIdentity??null),h,g]),[y,b]=l(()=>n(v,++d,g)),x=y;x.identity!==v&&(x=n(v,++d,g));let S=c(()=>Object.fromEntries(Object.entries(x.intervals).map(([e,t])=>{let n={numItems:h,cursor:t.cursor,id:x.epoch};return t.endCursor!==void 0&&(n.endCursor=t.endCursor),[e,{query:f,args:{..._,paginationOpts:n}}]})),[x.intervals,x.epoch,v]),C=u(S);x=a(x,C);let w=m.errors??e,T=x.error?t(x.error,w):void 0,E=x.error?t(x.error,e):void 0,D=x.error&&T?._tag===`DeclaredFailure`&&T.code===`invalid-cursor`&&E?._tag===`DeclaredFailure`&&E.code===`invalid-cursor`;if(D&&m.onInvalidCursor!==`throw`&&!x.restarted&&(x=n(v,++d,g,!0),T=void 0),x!==y&&b(x),D&&m.onInvalidCursor===`throw`)throw x.error;let O=i(x),k=x.epoch;return{...O,rows:O.rows,completeness:O.completeness,failure:T,resetKey:`${v}:${+!!x.restarted}`,fetchNextPage:()=>b(e=>e.epoch===k&&e.identity===v?r(e):e)}}export{f as usePaginatedList};
2
+ //# sourceMappingURL=use-paginated-list.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-paginated-list.mjs","names":["epoch","usePaginatedList","options","pageSize","skip","args","effectiveArgs","identity","getFunctionName","query","convexToJson","stored","setState","useState","initialPagination","state","queries","useMemo","key","interval","paginationOpts","results","useQueries","reconcilePagination","errors","queryErrors","failure","decodeFailure","queryFailure","invalid","view","paginationView","currentEpoch","previous","nextPagination"],"sources":["../../src/react/use-paginated-list.ts"],"sourcesContent":["import { useMemo, useState } from 'react'\nimport { useQueries } from 'convex/react'\nimport {\n\tgetFunctionName,\n\ttype FunctionArgs,\n\ttype FunctionReference,\n\ttype FunctionReturnType,\n\ttype PaginationOptions,\n} from 'convex/server'\nimport { convexToJson, type Value } from 'convex/values'\nimport { queryErrors } from '../modules/contracts/errors'\nimport { decodeFailure, type FailureContract, type FailureOf } from './failures'\nimport {\n\tinitialPagination,\n\treconcilePagination,\n\tnextPagination,\n\tpaginationView,\n\ttype ListPage,\n} from './pagination-state'\n\nexport type ListQueryReference = FunctionReference<\n\t'query',\n\t'public',\n\t{ paginationOpts: PaginationOptions },\n\tListPage\n>\nexport type PaginatedList<\n\tQuery extends ListQueryReference,\n\tContract extends FailureContract = typeof queryErrors,\n> = {\n\trows: FunctionReturnType<Query>['page']\n\tisLoading: boolean\n\thasNextPage: boolean\n\tisFetchingNextPage: boolean\n\tfetchNextPage: () => void\n\tresetKey: string\n\tcompleteness: FunctionReturnType<Query>['completeness'] | undefined\n\tfailure: FailureOf<Contract> | undefined\n}\nexport type PaginatedListOptions<Contract extends FailureContract = typeof queryErrors> = {\n\t/** Integer 1..100. Initial target for native search; browse uses fixed adjacent pages. */\n\tpageSize: number\n\tonInvalidCursor?: 'restart' | 'throw'\n\t/** Explicit server contract; generated references do not carry error metadata. Defaults to queryErrors. */\n\terrors?: Contract\n\t/** Convex value identifying the current auth/scope/reset generation. Never a credential. */\n\tresetIdentity?: Value\n}\ntype IntervalPagination = {\n\tnumItems: number\n\tcursor: string | null\n\tid: number\n\tendCursor?: string\n}\nlet epoch = 0\n/** Reactive engine-backed list: fixed browse ranges or SDK-journal search windows. Empty pages advance manually. */\nexport function usePaginatedList<\n\tQuery extends ListQueryReference,\n\tContract extends FailureContract = typeof queryErrors,\n>(\n\tquery: Query,\n\targs: Omit<FunctionArgs<Query>, 'paginationOpts'> | 'skip',\n\toptions: PaginatedListOptions<Contract>,\n): PaginatedList<Query, Contract> {\n\tconst { pageSize } = options\n\tif (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > 100)\n\t\tthrow new Error('pageSize must be an integer from 1 to 100')\n\tconst skip = args === 'skip'\n\t// Convex's public encoder sorts object keys recursively and preserves array order, IDs, bytes and int64.\n\t// SAFETY: FunctionArgs are Convex values; pagination transport is owned exclusively by this hook.\n\tconst effectiveArgs = skip ? {} : (args as Record<string, Value>)\n\tconst identity = JSON.stringify([\n\t\tgetFunctionName(query),\n\t\tconvexToJson(effectiveArgs),\n\t\tconvexToJson(options.resetIdentity ?? null),\n\t\tpageSize,\n\t\tskip,\n\t])\n\tconst [stored, setState] = useState(() =>\n\t\tinitialPagination<FunctionReturnType<Query>>(identity, ++epoch, skip),\n\t)\n\tlet state = stored\n\tif (state.identity !== identity) state = initialPagination(identity, ++epoch, skip)\n\tconst queries = useMemo(\n\t\t() =>\n\t\t\tObject.fromEntries(\n\t\t\t\tObject.entries(state.intervals).map(([key, interval]) => {\n\t\t\t\t\tconst paginationOpts: IntervalPagination = {\n\t\t\t\t\t\tnumItems: pageSize,\n\t\t\t\t\t\tcursor: interval.cursor,\n\t\t\t\t\t\tid: state.epoch,\n\t\t\t\t\t}\n\t\t\t\t\tif (interval.endCursor !== undefined) paginationOpts.endCursor = interval.endCursor\n\t\t\t\t\treturn [key, { query, args: { ...effectiveArgs, paginationOpts } }]\n\t\t\t\t}),\n\t\t\t),\n\t\t// Equivalent args/references must keep subscriptions stable; identity encodes their effective values.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t\t[state.intervals, state.epoch, identity],\n\t)\n\t// SAFETY: useQueries returns each complete endpoint result or an Error for the keyed subscription.\n\tconst results = useQueries(queries) as Record<\n\t\tstring,\n\t\tFunctionReturnType<Query> | Error | undefined\n\t>\n\tstate = reconcilePagination(state, results)\n\tconst errors = options.errors ?? queryErrors\n\tlet failure = state.error ? decodeFailure(state.error, errors) : undefined\n\t// Both the explicit decoder and the fixed query contract must validate the actual transported envelope.\n\tconst queryFailure = state.error ? decodeFailure(state.error, queryErrors) : undefined\n\tconst invalid =\n\t\tstate.error &&\n\t\tfailure?._tag === 'DeclaredFailure' &&\n\t\tfailure.code === 'invalid-cursor' &&\n\t\tqueryFailure?._tag === 'DeclaredFailure' &&\n\t\tqueryFailure.code === 'invalid-cursor'\n\tif (invalid && options.onInvalidCursor !== 'throw' && !state.restarted) {\n\t\tstate = initialPagination(identity, ++epoch, skip, true)\n\t\tfailure = undefined\n\t}\n\tif (state !== stored) setState(state)\n\tif (invalid && options.onInvalidCursor === 'throw') throw state.error\n\tconst view = paginationView(state)\n\tconst currentEpoch = state.epoch\n\treturn {\n\t\t...view,\n\t\t// SAFETY: the controller concatenates unmodified elements from this query's validated page DTOs.\n\t\trows: view.rows as FunctionReturnType<Query>['page'],\n\t\tcompleteness: view.completeness,\n\t\t// SAFETY: omitted errors selects the default Contract parameter; an explicit contract owns its decoder.\n\t\tfailure: failure as FailureOf<Contract> | undefined,\n\t\tresetKey: `${identity}:${state.restarted ? 1 : 0}`,\n\t\tfetchNextPage: () =>\n\t\t\tsetState((previous) =>\n\t\t\t\tprevious.epoch === currentEpoch && previous.identity === identity\n\t\t\t\t\t? nextPagination(previous)\n\t\t\t\t\t: previous,\n\t\t\t),\n\t}\n}\n"],"mappings":"8ZAsDA,IAAIA,EAAQ,EAEZ,SAAgBC,EAIf,EACA,EACA,EACiC,CACjC,GAAM,CAAE,YAAaC,EACrB,GAAI,CAAC,OAAO,UAAUC,CAAQ,GAAKA,EAAW,GAAKA,EAAW,IAC7D,MAAU,MAAM,2CAA2C,EAC5D,IAAMC,EAAOC,IAAS,OAGhBC,EAAgBF,EAAO,CAAC,EAAKC,EAC7BE,EAAW,KAAK,UAAU,CAC/BC,EAAgBC,CAAK,EACrBC,EAAaJ,CAAa,EAC1BI,EAAaR,EAAQ,eAAiB,IAAI,EAC1CC,EACAC,CACD,CAAC,EACK,CAACO,EAAQC,GAAYC,MAC1BC,EAA6CP,EAAU,EAAEP,EAAOI,CAAI,CACrE,EACIW,EAAQJ,EACRI,EAAM,WAAaR,IAAU,EAAQO,EAAkBP,EAAU,EAAEP,EAAOI,CAAI,GAClF,IAAMY,EAAUC,MAEd,OAAO,YACN,OAAO,QAAQF,EAAM,SAAS,CAAC,CAAC,KAAK,CAACG,EAAKC,KAAc,CACxD,IAAMC,EAAqC,CAC1C,SAAUjB,EACV,OAAQgB,EAAS,OACjB,GAAIJ,EAAM,KACX,EAEA,OADII,EAAS,YAAc,IAAA,KAAW,EAAe,UAAYA,EAAS,WACnE,CAACD,EAAK,CAAE,QAAO,KAAM,CAAE,GAAGZ,EAAe,gBAAe,CAAE,CAAC,CACnE,CAAC,CACF,EAGD,CAACS,EAAM,UAAWA,EAAM,MAAOR,CAAQ,CACxC,EAEMc,EAAUC,EAAWN,CAAO,EAIlC,EAAQO,EAAoBR,EAAOM,CAAO,EAC1C,IAAMG,EAAStB,EAAQ,QAAUuB,EAC7BC,EAAUX,EAAM,MAAQY,EAAcZ,EAAM,MAAOS,CAAM,EAAI,IAAA,GAE3DI,EAAeb,EAAM,MAAQY,EAAcZ,EAAM,MAAOU,CAAW,EAAI,IAAA,GACvEI,EACLd,EAAM,OACNW,GAAS,OAAS,mBAClBA,EAAQ,OAAS,kBACjBE,GAAc,OAAS,mBACvBA,EAAa,OAAS,iBAMvB,GALIC,GAAW3B,EAAQ,kBAAoB,SAAW,CAACa,EAAM,YAC5D,EAAQD,EAAkBP,EAAU,EAAEP,EAAOI,EAAM,EAAI,EACvD,EAAU,IAAA,IAEPW,IAAUJ,GAAQC,EAASG,CAAK,EAChCc,GAAW3B,EAAQ,kBAAoB,QAAS,MAAMa,EAAM,MAChE,IAAMe,EAAOC,EAAehB,CAAK,EAC3BiB,EAAejB,EAAM,MAC3B,MAAO,CACN,GAAGe,EAEH,KAAMA,EAAK,KACX,aAAcA,EAAK,aAEV,UACT,SAAU,GAAGvB,EAAS,GAAG,KAAM,YAC/B,kBACCK,EAAU,GACTqB,EAAS,QAAUD,GAAgBC,EAAS,WAAa1B,EACtD2B,EAAeD,CAAQ,EACvBA,CACJ,CACF,CACD"}
@@ -0,0 +1,6 @@
1
+ import { DeclaredFailure, DecodedFailure, ErrorContract, UnknownFailure, queryErrors } from "./modules/contracts/errors.mjs";
2
+ import { FailureHandlers, decodeFailure, matchFailure } from "./react/failures.mjs";
3
+ import { Command, CommandResult, useCommand } from "./react/use-command.mjs";
4
+ import { ListQueryReference, PaginatedList, PaginatedListOptions, usePaginatedList } from "./react/use-paginated-list.mjs";
5
+ import { OptimisticInterval, OptimisticList, OptimisticListDescriptor, OptimisticOrder, defineOptimisticList } from "./react/optimistic.mjs";
6
+ export { type Command, type CommandResult, type DeclaredFailure, type DecodedFailure, type ErrorContract, type FailureHandlers, type ListQueryReference, type OptimisticInterval, type OptimisticList, type OptimisticListDescriptor, type OptimisticOrder, type PaginatedList, type PaginatedListOptions, type UnknownFailure, decodeFailure, defineOptimisticList, matchFailure, queryErrors, useCommand, usePaginatedList };
package/dist/react.mjs ADDED
@@ -0,0 +1 @@
1
+ import{queryErrors as e}from"./modules/contracts/errors.mjs";import{decodeFailure as t,matchFailure as n}from"./react/failures.mjs";import{useCommand as r}from"./react/use-command.mjs";import{usePaginatedList as i}from"./react/use-paginated-list.mjs";import{defineOptimisticList as a}from"./react/optimistic.mjs";export{t as decodeFailure,a as defineOptimisticList,n as matchFailure,e as queryErrors,r as useCommand,i as usePaginatedList};
@@ -1,2 +1,2 @@
1
- import { BranchBuilder, FieldReference, RelationBuilder, RelationDeclarations, RelationEdge, RelationFilterSelection, RelationFilters, RelationRegistry, RelationRegistryIdentity, RelationRow, RelationSelection, RelationTable, RelationTableHelpers, RelationTables, ThroughReference, defineRelations } from "./relations.mjs";
2
- export { type BranchBuilder, type FieldReference, type RelationBuilder, type RelationDeclarations, type RelationEdge, type RelationFilterSelection, type RelationFilters, type RelationRegistry, type RelationRegistryIdentity, type RelationRow, type RelationSelection, type RelationTable, type RelationTableHelpers, type RelationTables, type ThroughReference, defineRelations };
1
+ import { BranchBuilder, FieldGroupMode, FieldGroupRequest, FieldReference, RelationBuilder, RelationDeclarations, RelationEdge, RelationFilterSelection, RelationFilters, RelationGroupSelection, RelationRegistry, RelationRegistryIdentity, RelationRow, RelationSelection, RelationTable, RelationTableHelpers, RelationTables, ThroughReference, defineRelations } from "./relations.mjs";
2
+ export { type BranchBuilder, type FieldGroupMode, type FieldGroupRequest, type FieldReference, type RelationBuilder, type RelationDeclarations, type RelationEdge, type RelationFilterSelection, type RelationFilters, type RelationGroupSelection, type RelationRegistry, type RelationRegistryIdentity, type RelationRow, type RelationSelection, type RelationTable, type RelationTableHelpers, type RelationTables, type ThroughReference, defineRelations };
@@ -1,6 +1,10 @@
1
- import { FieldSchemas, PaginationOptionsSchema, ScalarPredicate, ScalarSelection } from "./querying/filters.mjs";
1
+ import { FilterContract, SharedFilters } from "./querying/shared/contract.mjs";
2
+ import "./filters.mjs";
3
+ import { FieldSchemas } from "./querying/shared/filters.mjs";
4
+ import { PaginationOptionsSchema, ScalarPredicate, ScalarSelection } from "./querying/filters.mjs";
5
+ import { EnginePaginationResult } from "./zod-table.mjs";
2
6
  import { ConvexValidatorFromZod } from "convex-helpers/server/zod4";
3
- import { PaginationResult, TableDefinition } from "convex/server";
7
+ import { TableDefinition } from "convex/server";
4
8
  import { z } from "zod";
5
9
  import { GenericId, GenericValidator, ValidatorJSON } from "convex/values";
6
10
  //#region src/relations.d.ts
@@ -11,8 +15,48 @@ export interface RelationTable {
11
15
  publicDto: z.ZodObject | z.ZodDiscriminatedUnion<any, string>;
12
16
  table: TableDefinition;
13
17
  dto(includeId: true): z.ZodType;
18
+ /** Whole stored fields; schemas are captured from the native table, never a DTO transform. */
19
+ fieldGroups?: Readonly<Record<string, readonly string[]>>;
14
20
  }
15
21
  export type RelationTables = Record<string, RelationTable>;
22
+ export type FieldGroupMode = 'if-permitted' | 'required';
23
+ export type FieldGroupRequest<T extends RelationTable> = { [K in keyof NonNullable<T['fieldGroups']>]?: FieldGroupMode; };
24
+ /** Separate from relation keys so existing selection syntax remains unambiguous. */
25
+ export type RelationGroupSelection<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, L extends readonly 1[] = readonly [1, 1, 1, 1]> = {
26
+ fieldGroups?: FieldGroupRequest<Tables[T]>;
27
+ relations?: L extends readonly [] ? never : { [K in keyof Edges<D, T>]?: RelationGroupSelection<Tables, D, Extract<Target<Edges<D, T>[K]>, keyof Tables>, Tail<L>>; };
28
+ };
29
+ /** Internal admitted runtime tree, independent of user relation names. */
30
+ export interface GroupSelection {
31
+ fieldGroups?: Readonly<Record<string, FieldGroupMode>>;
32
+ relations?: Readonly<Record<string, GroupSelection>>;
33
+ }
34
+ export type ExactGroupSelection<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, G> = G & { [K in keyof G]: K extends 'fieldGroups' ? G[K] & { [N in keyof G[K]]: N extends keyof FieldGroupRequest<Tables[T]> ? FieldGroupMode : never; } : K extends 'relations' ? G[K] & { [N in keyof G[K]]: N extends keyof Edges<D, T> ? ExactGroupSelection<Tables, D, Extract<Target<Edges<D, T>[N]>, keyof Tables>, G[K][N]> : never; } : never; };
35
+ type StoredValue<V extends GenericValidator> = GenericValidator extends V ? V['type'] : V extends {
36
+ kind: 'object';
37
+ fields: infer F extends Record<string, GenericValidator>;
38
+ } ? { [K in keyof F as F[K]['isOptional'] extends 'optional' ? never : K]: StoredValue<F[K]>; } & { [K in keyof F as F[K]['isOptional'] extends 'optional' ? K : never]?: StoredValue<F[K]>; } : V extends {
39
+ kind: 'array';
40
+ element: infer E extends GenericValidator;
41
+ } ? StoredValue<E>[] : V extends {
42
+ kind: 'union';
43
+ members: infer M extends GenericValidator[];
44
+ } ? StoredValue<M[number]> : V extends {
45
+ kind: 'record';
46
+ key: infer K extends GenericValidator;
47
+ value: infer E extends GenericValidator;
48
+ } ? Record<Extract<K['type'], string>, StoredValue<E>> : V['type'];
49
+ type GroupStoredRow<T extends RelationTable, Row, Stored = StoredValue<ConvexValidatorFromZod<T['schema'], 'required'>>> = [Tags<T>] extends [never] ? Stored : Extract<Stored, Pick<Row, Extract<Discriminator<T>, keyof Row>>>;
50
+ type GroupFields<T extends RelationTable, G, Row> = T extends {
51
+ fieldGroups: infer Definitions extends Readonly<Record<string, readonly string[]>>;
52
+ } ? { [K in keyof G & keyof Definitions]: Pick<GroupStoredRow<T, Row>, Extract<Definitions[K][number], keyof GroupStoredRow<T, Row>>>; } : {};
53
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
54
+ type IncludedFields<T extends RelationTable, G, Row> = G extends {
55
+ fieldGroups: infer Requests;
56
+ } ? UnionToIntersection<{ [K in keyof Requests & keyof GroupFields<T, Requests, Row>]: Requests[K] extends 'required' ? GroupFields<T, Requests, Row>[K] : Partial<GroupFields<T, Requests, Row>[K]>; }[keyof Requests & keyof GroupFields<T, Requests, Row>]> : {};
57
+ type NestedGroups<G, K extends PropertyKey> = G extends {
58
+ relations: infer R;
59
+ } ? K extends keyof R ? R[K] : {} : {};
16
60
  /** Internal named declaration dependency; excluded from the supported relations facade. */
17
61
  export interface SelectionMask {
18
62
  [key: string]: true | SelectionMask;
@@ -133,12 +177,13 @@ type PublicRow<T extends RelationTable> = z.output<T['publicDto']> & {
133
177
  _id: GenericId<T['tableName']>;
134
178
  };
135
179
  export type ScopedRelationRow<Row, Scope extends string, Key extends PropertyKey> = [Scope] extends [never] ? Row : Extract<Row, Record<Key, Scope>>;
136
- type ComposeRelationRow<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S, Level extends readonly 1[], Row> = Row extends unknown ? Row & (Level extends readonly [] ? {} : { [K in keyof S]: K extends keyof Edges<D, T> ? Edges<D, T>[K] extends RelationEdge<string, infer Target, infer C, infer SourceScope, infer TargetScope> ? C extends 'one' ? ([SourceScope] extends [never] ? true : Row extends ScopedRelationRow<Row, SourceScope, Discriminator<Tables[T]>> ? true : false) extends true ? ScopedRelationRow<RelationRow<Tables, D, Extract<Target, keyof Tables>, S[K] extends true ? {} : S[K], Tail<Level>>, TargetScope, Discriminator<Tables[Extract<Target, keyof Tables>]>> | null : null : PaginationResult<ScopedRelationRow<RelationRow<Tables, D, Extract<Target, keyof Tables>, S[K] extends true ? {} : S[K], Tail<Level>>, TargetScope, Discriminator<Tables[Extract<Target, keyof Tables>]>>> : never : never; }) : never;
137
- export type RelationRow<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S, Level extends readonly 1[] = Depth> = ComposeRelationRow<Tables, D, T, S, Level, PublicRow<Tables[T]>>;
138
- export type RelationQueryRow<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S, Scope extends string = never> = ScopedRelationRow<RelationRow<Tables, D, T, S>, Scope, Discriminator<Tables[T]>>;
180
+ type ComposeRelationRow<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S, Level extends readonly 1[], Row, G = {}> = Row extends unknown ? Row & IncludedFields<Tables[T], G, Row> & (Level extends readonly [] ? {} : { [K in keyof S]: K extends keyof Edges<D, T> ? Edges<D, T>[K] extends RelationEdge<string, infer Target, infer C, infer SourceScope, infer TargetScope> ? C extends 'one' ? ([SourceScope] extends [never] ? true : Row extends ScopedRelationRow<Row, SourceScope, Discriminator<Tables[T]>> ? true : false) extends true ? ScopedRelationRow<RelationRow<Tables, D, Extract<Target, keyof Tables>, S[K] extends true ? {} : S[K], Tail<Level>, NestedGroups<G, K>>, TargetScope, Discriminator<Tables[Extract<Target, keyof Tables>]>> | null : null : EnginePaginationResult<ScopedRelationRow<RelationRow<Tables, D, Extract<Target, keyof Tables>, S[K] extends true ? {} : S[K], Tail<Level>, NestedGroups<G, K>>, TargetScope, Discriminator<Tables[Extract<Target, keyof Tables>]>>> : never : never; }) : never;
181
+ export type RelationRow<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S, Level extends readonly 1[] = Depth, G = {}> = ComposeRelationRow<Tables, D, T, S, Level, PublicRow<Tables[T]>, G>;
182
+ export type RelationQueryRow<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables, S, Scope extends string = never, G = {}> = ScopedRelationRow<RelationRow<Tables, D, T, S, Depth, G>, Scope, Discriminator<Tables[T]>>;
139
183
  export interface RelationTableHelpers<Tables extends RelationTables, D extends RelationDeclarations, T extends keyof Tables> {
184
+ filters<F extends Record<string, GenericValidator>>(contract: FilterContract<F>): PaginationOptionsSchema<SharedFilters<F>, SharedFilters<F, 'input'>>;
140
185
  paginationOpts<const S extends RelationFilterSelection<Tables, D, T>>(selection: ExactFilterMask<Tables, D, T, S>): PaginationOptionsSchema<RelationFilters<Tables, D, T, S>, RelationFilters<Tables, D, T, S, 'input'>>;
141
- pageDto<const S extends RelationSelection<Tables, D, T>>(selection: ExactOutputMask<Tables, D, T, S>): z.ZodType<PaginationResult<RelationRow<Tables, D, T, S>>>;
186
+ pageDto<const S extends RelationSelection<Tables, D, T>, const G extends RelationGroupSelection<Tables, D, T> = {}>(selection: ExactOutputMask<Tables, D, T, S>, groups?: ExactGroupSelection<Tables, D, T, G>): z.ZodType<EnginePaginationResult<RelationRow<Tables, D, T, S, Depth, G>>>;
142
187
  }
143
188
  export interface RelationRegistryIdentity {
144
189
  readonly identity: string;
@@ -156,7 +201,15 @@ export interface RelationFieldMetadata {
156
201
  readonly idTables: readonly string[];
157
202
  readonly native: Readonly<ValidatorJSON>;
158
203
  }
204
+ export interface SearchIndexMetadata {
205
+ readonly name: string;
206
+ readonly searchField: string;
207
+ readonly filterFields: readonly string[];
208
+ readonly staged: boolean;
209
+ }
159
210
  export interface RelationTableMetadata {
211
+ readonly searchIndexes: readonly SearchIndexMetadata[];
212
+ readonly fieldGroups: Readonly<Record<string, readonly string[]>>;
160
213
  readonly fields: Readonly<Record<string, RelationFieldMetadata>>;
161
214
  readonly variant?: {
162
215
  readonly discriminator: string;
@@ -176,12 +229,14 @@ export declare function defineRelations<const Tables extends RelationTables, con
176
229
  /** Internal owned executor bridge. Source ownership is checked once by each engine. */
177
230
  export declare function getRelationExecutor(registry: RelationRegistryIdentity): Readonly<{
178
231
  streamSchema: import("convex/server").SchemaDefinition<import("convex/server").GenericSchema, boolean>;
232
+ groups(table: string, groups: GroupSelection): GroupSelection;
179
233
  validateDocument: (table: string, row: Record<string, import('convex/values').Value>) => void;
180
234
  assertSchema: (tables: Readonly<Record<string, TableDefinition>>) => void;
181
235
  pagination(table: string): z.ZodObject<{
182
236
  cursor: z.ZodUnion<readonly [z.ZodString, z.ZodNull]>;
183
237
  endCursor: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>;
184
238
  id: z.ZodOptional<z.ZodNumber>;
239
+ onEmptyBudget: z.ZodOptional<z.ZodLiteral<"split">>;
185
240
  numItems: z.ZodNumber;
186
241
  maximumRowsRead: z.ZodOptional<z.ZodNumber>;
187
242
  maximumBytesRead: z.ZodOptional<z.ZodNumber>;
@@ -192,7 +247,7 @@ export declare function getRelationExecutor(registry: RelationRegistryIdentity):
192
247
  }>>;
193
248
  }, z.core.$strict>;
194
249
  select(table: string, selection: SelectionMask): void;
195
- project(table: string, row: Record<string, import('convex/values').Value>, eligible: () => boolean): Record<string, unknown> | null;
250
+ project(table: string, row: Record<string, import('convex/values').Value>, eligible: () => boolean, groups?: readonly string[]): Record<string, unknown> | null;
196
251
  }>;
197
252
  /** Internal compiler/engine adapter. Registry identity alone cannot forge a registry. */
198
253
  export declare function getRelationMetadata(registry: RelationRegistryIdentity): RelationMetadata;
@@ -1,2 +1,2 @@
1
- import{nativePagination as e,relationFilterSchema as t,scalarPredicateSchema as n}from"./querying/filters.mjs";import{paginated as r}from"./zod-table.mjs";import{captureDto as i,materializeDto as a}from"./querying/schema-snapshot.mjs";import{convexToZod as o,zodToConvex as s}from"convex-helpers/server/zod4";import{defineSchema as c,defineTable as l}from"convex/server";import{z as u}from"zod";import{v as d}from"convex/values";const f=i(e),p=Symbol(`relationField`),m=Symbol(`relationEdge`),h=/* @__PURE__ */ new WeakMap,g=/* @__PURE__ */ new WeakMap,_=/* @__PURE__ */ new WeakMap,v=/* @__PURE__ */ new WeakMap,y=/* @__PURE__ */ new WeakSet,b=/* @__PURE__ */ new WeakSet,x=u.object({indexes:u.array(u.object({indexDescriptor:u.string(),fields:u.array(u.string())}))});function S(e,n){let o={},m={},S=/* @__PURE__ */ new Set,C=/* @__PURE__ */ new Map,w={},T={},k={};for(let[t,n]of Object.entries(e)){if(n.tableName!==t||[`one`,`many`,`__proto__`,`constructor`,`prototype`].includes(t))throw Error(`Invalid relation table "${t}"`);let e=Object.getOwnPropertyDescriptor(n,`table`);if(!e||!(`value`in e))throw Error(`Unsupported native table accessor`);let r=e.value;ee(r),X(n.schema,`stored`),X(n.publicDto,`dto`);let c=n.dto(!0);if(!(c instanceof u.ZodObject)&&!(c instanceof u.ZodDiscriminatedUnion))throw Error(`Expected object or discriminated union DTO`);X(c,`dto`);let l=i(c),f=a(l);if(!(f instanceof u.ZodObject)&&!(f instanceof u.ZodDiscriminatedUnion))throw Error(`Expected object or discriminated union DTO`);let h=V(r);W(h.documentType);let g=R(t,n.schema,f,h.documentType),b=x.parse(h).indexes.map(e=>({name:e.indexDescriptor,fields:[...e.fields]})).sort((e,t)=>e.name.localeCompare(t.name));W(H(s(f))),m[t]=r,o[t]={...g,indexes:b,dto:f,dtoRecipe:l};let E=(e,n)=>{let r=Object.create(null);function i(e,r,a){let s={[p]:void 0,table:t,field:e,guard:n,forTable(t){if(n)throw Error(`forTable on branch-scoped fields is unsupported`);if(!A(r)?.includes(t))throw Error(`Invalid native ID member selection`);if(!Object.hasOwn(o,t))throw Error(`Native ID member table is not registered`);let a=Q(r)?d.union(d.id(t),d.null()):d.id(t);return i(e,r.isOptional===`optional`?d.optional(a):a,Object.freeze({table:t}))},through(e){if(a||v.has(e))throw Error(`forTable with through is unsupported`);let t=_.get(e);if(!S.has(e)||!t||!j(r,t))throw Error(`Invalid junction field or registry`);let n=Object.freeze({base:s,junction:e});return y.add(n),n}};return _.set(s,r),a&&v.set(s,a),S.add(s),Object.freeze(s)}for(let[t,n]of Object.entries(e))r[t]=i(t,n);return Object.freeze(r)};if(w[t]=E(g.fields),g.branches)for(let[e,n]of Object.entries(g.branches.options))C.set(JSON.stringify([t,e]),E(n.fields,Object.freeze({discriminator:g.branches.discriminator,tag:e})));T[t]=e=>O(t,`one`,e,S),k[t]=e=>O(t,`many`,e,S)}let M=n(Object.freeze({...w,one:Object.freeze(T),many:Object.freeze(k)}),((e,t)=>{let n=C.get(JSON.stringify([e,t]));if(!n)throw Error(`Unknown variant scope "${e}.${t}"`);return n})),P=Object.fromEntries(Object.entries(M).map(([e,t])=>[e,Object.freeze({...t})]));Object.freeze(P);for(let[e,t]of Object.entries(P)){if(!Object.hasOwn(o,e))throw Error(`Unknown source table "${e}"`);for(let[n,r]of Object.entries(t)){if(o[e].allFields.has(n)||o[e].branches&&[`variant`,`variants`].includes(n)||[`and`,`or`,`not`,`fields`,`then`,`__proto__`,`constructor`,`prototype`].includes(n))throw Error(`Relation name collision "${n}"`);if(!b.has(r)||!S.has(D(r.from))||!S.has(D(r.to))||r.source!==e)throw Error(`Relation source bucket mismatch`);N(r,o)}}let z={metadata:o,declarations:P},B={};for(let e of Object.keys(o))B[e]={paginationOpts(n){return E(n),a(f).extend({filters:t(I(z,e,n)).optional(),order:u.enum([`asc`,`desc`]).optional()})},pageDto(t){return E(t),r(L(z,e,t)).result}};let G=JSON.stringify([2,Object.entries(o).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,Object.entries(t.fields).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,t.isOptional,H(t)]),t.branches?[t.branches.discriminator,Object.entries(t.branches.options).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,Object.entries(t.fields).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,t.isOptional,H(t)])])]:null,t.indexes,U(H(s(t.dto)))]),Object.entries(P).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,Object.entries(t).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,t.cardinality,t.target,F(t.from),F(t.to)])])]),K=Object.freeze({identity:G,version:1,tables:Object.freeze(B)});h.set(K,Z(z));let q={};for(let[e,t]of Object.entries(o)){let n=l({});for(let e of t.indexes){let[t,...r]=e.fields;if(t===void 0)throw Error(`Invalid empty active index`);n.index(e.name,[t,...r])}let r=Object.getOwnPropertyDescriptor(n,`indexes`).value;for(let e of r)Object.freeze(e.fields),Object.freeze(e);Object.freeze(r),Object.freeze(n),q[e]=n}return g.set(K,{internal:z,nativeTables:Object.freeze(m),streamSchema:c(Object.freeze(q))}),K}function C(e){let r=g.get(e);if(!r)throw Error(`Unknown relation registry`);let i=e=>{let t=Object.keys(r.nativeTables);if(t.length!==Reflect.ownKeys(e).length||t.some(t=>{let n=Object.getOwnPropertyDescriptor(e,t);return!n||!(`value`in n)||n.value!==r.nativeTables[t]}))throw Error(`Native schema/table ownership disagrees with relation registry`)},s=/* @__PURE__ */ new WeakMap,c=/* @__PURE__ */ new WeakMap,l=/* @__PURE__ */ new Map,p=/* @__PURE__ */ new Map,m=/* @__PURE__ */ new WeakMap;function h(e,t){let n=r.internal.metadata[e];if(!n)throw Error(`Unknown query table`);if(!n.branches)return;let i=t[n.branches.discriminator],a=typeof i==`string`&&Object.hasOwn(n.branches.options,i)?n.branches.options[i]:void 0;if(!a)throw Error(`Invalid variant document`);let c=s.get(a),l=c?.fieldKeys??Object.keys(a.fields),u=[];for(let e of l)Object.hasOwn(t,e)&&u.push([e,void 0]);for(let e of u)e[1]=t[e[0]];let f=Object.fromEntries(u);c||(c={validator:o(d.object(a.fields)),fieldKeys:l},s.set(a,c)),c.validator.parse(f)}return Object.freeze({streamSchema:r.streamSchema,validateDocument:h,assertSchema:i,pagination(e){let i=r.internal;function o(e,t,r){let a=JSON.stringify([e,t,r??null]),s=p.get(a);if(s)return s;let c=i.metadata[e];if(!c)throw Error(`Unknown query table`);let u=JSON.stringify([e,r??null]),d=l.get(u);if(!d){d={};for(let[e,t]of Object.entries(r===void 0?c.fields:c.branches.options[r].fields))T(t)&&(d[e]=n(t).optional());l.set(u,d)}let f={fields:d,variants:c.branches&&r===void 0&&t<4?{discriminator:c.branches.discriminator,options:Object.fromEntries(Object.keys(c.branches.options).map(n=>[n,o(e,t+1,n)]))}:void 0,relations:t>=4?{}:Object.fromEntries(Object.entries(i.declarations[e]??{}).map(([e,n])=>[e,{cardinality:n.cardinality,target:o(n.target,t+1)}]))};return p.set(a,f),f}return a(f).extend({filters:t(o(e,0),m).optional(),order:u.enum([`asc`,`desc`]).optional()})},select(e,t){E(t);function n(e,t,i){if(!Object.hasOwn(r.internal.metadata,e))throw Error(`Unknown query table`);for(let[a,o]of Object.entries(t)){let t=r.internal.declarations[e]?.[a];if(!t||i>=4)throw Error(`Unknown or too deep relation "${e}.${a}"`);o!==!0&&n(t.target,o,i+1)}}n(e,t,0)},project(e,t,n){if(!n())return null;let i=r.internal.metadata[e];if(!i)throw Error(`Unknown query table`);let a=i.branches?i.branches.options[String(t[i.branches.discriminator])]:void 0;if(i.branches&&!a)throw Error(`Invalid variant document`);let o=a?.dto??i.dto;if(!(o instanceof u.ZodObject))throw Error(`Invalid variant DTO`);h(e,t);let s=c.get(o);return s||(s=Object.keys(o.shape),c.set(o,s)),o.parse(Object.fromEntries(s.filter(e=>Object.hasOwn(t,e)).map(e=>[e,t[e]])))}})}function w(e){let t=h.get(e);if(!t)throw Error(`Unknown relation registry`);return t}function T(e){return[`id`,`string`,`float64`,`int64`,`boolean`,`null`,`literal`].includes(e.kind)||e.kind===`union`&&e.members.every(T)}function E(e){let t=[{value:e,depth:0,ancestors:[]}],n=0;for(;t.length;){let{value:e,depth:r,ancestors:i}=t.pop();if(++n>256||r>4||i.includes(e))throw Error(`Selection cycle or depth/node budget exceeded`);let a=Object.getPrototypeOf(e);if(a!==Object.prototype&&a!==null)throw Error(`Invalid selection`);let o=Reflect.ownKeys(e);if(o.length+n+t.length>256)throw Error(`Selection node budget exceeded`);for(let a of o){let o=Object.getOwnPropertyDescriptor(e,a);if(!o.enumerable||!(`value`in o)||String(a)!==a)throw Error(`Invalid selection property`);if(o.value!==!0)t.push({value:o.value,depth:r+1,ancestors:[...i,e]});else if(++n>256)throw Error(`Selection node budget exceeded`)}}}function D(e){return`base`in e?e.base:e}function O(e,t,n,r){for(let e of[n.from,n.to])if(!r.has(D(e))||`base`in e&&(!y.has(e)||!r.has(e.junction)))throw Error(`Foreign registry or invalid field reference`);if(D(n.to).table!==e)throw Error(`Wrong relation target table`);let i=Object.freeze({[m]:!0,source:D(n.from).table,target:e,cardinality:t,from:n.from,to:n.to,sourceGuard:D(n.from).guard,targetGuard:D(n.to).guard,junctionGuard:k(n.from,n.to),sourceMember:v.get(D(n.from)),targetMember:v.get(D(n.to))});return b.add(i),i}function k(e,t){let n=`base`in e?e.junction.guard:void 0,r=`base`in t?t.junction.guard:void 0;if(n&&r&&(n.discriminator!==r.discriminator||n.tag!==r.tag))throw Error(`Contradictory junction scopes`);return n??r}function A(e){if(e.kind===`id`)return[e.tableName];if(e.kind===`null`)return[];if(e.kind!==`union`)return null;let t=e.members.map(A);return t.some(e=>e===null)?null:[...new Set(t.flatMap(e=>e))].sort()}function j(e,t){let n=M(e);return n.length>0&&JSON.stringify(n)===JSON.stringify(M(t))}function M(e){if(e.kind===`union`)return[...new Set(e.members.flatMap(M))].sort();if(e.kind===`null`)return[];if(![`id`,`string`,`float64`,`int64`,`boolean`,`literal`].includes(e.kind))throw Error(`Unsupported relation field kind`);return[JSON.stringify(H(e))]}function N(e,t){let n=e.from,r=e.to;if(`base`in n!=`base`in r)throw Error(`Both relation legs must use through`);if(`base`in n&&`base`in r){if(n.junction.table!==r.junction.table)throw Error(`Different junction tables`);P(t,n.junction.table,n.junction.field,e.junctionGuard),P(t,e.target,r.base.field,e.targetGuard);return}if(!j(_.get(D(n)),_.get(D(r))))throw Error(`Incompatible relation field types`);P(t,e.target,D(r).field,e.targetGuard)}function P(e,t,n,r){if(n!==`_id`&&!e[t].indexes.some(e=>{let t=e.fields.indexOf(n);return t>=0&&e.fields.slice(0,t).every(e=>e===r?.discriminator)}))throw Error(`No active index begins with or has a guarded prefix for "${t}.${n}"`)}function F(e){return`base`in e?[e.base.table,e.base.field,e.base.guard??null,e.junction.table,e.junction.field,e.junction.guard??null]:v.has(e)?[e.table,e.field,e.guard??null,v.get(e)]:[e.table,e.field,e.guard??null]}function I(e,t,r,i=0,a){let o={},s={},c=e.metadata[t],l={};for(let[u,d]of Object.entries(r)){if(u===`variants`&&d!==!0&&c.branches&&a===void 0){if(i>=4)throw Error(`Invalid variant selection`);for(let[n,a]of Object.entries(d)){if(!Object.hasOwn(c.branches.options,n)||a===!0)throw Error(`Unknown variant filter selection`);l[n]=I(e,t,{...Object.fromEntries(Object.entries(r).filter(([e])=>e!==`variants`)),...a},i+1,n)}continue}let f=(a===void 0?c.fields:c.branches.options[a].fields)[u],p=e.declarations[t]?.[u];if(d===!0&&f)o[u]=n(f).optional();else if(d!==!0&&p&&i<4)s[u]={cardinality:p.cardinality,target:I(e,p.target,d,i+1)};else throw Error(`Invalid relation filter selection "${t}.${u}"`)}return{fields:o,relations:s,variants:c.branches&&a===void 0?{discriminator:c.branches.discriminator,options:l}:void 0}}function L(e,t,n,i=0){let o={};for(let[s,c]of Object.entries(n)){let n=e.declarations[t]?.[s];if(!n||i>=4)throw Error(`Unknown or too deep relation "${t}.${s}"`);let l=c===!0?a(e.metadata[n.target].dtoRecipe):L(e,n.target,c,i+1);if(n.targetGuard){if(!(l instanceof u.ZodDiscriminatedUnion))throw Error(`Invalid target scope`);l=l.options.filter(e=>e instanceof u.ZodObject).find(e=>e.shape[n.targetGuard.discriminator]instanceof u.ZodLiteral&&e.shape[n.targetGuard.discriminator].value===n.targetGuard.tag)}o[s]=n.cardinality===`one`?l.nullable():r(l).result}let s=e.metadata[t],c=a(s.dtoRecipe);function l(n,r){let i={...o};for(let n of Object.keys(i)){let a=e.declarations[t][n];a.sourceGuard&&r!==a.sourceGuard.tag&&a.cardinality===`one`&&(i[n]=u.null())}return n.extend(i).strict()}if(s.branches){if(!(c instanceof u.ZodDiscriminatedUnion))throw Error(`Invalid variant DTO`);let e=c.options.map(e=>{if(!(e instanceof u.ZodObject))throw Error(`Invalid variant DTO`);let t=e.shape[s.branches.discriminator];if(!(t instanceof u.ZodLiteral))throw Error(`Invalid variant tag`);return l(e,String(t.value))});return u.discriminatedUnion(s.branches.discriminator,[e[0],...e.slice(1)])}if(!(c instanceof u.ZodObject))throw Error(`Expected object DTO`);return l(c)}function R(e,t,n,r){if(t instanceof u.ZodObject&&n instanceof u.ZodObject){let n=s(t).fields;return G(e,n,r),{fields:n,allFields:new Set(Object.keys(n))}}if(!(t instanceof u.ZodDiscriminatedUnion)||!(n instanceof u.ZodDiscriminatedUnion))throw Error(`Expected matching discriminated union boundaries "${e}"`);let i=t._zod.def.discriminator;if(n._zod.def.discriminator!==i)throw Error(`DTO discriminator mismatch`);function a(e){let t=Object.create(null);for(let n of e.options){if(!(n instanceof u.ZodObject))throw Error(`Variant branches must be objects`);let e=n.shape[i];if(!(e instanceof u.ZodLiteral)||e.values.size!==1)throw Error(`Variant tags must be unique required string literals`);let r=u.string().safeParse(e.value);if(!r.success||Object.hasOwn(t,r.data))throw Error(`Variant tags must be unique required string literals`);t[r.data]=n}if(Object.keys(t).length===0)throw Error(`Expected at least one variant branch`);return t}let o=a(t),c=a(n);if(Object.keys(o).sort().join(`\0`)!==Object.keys(c).sort().join(`\0`))throw Error(`DTO variant tags mismatch`);let l={discriminator:i,options:Object.create(null)},f=[];for(let[t,n]of Object.entries(o)){let r=s(n).fields,{_id:i,_creationTime:a,...o}=r;G(e,r,H(d.object(o))),f.push(d.object(o)),l.options[t]={fields:r,dto:c[t]}}if(U(r)!==U(H(d.union(...f))))throw Error(`Native stored document disagrees with boundary "${e}"`);let p=Object.values(l.options).map(e=>e.fields),m={};for(let e of Object.keys(p[0])){if(!p.every(t=>Object.hasOwn(t,e))||e!==i&&!p.every(t=>z(t[e],p[0][e])))continue;let t=p.map(t=>t[e]),n=d.union(...t);m[e]=t.some(e=>e.isOptional===`optional`)?d.optional(n):n}return{fields:m,branches:l,allFields:new Set(p.flatMap(e=>Object.keys(e)))}}function z(e,t){try{return j(e,t)}catch{return U(H(e))===U(H(t))}}const B=/* @__PURE__ */ new Map;for(let e of[l(d.object({})),d.id(`sample`),d.null(),d.number(),d.int64(),d.commitTs(),d.boolean(),d.string(),d.bytes(),d.any(),d.object({}),d.literal(`sample`),d.array(d.string()),d.record(d.string(),d.string()),d.union(d.string(),d.null())]){let t=Object.getPrototypeOf(e);for(;t&&t!==Object.prototype;)B.has(t)||B.set(t,Object.getOwnPropertyDescriptors(t)),t=Object.getPrototypeOf(t)}function ee(e){let t=/* @__PURE__ */ new Set,n=/* @__PURE__ */ new Set;function r(e,i,a=!1){if(n.has(e))throw Error(`Unsupported cyclic native schema`);if(t.has(e))return;if(i>64||t.size>=8192)throw Error(`Native schema graph budget exceeded`);t.add(e),n.add(e);let o=Object.getPrototypeOf(e),s=o&&B.get(o);if(o!==null&&o!==Object.prototype&&o!==Array.prototype&&!s)throw Error(`Unsupported native schema prototype`);if(Object.getOwnPropertySymbols(e).length)throw Error(`Unsupported native schema symbol`);let c=Object.getOwnPropertyNames(e).map(t=>Object.getOwnPropertyDescriptor(e,t));if(!a&&c.some(e=>!(`value`in e)||e.value instanceof Function))throw Error(`Unsupported native schema accessor or method`);if(s){let e=Object.getOwnPropertyNames(o);if(e.length!==Object.getOwnPropertyNames(s).length||e.some(e=>{let t=Object.getOwnPropertyDescriptor(o,e),n=Object.getOwnPropertyDescriptor(s,e)?.value;return!n||!Object.is(t.value,n.value)||t.get!==n.get||t.set!==n.set}))throw Error(`Unsupported native schema prototype mutation`);r(o,i+1,!0)}if(!a)for(let e of c)e.value!==null&&Object(e.value)===e.value&&r(e.value,i+1);n.delete(e)}r(e,0)}function V(e){return e.export()}function H(e){return e.json}function U(e){if(Array.isArray(e))return`[${e.map(U).join(`,`)}]`;if(e!==null&&Object(e)===e){let t=e;return`{${Object.keys(t).sort().map(e=>`${JSON.stringify(e)}:${U(t[e])}`).join(`,`)}}`}return JSON.stringify(e)}function W(e){if(e===null||Object(e)!==e)return;let t=e;if(t.type===`any`)throw Error(`Unsupported native validation form`);for(let e of Object.values(t))W(e)}function G(e,t,n){let{_id:r,_creationTime:i,...a}=t;if(!r||!i||U(H(r))!==U(H(d.id(e)))||U(H(i))!==U(H(d.number()))||r.isOptional!==`required`||i.isOptional!==`required`||U(n)!==U(H(d.object(a))))throw Error(`Native stored document disagrees with boundary "${e}"`)}const K=u.object({field:u.string()}),q=new Set([K,K.pick({field:!0}),K.omit({field:!0}),K.extend({other:u.string()}),K.safeExtend({other:u.string()}),K.merge(u.object({other:u.string()})),K.partial(),K.required()].flatMap(e=>{let t=Object.getOwnPropertyDescriptor(e._zod.def,`shape`)?.get;return t?[Function.prototype.toString.call(t)]:[]})),J=Function.prototype.toString.call(Object.getOwnPropertyDescriptor(u.string().default(``)._zod.def,`defaultValue`).get),Y=Function.prototype.toString.call(Object.getOwnPropertyDescriptor(u.string().prefault(``)._zod.def,`defaultValue`).get);function X(e,t){let n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Set,i=/* @__PURE__ */ new Set,a=/* @__PURE__ */ new Set;function o(e,s){if(i.has(e))throw Error(`Unsupported cyclic DTO schema`);if(!r.has(e)){if(s>32||r.size>=4096)throw Error(`DTO schema graph budget exceeded`);r.add(e),i.add(e);try{let r=Object.getOwnPropertyDescriptor(e,`_zod`);if(r){if(!(`value`in r))throw Error(`Unsupported DTO schema accessor`);let e=Object.getOwnPropertyDescriptor(r.value,`def`);if(!e||!(`value`in e))throw Error(`Unsupported DTO schema accessor`)}if(e instanceof u.core.$ZodCheck&&!(e instanceof u.core.$ZodType)){if(t===`dto`&&e._zod.def.check===`overwrite`)throw Error(`Unsupported DTO overwrite check`);o(e._zod.def,s+1);return}if(e instanceof u.core.$ZodType){let r=e._zod.def;if(t===`dto`&&(![`object`,`array`,`optional`,`nullable`,`nonoptional`,`union`,`intersection`,`tuple`,`record`,`string`,`number`,`boolean`,`bigint`,`null`,`never`,`custom`,`literal`,`enum`].includes(r.type)||`coerce`in r&&r.coerce))throw Error(`Unsupported DTO schema "${r.type}"`);if(t===`stored`&&(r.type==="default"||r.type===`prefault`)){let e=Object.getOwnPropertyDescriptor(r,`defaultValue`);if(e?.get){if(e.set||Function.prototype.toString.call(e.get)!==(r.type==="default"?J:Y))throw Error(`Unsupported stored schema accessor`);n.add(r)}}if(e instanceof u.ZodUnion&&o(e.options,s+1),r.type===`object`){let t=Object.getOwnPropertyDescriptor(r,`shape`);if(t?.get){if(t.set||!q.has(Function.prototype.toString.call(t.get)))throw Error(`Unsupported DTO schema accessor`);let e=r.shape;o(e,s+1),a.add(r)}if(e instanceof u.ZodObject){let t=Object.getOwnPropertyDescriptor(e,`shape`);if(t&&!(`value`in t))throw Error(`Unsupported DTO schema accessor`);o(e.shape,s+1)}}o(r,s+1);return}let i=Reflect.ownKeys(e),c=i.map(t=>Object.getOwnPropertyDescriptor(e,t));if(c.some((t,r)=>!(`value`in t)&&!(a.has(e)&&i[r]===`shape`)&&!(n.has(e)&&i[r]===`defaultValue`)))throw Error(`Unsupported DTO schema accessor`);for(let e of c)e.value!==null&&Object(e.value)===e.value&&!(e.value instanceof Function)&&o(e.value,s+1)}finally{i.delete(e)}}}o(e,0)}function Z(e){let t={};for(let[n,r]of Object.entries(e.metadata)){let e={};for(let[t,n]of Object.entries(r.fields))e[t]=Object.freeze({kind:n.kind,optional:n.isOptional===`optional`,nullable:Q(n),idTables:Object.freeze($(n)),native:te(H(n))});t[n]=Object.freeze({fields:Object.freeze(e),variant:r.branches?Object.freeze({discriminator:r.branches.discriminator,tags:Object.freeze(Object.keys(r.branches.options))}):void 0,indexes:Object.freeze(r.indexes.map(e=>Object.freeze({name:e.name,fields:Object.freeze([...e.fields])})))})}return Object.freeze({tables:Object.freeze(t),declarations:e.declarations})}function Q(e){return e.kind===`null`||e.kind===`union`&&e.members.some(Q)}function $(e){return e.kind===`id`?[e.tableName]:e.kind===`union`?[...new Set(e.members.flatMap($))].sort():[]}function te(e){let t=structuredClone(e),n=[t];for(;n.length;){let e=n.pop();if(Object(e)!==e)continue;let t=e;Object.freeze(t),n.push(...Object.values(t))}return t}export{S as defineRelations,C as getRelationExecutor,w as getRelationMetadata};
1
+ import{relationFilterSchema as e}from"./querying/shared/filters.mjs";import{zodToConvex as t}from"./zod-convex.mjs";import{nativePagination as n,scalarPredicateSchema as r}from"./querying/filters.mjs";import{paginated as i}from"./zod-table.mjs";import{captureDto as a,materializeDto as o}from"./querying/schema-snapshot.mjs";import{convexToZod as s}from"convex-helpers/server/zod4";import{defineSchema as c,defineTable as l}from"convex/server";import{z as u}from"zod";import{v as d}from"convex/values";const f=a(n),p=Symbol(`relationField`),m=Symbol(`relationEdge`),h=/* @__PURE__ */ new WeakMap,g=/* @__PURE__ */ new WeakMap,_=/* @__PURE__ */ new WeakMap,v=/* @__PURE__ */ new WeakMap,y=/* @__PURE__ */ new WeakSet,b=/* @__PURE__ */ new WeakSet,x=u.object({indexDescriptor:u.string(),searchField:u.string(),filterFields:u.array(u.string())}),S=u.object({searchIndexes:u.array(x),stagedSearchIndexes:u.array(x),indexes:u.array(u.object({indexDescriptor:u.string(),fields:u.array(u.string())}))});function C(n,r){let m={},x={},C=/* @__PURE__ */ new Set,w=/* @__PURE__ */ new Map,T={},O={},k={};for(let[e,r]of Object.entries(n)){if(r.tableName!==e||[`one`,`many`,`__proto__`,`constructor`,`prototype`].includes(e))throw Error(`Invalid relation table "${e}"`);let n=Object.getOwnPropertyDescriptor(r,`table`);if(!n||!(`value`in n))throw Error(`Unsupported native table accessor`);let i=n.value;G(i),Z(r.schema,`stored`),Z(r.publicDto,`dto`);let c=r.dto(!0);if(!(c instanceof u.ZodObject)&&!(c instanceof u.ZodDiscriminatedUnion))throw Error(`Expected object or discriminated union DTO`);Z(c,`dto`);let l=a(c),f=o(l);if(!(f instanceof u.ZodObject)&&!(f instanceof u.ZodDiscriminatedUnion))throw Error(`Expected object or discriminated union DTO`);let h=ee(i);J(h.documentType);let g=H(e,r.schema,f,h.documentType),b=S.parse(h),D=Object.freeze([...b.searchIndexes.map(e=>({...e,staged:!1})),...b.stagedSearchIndexes.map(e=>({...e,staged:!0}))].map(e=>Object.freeze({name:e.indexDescriptor,searchField:e.searchField,filterFields:Object.freeze([...e.filterFields].sort()),staged:e.staged})).sort((e,t)=>e.name.localeCompare(t.name))),A=b.indexes.map(e=>({name:e.indexDescriptor,fields:[...e.fields]})).sort((e,t)=>e.name.localeCompare(t.name));J(K(t(f))),x[e]=i;let j=Object.create(null),N=Object.create(null),I=Object.getOwnPropertyDescriptor(r,`fieldGroups`);if(!I&&`fieldGroups`in r||I&&!(`value`in I))throw Error(`Invalid field groups`);E(I?.value??{});let L=u.record(u.string(),u.array(u.string()).nonempty()).parse(I?.value??{}),R=/* @__PURE__ */ new Set,z=f instanceof u.ZodObject?[f]:f.options;for(let[e,t]of Object.entries(L)){if(!e||[`__proto__`,`constructor`,`prototype`].includes(e))throw Error(`Invalid field groups`);for(let e of t){if(!g.allFields.has(e)||e.startsWith(`_`)||R.has(e)||z.some(t=>!(t instanceof u.ZodObject)||Object.hasOwn(t.shape,e)))throw Error(`Conflicting or incompatible field groups`);let t=g.branches?Object.values(g.branches.options).map(t=>t.fields[e]).filter(e=>e!==void 0):[g.fields[e]];if(!t.every(e=>q(K(e))===q(K(t[0]))&&e.isOptional===t[0].isOptional))throw Error(`Conflicting or incompatible field groups`);R.add(e)}j[e]=Object.freeze([...t].sort());for(let[n,r]of g.branches?Object.entries(g.branches.options).map(([e,t])=>[e,t.fields]):[[null,g.fields]]){let i=Object.fromEntries(t.filter(e=>Object.hasOwn(r,e)).map(e=>[e,r[e]]));N[JSON.stringify([e,n])]=a(s(d.object(i)).strict())}}m[e]={...g,indexes:A,searchIndexes:D,dto:f,dtoRecipe:l,fieldGroups:Object.freeze(j),groupRecipes:Object.freeze(N)};let B=(t,n)=>{let r=Object.create(null);function i(t,r,a){let o={[p]:void 0,table:e,field:t,guard:n,forTable(e){if(n)throw Error(`forTable on branch-scoped fields is unsupported`);if(!P(r)?.includes(e))throw Error(`Invalid native ID member selection`);if(!Object.hasOwn(m,e))throw Error(`Native ID member table is not registered`);let a=Q(r)?d.union(d.id(e),d.null()):d.id(e);return i(t,r.isOptional===`optional`?d.optional(a):a,Object.freeze({table:e}))},through(e){if(a||v.has(e))throw Error(`forTable with through is unsupported`);let t=_.get(e);if(!C.has(e)||!t||!F(r,t))throw Error(`Invalid junction field or registry`);let n=Object.freeze({base:o,junction:e});return y.add(n),n}};return _.set(o,r),a&&v.set(o,a),C.add(o),Object.freeze(o)}for(let[e,n]of Object.entries(t))r[e]=i(e,n);return Object.freeze(r)};if(T[e]=B(g.fields),g.branches)for(let[t,n]of Object.entries(g.branches.options))w.set(JSON.stringify([e,t]),B(n.fields,Object.freeze({discriminator:g.branches.discriminator,tag:t})));O[e]=t=>M(e,`one`,t,C),k[e]=t=>M(e,`many`,t,C)}let N=r(Object.freeze({...T,one:Object.freeze(O),many:Object.freeze(k)}),((e,t)=>{let n=w.get(JSON.stringify([e,t]));if(!n)throw Error(`Unknown variant scope "${e}.${t}"`);return n})),I=Object.fromEntries(Object.entries(N).map(([e,t])=>[e,Object.freeze({...t})]));Object.freeze(I);for(let[e,t]of Object.entries(I)){if(!Object.hasOwn(m,e))throw Error(`Unknown source table "${e}"`);for(let[n,r]of Object.entries(t)){if(m[e].allFields.has(n)||m[e].branches&&[`variant`,`variants`].includes(n)||[`and`,`or`,`not`,`fields`,`then`,`__proto__`,`constructor`,`prototype`].includes(n))throw Error(`Relation name collision "${n}"`);if(!b.has(r)||!C.has(j(r.from))||!C.has(j(r.to))||r.source!==e)throw Error(`Relation source bucket mismatch`);L(r,m)}}let R={metadata:m,declarations:I},U={};for(let t of Object.keys(m))U[t]={filters(e){if(m[t].branches)throw Error(`Shared scalar contracts do not support variant tables`);for(let[n,r]of Object.entries(e.native)){let e=m[t].fields[n];if(!e||JSON.stringify(K(e))!==JSON.stringify(r.json)||e.isOptional===`optional`!==r.optional)throw Error(`Shared filter field mismatch "${n}"`)}return o(f).extend({filters:e.schema.optional(),order:u.enum([`asc`,`desc`]).optional()})},paginationOpts(n){return A(n),o(f).extend({filters:e(B(R,t,n)).optional(),order:u.enum([`asc`,`desc`]).optional()})},pageDto(e,n={}){return A(e),D(R,t,n),i(V(R,t,e,0,n)).result}};let W=JSON.stringify([2,Object.entries(m).sort(([e],[t])=>e.localeCompare(t)).map(([e,n])=>[e,Object.entries(n.fields).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,t.isOptional,K(t)]),n.branches?[n.branches.discriminator,Object.entries(n.branches.options).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,Object.entries(t.fields).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,t.isOptional,K(t)])])]:null,n.indexes,q(K(t(n.dto))),...Object.keys(n.fieldGroups).length?[n.fieldGroups]:[],...n.searchIndexes.length?[{searchIndexes:n.searchIndexes}]:[]]),Object.entries(I).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,Object.entries(t).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,t.cardinality,t.target,z(t.from),z(t.to)])])]),Y=Object.freeze({identity:W,version:1,tables:Object.freeze(U)});h.set(Y,ie(R));let X={};for(let[e,t]of Object.entries(m)){let n=l({});for(let e of t.indexes){let[t,...r]=e.fields;if(t===void 0)throw Error(`Invalid empty active index`);n.index(e.name,[t,...r])}let r=Object.getOwnPropertyDescriptor(n,`indexes`).value;for(let e of r)Object.freeze(e.fields),Object.freeze(e);Object.freeze(r),Object.freeze(n),X[e]=n}return g.set(Y,{internal:R,nativeTables:Object.freeze(x),streamSchema:c(Object.freeze(X))}),Y}function w(t){let n=g.get(t);if(!n)throw Error(`Unknown relation registry`);let i=e=>{let t=Object.keys(n.nativeTables);if(t.length!==Reflect.ownKeys(e).length||t.some(t=>{let r=Object.getOwnPropertyDescriptor(e,t);return!r||!(`value`in r)||r.value!==n.nativeTables[t]}))throw Error(`Native schema/table ownership disagrees with relation registry`)},a=/* @__PURE__ */ new WeakMap,c=/* @__PURE__ */ new WeakMap,l=/* @__PURE__ */ new WeakMap,p=/* @__PURE__ */ new Map,m=/* @__PURE__ */ new Map,h=/* @__PURE__ */ new WeakMap;function _(e,t){let r=n.internal.metadata[e];if(!r)throw Error(`Unknown query table`);if(!r.branches)return;let i=t[r.branches.discriminator],o=typeof i==`string`&&Object.hasOwn(r.branches.options,i)?r.branches.options[i]:void 0;if(!o)throw Error(`Invalid variant document`);let c=a.get(o),l=c?.fieldKeys??Object.keys(o.fields),u=[];for(let e of l)Object.hasOwn(t,e)&&u.push([e,void 0]);for(let e of u)e[1]=t[e[0]];let f=Object.fromEntries(u);c||(c={validator:s(d.object(o.fields)),fieldKeys:l},a.set(o,c)),c.validator.parse(f)}return Object.freeze({streamSchema:n.streamSchema,groups(e,t){return D(n.internal,e,t)},validateDocument:_,assertSchema:i,pagination(t){let i=n.internal;function a(e,t,n){let o=JSON.stringify([e,t,n??null]),s=m.get(o);if(s)return s;let c=i.metadata[e];if(!c)throw Error(`Unknown query table`);let l=JSON.stringify([e,n??null]),u=p.get(l);if(!u){u={};for(let[e,t]of Object.entries(n===void 0?c.fields:c.branches.options[n].fields))k(t)&&(u[e]=r(t).optional());p.set(l,u)}let d={fields:u,variants:c.branches&&n===void 0&&t<4?{discriminator:c.branches.discriminator,options:Object.fromEntries(Object.keys(c.branches.options).map(n=>[n,a(e,t+1,n)]))}:void 0,relations:t>=4?{}:Object.fromEntries(Object.entries(i.declarations[e]??{}).map(([e,n])=>[e,{cardinality:n.cardinality,target:a(n.target,t+1)}]))};return m.set(o,d),d}return o(f).extend({filters:e(a(t,0),h).optional(),order:u.enum([`asc`,`desc`]).optional()})},select(e,t){A(t);function r(e,t,i){if(!Object.hasOwn(n.internal.metadata,e))throw Error(`Unknown query table`);for(let[a,o]of Object.entries(t)){let t=n.internal.declarations[e]?.[a];if(!t||i>=4)throw Error(`Unknown or too deep relation "${e}.${a}"`);o!==!0&&r(t.target,o,i+1)}}r(e,t,0)},project(e,t,r,i=[]){if(!r())return null;let a=n.internal.metadata[e];if(!a)throw Error(`Unknown query table`);let o=a.branches?a.branches.options[String(t[a.branches.discriminator])]:void 0;if(a.branches&&!o)throw Error(`Invalid variant document`);let s=o?.dto??a.dto;if(!(s instanceof u.ZodObject))throw Error(`Invalid variant DTO`);if(i.length){let e=l.get(s);e||(e=/* @__PURE__ */ new Map,l.set(s,e));let n=JSON.stringify([...i].sort()),r=e.get(n);r||(r=s.extend(O(a,i,void 0,a.branches?String(t[a.branches.discriminator]):void 0)).strict(),e.set(n,r)),s=r}_(e,t);let d=c.get(s);return d||(d=Object.keys(s.shape),c.set(s,d)),s.parse(Object.fromEntries(d.filter(e=>Object.hasOwn(t,e)).map(e=>[e,t[e]])))}})}function T(e){let t=h.get(e);if(!t)throw Error(`Unknown relation registry`);return t}function E(e,t=0){if(t>16)throw Error(`Invalid field groups`);if(typeof e!=`object`||!e)return;let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null&&n!==Array.prototype)throw Error(`Invalid field groups`);for(let n of Reflect.ownKeys(e)){let r=Object.getOwnPropertyDescriptor(e,n);if(!u.string().safeParse(n).success||!(`value`in r))throw Error(`Invalid field groups`);E(r.value,t+1)}}function D(e,t,n){E(n);function r(t,n,i){let a=u.object({fieldGroups:u.record(u.string(),u.enum([`required`,`if-permitted`])).optional(),relations:u.record(u.string(),u.unknown()).optional()}).strict().parse(n),o=e.metadata[t];if(!o)throw Error(`Unknown query table`);for(let e of Object.keys(a.fieldGroups??{}))if(!Object.hasOwn(o.fieldGroups,e))throw Error(`Unknown field group`);let s={};for(let[n,o]of Object.entries(a.relations??{})){let a=e.declarations[t]?.[n];if(!a||i>=4)throw Error(`Invalid field group relation`);s[n]=r(a.target,o,i+1)}return Object.freeze({fieldGroups:Object.freeze(a.fieldGroups??{}),relations:Object.freeze(s)})}return r(t,n,0)}function O(e,t,n,r){let i={};for(let a of t){let t=JSON.stringify([a,r??null]);if(!Object.hasOwn(e.groupRecipes,t))throw Error(`Unknown field group`);let s=o(e.groupRecipes[t]);if(!(s instanceof u.ZodObject))throw Error(`Invalid field group schema`);for(let[e,t]of Object.entries(s.shape))i[e]=n?.[a]===`if-permitted`?t.optional():t}return i}function k(e){return[`id`,`string`,`float64`,`int64`,`boolean`,`null`,`literal`].includes(e.kind)||e.kind===`union`&&e.members.every(k)}function A(e){let t=[{value:e,depth:0,ancestors:[]}],n=0;for(;t.length;){let{value:e,depth:r,ancestors:i}=t.pop();if(++n>256||r>4||i.includes(e))throw Error(`Selection cycle or depth/node budget exceeded`);let a=Object.getPrototypeOf(e);if(a!==Object.prototype&&a!==null)throw Error(`Invalid selection`);let o=Reflect.ownKeys(e);if(o.length+n+t.length>256)throw Error(`Selection node budget exceeded`);for(let a of o){let o=Object.getOwnPropertyDescriptor(e,a);if(!o.enumerable||!(`value`in o)||String(a)!==a)throw Error(`Invalid selection property`);if(o.value!==!0)t.push({value:o.value,depth:r+1,ancestors:[...i,e]});else if(++n>256)throw Error(`Selection node budget exceeded`)}}}function j(e){return`base`in e?e.base:e}function M(e,t,n,r){for(let e of[n.from,n.to])if(!r.has(j(e))||`base`in e&&(!y.has(e)||!r.has(e.junction)))throw Error(`Foreign registry or invalid field reference`);if(j(n.to).table!==e)throw Error(`Wrong relation target table`);let i=Object.freeze({[m]:!0,source:j(n.from).table,target:e,cardinality:t,from:n.from,to:n.to,sourceGuard:j(n.from).guard,targetGuard:j(n.to).guard,junctionGuard:N(n.from,n.to),sourceMember:v.get(j(n.from)),targetMember:v.get(j(n.to))});return b.add(i),i}function N(e,t){let n=`base`in e?e.junction.guard:void 0,r=`base`in t?t.junction.guard:void 0;if(n&&r&&(n.discriminator!==r.discriminator||n.tag!==r.tag))throw Error(`Contradictory junction scopes`);return n??r}function P(e){if(e.kind===`id`)return[e.tableName];if(e.kind===`null`)return[];if(e.kind!==`union`)return null;let t=e.members.map(P);return t.some(e=>e===null)?null:[...new Set(t.flatMap(e=>e))].sort()}function F(e,t){let n=I(e);return n.length>0&&JSON.stringify(n)===JSON.stringify(I(t))}function I(e){if(e.kind===`union`)return[...new Set(e.members.flatMap(I))].sort();if(e.kind===`null`)return[];if(![`id`,`string`,`float64`,`int64`,`boolean`,`literal`].includes(e.kind))throw Error(`Unsupported relation field kind`);return[JSON.stringify(K(e))]}function L(e,t){let n=e.from,r=e.to;if(`base`in n!=`base`in r)throw Error(`Both relation legs must use through`);if(`base`in n&&`base`in r){if(n.junction.table!==r.junction.table)throw Error(`Different junction tables`);R(t,n.junction.table,n.junction.field,e.junctionGuard),R(t,e.target,r.base.field,e.targetGuard);return}if(!F(_.get(j(n)),_.get(j(r))))throw Error(`Incompatible relation field types`);R(t,e.target,j(r).field,e.targetGuard)}function R(e,t,n,r){if(n!==`_id`&&!e[t].indexes.some(e=>{let t=e.fields.indexOf(n);return t>=0&&e.fields.slice(0,t).every(e=>e===r?.discriminator)}))throw Error(`No active index begins with or has a guarded prefix for "${t}.${n}"`)}function z(e){return`base`in e?[e.base.table,e.base.field,e.base.guard??null,e.junction.table,e.junction.field,e.junction.guard??null]:v.has(e)?[e.table,e.field,e.guard??null,v.get(e)]:[e.table,e.field,e.guard??null]}function B(e,t,n,i=0,a){let o={},s={},c=e.metadata[t],l={};for(let[u,d]of Object.entries(n)){if(u===`variants`&&d!==!0&&c.branches&&a===void 0){if(i>=4)throw Error(`Invalid variant selection`);for(let[r,a]of Object.entries(d)){if(!Object.hasOwn(c.branches.options,r)||a===!0)throw Error(`Unknown variant filter selection`);l[r]=B(e,t,{...Object.fromEntries(Object.entries(n).filter(([e])=>e!==`variants`)),...a},i+1,r)}continue}let f=(a===void 0?c.fields:c.branches.options[a].fields)[u],p=e.declarations[t]?.[u];if(d===!0&&f)o[u]=r(f).optional();else if(d!==!0&&p&&i<4)s[u]={cardinality:p.cardinality,target:B(e,p.target,d,i+1)};else throw Error(`Invalid relation filter selection "${t}.${u}"`)}return{fields:o,relations:s,variants:c.branches&&a===void 0?{discriminator:c.branches.discriminator,options:l}:void 0}}function V(e,t,n,r=0,a={}){let s={};for(let[o,c]of Object.entries(n)){let n=e.declarations[t]?.[o];if(!n||r>=4)throw Error(`Unknown or too deep relation "${t}.${o}"`);let l=V(e,n.target,c===!0?{}:c,r+1,a.relations?.[o]);if(n.targetGuard){if(!(l instanceof u.ZodDiscriminatedUnion))throw Error(`Invalid target scope`);l=l.options.filter(e=>e instanceof u.ZodObject).find(e=>e.shape[n.targetGuard.discriminator]instanceof u.ZodLiteral&&e.shape[n.targetGuard.discriminator].value===n.targetGuard.tag)}s[o]=n.cardinality===`one`?l.nullable():i(l).result}let c=e.metadata[t],l=o(c.dtoRecipe);function d(n,r){let i={...s};for(let n of Object.keys(i)){let a=e.declarations[t][n];a.sourceGuard&&r!==a.sourceGuard.tag&&a.cardinality===`one`&&(i[n]=u.null())}return n.extend({...O(c,Object.keys(a.fieldGroups??{}),a.fieldGroups,r),...i}).strict()}if(c.branches){if(!(l instanceof u.ZodDiscriminatedUnion))throw Error(`Invalid variant DTO`);let e=l.options.map(e=>{if(!(e instanceof u.ZodObject))throw Error(`Invalid variant DTO`);let t=e.shape[c.branches.discriminator];if(!(t instanceof u.ZodLiteral))throw Error(`Invalid variant tag`);return d(e,String(t.value))});return u.discriminatedUnion(c.branches.discriminator,[e[0],...e.slice(1)])}if(!(l instanceof u.ZodObject))throw Error(`Expected object DTO`);return d(l)}function H(e,n,r,i){if(n instanceof u.ZodObject&&r instanceof u.ZodObject){let r=t(n).fields;return Y(e,r,i),{fields:r,allFields:new Set(Object.keys(r))}}if(!(n instanceof u.ZodDiscriminatedUnion)||!(r instanceof u.ZodDiscriminatedUnion))throw Error(`Expected matching discriminated union boundaries "${e}"`);let a=n._zod.def.discriminator;if(r._zod.def.discriminator!==a)throw Error(`DTO discriminator mismatch`);function o(e){let t=Object.create(null);for(let n of e.options){if(!(n instanceof u.ZodObject))throw Error(`Variant branches must be objects`);let e=n.shape[a];if(!(e instanceof u.ZodLiteral)||e.values.size!==1)throw Error(`Variant tags must be unique required string literals`);let r=u.string().safeParse(e.value);if(!r.success||Object.hasOwn(t,r.data))throw Error(`Variant tags must be unique required string literals`);t[r.data]=n}if(Object.keys(t).length===0)throw Error(`Expected at least one variant branch`);return t}let s=o(n),c=o(r);if(Object.keys(s).sort().join(`\0`)!==Object.keys(c).sort().join(`\0`))throw Error(`DTO variant tags mismatch`);let l={discriminator:a,options:Object.create(null)},f=[];for(let[n,r]of Object.entries(s)){let i=t(r).fields,{_id:a,_creationTime:o,...s}=i;Y(e,i,K(d.object(s))),f.push(d.object(s)),l.options[n]={fields:i,dto:c[n]}}if(q(i)!==q(K(d.union(...f))))throw Error(`Native stored document disagrees with boundary "${e}"`);let p=Object.values(l.options).map(e=>e.fields),m={};for(let e of Object.keys(p[0])){if(!p.every(t=>Object.hasOwn(t,e))||e!==a&&!p.every(t=>U(t[e],p[0][e])))continue;let t=p.map(t=>t[e]),n=d.union(...t);m[e]=t.some(e=>e.isOptional===`optional`)?d.optional(n):n}return{fields:m,branches:l,allFields:new Set(p.flatMap(e=>Object.keys(e)))}}function U(e,t){try{return F(e,t)}catch{return q(K(e))===q(K(t))}}const W=/* @__PURE__ */ new Map;for(let e of[l(d.object({})),d.id(`sample`),d.null(),d.number(),d.int64(),d.commitTs(),d.boolean(),d.string(),d.bytes(),d.any(),d.object({}),d.literal(`sample`),d.array(d.string()),d.record(d.string(),d.string()),d.union(d.string(),d.null())]){let t=Object.getPrototypeOf(e);for(;t&&t!==Object.prototype;)W.has(t)||W.set(t,Object.getOwnPropertyDescriptors(t)),t=Object.getPrototypeOf(t)}function G(e){let t=/* @__PURE__ */ new Set,n=/* @__PURE__ */ new Set;function r(e,i,a=!1){if(n.has(e))throw Error(`Unsupported cyclic native schema`);if(t.has(e))return;if(i>64||t.size>=8192)throw Error(`Native schema graph budget exceeded`);t.add(e),n.add(e);let o=Object.getPrototypeOf(e),s=o&&W.get(o);if(o!==null&&o!==Object.prototype&&o!==Array.prototype&&!s)throw Error(`Unsupported native schema prototype`);if(Object.getOwnPropertySymbols(e).length)throw Error(`Unsupported native schema symbol`);let c=Object.getOwnPropertyNames(e).map(t=>Object.getOwnPropertyDescriptor(e,t));if(!a&&c.some(e=>!(`value`in e)||e.value instanceof Function))throw Error(`Unsupported native schema accessor or method`);if(s){let e=Object.getOwnPropertyNames(o);if(e.length!==Object.getOwnPropertyNames(s).length||e.some(e=>{let t=Object.getOwnPropertyDescriptor(o,e),n=Object.getOwnPropertyDescriptor(s,e)?.value;return!n||!Object.is(t.value,n.value)||t.get!==n.get||t.set!==n.set}))throw Error(`Unsupported native schema prototype mutation`);r(o,i+1,!0)}if(!a)for(let e of c)e.value!==null&&Object(e.value)===e.value&&r(e.value,i+1);n.delete(e)}r(e,0)}function ee(e){return e.export()}function K(e){return e.json}function q(e){if(Array.isArray(e))return`[${e.map(q).join(`,`)}]`;if(e!==null&&Object(e)===e){let t=e;return`{${Object.keys(t).sort().map(e=>`${JSON.stringify(e)}:${q(t[e])}`).join(`,`)}}`}return JSON.stringify(e)}function J(e){if(e===null||Object(e)!==e)return;let t=e;if(t.type===`any`)throw Error(`Unsupported native validation form`);for(let e of Object.values(t))J(e)}function Y(e,t,n){let{_id:r,_creationTime:i,...a}=t;if(!r||!i||q(K(r))!==q(K(d.id(e)))||q(K(i))!==q(K(d.number()))||r.isOptional!==`required`||i.isOptional!==`required`||q(n)!==q(K(d.object(a))))throw Error(`Native stored document disagrees with boundary "${e}"`)}const X=u.object({field:u.string()}),te=new Set([X,X.pick({field:!0}),X.omit({field:!0}),X.extend({other:u.string()}),X.safeExtend({other:u.string()}),X.merge(u.object({other:u.string()})),X.partial(),X.required()].flatMap(e=>{let t=Object.getOwnPropertyDescriptor(e._zod.def,`shape`)?.get;return t?[Function.prototype.toString.call(t)]:[]})),ne=Function.prototype.toString.call(Object.getOwnPropertyDescriptor(u.string().default(``)._zod.def,`defaultValue`).get),re=Function.prototype.toString.call(Object.getOwnPropertyDescriptor(u.string().prefault(``)._zod.def,`defaultValue`).get);function Z(e,t){let n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Set,i=/* @__PURE__ */ new Set,a=/* @__PURE__ */ new Set;function o(e,s){if(i.has(e))throw Error(`Unsupported cyclic DTO schema`);if(!r.has(e)){if(s>32||r.size>=4096)throw Error(`DTO schema graph budget exceeded`);r.add(e),i.add(e);try{let r=Object.getOwnPropertyDescriptor(e,`_zod`);if(r){if(!(`value`in r))throw Error(`Unsupported DTO schema accessor`);let e=Object.getOwnPropertyDescriptor(r.value,`def`);if(!e||!(`value`in e))throw Error(`Unsupported DTO schema accessor`)}if(e instanceof u.core.$ZodCheck&&!(e instanceof u.core.$ZodType)){if(t===`dto`&&e._zod.def.check===`overwrite`)throw Error(`Unsupported DTO overwrite check`);o(e._zod.def,s+1);return}if(e instanceof u.core.$ZodType){let r=e._zod.def;if(t===`dto`&&(![`object`,`array`,`optional`,`nullable`,`nonoptional`,`union`,`intersection`,`tuple`,`record`,`string`,`number`,`boolean`,`bigint`,`null`,`never`,`custom`,`literal`,`enum`].includes(r.type)||`coerce`in r&&r.coerce))throw Error(`Unsupported DTO schema "${r.type}"`);if(t===`stored`&&(r.type==="default"||r.type===`prefault`)){let e=Object.getOwnPropertyDescriptor(r,`defaultValue`);if(e?.get){if(e.set||Function.prototype.toString.call(e.get)!==(r.type==="default"?ne:re))throw Error(`Unsupported stored schema accessor`);n.add(r)}}if(e instanceof u.ZodUnion&&o(e.options,s+1),r.type===`object`){let t=Object.getOwnPropertyDescriptor(r,`shape`);if(t?.get){if(t.set||!te.has(Function.prototype.toString.call(t.get)))throw Error(`Unsupported DTO schema accessor`);let e=r.shape;o(e,s+1),a.add(r)}if(e instanceof u.ZodObject){let t=Object.getOwnPropertyDescriptor(e,`shape`);if(t&&!(`value`in t))throw Error(`Unsupported DTO schema accessor`);o(e.shape,s+1)}}o(r,s+1);return}let i=Reflect.ownKeys(e),c=i.map(t=>Object.getOwnPropertyDescriptor(e,t));if(c.some((t,r)=>!(`value`in t)&&!(a.has(e)&&i[r]===`shape`)&&!(n.has(e)&&i[r]===`defaultValue`)))throw Error(`Unsupported DTO schema accessor`);for(let e of c)e.value!==null&&Object(e.value)===e.value&&!(e.value instanceof Function)&&o(e.value,s+1)}finally{i.delete(e)}}}o(e,0)}function ie(e){let t={};for(let[n,r]of Object.entries(e.metadata)){let e={};for(let[t,n]of Object.entries(r.fields))e[t]=Object.freeze({kind:n.kind,optional:n.isOptional===`optional`,nullable:Q(n),idTables:Object.freeze($(n)),native:ae(K(n))});t[n]=Object.freeze({fieldGroups:r.fieldGroups,searchIndexes:r.searchIndexes,fields:Object.freeze(e),variant:r.branches?Object.freeze({discriminator:r.branches.discriminator,tags:Object.freeze(Object.keys(r.branches.options))}):void 0,indexes:Object.freeze(r.indexes.map(e=>Object.freeze({name:e.name,fields:Object.freeze([...e.fields])})))})}return Object.freeze({tables:Object.freeze(t),declarations:e.declarations})}function Q(e){return e.kind===`null`||e.kind===`union`&&e.members.some(Q)}function $(e){return e.kind===`id`?[e.tableName]:e.kind===`union`?[...new Set(e.members.flatMap($))].sort():[]}function ae(e){let t=structuredClone(e),n=[t];for(;n.length;){let e=n.pop();if(Object(e)!==e)continue;let t=e;Object.freeze(t),n.push(...Object.values(t))}return t}export{C as defineRelations,w as getRelationExecutor,T as getRelationMetadata};
2
2
  //# sourceMappingURL=relations.mjs.map