kitcn 0.28.0 → 0.29.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,73 @@
1
1
  # kitcn
2
2
 
3
+ ## 0.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#421](https://github.com/udecode/kitcn/pull/421) [`26dd9b5`](https://github.com/udecode/kitcn/commit/26dd9b55357e4d49b7ada84812fefd52648f304a) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
8
+
9
+ - Register `migrationStatus` and `aggregateBackfillStatus` as internal
10
+ **queries** instead of internal mutations. Polling migration or aggregate
11
+ status no longer opens a write transaction, so a status monitor stops
12
+ competing for OCC write slots on the very tables it is reporting on. Both can
13
+ now back a live subscription, and neither can be scheduled any more.
14
+
15
+ ```ts
16
+ // Before — status read had to run from a mutation context
17
+ export const getStatus = authMutation.mutation(async ({ ctx }) => {
18
+ const server = createServerCaller(ctx);
19
+ return await server.migrationStatus({});
20
+ });
21
+
22
+ // After — status reads from a query context
23
+ export const getStatus = authQuery.query(async ({ ctx }) => {
24
+ const server = createServerCaller(ctx);
25
+ return await server.migrationStatus({});
26
+ });
27
+ ```
28
+
29
+ - Accept an `internalQuery` builder in `createOrm(...)` alongside
30
+ `internalMutation`. Apps generated by `kitcn codegen` pass it automatically;
31
+ hand-written `createOrm` calls that use `orm.api()` should pass it too so the
32
+ status procedures are built with the app's own Convex builder.
33
+
34
+ ```ts
35
+ // Before
36
+ const orm = createOrm({ schema, ormFunctions, internalMutation });
37
+
38
+ // After
39
+ const orm = createOrm({
40
+ schema,
41
+ ormFunctions,
42
+ internalMutation,
43
+ internalQuery,
44
+ });
45
+ ```
46
+
47
+ ## Patches
48
+
49
+ - Fix `migrationStatus` reading the entire `migration_run` history to return the
50
+ most recent runs. The listing now walks a new `by_started_at` index in reverse
51
+ and stops at `limit`, so the cost of a status call no longer grows with the
52
+ number of migrations ever run. Runs that share a `startedAt` millisecond now
53
+ order newest-first.
54
+ - Bound the `limit` argument of `migrationStatus` at `MAX_STATUS_RUN_LIMIT`
55
+ (`100`, default `25`), exported from `kitcn/orm/migrations`, so a caller
56
+ cannot reintroduce an unbounded read through the args.
57
+ - Resolve `migrationStatus`'s `runId` and `activeRun` through their existing
58
+ indexes instead of scanning the run history. `activeRun` now agrees with the
59
+ run that `migrate cancel` targets.
60
+
61
+ ## 0.28.1
62
+
63
+ ### Patch Changes
64
+
65
+ - [#420](https://github.com/udecode/kitcn/pull/420) [`73741ed`](https://github.com/udecode/kitcn/commit/73741ed08779d539c9f186db366e326b138dbd36) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
66
+
67
+ - Fix `insert()` re-reading the same parent row once per inserted row. Rows of one statement that share a foreign key now cost one existence check instead of one per row.
68
+ - Fix the aggregate write barrier re-scanning the `CLEARING` index-state range once per written row. A multi-row write now checks it once per transaction, and a backfill that starts clearing an index still blocks the writes that follow it.
69
+ - Fix a relation `where` re-reading the same related document once per scanned row. Filtering by a relation now reads each distinct related document once per query instead of once per candidate row.
70
+
3
71
  ## 0.28.0
4
72
 
5
73
  ### Minor Changes
@@ -1,5 +1,5 @@
1
- import { Bn as ConvexTextBuilderInitial, Xt as ConvexTableWithColumns } from "../capabilities-DkfnnNp7.js";
2
- import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-CETRjurp.js";
1
+ import { Vn as ConvexTextBuilderInitial, Zt as ConvexTableWithColumns } from "../capabilities-6PZBmvc8.js";
2
+ import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-CX5-0M5p.js";
3
3
  import * as convex_values0 from "convex/values";
4
4
  import { GenericId, Infer, Value } from "convex/values";
5
5
  import { DocumentByName, GenericDataModel, GenericDatabaseReader, GenericDatabaseWriter, TableNamesInDataModel } from "convex/server";
@@ -1,2 +1,2 @@
1
- import { C as GenericAuthTriggers, S as GenericAuthTriggerHandlers, b as GenericAuthDefinition, i as getGeneratedAuthDisabledReason, n as GeneratedAuthDisabledReasonKind, r as createDisabledAuthRuntime, t as AuthRuntime, v as BetterAuthOptionsWithoutDatabase, w as defineAuth, x as GenericAuthTriggerChange, y as GenericAuthBeforeResult } from "../../generated-contract-disabled-Btfy2opW.js";
1
+ import { C as GenericAuthTriggers, S as GenericAuthTriggerHandlers, b as GenericAuthDefinition, i as getGeneratedAuthDisabledReason, n as GeneratedAuthDisabledReasonKind, r as createDisabledAuthRuntime, t as AuthRuntime, v as BetterAuthOptionsWithoutDatabase, w as defineAuth, x as GenericAuthTriggerChange, y as GenericAuthBeforeResult } from "../../generated-contract-disabled-CgYQZCw2.js";
2
2
  export { type AuthRuntime, BetterAuthOptionsWithoutDatabase, type GeneratedAuthDisabledReasonKind, GenericAuthBeforeResult, GenericAuthDefinition, GenericAuthTriggerChange, GenericAuthTriggerHandlers, GenericAuthTriggers, createDisabledAuthRuntime, defineAuth, getGeneratedAuthDisabledReason };
@@ -1,7 +1,7 @@
1
1
  import { a as QueryCtxWithPreferredOrmQueryTable, n as LookupByIdResultByCtx, t as DocByCtx } from "../query-context-DJONf8X5.js";
2
2
  import { t as GetAuth } from "../types-Bf3XQex5.js";
3
3
  import { t as GenericCtx } from "../context-utils-DwZ3Cam1.js";
4
- import { C as GenericAuthTriggers, S as GenericAuthTriggerHandlers, _ as updateOneHandler, a as AuthFunctions, b as GenericAuthDefinition, c as consumeOneHandler, d as deleteManyHandler, f as deleteOneHandler, g as updateManyHandler, h as incrementOneHandler, i as getGeneratedAuthDisabledReason, l as createApi, m as findOneHandler, n as GeneratedAuthDisabledReasonKind, o as Triggers, p as findManyHandler, r as createDisabledAuthRuntime, s as createClient, t as AuthRuntime, u as createHandler, v as BetterAuthOptionsWithoutDatabase, w as defineAuth, x as GenericAuthTriggerChange, y as GenericAuthBeforeResult } from "../generated-contract-disabled-Btfy2opW.js";
4
+ import { C as GenericAuthTriggers, S as GenericAuthTriggerHandlers, _ as updateOneHandler, a as AuthFunctions, b as GenericAuthDefinition, c as consumeOneHandler, d as deleteManyHandler, f as deleteOneHandler, g as updateManyHandler, h as incrementOneHandler, i as getGeneratedAuthDisabledReason, l as createApi, m as findOneHandler, n as GeneratedAuthDisabledReasonKind, o as Triggers, p as findManyHandler, r as createDisabledAuthRuntime, s as createClient, t as AuthRuntime, u as createHandler, v as BetterAuthOptionsWithoutDatabase, w as defineAuth, x as GenericAuthTriggerChange, y as GenericAuthBeforeResult } from "../generated-contract-disabled-CgYQZCw2.js";
5
5
  import * as convex_values0 from "convex/values";
6
6
  import { Infer } from "convex/values";
7
7
  import { AuthConfig, DocumentByName, GenericDataModel, GenericMutationCtx, GenericQueryCtx, GenericSchema, PaginationOptions, PaginationResult, SchemaDefinition, TableNamesInDataModel } from "convex/server";
@@ -121,7 +121,6 @@ declare const adapterWhereValidator: convex_values0.VObject<{
121
121
  value: convex_values0.VUnion<string | number | boolean | string[] | number[] | null, [convex_values0.VString<string, "required">, convex_values0.VFloat64<number, "required">, convex_values0.VBoolean<boolean, "required">, convex_values0.VArray<string[], convex_values0.VString<string, "required">, "required">, convex_values0.VArray<number[], convex_values0.VFloat64<number, "required">, "required">, convex_values0.VNull<null, "required">], "required", never>;
122
122
  }, "required", "mode" | "connector" | "field" | "operator" | "value">;
123
123
  declare const adapterArgsValidator: convex_values0.VObject<{
124
- limit?: number | undefined;
125
124
  where?: {
126
125
  mode?: "sensitive" | "insensitive" | undefined;
127
126
  connector?: "AND" | "OR" | undefined;
@@ -129,6 +128,7 @@ declare const adapterArgsValidator: convex_values0.VObject<{
129
128
  field: string;
130
129
  value: string | number | boolean | string[] | number[] | null;
131
130
  }[] | undefined;
131
+ limit?: number | undefined;
132
132
  offset?: number | undefined;
133
133
  select?: string[] | undefined;
134
134
  sortBy?: {
@@ -167,7 +167,7 @@ declare const adapterArgsValidator: convex_values0.VObject<{
167
167
  operator: convex_values0.VUnion<"lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined, [convex_values0.VLiteral<"lt", "required">, convex_values0.VLiteral<"lte", "required">, convex_values0.VLiteral<"gt", "required">, convex_values0.VLiteral<"gte", "required">, convex_values0.VLiteral<"eq", "required">, convex_values0.VLiteral<"in", "required">, convex_values0.VLiteral<"not_in", "required">, convex_values0.VLiteral<"ne", "required">, convex_values0.VLiteral<"contains", "required">, convex_values0.VLiteral<"starts_with", "required">, convex_values0.VLiteral<"ends_with", "required">], "optional", never>;
168
168
  value: convex_values0.VUnion<string | number | boolean | string[] | number[] | null, [convex_values0.VString<string, "required">, convex_values0.VFloat64<number, "required">, convex_values0.VBoolean<boolean, "required">, convex_values0.VArray<string[], convex_values0.VString<string, "required">, "required">, convex_values0.VArray<number[], convex_values0.VFloat64<number, "required">, "required">, convex_values0.VNull<null, "required">], "required", never>;
169
169
  }, "required", "mode" | "connector" | "field" | "operator" | "value">, "optional">;
170
- }, "required", "limit" | "model" | "where" | "offset" | "select" | "sortBy" | "sortBy.field" | "sortBy.direction">;
170
+ }, "required", "model" | "where" | "limit" | "offset" | "select" | "sortBy" | "sortBy.field" | "sortBy.direction">;
171
171
  declare const hasUniqueFields: (betterAuthSchema: BetterAuthDBSchema, model: string, input: Record<string, any>) => boolean;
172
172
  declare const checkUniqueFields: <Schema extends SchemaDefinition<any, any>>(ctx: GenericQueryCtx<GenericDataModel>, schema: Schema, betterAuthSchema: BetterAuthDBSchema, table: string, input: Record<string, any>, doc?: Record<string, any>) => Promise<void>;
173
173
  declare const selectFields: <T extends TableNamesInDataModel<GenericDataModel>, D extends DocumentByName<GenericDataModel, T>>(doc: D | null, select?: string[]) => D | null;
@@ -2892,6 +2892,22 @@ declare class GelRelationalQuery<TSchema extends TablesRelationalConfig, TTableC
2892
2892
  * hands it to the next run rather than re-probing.
2893
2893
  */
2894
2894
  private _aggregateIndexReadinessByKey;
2895
+ /**
2896
+ * Documents resolved by id during one execution, keyed on the normalized id.
2897
+ *
2898
+ * A relation `where` never compiles into the index plan, so it runs as a
2899
+ * post-fetch membership predicate over a residual stream — one row at a time.
2900
+ * Every de-duplication map inside the relation loaders is scoped to the batch
2901
+ * it is handed, and a batch of one makes all of them no-ops, so a page whose
2902
+ * rows share two parents re-read those two documents once per scanned row.
2903
+ *
2904
+ * Scoped to one execution, like `_rlsPolicyResolution`: `_executionClaimed`
2905
+ * diverts later executions to a fresh instance, and an execution reads
2906
+ * without writing, so a hit is always the document the caller would have read
2907
+ * for itself. It must not be handed to the next run by `_forExecution` — an
2908
+ * intervening write would make it stale.
2909
+ */
2910
+ private readonly _documentByNormalizedId;
2895
2911
  constructor(schema: TSchema, tableConfig: TTableConfig, edgeMetadata: EdgeMetadata[], db: GenericDatabaseReader<any>, config: DBQueryConfig<'one' | 'many', boolean, TSchema, TTableConfig>, mode: 'many' | 'first' | 'firstOrThrow' | 'count' | 'aggregate' | 'groupBy', _allEdges?: EdgeMetadata[] | undefined, // M6.5 Phase 2: All edges for nested loading
2896
2912
  rls?: RlsContext | undefined, relationLoading?: {
2897
2913
  concurrency?: number;
@@ -3631,8 +3647,15 @@ declare function buildMigrationPlan<TSchema extends MigrationSchemaInput = Table
3631
3647
  to?: string;
3632
3648
  }): MigrationPlan<TSchema>;
3633
3649
  declare namespace runtime_d_exports {
3634
- export { MigrationCancelArgs, MigrationRunArgs, MigrationRunChunkArgs, MigrationStatusArgs, createMigrationHandlers };
3650
+ export { MAX_STATUS_RUN_LIMIT, MigrationCancelArgs, MigrationRunArgs, MigrationRunChunkArgs, MigrationStatusArgs, createMigrationHandlers };
3635
3651
  }
3652
+ /**
3653
+ * Hard ceiling on how many `migration_run` rows one `status()` call may read.
3654
+ *
3655
+ * `limit` is caller-supplied, so bounding the query without bounding the
3656
+ * argument would just move the unbounded read behind the args surface.
3657
+ */
3658
+ declare const MAX_STATUS_RUN_LIMIT = 100;
3636
3659
  type MigrationRunArgs = {
3637
3660
  direction?: MigrationDirection;
3638
3661
  steps?: number;
@@ -3657,6 +3680,13 @@ type RuntimeCtx = {
3657
3680
  db: GenericDatabaseWriter<any>;
3658
3681
  scheduler?: Scheduler;
3659
3682
  };
3683
+ /**
3684
+ * `status()` never writes, so it runs on a query ctx where `db` is a reader and
3685
+ * there is no scheduler.
3686
+ */
3687
+ type RuntimeReadCtx = {
3688
+ db: GenericDatabaseReader<any> | GenericDatabaseWriter<any>;
3689
+ };
3660
3690
  type CreateMigrationHandlersParams<TSchema extends TablesRelationalConfig> = {
3661
3691
  schema: TSchema;
3662
3692
  migrations?: MigrationSet<TSchema>;
@@ -3666,7 +3696,7 @@ type CreateMigrationHandlersParams<TSchema extends TablesRelationalConfig> = {
3666
3696
  declare function createMigrationHandlers<TSchema extends TablesRelationalConfig>(params: CreateMigrationHandlersParams<TSchema>): {
3667
3697
  run: (ctx: RuntimeCtx, args?: MigrationRunArgs) => Promise<Record<string, unknown>>;
3668
3698
  chunk: (ctx: RuntimeCtx, args: MigrationRunChunkArgs) => Promise<Record<string, unknown>>;
3669
- status: (ctx: RuntimeCtx, args?: MigrationStatusArgs) => Promise<Record<string, unknown>>;
3699
+ status: (ctx: RuntimeReadCtx, args?: MigrationStatusArgs) => Promise<Record<string, unknown>>;
3670
3700
  cancel: (ctx: RuntimeCtx, args?: MigrationCancelArgs) => Promise<Record<string, unknown>>;
3671
3701
  };
3672
3702
  //#endregion
@@ -3748,4 +3778,4 @@ type OrmCapabilities = {
3748
3778
  migrations?: OrmMigrationCapability;
3749
3779
  };
3750
3780
  //#endregion
3751
- export { RankOrderField as $, BinaryExpression as $n, OrmLifecycleOperation as $t, DatabaseWithMutations as A, ConvexCheckConfig as An, AnyColumn as Ar, VectorQueryConfig as At, RlsContext as B, ConvexTextBuilderInitial as Bn, IsUnique as Br, RelationsBuilderColumnConfig as Bt, MigrationTableName as C, aggregateIndex as Cn, notBetween as Cr, OrderDirection as Ct, defineMigrationSet as D, uniqueIndex as Dn, SystemFieldAliases as Dr, ReturningResult as Dt, defineMigration as E, searchIndex as En, startsWith as Er, ReturningAll as Et, DeleteMode as F, ConvexUniqueConstraintConfig as Fn, ColumnBuilderWithTableName as Fr, ExtractTablesWithRelations as Ft, CountBackfillKickoffArgs as G, OrmRuntimeDefaults as Gn, defineRelations as Gt, EdgeMetadata as H, ConvexColumnBuilder as Hn, entityKind as Hr, RelationsConfigWithSchema as Ht, SerializedFilterExpression as I, check as In, ColumnDataType as Ir, ManyConfig as It, AggregateQueryPlan as J, OrmSchemaExtensionTriggers as Jn, ConvexDeletionConfig as Jt, CountBackfillMode as K, OrmSchemaExtensionRelations as Kn, defineRelationsPart as Kt, getChecks as L, foreignKey as Ln, DrizzleEntity as Lr, OneConfig as Lt, OrmReader as M, ConvexForeignKeyConfig as Mn, ColumnBuilderBaseConfig as Mr, unsetToken as Mt, OrmWriter as N, ConvexUniqueConstraintBuilder as Nn, ColumnBuilderRuntimeConfig as Nr, AnyRelationsBuilderConfig as Nt, detectMigrationDrift as O, vectorIndex as On, SystemFields as Or, ReturningSelection as Ot, CascadeMode as P, ConvexUniqueConstraintBuilderOn as Pn, ColumnBuilderTypeConfig as Pr, ExtractTablesFromSchema as Pt, RankIndexDefinition as Q, TableName as Qn, OrmLifecycleChange as Qt, getForeignKeys as R, unique as Rn, HasDefault as Rr, RelationsBuilder as Rt, MigrationStep as S, ConvexVectorIndexConfig as Sn, not as Sr, OrderByClause as St, buildMigrationPlan as T, rankIndex as Tn, or as Tr, PredicateWhereIndexConfig as Tt, extractRelationsConfig as U, Brand as Un, TableRelationalConfig as Ut, RlsMode as V, text as Vn, NotNull as Vr, RelationsBuilderConfigValue as Vt, CountBackfillChunkArgs as W, Columns as Wn, TablesRelationalConfig as Wt, AggregateIndexDefinition as X, OrmSchemaRelations as Xn, ConvexTableWithColumns as Xt, CountQueryPlan as Y, OrmSchemaExtensions as Yn, ConvexTable as Yt, CountIndexDefinition as Z, OrmSchemaTriggers as Zn, DiscriminatorBuilderConfig as Zt, MigrationMigrateOne as _, ConvexSearchIndexBuilder as _n, isNull as _r, MutationPaginateConfig as _t, MigrationCancelArgs as a, RlsPolicyConfig as an, and as ar, CountConfig as at, MigrationSet as b, ConvexVectorIndexBuilder as bn, lte as br, MutationReturning as bt, MigrationStatusArgs as c, RlsRole as cn, endsWith as cr, FilterOperators as ct, MigrationDefinition as d, ConvexAggregateIndexBuilder as dn, gt as dr, InferModelFromColumns as dt, TableConfig as en, ExpressionVisitor as er, AggregateConfig as et, MigrationDirection as f, ConvexAggregateIndexBuilderOn as fn, gte as fr, InferSelectModel as ft, MigrationManifestEntry as g, ConvexRankIndexBuilderOn as gn, isNotNull as gr, MutationExecutionMode as gt, MigrationDriftIssue as h, ConvexRankIndexBuilder as hn, isFieldReference as hr, MutationExecuteResult as ht, OrmMigrationCapability as i, RlsPolicy as in, UnaryExpression as ir, BuildRelationResult as it, DatabaseWithQuery as j, ConvexForeignKeyBuilder as jn, ColumnBuilder as jr, VectorSearchProvider as jt, CreateDatabaseOptions as k, ConvexCheckBuilder as kn, $Type as kr, UpdateSet as kt, createMigrationHandlers as l, RlsRoleConfig as ln, eq as lr, GetColumnData as lt, MigrationDocContext as m, ConvexIndexBuilderOn as mn, inArray as mr, MutationExecuteConfig as mt, OrmCapabilities as n, deletion as nn, FilterExpression$1 as nr, AggregateResult as nt, MigrationRunArgs as o, RlsPolicyToOption as on, between as or, CountResult as ot, MigrationDoc as p, ConvexIndexBuilder as pn, ilike as pr, InsertValue as pt, CountBackfillStatusArgs as q, OrmSchemaExtensionTables as qn, ConvexDeletionBuilder as qt, OrmCapability as r, discriminator as rn, LogicalExpression as rr, BuildQueryResult as rt, MigrationRunChunkArgs as s, rlsPolicy as sn, contains as sr, DBQueryConfig as st, OrmAggregateCapability as t, convexTable as tn, FieldReference as tr, AggregateFieldValue as tt, MigrationAppliedState as u, rlsRole as un, fieldRef as ur, InferInsertModel as ut, MigrationPlan as v, ConvexSearchIndexBuilderOn as vn, like as vr, MutationPaginatedResult as vt, MigrationWriteMode as w, index as wn, notInArray as wr, PaginatedResult as wt, MigrationStateMap as x, ConvexVectorIndexBuilderOn as xn, ne as xr, MutationRunMode as xt, MigrationRunStatus as y, ConvexSearchIndexConfig as yn, lt as yr, MutationResult as yt, getUniqueIndexes as z, ConvexTextBuilder as zn, IsPrimaryKey as zr, RelationsBuilderColumnBase as zt };
3781
+ export { RankIndexDefinition as $, TableName as $n, OrmLifecycleChange as $t, CreateDatabaseOptions as A, ConvexCheckBuilder as An, $Type as Ar, UpdateSet as At, getUniqueIndexes as B, ConvexTextBuilder as Bn, IsPrimaryKey as Br, RelationsBuilderColumnBase as Bt, MigrationStep as C, ConvexVectorIndexConfig as Cn, not as Cr, OrderByClause as Ct, defineMigration as D, searchIndex as Dn, startsWith as Dr, ReturningAll as Dt, buildMigrationPlan as E, rankIndex as En, or as Er, PredicateWhereIndexConfig as Et, CascadeMode as F, ConvexUniqueConstraintBuilderOn as Fn, ColumnBuilderTypeConfig as Fr, ExtractTablesFromSchema as Ft, CountBackfillChunkArgs as G, Columns as Gn, TablesRelationalConfig as Gt, RlsMode as H, text as Hn, NotNull as Hr, RelationsBuilderConfigValue as Ht, DeleteMode as I, ConvexUniqueConstraintConfig as In, ColumnBuilderWithTableName as Ir, ExtractTablesWithRelations as It, CountBackfillStatusArgs as J, OrmSchemaExtensionTables as Jn, ConvexDeletionBuilder as Jt, CountBackfillKickoffArgs as K, OrmRuntimeDefaults as Kn, defineRelations as Kt, SerializedFilterExpression as L, check as Ln, ColumnDataType as Lr, ManyConfig as Lt, DatabaseWithQuery as M, ConvexForeignKeyBuilder as Mn, ColumnBuilder as Mr, VectorSearchProvider as Mt, OrmReader as N, ConvexForeignKeyConfig as Nn, ColumnBuilderBaseConfig as Nr, unsetToken as Nt, defineMigrationSet as O, uniqueIndex as On, SystemFieldAliases as Or, ReturningResult as Ot, OrmWriter as P, ConvexUniqueConstraintBuilder as Pn, ColumnBuilderRuntimeConfig as Pr, AnyRelationsBuilderConfig as Pt, CountIndexDefinition as Q, OrmSchemaTriggers as Qn, DiscriminatorBuilderConfig as Qt, getChecks as R, foreignKey as Rn, DrizzleEntity as Rr, OneConfig as Rt, MigrationStateMap as S, ConvexVectorIndexBuilderOn as Sn, ne as Sr, MutationRunMode as St, MigrationWriteMode as T, index as Tn, notInArray as Tr, PaginatedResult as Tt, EdgeMetadata as U, ConvexColumnBuilder as Un, entityKind as Ur, RelationsConfigWithSchema as Ut, RlsContext as V, ConvexTextBuilderInitial as Vn, IsUnique as Vr, RelationsBuilderColumnConfig as Vt, extractRelationsConfig as W, Brand as Wn, TableRelationalConfig as Wt, CountQueryPlan as X, OrmSchemaExtensions as Xn, ConvexTable as Xt, AggregateQueryPlan as Y, OrmSchemaExtensionTriggers as Yn, ConvexDeletionConfig as Yt, AggregateIndexDefinition as Z, OrmSchemaRelations as Zn, ConvexTableWithColumns as Zt, MigrationManifestEntry as _, ConvexRankIndexBuilderOn as _n, isNotNull as _r, MutationExecutionMode as _t, MAX_STATUS_RUN_LIMIT as a, RlsPolicy as an, UnaryExpression as ar, BuildRelationResult as at, MigrationRunStatus as b, ConvexSearchIndexConfig as bn, lt as br, MutationResult as bt, MigrationRunChunkArgs as c, rlsPolicy as cn, contains as cr, DBQueryConfig as ct, MigrationAppliedState as d, rlsRole as dn, fieldRef as dr, InferInsertModel as dt, OrmLifecycleOperation as en, BinaryExpression as er, RankOrderField as et, MigrationDefinition as f, ConvexAggregateIndexBuilder as fn, gt as fr, InferModelFromColumns as ft, MigrationDriftIssue as g, ConvexRankIndexBuilder as gn, isFieldReference as gr, MutationExecuteResult as gt, MigrationDocContext as h, ConvexIndexBuilderOn as hn, inArray as hr, MutationExecuteConfig as ht, OrmMigrationCapability as i, discriminator as in, LogicalExpression as ir, BuildQueryResult as it, DatabaseWithMutations as j, ConvexCheckConfig as jn, AnyColumn as jr, VectorQueryConfig as jt, detectMigrationDrift as k, vectorIndex as kn, SystemFields as kr, ReturningSelection as kt, MigrationStatusArgs as l, RlsRole as ln, endsWith as lr, FilterOperators as lt, MigrationDoc as m, ConvexIndexBuilder as mn, ilike as mr, InsertValue as mt, OrmCapabilities as n, convexTable as nn, FieldReference as nr, AggregateFieldValue as nt, MigrationCancelArgs as o, RlsPolicyConfig as on, and as or, CountConfig as ot, MigrationDirection as p, ConvexAggregateIndexBuilderOn as pn, gte as pr, InferSelectModel as pt, CountBackfillMode as q, OrmSchemaExtensionRelations as qn, defineRelationsPart as qt, OrmCapability as r, deletion as rn, FilterExpression$1 as rr, AggregateResult as rt, MigrationRunArgs as s, RlsPolicyToOption as sn, between as sr, CountResult as st, OrmAggregateCapability as t, TableConfig as tn, ExpressionVisitor as tr, AggregateConfig as tt, createMigrationHandlers as u, RlsRoleConfig as un, eq as ur, GetColumnData as ut, MigrationMigrateOne as v, ConvexSearchIndexBuilder as vn, isNull as vr, MutationPaginateConfig as vt, MigrationTableName as w, aggregateIndex as wn, notBetween as wr, OrderDirection as wt, MigrationSet as x, ConvexVectorIndexBuilder as xn, lte as xr, MutationReturning as xt, MigrationPlan as y, ConvexSearchIndexBuilderOn as yn, like as yr, MutationPaginatedResult as yt, getForeignKeys as z, unique as zn, HasDefault as zr, RelationsBuilder as zt };
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as Columns, D as TableName, E as RlsPolicies, O as createSystemFields, S as getRankIndexes, T as OrmSchemaExtensions, _ as loadEsbuild, a as generateMeta, b as getAggregateIndexes, c as resolveSchemaDefaultExport, f as createProjectJiti, g as loadDotenv, h as loadClackPrompts, i as resolveConfiguredBackend, l as schemaDeclaresAggregateIndexes, m as loadBabelParser, n as withLocalCodegenEnv, o as getConvexConfig, p as CRPC_BUILDER_STUB_SOURCE, r as loadCliConfig, s as collectSchemaTables, t as getLocalBackendEnvVars, u as logger, v as highlighter, w as EnableRLS, x as getIndexes, y as isColorEnabled } from "./local-env-Z8jj6ecD.mjs";
2
+ import { C as Columns, D as TableName, E as RlsPolicies, O as createSystemFields, S as getRankIndexes, T as OrmSchemaExtensions, _ as loadEsbuild, a as generateMeta, b as getAggregateIndexes, c as resolveSchemaDefaultExport, f as createProjectJiti, g as loadDotenv, h as loadClackPrompts, i as resolveConfiguredBackend, l as schemaDeclaresAggregateIndexes, m as loadBabelParser, n as withLocalCodegenEnv, o as getConvexConfig, p as CRPC_BUILDER_STUB_SOURCE, r as loadCliConfig, s as collectSchemaTables, t as getLocalBackendEnvVars, u as logger, v as highlighter, w as EnableRLS, x as getIndexes, y as isColorEnabled } from "./local-env-Dk8RJvt5.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import fs, { existsSync, readFileSync } from "node:fs";
5
5
  import path, { basename, delimiter, dirname, extname, isAbsolute, join, posix, relative, resolve } from "node:path";
@@ -64,7 +64,11 @@ const migrationRunTable = convexTable(MIGRATION_RUN_TABLE, {
64
64
  completedAt: integer(),
65
65
  cancelRequested: boolean().notNull(),
66
66
  lastError: text()
67
- }, (t) => [index("by_run_id").on(t.runId), index("by_status").on(t.status)]);
67
+ }, (t) => [
68
+ index("by_run_id").on(t.runId),
69
+ index("by_status").on(t.status),
70
+ index("by_started_at").on(t.startedAt)
71
+ ]);
68
72
  const migrationStorageTables = {
69
73
  [MIGRATION_STATE_TABLE]: migrationStateTable,
70
74
  [MIGRATION_RUN_TABLE]: migrationRunTable
@@ -250,7 +250,6 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
250
250
  };
251
251
  }, Promise<Record<string, unknown> | undefined>>;
252
252
  findMany: convex_server0.RegisteredQuery<"internal", {
253
- limit?: number | undefined;
254
253
  join?: any;
255
254
  where?: {
256
255
  mode?: "sensitive" | "insensitive" | undefined;
@@ -259,6 +258,7 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
259
258
  field: string;
260
259
  value: string | number | boolean | string[] | number[] | null;
261
260
  }[] | undefined;
261
+ limit?: number | undefined;
262
262
  offset?: number | undefined;
263
263
  sortBy?: {
264
264
  field: string;
@@ -289,7 +289,6 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
289
289
  getLatestJwks: convex_server0.RegisteredAction<"internal", {}, Promise<unknown>>;
290
290
  incrementOne: convex_server0.RegisteredMutation<"internal", {
291
291
  input: {
292
- set?: Record<string, any> | undefined;
293
292
  where?: {
294
293
  mode?: "sensitive" | "insensitive" | undefined;
295
294
  connector?: "AND" | "OR" | undefined;
@@ -297,6 +296,7 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
297
296
  field: string;
298
297
  value: string | number | boolean | string[] | number[] | null;
299
298
  }[] | undefined;
299
+ set?: Record<string, any> | undefined;
300
300
  model: string;
301
301
  increment: Record<string, number>;
302
302
  };
@@ -2089,7 +2089,11 @@ const migrationRunTable = convexTable(MIGRATION_RUN_TABLE, {
2089
2089
  completedAt: integer(),
2090
2090
  cancelRequested: boolean$1().notNull(),
2091
2091
  lastError: text()
2092
- }, (t) => [index("by_run_id").on(t.runId), index("by_status").on(t.status)]);
2092
+ }, (t) => [
2093
+ index("by_run_id").on(t.runId),
2094
+ index("by_status").on(t.status),
2095
+ index("by_started_at").on(t.startedAt)
2096
+ ]);
2093
2097
  const migrationStorageTables = {
2094
2098
  [MIGRATION_STATE_TABLE]: migrationStateTable,
2095
2099
  [MIGRATION_RUN_TABLE]: migrationRunTable
@@ -2805,7 +2809,7 @@ const GENERATED_ORM_RUNTIME_PROCEDURES = [
2805
2809
  {
2806
2810
  exportName: "migrationStatus",
2807
2811
  internal: true,
2808
- type: "mutation"
2812
+ type: "query"
2809
2813
  },
2810
2814
  {
2811
2815
  exportName: "migrationCancel",
@@ -2837,7 +2841,7 @@ const GENERATED_AGGREGATE_RUNTIME_PROCEDURES = [
2837
2841
  {
2838
2842
  exportName: "aggregateBackfillStatus",
2839
2843
  internal: true,
2840
- type: "mutation"
2844
+ type: "query"
2841
2845
  }
2842
2846
  ];
2843
2847
  function listFilesRecursive(cwd, relDir = "") {
@@ -3413,7 +3417,7 @@ import type {
3413
3417
  MutationCtx as ServerMutationCtx,
3414
3418
  QueryCtx as ServerQueryCtx,
3415
3419
  } from ${serverTypesImportLiteral};
3416
- import { httpAction, internalMutation } from ${serverTypesImportLiteral};
3420
+ import { httpAction, internalMutation, internalQuery } from ${serverTypesImportLiteral};
3417
3421
  import schema from ${schemaImportLiteral};
3418
3422
  import { procedureNames } from ${procedureNamesImportLiteral};
3419
3423
  ${migrationsImportLine}
@@ -3433,6 +3437,7 @@ export const orm = createOrm({
3433
3437
  schema: ormSchema,
3434
3438
  ormFunctions,
3435
3439
  ${capabilitiesConfigLine}${migrationsConfigLine} internalMutation,
3440
+ internalQuery,
3436
3441
  });
3437
3442
 
3438
3443
  export type OrmCtx<Ctx extends ServerQueryCtx | ServerMutationCtx = ServerQueryCtx> = GenericOrmCtx<Ctx, typeof ormSchema>;
@@ -3476,7 +3481,7 @@ function emitGeneratedAggregateFile(outputFile, functionsDir) {
3476
3481
  import { createOrm, type OrmFunctions } from 'kitcn/orm';
3477
3482
  import { aggregateCapability } from 'kitcn/orm/aggregate-index';
3478
3483
  import { createGeneratedFunctionReference } from 'kitcn/server';
3479
- import { internalMutation } from ${serverTypesImportLiteral};
3484
+ import { internalMutation, internalQuery } from ${serverTypesImportLiteral};
3480
3485
  import schema from ${schemaImportLiteral};
3481
3486
 
3482
3487
  const ormFunctions: OrmFunctions = {
@@ -3490,6 +3495,7 @@ const orm = createOrm({
3490
3495
  ormFunctions,
3491
3496
  capabilities: [aggregateCapability()],
3492
3497
  internalMutation,
3498
+ internalQuery,
3493
3499
  });
3494
3500
 
3495
3501
  export const {
@@ -1,4 +1,4 @@
1
- import { $ as RankOrderField, G as CountBackfillKickoffArgs, J as AggregateQueryPlan, K as CountBackfillMode, Q as RankIndexDefinition, W as CountBackfillChunkArgs, X as AggregateIndexDefinition, Y as CountQueryPlan, Z as CountIndexDefinition, q as CountBackfillStatusArgs, r as OrmCapability } from "../../capabilities-DkfnnNp7.js";
1
+ import { $ as RankIndexDefinition, G as CountBackfillChunkArgs, J as CountBackfillStatusArgs, K as CountBackfillKickoffArgs, Q as CountIndexDefinition, X as CountQueryPlan, Y as AggregateQueryPlan, Z as AggregateIndexDefinition, et as RankOrderField, q as CountBackfillMode, r as OrmCapability } from "../../capabilities-6PZBmvc8.js";
2
2
 
3
3
  //#region src/orm/aggregate-index/capability.d.ts
4
4
  /**
@@ -1,7 +1,76 @@
1
1
  import { t as DirectAggregate } from "../../runtime-CcOvOf4K.js";
2
2
  import { a as Columns } from "../../table-CX2lnX7e.js";
3
- import { Et as usesSystemCreatedAtAlias, Tt as PUBLIC_CREATED_AT_FIELD, Z as normalizeTemporalComparableValue, a as AGGREGATE_STATE_TABLE, c as getAggregateIndexDefinitions, d as COUNT_ERROR, i as AGGREGATE_RANK_TREE_TABLE, l as getRankIndexDefinitions, m as createError, mt as mapWithConcurrency, n as AGGREGATE_EXTREMA_TABLE, r as AGGREGATE_MEMBER_TABLE, s as rankAggregateName, t as AGGREGATE_BUCKET_TABLE, u as AGGREGATE_ERROR, wt as INTERNAL_CREATION_TIME_FIELD } from "../../schema-D95Z3Kss.js";
3
+ import { Dt as usesSystemCreatedAtAlias, Et as PUBLIC_CREATED_AT_FIELD, Q as normalizeTemporalComparableValue, Tt as INTERNAL_CREATION_TIME_FIELD, a as AGGREGATE_STATE_TABLE, c as getAggregateIndexDefinitions, d as COUNT_ERROR, ht as mapWithConcurrency, i as AGGREGATE_RANK_TREE_TABLE, l as getRankIndexDefinitions, m as createError, n as AGGREGATE_EXTREMA_TABLE, r as AGGREGATE_MEMBER_TABLE, s as rankAggregateName, t as AGGREGATE_BUCKET_TABLE, u as AGGREGATE_ERROR } from "../../schema-CzdjX7nx.js";
4
4
 
5
+ //#region src/orm/transaction-cache.ts
6
+ /**
7
+ * Per-transaction memo storage for the ORM.
8
+ *
9
+ * The ORM already has isolate-, execution-, statement- and row-scoped memos.
10
+ * The lifetime it lacked is the one a hook needs: `prependWriteBarrier` is
11
+ * built inside `createOrmDbLifecycle`, which `createOrm` runs at module scope,
12
+ * so a flag in that closure lives as long as the isolate and would leak an
13
+ * answer from one transaction into the next.
14
+ *
15
+ * Deliberately dependency-free, for the same reason as `write-fanout`:
16
+ * `aggregate-index/runtime` is contractually unreachable from `orm/index`
17
+ * (`import-graph.test.ts`), so importing `lifecycle` here to read one symbol
18
+ * would drag the trigger runtime into the aggregate entry's bundle.
19
+ * `Symbol.for` is registry-based, so re-declaring the key resolves to the same
20
+ * symbol `lifecycle` installs.
21
+ */
22
+ const ORMLIFECYCLE_INNER_DB = Symbol.for("kitcn:OrmLifecycleInnerDB");
23
+ /**
24
+ * The object whose identity stands in for "this transaction".
25
+ *
26
+ * Convex builds `ctx.db` fresh on every UDF invocation, so it can never be
27
+ * shared by two transactions. `getOrmLifecycleInnerDb` cannot be used on its
28
+ * own: the lifecycle refuses to wrap readers and returns a no-op wrapper for
29
+ * schemas with no triggers and no aggregate indexes, so the inner-db symbol is
30
+ * absent for every query and for most mutations. Resolving through it when it
31
+ * is there, and falling back to the db itself when it is not, converges on the
32
+ * same raw writer from the main scope, `skipRules`, `withoutTriggers` and the
33
+ * scheduled workers.
34
+ *
35
+ * A nested `ctx.runMutation` shares the transaction but gets its own `ctx.db`,
36
+ * so it starts a fresh memo. That direction only costs extra reads.
37
+ */
38
+ const resolveTransactionAnchor = (db) => {
39
+ if (typeof db !== "object" || db === null) return;
40
+ const inner = db[ORMLIFECYCLE_INNER_DB];
41
+ return typeof inner === "object" && inner !== null ? inner : db;
42
+ };
43
+ /**
44
+ * One memo namespace with transaction lifetime.
45
+ *
46
+ * The store is a `WeakMap` keyed on the anchor rather than a slot on the db,
47
+ * because `createDatabase` promises not to mutate the `ctx.db` it was handed.
48
+ * Entries die with the transaction's db object.
49
+ *
50
+ * Callers own staleness: only memoize a fact that nothing inside the
51
+ * transaction can invalidate.
52
+ */
53
+ const createOrmTransactionMemo = () => {
54
+ const byTransaction = /* @__PURE__ */ new WeakMap();
55
+ return {
56
+ get(db, key) {
57
+ const anchor = resolveTransactionAnchor(db);
58
+ return anchor ? byTransaction.get(anchor)?.get(key) : void 0;
59
+ },
60
+ set(db, key, value) {
61
+ const anchor = resolveTransactionAnchor(db);
62
+ if (!anchor) return;
63
+ const existing = byTransaction.get(anchor);
64
+ if (existing) {
65
+ existing.set(key, value);
66
+ return;
67
+ }
68
+ byTransaction.set(anchor, new Map([[key, value]]));
69
+ }
70
+ };
71
+ };
72
+
73
+ //#endregion
5
74
  //#region src/orm/aggregate-index/runtime.ts
6
75
  const UNDEFINED_SENTINEL = "__kitcnUndefined";
7
76
  const FLOAT64_SIGN_BIT = 1n << 63n;
@@ -1247,8 +1316,36 @@ const getCountState = async (db, tableName, indexName, kind = AGGREGATE_STATE_KI
1247
1316
  tableName: tableKey
1248
1317
  };
1249
1318
  };
1319
+ /**
1320
+ * Bumped by every `setCountState`, which is the only writer that can move a
1321
+ * state row into CLEARING.
1322
+ *
1323
+ * Isolate-scoped mutable state is exactly what the write barrier must not rely
1324
+ * on, so this counter only ever invalidates: a bump can turn a cache hit into a
1325
+ * re-read, never a re-read into a hit. That direction stays safe when a
1326
+ * mutation reaches the backfill through `ctx.runMutation`, whose nested
1327
+ * invocation gets its own `ctx.db` and so cannot be reached by any
1328
+ * transaction-scoped invalidation.
1329
+ */
1330
+ let aggregateStateGeneration = 0;
1331
+ /**
1332
+ * Tables whose CLEARING range was read and found empty, with the generation
1333
+ * that read was valid at.
1334
+ *
1335
+ * The barrier runs from a before-hook, once per written row, so a 40-row
1336
+ * statement re-scanned the same empty range 40 times. Only the empty result is
1337
+ * memoized: a blocking state throws, so it never loops, and refusing to cache
1338
+ * it keeps `convex/orm/count.test.ts`'s interleaved state writes honest.
1339
+ */
1340
+ const clearingRangeEmptyAtGeneration = createOrmTransactionMemo();
1250
1341
  const assertAggregateIndexesWritable = async (db, tableName, metricIndexNames, rankIndexNames) => {
1342
+ const generation = aggregateStateGeneration;
1343
+ if (clearingRangeEmptyAtGeneration.get(db, tableName) === generation) return;
1251
1344
  const clearingStates = await db.query(AGGREGATE_STATE_TABLE).withIndex("by_table_status", (q) => q.eq("tableKey", tableName).eq("status", COUNT_STATUS_CLEARING)).collect();
1345
+ if (clearingStates.length === 0) {
1346
+ clearingRangeEmptyAtGeneration.set(db, tableName, generation);
1347
+ return;
1348
+ }
1252
1349
  const metricNames = new Set(metricIndexNames);
1253
1350
  const rankNames = new Set(rankIndexNames);
1254
1351
  const blockingState = clearingStates.find((state) => state.kind === AGGREGATE_STATE_KIND_RANK ? rankNames.has(state.indexName) : metricNames.has(state.indexName));
@@ -1269,6 +1366,7 @@ const isIndexStateDrained = async (db, kind, tableName, indexName) => {
1269
1366
  return bucket === null && extrema === null;
1270
1367
  };
1271
1368
  const setCountState = async (db, nextState, kind = AGGREGATE_STATE_KIND_METRIC) => {
1369
+ aggregateStateGeneration += 1;
1272
1370
  const existing = await getCountState(db, nextState.tableName, nextState.indexName, kind);
1273
1371
  const payload = {
1274
1372
  kind,
@@ -1,5 +1,5 @@
1
- import { $n as BinaryExpression, $t as OrmLifecycleOperation, A as DatabaseWithMutations, An as ConvexCheckConfig, Ar as AnyColumn, At as VectorQueryConfig, B as RlsContext, Bn as ConvexTextBuilderInitial, Br as IsUnique, Bt as RelationsBuilderColumnConfig, C as MigrationTableName, Cn as aggregateIndex, Cr as notBetween, Ct as OrderDirection, D as defineMigrationSet, Dn as uniqueIndex, Dt as ReturningResult, E as defineMigration, En as searchIndex, Er as startsWith, Et as ReturningAll, Fn as ConvexUniqueConstraintConfig, Fr as ColumnBuilderWithTableName, Ft as ExtractTablesWithRelations, Gt as defineRelations, H as EdgeMetadata, In as check, Ir as ColumnDataType, It as ManyConfig, Jt as ConvexDeletionConfig, Kt as defineRelationsPart, Ln as foreignKey, Lr as DrizzleEntity, Lt as OneConfig, M as OrmReader$1, Mn as ConvexForeignKeyConfig, Mr as ColumnBuilderBaseConfig, Mt as unsetToken, N as OrmWriter$1, Nn as ConvexUniqueConstraintBuilder, Nr as ColumnBuilderRuntimeConfig, O as detectMigrationDrift, On as vectorIndex, Or as SystemFields, Ot as ReturningSelection, Pn as ConvexUniqueConstraintBuilderOn, Pr as ColumnBuilderTypeConfig, Pt as ExtractTablesFromSchema, Qn as TableName, Qt as OrmLifecycleChange, Rn as unique, Rr as HasDefault, Rt as RelationsBuilder, S as MigrationStep, Sn as ConvexVectorIndexConfig, Sr as not, St as OrderByClause, T as buildMigrationPlan, Tn as rankIndex, Tr as or, Tt as PredicateWhereIndexConfig, U as extractRelationsConfig, Un as Brand, Ut as TableRelationalConfig, V as RlsMode, Vn as text, Vr as NotNull, Wn as Columns, Wt as TablesRelationalConfig, Xn as OrmSchemaRelations, Xt as ConvexTableWithColumns, Yn as OrmSchemaExtensions, Yt as ConvexTable, Zn as OrmSchemaTriggers, Zt as DiscriminatorBuilderConfig, _ as MigrationMigrateOne, _n as ConvexSearchIndexBuilder, _r as isNull, _t as MutationPaginateConfig, an as RlsPolicyConfig, ar as and, at as CountConfig, b as MigrationSet, bn as ConvexVectorIndexBuilder, br as lte, bt as MutationReturning, cn as RlsRole, cr as endsWith, ct as FilterOperators, d as MigrationDefinition, dn as ConvexAggregateIndexBuilder, dr as gt, dt as InferModelFromColumns, en as TableConfig, er as ExpressionVisitor, et as AggregateConfig, f as MigrationDirection, fn as ConvexAggregateIndexBuilderOn, fr as gte, ft as InferSelectModel, g as MigrationManifestEntry, gn as ConvexRankIndexBuilderOn, gr as isNotNull, gt as MutationExecutionMode, h as MigrationDriftIssue, hn as ConvexRankIndexBuilder, hr as isFieldReference, ht as MutationExecuteResult, i as OrmMigrationCapability, in as RlsPolicy, ir as UnaryExpression, it as BuildRelationResult, j as DatabaseWithQuery, jn as ConvexForeignKeyBuilder, jr as ColumnBuilder, jt as VectorSearchProvider, kn as ConvexCheckBuilder, kt as UpdateSet, ln as RlsRoleConfig, lr as eq, lt as GetColumnData, m as MigrationDocContext, mn as ConvexIndexBuilderOn, mr as inArray, mt as MutationExecuteConfig, n as OrmCapabilities, nn as deletion, nr as FilterExpression, nt as AggregateResult, on as RlsPolicyToOption, or as between, ot as CountResult, p as MigrationDoc, pn as ConvexIndexBuilder, pr as ilike, pt as InsertValue, qn as OrmSchemaExtensionTables, qt as ConvexDeletionBuilder, r as OrmCapability, rn as discriminator, rr as LogicalExpression, rt as BuildQueryResult, sn as rlsPolicy, sr as contains, st as DBQueryConfig, t as OrmAggregateCapability, tn as convexTable, tr as FieldReference, tt as AggregateFieldValue, u as MigrationAppliedState, un as rlsRole, ur as fieldRef, ut as InferInsertModel, v as MigrationPlan, vn as ConvexSearchIndexBuilderOn, vr as like, vt as MutationPaginatedResult, w as MigrationWriteMode, wn as index, wr as notInArray, wt as PaginatedResult, x as MigrationStateMap, xn as ConvexVectorIndexBuilderOn, xr as ne, xt as MutationRunMode, y as MigrationRunStatus, yn as ConvexSearchIndexConfig, yr as lt, yt as MutationResult, zn as ConvexTextBuilder, zr as IsPrimaryKey, zt as RelationsBuilderColumnBase } from "../capabilities-DkfnnNp7.js";
2
- import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-CETRjurp.js";
1
+ import { $n as TableName, $t as OrmLifecycleChange, An as ConvexCheckBuilder, At as UpdateSet, Bn as ConvexTextBuilder, Br as IsPrimaryKey, Bt as RelationsBuilderColumnBase, C as MigrationStep, Cn as ConvexVectorIndexConfig, Cr as not, Ct as OrderByClause, D as defineMigration, Dn as searchIndex, Dr as startsWith, Dt as ReturningAll, E as buildMigrationPlan, En as rankIndex, Er as or, Et as PredicateWhereIndexConfig, Fn as ConvexUniqueConstraintBuilderOn, Fr as ColumnBuilderTypeConfig, Ft as ExtractTablesFromSchema, Gn as Columns, Gt as TablesRelationalConfig, H as RlsMode, Hn as text, Hr as NotNull, In as ConvexUniqueConstraintConfig, Ir as ColumnBuilderWithTableName, It as ExtractTablesWithRelations, Jn as OrmSchemaExtensionTables, Jt as ConvexDeletionBuilder, Kt as defineRelations, Ln as check, Lr as ColumnDataType, Lt as ManyConfig, M as DatabaseWithQuery, Mn as ConvexForeignKeyBuilder, Mr as ColumnBuilder, Mt as VectorSearchProvider, N as OrmReader$1, Nn as ConvexForeignKeyConfig, Nr as ColumnBuilderBaseConfig, Nt as unsetToken, O as defineMigrationSet, On as uniqueIndex, Ot as ReturningResult, P as OrmWriter$1, Pn as ConvexUniqueConstraintBuilder, Pr as ColumnBuilderRuntimeConfig, Qn as OrmSchemaTriggers, Qt as DiscriminatorBuilderConfig, Rn as foreignKey, Rr as DrizzleEntity, Rt as OneConfig, S as MigrationStateMap, Sn as ConvexVectorIndexBuilderOn, Sr as ne, St as MutationRunMode, T as MigrationWriteMode, Tn as index, Tr as notInArray, Tt as PaginatedResult, U as EdgeMetadata, V as RlsContext, Vn as ConvexTextBuilderInitial, Vr as IsUnique, Vt as RelationsBuilderColumnConfig, W as extractRelationsConfig, Wn as Brand, Wt as TableRelationalConfig, Xn as OrmSchemaExtensions, Xt as ConvexTable, Yt as ConvexDeletionConfig, Zn as OrmSchemaRelations, Zt as ConvexTableWithColumns, _ as MigrationManifestEntry, _n as ConvexRankIndexBuilderOn, _r as isNotNull, _t as MutationExecutionMode, an as RlsPolicy, ar as UnaryExpression, at as BuildRelationResult, b as MigrationRunStatus, bn as ConvexSearchIndexConfig, br as lt, bt as MutationResult, cn as rlsPolicy, cr as contains, ct as DBQueryConfig, d as MigrationAppliedState, dn as rlsRole, dr as fieldRef, dt as InferInsertModel, en as OrmLifecycleOperation, er as BinaryExpression, f as MigrationDefinition, fn as ConvexAggregateIndexBuilder, fr as gt, ft as InferModelFromColumns, g as MigrationDriftIssue, gn as ConvexRankIndexBuilder, gr as isFieldReference, gt as MutationExecuteResult, h as MigrationDocContext, hn as ConvexIndexBuilderOn, hr as inArray, ht as MutationExecuteConfig, i as OrmMigrationCapability, in as discriminator, ir as LogicalExpression, it as BuildQueryResult, j as DatabaseWithMutations, jn as ConvexCheckConfig, jr as AnyColumn, jt as VectorQueryConfig, k as detectMigrationDrift, kn as vectorIndex, kr as SystemFields, kt as ReturningSelection, ln as RlsRole, lr as endsWith, lt as FilterOperators, m as MigrationDoc, mn as ConvexIndexBuilder, mr as ilike, mt as InsertValue, n as OrmCapabilities, nn as convexTable, nr as FieldReference, nt as AggregateFieldValue, on as RlsPolicyConfig, or as and, ot as CountConfig, p as MigrationDirection, pn as ConvexAggregateIndexBuilderOn, pr as gte, pt as InferSelectModel, qt as defineRelationsPart, r as OrmCapability, rn as deletion, rr as FilterExpression, rt as AggregateResult, sn as RlsPolicyToOption, sr as between, st as CountResult, t as OrmAggregateCapability, tn as TableConfig, tr as ExpressionVisitor, tt as AggregateConfig, un as RlsRoleConfig, ur as eq, ut as GetColumnData, v as MigrationMigrateOne, vn as ConvexSearchIndexBuilder, vr as isNull, vt as MutationPaginateConfig, w as MigrationTableName, wn as aggregateIndex, wr as notBetween, wt as OrderDirection, x as MigrationSet, xn as ConvexVectorIndexBuilder, xr as lte, xt as MutationReturning, y as MigrationPlan, yn as ConvexSearchIndexBuilderOn, yr as like, yt as MutationPaginatedResult, zn as unique, zr as HasDefault, zt as RelationsBuilder } from "../capabilities-6PZBmvc8.js";
2
+ import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-CX5-0M5p.js";
3
3
  import { i as pretendRequired, n as deprecated, r as pretend } from "../validators-wOIjhkfN.js";
4
4
  import { a as QueryCtxWithPreferredOrmQueryTable, i as QueryCtxWithOrmQueryTable, n as LookupByIdResultByCtx, o as getByIdWithOrmQueryFallback, r as QueryCtxWithOptionalOrmQueryTable, t as DocByCtx } from "../query-context-DJONf8X5.js";
5
5
  import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchemaDefinition } from "convex/server";
package/dist/orm/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { A as integer, C as index, D as vectorIndex, E as uniqueIndex, F as unionOf, I as ConvexColumnBuilder, L as entityKind, M as custom, N as json, O as text, P as objectOf, S as aggregateIndex, T as searchIndex, a as Columns, b as RlsPolicy, c as OrmSchemaDefinition, d as OrmSchemaExtensionTriggers, f as OrmSchemaExtensions, g as RlsPolicies, h as OrmSchemaTriggers, i as Brand, j as arrayOf, k as createSystemFields, l as OrmSchemaExtensionRelations, m as OrmSchemaRelations, n as deletion, o as EnableRLS, p as OrmSchemaOptions, r as discriminator, s as OrmContext, t as convexTable, u as OrmSchemaExtensionTables, v as TableName, w as rankIndex, x as rlsPolicy, y as TablePolymorphic } from "../table-CX2lnX7e.js";
2
- import { d as boolean, i as detectMigrationDrift, l as migrationExtension, n as defineMigration, r as defineMigrationSet, t as buildMigrationPlan } from "../definitions-Dzk8mSTL.js";
2
+ import { d as boolean, i as detectMigrationDrift, l as migrationExtension, n as defineMigration, r as defineMigrationSet, t as buildMigrationPlan } from "../definitions-DS8ZDc74.js";
3
3
  import { a as pretendRequired, i as pretend, n as deprecated } from "../validators-CIoUYCqO.js";
4
4
  import { t as id } from "../id-CuSfWa5q.js";
5
5
  import { A as or, C as matchLikePattern, D as notIlike, E as notBetween, O as notInArray, S as lte, T as not, _ as isFieldReference, a as between, b as like, c as endsWith, d as filterValueInList, f as filterValuesEqual, g as inArray, h as ilike, i as arrayOverlaps, j as startsWith, k as notLike, l as eq, m as gte, n as arrayContained, o as column, p as gt, r as arrayContains, s as contains, t as and, u as fieldRef, v as isNotNull, w as ne, x as lt, y as isNull } from "../filter-expression-Dydt8wS0.js";
6
6
  import { a as indexKeyWithinBounds, c as streamIndexRange, i as getIndexFields, l as isUnsetToken, n as EmptyStream, o as mergedStream, r as QueryStream, s as stream, t as getByIdWithOrmQueryFallback, u as unsetToken } from "../query-context-DOm5Xm3H.js";
7
- import { $ as resolveOrmRuntimeDefaults, A as enforceUniqueIndexes, B as getMutationAsyncDelayMs, C as collectPrimaryIdLookupRows, Ct as CREATED_AT_MIGRATION_MESSAGE, D as enforceCheckConstraints, E as encodeUndefinedDeep, Et as usesSystemCreatedAtAlias, F as evaluateFilter, G as getTableDeleteConfig, H as getMutationExecutionMode, I as extractPrimaryIdLookup, J as hardDeleteRow, K as getTableName, L as getChecks, M as ensureNonNullValues, N as ensureNullableColumns, O as enforceForeignKeys, P as evaluateCheckConstraintTriState, Q as patchReferencingRows, R as getColumnName$1, S as collectMutationRowsBounded, St as resolveIndexOrderPushdown, T as deserializeFilterExpression, Tt as PUBLIC_CREATED_AT_FIELD, U as getOrmContext, V as getMutationCollectionLimits, W as getTableColumns$2, X as normalizeDateFieldsForWrite, Y as hydrateDateFieldsForRead, Z as normalizeTemporalComparableValue, _ as applyDefaults, _t as findSearchIndexByName, at as stripUnsetFields, b as buildForeignKeyGraph, bt as getIndexes, c as getAggregateIndexDefinitions, ct as unsetFieldsOf, d as COUNT_ERROR, dt as compileConvexFilter, et as returningSelectionReadsCreationTime, f as createAggregateError, ft as convexAnd, g as ensureCountAllowedForRls, gt as findRelationIndex, h as ensureAggregateAllowedForRls, ht as findIndexForColumns, it as splitReturningSelection, j as ensureDefaultColumns, k as enforcePolymorphicWrite, l as getRankIndexDefinitions, lt as hasLifecycleHooks, mt as mapWithConcurrency, nt as serializeFilterExpression, o as aggregateExtension, ot as takeRowsWithinByteBudget, p as createCountError, pt as isConvexEnforceableFilter, q as getUniqueIndexes, rt as softDeleteRow, st as toConvexFilter, tt as selectReturningRowWithHydration, u as AGGREGATE_ERROR, ut as markLifecycleHookedTables, v as applyIncomingForeignKeyActionsOnDelete, vt as findVectorIndexByName, w as decodeUndefinedDeep, wt as INTERNAL_CREATION_TIME_FIELD, x as canUsePrimaryIdLookupCursor, xt as getRankIndexes, y as applyIncomingForeignKeyActionsOnUpdate, yt as getAggregateIndexes, z as getForeignKeys } from "../schema-D95Z3Kss.js";
7
+ import { $ as patchReferencingRows, A as enforcePolymorphicWrite, B as getForeignKeys, C as collectPrimaryIdLookupRows, Ct as resolveIndexOrderPushdown, D as encodeUndefinedDeep, Dt as usesSystemCreatedAtAlias, E as deserializeFilterExpression, Et as PUBLIC_CREATED_AT_FIELD, F as evaluateCheckConstraintTriState, G as getTableColumns$2, H as getMutationCollectionLimits, I as evaluateFilter, J as getUniqueIndexes, K as getTableDeleteConfig, L as extractPrimaryIdLookup, M as ensureDefaultColumns, N as ensureNonNullValues, O as enforceCheckConstraints, P as ensureNullableColumns, Q as normalizeTemporalComparableValue, R as getChecks, S as collectMutationRowsBounded, St as getRankIndexes, T as decodeUndefinedDeep, Tt as INTERNAL_CREATION_TIME_FIELD, U as getMutationExecutionMode, V as getMutationAsyncDelayMs, W as getOrmContext, X as hydrateDateFieldsForRead, Y as hardDeleteRow, Z as normalizeDateFieldsForWrite, _ as applyDefaults, _t as findRelationIndex, at as splitReturningSelection, b as buildForeignKeyGraph, bt as getAggregateIndexes, c as getAggregateIndexDefinitions, ct as toConvexFilter, d as COUNT_ERROR, dt as markLifecycleHookedTables, et as resolveOrmRuntimeDefaults, f as createAggregateError, ft as compileConvexFilter, g as ensureCountAllowedForRls, gt as findIndexForColumns, h as ensureAggregateAllowedForRls, ht as mapWithConcurrency, it as softDeleteRow, j as enforceUniqueIndexes, k as enforceForeignKeys, l as getRankIndexDefinitions, lt as unsetFieldsOf, mt as isConvexEnforceableFilter, nt as selectReturningRowWithHydration, o as aggregateExtension, ot as stripUnsetFields, p as createCountError, pt as convexAnd, q as getTableName, rt as serializeFilterExpression, st as takeRowsWithinByteBudget, tt as returningSelectionReadsCreationTime, u as AGGREGATE_ERROR, ut as hasLifecycleHooks, v as applyIncomingForeignKeyActionsOnDelete, vt as findSearchIndexByName, w as createForeignKeyProbeMemo, wt as CREATED_AT_MIGRATION_MESSAGE, x as canUsePrimaryIdLookupCursor, xt as getIndexes, y as applyIncomingForeignKeyActionsOnUpdate, yt as findVectorIndexByName, z as getColumnName$1 } from "../schema-CzdjX7nx.js";
8
8
  import { t as defineSchemaExtension } from "../extensions-Blzsyekm.js";
9
9
  import { compareValues, convexToJson, jsonToConvex, v } from "convex/values";
10
- import { defineSchema as defineSchema$1, internalActionGeneric, internalMutationGeneric } from "convex/server";
10
+ import { defineSchema as defineSchema$1, internalActionGeneric, internalMutationGeneric, internalQueryGeneric } from "convex/server";
11
11
 
12
12
  //#region src/orm/builders/bigint.ts
13
13
  /**
@@ -1543,6 +1543,22 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
1543
1543
  * hands it to the next run rather than re-probing.
1544
1544
  */
1545
1545
  _aggregateIndexReadinessByKey = /* @__PURE__ */ new Map();
1546
+ /**
1547
+ * Documents resolved by id during one execution, keyed on the normalized id.
1548
+ *
1549
+ * A relation `where` never compiles into the index plan, so it runs as a
1550
+ * post-fetch membership predicate over a residual stream — one row at a time.
1551
+ * Every de-duplication map inside the relation loaders is scoped to the batch
1552
+ * it is handed, and a batch of one makes all of them no-ops, so a page whose
1553
+ * rows share two parents re-read those two documents once per scanned row.
1554
+ *
1555
+ * Scoped to one execution, like `_rlsPolicyResolution`: `_executionClaimed`
1556
+ * diverts later executions to a fresh instance, and an execution reads
1557
+ * without writing, so a hit is always the document the caller would have read
1558
+ * for itself. It must not be handed to the next run by `_forExecution` — an
1559
+ * intervening write would make it stale.
1560
+ */
1561
+ _documentByNormalizedId = /* @__PURE__ */ new Map();
1546
1562
  constructor(schema, tableConfig, edgeMetadata, db, config, mode, _allEdges, rls, relationLoading, vectorSearchProvider, configuredIndex, countIndexReadiness) {
1547
1563
  super();
1548
1564
  this.schema = schema;
@@ -4428,7 +4444,15 @@ var GelRelationalQuery = class GelRelationalQuery extends QueryPromise {
4428
4444
  async _getById(tableName, id) {
4429
4445
  if (id === null || id === void 0) return null;
4430
4446
  const normalizedId = this.db.normalizeId(tableName, id);
4431
- return normalizedId === null ? null : await this.db.get(normalizedId);
4447
+ if (normalizedId === null) return null;
4448
+ const existing = this._documentByNormalizedId.get(normalizedId);
4449
+ if (existing) return await existing;
4450
+ const pending = Promise.resolve(this.db.get(normalizedId)).catch((error) => {
4451
+ this._documentByNormalizedId.delete(normalizedId);
4452
+ throw error;
4453
+ });
4454
+ this._documentByNormalizedId.set(normalizedId, pending);
4455
+ return await pending;
4432
4456
  }
4433
4457
  _getRelationConcurrency() {
4434
4458
  const value = this.relationLoading?.concurrency;
@@ -5552,6 +5576,8 @@ var ConvexInsertBuilder = class extends QueryPromise {
5552
5576
  const ormContext = getOrmContext(this.db);
5553
5577
  const tableName = getTableName(this.table);
5554
5578
  const returningSelection = this.returningFields && this.returningFields !== true ? splitReturningSelection(this.returningFields) : void 0;
5579
+ const statementTableName = getTableName(this.table);
5580
+ const probedForeignIds = hasLifecycleHooks(this.db, statementTableName) ? void 0 : createForeignKeyProbeMemo();
5555
5581
  const derivedRowSatisfiesCount = returningSelection?.countSelection === void 0 || !countedEdgesReadCreationTime(ormContext?.edgeMetadata, tableName) && !isRlsEnabled(this.table);
5556
5582
  const canDerivePostImage = returningSelection !== void 0 && !hasLifecycleHooks(this.db, tableName) && !returningSelectionReadsCreationTime(returningSelection.columnSelection) && derivedRowSatisfiesCount;
5557
5583
  const results = [];
@@ -5566,14 +5592,17 @@ var ConvexInsertBuilder = class extends QueryPromise {
5566
5592
  row: preparedValue,
5567
5593
  rls
5568
5594
  })) throw new Error(`RLS policy violation for insert on table "${tableName}"`);
5569
- const conflictResult = await this.handleConflict(preparedValue, rlsResolution);
5595
+ const conflictResult = await this.handleConflict(preparedValue, rlsResolution, probedForeignIds);
5570
5596
  if (conflictResult?.status === "skip") continue;
5571
5597
  if (conflictResult?.status === "updated") {
5572
5598
  if (conflictResult.row && this.returningFields) results.push(await this.resolveReturningRow(conflictResult.row, returningSelection, ormContext));
5573
5599
  continue;
5574
5600
  }
5575
5601
  enforceCheckConstraints(this.table, preparedValue);
5576
- await enforceForeignKeys(this.db, this.table, preparedValue, { changedFields: new Set(Object.keys(preparedValue)) });
5602
+ await enforceForeignKeys(this.db, this.table, preparedValue, {
5603
+ changedFields: new Set(Object.keys(preparedValue)),
5604
+ probed: probedForeignIds
5605
+ });
5577
5606
  await enforceUniqueIndexes(this.db, this.table, preparedValue, { changedFields: new Set(Object.keys(preparedValue)) });
5578
5607
  const id = await this.db.insert(tableName, preparedValue);
5579
5608
  if (!this.returningFields) continue;
@@ -5592,7 +5621,7 @@ var ConvexInsertBuilder = class extends QueryPromise {
5592
5621
  if (returningSelection?.countSelection) selected._count = await this._loadReturningCount(row, returningSelection.countSelection, ormContext);
5593
5622
  return selected;
5594
5623
  }
5595
- async handleConflict(value, rlsResolution) {
5624
+ async handleConflict(value, rlsResolution, probedForeignIds) {
5596
5625
  if (!this.conflictConfig) return;
5597
5626
  const { action, config } = this.conflictConfig;
5598
5627
  const targetColumns = Array.isArray(config.target) ? config.target : config.target ? [config.target] : [];
@@ -5660,7 +5689,10 @@ var ConvexInsertBuilder = class extends QueryPromise {
5660
5689
  };
5661
5690
  enforceCheckConstraints(this.table, candidate);
5662
5691
  return candidate;
5663
- })(), { changedFields: new Set(Object.keys(writeSet)) });
5692
+ })(), {
5693
+ changedFields: new Set(Object.keys(writeSet)),
5694
+ probed: probedForeignIds
5695
+ });
5664
5696
  await enforceUniqueIndexes(this.db, this.table, {
5665
5697
  ...existing,
5666
5698
  ...writeSet
@@ -7829,6 +7861,7 @@ function createOrm(config) {
7829
7861
  with: withContext
7830
7862
  };
7831
7863
  const mutationBuilder = config.internalMutation ?? internalMutationGeneric;
7864
+ const queryBuilder = config.internalQuery ?? internalQueryGeneric;
7832
7865
  return {
7833
7866
  db,
7834
7867
  with: withContext,
@@ -7894,7 +7927,7 @@ function createOrm(config) {
7894
7927
  handler: ((ctx, args) => countBackfillHandlers().kickoff(ctx, args))
7895
7928
  }),
7896
7929
  aggregateBackfillChunk,
7897
- aggregateBackfillStatus: mutationBuilder({
7930
+ aggregateBackfillStatus: queryBuilder({
7898
7931
  args: v.any(),
7899
7932
  handler: ((ctx, args) => countBackfillHandlers().status(ctx, args))
7900
7933
  }),
@@ -7903,7 +7936,7 @@ function createOrm(config) {
7903
7936
  handler: ((ctx, args) => migrationHandlers().run(ctx, args))
7904
7937
  }),
7905
7938
  migrationRunChunk,
7906
- migrationStatus: mutationBuilder({
7939
+ migrationStatus: queryBuilder({
7907
7940
  args: v.any(),
7908
7941
  handler: ((ctx, args) => migrationHandlers().status(ctx, args))
7909
7942
  }),
@@ -1,3 +1,3 @@
1
- import { C as MigrationTableName, D as defineMigrationSet, E as defineMigration, O as detectMigrationDrift, S as MigrationStep, T as buildMigrationPlan, _ as MigrationMigrateOne, a as MigrationCancelArgs, b as MigrationSet, c as MigrationStatusArgs, d as MigrationDefinition, f as MigrationDirection, g as MigrationManifestEntry, h as MigrationDriftIssue, l as createMigrationHandlers, m as MigrationDocContext, o as MigrationRunArgs, p as MigrationDoc, s as MigrationRunChunkArgs, u as MigrationAppliedState, v as MigrationPlan, w as MigrationWriteMode, x as MigrationStateMap, y as MigrationRunStatus } from "../../capabilities-DkfnnNp7.js";
2
- import { Ct as migrationCapability, dt as MIGRATION_STORAGE_TABLE_NAMES, ft as injectMigrationStorageTables, lt as MIGRATION_RUN_TABLE, mt as migrationStorageTables, pt as migrationExtension, ut as MIGRATION_STATE_TABLE } from "../../where-clause-compiler-CETRjurp.js";
3
- export { MIGRATION_RUN_TABLE, MIGRATION_STATE_TABLE, MIGRATION_STORAGE_TABLE_NAMES, type MigrationAppliedState, type MigrationCancelArgs, type MigrationDefinition, type MigrationDirection, type MigrationDoc, type MigrationDocContext, type MigrationDriftIssue, type MigrationManifestEntry, type MigrationMigrateOne, type MigrationPlan, type MigrationRunArgs, type MigrationRunChunkArgs, type MigrationRunStatus, type MigrationSet, type MigrationStateMap, type MigrationStatusArgs, type MigrationStep, type MigrationTableName, type MigrationWriteMode, buildMigrationPlan, createMigrationHandlers, defineMigration, defineMigrationSet, detectMigrationDrift, injectMigrationStorageTables, migrationCapability, migrationExtension, migrationStorageTables };
1
+ import { C as MigrationStep, D as defineMigration, E as buildMigrationPlan, O as defineMigrationSet, S as MigrationStateMap, T as MigrationWriteMode, _ as MigrationManifestEntry, a as MAX_STATUS_RUN_LIMIT, b as MigrationRunStatus, c as MigrationRunChunkArgs, d as MigrationAppliedState, f as MigrationDefinition, g as MigrationDriftIssue, h as MigrationDocContext, k as detectMigrationDrift, l as MigrationStatusArgs, m as MigrationDoc, o as MigrationCancelArgs, p as MigrationDirection, s as MigrationRunArgs, u as createMigrationHandlers, v as MigrationMigrateOne, w as MigrationTableName, x as MigrationSet, y as MigrationPlan } from "../../capabilities-6PZBmvc8.js";
2
+ import { Ct as migrationCapability, dt as MIGRATION_STORAGE_TABLE_NAMES, ft as injectMigrationStorageTables, lt as MIGRATION_RUN_TABLE, mt as migrationStorageTables, pt as migrationExtension, ut as MIGRATION_STATE_TABLE } from "../../where-clause-compiler-CX5-0M5p.js";
3
+ export { MAX_STATUS_RUN_LIMIT, MIGRATION_RUN_TABLE, MIGRATION_STATE_TABLE, MIGRATION_STORAGE_TABLE_NAMES, type MigrationAppliedState, type MigrationCancelArgs, type MigrationDefinition, type MigrationDirection, type MigrationDoc, type MigrationDocContext, type MigrationDriftIssue, type MigrationManifestEntry, type MigrationMigrateOne, type MigrationPlan, type MigrationRunArgs, type MigrationRunChunkArgs, type MigrationRunStatus, type MigrationSet, type MigrationStateMap, type MigrationStatusArgs, type MigrationStep, type MigrationTableName, type MigrationWriteMode, buildMigrationPlan, createMigrationHandlers, defineMigration, defineMigrationSet, detectMigrationDrift, injectMigrationStorageTables, migrationCapability, migrationExtension, migrationStorageTables };
@@ -1,7 +1,15 @@
1
- import { a as MIGRATION_RUN_TABLE, c as injectMigrationStorageTables, i as detectMigrationDrift, l as migrationExtension, n as defineMigration, o as MIGRATION_STATE_TABLE, r as defineMigrationSet, s as MIGRATION_STORAGE_TABLE_NAMES, t as buildMigrationPlan, u as migrationStorageTables } from "../../definitions-Dzk8mSTL.js";
1
+ import { a as MIGRATION_RUN_TABLE, c as injectMigrationStorageTables, i as detectMigrationDrift, l as migrationExtension, n as defineMigration, o as MIGRATION_STATE_TABLE, r as defineMigrationSet, s as MIGRATION_STORAGE_TABLE_NAMES, t as buildMigrationPlan, u as migrationStorageTables } from "../../definitions-DS8ZDc74.js";
2
2
 
3
3
  //#region src/orm/migrations/runtime.ts
4
4
  const DEFAULT_BATCH_SIZE = 128;
5
+ const DEFAULT_STATUS_RUN_LIMIT = 25;
6
+ /**
7
+ * Hard ceiling on how many `migration_run` rows one `status()` call may read.
8
+ *
9
+ * `limit` is caller-supplied, so bounding the query without bounding the
10
+ * argument would just move the unbounded read behind the args surface.
11
+ */
12
+ const MAX_STATUS_RUN_LIMIT = 100;
5
13
  function createMigrationHandlers(params) {
6
14
  const { schema, migrations, getOrm, getChunkRef } = params;
7
15
  const knownTables = new Set(Object.values(schema).map((tableConfig) => tableConfig.name));
@@ -287,12 +295,11 @@ function createMigrationHandlers(params) {
287
295
  status: "noop",
288
296
  reason: "no_migrations_registered"
289
297
  };
290
- const limit = parseOptionalPositiveInteger(args.limit, "limit") ?? 25;
298
+ const limit = Math.min(parseOptionalPositiveInteger(args.limit, "limit") ?? DEFAULT_STATUS_RUN_LIMIT, MAX_STATUS_RUN_LIMIT);
291
299
  const runId = parseOptionalString(args.runId, "runId");
292
300
  const stateRows = await getAllStateRows(ctx.db);
293
- const sortedRuns = [...await getAllRunRows(ctx.db)].sort((left, right) => right.startedAt - left.startedAt);
294
- const selectedRuns = runId ? sortedRuns.filter((entry) => entry.runId === runId).slice(0, 1) : sortedRuns.slice(0, limit);
295
- const activeRun = sortedRuns.find((entry) => entry.status === "running") ?? null;
301
+ const selectedRuns = runId ? await getRunsById(ctx.db, runId) : await getRecentRuns(ctx.db, limit);
302
+ const activeRun = await getActiveRun(ctx.db);
296
303
  const appliedState = toAppliedStateMap(stateRows);
297
304
  const drift = detectMigrationDrift({
298
305
  migrationSet: migrations,
@@ -405,11 +412,21 @@ function toAppliedStateMap(stateRows) {
405
412
  };
406
413
  return entries;
407
414
  }
415
+ /**
416
+ * Bounded by the number of authored migrations, not by run history, and the
417
+ * full set is part of the `status()` payload (`migrations`, `pending`,
418
+ * `drift`), so this one stays a collect.
419
+ */
408
420
  async function getAllStateRows(db) {
409
421
  return await db.query(MIGRATION_STATE_TABLE).collect();
410
422
  }
411
- async function getAllRunRows(db) {
412
- return await db.query(MIGRATION_RUN_TABLE).collect();
423
+ /** Most recent `limit` runs, read straight off `by_started_at` in reverse. */
424
+ async function getRecentRuns(db, limit) {
425
+ return await db.query(MIGRATION_RUN_TABLE).withIndex("by_started_at").order("desc").take(limit);
426
+ }
427
+ async function getRunsById(db, runId) {
428
+ const row = await getRunById(db, runId);
429
+ return row ? [row] : [];
413
430
  }
414
431
  async function getRunById(db, runId) {
415
432
  return await db.query(MIGRATION_RUN_TABLE).withIndex("by_run_id", (query) => query.eq("runId", runId)).first() ?? null;
@@ -503,4 +520,4 @@ const migrationCapability = () => ({
503
520
  });
504
521
 
505
522
  //#endregion
506
- export { MIGRATION_RUN_TABLE, MIGRATION_STATE_TABLE, MIGRATION_STORAGE_TABLE_NAMES, buildMigrationPlan, createMigrationHandlers, defineMigration, defineMigrationSet, detectMigrationDrift, injectMigrationStorageTables, migrationCapability, migrationExtension, migrationStorageTables };
523
+ export { MAX_STATUS_RUN_LIMIT, MIGRATION_RUN_TABLE, MIGRATION_STATE_TABLE, MIGRATION_STORAGE_TABLE_NAMES, buildMigrationPlan, createMigrationHandlers, defineMigration, defineMigrationSet, detectMigrationDrift, injectMigrationStorageTables, migrationCapability, migrationExtension, migrationStorageTables };
@@ -852,18 +852,22 @@ async function enforceUniqueIndexes(db, table, candidate, options) {
852
852
  if (existing !== null && (options?.currentId === void 0 || existing._id !== options.currentId)) throw new Error(`Unique index '${index.name}' violation on '${tableName}'.`);
853
853
  }
854
854
  }
855
+ const createForeignKeyProbeMemo = () => /* @__PURE__ */ new Set();
855
856
  async function enforceForeignKeys(db, table, candidate, options) {
856
857
  const foreignKeys = getForeignKeys(table);
857
858
  if (foreignKeys.length === 0) return;
858
859
  const tableName = getTableName(table);
859
860
  const changedFields = options?.changedFields;
861
+ const probed = options?.probed;
860
862
  for (const foreignKey of foreignKeys) {
861
863
  if (changedFields && !foreignKey.columns.some((field) => changedFields.has(field))) continue;
862
864
  const entries = foreignKey.columns.map((field) => [field, candidate[field]]);
863
865
  if (entries.some(([, value]) => value === void 0 || value === null)) continue;
864
866
  if (foreignKey.foreignColumns.length === 1 && foreignKey.foreignColumns[0] === "_id") {
865
867
  const foreignId = entries[0]?.[1];
868
+ if (probed?.has(foreignId)) continue;
866
869
  if (!await db.get(foreignId)) throw new Error(`Foreign key violation on '${tableName}': missing document in '${foreignKey.foreignTableName}'.`);
870
+ probed?.add(foreignId);
867
871
  continue;
868
872
  }
869
873
  if (!foreignKey.foreignTable) throw new Error(`Foreign key on '${tableName}' requires indexed foreign columns on '${foreignKey.foreignTableName}'.`);
@@ -1522,4 +1526,4 @@ function aggregateExtension() {
1522
1526
  }
1523
1527
 
1524
1528
  //#endregion
1525
- export { resolveOrmRuntimeDefaults as $, enforceUniqueIndexes as A, getMutationAsyncDelayMs as B, collectPrimaryIdLookupRows as C, CREATED_AT_MIGRATION_MESSAGE as Ct, enforceCheckConstraints as D, encodeUndefinedDeep as E, usesSystemCreatedAtAlias as Et, evaluateFilter as F, getTableDeleteConfig as G, getMutationExecutionMode as H, extractPrimaryIdLookup as I, hardDeleteRow as J, getTableName as K, getChecks as L, ensureNonNullValues as M, ensureNullableColumns as N, enforceForeignKeys as O, evaluateCheckConstraintTriState as P, patchReferencingRows as Q, getColumnName as R, collectMutationRowsBounded as S, resolveIndexOrderPushdown as St, deserializeFilterExpression as T, PUBLIC_CREATED_AT_FIELD as Tt, getOrmContext as U, getMutationCollectionLimits as V, getTableColumns as W, normalizeDateFieldsForWrite as X, hydrateDateFieldsForRead as Y, normalizeTemporalComparableValue as Z, applyDefaults as _, findSearchIndexByName as _t, AGGREGATE_STATE_TABLE as a, stripUnsetFields as at, buildForeignKeyGraph as b, getIndexes as bt, getAggregateIndexDefinitions as c, unsetFieldsOf as ct, COUNT_ERROR as d, compileConvexFilter as dt, returningSelectionReadsCreationTime as et, createAggregateError as f, convexAnd as ft, ensureCountAllowedForRls as g, findRelationIndex as gt, ensureAggregateAllowedForRls as h, findIndexForColumns as ht, AGGREGATE_RANK_TREE_TABLE as i, splitReturningSelection as it, ensureDefaultColumns as j, enforcePolymorphicWrite as k, getRankIndexDefinitions as l, hasLifecycleHooks as lt, createError as m, mapWithConcurrency as mt, AGGREGATE_EXTREMA_TABLE as n, serializeFilterExpression as nt, aggregateExtension as o, takeRowsWithinByteBudget as ot, createCountError as p, isConvexEnforceableFilter as pt, getUniqueIndexes as q, AGGREGATE_MEMBER_TABLE as r, softDeleteRow as rt, rankAggregateName as s, toConvexFilter as st, AGGREGATE_BUCKET_TABLE as t, selectReturningRowWithHydration as tt, AGGREGATE_ERROR as u, markLifecycleHookedTables as ut, applyIncomingForeignKeyActionsOnDelete as v, findVectorIndexByName as vt, decodeUndefinedDeep as w, INTERNAL_CREATION_TIME_FIELD as wt, canUsePrimaryIdLookupCursor as x, getRankIndexes as xt, applyIncomingForeignKeyActionsOnUpdate as y, getAggregateIndexes as yt, getForeignKeys as z };
1529
+ export { patchReferencingRows as $, enforcePolymorphicWrite as A, getForeignKeys as B, collectPrimaryIdLookupRows as C, resolveIndexOrderPushdown as Ct, encodeUndefinedDeep as D, usesSystemCreatedAtAlias as Dt, deserializeFilterExpression as E, PUBLIC_CREATED_AT_FIELD as Et, evaluateCheckConstraintTriState as F, getTableColumns as G, getMutationCollectionLimits as H, evaluateFilter as I, getUniqueIndexes as J, getTableDeleteConfig as K, extractPrimaryIdLookup as L, ensureDefaultColumns as M, ensureNonNullValues as N, enforceCheckConstraints as O, ensureNullableColumns as P, normalizeTemporalComparableValue as Q, getChecks as R, collectMutationRowsBounded as S, getRankIndexes as St, decodeUndefinedDeep as T, INTERNAL_CREATION_TIME_FIELD as Tt, getMutationExecutionMode as U, getMutationAsyncDelayMs as V, getOrmContext as W, hydrateDateFieldsForRead as X, hardDeleteRow as Y, normalizeDateFieldsForWrite as Z, applyDefaults as _, findRelationIndex as _t, AGGREGATE_STATE_TABLE as a, splitReturningSelection as at, buildForeignKeyGraph as b, getAggregateIndexes as bt, getAggregateIndexDefinitions as c, toConvexFilter as ct, COUNT_ERROR as d, markLifecycleHookedTables as dt, resolveOrmRuntimeDefaults as et, createAggregateError as f, compileConvexFilter as ft, ensureCountAllowedForRls as g, findIndexForColumns as gt, ensureAggregateAllowedForRls as h, mapWithConcurrency as ht, AGGREGATE_RANK_TREE_TABLE as i, softDeleteRow as it, enforceUniqueIndexes as j, enforceForeignKeys as k, getRankIndexDefinitions as l, unsetFieldsOf as lt, createError as m, isConvexEnforceableFilter as mt, AGGREGATE_EXTREMA_TABLE as n, selectReturningRowWithHydration as nt, aggregateExtension as o, stripUnsetFields as ot, createCountError as p, convexAnd as pt, getTableName as q, AGGREGATE_MEMBER_TABLE as r, serializeFilterExpression as rt, rankAggregateName as s, takeRowsWithinByteBudget as st, AGGREGATE_BUCKET_TABLE as t, returningSelectionReadsCreationTime as tt, AGGREGATE_ERROR as u, hasLifecycleHooks as ut, applyIncomingForeignKeyActionsOnDelete as v, findSearchIndexByName as vt, createForeignKeyProbeMemo as w, CREATED_AT_MIGRATION_MESSAGE as wt, canUsePrimaryIdLookupCursor as x, getIndexes as xt, applyIncomingForeignKeyActionsOnUpdate as y, findVectorIndexByName as yt, getColumnName as z };
package/dist/watcher.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as generateMeta, d as PARSE_SNAPSHOT_SUFFIX, i as resolveConfiguredBackend, n as withLocalCodegenEnv, o as getConvexConfig, r as loadCliConfig, u as logger } from "./local-env-Z8jj6ecD.mjs";
2
+ import { a as generateMeta, d as PARSE_SNAPSHOT_SUFFIX, i as resolveConfiguredBackend, n as withLocalCodegenEnv, o as getConvexConfig, r as loadCliConfig, u as logger } from "./local-env-Dk8RJvt5.mjs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
 
@@ -1,7 +1,7 @@
1
- import { Bn as ConvexTextBuilderInitial, Dr as SystemFieldAliases, F as DeleteMode, Gn as OrmRuntimeDefaults, H as EdgeMetadata, Hn as ConvexColumnBuilder, Hr as entityKind, Ht as RelationsConfigWithSchema, I as SerializedFilterExpression, Jn as OrmSchemaExtensionTriggers, Kn as OrmSchemaExtensionRelations, L as getChecks, M as OrmReader, Mr as ColumnBuilderBaseConfig, N as OrmWriter, Nt as AnyRelationsBuilderConfig, Or as SystemFields, P as CascadeMode, Pt as ExtractTablesFromSchema, Qt as OrmLifecycleChange, R as getForeignKeys, Rr as HasDefault, Rt as RelationsBuilder, St as OrderByClause, Ut as TableRelationalConfig, Vt as RelationsBuilderConfigValue, Wn as Columns, Wt as TablesRelationalConfig, Xn as OrmSchemaRelations, Xt as ConvexTableWithColumns, Yt as ConvexTable, Zn as OrmSchemaTriggers, b as MigrationSet, ft as InferSelectModel, in as RlsPolicy, jr as ColumnBuilder, jt as VectorSearchProvider, k as CreateDatabaseOptions, kr as $Type, nr as FilterExpression$1, r as OrmCapability, ut as InferInsertModel, z as getUniqueIndexes } from "./capabilities-DkfnnNp7.js";
1
+ import { $t as OrmLifecycleChange, A as CreateDatabaseOptions, Ar as $Type, B as getUniqueIndexes, Ct as OrderByClause, F as CascadeMode, Ft as ExtractTablesFromSchema, Gn as Columns, Gt as TablesRelationalConfig, Ht as RelationsBuilderConfigValue, I as DeleteMode, Kn as OrmRuntimeDefaults, L as SerializedFilterExpression, Mr as ColumnBuilder, Mt as VectorSearchProvider, N as OrmReader, Nr as ColumnBuilderBaseConfig, Or as SystemFieldAliases, P as OrmWriter, Pt as AnyRelationsBuilderConfig, Qn as OrmSchemaTriggers, R as getChecks, U as EdgeMetadata, Un as ConvexColumnBuilder, Ur as entityKind, Ut as RelationsConfigWithSchema, Vn as ConvexTextBuilderInitial, Wt as TableRelationalConfig, Xt as ConvexTable, Yn as OrmSchemaExtensionTriggers, Zn as OrmSchemaRelations, Zt as ConvexTableWithColumns, an as RlsPolicy, dt as InferInsertModel, kr as SystemFields, pt as InferSelectModel, qn as OrmSchemaExtensionRelations, r as OrmCapability, rr as FilterExpression$1, x as MigrationSet, z as getForeignKeys, zr as HasDefault, zt as RelationsBuilder } from "./capabilities-6PZBmvc8.js";
2
2
  import * as convex_values0 from "convex/values";
3
3
  import { GenericId, Validator, Value } from "convex/values";
4
- import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchedulableFunctionReference, Scheduler, SchemaDefinition, internalActionGeneric, internalMutationGeneric } from "convex/server";
4
+ import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchedulableFunctionReference, Scheduler, SchemaDefinition, internalActionGeneric, internalMutationGeneric, internalQueryGeneric } from "convex/server";
5
5
 
6
6
  //#region src/orm/migrations/capability.d.ts
7
7
  /**
@@ -102,15 +102,6 @@ declare const migrationStorageTables: {
102
102
  fieldName: "status";
103
103
  };
104
104
  };
105
- cursor: ConvexTextBuilderInitial<""> & {
106
- _: {
107
- tableName: "migration_state";
108
- };
109
- } & {
110
- _: {
111
- fieldName: "cursor";
112
- };
113
- };
114
105
  direction: ConvexTextBuilderInitial<""> & {
115
106
  _: {
116
107
  tableName: "migration_state";
@@ -120,17 +111,13 @@ declare const migrationStorageTables: {
120
111
  fieldName: "direction";
121
112
  };
122
113
  };
123
- updatedAt: ConvexNumberBuilderInitial<""> & {
124
- _: {
125
- notNull: true;
126
- };
127
- } & {
114
+ cursor: ConvexTextBuilderInitial<""> & {
128
115
  _: {
129
116
  tableName: "migration_state";
130
117
  };
131
118
  } & {
132
119
  _: {
133
- fieldName: "updatedAt";
120
+ fieldName: "cursor";
134
121
  };
135
122
  };
136
123
  migrationId: ConvexTextBuilderInitial<""> & {
@@ -203,6 +190,19 @@ declare const migrationStorageTables: {
203
190
  fieldName: "startedAt";
204
191
  };
205
192
  };
193
+ updatedAt: ConvexNumberBuilderInitial<""> & {
194
+ _: {
195
+ notNull: true;
196
+ };
197
+ } & {
198
+ _: {
199
+ tableName: "migration_state";
200
+ };
201
+ } & {
202
+ _: {
203
+ fieldName: "updatedAt";
204
+ };
205
+ };
206
206
  completedAt: ConvexNumberBuilderInitial<""> & {
207
207
  _: {
208
208
  tableName: "migration_state";
@@ -269,7 +269,7 @@ declare const migrationStorageTables: {
269
269
  fieldName: "direction";
270
270
  };
271
271
  };
272
- updatedAt: ConvexNumberBuilderInitial<""> & {
272
+ runId: ConvexTextBuilderInitial<""> & {
273
273
  _: {
274
274
  notNull: true;
275
275
  };
@@ -279,10 +279,10 @@ declare const migrationStorageTables: {
279
279
  };
280
280
  } & {
281
281
  _: {
282
- fieldName: "updatedAt";
282
+ fieldName: "runId";
283
283
  };
284
284
  };
285
- runId: ConvexTextBuilderInitial<""> & {
285
+ startedAt: ConvexNumberBuilderInitial<""> & {
286
286
  _: {
287
287
  notNull: true;
288
288
  };
@@ -292,10 +292,10 @@ declare const migrationStorageTables: {
292
292
  };
293
293
  } & {
294
294
  _: {
295
- fieldName: "runId";
295
+ fieldName: "startedAt";
296
296
  };
297
297
  };
298
- startedAt: ConvexNumberBuilderInitial<""> & {
298
+ updatedAt: ConvexNumberBuilderInitial<""> & {
299
299
  _: {
300
300
  notNull: true;
301
301
  };
@@ -305,7 +305,7 @@ declare const migrationStorageTables: {
305
305
  };
306
306
  } & {
307
307
  _: {
308
- fieldName: "startedAt";
308
+ fieldName: "updatedAt";
309
309
  };
310
310
  };
311
311
  completedAt: ConvexNumberBuilderInitial<""> & {
@@ -396,6 +396,7 @@ declare const migrationStorageTables: {
396
396
  by_creation_time: ["_creationTime"];
397
397
  by_status: ["status", "_creationTime"];
398
398
  by_run_id: ["runId", "_creationTime"];
399
+ by_started_at: ["startedAt", "_creationTime"];
399
400
  }, {}, {}, {}>;
400
401
  };
401
402
  declare const MIGRATION_STORAGE_TABLE_NAMES: Set<string>;
@@ -491,6 +492,7 @@ type CreateOrmConfigBase<TSchema extends OrmSchemaInput> = {
491
492
  capabilities?: readonly OrmCapability[];
492
493
  migrations?: MigrationSet<any>;
493
494
  internalMutation?: typeof internalMutationGeneric;
495
+ internalQuery?: typeof internalQueryGeneric;
494
496
  };
495
497
  type CreateOrmConfigWithFunctions<TSchema extends OrmSchemaInput> = CreateOrmConfigBase<TSchema> & {
496
498
  ormFunctions: OrmFunctions;
@@ -504,10 +506,10 @@ type OrmApiResult = {
504
506
  scheduledDelete: ReturnType<typeof internalMutationGeneric>;
505
507
  aggregateBackfill: ReturnType<typeof internalMutationGeneric>;
506
508
  aggregateBackfillChunk: ReturnType<typeof internalMutationGeneric>;
507
- aggregateBackfillStatus: ReturnType<typeof internalMutationGeneric>;
509
+ aggregateBackfillStatus: ReturnType<typeof internalQueryGeneric>;
508
510
  migrationRun: ReturnType<typeof internalMutationGeneric>;
509
511
  migrationRunChunk: ReturnType<typeof internalMutationGeneric>;
510
- migrationStatus: ReturnType<typeof internalMutationGeneric>;
512
+ migrationStatus: ReturnType<typeof internalQueryGeneric>;
511
513
  migrationCancel: ReturnType<typeof internalMutationGeneric>;
512
514
  resetChunk: ReturnType<typeof internalMutationGeneric>;
513
515
  reset: ReturnType<typeof internalActionGeneric>;
@@ -1008,7 +1010,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1008
1010
  readonly aggregate_bucket: ConvexTableWithColumns<{
1009
1011
  name: "aggregate_bucket";
1010
1012
  columns: {
1011
- count: ConvexNumberBuilderInitial<""> & {
1013
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1012
1014
  _: {
1013
1015
  notNull: true;
1014
1016
  };
@@ -1018,10 +1020,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1018
1020
  };
1019
1021
  } & {
1020
1022
  _: {
1021
- fieldName: "count";
1023
+ fieldName: "updatedAt";
1022
1024
  };
1023
1025
  };
1024
- updatedAt: ConvexNumberBuilderInitial<""> & {
1026
+ count: ConvexNumberBuilderInitial<""> & {
1025
1027
  _: {
1026
1028
  notNull: true;
1027
1029
  };
@@ -1031,7 +1033,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1031
1033
  };
1032
1034
  } & {
1033
1035
  _: {
1034
- fieldName: "updatedAt";
1036
+ fieldName: "count";
1035
1037
  };
1036
1038
  };
1037
1039
  tableKey: ConvexTextBuilderInitial<""> & {
@@ -1340,7 +1342,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1340
1342
  fieldName: "value";
1341
1343
  };
1342
1344
  };
1343
- count: ConvexNumberBuilderInitial<""> & {
1345
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1344
1346
  _: {
1345
1347
  notNull: true;
1346
1348
  };
@@ -1350,10 +1352,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1350
1352
  };
1351
1353
  } & {
1352
1354
  _: {
1353
- fieldName: "count";
1355
+ fieldName: "updatedAt";
1354
1356
  };
1355
1357
  };
1356
- updatedAt: ConvexNumberBuilderInitial<""> & {
1358
+ count: ConvexNumberBuilderInitial<""> & {
1357
1359
  _: {
1358
1360
  notNull: true;
1359
1361
  };
@@ -1363,7 +1365,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1363
1365
  };
1364
1366
  } & {
1365
1367
  _: {
1366
- fieldName: "updatedAt";
1368
+ fieldName: "count";
1367
1369
  };
1368
1370
  };
1369
1371
  tableKey: ConvexTextBuilderInitial<""> & {
@@ -1589,29 +1591,29 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1589
1591
  fieldName: "status";
1590
1592
  };
1591
1593
  };
1592
- cursor: ConvexTextBuilderInitial<""> & {
1594
+ kind: ConvexTextBuilderInitial<""> & {
1593
1595
  _: {
1594
- tableName: "aggregate_state";
1596
+ notNull: true;
1595
1597
  };
1596
1598
  } & {
1597
1599
  _: {
1598
- fieldName: "cursor";
1600
+ tableName: "aggregate_state";
1599
1601
  };
1600
- };
1601
- kind: ConvexTextBuilderInitial<""> & {
1602
+ } & {
1602
1603
  _: {
1603
- notNull: true;
1604
+ fieldName: "kind";
1604
1605
  };
1605
- } & {
1606
+ };
1607
+ cursor: ConvexTextBuilderInitial<""> & {
1606
1608
  _: {
1607
1609
  tableName: "aggregate_state";
1608
1610
  };
1609
1611
  } & {
1610
1612
  _: {
1611
- fieldName: "kind";
1613
+ fieldName: "cursor";
1612
1614
  };
1613
1615
  };
1614
- updatedAt: ConvexNumberBuilderInitial<""> & {
1616
+ processed: ConvexNumberBuilderInitial<""> & {
1615
1617
  _: {
1616
1618
  notNull: true;
1617
1619
  };
@@ -1621,10 +1623,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1621
1623
  };
1622
1624
  } & {
1623
1625
  _: {
1624
- fieldName: "updatedAt";
1626
+ fieldName: "processed";
1625
1627
  };
1626
1628
  };
1627
- processed: ConvexNumberBuilderInitial<""> & {
1629
+ startedAt: ConvexNumberBuilderInitial<""> & {
1628
1630
  _: {
1629
1631
  notNull: true;
1630
1632
  };
@@ -1634,10 +1636,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1634
1636
  };
1635
1637
  } & {
1636
1638
  _: {
1637
- fieldName: "processed";
1639
+ fieldName: "startedAt";
1638
1640
  };
1639
1641
  };
1640
- startedAt: ConvexNumberBuilderInitial<""> & {
1642
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1641
1643
  _: {
1642
1644
  notNull: true;
1643
1645
  };
@@ -1647,7 +1649,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1647
1649
  };
1648
1650
  } & {
1649
1651
  _: {
1650
- fieldName: "startedAt";
1652
+ fieldName: "updatedAt";
1651
1653
  };
1652
1654
  };
1653
1655
  completedAt: ConvexNumberBuilderInitial<""> & {
@@ -1744,15 +1746,6 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1744
1746
  fieldName: "status";
1745
1747
  };
1746
1748
  };
1747
- cursor: ConvexTextBuilderInitial<""> & {
1748
- _: {
1749
- tableName: "migration_state";
1750
- };
1751
- } & {
1752
- _: {
1753
- fieldName: "cursor";
1754
- };
1755
- };
1756
1749
  direction: ConvexTextBuilderInitial<""> & {
1757
1750
  _: {
1758
1751
  tableName: "migration_state";
@@ -1762,17 +1755,13 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1762
1755
  fieldName: "direction";
1763
1756
  };
1764
1757
  };
1765
- updatedAt: ConvexNumberBuilderInitial<""> & {
1766
- _: {
1767
- notNull: true;
1768
- };
1769
- } & {
1758
+ cursor: ConvexTextBuilderInitial<""> & {
1770
1759
  _: {
1771
1760
  tableName: "migration_state";
1772
1761
  };
1773
1762
  } & {
1774
1763
  _: {
1775
- fieldName: "updatedAt";
1764
+ fieldName: "cursor";
1776
1765
  };
1777
1766
  };
1778
1767
  migrationId: ConvexTextBuilderInitial<""> & {
@@ -1845,6 +1834,19 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1845
1834
  fieldName: "startedAt";
1846
1835
  };
1847
1836
  };
1837
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1838
+ _: {
1839
+ notNull: true;
1840
+ };
1841
+ } & {
1842
+ _: {
1843
+ tableName: "migration_state";
1844
+ };
1845
+ } & {
1846
+ _: {
1847
+ fieldName: "updatedAt";
1848
+ };
1849
+ };
1848
1850
  completedAt: ConvexNumberBuilderInitial<""> & {
1849
1851
  _: {
1850
1852
  tableName: "migration_state";
@@ -1911,7 +1913,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1911
1913
  fieldName: "direction";
1912
1914
  };
1913
1915
  };
1914
- updatedAt: ConvexNumberBuilderInitial<""> & {
1916
+ runId: ConvexTextBuilderInitial<""> & {
1915
1917
  _: {
1916
1918
  notNull: true;
1917
1919
  };
@@ -1921,10 +1923,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1921
1923
  };
1922
1924
  } & {
1923
1925
  _: {
1924
- fieldName: "updatedAt";
1926
+ fieldName: "runId";
1925
1927
  };
1926
1928
  };
1927
- runId: ConvexTextBuilderInitial<""> & {
1929
+ startedAt: ConvexNumberBuilderInitial<""> & {
1928
1930
  _: {
1929
1931
  notNull: true;
1930
1932
  };
@@ -1934,10 +1936,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1934
1936
  };
1935
1937
  } & {
1936
1938
  _: {
1937
- fieldName: "runId";
1939
+ fieldName: "startedAt";
1938
1940
  };
1939
1941
  };
1940
- startedAt: ConvexNumberBuilderInitial<""> & {
1942
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1941
1943
  _: {
1942
1944
  notNull: true;
1943
1945
  };
@@ -1947,7 +1949,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1947
1949
  };
1948
1950
  } & {
1949
1951
  _: {
1950
- fieldName: "startedAt";
1952
+ fieldName: "updatedAt";
1951
1953
  };
1952
1954
  };
1953
1955
  completedAt: ConvexNumberBuilderInitial<""> & {
@@ -2038,6 +2040,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
2038
2040
  by_creation_time: ["_creationTime"];
2039
2041
  by_status: ["status", "_creationTime"];
2040
2042
  by_run_id: ["runId", "_creationTime"];
2043
+ by_started_at: ["startedAt", "_creationTime"];
2041
2044
  }, {}, {}, {}>;
2042
2045
  }>];
2043
2046
  declare function defineSchema$1<TSchema extends GenericSchema, StrictTableNameTypes extends boolean = true>(schema: TSchema, options?: SchemaOptions<StrictTableNameTypes>): SchemaChain<TSchema, StrictTableNameTypes, readonly [], undefined, true, true, true>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitcn",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "description": "kitcn - React Query integration and CLI tools for Convex",
5
5
  "keywords": [
6
6
  "convex",
@@ -56,7 +56,7 @@ const orders = convexTable(
56
56
  - `.all()` — unfiltered global metrics
57
57
  - `.count(field)` / `.sum(field)` / `.avg(field)` / `.min(field)` / `.max(field)` — chainable metrics
58
58
 
59
- After deploying, CLI runs `aggregateBackfill` automatically. Wait for `aggregateBackfillStatus` to report `READY`.
59
+ After deploying, CLI runs `aggregateBackfill` automatically. Wait for `aggregateBackfillStatus` (an internal query) to report `READY`.
60
60
 
61
61
  ### `count()` — O(1) No-Scan Counts
62
62
 
@@ -137,6 +137,23 @@ Applied migrations are immutable. Two drift checks:
137
137
 
138
138
  Reserved names — do not create tables with these names.
139
139
 
140
+ ## Status Procedure
141
+
142
+ `generated/server:migrationStatus` is an internal **query** — reading status
143
+ takes no write transaction and can back a live subscription.
144
+
145
+ | Arg | Description |
146
+ |-----|-------------|
147
+ | `limit` | Most recent runs to list. Default `25`, capped at `MAX_STATUS_RUN_LIMIT` (`100`); higher values clamp. |
148
+ | `runId` | Return only this run. Ignores `limit`. |
149
+
150
+ `activeRun` resolves independently of `runId`. `migrations`, `pending`, and
151
+ `drift` always cover every authored migration and ignore `limit`.
152
+
153
+ ```ts
154
+ import { MAX_STATUS_RUN_LIMIT } from 'kitcn/orm/migrations';
155
+ ```
156
+
140
157
  ## Runtime Statuses
141
158
 
142
159
  `pending` → `running` → `completed` | `failed` | `canceled` | `dry_run` | `noop` | `drift_blocked`