kitcn 0.33.5 → 0.33.6

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,16 @@
1
1
  # kitcn
2
2
 
3
+ ## 0.33.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [#473](https://github.com/udecode/kitcn/pull/473) [`16e0bb4`](https://github.com/udecode/kitcn/commit/16e0bb46d66a4d7166d577793fcb47f8161efa5d) Thanks [@EfficiencyCorp](https://github.com/EfficiencyCorp)! - - Add opt-in optimistic auth and document identity admission to
8
+ `ConvexAuthProvider`, with the same guarded token source for Convex and cRPC
9
+ HTTP requests.
10
+ - Add Convex-native `optimisticUpdate` support to cRPC `mutationOptions`.
11
+ - Reuse the Convex client's logger for server HTTP clients so construction is
12
+ deterministic during prerendering.
13
+
3
14
  ## 0.33.5
4
15
 
5
16
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  import { Vn as ConvexTextBuilderInitial, Zt as ConvexTableWithColumns } from "../capabilities-Bxzoofl4.js";
2
- import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-qH6-NCM9.js";
2
+ import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-BzAJnWt4.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";
@@ -398,6 +398,51 @@ type ConvexAuthProviderProps = {
398
398
  queryName: string;
399
399
  }) => void; /** Custom function to detect UNAUTHORIZED errors. Default checks code property. */
400
400
  isUnauthorized?: (error: unknown) => boolean;
401
+ /**
402
+ * Run auth-bound queries as soon as an unexpired JWT is held instead of
403
+ * after Convex confirms it. Convex sends them after Authenticate on the same
404
+ * socket and evaluates none of them if the token is refused; a refused token
405
+ * sets `isAuthenticated` back to false, which resets auth-bound queries, and
406
+ * never opens the gate again. Default `false`.
407
+ */
408
+ optimisticAuth?: boolean;
409
+ /**
410
+ * Fix the identity (JWT `sub` and `sessionId`) the document speaks for: the
411
+ * one it holds when it mounts (`initialToken`), or, with none, the first
412
+ * token it obtains. A token for another user or session is refused before
413
+ * it is cached, so neither Convex, the optimistic gate nor HTTP headers ever
414
+ * see it: the Convex client is closed (dropping queued requests and
415
+ * optimistic updates), every later token request answers null, and this is
416
+ * called, typically to reload the page. Same-session refreshes pass
417
+ * through. Off when not set.
418
+ */
419
+ onTokenIdentityChange?: () => void;
420
+ /**
421
+ * The identity (`sub|sessionId`, as the guard decodes it from a JWT) the
422
+ * document already speaks for when this provider mounts, for an app that
423
+ * mounts the provider more than once in one document (for example one per
424
+ * route group, over a shared Convex client). The guard starts from it
425
+ * instead of from `initialToken` or the first token obtained, so a remount
426
+ * without a token still refuses another user's or session's token.
427
+ *
428
+ * A fixed value is read on the first render only. A getter is read at
429
+ * every admission, cached tokens included, and a token must match both the
430
+ * identity it returns and the one this guard already admitted; any
431
+ * mismatch trips the guard. So a provider kept mounted but hidden (React
432
+ * `<Activity>`) cannot resume under an identity the document has since
433
+ * moved away from. A getter returning null does not constrain. Needs
434
+ * `onTokenIdentityChange`.
435
+ */
436
+ tokenIdentityBaseline?: string | null | (() => string | null);
437
+ /**
438
+ * Called synchronously with every token the identity guard admits as it is
439
+ * handed to Convex or HTTP headers, cached tokens included, so the document
440
+ * can claim the identity at that moment (for example the first token a
441
+ * document without one obtains). Never called for a refused token. Read
442
+ * from a ref, so passing a new function does not re-run effects. Needs
443
+ * `onTokenIdentityChange`.
444
+ */
445
+ onTokenIdentityAdmitted?: (token: string) => void;
401
446
  };
402
447
  /**
403
448
  * Unified auth provider for Convex + Better Auth.
@@ -414,7 +459,11 @@ declare function ConvexAuthProvider({
414
459
  initialToken,
415
460
  onMutationUnauthorized,
416
461
  onQueryUnauthorized,
417
- isUnauthorized
462
+ isUnauthorized,
463
+ optimisticAuth,
464
+ onTokenIdentityChange,
465
+ onTokenIdentityAdmitted,
466
+ tokenIdentityBaseline
418
467
  }: ConvexAuthProviderProps): react_jsx_runtime0.JSX.Element;
419
468
  //#endregion
420
469
  export { type AuthClient, type AuthClientWithPlugins, ConvexAuthProvider, type ConvexAuthProviderClient, ConvexAuthProviderProps, ConvexAuthProviderQueryClient, type PluginsWithCrossDomain, type PluginsWithoutCrossDomain, convexClient };
@@ -134,7 +134,7 @@ const clearSessionAtom = (authClient) => {
134
134
  * Structure: AuthProvider wraps ConvexAuthProviderInner so that
135
135
  * useAuthStore() is available when creating fetchAccessToken.
136
136
  */
137
- function ConvexAuthProvider({ children, client, authClient, convexQueryClient, initialToken, onMutationUnauthorized, onQueryUnauthorized, isUnauthorized }) {
137
+ function ConvexAuthProvider({ children, client, authClient, convexQueryClient, initialToken, onMutationUnauthorized, onQueryUnauthorized, isUnauthorized, optimisticAuth = false, onTokenIdentityChange, onTokenIdentityAdmitted, tokenIdentityBaseline }) {
138
138
  useOTTHandler(authClient);
139
139
  return /* @__PURE__ */ jsx(AuthProvider, {
140
140
  initialValues: useMemo(() => ({
@@ -148,6 +148,10 @@ function ConvexAuthProvider({ children, client, authClient, convexQueryClient, i
148
148
  authClient,
149
149
  client,
150
150
  convexQueryClient,
151
+ onTokenIdentityAdmitted,
152
+ onTokenIdentityChange,
153
+ optimisticAuth,
154
+ tokenIdentityBaseline,
151
155
  children
152
156
  })
153
157
  });
@@ -156,7 +160,7 @@ function ConvexAuthProvider({ children, client, authClient, convexQueryClient, i
156
160
  * Inner provider that has access to AuthStore via useAuthStore().
157
161
  * Creates fetchAccessToken and passes it through context (no race condition).
158
162
  */
159
- function ConvexAuthProviderInner({ children, client, authClient, convexQueryClient }) {
163
+ function ConvexAuthProviderInner({ children, client, authClient, convexQueryClient, optimisticAuth, onTokenIdentityChange, onTokenIdentityAdmitted, tokenIdentityBaseline }) {
160
164
  const authStore = useAuthStore();
161
165
  convexQueryClient?.updateAuthStore(authStore);
162
166
  const { data: session, isPending } = authClient.useSession();
@@ -239,6 +243,25 @@ function ConvexAuthProviderInner({ children, client, authClient, convexQueryClie
239
243
  authStore,
240
244
  authClient
241
245
  ]);
246
+ const onTokenIdentityChangeRef = useRef(onTokenIdentityChange);
247
+ onTokenIdentityChangeRef.current = onTokenIdentityChange;
248
+ const onTokenIdentityAdmittedRef = useRef(onTokenIdentityAdmitted);
249
+ onTokenIdentityAdmittedRef.current = onTokenIdentityAdmitted;
250
+ const tokenIdentityBaselineRef = useRef(tokenIdentityBaseline);
251
+ tokenIdentityBaselineRef.current = tokenIdentityBaseline;
252
+ const identityGuardRef = useRef(null);
253
+ identityGuardRef.current ??= {
254
+ identity: (typeof tokenIdentityBaseline === "function" ? null : resolveTokenIdentityBaseline(tokenIdentityBaseline)) ?? decodeTokenSubjectSessionIdentity(authStore.get("token")),
255
+ currentDocumentIdentity: typeof tokenIdentityBaseline === "function" ? () => resolveTokenIdentityBaseline(tokenIdentityBaselineRef.current) : null,
256
+ tripped: false
257
+ };
258
+ const admitToken = useCallback((token, onAdmitted) => guardTokenIdentity({
259
+ client,
260
+ guard: identityGuardRef.current,
261
+ onAdmitted,
262
+ onIdentityChange: onTokenIdentityChangeRef.current,
263
+ token
264
+ }), [client]);
242
265
  const fetchAccessToken = useCallback(async ({ forceRefreshToken = false } = {}) => {
243
266
  const fetchFreshToken = () => {
244
267
  if (pendingTokenRef.current) return pendingTokenRef.current;
@@ -250,6 +273,7 @@ function ConvexAuthProviderInner({ children, client, authClient, convexQueryClie
250
273
  }
251
274
  pendingTokenRef.current = authClient.convex.token({ fetchOptions }).then((result) => {
252
275
  const jwt = result.data?.token || null;
276
+ if (jwt && !admitToken(jwt)) return null;
253
277
  if (jwt) {
254
278
  const exp = decodeJwtExp(jwt);
255
279
  authStore.set("token", jwt);
@@ -326,8 +350,15 @@ function ConvexAuthProviderInner({ children, client, authClient, convexQueryClie
326
350
  }, [
327
351
  authStore,
328
352
  authClient,
329
- getCachedJwt
353
+ getCachedJwt,
354
+ admitToken
330
355
  ]);
356
+ const guardedFetchAccessToken = useCallback(async (args = {}) => {
357
+ if (identityGuardRef.current?.tripped) return null;
358
+ const token = await fetchAccessToken(args);
359
+ if (!token || !admitToken(token, onTokenIdentityAdmittedRef.current)) return null;
360
+ return token;
361
+ }, [fetchAccessToken, admitToken]);
331
362
  const useAuth = useCallback(function useConvexAuthHook() {
332
363
  const token = authStore.get("token");
333
364
  const hasSession = hasActiveSessionData(sessionRef.current);
@@ -335,15 +366,18 @@ function ConvexAuthProviderInner({ children, client, authClient, convexQueryClie
335
366
  return {
336
367
  isLoading: isPendingRef.current && !token,
337
368
  isAuthenticated: sessionMissing ? false : hasSession || token !== null,
338
- fetchAccessToken
369
+ fetchAccessToken: guardedFetchAccessToken
339
370
  };
340
- }, [fetchAccessToken, authStore]);
371
+ }, [guardedFetchAccessToken, authStore]);
341
372
  return /* @__PURE__ */ jsx(FetchAccessTokenContext.Provider, {
342
- value: fetchAccessToken,
373
+ value: guardedFetchAccessToken,
343
374
  children: /* @__PURE__ */ jsx(ConvexProviderWithAuth$1, {
344
375
  client,
345
376
  useAuth,
346
- children: /* @__PURE__ */ jsx(AuthStateSync, { children })
377
+ children: /* @__PURE__ */ jsx(AuthStateSync, {
378
+ optimisticAuth,
379
+ children
380
+ })
347
381
  })
348
382
  });
349
383
  }
@@ -359,22 +393,102 @@ function ConvexAuthProviderInner({ children, client, authClient, convexQueryClie
359
393
  * 5. Without defensive check, we'd sync { isLoading: false, isAuthenticated: false }
360
394
  * 6. Queries would throw UNAUTHORIZED before token is validated
361
395
  */
362
- function AuthStateSync({ children }) {
396
+ function AuthStateSync({ children, optimisticAuth = false }) {
363
397
  const { isLoading: convexIsLoading, isAuthenticated } = useConvexAuth();
364
398
  const authStore = useAuthStore();
365
399
  const token = useAuthValue("token");
400
+ const rejectedTokenRef = useRef(null);
366
401
  useEffect(() => {
367
- const isLoading = convexIsLoading || !!token && !isAuthenticated;
368
- authStore.set("isLoading", isLoading);
369
- authStore.set("isAuthenticated", isAuthenticated);
402
+ const gate = resolveAuthGate({
403
+ convexIsLoading,
404
+ isAuthenticated,
405
+ optimisticAuth,
406
+ rejectedToken: rejectedTokenRef.current,
407
+ token
408
+ });
409
+ if (optimisticAuth && isTokenRejectedByConvex({
410
+ convexIsLoading,
411
+ isAuthenticated,
412
+ token
413
+ })) rejectedTokenRef.current = token;
414
+ authStore.set("isLoading", gate.isLoading);
415
+ authStore.set("isAuthenticated", gate.isAuthenticated);
370
416
  }, [
371
417
  convexIsLoading,
372
418
  isAuthenticated,
419
+ optimisticAuth,
373
420
  token,
374
421
  authStore
375
422
  ]);
376
423
  return children;
377
424
  }
425
+ function decodeTokenSubjectSessionIdentity(token) {
426
+ if (!token) return null;
427
+ try {
428
+ const segment = token.split(".")[1];
429
+ if (!segment) return null;
430
+ const payload = JSON.parse(atob(segment.replaceAll("-", "+").replaceAll("_", "/")));
431
+ if (typeof payload !== "object" || payload === null) return null;
432
+ const sub = "sub" in payload ? payload.sub : null;
433
+ const sessionId = "sessionId" in payload ? payload.sessionId : null;
434
+ if (typeof sub !== "string") return null;
435
+ return `${sub}|${typeof sessionId === "string" ? sessionId : ""}`;
436
+ } catch {
437
+ return null;
438
+ }
439
+ }
440
+ function resolveTokenIdentityBaseline(baseline) {
441
+ return typeof baseline === "function" ? baseline() : baseline ?? null;
442
+ }
443
+ function guardTokenIdentity({ client, guard, onAdmitted, onIdentityChange, token }) {
444
+ if (!onIdentityChange) return true;
445
+ if (guard.tripped) return false;
446
+ const identity = decodeTokenSubjectSessionIdentity(token);
447
+ if (identity === null) return true;
448
+ const current = guard.currentDocumentIdentity?.() ?? null;
449
+ if ((guard.identity === null || guard.identity === identity) && (current === null || current === identity)) {
450
+ guard.identity = identity;
451
+ onAdmitted?.(token);
452
+ return true;
453
+ }
454
+ guard.tripped = true;
455
+ client.close();
456
+ onIdentityChange();
457
+ return false;
458
+ }
459
+ /**
460
+ * Convex has settled on "not authenticated" while a token is still held: the
461
+ * server refused it (or refused its refresh).
462
+ */
463
+ function isTokenRejectedByConvex({ convexIsLoading, isAuthenticated, token }) {
464
+ return !!token && !convexIsLoading && !isAuthenticated;
465
+ }
466
+ /**
467
+ * The auth state published to the store, which is what every query gate reads.
468
+ *
469
+ * Without `optimisticAuth` this is the confirmed state: queries wait until
470
+ * Convex has confirmed the token. With it, a held, unexpired JWT that Convex
471
+ * has not refused yet counts as authenticated while Convex confirms it, so
472
+ * auth-bound queries subscribe at once; Convex sends them after Authenticate on
473
+ * the same socket, and a refused token closes the socket before any of them is
474
+ * evaluated. When Convex refuses the token, `isAuthenticated` falls back to
475
+ * false, which resets auth-bound queries (see `CRPCProviderInner`).
476
+ */
477
+ function resolveAuthGate({ convexIsLoading, isAuthenticated, optimisticAuth, rejectedToken, token }) {
478
+ if (optimisticAuth && convexIsLoading && isOptimisticToken(token, rejectedToken)) return {
479
+ isAuthenticated: true,
480
+ isLoading: false
481
+ };
482
+ return {
483
+ isAuthenticated,
484
+ isLoading: convexIsLoading || !!token && !isAuthenticated
485
+ };
486
+ }
487
+ function isOptimisticToken(token, rejectedToken) {
488
+ if (!token || token === rejectedToken) return false;
489
+ const expiresAt = decodeJwtExp(token);
490
+ return expiresAt !== null && expiresAt > Date.now();
491
+ }
378
492
  /**
379
493
  * Handles cross-domain one-time token (OTT) verification.
380
494
  */
@@ -1,5 +1,5 @@
1
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-Bxzoofl4.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-qH6-NCM9.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-BzAJnWt4.js";
3
3
  import { i as pretendRequired, n as deprecated, r as pretend } from "../validators-0I-Ik1EN.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-BkNjkDCk.js";
5
5
  import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchemaDefinition } from "convex/server";
@@ -1,3 +1,3 @@
1
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-Bxzoofl4.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-qH6-NCM9.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-BzAJnWt4.js";
3
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 };
@@ -5,7 +5,8 @@ import { ReactNode } from "react";
5
5
  import * as react_jsx_runtime0 from "react/jsx-runtime";
6
6
  import { FunctionArgs, FunctionReference, FunctionReturnType } from "convex/server";
7
7
  import { DefaultError, QueryCache, QueryClient, QueryFilters, QueryFunction, QueryFunctionContext, QueryKey, SkipToken, UseMutationOptions, UseQueryOptions, UseQueryResult } from "@tanstack/react-query";
8
- import { ConvexHttpClient } from "convex/browser";
8
+ import { Value } from "convex/values";
9
+ import { ConvexHttpClient, OptimisticUpdate } from "convex/browser";
9
10
  import { z } from "zod";
10
11
 
11
12
  //#region src/crpc/auth-error.d.ts
@@ -582,11 +583,19 @@ type DecorateInfiniteQuery<T extends FunctionReference<'query'>> = {
582
583
  infiniteQueryKey: (args?: DeepPartial<InfiniteQueryInput<FunctionArgs<T>>>) => ConvexQueryKey<T>; /** Function metadata from server (auth, limit, rateLimit, role, type) */
583
584
  meta: PaginatedFnMeta;
584
585
  };
586
+ /**
587
+ * Convex-native optimistic update for a cRPC mutation. It edits Convex's local
588
+ * query store, which the query client reads, so Convex rolls it back when the
589
+ * mutation fails. Args and query values are in their wire shape.
590
+ */
591
+ type ConvexOptimisticUpdateOption<Args extends Record<string, Value>> = {
592
+ optimisticUpdate?: OptimisticUpdate<Args>;
593
+ };
585
594
  /**
586
595
  * Decorated mutation procedure with mutationOptions and mutationKey methods.
587
596
  */
588
597
  type DecorateMutation<T extends FunctionReference<'mutation'>> = {
589
- mutationOptions: (opts?: DistributiveOmit<UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>, ReservedMutationOptions$2>) => UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>; /** Get mutation key for QueryClient methods */
598
+ mutationOptions: (opts?: DistributiveOmit<UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>, ReservedMutationOptions$2> & ConvexOptimisticUpdateOption<FunctionArgs<T>>) => UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>; /** Get mutation key for QueryClient methods */
590
599
  mutationKey: () => ConvexMutationKey;
591
600
  };
592
601
  /**
@@ -1087,7 +1096,7 @@ declare function useConvexActionQueryOptions<Action extends FunctionReference<'a
1087
1096
  * }));
1088
1097
  * ```
1089
1098
  */
1090
- declare function useConvexMutationOptions<Mutation extends FunctionReference<'mutation'>>(mutation: Mutation, options?: DistributiveOmit<UseMutationOptions<FunctionReturnType<Mutation>, DefaultError, FunctionArgs<Mutation>>, ReservedMutationOptions>, transformer?: DataTransformerOptions): UseMutationOptions<FunctionReturnType<Mutation>, DefaultError, FunctionArgs<Mutation>>;
1099
+ declare function useConvexMutationOptions<Mutation extends FunctionReference<'mutation'>>(mutation: Mutation, options?: DistributiveOmit<UseMutationOptions<FunctionReturnType<Mutation>, DefaultError, FunctionArgs<Mutation>>, ReservedMutationOptions> & ConvexOptimisticUpdateOption<FunctionArgs<Mutation>>, transformer?: DataTransformerOptions): UseMutationOptions<FunctionReturnType<Mutation>, DefaultError, FunctionArgs<Mutation>>;
1091
1100
  /**
1092
1101
  * Hook that returns action options for use with useMutation.
1093
1102
  * Wraps the Convex action with auth guard logic.
@@ -1155,10 +1155,12 @@ function useConvexMutationOptions(mutation, options, transformer) {
1155
1155
  const name = getFunctionName(mutation);
1156
1156
  const [namespace, fnName] = name.split(":");
1157
1157
  const authType = getMeta(namespace, fnName)?.auth;
1158
- const convexMutation = useMutation(mutation);
1158
+ const { optimisticUpdate, ...mutationOptions } = options ?? {};
1159
+ const reactMutation = useMutation(mutation);
1160
+ const convexMutation = optimisticUpdate ? reactMutation.withOptimisticUpdate(optimisticUpdate) : reactMutation;
1159
1161
  const resolvedTransformer = getTransformer(transformer);
1160
1162
  return {
1161
- ...options,
1163
+ ...mutationOptions,
1162
1164
  mutationFn: async (args) => {
1163
1165
  if (authType === "required" && guard()) throw new CRPCClientError({
1164
1166
  code: "UNAUTHORIZED",
@@ -1496,6 +1498,16 @@ function createCRPCContext(options) {
1496
1498
  convexSiteUrl: httpOptions.convexSiteUrl,
1497
1499
  routes: meta._http,
1498
1500
  headers: async () => {
1501
+ if (fetchAccessToken) {
1502
+ const expiresAt = authStore.get("expiresAt");
1503
+ const timeRemaining = expiresAt ? expiresAt - Date.now() : 0;
1504
+ const guardedToken = await fetchAccessToken({ forceRefreshToken: !!expiresAt && timeRemaining < 6e4 });
1505
+ const userHeaders = typeof httpOptions.headers === "function" ? await httpOptions.headers() : httpOptions.headers;
1506
+ return guardedToken ? {
1507
+ ...userHeaders,
1508
+ Authorization: `Bearer ${guardedToken}`
1509
+ } : { ...userHeaders };
1510
+ }
1499
1511
  const token = authStore.get("token");
1500
1512
  const expiresAt = authStore.get("expiresAt");
1501
1513
  const timeRemaining = expiresAt ? expiresAt - Date.now() : 0;
@@ -1503,13 +1515,6 @@ function createCRPCContext(options) {
1503
1515
  ...typeof httpOptions.headers === "function" ? await httpOptions.headers() : httpOptions.headers,
1504
1516
  Authorization: `Bearer ${token}`
1505
1517
  };
1506
- if (fetchAccessToken) {
1507
- const newToken = await fetchAccessToken({ forceRefreshToken: !!expiresAt });
1508
- if (newToken) return {
1509
- ...typeof httpOptions.headers === "function" ? await httpOptions.headers() : httpOptions.headers,
1510
- Authorization: `Bearer ${newToken}`
1511
- };
1512
- }
1513
1518
  return { ...typeof httpOptions.headers === "function" ? await httpOptions.headers() : httpOptions.headers };
1514
1519
  },
1515
1520
  fetch: httpOptions.fetch,
@@ -2105,7 +2110,10 @@ var ConvexQueryClient = class {
2105
2110
  this._queryClient = options.queryClient;
2106
2111
  this.unsubscribe = this.subscribeInner(options.queryClient.getQueryCache());
2107
2112
  }
2108
- if (isServer) this.serverHttpClient = new ConvexHttpClient(this.convexClient.url, { fetch: options.serverFetch });
2113
+ if (isServer) this.serverHttpClient = new ConvexHttpClient(this.convexClient.url, {
2114
+ fetch: options.serverFetch,
2115
+ logger: this.convexClient.logger
2116
+ });
2109
2117
  }
2110
2118
  /**
2111
2119
  * Connect to TanStack QueryClient.
@@ -2,7 +2,9 @@ import { n as DeepPartial, o as Simplify, r as DistributiveOmit } from "../types
2
2
  import { L as DataTransformerOptions, _ as CRPCHttpRouter, c as HttpQueryKey, k as HttpProcedure, o as HttpMutationKey, y as HttpRouterRecord } from "../http-types-BhhPZtwa.js";
3
3
  import { g as UnsetMarker } from "../types-Bkeicpo6.js";
4
4
  import { A as HttpInputArgs, C as ReservedMutationOptions$1, S as ReservedInfiniteQueryOptions, T as StaticQueryOptsParam, _ as IsPaginated, b as PaginatedFnMeta, c as ConvexMutationKey, d as ConvexQueryMeta, f as EmptyObject, g as InfiniteQueryInput, l as ConvexQueryHookOptions, m as FUNC_REF_SYMBOL, o as ConvexActionKey, p as ExtractPaginatedItem, s as ConvexInfiniteQueryMeta, u as ConvexQueryKey, w as ReservedQueryOptions$1, y as MutationVariables } from "../types-C7JkpfeY.js";
5
+ import { Value } from "convex/values";
5
6
  import { FunctionArgs, FunctionReference, FunctionReturnType } from "convex/server";
7
+ import { OptimisticUpdate } from "convex/browser";
6
8
  import { z } from "zod";
7
9
  import { DefaultError, QueryFilters, SkipToken, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
8
10
 
@@ -70,11 +72,19 @@ type DecorateInfiniteQuery<T extends FunctionReference<'query'>> = {
70
72
  infiniteQueryKey: (args?: DeepPartial<InfiniteQueryInput<FunctionArgs<T>>>) => ConvexQueryKey<T>; /** Function metadata from server (auth, limit, rateLimit, role, type) */
71
73
  meta: PaginatedFnMeta;
72
74
  };
75
+ /**
76
+ * Convex-native optimistic update for a cRPC mutation. It edits Convex's local
77
+ * query store, which the query client reads, so Convex rolls it back when the
78
+ * mutation fails. Args and query values are in their wire shape.
79
+ */
80
+ type ConvexOptimisticUpdateOption<Args extends Record<string, Value>> = {
81
+ optimisticUpdate?: OptimisticUpdate<Args>;
82
+ };
73
83
  /**
74
84
  * Decorated mutation procedure with mutationOptions and mutationKey methods.
75
85
  */
76
86
  type DecorateMutation<T extends FunctionReference<'mutation'>> = {
77
- mutationOptions: (opts?: DistributiveOmit<UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>, ReservedMutationOptions$1>) => UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>; /** Get mutation key for QueryClient methods */
87
+ mutationOptions: (opts?: DistributiveOmit<UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>, ReservedMutationOptions$1> & ConvexOptimisticUpdateOption<FunctionArgs<T>>) => UseMutationOptions<FunctionReturnType<T>, DefaultError, MutationVariables<T>>; /** Get mutation key for QueryClient methods */
78
88
  mutationKey: () => ConvexMutationKey;
79
89
  };
80
90
  /**
@@ -120,7 +120,7 @@ declare const migrationStorageTables: {
120
120
  fieldName: "cursor";
121
121
  };
122
122
  };
123
- processed: ConvexNumberBuilderInitial<""> & {
123
+ migrationId: ConvexTextBuilderInitial<""> & {
124
124
  _: {
125
125
  notNull: true;
126
126
  };
@@ -130,19 +130,23 @@ declare const migrationStorageTables: {
130
130
  };
131
131
  } & {
132
132
  _: {
133
- fieldName: "processed";
133
+ fieldName: "migrationId";
134
134
  };
135
135
  };
136
- startedAt: ConvexNumberBuilderInitial<""> & {
136
+ checksum: ConvexTextBuilderInitial<""> & {
137
+ _: {
138
+ notNull: true;
139
+ };
140
+ } & {
137
141
  _: {
138
142
  tableName: "migration_state";
139
143
  };
140
144
  } & {
141
145
  _: {
142
- fieldName: "startedAt";
146
+ fieldName: "checksum";
143
147
  };
144
148
  };
145
- updatedAt: ConvexNumberBuilderInitial<""> & {
149
+ applied: ConvexBooleanBuilderInitial<""> & {
146
150
  _: {
147
151
  notNull: true;
148
152
  };
@@ -152,41 +156,41 @@ declare const migrationStorageTables: {
152
156
  };
153
157
  } & {
154
158
  _: {
155
- fieldName: "updatedAt";
159
+ fieldName: "applied";
156
160
  };
157
161
  };
158
- completedAt: ConvexNumberBuilderInitial<""> & {
162
+ runId: ConvexTextBuilderInitial<""> & {
159
163
  _: {
160
164
  tableName: "migration_state";
161
165
  };
162
166
  } & {
163
167
  _: {
164
- fieldName: "completedAt";
168
+ fieldName: "runId";
165
169
  };
166
170
  };
167
- lastError: ConvexTextBuilderInitial<""> & {
171
+ processed: ConvexNumberBuilderInitial<""> & {
168
172
  _: {
169
- tableName: "migration_state";
173
+ notNull: true;
170
174
  };
171
175
  } & {
172
176
  _: {
173
- fieldName: "lastError";
177
+ tableName: "migration_state";
174
178
  };
175
- };
176
- migrationId: ConvexTextBuilderInitial<""> & {
179
+ } & {
177
180
  _: {
178
- notNull: true;
181
+ fieldName: "processed";
179
182
  };
180
- } & {
183
+ };
184
+ startedAt: ConvexNumberBuilderInitial<""> & {
181
185
  _: {
182
186
  tableName: "migration_state";
183
187
  };
184
188
  } & {
185
189
  _: {
186
- fieldName: "migrationId";
190
+ fieldName: "startedAt";
187
191
  };
188
192
  };
189
- checksum: ConvexTextBuilderInitial<""> & {
193
+ updatedAt: ConvexNumberBuilderInitial<""> & {
190
194
  _: {
191
195
  notNull: true;
192
196
  };
@@ -196,29 +200,25 @@ declare const migrationStorageTables: {
196
200
  };
197
201
  } & {
198
202
  _: {
199
- fieldName: "checksum";
203
+ fieldName: "updatedAt";
200
204
  };
201
205
  };
202
- applied: ConvexBooleanBuilderInitial<""> & {
203
- _: {
204
- notNull: true;
205
- };
206
- } & {
206
+ completedAt: ConvexNumberBuilderInitial<""> & {
207
207
  _: {
208
208
  tableName: "migration_state";
209
209
  };
210
210
  } & {
211
211
  _: {
212
- fieldName: "applied";
212
+ fieldName: "completedAt";
213
213
  };
214
214
  };
215
- runId: ConvexTextBuilderInitial<""> & {
215
+ lastError: ConvexTextBuilderInitial<""> & {
216
216
  _: {
217
217
  tableName: "migration_state";
218
218
  };
219
219
  } & {
220
220
  _: {
221
- fieldName: "runId";
221
+ fieldName: "lastError";
222
222
  };
223
223
  };
224
224
  writeMode: ConvexTextBuilderInitial<""> & {
@@ -269,6 +269,19 @@ declare const migrationStorageTables: {
269
269
  fieldName: "direction";
270
270
  };
271
271
  };
272
+ runId: ConvexTextBuilderInitial<""> & {
273
+ _: {
274
+ notNull: true;
275
+ };
276
+ } & {
277
+ _: {
278
+ tableName: "migration_run";
279
+ };
280
+ } & {
281
+ _: {
282
+ fieldName: "runId";
283
+ };
284
+ };
272
285
  startedAt: ConvexNumberBuilderInitial<""> & {
273
286
  _: {
274
287
  notNull: true;
@@ -313,19 +326,6 @@ declare const migrationStorageTables: {
313
326
  fieldName: "lastError";
314
327
  };
315
328
  };
316
- runId: ConvexTextBuilderInitial<""> & {
317
- _: {
318
- notNull: true;
319
- };
320
- } & {
321
- _: {
322
- tableName: "migration_run";
323
- };
324
- } & {
325
- _: {
326
- fieldName: "runId";
327
- };
328
- };
329
329
  dryRun: ConvexBooleanBuilderInitial<""> & {
330
330
  _: {
331
331
  notNull: true;
@@ -1011,7 +1011,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1011
1011
  readonly aggregate_bucket: ConvexTableWithColumns<{
1012
1012
  name: "aggregate_bucket";
1013
1013
  columns: {
1014
- indexName: ConvexTextBuilderInitial<""> & {
1014
+ count: ConvexNumberBuilderInitial<""> & {
1015
1015
  _: {
1016
1016
  notNull: true;
1017
1017
  };
@@ -1021,7 +1021,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1021
1021
  };
1022
1022
  } & {
1023
1023
  _: {
1024
- fieldName: "indexName";
1024
+ fieldName: "count";
1025
1025
  };
1026
1026
  };
1027
1027
  updatedAt: ConvexNumberBuilderInitial<""> & {
@@ -1037,7 +1037,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1037
1037
  fieldName: "updatedAt";
1038
1038
  };
1039
1039
  };
1040
- tableKey: ConvexTextBuilderInitial<""> & {
1040
+ indexName: ConvexTextBuilderInitial<""> & {
1041
1041
  _: {
1042
1042
  notNull: true;
1043
1043
  };
@@ -1047,10 +1047,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1047
1047
  };
1048
1048
  } & {
1049
1049
  _: {
1050
- fieldName: "tableKey";
1050
+ fieldName: "indexName";
1051
1051
  };
1052
1052
  };
1053
- count: ConvexNumberBuilderInitial<""> & {
1053
+ tableKey: ConvexTextBuilderInitial<""> & {
1054
1054
  _: {
1055
1055
  notNull: true;
1056
1056
  };
@@ -1060,7 +1060,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1060
1060
  };
1061
1061
  } & {
1062
1062
  _: {
1063
- fieldName: "count";
1063
+ fieldName: "tableKey";
1064
1064
  };
1065
1065
  };
1066
1066
  keyHash: ConvexTextBuilderInitial<""> & {
@@ -1149,7 +1149,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1149
1149
  fieldName: "kind";
1150
1150
  };
1151
1151
  };
1152
- indexName: ConvexTextBuilderInitial<""> & {
1152
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1153
1153
  _: {
1154
1154
  notNull: true;
1155
1155
  };
@@ -1159,10 +1159,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1159
1159
  };
1160
1160
  } & {
1161
1161
  _: {
1162
- fieldName: "indexName";
1162
+ fieldName: "updatedAt";
1163
1163
  };
1164
1164
  };
1165
- updatedAt: ConvexNumberBuilderInitial<""> & {
1165
+ indexName: ConvexTextBuilderInitial<""> & {
1166
1166
  _: {
1167
1167
  notNull: true;
1168
1168
  };
@@ -1172,7 +1172,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1172
1172
  };
1173
1173
  } & {
1174
1174
  _: {
1175
- fieldName: "updatedAt";
1175
+ fieldName: "indexName";
1176
1176
  };
1177
1177
  };
1178
1178
  tableKey: ConvexTextBuilderInitial<""> & {
@@ -1343,7 +1343,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1343
1343
  fieldName: "value";
1344
1344
  };
1345
1345
  };
1346
- indexName: ConvexTextBuilderInitial<""> & {
1346
+ count: ConvexNumberBuilderInitial<""> & {
1347
1347
  _: {
1348
1348
  notNull: true;
1349
1349
  };
@@ -1353,7 +1353,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1353
1353
  };
1354
1354
  } & {
1355
1355
  _: {
1356
- fieldName: "indexName";
1356
+ fieldName: "count";
1357
1357
  };
1358
1358
  };
1359
1359
  updatedAt: ConvexNumberBuilderInitial<""> & {
@@ -1369,7 +1369,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1369
1369
  fieldName: "updatedAt";
1370
1370
  };
1371
1371
  };
1372
- tableKey: ConvexTextBuilderInitial<""> & {
1372
+ indexName: ConvexTextBuilderInitial<""> & {
1373
1373
  _: {
1374
1374
  notNull: true;
1375
1375
  };
@@ -1379,10 +1379,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1379
1379
  };
1380
1380
  } & {
1381
1381
  _: {
1382
- fieldName: "tableKey";
1382
+ fieldName: "indexName";
1383
1383
  };
1384
1384
  };
1385
- count: ConvexNumberBuilderInitial<""> & {
1385
+ tableKey: ConvexTextBuilderInitial<""> & {
1386
1386
  _: {
1387
1387
  notNull: true;
1388
1388
  };
@@ -1392,7 +1392,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1392
1392
  };
1393
1393
  } & {
1394
1394
  _: {
1395
- fieldName: "count";
1395
+ fieldName: "tableKey";
1396
1396
  };
1397
1397
  };
1398
1398
  keyHash: ConvexTextBuilderInitial<""> & {
@@ -1618,7 +1618,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1618
1618
  fieldName: "cursor";
1619
1619
  };
1620
1620
  };
1621
- indexName: ConvexTextBuilderInitial<""> & {
1621
+ processed: ConvexNumberBuilderInitial<""> & {
1622
1622
  _: {
1623
1623
  notNull: true;
1624
1624
  };
@@ -1628,10 +1628,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1628
1628
  };
1629
1629
  } & {
1630
1630
  _: {
1631
- fieldName: "indexName";
1631
+ fieldName: "processed";
1632
1632
  };
1633
1633
  };
1634
- keyDefinitionHash: ConvexTextBuilderInitial<""> & {
1634
+ startedAt: ConvexNumberBuilderInitial<""> & {
1635
1635
  _: {
1636
1636
  notNull: true;
1637
1637
  };
@@ -1641,10 +1641,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1641
1641
  };
1642
1642
  } & {
1643
1643
  _: {
1644
- fieldName: "keyDefinitionHash";
1644
+ fieldName: "startedAt";
1645
1645
  };
1646
1646
  };
1647
- metricDefinitionHash: ConvexTextBuilderInitial<""> & {
1647
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1648
1648
  _: {
1649
1649
  notNull: true;
1650
1650
  };
@@ -1654,23 +1654,28 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1654
1654
  };
1655
1655
  } & {
1656
1656
  _: {
1657
- fieldName: "metricDefinitionHash";
1657
+ fieldName: "updatedAt";
1658
1658
  };
1659
1659
  };
1660
- processed: ConvexNumberBuilderInitial<""> & {
1660
+ completedAt: ConvexNumberBuilderInitial<""> & {
1661
1661
  _: {
1662
- notNull: true;
1662
+ tableName: "aggregate_state";
1663
1663
  };
1664
1664
  } & {
1665
+ _: {
1666
+ fieldName: "completedAt";
1667
+ };
1668
+ };
1669
+ lastError: ConvexTextBuilderInitial<""> & {
1665
1670
  _: {
1666
1671
  tableName: "aggregate_state";
1667
1672
  };
1668
1673
  } & {
1669
1674
  _: {
1670
- fieldName: "processed";
1675
+ fieldName: "lastError";
1671
1676
  };
1672
1677
  };
1673
- startedAt: ConvexNumberBuilderInitial<""> & {
1678
+ indexName: ConvexTextBuilderInitial<""> & {
1674
1679
  _: {
1675
1680
  notNull: true;
1676
1681
  };
@@ -1680,10 +1685,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1680
1685
  };
1681
1686
  } & {
1682
1687
  _: {
1683
- fieldName: "startedAt";
1688
+ fieldName: "indexName";
1684
1689
  };
1685
1690
  };
1686
- updatedAt: ConvexNumberBuilderInitial<""> & {
1691
+ keyDefinitionHash: ConvexTextBuilderInitial<""> & {
1687
1692
  _: {
1688
1693
  notNull: true;
1689
1694
  };
@@ -1693,25 +1698,20 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1693
1698
  };
1694
1699
  } & {
1695
1700
  _: {
1696
- fieldName: "updatedAt";
1701
+ fieldName: "keyDefinitionHash";
1697
1702
  };
1698
1703
  };
1699
- completedAt: ConvexNumberBuilderInitial<""> & {
1704
+ metricDefinitionHash: ConvexTextBuilderInitial<""> & {
1700
1705
  _: {
1701
- tableName: "aggregate_state";
1706
+ notNull: true;
1702
1707
  };
1703
1708
  } & {
1704
- _: {
1705
- fieldName: "completedAt";
1706
- };
1707
- };
1708
- lastError: ConvexTextBuilderInitial<""> & {
1709
1709
  _: {
1710
1710
  tableName: "aggregate_state";
1711
1711
  };
1712
1712
  } & {
1713
1713
  _: {
1714
- fieldName: "lastError";
1714
+ fieldName: "metricDefinitionHash";
1715
1715
  };
1716
1716
  };
1717
1717
  tableKey: ConvexTextBuilderInitial<""> & {
@@ -1769,7 +1769,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1769
1769
  fieldName: "cursor";
1770
1770
  };
1771
1771
  };
1772
- processed: ConvexNumberBuilderInitial<""> & {
1772
+ migrationId: ConvexTextBuilderInitial<""> & {
1773
1773
  _: {
1774
1774
  notNull: true;
1775
1775
  };
@@ -1779,19 +1779,23 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1779
1779
  };
1780
1780
  } & {
1781
1781
  _: {
1782
- fieldName: "processed";
1782
+ fieldName: "migrationId";
1783
1783
  };
1784
1784
  };
1785
- startedAt: ConvexNumberBuilderInitial<""> & {
1785
+ checksum: ConvexTextBuilderInitial<""> & {
1786
+ _: {
1787
+ notNull: true;
1788
+ };
1789
+ } & {
1786
1790
  _: {
1787
1791
  tableName: "migration_state";
1788
1792
  };
1789
1793
  } & {
1790
1794
  _: {
1791
- fieldName: "startedAt";
1795
+ fieldName: "checksum";
1792
1796
  };
1793
1797
  };
1794
- updatedAt: ConvexNumberBuilderInitial<""> & {
1798
+ applied: ConvexBooleanBuilderInitial<""> & {
1795
1799
  _: {
1796
1800
  notNull: true;
1797
1801
  };
@@ -1801,41 +1805,41 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1801
1805
  };
1802
1806
  } & {
1803
1807
  _: {
1804
- fieldName: "updatedAt";
1808
+ fieldName: "applied";
1805
1809
  };
1806
1810
  };
1807
- completedAt: ConvexNumberBuilderInitial<""> & {
1811
+ runId: ConvexTextBuilderInitial<""> & {
1808
1812
  _: {
1809
1813
  tableName: "migration_state";
1810
1814
  };
1811
1815
  } & {
1812
1816
  _: {
1813
- fieldName: "completedAt";
1817
+ fieldName: "runId";
1814
1818
  };
1815
1819
  };
1816
- lastError: ConvexTextBuilderInitial<""> & {
1820
+ processed: ConvexNumberBuilderInitial<""> & {
1817
1821
  _: {
1818
- tableName: "migration_state";
1822
+ notNull: true;
1819
1823
  };
1820
1824
  } & {
1821
1825
  _: {
1822
- fieldName: "lastError";
1826
+ tableName: "migration_state";
1823
1827
  };
1824
- };
1825
- migrationId: ConvexTextBuilderInitial<""> & {
1828
+ } & {
1826
1829
  _: {
1827
- notNull: true;
1830
+ fieldName: "processed";
1828
1831
  };
1829
- } & {
1832
+ };
1833
+ startedAt: ConvexNumberBuilderInitial<""> & {
1830
1834
  _: {
1831
1835
  tableName: "migration_state";
1832
1836
  };
1833
1837
  } & {
1834
1838
  _: {
1835
- fieldName: "migrationId";
1839
+ fieldName: "startedAt";
1836
1840
  };
1837
1841
  };
1838
- checksum: ConvexTextBuilderInitial<""> & {
1842
+ updatedAt: ConvexNumberBuilderInitial<""> & {
1839
1843
  _: {
1840
1844
  notNull: true;
1841
1845
  };
@@ -1845,29 +1849,25 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1845
1849
  };
1846
1850
  } & {
1847
1851
  _: {
1848
- fieldName: "checksum";
1852
+ fieldName: "updatedAt";
1849
1853
  };
1850
1854
  };
1851
- applied: ConvexBooleanBuilderInitial<""> & {
1852
- _: {
1853
- notNull: true;
1854
- };
1855
- } & {
1855
+ completedAt: ConvexNumberBuilderInitial<""> & {
1856
1856
  _: {
1857
1857
  tableName: "migration_state";
1858
1858
  };
1859
1859
  } & {
1860
1860
  _: {
1861
- fieldName: "applied";
1861
+ fieldName: "completedAt";
1862
1862
  };
1863
1863
  };
1864
- runId: ConvexTextBuilderInitial<""> & {
1864
+ lastError: ConvexTextBuilderInitial<""> & {
1865
1865
  _: {
1866
1866
  tableName: "migration_state";
1867
1867
  };
1868
1868
  } & {
1869
1869
  _: {
1870
- fieldName: "runId";
1870
+ fieldName: "lastError";
1871
1871
  };
1872
1872
  };
1873
1873
  writeMode: ConvexTextBuilderInitial<""> & {
@@ -1918,6 +1918,19 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1918
1918
  fieldName: "direction";
1919
1919
  };
1920
1920
  };
1921
+ runId: ConvexTextBuilderInitial<""> & {
1922
+ _: {
1923
+ notNull: true;
1924
+ };
1925
+ } & {
1926
+ _: {
1927
+ tableName: "migration_run";
1928
+ };
1929
+ } & {
1930
+ _: {
1931
+ fieldName: "runId";
1932
+ };
1933
+ };
1921
1934
  startedAt: ConvexNumberBuilderInitial<""> & {
1922
1935
  _: {
1923
1936
  notNull: true;
@@ -1962,19 +1975,6 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
1962
1975
  fieldName: "lastError";
1963
1976
  };
1964
1977
  };
1965
- runId: ConvexTextBuilderInitial<""> & {
1966
- _: {
1967
- notNull: true;
1968
- };
1969
- } & {
1970
- _: {
1971
- tableName: "migration_run";
1972
- };
1973
- } & {
1974
- _: {
1975
- fieldName: "runId";
1976
- };
1977
- };
1978
1978
  dryRun: ConvexBooleanBuilderInitial<""> & {
1979
1979
  _: {
1980
1980
  notNull: true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitcn",
3
- "version": "0.33.5",
3
+ "version": "0.33.6",
4
4
  "description": "kitcn - React Query integration and CLI tools for Convex",
5
5
  "keywords": [
6
6
  "convex",
@@ -406,11 +406,26 @@ All from `kitcn/react`:
406
406
  authClient={authClient}
407
407
  convexQueryClient={convexQueryClient} // when using TanStack Query
408
408
  initialToken={token} // from SSR (caller.getToken())
409
+ optimisticAuth // opt in: open gates while Convex confirms a held JWT
410
+ onTokenIdentityChange={() => window.location.reload()}
409
411
  onMutationUnauthorized={() => router.push('/login')}
410
412
  onQueryUnauthorized={({ queryName }) => console.log(`Unauth: ${queryName}`)}
411
413
  >
412
414
  ```
413
415
 
416
+ `optimisticAuth` only opens auth-bound query gates for a held, unexpired JWT;
417
+ expired, opaque, and refused tokens stay closed. Enable
418
+ `onTokenIdentityChange` to refuse a JWT whose `sub` or `sessionId` differs from
419
+ the document identity before Convex or HTTP sees it. The client closes before
420
+ the callback runs, so reload the document there.
421
+
422
+ For multiple provider mounts, pass `tokenIdentityBaseline` as
423
+ `sub|sessionId`, or a getter returning the document's current identity. The
424
+ getter is checked for every admission, cached tokens included.
425
+ `onTokenIdentityAdmitted(token)` observes admitted JWTs so the app can update
426
+ that shared baseline. All three identity options require
427
+ `onTokenIdentityChange`.
428
+
414
429
  For `@convex-dev/auth` (React Native):
415
430
  ```tsx
416
431
  import { ConvexProviderWithAuth } from 'kitcn/react';
@@ -298,6 +298,22 @@ const mutation = useMutation(crpc.user.update.mutationOptions({
298
298
 
299
299
  Signature: `crpc.path.mutationOptions(options?)` — standard TanStack mutation options except `mutationFn`.
300
300
 
301
+ Pass `optimisticUpdate(localStore, args)` to use Convex's optimistic local
302
+ query store. This option is removed before the TanStack options are returned;
303
+ Convex replays it as query data changes and owns rollback when the mutation
304
+ completes.
305
+
306
+ ```ts
307
+ const mutation = useMutation(crpc.todos.rename.mutationOptions({
308
+ optimisticUpdate: (store, args) => {
309
+ const todos = store.getQuery(api.todos.list, {});
310
+ if (todos) store.setQuery(api.todos.list, {}, todos.map((todo) =>
311
+ todo._id === args.id ? { ...todo, title: args.title } : todo
312
+ ));
313
+ },
314
+ }));
315
+ ```
316
+
301
317
  ### Mutation Keys
302
318
 
303
319
  ```ts