kitcn 0.25.5 → 0.25.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 ADDED
@@ -0,0 +1,3228 @@
1
+ # kitcn
2
+
3
+ ## 0.25.6
4
+
5
+ ### Patch Changes
6
+
7
+ - [#373](https://github.com/udecode/kitcn/pull/373) [`118093a`](https://github.com/udecode/kitcn/commit/118093aa97c269b4d6d544b31aa939bd62cb8ec4) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
8
+
9
+ - Fix `.output()` validation failures reaching the client as an opaque
10
+ `Server Error`. They now throw a `CRPCError` with code
11
+ `INTERNAL_SERVER_ERROR`, message `Output validation failed`, and sanitized
12
+ structural Zod issues in `error.data.ZodError`, so a handler returning the
13
+ wrong shape names itself without exposing rejected server output.
14
+ `.paginated()` is covered too.
15
+
16
+ ```ts
17
+ // A handler that returns the wrong shape
18
+ c.query
19
+ .output(z.object({ ok: z.boolean() }))
20
+ .query(async () => ({ ok: "yes" }));
21
+
22
+ // Client
23
+ error.data.ZodError;
24
+ // [{ expected: 'boolean', code: 'invalid_type', path: ['ok'] }]
25
+ ```
26
+
27
+ - Log server faults from HTTP routes. A route that fails its `.output()` schema
28
+ still answers `500` with only a code and message, but the full error now
29
+ reaches the server log instead of being discarded.
30
+
31
+ - Ship `CHANGELOG.md` in the published package.
32
+
33
+ - Document the `.output()` return contract: the handler returns the schema's
34
+ input type, an `undefined` return is parsed as-is rather than substituted with
35
+ `null`, and an absent value is modelled as `.nullable()` rather than a
36
+ top-level `.optional()`, which Convex's returns validator cannot express.
37
+
38
+ ## 0.25.5
39
+
40
+ ### Patch Changes
41
+
42
+ - [#372](https://github.com/udecode/kitcn/pull/372) [`f288304`](https://github.com/udecode/kitcn/commit/f2883042f1c8f9467ea8f1bcb57ee88c43cbdfc2) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
43
+
44
+ - Fix `kitcn codegen` and `kitcn dev` aborting on a `generated/server.ts` written
45
+ by an older kitcn, or one that no longer matches the schema. That file is now
46
+ rewritten from the schema before codegen reads any app module, so it repairs
47
+ itself instead of failing every module with the error it is supposed to fix.
48
+ - Keep the procedure names recorded by the last full run when running
49
+ `kitcn codegen --scope auth` or `--scope orm`. Scoped runs no longer blank the
50
+ lookup that middleware reads `procedure.name` from.
51
+ - Fail `kitcn codegen` with the underlying error when `schema.ts` cannot be
52
+ loaded, instead of silently regenerating the app as if it had no ORM schema
53
+ and deleting the generated aggregate entry.
54
+ - Point the aggregate and migration capability setup errors at a step that
55
+ works. They previously advised rerunning the command that had just failed.
56
+
57
+ ## 0.25.4
58
+
59
+ ### Patch Changes
60
+
61
+ - [#371](https://github.com/udecode/kitcn/pull/371) [`80a8441`](https://github.com/udecode/kitcn/commit/80a84414ea684ac8faedc4b16181594528427079) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
62
+
63
+ - Fix large `in` and `notIn` filters across ORM reads, updates, and deletes.
64
+ - Fix large `OR` and `AND` filters exceeding Convex's nesting limit.
65
+ - Reject malformed empty logical filters before scheduled mutations run.
66
+
67
+ ## 0.25.3
68
+
69
+ ### Patch Changes
70
+
71
+ - [#370](https://github.com/udecode/kitcn/pull/370) [`54c88d1`](https://github.com/udecode/kitcn/commit/54c88d18acbcbe60ae17691ac813384b79e41182) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
72
+
73
+ - Fix `count()`, `aggregate()`, `groupBy()`, and relation `_count` so `isNull: true` matches rows whose column is absent from the document, not just rows holding an explicit `null` — matching `findMany()` under the same filter.
74
+ - Emit a single group keyed `null` for an `isNull`-constrained `groupBy()` field, combining every metric over both explicitly-`null` and absent rows.
75
+ - Improve `groupBy()` fan-out guards so merged nullish groups count every physical aggregate bucket probe.
76
+
77
+ ## 0.25.2
78
+
79
+ ### Patch Changes
80
+
81
+ - [#352](https://github.com/udecode/kitcn/pull/352) [`942fb08`](https://github.com/udecode/kitcn/commit/942fb084db467fa76722941ede4b77781697cffd) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
82
+
83
+ - Cut ~256 KB (−22%) from the bundle Convex deploys for apps without Better Auth. `import { z } from 'zod'` binds zod's namespace object, which pins all 50 translation files; scaffolds and internals now use `import * as z from 'zod'`, which tree-shakes them. Apps using Better Auth are unchanged — it pins the barrel itself.
84
+ - Improve `update().returning()`: it reuses the row it just wrote instead of reading it back, so a matched-row update costs one fewer read per row. Tables with lifecycle hooks or a self-referencing cascade still read back, since either can rewrite the row.
85
+ - Improve `update()` foreign-key checks: a single-column reference supplied by `set()` is validated once per statement instead of once per matched row. Unique-index checks still run per row, as they must.
86
+ - Speed up `kitcn analyze` by bundling entry points concurrently: 2.9 s → 2.1 s on a 20-entry app, with byte-identical output.
87
+ - Reduce `kitcn add <plugin>` from three package-manager installs to two. Saves ~2 s on npm; bun is already fast enough that the difference is noise.
88
+
89
+ ## 0.25.1
90
+
91
+ ### Patch Changes
92
+
93
+ - [#343](https://github.com/udecode/kitcn/pull/343) [`3f9631c`](https://github.com/udecode/kitcn/commit/3f9631cad7e07fbe034afba702f84a9318067a77) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
94
+
95
+ - Support Convex commit timestamp validators in ORM and Zod conversion.
96
+ - Warn when an installed Convex version is outside the supported minor range.
97
+ - Keep emitted declarations compatible with the minimum supported Convex and
98
+ forward commit timestamp variables through database wrappers.
99
+
100
+ ## 0.25.0
101
+
102
+ ### Minor Changes
103
+
104
+ - [#342](https://github.com/udecode/kitcn/pull/342) [`3aff976`](https://github.com/udecode/kitcn/commit/3aff976a2d955fb9dc916b94bd3cd39e3e2e418d) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - - Rerun `kitcn codegen` to register aggregate, rank, and migration runtimes through the generated ORM setup.
105
+ - Register `aggregateCapability()` from `kitcn/orm/aggregate-index` and `migrationCapability()` from `kitcn/orm/migrations` when constructing a hand-written ORM that uses those subsystems.
106
+ - Import aggregate backfill argument types from `kitcn/orm/aggregate-index` and migration argument types from `kitcn/orm/migrations`.
107
+ - Keep `kitcn/orm` free of optional aggregate, rank, backfill, and migration runtime imports until the corresponding capability is registered.
108
+ - Run `kitcn aggregate prune` after removing the final aggregate or rank index; the generated maintenance entry remains available and drains large rank trees in bounded chunks.
109
+ - Read authenticated query and mutation sessions with `getSession(ctx)`, and keep authenticated action builders in a separate module that owns `getAuth(ctx)`.
110
+
111
+ ## 0.24.0
112
+
113
+ ### Minor Changes
114
+
115
+ - [#341](https://github.com/udecode/kitcn/pull/341) [`c255ae2`](https://github.com/udecode/kitcn/commit/c255ae2a9305c3ccd2793b109ef6a259202be906) Thanks [@RatelimitUser](https://github.com/RatelimitUser)! - ## Breaking changes
116
+
117
+ - Resolve `getSignals` before `getIdentifier` in `RatelimitPlugin.configure` and
118
+ pass its result in as `signals`. `getSignals` no longer receives `identifier`,
119
+ and `getIdentifier` also receives `tier`.
120
+
121
+ ```ts
122
+ // Before
123
+ getIdentifier: ({ user }: { user: RatelimitUser | null }) =>
124
+ user?.id ?? 'anonymous',
125
+ getSignals: ({ ctx }: { ctx: RatelimitCtx }) => getRequestSignals(ctx),
126
+
127
+ // After
128
+ getSignals: ({ ctx }: { ctx: RatelimitCtx }) => getRequestSignals(ctx),
129
+ getIdentifier: ({
130
+ user,
131
+ signals,
132
+ }: {
133
+ | null;
134
+ signals: LimitRequest | undefined;
135
+ }) => (user ? user.id : signals?.ip ? `ip:${signals.ip}` : 'ip:unknown'),
136
+ ```
137
+
138
+ - Key anonymous rate-limit traffic by request IP instead of one shared
139
+ identifier, so a single visitor can no longer spend every other visitor's
140
+ budget or arm a 24 hour deny-list block against all of them. Run
141
+ `kitcn add ratelimit --overwrite` to take the new plugin.
142
+ - Add `cleanupRatelimitState` and scaffold an indexed, batched private mutation
143
+ for manual cleanup of state older than a caller-owned cutoff. Repeat the
144
+ on-demand call while it returns `hasMore: true`.
145
+ - Store no-arg `crpc.http.*` entries under `['httpQuery', route, {}]` on both the
146
+ client and the RSC server, so a server-prefetched route hydrates instead of
147
+ refetching.
148
+ - Return the exact cache key from `crpc.http.*.queryKey()`, `{}` included, so
149
+ `getQueryData` and `setQueryData` hit. Use `queryFilter()` to match every args
150
+ variant of a route.
151
+
152
+ ```ts
153
+ // Before
154
+ queryClient.getQueryData(["httpQuery", "health", undefined]);
155
+ crpc.http.health.queryKey(); // ['httpQuery', 'health']
156
+
157
+ // After
158
+ queryClient.getQueryData(crpc.http.health.queryKey());
159
+ crpc.http.health.queryKey(); // ['httpQuery', 'health', {}]
160
+ ```
161
+
162
+ - Narrow `HttpQueryKey` to that exact three-element key. The route-wide prefix
163
+ `queryFilter()` builds is typed as `HttpQueryPrefixKey`.
164
+
165
+ ## Features
166
+
167
+ - Add `timeout`, `dynamicLimits`, `denyList`, and `ephemeralCache` to
168
+ `RatelimitPlugin.configure`. They reach the limiter instead of being dropped.
169
+
170
+ ## Patches
171
+
172
+ - Fix `crpc.http.*` routes being fetched twice on first paint. `queryOptions`
173
+ carries a 30 second `staleTime` shared with the RSC QueryClient, overridable
174
+ per call, and `refetchOnMount` keeps its default so a route invalidated while
175
+ unmounted still refetches.
176
+ - Fix the deny list blocking shared NAT and mobile-carrier IPs. Count only
177
+ failures inside a rolling 10-minute window and cache values that reach
178
+ `denyListThreshold` as blocked for up to 24 hours.
179
+ - Fix deny-list memory growing without bound when callers forge `User-Agent`
180
+ headers.
181
+ - Fix `ephemeralCache: false` being ignored while a limit is evaluated, which
182
+ kept an in-memory block cache alive after you disabled it.
183
+
184
+ ## 0.23.0
185
+
186
+ ### Minor Changes
187
+
188
+ - [#340](https://github.com/udecode/kitcn/pull/340) [`13fbae3`](https://github.com/udecode/kitcn/commit/13fbae321d73801c90423c8f9025fef5f958553d) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
189
+
190
+ - `.output()` is now validated once, against the value your handler returned,
191
+ instead of against its wire encoding. Schemas that transform a value into a
192
+ `Date` (or into any type a custom wire codec owns) now encode correctly
193
+ instead of being rejected, and `.output()` schemas using async refinements
194
+ work. Procedure handlers return the schema input type; generated clients
195
+ receive its output type.
196
+
197
+ ```ts
198
+ const at = c.query
199
+ .output(z.object({ at: z.string().transform((s) => new Date(s)) }))
200
+ .query(async () => ({ at: "2024-01-01T00:00:00.000Z" }));
201
+
202
+ // Before: the schema ran after encoding, so the Date left the server raw
203
+ // After: { at: { __crpc: 1, t: '$date', v: 1704067200000 } }
204
+ ```
205
+
206
+ - `.output()` parses the handler's value as-is and no longer substitutes `null`
207
+ for an `undefined` return. A nullable schema needs an explicit `null`; in
208
+ exchange, `.output(z.string().default(...))` now applies its default to an
209
+ `undefined` return instead of rejecting it. The low-level `returns:` option
210
+ still substitutes. Handlers were already typed to return the schema's input
211
+ type, so TypeScript rejects this ahead of runtime except where a lookup is
212
+ typed as always-present — an index signature or `array[0]` under the default
213
+ `noUncheckedIndexedAccess: false`.
214
+
215
+ ```ts
216
+ const name = c.query
217
+ .input(z.object({ id: z.string() }))
218
+ .output(z.string().nullable())
219
+ // Before: an `undefined` return was parsed as `null`
220
+ // After: coalesce it
221
+ .query(async ({ input }) => names[input.id] ?? null);
222
+ ```
223
+
224
+ ## Features
225
+
226
+ - `zCustomQuery`, `zCustomMutation` and `zCustomAction` accept
227
+ `skipZodReturnsValidation`, so `returns` can declare the Convex validator and
228
+ the return type without also parsing the response in JS. The handler is then
229
+ typed as the schema's output, since that value reaches Convex unchanged.
230
+
231
+ ```ts
232
+ zCustomQuery(
233
+ query,
234
+ customCtx(withUser)
235
+ )({
236
+ args: { id: z.string() },
237
+ returns: z.object({ name: z.string() }),
238
+ skipZodReturnsValidation: true,
239
+ handler,
240
+ });
241
+ ```
242
+
243
+ - Wire codecs accept `objectsOnly`, declaring that `isType` never claims a
244
+ primitive. `serialize` then skips codec dispatch on primitive values.
245
+
246
+ ```ts
247
+ const mapCodec: WireCodec = {
248
+ tag: "$map",
249
+ objectsOnly: true,
250
+ isType: (value) => value instanceof Map,
251
+ encode: (value) => [...value],
252
+ decode: (value) => new Map(value),
253
+ };
254
+ ```
255
+
256
+ ## Patches
257
+
258
+ - Cut one full traversal of every response with an `.output()` or
259
+ `.paginated()` declaration.
260
+ - Reuse the argument schema and its parse cache across requests instead of
261
+ rebuilding them on every procedure call.
262
+ - Resolve the multi-`.input()` merge plan when the procedure is defined.
263
+ Declaring a key that `.paginated()` also declares no longer clones a schema
264
+ on every request.
265
+ - Skip codec dispatch on primitive values while encoding the built-in `Date`
266
+ payloads, and stop walking a payload twice per direction when a transformer
267
+ is passed to a server-side caller.
268
+ - Resolve HTTP `searchParams` coercion per route instead of per request, and
269
+ read the query string in a single pass.
270
+ - Convert an `.input()` shape to its Convex validator once per procedure
271
+ instead of three times.
272
+
273
+ ## 0.22.1
274
+
275
+ ### Patch Changes
276
+
277
+ - [#356](https://github.com/udecode/kitcn/pull/356) [`f5d9edd`](https://github.com/udecode/kitcn/commit/f5d9edd62670ce098bb18d7f4987ec1f3b3365aa) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix prefetched optional React pagination remaining disabled after authentication
278
+ settles.
279
+
280
+ ## 0.22.0
281
+
282
+ ### Minor Changes
283
+
284
+ - [#339](https://github.com/udecode/kitcn/pull/339) [`ed72944`](https://github.com/udecode/kitcn/commit/ed72944a45e7cae642bd33c7b20dff2968c70508) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Features
285
+
286
+ - Support stable identity values from custom Solid auth providers.
287
+
288
+ ## Patches
289
+
290
+ - Fix function-form `enabled` predicates in `kitcn/solid` query options so
291
+ they gate both requests and live subscriptions.
292
+ - Fix unauthenticated `auth: "required"` Solid action queries to reject locally with
293
+ `CRPCClientError`, matching the React bindings.
294
+ - Fix auth-bound cached data crossing identity transitions. Unobserved entries are
295
+ removed; mounted entries are rebuilt without their previous `initialData`,
296
+ return to pending without prior-account placeholder data, and refetch for the
297
+ new account.
298
+
299
+ - Fix `kitcn/solid` paginated lists on an `auth: 'required'` function never
300
+ issuing a query. Auth state is tracked, so a list mounted before sign-in loads
301
+ once auth settles instead of showing a permanent loading state, and logging
302
+ out stops its page subscriptions.
303
+ - Fix `kitcn/solid` tearing down a Convex subscription that another mounted
304
+ component still needs when two components share a query key and one passes
305
+ `enabled: false`. The remaining component keeps receiving real-time updates.
306
+ - Fix `skipUnauth` being ignored by `kitcn/solid`. Queries marked
307
+ `skipUnauth: true` resolve to `null` on an unauthorized result instead of
308
+ sticking in an error state.
309
+ - Fix `kitcn/solid` re-authenticating Convex on every JWT write. Signing in
310
+ authenticates once instead of three times, and a scheduled token refresh no
311
+ longer pauses the socket and re-runs every live subscription.
312
+ - Fix `kitcn/solid` ignoring a `useAuth` that returns a new `fetchAccessToken`.
313
+ Convex is rebound to the current fetcher instead of refreshing through the one
314
+ captured for the previous session.
315
+ - Fix provider-driven identity transitions retaining the previous account's
316
+ auth-bound cache or Convex binding. `ConvexProviderWithAuth` accepts an
317
+ optional stable `identity`; providers that omit it retain the safe legacy
318
+ behavior of rebinding on reactive auth changes. Replacing a Better Auth
319
+ session also invalidates its cached JWT and abandons in-flight token requests
320
+ owned by the previous session before authenticating the new one. SSR tokens
321
+ remain hydration fallbacks only until a client session is confirmed and
322
+ cannot seed that session's cache identity. The first settled client identity
323
+ clears auth-bound hydration state when its ownership cannot be proven.
324
+ - Fix an account transition leaving the previous account's rows in disabled,
325
+ unobserved, or non-subscribed queries.
326
+ - Fix a paginated list restoring the previous account's cursors after signing
327
+ in or out. An auth-bound list starts again from its first page instead of
328
+ paging from cursors that point into another account's results.
329
+ - Fix an auth-bound query refetching everything on every scheduled token
330
+ refresh. A refreshed JWT for the same account leaves the cache alone; only an
331
+ authorization identity change clears it, including tenant or role claims
332
+ changing inside the same Better Auth session.
333
+ - Fix sign-in and sign-up mutations clearing auth-bound queries before Convex
334
+ adopts the new identity. The provider clears previous-account data while the
335
+ binding changes, holds mounted observers idle, then restores and refetches
336
+ only after Convex reports the transition as settled. Sign-out follows the
337
+ same provider-owned transition.
338
+ - Fix custom Solid Convex auth being replaced by the fallback Better Auth
339
+ store. Query subscriptions follow the custom provider, settled identity and
340
+ account epoch instead of remaining blocked or reusing another account's
341
+ pagination state.
342
+ - Fix account transitions retaining obsolete pagination ID entries. Pagination
343
+ state in the QueryClient remains the persistence owner without a second
344
+ process-wide key map.
345
+ - Fix prefetched optional pagination queries fetching while authentication is
346
+ loading. Hydrated data remains readable, but its observer stays disabled
347
+ until the auth binding settles.
348
+ - Fix overlapping auth transitions restoring stale observer options or letting
349
+ an older settlement refetch during a newer identity change. Only the latest
350
+ transition can restore and refetch, and option updates made while observers
351
+ are suspended remain authoritative.
352
+ - Keep auth-bound queries mounted during a Solid identity transition disabled
353
+ until Convex confirms the new identity. Both one-shot requests and live
354
+ subscriptions wait behind the same client-owned settlement barrier.
355
+ - Ignore Convex auth-settlement callbacks from superseded bindings. A late
356
+ callback from an older account cannot republish that identity or reopen the
357
+ query barrier during a newer transition.
358
+
359
+ ## 0.21.0
360
+
361
+ ### Minor Changes
362
+
363
+ - [#338](https://github.com/udecode/kitcn/pull/338) [`7163710`](https://github.com/udecode/kitcn/commit/7163710aea8ec3758af04128836027aca8bf724b) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
364
+
365
+ - `createClient` now takes a `getBetterAuthSchema` thunk and its `adapter(ctx)`
366
+ takes only the context. The Better Auth table schema is derived once for the
367
+ isolate and shared, instead of every adapter re-deriving it. `dbAdapter` drops
368
+ its options-getter argument for the same reason.
369
+
370
+ ```ts
371
+ // Before
372
+ const authClient = createClient({ authFunctions, schema });
373
+ const database = authClient.adapter(ctx, getAuthOptions);
374
+
375
+ // After
376
+ const authClient = createClient({
377
+ authFunctions,
378
+ getBetterAuthSchema,
379
+ schema,
380
+ });
381
+ const database = authClient.adapter(ctx);
382
+ ```
383
+
384
+ ## Patches
385
+
386
+ - Improve authenticated request latency: `getAuth(ctx)` evaluates your
387
+ `defineAuth` callback once per request instead of twice.
388
+ - Improve `admin.listUsers` and other counted reads: totals no longer hold every
389
+ matching row in memory while paginating.
390
+ - Improve Better Auth record updates: an update is one Convex call that reads
391
+ the row once, instead of a separate pre-check call that read it again. The
392
+ "expected exactly 1 match" error now comes from the write itself, so it can no
393
+ longer be invalidated by a concurrent insert or delete.
394
+ - Improve auth request CPU: the Convex auth plugin reuses its OIDC provider, and
395
+ unique-field lookups no longer rescan the auth schema on every read and write.
396
+ - Fix session recovery from a persisted token issuing a fixed 250ms delay plus
397
+ up to ten `/get-session` requests. A live token is recovered with one immediate
398
+ request, a server-confirmed missing session stops after one, and only transport
399
+ failures retry.
400
+ - Fix a dropped `/get-session` request signing the user out. Transport failures
401
+ retry with backoff for the rest of the session-sync grace window, so a session
402
+ is restored in the same mount once connectivity returns.
403
+ - Fix an outage during session recovery leaving the app stuck on `isLoading`.
404
+ When the grace window closes with no answer, auth resolves to unauthenticated
405
+ instead of holding a token no request ever confirmed. The persisted token is
406
+ kept so the next mount can retry it.
407
+
408
+ ## 0.20.0
409
+
410
+ ### Minor Changes
411
+
412
+ - [#337](https://github.com/udecode/kitcn/pull/337) [`5d3172b`](https://github.com/udecode/kitcn/commit/5d3172b260bba6d44ba06b5639c22711c0d58f79) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
413
+
414
+ - Range-filtered `count()` and `aggregate()` now stop at `aggregateWorkBudget`
415
+ work units and throw `COUNT_FILTER_UNSUPPORTED` /
416
+ `AGGREGATE_FILTER_UNSUPPORTED` naming the index, instead of reading the whole
417
+ equality prefix and failing on Convex's transaction read limit. Bucket scans
418
+ cost one unit; `_min` and `_max` also reserve one extrema read per matching
419
+ bucket. One budget covers every `IN` prefix and extrema metric sharing the
420
+ range plan. Raise it cautiously if a wide range scan is intentional.
421
+
422
+ ```ts
423
+ // Before
424
+ export default defineSchema({ runs });
425
+
426
+ // After
427
+ export default defineSchema(
428
+ { runs },
429
+ // Keep headroom below Convex's 32,000-document transaction ceiling.
430
+ { defaults: { aggregateWorkBudget: 20_000 } }
431
+ );
432
+ ```
433
+
434
+ ## Features
435
+
436
+ - `kitcn aggregate rebuild` and index pruning clear stored aggregate state in
437
+ scheduled batches, so rebuilding or dropping an `aggregateIndex` / `rankIndex`
438
+ on a large table no longer has to fit in a single Convex mutation. Indexes
439
+ report a `CLEARING` status while draining, and `kitcn aggregate prune` reports
440
+ how many removed indexes are still being cleared in the background.
441
+ - ORM writes targeting a declared index in `CLEARING` fail before the document
442
+ write. Retry after the index advances to `BUILDING` or `READY`; this prevents
443
+ concurrent writes from being erased by a multi-mutation clear.
444
+ - Automatic pruning follows canonical aggregate lifecycle state instead of
445
+ reverse-scanning every distinct backing-table index. Exact `tableName` and
446
+ `indexName` handler arguments retain bounded recovery for state-less storage.
447
+
448
+ ## Patches
449
+
450
+ - Reduce database reads per rank-index write: the btree descent no longer
451
+ re-queries the tree document at every node, re-reads nodes it just wrote, or
452
+ re-reads the child it descends into.
453
+ - Reduce database reads for `rank().min()`, `rank().max()` and `rank().random()`
454
+ by dropping a redundant count scan per call.
455
+ - Reduce document writes during aggregate backfill: a page of rows sharing a key
456
+ tuple now writes its bucket once instead of once per row.
457
+ - Stop writing `aggregate_member` rows when a mutation changes no aggregated
458
+ field.
459
+ - Improve `count()` and `aggregate()` latency for multi-value `IN` filters and
460
+ for `_min` / `_max` by issuing independent bucket reads through a bounded pool.
461
+ - Keep a partially cleared index in `CLEARING` when an error interrupts a
462
+ rebuild, so a retry resumes clearing instead of building over stale buckets.
463
+
464
+ ## 0.19.0
465
+
466
+ ### Minor Changes
467
+
468
+ - [#336](https://github.com/udecode/kitcn/pull/336) [`aba33f5`](https://github.com/udecode/kitcn/commit/aba33f55f1eacacdf36c8408391068a7e3868132) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
469
+
470
+ - Read `.select().where({ id: { in: [...] } })` in the order the ids are given
471
+ instead of creation order. Each page reads only the listed positions it
472
+ visits rather than the complete ID list; missing or policy-filtered ids still
473
+ count as reads. Add `orderBy` to keep creation order. Cursors issued by the
474
+ previous behavior are not portable.
475
+
476
+ ```ts
477
+ // Before — creation order, and every page read the whole id list
478
+ await ctx.orm.query.posts
479
+ .select()
480
+ .where({ id: { in: ids } })
481
+ .map((row) => row)
482
+ .paginate({ cursor, limit: 10 });
483
+
484
+ // After — same call, rows come back in the order `ids` lists them
485
+ await ctx.orm.query.posts
486
+ .select()
487
+ .where({ id: { in: ids } })
488
+ .map((row) => row)
489
+ .paginate({ cursor, limit: 10 });
490
+
491
+ // After — creation order, which still reads every id in the list
492
+ await ctx.orm.query.posts
493
+ .select()
494
+ .where({ id: { in: ids } })
495
+ .orderBy({ createdAt: "asc" })
496
+ .map((row) => row)
497
+ .paginate({ cursor, limit: 10 });
498
+ ```
499
+
500
+ ## Patches
501
+
502
+ - Fix `.distinct({ fields })` on more than one field growing exponentially more
503
+ expensive with each row returned, which made pages of about twenty rows fail
504
+ to return at all.
505
+ - Fix `.distinct({ fields })` over `.union(...).interleaveBy(...)` slowing down
506
+ sharply as the number of returned rows grows.
507
+ - Support `maxScan` on paginated `where: { id: { in: [...] } }` reads, including
508
+ reads ordered by a single indexed field.
509
+ - Improve paginated reads to register fewer Convex queries per page, and to
510
+ release the ones they opened when a page stops early.
511
+ - Improve the per-row cost of every stream-backed read.
512
+
513
+ ## 0.18.0
514
+
515
+ ### Minor Changes
516
+
517
+ - [#335](https://github.com/udecode/kitcn/pull/335) [`9b3494d`](https://github.com/udecode/kitcn/commit/9b3494de4a057612b718b8c522d99c012926832f) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
518
+
519
+ - Fix `orderBy` returning the wrong rows when the `where` pins only part of a
520
+ compound index. Ordering by `createdAt` under `where: { type: 'a' }` on an
521
+ index of `(type, numLikes)` used to hand back the rows sorted by `numLikes`.
522
+ It now returns creation order. Queries in that shape return different rows
523
+ than before, and under `cursor` pagination with `strict` they now report that
524
+ the field has no usable index instead of paginating in the wrong order.
525
+
526
+ ```ts
527
+ // Schema: index('numLikesAndType').on(t.type, t.numLikes)
528
+
529
+ // Before — returned the two most-liked posts
530
+ // After — returns the two newest posts, as asked
531
+ await ctx.orm.query.posts.findMany({
532
+ where: { type: "a" },
533
+ orderBy: { createdAt: "desc" },
534
+ limit: 2,
535
+ });
536
+
537
+ // Pinning the narrower index leaves creation time as the implicit next key
538
+ index("by_type").on(t.type);
539
+ ```
540
+
541
+ - Change which rows a `.through()` relation returns for a given `limit`. Each
542
+ parent now gets its own first `limit` links instead of a window over the
543
+ order in which targets happened to be discovered across the whole page.
544
+ `orderBy` on a through relation is unaffected.
545
+
546
+ ## Patches
547
+
548
+ - Push `limit` and `orderBy` on a `many()` relation into the relation index.
549
+ `with: { posts: { limit: 5, orderBy: { createdAt: 'desc' } } }` reads five
550
+ posts per parent instead of every post of every parent.
551
+ - Bound `.through()` relation reads by the requested `limit` instead of reading
552
+ every junction row of every parent. Links whose target is missing or is
553
+ dropped by RLS or the relation `where` do not consume a slot, so the page
554
+ still comes back full.
555
+ - Fill `limit` with rows that survive RLS and relation `where` instead of
556
+ filtering after the read. `findMany({ where: { ownerId }, limit: 3 })` on a
557
+ table with a select policy used to return only whichever of the first three
558
+ stored rows happened to be visible — often none.
559
+ - Push `limit` into `in`, `notIn`, `ne` and `isNotNull` reads, which previously
560
+ read every matching row and sliced afterwards.
561
+ - Use an index for `in` combined with another filter — `where: { status: { in:
562
+ [...] }, name: { contains: 'x' } }` scanned the whole table.
563
+ - Order by a field the `where` does not pin without reading the whole bucket,
564
+ as long as the index sorts by it next.
565
+ - Prefer an index that also supplies the requested order, so a compound
566
+ `(tenantId, createdAt)` is chosen over a narrow `(tenantId)` for a
567
+ tenant-scoped feed.
568
+ - Serve `orderBy` on the leading field of a pinned `.withIndex()` from the
569
+ index instead of scanning the table.
570
+ - Stop loading nested `with:` data, extras and column selection for relation
571
+ rows that the per-parent `limit` or `offset` then discards. Deeply nested
572
+ reads that previously failed the relation fan-out guard now succeed.
573
+ - Read each shared target once when counting a `.through()` relation with a
574
+ `where`, instead of once per parent row.
575
+ - Reuse aggregate bucket reads across rows of a `with._count`.
576
+ - Build the ORM once per request instead of twice; the RLS bypass client is
577
+ now created only when it is used.
578
+ - Reduce per-row work on filtered reads, relation counts, and query planning.
579
+
580
+ ## 0.17.5
581
+
582
+ ### Patch Changes
583
+
584
+ - [#332](https://github.com/udecode/kitcn/pull/332) [`2609245`](https://github.com/udecode/kitcn/commit/2609245de4e468715e4691f9a159c88a659d4f75) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
585
+
586
+ - Fix auth-bound queries being reset every time Convex refreshes the access
587
+ token. Convex rotates the token roughly every 15 minutes and on every socket
588
+ reauth, and each mint carried a new timestamp, so the whole page flashed back
589
+ to its loading state and every query ran twice against the backend. Queries now
590
+ keep their data and their live subscriptions across a refresh, and still reset
591
+ on a real identity change — sign in, sign out, session rotation, or an
592
+ organization/role switch.
593
+ - Fix `fetchNextPage` from `useInfiniteQuery` getting a new identity on every
594
+ render, which re-registered any effect keyed on it — including the
595
+ infinite-scroll observer pattern the docs recommend. It is now stable for the
596
+ life of the hook.
597
+ - Improve `useInfiniteQuery` to reuse its page queries and aggregation across
598
+ unrelated re-renders, instead of re-hashing arguments once per loaded page and
599
+ re-scanning every loaded item.
600
+ - Improve `queryOptions()` to keep its result referentially stable when nothing
601
+ changed, including the two-argument form with inline options.
602
+ - Fix query options losing referential stability entirely on pages that hold more
603
+ than 500 distinct sets of query arguments.
604
+ - Improve `useCRPC()` and `useCRPCClient()` to return the same value across
605
+ renders, so they are safe to place in a dependency array.
606
+ - Improve real-time updates to skip a redundant query-key hash per pushed query.
607
+
608
+ ## 0.17.4
609
+
610
+ ### Patch Changes
611
+
612
+ - [#331](https://github.com/udecode/kitcn/pull/331) [`23c0c99`](https://github.com/udecode/kitcn/commit/23c0c999adda8aab66d4d4f88806368fbcff8d2f) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
613
+
614
+ - Improve mutation latency on tables with triggers, `aggregateIndex()` or
615
+ `rankIndex()`. Writes no longer re-read the document after patching or
616
+ replacing it, and no longer read it at all when no hook consumes it.
617
+ - Improve `update()` and `delete()` cascade latency: `set null`, `set default`
618
+ and cascade-update fan-out now apply their patches concurrently with a
619
+ bounded pool instead of one round trip at a time. Tables with hooks keep
620
+ their strict write order.
621
+ - Improve read throughput on row-level-security tables. Policy `using` /
622
+ `withCheck` callbacks run once per query execution or write-free mutation
623
+ decision batch instead of once per returned row. Multi-row insert and delete
624
+ re-resolve stateful policies after each write.
625
+ - Fix row-level-security visibility when one query object is awaited more than
626
+ once. Every await re-resolves the table's policies, so a policy that reads
627
+ the database sees writes made between the two awaits.
628
+ - Improve CPU cost of every ORM read and every `returning()` row by reshaping
629
+ documents in a single pass.
630
+ - Improve `returning({ _count })` on multi-row mutations: the aggregate-index
631
+ readiness check now runs once per index instead of once per row.
632
+ - Improve cascade delete throughput on schemas with many triggered or
633
+ aggregate-indexed tables by removing per-row table-name probing.
634
+ - Improve mutations that issue concurrent writes to a hooked table: the
635
+ internal write lock now hands off to one waiter instead of waking all of
636
+ them.
637
+ - Fix `kitcn codegen` dropping nested cRPC HTTP routes when parsing projects
638
+ through generated server placeholders.
639
+
640
+ ## 0.17.3
641
+
642
+ ### Patch Changes
643
+
644
+ - [#330](https://github.com/udecode/kitcn/pull/330) [`b78d94a`](https://github.com/udecode/kitcn/commit/b78d94a53d2f044816944317acea0ee9973739d8) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
645
+
646
+ - Start the CLI faster. esbuild, Babel, jiti, dotenv and the interactive prompt
647
+ stack are loaded the first time a command needs them instead of on every
648
+ invocation, so `kitcn --version`, `kitcn --help` and `--json` calls no longer
649
+ pay for tooling they never use.
650
+ - Run `kitcn codegen` with less repeated work: one module loader per run instead
651
+ of two, and the parse shim resolved once instead of once per Convex module.
652
+ - Speed up `kitcn add`, `kitcn view` and `kitcn info` on large schemas by
653
+ parsing each schema revision once instead of once per managed table.
654
+ - Speed up `kitcn init` and `kitcn add` file comparison, which no longer copies
655
+ and serializes both syntax trees before comparing them.
656
+ - Fix `kitcn dev` ignoring edits to shared routers, builders and contracts that
657
+ sit next to the functions directory. Changing one regenerates the api like
658
+ changing a function file does, for any functions path configured in
659
+ `convex.json`.
660
+ - Generate api and procedure metadata in a stable order regardless of the
661
+ filesystem's directory listing order.
662
+ - Shrink the `kitcn dev` file watcher, which no longer loads the rest of the CLI
663
+ into the background process it keeps alive for the session.
664
+
665
+ ## 0.17.2
666
+
667
+ ### Patch Changes
668
+
669
+ - [#329](https://github.com/udecode/kitcn/pull/329) [`c853115`](https://github.com/udecode/kitcn/commit/c853115311cc6b2645c47736db529731af3fc2c6) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
670
+
671
+ - Fix `useInfiniteQuery` from `kitcn/solid` crashing with `state.map is not a function` on every mount.
672
+ - Update Solid infinite query results field by field, so a component reading `status` is not re-run when only `data` changes.
673
+
674
+ ## 0.17.1
675
+
676
+ ### Patch Changes
677
+
678
+ - [#324](https://github.com/udecode/kitcn/pull/324) [`0536f17`](https://github.com/udecode/kitcn/commit/0536f17bbd22f11d325c26c5e64bed160825a908) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
679
+
680
+ - Fix `kitcn codegen` emitting both the `api` and `internal` type imports into
681
+ generated runtime files that only reference one of them. A module whose
682
+ procedures are all internal, or all public, no longer carries an unused import
683
+ that editors grey out and that `tsc` rejects with `TS6196` when
684
+ `noUnusedLocals` is enabled. Each generated runtime now imports only the api
685
+ roots its procedures reference.
686
+
687
+ - [#326](https://github.com/udecode/kitcn/pull/326) [`6196625`](https://github.com/udecode/kitcn/commit/6196625d8ce3e9bd08f25373a7e536a43718b167) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
688
+
689
+ - Fix `CRPCError` reaching the client as a bare `Error` with the message
690
+ redacted to `Server Error` and `error.data` undefined. Errors converted by
691
+ cRPC — a procedure calling another procedure through a caller, an ORM
692
+ not-found, a Better Auth `APIError`, or any error wrapped by
693
+ `getCRPCErrorFromUnknown` — now arrive as a `ConvexError` carrying the
694
+ original `code`, `message`, and custom `data`.
695
+
696
+ ```ts
697
+ // convex/functions/payment.ts — internal procedure
698
+ throw new CRPCError({
699
+ code: "BAD_REQUEST",
700
+ message: "Declined: INSUFFICIENT_FUNDS",
701
+ data: { processorCode },
702
+ });
703
+
704
+ // Before — the public procedure delegating to it lost the reason
705
+ onError: (error) => {
706
+ error.data; // undefined
707
+ };
708
+
709
+ // After
710
+ onError: (error) => {
711
+ error.data; // { code: 'BAD_REQUEST', message: 'Declined: …', processorCode }
712
+ };
713
+ ```
714
+
715
+ - Fix converted errors losing every source-mapped frame in Convex dashboard
716
+ logs. Traces carry frames again; the original throw site stays on
717
+ `error.cause`.
718
+
719
+ ## 0.17.0
720
+
721
+ ### Minor Changes
722
+
723
+ - [#322](https://github.com/udecode/kitcn/pull/322) [`b80d734`](https://github.com/udecode/kitcn/commit/b80d73402165543c91c7f83bba3eae59a6a82184) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
724
+
725
+ - `kitcn add` no longer replaces scaffold files you have edited. Files that still
726
+ match the scaffold are upgraded as before; edited files are kept, listed under
727
+ `Refused files`, and the command exits `1` because the plugin is only partially
728
+ installed. Pass `--overwrite` for the previous behavior.
729
+
730
+ ```bash
731
+ # Before — edits to crpc.ts were replaced, exit 0
732
+ kitcn add auth --yes
733
+
734
+ # After — edits are kept and the run fails until you choose
735
+ kitcn add auth --yes --overwrite
736
+ ```
737
+
738
+ - `kitcn add --json` splits the old `skipped` list in two. `skipped` now means
739
+ "already up to date", refused files move to `refused`, and `complete` reports
740
+ whether everything was applied.
741
+
742
+ ```jsonc
743
+ // Before
744
+ { "skipped": ["convex/lib/crpc.ts"] }
745
+
746
+ // After
747
+ { "skipped": [], "refused": ["convex/lib/crpc.ts"], "complete": false }
748
+ ```
749
+
750
+ ## Patches
751
+
752
+ - Fix `kitcn codegen` leaving a hidden parse snapshot behind when a Convex module
753
+ fails to load, which kept reporting the old error after the real file was
754
+ fixed. Codegen evaluates modules in memory instead of mirroring them to a
755
+ sibling file, so it no longer writes to — or deletes from — your Convex
756
+ directory, and import-time stack traces now point at the real module rather
757
+ than a temporary path. A file of your own ending in `.kitcn-parse.ts` is left
758
+ untouched.
759
+ - Fix plugin registration landing inside a comment or string that happens to
760
+ mention `defineSchema(`, which recorded the plugin as installed while its
761
+ tables and relations never reached the schema.
762
+ - Fix `kitcn add auth` deleting a table's index callback when it was written as a
763
+ block-bodied arrow or a named function. The callback is now preserved while
764
+ managed fields are merged.
765
+ - Fix schema patching merging value imports into a type-only `kitcn/orm` import,
766
+ which produced duplicate identifiers, and skipping the import entirely when
767
+ only `import * as orm from 'kitcn/orm'` was present.
768
+
769
+ - [#320](https://github.com/udecode/kitcn/pull/320) [`799dc4f`](https://github.com/udecode/kitcn/commit/799dc4f80ab998646fd1960fbf82d6f536e5317a) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
770
+
771
+ - Improve Convex and HTTP middleware to wrap the whole procedure: `next()`
772
+ resolves after the handler runs, so timing, error reporting, and cleanup
773
+ around it observe the handler, and handler errors propagate through every
774
+ wrapping `catch`. A `ctx` changed on the return path no longer reaches the
775
+ handler — pass it to `next()` instead.
776
+
777
+ ```ts
778
+ // Before — logged 0ms, never saw handler errors, and this ctx was ignored
779
+ .use(async ({ ctx, next }) => {
780
+ const start = Date.now();
781
+ const result = await next({ ctx });
782
+ console.log(`${Date.now() - start}ms`);
783
+ return { ...result, ctx: { ...ctx, tenant } };
784
+ })
785
+
786
+ // After — times the handler, sees its errors, and passes ctx forward
787
+ .use(async ({ ctx, next }) => {
788
+ const start = Date.now();
789
+ try {
790
+ return await next({ ctx: { ...ctx, tenant } });
791
+ } finally {
792
+ console.log(`${Date.now() - start}ms`);
793
+ }
794
+ })
795
+ ```
796
+
797
+ - Improve chained `.input()` to apply each schema on its own instead of
798
+ flattening them into one shape, so object-level rules run. A key declared by
799
+ more than one schema is validated only by the last schema to declare it, even
800
+ when an earlier schema carries object-level rules.
801
+
802
+ ```ts
803
+ // Before — the object-level rule was dropped and both fields reached the handler
804
+ .input(z.object({ password: z.string(), confirm: z.string() }))
805
+
806
+ // After — mismatched values are rejected before the handler runs
807
+ .input(
808
+ z
809
+ .object({ password: z.string(), confirm: z.string() })
810
+ .refine((v) => v.password === v.confirm)
811
+ )
812
+ ```
813
+
814
+ ## Patches
815
+
816
+ - Fix `.input()` schemas running twice per request, which made field transforms
817
+ apply to their own output — `z.string().transform(s => s.length)` threw on
818
+ valid input and `z.number().transform(n => n * 2)` doubled twice. Transforms
819
+ and refinements now run exactly once.
820
+ - Fix `next({ input })` being dropped for every middleware after the first, so
821
+ input enrichment placed after an auth middleware no longer silently no-ops.
822
+ - Fix HTTP routes returning a retryable `500` for errors raised by a procedure
823
+ they called through a caller. `NOT_FOUND`, `FORBIDDEN`, and other codes now
824
+ keep their status and message.
825
+ - Fix HTTP routes returning `500` for the twelve error codes missing from the
826
+ route status map, including `PAYLOAD_TOO_LARGE` (`413`),
827
+ `UNSUPPORTED_MEDIA_TYPE` (`415`), and `PRECONDITION_FAILED` (`412`).
828
+ - Fix a malformed or empty JSON body returning `500` instead of `400`,
829
+ including when HTTP middleware reads it through `getRawInput()`.
830
+
831
+ - [#317](https://github.com/udecode/kitcn/pull/317) [`b765f01`](https://github.com/udecode/kitcn/commit/b765f016cc82aabaad9d5f4d218955163f1a73a5) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
832
+
833
+ - `orderBy` on a field that no index _leads_ now sorts after reading, and under
834
+ cursor pagination it raises instead of returning a page ordered by the wrong
835
+ column. An index merely containing the field no longer counts: Convex walks an
836
+ index in full key order, so `on(type, numLikes)` orders by `type` first. Add an
837
+ index led by the sort field, or read without a cursor.
838
+
839
+ ```ts
840
+ // Before: paged, silently ordered by `type`
841
+ index("numLikesAndType").on(t.type, t.numLikes);
842
+
843
+ await db.query.posts.findMany({
844
+ orderBy: { numLikes: "desc" },
845
+ cursor: null,
846
+ limit: 20,
847
+ });
848
+
849
+ // After: add an index the sort field leads
850
+ index("numLikesAndType").on(t.type, t.numLikes);
851
+ index("by_num_likes").on(t.numLikes);
852
+
853
+ await db.query.posts.findMany({
854
+ orderBy: { numLikes: "desc" },
855
+ cursor: null,
856
+ limit: 20,
857
+ });
858
+ ```
859
+
860
+ - `.withIndex(name, range)` now wins over the index a `where` object would have
861
+ selected, so a `where` the pinned index cannot serve becomes a scan the caller
862
+ has to bound. Under cursor pagination that combination now asks for `maxScan`
863
+ instead of quietly reading through a different index.
864
+
865
+ ```ts
866
+ // Before: scanned `by_status` and returned rows from every city
867
+ await db.query.users
868
+ .withIndex("by_city", (q) => q.eq("cityId", cityId))
869
+ .findMany({ where: { status: "active" }, cursor: null, limit: 20 });
870
+
871
+ // After: bound the scan
872
+ await db.query.users
873
+ .withIndex("by_city", (q) => q.eq("cityId", cityId))
874
+ .findMany({
875
+ where: { status: "active" },
876
+ cursor: null,
877
+ limit: 20,
878
+ maxScan: 500,
879
+ });
880
+ ```
881
+
882
+ ## Patches
883
+
884
+ - Fix `.withIndex(name, range)` being ignored whenever the `where` object also
885
+ matched another index. The index and its bounds you asked for are now the ones
886
+ scanned — including under cursor pagination — so a range used to scope a query,
887
+ a tenant id for instance, can no longer be dropped and return rows outside it.
888
+ - Fix `where: { field: { in: [...] } }` combined with `orderBy` and `limit`
889
+ returning an arbitrary slice — usually the oldest rows — instead of the
890
+ requested window.
891
+ - Fix `like`, `ilike`, `notLike`, and `notIlike` matching nothing when the
892
+ pattern has a wildcard anywhere but the ends. `%` now matches any run of
893
+ characters and `_` matches exactly one Unicode character, at any position.
894
+ - Fix `eq`, `ne`, `in`, and `notIn` never matching array or object columns.
895
+ Values are compared by content, in queries and in `update`/`delete` filters.
896
+ - Fix `select()` returning raw rows for a `where: { id }` lookup, which silently
897
+ skipped `map`, `filter`, `flatMap`, and `distinct`. `pageByKey` with the same
898
+ `where` also returns its page shape instead of a bare array. A `where` on `id`
899
+ or `id: { in: [...] }` reads those rows by key rather than scanning the table
900
+ for them, so `select()` costs one read per id however large the table is.
901
+ Cursor pagination rejects `id: { in: [...] }` with `maxScan`, because sorting
902
+ arbitrary IDs by creation time requires reading the complete list first.
903
+ - Apply RLS to source rows before any `select()` pipeline callback runs, so a
904
+ mapper or flat-map stage cannot inspect or project a forbidden document.
905
+ - Fix `flatMap`'s `limit` counting rows excluded by its `where`, which returned
906
+ fewer children than asked for and often none. The limit now counts matching
907
+ children, stays stable across pages instead of yielding a fresh batch per page,
908
+ and reads each child once within the `maxScan` budget. It also stops on the
909
+ last child it can return instead of reading one past it, so a small `limit`
910
+ across many parents no longer spends reads no page can show. Exhausted and
911
+ missing optional relations advance cursors without duplicates or loops.
912
+ - Fix a relation `limit` combined with a relation `where` returning too few
913
+ children — none when enough non-matching children sorted first. The limit now
914
+ counts matching children. Without an explicit relation `orderBy`, the scan
915
+ also stops after the requested visible rows, including rows filtered by RLS.
916
+
917
+ - [#316](https://github.com/udecode/kitcn/pull/316) [`59b80d0`](https://github.com/udecode/kitcn/commit/59b80d0f7c8c9aea78a15b427449907ef8976750) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
918
+
919
+ - Require `rls.roleResolver` for policies scoped with `to`. A role-scoped policy
920
+ previously applied to every caller when no resolver was configured; it now
921
+ throws `RLS_ROLE_RESOLVER_REQUIRED`. Queries and mutations check this for
922
+ every table they touch before reading rows, so the error depends only on
923
+ configuration and not on whether the table holds rows. SQL pseudo-roles
924
+ (`public`, `current_user`, `current_role`, `session_user`) apply to everyone
925
+ and still need no resolver.
926
+
927
+ ```ts
928
+ // Before
929
+ const ormDb = orm.db(ctx, { rls: { ctx } });
930
+
931
+ // After
932
+ const ormDb = orm.db(ctx, {
933
+ rls: { ctx, roleResolver: (ctx) => ctx.roles ?? [] },
934
+ });
935
+ ```
936
+
937
+ - Deny RLS policy comparisons against a missing value, following SQL null
938
+ semantics. A policy written as `eq(column, null)` now denies instead of
939
+ matching explicitly-null columns, and an unauthenticated caller no longer
940
+ matches rows whose owner column was never set. Use `isNull` to match absent
941
+ or null columns.
942
+
943
+ ```ts
944
+ // Before
945
+ rlsPolicy("read_unassigned", {
946
+ for: "select",
947
+ using: (ctx, t) => eq(t.ownerId, null),
948
+ });
949
+
950
+ // After
951
+ rlsPolicy("read_unassigned", {
952
+ for: "select",
953
+ using: (ctx, t) => isNull(t.ownerId),
954
+ });
955
+ ```
956
+
957
+ ## Patches
958
+
959
+ - Fix many-to-many relations ignoring the junction table's RLS policies, which
960
+ revealed which rows other users were linked to. Loading a relation with `with`
961
+ now enforces the junction table's policies alongside the related table's.
962
+
963
+ - [#319](https://github.com/udecode/kitcn/pull/319) [`2aee478`](https://github.com/udecode/kitcn/commit/2aee478fcc750d06bd914bf5cd701045d1c79736) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
964
+
965
+ - Enforce the configured total budget across all `shards`.
966
+
967
+ ```ts
968
+ // 20 per minute in total, spread over 4 shards
969
+ Ratelimit.fixedWindow(20, "1 m", { shards: 4 });
970
+ ```
971
+
972
+ - Preserve configured `maxReserved` headroom across sharded limiters.
973
+ - Reject limiter budgets that leave any shard with less than one usable token.
974
+ - Reject non-positive, non-finite, or unservable dynamic limit overrides.
975
+
976
+ - Evaluate the requested `count` / `rate` in `check()` against the tokens already
977
+ spent. It previously evaluated nothing and returned `success: true` for every
978
+ caller, so a pre-flight gate now reports `success: false` where it always said
979
+ "allowed".
980
+
981
+ ```ts
982
+ // Before: always true, even for an exhausted identifier
983
+ const gate = await limiter.check(userId, { count: 5 });
984
+
985
+ // After: matches what limit() would decide, without consuming tokens
986
+ const gate = await limiter.check(userId, { count: 5 });
987
+ if (!gate.success) return { retryAt: gate.reset };
988
+ ```
989
+
990
+ ## Features
991
+
992
+ - Add `snapshotToState` to convert a `getValue()` snapshot into the state shape
993
+ `calculateRatelimit()` expects. Snapshots retain the full projected state,
994
+ including sliding-window current and previous counts, so later projections
995
+ preserve boundary decay.
996
+ - Add `remainingRaw` to `calculateRatelimit()` results for the exact token
997
+ balance, including the negative value when a request overdraws.
998
+
999
+ ## Patches
1000
+
1001
+ - Fix `getRemaining()` inverting sliding-window quotas. An identifier with no
1002
+ traffic reported `remaining: 0`, and quota banners or `X-RateLimit-Remaining`
1003
+ headers showed the opposite of the truth.
1004
+ - Fix `resetUsedTokens()` leaving an identifier blocked by the ephemeral cache,
1005
+ so an admin quota reset silently failed for the rest of the window.
1006
+ - Key the ephemeral block cache per shard. One exhausted shard used to block the
1007
+ identifier outright, stranding every other shard's tokens until the window
1008
+ reset and enforcing well under the configured limit.
1009
+ - Sum every shard in `getRemaining()` rather than extrapolating the fullest one.
1010
+ A half-drained sharded limiter reported its full budget as still available.
1011
+ - Improve shard selection to compare exact token balances, so sharded limiters
1012
+ spread load onto the emptier shard instead of tying on rounded counts.
1013
+ - Retry the remaining shards when the preferred candidates are exhausted, so
1014
+ routing cannot deny a request while another shard can still serve it.
1015
+ - Preserve whole-request capacity for fractional budgets by dealing the whole
1016
+ portion and keeping the fractional remainder on one shard.
1017
+ - Scale fixed-window snapshots and response balances by `capacity` rather than
1018
+ the refill `limit`, so burst configurations report valid remaining tokens.
1019
+ - Scope ephemeral blocks by shard, requested count, and reservation mode, so a
1020
+ failed large or ordinary request does not hide tokens from a smaller or
1021
+ reserved request, and include cached shards when reporting the earliest
1022
+ global retry time.
1023
+ - Prune expired ephemeral block variants when recording a new block.
1024
+ - Allocate token-bucket refill rates in proportion to shard capacity, preserving
1025
+ the full configured refill when capacity shares are uneven.
1026
+ - Compute reserved-request retry times against `maxReserved` headroom rather
1027
+ than the non-reserved zero-debt threshold.
1028
+ - Evaluate sampled shard states at one common read timestamp, avoid refilling
1029
+ their aggregate again, and sum each shard's independently usable whole tokens
1030
+ in `getRemaining()` without netting debt or fractions across isolated shards.
1031
+ - Preserve sampled per-shard state in snapshots so all-shard projections retain
1032
+ independent capacity saturation and sliding-window decay.
1033
+ - Read each candidate shard set concurrently, including exhaustion fallbacks.
1034
+ - Reject requests that exceed every shard's capacity and reservation headroom
1035
+ with `reason: "requestTooLarge"` and no retry deadline or shard reads.
1036
+ - Exclude permanently undersized shards from retry deadlines and invalidate
1037
+ local snapshot and block-decision caches when dynamic limits change.
1038
+ - Preserve permanent oversized denials through all-shard snapshots and React
1039
+ projections without scheduling an infinite retry timer.
1040
+ - Apply per-shard capacity guards to partial snapshots while retaining uncapped
1041
+ reservation headroom when `maxReserved` is omitted.
1042
+ - Reject negative, non-finite `maxReserved` values before sharding or retry
1043
+ calculation.
1044
+ - Normalize shard-local algorithms, enforce per-shard capacity for fresh
1045
+ projections, and generation-guard cache writes across dynamic updates.
1046
+ - Skip infinite block-cache entries and retain at most 32 finite variants per
1047
+ identifier.
1048
+
1049
+ ### Patch Changes
1050
+
1051
+ - [#318](https://github.com/udecode/kitcn/pull/318) [`eddfc08`](https://github.com/udecode/kitcn/commit/eddfc083de4e1656237f1b871919c9c382eeb67e) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
1052
+
1053
+ - Fix auth queries that filter by `id` resolving records from the wrong model,
1054
+ which let a lookup, update, or delete for one model read, patch, or destroy a
1055
+ record belonging to another. IDs are now checked against the model being
1056
+ queried, and IDs that belong elsewhere or are malformed resolve to "not
1057
+ found" instead of a foreign record or an error.
1058
+ - Fix `findMany` and `count` returning duplicated records past the first page,
1059
+ which also inflated counts used for membership, role, and API key limits.
1060
+ - Fix mixed `AND`/`OR` filters in `findMany` and `count` returning records the
1061
+ filter excluded, such as rows outside the requested organization. Mixed
1062
+ filters are now rejected, matching `updateMany` and `deleteMany`.
1063
+ - Fix `not_in` filters returning no match when the matching record was not
1064
+ among the first records scanned, which made those updates fail and those
1065
+ deletes silently do nothing.
1066
+ - Fix `auth.jwtCache: false` in the Next.js integration disabling
1067
+ authentication instead of just the JWT cookie cache, which made every server
1068
+ request anonymous.
1069
+
1070
+ - [#321](https://github.com/udecode/kitcn/pull/321) [`9a7feab`](https://github.com/udecode/kitcn/commit/9a7feab2f99ee383a02225c293137416a0438fbd) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
1071
+
1072
+ - Fix signed-in users being signed out when their name or email contains
1073
+ non-ASCII characters.
1074
+ - Fix server callers re-running a failed mutation or action after a
1075
+ non-authorization error, which could charge a card or write a row twice.
1076
+ - Fix results of auth-scoped actions surviving sign-out and being served to the
1077
+ next user in the same tab.
1078
+ - Fix `skipUnauth` being ignored on queries and action queries, so backend
1079
+ authorization errors resolve to `null` as documented instead of surfacing as
1080
+ query errors.
1081
+ - Fix `Date` values in query args crashing the render.
1082
+ - Fix a function-form `enabled` being ignored on queries, action queries, and
1083
+ infinite queries, which ran queries the caller had disabled.
1084
+ - Fix mutating a query args object in place returning another component's args
1085
+ for a previously used key, which subscribed to the wrong Convex query.
1086
+ - Fix RSC prefetch of `crpc.http.*` building a different URL than the browser
1087
+ client for `params` and `searchParams`, so prefetched data now hydrates
1088
+ instead of being refetched.
1089
+
1090
+ ## 0.16.1
1091
+
1092
+ ### Patch Changes
1093
+
1094
+ - [#314](https://github.com/udecode/kitcn/pull/314) [`e01e3f5`](https://github.com/udecode/kitcn/commit/e01e3f58ae33e118f1bf844e7d5a98694ce10ab0) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
1095
+
1096
+ - Fix `like`, `ilike`, `contains`, `endsWith`, and the array operators returning
1097
+ too few rows — often none — when combined with `limit`. These operators are
1098
+ matched after the rows are read, so `limit` now counts matches instead of
1099
+ scanned rows. `offset` counts matches too.
1100
+ - Fix those same operators being ignored entirely under cursor pagination, which
1101
+ returned pages containing rows that did not match. Pages now hold only
1102
+ matching rows.
1103
+ - Fix `NOT` around one of those operators matching nothing instead of negating,
1104
+ with or without a cursor.
1105
+ - Fix `isNull` skipping rows whose column was never written once that column is
1106
+ indexed. Absent and explicitly-null columns now both match, with or without an
1107
+ index.
1108
+ - Fix `flatMap` pagination dropping and duplicating children after the first
1109
+ page. Walking every page now returns the same rows as reading them at once.
1110
+ - Fix soft cascade deletes rescheduling themselves forever and never reaching
1111
+ the children past the first batch.
1112
+
1113
+ ## 0.16.0
1114
+
1115
+ ### Minor Changes
1116
+
1117
+ - [#310](https://github.com/udecode/kitcn/pull/310) [`a229128`](https://github.com/udecode/kitcn/commit/a229128a94605c229d0ba9a5e9e7f2f98ee76e7e) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Breaking changes
1118
+
1119
+ - Require Convex 1.42 or newer.
1120
+
1121
+ ```bash
1122
+ # Before
1123
+ bun add convex@1.38.0
1124
+
1125
+ # After
1126
+ bun add convex@1.42.3
1127
+ ```
1128
+
1129
+ ### Patch Changes
1130
+
1131
+ - [#311](https://github.com/udecode/kitcn/pull/311) [`644ed41`](https://github.com/udecode/kitcn/commit/644ed41f38db3796790a947019ea089c224bf83d) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1132
+
1133
+ - Fix unbounded auth queries hanging after 200 rows.
1134
+ - Prevent action contexts from exposing mutation-only transaction options.
1135
+
1136
+ ## 0.15.18
1137
+
1138
+ ### Patch Changes
1139
+
1140
+ - [#308](https://github.com/udecode/kitcn/pull/308) [`65a331b`](https://github.com/udecode/kitcn/commit/65a331b7b9cb541b46c031e9afabdadd4d9d0c91) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1141
+
1142
+ - Fix ORM ID queries and relation loading to treat malformed IDs as missing
1143
+ records.
1144
+
1145
+ ## 0.15.17
1146
+
1147
+ ### Patch Changes
1148
+
1149
+ - [#305](https://github.com/udecode/kitcn/pull/305) [`b7ccc0b`](https://github.com/udecode/kitcn/commit/b7ccc0b19fb79017a9116bebc548b63b6081b822) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1150
+
1151
+ - Fix cRPC infinite queries backed by native Convex pagination loading pages
1152
+ before `fetchNextPage()` is called.
1153
+
1154
+ ## 0.15.16
1155
+
1156
+ ### Patch Changes
1157
+
1158
+ - [#301](https://github.com/udecode/kitcn/pull/301) [`3248105`](https://github.com/udecode/kitcn/commit/32481058f1043a4f9a0a897ee966d9048dc79739) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
1159
+
1160
+ - Add provider-owned Convex authentication recovery after transient token failures.
1161
+
1162
+ ## 0.15.15
1163
+
1164
+ ### Patch Changes
1165
+
1166
+ - [#297](https://github.com/udecode/kitcn/pull/297) [`4fba1b8`](https://github.com/udecode/kitcn/commit/4fba1b8dcef38e3433984553063306aafd87a453) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
1167
+
1168
+ - Fix `kitcn deploy` and `kitcn aggregate backfill|rebuild|prune` failing with `Too many documents read in a single function execution (limit: 32000)` once a table with an `aggregateIndex()` grows past ~32k rows. Backfill kickoff now discovers removed aggregate indexes with bounded distinct-key index scans instead of reading every aggregate row. Clearing a removed index whose aggregate rows already exceed platform limits still requires a chunked prune.
1169
+ - Fix `backend=concave` failing to locate the Concave CLI with `@concavejs/cli` releases that do not export `./package.json`.
1170
+ - Pin `@concavejs/cli` in concave scaffolds to the supported version instead of `latest`.
1171
+
1172
+ ## 0.15.14
1173
+
1174
+ ### Patch Changes
1175
+
1176
+ - [#293](https://github.com/udecode/kitcn/pull/293) [`0fcbae0`](https://github.com/udecode/kitcn/commit/0fcbae099b0658c2d921a42a189e713a71ebeb71) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1177
+
1178
+ - Fix Better Auth client type compatibility for auth providers and organization-heavy auth clients.
1179
+ - Support Better Auth 1.6.18 across generated auth apps.
1180
+
1181
+ ## 0.15.13
1182
+
1183
+ ### Patch Changes
1184
+
1185
+ - [#289](https://github.com/udecode/kitcn/pull/289) [`4aae1ee`](https://github.com/udecode/kitcn/commit/4aae1ee1dfac8ae85fe0999fba8a78e523fec975) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1186
+
1187
+ - Fix auth adapter updates with no `where` clauses to return `null`.
1188
+ - Fix Next.js and TanStack Start auth proxies to strip hop-by-hop headers.
1189
+ - Update supported Better Auth installs to `1.6.15` with a `>=1.6.11 <1.7.0` peer range.
1190
+
1191
+ ## 0.15.12
1192
+
1193
+ ### Patch Changes
1194
+
1195
+ - [#285](https://github.com/udecode/kitcn/pull/285) [`0ca9202`](https://github.com/udecode/kitcn/commit/0ca9202b83ccaa692507242aee99e086c1994cb1) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1196
+
1197
+ - Fix auth providers to accept plugin-rich Better Auth clients without casts.
1198
+
1199
+ ## 0.15.11
1200
+
1201
+ ### Patch Changes
1202
+
1203
+ - [#283](https://github.com/udecode/kitcn/pull/283) [`2e09a29`](https://github.com/udecode/kitcn/commit/2e09a297e27ea714fe73d0a388d3ed11359630c3) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1204
+
1205
+ - Fix `kitcn init -t start` to preserve the shadcn Start template while safely staging existing empty target directories.
1206
+ - Fix `rankIndex().orderBy()` so documented direction objects typecheck and normalize correctly.
1207
+
1208
+ ## 0.15.10
1209
+
1210
+ ### Patch Changes
1211
+
1212
+ - [#280](https://github.com/udecode/kitcn/pull/280) [`a684485`](https://github.com/udecode/kitcn/commit/a6844855d69725321ddfbd4b50e8a1f517e70e96) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1213
+
1214
+ - Fix `kitcn init -t start` to preserve the shadcn Start template while safely staging existing empty target directories.
1215
+
1216
+ ## 0.15.9
1217
+
1218
+ ### Patch Changes
1219
+
1220
+ - [`386b54e`](https://github.com/udecode/kitcn/commit/386b54e2d5a9c1b48e9a8db5604d29d8e9013f9f) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1221
+
1222
+ - Fix `kitcn init -t start` for TanStack Start scaffolds that use Vite
1223
+ `resolve.tsconfigPaths`.
1224
+ - Improve the packaged kitcn agent skill prompt and reference footprint.
1225
+
1226
+ ## 0.15.8
1227
+
1228
+ ### Patch Changes
1229
+
1230
+ - [#275](https://github.com/udecode/kitcn/pull/275) [`4dd56d0`](https://github.com/udecode/kitcn/commit/4dd56d062dbd268e7768f0a0e854572a840d7de6) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
1231
+
1232
+ - Support Better Auth plugin sign-in methods in `useSignInMutationOptions`.
1233
+
1234
+ ## 0.15.7
1235
+
1236
+ ### Patch Changes
1237
+
1238
+ - [#272](https://github.com/udecode/kitcn/pull/272) [`d286077`](https://github.com/udecode/kitcn/commit/d286077bf388956d8f423eaaa1afed18b0b4b7b9) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1239
+
1240
+ - Fix ORM update and delete filters on primary id arrays so bounded mutations do not require `allowFullScan`.
1241
+ - Bound sync primary-id mutation fanout by `mutationBatchSize` and keep legacy scheduled cursors on the query-pagination path.
1242
+
1243
+ ## 0.15.6
1244
+
1245
+ ### Patch Changes
1246
+
1247
+ - [#270](https://github.com/udecode/kitcn/pull/270) [`2703bf0`](https://github.com/udecode/kitcn/commit/2703bf056b129c783ec772280b4e1648bffdf171) Thanks [@zbeyens](https://github.com/zbeyens)! - Support `OPTIONS` preflight forwarding in `kitcn/auth/nextjs` route handlers and generated Next auth routes.
1248
+
1249
+ ## 0.15.5
1250
+
1251
+ ### Patch Changes
1252
+
1253
+ - [#268](https://github.com/udecode/kitcn/pull/268) [`da34316`](https://github.com/udecode/kitcn/commit/da34316d76a64ebd6d0ac683ded2472246bb9439) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
1254
+
1255
+ - Support syncing shared Convex query clients directly from `ConvexAuthProvider`.
1256
+
1257
+ ## Patches
1258
+
1259
+ - Keep the existing auth store attached when reusing a Convex query client before `ConvexAuthProvider` resyncs it.
1260
+ - Fix `kitcn/auth/start/server` so Nitro production builds can trace and include the TanStack Start server dependency without making `kitcn/auth/start` unsafe for browser loaders.
1261
+
1262
+ ## 0.15.4
1263
+
1264
+ ### Patch Changes
1265
+
1266
+ - [#266](https://github.com/udecode/kitcn/pull/266) [`5de6e94`](https://github.com/udecode/kitcn/commit/5de6e9466bf066180b76062cbbb5632e27fc6bd1) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
1267
+
1268
+ - Support syncing shared Convex query clients directly from `ConvexAuthProvider`.
1269
+
1270
+ ## 0.15.3
1271
+
1272
+ ### Patch Changes
1273
+
1274
+ - [#264](https://github.com/udecode/kitcn/pull/264) [`21760cb`](https://github.com/udecode/kitcn/commit/21760cb994a8f3e093795c342cdbda11ae8e8819) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1275
+
1276
+ - Fix Convex query cache updates when a subscription returns `null`.
1277
+
1278
+ ## 0.15.2
1279
+
1280
+ ### Patch Changes
1281
+
1282
+ - [#262](https://github.com/udecode/kitcn/pull/262) [`a33d263`](https://github.com/udecode/kitcn/commit/a33d2633e0b2c2e016f4d951b3bea8a2852b7a03) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1283
+
1284
+ - Fix Resend scaffolds to resolve optional Resend env values from Convex runtime env proxies.
1285
+ - Fix Resend env helper reruns to update noncanonical `createEnv` formatting instead of silently skipping `readOptionalRuntimeEnv`.
1286
+ - Fix env helper reruns to fail loudly instead of duplicating or rewriting non-literal `readOptionalRuntimeEnv` options.
1287
+ - Fix Resend scaffold table names to match the camelCase schema extension keys.
1288
+
1289
+ ## 0.15.1
1290
+
1291
+ ### Patch Changes
1292
+
1293
+ - [#260](https://github.com/udecode/kitcn/pull/260) [`b9ae68b`](https://github.com/udecode/kitcn/commit/b9ae68bc6c3c26b783f6ae491555026f05510d80) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
1294
+
1295
+ - Add a TanStack Start loader auth helper for priming Convex query clients before protected route loaders run.
1296
+
1297
+ ## 0.15.0
1298
+
1299
+ ### Minor Changes
1300
+
1301
+ - [#257](https://github.com/udecode/kitcn/pull/257) [`d476288`](https://github.com/udecode/kitcn/commit/d476288e617db8d5d44821a70af3ec787280ea5c) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Breaking changes
1302
+
1303
+ - Require Convex 1.38.0 or newer for generated apps and peer dependency checks.
1304
+
1305
+ ```sh
1306
+ # Before
1307
+ bun add convex@1.36.1 kitcn
1308
+
1309
+ # After
1310
+ bun add convex@1.38.0 kitcn
1311
+ ```
1312
+
1313
+ ## Features
1314
+
1315
+ - Support IP-aware rate-limit scaffolds with Convex request metadata.
1316
+
1317
+ ## Patches
1318
+
1319
+ - Support Expo app adoption and avoid Bun-only Expo scaffolding in npm-launched init flows.
1320
+ - Document Convex request metadata for IP-aware rate-limit protection.
1321
+
1322
+ ## 0.14.3
1323
+
1324
+ ### Patch Changes
1325
+
1326
+ - [#255](https://github.com/udecode/kitcn/pull/255) [`0bf1fc2`](https://github.com/udecode/kitcn/commit/0bf1fc2136bf9a2dd1f2ac218d614dcb58a5888b) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1327
+
1328
+ - Fix plugin dependency installs to use the project's package manager.
1329
+
1330
+ ## 0.14.2
1331
+
1332
+ ### Patch Changes
1333
+
1334
+ - [`21acedd`](https://github.com/udecode/kitcn/commit/21acedd829df53c9207c75cee4fe7f68c6a0bd24) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1335
+
1336
+ - Fix raw Convex auth adoption for TanStack Start apps that do not keep a kitcn provider at the default path.
1337
+ - Clarify organization auth guidance for Stripe-style plugin side effects in Convex actions.
1338
+
1339
+ ## 0.14.1
1340
+
1341
+ ### Patch Changes
1342
+
1343
+ - [#251](https://github.com/udecode/kitcn/pull/251) [`8ac174c`](https://github.com/udecode/kitcn/commit/8ac174cde9642dd61d5e9420b6cbc53ef7a7c124) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1344
+
1345
+ - Fix ORM updates so timestamp `$onUpdateFn` hooks can return `Date` values.
1346
+
1347
+ ## 0.14.0
1348
+
1349
+ ### Minor Changes
1350
+
1351
+ - [#248](https://github.com/udecode/kitcn/pull/248) [`26023d2`](https://github.com/udecode/kitcn/commit/26023d2ae1b359174658aa4e9dabaeb3683d2142) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Breaking changes
1352
+
1353
+ - Require Convex 1.36 or newer.
1354
+
1355
+ ```bash
1356
+ # Before
1357
+ bun add convex@1.35.1
1358
+
1359
+ # After
1360
+ bun add convex@1.36.1
1361
+ ```
1362
+
1363
+ ## Features
1364
+
1365
+ - Add `kitcn env default` passthrough for Convex default environment variables.
1366
+
1367
+ ## Patches
1368
+
1369
+ - Align Better Auth scaffolds and auth runtime helpers with Better Auth 1.6.9.
1370
+ - Document Convex inline query, branch deployment, deploy message, and preview deployment passthroughs.
1371
+
1372
+ ## 0.13.10
1373
+
1374
+ ### Patch Changes
1375
+
1376
+ - [#245](https://github.com/udecode/kitcn/pull/245) [`547ccfd`](https://github.com/udecode/kitcn/commit/547ccfd2673c0099c63b55137b201476da13a56e) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1377
+
1378
+ - Fix `createAuthMutations` support for Better Auth clients that use the Convex client plugin.
1379
+
1380
+ ## 0.13.9
1381
+
1382
+ ### Patch Changes
1383
+
1384
+ - [#240](https://github.com/udecode/kitcn/pull/240) [`042a568`](https://github.com/udecode/kitcn/commit/042a5684066e6a6691f858afc22de68c71b58136) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1385
+
1386
+ - Fix raw Convex auth reruns so added Better Auth plugins refresh the generated schema without `--overwrite`.
1387
+
1388
+ ## 0.13.8
1389
+
1390
+ ### Patch Changes
1391
+
1392
+ - [#238](https://github.com/udecode/kitcn/pull/238) [`f43fc36`](https://github.com/udecode/kitcn/commit/f43fc3623b7f05fb8d55d9be1144d192c3e9235f) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1393
+
1394
+ - Fix `kitcn add auth --preset convex` so schema registration reuses existing `authSchema` imports.
1395
+
1396
+ ## 0.13.7
1397
+
1398
+ ### Patch Changes
1399
+
1400
+ - [#236](https://github.com/udecode/kitcn/pull/236) [`508f6df`](https://github.com/udecode/kitcn/commit/508f6df2cfb0e7177fefcdc48767473560b4b69b) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1401
+
1402
+ - Fix auth Stripe subscription writes so `createdAt` and `updatedAt` are only written when the target table defines them.
1403
+
1404
+ ## 0.13.6
1405
+
1406
+ ### Patch Changes
1407
+
1408
+ - [#234](https://github.com/udecode/kitcn/pull/234) [`f137874`](https://github.com/udecode/kitcn/commit/f13787454ca5cf9a7ea37ca48d021b19de38a2db) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1409
+
1410
+ - Fix React query options to stay stable for equal Convex query args.
1411
+
1412
+ ## 0.13.5
1413
+
1414
+ ### Patch Changes
1415
+
1416
+ - [#232](https://github.com/udecode/kitcn/pull/232) [`24ca124`](https://github.com/udecode/kitcn/commit/24ca124401b22f0ce370709675f796260bebb74e) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1417
+
1418
+ - Fix noisy `oidc-provider` deprecation warnings from the internal Convex auth plugin.
1419
+
1420
+ ## 0.13.4
1421
+
1422
+ ### Patch Changes
1423
+
1424
+ - [#229](https://github.com/udecode/kitcn/pull/229) [`a93f264`](https://github.com/udecode/kitcn/commit/a93f264c522f2818a0166b85770ffe88d1a1eb6d) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1425
+
1426
+ - Fix `kitcn migrate` and `kitcn aggregate` so Convex prod-target runs keep
1427
+ ambient deployment auth env in CI.
1428
+
1429
+ ## 0.13.3
1430
+
1431
+ ### Patch Changes
1432
+
1433
+ - [#227](https://github.com/udecode/kitcn/pull/227) [`2446f3e`](https://github.com/udecode/kitcn/commit/2446f3e53fd74153a1e5ffffc7773553086f899b) Thanks [@zbeyens](https://github.com/zbeyens)! - Add `kitcn init -t expo` for a fresh Expo scaffold built on the official
1434
+ `create-expo-app` shell, including the Convex baseline, starter messages
1435
+ screen, and first-class `kitcn add auth` parity on the Expo scaffold.
1436
+
1437
+ Expo local env now also owns `EXPO_PUBLIC_SITE_URL`, so Concave dev and Expo
1438
+ auth keep one local app-origin contract instead of drifting back to
1439
+ `http://localhost:3000`.
1440
+
1441
+ ## 0.13.2
1442
+
1443
+ ### Patch Changes
1444
+
1445
+ - [`0f1bed4`](https://github.com/udecode/kitcn/commit/0f1bed493208211e3f452420b2756456ed16f5de) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1446
+
1447
+ - Fix `kitcn add auth` in fresh apps so the CLI does not require `better-auth` to be installed before the auth scaffold planner runs.
1448
+
1449
+ ## 0.13.1
1450
+
1451
+ ### Patch Changes
1452
+
1453
+ - [#219](https://github.com/udecode/kitcn/pull/219) [`3ec2d3b`](https://github.com/udecode/kitcn/commit/3ec2d3b4d4049817124dc4fff12162d1fed2b1a5) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1454
+
1455
+ - Fix auth env sync and local auth bootstrap so `kitcn add auth`, `kitcn env push`, and `kitcn dev --bootstrap` use the real Convex CLI entrypoint more reliably across runtimes and platforms.
1456
+ - Fix `kitcn init -t <next|start|vite>` custom shadcn preset exits so they stop with a clear rerun instruction instead of crashing while patching scaffold files.
1457
+ - Improve `kitcn init -t <next|start|vite>` fresh scaffolds by syncing the shadcn wrapper to `shadcn@4.3.0` and regenerating the starter outputs against the latest upstream template contract.
1458
+
1459
+ ## 0.13.0
1460
+
1461
+ ### Minor Changes
1462
+
1463
+ - [#213](https://github.com/udecode/kitcn/pull/213) [`71dbc28`](https://github.com/udecode/kitcn/commit/71dbc28f9a59716f8ecd41fda8ee61709ad9c9da) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Breaking changes
1464
+
1465
+ - Require explicit `basePath` when `registerRoutes` is used with non-default auth routes.
1466
+
1467
+ ```ts
1468
+ // Before
1469
+ import { registerRoutes } from "kitcn/auth/http";
1470
+
1471
+ // auth config uses basePath: "/custom-auth"
1472
+ registerRoutes(http, getAuth, {
1473
+ cors: {
1474
+ allowedOrigins: [process.env.SITE_URL!],
1475
+ },
1476
+ });
1477
+
1478
+ // After
1479
+ import { registerRoutes } from "kitcn/auth/http";
1480
+
1481
+ registerRoutes(http, getAuth, {
1482
+ basePath: "/custom-auth",
1483
+ cors: {
1484
+ allowedOrigins: [process.env.SITE_URL!],
1485
+ },
1486
+ });
1487
+ ```
1488
+
1489
+ - Require `better-auth@1.6.5`.
1490
+
1491
+ ```bash
1492
+ # Before
1493
+ bun add better-auth@1.5.3
1494
+
1495
+ # After
1496
+ bun add better-auth@1.6.5
1497
+ ```
1498
+
1499
+ ## Patches
1500
+
1501
+ - Let Convex handle anonymous non-interactive local setup without forcing `CONVEX_AGENT_MODE`.
1502
+ - Warn when an app pins an older Convex dependency family than kitcn expects.
1503
+ - Support Convex `dev --start` as a pre-run conflict flag.
1504
+ - Improve auth route registration so default Convex auth routes avoid eager Better Auth initialization during startup.
1505
+ - Preserve forwarded host and protocol headers through Next.js, TanStack Start, and Convex auth route proxies.
1506
+ - Fix auth helper token refresh, custom auth `basePath` support, and async custom JWT payload resolution.
1507
+ - Fix Better Auth adapter index matching and static filtering for composite and case-insensitive queries.
1508
+ - Support Better Auth `1.6.5` auth clients without user-code casts.
1509
+
1510
+ ## 0.12.28
1511
+
1512
+ ### Patch Changes
1513
+
1514
+ - [#210](https://github.com/udecode/kitcn/pull/210) [`1b3468a`](https://github.com/udecode/kitcn/commit/1b3468a867d62a9b55679170628d5a78c747f156) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1515
+
1516
+ - Fix raw Convex auth adoption so `kitcn add auth --preset convex --yes`
1517
+ installs `kitcn` before codegen and local bootstrap.
1518
+ - Fix `kitcn deploy` so CI deployment env vars reach Convex deploy, migrations,
1519
+ and aggregate backfill.
1520
+
1521
+ ## 0.12.27
1522
+
1523
+ ### Patch Changes
1524
+
1525
+ - [#206](https://github.com/udecode/kitcn/pull/206) [`7edbb5e`](https://github.com/udecode/kitcn/commit/7edbb5e3e445ed7331a4cc19ec795900ccb9ca52) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1526
+
1527
+ - Fix `bunx --bun kitcn init -t start --yes` so Bun-native parse-time imports
1528
+ no longer bypass project aliases and crash first-run codegen on scaffolded
1529
+ Start files.
1530
+ - Fix raw auth reruns so `http.ts` import detection respects both quote styles,
1531
+ `registerRoutes(http, getAuth, ...)` accepts Better Auth route contracts
1532
+ without a type cast, and raw auth clients keep the app `SITE_URL` while
1533
+ preserving user-edited raw `auth-client.ts` files on reruns.
1534
+
1535
+ ## 0.12.26
1536
+
1537
+ ### Patch Changes
1538
+
1539
+ - [`897a06b`](https://github.com/udecode/kitcn/commit/897a06b9e6ee5289ccf507d6c878d377ecfb1475) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1540
+
1541
+ - Fix raw auth reruns so `http.ts` import detection respects both quote styles,
1542
+ and `registerRoutes(http, getAuth, ...)` accepts Better Auth route contracts
1543
+ without a type cast.
1544
+
1545
+ ## 0.12.25
1546
+
1547
+ ### Patch Changes
1548
+
1549
+ - [`c1bc1a0`](https://github.com/udecode/kitcn/commit/c1bc1a046e71af2b311a3568fa397b57093138b1) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1550
+
1551
+ - Fix raw TanStack Start auth adoption reruns so `http.ts` import detection
1552
+ respects both quote styles and `registerRoutes(http, getAuth, ...)`
1553
+ typechecks without casts.
1554
+
1555
+ ## 0.12.24
1556
+
1557
+ ### Patch Changes
1558
+
1559
+ - [#202](https://github.com/udecode/kitcn/pull/202) [`10c2dc4`](https://github.com/udecode/kitcn/commit/10c2dc4f6de34fd7aaf1ac7bb6c964d7e63fcd3d) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1560
+
1561
+ - Support `kitcn add auth --preset convex --yes` on TanStack Start apps
1562
+ without falling through the Vite `main.tsx` patch path.
1563
+
1564
+ ## 0.12.23
1565
+
1566
+ ### Patch Changes
1567
+
1568
+ - [#200](https://github.com/udecode/kitcn/pull/200) [`7531fc9`](https://github.com/udecode/kitcn/commit/7531fc90d77b12b2e0815b8775ccecab3134784e) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1569
+
1570
+ - Fix React auth hooks so `useAuth()` and `useSafeConvexAuth()` stay loading
1571
+ while a cached session token is still syncing to Convex, which prevents a
1572
+ brief signed-out flash before the signed-in state settles.
1573
+
1574
+ ## 0.12.22
1575
+
1576
+ ### Patch Changes
1577
+
1578
+ - [`998ee69`](https://github.com/udecode/kitcn/commit/998ee69335c3e8f4b86333b15c14d0965a3aaae9) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1579
+
1580
+ - Fix `kitcn dev` so local Convex preflight uses `convex init` by default, and only falls back to the upgrade-capable local dev lane when older local backends require it.
1581
+ - Improve auth and backend docs so Convex and Concave env/JWKS flows are split into explicit backend lanes.
1582
+
1583
+ ## 0.12.21
1584
+
1585
+ ### Patch Changes
1586
+
1587
+ - [`96d5572`](https://github.com/udecode/kitcn/commit/96d55722434c09f7acbfbc8b89efc22f9e24768f) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1588
+
1589
+ - Improve TanStack Start auth migration docs and clarify the `kitcn add auth --schema --yes` schema refresh flow.
1590
+ - Fix the Next.js auth proxy so POST auth errors return the upstream response instead of crashing with a 500.
1591
+ - Fix `kitcn dev` local bootstrap so older local Convex backends auto-upgrade without hanging on a non-interactive prompt, and preserve local component targeting during preflight.
1592
+
1593
+ ## 0.12.20
1594
+
1595
+ ### Patch Changes
1596
+
1597
+ - [#193](https://github.com/udecode/kitcn/pull/193) [`db4b2a9`](https://github.com/udecode/kitcn/commit/db4b2a9c0e7ba4bf2fe52eba2f6d00c6c82bf605) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1598
+
1599
+ - Improve mutation-driven action-caller guidance so `requireActionCtx()` points
1600
+ scheduler-capable flows to `requireSchedulerCtx()` and `caller.schedule.*`.
1601
+ - Fix server-side call docs so mutation-or-action callbacks schedule actions
1602
+ instead of showing an invalid direct action call path.
1603
+ - Improve React error-handling docs to recommend `error.data?.message` and a
1604
+ global mutation toast pattern with `meta.errorMessage`.
1605
+
1606
+ ## 0.12.19
1607
+
1608
+ ### Patch Changes
1609
+
1610
+ - [#187](https://github.com/udecode/kitcn/pull/187) [`269966e`](https://github.com/udecode/kitcn/commit/269966eddf9c2a3407e284c86ef3becca9ff441a) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1611
+
1612
+ - Fix `kitcn dev` watcher codegen so Convex parse-time imports read local env
1613
+ values from `.env` and `convex/.env`, matching the initial codegen path.
1614
+ - Ignore watcher-owned `*.kitcn-parse.ts` temp files during `kitcn dev` so
1615
+ parse-time source rewrites do not retrigger codegen in a save loop.
1616
+ - Fix `kitcn codegen` so parse-time imports skip helper `.ts` files that do not
1617
+ define procedures, and support transitive `.tsx` imports like React Email
1618
+ templates.
1619
+ - Add server-only middleware procedure info for logging and tracing. Standard
1620
+ `export const` queries, mutations, and actions infer `module:function`
1621
+ automatically through app `generated/server`; `.name("module:function")`
1622
+ overrides when needed, and HTTP routes expose route method and path
1623
+ automatically.
1624
+ - Add `requireSchedulerCtx()` for mutation-or-action scheduling flows so auth
1625
+ callbacks and other generic ctx paths can enqueue work without lying about
1626
+ action context.
1627
+
1628
+ ## 0.12.18
1629
+
1630
+ ### Patch Changes
1631
+
1632
+ - [#183](https://github.com/udecode/kitcn/pull/183) [`40db401`](https://github.com/udecode/kitcn/commit/40db401bc93a9eb1ed7f2398445ba0cebc0a5b28) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1633
+
1634
+ - Fix `kitcn codegen` parse-time cRPC builder stubs so `.paginated()` chains
1635
+ after `.input()` keep working and preserve pagination metadata.
1636
+ - Fix TanStack Start auth reloads so `createAuthMutations()` persists the
1637
+ returned Better Auth session token/data and `ConvexAuthProvider` restores the
1638
+ signed-in state after a page refresh.
1639
+
1640
+ - [#183](https://github.com/udecode/kitcn/pull/183) [`1218930`](https://github.com/udecode/kitcn/commit/1218930db83b112a43dca074d457ed76c9d4f4c7) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1641
+
1642
+ - Support custom structured `data` payloads on `CRPCError` so conflict and
1643
+ validation handlers can return client-readable metadata alongside the built-in
1644
+ error code and message.
1645
+
1646
+ ## 0.12.17
1647
+
1648
+ ### Patch Changes
1649
+
1650
+ - [#179](https://github.com/udecode/kitcn/pull/179) [`4d2158b`](https://github.com/udecode/kitcn/commit/4d2158b09b4a316df96b4597e9c999517d7a44f8) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1651
+
1652
+ - Fix `kitcn codegen` module parsing so project `tsconfig.json` path aliases
1653
+ like `@/lib/crpc` resolve during codegen.
1654
+ - Fix `kitcn dev` and `kitcn codegen` parse-time env loading so Concave apps
1655
+ can read required values from the project root `.env`.
1656
+
1657
+ ## 0.12.16
1658
+
1659
+ ### Patch Changes
1660
+
1661
+ - [#177](https://github.com/udecode/kitcn/pull/177) [`2c7ff80`](https://github.com/udecode/kitcn/commit/2c7ff80b571147183316115e86df53f2dc1269d6) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1662
+
1663
+ - Fix shared `c.middleware()` auth chains so mutation procedures keep mutation
1664
+ writer types like `ctx.db.insert`.
1665
+ - Improve shared middleware docs so mutation-only middleware uses
1666
+ `c.middleware<MutationCtx>(...)` instead of a query-only workaround.
1667
+
1668
+ ## 0.12.15
1669
+
1670
+ ### Patch Changes
1671
+
1672
+ - [`a0037ff`](https://github.com/udecode/kitcn/commit/a0037ff26d46749f60788548cb73bf81404fbbc8) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1673
+
1674
+ - Fix the remaining `bunx --bun kitcn@latest init -t start --yes` bootstrap
1675
+ codegen failure when scaffolded files import `kitcn/server`.
1676
+
1677
+ ## 0.12.14
1678
+
1679
+ ### Patch Changes
1680
+
1681
+ - [`a5974eb`](https://github.com/udecode/kitcn/commit/a5974ebf70ce984aab6098ffad397c9b116fa7b9) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1682
+
1683
+ - Fix the remaining `bunx --bun kitcn@latest init -t start --yes` bootstrap
1684
+ parse failure by inlining a bootstrap-safe generated server stub for the real
1685
+ nested scaffold chain.
1686
+
1687
+ ## 0.12.13
1688
+
1689
+ ### Patch Changes
1690
+
1691
+ - [#170](https://github.com/udecode/kitcn/pull/170) [`437eff4`](https://github.com/udecode/kitcn/commit/437eff4f19222867dafc278f8f39aef9a81d4647) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1692
+
1693
+ - Fix `bunx --bun kitcn init -t start --yes` bootstrap parsing so scaffolded
1694
+ backend files resolve against the project install instead of the Bun cache,
1695
+ and preserve anonymous local Convex mode for follow-up `kitcn dev` runs.
1696
+
1697
+ ## 0.12.12
1698
+
1699
+ ### Patch Changes
1700
+
1701
+ - [#163](https://github.com/udecode/kitcn/pull/163) [`38ffd3c`](https://github.com/udecode/kitcn/commit/38ffd3c3843cc4549fd6366190b43977e23d34c0) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1702
+
1703
+ - Add `kitcn auth jwks` for manual static JWKS export and key rotation when a
1704
+ deployment cannot use the Convex-only `env push` flow.
1705
+
1706
+ ## 0.12.11
1707
+
1708
+ ### Patch Changes
1709
+
1710
+ - [#166](https://github.com/udecode/kitcn/pull/166) [`3a95ffb`](https://github.com/udecode/kitcn/commit/3a95ffbf86872dbd29dbe806c1a48a10189ce611) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1711
+
1712
+ - Fix `kitcn init -t next` monorepo scaffolds so the Next overlay targets the real app root under `apps/*` and uses the workspace package manager instead of assuming a single-app root layout.
1713
+
1714
+ - [#163](https://github.com/udecode/kitcn/pull/163) [`38ffd3c`](https://github.com/udecode/kitcn/commit/38ffd3c3843cc4549fd6366190b43977e23d34c0) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1715
+
1716
+ - Fix Concave local `kitcn dev` schema watches so `schema.ts` edits rerun fresh codegen and refresh generated schema outputs without a manual `kitcn codegen`.
1717
+ - Fix `count()` and aggregate range filters on `timestamp({ mode: "string" })`
1718
+ aggregateIndex suffix fields so stored millis buckets match ISO-string
1719
+ filters instead of silently returning zero.
1720
+
1721
+ ## 0.12.10
1722
+
1723
+ ### Patch Changes
1724
+
1725
+ - [#157](https://github.com/udecode/kitcn/pull/157) [`bb038d8`](https://github.com/udecode/kitcn/commit/bb038d880902ef3c2b7388161945dd067073c08f) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1726
+
1727
+ - Fix auth-bound React Query data so guest, sign-in, and account-switch transitions do not keep stale cached user data.
1728
+
1729
+ ## 0.12.9
1730
+
1731
+ ### Patch Changes
1732
+
1733
+ - [#154](https://github.com/udecode/kitcn/pull/154) [`4681298`](https://github.com/udecode/kitcn/commit/46812983553da242a7ee478fc2ec7d024ca018cc) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1734
+
1735
+ - Fix `kitcn dev` so projects with a remote Convex deployment in `.env.local` keep using that remote target instead of falling back to local Convex.
1736
+
1737
+ ## 0.12.8
1738
+
1739
+ ### Patch Changes
1740
+
1741
+ - [#152](https://github.com/udecode/kitcn/pull/152) [`92dd2bc`](https://github.com/udecode/kitcn/commit/92dd2bcf1ce35c1eb34315b88f025c7ee360a9a1) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1742
+
1743
+ - Fix interactive scaffold selection so duplicate file paths are shown once and the active preset stays selected.
1744
+ - Fix generated auth demo pages so sign-in and sign-up stay on the signed-in view instead of bouncing back to the auth route.
1745
+
1746
+ ## 0.12.7
1747
+
1748
+ ### Patch Changes
1749
+
1750
+ - [#150](https://github.com/udecode/kitcn/pull/150) [`9fb1adf`](https://github.com/udecode/kitcn/commit/9fb1adf3a8f9bb7b54ba4dd42c809c9b54ba7e31) Thanks [@zbeyens](https://github.com/zbeyens)! - - Pin the scaffolded Zod install to the supported Zod 4 line so npm
1751
+ `kitcn init -t start` resolves without the peer conflict hit during release
1752
+ validation.
1753
+
1754
+ ## 0.12.6
1755
+
1756
+ ### Patch Changes
1757
+
1758
+ - [#148](https://github.com/udecode/kitcn/pull/148) [`8c59d89`](https://github.com/udecode/kitcn/commit/8c59d892f5fdfc12448aee35d86f286378e61aa6) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
1759
+
1760
+ - Add `kitcn init -t start` for fresh TanStack Start apps.
1761
+ - Add `kitcn/auth/start` and Start-specific auth scaffolding for `kitcn add auth`.
1762
+
1763
+ ## Patches
1764
+
1765
+ - Fix generated file rewrites so unchanged codegen output does not trigger
1766
+ repeated TanStack Start reloads during local development.
1767
+
1768
+ ## 0.12.5
1769
+
1770
+ ## 0.12.4
1771
+
1772
+ ### Patch Changes
1773
+
1774
+ - [`d264542`](https://github.com/udecode/kitcn/commit/d264542e0e6818693cad2ad9520da145c0a72694) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1775
+
1776
+ - Fix `kitcn add auth` in fresh apps so auth planning installs its required dependencies before the scaffold loads Better Auth internals.
1777
+
1778
+ ## 0.12.3
1779
+
1780
+ ### Patch Changes
1781
+
1782
+ - [`ec0aaaa`](https://github.com/udecode/kitcn/commit/ec0aaaa525a95788db5b2ec76626ae445e68eae2) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1783
+
1784
+ - Fix scenario packaging for `@kitcn/resend` after the plugin moved `kitcn` to peer dependencies.
1785
+
1786
+ ## 0.12.2
1787
+
1788
+ ### Patch Changes
1789
+
1790
+ - [`4f9907e`](https://github.com/udecode/kitcn/commit/4f9907e95ceae9f30499b2bad0d1fb20d1fa5fc1) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1791
+
1792
+ - Fix fresh `bunx kitcn` installs so the CLI keeps TypeScript off the cold
1793
+ startup path and still boots when Bun omits `typescript` from the transient
1794
+ install tree.
1795
+
1796
+ ## 0.12.1
1797
+
1798
+ ### Patch Changes
1799
+
1800
+ - [`93726d3`](https://github.com/udecode/kitcn/commit/93726d3d337a7469f98efbf5d932beb370d09d5d) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
1801
+
1802
+ - Fix fresh `bunx kitcn init` installs so the published CLI ships its runtime
1803
+ TypeScript dependency instead of failing before scaffold setup starts.
1804
+ - Fix `kitcn init -t next --yes` so non-interactive local bootstrap provisions
1805
+ an anonymous Convex deployment instead of stopping on a login prompt.
1806
+
1807
+ ## 0.12.0
1808
+
1809
+ ### Minor Changes
1810
+
1811
+ - [#139](https://github.com/udecode/kitcn/pull/139) [`11aa0ee`](https://github.com/udecode/kitcn/commit/11aa0ee2091827e6d52b30c261004f4ed64cac07) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Breaking changes
1812
+
1813
+ - Use `kitcn` and `@kitcn/resend` as the published package names, CLI
1814
+ commands, import paths, generated comments, and scaffold output.
1815
+
1816
+ ```ts
1817
+ // Before
1818
+ import { defineSchema } from "<previous package name>/orm";
1819
+ import { sendEmail } from "<previous scoped plugin>/resend";
1820
+
1821
+ // After
1822
+ import { defineSchema } from "kitcn/orm";
1823
+ import { sendEmail } from "@kitcn/resend";
1824
+ ```
1825
+
1826
+ - Use `kitcn.json` as the default discovered kitcn config file.
1827
+
1828
+ ```ts
1829
+ // Before
1830
+ export default {
1831
+ outputDir: "convex/shared",
1832
+ };
1833
+
1834
+ // After
1835
+ {
1836
+ "paths": {
1837
+ "shared": "convex/shared"
1838
+ }
1839
+ }
1840
+ ```
1841
+
1842
+ - Use app-owned schema composition from the default export. Package schema
1843
+ plugin entrypoints are gone, and relations/triggers chain on
1844
+ `defineSchema(...)`.
1845
+
1846
+ ```ts
1847
+ // Before
1848
+ import { defineRelations, defineSchema } from "kitcn/orm";
1849
+ import { ratelimitPlugin } from "kitcn/plugins/ratelimit";
1850
+
1851
+ export const schema = defineSchema(tables, {
1852
+ plugins: [ratelimitPlugin()],
1853
+ });
1854
+
1855
+ export const relations = defineRelations(tables, (r) => ({
1856
+ users: {
1857
+ posts: r.many.posts(),
1858
+ },
1859
+ }));
1860
+
1861
+ // After
1862
+ import { defineSchema } from "kitcn/orm";
1863
+ import { ratelimitExtension } from "../lib/plugins/ratelimit/schema";
1864
+
1865
+ export default defineSchema(tables)
1866
+ .extend(ratelimitExtension())
1867
+ .relations((r) => ({
1868
+ users: {
1869
+ posts: r.many.posts(),
1870
+ },
1871
+ }));
1872
+ ```
1873
+
1874
+ - Use `kitcn env push` and `kitcn env pull` for env sync.
1875
+ `env sync` is gone.
1876
+
1877
+ ```bash
1878
+ # Before
1879
+ npx kitcn env sync --auth
1880
+
1881
+ # After
1882
+ npx kitcn env push
1883
+ ```
1884
+
1885
+ - Use `kitcn/ratelimit` and `kitcn/ratelimit/react`. The old
1886
+ `kitcn/plugins/ratelimit*` surface is gone.
1887
+
1888
+ ```ts
1889
+ // Before
1890
+ import { calculateRateLimit } from "kitcn/plugins/ratelimit";
1891
+ import { useRateLimit } from "kitcn/plugins/ratelimit/react";
1892
+
1893
+ // After
1894
+ import { calculateRatelimit } from "kitcn/ratelimit";
1895
+ import { useRatelimit } from "kitcn/ratelimit/react";
1896
+ ```
1897
+
1898
+ ## Features
1899
+
1900
+ - Add a registry-driven CLI with `init`, `add`, `view`, `info`, and `docs`,
1901
+ plus `--json`, dry-run, and diff output for scaffold changes.
1902
+ - Add backend-aware CLI support for both Convex and Concave, including
1903
+ `kitcn.json`, local bootstrap wrappers, and `kitcn verify`.
1904
+ - Add project-owned ORM migrations with generated `defineMigration(...)`
1905
+ helpers, migration manifests, docs, and `kitcn migrate`.
1906
+ - Add starter scaffolds for Next.js and Vite, plus adoption flows for raw
1907
+ Convex and create-convex-style apps.
1908
+ - Add packaged Convex skills and TanStack Intent metadata so installed apps
1909
+ carry their own agent guidance.
1910
+ - Add auth scaffolding and schema sync that picks up plugin changes from
1911
+ `auth.ts`, keeps `jwks` wired on first install, and supports raw Convex
1912
+ auth adoption.
1913
+ - Add `kitcn/auth/generated` and typed auth runtime helpers for
1914
+ generated auth files.
1915
+ - Add `@kitcn/resend` with scaffolded schema, plugin, webhook, cron,
1916
+ and email helpers.
1917
+ - Add app-owned schema extensions, typed plugin middleware helpers, and
1918
+ project-owned ratelimit scaffolding.
1919
+ - Add `codegen.trimSegments`, `unionOf(...)`, and broader `objectOf(...)`
1920
+ support for generated runtimes and schema builders.
1921
+
1922
+ ## Patches
1923
+
1924
+ - Improve local dev and codegen so env bootstrap, JWKS sync, watcher reruns,
1925
+ and supported-Node re-exec behave consistently in real apps.
1926
+ - Improve `dev` and `verify` output so one-shot bootstrap stays readable while
1927
+ long-running dev still preserves raw Convex logs.
1928
+ - Improve codegen failure handling so fatal parse errors keep the last good
1929
+ generated files instead of clobbering them with partial output.
1930
+ - Fix relation pairing for aliased auth organization edges so generated
1931
+ runtimes recover cleanly in apps with multiple relations between the same
1932
+ tables.
1933
+ - Fix TanStack Query/provider drift and generated runtime typing so local apps
1934
+ avoid duplicate React Query context failures and self-import cycles.
1935
+ - Improve auth runtime behavior so local auth metadata routes stay quiet, state
1936
+ updates land immediately, and optional env values do not break auth analysis.
1937
+ - Improve schema-only auth refresh so app-owned `schema.ts` files merge missing
1938
+ compatible auth fields, indexes, and relations, then stop on real conflicts
1939
+ with manual-action guidance.
1940
+ - Keep internal example and scenario typechecks pointed at workspace source so
1941
+ fresh CI runs do not depend on stale built package output after package
1942
+ renames.
1943
+ - Fix ratelimit storage and generated scaffolds so apps use the real
1944
+ ratelimit tables instead of failing with bogus missing-table guidance.
1945
+ - Keep scaffolded apps on the tested Hono and TanStack Query baselines across
1946
+ the example app, generated fixtures, and prepared scenarios.
1947
+
1948
+ ## 0.11.0
1949
+
1950
+ ### Minor Changes
1951
+
1952
+ - [#135](https://github.com/udecode/kitcn/pull/135) [`2977aa6`](https://github.com/udecode/kitcn/commit/2977aa68204f239bce5214582f111901affdc2ee) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Breaking changes
1953
+
1954
+ - Drop Better Auth `1.4` support and align auth integrations with Better Auth `1.5.3` and `@convex-dev/better-auth@0.11.1`.
1955
+ - Remove bundled passkey schema assumptions and follow the upstream `oauthApplication.redirectUrls` rename during `0.11` migrations.
1956
+
1957
+ ```ts
1958
+ // Before
1959
+ "better-auth": "1.4.9";
1960
+ "@convex-dev/better-auth": "0.10.11";
1961
+
1962
+ oauthApplication: {
1963
+ redirectURLs: ["https://example.com/callback"];
1964
+ }
1965
+
1966
+ // After
1967
+ "better-auth": "1.5.3";
1968
+ "@convex-dev/better-auth": "0.11.1";
1969
+
1970
+ oauthApplication: {
1971
+ redirectUrls: ["https://example.com/callback"];
1972
+ }
1973
+ ```
1974
+
1975
+ ## Patches
1976
+
1977
+ - Improve Next.js server-side token forwarding by forcing `accept-encoding: identity` for internal auth fetches behind proxy compression.
1978
+ - Fix auth adapter selection and OR-query handling so `id` selects preserve `_id`, nullish filters behave correctly, unsupported `experimental.joins` are rejected, and OR updates/deletes/counts dedupe by document id.
1979
+ - Improve auth route origin handling by filtering nullish `trustedOrigins` values before CORS matching.
1980
+ - Reduce generated runtime boilerplate by moving lazy registry/factory caching and caller/handler context typing into shared server helpers without changing generated caller or handler types.
1981
+
1982
+ ## 0.10.3
1983
+
1984
+ ### Patch Changes
1985
+
1986
+ - [#132](https://github.com/udecode/kitcn/pull/132) [`7182e18`](https://github.com/udecode/kitcn/commit/7182e18a00ee038d64d14c0078a456678fa9e79f) Thanks [@thuillart](https://github.com/thuillart)! - Support loading ORM triggers from `triggers.ts` during codegen, with fallback to `schema.ts` for backward compatibility. This keeps `schema.ts` schema-safe when triggers need generated runtime helpers like `createXCaller(...)`.
1987
+
1988
+ ## 0.10.2
1989
+
1990
+ ### Patch Changes
1991
+
1992
+ - [#129](https://github.com/udecode/kitcn/pull/129) [`9262e6f`](https://github.com/udecode/kitcn/commit/9262e6fe823bf8ededc84c1ee2ba9087efa96aa9) Thanks [@thuillart](https://github.com/thuillart)! - Fix trigger-generated callers in `schema.ts` so they stay schema-safe during Convex pushes, and preserve mutation scheduling APIs when triggers are parameterized with `MutationCtx`.
1993
+
1994
+ ## 0.10.1
1995
+
1996
+ ### Patch Changes
1997
+
1998
+ - [#128](https://github.com/udecode/kitcn/pull/128) [`24e1e60`](https://github.com/udecode/kitcn/commit/24e1e60877b1a0c46631abc6d4118058d42acd4e) Thanks [@thuillart](https://github.com/thuillart)! - ## Patches
1999
+ - Fix `kitcn dev` codegen watch mode so added, changed, and removed procedure files regenerate runtime artifacts more reliably during local development.
2000
+
2001
+ ## 0.10.0
2002
+
2003
+ ### Minor Changes
2004
+
2005
+ - [#121](https://github.com/udecode/kitcn/pull/121) [`7aa4f16`](https://github.com/udecode/kitcn/commit/7aa4f1643b2538627d3c6e51a6e5ab34bec0b500) Thanks [@carere](https://github.com/carere)! - ## Features
2006
+ - Add SolidJS flavor with full feature parity to React integration
2007
+ - Add `ConvexProvider`, `ConvexProviderWithAuth`, `useConvex`, and `useConvexAuth` for SolidJS
2008
+ - Add `createConvexQueryClient` and `useConvexQuery` bridging Convex subscriptions to TanStack Solid Query
2009
+ - Add cRPC layer for SolidJS with typed query/mutation/action proxies
2010
+ - Add `useConvexInfiniteQuery` for paginated queries in SolidJS
2011
+ - Add `createConvexHTTPProxy` for SSR-compatible HTTP client in SolidJS
2012
+ - Add auth mutation helpers (`useSignIn`, `useSignUp`, `useSignOut`) for SolidJS
2013
+ - Add `useRateLimit` hook for SolidJS using `client.onUpdate()` subscriptions
2014
+ - Add `./solid` and `./plugins/ratelimit/solid` package exports
2015
+
2016
+ ### Patch Changes
2017
+
2018
+ - [#126](https://github.com/udecode/kitcn/pull/126) [`0c88268`](https://github.com/udecode/kitcn/commit/0c88268d8efe4160a734ff119aba859d8b4b3fb3) Thanks [@thuillart](https://github.com/thuillart)! - Preserve real `createdAt` columns during ORM writes so auth records keep schema-defaulted timestamps when created through the generated auth runtime.
2019
+
2020
+ ## 0.9.2
2021
+
2022
+ ### Patch Changes
2023
+
2024
+ - [#123](https://github.com/udecode/kitcn/pull/123) [`ba8ce1a`](https://github.com/udecode/kitcn/commit/ba8ce1aaf23c7a152047115763d5e4b7a3e84a64) Thanks [@thuillart](https://github.com/thuillart)! - Pass the Convex deployment URL through the SSR server caller instead of falling back to `NEXT_PUBLIC_CONVEX_URL`.
2025
+
2026
+ `createCallerFactory` now derives the `.convex.cloud` URL from `convexSiteUrl` by default and also accepts an explicit `convexUrl` override for frameworks that do not use Next.js env naming.
2027
+
2028
+ - [#124](https://github.com/udecode/kitcn/pull/124) [`e19de1d`](https://github.com/udecode/kitcn/commit/e19de1d431857851012f9e5e4a1dfa276700c2cd) Thanks [@thuillart](https://github.com/thuillart)! - fix(auth): persist createdAt for auth records
2029
+
2030
+ ## 0.9.1
2031
+
2032
+ ### Patch Changes
2033
+
2034
+ - [#116](https://github.com/udecode/kitcn/pull/116) [`2c98958`](https://github.com/udecode/kitcn/commit/2c98958f35953dfb4514ee038d2363e3ac92df88) Thanks [@thuillart](https://github.com/thuillart)! - Fix `createEnv` throwing "Invalid environment variables" during `kitcn dev`. The CLI now sets a `globalThis.__KITCN_CODEGEN__` sentinel before importing Convex files via jiti, and `createEnv` reads that sentinel (instead of `process.env`) to activate a safe fallback — using `options[0]` for `z.enum` fields instead of `""` to avoid false validation failures.
2035
+
2036
+ - [#120](https://github.com/udecode/kitcn/pull/120) [`c50c99b`](https://github.com/udecode/kitcn/commit/c50c99b5585721e9e6dccc371c3007def1abd09c) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix SSR auth token refresh when Convex requests `forceRefreshToken` during pending Better Auth session hydration.
2037
+
2038
+ `ConvexAuthProvider` now fetches a fresh JWT instead of reusing the cached SSR token in that forced-refresh path, so Convex can schedule preemptive refresh instead of waiting for an auth failure.
2039
+
2040
+ ## 0.9.0
2041
+
2042
+ ### Minor Changes
2043
+
2044
+ - [#112](https://github.com/udecode/kitcn/pull/112) [`5bd956c`](https://github.com/udecode/kitcn/commit/5bd956c7d6602d14f3a8f9062638b31879fa1160) Thanks [@zbeyens](https://github.com/zbeyens)! - ORM Discriminator (polymorphic):
2045
+
2046
+ - Drop the experimental query-level `polymorphic` config from `findMany`, `findFirst`, and `findFirstOrThrow`.
2047
+
2048
+ ```ts
2049
+ // Before
2050
+ await db.query.auditLogs.findMany({
2051
+ polymorphic: {
2052
+ discriminator: "actionType",
2053
+ schema: targetSchema,
2054
+ cases: { role_change: "roleChange", document_update: "documentUpdate" },
2055
+ },
2056
+ limit: 20,
2057
+ });
2058
+
2059
+ // After
2060
+ const rows = await db.query.auditLogs.findMany({ limit: 20 });
2061
+ // Polymorphic data is synthesized from table schema at row.details
2062
+ ```
2063
+
2064
+ - Add schema-first polymorphic discriminator columns via `discriminator({ variants, as? })` directly in `convexTable(...)`.
2065
+ - Add typed nested read unions at `details` by default (or custom alias via `as`).
2066
+ - Add `withVariants: true` as a query shortcut to auto-load one() relations on discriminator tables.
2067
+ - Reject invalid branch writes when required variant fields are missing.
2068
+ - Reject cross-branch write combinations that set fields outside the active discriminator variant.
2069
+
2070
+ ### Patch Changes
2071
+
2072
+ - [#115](https://github.com/udecode/kitcn/pull/115) [`dab1447`](https://github.com/udecode/kitcn/commit/dab14473a9d2285459add2781fa5fbf9c8bd8569) Thanks [@zbeyens](https://github.com/zbeyens)! - - Improve `kitcn analyze` to respect `convex.json` `functions` paths so non-default layouts are discovered.
2073
+
2074
+ ## 0.8.4
2075
+
2076
+ ### Patch Changes
2077
+
2078
+ - [#110](https://github.com/udecode/kitcn/pull/110) [`589e2bc`](https://github.com/udecode/kitcn/commit/589e2bc932b78c552233babe37441deae7ebdcb9) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
2079
+ - Fix nested `arrayOf(objectOf(...))` field nullability so `text()` and `text().notNull()` produce distinct schema/data-model types and avoid deploy mismatches.
2080
+
2081
+ ## 0.8.3
2082
+
2083
+ ### Patch Changes
2084
+
2085
+ - [`7f23a8e`](https://github.com/udecode/kitcn/commit/7f23a8eb512b626b952313b31ed0c2a74b1bee46) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix generated caller support for non-cRPC Convex procedure exports (like `orm.api()` internals such as `migrationStatus`).
2086
+
2087
+ - [`02e40e8`](https://github.com/udecode/kitcn/commit/02e40e8610b6f51962326abce95c51277c3d0177) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
2088
+
2089
+ - Add `polymorphic` query config support for `findMany()`, `findFirst()`, and `findFirstOrThrow()` to synthesize discriminated-union targets from `one()` relations.
2090
+ - Support custom target aliases with `polymorphic.as` (default alias is `target`) while preserving discriminated-union narrowing by discriminator value.
2091
+
2092
+ ## Patches
2093
+
2094
+ - Validate polymorphic configs at runtime and throw on discriminator/case mismatches or schema parse failures.
2095
+ - Auto-load required polymorphic case relations during synthesis and strip them from results unless explicitly requested via `with`.
2096
+ - Reject `pipeline` + `polymorphic` combinations with explicit query-builder errors.
2097
+
2098
+ ## 0.8.2
2099
+
2100
+ ### Patch Changes
2101
+
2102
+ - [`fb0064b`](https://github.com/udecode/kitcn/commit/fb0064bba994ba0ea9db7d7862a6632f53c9cede) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
2103
+ - Add `getSessionNetworkSignals(ctx, session?)` in `kitcn/auth` to expose session-derived `ip` and `userAgent` for query/mutation middleware and rate-limit guards without per-endpoint HTTP wrappers.
2104
+
2105
+ ## 0.8.1
2106
+
2107
+ ### Patch Changes
2108
+
2109
+ - [`fc9e17c`](https://github.com/udecode/kitcn/commit/fc9e17c7cf220435451e45eeb2cc08c8d34c7d46) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Fixes
2110
+ - Fix `kitcn/plugins/ratelimit` so `limit()` and `check()` no longer call timer APIs (`setTimeout`/`clearTimeout`) during normal execution.
2111
+ - Remove `blockUntilReady()`
2112
+
2113
+ ## 0.8.0
2114
+
2115
+ ### Minor Changes
2116
+
2117
+ - [#105](https://github.com/udecode/kitcn/pull/105) [`9ea3902`](https://github.com/udecode/kitcn/commit/9ea3902a9b37bf1206c99c46d3121b95b10af8e7) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Breaking Changes
2118
+
2119
+ - Moved imports from `kitcn/migration` to `kitcn/orm`.
2120
+
2121
+ ## Features
2122
+
2123
+ - Add `arrayOf(...)` and `objectOf(...)` ORM helpers to reduce `custom(...)` boilerplate for nested array/object schemas.
2124
+ - Add schema plugin pipeline to `defineSchema(...)` with builtin/default `aggregatePlugin()` and `migrationPlugin()`.
2125
+ - Add optional `plugins` option on `defineSchema` so feature tables can be opt-in.
2126
+ - Expose `aggregatePlugin` and `migrationPlugin` from `kitcn/plugins`.
2127
+ - Add new `kitcn/plugins/ratelimit` module with Upstash-style APIs (`limit`, `check`, `getRemaining`, `blockUntilReady`, `resetUsedTokens`, dynamic limits, timeout/cache/deny reasons) backed by Convex DB tables.
2128
+ - Add `kitcn/plugins/ratelimit/react` with `useRateLimit` hook support for browser-side status checks and retry timing.
2129
+ - Add `ratelimitPlugin()` for explicit ratelimit internal table enablement in ORM `defineSchema`.
2130
+
2131
+ Usage:
2132
+
2133
+ - Replace example app rate limiting from `@convex-dev/rate-limiter` component usage to `kitcn/plugins/ratelimit`.
2134
+ - Add `/ratelimit` coverage demo and guard test suite for ratelimit coverage definitions.
2135
+ - Rewrite rate-limiting docs/template references to the new `kitcn/plugins/ratelimit` package surface.
2136
+
2137
+ ## 0.7.3
2138
+
2139
+ ### Patch Changes
2140
+
2141
+ - [#103](https://github.com/udecode/kitcn/pull/103) [`590c6e3`](https://github.com/udecode/kitcn/commit/590c6e37d1d61cd4f91b7edba3cd3120206d751a) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Features
2142
+ - Add built-in ORM migrations with `defineMigration`, `defineMigrationSet`, and typed migration plan/status helpers.
2143
+ - Add generated migration procedures (`migrationRun`, `migrationRunChunk`, `migrationStatus`, `migrationCancel`) to generated server/runtime contracts.
2144
+ - Add `kitcn migrate` CLI commands: `create`, `up`, `down`, `status`, and `cancel`.
2145
+ - Add migration orchestration to `kitcn dev` and `kitcn deploy` with configurable strictness, waiting, batching, and drift policy.
2146
+ - Add safe-bypass migration writes by default with per-migration `writeMode: "normal"` override.
2147
+ - Make `kitcn reset` clear migration state/history tables (`migration_state`, `migration_run`) in addition to user and aggregate tables.
2148
+
2149
+ ## 0.7.2
2150
+
2151
+ ### Patch Changes
2152
+
2153
+ - [`9bccd91`](https://github.com/udecode/kitcn/commit/9bccd91a5ac883fcfe6d1345d1f04ca000dcd62e) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix auth adapter date output regression.
2154
+
2155
+ `getAuth(ctx).api.*` date fields are normalized back to Convex-safe unix millis (`number`) on output, preventing unsupported `Date` values from leaking into raw Convex query/mutation/action returns (for example `auth.api.listOrganizations`).
2156
+
2157
+ ## 0.7.1
2158
+
2159
+ ### Patch Changes
2160
+
2161
+ - [#99](https://github.com/udecode/kitcn/pull/99) [`ea02427`](https://github.com/udecode/kitcn/commit/ea02427192747fe18859de2e65ede0a96ba7a446) Thanks [@zbeyens](https://github.com/zbeyens)! - ## Patches
2162
+ - Fix server auth queries and mutations to refresh stale JWTs and retry once on unauthorized responses before returning unauthenticated results.
2163
+ - Fix auth header generation to fall back to Better Auth session-token cookies when JWT identity is unavailable, including secure and custom cookie prefixes.
2164
+ - Update `@convex-dev/better-auth` support to `0.10.11` to include upstream cross-domain and Convex plugin auth fixes.
2165
+ - Fix `ConvexAuthProvider` token refresh behavior by deduplicating concurrent token fetches and forcing non-throwing internal token fetch calls.
2166
+ - Improve SSR/OTT auth stability in `ConvexAuthProvider` so session hydration and one-time-token URL handling avoid transient unauthorized states.
2167
+ - Align reactive auth query subscriptions with `skipUnauth` semantics so unauthorized subscription updates resolve to `null` instead of triggering unauthorized callbacks.
2168
+ - Ensure `ConvexAuthProvider` auth state follows confirmed Better Auth session state so stale JWTs do not keep authenticated state after sign-out.
2169
+ - Fix auth adapter date output normalization to return `Date` values for date fields.
2170
+ - Fix Next.js auth token forwarding by removing body-related headers from internal token fetch requests.
2171
+ - Prefer `better-auth/minimal` imports in auth runtime/type paths where available
2172
+
2173
+ ## 0.7.0
2174
+
2175
+ ### Minor Changes
2176
+
2177
+ - [#97](https://github.com/udecode/kitcn/pull/97) [`4f83203`](https://github.com/udecode/kitcn/commit/4f83203381bbd5030db77b76baed47db29d25057) Thanks [@{](https://github.com/{)! - ## Auth
2178
+
2179
+ ### Breaking changes
2180
+
2181
+ - Redesign auth trigger API from flat callbacks to nested `{ create, update, delete, change }` shape matching ORM `defineTriggers` pattern.
2182
+ - Replace split auth exports (`getAuthOptions` + `authTriggers`) with one default `defineAuth((ctx) => ({ ...options, triggers }))` contract.
2183
+ - Drop generated trigger procedures (`beforeCreate`, `onCreate`, `beforeUpdate`, `onUpdate`, `beforeDelete`, `onDelete`); triggers now run inline in the same CRUD transaction.
2184
+ - Add `ctx` as second parameter to all trigger callbacks for access to mutation context.
2185
+ - Add `before` hook return contract: `void` (continue unchanged), `{ data }` (shallow merge into payload), `false` (cancel write).
2186
+ - Add unified `change(change, ctx)` handler with discriminated union `{ operation, id, newDoc, oldDoc }`.
2187
+ - Rename `createApi` option `skipValidation` to `validateInput`; default is now `validateInput: false`.
2188
+ - Rename auth package entrypoints from hyphenated to namespaced paths:
2189
+ - `kitcn/auth-client` -> `kitcn/auth/client`
2190
+ - `kitcn/auth-config` -> `kitcn/auth/config`
2191
+ - `kitcn/auth-nextjs` -> `kitcn/auth/nextjs`
2192
+ - Move HTTP auth helpers to `kitcn/auth/http`:
2193
+ - `authMiddleware` and `registerRoutes` now import from `kitcn/auth/http` (not `kitcn/auth`).
2194
+ - `kitcn/auth/http` auto-installs the Convex-safe `MessageChannel` polyfill. You can remove your own `http-polyfills.ts` file.
2195
+
2196
+ ```ts
2197
+ // Before
2198
+ export const getAuthOptions = (ctx) => ({ ...options });
2199
+ export const authTriggers = { user: { onCreate: async (ctx, user) => {} } };
2200
+
2201
+ // After
2202
+ import { defineAuth } from "./generated/auth";
2203
+
2204
+ export default defineAuth((ctx) => ({
2205
+ ...options,
2206
+ triggers: {
2207
+
2208
+ create: {
2209
+ before: async (data, ctx) => ({ data: { ...data, role: "user" } }),
2210
+ after: async (doc, ctx) => {},
2211
+ },
2212
+ update: {
2213
+ after: async (newDoc, ctx) => {},
2214
+ },
2215
+ change: async (change, ctx) => {
2216
+ // change.operation: 'insert' | 'update' | 'delete'
2217
+ // change.id, change.newDoc, change.oldDoc
2218
+ },
2219
+ },
2220
+ },
2221
+ }));
2222
+ ```
2223
+
2224
+ ```ts
2225
+ // Before
2226
+ import { getAuth } from "./auth";
2227
+ createApi(schema, getAuth, { skipValidation: true });
2228
+
2229
+ // After
2230
+ import { getAuth } from "./generated/auth";
2231
+ createApi(schema, getAuth); // validateInput defaults to false
2232
+ createApi(schema, getAuth, { validateInput: true });
2233
+ ```
2234
+
2235
+ ```ts
2236
+ // Before
2237
+ import { convexClient } from "kitcn/auth-client";
2238
+ import { getAuthConfigProvider } from "kitcn/auth-config";
2239
+ import { convexBetterAuth } from "kitcn/auth-nextjs";
2240
+
2241
+ // After
2242
+ import { convexClient } from "kitcn/auth/client";
2243
+ import { getAuthConfigProvider } from "kitcn/auth/config";
2244
+ import { convexBetterAuth } from "kitcn/auth/nextjs";
2245
+ ```
2246
+
2247
+ ```ts
2248
+ // Before
2249
+ import "../lib/http-polyfills";
2250
+ import { authMiddleware, registerRoutes } from "kitcn/auth";
2251
+
2252
+ // After
2253
+ import { authMiddleware, registerRoutes } from "kitcn/auth/http";
2254
+ ```
2255
+
2256
+ ### Features
2257
+
2258
+ - Add `defineAuth` helpers to unify codegen and non-codegen auth setup.
2259
+ - Add always-generated Better Auth runtime contract in `convex/functions/generated/auth.ts`.
2260
+ - Add generated `defineAuth` export in `convex/functions/generated/auth.ts` for inference-first `auth.ts` authoring.
2261
+ - Support ORM-aware auth writes (insert/update/delete go through ORM when available).
2262
+
2263
+ ## Codegen
2264
+
2265
+ ### Breaking changes
2266
+
2267
+ - Drop generated internal auth calls from `internal.auth.*`; use `internal.generated.*`.
2268
+ - Drop manual `initCRPC.dataModel().context(...)` bootstrap; import generated `initCRPC` from `convex/functions/generated/server`.
2269
+ - Drop manual `ctx.runQuery`/`ctx.runMutation` for inter-procedure calls; use per-module `create<Module>Handler`/`create<Module>Caller` from `convex/functions/generated/<module>.runtime`.
2270
+ - Require `export const httpRouter = router(...)` in `convex/functions/http.ts` so codegen can include typed HTTP routes in generated API output.
2271
+
2272
+ ```ts
2273
+ // Before
2274
+ import { initCRPC } from "kitcn/server";
2275
+ import type { DataModel } from "./_generated/dataModel";
2276
+
2277
+ const c = initCRPC
2278
+ .dataModel<DataModel>()
2279
+ .context({
2280
+ query: (ctx) => withOrm(ctx),
2281
+ mutation: (ctx) => withOrm(ctx),
2282
+ })
2283
+ .meta<{
2284
+ auth?: "optional" | "required";
2285
+ role?: "admin";
2286
+ rateLimit?: string;
2287
+ }>()
2288
+ .create();
2289
+
2290
+ // After
2291
+ import { initCRPC } from "./generated/server";
2292
+
2293
+ const c = initCRPC
2294
+ .meta<{
2295
+ auth?: "optional" | "required";
2296
+ role?: "admin";
2297
+ rateLimit?: string;
2298
+ }>()
2299
+ .create();
2300
+ ```
2301
+
2302
+ ```ts
2303
+ // Before (http.ts)
2304
+ export const appRouter = router({
2305
+ health,
2306
+ todos: todosRouter,
2307
+ });
2308
+ export default createHttpRouter(app, appRouter);
2309
+
2310
+ // After (http.ts)
2311
+ export const httpRouter = router({
2312
+ health,
2313
+ todos: todosRouter,
2314
+ });
2315
+ export default createHttpRouter(app, httpRouter);
2316
+ ```
2317
+
2318
+ ### Features
2319
+
2320
+ - Add generated `convex/functions/generated/` directory:
2321
+ - `generated/server.ts` — ORM exports (`orm`, `withOrm`, `scheduledMutationBatch`, `scheduledDelete`), wrapped ctx types (`OrmCtx`, `QueryCtx`, `MutationCtx`, `GenericCtx`), prewired `initCRPC`.
2322
+ - `generated/auth.ts` — `defineAuth`, `getAuth`, auth runtime contract.
2323
+ - `generated/<module>.runtime.ts` — per-module scoped caller/handler factories.
2324
+ - Add per-module `create<Module>Handler(ctx)` (DEFAULT) for zero-overhead internal composition in queries/mutations. Bypasses input validation, middleware, and output validation. Same transaction, no serialization.
2325
+ - Add per-module `create<Module>Caller(ctx)` for actions and HTTP routes only. Goes through validation + middleware.
2326
+ - Root calls in `ActionCtx` dispatch via `ctx.runQuery` / `ctx.runMutation`.
2327
+ - Direct action calls are explicit under `caller.actions.*` and dispatch via `ctx.runAction`.
2328
+ - Scheduled calls are available under `caller.schedule.*`:
2329
+ - `caller.schedule.now.<mutation|action>(input)` (alias for `after(0)`)
2330
+ - `caller.schedule.after(ms).<mutation|action>(input)`
2331
+ - `caller.schedule.at(dateOrMs).<mutation|action>(input)`
2332
+ - `caller.schedule.cancel(jobId)`
2333
+ - Auto-generate procedure registry per module from cRPC exports (public + internal).
2334
+ - Enforce call matrix: query ctx → root queries only; mutation ctx → root queries+mutations plus `schedule`; action ctx → root queries+mutations plus `actions` and `schedule`.
2335
+ - Reserve module export names `actions` and `schedule` in runtime callers (codegen throws explicit conflict error).
2336
+ - Never use `ctx.runQuery`/`ctx.runMutation` directly — always use `create<Module>Handler` or `create<Module>Caller`.
2337
+ - Keep manual `initCRPC` setup from `kitcn/server` supported for apps not using codegen.
2338
+ - Add `kitcn.json` support (plus `--config <path>`) for codegen/dev defaults, feature toggles (`api`, `auth`), and passthrough Convex arg presets.
2339
+
2340
+ ```ts
2341
+ // Before — manual runQuery/runMutation with function references
2342
+ import { api, internal } from "./_generated/api";
2343
+
2344
+ const result = await ctx.runQuery(api.todos.list, { limit: 10 });
2345
+ await ctx.runMutation(internal.todoInternal.create, { userId, ...input });
2346
+
2347
+ // After (query/mutation) — per-module handler, zero overhead, same transaction
2348
+ import { createSeedHandler } from "./generated/seed.runtime";
2349
+
2350
+ const handler = createSeedHandler(ctx);
2351
+ await handler.cleanupSeedData();
2352
+ await handler.seedUsers();
2353
+ ```
2354
+
2355
+ ```ts
2356
+ // After (action/HTTP) — per-module caller, validation + middleware
2357
+ import { createSeedCaller } from "./generated/seed.runtime";
2358
+
2359
+ const caller = createSeedCaller(ctx);
2360
+ await caller.generateSamplesBatch({ count: 5, userId, batchIndex: 0 });
2361
+ ```
2362
+
2363
+ ### Patches
2364
+
2365
+ - Add generated internal API refs for async ORM workers and generated auth handlers under `internal.generated`.
2366
+
2367
+ ## API Types
2368
+
2369
+ ### Breaking changes
2370
+
2371
+ - Drop separate `meta` arguments in context/proxy/caller/auth setup APIs; pass only `api`.
2372
+ - Drop the `@convex/types` workflow and use generated `@convex/api` types.
2373
+ - Drop manual codegen outputs `convex/shared/meta.ts` and `convex/shared/types.ts` in favor of generated `convex/shared/api.ts`.
2374
+
2375
+ ```ts
2376
+ // Before
2377
+ import type { Api, ApiInputs, ApiOutputs } from "@convex/types";
2378
+ createCRPCContext({ api, meta, convexSiteUrl });
2379
+ createServerCRPCProxy({ api, meta });
2380
+
2381
+ // After
2382
+ import type { Api, ApiInputs, ApiOutputs } from "@convex/api";
2383
+ createCRPCContext({ api, convexSiteUrl });
2384
+ createServerCRPCProxy({ api });
2385
+ ```
2386
+
2387
+ ```ts
2388
+ // Before
2389
+ import type { Select, Insert } from "./shared/types";
2390
+
2391
+ // After
2392
+ import type { Select, Insert } from "@convex/api";
2393
+ ```
2394
+
2395
+ ### Features
2396
+
2397
+ - Add a single generated `@convex/api` surface that exports `api`, `Api`, `ApiInputs`, and `ApiOutputs` for client typing.
2398
+ - Add optional generated table helpers (`TableName`, `Select`, `Insert`) when schema exports `tables`.
2399
+
2400
+ ### Patches
2401
+
2402
+ - Add Date-safe API inference from cRPC exports so `z.date()` fields stay typed as `Date` in generated API input/output types.
2403
+ - Improve generated `Api` typing so HTTP router types are embedded in `typeof api`, reducing manual `<Api>` generics in common setup calls.
2404
+ - Build function metadata from the generated `api` object at runtime, eliminating separate `meta` plumbing in cRPC React/RSC/server helpers.
2405
+ - Filter internal/private namespaces from generated client/caller type surfaces (e.g. `_http`, `_generated`-style keys).
2406
+ - Improve lazy caller invalid-path errors with clearer failure messages.
2407
+
2408
+ ```ts
2409
+ // Before
2410
+ import type { Api } from "@convex/api";
2411
+
2412
+ export const { CRPCProvider, useCRPC, useCRPCClient } =
2413
+ createCRPCContext<Api>({
2414
+ api,
2415
+ convexSiteUrl: env.NEXT_PUBLIC_CONVEX_SITE_URL,
2416
+ });
2417
+
2418
+ export const crpc = createServerCRPCProxy<Api>({ api });
2419
+
2420
+ // After
2421
+ export const { CRPCProvider, useCRPC, useCRPCClient } = createCRPCContext({
2422
+ api,
2423
+ convexSiteUrl: env.NEXT_PUBLIC_CONVEX_SITE_URL,
2424
+ });
2425
+
2426
+ export const crpc = createServerCRPCProxy({ api });
2427
+ ```
2428
+
2429
+ ## Dependency
2430
+
2431
+ ### Breaking changes
2432
+
2433
+ - Bump Convex minimum peer dependency to `>=1.32`.
2434
+
2435
+ ## ORM
2436
+
2437
+ ### Breaking changes
2438
+
2439
+ - Drop manual `convex/lib/orm.ts` server wiring; import `orm`/`withOrm` from `convex/functions/generated/server`.
2440
+ - Drop `OrmQueryCtx`/`OrmMutationCtx`; import wrapped `QueryCtx`/`MutationCtx` from `convex/functions/generated/server`.
2441
+ - Table-level lifecycle registration in `convexTable(..., extraConfig)` is removed.
2442
+ - Lifecycle helpers `onInsert`, `onUpdate`, `onDelete`, and `onChange` are removed from `kitcn/orm`.
2443
+
2444
+ ```ts
2445
+ // Before
2446
+ import type { OrmQueryCtx, OrmMutationCtx } from "../lib/orm";
2447
+ import { withOrm } from "../lib/orm";
2448
+
2449
+ // After
2450
+ import type { QueryCtx, MutationCtx } from "./generated/server";
2451
+ import { withOrm } from "./generated/server";
2452
+ ```
2453
+
2454
+ ### Features
2455
+
2456
+ - ORM triggers are schema-level only and must be exported as `export const triggers = defineTriggers(relations, { ... })`.
2457
+ - Trigger definitions use object hooks per table:
2458
+ - `create.before` / `create.after`
2459
+ - `update.before` / `update.after`
2460
+ - `delete.before` / `delete.after`
2461
+ - `change(change, ctx)`
2462
+ - `before` return contract is:
2463
+ - `void` => continue unchanged
2464
+ - `{ data }` => shallow merge into write payload
2465
+ - `false` => cancel write via `TriggerCancelledError`
2466
+ - Generated server wiring includes `triggers` only when `schema.ts` exports both `relations` and `triggers`.
2467
+ - Add `createOrm({ schema, triggers })` support for generated and manual setups.
2468
+ - Add `ctx.orm.withoutTriggers(callback)` to bypass trigger hooks for bulk operations (e.g. data resets, migrations). The callback receives a trigger-free ORM instance scoped to the same transaction.
2469
+
2470
+ ## Aggregates
2471
+
2472
+ ### Features
2473
+
2474
+ - Add built-in aggregate-core runtime (B-tree backed).
2475
+ - Add `aggregateIndex` schema builder for declaring ORM count and aggregate index coverage:
2476
+ - `aggregateIndex(name).on(field1, field2)` — filter key fields.
2477
+ - `aggregateIndex(name).all()` — unfiltered (global) metrics.
2478
+ - Chainable metric methods: `.count(field)`, `.sum(field)`, `.avg(field)`, `.min(field)`, `.max(field)`.
2479
+
2480
+ ```ts
2481
+ // Schema declaration
2482
+ const orders = convexTable(
2483
+ "orders",
2484
+ { orgId: text(), amount: integer(), score: integer() },
2485
+ (t) => [
2486
+ aggregateIndex("by_org")
2487
+ .on(t.orgId)
2488
+ .sum(t.amount)
2489
+ .avg(t.amount)
2490
+ .min(t.score)
2491
+ .max(t.score),
2492
+ aggregateIndex("all_metrics").all().sum(t.amount).count(t.orgId),
2493
+ ]
2494
+ );
2495
+ ```
2496
+
2497
+ - Add `ctx.orm.query.<table>.count()` and `ctx.orm.query.<table>.count({ where, select, orderBy, skip, take, cursor })` for O(1) filtered counts backed by `aggregateIndex`. Windowed count (`skip`/`take`/`cursor`) counts rows within a window defined by ordering and bounds.
2498
+ - Add `ctx.orm.query.<table>.aggregate({ where, _count, _sum, _avg, _min, _max, orderBy, skip, take, cursor })` for Prisma-style aggregate blocks with optional windowed bounds.
2499
+ - Add safe finite `OR` rewrite for aggregate/count `where` — `OR` branches collapse when each is index-plannable (differs on one scalar eq/in/isNull field).
2500
+ - Add `findMany({ distinct })` deterministic `DISTINCT_UNSUPPORTED` error directing to `select().distinct({ fields })` pipeline.
2501
+ - Add relation `_count` loading via `with: { _count: { todos: true } }` with optional filtered variants.
2502
+ - Add through-filtered relation `_count` for `through()` relations using indexed lookups + no-scan-safe filter validation.
2503
+ - Add mutation `returning({ _count })` for insert/update/delete via split selection + relation count loading.
2504
+ - Add Prisma-style `_sum` nullability: returns `null` for empty sets or all-null field values (instead of `0`).
2505
+ - Add `groupBy()` to the ORM query builder with Prisma-style `by`, `_count`, `_sum`, `_avg`, `_min`, `_max` blocks. Requires finite `where` constraints (`eq`/`in`/`isNull`) on every `by` field — no `having`/`orderBy`/`skip`/`take`/`cursor` in v1.
2506
+
2507
+ ```ts
2508
+ // Count
2509
+ const total = await ctx.orm.query.todos.count({ where: { projectId } });
2510
+
2511
+ // Aggregate
2512
+ const stats = await ctx.orm.query.orders.aggregate({
2513
+ where: { orgId: "org-1" },
2514
+ _count: { _all: true },
2515
+ _sum: { amount: true },
2516
+ _avg: { amount: true },
2517
+ });
2518
+
2519
+ // Relation _count
2520
+ const users = await ctx.orm.query.user.findMany({
2521
+ with: { _count: { todos: { where: { completed: true } } } },
2522
+ });
2523
+ ```
2524
+
2525
+ - Add generated `aggregateBackfill` and `aggregateBackfillStatus` procedures for index building and status polling.
2526
+ - Add ORM internal storage tables (`aggregate_bucket`, `aggregate_member`, `aggregate_extrema`, `aggregate_state`, `aggregate_rank_tree`, `aggregate_rank_node`) auto-injected by `defineSchema`. Convex rejects table names starting with `_`, so internals use the `aggregate_` prefix.
2527
+ - Add `rankIndex` schema builder for declaring ranked/ordered aggregate indexes:
2528
+ - `rankIndex(name).partitionBy(field1, field2).orderBy(t.score).sum(t.amount)` — partitioned rank index with optional weighted sum.
2529
+ - `rankIndex(name).all().orderBy(t.score)` — unpartitioned (global) rank index.
2530
+ - `orderBy()` supports `integer()`/`timestamp()`/`date()` columns only.
2531
+ - Add `db.query.<table>.rank(indexName, { where })` query builder with O(log n) operations:
2532
+ - `.count()`, `.sum()` — aggregate reads.
2533
+ - `.at(offset)` — positional access by rank.
2534
+ - `.indexOf({ id })` — rank lookup by document ID.
2535
+ - `.paginate({ cursor, limit })` — cursor-based ranked pagination.
2536
+ - `.min()`, `.max()`, `.random()` — extrema and random sampling.
2537
+ - Add backfill support for rank indexes alongside metric indexes (shared `aggregateBackfill`/`aggregateBackfillStatus` procedures).
2538
+
2539
+ ## CLI
2540
+
2541
+ ### Features
2542
+
2543
+ - Add `kitcn analyze` command with two modes:
2544
+ - Default **hotspot** mode: per-entry bundle analysis showing output size, dependency size, and handler counts. Interactive TUI with keyboard navigation, live filtering, sort cycling, detail panes (handlers/packages/inputs), and file watch for auto-refresh.
2545
+ - `--deploy` mode: single-isolate bundle analysis matching Convex deploy bundling. Reports total size, top inputs, and top packages.
2546
+ - `--fail-mb <n>` for CI gating: exit 1 if largest entry or chunk exceeds threshold.
2547
+ - Positional regex argument to filter entry points (e.g. `kitcn analyze "auth.*"`).
2548
+ - Add `kitcn deploy` command that wraps `convex deploy` with automatic post-deploy aggregate backfill.
2549
+ - Add `kitcn aggregate rebuild` command for full aggregate index rebuild.
2550
+ - Add `kitcn aggregate backfill` command for resume-mode backfill (no clear/rebuild).
2551
+ - Add automatic aggregate backfill to `kitcn dev` (auto-resumes on startup, non-blocking).
2552
+ - Add `aggregateBackfill` config section in `kitcn.json` for both `dev` and `deploy`:
2553
+ - `enabled`: `"auto"` (skip if function not found), `"on"`, or `"off"`.
2554
+ - `wait`: poll until all indexes READY or timeout (default `true`).
2555
+ - `batchSize`, `pollIntervalMs`, `timeoutMs`: tuning knobs.
2556
+ - `strict`: exit 1 on failure/timeout (default `true` for deploy, `false` for dev).
2557
+ - Add CLI flags for aggregate backfill overrides: `--backfill`, `--backfill-wait`, `--backfill-strict`, `--backfill-batch-size`, `--backfill-timeout-ms`, `--backfill-poll-ms`.
2558
+ - Add `kitcn reset --yes` command: calls `generated/server:reset`. Supports `--before <fn>` and `--after <fn>` hooks.
2559
+
2560
+ ## 0.6.4
2561
+
2562
+ ### Patch Changes
2563
+
2564
+ - [#93](https://github.com/udecode/kitcn/pull/93) [`8153811`](https://github.com/udecode/kitcn/commit/81538110000a33855f1b5bb9b66f613604cd8388) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix `findFirst` now returns `null` instead of `undefined` when no result is found. Fix `.returning()` crash on nullable timestamp fields.
2565
+
2566
+ ## 0.6.3
2567
+
2568
+ ### Patch Changes
2569
+
2570
+ - [#88](https://github.com/udecode/kitcn/pull/88) [`207d62f`](https://github.com/udecode/kitcn/commit/207d62f19912ccf355ff4c5e9ec5fee56ecf58cb) Thanks [@zbeyens](https://github.com/zbeyens)! - ORM/RLS update: async policy callbacks, safe empty `inArray([])` handling in query + mutation paths, and runtime+types support for system fields (`t.id`) in `extraConfig` callbacks.
2571
+
2572
+ ## 0.6.2
2573
+
2574
+ ### Patch Changes
2575
+
2576
+ - [#86](https://github.com/udecode/kitcn/pull/86) [`49098fa`](https://github.com/udecode/kitcn/commit/49098fa5919b4a9c4a3e73b989ab55d897df02c3) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix Better Auth HTTP adapter error handling to preserve auth error status/code instead of surfacing unexpected 500s.
2577
+
2578
+ ## 0.6.1
2579
+
2580
+ ### Patch Changes
2581
+
2582
+ - [#82](https://github.com/udecode/kitcn/pull/82) [`aed9972`](https://github.com/udecode/kitcn/commit/aed9972f5869949cfc02ca2eb6bfcb7e57fb754d) Thanks [@zbeyens](https://github.com/zbeyens)! - Migration example: https://github.com/udecode/kitcn/pull/82
2583
+
2584
+ Added `AnyColumn` type export for self-referencing foreign keys (mirrors Drizzle's `AnyPgColumn`).
2585
+
2586
+ ```ts
2587
+ import { type AnyColumn, convexTable, text } from "kitcn/orm";
2588
+
2589
+ export const comments = convexTable("comments", {
2590
+ body: text().notNull(),
2591
+ parentId: text().references((): AnyColumn => comments.id, {
2592
+ onDelete: "cascade",
2593
+ }),
2594
+ });
2595
+ ```
2596
+
2597
+ ## 0.6.0
2598
+
2599
+ ### Minor Changes
2600
+
2601
+ - [#75](https://github.com/udecode/kitcn/pull/75) [`54eeb6d`](https://github.com/udecode/kitcn/commit/54eeb6d68909737b21b3dddfa860de0fc84e7924) Thanks [@zbeyens](https://github.com/zbeyens)! - - Added `kitcn/orm` as the recommended DB API surface (Drizzle-style schema/query/mutation API).
2602
+
2603
+ - Docs: [/docs/db/orm](https://www.kitcn.dev/docs/db/orm)
2604
+ - Migration guide: [/docs/migrations/convex](https://www.kitcn.dev/docs/migrations/convex)
2605
+
2606
+ ## Breaking changes
2607
+
2608
+ - `createAuth(ctx)` is removed. Use `getAuth(ctx)` for query/mutation/action/http.
2609
+
2610
+ ```ts
2611
+ // Before
2612
+ export const createAuth = (ctx: ActionCtx) =>
2613
+ betterAuth(createAuthOptions(ctx));
2614
+ app.use(authMiddleware(createAuth));
2615
+
2616
+ // After
2617
+ export const getAuth = (ctx: GenericCtx) => betterAuth(getAuthOptions(ctx));
2618
+ app.use(authMiddleware(getAuth));
2619
+ ```
2620
+
2621
+ - `authClient.httpAdapter` is no longer needed. Use context-aware `adapter(...)`.
2622
+
2623
+ ```ts
2624
+ // Before
2625
+ database: authClient.httpAdapter(ctx);
2626
+
2627
+ // After
2628
+ database: authClient.adapter(ctx, getAuthOptions);
2629
+ ```
2630
+
2631
+ - cRPC templates now use `ctx.orm` (not `ctx.table`) and string IDs at the API boundary.
2632
+
2633
+ ```ts
2634
+ // Before
2635
+ input: z.object({ id: zid("user") });
2636
+ const user = await ctx.table("user").get(input.id);
2637
+
2638
+ // After
2639
+ input: z.object({ id: z.string() });
2640
+ const user = await ctx.orm.query.user.findFirst({ where: { id: input.id } });
2641
+ ```
2642
+
2643
+ - cRPC/auth context ID types are now string-based at the procedure boundary (`ctx.userId`, params, input/output IDs).
2644
+
2645
+ ```ts
2646
+ // Before
2647
+ const userId: Id<"user"> = ctx.userId;
2648
+
2649
+ // After
2650
+ const userId: string = ctx.userId;
2651
+ ```
2652
+
2653
+ - `getAuthConfigProvider` should be imported from `kitcn/auth/config`.
2654
+ (instead of legacy `@convex-dev/better-auth/auth-config`, or old `kitcn/auth` docs)
2655
+
2656
+ ```ts
2657
+ // Before
2658
+ import { getAuthConfigProvider } from "@convex-dev/better-auth/auth-config";
2659
+
2660
+ // After
2661
+ import { getAuthConfigProvider } from "kitcn/auth/config";
2662
+ ```
2663
+
2664
+ - Remove legacy app deps: `@convex-dev/better-auth`, `convex-ents`, and `convex-helpers`.
2665
+
2666
+ ```sh
2667
+ bun remove @convex-dev/better-auth convex-ents convex-helpers
2668
+ ```
2669
+
2670
+ - `convex-helpers` primitives are no longer part of the template path.
2671
+ Replace `zid(...)` with `z.string()`, and remove `customMutation`/`Triggers` wrappers in favor of:
2672
+ - `initCRPC.create()` defaults
2673
+ - trigger declarations in schema table config
2674
+ - ORM row shape is `id`/`createdAt` (not `_id`/`_creationTime`) at the app boundary.
2675
+ Update UI/client code and shared types accordingly.
2676
+
2677
+ ## Features
2678
+
2679
+ - `initCRPC.create()` supports default Convex builders, so old manual wiring is usually unnecessary.
2680
+
2681
+ ```ts
2682
+ // Before (remove this boilerplate)
2683
+ const c = initCRPC.create({
2684
+ query,
2685
+ internalQuery,
2686
+ mutation,
2687
+ internalMutation,
2688
+ action,
2689
+ internalAction,
2690
+ httpAction,
2691
+ });
2692
+ const internalMutationWithTriggers = customMutation(...);
2693
+
2694
+ // After
2695
+ const c = initCRPC.create();
2696
+ // Triggers are declared in schema table config.
2697
+ ```
2698
+
2699
+ - cRPC now supports wire transformers end-to-end (Date codec included by default).
2700
+ - Supported in `initCRPC.create({ transformer })`, HTTP proxy, server caller, React client, and RSC query client.
2701
+
2702
+ ```ts
2703
+ const c = initCRPC.create({ transformer: superjson });
2704
+
2705
+ const http = createHttpProxy({
2706
+ convexSiteUrl,
2707
+ routes,
2708
+ transformer: superjson,
2709
+ });
2710
+ ```
2711
+
2712
+ - Auth setup supports `triggers` + `context` in `createClient`, and `context` in `createApi`.
2713
+
2714
+ ```ts
2715
+ const authClient = createClient({
2716
+ authFunctions,
2717
+ schema,
2718
+ triggers,
2719
+ context: getOrmCtx,
2720
+ });
2721
+
2722
+ const authApi = createApi(schema, getAuth, {
2723
+ context: getOrmCtx,
2724
+ });
2725
+ ```
2726
+
2727
+ - `createEnv` can replace manual env parsing/throw boilerplate.
2728
+
2729
+ ```ts
2730
+ // Before
2731
+ export const getEnv = () => {
2732
+ const parsed = envSchema.safeParse(process.env);
2733
+ if (!parsed.success) throw new Error("Invalid environment variables");
2734
+ return parsed.data;
2735
+ };
2736
+
2737
+ // After
2738
+ export const getEnv = createEnv({ schema: envSchema });
2739
+ ```
2740
+
2741
+ - Added new public server helpers: context guards (`isActionCtx`/`requireActionCtx`, etc.).
2742
+
2743
+ ## Patched
2744
+
2745
+ - Updated template and docs to use:
2746
+ - `kitcn/auth/client` (`convexClient`)
2747
+ - `kitcn/auth/config` (`getAuthConfigProvider`)
2748
+ - Example app migration now reflects the current user-facing API (`ctx.orm`, `getAuth(ctx)`, simpler `initCRPC.create()`).
2749
+ - cRPC/server error handling now normalizes known causes into deterministic CRPC errors:
2750
+ - `OrmNotFoundError` -> `NOT_FOUND`
2751
+ - `APIError` status/statusCode -> mapped cRPC code
2752
+ - standard `Error.message`/stack preservation on wrapped errors
2753
+ - HTTP route validation errors (params/query/body/form) now return `BAD_REQUEST` consistently.
2754
+ - `createAuthMutations` now throws `AUTH_STATE_TIMEOUT` when auth token never appears after sign-in/up flow.
2755
+ - `getSession` now returns `null` when no session id is present (instead of attempting invalid DB lookups).
2756
+ - CLI reliability improvements (`kitcn dev/codegen/env`): argument parsing and entrypoint resolution are more robust across runtime/symlink setups.
2757
+
2758
+ ```ts
2759
+ // Client import migration
2760
+ // Before
2761
+ import { convexClient } from "@convex-dev/better-auth/client/plugins";
2762
+
2763
+ // After
2764
+ import { convexClient } from "kitcn/auth/client";
2765
+ ```
2766
+
2767
+ ```ts
2768
+ // Retry only non-deterministic errors
2769
+ import { isCRPCError } from "kitcn/crpc";
2770
+
2771
+ retry: (count, error) => !isCRPCError(error) && count < 3;
2772
+ ```
2773
+
2774
+ ## 0.5.8
2775
+
2776
+ ### Patch Changes
2777
+
2778
+ - [#73](https://github.com/udecode/kitcn/pull/73) [`232d126`](https://github.com/udecode/kitcn/commit/232d12697602e5c1cb3965b6e12cfe9b880d3c5c) Thanks [@zbeyens](https://github.com/zbeyens)! - Support multiple WHERE conditions in `update()` for Better Auth organization plugin compatibility.
2779
+ - Multiple AND conditions with equality checks now work
2780
+ - Validates exactly 1 document matches before updating (prevents accidental bulk updates)
2781
+ - OR conditions and non-eq operators still require `updateMany()`
2782
+
2783
+ ## 0.5.7
2784
+
2785
+ ### Patch Changes
2786
+
2787
+ - [#61](https://github.com/udecode/kitcn/pull/61) [`7e63e54`](https://github.com/udecode/kitcn/commit/7e63e541fc2853d8d1d45e4f1fb7db3f82e0592c) Thanks [@zbeyens](https://github.com/zbeyens)! - Auth mutation hooks now properly trigger `onError` when Better Auth returns errors (401, 422, etc.).
2788
+
2789
+ ```tsx
2790
+ // Before: onSuccess always ran, even on errors
2791
+ // After: onError fires on auth failures
2792
+
2793
+ const signUp = useMutation(
2794
+ useSignUpMutationOptions({
2795
+ onSuccess: () => router.push("/"), // Only on success now
2796
+ onError: (error) => toast.error(error.message), // Fires on auth errors
2797
+ })
2798
+ );
2799
+ ```
2800
+
2801
+ New exports: `AuthMutationError` class and `isAuthMutationError` type guard for error handling.
2802
+
2803
+ ## 0.5.6
2804
+
2805
+ ### Patch Changes
2806
+
2807
+ - [`fdeae26`](https://github.com/udecode/kitcn/commit/fdeae26ef81b46dc1334a4940814628d398659d9) Thanks [@zbeyens](https://github.com/zbeyens)! - - Support Convex 1.31.6
2808
+ - Missing `jotai` dependency
2809
+
2810
+ ## 0.5.5
2811
+
2812
+ ### Patch Changes
2813
+
2814
+ - [#56](https://github.com/udecode/kitcn/pull/56) [`b34a396`](https://github.com/udecode/kitcn/commit/b34a39621af83c6b6f2b2e6e11e35997981c5bb4) Thanks [@zbeyens](https://github.com/zbeyens)! - Add `ConvexProviderWithAuth` for `@convex-dev/auth` users (React Native):
2815
+
2816
+ ```tsx
2817
+ import { ConvexProviderWithAuth } from "kitcn/react";
2818
+
2819
+ <ConvexProviderWithAuth client={convex} useAuth={useAuthFromConvexDev}>
2820
+ <App />
2821
+ </ConvexProviderWithAuth>;
2822
+ ```
2823
+
2824
+ Enables `skipUnauth` queries, `useAuth`, and conditional rendering components.
2825
+
2826
+ ## 0.5.4
2827
+
2828
+ ### Patch Changes
2829
+
2830
+ - [#54](https://github.com/udecode/kitcn/pull/54) [`4321118`](https://github.com/udecode/kitcn/commit/43211189285333f998cef34c7726efa1735837aa) Thanks [@zbeyens](https://github.com/zbeyens)! - Support nested file structures in meta generation:
2831
+
2832
+ ```
2833
+ convex/functions/
2834
+ todos.ts → crpc.todos.*
2835
+ items/queries.ts → crpc.items.queries.*
2836
+ ```
2837
+
2838
+ - Organize functions in subdirectories
2839
+ - `_` prefixed files/directories are excluded
2840
+
2841
+ ## 0.5.3
2842
+
2843
+ ### Patch Changes
2844
+
2845
+ - [#44](https://github.com/udecode/kitcn/pull/44) [`ea6bfce`](https://github.com/udecode/kitcn/commit/ea6bfce4fb20dda7afdad4a9d0663aa7021e2a88) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix queries throwing without auth provider.
2846
+
2847
+ ## 0.5.2
2848
+
2849
+ ### Patch Changes
2850
+
2851
+ - [`185f496`](https://github.com/udecode/kitcn/commit/185f496c6b64e70cba96adcfe25e459c8c559a92) Thanks [@zbeyens](https://github.com/zbeyens)! - Add `staticQueryOptions` method to CRPC proxy for non-hook usage in event handlers.
2852
+
2853
+ - [`2288076`](https://github.com/udecode/kitcn/commit/228807652c04df9bdb1e9f054a0664d35a643ff2) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix `MiddlewareBuilder` generic parameter mismatch causing typecheck failures when using reusable middleware with `.use()`. Factory functions now correctly pass through the `TInputOut` parameter added in v0.5.1.
2854
+
2855
+ ## 0.5.1
2856
+
2857
+ ### Patch Changes
2858
+
2859
+ - [#39](https://github.com/udecode/kitcn/pull/39) [`ede0d47`](https://github.com/udecode/kitcn/commit/ede0d473ed8f7254f44b9edb86172cfd3c900857) Thanks [@zbeyens](https://github.com/zbeyens)! - Middleware now receives `input` and `getRawInput` parameters:
2860
+
2861
+ ```ts
2862
+ publicQuery
2863
+ .input(z.object({ projectId: zid("projects") }))
2864
+ .use(async ({ ctx, input, next }) => {
2865
+ // input.projectId is typed!
2866
+ const project = await ctx.db.get(input.projectId);
2867
+ return next({ ctx: { ...ctx, project } });
2868
+ });
2869
+ ```
2870
+
2871
+ - Middleware after `.input()` receives typed input
2872
+ - Middleware before `.input()` receives `unknown`
2873
+ - `getRawInput()` returns raw input before validation
2874
+ - `next({ input })` allows modifying input for downstream middleware
2875
+ - Non-breaking: existing middleware works unchanged
2876
+
2877
+ ## 0.5.0
2878
+
2879
+ ### Minor Changes
2880
+
2881
+ - [#34](https://github.com/udecode/kitcn/pull/34) [`e2a2f62`](https://github.com/udecode/kitcn/commit/e2a2f6258d75007c39b6dc86d6000e0a9460052d) Thanks [@zbeyens](https://github.com/zbeyens)! - URL searchParams now auto-coerce to numbers and booleans based on Zod schema type, eliminating `z.coerce.*` boilerplate:
2882
+
2883
+ ```ts
2884
+ // Before: Required z.coerce.* boilerplate
2885
+ .searchParams(z.object({
2886
+ page: z.coerce.number().optional(),
2887
+ active: z.coerce.boolean().optional(),
2888
+ }))
2889
+
2890
+ // After: Standard Zod schemas work directly
2891
+ .searchParams(z.object({
2892
+ page: z.number().optional(),
2893
+ active: z.boolean().optional(),
2894
+ }))
2895
+ ```
2896
+
2897
+ Coercion behavior:
2898
+
2899
+ - `z.number()` - parses string to number (`"5"` → `5`)
2900
+ - `z.boolean()` - parses `"true"`/`"1"` → `true`, everything else → `false`
2901
+ - Works with `.optional()`, `.nullable()`, `.default()` wrappers
2902
+ - `z.coerce.*` still works if preferred
2903
+
2904
+ ### Vanilla CRPC client
2905
+
2906
+ `useCRPCClient()` now returns a typed proxy for direct procedural calls without React Query:
2907
+
2908
+ ```ts
2909
+ const client = useCRPCClient();
2910
+
2911
+ // Convex functions
2912
+ const user = await client.user.get.query({ id });
2913
+ await client.user.update.mutate({ id, name: "test" });
2914
+
2915
+ // HTTP endpoints
2916
+ const todos = await client.http.todos.list.query();
2917
+ await client.http.todos.create.mutate({ title: "New" });
2918
+ ```
2919
+
2920
+ Useful for event handlers, effects, or when you don't need caching/deduplication.
2921
+
2922
+ **Breaking:** `useCRPCClient()` return type changed from `ConvexReactClient` to typed proxy. Use `useConvex()` (now exported from `kitcn/react`) for raw client access.
2923
+
2924
+ ### Error handling: `isCRPCError` helper
2925
+
2926
+ New unified error check for retry logic - returns true for any deterministic CRPC error (Convex 4xx or HTTP 4xx):
2927
+
2928
+ ```ts
2929
+ import { isCRPCError } from "kitcn/crpc";
2930
+
2931
+ // In query client config
2932
+ retry: (failureCount, error) => {
2933
+ if (isCRPCError(error)) return false; // Don't retry client errors
2934
+ return failureCount < 3;
2935
+ };
2936
+ ```
2937
+
2938
+ ## 0.4.0
2939
+
2940
+ ### Minor Changes
2941
+
2942
+ - [#31](https://github.com/udecode/kitcn/pull/31) [`618ec38`](https://github.com/udecode/kitcn/commit/618ec386eaf7e893d87570616871386953789753) Thanks [@zbeyens](https://github.com/zbeyens)! - ### HTTP Client: Hybrid API
2943
+
2944
+ The HTTP client now uses a hybrid API combining tRPC-style JSON body at root level with explicit `params`/`searchParams` for URL data.
2945
+
2946
+ #### Breaking Changes
2947
+
2948
+ - **Query/mutation args restructured**: Path params and search params now use explicit keys instead of flat merging
2949
+ - Before: `queryOptions({ id: '123', limit: 10 })`
2950
+ - After: `queryOptions({ params: { id: '123' }, searchParams: { limit: '10' } })`
2951
+ - **Client options in args**: `fetch`, `init`, `headers` go in args (1st param)
2952
+ - `queryOptions(args?, queryOpts?)` - args = params/searchParams/form/headers/etc
2953
+ - `mutationOptions(mutationOpts?)` - client opts go in `mutate(args)` call
2954
+ - **Server handler `query` renamed to `searchParams`**: Consistent naming between client and server
2955
+ - Before: `.query(async ({ query }) => { query.limit })`
2956
+ - After: `.query(async ({ searchParams }) => { searchParams.limit })`
2957
+
2958
+ #### New Features
2959
+
2960
+ - **Explicit input args**: `params`, `searchParams` keys for clear separation
2961
+ - **JSON body at root**: Non-reserved keys spread at root level (tRPC-style): `mutate({ title: 'New' })`
2962
+ - **Typed form uploads**: `.form()` builder method for typed FormData schemas (client args + server handler)
2963
+ - **Client options in args**: Per-request `fetch`, `init`, `headers` in args (1st param)
2964
+ - **mutationOptions for GET**: Use `useMutation` for one-time fetches (exports/downloads) without caching
2965
+
2966
+ #### Migration
2967
+
2968
+ ```tsx
2969
+ // Client: Before
2970
+ crpc.http.todos.list.queryOptions({ limit: 10 });
2971
+ updateTodo.mutate({ id, completed: true });
2972
+ deleteTodo.mutate({ id });
2973
+
2974
+ // Client: After
2975
+ crpc.http.todos.list.queryOptions({ searchParams: { limit: "10" } });
2976
+ updateTodo.mutate({ params: { id }, completed: true });
2977
+ deleteTodo.mutate({ params: { id } });
2978
+
2979
+ // Headers go in args (1st param)
2980
+ // Before: queryOptions({ header: { 'X-Custom': 'value' } })
2981
+ // After:
2982
+ crpc.http.todos.list.queryOptions({ headers: { 'X-Custom': 'value' } });
2983
+
2984
+ // Mutations: client opts in mutate args
2985
+ updateTodo.mutate({ params: { id }, completed: true, headers: { 'X-Custom': 'value' } });
2986
+
2987
+ // Server: Before
2988
+ .query(async ({ query }) => ({ limit: query.limit }))
2989
+
2990
+ // Server: After
2991
+ .query(async ({ searchParams }) => ({ limit: searchParams.limit }))
2992
+
2993
+ // Server: Typed form (new)
2994
+ .form(z.object({ file: z.instanceof(Blob) }))
2995
+ .mutation(async ({ form }) => {
2996
+ // form.file is typed as Blob
2997
+ })
2998
+ ```
2999
+
3000
+ ## 0.3.1
3001
+
3002
+ ### Patch Changes
3003
+
3004
+ - [#29](https://github.com/udecode/kitcn/pull/29) [`2638311`](https://github.com/udecode/kitcn/commit/26383112835605dd806151832edfbcd98e1e75b2) Thanks [@zbeyens](https://github.com/zbeyens)! - - Move hono to peerDependencies (type-only imports in package)
3005
+ - Add stale cursor auto-recovery for `useInfiniteQuery` - automatically recovers from stale pagination cursors after WebSocket reconnection without losing scroll position
3006
+
3007
+ ## 0.3.0
3008
+
3009
+ ### Minor Changes
3010
+
3011
+ - [#27](https://github.com/udecode/kitcn/pull/27) [`6309e68`](https://github.com/udecode/kitcn/commit/6309e688b3f92b07877966a6f6f7929f2cb7ade0) Thanks [@zbeyens](https://github.com/zbeyens)! - ### HTTP Router: Hono Integration
3012
+
3013
+ The HTTP router now wraps a Hono app, enabling full middleware support.
3014
+
3015
+ #### New Features
3016
+
3017
+ - **Hono-based routing**: `createHttpRouter(app, router)` accepts a Hono app
3018
+ - **Auth middleware**: `authMiddleware(createAuth)` for Better Auth routes
3019
+ - **Hono context in handlers**: Access `c.json()`, `c.text()`, `c.redirect()`, `c.req`
3020
+ - **Non-JSON response support**
3021
+ - **CLI watch improvements**: Watches `routers/**/*.ts` and `http.ts` for changes
3022
+
3023
+ #### Breaking Changes
3024
+
3025
+ - **Removed `response()` mode**: Return `Response` directly from handler
3026
+ - **Removed per-procedure `cors()`**: Use Hono's `cors()` middleware
3027
+ - **CORS via Hono**: `app.use('/api/*', cors())` instead of router options
3028
+ - **Handler signature**: `{ ctx, c, input, params, query }` - `c` is Hono Context
3029
+
3030
+ #### Migration
3031
+
3032
+ Before:
3033
+
3034
+ ```ts
3035
+ import { registerRoutes } from "kitcn/auth/http";
3036
+ import { registerCRPCRoutes } from "kitcn/server";
3037
+ import { httpRouter } from "convex/server";
3038
+
3039
+ const http = httpRouter();
3040
+
3041
+ registerRoutes(http, createAuth);
3042
+
3043
+ export const appRouter = router({
3044
+ health,
3045
+ todos: todosRouter,
3046
+ });
3047
+
3048
+ registerCRPCRoutes(http, appRouter, {
3049
+ httpAction,
3050
+ cors: {
3051
+ allowedOrigins: [process.env.SITE_URL!],
3052
+ allowCredentials: true,
3053
+ },
3054
+ });
3055
+
3056
+ export default http;
3057
+ ```
3058
+
3059
+ After:
3060
+
3061
+ ```ts
3062
+ import { authMiddleware } from "kitcn/auth/http";
3063
+ import { createHttpRouter } from "kitcn/server";
3064
+ import { Hono } from "hono";
3065
+ import { cors } from "hono/cors";
3066
+
3067
+ const app = new Hono();
3068
+
3069
+ app.use(
3070
+ "/api/*",
3071
+ cors({
3072
+ origin: process.env.SITE_URL!,
3073
+ credentials: true,
3074
+ })
3075
+ );
3076
+
3077
+ app.use(authMiddleware(createAuth));
3078
+
3079
+ export const appRouter = router({
3080
+ health,
3081
+ todos: todosRouter,
3082
+ });
3083
+
3084
+ export default createHttpRouter(app, appRouter);
3085
+ ```
3086
+
3087
+ #### Handler Examples with `c`
3088
+
3089
+ cRPC handlers now receive `c` (Hono Context) for custom responses:
3090
+
3091
+ ```ts
3092
+ // File download with custom headers
3093
+ export const download = authRoute
3094
+ .get("/api/todos/export/:format")
3095
+ .params(z.object({ format: z.enum(["json", "csv"]) }))
3096
+ .query(async ({ ctx, params, c }) => {
3097
+ const todos = await ctx.runQuery(api.todos.list, {});
3098
+
3099
+ c.header(
3100
+ "Content-Disposition",
3101
+ `attachment; filename="todos.${params.format}"`
3102
+ );
3103
+
3104
+ if (params.format === "csv") {
3105
+ return c.text(todos.map((t) => `${t.id},${t.title}`).join("\n"));
3106
+ }
3107
+ return c.json({ todos });
3108
+ });
3109
+
3110
+ // Webhook with signature verification
3111
+ export const webhook = publicRoute
3112
+ .post("/webhooks/stripe")
3113
+ .mutation(async ({ ctx, c }) => {
3114
+ const signature = c.req.header("stripe-signature");
3115
+ if (!signature) throw new CRPCError({ code: "BAD_REQUEST" });
3116
+
3117
+ const body = await c.req.text();
3118
+ await ctx.runMutation(internal.stripe.process, { body, signature });
3119
+
3120
+ return c.text("OK", 200);
3121
+ });
3122
+
3123
+ // Redirect
3124
+ export const redirect = publicRoute
3125
+ .get("/api/old-path")
3126
+ .query(async ({ c }) => c.redirect("/api/new-path", 301));
3127
+ ```
3128
+
3129
+ ## 0.2.1
3130
+
3131
+ ### Patch Changes
3132
+
3133
+ - [#24](https://github.com/udecode/kitcn/pull/24) [`b5555ea`](https://github.com/udecode/kitcn/commit/b5555eac9e67ef06328f5e122ce2d4512f3b3c7f) Thanks [@zbeyens](https://github.com/zbeyens)! - - Fix (`UNAUTHORIZED`) queries failing after switching tabs and returning to the app. The auth token is now preserved during session refetch instead of being cleared.
3134
+ - Fix (`UNAUTHORIZED`) `useSuspenseQuery` failing on initial page load when auth is still loading. WebSocket subscriptions now wait for auth to settle before connecting.
3135
+ - Fix logout setting `isAuthenticated: false` before unsubscribing to prevent query re-subscriptions.
3136
+ - Add missing `dotenv` dependency for CLI.
3137
+
3138
+ ## 0.2.0
3139
+
3140
+ ### Minor Changes
3141
+
3142
+ - [#22](https://github.com/udecode/kitcn/pull/22) [`27d355e`](https://github.com/udecode/kitcn/commit/27d355e4ac067503e00bf534164c6ce2974a8a46) Thanks [@zbeyens](https://github.com/zbeyens)! - **BREAKING:** Refactored `createCRPCContext` and `createServerCRPCProxy` to use options object:
3143
+
3144
+ Before:
3145
+
3146
+ ```ts
3147
+ createCRPCContext(api, meta);
3148
+ createServerCRPCProxy(api, meta);
3149
+ ```
3150
+
3151
+ After:
3152
+
3153
+ ```ts
3154
+ createCRPCContext<Api>({ api, meta, convexSiteUrl });
3155
+ createServerCRPCProxy<Api>({ api, meta });
3156
+ ```
3157
+
3158
+ **BREAKING:** `getServerQueryClientOptions` now requires `convexSiteUrl`:
3159
+
3160
+ ```ts
3161
+ getServerQueryClientOptions({
3162
+ getToken: caller.getToken,
3163
+ convexSiteUrl: env.NEXT_PUBLIC_CONVEX_SITE_URL,
3164
+ });
3165
+ ```
3166
+
3167
+ **Feature:** Added type-safe HTTP routes with tRPC-style client:
3168
+
3169
+ ```ts
3170
+ // 1. Pass httpAction to initCRPC.create()
3171
+ const c = initCRPC.dataModel<DataModel>().create({
3172
+ query, mutation, action, httpAction,
3173
+ });
3174
+ export const publicRoute = c.httpAction;
3175
+ export const authRoute = c.httpAction.use(authMiddleware);
3176
+ export const router = c.router;
3177
+
3178
+ // 2. Define routes with .get()/.post()/.patch()/.delete()
3179
+ export const health = publicRoute
3180
+ .get('/api/health')
3181
+ .output(z.object({ status: z.string() }))
3182
+ .query(async () => ({ status: 'ok' }));
3183
+
3184
+ // 3. Use .params(), .searchParams(), .input() for typed inputs
3185
+ export const todosRouter = router({
3186
+ list: publicRoute.get('/api/todos')
3187
+ .searchParams(z.object({ limit: z.coerce.number().optional() }))
3188
+ .query(...),
3189
+ get: publicRoute.get('/api/todos/:id')
3190
+ .params(z.object({ id: zid('todos') }))
3191
+ .query(...),
3192
+ create: authRoute.post('/api/todos')
3193
+ .input(z.object({ title: z.string() }))
3194
+ .mutation(...),
3195
+ });
3196
+
3197
+ // 4. Register with CORS
3198
+ registerCRPCRoutes(http, appRouter, {
3199
+ httpAction,
3200
+ cors: { allowedOrigins: [process.env.SITE_URL!], allowCredentials: true },
3201
+ });
3202
+
3203
+ // 5. Add to Api type for inference
3204
+ export type Api = WithHttpRouter<typeof api, typeof appRouter>;
3205
+
3206
+ // 6. Client: TanStack Query integration via crpc.http.*
3207
+ const crpc = useCRPC();
3208
+ useSuspenseQuery(crpc.http.todos.list.queryOptions({ limit: 10 }));
3209
+ useMutation(crpc.http.todos.create.mutationOptions());
3210
+ queryClient.invalidateQueries(crpc.http.todos.list.queryFilter());
3211
+
3212
+ // 7. RSC: prefetch helper
3213
+ prefetch(crpc.http.health.queryOptions({}));
3214
+ ```
3215
+
3216
+ **Fix:** Improved authentication in `ConvexAuthProvider`:
3217
+
3218
+ - **FetchAccessTokenContext**: New context passes `fetchAccessToken` through React tree - eliminates race conditions where token wasn't available during render
3219
+ - **Token Expiration Tracking**: Added `expiresAt` field with `decodeJwtExp()` - 60s cache leeway prevents unnecessary token refreshes
3220
+ - **SSR Hydration Fix**: Defensive `isLoading` check prevents UNAUTHORIZED errors when Better Auth briefly returns null during hydration
3221
+ - **Removed HMR persistence**: No more globalThis Symbol storage (`getPersistedToken`/`persistToken`)
3222
+ - **Simplified AuthStore**: Removed `guard` method and `AuthEffect` - state synced via `useConvexAuth()` directly
3223
+
3224
+ ## 0.1.0
3225
+
3226
+ ### Minor Changes
3227
+
3228
+ - [#18](https://github.com/udecode/kitcn/pull/18) [`681e9ba`](https://github.com/udecode/kitcn/commit/681e9bafdeaa62928f15fe9781f944d42ce2d2b4) Thanks [@zbeyens](https://github.com/zbeyens)! - Initial release