convex 1.36.0 → 1.37.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 (240) hide show
  1. package/CHANGELOG.md +50 -27
  2. package/dist/browser.bundle.js +1 -1
  3. package/dist/browser.bundle.js.map +1 -1
  4. package/dist/cjs/cli/codegen_templates/agentsmd.js +8 -2
  5. package/dist/cjs/cli/codegen_templates/agentsmd.js.map +2 -2
  6. package/dist/cjs/cli/codegen_templates/claudemd.js +2 -0
  7. package/dist/cjs/cli/codegen_templates/claudemd.js.map +2 -2
  8. package/dist/cjs/cli/configure.js +0 -8
  9. package/dist/cjs/cli/configure.js.map +2 -2
  10. package/dist/cjs/cli/deployment.js +2 -1
  11. package/dist/cjs/cli/deployment.js.map +2 -2
  12. package/dist/cjs/cli/deploymentToken.js +30 -0
  13. package/dist/cjs/cli/deploymentToken.js.map +7 -0
  14. package/dist/cjs/cli/deploymentTokenCreate.js +109 -0
  15. package/dist/cjs/cli/deploymentTokenCreate.js.map +7 -0
  16. package/dist/cjs/cli/deploymentTokenDelete.js +87 -0
  17. package/dist/cjs/cli/deploymentTokenDelete.js.map +7 -0
  18. package/dist/cjs/cli/envDefault.js +130 -41
  19. package/dist/cjs/cli/envDefault.js.map +3 -3
  20. package/dist/cjs/cli/generatedApi.js.map +1 -1
  21. package/dist/cjs/cli/lib/command.js +1 -1
  22. package/dist/cjs/cli/lib/command.js.map +1 -1
  23. package/dist/cjs/cli/lib/generatedFunctionLogsApi.js.map +1 -1
  24. package/dist/cjs/cli/lib/login.js +51 -0
  25. package/dist/cjs/cli/lib/login.js.map +3 -3
  26. package/dist/cjs/cli/lib/usage.js +13 -6
  27. package/dist/cjs/cli/lib/usage.js.map +2 -2
  28. package/dist/cjs/cli/lib/workos/environmentApi.js +6 -12
  29. package/dist/cjs/cli/lib/workos/environmentApi.js.map +3 -3
  30. package/dist/cjs/index.js +1 -1
  31. package/dist/cjs/index.js.map +1 -1
  32. package/dist/cjs/react/client.js +40 -42
  33. package/dist/cjs/react/client.js.map +2 -2
  34. package/dist/cjs/react/index.js +1 -0
  35. package/dist/cjs/react/index.js.map +2 -2
  36. package/dist/cjs/react/use_paginated_query.js +5 -46
  37. package/dist/cjs/react/use_paginated_query.js.map +2 -2
  38. package/dist/cjs/react/use_paginated_query2.js.map +2 -2
  39. package/dist/cjs/server/audit_logging.js +67 -0
  40. package/dist/cjs/server/audit_logging.js.map +7 -0
  41. package/dist/cjs/server/impl/meta_impl.js +27 -3
  42. package/dist/cjs/server/impl/meta_impl.js.map +2 -2
  43. package/dist/cjs/server/impl/registration_impl.js +2 -0
  44. package/dist/cjs/server/impl/registration_impl.js.map +2 -2
  45. package/dist/cjs/server/index.js +2 -0
  46. package/dist/cjs/server/index.js.map +2 -2
  47. package/dist/cjs/server/log.js +30 -0
  48. package/dist/cjs/server/log.js.map +7 -0
  49. package/dist/cjs/server/logVars.js +48 -0
  50. package/dist/cjs/server/logVars.js.map +7 -0
  51. package/dist/cjs/server/meta.js.map +1 -1
  52. package/dist/cjs/server/registration.js.map +1 -1
  53. package/dist/cjs-types/cli/codegen_templates/agentsmd.d.ts.map +1 -1
  54. package/dist/cjs-types/cli/codegen_templates/claudemd.d.ts.map +1 -1
  55. package/dist/cjs-types/cli/configure.d.ts.map +1 -1
  56. package/dist/cjs-types/cli/deployment.d.ts.map +1 -1
  57. package/dist/cjs-types/cli/deploymentToken.d.ts +3 -0
  58. package/dist/cjs-types/cli/deploymentToken.d.ts.map +1 -0
  59. package/dist/cjs-types/cli/deploymentToken.test.d.ts +2 -0
  60. package/dist/cjs-types/cli/deploymentToken.test.d.ts.map +1 -0
  61. package/dist/cjs-types/cli/deploymentTokenCreate.d.ts +13 -0
  62. package/dist/cjs-types/cli/deploymentTokenCreate.d.ts.map +1 -0
  63. package/dist/cjs-types/cli/deploymentTokenDelete.d.ts +11 -0
  64. package/dist/cjs-types/cli/deploymentTokenDelete.d.ts.map +1 -0
  65. package/dist/cjs-types/cli/envDefault.d.ts +2 -2
  66. package/dist/cjs-types/cli/envDefault.d.ts.map +1 -1
  67. package/dist/cjs-types/cli/envDefault.test.d.ts +2 -0
  68. package/dist/cjs-types/cli/envDefault.test.d.ts.map +1 -0
  69. package/dist/cjs-types/cli/generatedApi.d.ts +1 -1
  70. package/dist/cjs-types/cli/generatedApi.d.ts.map +1 -1
  71. package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts +1 -0
  72. package/dist/cjs-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
  73. package/dist/cjs-types/cli/lib/login.d.ts.map +1 -1
  74. package/dist/cjs-types/cli/lib/usage.d.ts.map +1 -1
  75. package/dist/cjs-types/cli/lib/workos/environmentApi.d.ts.map +1 -1
  76. package/dist/cjs-types/cli/lib/workos/environmentApi.test.d.ts +2 -0
  77. package/dist/cjs-types/cli/lib/workos/environmentApi.test.d.ts.map +1 -0
  78. package/dist/cjs-types/index.d.ts +1 -1
  79. package/dist/cjs-types/react/client.d.ts +52 -0
  80. package/dist/cjs-types/react/client.d.ts.map +1 -1
  81. package/dist/cjs-types/react/index.d.ts +2 -2
  82. package/dist/cjs-types/react/index.d.ts.map +1 -1
  83. package/dist/cjs-types/react/use_paginated_query.d.ts.map +1 -1
  84. package/dist/cjs-types/react/use_paginated_query2.d.ts +63 -1
  85. package/dist/cjs-types/react/use_paginated_query2.d.ts.map +1 -1
  86. package/dist/cjs-types/server/api.intersect.test.d.ts +2 -0
  87. package/dist/cjs-types/server/api.intersect.test.d.ts.map +1 -0
  88. package/dist/cjs-types/server/audit_logging.d.ts +19 -0
  89. package/dist/cjs-types/server/audit_logging.d.ts.map +1 -0
  90. package/dist/cjs-types/server/audit_logging.test.d.ts +2 -0
  91. package/dist/cjs-types/server/audit_logging.test.d.ts.map +1 -0
  92. package/dist/cjs-types/server/impl/meta_impl.d.ts.map +1 -1
  93. package/dist/cjs-types/server/impl/registration_impl.d.ts.map +1 -1
  94. package/dist/cjs-types/server/index.d.ts +2 -2
  95. package/dist/cjs-types/server/index.d.ts.map +1 -1
  96. package/dist/cjs-types/server/log.d.ts +2 -0
  97. package/dist/cjs-types/server/log.d.ts.map +1 -0
  98. package/dist/cjs-types/server/logVars.d.ts +20 -0
  99. package/dist/cjs-types/server/logVars.d.ts.map +1 -0
  100. package/dist/cjs-types/server/meta.d.ts +40 -0
  101. package/dist/cjs-types/server/meta.d.ts.map +1 -1
  102. package/dist/cjs-types/server/registration.d.ts +5 -2
  103. package/dist/cjs-types/server/registration.d.ts.map +1 -1
  104. package/dist/cli.bundle.cjs +362 -74
  105. package/dist/cli.bundle.cjs.map +4 -4
  106. package/dist/esm/cli/codegen_templates/agentsmd.js +8 -2
  107. package/dist/esm/cli/codegen_templates/agentsmd.js.map +2 -2
  108. package/dist/esm/cli/codegen_templates/claudemd.js +2 -0
  109. package/dist/esm/cli/codegen_templates/claudemd.js.map +2 -2
  110. package/dist/esm/cli/configure.js +0 -8
  111. package/dist/esm/cli/configure.js.map +2 -2
  112. package/dist/esm/cli/deployment.js +2 -1
  113. package/dist/esm/cli/deployment.js.map +2 -2
  114. package/dist/esm/cli/deploymentToken.js +8 -0
  115. package/dist/esm/cli/deploymentToken.js.map +7 -0
  116. package/dist/esm/cli/deploymentTokenCreate.js +91 -0
  117. package/dist/esm/cli/deploymentTokenCreate.js.map +7 -0
  118. package/dist/esm/cli/deploymentTokenDelete.js +68 -0
  119. package/dist/esm/cli/deploymentTokenDelete.js.map +7 -0
  120. package/dist/esm/cli/envDefault.js +131 -42
  121. package/dist/esm/cli/envDefault.js.map +3 -3
  122. package/dist/esm/cli/lib/command.js +1 -1
  123. package/dist/esm/cli/lib/command.js.map +1 -1
  124. package/dist/esm/cli/lib/login.js +52 -0
  125. package/dist/esm/cli/lib/login.js.map +3 -3
  126. package/dist/esm/cli/lib/usage.js +15 -8
  127. package/dist/esm/cli/lib/usage.js.map +2 -2
  128. package/dist/esm/cli/lib/workos/environmentApi.js +6 -12
  129. package/dist/esm/cli/lib/workos/environmentApi.js.map +3 -3
  130. package/dist/esm/index.js +1 -1
  131. package/dist/esm/index.js.map +1 -1
  132. package/dist/esm/react/client.js +38 -41
  133. package/dist/esm/react/client.js.map +2 -2
  134. package/dist/esm/react/index.js +4 -1
  135. package/dist/esm/react/index.js.map +2 -2
  136. package/dist/esm/react/use_paginated_query.js +5 -46
  137. package/dist/esm/react/use_paginated_query.js.map +2 -2
  138. package/dist/esm/react/use_paginated_query2.js.map +2 -2
  139. package/dist/esm/server/audit_logging.js +44 -0
  140. package/dist/esm/server/audit_logging.js.map +7 -0
  141. package/dist/esm/server/impl/meta_impl.js +27 -3
  142. package/dist/esm/server/impl/meta_impl.js.map +2 -2
  143. package/dist/esm/server/impl/registration_impl.js +2 -0
  144. package/dist/esm/server/impl/registration_impl.js.map +2 -2
  145. package/dist/esm/server/index.js +1 -0
  146. package/dist/esm/server/index.js.map +2 -2
  147. package/dist/esm/server/log.js +8 -0
  148. package/dist/esm/server/log.js.map +7 -0
  149. package/dist/esm/server/logVars.js +25 -0
  150. package/dist/esm/server/logVars.js.map +7 -0
  151. package/dist/esm-types/cli/codegen_templates/agentsmd.d.ts.map +1 -1
  152. package/dist/esm-types/cli/codegen_templates/claudemd.d.ts.map +1 -1
  153. package/dist/esm-types/cli/configure.d.ts.map +1 -1
  154. package/dist/esm-types/cli/deployment.d.ts.map +1 -1
  155. package/dist/esm-types/cli/deploymentToken.d.ts +3 -0
  156. package/dist/esm-types/cli/deploymentToken.d.ts.map +1 -0
  157. package/dist/esm-types/cli/deploymentToken.test.d.ts +2 -0
  158. package/dist/esm-types/cli/deploymentToken.test.d.ts.map +1 -0
  159. package/dist/esm-types/cli/deploymentTokenCreate.d.ts +13 -0
  160. package/dist/esm-types/cli/deploymentTokenCreate.d.ts.map +1 -0
  161. package/dist/esm-types/cli/deploymentTokenDelete.d.ts +11 -0
  162. package/dist/esm-types/cli/deploymentTokenDelete.d.ts.map +1 -0
  163. package/dist/esm-types/cli/envDefault.d.ts +2 -2
  164. package/dist/esm-types/cli/envDefault.d.ts.map +1 -1
  165. package/dist/esm-types/cli/envDefault.test.d.ts +2 -0
  166. package/dist/esm-types/cli/envDefault.test.d.ts.map +1 -0
  167. package/dist/esm-types/cli/generatedApi.d.ts +1 -1
  168. package/dist/esm-types/cli/generatedApi.d.ts.map +1 -1
  169. package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts +1 -0
  170. package/dist/esm-types/cli/lib/generatedFunctionLogsApi.d.ts.map +1 -1
  171. package/dist/esm-types/cli/lib/login.d.ts.map +1 -1
  172. package/dist/esm-types/cli/lib/usage.d.ts.map +1 -1
  173. package/dist/esm-types/cli/lib/workos/environmentApi.d.ts.map +1 -1
  174. package/dist/esm-types/cli/lib/workos/environmentApi.test.d.ts +2 -0
  175. package/dist/esm-types/cli/lib/workos/environmentApi.test.d.ts.map +1 -0
  176. package/dist/esm-types/index.d.ts +1 -1
  177. package/dist/esm-types/react/client.d.ts +52 -0
  178. package/dist/esm-types/react/client.d.ts.map +1 -1
  179. package/dist/esm-types/react/index.d.ts +2 -2
  180. package/dist/esm-types/react/index.d.ts.map +1 -1
  181. package/dist/esm-types/react/use_paginated_query.d.ts.map +1 -1
  182. package/dist/esm-types/react/use_paginated_query2.d.ts +63 -1
  183. package/dist/esm-types/react/use_paginated_query2.d.ts.map +1 -1
  184. package/dist/esm-types/server/api.intersect.test.d.ts +2 -0
  185. package/dist/esm-types/server/api.intersect.test.d.ts.map +1 -0
  186. package/dist/esm-types/server/audit_logging.d.ts +19 -0
  187. package/dist/esm-types/server/audit_logging.d.ts.map +1 -0
  188. package/dist/esm-types/server/audit_logging.test.d.ts +2 -0
  189. package/dist/esm-types/server/audit_logging.test.d.ts.map +1 -0
  190. package/dist/esm-types/server/impl/meta_impl.d.ts.map +1 -1
  191. package/dist/esm-types/server/impl/registration_impl.d.ts.map +1 -1
  192. package/dist/esm-types/server/index.d.ts +2 -2
  193. package/dist/esm-types/server/index.d.ts.map +1 -1
  194. package/dist/esm-types/server/log.d.ts +2 -0
  195. package/dist/esm-types/server/log.d.ts.map +1 -0
  196. package/dist/esm-types/server/logVars.d.ts +20 -0
  197. package/dist/esm-types/server/logVars.d.ts.map +1 -0
  198. package/dist/esm-types/server/meta.d.ts +40 -0
  199. package/dist/esm-types/server/meta.d.ts.map +1 -1
  200. package/dist/esm-types/server/registration.d.ts +5 -2
  201. package/dist/esm-types/server/registration.d.ts.map +1 -1
  202. package/dist/react.bundle.js +45 -88
  203. package/dist/react.bundle.js.map +2 -2
  204. package/package.json +4 -4
  205. package/src/cli/codegen_templates/agentsmd.ts +8 -2
  206. package/src/cli/codegen_templates/claudemd.ts +2 -0
  207. package/src/cli/configure.ts +0 -9
  208. package/src/cli/deployment.ts +3 -1
  209. package/src/cli/deploymentToken.test.ts +372 -0
  210. package/src/cli/deploymentToken.ts +11 -0
  211. package/src/cli/deploymentTokenCreate.ts +113 -0
  212. package/src/cli/deploymentTokenDelete.ts +91 -0
  213. package/src/cli/envDefault.test.ts +495 -0
  214. package/src/cli/envDefault.ts +222 -107
  215. package/src/cli/generatedApi.ts +1 -1
  216. package/src/cli/lib/command.ts +1 -1
  217. package/src/cli/lib/generatedFunctionLogsApi.ts +1 -0
  218. package/src/cli/lib/login.ts +67 -0
  219. package/src/cli/lib/usage.ts +18 -8
  220. package/src/cli/lib/workos/environmentApi.test.ts +107 -0
  221. package/src/cli/lib/workos/environmentApi.ts +12 -19
  222. package/src/index.ts +1 -1
  223. package/src/react/client.test.tsx +10 -8
  224. package/src/react/client.ts +88 -96
  225. package/src/react/index.ts +6 -1
  226. package/src/react/use_paginated_query.test.tsx +215 -132
  227. package/src/react/use_paginated_query.ts +8 -142
  228. package/src/react/use_paginated_query2.ts +78 -5
  229. package/src/react/use_query_object_options.test.ts +8 -7
  230. package/src/react/use_query_result.test.ts +40 -7
  231. package/src/server/api.intersect.test.ts +109 -0
  232. package/src/server/audit_logging.test.ts +129 -0
  233. package/src/server/audit_logging.ts +75 -0
  234. package/src/server/impl/meta_impl.ts +28 -0
  235. package/src/server/impl/registration_impl.ts +2 -0
  236. package/src/server/index.ts +12 -0
  237. package/src/server/log.ts +16 -0
  238. package/src/server/logVars.ts +34 -0
  239. package/src/server/meta.ts +53 -1
  240. package/src/server/registration.ts +10 -8
@@ -22,9 +22,9 @@ import type {
22
22
  PaginatedQueryArgs,
23
23
  PaginatedQueryItem,
24
24
  PaginatedQueryReference,
25
- UsePaginatedQueryObjectReturnType,
26
25
  UsePaginatedQueryReturnType,
27
26
  } from "./use_paginated_query.js";
27
+ import type { UsePaginatedQueryObjectReturnType } from "./use_paginated_query2.js";
28
28
  import {
29
29
  resetPaginationId,
30
30
  usePaginatedQuery,
@@ -76,7 +76,9 @@ describe.each([
76
76
  version: "client-based logic" as const,
77
77
  },
78
78
  ] as {
79
- usePaginatedQuery: typeof usePaginatedQuery;
79
+ usePaginatedQuery:
80
+ | typeof usePaginatedQuery
81
+ | typeof usePaginatedQuery_experimental;
80
82
  resetPaginationId: typeof resetPaginationId;
81
83
  version: "hook-based logic" | "client-based logic";
82
84
  }[])(
@@ -161,67 +163,6 @@ describe.each([
161
163
  });
162
164
  }
163
165
 
164
- test("Object options default to non-throwing error state", () => {
165
- if (version === "client-based logic") {
166
- return;
167
- }
168
- const convexClient = new ConvexReactClient(address);
169
- resetPaginationId();
170
- const wrapper = ({ children }: { children: React.ReactNode }) => (
171
- <ConvexProvider client={convexClient}>{children}</ConvexProvider>
172
- );
173
-
174
- const { result } = renderHook(
175
- () =>
176
- usePaginatedQuery({
177
- query: makeFunctionReference<"query">("myQuery"),
178
- args: {},
179
- initialNumItems: 10,
180
- }),
181
- { wrapper },
182
- );
183
-
184
- pushFirstPageError(convexClient, "boom-default");
185
-
186
- if (result.current.status !== "error") {
187
- throw new Error("Expected error status");
188
- }
189
- expect(result.current.error.message).toBe("boom-default");
190
- expect(result.current.isLoading).toBe(false);
191
- expect(result.current.canLoadMore).toBe(false);
192
- expect(result.current.data).toEqual([]);
193
- });
194
-
195
- test("Object options throw when throwOnError is true", () => {
196
- if (version === "client-based logic") {
197
- return;
198
- }
199
- const convexClient = new ConvexReactClient(address);
200
- resetPaginationId();
201
- let lastError: Error | undefined;
202
- const wrapper = ({ children }: { children: React.ReactNode }) => (
203
- <ErrorBoundary onError={(e) => (lastError = e)}>
204
- <ConvexProvider client={convexClient}>{children}</ConvexProvider>
205
- </ErrorBoundary>
206
- );
207
-
208
- renderHook(
209
- () =>
210
- usePaginatedQuery({
211
- query: makeFunctionReference<"query">("myQuery"),
212
- args: {},
213
- initialNumItems: 10,
214
- throwOnError: true,
215
- }),
216
- { wrapper },
217
- );
218
-
219
- pushFirstPageError(convexClient, "boom-throw");
220
-
221
- expect(lastError).toBeDefined();
222
- expect(lastError?.message).toBe("boom-throw");
223
- });
224
-
225
166
  test("Positional form continues throwing on errors", () => {
226
167
  if (version === "client-based logic") {
227
168
  return;
@@ -279,75 +220,6 @@ describe.each([
279
220
  });
280
221
  });
281
222
 
282
- test("Returns nothing when object-form args are 'skip'", () => {
283
- const convexClient = new ConvexReactClient(address);
284
- // The experimental path subscribes through watchPaginatedQuery directly,
285
- // while the original implementation still goes through watchQuery.
286
- const subscriptionSpy =
287
- version === "hook-based logic"
288
- ? vi.spyOn(convexClient, "watchQuery")
289
- : vi.spyOn(convexClient, "watchPaginatedQuery");
290
- const wrapper = ({ children }: { children: React.ReactNode }) => (
291
- <ConvexProvider client={convexClient}>{children}</ConvexProvider>
292
- );
293
-
294
- const { result } = renderHook(
295
- () =>
296
- usePaginatedQuery({
297
- query: makeFunctionReference<"query">("myQuery"),
298
- args: "skip",
299
- initialNumItems: 10,
300
- }),
301
- { wrapper },
302
- );
303
-
304
- expect(subscriptionSpy.mock.calls).toEqual([]);
305
- expect(result.current).toMatchObject({
306
- isLoading: true,
307
- data: undefined,
308
- status: "pending",
309
- canLoadMore: false,
310
- });
311
- });
312
-
313
- test("Initially returns pending for object options", () => {
314
- const convexClient = new ConvexReactClient(address);
315
- const watchQuerySpy = vi.spyOn(convexClient, "watchQuery");
316
- const wrapper = ({ children }: { children: React.ReactNode }) => (
317
- <ConvexProvider client={convexClient}>{children}</ConvexProvider>
318
- );
319
-
320
- const { result } = renderHook(
321
- () =>
322
- usePaginatedQuery({
323
- query: makeFunctionReference<"query">("myQuery"),
324
- args: {},
325
- initialNumItems: 10,
326
- }),
327
- { wrapper },
328
- );
329
-
330
- if (version === "hook-based logic") {
331
- expect(watchQuerySpy.mock.calls[1]).toEqual([
332
- makeFunctionReference("myQuery"),
333
- {
334
- paginationOpts: {
335
- cursor: null,
336
- id: expect.anything(),
337
- numItems: 10,
338
- },
339
- },
340
- { journal: undefined },
341
- ]);
342
- }
343
- expect(result.current).toMatchObject({
344
- isLoading: true,
345
- data: undefined,
346
- status: "pending",
347
- canLoadMore: false,
348
- });
349
- });
350
-
351
223
  test("Initially returns LoadingFirstPage", () => {
352
224
  const convexClient = new ConvexReactClient(address);
353
225
  const watchQuerySpy = vi.spyOn(convexClient, "watchQuery");
@@ -1335,3 +1207,214 @@ describe.each([
1335
1207
  });
1336
1208
  },
1337
1209
  );
1210
+
1211
+ describe("usePaginatedQuery_experimental object form", () => {
1212
+ test("Returns nothing when object-form args are 'skip'", () => {
1213
+ const convexClient = new ConvexReactClient(address);
1214
+ const subscriptionSpy = vi.spyOn(convexClient, "watchPaginatedQuery");
1215
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
1216
+ <ConvexProvider client={convexClient}>{children}</ConvexProvider>
1217
+ );
1218
+
1219
+ const { result } = renderHook(
1220
+ () =>
1221
+ usePaginatedQuery_experimental({
1222
+ query: makeFunctionReference<"query">("myQuery"),
1223
+ args: "skip",
1224
+ initialNumItems: 10,
1225
+ }),
1226
+ { wrapper },
1227
+ );
1228
+
1229
+ expect(subscriptionSpy.mock.calls).toEqual([]);
1230
+ expect(result.current).toMatchObject({
1231
+ isLoading: true,
1232
+ data: undefined,
1233
+ status: "pending",
1234
+ canLoadMore: false,
1235
+ });
1236
+ });
1237
+
1238
+ test("Initially returns pending for object options", () => {
1239
+ const convexClient = new ConvexReactClient(address);
1240
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
1241
+ <ConvexProvider client={convexClient}>{children}</ConvexProvider>
1242
+ );
1243
+
1244
+ const { result } = renderHook(
1245
+ () =>
1246
+ usePaginatedQuery_experimental({
1247
+ query: makeFunctionReference<"query">("myQuery"),
1248
+ args: {},
1249
+ initialNumItems: 10,
1250
+ }),
1251
+ { wrapper },
1252
+ );
1253
+
1254
+ expect(result.current).toMatchObject({
1255
+ isLoading: true,
1256
+ data: undefined,
1257
+ status: "pending",
1258
+ canLoadMore: false,
1259
+ });
1260
+ });
1261
+
1262
+ describe("object form with data", () => {
1263
+ let client: ConvexReactClient;
1264
+ const query: FunctionReference<"query"> = makeFunctionReference("myQuery");
1265
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
1266
+ <ConvexProvider client={client}>{children}</ConvexProvider>
1267
+ );
1268
+
1269
+ const mockPage = (
1270
+ opts: PaginationOptions,
1271
+ retval: PaginationResult<unknown>,
1272
+ ) => {
1273
+ act(() => {
1274
+ void client.mutation(
1275
+ anyApi.myMutation.default,
1276
+ {},
1277
+ {
1278
+ optimisticUpdate: (localStore) => {
1279
+ localStore.setQuery(
1280
+ anyApi.myQuery.default,
1281
+ {
1282
+ paginationOpts: { ...opts, id: 1 },
1283
+ },
1284
+ retval,
1285
+ );
1286
+ },
1287
+ },
1288
+ );
1289
+ });
1290
+ };
1291
+
1292
+ beforeEach(() => {
1293
+ client = new ConvexReactClient(address);
1294
+ resetPaginatedId2();
1295
+ });
1296
+
1297
+ test("returns success with data for a single exhausted page", () => {
1298
+ const { result } = renderHook(
1299
+ () =>
1300
+ usePaginatedQuery_experimental({
1301
+ query,
1302
+ args: {},
1303
+ initialNumItems: 5,
1304
+ }),
1305
+ { wrapper },
1306
+ );
1307
+
1308
+ expect(result.current.status).toBe("pending");
1309
+
1310
+ mockPage(
1311
+ { numItems: 5, cursor: null },
1312
+ { page: ["a", "b", "c"], continueCursor: "end", isDone: true },
1313
+ );
1314
+
1315
+ expect(result.current).toMatchObject({
1316
+ status: "success",
1317
+ data: ["a", "b", "c"],
1318
+ canLoadMore: false,
1319
+ isLoading: false,
1320
+ error: undefined,
1321
+ });
1322
+ });
1323
+
1324
+ test("returns success with canLoadMore true when more pages exist", () => {
1325
+ const { result } = renderHook(
1326
+ () =>
1327
+ usePaginatedQuery_experimental({
1328
+ query,
1329
+ args: {},
1330
+ initialNumItems: 2,
1331
+ }),
1332
+ { wrapper },
1333
+ );
1334
+
1335
+ mockPage(
1336
+ { numItems: 2, cursor: null },
1337
+ { page: ["item1", "item2"], continueCursor: "cur1", isDone: false },
1338
+ );
1339
+
1340
+ expect(result.current).toMatchObject({
1341
+ status: "success",
1342
+ data: ["item1", "item2"],
1343
+ canLoadMore: true,
1344
+ isLoading: false,
1345
+ error: undefined,
1346
+ });
1347
+ });
1348
+
1349
+ test("loadMore appends data and transitions to exhausted", () => {
1350
+ const { result } = renderHook(
1351
+ () =>
1352
+ usePaginatedQuery_experimental({
1353
+ query,
1354
+ args: {},
1355
+ initialNumItems: 1,
1356
+ }),
1357
+ { wrapper },
1358
+ );
1359
+
1360
+ mockPage(
1361
+ { numItems: 1, cursor: null },
1362
+ { page: ["first"], continueCursor: "abc", isDone: false },
1363
+ );
1364
+
1365
+ expect(result.current).toMatchObject({
1366
+ status: "success",
1367
+ data: ["first"],
1368
+ canLoadMore: true,
1369
+ });
1370
+
1371
+ mockPage(
1372
+ { numItems: 2, cursor: "abc" },
1373
+ { page: ["second"], continueCursor: "def", isDone: true },
1374
+ );
1375
+ act(() => {
1376
+ result.current.loadMore(2);
1377
+ });
1378
+
1379
+ expect(result.current).toMatchObject({
1380
+ status: "success",
1381
+ data: ["first", "second"],
1382
+ canLoadMore: false,
1383
+ isLoading: false,
1384
+ });
1385
+ });
1386
+
1387
+ test("page updates reflect in data", () => {
1388
+ const { result } = renderHook(
1389
+ () =>
1390
+ usePaginatedQuery_experimental({
1391
+ query,
1392
+ args: {},
1393
+ initialNumItems: 5,
1394
+ }),
1395
+ { wrapper },
1396
+ );
1397
+
1398
+ mockPage(
1399
+ { numItems: 5, cursor: null },
1400
+ { page: ["old"], continueCursor: "c1", isDone: true },
1401
+ );
1402
+
1403
+ expect(result.current).toMatchObject({
1404
+ status: "success",
1405
+ data: ["old"],
1406
+ });
1407
+
1408
+ mockPage(
1409
+ { numItems: 5, cursor: null },
1410
+ { page: ["new1", "new2"], continueCursor: "c2", isDone: true },
1411
+ );
1412
+
1413
+ expect(result.current).toMatchObject({
1414
+ status: "success",
1415
+ data: ["new1", "new2"],
1416
+ canLoadMore: false,
1417
+ });
1418
+ });
1419
+ });
1420
+ });
@@ -35,23 +35,6 @@ export type PaginatedQueryReference = FunctionReference<
35
35
  PaginationResult<any>
36
36
  >;
37
37
 
38
- /**
39
- * Options for object-form {@link usePaginatedQuery}.
40
- *
41
- * @internal
42
- */
43
- export type UsePaginatedQueryOptions<Query extends PaginatedQueryReference> = {
44
- query: Query;
45
- args: PaginatedQueryArgs<Query> | "skip";
46
- initialNumItems: number;
47
- /**
48
- * When `true` (default for positional form), errors are thrown and caught
49
- * by an error boundary. When `false` (default for object form), errors are
50
- * returned as `{ status: "Error", error: Error }` instead of being thrown.
51
- */
52
- throwOnError?: boolean;
53
- };
54
-
55
38
  // Incrementing integer for each page queried in the usePaginatedQuery hook.
56
39
  type QueryPageKey = number;
57
40
 
@@ -182,56 +165,18 @@ export function usePaginatedQuery<Query extends PaginatedQueryReference>(
182
165
  options: { initialNumItems: number },
183
166
  ): UsePaginatedQueryReturnType<Query>;
184
167
 
185
- /**
186
- * Load data reactively from a paginated query using an options object.
187
- *
188
- * @param options - Object-form options for the paginated query.
189
- * @returns An object with `data`, `status`, `canLoadMore`, `isLoading`,
190
- * `error`, and `loadMore`. `status` is `"pending"` while loading,
191
- * `"success"` when data is available, or `"error"` if the query threw.
192
- * `canLoadMore` is `true` only when idle and more pages exist.
193
- *
194
- * @internal
195
- */
196
- export function usePaginatedQuery<Query extends PaginatedQueryReference>(
197
- options: UsePaginatedQueryOptions<Query>,
198
- ): UsePaginatedQueryObjectReturnType<Query>;
199
-
200
168
  export function usePaginatedQuery<Query extends PaginatedQueryReference>(
201
- queryOrOptions: Query | UsePaginatedQueryOptions<Query>,
202
- args?: PaginatedQueryArgs<Query> | "skip",
203
- options?: { initialNumItems: number },
204
- ):
205
- | UsePaginatedQueryReturnType<Query>
206
- | UsePaginatedQueryObjectReturnType<Query> {
207
- const isObjectOptions =
208
- typeof queryOrOptions === "object" &&
209
- queryOrOptions !== null &&
210
- "query" in queryOrOptions;
211
-
212
- const query = isObjectOptions ? queryOrOptions.query : queryOrOptions;
213
- const queryArgs = isObjectOptions ? queryOrOptions.args : args;
214
- const throwOnError = isObjectOptions
215
- ? (queryOrOptions.throwOnError ?? false)
216
- : true;
217
- const initialOptions = isObjectOptions
218
- ? { initialNumItems: queryOrOptions.initialNumItems }
219
- : options;
220
-
169
+ query: Query,
170
+ args: PaginatedQueryArgs<Query> | "skip",
171
+ options: { initialNumItems: number },
172
+ ): UsePaginatedQueryReturnType<Query> {
221
173
  const { user: positionalResult } = usePaginatedQueryInternal(
222
174
  query,
223
- queryArgs as PaginatedQueryArgs<Query> | "skip",
224
- initialOptions as { initialNumItems: number },
225
- throwOnError,
175
+ args,
176
+ options,
177
+ true,
226
178
  );
227
-
228
- if (!isObjectOptions) {
229
- return positionalResult as unknown as UsePaginatedQueryReturnType<Query>;
230
- }
231
-
232
- return reshapeToObjectForm(
233
- positionalResult,
234
- ) as unknown as UsePaginatedQueryObjectReturnType<Query>;
179
+ return positionalResult as unknown as UsePaginatedQueryReturnType<Query>;
235
180
  }
236
181
 
237
182
  /** @internal */
@@ -504,48 +449,6 @@ export function usePaginatedQueryInternal<
504
449
  };
505
450
  }
506
451
 
507
- /**
508
- * Reshape the internal TitleCase pagination result into the object-form
509
- * return type with lowercase `status`, `canLoadMore`, and `data`.
510
- */
511
- function reshapeToObjectForm<Item>(
512
- internal: UsePaginatedQueryInternalResult<Item>,
513
- ) {
514
- const { results, loadMore } = internal;
515
- if (internal.status === "Error" && "error" in internal) {
516
- return {
517
- data: results,
518
- status: "error" as const,
519
- canLoadMore: false as const,
520
- isLoading: false as const,
521
- error: internal.error,
522
- loadMore,
523
- };
524
- }
525
- if (
526
- internal.status === "LoadingFirstPage" ||
527
- internal.status === "LoadingMore"
528
- ) {
529
- return {
530
- data: internal.status === "LoadingFirstPage" ? undefined : results,
531
- status: "pending" as const,
532
- canLoadMore: false as const,
533
- isLoading: true as const,
534
- error: undefined,
535
- loadMore,
536
- };
537
- }
538
- // CanLoadMore or Exhausted
539
- return {
540
- data: results,
541
- status: "success" as const,
542
- canLoadMore: internal.status === "CanLoadMore",
543
- isLoading: false as const,
544
- error: undefined,
545
- loadMore,
546
- };
547
- }
548
-
549
452
  let paginationId = 0;
550
453
  /**
551
454
  * Generate a new, unique ID for a pagination session.
@@ -669,43 +572,6 @@ export type PaginatedQueryItem<Query extends PaginatedQueryReference> =
669
572
  export type UsePaginatedQueryReturnType<Query extends PaginatedQueryReference> =
670
573
  UsePaginatedQueryResult<PaginatedQueryItem<Query>>;
671
574
 
672
- /**
673
- * Return type of the object-form {@link usePaginatedQuery} overload.
674
- *
675
- * Uses lowercase query status (`"pending" | "success" | "error"`) and a
676
- * `canLoadMore` boolean instead of the TitleCase pagination status strings
677
- * used by the positional form.
678
- *
679
- * @internal
680
- */
681
- export type UsePaginatedQueryObjectReturnType<
682
- Query extends PaginatedQueryReference,
683
- > =
684
- | {
685
- data: PaginatedQueryItem<Query>[] | undefined;
686
- status: "pending";
687
- canLoadMore: false;
688
- isLoading: true;
689
- error: undefined;
690
- loadMore: (numItems: number) => void;
691
- }
692
- | {
693
- data: PaginatedQueryItem<Query>[];
694
- status: "success";
695
- canLoadMore: boolean;
696
- isLoading: false;
697
- error: undefined;
698
- loadMore: (numItems: number) => void;
699
- }
700
- | {
701
- data: PaginatedQueryItem<Query>[];
702
- status: "error";
703
- canLoadMore: false;
704
- isLoading: false;
705
- error: Error;
706
- loadMore: (numItems: number) => void;
707
- };
708
-
709
575
  /**
710
576
  * Optimistically update the values in a paginated list.
711
577
  *
@@ -4,9 +4,8 @@ import { FunctionReference, getFunctionName } from "../server/api.js";
4
4
  import {
5
5
  PaginatedQueryReference,
6
6
  PaginatedQueryArgs,
7
- UsePaginatedQueryOptions,
7
+ PaginatedQueryItem,
8
8
  UsePaginatedQueryReturnType,
9
- UsePaginatedQueryObjectReturnType,
10
9
  } from "./use_paginated_query.js";
11
10
  import { convexToJson, Value } from "../values/value.js";
12
11
  import { useQueries } from "./use_queries.js";
@@ -15,6 +14,66 @@ import { SubscribeToPaginatedQueryOptions } from "../browser/sync/paginated_quer
15
14
  import { ConvexError } from "../values/errors.js";
16
15
  import { useConvex } from "./client.js";
17
16
 
17
+ /**
18
+ * Options for object-form {@link usePaginatedQuery_experimental}.
19
+ *
20
+ * @public
21
+ */
22
+ export type UsePaginatedQueryOptions<
23
+ Query extends PaginatedQueryReference,
24
+ ThrowOnError extends boolean = false,
25
+ > = {
26
+ query: Query;
27
+ args: PaginatedQueryArgs<Query> | "skip";
28
+ initialNumItems: number;
29
+ /**
30
+ * When `true` (default for positional form), errors are thrown and caught
31
+ * by an error boundary. When `false` (default for object form), errors are
32
+ * returned as `{ status: "Error", error: Error }` instead of being thrown.
33
+ */
34
+ throwOnError?: ThrowOnError;
35
+ };
36
+
37
+ /**
38
+ * Return type of the object-form {@link usePaginatedQuery_experimental} overload.
39
+ *
40
+ * Uses lowercase query status (`"pending" | "success" | "error"`) and a
41
+ * `canLoadMore` boolean instead of the TitleCase pagination status strings
42
+ * used by the positional form.
43
+ *
44
+ * @public
45
+ */
46
+ export type UsePaginatedQueryObjectReturnType<
47
+ Query extends PaginatedQueryReference,
48
+ ThrowOnError extends boolean = false,
49
+ > =
50
+ | {
51
+ data: PaginatedQueryItem<Query>[] | undefined;
52
+ status: "pending";
53
+ canLoadMore: false;
54
+ isLoading: true;
55
+ error: undefined;
56
+ loadMore: (numItems: number) => void;
57
+ }
58
+ | {
59
+ data: PaginatedQueryItem<Query>[];
60
+ status: "success";
61
+ canLoadMore: boolean;
62
+ isLoading: false;
63
+ error: undefined;
64
+ loadMore: (numItems: number) => void;
65
+ }
66
+ | (ThrowOnError extends true
67
+ ? never
68
+ : {
69
+ data: PaginatedQueryItem<Query>[];
70
+ status: "error";
71
+ canLoadMore: false;
72
+ isLoading: false;
73
+ error: Error;
74
+ loadMore: (numItems: number) => void;
75
+ });
76
+
18
77
  type UsePaginatedQueryState = {
19
78
  query: FunctionReference<"query">;
20
79
  args: Record<string, Value>;
@@ -83,12 +142,26 @@ export function usePaginatedQuery_experimental<
83
142
  options: { initialNumItems: number },
84
143
  ): UsePaginatedQueryReturnType<Query>;
85
144
 
86
- /** @internal */
145
+ /**
146
+ * Experimental new usePaginatedQuery implementation that accepts an options object
147
+ * rather than positional arguments.
148
+ *
149
+ * @param options - A {@link UsePaginatedQueryOptions} object including `query` and `args`.
150
+ * @returns A {@link UsePaginatedQueryObjectReturnType} object with `data`, `status`,
151
+ * `canLoadMore`, `isLoading`, `error`, and `loadMore`. `status` is `"pending"` while
152
+ * loading, `"success"` when data is available, or `"error"` if the query threw.
153
+ * When `throwOnError` is `true`, the `"error"` status is excluded from the return
154
+ * type since errors will be thrown instead.
155
+ * `canLoadMore` is `true` only when idle and more pages exist.
156
+ *
157
+ * @public
158
+ */
87
159
  export function usePaginatedQuery_experimental<
88
160
  Query extends PaginatedQueryReference,
161
+ ThrowOnError extends boolean = false,
89
162
  >(
90
- options: UsePaginatedQueryOptions<Query>,
91
- ): UsePaginatedQueryObjectReturnType<Query>;
163
+ options: UsePaginatedQueryOptions<Query, ThrowOnError>,
164
+ ): UsePaginatedQueryObjectReturnType<Query, ThrowOnError>;
92
165
 
93
166
  export function usePaginatedQuery_experimental<
94
167
  Query extends PaginatedQueryReference,