kitcn 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/aggregate/index.d.ts +11 -1
  2. package/dist/aggregate/index.js +1 -1
  3. package/dist/auth/generated/index.d.ts +1 -1
  4. package/dist/auth/generated/index.js +1 -1
  5. package/dist/auth/http/index.d.ts +1 -1
  6. package/dist/auth/index.d.ts +4 -4
  7. package/dist/auth/index.js +10 -9
  8. package/dist/auth/nextjs/index.d.ts +2 -2
  9. package/dist/auth/nextjs/index.js +3 -3
  10. package/dist/auth/start/server/index.d.ts +1 -1
  11. package/dist/auth/start/server/index.js +1 -1
  12. package/dist/{builder-CsxVc5xC.js → builder-1Vx-tEnS.js} +3 -3
  13. package/dist/{caller-factory-CWa0ELLD.js → caller-factory-Dd3H7j3V.js} +3 -3
  14. package/dist/{where-clause-compiler-B_H3oio5.d.ts → capabilities-Bem7xvGK.d.ts} +2958 -4145
  15. package/dist/cli.mjs +155 -60
  16. package/dist/{convex-plugin-D8B0oCFq.js → convex-plugin-DfOhBU9g.js} +1 -1
  17. package/dist/{create-schema-orm-B3f2Kc8O.js → create-schema-orm-Bu2JCiBS.js} +1 -1
  18. package/dist/crpc/index.d.ts +3 -3
  19. package/dist/crpc/index.js +4 -4
  20. package/dist/{customFunctions-DxEEO4Dq.js → customFunctions-BbhgdRGl.js} +2 -2
  21. package/dist/definitions-D9vhJ6OV.js +215 -0
  22. package/dist/extensions-DzjCJXYl.js +55 -0
  23. package/dist/filter-expression-Dydt8wS0.js +402 -0
  24. package/dist/{generated-contract-disabled-B-nmd7Ne.d.ts → generated-contract-disabled-BEc4d98x.d.ts} +2 -2
  25. package/dist/{http-types-BoSDAh4Y.d.ts → http-types-90mapMP9.d.ts} +33 -3
  26. package/dist/id-Bibg34Yb.js +37 -0
  27. package/dist/{local-env-yFKub75x.mjs → local-env-Du24tdbp.mjs} +2243 -2113
  28. package/dist/{middleware-Br5zubu7.d.ts → middleware-CE_MC6Gi.d.ts} +1 -1
  29. package/dist/{middleware-DUd1Sj39.js → middleware-cJDRHTRY.js} +1 -1
  30. package/dist/orm/aggregate-index/index.d.ts +20 -0
  31. package/dist/orm/aggregate-index/index.js +2136 -0
  32. package/dist/orm/index.d.ts +5 -4
  33. package/dist/orm/index.js +126 -4292
  34. package/dist/orm/migrations/index.d.ts +3 -0
  35. package/dist/orm/migrations/index.js +506 -0
  36. package/dist/plugins/index.d.ts +1 -1
  37. package/dist/plugins/index.js +1 -1
  38. package/dist/{procedure-caller-DQxnLBS_.js → procedure-caller-DIzXfX2E.js} +2 -2
  39. package/dist/{procedure-name-C55TynK3.d.ts → procedure-name-B09-cf1-.d.ts} +3 -3
  40. package/dist/{query-context-BzihIpnM.js → query-context-DOm5Xm3H.js} +1 -402
  41. package/dist/{query-options-C_eBSIXG.js → query-options-DUiOj01a.js} +33 -1
  42. package/dist/ratelimit/index.d.ts +47 -11
  43. package/dist/ratelimit/index.js +256 -102
  44. package/dist/react/index.d.ts +9 -6
  45. package/dist/react/index.js +36 -17
  46. package/dist/rsc/index.d.ts +6 -9
  47. package/dist/rsc/index.js +7 -11
  48. package/dist/runtime-DfGsZtx3.js +1074 -0
  49. package/dist/schema-Besl-rpv.js +1411 -0
  50. package/dist/server/index.d.ts +4 -4
  51. package/dist/server/index.js +4 -4
  52. package/dist/solid/index.d.ts +9 -6
  53. package/dist/solid/index.js +36 -17
  54. package/dist/{runtime-6DJxpDfb.js → table-rmJm5Qio.js} +3 -1095
  55. package/dist/{token-xlpENMVn.js → token-DcV_0fkF.js} +1 -1
  56. package/dist/{types-C0Xl7P8K.d.ts → types-In-ZZOsd.d.ts} +1 -1
  57. package/dist/{validators-C7LelqTN.js → validators-Dmbhsd3U.js} +1 -1
  58. package/dist/watcher.mjs +1 -1
  59. package/dist/where-clause-compiler-mohWFiG0.d.ts +2042 -0
  60. package/package.json +3 -2
  61. package/skills/kitcn/SKILL.md +19 -18
  62. package/skills/kitcn/references/features/aggregates.md +21 -0
  63. package/skills/kitcn/references/features/auth-organizations.md +3 -3
  64. package/skills/kitcn/references/features/auth-polar.md +2 -1
  65. package/skills/kitcn/references/features/auth.md +8 -1
  66. package/skills/kitcn/references/features/http.md +26 -1
  67. package/skills/kitcn/references/features/ratelimit.md +11 -0
  68. package/skills/kitcn/references/features/react.md +1 -1
  69. package/skills/kitcn/references/setup/auth.md +52 -42
  70. package/skills/kitcn/references/setup/index.md +1 -1
  71. package/skills/kitcn/references/setup/server.md +37 -6
  72. /package/dist/{api-entry-N3nBOlI2.js → api-entry-CkDpGYVg.js} +0 -0
  73. /package/dist/{context-utils-BBUtBqjN.d.ts → context-utils-DwZ3Cam1.d.ts} +0 -0
  74. /package/dist/{create-schema-BXrKE2YY.js → create-schema-BRFjdgRr.js} +0 -0
  75. /package/dist/{error-Bvo7YEhk.js → error-CMLeCadS.js} +0 -0
  76. /package/dist/{generated-contract-disabled-BXaz7JCE.js → generated-contract-disabled-CZa0iyV0.js} +0 -0
  77. /package/dist/{meta-utils-D9K4fICl.js → meta-utils-D2lqN2Lg.js} +0 -0
  78. /package/dist/{query-context-CNo9ffvI.d.ts → query-context-DJONf8X5.d.ts} +0 -0
  79. /package/dist/{token-B9Bjcqug.d.ts → token-kQaqFby4.d.ts} +0 -0
  80. /package/dist/{transformer-yZuBWo8v.js → transformer-D8wO-kEj.js} +0 -0
  81. /package/dist/{types-BCl8gfGy.d.ts → types-Bf3XQex5.d.ts} +0 -0
  82. /package/dist/{types-DF2cg_w0.d.ts → types-MHYXboyy.d.ts} +0 -0
  83. /package/dist/{types-CnTpHR1F.d.ts → types-eNzQmbqM.d.ts} +0 -0
  84. /package/dist/{upstream-BR6sBLg3.js → upstream-BCgGZX6q.js} +0 -0
  85. /package/dist/{validators-BhsByJeg.d.ts → validators-V4eM2-Jg.d.ts} +0 -0
@@ -1,406 +1,5 @@
1
1
  import { compareValues, convexToJson, jsonToConvex } from "convex/values";
2
2
 
3
- //#region src/orm/filter-expression.ts
4
- /**
5
- * Unique symbol for FilterExpression brand
6
- * Prevents structural typing - only expressions created by factory functions are valid
7
- */
8
- const FilterExpressionBrand = Symbol("FilterExpression");
9
- /**
10
- * Create a field reference
11
- * Used internally by operator functions
12
- */
13
- function fieldRef(fieldName) {
14
- return {
15
- __brand: "FieldReference",
16
- fieldName
17
- };
18
- }
19
- /**
20
- * Type guard for FieldReference
21
- */
22
- function isFieldReference(value) {
23
- return value && typeof value === "object" && value.__brand === "FieldReference";
24
- }
25
- /**
26
- * The pattern is the same for every row of a scan while the value is not, so
27
- * only the value genuinely has to be split per call. A small bounded cache
28
- * keeps the split pattern across rows without unbounded growth on
29
- * caller-supplied patterns; a query with a handful of LIKE filters still hits
30
- * on every row.
31
- */
32
- const LIKE_PATTERN_CACHE_MAX = 16;
33
- const likePatternCache = /* @__PURE__ */ new Map();
34
- function likePatternCodePoints(pattern, caseInsensitive) {
35
- const key = caseInsensitive ? `i:${pattern}` : `s:${pattern}`;
36
- const cached = likePatternCache.get(key);
37
- if (cached) return cached;
38
- const source = Array.from(caseInsensitive ? pattern.toLowerCase() : pattern);
39
- if (likePatternCache.size >= LIKE_PATTERN_CACHE_MAX) for (const oldest of likePatternCache.keys()) {
40
- likePatternCache.delete(oldest);
41
- break;
42
- }
43
- likePatternCache.set(key, source);
44
- return source;
45
- }
46
- /**
47
- * SQL `LIKE` semantics: `%` matches any run of characters, `_` matches exactly
48
- * one, everything else is literal. Wildcards work anywhere in the pattern, not
49
- * only at the ends.
50
- *
51
- * Matched with a single-backtrack scan rather than a compiled regex. A pattern
52
- * is caller data — anything interpolated into `` `%${query}%` `` reaches here —
53
- * and translating `%` to a regex quantifier makes `'%%%%%z'` backtrack
54
- * exponentially, which would burn the whole Convex function CPU budget on one
55
- * row. This scan remembers only the most recent `%`, so the worst case is
56
- * O(value * pattern) with no catastrophic case at all.
57
- */
58
- function matchLikePattern(value, pattern, caseInsensitive) {
59
- const target = Array.from(caseInsensitive ? value.toLowerCase() : value);
60
- const source = likePatternCodePoints(pattern, caseInsensitive);
61
- let valueIndex = 0;
62
- let patternIndex = 0;
63
- let wildcardPatternIndex = -1;
64
- let wildcardValueIndex = 0;
65
- while (valueIndex < target.length) {
66
- const patternChar = patternIndex < source.length ? source[patternIndex] : void 0;
67
- if (patternChar === "_" || patternChar === target[valueIndex]) {
68
- valueIndex += 1;
69
- patternIndex += 1;
70
- } else if (patternChar === "%") {
71
- wildcardPatternIndex = patternIndex;
72
- wildcardValueIndex = valueIndex;
73
- patternIndex += 1;
74
- } else if (wildcardPatternIndex === -1) return false;
75
- else {
76
- wildcardValueIndex += 1;
77
- valueIndex = wildcardValueIndex;
78
- patternIndex = wildcardPatternIndex + 1;
79
- }
80
- }
81
- while (patternIndex < source.length && source[patternIndex] === "%") patternIndex += 1;
82
- return patternIndex === source.length;
83
- }
84
- /**
85
- * Structural equality matching Convex's own `q.eq`. Arrays, objects and bytes
86
- * are compared by content: reference identity would make every `eq`/`in` filter
87
- * on a `custom(v.array(...))` / `custom(v.object(...))` column match nothing.
88
- */
89
- function filterValuesEqual(a, b) {
90
- if (a === b) return true;
91
- if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
92
- if (Array.isArray(a) || Array.isArray(b)) {
93
- if (!(Array.isArray(a) && Array.isArray(b)) || a.length !== b.length) return false;
94
- return a.every((item, index) => filterValuesEqual(item, b[index]));
95
- }
96
- if (a instanceof ArrayBuffer || b instanceof ArrayBuffer) {
97
- if (!(a instanceof ArrayBuffer && b instanceof ArrayBuffer) || a.byteLength !== b.byteLength) return false;
98
- const left = new Uint8Array(a);
99
- const right = new Uint8Array(b);
100
- return left.every((byte, index) => byte === right[index]);
101
- }
102
- const aKeys = Object.keys(a);
103
- const bKeys = Object.keys(b);
104
- if (aKeys.length !== bKeys.length) return false;
105
- return aKeys.every((key) => Object.hasOwn(b, key) && filterValuesEqual(a[key], b[key]));
106
- }
107
- /** `inArray`/`notInArray` membership using {@link filterValuesEqual}. */
108
- function filterValueInList(value, list) {
109
- return list.some((candidate) => filterValuesEqual(candidate, value));
110
- }
111
- /**
112
- * Create a column wrapper
113
- * Used internally by query builder's _createColumnProxies
114
- */
115
- function column(builder, columnName) {
116
- return {
117
- builder,
118
- columnName
119
- };
120
- }
121
- function resolveColumn(col) {
122
- if (col && typeof col === "object" && "columnName" in col) return col;
123
- if (isFieldReference(col)) return {
124
- builder: col,
125
- columnName: col.fieldName
126
- };
127
- const builder = col;
128
- const columnName = builder?.config?.name;
129
- if (!columnName) throw new Error("Column builder is missing a column name");
130
- return column(builder, columnName);
131
- }
132
- /**
133
- * Internal binary expression implementation
134
- * Private class - only accessible via factory functions
135
- */
136
- var BinaryExpressionImpl = class {
137
- [FilterExpressionBrand] = true;
138
- type = "binary";
139
- constructor(operator, operands) {
140
- this.operator = operator;
141
- this.operands = operands;
142
- }
143
- accept(visitor) {
144
- return visitor.visitBinary(this);
145
- }
146
- };
147
- /**
148
- * Internal logical expression implementation
149
- * Private class - only accessible via factory functions
150
- */
151
- var LogicalExpressionImpl = class {
152
- [FilterExpressionBrand] = true;
153
- type = "logical";
154
- constructor(operator, operands) {
155
- this.operator = operator;
156
- this.operands = operands;
157
- }
158
- accept(visitor) {
159
- return visitor.visitLogical(this);
160
- }
161
- };
162
- /**
163
- * Internal unary expression implementation
164
- * Private class - only accessible via factory functions
165
- */
166
- var UnaryExpressionImpl = class {
167
- [FilterExpressionBrand] = true;
168
- type = "unary";
169
- constructor(operator, operands) {
170
- this.operator = operator;
171
- this.operands = operands;
172
- }
173
- accept(visitor) {
174
- return visitor.visitUnary(this);
175
- }
176
- };
177
- /**
178
- * Equality operator: field == value
179
- *
180
- * @example
181
- * const filter = eq(cols.name, 'Alice');
182
- */
183
- function eq(col, value) {
184
- return new BinaryExpressionImpl("eq", [fieldRef(resolveColumn(col).columnName), value]);
185
- }
186
- /**
187
- * Not equal operator: field != value
188
- */
189
- function ne(col, value) {
190
- return new BinaryExpressionImpl("ne", [fieldRef(resolveColumn(col).columnName), value]);
191
- }
192
- /**
193
- * Greater than operator: field > value
194
- */
195
- function gt(col, value) {
196
- return new BinaryExpressionImpl("gt", [fieldRef(resolveColumn(col).columnName), value]);
197
- }
198
- /**
199
- * Greater than or equal operator: field >= value
200
- */
201
- function gte(col, value) {
202
- return new BinaryExpressionImpl("gte", [fieldRef(resolveColumn(col).columnName), value]);
203
- }
204
- /**
205
- * Less than operator: field < value
206
- */
207
- function lt(col, value) {
208
- return new BinaryExpressionImpl("lt", [fieldRef(resolveColumn(col).columnName), value]);
209
- }
210
- /**
211
- * Less than or equal operator: field <= value
212
- */
213
- function lte(col, value) {
214
- return new BinaryExpressionImpl("lte", [fieldRef(resolveColumn(col).columnName), value]);
215
- }
216
- /**
217
- * Between operator: field BETWEEN min AND max (inclusive)
218
- *
219
- * Sugar for and(gte(field, min), lte(field, max)).
220
- */
221
- function between(col, min, max) {
222
- return and(gte(col, min), lte(col, max));
223
- }
224
- /**
225
- * Not between operator: field < min OR field > max
226
- *
227
- * Sugar for or(lt(field, min), gt(field, max)).
228
- */
229
- function notBetween(col, min, max) {
230
- return or(lt(col, min), gt(col, max));
231
- }
232
- /**
233
- * LIKE operator: SQL-style pattern matching with % wildcards
234
- * Note: Implemented as post-filter (Convex has no native LIKE)
235
- *
236
- * @example
237
- * const users = await db.query.users.findMany({
238
- * where: like(users.name, '%alice%'),
239
- * });
240
- */
241
- function like(col, pattern) {
242
- return new BinaryExpressionImpl("like", [fieldRef(resolveColumn(col).columnName), pattern]);
243
- }
244
- /**
245
- * ILIKE operator: Case-insensitive LIKE
246
- * Note: Implemented as post-filter (Convex has no native LIKE)
247
- *
248
- * @example
249
- * const users = await db.query.users.findMany({
250
- * where: ilike(users.name, '%ALICE%'),
251
- * });
252
- */
253
- function ilike(col, pattern) {
254
- return new BinaryExpressionImpl("ilike", [fieldRef(resolveColumn(col).columnName), pattern]);
255
- }
256
- /**
257
- * NOT LIKE operator: Negated LIKE pattern
258
- */
259
- function notLike(col, pattern) {
260
- return new BinaryExpressionImpl("notLike", [fieldRef(resolveColumn(col).columnName), pattern]);
261
- }
262
- /**
263
- * NOT ILIKE operator: Negated case-insensitive LIKE
264
- */
265
- function notIlike(col, pattern) {
266
- return new BinaryExpressionImpl("notIlike", [fieldRef(resolveColumn(col).columnName), pattern]);
267
- }
268
- /**
269
- * startsWith operator: Check if string starts with prefix
270
- * Optimized for prefix matching
271
- *
272
- * @example
273
- * const users = await db.query.users.findMany({
274
- * where: startsWith(users.email, 'admin@'),
275
- * });
276
- */
277
- function startsWith(col, prefix) {
278
- return new BinaryExpressionImpl("startsWith", [fieldRef(resolveColumn(col).columnName), prefix]);
279
- }
280
- /**
281
- * endsWith operator: Check if string ends with suffix
282
- *
283
- * @example
284
- * const users = await db.query.users.findMany({
285
- * where: endsWith(users.email, '@example.com'),
286
- * });
287
- */
288
- function endsWith(col, suffix) {
289
- return new BinaryExpressionImpl("endsWith", [fieldRef(resolveColumn(col).columnName), suffix]);
290
- }
291
- /**
292
- * contains operator: Check if string contains substring
293
- * Can use search index for optimization when available
294
- *
295
- * @example
296
- * const posts = await db.query.posts.findMany({
297
- * where: contains(posts.title, 'javascript'),
298
- * });
299
- */
300
- function contains(col, substring) {
301
- return new BinaryExpressionImpl("contains", [fieldRef(resolveColumn(col).columnName), substring]);
302
- }
303
- /**
304
- * Logical AND: all expressions must be true
305
- * Filters out undefined expressions (following Drizzle pattern)
306
- *
307
- * @example
308
- * const filter = and(
309
- * eq(fieldRef('age'), 25),
310
- * eq(fieldRef('name'), 'Alice')
311
- * );
312
- */
313
- function and(...expressions) {
314
- const defined = expressions.filter((expr) => expr !== void 0);
315
- if (defined.length === 0) return;
316
- if (defined.length === 1) return defined[0];
317
- return new LogicalExpressionImpl("and", defined);
318
- }
319
- /**
320
- * Logical OR: at least one expression must be true
321
- * Filters out undefined expressions (following Drizzle pattern)
322
- *
323
- * @example
324
- * const filter = or(
325
- * eq(fieldRef('status'), 'active'),
326
- * eq(fieldRef('status'), 'pending')
327
- * );
328
- */
329
- function or(...expressions) {
330
- const defined = expressions.filter((expr) => expr !== void 0);
331
- if (defined.length === 0) return;
332
- if (defined.length === 1) return defined[0];
333
- return new LogicalExpressionImpl("or", defined);
334
- }
335
- /**
336
- * Logical NOT: negates expression
337
- *
338
- * @example
339
- * const filter = not(eq(fieldRef('isDeleted'), true));
340
- */
341
- function not(expression) {
342
- return new UnaryExpressionImpl("not", [expression]);
343
- }
344
- /**
345
- * Array membership operator: field IN array
346
- *
347
- * @example
348
- * const filter = inArray(cols.status, ['active', 'pending']);
349
- */
350
- function inArray(col, values) {
351
- return new BinaryExpressionImpl("inArray", [fieldRef(resolveColumn(col).columnName), values]);
352
- }
353
- /**
354
- * Array exclusion operator: field NOT IN array
355
- * Validates array is non-empty at construction time
356
- *
357
- * @example
358
- * const filter = notInArray(cols.role, ['admin', 'moderator']);
359
- */
360
- function notInArray(col, values) {
361
- if (!Array.isArray(values) || values.length === 0) throw new Error("notInArray requires a non-empty array of values");
362
- return new BinaryExpressionImpl("notInArray", [fieldRef(resolveColumn(col).columnName), values]);
363
- }
364
- /**
365
- * Array contains operator: field @> array
366
- */
367
- function arrayContains(col, values) {
368
- return new BinaryExpressionImpl("arrayContains", [fieldRef(resolveColumn(col).columnName), values]);
369
- }
370
- /**
371
- * Array contained operator: field <@ array
372
- */
373
- function arrayContained(col, values) {
374
- return new BinaryExpressionImpl("arrayContained", [fieldRef(resolveColumn(col).columnName), values]);
375
- }
376
- /**
377
- * Array overlaps operator: field && array
378
- */
379
- function arrayOverlaps(col, values) {
380
- return new BinaryExpressionImpl("arrayOverlaps", [fieldRef(resolveColumn(col).columnName), values]);
381
- }
382
- /**
383
- * Null check operator: field IS NULL
384
- * Type validation: Only works with nullable fields
385
- *
386
- * @example
387
- * const filter = isNull(cols.deletedAt);
388
- */
389
- function isNull(col) {
390
- return new UnaryExpressionImpl("isNull", [fieldRef(resolveColumn(col).columnName)]);
391
- }
392
- /**
393
- * Not null check operator: field IS NOT NULL
394
- * Type validation: Only works with nullable fields
395
- *
396
- * @example
397
- * const filter = isNotNull(cols.deletedAt);
398
- */
399
- function isNotNull(col) {
400
- return new UnaryExpressionImpl("isNotNull", [fieldRef(resolveColumn(col).columnName)]);
401
- }
402
-
403
- //#endregion
404
3
  //#region src/orm/unset-token.ts
405
4
  const unsetToken = Symbol.for("kitcn/orm/unsetToken");
406
5
  function isUnsetToken(value) {
@@ -1743,4 +1342,4 @@ async function getByIdWithOrmQueryFallback(ctx, tableName, id) {
1743
1342
  }
1744
1343
 
1745
1344
  //#endregion
1746
- export { like as A, or as B, gt as C, isFieldReference as D, inArray as E, not as F, notBetween as I, notIlike as L, lte as M, matchLikePattern as N, isNotNull as O, ne as P, notInArray as R, filterValuesEqual as S, ilike as T, startsWith as V, contains as _, indexKeyWithinBounds as a, fieldRef as b, streamIndexRange as c, and as d, arrayContained as f, column as g, between as h, getIndexFields as i, lt as j, isNull as k, isUnsetToken as l, arrayOverlaps as m, EmptyStream as n, mergedStream as o, arrayContains as p, QueryStream as r, stream as s, getByIdWithOrmQueryFallback as t, unsetToken as u, endsWith as v, gte as w, filterValueInList as x, eq as y, notLike as z };
1345
+ export { indexKeyWithinBounds as a, streamIndexRange as c, getIndexFields as i, isUnsetToken as l, EmptyStream as n, mergedStream as o, QueryStream as r, stream as s, getByIdWithOrmQueryFallback as t, unsetToken as u };
@@ -1,6 +1,38 @@
1
1
  import { getFunctionName } from "convex/server";
2
2
 
3
3
  //#region src/crpc/http-types.ts
4
+ /**
5
+ * Build the exact cache key for an HTTP route.
6
+ *
7
+ * Missing args normalize to `{}` so the RSC prefetch, the browser observer, and
8
+ * a hand-written `getQueryData` call all hash to the same key. Every producer
9
+ * of an `httpQuery` cache key goes through here.
10
+ */
11
+ function buildHttpQueryKey(routeKey, args) {
12
+ return [
13
+ "httpQuery",
14
+ routeKey,
15
+ args ?? {}
16
+ ];
17
+ }
18
+ /**
19
+ * Build the route-wide prefix key.
20
+ *
21
+ * Filters match on prefix, so this matches every args variant of the route.
22
+ * Not a cache key: nothing is ever stored under it.
23
+ */
24
+ function buildHttpQueryPrefixKey(routeKey) {
25
+ return ["httpQuery", routeKey];
26
+ }
27
+ /**
28
+ * Freshness window for `crpc.http.*` routes, in milliseconds.
29
+ *
30
+ * HTTP routes are a pull model with no push channel, so hydrated data needs a
31
+ * real freshness window or the browser refetches it on mount. The RSC
32
+ * QueryClient reads the same constant, so the server dedupe window and the
33
+ * client freshness window cannot drift apart.
34
+ */
35
+ const HTTP_DEFAULT_STALE_TIME = 3e4;
4
36
  /** HTTP client error */
5
37
  var HttpClientError = class extends Error {
6
38
  name = "HttpClientError";
@@ -244,4 +276,4 @@ function convexInfiniteQueryOptions(funcRef, args, opts = {}, meta) {
244
276
  }
245
277
 
246
278
  //#endregion
247
- export { buildSearchParams as a, HttpClientError as c, RESERVED_KEYS as i, isHttpClientError as l, convexInfiniteQueryOptions as n, executeHttpRequest as o, convexQuery as r, replaceUrlParam as s, convexAction as t };
279
+ export { buildSearchParams as a, HTTP_DEFAULT_STALE_TIME as c, buildHttpQueryPrefixKey as d, isHttpClientError as f, RESERVED_KEYS as i, HttpClientError as l, convexInfiniteQueryOptions as n, executeHttpRequest as o, convexQuery as r, replaceUrlParam as s, convexAction as t, buildHttpQueryKey as u };
@@ -1,5 +1,5 @@
1
- import { o as MiddlewareBuilder } from "../types-CnTpHR1F.js";
2
- import { t as Plugin } from "../middleware-Br5zubu7.js";
1
+ import { o as MiddlewareBuilder } from "../types-eNzQmbqM.js";
2
+ import { t as Plugin } from "../middleware-CE_MC6Gi.js";
3
3
  import * as convex_server0 from "convex/server";
4
4
 
5
5
  //#region src/ratelimit/duration.d.ts
@@ -127,6 +127,7 @@ type ConvexQueryBuilder = {
127
127
  withIndex: (name: any, cb: any) => {
128
128
  unique: () => Promise<any>;
129
129
  collect: () => Promise<any[]>;
130
+ take: (limit: number) => Promise<any[]>;
130
131
  };
131
132
  };
132
133
  type ConvexRatelimitDbReader = {
@@ -176,17 +177,36 @@ declare function calculateRatelimit(state: RatelimitState | null, algorithm: Res
176
177
  */
177
178
  declare function snapshotToState(snapshot: RatelimitSnapshot): RatelimitState;
178
179
  //#endregion
180
+ //#region src/ratelimit/maintenance.d.ts
181
+ type CleanupRatelimitStateOptions = {
182
+ before: number;
183
+ limit?: number;
184
+ };
185
+ type CleanupRatelimitStateResult = {
186
+ deleted: number;
187
+ hasMore: boolean;
188
+ };
189
+ /** Deletes one on-demand batch of state older than the caller-owned cutoff. */
190
+ declare function cleanupRatelimitState(db: ConvexRatelimitDbWriter, options: CleanupRatelimitStateOptions): Promise<CleanupRatelimitStateResult>;
191
+ //#endregion
179
192
  //#region src/ratelimit/plugin.d.ts
180
193
  type MaybePromise<T> = T | Promise<T>;
181
194
  type RatelimitBuckets = Record<string, Record<string, ResolvedAlgorithm>>;
182
195
  type BucketName<TBuckets extends RatelimitBuckets> = Extract<keyof TBuckets, string>;
183
196
  type TierName<TBuckets extends RatelimitBuckets> = Extract<keyof TBuckets[BucketName<TBuckets>], string>;
184
- type RatelimitResolvedArgs<TCtx, TMeta extends object, TUser, TBuckets extends RatelimitBuckets> = {
197
+ /** What is known before request signals are resolved. */
198
+ type RatelimitRequestArgs<TCtx, TMeta extends object, TUser, TBuckets extends RatelimitBuckets> = {
185
199
  ctx: TCtx;
186
200
  meta: TMeta;
187
201
  user: TUser;
188
202
  bucket: BucketName<TBuckets>;
189
203
  tier: TierName<TBuckets>;
204
+ };
205
+ /** Signals are resolved once per request and reused as the identifier input. */
206
+ type RatelimitIdentifierArgs<TCtx, TMeta extends object, TUser, TBuckets extends RatelimitBuckets> = RatelimitRequestArgs<TCtx, TMeta, TUser, TBuckets> & {
207
+ signals: LimitRequest | undefined;
208
+ };
209
+ type RatelimitResolvedArgs<TCtx, TMeta extends object, TUser, TBuckets extends RatelimitBuckets> = RatelimitIdentifierArgs<TCtx, TMeta, TUser, TBuckets> & {
190
210
  identifier: string;
191
211
  };
192
212
  type RatelimitPluginOptions<TCtx = unknown, TMeta extends object = object, TUser = unknown, TBuckets extends RatelimitBuckets = RatelimitBuckets> = {
@@ -199,18 +219,34 @@ type RatelimitPluginOptions<TCtx = unknown, TMeta extends object = object, TUser
199
219
  ctx: TCtx;
200
220
  meta: TMeta;
201
221
  }) => MaybePromise<TUser>;
202
- getIdentifier: (args: {
203
- ctx: TCtx;
204
- meta: TMeta;
205
- user: TUser;
206
- bucket: BucketName<TBuckets>;
207
- }) => MaybePromise<string>;
208
222
  getTier: (user: TUser) => MaybePromise<TierName<TBuckets>>;
209
- getSignals: (args: RatelimitResolvedArgs<TCtx, TMeta, TUser, TBuckets>) => MaybePromise<LimitRequest | undefined>;
223
+ /**
224
+ * Resolved once per request, before `getIdentifier`, and reused for the limit
225
+ * call. Read request metadata here rather than in `getIdentifier`, so a
226
+ * guarded mutation pays at most one `ctx.meta.getRequestMetadata()` syscall.
227
+ */
228
+ getSignals: (args: RatelimitRequestArgs<TCtx, TMeta, TUser, TBuckets>) => MaybePromise<LimitRequest | undefined>;
229
+ /**
230
+ * The rate-limit partition key. Everything sharing a value shares one budget
231
+ * and one `ratelimitState` document, so key unauthenticated traffic by
232
+ * `signals.ip` rather than a constant.
233
+ */
234
+ getIdentifier: (args: RatelimitIdentifierArgs<TCtx, TMeta, TUser, TBuckets>) => MaybePromise<string>;
210
235
  prefix?: string | ((args: RatelimitResolvedArgs<TCtx, TMeta, TUser, TBuckets>) => MaybePromise<string>);
211
236
  failureMode?: 'closed' | 'open';
212
237
  enableProtection?: boolean;
213
238
  denyListThreshold?: number;
239
+ denyList?: RatelimitConfig['denyList'];
240
+ dynamicLimits?: boolean;
241
+ timeout?: number;
242
+ /**
243
+ * Block cache backing store. The plugin builds one `Ratelimit` per guarded
244
+ * mutation, so the default per-instance cache never outlives a request. Pass
245
+ * a longer-lived `Map` only if you accept that a stale block can deny a
246
+ * request a refilled shard could have served, and that a mutation replayed
247
+ * after an OCC conflict can observe entries its first attempt wrote.
248
+ */
249
+ ephemeralCache?: RatelimitConfig['ephemeralCache'];
214
250
  message?: string | ((args: RatelimitResolvedArgs<TCtx, TMeta, TUser, TBuckets>) => MaybePromise<string>);
215
251
  };
216
252
  type AnyRatelimitPluginOptions = RatelimitPluginOptions<any, any, any, any>;
@@ -285,4 +321,4 @@ declare const HOUR: number;
285
321
  declare const DAY: number;
286
322
  declare const WEEK: number;
287
323
  //#endregion
288
- export { type CheckRequest, type ConvexQueryBuilder, type ConvexRatelimitDbReader, type ConvexRatelimitDbWriter, DAY, type Duration, type DurationString, type DurationUnit, type DynamicLimitResponse, type EvaluationResult, type FixedWindowAlgorithm, HOUR, type HookAPIOptions, type HookCheckValue, type LimitRequest, MINUTE, RATE_LIMIT_DYNAMIC_TABLE, RATE_LIMIT_HIT_TABLE, RATE_LIMIT_STATE_TABLE, Ratelimit, type RatelimitConfig, RatelimitPlugin, type RatelimitPluginOptions, type RatelimitReason, type RatelimitResponse, type RatelimitRow, type RatelimitShardState, type RatelimitSnapshot, type RatelimitState, type RatelimitStoredState, type RemainingResponse, type ResolvedAlgorithm, SECOND, type SlidingWindowAlgorithm, type TokenBucketAlgorithm, WEEK, applyDynamicLimit, calculateRatelimit, fixedWindow, slidingWindow, snapshotToState, toMs, tokenBucket };
324
+ export { type CheckRequest, type CleanupRatelimitStateOptions, type CleanupRatelimitStateResult, type ConvexQueryBuilder, type ConvexRatelimitDbReader, type ConvexRatelimitDbWriter, DAY, type Duration, type DurationString, type DurationUnit, type DynamicLimitResponse, type EvaluationResult, type FixedWindowAlgorithm, HOUR, type HookAPIOptions, type HookCheckValue, type LimitRequest, MINUTE, RATE_LIMIT_DYNAMIC_TABLE, RATE_LIMIT_HIT_TABLE, RATE_LIMIT_STATE_TABLE, Ratelimit, type RatelimitConfig, RatelimitPlugin, type RatelimitPluginOptions, type RatelimitReason, type RatelimitResponse, type RatelimitRow, type RatelimitShardState, type RatelimitSnapshot, type RatelimitState, type RatelimitStoredState, type RemainingResponse, type ResolvedAlgorithm, SECOND, type SlidingWindowAlgorithm, type TokenBucketAlgorithm, WEEK, applyDynamicLimit, calculateRatelimit, cleanupRatelimitState, fixedWindow, slidingWindow, snapshotToState, toMs, tokenBucket };