convex-cms 0.0.2 → 0.0.3

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 (265) hide show
  1. package/admin-dist/nitro.json +15 -0
  2. package/admin-dist/public/assets/CmsEmptyState-CRswfTzk.js +5 -0
  3. package/admin-dist/public/assets/CmsPageHeader-CirpXndm.js +1 -0
  4. package/admin-dist/public/assets/CmsStatusBadge-CbEUpQu-.js +1 -0
  5. package/admin-dist/public/assets/CmsToolbar-BI2nZOXp.js +1 -0
  6. package/admin-dist/public/assets/ContentEntryEditor-CBeCyK_m.js +4 -0
  7. package/admin-dist/public/assets/ErrorState-BIVaWmom.js +1 -0
  8. package/admin-dist/public/assets/TaxonomyFilter-ChaY6Y_x.js +1 -0
  9. package/admin-dist/public/assets/_contentTypeId-DQ8k_Rvw.js +1 -0
  10. package/admin-dist/public/assets/_entryId-CKU_glsK.js +1 -0
  11. package/admin-dist/public/assets/alert-BXjTqrwQ.js +1 -0
  12. package/admin-dist/public/assets/badge-hvUOzpVZ.js +1 -0
  13. package/admin-dist/public/assets/circle-check-big-CF_pR17r.js +1 -0
  14. package/admin-dist/public/assets/command-DU82cJlt.js +1 -0
  15. package/admin-dist/public/assets/content-_LXl3pp7.js +1 -0
  16. package/admin-dist/public/assets/content-types-KjxaXGxY.js +2 -0
  17. package/admin-dist/public/assets/globals-CS6BZ0zp.css +1 -0
  18. package/admin-dist/public/assets/index-DNGIZHL-.js +1 -0
  19. package/admin-dist/public/assets/label-KNtpL71g.js +1 -0
  20. package/admin-dist/public/assets/link-2-Bw2aI4V4.js +1 -0
  21. package/admin-dist/public/assets/list-sYepHjt_.js +1 -0
  22. package/admin-dist/public/assets/main-CKj5yfEi.js +97 -0
  23. package/admin-dist/public/assets/media-Bkrkffm7.js +1 -0
  24. package/admin-dist/public/assets/new._contentTypeId-C3LstjNs.js +1 -0
  25. package/admin-dist/public/assets/plus-DUn8v_Xf.js +1 -0
  26. package/admin-dist/public/assets/rotate-ccw-DJEoHcRI.js +1 -0
  27. package/admin-dist/public/assets/scroll-area-DfIlT0in.js +1 -0
  28. package/admin-dist/public/assets/search-MuAUDJKR.js +1 -0
  29. package/admin-dist/public/assets/select-BD29IXCI.js +1 -0
  30. package/admin-dist/public/assets/settings-DmMyn_6A.js +1 -0
  31. package/admin-dist/public/assets/switch-h3Rrnl5i.js +1 -0
  32. package/admin-dist/public/assets/tabs-imc8h-Dp.js +1 -0
  33. package/admin-dist/public/assets/taxonomies-dAsrT65H.js +1 -0
  34. package/admin-dist/public/assets/textarea-BTy7nwzR.js +1 -0
  35. package/admin-dist/public/assets/trash-SAWKZZHv.js +1 -0
  36. package/admin-dist/public/assets/triangle-alert-E52Vfeuh.js +1 -0
  37. package/admin-dist/public/assets/useBreadcrumbLabel-BECBMCzM.js +1 -0
  38. package/admin-dist/public/assets/usePermissions-Basjs9BT.js +1 -0
  39. package/admin-dist/public/favicon.ico +0 -0
  40. package/admin-dist/server/_chunks/_libs/@date-fns/tz.mjs +217 -0
  41. package/admin-dist/server/_chunks/_libs/@floating-ui/core.mjs +719 -0
  42. package/admin-dist/server/_chunks/_libs/@floating-ui/dom.mjs +622 -0
  43. package/admin-dist/server/_chunks/_libs/@floating-ui/react-dom.mjs +292 -0
  44. package/admin-dist/server/_chunks/_libs/@floating-ui/utils.mjs +320 -0
  45. package/admin-dist/server/_chunks/_libs/@radix-ui/number.mjs +6 -0
  46. package/admin-dist/server/_chunks/_libs/@radix-ui/primitive.mjs +11 -0
  47. package/admin-dist/server/_chunks/_libs/@radix-ui/react-arrow.mjs +23 -0
  48. package/admin-dist/server/_chunks/_libs/@radix-ui/react-avatar.mjs +119 -0
  49. package/admin-dist/server/_chunks/_libs/@radix-ui/react-checkbox.mjs +270 -0
  50. package/admin-dist/server/_chunks/_libs/@radix-ui/react-collection.mjs +69 -0
  51. package/admin-dist/server/_chunks/_libs/@radix-ui/react-compose-refs.mjs +39 -0
  52. package/admin-dist/server/_chunks/_libs/@radix-ui/react-context.mjs +137 -0
  53. package/admin-dist/server/_chunks/_libs/@radix-ui/react-dialog.mjs +325 -0
  54. package/admin-dist/server/_chunks/_libs/@radix-ui/react-direction.mjs +9 -0
  55. package/admin-dist/server/_chunks/_libs/@radix-ui/react-dismissable-layer.mjs +210 -0
  56. package/admin-dist/server/_chunks/_libs/@radix-ui/react-dropdown-menu.mjs +253 -0
  57. package/admin-dist/server/_chunks/_libs/@radix-ui/react-focus-guards.mjs +29 -0
  58. package/admin-dist/server/_chunks/_libs/@radix-ui/react-focus-scope.mjs +206 -0
  59. package/admin-dist/server/_chunks/_libs/@radix-ui/react-id.mjs +14 -0
  60. package/admin-dist/server/_chunks/_libs/@radix-ui/react-label.mjs +23 -0
  61. package/admin-dist/server/_chunks/_libs/@radix-ui/react-menu.mjs +812 -0
  62. package/admin-dist/server/_chunks/_libs/@radix-ui/react-popover.mjs +300 -0
  63. package/admin-dist/server/_chunks/_libs/@radix-ui/react-popper.mjs +286 -0
  64. package/admin-dist/server/_chunks/_libs/@radix-ui/react-portal.mjs +16 -0
  65. package/admin-dist/server/_chunks/_libs/@radix-ui/react-presence.mjs +128 -0
  66. package/admin-dist/server/_chunks/_libs/@radix-ui/react-primitive.mjs +141 -0
  67. package/admin-dist/server/_chunks/_libs/@radix-ui/react-roving-focus.mjs +224 -0
  68. package/admin-dist/server/_chunks/_libs/@radix-ui/react-scroll-area.mjs +721 -0
  69. package/admin-dist/server/_chunks/_libs/@radix-ui/react-select.mjs +1163 -0
  70. package/admin-dist/server/_chunks/_libs/@radix-ui/react-separator.mjs +28 -0
  71. package/admin-dist/server/_chunks/_libs/@radix-ui/react-slot.mjs +601 -0
  72. package/admin-dist/server/_chunks/_libs/@radix-ui/react-switch.mjs +152 -0
  73. package/admin-dist/server/_chunks/_libs/@radix-ui/react-tabs.mjs +189 -0
  74. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-callback-ref.mjs +11 -0
  75. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-controllable-state.mjs +69 -0
  76. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-effect-event.mjs +1 -0
  77. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-escape-keydown.mjs +17 -0
  78. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-is-hydrated.mjs +15 -0
  79. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-layout-effect.mjs +6 -0
  80. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-previous.mjs +14 -0
  81. package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-size.mjs +39 -0
  82. package/admin-dist/server/_chunks/_libs/@radix-ui/react-visually-hidden.mjs +33 -0
  83. package/admin-dist/server/_chunks/_libs/@tanstack/history.mjs +409 -0
  84. package/admin-dist/server/_chunks/_libs/@tanstack/react-router.mjs +1711 -0
  85. package/admin-dist/server/_chunks/_libs/@tanstack/react-store.mjs +56 -0
  86. package/admin-dist/server/_chunks/_libs/@tanstack/router-core.mjs +4829 -0
  87. package/admin-dist/server/_chunks/_libs/@tanstack/store.mjs +134 -0
  88. package/admin-dist/server/_chunks/_libs/react-dom.mjs +10781 -0
  89. package/admin-dist/server/_chunks/_libs/react.mjs +513 -0
  90. package/admin-dist/server/_libs/aria-hidden.mjs +122 -0
  91. package/admin-dist/server/_libs/class-variance-authority.mjs +44 -0
  92. package/admin-dist/server/_libs/clsx.mjs +16 -0
  93. package/admin-dist/server/_libs/cmdk.mjs +315 -0
  94. package/admin-dist/server/_libs/convex.mjs +4841 -0
  95. package/admin-dist/server/_libs/cookie-es.mjs +58 -0
  96. package/admin-dist/server/_libs/croner.mjs +1 -0
  97. package/admin-dist/server/_libs/crossws.mjs +1 -0
  98. package/admin-dist/server/_libs/date-fns.mjs +1716 -0
  99. package/admin-dist/server/_libs/detect-node-es.mjs +1 -0
  100. package/admin-dist/server/_libs/get-nonce.mjs +9 -0
  101. package/admin-dist/server/_libs/h3-v2.mjs +277 -0
  102. package/admin-dist/server/_libs/h3.mjs +401 -0
  103. package/admin-dist/server/_libs/hookable.mjs +1 -0
  104. package/admin-dist/server/_libs/isbot.mjs +20 -0
  105. package/admin-dist/server/_libs/lucide-react.mjs +850 -0
  106. package/admin-dist/server/_libs/ohash.mjs +1 -0
  107. package/admin-dist/server/_libs/react-day-picker.mjs +2201 -0
  108. package/admin-dist/server/_libs/react-remove-scroll-bar.mjs +82 -0
  109. package/admin-dist/server/_libs/react-remove-scroll.mjs +328 -0
  110. package/admin-dist/server/_libs/react-style-singleton.mjs +69 -0
  111. package/admin-dist/server/_libs/rou3.mjs +8 -0
  112. package/admin-dist/server/_libs/seroval-plugins.mjs +58 -0
  113. package/admin-dist/server/_libs/seroval.mjs +1765 -0
  114. package/admin-dist/server/_libs/srvx.mjs +719 -0
  115. package/admin-dist/server/_libs/tailwind-merge.mjs +3010 -0
  116. package/admin-dist/server/_libs/tiny-invariant.mjs +12 -0
  117. package/admin-dist/server/_libs/tiny-warning.mjs +5 -0
  118. package/admin-dist/server/_libs/tslib.mjs +39 -0
  119. package/admin-dist/server/_libs/ufo.mjs +54 -0
  120. package/admin-dist/server/_libs/unctx.mjs +1 -0
  121. package/admin-dist/server/_libs/unstorage.mjs +1 -0
  122. package/admin-dist/server/_libs/use-callback-ref.mjs +66 -0
  123. package/admin-dist/server/_libs/use-sidecar.mjs +106 -0
  124. package/admin-dist/server/_libs/use-sync-external-store.mjs +139 -0
  125. package/admin-dist/server/_libs/zod.mjs +4223 -0
  126. package/admin-dist/server/_ssr/CmsEmptyState-DU7-7-mV.mjs +290 -0
  127. package/admin-dist/server/_ssr/CmsPageHeader-CseW0AHm.mjs +24 -0
  128. package/admin-dist/server/_ssr/CmsStatusBadge-B_pi4KCp.mjs +127 -0
  129. package/admin-dist/server/_ssr/CmsToolbar-X75ex6ek.mjs +49 -0
  130. package/admin-dist/server/_ssr/ContentEntryEditor-CepusRsA.mjs +3720 -0
  131. package/admin-dist/server/_ssr/ErrorState-cI-bKLez.mjs +89 -0
  132. package/admin-dist/server/_ssr/TaxonomyFilter-Bwrq0-cz.mjs +188 -0
  133. package/admin-dist/server/_ssr/_contentTypeId-BqYKEcLr.mjs +379 -0
  134. package/admin-dist/server/_ssr/_entryId-CRfnqeDf.mjs +161 -0
  135. package/admin-dist/server/_ssr/_tanstack-start-manifest_v-BwDlABVk.mjs +4 -0
  136. package/admin-dist/server/_ssr/alert-CVt45UUP.mjs +92 -0
  137. package/admin-dist/server/_ssr/badge-6BsP37vG.mjs +125 -0
  138. package/admin-dist/server/_ssr/command-fy8epIKf.mjs +128 -0
  139. package/admin-dist/server/_ssr/config.server-D7JHDcDv.mjs +117 -0
  140. package/admin-dist/server/_ssr/content-B5RhL7uW.mjs +532 -0
  141. package/admin-dist/server/_ssr/content-types-BIOqCQYN.mjs +1166 -0
  142. package/admin-dist/server/_ssr/index-DHSHDPt1.mjs +193 -0
  143. package/admin-dist/server/_ssr/index.mjs +1275 -0
  144. package/admin-dist/server/_ssr/label-C8Dko1j7.mjs +22 -0
  145. package/admin-dist/server/_ssr/media-CSx3XttC.mjs +1832 -0
  146. package/admin-dist/server/_ssr/new._contentTypeId-DzanEZQM.mjs +144 -0
  147. package/admin-dist/server/_ssr/router-DDWcF-kt.mjs +1556 -0
  148. package/admin-dist/server/_ssr/scroll-area-bjPYwhXN.mjs +59 -0
  149. package/admin-dist/server/_ssr/select-BUhDDf4T.mjs +142 -0
  150. package/admin-dist/server/_ssr/settings-DAsxnw2q.mjs +348 -0
  151. package/admin-dist/server/_ssr/start-HYkvq4Ni.mjs +4 -0
  152. package/admin-dist/server/_ssr/switch-BgyRtQ1Z.mjs +31 -0
  153. package/admin-dist/server/_ssr/tabs-DzMdRB1A.mjs +628 -0
  154. package/admin-dist/server/_ssr/taxonomies-C8j8g5Q5.mjs +915 -0
  155. package/admin-dist/server/_ssr/textarea-9jNeYJSc.mjs +18 -0
  156. package/admin-dist/server/_ssr/trash-DYMxwhZB.mjs +291 -0
  157. package/admin-dist/server/_ssr/useBreadcrumbLabel-FNSAr2Ha.mjs +16 -0
  158. package/admin-dist/server/_ssr/usePermissions-BJGGahrJ.mjs +68 -0
  159. package/admin-dist/server/favicon.ico +0 -0
  160. package/admin-dist/server/index.mjs +627 -0
  161. package/dist/cli/index.js +0 -0
  162. package/dist/client/admin-config.d.ts +0 -1
  163. package/dist/client/admin-config.d.ts.map +1 -1
  164. package/dist/client/admin-config.js +0 -1
  165. package/dist/client/admin-config.js.map +1 -1
  166. package/dist/client/adminApi.d.ts.map +1 -1
  167. package/dist/client/agentTools.d.ts +1237 -135
  168. package/dist/client/agentTools.d.ts.map +1 -1
  169. package/dist/client/agentTools.js +33 -9
  170. package/dist/client/agentTools.js.map +1 -1
  171. package/dist/client/index.d.ts +1 -1
  172. package/dist/client/index.d.ts.map +1 -1
  173. package/dist/client/index.js.map +1 -1
  174. package/dist/component/_generated/component.d.ts +9 -0
  175. package/dist/component/_generated/component.d.ts.map +1 -1
  176. package/dist/component/mediaAssets.d.ts +35 -0
  177. package/dist/component/mediaAssets.d.ts.map +1 -1
  178. package/dist/component/mediaAssets.js +81 -0
  179. package/dist/component/mediaAssets.js.map +1 -1
  180. package/dist/test.d.ts.map +1 -1
  181. package/dist/test.js +2 -1
  182. package/dist/test.js.map +1 -1
  183. package/package.json +9 -5
  184. package/dist/component/auditLog.d.ts +0 -410
  185. package/dist/component/auditLog.d.ts.map +0 -1
  186. package/dist/component/auditLog.js +0 -607
  187. package/dist/component/auditLog.js.map +0 -1
  188. package/dist/component/types.d.ts +0 -4
  189. package/dist/component/types.d.ts.map +0 -1
  190. package/dist/component/types.js +0 -2
  191. package/dist/component/types.js.map +0 -1
  192. package/src/cli/commands/admin.ts +0 -104
  193. package/src/cli/index.ts +0 -21
  194. package/src/cli/utils/detectConvexUrl.ts +0 -54
  195. package/src/cli/utils/openBrowser.ts +0 -16
  196. package/src/client/admin-config.ts +0 -138
  197. package/src/client/adminApi.ts +0 -942
  198. package/src/client/agentTools.ts +0 -1311
  199. package/src/client/argTypes.ts +0 -316
  200. package/src/client/field-types.ts +0 -187
  201. package/src/client/index.ts +0 -1301
  202. package/src/client/queryBuilder.ts +0 -1100
  203. package/src/client/schema/codegen.ts +0 -500
  204. package/src/client/schema/defineContentType.ts +0 -501
  205. package/src/client/schema/index.ts +0 -169
  206. package/src/client/schema/schemaDrift.ts +0 -574
  207. package/src/client/schema/typedClient.ts +0 -688
  208. package/src/client/schema/types.ts +0 -666
  209. package/src/client/types.ts +0 -723
  210. package/src/client/workflows.ts +0 -141
  211. package/src/client/wrapper.ts +0 -4304
  212. package/src/component/_generated/api.ts +0 -140
  213. package/src/component/_generated/component.ts +0 -5029
  214. package/src/component/_generated/dataModel.ts +0 -60
  215. package/src/component/_generated/server.ts +0 -156
  216. package/src/component/authorization.ts +0 -647
  217. package/src/component/authorizationHooks.ts +0 -668
  218. package/src/component/bulkOperations.ts +0 -687
  219. package/src/component/contentEntries.ts +0 -1976
  220. package/src/component/contentEntryMutations.ts +0 -1223
  221. package/src/component/contentEntryValidation.ts +0 -707
  222. package/src/component/contentLock.ts +0 -550
  223. package/src/component/contentTypeMigration.ts +0 -1064
  224. package/src/component/contentTypeMutations.ts +0 -969
  225. package/src/component/contentTypes.ts +0 -346
  226. package/src/component/convex.config.ts +0 -44
  227. package/src/component/documentTypes.ts +0 -240
  228. package/src/component/eventEmitter.ts +0 -485
  229. package/src/component/exportImport.ts +0 -1169
  230. package/src/component/index.ts +0 -491
  231. package/src/component/lib/deepReferenceResolver.ts +0 -999
  232. package/src/component/lib/errors.ts +0 -816
  233. package/src/component/lib/index.ts +0 -145
  234. package/src/component/lib/mediaReferenceResolver.ts +0 -495
  235. package/src/component/lib/metadataExtractor.ts +0 -792
  236. package/src/component/lib/mutationAuth.ts +0 -199
  237. package/src/component/lib/queries.ts +0 -79
  238. package/src/component/lib/ragContentChunker.ts +0 -1371
  239. package/src/component/lib/referenceResolver.ts +0 -430
  240. package/src/component/lib/slugGenerator.ts +0 -262
  241. package/src/component/lib/slugUniqueness.ts +0 -333
  242. package/src/component/lib/softDelete.ts +0 -44
  243. package/src/component/localeFallbackChain.ts +0 -673
  244. package/src/component/localeFields.ts +0 -896
  245. package/src/component/mediaAssetMutations.ts +0 -725
  246. package/src/component/mediaAssets.ts +0 -932
  247. package/src/component/mediaFolderMutations.ts +0 -1046
  248. package/src/component/mediaUploadMutations.ts +0 -224
  249. package/src/component/mediaVariantMutations.ts +0 -900
  250. package/src/component/mediaVariants.ts +0 -793
  251. package/src/component/ragContentIndexer.ts +0 -1067
  252. package/src/component/rateLimitHooks.ts +0 -572
  253. package/src/component/roles.ts +0 -1360
  254. package/src/component/scheduledPublish.ts +0 -358
  255. package/src/component/schema.ts +0 -617
  256. package/src/component/taxonomies.ts +0 -949
  257. package/src/component/taxonomyMutations.ts +0 -1210
  258. package/src/component/trash.ts +0 -724
  259. package/src/component/userContext.ts +0 -898
  260. package/src/component/validation.ts +0 -1388
  261. package/src/component/validators.ts +0 -949
  262. package/src/component/versionMutations.ts +0 -392
  263. package/src/component/webhookTrigger.ts +0 -1922
  264. package/src/react/index.ts +0 -898
  265. package/src/test.ts +0 -1580
@@ -0,0 +1,4841 @@
1
+ import { r as reactExports, a as React } from "../_chunks/_libs/react.mjs";
2
+ var lookup = [];
3
+ var revLookup = [];
4
+ var Arr = Uint8Array;
5
+ var code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6
+ for (var i = 0, len = code.length; i < len; ++i) {
7
+ lookup[i] = code[i];
8
+ revLookup[code.charCodeAt(i)] = i;
9
+ }
10
+ revLookup["-".charCodeAt(0)] = 62;
11
+ revLookup["_".charCodeAt(0)] = 63;
12
+ function getLens(b64) {
13
+ var len = b64.length;
14
+ if (len % 4 > 0) {
15
+ throw new Error("Invalid string. Length must be a multiple of 4");
16
+ }
17
+ var validLen = b64.indexOf("=");
18
+ if (validLen === -1) validLen = len;
19
+ var placeHoldersLen = validLen === len ? 0 : 4 - validLen % 4;
20
+ return [validLen, placeHoldersLen];
21
+ }
22
+ function _byteLength(_b64, validLen, placeHoldersLen) {
23
+ return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen;
24
+ }
25
+ function toByteArray(b64) {
26
+ var tmp;
27
+ var lens = getLens(b64);
28
+ var validLen = lens[0];
29
+ var placeHoldersLen = lens[1];
30
+ var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen));
31
+ var curByte = 0;
32
+ var len = placeHoldersLen > 0 ? validLen - 4 : validLen;
33
+ var i;
34
+ for (i = 0; i < len; i += 4) {
35
+ tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)];
36
+ arr[curByte++] = tmp >> 16 & 255;
37
+ arr[curByte++] = tmp >> 8 & 255;
38
+ arr[curByte++] = tmp & 255;
39
+ }
40
+ if (placeHoldersLen === 2) {
41
+ tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4;
42
+ arr[curByte++] = tmp & 255;
43
+ }
44
+ if (placeHoldersLen === 1) {
45
+ tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2;
46
+ arr[curByte++] = tmp >> 8 & 255;
47
+ arr[curByte++] = tmp & 255;
48
+ }
49
+ return arr;
50
+ }
51
+ function tripletToBase64(num) {
52
+ return lookup[num >> 18 & 63] + lookup[num >> 12 & 63] + lookup[num >> 6 & 63] + lookup[num & 63];
53
+ }
54
+ function encodeChunk(uint8, start, end) {
55
+ var tmp;
56
+ var output = [];
57
+ for (var i = start; i < end; i += 3) {
58
+ tmp = (uint8[i] << 16 & 16711680) + (uint8[i + 1] << 8 & 65280) + (uint8[i + 2] & 255);
59
+ output.push(tripletToBase64(tmp));
60
+ }
61
+ return output.join("");
62
+ }
63
+ function fromByteArray(uint8) {
64
+ var tmp;
65
+ var len = uint8.length;
66
+ var extraBytes = len % 3;
67
+ var parts = [];
68
+ var maxChunkLength = 16383;
69
+ for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
70
+ parts.push(
71
+ encodeChunk(
72
+ uint8,
73
+ i,
74
+ i + maxChunkLength > len2 ? len2 : i + maxChunkLength
75
+ )
76
+ );
77
+ }
78
+ if (extraBytes === 1) {
79
+ tmp = uint8[len - 1];
80
+ parts.push(lookup[tmp >> 2] + lookup[tmp << 4 & 63] + "==");
81
+ } else if (extraBytes === 2) {
82
+ tmp = (uint8[len - 2] << 8) + uint8[len - 1];
83
+ parts.push(
84
+ lookup[tmp >> 10] + lookup[tmp >> 4 & 63] + lookup[tmp << 2 & 63] + "="
85
+ );
86
+ }
87
+ return parts.join("");
88
+ }
89
+ function parseArgs(args) {
90
+ if (args === void 0) {
91
+ return {};
92
+ }
93
+ if (!isSimpleObject(args)) {
94
+ throw new Error(
95
+ `The arguments to a Convex function must be an object. Received: ${args}`
96
+ );
97
+ }
98
+ return args;
99
+ }
100
+ function validateDeploymentUrl(deploymentUrl) {
101
+ if (typeof deploymentUrl === "undefined") {
102
+ throw new Error(
103
+ `Client created with undefined deployment address. If you used an environment variable, check that it's set.`
104
+ );
105
+ }
106
+ if (typeof deploymentUrl !== "string") {
107
+ throw new Error(
108
+ `Invalid deployment address: found ${deploymentUrl}".`
109
+ );
110
+ }
111
+ if (!(deploymentUrl.startsWith("http:") || deploymentUrl.startsWith("https:"))) {
112
+ throw new Error(
113
+ `Invalid deployment address: Must start with "https://" or "http://". Found "${deploymentUrl}".`
114
+ );
115
+ }
116
+ try {
117
+ new URL(deploymentUrl);
118
+ } catch {
119
+ throw new Error(
120
+ `Invalid deployment address: "${deploymentUrl}" is not a valid URL. If you believe this URL is correct, use the \`skipConvexDeploymentUrlCheck\` option to bypass this.`
121
+ );
122
+ }
123
+ if (deploymentUrl.endsWith(".convex.site")) {
124
+ throw new Error(
125
+ `Invalid deployment address: "${deploymentUrl}" ends with .convex.site, which is used for HTTP Actions. Convex deployment URLs typically end with .convex.cloud? If you believe this URL is correct, use the \`skipConvexDeploymentUrlCheck\` option to bypass this.`
126
+ );
127
+ }
128
+ }
129
+ function isSimpleObject(value) {
130
+ const isObject = typeof value === "object";
131
+ const prototype = Object.getPrototypeOf(value);
132
+ const isSimple = prototype === null || prototype === Object.prototype || // Objects generated from other contexts (e.g. across Node.js `vm` modules) will not satisfy the previous
133
+ // conditions but are still simple objects.
134
+ prototype?.constructor?.name === "Object";
135
+ return isObject && isSimple;
136
+ }
137
+ const LITTLE_ENDIAN = true;
138
+ const MIN_INT64 = BigInt("-9223372036854775808");
139
+ const MAX_INT64 = BigInt("9223372036854775807");
140
+ const ZERO = BigInt("0");
141
+ const EIGHT = BigInt("8");
142
+ const TWOFIFTYSIX = BigInt("256");
143
+ function isSpecial(n) {
144
+ return Number.isNaN(n) || !Number.isFinite(n) || Object.is(n, -0);
145
+ }
146
+ function slowBigIntToBase64(value) {
147
+ if (value < ZERO) {
148
+ value -= MIN_INT64 + MIN_INT64;
149
+ }
150
+ let hex = value.toString(16);
151
+ if (hex.length % 2 === 1) hex = "0" + hex;
152
+ const bytes = new Uint8Array(new ArrayBuffer(8));
153
+ let i = 0;
154
+ for (const hexByte of hex.match(/.{2}/g).reverse()) {
155
+ bytes.set([parseInt(hexByte, 16)], i++);
156
+ value >>= EIGHT;
157
+ }
158
+ return fromByteArray(bytes);
159
+ }
160
+ function slowBase64ToBigInt(encoded) {
161
+ const integerBytes = toByteArray(encoded);
162
+ if (integerBytes.byteLength !== 8) {
163
+ throw new Error(
164
+ `Received ${integerBytes.byteLength} bytes, expected 8 for $integer`
165
+ );
166
+ }
167
+ let value = ZERO;
168
+ let power = ZERO;
169
+ for (const byte of integerBytes) {
170
+ value += BigInt(byte) * TWOFIFTYSIX ** power;
171
+ power++;
172
+ }
173
+ if (value > MAX_INT64) {
174
+ value += MIN_INT64 + MIN_INT64;
175
+ }
176
+ return value;
177
+ }
178
+ function modernBigIntToBase64(value) {
179
+ if (value < MIN_INT64 || MAX_INT64 < value) {
180
+ throw new Error(
181
+ `BigInt ${value} does not fit into a 64-bit signed integer.`
182
+ );
183
+ }
184
+ const buffer = new ArrayBuffer(8);
185
+ new DataView(buffer).setBigInt64(0, value, true);
186
+ return fromByteArray(new Uint8Array(buffer));
187
+ }
188
+ function modernBase64ToBigInt(encoded) {
189
+ const integerBytes = toByteArray(encoded);
190
+ if (integerBytes.byteLength !== 8) {
191
+ throw new Error(
192
+ `Received ${integerBytes.byteLength} bytes, expected 8 for $integer`
193
+ );
194
+ }
195
+ const intBytesView = new DataView(integerBytes.buffer);
196
+ return intBytesView.getBigInt64(0, true);
197
+ }
198
+ const bigIntToBase64 = DataView.prototype.setBigInt64 ? modernBigIntToBase64 : slowBigIntToBase64;
199
+ const base64ToBigInt = DataView.prototype.getBigInt64 ? modernBase64ToBigInt : slowBase64ToBigInt;
200
+ const MAX_IDENTIFIER_LEN = 1024;
201
+ function validateObjectField(k) {
202
+ if (k.length > MAX_IDENTIFIER_LEN) {
203
+ throw new Error(
204
+ `Field name ${k} exceeds maximum field name length ${MAX_IDENTIFIER_LEN}.`
205
+ );
206
+ }
207
+ if (k.startsWith("$")) {
208
+ throw new Error(`Field name ${k} starts with a '$', which is reserved.`);
209
+ }
210
+ for (let i = 0; i < k.length; i += 1) {
211
+ const charCode = k.charCodeAt(i);
212
+ if (charCode < 32 || charCode >= 127) {
213
+ throw new Error(
214
+ `Field name ${k} has invalid character '${k[i]}': Field names can only contain non-control ASCII characters`
215
+ );
216
+ }
217
+ }
218
+ }
219
+ function jsonToConvex(value) {
220
+ if (value === null) {
221
+ return value;
222
+ }
223
+ if (typeof value === "boolean") {
224
+ return value;
225
+ }
226
+ if (typeof value === "number") {
227
+ return value;
228
+ }
229
+ if (typeof value === "string") {
230
+ return value;
231
+ }
232
+ if (Array.isArray(value)) {
233
+ return value.map((value2) => jsonToConvex(value2));
234
+ }
235
+ if (typeof value !== "object") {
236
+ throw new Error(`Unexpected type of ${value}`);
237
+ }
238
+ const entries = Object.entries(value);
239
+ if (entries.length === 1) {
240
+ const key = entries[0][0];
241
+ if (key === "$bytes") {
242
+ if (typeof value.$bytes !== "string") {
243
+ throw new Error(`Malformed $bytes field on ${value}`);
244
+ }
245
+ return toByteArray(value.$bytes).buffer;
246
+ }
247
+ if (key === "$integer") {
248
+ if (typeof value.$integer !== "string") {
249
+ throw new Error(`Malformed $integer field on ${value}`);
250
+ }
251
+ return base64ToBigInt(value.$integer);
252
+ }
253
+ if (key === "$float") {
254
+ if (typeof value.$float !== "string") {
255
+ throw new Error(`Malformed $float field on ${value}`);
256
+ }
257
+ const floatBytes = toByteArray(value.$float);
258
+ if (floatBytes.byteLength !== 8) {
259
+ throw new Error(
260
+ `Received ${floatBytes.byteLength} bytes, expected 8 for $float`
261
+ );
262
+ }
263
+ const floatBytesView = new DataView(floatBytes.buffer);
264
+ const float = floatBytesView.getFloat64(0, LITTLE_ENDIAN);
265
+ if (!isSpecial(float)) {
266
+ throw new Error(`Float ${float} should be encoded as a number`);
267
+ }
268
+ return float;
269
+ }
270
+ if (key === "$set") {
271
+ throw new Error(
272
+ `Received a Set which is no longer supported as a Convex type.`
273
+ );
274
+ }
275
+ if (key === "$map") {
276
+ throw new Error(
277
+ `Received a Map which is no longer supported as a Convex type.`
278
+ );
279
+ }
280
+ }
281
+ const out = {};
282
+ for (const [k, v2] of Object.entries(value)) {
283
+ validateObjectField(k);
284
+ out[k] = jsonToConvex(v2);
285
+ }
286
+ return out;
287
+ }
288
+ const MAX_VALUE_FOR_ERROR_LEN = 16384;
289
+ function stringifyValueForError(value) {
290
+ const str = JSON.stringify(value, (_key, value2) => {
291
+ if (value2 === void 0) {
292
+ return "undefined";
293
+ }
294
+ if (typeof value2 === "bigint") {
295
+ return `${value2.toString()}n`;
296
+ }
297
+ return value2;
298
+ });
299
+ if (str.length > MAX_VALUE_FOR_ERROR_LEN) {
300
+ const rest = "[...truncated]";
301
+ let truncateAt = MAX_VALUE_FOR_ERROR_LEN - rest.length;
302
+ const codePoint = str.codePointAt(truncateAt - 1);
303
+ if (codePoint !== void 0 && codePoint > 65535) {
304
+ truncateAt -= 1;
305
+ }
306
+ return str.substring(0, truncateAt) + rest;
307
+ }
308
+ return str;
309
+ }
310
+ function convexToJsonInternal(value, originalValue, context, includeTopLevelUndefined) {
311
+ if (value === void 0) {
312
+ const contextText = context && ` (present at path ${context} in original object ${stringifyValueForError(
313
+ originalValue
314
+ )})`;
315
+ throw new Error(
316
+ `undefined is not a valid Convex value${contextText}. To learn about Convex's supported types, see https://docs.convex.dev/using/types.`
317
+ );
318
+ }
319
+ if (value === null) {
320
+ return value;
321
+ }
322
+ if (typeof value === "bigint") {
323
+ if (value < MIN_INT64 || MAX_INT64 < value) {
324
+ throw new Error(
325
+ `BigInt ${value} does not fit into a 64-bit signed integer.`
326
+ );
327
+ }
328
+ return { $integer: bigIntToBase64(value) };
329
+ }
330
+ if (typeof value === "number") {
331
+ if (isSpecial(value)) {
332
+ const buffer = new ArrayBuffer(8);
333
+ new DataView(buffer).setFloat64(0, value, LITTLE_ENDIAN);
334
+ return { $float: fromByteArray(new Uint8Array(buffer)) };
335
+ } else {
336
+ return value;
337
+ }
338
+ }
339
+ if (typeof value === "boolean") {
340
+ return value;
341
+ }
342
+ if (typeof value === "string") {
343
+ return value;
344
+ }
345
+ if (value instanceof ArrayBuffer) {
346
+ return { $bytes: fromByteArray(new Uint8Array(value)) };
347
+ }
348
+ if (Array.isArray(value)) {
349
+ return value.map(
350
+ (value2, i) => convexToJsonInternal(value2, originalValue, context + `[${i}]`)
351
+ );
352
+ }
353
+ if (value instanceof Set) {
354
+ throw new Error(
355
+ errorMessageForUnsupportedType(context, "Set", [...value], originalValue)
356
+ );
357
+ }
358
+ if (value instanceof Map) {
359
+ throw new Error(
360
+ errorMessageForUnsupportedType(context, "Map", [...value], originalValue)
361
+ );
362
+ }
363
+ if (!isSimpleObject(value)) {
364
+ const theType = value?.constructor?.name;
365
+ const typeName = theType ? `${theType} ` : "";
366
+ throw new Error(
367
+ errorMessageForUnsupportedType(context, typeName, value, originalValue)
368
+ );
369
+ }
370
+ const out = {};
371
+ const entries = Object.entries(value);
372
+ entries.sort(([k1, _v1], [k2, _v2]) => k1 === k2 ? 0 : k1 < k2 ? -1 : 1);
373
+ for (const [k, v2] of entries) {
374
+ if (v2 !== void 0) {
375
+ validateObjectField(k);
376
+ out[k] = convexToJsonInternal(v2, originalValue, context + `.${k}`);
377
+ }
378
+ }
379
+ return out;
380
+ }
381
+ function errorMessageForUnsupportedType(context, typeName, value, originalValue) {
382
+ if (context) {
383
+ return `${typeName}${stringifyValueForError(
384
+ value
385
+ )} is not a supported Convex type (present at path ${context} in original object ${stringifyValueForError(
386
+ originalValue
387
+ )}). To learn about Convex's supported types, see https://docs.convex.dev/using/types.`;
388
+ } else {
389
+ return `${typeName}${stringifyValueForError(
390
+ value
391
+ )} is not a supported Convex type.`;
392
+ }
393
+ }
394
+ function convexToJson(value) {
395
+ return convexToJsonInternal(value, value, "");
396
+ }
397
+ var __defProp$d = Object.defineProperty;
398
+ var __defNormalProp$d = (obj, key, value) => key in obj ? __defProp$d(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
399
+ var __publicField$d = (obj, key, value) => __defNormalProp$d(obj, typeof key !== "symbol" ? key + "" : key, value);
400
+ const UNDEFINED_VALIDATOR_ERROR_URL = "https://docs.convex.dev/error#undefined-validator";
401
+ function throwUndefinedValidatorError(context, fieldName) {
402
+ const fieldInfo = fieldName !== void 0 ? ` for field "${fieldName}"` : "";
403
+ throw new Error(
404
+ `A validator is undefined${fieldInfo} in ${context}. This is often caused by circular imports. See ${UNDEFINED_VALIDATOR_ERROR_URL} for details.`
405
+ );
406
+ }
407
+ class BaseValidator {
408
+ constructor({ isOptional }) {
409
+ __publicField$d(this, "type");
410
+ __publicField$d(this, "fieldPaths");
411
+ __publicField$d(this, "isOptional");
412
+ __publicField$d(this, "isConvexValidator");
413
+ this.isOptional = isOptional;
414
+ this.isConvexValidator = true;
415
+ }
416
+ }
417
+ class VId extends BaseValidator {
418
+ /**
419
+ * Usually you'd use `v.id(tableName)` instead.
420
+ */
421
+ constructor({
422
+ isOptional,
423
+ tableName
424
+ }) {
425
+ super({ isOptional });
426
+ __publicField$d(this, "tableName");
427
+ __publicField$d(this, "kind", "id");
428
+ if (typeof tableName !== "string") {
429
+ throw new Error("v.id(tableName) requires a string");
430
+ }
431
+ this.tableName = tableName;
432
+ }
433
+ /** @internal */
434
+ get json() {
435
+ return { type: "id", tableName: this.tableName };
436
+ }
437
+ /** @internal */
438
+ asOptional() {
439
+ return new VId({
440
+ isOptional: "optional",
441
+ tableName: this.tableName
442
+ });
443
+ }
444
+ }
445
+ class VFloat64 extends BaseValidator {
446
+ constructor() {
447
+ super(...arguments);
448
+ __publicField$d(this, "kind", "float64");
449
+ }
450
+ /** @internal */
451
+ get json() {
452
+ return { type: "number" };
453
+ }
454
+ /** @internal */
455
+ asOptional() {
456
+ return new VFloat64({
457
+ isOptional: "optional"
458
+ });
459
+ }
460
+ }
461
+ class VInt64 extends BaseValidator {
462
+ constructor() {
463
+ super(...arguments);
464
+ __publicField$d(this, "kind", "int64");
465
+ }
466
+ /** @internal */
467
+ get json() {
468
+ return { type: "bigint" };
469
+ }
470
+ /** @internal */
471
+ asOptional() {
472
+ return new VInt64({ isOptional: "optional" });
473
+ }
474
+ }
475
+ class VBoolean extends BaseValidator {
476
+ constructor() {
477
+ super(...arguments);
478
+ __publicField$d(this, "kind", "boolean");
479
+ }
480
+ /** @internal */
481
+ get json() {
482
+ return { type: this.kind };
483
+ }
484
+ /** @internal */
485
+ asOptional() {
486
+ return new VBoolean({
487
+ isOptional: "optional"
488
+ });
489
+ }
490
+ }
491
+ class VBytes extends BaseValidator {
492
+ constructor() {
493
+ super(...arguments);
494
+ __publicField$d(this, "kind", "bytes");
495
+ }
496
+ /** @internal */
497
+ get json() {
498
+ return { type: this.kind };
499
+ }
500
+ /** @internal */
501
+ asOptional() {
502
+ return new VBytes({ isOptional: "optional" });
503
+ }
504
+ }
505
+ class VString extends BaseValidator {
506
+ constructor() {
507
+ super(...arguments);
508
+ __publicField$d(this, "kind", "string");
509
+ }
510
+ /** @internal */
511
+ get json() {
512
+ return { type: this.kind };
513
+ }
514
+ /** @internal */
515
+ asOptional() {
516
+ return new VString({
517
+ isOptional: "optional"
518
+ });
519
+ }
520
+ }
521
+ class VNull extends BaseValidator {
522
+ constructor() {
523
+ super(...arguments);
524
+ __publicField$d(this, "kind", "null");
525
+ }
526
+ /** @internal */
527
+ get json() {
528
+ return { type: this.kind };
529
+ }
530
+ /** @internal */
531
+ asOptional() {
532
+ return new VNull({ isOptional: "optional" });
533
+ }
534
+ }
535
+ class VAny extends BaseValidator {
536
+ constructor() {
537
+ super(...arguments);
538
+ __publicField$d(this, "kind", "any");
539
+ }
540
+ /** @internal */
541
+ get json() {
542
+ return {
543
+ type: this.kind
544
+ };
545
+ }
546
+ /** @internal */
547
+ asOptional() {
548
+ return new VAny({
549
+ isOptional: "optional"
550
+ });
551
+ }
552
+ }
553
+ class VObject extends BaseValidator {
554
+ /**
555
+ * Usually you'd use `v.object({ ... })` instead.
556
+ */
557
+ constructor({
558
+ isOptional,
559
+ fields
560
+ }) {
561
+ super({ isOptional });
562
+ __publicField$d(this, "fields");
563
+ __publicField$d(this, "kind", "object");
564
+ globalThis.Object.entries(fields).forEach(([fieldName, validator]) => {
565
+ if (validator === void 0) {
566
+ throwUndefinedValidatorError("v.object()", fieldName);
567
+ }
568
+ if (!validator.isConvexValidator) {
569
+ throw new Error("v.object() entries must be validators");
570
+ }
571
+ });
572
+ this.fields = fields;
573
+ }
574
+ /** @internal */
575
+ get json() {
576
+ return {
577
+ type: this.kind,
578
+ value: globalThis.Object.fromEntries(
579
+ globalThis.Object.entries(this.fields).map(([k, v2]) => [
580
+ k,
581
+ {
582
+ fieldType: v2.json,
583
+ optional: v2.isOptional === "optional" ? true : false
584
+ }
585
+ ])
586
+ )
587
+ };
588
+ }
589
+ /** @internal */
590
+ asOptional() {
591
+ return new VObject({
592
+ isOptional: "optional",
593
+ fields: this.fields
594
+ });
595
+ }
596
+ /**
597
+ * Create a new VObject with the specified fields omitted.
598
+ * @param fields The field names to omit from this VObject.
599
+ */
600
+ omit(...fields) {
601
+ const newFields = { ...this.fields };
602
+ for (const field of fields) {
603
+ delete newFields[field];
604
+ }
605
+ return new VObject({
606
+ isOptional: this.isOptional,
607
+ fields: newFields
608
+ });
609
+ }
610
+ /**
611
+ * Create a new VObject with only the specified fields.
612
+ * @param fields The field names to pick from this VObject.
613
+ */
614
+ pick(...fields) {
615
+ const newFields = {};
616
+ for (const field of fields) {
617
+ newFields[field] = this.fields[field];
618
+ }
619
+ return new VObject({
620
+ isOptional: this.isOptional,
621
+ fields: newFields
622
+ });
623
+ }
624
+ /**
625
+ * Create a new VObject with all fields marked as optional.
626
+ */
627
+ partial() {
628
+ const newFields = {};
629
+ for (const [key, validator] of globalThis.Object.entries(this.fields)) {
630
+ newFields[key] = validator.asOptional();
631
+ }
632
+ return new VObject({
633
+ isOptional: this.isOptional,
634
+ fields: newFields
635
+ });
636
+ }
637
+ /**
638
+ * Create a new VObject with additional fields merged in.
639
+ * @param fields An object with additional validators to merge into this VObject.
640
+ */
641
+ extend(fields) {
642
+ return new VObject({
643
+ isOptional: this.isOptional,
644
+ fields: { ...this.fields, ...fields }
645
+ });
646
+ }
647
+ }
648
+ class VLiteral extends BaseValidator {
649
+ /**
650
+ * Usually you'd use `v.literal(value)` instead.
651
+ */
652
+ constructor({ isOptional, value }) {
653
+ super({ isOptional });
654
+ __publicField$d(this, "value");
655
+ __publicField$d(this, "kind", "literal");
656
+ if (typeof value !== "string" && typeof value !== "boolean" && typeof value !== "number" && typeof value !== "bigint") {
657
+ throw new Error("v.literal(value) must be a string, number, or boolean");
658
+ }
659
+ this.value = value;
660
+ }
661
+ /** @internal */
662
+ get json() {
663
+ return {
664
+ type: this.kind,
665
+ value: convexToJson(this.value)
666
+ };
667
+ }
668
+ /** @internal */
669
+ asOptional() {
670
+ return new VLiteral({
671
+ isOptional: "optional",
672
+ value: this.value
673
+ });
674
+ }
675
+ }
676
+ class VArray extends BaseValidator {
677
+ /**
678
+ * Usually you'd use `v.array(element)` instead.
679
+ */
680
+ constructor({
681
+ isOptional,
682
+ element
683
+ }) {
684
+ super({ isOptional });
685
+ __publicField$d(this, "element");
686
+ __publicField$d(this, "kind", "array");
687
+ if (element === void 0) {
688
+ throwUndefinedValidatorError("v.array()");
689
+ }
690
+ this.element = element;
691
+ }
692
+ /** @internal */
693
+ get json() {
694
+ return {
695
+ type: this.kind,
696
+ value: this.element.json
697
+ };
698
+ }
699
+ /** @internal */
700
+ asOptional() {
701
+ return new VArray({
702
+ isOptional: "optional",
703
+ element: this.element
704
+ });
705
+ }
706
+ }
707
+ class VRecord extends BaseValidator {
708
+ /**
709
+ * Usually you'd use `v.record(key, value)` instead.
710
+ */
711
+ constructor({
712
+ isOptional,
713
+ key,
714
+ value
715
+ }) {
716
+ super({ isOptional });
717
+ __publicField$d(this, "key");
718
+ __publicField$d(this, "value");
719
+ __publicField$d(this, "kind", "record");
720
+ if (key === void 0) {
721
+ throwUndefinedValidatorError("v.record()", "key");
722
+ }
723
+ if (value === void 0) {
724
+ throwUndefinedValidatorError("v.record()", "value");
725
+ }
726
+ if (key.isOptional === "optional") {
727
+ throw new Error("Record validator cannot have optional keys");
728
+ }
729
+ if (value.isOptional === "optional") {
730
+ throw new Error("Record validator cannot have optional values");
731
+ }
732
+ if (!key.isConvexValidator || !value.isConvexValidator) {
733
+ throw new Error("Key and value of v.record() but be validators");
734
+ }
735
+ this.key = key;
736
+ this.value = value;
737
+ }
738
+ /** @internal */
739
+ get json() {
740
+ return {
741
+ type: this.kind,
742
+ // This cast is needed because TypeScript thinks the key type is too wide
743
+ keys: this.key.json,
744
+ values: {
745
+ fieldType: this.value.json,
746
+ optional: false
747
+ }
748
+ };
749
+ }
750
+ /** @internal */
751
+ asOptional() {
752
+ return new VRecord({
753
+ isOptional: "optional",
754
+ key: this.key,
755
+ value: this.value
756
+ });
757
+ }
758
+ }
759
+ class VUnion extends BaseValidator {
760
+ /**
761
+ * Usually you'd use `v.union(...members)` instead.
762
+ */
763
+ constructor({ isOptional, members }) {
764
+ super({ isOptional });
765
+ __publicField$d(this, "members");
766
+ __publicField$d(this, "kind", "union");
767
+ members.forEach((member, index) => {
768
+ if (member === void 0) {
769
+ throwUndefinedValidatorError("v.union()", `member at index ${index}`);
770
+ }
771
+ if (!member.isConvexValidator) {
772
+ throw new Error("All members of v.union() must be validators");
773
+ }
774
+ });
775
+ this.members = members;
776
+ }
777
+ /** @internal */
778
+ get json() {
779
+ return {
780
+ type: this.kind,
781
+ value: this.members.map((v2) => v2.json)
782
+ };
783
+ }
784
+ /** @internal */
785
+ asOptional() {
786
+ return new VUnion({
787
+ isOptional: "optional",
788
+ members: this.members
789
+ });
790
+ }
791
+ }
792
+ const v = {
793
+ /**
794
+ * Validates that the value corresponds to an ID of a document in given table.
795
+ * @param tableName The name of the table.
796
+ */
797
+ id: (tableName) => {
798
+ return new VId({
799
+ isOptional: "required",
800
+ tableName
801
+ });
802
+ },
803
+ /**
804
+ * Validates that the value is of type Null.
805
+ */
806
+ null: () => {
807
+ return new VNull({ isOptional: "required" });
808
+ },
809
+ /**
810
+ * Validates that the value is of Convex type Float64 (Number in JS).
811
+ *
812
+ * Alias for `v.float64()`
813
+ */
814
+ number: () => {
815
+ return new VFloat64({ isOptional: "required" });
816
+ },
817
+ /**
818
+ * Validates that the value is of Convex type Float64 (Number in JS).
819
+ */
820
+ float64: () => {
821
+ return new VFloat64({ isOptional: "required" });
822
+ },
823
+ /**
824
+ * @deprecated Use `v.int64()` instead
825
+ */
826
+ bigint: () => {
827
+ return new VInt64({ isOptional: "required" });
828
+ },
829
+ /**
830
+ * Validates that the value is of Convex type Int64 (BigInt in JS).
831
+ */
832
+ int64: () => {
833
+ return new VInt64({ isOptional: "required" });
834
+ },
835
+ /**
836
+ * Validates that the value is of type Boolean.
837
+ */
838
+ boolean: () => {
839
+ return new VBoolean({ isOptional: "required" });
840
+ },
841
+ /**
842
+ * Validates that the value is of type String.
843
+ */
844
+ string: () => {
845
+ return new VString({ isOptional: "required" });
846
+ },
847
+ /**
848
+ * Validates that the value is of Convex type Bytes (constructed in JS via `ArrayBuffer`).
849
+ */
850
+ bytes: () => {
851
+ return new VBytes({ isOptional: "required" });
852
+ },
853
+ /**
854
+ * Validates that the value is equal to the given literal value.
855
+ * @param literal The literal value to compare against.
856
+ */
857
+ literal: (literal) => {
858
+ return new VLiteral({ isOptional: "required", value: literal });
859
+ },
860
+ /**
861
+ * Validates that the value is an Array of the given element type.
862
+ * @param element The validator for the elements of the array.
863
+ */
864
+ array: (element) => {
865
+ return new VArray({ isOptional: "required", element });
866
+ },
867
+ /**
868
+ * Validates that the value is an Object with the given properties.
869
+ * @param fields An object specifying the validator for each property.
870
+ */
871
+ object: (fields) => {
872
+ return new VObject({ isOptional: "required", fields });
873
+ },
874
+ /**
875
+ * Validates that the value is a Record with keys and values that match the given types.
876
+ * @param keys The validator for the keys of the record. This cannot contain string literals.
877
+ * @param values The validator for the values of the record.
878
+ */
879
+ record: (keys, values) => {
880
+ return new VRecord({
881
+ isOptional: "required",
882
+ key: keys,
883
+ value: values
884
+ });
885
+ },
886
+ /**
887
+ * Validates that the value matches one of the given validators.
888
+ * @param members The validators to match against.
889
+ */
890
+ union: (...members) => {
891
+ return new VUnion({
892
+ isOptional: "required",
893
+ members
894
+ });
895
+ },
896
+ /**
897
+ * Does not validate the value.
898
+ */
899
+ any: () => {
900
+ return new VAny({ isOptional: "required" });
901
+ },
902
+ /**
903
+ * Allows not specifying a value for a property in an Object.
904
+ * @param value The property value validator to make optional.
905
+ *
906
+ * ```typescript
907
+ * const objectWithOptionalFields = v.object({
908
+ * requiredField: v.string(),
909
+ * optionalField: v.optional(v.string()),
910
+ * });
911
+ * ```
912
+ */
913
+ optional: (value) => {
914
+ return value.asOptional();
915
+ },
916
+ /**
917
+ * Allows specifying a value or null.
918
+ */
919
+ nullable: (value) => {
920
+ return v.union(value, v.null());
921
+ }
922
+ };
923
+ var __defProp$c = Object.defineProperty;
924
+ var __defNormalProp$c = (obj, key, value) => key in obj ? __defProp$c(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
925
+ var __publicField$c = (obj, key, value) => __defNormalProp$c(obj, typeof key !== "symbol" ? key + "" : key, value);
926
+ var _a, _b;
927
+ const IDENTIFYING_FIELD = Symbol.for("ConvexError");
928
+ class ConvexError extends (_b = Error, _a = IDENTIFYING_FIELD, _b) {
929
+ constructor(data) {
930
+ super(typeof data === "string" ? data : stringifyValueForError(data));
931
+ __publicField$c(this, "name", "ConvexError");
932
+ __publicField$c(this, "data");
933
+ __publicField$c(this, _a, true);
934
+ this.data = data;
935
+ }
936
+ }
937
+ const version = "1.31.6";
938
+ var __defProp$b = Object.defineProperty;
939
+ var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
940
+ var __publicField$b = (obj, key, value) => __defNormalProp$b(obj, typeof key !== "symbol" ? key + "" : key, value);
941
+ const INFO_COLOR = "color:rgb(0, 145, 255)";
942
+ function prefix_for_source(source) {
943
+ switch (source) {
944
+ case "query":
945
+ return "Q";
946
+ case "mutation":
947
+ return "M";
948
+ case "action":
949
+ return "A";
950
+ case "any":
951
+ return "?";
952
+ }
953
+ }
954
+ class DefaultLogger {
955
+ constructor(options) {
956
+ __publicField$b(this, "_onLogLineFuncs");
957
+ __publicField$b(this, "_verbose");
958
+ this._onLogLineFuncs = {};
959
+ this._verbose = options.verbose;
960
+ }
961
+ addLogLineListener(func) {
962
+ let id = Math.random().toString(36).substring(2, 15);
963
+ for (let i = 0; i < 10; i++) {
964
+ if (this._onLogLineFuncs[id] === void 0) {
965
+ break;
966
+ }
967
+ id = Math.random().toString(36).substring(2, 15);
968
+ }
969
+ this._onLogLineFuncs[id] = func;
970
+ return () => {
971
+ delete this._onLogLineFuncs[id];
972
+ };
973
+ }
974
+ logVerbose(...args) {
975
+ if (this._verbose) {
976
+ for (const func of Object.values(this._onLogLineFuncs)) {
977
+ func("debug", `${(/* @__PURE__ */ new Date()).toISOString()}`, ...args);
978
+ }
979
+ }
980
+ }
981
+ log(...args) {
982
+ for (const func of Object.values(this._onLogLineFuncs)) {
983
+ func("info", ...args);
984
+ }
985
+ }
986
+ warn(...args) {
987
+ for (const func of Object.values(this._onLogLineFuncs)) {
988
+ func("warn", ...args);
989
+ }
990
+ }
991
+ error(...args) {
992
+ for (const func of Object.values(this._onLogLineFuncs)) {
993
+ func("error", ...args);
994
+ }
995
+ }
996
+ }
997
+ function instantiateDefaultLogger(options) {
998
+ const logger = new DefaultLogger(options);
999
+ logger.addLogLineListener((level, ...args) => {
1000
+ switch (level) {
1001
+ case "debug":
1002
+ console.debug(...args);
1003
+ break;
1004
+ case "info":
1005
+ console.log(...args);
1006
+ break;
1007
+ case "warn":
1008
+ console.warn(...args);
1009
+ break;
1010
+ case "error":
1011
+ console.error(...args);
1012
+ break;
1013
+ default: {
1014
+ console.log(...args);
1015
+ }
1016
+ }
1017
+ });
1018
+ return logger;
1019
+ }
1020
+ function instantiateNoopLogger(options) {
1021
+ return new DefaultLogger(options);
1022
+ }
1023
+ function logForFunction(logger, type, source, udfPath, message) {
1024
+ const prefix = prefix_for_source(source);
1025
+ if (typeof message === "object") {
1026
+ message = `ConvexError ${JSON.stringify(message.errorData, null, 2)}`;
1027
+ }
1028
+ if (type === "info") {
1029
+ const match = message.match(/^\[.*?\] /);
1030
+ if (match === null) {
1031
+ logger.error(
1032
+ `[CONVEX ${prefix}(${udfPath})] Could not parse console.log`
1033
+ );
1034
+ return;
1035
+ }
1036
+ const level = message.slice(1, match[0].length - 2);
1037
+ const args = message.slice(match[0].length);
1038
+ logger.log(`%c[CONVEX ${prefix}(${udfPath})] [${level}]`, INFO_COLOR, args);
1039
+ } else {
1040
+ logger.error(`[CONVEX ${prefix}(${udfPath})] ${message}`);
1041
+ }
1042
+ }
1043
+ function logFatalError(logger, message) {
1044
+ const errorMessage = `[CONVEX FATAL ERROR] ${message}`;
1045
+ logger.error(errorMessage);
1046
+ return new Error(errorMessage);
1047
+ }
1048
+ function createHybridErrorStacktrace(source, udfPath, result) {
1049
+ const prefix = prefix_for_source(source);
1050
+ return `[CONVEX ${prefix}(${udfPath})] ${result.errorMessage}
1051
+ Called by client`;
1052
+ }
1053
+ function forwardData(result, error) {
1054
+ error.data = result.errorData;
1055
+ return error;
1056
+ }
1057
+ function canonicalizeUdfPath(udfPath) {
1058
+ const pieces = udfPath.split(":");
1059
+ let moduleName;
1060
+ let functionName2;
1061
+ if (pieces.length === 1) {
1062
+ moduleName = pieces[0];
1063
+ functionName2 = "default";
1064
+ } else {
1065
+ moduleName = pieces.slice(0, pieces.length - 1).join(":");
1066
+ functionName2 = pieces[pieces.length - 1];
1067
+ }
1068
+ if (moduleName.endsWith(".js")) {
1069
+ moduleName = moduleName.slice(0, -3);
1070
+ }
1071
+ return `${moduleName}:${functionName2}`;
1072
+ }
1073
+ function serializePathAndArgs(udfPath, args) {
1074
+ return JSON.stringify({
1075
+ udfPath: canonicalizeUdfPath(udfPath),
1076
+ args: convexToJson(args)
1077
+ });
1078
+ }
1079
+ function serializePaginatedPathAndArgs(udfPath, args, options) {
1080
+ const { initialNumItems, id } = options;
1081
+ const result = JSON.stringify({
1082
+ type: "paginated",
1083
+ udfPath: canonicalizeUdfPath(udfPath),
1084
+ args: convexToJson(args),
1085
+ options: convexToJson({ initialNumItems, id })
1086
+ });
1087
+ return result;
1088
+ }
1089
+ var __defProp$a = Object.defineProperty;
1090
+ var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1091
+ var __publicField$a = (obj, key, value) => __defNormalProp$a(obj, typeof key !== "symbol" ? key + "" : key, value);
1092
+ class LocalSyncState {
1093
+ constructor() {
1094
+ __publicField$a(this, "nextQueryId");
1095
+ __publicField$a(this, "querySetVersion");
1096
+ __publicField$a(this, "querySet");
1097
+ __publicField$a(this, "queryIdToToken");
1098
+ __publicField$a(this, "identityVersion");
1099
+ __publicField$a(this, "auth");
1100
+ __publicField$a(this, "outstandingQueriesOlderThanRestart");
1101
+ __publicField$a(this, "outstandingAuthOlderThanRestart");
1102
+ __publicField$a(this, "paused");
1103
+ __publicField$a(this, "pendingQuerySetModifications");
1104
+ this.nextQueryId = 0;
1105
+ this.querySetVersion = 0;
1106
+ this.identityVersion = 0;
1107
+ this.querySet = /* @__PURE__ */ new Map();
1108
+ this.queryIdToToken = /* @__PURE__ */ new Map();
1109
+ this.outstandingQueriesOlderThanRestart = /* @__PURE__ */ new Set();
1110
+ this.outstandingAuthOlderThanRestart = false;
1111
+ this.paused = false;
1112
+ this.pendingQuerySetModifications = /* @__PURE__ */ new Map();
1113
+ }
1114
+ hasSyncedPastLastReconnect() {
1115
+ return this.outstandingQueriesOlderThanRestart.size === 0 && !this.outstandingAuthOlderThanRestart;
1116
+ }
1117
+ markAuthCompletion() {
1118
+ this.outstandingAuthOlderThanRestart = false;
1119
+ }
1120
+ subscribe(udfPath, args, journal, componentPath) {
1121
+ const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);
1122
+ const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);
1123
+ const existingEntry = this.querySet.get(queryToken);
1124
+ if (existingEntry !== void 0) {
1125
+ existingEntry.numSubscribers += 1;
1126
+ return {
1127
+ queryToken,
1128
+ modification: null,
1129
+ unsubscribe: () => this.removeSubscriber(queryToken)
1130
+ };
1131
+ } else {
1132
+ const queryId = this.nextQueryId++;
1133
+ const query = {
1134
+ id: queryId,
1135
+ canonicalizedUdfPath,
1136
+ args,
1137
+ numSubscribers: 1,
1138
+ journal,
1139
+ componentPath
1140
+ };
1141
+ this.querySet.set(queryToken, query);
1142
+ this.queryIdToToken.set(queryId, queryToken);
1143
+ const baseVersion = this.querySetVersion;
1144
+ const newVersion = this.querySetVersion + 1;
1145
+ const add = {
1146
+ type: "Add",
1147
+ queryId,
1148
+ udfPath: canonicalizedUdfPath,
1149
+ args: [convexToJson(args)],
1150
+ journal,
1151
+ componentPath
1152
+ };
1153
+ if (this.paused) {
1154
+ this.pendingQuerySetModifications.set(queryId, add);
1155
+ } else {
1156
+ this.querySetVersion = newVersion;
1157
+ }
1158
+ const modification = {
1159
+ type: "ModifyQuerySet",
1160
+ baseVersion,
1161
+ newVersion,
1162
+ modifications: [add]
1163
+ };
1164
+ return {
1165
+ queryToken,
1166
+ modification,
1167
+ unsubscribe: () => this.removeSubscriber(queryToken)
1168
+ };
1169
+ }
1170
+ }
1171
+ transition(transition) {
1172
+ for (const modification of transition.modifications) {
1173
+ switch (modification.type) {
1174
+ case "QueryUpdated":
1175
+ case "QueryFailed": {
1176
+ this.outstandingQueriesOlderThanRestart.delete(modification.queryId);
1177
+ const journal = modification.journal;
1178
+ if (journal !== void 0) {
1179
+ const queryToken = this.queryIdToToken.get(modification.queryId);
1180
+ if (queryToken !== void 0) {
1181
+ this.querySet.get(queryToken).journal = journal;
1182
+ }
1183
+ }
1184
+ break;
1185
+ }
1186
+ case "QueryRemoved": {
1187
+ this.outstandingQueriesOlderThanRestart.delete(modification.queryId);
1188
+ break;
1189
+ }
1190
+ default: {
1191
+ throw new Error(`Invalid modification ${modification.type}`);
1192
+ }
1193
+ }
1194
+ }
1195
+ }
1196
+ queryId(udfPath, args) {
1197
+ const canonicalizedUdfPath = canonicalizeUdfPath(udfPath);
1198
+ const queryToken = serializePathAndArgs(canonicalizedUdfPath, args);
1199
+ const existingEntry = this.querySet.get(queryToken);
1200
+ if (existingEntry !== void 0) {
1201
+ return existingEntry.id;
1202
+ }
1203
+ return null;
1204
+ }
1205
+ isCurrentOrNewerAuthVersion(version2) {
1206
+ return version2 >= this.identityVersion;
1207
+ }
1208
+ getAuth() {
1209
+ return this.auth;
1210
+ }
1211
+ setAuth(value) {
1212
+ this.auth = {
1213
+ tokenType: "User",
1214
+ value
1215
+ };
1216
+ const baseVersion = this.identityVersion;
1217
+ if (!this.paused) {
1218
+ this.identityVersion = baseVersion + 1;
1219
+ }
1220
+ return {
1221
+ type: "Authenticate",
1222
+ baseVersion,
1223
+ ...this.auth
1224
+ };
1225
+ }
1226
+ setAdminAuth(value, actingAs) {
1227
+ const auth = {
1228
+ tokenType: "Admin",
1229
+ value,
1230
+ impersonating: actingAs
1231
+ };
1232
+ this.auth = auth;
1233
+ const baseVersion = this.identityVersion;
1234
+ if (!this.paused) {
1235
+ this.identityVersion = baseVersion + 1;
1236
+ }
1237
+ return {
1238
+ type: "Authenticate",
1239
+ baseVersion,
1240
+ ...auth
1241
+ };
1242
+ }
1243
+ clearAuth() {
1244
+ this.auth = void 0;
1245
+ this.markAuthCompletion();
1246
+ const baseVersion = this.identityVersion;
1247
+ if (!this.paused) {
1248
+ this.identityVersion = baseVersion + 1;
1249
+ }
1250
+ return {
1251
+ type: "Authenticate",
1252
+ tokenType: "None",
1253
+ baseVersion
1254
+ };
1255
+ }
1256
+ hasAuth() {
1257
+ return !!this.auth;
1258
+ }
1259
+ isNewAuth(value) {
1260
+ return this.auth?.value !== value;
1261
+ }
1262
+ queryPath(queryId) {
1263
+ const pathAndArgs = this.queryIdToToken.get(queryId);
1264
+ if (pathAndArgs) {
1265
+ return this.querySet.get(pathAndArgs).canonicalizedUdfPath;
1266
+ }
1267
+ return null;
1268
+ }
1269
+ queryArgs(queryId) {
1270
+ const pathAndArgs = this.queryIdToToken.get(queryId);
1271
+ if (pathAndArgs) {
1272
+ return this.querySet.get(pathAndArgs).args;
1273
+ }
1274
+ return null;
1275
+ }
1276
+ queryToken(queryId) {
1277
+ return this.queryIdToToken.get(queryId) ?? null;
1278
+ }
1279
+ queryJournal(queryToken) {
1280
+ return this.querySet.get(queryToken)?.journal;
1281
+ }
1282
+ restart(oldRemoteQueryResults) {
1283
+ this.unpause();
1284
+ this.outstandingQueriesOlderThanRestart.clear();
1285
+ const modifications = [];
1286
+ for (const localQuery of this.querySet.values()) {
1287
+ const add = {
1288
+ type: "Add",
1289
+ queryId: localQuery.id,
1290
+ udfPath: localQuery.canonicalizedUdfPath,
1291
+ args: [convexToJson(localQuery.args)],
1292
+ journal: localQuery.journal,
1293
+ componentPath: localQuery.componentPath
1294
+ };
1295
+ modifications.push(add);
1296
+ if (!oldRemoteQueryResults.has(localQuery.id)) {
1297
+ this.outstandingQueriesOlderThanRestart.add(localQuery.id);
1298
+ }
1299
+ }
1300
+ this.querySetVersion = 1;
1301
+ const querySet = {
1302
+ type: "ModifyQuerySet",
1303
+ baseVersion: 0,
1304
+ newVersion: 1,
1305
+ modifications
1306
+ };
1307
+ if (!this.auth) {
1308
+ this.identityVersion = 0;
1309
+ return [querySet, void 0];
1310
+ }
1311
+ this.outstandingAuthOlderThanRestart = true;
1312
+ const authenticate = {
1313
+ type: "Authenticate",
1314
+ baseVersion: 0,
1315
+ ...this.auth
1316
+ };
1317
+ this.identityVersion = 1;
1318
+ return [querySet, authenticate];
1319
+ }
1320
+ pause() {
1321
+ this.paused = true;
1322
+ }
1323
+ resume() {
1324
+ const querySet = this.pendingQuerySetModifications.size > 0 ? {
1325
+ type: "ModifyQuerySet",
1326
+ baseVersion: this.querySetVersion,
1327
+ newVersion: ++this.querySetVersion,
1328
+ modifications: Array.from(
1329
+ this.pendingQuerySetModifications.values()
1330
+ )
1331
+ } : void 0;
1332
+ const authenticate = this.auth !== void 0 ? {
1333
+ type: "Authenticate",
1334
+ baseVersion: this.identityVersion++,
1335
+ ...this.auth
1336
+ } : void 0;
1337
+ this.unpause();
1338
+ return [querySet, authenticate];
1339
+ }
1340
+ unpause() {
1341
+ this.paused = false;
1342
+ this.pendingQuerySetModifications.clear();
1343
+ }
1344
+ removeSubscriber(queryToken) {
1345
+ const localQuery = this.querySet.get(queryToken);
1346
+ if (localQuery.numSubscribers > 1) {
1347
+ localQuery.numSubscribers -= 1;
1348
+ return null;
1349
+ } else {
1350
+ this.querySet.delete(queryToken);
1351
+ this.queryIdToToken.delete(localQuery.id);
1352
+ this.outstandingQueriesOlderThanRestart.delete(localQuery.id);
1353
+ const baseVersion = this.querySetVersion;
1354
+ const newVersion = this.querySetVersion + 1;
1355
+ const remove = {
1356
+ type: "Remove",
1357
+ queryId: localQuery.id
1358
+ };
1359
+ if (this.paused) {
1360
+ if (this.pendingQuerySetModifications.has(localQuery.id)) {
1361
+ this.pendingQuerySetModifications.delete(localQuery.id);
1362
+ } else {
1363
+ this.pendingQuerySetModifications.set(localQuery.id, remove);
1364
+ }
1365
+ } else {
1366
+ this.querySetVersion = newVersion;
1367
+ }
1368
+ return {
1369
+ type: "ModifyQuerySet",
1370
+ baseVersion,
1371
+ newVersion,
1372
+ modifications: [remove]
1373
+ };
1374
+ }
1375
+ }
1376
+ }
1377
+ var __defProp$9 = Object.defineProperty;
1378
+ var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1379
+ var __publicField$9 = (obj, key, value) => __defNormalProp$9(obj, typeof key !== "symbol" ? key + "" : key, value);
1380
+ class RequestManager {
1381
+ constructor(logger, markConnectionStateDirty) {
1382
+ this.logger = logger;
1383
+ this.markConnectionStateDirty = markConnectionStateDirty;
1384
+ __publicField$9(this, "inflightRequests");
1385
+ __publicField$9(this, "requestsOlderThanRestart");
1386
+ __publicField$9(this, "inflightMutationsCount", 0);
1387
+ __publicField$9(this, "inflightActionsCount", 0);
1388
+ this.inflightRequests = /* @__PURE__ */ new Map();
1389
+ this.requestsOlderThanRestart = /* @__PURE__ */ new Set();
1390
+ }
1391
+ request(message, sent) {
1392
+ const result = new Promise((resolve) => {
1393
+ const status = sent ? "Requested" : "NotSent";
1394
+ this.inflightRequests.set(message.requestId, {
1395
+ message,
1396
+ status: { status, requestedAt: /* @__PURE__ */ new Date(), onResult: resolve }
1397
+ });
1398
+ if (message.type === "Mutation") {
1399
+ this.inflightMutationsCount++;
1400
+ } else if (message.type === "Action") {
1401
+ this.inflightActionsCount++;
1402
+ }
1403
+ });
1404
+ this.markConnectionStateDirty();
1405
+ return result;
1406
+ }
1407
+ /**
1408
+ * Update the state after receiving a response.
1409
+ *
1410
+ * @returns A RequestId if the request is complete and its optimistic update
1411
+ * can be dropped, null otherwise.
1412
+ */
1413
+ onResponse(response) {
1414
+ const requestInfo = this.inflightRequests.get(response.requestId);
1415
+ if (requestInfo === void 0) {
1416
+ return null;
1417
+ }
1418
+ if (requestInfo.status.status === "Completed") {
1419
+ return null;
1420
+ }
1421
+ const udfType = requestInfo.message.type === "Mutation" ? "mutation" : "action";
1422
+ const udfPath = requestInfo.message.udfPath;
1423
+ for (const line of response.logLines) {
1424
+ logForFunction(this.logger, "info", udfType, udfPath, line);
1425
+ }
1426
+ const status = requestInfo.status;
1427
+ let result;
1428
+ let onResolve;
1429
+ if (response.success) {
1430
+ result = {
1431
+ success: true,
1432
+ logLines: response.logLines,
1433
+ value: jsonToConvex(response.result)
1434
+ };
1435
+ onResolve = () => status.onResult(result);
1436
+ } else {
1437
+ const errorMessage = response.result;
1438
+ const { errorData } = response;
1439
+ logForFunction(this.logger, "error", udfType, udfPath, errorMessage);
1440
+ result = {
1441
+ success: false,
1442
+ errorMessage,
1443
+ errorData: errorData !== void 0 ? jsonToConvex(errorData) : void 0,
1444
+ logLines: response.logLines
1445
+ };
1446
+ onResolve = () => status.onResult(result);
1447
+ }
1448
+ if (response.type === "ActionResponse" || !response.success) {
1449
+ onResolve();
1450
+ this.inflightRequests.delete(response.requestId);
1451
+ this.requestsOlderThanRestart.delete(response.requestId);
1452
+ if (requestInfo.message.type === "Action") {
1453
+ this.inflightActionsCount--;
1454
+ } else if (requestInfo.message.type === "Mutation") {
1455
+ this.inflightMutationsCount--;
1456
+ }
1457
+ this.markConnectionStateDirty();
1458
+ return { requestId: response.requestId, result };
1459
+ }
1460
+ requestInfo.status = {
1461
+ status: "Completed",
1462
+ result,
1463
+ ts: response.ts,
1464
+ onResolve
1465
+ };
1466
+ return null;
1467
+ }
1468
+ // Remove and returns completed requests.
1469
+ removeCompleted(ts) {
1470
+ const completeRequests = /* @__PURE__ */ new Map();
1471
+ for (const [requestId, requestInfo] of this.inflightRequests.entries()) {
1472
+ const status = requestInfo.status;
1473
+ if (status.status === "Completed" && status.ts.lessThanOrEqual(ts)) {
1474
+ status.onResolve();
1475
+ completeRequests.set(requestId, status.result);
1476
+ if (requestInfo.message.type === "Mutation") {
1477
+ this.inflightMutationsCount--;
1478
+ } else if (requestInfo.message.type === "Action") {
1479
+ this.inflightActionsCount--;
1480
+ }
1481
+ this.inflightRequests.delete(requestId);
1482
+ this.requestsOlderThanRestart.delete(requestId);
1483
+ }
1484
+ }
1485
+ if (completeRequests.size > 0) {
1486
+ this.markConnectionStateDirty();
1487
+ }
1488
+ return completeRequests;
1489
+ }
1490
+ restart() {
1491
+ this.requestsOlderThanRestart = new Set(this.inflightRequests.keys());
1492
+ const allMessages = [];
1493
+ for (const [requestId, value] of this.inflightRequests) {
1494
+ if (value.status.status === "NotSent") {
1495
+ value.status.status = "Requested";
1496
+ allMessages.push(value.message);
1497
+ continue;
1498
+ }
1499
+ if (value.message.type === "Mutation") {
1500
+ allMessages.push(value.message);
1501
+ } else if (value.message.type === "Action") {
1502
+ this.inflightRequests.delete(requestId);
1503
+ this.requestsOlderThanRestart.delete(requestId);
1504
+ this.inflightActionsCount--;
1505
+ if (value.status.status === "Completed") {
1506
+ throw new Error("Action should never be in 'Completed' state");
1507
+ }
1508
+ value.status.onResult({
1509
+ success: false,
1510
+ errorMessage: "Connection lost while action was in flight",
1511
+ logLines: []
1512
+ });
1513
+ }
1514
+ }
1515
+ this.markConnectionStateDirty();
1516
+ return allMessages;
1517
+ }
1518
+ resume() {
1519
+ const allMessages = [];
1520
+ for (const [, value] of this.inflightRequests) {
1521
+ if (value.status.status === "NotSent") {
1522
+ value.status.status = "Requested";
1523
+ allMessages.push(value.message);
1524
+ continue;
1525
+ }
1526
+ }
1527
+ return allMessages;
1528
+ }
1529
+ /**
1530
+ * @returns true if there are any requests that have been requested but have
1531
+ * not be completed yet.
1532
+ */
1533
+ hasIncompleteRequests() {
1534
+ for (const requestInfo of this.inflightRequests.values()) {
1535
+ if (requestInfo.status.status === "Requested") {
1536
+ return true;
1537
+ }
1538
+ }
1539
+ return false;
1540
+ }
1541
+ /**
1542
+ * @returns true if there are any inflight requests, including ones that have
1543
+ * completed on the server, but have not been applied.
1544
+ */
1545
+ hasInflightRequests() {
1546
+ return this.inflightRequests.size > 0;
1547
+ }
1548
+ /**
1549
+ * @returns true if there are any inflight requests, that have been hanging around
1550
+ * since prior to the most recent restart.
1551
+ */
1552
+ hasSyncedPastLastReconnect() {
1553
+ return this.requestsOlderThanRestart.size === 0;
1554
+ }
1555
+ timeOfOldestInflightRequest() {
1556
+ if (this.inflightRequests.size === 0) {
1557
+ return null;
1558
+ }
1559
+ let oldestInflightRequest = Date.now();
1560
+ for (const request of this.inflightRequests.values()) {
1561
+ if (request.status.status !== "Completed") {
1562
+ if (request.status.requestedAt.getTime() < oldestInflightRequest) {
1563
+ oldestInflightRequest = request.status.requestedAt.getTime();
1564
+ }
1565
+ }
1566
+ }
1567
+ return new Date(oldestInflightRequest);
1568
+ }
1569
+ /**
1570
+ * @returns The number of mutations currently in flight.
1571
+ */
1572
+ inflightMutations() {
1573
+ return this.inflightMutationsCount;
1574
+ }
1575
+ /**
1576
+ * @returns The number of actions currently in flight.
1577
+ */
1578
+ inflightActions() {
1579
+ return this.inflightActionsCount;
1580
+ }
1581
+ }
1582
+ const functionName = Symbol.for("functionName");
1583
+ const toReferencePath = Symbol.for("toReferencePath");
1584
+ function extractReferencePath(reference) {
1585
+ return reference[toReferencePath] ?? null;
1586
+ }
1587
+ function isFunctionHandle(s) {
1588
+ return s.startsWith("function://");
1589
+ }
1590
+ function getFunctionAddress(functionReference) {
1591
+ let functionAddress;
1592
+ if (typeof functionReference === "string") {
1593
+ if (isFunctionHandle(functionReference)) {
1594
+ functionAddress = { functionHandle: functionReference };
1595
+ } else {
1596
+ functionAddress = { name: functionReference };
1597
+ }
1598
+ } else if (functionReference[functionName]) {
1599
+ functionAddress = { name: functionReference[functionName] };
1600
+ } else {
1601
+ const referencePath = extractReferencePath(functionReference);
1602
+ if (!referencePath) {
1603
+ throw new Error(`${functionReference} is not a functionReference`);
1604
+ }
1605
+ functionAddress = { reference: referencePath };
1606
+ }
1607
+ return functionAddress;
1608
+ }
1609
+ function getFunctionName(functionReference) {
1610
+ const address = getFunctionAddress(functionReference);
1611
+ if (address.name === void 0) {
1612
+ if (address.functionHandle !== void 0) {
1613
+ throw new Error(
1614
+ `Expected function reference like "api.file.func" or "internal.file.func", but received function handle ${address.functionHandle}`
1615
+ );
1616
+ } else if (address.reference !== void 0) {
1617
+ throw new Error(
1618
+ `Expected function reference in the current component like "api.file.func" or "internal.file.func", but received reference ${address.reference}`
1619
+ );
1620
+ }
1621
+ throw new Error(
1622
+ `Expected function reference like "api.file.func" or "internal.file.func", but received ${JSON.stringify(address)}`
1623
+ );
1624
+ }
1625
+ if (typeof functionReference === "string") return functionReference;
1626
+ const name = functionReference[functionName];
1627
+ if (!name) {
1628
+ throw new Error(`${functionReference} is not a functionReference`);
1629
+ }
1630
+ return name;
1631
+ }
1632
+ function makeFunctionReference(name) {
1633
+ return { [functionName]: name };
1634
+ }
1635
+ function createApi(pathParts = []) {
1636
+ const handler = {
1637
+ get(_, prop) {
1638
+ if (typeof prop === "string") {
1639
+ const newParts = [...pathParts, prop];
1640
+ return createApi(newParts);
1641
+ } else if (prop === functionName) {
1642
+ if (pathParts.length < 2) {
1643
+ const found = ["api", ...pathParts].join(".");
1644
+ throw new Error(
1645
+ `API path is expected to be of the form \`api.moduleName.functionName\`. Found: \`${found}\``
1646
+ );
1647
+ }
1648
+ const path = pathParts.slice(0, -1).join("/");
1649
+ const exportName = pathParts[pathParts.length - 1];
1650
+ if (exportName === "default") {
1651
+ return path;
1652
+ } else {
1653
+ return path + ":" + exportName;
1654
+ }
1655
+ } else if (prop === Symbol.toStringTag) {
1656
+ return "FunctionReference";
1657
+ } else {
1658
+ return void 0;
1659
+ }
1660
+ }
1661
+ };
1662
+ return new Proxy({}, handler);
1663
+ }
1664
+ const anyApi = createApi();
1665
+ var __defProp$8 = Object.defineProperty;
1666
+ var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1667
+ var __publicField$8 = (obj, key, value) => __defNormalProp$8(obj, typeof key !== "symbol" ? key + "" : key, value);
1668
+ class OptimisticLocalStoreImpl {
1669
+ constructor(queryResults) {
1670
+ __publicField$8(this, "queryResults");
1671
+ __publicField$8(this, "modifiedQueries");
1672
+ this.queryResults = queryResults;
1673
+ this.modifiedQueries = [];
1674
+ }
1675
+ getQuery(query, ...args) {
1676
+ const queryArgs = parseArgs(args[0]);
1677
+ const name = getFunctionName(query);
1678
+ const queryResult = this.queryResults.get(
1679
+ serializePathAndArgs(name, queryArgs)
1680
+ );
1681
+ if (queryResult === void 0) {
1682
+ return void 0;
1683
+ }
1684
+ return OptimisticLocalStoreImpl.queryValue(queryResult.result);
1685
+ }
1686
+ getAllQueries(query) {
1687
+ const queriesWithName = [];
1688
+ const name = getFunctionName(query);
1689
+ for (const queryResult of this.queryResults.values()) {
1690
+ if (queryResult.udfPath === canonicalizeUdfPath(name)) {
1691
+ queriesWithName.push({
1692
+ args: queryResult.args,
1693
+ value: OptimisticLocalStoreImpl.queryValue(queryResult.result)
1694
+ });
1695
+ }
1696
+ }
1697
+ return queriesWithName;
1698
+ }
1699
+ setQuery(queryReference, args, value) {
1700
+ const queryArgs = parseArgs(args);
1701
+ const name = getFunctionName(queryReference);
1702
+ const queryToken = serializePathAndArgs(name, queryArgs);
1703
+ let result;
1704
+ if (value === void 0) {
1705
+ result = void 0;
1706
+ } else {
1707
+ result = {
1708
+ success: true,
1709
+ value,
1710
+ // It's an optimistic update, so there are no function logs to show.
1711
+ logLines: []
1712
+ };
1713
+ }
1714
+ const query = {
1715
+ udfPath: name,
1716
+ args: queryArgs,
1717
+ result
1718
+ };
1719
+ this.queryResults.set(queryToken, query);
1720
+ this.modifiedQueries.push(queryToken);
1721
+ }
1722
+ static queryValue(result) {
1723
+ if (result === void 0) {
1724
+ return void 0;
1725
+ } else if (result.success) {
1726
+ return result.value;
1727
+ } else {
1728
+ return void 0;
1729
+ }
1730
+ }
1731
+ }
1732
+ class OptimisticQueryResults {
1733
+ constructor() {
1734
+ __publicField$8(this, "queryResults");
1735
+ __publicField$8(this, "optimisticUpdates");
1736
+ this.queryResults = /* @__PURE__ */ new Map();
1737
+ this.optimisticUpdates = [];
1738
+ }
1739
+ /**
1740
+ * Apply all optimistic updates on top of server query results
1741
+ */
1742
+ ingestQueryResultsFromServer(serverQueryResults, optimisticUpdatesToDrop) {
1743
+ this.optimisticUpdates = this.optimisticUpdates.filter((updateAndId) => {
1744
+ return !optimisticUpdatesToDrop.has(updateAndId.mutationId);
1745
+ });
1746
+ const oldQueryResults = this.queryResults;
1747
+ this.queryResults = new Map(serverQueryResults);
1748
+ const localStore = new OptimisticLocalStoreImpl(this.queryResults);
1749
+ for (const updateAndId of this.optimisticUpdates) {
1750
+ updateAndId.update(localStore);
1751
+ }
1752
+ const changedQueries = [];
1753
+ for (const [queryToken, query] of this.queryResults) {
1754
+ const oldQuery = oldQueryResults.get(queryToken);
1755
+ if (oldQuery === void 0 || oldQuery.result !== query.result) {
1756
+ changedQueries.push(queryToken);
1757
+ }
1758
+ }
1759
+ return changedQueries;
1760
+ }
1761
+ applyOptimisticUpdate(update, mutationId) {
1762
+ this.optimisticUpdates.push({
1763
+ update,
1764
+ mutationId
1765
+ });
1766
+ const localStore = new OptimisticLocalStoreImpl(this.queryResults);
1767
+ update(localStore);
1768
+ return localStore.modifiedQueries;
1769
+ }
1770
+ /**
1771
+ * "Raw" with respect to errors vs values, but query results still have
1772
+ * optimistic updates applied.
1773
+ *
1774
+ * @internal
1775
+ */
1776
+ rawQueryResult(queryToken) {
1777
+ const query = this.queryResults.get(queryToken);
1778
+ if (query === void 0) {
1779
+ return void 0;
1780
+ }
1781
+ return query.result;
1782
+ }
1783
+ queryResult(queryToken) {
1784
+ const query = this.queryResults.get(queryToken);
1785
+ if (query === void 0) {
1786
+ return void 0;
1787
+ }
1788
+ const result = query.result;
1789
+ if (result === void 0) {
1790
+ return void 0;
1791
+ } else if (result.success) {
1792
+ return result.value;
1793
+ } else {
1794
+ if (result.errorData !== void 0) {
1795
+ throw forwardData(
1796
+ result,
1797
+ new ConvexError(
1798
+ createHybridErrorStacktrace("query", query.udfPath, result)
1799
+ )
1800
+ );
1801
+ }
1802
+ throw new Error(
1803
+ createHybridErrorStacktrace("query", query.udfPath, result)
1804
+ );
1805
+ }
1806
+ }
1807
+ hasQueryResult(queryToken) {
1808
+ return this.queryResults.get(queryToken) !== void 0;
1809
+ }
1810
+ /**
1811
+ * @internal
1812
+ */
1813
+ queryLogs(queryToken) {
1814
+ const query = this.queryResults.get(queryToken);
1815
+ return query?.result?.logLines;
1816
+ }
1817
+ }
1818
+ var __defProp$7 = Object.defineProperty;
1819
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1820
+ var __publicField$7 = (obj, key, value) => __defNormalProp$7(obj, typeof key !== "symbol" ? key + "" : key, value);
1821
+ class Long {
1822
+ constructor(low, high) {
1823
+ __publicField$7(this, "low");
1824
+ __publicField$7(this, "high");
1825
+ __publicField$7(this, "__isUnsignedLong__");
1826
+ this.low = low | 0;
1827
+ this.high = high | 0;
1828
+ this.__isUnsignedLong__ = true;
1829
+ }
1830
+ static isLong(obj) {
1831
+ return (obj && obj.__isUnsignedLong__) === true;
1832
+ }
1833
+ // prettier-ignore
1834
+ static fromBytesLE(bytes) {
1835
+ return new Long(
1836
+ bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24,
1837
+ bytes[4] | bytes[5] << 8 | bytes[6] << 16 | bytes[7] << 24
1838
+ );
1839
+ }
1840
+ // prettier-ignore
1841
+ toBytesLE() {
1842
+ const hi = this.high;
1843
+ const lo = this.low;
1844
+ return [
1845
+ lo & 255,
1846
+ lo >>> 8 & 255,
1847
+ lo >>> 16 & 255,
1848
+ lo >>> 24,
1849
+ hi & 255,
1850
+ hi >>> 8 & 255,
1851
+ hi >>> 16 & 255,
1852
+ hi >>> 24
1853
+ ];
1854
+ }
1855
+ static fromNumber(value) {
1856
+ if (isNaN(value)) return UZERO;
1857
+ if (value < 0) return UZERO;
1858
+ if (value >= TWO_PWR_64_DBL) return MAX_UNSIGNED_VALUE;
1859
+ return new Long(value % TWO_PWR_32_DBL | 0, value / TWO_PWR_32_DBL | 0);
1860
+ }
1861
+ toString() {
1862
+ return (BigInt(this.high) * BigInt(TWO_PWR_32_DBL) + BigInt(this.low)).toString();
1863
+ }
1864
+ equals(other) {
1865
+ if (!Long.isLong(other)) other = Long.fromValue(other);
1866
+ if (this.high >>> 31 === 1 && other.high >>> 31 === 1) return false;
1867
+ return this.high === other.high && this.low === other.low;
1868
+ }
1869
+ notEquals(other) {
1870
+ return !this.equals(other);
1871
+ }
1872
+ comp(other) {
1873
+ if (!Long.isLong(other)) other = Long.fromValue(other);
1874
+ if (this.equals(other)) return 0;
1875
+ return other.high >>> 0 > this.high >>> 0 || other.high === this.high && other.low >>> 0 > this.low >>> 0 ? -1 : 1;
1876
+ }
1877
+ lessThanOrEqual(other) {
1878
+ return this.comp(
1879
+ /* validates */
1880
+ other
1881
+ ) <= 0;
1882
+ }
1883
+ static fromValue(val) {
1884
+ if (typeof val === "number") return Long.fromNumber(val);
1885
+ return new Long(val.low, val.high);
1886
+ }
1887
+ }
1888
+ const UZERO = new Long(0, 0);
1889
+ const TWO_PWR_16_DBL = 1 << 16;
1890
+ const TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL;
1891
+ const TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL;
1892
+ const MAX_UNSIGNED_VALUE = new Long(4294967295 | 0, 4294967295 | 0);
1893
+ var __defProp$6 = Object.defineProperty;
1894
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1895
+ var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
1896
+ class RemoteQuerySet {
1897
+ constructor(queryPath, logger) {
1898
+ __publicField$6(this, "version");
1899
+ __publicField$6(this, "remoteQuerySet");
1900
+ __publicField$6(this, "queryPath");
1901
+ __publicField$6(this, "logger");
1902
+ this.version = { querySet: 0, ts: Long.fromNumber(0), identity: 0 };
1903
+ this.remoteQuerySet = /* @__PURE__ */ new Map();
1904
+ this.queryPath = queryPath;
1905
+ this.logger = logger;
1906
+ }
1907
+ transition(transition) {
1908
+ const start = transition.startVersion;
1909
+ if (this.version.querySet !== start.querySet || this.version.ts.notEquals(start.ts) || this.version.identity !== start.identity) {
1910
+ throw new Error(
1911
+ `Invalid start version: ${start.ts.toString()}:${start.querySet}:${start.identity}, transitioning from ${this.version.ts.toString()}:${this.version.querySet}:${this.version.identity}`
1912
+ );
1913
+ }
1914
+ for (const modification of transition.modifications) {
1915
+ switch (modification.type) {
1916
+ case "QueryUpdated": {
1917
+ const queryPath = this.queryPath(modification.queryId);
1918
+ if (queryPath) {
1919
+ for (const line of modification.logLines) {
1920
+ logForFunction(this.logger, "info", "query", queryPath, line);
1921
+ }
1922
+ }
1923
+ const value = jsonToConvex(modification.value ?? null);
1924
+ this.remoteQuerySet.set(modification.queryId, {
1925
+ success: true,
1926
+ value,
1927
+ logLines: modification.logLines
1928
+ });
1929
+ break;
1930
+ }
1931
+ case "QueryFailed": {
1932
+ const queryPath = this.queryPath(modification.queryId);
1933
+ if (queryPath) {
1934
+ for (const line of modification.logLines) {
1935
+ logForFunction(this.logger, "info", "query", queryPath, line);
1936
+ }
1937
+ }
1938
+ const { errorData } = modification;
1939
+ this.remoteQuerySet.set(modification.queryId, {
1940
+ success: false,
1941
+ errorMessage: modification.errorMessage,
1942
+ errorData: errorData !== void 0 ? jsonToConvex(errorData) : void 0,
1943
+ logLines: modification.logLines
1944
+ });
1945
+ break;
1946
+ }
1947
+ case "QueryRemoved": {
1948
+ this.remoteQuerySet.delete(modification.queryId);
1949
+ break;
1950
+ }
1951
+ default: {
1952
+ throw new Error(`Invalid modification ${modification.type}`);
1953
+ }
1954
+ }
1955
+ }
1956
+ this.version = transition.endVersion;
1957
+ }
1958
+ remoteQueryResults() {
1959
+ return this.remoteQuerySet;
1960
+ }
1961
+ timestamp() {
1962
+ return this.version.ts;
1963
+ }
1964
+ }
1965
+ function u64ToLong(encoded) {
1966
+ const integerBytes = toByteArray(encoded);
1967
+ return Long.fromBytesLE(Array.from(integerBytes));
1968
+ }
1969
+ function longToU64(raw) {
1970
+ const integerBytes = new Uint8Array(raw.toBytesLE());
1971
+ return fromByteArray(integerBytes);
1972
+ }
1973
+ function parseServerMessage(encoded) {
1974
+ switch (encoded.type) {
1975
+ case "FatalError":
1976
+ case "AuthError":
1977
+ case "ActionResponse":
1978
+ case "TransitionChunk":
1979
+ case "Ping": {
1980
+ return { ...encoded };
1981
+ }
1982
+ case "MutationResponse": {
1983
+ if (encoded.success) {
1984
+ return { ...encoded, ts: u64ToLong(encoded.ts) };
1985
+ } else {
1986
+ return { ...encoded };
1987
+ }
1988
+ }
1989
+ case "Transition": {
1990
+ return {
1991
+ ...encoded,
1992
+ startVersion: {
1993
+ ...encoded.startVersion,
1994
+ ts: u64ToLong(encoded.startVersion.ts)
1995
+ },
1996
+ endVersion: {
1997
+ ...encoded.endVersion,
1998
+ ts: u64ToLong(encoded.endVersion.ts)
1999
+ }
2000
+ };
2001
+ }
2002
+ }
2003
+ return void 0;
2004
+ }
2005
+ function encodeClientMessage(message) {
2006
+ switch (message.type) {
2007
+ case "Authenticate":
2008
+ case "ModifyQuerySet":
2009
+ case "Mutation":
2010
+ case "Action":
2011
+ case "Event": {
2012
+ return { ...message };
2013
+ }
2014
+ case "Connect": {
2015
+ if (message.maxObservedTimestamp !== void 0) {
2016
+ return {
2017
+ ...message,
2018
+ maxObservedTimestamp: longToU64(message.maxObservedTimestamp)
2019
+ };
2020
+ } else {
2021
+ return { ...message, maxObservedTimestamp: void 0 };
2022
+ }
2023
+ }
2024
+ }
2025
+ return void 0;
2026
+ }
2027
+ var __defProp$5 = Object.defineProperty;
2028
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2029
+ var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
2030
+ const CLOSE_NORMAL = 1e3;
2031
+ const CLOSE_GOING_AWAY = 1001;
2032
+ const CLOSE_NO_STATUS = 1005;
2033
+ const CLOSE_NOT_FOUND = 4040;
2034
+ let firstTime;
2035
+ function monotonicMillis() {
2036
+ if (firstTime === void 0) {
2037
+ firstTime = Date.now();
2038
+ }
2039
+ if (typeof performance === "undefined" || !performance.now) {
2040
+ return Date.now();
2041
+ }
2042
+ return Math.round(firstTime + performance.now());
2043
+ }
2044
+ function prettyNow() {
2045
+ return `t=${Math.round((monotonicMillis() - firstTime) / 100) / 10}s`;
2046
+ }
2047
+ const serverDisconnectErrors = {
2048
+ // A known error, e.g. during a restart or push
2049
+ InternalServerError: { timeout: 1e3 },
2050
+ // ErrorMetadata::overloaded() messages that we realy should back off
2051
+ SubscriptionsWorkerFullError: { timeout: 3e3 },
2052
+ TooManyConcurrentRequests: { timeout: 3e3 },
2053
+ CommitterFullError: { timeout: 3e3 },
2054
+ AwsTooManyRequestsException: { timeout: 3e3 },
2055
+ ExecuteFullError: { timeout: 3e3 },
2056
+ SystemTimeoutError: { timeout: 3e3 },
2057
+ ExpiredInQueue: { timeout: 3e3 },
2058
+ // ErrorMetadata::feature_temporarily_unavailable() that typically indicate a deploy just happened
2059
+ VectorIndexesUnavailable: { timeout: 1e3 },
2060
+ SearchIndexesUnavailable: { timeout: 1e3 },
2061
+ TableSummariesUnavailable: { timeout: 1e3 },
2062
+ // More ErrorMetadata::overloaded()
2063
+ VectorIndexTooLarge: { timeout: 3e3 },
2064
+ SearchIndexTooLarge: { timeout: 3e3 },
2065
+ TooManyWritesInTimePeriod: { timeout: 3e3 }
2066
+ };
2067
+ function classifyDisconnectError(s) {
2068
+ if (s === void 0) return "Unknown";
2069
+ for (const prefix of Object.keys(
2070
+ serverDisconnectErrors
2071
+ )) {
2072
+ if (s.startsWith(prefix)) {
2073
+ return prefix;
2074
+ }
2075
+ }
2076
+ return "Unknown";
2077
+ }
2078
+ class WebSocketManager {
2079
+ constructor(uri, callbacks, webSocketConstructor, logger, markConnectionStateDirty, debug) {
2080
+ this.markConnectionStateDirty = markConnectionStateDirty;
2081
+ this.debug = debug;
2082
+ __publicField$5(this, "socket");
2083
+ __publicField$5(this, "connectionCount");
2084
+ __publicField$5(this, "_hasEverConnected", false);
2085
+ __publicField$5(this, "lastCloseReason");
2086
+ __publicField$5(this, "transitionChunkBuffer", null);
2087
+ __publicField$5(this, "defaultInitialBackoff");
2088
+ __publicField$5(this, "maxBackoff");
2089
+ __publicField$5(this, "retries");
2090
+ __publicField$5(this, "serverInactivityThreshold");
2091
+ __publicField$5(this, "reconnectDueToServerInactivityTimeout");
2092
+ __publicField$5(this, "scheduledReconnect", null);
2093
+ __publicField$5(this, "networkOnlineHandler", null);
2094
+ __publicField$5(this, "pendingNetworkRecoveryInfo", null);
2095
+ __publicField$5(this, "uri");
2096
+ __publicField$5(this, "onOpen");
2097
+ __publicField$5(this, "onResume");
2098
+ __publicField$5(this, "onMessage");
2099
+ __publicField$5(this, "webSocketConstructor");
2100
+ __publicField$5(this, "logger");
2101
+ __publicField$5(this, "onServerDisconnectError");
2102
+ this.webSocketConstructor = webSocketConstructor;
2103
+ this.socket = { state: "disconnected" };
2104
+ this.connectionCount = 0;
2105
+ this.lastCloseReason = "InitialConnect";
2106
+ this.defaultInitialBackoff = 1e3;
2107
+ this.maxBackoff = 16e3;
2108
+ this.retries = 0;
2109
+ this.serverInactivityThreshold = 6e4;
2110
+ this.reconnectDueToServerInactivityTimeout = null;
2111
+ this.uri = uri;
2112
+ this.onOpen = callbacks.onOpen;
2113
+ this.onResume = callbacks.onResume;
2114
+ this.onMessage = callbacks.onMessage;
2115
+ this.onServerDisconnectError = callbacks.onServerDisconnectError;
2116
+ this.logger = logger;
2117
+ this.setupNetworkListener();
2118
+ this.connect();
2119
+ }
2120
+ setSocketState(state) {
2121
+ this.socket = state;
2122
+ this._logVerbose(
2123
+ `socket state changed: ${this.socket.state}, paused: ${"paused" in this.socket ? this.socket.paused : void 0}`
2124
+ );
2125
+ this.markConnectionStateDirty();
2126
+ }
2127
+ setupNetworkListener() {
2128
+ if (typeof window === "undefined" || typeof window.addEventListener !== "function") {
2129
+ return;
2130
+ }
2131
+ if (this.networkOnlineHandler !== null) {
2132
+ return;
2133
+ }
2134
+ this.networkOnlineHandler = () => {
2135
+ this._logVerbose("network online event detected");
2136
+ this.tryReconnectImmediately();
2137
+ };
2138
+ window.addEventListener("online", this.networkOnlineHandler);
2139
+ this._logVerbose("network online event listener registered");
2140
+ }
2141
+ cleanupNetworkListener() {
2142
+ if (this.networkOnlineHandler && typeof window !== "undefined" && typeof window.removeEventListener === "function") {
2143
+ window.removeEventListener("online", this.networkOnlineHandler);
2144
+ this.networkOnlineHandler = null;
2145
+ this._logVerbose("network online event listener removed");
2146
+ }
2147
+ }
2148
+ assembleTransition(chunk) {
2149
+ if (chunk.partNumber < 0 || chunk.partNumber >= chunk.totalParts || chunk.totalParts === 0 || this.transitionChunkBuffer && (this.transitionChunkBuffer.totalParts !== chunk.totalParts || this.transitionChunkBuffer.transitionId !== chunk.transitionId)) {
2150
+ this.transitionChunkBuffer = null;
2151
+ throw new Error("Invalid TransitionChunk");
2152
+ }
2153
+ if (this.transitionChunkBuffer === null) {
2154
+ this.transitionChunkBuffer = {
2155
+ chunks: [],
2156
+ totalParts: chunk.totalParts,
2157
+ transitionId: chunk.transitionId
2158
+ };
2159
+ }
2160
+ if (chunk.partNumber !== this.transitionChunkBuffer.chunks.length) {
2161
+ const expectedLength = this.transitionChunkBuffer.chunks.length;
2162
+ this.transitionChunkBuffer = null;
2163
+ throw new Error(
2164
+ `TransitionChunk received out of order: expected part ${expectedLength}, got ${chunk.partNumber}`
2165
+ );
2166
+ }
2167
+ this.transitionChunkBuffer.chunks.push(chunk.chunk);
2168
+ if (this.transitionChunkBuffer.chunks.length === chunk.totalParts) {
2169
+ const fullJson = this.transitionChunkBuffer.chunks.join("");
2170
+ this.transitionChunkBuffer = null;
2171
+ const transition = parseServerMessage(JSON.parse(fullJson));
2172
+ if (transition.type !== "Transition") {
2173
+ throw new Error(
2174
+ `Expected Transition, got ${transition.type} after assembling chunks`
2175
+ );
2176
+ }
2177
+ return transition;
2178
+ }
2179
+ return null;
2180
+ }
2181
+ connect() {
2182
+ if (this.socket.state === "terminated") {
2183
+ return;
2184
+ }
2185
+ if (this.socket.state !== "disconnected" && this.socket.state !== "stopped") {
2186
+ throw new Error(
2187
+ "Didn't start connection from disconnected state: " + this.socket.state
2188
+ );
2189
+ }
2190
+ const ws = new this.webSocketConstructor(this.uri);
2191
+ this._logVerbose("constructed WebSocket");
2192
+ this.setSocketState({
2193
+ state: "connecting",
2194
+ ws,
2195
+ paused: "no"
2196
+ });
2197
+ this.resetServerInactivityTimeout();
2198
+ ws.onopen = () => {
2199
+ this.logger.logVerbose("begin ws.onopen");
2200
+ if (this.socket.state !== "connecting") {
2201
+ throw new Error("onopen called with socket not in connecting state");
2202
+ }
2203
+ this.setSocketState({
2204
+ state: "ready",
2205
+ ws,
2206
+ paused: this.socket.paused === "yes" ? "uninitialized" : "no"
2207
+ });
2208
+ this.resetServerInactivityTimeout();
2209
+ if (this.socket.paused === "no") {
2210
+ this._hasEverConnected = true;
2211
+ this.onOpen({
2212
+ connectionCount: this.connectionCount,
2213
+ lastCloseReason: this.lastCloseReason,
2214
+ clientTs: monotonicMillis()
2215
+ });
2216
+ }
2217
+ if (this.lastCloseReason !== "InitialConnect") {
2218
+ if (this.lastCloseReason) {
2219
+ this.logger.log(
2220
+ "WebSocket reconnected at",
2221
+ prettyNow(),
2222
+ "after disconnect due to",
2223
+ this.lastCloseReason
2224
+ );
2225
+ } else {
2226
+ this.logger.log("WebSocket reconnected at", prettyNow());
2227
+ }
2228
+ }
2229
+ this.connectionCount += 1;
2230
+ this.lastCloseReason = null;
2231
+ if (this.pendingNetworkRecoveryInfo !== null) {
2232
+ const { timeSavedMs } = this.pendingNetworkRecoveryInfo;
2233
+ this.pendingNetworkRecoveryInfo = null;
2234
+ this.sendMessage({
2235
+ type: "Event",
2236
+ eventType: "NetworkRecoveryReconnect",
2237
+ event: { timeSavedMs }
2238
+ });
2239
+ this.logger.log(
2240
+ `Network recovery reconnect saved ~${Math.round(timeSavedMs / 1e3)}s of waiting`
2241
+ );
2242
+ }
2243
+ };
2244
+ ws.onerror = (error) => {
2245
+ this.transitionChunkBuffer = null;
2246
+ const message = error.message;
2247
+ if (message) {
2248
+ this.logger.log(`WebSocket error message: ${message}`);
2249
+ }
2250
+ };
2251
+ ws.onmessage = (message) => {
2252
+ this.resetServerInactivityTimeout();
2253
+ const messageLength = message.data.length;
2254
+ let serverMessage = parseServerMessage(JSON.parse(message.data));
2255
+ this._logVerbose(`received ws message with type ${serverMessage.type}`);
2256
+ if (serverMessage.type === "Ping") {
2257
+ return;
2258
+ }
2259
+ if (serverMessage.type === "TransitionChunk") {
2260
+ const transition = this.assembleTransition(serverMessage);
2261
+ if (!transition) {
2262
+ return;
2263
+ }
2264
+ serverMessage = transition;
2265
+ this._logVerbose(
2266
+ `assembled full ws message of type ${serverMessage.type}`
2267
+ );
2268
+ }
2269
+ if (this.transitionChunkBuffer !== null) {
2270
+ this.transitionChunkBuffer = null;
2271
+ this.logger.log(
2272
+ `Received unexpected ${serverMessage.type} while buffering TransitionChunks`
2273
+ );
2274
+ }
2275
+ if (serverMessage.type === "Transition") {
2276
+ this.reportLargeTransition({
2277
+ messageLength,
2278
+ transition: serverMessage
2279
+ });
2280
+ }
2281
+ const response = this.onMessage(serverMessage);
2282
+ if (response.hasSyncedPastLastReconnect) {
2283
+ this.retries = 0;
2284
+ this.markConnectionStateDirty();
2285
+ }
2286
+ };
2287
+ ws.onclose = (event) => {
2288
+ this._logVerbose("begin ws.onclose");
2289
+ this.transitionChunkBuffer = null;
2290
+ if (this.lastCloseReason === null) {
2291
+ this.lastCloseReason = event.reason || `closed with code ${event.code}`;
2292
+ }
2293
+ if (event.code !== CLOSE_NORMAL && event.code !== CLOSE_GOING_AWAY && // This commonly gets fired on mobile apps when the app is backgrounded
2294
+ event.code !== CLOSE_NO_STATUS && event.code !== CLOSE_NOT_FOUND) {
2295
+ let msg = `WebSocket closed with code ${event.code}`;
2296
+ if (event.reason) {
2297
+ msg += `: ${event.reason}`;
2298
+ }
2299
+ this.logger.log(msg);
2300
+ if (this.onServerDisconnectError && event.reason) {
2301
+ this.onServerDisconnectError(msg);
2302
+ }
2303
+ }
2304
+ const reason = classifyDisconnectError(event.reason);
2305
+ this.scheduleReconnect(reason);
2306
+ return;
2307
+ };
2308
+ }
2309
+ /**
2310
+ * @returns The state of the {@link Socket}.
2311
+ */
2312
+ socketState() {
2313
+ return this.socket.state;
2314
+ }
2315
+ /**
2316
+ * @param message - A ClientMessage to send.
2317
+ * @returns Whether the message (might have been) sent.
2318
+ */
2319
+ sendMessage(message) {
2320
+ const messageForLog = {
2321
+ type: message.type,
2322
+ ...message.type === "Authenticate" && message.tokenType === "User" ? {
2323
+ value: `...${message.value.slice(-7)}`
2324
+ } : {}
2325
+ };
2326
+ if (this.socket.state === "ready" && this.socket.paused === "no") {
2327
+ const encodedMessage = encodeClientMessage(message);
2328
+ const request = JSON.stringify(encodedMessage);
2329
+ let sent = false;
2330
+ try {
2331
+ this.socket.ws.send(request);
2332
+ sent = true;
2333
+ } catch (error) {
2334
+ this.logger.log(
2335
+ `Failed to send message on WebSocket, reconnecting: ${error}`
2336
+ );
2337
+ this.closeAndReconnect("FailedToSendMessage");
2338
+ }
2339
+ this._logVerbose(
2340
+ `${sent ? "sent" : "failed to send"} message with type ${message.type}: ${JSON.stringify(
2341
+ messageForLog
2342
+ )}`
2343
+ );
2344
+ return true;
2345
+ }
2346
+ this._logVerbose(
2347
+ `message not sent (socket state: ${this.socket.state}, paused: ${"paused" in this.socket ? this.socket.paused : void 0}): ${JSON.stringify(
2348
+ messageForLog
2349
+ )}`
2350
+ );
2351
+ return false;
2352
+ }
2353
+ resetServerInactivityTimeout() {
2354
+ if (this.socket.state === "terminated") {
2355
+ return;
2356
+ }
2357
+ if (this.reconnectDueToServerInactivityTimeout !== null) {
2358
+ clearTimeout(this.reconnectDueToServerInactivityTimeout);
2359
+ this.reconnectDueToServerInactivityTimeout = null;
2360
+ }
2361
+ this.reconnectDueToServerInactivityTimeout = setTimeout(() => {
2362
+ this.closeAndReconnect("InactiveServer");
2363
+ }, this.serverInactivityThreshold);
2364
+ }
2365
+ scheduleReconnect(reason) {
2366
+ if (this.scheduledReconnect) {
2367
+ clearTimeout(this.scheduledReconnect.timeout);
2368
+ this.scheduledReconnect = null;
2369
+ }
2370
+ this.socket = { state: "disconnected" };
2371
+ const backoff = this.nextBackoff(reason);
2372
+ this.markConnectionStateDirty();
2373
+ this.logger.log(`Attempting reconnect in ${Math.round(backoff)}ms`);
2374
+ const scheduledAt = monotonicMillis();
2375
+ const timeoutId = setTimeout(() => {
2376
+ if (this.scheduledReconnect?.timeout === timeoutId) {
2377
+ this.scheduledReconnect = null;
2378
+ this.connect();
2379
+ }
2380
+ }, backoff);
2381
+ this.scheduledReconnect = {
2382
+ timeout: timeoutId,
2383
+ scheduledAt,
2384
+ backoffMs: backoff
2385
+ };
2386
+ }
2387
+ /**
2388
+ * Close the WebSocket and schedule a reconnect.
2389
+ *
2390
+ * This should be used when we hit an error and would like to restart the session.
2391
+ */
2392
+ closeAndReconnect(closeReason) {
2393
+ this._logVerbose(`begin closeAndReconnect with reason ${closeReason}`);
2394
+ switch (this.socket.state) {
2395
+ case "disconnected":
2396
+ case "terminated":
2397
+ case "stopped":
2398
+ return;
2399
+ case "connecting":
2400
+ case "ready": {
2401
+ this.lastCloseReason = closeReason;
2402
+ void this.close();
2403
+ this.scheduleReconnect("client");
2404
+ return;
2405
+ }
2406
+ default: {
2407
+ this.socket;
2408
+ }
2409
+ }
2410
+ }
2411
+ /**
2412
+ * Close the WebSocket, being careful to clear the onclose handler to avoid re-entrant
2413
+ * calls. Use this instead of directly calling `ws.close()`
2414
+ *
2415
+ * It is the callers responsibility to update the state after this method is called so that the
2416
+ * closed socket is not accessible or used again after this method is called
2417
+ */
2418
+ close() {
2419
+ this.transitionChunkBuffer = null;
2420
+ switch (this.socket.state) {
2421
+ case "disconnected":
2422
+ case "terminated":
2423
+ case "stopped":
2424
+ return Promise.resolve();
2425
+ case "connecting": {
2426
+ const ws = this.socket.ws;
2427
+ ws.onmessage = (_message) => {
2428
+ this._logVerbose("Ignoring message received after close");
2429
+ };
2430
+ return new Promise((r) => {
2431
+ ws.onclose = () => {
2432
+ this._logVerbose("Closed after connecting");
2433
+ r();
2434
+ };
2435
+ ws.onopen = () => {
2436
+ this._logVerbose("Opened after connecting");
2437
+ ws.close();
2438
+ };
2439
+ });
2440
+ }
2441
+ case "ready": {
2442
+ this._logVerbose("ws.close called");
2443
+ const ws = this.socket.ws;
2444
+ ws.onmessage = (_message) => {
2445
+ this._logVerbose("Ignoring message received after close");
2446
+ };
2447
+ const result = new Promise((r) => {
2448
+ ws.onclose = () => {
2449
+ r();
2450
+ };
2451
+ });
2452
+ ws.close();
2453
+ return result;
2454
+ }
2455
+ default: {
2456
+ this.socket;
2457
+ return Promise.resolve();
2458
+ }
2459
+ }
2460
+ }
2461
+ /**
2462
+ * Close the WebSocket and do not reconnect.
2463
+ * @returns A Promise that resolves when the WebSocket `onClose` callback is called.
2464
+ */
2465
+ terminate() {
2466
+ if (this.reconnectDueToServerInactivityTimeout) {
2467
+ clearTimeout(this.reconnectDueToServerInactivityTimeout);
2468
+ }
2469
+ if (this.scheduledReconnect) {
2470
+ clearTimeout(this.scheduledReconnect.timeout);
2471
+ this.scheduledReconnect = null;
2472
+ }
2473
+ this.cleanupNetworkListener();
2474
+ switch (this.socket.state) {
2475
+ case "terminated":
2476
+ case "stopped":
2477
+ case "disconnected":
2478
+ case "connecting":
2479
+ case "ready": {
2480
+ const result = this.close();
2481
+ this.setSocketState({ state: "terminated" });
2482
+ return result;
2483
+ }
2484
+ default: {
2485
+ this.socket;
2486
+ throw new Error(
2487
+ `Invalid websocket state: ${this.socket.state}`
2488
+ );
2489
+ }
2490
+ }
2491
+ }
2492
+ stop() {
2493
+ switch (this.socket.state) {
2494
+ case "terminated":
2495
+ return Promise.resolve();
2496
+ case "connecting":
2497
+ case "stopped":
2498
+ case "disconnected":
2499
+ case "ready": {
2500
+ this.cleanupNetworkListener();
2501
+ const result = this.close();
2502
+ this.socket = { state: "stopped" };
2503
+ return result;
2504
+ }
2505
+ default: {
2506
+ this.socket;
2507
+ return Promise.resolve();
2508
+ }
2509
+ }
2510
+ }
2511
+ /**
2512
+ * Create a new WebSocket after a previous `stop()`, unless `terminate()` was
2513
+ * called before.
2514
+ */
2515
+ tryRestart() {
2516
+ switch (this.socket.state) {
2517
+ case "stopped":
2518
+ break;
2519
+ case "terminated":
2520
+ case "connecting":
2521
+ case "ready":
2522
+ case "disconnected":
2523
+ this.logger.logVerbose("Restart called without stopping first");
2524
+ return;
2525
+ default: {
2526
+ this.socket;
2527
+ }
2528
+ }
2529
+ this.setupNetworkListener();
2530
+ this.connect();
2531
+ }
2532
+ pause() {
2533
+ switch (this.socket.state) {
2534
+ case "disconnected":
2535
+ case "stopped":
2536
+ case "terminated":
2537
+ return;
2538
+ case "connecting":
2539
+ case "ready": {
2540
+ this.socket = { ...this.socket, paused: "yes" };
2541
+ return;
2542
+ }
2543
+ default: {
2544
+ this.socket;
2545
+ return;
2546
+ }
2547
+ }
2548
+ }
2549
+ /**
2550
+ * Try to reconnect immediately, canceling any scheduled reconnect.
2551
+ * This is useful when detecting network recovery.
2552
+ * Only takes action if we're in disconnected state (waiting to reconnect).
2553
+ */
2554
+ tryReconnectImmediately() {
2555
+ this._logVerbose("tryReconnectImmediately called");
2556
+ if (this.socket.state !== "disconnected") {
2557
+ this._logVerbose(
2558
+ `tryReconnectImmediately called but socket state is ${this.socket.state}, no action taken`
2559
+ );
2560
+ return;
2561
+ }
2562
+ let timeSavedMs = null;
2563
+ if (this.scheduledReconnect) {
2564
+ const elapsed = monotonicMillis() - this.scheduledReconnect.scheduledAt;
2565
+ timeSavedMs = Math.max(0, this.scheduledReconnect.backoffMs - elapsed);
2566
+ this._logVerbose(
2567
+ `would have waited ${Math.round(timeSavedMs)}ms more (backoff was ${Math.round(this.scheduledReconnect.backoffMs)}ms, elapsed ${Math.round(elapsed)}ms)`
2568
+ );
2569
+ clearTimeout(this.scheduledReconnect.timeout);
2570
+ this.scheduledReconnect = null;
2571
+ this._logVerbose("canceled scheduled reconnect");
2572
+ }
2573
+ this.logger.log("Network recovery detected, reconnecting immediately");
2574
+ this.pendingNetworkRecoveryInfo = timeSavedMs !== null ? { timeSavedMs } : null;
2575
+ this.connect();
2576
+ }
2577
+ /**
2578
+ * Resume the state machine if previously paused.
2579
+ */
2580
+ resume() {
2581
+ switch (this.socket.state) {
2582
+ case "connecting":
2583
+ this.socket = { ...this.socket, paused: "no" };
2584
+ return;
2585
+ case "ready":
2586
+ if (this.socket.paused === "uninitialized") {
2587
+ this.socket = { ...this.socket, paused: "no" };
2588
+ this.onOpen({
2589
+ connectionCount: this.connectionCount,
2590
+ lastCloseReason: this.lastCloseReason,
2591
+ clientTs: monotonicMillis()
2592
+ });
2593
+ } else if (this.socket.paused === "yes") {
2594
+ this.socket = { ...this.socket, paused: "no" };
2595
+ this.onResume();
2596
+ }
2597
+ return;
2598
+ case "terminated":
2599
+ case "stopped":
2600
+ case "disconnected":
2601
+ return;
2602
+ default: {
2603
+ this.socket;
2604
+ }
2605
+ }
2606
+ this.connect();
2607
+ }
2608
+ connectionState() {
2609
+ return {
2610
+ isConnected: this.socket.state === "ready",
2611
+ hasEverConnected: this._hasEverConnected,
2612
+ connectionCount: this.connectionCount,
2613
+ connectionRetries: this.retries
2614
+ };
2615
+ }
2616
+ _logVerbose(message) {
2617
+ this.logger.logVerbose(message);
2618
+ }
2619
+ nextBackoff(reason) {
2620
+ const initialBackoff = reason === "client" ? 100 : reason === "Unknown" ? this.defaultInitialBackoff : serverDisconnectErrors[reason].timeout;
2621
+ const baseBackoff = initialBackoff * Math.pow(2, this.retries);
2622
+ this.retries += 1;
2623
+ const actualBackoff = Math.min(baseBackoff, this.maxBackoff);
2624
+ const jitter = actualBackoff * (Math.random() - 0.5);
2625
+ return actualBackoff + jitter;
2626
+ }
2627
+ reportLargeTransition({
2628
+ transition,
2629
+ messageLength
2630
+ }) {
2631
+ if (transition.clientClockSkew === void 0 || transition.serverTs === void 0) {
2632
+ return;
2633
+ }
2634
+ const transitionTransitTime = monotonicMillis() - // client time now
2635
+ // clientClockSkew = (server time + upstream latency) - client time
2636
+ // clientClockSkew is "how many milliseconds behind (slow) is the client clock"
2637
+ // but the latency of the Connect message inflates this, making it appear further behind
2638
+ transition.clientClockSkew - transition.serverTs / 1e6;
2639
+ const prettyTransitionTime = `${Math.round(transitionTransitTime)}ms`;
2640
+ const prettyMessageMB = `${Math.round(messageLength / 1e4) / 100}MB`;
2641
+ const bytesPerSecond = messageLength / (transitionTransitTime / 1e3);
2642
+ const prettyBytesPerSecond = `${Math.round(bytesPerSecond / 1e4) / 100}MB per second`;
2643
+ this._logVerbose(
2644
+ `received ${prettyMessageMB} transition in ${prettyTransitionTime} at ${prettyBytesPerSecond}`
2645
+ );
2646
+ if (messageLength > 2e7) {
2647
+ this.logger.log(
2648
+ `received query results totaling more that 20MB (${prettyMessageMB}) which will take a long time to download on slower connections`
2649
+ );
2650
+ } else if (transitionTransitTime > 2e4) {
2651
+ this.logger.log(
2652
+ `received query results totaling ${prettyMessageMB} which took more than 20s to arrive (${prettyTransitionTime})`
2653
+ );
2654
+ }
2655
+ if (this.debug) {
2656
+ this.sendMessage({
2657
+ type: "Event",
2658
+ eventType: "ClientReceivedTransition",
2659
+ event: { transitionTransitTime, messageLength }
2660
+ });
2661
+ }
2662
+ }
2663
+ }
2664
+ function newSessionId() {
2665
+ return uuidv4();
2666
+ }
2667
+ function uuidv4() {
2668
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
2669
+ const r = Math.random() * 16 | 0, v2 = c === "x" ? r : r & 3 | 8;
2670
+ return v2.toString(16);
2671
+ });
2672
+ }
2673
+ class InvalidTokenError extends Error {
2674
+ }
2675
+ InvalidTokenError.prototype.name = "InvalidTokenError";
2676
+ function b64DecodeUnicode(str) {
2677
+ return decodeURIComponent(
2678
+ atob(str).replace(/(.)/g, (_m, p) => {
2679
+ let code2 = p.charCodeAt(0).toString(16).toUpperCase();
2680
+ if (code2.length < 2) {
2681
+ code2 = "0" + code2;
2682
+ }
2683
+ return "%" + code2;
2684
+ })
2685
+ );
2686
+ }
2687
+ function base64UrlDecode(str) {
2688
+ let output = str.replace(/-/g, "+").replace(/_/g, "/");
2689
+ switch (output.length % 4) {
2690
+ case 0:
2691
+ break;
2692
+ case 2:
2693
+ output += "==";
2694
+ break;
2695
+ case 3:
2696
+ output += "=";
2697
+ break;
2698
+ default:
2699
+ throw new Error("base64 string is not of the correct length");
2700
+ }
2701
+ try {
2702
+ return b64DecodeUnicode(output);
2703
+ } catch {
2704
+ return atob(output);
2705
+ }
2706
+ }
2707
+ function jwtDecode(token, options) {
2708
+ if (typeof token !== "string") {
2709
+ throw new InvalidTokenError("Invalid token specified: must be a string");
2710
+ }
2711
+ options || (options = {});
2712
+ const pos = options.header === true ? 0 : 1;
2713
+ const part = token.split(".")[pos];
2714
+ if (typeof part !== "string") {
2715
+ throw new InvalidTokenError(
2716
+ `Invalid token specified: missing part #${pos + 1}`
2717
+ );
2718
+ }
2719
+ let decoded;
2720
+ try {
2721
+ decoded = base64UrlDecode(part);
2722
+ } catch (e) {
2723
+ throw new InvalidTokenError(
2724
+ `Invalid token specified: invalid base64 for part #${pos + 1} (${e.message})`
2725
+ );
2726
+ }
2727
+ try {
2728
+ return JSON.parse(decoded);
2729
+ } catch (e) {
2730
+ throw new InvalidTokenError(
2731
+ `Invalid token specified: invalid json for part #${pos + 1} (${e.message})`
2732
+ );
2733
+ }
2734
+ }
2735
+ var __defProp$4 = Object.defineProperty;
2736
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2737
+ var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
2738
+ const MAXIMUM_REFRESH_DELAY = 20 * 24 * 60 * 60 * 1e3;
2739
+ const MAX_TOKEN_CONFIRMATION_ATTEMPTS = 2;
2740
+ class AuthenticationManager {
2741
+ constructor(syncState, callbacks, config) {
2742
+ __publicField$4(this, "authState", { state: "noAuth" });
2743
+ __publicField$4(this, "configVersion", 0);
2744
+ __publicField$4(this, "syncState");
2745
+ __publicField$4(this, "authenticate");
2746
+ __publicField$4(this, "stopSocket");
2747
+ __publicField$4(this, "tryRestartSocket");
2748
+ __publicField$4(this, "pauseSocket");
2749
+ __publicField$4(this, "resumeSocket");
2750
+ __publicField$4(this, "clearAuth");
2751
+ __publicField$4(this, "logger");
2752
+ __publicField$4(this, "refreshTokenLeewaySeconds");
2753
+ __publicField$4(this, "tokenConfirmationAttempts", 0);
2754
+ this.syncState = syncState;
2755
+ this.authenticate = callbacks.authenticate;
2756
+ this.stopSocket = callbacks.stopSocket;
2757
+ this.tryRestartSocket = callbacks.tryRestartSocket;
2758
+ this.pauseSocket = callbacks.pauseSocket;
2759
+ this.resumeSocket = callbacks.resumeSocket;
2760
+ this.clearAuth = callbacks.clearAuth;
2761
+ this.logger = config.logger;
2762
+ this.refreshTokenLeewaySeconds = config.refreshTokenLeewaySeconds;
2763
+ }
2764
+ async setConfig(fetchToken, onChange) {
2765
+ this.resetAuthState();
2766
+ this._logVerbose("pausing WS for auth token fetch");
2767
+ this.pauseSocket();
2768
+ const token = await this.fetchTokenAndGuardAgainstRace(fetchToken, {
2769
+ forceRefreshToken: false
2770
+ });
2771
+ if (token.isFromOutdatedConfig) {
2772
+ return;
2773
+ }
2774
+ if (token.value) {
2775
+ this.setAuthState({
2776
+ state: "waitingForServerConfirmationOfCachedToken",
2777
+ config: { fetchToken, onAuthChange: onChange },
2778
+ hasRetried: false
2779
+ });
2780
+ this.authenticate(token.value);
2781
+ } else {
2782
+ this.setAuthState({
2783
+ state: "initialRefetch",
2784
+ config: { fetchToken, onAuthChange: onChange }
2785
+ });
2786
+ await this.refetchToken();
2787
+ }
2788
+ this._logVerbose("resuming WS after auth token fetch");
2789
+ this.resumeSocket();
2790
+ }
2791
+ onTransition(serverMessage) {
2792
+ if (!this.syncState.isCurrentOrNewerAuthVersion(
2793
+ serverMessage.endVersion.identity
2794
+ )) {
2795
+ return;
2796
+ }
2797
+ if (serverMessage.endVersion.identity <= serverMessage.startVersion.identity) {
2798
+ return;
2799
+ }
2800
+ if (this.authState.state === "waitingForServerConfirmationOfCachedToken") {
2801
+ this._logVerbose("server confirmed auth token is valid");
2802
+ void this.refetchToken();
2803
+ this.authState.config.onAuthChange(true);
2804
+ return;
2805
+ }
2806
+ if (this.authState.state === "waitingForServerConfirmationOfFreshToken") {
2807
+ this._logVerbose("server confirmed new auth token is valid");
2808
+ this.scheduleTokenRefetch(this.authState.token);
2809
+ this.tokenConfirmationAttempts = 0;
2810
+ if (!this.authState.hadAuth) {
2811
+ this.authState.config.onAuthChange(true);
2812
+ }
2813
+ }
2814
+ }
2815
+ onAuthError(serverMessage) {
2816
+ if (serverMessage.authUpdateAttempted === false && (this.authState.state === "waitingForServerConfirmationOfFreshToken" || this.authState.state === "waitingForServerConfirmationOfCachedToken")) {
2817
+ this._logVerbose("ignoring non-auth token expired error");
2818
+ return;
2819
+ }
2820
+ const { baseVersion } = serverMessage;
2821
+ if (!this.syncState.isCurrentOrNewerAuthVersion(baseVersion + 1)) {
2822
+ this._logVerbose("ignoring auth error for previous auth attempt");
2823
+ return;
2824
+ }
2825
+ void this.tryToReauthenticate(serverMessage);
2826
+ return;
2827
+ }
2828
+ // This is similar to `refetchToken` defined below, in fact we
2829
+ // don't represent them as different states, but it is different
2830
+ // in that we pause the WebSocket so that mutations
2831
+ // don't retry with bad auth.
2832
+ async tryToReauthenticate(serverMessage) {
2833
+ this._logVerbose(`attempting to reauthenticate: ${serverMessage.error}`);
2834
+ if (
2835
+ // No way to fetch another token, kaboom
2836
+ this.authState.state === "noAuth" || // We failed on a fresh token. After a small number of retries, we give up
2837
+ // and clear the auth state to avoid infinite retries.
2838
+ this.authState.state === "waitingForServerConfirmationOfFreshToken" && this.tokenConfirmationAttempts >= MAX_TOKEN_CONFIRMATION_ATTEMPTS
2839
+ ) {
2840
+ this.logger.error(
2841
+ `Failed to authenticate: "${serverMessage.error}", check your server auth config`
2842
+ );
2843
+ if (this.syncState.hasAuth()) {
2844
+ this.syncState.clearAuth();
2845
+ }
2846
+ if (this.authState.state !== "noAuth") {
2847
+ this.setAndReportAuthFailed(this.authState.config.onAuthChange);
2848
+ }
2849
+ return;
2850
+ }
2851
+ if (this.authState.state === "waitingForServerConfirmationOfFreshToken") {
2852
+ this.tokenConfirmationAttempts++;
2853
+ this._logVerbose(
2854
+ `retrying reauthentication, ${MAX_TOKEN_CONFIRMATION_ATTEMPTS - this.tokenConfirmationAttempts} attempts remaining`
2855
+ );
2856
+ }
2857
+ await this.stopSocket();
2858
+ const token = await this.fetchTokenAndGuardAgainstRace(
2859
+ this.authState.config.fetchToken,
2860
+ {
2861
+ forceRefreshToken: true
2862
+ }
2863
+ );
2864
+ if (token.isFromOutdatedConfig) {
2865
+ return;
2866
+ }
2867
+ if (token.value && this.syncState.isNewAuth(token.value)) {
2868
+ this.authenticate(token.value);
2869
+ this.setAuthState({
2870
+ state: "waitingForServerConfirmationOfFreshToken",
2871
+ config: this.authState.config,
2872
+ token: token.value,
2873
+ hadAuth: this.authState.state === "notRefetching" || this.authState.state === "waitingForScheduledRefetch"
2874
+ });
2875
+ } else {
2876
+ this._logVerbose("reauthentication failed, could not fetch a new token");
2877
+ if (this.syncState.hasAuth()) {
2878
+ this.syncState.clearAuth();
2879
+ }
2880
+ this.setAndReportAuthFailed(this.authState.config.onAuthChange);
2881
+ }
2882
+ this.tryRestartSocket();
2883
+ }
2884
+ // Force refetch the token and schedule another refetch
2885
+ // before the token expires - an active client should never
2886
+ // need to reauthenticate.
2887
+ async refetchToken() {
2888
+ if (this.authState.state === "noAuth") {
2889
+ return;
2890
+ }
2891
+ this._logVerbose("refetching auth token");
2892
+ const token = await this.fetchTokenAndGuardAgainstRace(
2893
+ this.authState.config.fetchToken,
2894
+ {
2895
+ forceRefreshToken: true
2896
+ }
2897
+ );
2898
+ if (token.isFromOutdatedConfig) {
2899
+ return;
2900
+ }
2901
+ if (token.value) {
2902
+ if (this.syncState.isNewAuth(token.value)) {
2903
+ this.setAuthState({
2904
+ state: "waitingForServerConfirmationOfFreshToken",
2905
+ hadAuth: this.syncState.hasAuth(),
2906
+ token: token.value,
2907
+ config: this.authState.config
2908
+ });
2909
+ this.authenticate(token.value);
2910
+ } else {
2911
+ this.setAuthState({
2912
+ state: "notRefetching",
2913
+ config: this.authState.config
2914
+ });
2915
+ }
2916
+ } else {
2917
+ this._logVerbose("refetching token failed");
2918
+ if (this.syncState.hasAuth()) {
2919
+ this.clearAuth();
2920
+ }
2921
+ this.setAndReportAuthFailed(this.authState.config.onAuthChange);
2922
+ }
2923
+ this._logVerbose(
2924
+ "restarting WS after auth token fetch (if currently stopped)"
2925
+ );
2926
+ this.tryRestartSocket();
2927
+ }
2928
+ scheduleTokenRefetch(token) {
2929
+ if (this.authState.state === "noAuth") {
2930
+ return;
2931
+ }
2932
+ const decodedToken = this.decodeToken(token);
2933
+ if (!decodedToken) {
2934
+ this.logger.error(
2935
+ "Auth token is not a valid JWT, cannot refetch the token"
2936
+ );
2937
+ return;
2938
+ }
2939
+ const { iat, exp } = decodedToken;
2940
+ if (!iat || !exp) {
2941
+ this.logger.error(
2942
+ "Auth token does not have required fields, cannot refetch the token"
2943
+ );
2944
+ return;
2945
+ }
2946
+ const tokenValiditySeconds = exp - iat;
2947
+ if (tokenValiditySeconds <= 2) {
2948
+ this.logger.error(
2949
+ "Auth token does not live long enough, cannot refetch the token"
2950
+ );
2951
+ return;
2952
+ }
2953
+ let delay = Math.min(
2954
+ MAXIMUM_REFRESH_DELAY,
2955
+ (tokenValiditySeconds - this.refreshTokenLeewaySeconds) * 1e3
2956
+ );
2957
+ if (delay <= 0) {
2958
+ this.logger.warn(
2959
+ `Refetching auth token immediately, configured leeway ${this.refreshTokenLeewaySeconds}s is larger than the token's lifetime ${tokenValiditySeconds}s`
2960
+ );
2961
+ delay = 0;
2962
+ }
2963
+ const refetchTokenTimeoutId = setTimeout(() => {
2964
+ this._logVerbose("running scheduled token refetch");
2965
+ void this.refetchToken();
2966
+ }, delay);
2967
+ this.setAuthState({
2968
+ state: "waitingForScheduledRefetch",
2969
+ refetchTokenTimeoutId,
2970
+ config: this.authState.config
2971
+ });
2972
+ this._logVerbose(
2973
+ `scheduled preemptive auth token refetching in ${delay}ms`
2974
+ );
2975
+ }
2976
+ // Protects against simultaneous calls to `setConfig`
2977
+ // while we're fetching a token
2978
+ async fetchTokenAndGuardAgainstRace(fetchToken, fetchArgs) {
2979
+ const originalConfigVersion = ++this.configVersion;
2980
+ this._logVerbose(
2981
+ `fetching token with config version ${originalConfigVersion}`
2982
+ );
2983
+ const token = await fetchToken(fetchArgs);
2984
+ if (this.configVersion !== originalConfigVersion) {
2985
+ this._logVerbose(
2986
+ `stale config version, expected ${originalConfigVersion}, got ${this.configVersion}`
2987
+ );
2988
+ return { isFromOutdatedConfig: true };
2989
+ }
2990
+ return { isFromOutdatedConfig: false, value: token };
2991
+ }
2992
+ stop() {
2993
+ this.resetAuthState();
2994
+ this.configVersion++;
2995
+ this._logVerbose(`config version bumped to ${this.configVersion}`);
2996
+ }
2997
+ setAndReportAuthFailed(onAuthChange) {
2998
+ onAuthChange(false);
2999
+ this.resetAuthState();
3000
+ }
3001
+ resetAuthState() {
3002
+ this.setAuthState({ state: "noAuth" });
3003
+ }
3004
+ setAuthState(newAuth) {
3005
+ const authStateForLog = newAuth.state === "waitingForServerConfirmationOfFreshToken" ? {
3006
+ hadAuth: newAuth.hadAuth,
3007
+ state: newAuth.state,
3008
+ token: `...${newAuth.token.slice(-7)}`
3009
+ } : { state: newAuth.state };
3010
+ this._logVerbose(
3011
+ `setting auth state to ${JSON.stringify(authStateForLog)}`
3012
+ );
3013
+ switch (newAuth.state) {
3014
+ case "waitingForScheduledRefetch":
3015
+ case "notRefetching":
3016
+ case "noAuth":
3017
+ this.tokenConfirmationAttempts = 0;
3018
+ break;
3019
+ }
3020
+ if (this.authState.state === "waitingForScheduledRefetch") {
3021
+ clearTimeout(this.authState.refetchTokenTimeoutId);
3022
+ this.syncState.markAuthCompletion();
3023
+ }
3024
+ this.authState = newAuth;
3025
+ }
3026
+ decodeToken(token) {
3027
+ try {
3028
+ return jwtDecode(token);
3029
+ } catch (e) {
3030
+ this._logVerbose(
3031
+ `Error decoding token: ${e instanceof Error ? e.message : "Unknown error"}`
3032
+ );
3033
+ return null;
3034
+ }
3035
+ }
3036
+ _logVerbose(message) {
3037
+ this.logger.logVerbose(`${message} [v${this.configVersion}]`);
3038
+ }
3039
+ }
3040
+ const markNames = [
3041
+ "convexClientConstructed",
3042
+ "convexWebSocketOpen",
3043
+ "convexFirstMessageReceived"
3044
+ ];
3045
+ function mark(name, sessionId) {
3046
+ const detail = { sessionId };
3047
+ if (typeof performance === "undefined" || !performance.mark) return;
3048
+ performance.mark(name, { detail });
3049
+ }
3050
+ function performanceMarkToJson(mark2) {
3051
+ let name = mark2.name.slice("convex".length);
3052
+ name = name.charAt(0).toLowerCase() + name.slice(1);
3053
+ return {
3054
+ name,
3055
+ startTime: mark2.startTime
3056
+ };
3057
+ }
3058
+ function getMarksReport(sessionId) {
3059
+ if (typeof performance === "undefined" || !performance.getEntriesByName) {
3060
+ return [];
3061
+ }
3062
+ const allMarks = [];
3063
+ for (const name of markNames) {
3064
+ const marks = performance.getEntriesByName(name).filter((entry) => entry.entryType === "mark").filter((mark2) => mark2.detail.sessionId === sessionId);
3065
+ allMarks.push(...marks);
3066
+ }
3067
+ return allMarks.map(performanceMarkToJson);
3068
+ }
3069
+ var __defProp$3 = Object.defineProperty;
3070
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3071
+ var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
3072
+ class BaseConvexClient {
3073
+ /**
3074
+ * @param address - The url of your Convex deployment, often provided
3075
+ * by an environment variable. E.g. `https://small-mouse-123.convex.cloud`.
3076
+ * @param onTransition - A callback receiving an array of query tokens
3077
+ * corresponding to query results that have changed -- additional handlers
3078
+ * can be added via `addOnTransitionHandler`.
3079
+ * @param options - See {@link BaseConvexClientOptions} for a full description.
3080
+ */
3081
+ constructor(address, onTransition, options) {
3082
+ __publicField$3(this, "address");
3083
+ __publicField$3(this, "state");
3084
+ __publicField$3(this, "requestManager");
3085
+ __publicField$3(this, "webSocketManager");
3086
+ __publicField$3(this, "authenticationManager");
3087
+ __publicField$3(this, "remoteQuerySet");
3088
+ __publicField$3(this, "optimisticQueryResults");
3089
+ __publicField$3(this, "_transitionHandlerCounter", 0);
3090
+ __publicField$3(this, "_nextRequestId");
3091
+ __publicField$3(this, "_onTransitionFns", /* @__PURE__ */ new Map());
3092
+ __publicField$3(this, "_sessionId");
3093
+ __publicField$3(this, "firstMessageReceived", false);
3094
+ __publicField$3(this, "debug");
3095
+ __publicField$3(this, "logger");
3096
+ __publicField$3(this, "maxObservedTimestamp");
3097
+ __publicField$3(this, "connectionStateSubscribers", /* @__PURE__ */ new Map());
3098
+ __publicField$3(this, "nextConnectionStateSubscriberId", 0);
3099
+ __publicField$3(this, "_lastPublishedConnectionState");
3100
+ __publicField$3(this, "markConnectionStateDirty", () => {
3101
+ void Promise.resolve().then(() => {
3102
+ const curConnectionState = this.connectionState();
3103
+ if (JSON.stringify(curConnectionState) !== JSON.stringify(this._lastPublishedConnectionState)) {
3104
+ this._lastPublishedConnectionState = curConnectionState;
3105
+ for (const cb of this.connectionStateSubscribers.values()) {
3106
+ cb(curConnectionState);
3107
+ }
3108
+ }
3109
+ });
3110
+ });
3111
+ __publicField$3(this, "mark", (name) => {
3112
+ if (this.debug) {
3113
+ mark(name, this.sessionId);
3114
+ }
3115
+ });
3116
+ if (typeof address === "object") {
3117
+ throw new Error(
3118
+ "Passing a ClientConfig object is no longer supported. Pass the URL of the Convex deployment as a string directly."
3119
+ );
3120
+ }
3121
+ if (options?.skipConvexDeploymentUrlCheck !== true) {
3122
+ validateDeploymentUrl(address);
3123
+ }
3124
+ options = { ...options };
3125
+ const authRefreshTokenLeewaySeconds = options.authRefreshTokenLeewaySeconds ?? 2;
3126
+ let webSocketConstructor = options.webSocketConstructor;
3127
+ if (!webSocketConstructor && typeof WebSocket === "undefined") {
3128
+ throw new Error(
3129
+ "No WebSocket global variable defined! To use Convex in an environment without WebSocket try the HTTP client: https://docs.convex.dev/api/classes/browser.ConvexHttpClient"
3130
+ );
3131
+ }
3132
+ webSocketConstructor = webSocketConstructor || WebSocket;
3133
+ this.debug = options.reportDebugInfoToConvex ?? false;
3134
+ this.address = address;
3135
+ this.logger = options.logger === false ? instantiateNoopLogger({ verbose: options.verbose ?? false }) : options.logger !== true && options.logger ? options.logger : instantiateDefaultLogger({ verbose: options.verbose ?? false });
3136
+ const i = address.search("://");
3137
+ if (i === -1) {
3138
+ throw new Error("Provided address was not an absolute URL.");
3139
+ }
3140
+ const origin = address.substring(i + 3);
3141
+ const protocol = address.substring(0, i);
3142
+ let wsProtocol;
3143
+ if (protocol === "http") {
3144
+ wsProtocol = "ws";
3145
+ } else if (protocol === "https") {
3146
+ wsProtocol = "wss";
3147
+ } else {
3148
+ throw new Error(`Unknown parent protocol ${protocol}`);
3149
+ }
3150
+ const wsUri = `${wsProtocol}://${origin}/api/${version}/sync`;
3151
+ this.state = new LocalSyncState();
3152
+ this.remoteQuerySet = new RemoteQuerySet(
3153
+ (queryId) => this.state.queryPath(queryId),
3154
+ this.logger
3155
+ );
3156
+ this.requestManager = new RequestManager(
3157
+ this.logger,
3158
+ this.markConnectionStateDirty
3159
+ );
3160
+ const pauseSocket = () => {
3161
+ this.webSocketManager.pause();
3162
+ this.state.pause();
3163
+ };
3164
+ this.authenticationManager = new AuthenticationManager(
3165
+ this.state,
3166
+ {
3167
+ authenticate: (token) => {
3168
+ const message = this.state.setAuth(token);
3169
+ this.webSocketManager.sendMessage(message);
3170
+ return message.baseVersion;
3171
+ },
3172
+ stopSocket: () => this.webSocketManager.stop(),
3173
+ tryRestartSocket: () => this.webSocketManager.tryRestart(),
3174
+ pauseSocket,
3175
+ resumeSocket: () => this.webSocketManager.resume(),
3176
+ clearAuth: () => {
3177
+ this.clearAuth();
3178
+ }
3179
+ },
3180
+ {
3181
+ logger: this.logger,
3182
+ refreshTokenLeewaySeconds: authRefreshTokenLeewaySeconds
3183
+ }
3184
+ );
3185
+ this.optimisticQueryResults = new OptimisticQueryResults();
3186
+ this.addOnTransitionHandler((transition) => {
3187
+ onTransition(transition.queries.map((q) => q.token));
3188
+ });
3189
+ this._nextRequestId = 0;
3190
+ this._sessionId = newSessionId();
3191
+ const { unsavedChangesWarning } = options;
3192
+ if (typeof window === "undefined" || typeof window.addEventListener === "undefined") {
3193
+ if (unsavedChangesWarning === true) {
3194
+ throw new Error(
3195
+ "unsavedChangesWarning requested, but window.addEventListener not found! Remove {unsavedChangesWarning: true} from Convex client options."
3196
+ );
3197
+ }
3198
+ } else if (unsavedChangesWarning !== false) {
3199
+ window.addEventListener("beforeunload", (e) => {
3200
+ if (this.requestManager.hasIncompleteRequests()) {
3201
+ e.preventDefault();
3202
+ const confirmationMessage = "Are you sure you want to leave? Your changes may not be saved.";
3203
+ (e || window.event).returnValue = confirmationMessage;
3204
+ return confirmationMessage;
3205
+ }
3206
+ });
3207
+ }
3208
+ this.webSocketManager = new WebSocketManager(
3209
+ wsUri,
3210
+ {
3211
+ onOpen: (reconnectMetadata) => {
3212
+ this.mark("convexWebSocketOpen");
3213
+ this.webSocketManager.sendMessage({
3214
+ ...reconnectMetadata,
3215
+ type: "Connect",
3216
+ sessionId: this._sessionId,
3217
+ maxObservedTimestamp: this.maxObservedTimestamp
3218
+ });
3219
+ const oldRemoteQueryResults = new Set(
3220
+ this.remoteQuerySet.remoteQueryResults().keys()
3221
+ );
3222
+ this.remoteQuerySet = new RemoteQuerySet(
3223
+ (queryId) => this.state.queryPath(queryId),
3224
+ this.logger
3225
+ );
3226
+ const [querySetModification, authModification] = this.state.restart(
3227
+ oldRemoteQueryResults
3228
+ );
3229
+ if (authModification) {
3230
+ this.webSocketManager.sendMessage(authModification);
3231
+ }
3232
+ this.webSocketManager.sendMessage(querySetModification);
3233
+ for (const message of this.requestManager.restart()) {
3234
+ this.webSocketManager.sendMessage(message);
3235
+ }
3236
+ },
3237
+ onResume: () => {
3238
+ const [querySetModification, authModification] = this.state.resume();
3239
+ if (authModification) {
3240
+ this.webSocketManager.sendMessage(authModification);
3241
+ }
3242
+ if (querySetModification) {
3243
+ this.webSocketManager.sendMessage(querySetModification);
3244
+ }
3245
+ for (const message of this.requestManager.resume()) {
3246
+ this.webSocketManager.sendMessage(message);
3247
+ }
3248
+ },
3249
+ onMessage: (serverMessage) => {
3250
+ if (!this.firstMessageReceived) {
3251
+ this.firstMessageReceived = true;
3252
+ this.mark("convexFirstMessageReceived");
3253
+ this.reportMarks();
3254
+ }
3255
+ switch (serverMessage.type) {
3256
+ case "Transition": {
3257
+ this.observedTimestamp(serverMessage.endVersion.ts);
3258
+ this.authenticationManager.onTransition(serverMessage);
3259
+ this.remoteQuerySet.transition(serverMessage);
3260
+ this.state.transition(serverMessage);
3261
+ const completedRequests = this.requestManager.removeCompleted(
3262
+ this.remoteQuerySet.timestamp()
3263
+ );
3264
+ this.notifyOnQueryResultChanges(completedRequests);
3265
+ break;
3266
+ }
3267
+ case "MutationResponse": {
3268
+ if (serverMessage.success) {
3269
+ this.observedTimestamp(serverMessage.ts);
3270
+ }
3271
+ const completedMutationInfo = this.requestManager.onResponse(serverMessage);
3272
+ if (completedMutationInfo !== null) {
3273
+ this.notifyOnQueryResultChanges(
3274
+ /* @__PURE__ */ new Map([
3275
+ [
3276
+ completedMutationInfo.requestId,
3277
+ completedMutationInfo.result
3278
+ ]
3279
+ ])
3280
+ );
3281
+ }
3282
+ break;
3283
+ }
3284
+ case "ActionResponse": {
3285
+ this.requestManager.onResponse(serverMessage);
3286
+ break;
3287
+ }
3288
+ case "AuthError": {
3289
+ this.authenticationManager.onAuthError(serverMessage);
3290
+ break;
3291
+ }
3292
+ case "FatalError": {
3293
+ const error = logFatalError(this.logger, serverMessage.error);
3294
+ void this.webSocketManager.terminate();
3295
+ throw error;
3296
+ }
3297
+ }
3298
+ return {
3299
+ hasSyncedPastLastReconnect: this.hasSyncedPastLastReconnect()
3300
+ };
3301
+ },
3302
+ onServerDisconnectError: options.onServerDisconnectError
3303
+ },
3304
+ webSocketConstructor,
3305
+ this.logger,
3306
+ this.markConnectionStateDirty,
3307
+ this.debug
3308
+ );
3309
+ this.mark("convexClientConstructed");
3310
+ if (options.expectAuth) {
3311
+ pauseSocket();
3312
+ }
3313
+ }
3314
+ /**
3315
+ * Return true if there is outstanding work from prior to the time of the most recent restart.
3316
+ * This indicates that the client has not proven itself to have gotten past the issue that
3317
+ * potentially led to the restart. Use this to influence when to reset backoff after a failure.
3318
+ */
3319
+ hasSyncedPastLastReconnect() {
3320
+ const hasSyncedPastLastReconnect = this.requestManager.hasSyncedPastLastReconnect() || this.state.hasSyncedPastLastReconnect();
3321
+ return hasSyncedPastLastReconnect;
3322
+ }
3323
+ observedTimestamp(observedTs) {
3324
+ if (this.maxObservedTimestamp === void 0 || this.maxObservedTimestamp.lessThanOrEqual(observedTs)) {
3325
+ this.maxObservedTimestamp = observedTs;
3326
+ }
3327
+ }
3328
+ getMaxObservedTimestamp() {
3329
+ return this.maxObservedTimestamp;
3330
+ }
3331
+ /**
3332
+ * Compute the current query results based on the remoteQuerySet and the
3333
+ * current optimistic updates and call `onTransition` for all the changed
3334
+ * queries.
3335
+ *
3336
+ * @param completedMutations - A set of mutation IDs whose optimistic updates
3337
+ * are no longer needed.
3338
+ */
3339
+ notifyOnQueryResultChanges(completedRequests) {
3340
+ const remoteQueryResults = this.remoteQuerySet.remoteQueryResults();
3341
+ const queryTokenToValue = /* @__PURE__ */ new Map();
3342
+ for (const [queryId, result] of remoteQueryResults) {
3343
+ const queryToken = this.state.queryToken(queryId);
3344
+ if (queryToken !== null) {
3345
+ const query = {
3346
+ result,
3347
+ udfPath: this.state.queryPath(queryId),
3348
+ args: this.state.queryArgs(queryId)
3349
+ };
3350
+ queryTokenToValue.set(queryToken, query);
3351
+ }
3352
+ }
3353
+ const changedQueryTokens = this.optimisticQueryResults.ingestQueryResultsFromServer(
3354
+ queryTokenToValue,
3355
+ new Set(completedRequests.keys())
3356
+ );
3357
+ this.handleTransition({
3358
+ queries: changedQueryTokens.map((token) => {
3359
+ const optimisticResult = this.optimisticQueryResults.rawQueryResult(token);
3360
+ return {
3361
+ token,
3362
+ modification: {
3363
+ kind: "Updated",
3364
+ result: optimisticResult
3365
+ }
3366
+ };
3367
+ }),
3368
+ reflectedMutations: Array.from(completedRequests).map(
3369
+ ([requestId, result]) => ({
3370
+ requestId,
3371
+ result
3372
+ })
3373
+ ),
3374
+ timestamp: this.remoteQuerySet.timestamp()
3375
+ });
3376
+ }
3377
+ handleTransition(transition) {
3378
+ for (const fn of this._onTransitionFns.values()) {
3379
+ fn(transition);
3380
+ }
3381
+ }
3382
+ /**
3383
+ * Add a handler that will be called on a transition.
3384
+ *
3385
+ * Any external side effects (e.g. setting React state) should be handled here.
3386
+ *
3387
+ * @param fn
3388
+ *
3389
+ * @returns
3390
+ */
3391
+ addOnTransitionHandler(fn) {
3392
+ const id = this._transitionHandlerCounter++;
3393
+ this._onTransitionFns.set(id, fn);
3394
+ return () => this._onTransitionFns.delete(id);
3395
+ }
3396
+ /**
3397
+ * Get the current JWT auth token and decoded claims.
3398
+ */
3399
+ getCurrentAuthClaims() {
3400
+ const authToken = this.state.getAuth();
3401
+ let decoded = {};
3402
+ if (authToken && authToken.tokenType === "User") {
3403
+ try {
3404
+ decoded = authToken ? jwtDecode(authToken.value) : {};
3405
+ } catch {
3406
+ decoded = {};
3407
+ }
3408
+ } else {
3409
+ return void 0;
3410
+ }
3411
+ return { token: authToken.value, decoded };
3412
+ }
3413
+ /**
3414
+ * Set the authentication token to be used for subsequent queries and mutations.
3415
+ * `fetchToken` will be called automatically again if a token expires.
3416
+ * `fetchToken` should return `null` if the token cannot be retrieved, for example
3417
+ * when the user's rights were permanently revoked.
3418
+ * @param fetchToken - an async function returning the JWT-encoded OpenID Connect Identity Token
3419
+ * @param onChange - a callback that will be called when the authentication status changes
3420
+ */
3421
+ setAuth(fetchToken, onChange) {
3422
+ void this.authenticationManager.setConfig(fetchToken, onChange);
3423
+ }
3424
+ hasAuth() {
3425
+ return this.state.hasAuth();
3426
+ }
3427
+ /** @internal */
3428
+ setAdminAuth(value, fakeUserIdentity) {
3429
+ const message = this.state.setAdminAuth(value, fakeUserIdentity);
3430
+ this.webSocketManager.sendMessage(message);
3431
+ }
3432
+ clearAuth() {
3433
+ const message = this.state.clearAuth();
3434
+ this.webSocketManager.sendMessage(message);
3435
+ }
3436
+ /**
3437
+ * Subscribe to a query function.
3438
+ *
3439
+ * Whenever this query's result changes, the `onTransition` callback
3440
+ * passed into the constructor will be called.
3441
+ *
3442
+ * @param name - The name of the query.
3443
+ * @param args - An arguments object for the query. If this is omitted, the
3444
+ * arguments will be `{}`.
3445
+ * @param options - A {@link SubscribeOptions} options object for this query.
3446
+
3447
+ * @returns An object containing a {@link QueryToken} corresponding to this
3448
+ * query and an `unsubscribe` callback.
3449
+ */
3450
+ subscribe(name, args, options) {
3451
+ const argsObject = parseArgs(args);
3452
+ const { modification, queryToken, unsubscribe } = this.state.subscribe(
3453
+ name,
3454
+ argsObject,
3455
+ options?.journal,
3456
+ options?.componentPath
3457
+ );
3458
+ if (modification !== null) {
3459
+ this.webSocketManager.sendMessage(modification);
3460
+ }
3461
+ return {
3462
+ queryToken,
3463
+ unsubscribe: () => {
3464
+ const modification2 = unsubscribe();
3465
+ if (modification2) {
3466
+ this.webSocketManager.sendMessage(modification2);
3467
+ }
3468
+ }
3469
+ };
3470
+ }
3471
+ /**
3472
+ * A query result based only on the current, local state.
3473
+ *
3474
+ * The only way this will return a value is if we're already subscribed to the
3475
+ * query or its value has been set optimistically.
3476
+ */
3477
+ localQueryResult(udfPath, args) {
3478
+ const argsObject = parseArgs(args);
3479
+ const queryToken = serializePathAndArgs(udfPath, argsObject);
3480
+ return this.optimisticQueryResults.queryResult(queryToken);
3481
+ }
3482
+ /**
3483
+ * Get query result by query token based on current, local state
3484
+ *
3485
+ * The only way this will return a value is if we're already subscribed to the
3486
+ * query or its value has been set optimistically.
3487
+ *
3488
+ * @internal
3489
+ */
3490
+ localQueryResultByToken(queryToken) {
3491
+ return this.optimisticQueryResults.queryResult(queryToken);
3492
+ }
3493
+ /**
3494
+ * Whether local query result is available for a token.
3495
+ *
3496
+ * This method does not throw if the result is an error.
3497
+ *
3498
+ * @internal
3499
+ */
3500
+ hasLocalQueryResultByToken(queryToken) {
3501
+ return this.optimisticQueryResults.hasQueryResult(queryToken);
3502
+ }
3503
+ /**
3504
+ * @internal
3505
+ */
3506
+ localQueryLogs(udfPath, args) {
3507
+ const argsObject = parseArgs(args);
3508
+ const queryToken = serializePathAndArgs(udfPath, argsObject);
3509
+ return this.optimisticQueryResults.queryLogs(queryToken);
3510
+ }
3511
+ /**
3512
+ * Retrieve the current {@link QueryJournal} for this query function.
3513
+ *
3514
+ * If we have not yet received a result for this query, this will be `undefined`.
3515
+ *
3516
+ * @param name - The name of the query.
3517
+ * @param args - The arguments object for this query.
3518
+ * @returns The query's {@link QueryJournal} or `undefined`.
3519
+ */
3520
+ queryJournal(name, args) {
3521
+ const argsObject = parseArgs(args);
3522
+ const queryToken = serializePathAndArgs(name, argsObject);
3523
+ return this.state.queryJournal(queryToken);
3524
+ }
3525
+ /**
3526
+ * Get the current {@link ConnectionState} between the client and the Convex
3527
+ * backend.
3528
+ *
3529
+ * @returns The {@link ConnectionState} with the Convex backend.
3530
+ */
3531
+ connectionState() {
3532
+ const wsConnectionState = this.webSocketManager.connectionState();
3533
+ return {
3534
+ hasInflightRequests: this.requestManager.hasInflightRequests(),
3535
+ isWebSocketConnected: wsConnectionState.isConnected,
3536
+ hasEverConnected: wsConnectionState.hasEverConnected,
3537
+ connectionCount: wsConnectionState.connectionCount,
3538
+ connectionRetries: wsConnectionState.connectionRetries,
3539
+ timeOfOldestInflightRequest: this.requestManager.timeOfOldestInflightRequest(),
3540
+ inflightMutations: this.requestManager.inflightMutations(),
3541
+ inflightActions: this.requestManager.inflightActions()
3542
+ };
3543
+ }
3544
+ /**
3545
+ * Subscribe to the {@link ConnectionState} between the client and the Convex
3546
+ * backend, calling a callback each time it changes.
3547
+ *
3548
+ * Subscribed callbacks will be called when any part of ConnectionState changes.
3549
+ * ConnectionState may grow in future versions (e.g. to provide a array of
3550
+ * inflight requests) in which case callbacks would be called more frequently.
3551
+ *
3552
+ * @returns An unsubscribe function to stop listening.
3553
+ */
3554
+ subscribeToConnectionState(cb) {
3555
+ const id = this.nextConnectionStateSubscriberId++;
3556
+ this.connectionStateSubscribers.set(id, cb);
3557
+ return () => {
3558
+ this.connectionStateSubscribers.delete(id);
3559
+ };
3560
+ }
3561
+ /**
3562
+ * Execute a mutation function.
3563
+ *
3564
+ * @param name - The name of the mutation.
3565
+ * @param args - An arguments object for the mutation. If this is omitted,
3566
+ * the arguments will be `{}`.
3567
+ * @param options - A {@link MutationOptions} options object for this mutation.
3568
+
3569
+ * @returns - A promise of the mutation's result.
3570
+ */
3571
+ async mutation(name, args, options) {
3572
+ const result = await this.mutationInternal(name, args, options);
3573
+ if (!result.success) {
3574
+ if (result.errorData !== void 0) {
3575
+ throw forwardData(
3576
+ result,
3577
+ new ConvexError(
3578
+ createHybridErrorStacktrace("mutation", name, result)
3579
+ )
3580
+ );
3581
+ }
3582
+ throw new Error(createHybridErrorStacktrace("mutation", name, result));
3583
+ }
3584
+ return result.value;
3585
+ }
3586
+ /**
3587
+ * @internal
3588
+ */
3589
+ async mutationInternal(udfPath, args, options, componentPath) {
3590
+ const { mutationPromise } = this.enqueueMutation(
3591
+ udfPath,
3592
+ args,
3593
+ options,
3594
+ componentPath
3595
+ );
3596
+ return mutationPromise;
3597
+ }
3598
+ /**
3599
+ * @internal
3600
+ */
3601
+ enqueueMutation(udfPath, args, options, componentPath) {
3602
+ const mutationArgs = parseArgs(args);
3603
+ this.tryReportLongDisconnect();
3604
+ const requestId = this.nextRequestId;
3605
+ this._nextRequestId++;
3606
+ if (options !== void 0) {
3607
+ const optimisticUpdate = options.optimisticUpdate;
3608
+ if (optimisticUpdate !== void 0) {
3609
+ const wrappedUpdate = (localQueryStore) => {
3610
+ const result = optimisticUpdate(
3611
+ localQueryStore,
3612
+ mutationArgs
3613
+ );
3614
+ if (result instanceof Promise) {
3615
+ this.logger.warn(
3616
+ "Optimistic update handler returned a Promise. Optimistic updates should be synchronous."
3617
+ );
3618
+ }
3619
+ };
3620
+ const changedQueryTokens = this.optimisticQueryResults.applyOptimisticUpdate(
3621
+ wrappedUpdate,
3622
+ requestId
3623
+ );
3624
+ const changedQueries = changedQueryTokens.map((token) => {
3625
+ const localResult = this.localQueryResultByToken(token);
3626
+ return {
3627
+ token,
3628
+ modification: {
3629
+ kind: "Updated",
3630
+ result: localResult === void 0 ? void 0 : {
3631
+ success: true,
3632
+ value: localResult,
3633
+ logLines: []
3634
+ }
3635
+ }
3636
+ };
3637
+ });
3638
+ this.handleTransition({
3639
+ queries: changedQueries,
3640
+ reflectedMutations: [],
3641
+ timestamp: this.remoteQuerySet.timestamp()
3642
+ });
3643
+ }
3644
+ }
3645
+ const message = {
3646
+ type: "Mutation",
3647
+ requestId,
3648
+ udfPath,
3649
+ componentPath,
3650
+ args: [convexToJson(mutationArgs)]
3651
+ };
3652
+ const mightBeSent = this.webSocketManager.sendMessage(message);
3653
+ const mutationPromise = this.requestManager.request(message, mightBeSent);
3654
+ return {
3655
+ requestId,
3656
+ mutationPromise
3657
+ };
3658
+ }
3659
+ /**
3660
+ * Execute an action function.
3661
+ *
3662
+ * @param name - The name of the action.
3663
+ * @param args - An arguments object for the action. If this is omitted,
3664
+ * the arguments will be `{}`.
3665
+ * @returns A promise of the action's result.
3666
+ */
3667
+ async action(name, args) {
3668
+ const result = await this.actionInternal(name, args);
3669
+ if (!result.success) {
3670
+ if (result.errorData !== void 0) {
3671
+ throw forwardData(
3672
+ result,
3673
+ new ConvexError(createHybridErrorStacktrace("action", name, result))
3674
+ );
3675
+ }
3676
+ throw new Error(createHybridErrorStacktrace("action", name, result));
3677
+ }
3678
+ return result.value;
3679
+ }
3680
+ /**
3681
+ * @internal
3682
+ */
3683
+ async actionInternal(udfPath, args, componentPath) {
3684
+ const actionArgs = parseArgs(args);
3685
+ const requestId = this.nextRequestId;
3686
+ this._nextRequestId++;
3687
+ this.tryReportLongDisconnect();
3688
+ const message = {
3689
+ type: "Action",
3690
+ requestId,
3691
+ udfPath,
3692
+ componentPath,
3693
+ args: [convexToJson(actionArgs)]
3694
+ };
3695
+ const mightBeSent = this.webSocketManager.sendMessage(message);
3696
+ return this.requestManager.request(message, mightBeSent);
3697
+ }
3698
+ /**
3699
+ * Close any network handles associated with this client and stop all subscriptions.
3700
+ *
3701
+ * Call this method when you're done with an {@link BaseConvexClient} to
3702
+ * dispose of its sockets and resources.
3703
+ *
3704
+ * @returns A `Promise` fulfilled when the connection has been completely closed.
3705
+ */
3706
+ async close() {
3707
+ this.authenticationManager.stop();
3708
+ return this.webSocketManager.terminate();
3709
+ }
3710
+ /**
3711
+ * Return the address for this client, useful for creating a new client.
3712
+ *
3713
+ * Not guaranteed to match the address with which this client was constructed:
3714
+ * it may be canonicalized.
3715
+ */
3716
+ get url() {
3717
+ return this.address;
3718
+ }
3719
+ /**
3720
+ * @internal
3721
+ */
3722
+ get nextRequestId() {
3723
+ return this._nextRequestId;
3724
+ }
3725
+ /**
3726
+ * @internal
3727
+ */
3728
+ get sessionId() {
3729
+ return this._sessionId;
3730
+ }
3731
+ /**
3732
+ * Reports performance marks to the server. This should only be called when
3733
+ * we have a functional websocket.
3734
+ */
3735
+ reportMarks() {
3736
+ if (this.debug) {
3737
+ const report = getMarksReport(this.sessionId);
3738
+ this.webSocketManager.sendMessage({
3739
+ type: "Event",
3740
+ eventType: "ClientConnect",
3741
+ event: report
3742
+ });
3743
+ }
3744
+ }
3745
+ tryReportLongDisconnect() {
3746
+ if (!this.debug) {
3747
+ return;
3748
+ }
3749
+ const timeOfOldestRequest = this.connectionState().timeOfOldestInflightRequest;
3750
+ if (timeOfOldestRequest === null || Date.now() - timeOfOldestRequest.getTime() <= 60 * 1e3) {
3751
+ return;
3752
+ }
3753
+ const endpoint = `${this.address}/api/debug_event`;
3754
+ fetch(endpoint, {
3755
+ method: "POST",
3756
+ headers: {
3757
+ "Content-Type": "application/json",
3758
+ "Convex-Client": `npm-${version}`
3759
+ },
3760
+ body: JSON.stringify({ event: "LongWebsocketDisconnect" })
3761
+ }).then((response) => {
3762
+ if (!response.ok) {
3763
+ this.logger.warn(
3764
+ "Analytics request failed with response:",
3765
+ response.body
3766
+ );
3767
+ }
3768
+ }).catch((error) => {
3769
+ this.logger.warn("Analytics response failed with error:", error);
3770
+ });
3771
+ }
3772
+ }
3773
+ function asPaginationResult(value) {
3774
+ if (typeof value !== "object" || value === null || !Array.isArray(value.page) || typeof value.isDone !== "boolean" || typeof value.continueCursor !== "string") {
3775
+ throw new Error(`Not a valid paginated query result: ${value?.toString()}`);
3776
+ }
3777
+ return value;
3778
+ }
3779
+ var __defProp$2 = Object.defineProperty;
3780
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3781
+ var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
3782
+ class PaginatedQueryClient {
3783
+ constructor(client, onTransition) {
3784
+ this.client = client;
3785
+ this.onTransition = onTransition;
3786
+ __publicField$2(this, "paginatedQuerySet", /* @__PURE__ */ new Map());
3787
+ __publicField$2(this, "lastTransitionTs");
3788
+ this.lastTransitionTs = Long.fromNumber(0);
3789
+ this.client.addOnTransitionHandler(
3790
+ (transition) => this.onBaseTransition(transition)
3791
+ );
3792
+ }
3793
+ /**
3794
+ * Subscribe to a paginated query.
3795
+ *
3796
+ * @param name - The name of the paginated query function
3797
+ * @param args - Arguments for the query (excluding paginationOpts)
3798
+ * @param options - Pagination options including initialNumItems
3799
+ * @returns Object with paginatedQueryToken and unsubscribe function
3800
+ */
3801
+ subscribe(name, args, options) {
3802
+ const canonicalizedUdfPath = canonicalizeUdfPath(name);
3803
+ const token = serializePaginatedPathAndArgs(
3804
+ canonicalizedUdfPath,
3805
+ args,
3806
+ options
3807
+ );
3808
+ const unsubscribe = () => this.removePaginatedQuerySubscriber(token);
3809
+ const existingEntry = this.paginatedQuerySet.get(token);
3810
+ if (existingEntry) {
3811
+ existingEntry.numSubscribers += 1;
3812
+ return {
3813
+ paginatedQueryToken: token,
3814
+ unsubscribe
3815
+ };
3816
+ }
3817
+ this.paginatedQuerySet.set(token, {
3818
+ token,
3819
+ canonicalizedUdfPath,
3820
+ args,
3821
+ numSubscribers: 1,
3822
+ options: { initialNumItems: options.initialNumItems },
3823
+ nextPageKey: 0,
3824
+ pageKeys: [],
3825
+ pageKeyToQuery: /* @__PURE__ */ new Map(),
3826
+ ongoingSplits: /* @__PURE__ */ new Map(),
3827
+ skip: false,
3828
+ id: options.id
3829
+ });
3830
+ this.addPageToPaginatedQuery(token, null, options.initialNumItems);
3831
+ return {
3832
+ paginatedQueryToken: token,
3833
+ unsubscribe
3834
+ };
3835
+ }
3836
+ /**
3837
+ * Get current results for a paginated query based on local state.
3838
+ *
3839
+ * Throws an error when one of the pages has errored.
3840
+ */
3841
+ localQueryResult(name, args, options) {
3842
+ const canonicalizedUdfPath = canonicalizeUdfPath(name);
3843
+ const token = serializePaginatedPathAndArgs(
3844
+ canonicalizedUdfPath,
3845
+ args,
3846
+ options
3847
+ );
3848
+ return this.localQueryResultByToken(token);
3849
+ }
3850
+ /**
3851
+ * @internal
3852
+ */
3853
+ localQueryResultByToken(token) {
3854
+ const paginatedQuery = this.paginatedQuerySet.get(token);
3855
+ if (!paginatedQuery) {
3856
+ return void 0;
3857
+ }
3858
+ const activePages = this.activePageQueryTokens(paginatedQuery);
3859
+ if (activePages.length === 0) {
3860
+ return {
3861
+ results: [],
3862
+ status: "LoadingFirstPage",
3863
+ loadMore: (numItems) => {
3864
+ return this.loadMoreOfPaginatedQuery(token, numItems);
3865
+ }
3866
+ };
3867
+ }
3868
+ let allResults = [];
3869
+ let hasUndefined = false;
3870
+ let isDone = false;
3871
+ for (const pageToken of activePages) {
3872
+ const result = this.client.localQueryResultByToken(pageToken);
3873
+ if (result === void 0) {
3874
+ hasUndefined = true;
3875
+ isDone = false;
3876
+ continue;
3877
+ }
3878
+ const paginationResult = asPaginationResult(result);
3879
+ allResults = allResults.concat(paginationResult.page);
3880
+ isDone = !!paginationResult.isDone;
3881
+ }
3882
+ let status;
3883
+ if (hasUndefined) {
3884
+ status = allResults.length === 0 ? "LoadingFirstPage" : "LoadingMore";
3885
+ } else if (isDone) {
3886
+ status = "Exhausted";
3887
+ } else {
3888
+ status = "CanLoadMore";
3889
+ }
3890
+ return {
3891
+ results: allResults,
3892
+ status,
3893
+ loadMore: (numItems) => {
3894
+ return this.loadMoreOfPaginatedQuery(token, numItems);
3895
+ }
3896
+ };
3897
+ }
3898
+ onBaseTransition(transition) {
3899
+ const changedBaseTokens = transition.queries.map((q) => q.token);
3900
+ const changed = this.queriesContainingTokens(changedBaseTokens);
3901
+ let paginatedQueries = [];
3902
+ if (changed.length > 0) {
3903
+ this.processPaginatedQuerySplits(
3904
+ changed,
3905
+ (token) => this.client.localQueryResultByToken(token)
3906
+ );
3907
+ paginatedQueries = changed.map((token) => ({
3908
+ token,
3909
+ modification: {
3910
+ kind: "Updated",
3911
+ result: this.localQueryResultByToken(token)
3912
+ }
3913
+ }));
3914
+ }
3915
+ const extendedTransition = {
3916
+ ...transition,
3917
+ paginatedQueries
3918
+ };
3919
+ this.onTransition(extendedTransition);
3920
+ }
3921
+ /**
3922
+ * Load more items for a paginated query.
3923
+ *
3924
+ * This *always* causes a transition, the status of the query
3925
+ * has probably changed from "CanLoadMore" to "LoadingMore".
3926
+ * Data might have changed too: maybe a subscription to this page
3927
+ * query already exists (unlikely but possible) or this page query
3928
+ * has an optimistic update providing some initial data.
3929
+ *
3930
+ * @internal
3931
+ */
3932
+ loadMoreOfPaginatedQuery(token, numItems) {
3933
+ this.mustGetPaginatedQuery(token);
3934
+ const lastPageToken = this.queryTokenForLastPageOfPaginatedQuery(token);
3935
+ const lastPageResult = this.client.localQueryResultByToken(lastPageToken);
3936
+ if (!lastPageResult) {
3937
+ return false;
3938
+ }
3939
+ const paginationResult = asPaginationResult(lastPageResult);
3940
+ if (paginationResult.isDone) {
3941
+ return false;
3942
+ }
3943
+ this.addPageToPaginatedQuery(
3944
+ token,
3945
+ paginationResult.continueCursor,
3946
+ numItems
3947
+ );
3948
+ const loadMoreTransition = {
3949
+ timestamp: this.lastTransitionTs,
3950
+ reflectedMutations: [],
3951
+ queries: [],
3952
+ paginatedQueries: [
3953
+ {
3954
+ token,
3955
+ modification: {
3956
+ kind: "Updated",
3957
+ result: this.localQueryResultByToken(token)
3958
+ }
3959
+ }
3960
+ ]
3961
+ };
3962
+ this.onTransition(loadMoreTransition);
3963
+ return true;
3964
+ }
3965
+ /**
3966
+ * @internal
3967
+ */
3968
+ queriesContainingTokens(queryTokens) {
3969
+ if (queryTokens.length === 0) {
3970
+ return [];
3971
+ }
3972
+ const changed = [];
3973
+ const queryTokenSet = new Set(queryTokens);
3974
+ for (const [paginatedToken, paginatedQuery] of this.paginatedQuerySet) {
3975
+ for (const pageToken of this.allQueryTokens(paginatedQuery)) {
3976
+ if (queryTokenSet.has(pageToken)) {
3977
+ changed.push(paginatedToken);
3978
+ break;
3979
+ }
3980
+ }
3981
+ }
3982
+ return changed;
3983
+ }
3984
+ /**
3985
+ * @internal
3986
+ */
3987
+ processPaginatedQuerySplits(changed, getResult) {
3988
+ for (const paginatedQueryToken of changed) {
3989
+ const paginatedQuery = this.mustGetPaginatedQuery(paginatedQueryToken);
3990
+ const { ongoingSplits, pageKeyToQuery, pageKeys } = paginatedQuery;
3991
+ for (const [pageKey, [splitKey1, splitKey2]] of ongoingSplits) {
3992
+ const bothNewPagesLoaded = getResult(pageKeyToQuery.get(splitKey1).queryToken) !== void 0 && getResult(pageKeyToQuery.get(splitKey2).queryToken) !== void 0;
3993
+ if (bothNewPagesLoaded) {
3994
+ this.completePaginatedQuerySplit(
3995
+ paginatedQuery,
3996
+ pageKey,
3997
+ splitKey1,
3998
+ splitKey2
3999
+ );
4000
+ }
4001
+ }
4002
+ for (const pageKey of pageKeys) {
4003
+ if (ongoingSplits.has(pageKey)) {
4004
+ continue;
4005
+ }
4006
+ const pageToken = pageKeyToQuery.get(pageKey).queryToken;
4007
+ const pageResult = getResult(pageToken);
4008
+ if (!pageResult) {
4009
+ continue;
4010
+ }
4011
+ const result = asPaginationResult(pageResult);
4012
+ const shouldSplit = result.splitCursor && (result.pageStatus === "SplitRecommended" || result.pageStatus === "SplitRequired" || // This client-driven page splitting condition will change in the future.
4013
+ result.page.length > paginatedQuery.options.initialNumItems * 2);
4014
+ if (shouldSplit) {
4015
+ this.splitPaginatedQueryPage(
4016
+ paginatedQuery,
4017
+ pageKey,
4018
+ result.splitCursor,
4019
+ // we just checked
4020
+ result.continueCursor
4021
+ );
4022
+ }
4023
+ }
4024
+ }
4025
+ }
4026
+ splitPaginatedQueryPage(paginatedQuery, pageKey, splitCursor, continueCursor) {
4027
+ const splitKey1 = paginatedQuery.nextPageKey++;
4028
+ const splitKey2 = paginatedQuery.nextPageKey++;
4029
+ const paginationOpts = {
4030
+ cursor: continueCursor,
4031
+ numItems: paginatedQuery.options.initialNumItems,
4032
+ id: paginatedQuery.id
4033
+ };
4034
+ const firstSubscription = this.client.subscribe(
4035
+ paginatedQuery.canonicalizedUdfPath,
4036
+ {
4037
+ ...paginatedQuery.args,
4038
+ paginationOpts: {
4039
+ ...paginationOpts,
4040
+ cursor: null,
4041
+ // Start from beginning for first split
4042
+ endCursor: splitCursor
4043
+ }
4044
+ }
4045
+ );
4046
+ paginatedQuery.pageKeyToQuery.set(splitKey1, firstSubscription);
4047
+ const secondSubscription = this.client.subscribe(
4048
+ paginatedQuery.canonicalizedUdfPath,
4049
+ {
4050
+ ...paginatedQuery.args,
4051
+ paginationOpts: {
4052
+ ...paginationOpts,
4053
+ cursor: splitCursor,
4054
+ endCursor: continueCursor
4055
+ }
4056
+ }
4057
+ );
4058
+ paginatedQuery.pageKeyToQuery.set(splitKey2, secondSubscription);
4059
+ paginatedQuery.ongoingSplits.set(pageKey, [splitKey1, splitKey2]);
4060
+ }
4061
+ /**
4062
+ * @internal
4063
+ */
4064
+ addPageToPaginatedQuery(token, continueCursor, numItems) {
4065
+ const paginatedQuery = this.mustGetPaginatedQuery(token);
4066
+ const pageKey = paginatedQuery.nextPageKey++;
4067
+ const paginationOpts = {
4068
+ cursor: continueCursor,
4069
+ numItems,
4070
+ id: paginatedQuery.id
4071
+ };
4072
+ const pageArgs = {
4073
+ ...paginatedQuery.args,
4074
+ paginationOpts
4075
+ };
4076
+ const subscription = this.client.subscribe(
4077
+ paginatedQuery.canonicalizedUdfPath,
4078
+ pageArgs
4079
+ );
4080
+ paginatedQuery.pageKeys.push(pageKey);
4081
+ paginatedQuery.pageKeyToQuery.set(pageKey, subscription);
4082
+ return subscription;
4083
+ }
4084
+ removePaginatedQuerySubscriber(token) {
4085
+ const paginatedQuery = this.paginatedQuerySet.get(token);
4086
+ if (!paginatedQuery) {
4087
+ return;
4088
+ }
4089
+ paginatedQuery.numSubscribers -= 1;
4090
+ if (paginatedQuery.numSubscribers > 0) {
4091
+ return;
4092
+ }
4093
+ for (const subscription of paginatedQuery.pageKeyToQuery.values()) {
4094
+ subscription.unsubscribe();
4095
+ }
4096
+ this.paginatedQuerySet.delete(token);
4097
+ }
4098
+ completePaginatedQuerySplit(paginatedQuery, pageKey, splitKey1, splitKey2) {
4099
+ const originalQuery = paginatedQuery.pageKeyToQuery.get(pageKey);
4100
+ paginatedQuery.pageKeyToQuery.delete(pageKey);
4101
+ const pageIndex = paginatedQuery.pageKeys.indexOf(pageKey);
4102
+ paginatedQuery.pageKeys.splice(pageIndex, 1, splitKey1, splitKey2);
4103
+ paginatedQuery.ongoingSplits.delete(pageKey);
4104
+ originalQuery.unsubscribe();
4105
+ }
4106
+ /** The query tokens for all active pages, in result order */
4107
+ activePageQueryTokens(paginatedQuery) {
4108
+ return paginatedQuery.pageKeys.map(
4109
+ (pageKey) => paginatedQuery.pageKeyToQuery.get(pageKey).queryToken
4110
+ );
4111
+ }
4112
+ allQueryTokens(paginatedQuery) {
4113
+ return Array.from(paginatedQuery.pageKeyToQuery.values()).map(
4114
+ (sub) => sub.queryToken
4115
+ );
4116
+ }
4117
+ queryTokenForLastPageOfPaginatedQuery(token) {
4118
+ const paginatedQuery = this.mustGetPaginatedQuery(token);
4119
+ const lastPageKey = paginatedQuery.pageKeys[paginatedQuery.pageKeys.length - 1];
4120
+ if (lastPageKey === void 0) {
4121
+ throw new Error(`No pages for paginated query ${token}`);
4122
+ }
4123
+ return paginatedQuery.pageKeyToQuery.get(lastPageKey).queryToken;
4124
+ }
4125
+ mustGetPaginatedQuery(token) {
4126
+ const paginatedQuery = this.paginatedQuerySet.get(token);
4127
+ if (!paginatedQuery) {
4128
+ throw new Error("paginated query no longer exists for token " + token);
4129
+ }
4130
+ return paginatedQuery;
4131
+ }
4132
+ }
4133
+ function useSubscription({
4134
+ // (Synchronously) returns the current value of our subscription.
4135
+ getCurrentValue,
4136
+ // This function is passed an event handler to attach to the subscription.
4137
+ // It should return an unsubscribe function that removes the handler.
4138
+ subscribe
4139
+ }) {
4140
+ const [state, setState] = reactExports.useState(() => ({
4141
+ getCurrentValue,
4142
+ subscribe,
4143
+ value: getCurrentValue()
4144
+ }));
4145
+ let valueToReturn = state.value;
4146
+ if (state.getCurrentValue !== getCurrentValue || state.subscribe !== subscribe) {
4147
+ valueToReturn = getCurrentValue();
4148
+ setState({
4149
+ getCurrentValue,
4150
+ subscribe,
4151
+ value: valueToReturn
4152
+ });
4153
+ }
4154
+ reactExports.useEffect(() => {
4155
+ let didUnsubscribe = false;
4156
+ const checkForUpdates = () => {
4157
+ if (didUnsubscribe) {
4158
+ return;
4159
+ }
4160
+ setState((prevState) => {
4161
+ if (prevState.getCurrentValue !== getCurrentValue || prevState.subscribe !== subscribe) {
4162
+ return prevState;
4163
+ }
4164
+ const value = getCurrentValue();
4165
+ if (prevState.value === value) {
4166
+ return prevState;
4167
+ }
4168
+ return { ...prevState, value };
4169
+ });
4170
+ };
4171
+ const unsubscribe = subscribe(checkForUpdates);
4172
+ checkForUpdates();
4173
+ return () => {
4174
+ didUnsubscribe = true;
4175
+ unsubscribe();
4176
+ };
4177
+ }, [getCurrentValue, subscribe]);
4178
+ return valueToReturn;
4179
+ }
4180
+ var __defProp$1 = Object.defineProperty;
4181
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4182
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
4183
+ const DEFAULT_EXTEND_SUBSCRIPTION_FOR = 5e3;
4184
+ if (typeof React === "undefined") {
4185
+ throw new Error("Required dependency 'react' not found");
4186
+ }
4187
+ function createMutation(mutationReference, client, update) {
4188
+ function mutation(args) {
4189
+ assertNotAccidentalArgument(args);
4190
+ return client.mutation(mutationReference, args, {
4191
+ optimisticUpdate: update
4192
+ });
4193
+ }
4194
+ mutation.withOptimisticUpdate = function withOptimisticUpdate(optimisticUpdate) {
4195
+ if (update !== void 0) {
4196
+ throw new Error(
4197
+ `Already specified optimistic update for mutation ${getFunctionName(
4198
+ mutationReference
4199
+ )}`
4200
+ );
4201
+ }
4202
+ return createMutation(mutationReference, client, optimisticUpdate);
4203
+ };
4204
+ return mutation;
4205
+ }
4206
+ class ConvexReactClient {
4207
+ /**
4208
+ * @param address - The url of your Convex deployment, often provided
4209
+ * by an environment variable. E.g. `https://small-mouse-123.convex.cloud`.
4210
+ * @param options - See {@link ConvexReactClientOptions} for a full description.
4211
+ */
4212
+ constructor(address, options) {
4213
+ __publicField$1(this, "address");
4214
+ __publicField$1(this, "cachedSync");
4215
+ __publicField$1(this, "cachedPaginatedQueryClient");
4216
+ __publicField$1(this, "listeners");
4217
+ __publicField$1(this, "options");
4218
+ __publicField$1(this, "closed", false);
4219
+ __publicField$1(this, "_logger");
4220
+ __publicField$1(this, "adminAuth");
4221
+ __publicField$1(this, "fakeUserIdentity");
4222
+ if (address === void 0) {
4223
+ throw new Error(
4224
+ "No address provided to ConvexReactClient.\nIf trying to deploy to production, make sure to follow all the instructions found at https://docs.convex.dev/production/hosting/\nIf running locally, make sure to run `convex dev` and ensure the .env.local file is populated."
4225
+ );
4226
+ }
4227
+ if (typeof address !== "string") {
4228
+ throw new Error(
4229
+ `ConvexReactClient requires a URL like 'https://happy-otter-123.convex.cloud', received something of type ${typeof address} instead.`
4230
+ );
4231
+ }
4232
+ if (!address.includes("://")) {
4233
+ throw new Error("Provided address was not an absolute URL.");
4234
+ }
4235
+ this.address = address;
4236
+ this.listeners = /* @__PURE__ */ new Map();
4237
+ this._logger = options?.logger === false ? instantiateNoopLogger({ verbose: options?.verbose ?? false }) : options?.logger !== true && options?.logger ? options.logger : instantiateDefaultLogger({ verbose: options?.verbose ?? false });
4238
+ this.options = { ...options, logger: this._logger };
4239
+ }
4240
+ /**
4241
+ * Return the address for this client, useful for creating a new client.
4242
+ *
4243
+ * Not guaranteed to match the address with which this client was constructed:
4244
+ * it may be canonicalized.
4245
+ */
4246
+ get url() {
4247
+ return this.address;
4248
+ }
4249
+ /**
4250
+ * Lazily instantiate the `BaseConvexClient` so we don't create the WebSocket
4251
+ * when server-side rendering.
4252
+ *
4253
+ * @internal
4254
+ */
4255
+ get sync() {
4256
+ if (this.closed) {
4257
+ throw new Error("ConvexReactClient has already been closed.");
4258
+ }
4259
+ if (this.cachedSync) {
4260
+ return this.cachedSync;
4261
+ }
4262
+ this.cachedSync = new BaseConvexClient(
4263
+ this.address,
4264
+ () => {
4265
+ },
4266
+ // Use the PaginatedQueryClient's transition instead.
4267
+ this.options
4268
+ );
4269
+ if (this.adminAuth) {
4270
+ this.cachedSync.setAdminAuth(this.adminAuth, this.fakeUserIdentity);
4271
+ }
4272
+ this.cachedPaginatedQueryClient = new PaginatedQueryClient(
4273
+ this.cachedSync,
4274
+ (transition) => this.handleTransition(transition)
4275
+ );
4276
+ return this.cachedSync;
4277
+ }
4278
+ /**
4279
+ * Lazily instantiate the `PaginatedQueryClient` so we don't create it
4280
+ * when server-side rendering.
4281
+ *
4282
+ * @internal
4283
+ */
4284
+ get paginatedQueryClient() {
4285
+ this.sync;
4286
+ if (this.cachedPaginatedQueryClient) {
4287
+ return this.cachedPaginatedQueryClient;
4288
+ }
4289
+ throw new Error("Should already be instantiated");
4290
+ }
4291
+ /**
4292
+ * Set the authentication token to be used for subsequent queries and mutations.
4293
+ * `fetchToken` will be called automatically again if a token expires.
4294
+ * `fetchToken` should return `null` if the token cannot be retrieved, for example
4295
+ * when the user's rights were permanently revoked.
4296
+ * @param fetchToken - an async function returning the JWT-encoded OpenID Connect Identity Token
4297
+ * @param onChange - a callback that will be called when the authentication status changes
4298
+ */
4299
+ setAuth(fetchToken, onChange) {
4300
+ if (typeof fetchToken === "string") {
4301
+ throw new Error(
4302
+ "Passing a string to ConvexReactClient.setAuth is no longer supported, please upgrade to passing in an async function to handle reauthentication."
4303
+ );
4304
+ }
4305
+ this.sync.setAuth(
4306
+ fetchToken,
4307
+ onChange ?? (() => {
4308
+ })
4309
+ );
4310
+ }
4311
+ /**
4312
+ * Clear the current authentication token if set.
4313
+ */
4314
+ clearAuth() {
4315
+ this.sync.clearAuth();
4316
+ }
4317
+ /**
4318
+ * @internal
4319
+ */
4320
+ setAdminAuth(token, identity) {
4321
+ this.adminAuth = token;
4322
+ this.fakeUserIdentity = identity;
4323
+ if (this.closed) {
4324
+ throw new Error("ConvexReactClient has already been closed.");
4325
+ }
4326
+ if (this.cachedSync) {
4327
+ this.sync.setAdminAuth(token, identity);
4328
+ }
4329
+ }
4330
+ /**
4331
+ * Construct a new {@link Watch} on a Convex query function.
4332
+ *
4333
+ * **Most application code should not call this method directly. Instead use
4334
+ * the {@link useQuery} hook.**
4335
+ *
4336
+ * The act of creating a watch does nothing, a Watch is stateless.
4337
+ *
4338
+ * @param query - A {@link server.FunctionReference} for the public query to run.
4339
+ * @param args - An arguments object for the query. If this is omitted,
4340
+ * the arguments will be `{}`.
4341
+ * @param options - A {@link WatchQueryOptions} options object for this query.
4342
+ *
4343
+ * @returns The {@link Watch} object.
4344
+ */
4345
+ watchQuery(query, ...argsAndOptions) {
4346
+ const [args, options] = argsAndOptions;
4347
+ const name = getFunctionName(query);
4348
+ return {
4349
+ onUpdate: (callback) => {
4350
+ const { queryToken, unsubscribe } = this.sync.subscribe(
4351
+ name,
4352
+ args,
4353
+ options
4354
+ );
4355
+ const currentListeners = this.listeners.get(queryToken);
4356
+ if (currentListeners !== void 0) {
4357
+ currentListeners.add(callback);
4358
+ } else {
4359
+ this.listeners.set(queryToken, /* @__PURE__ */ new Set([callback]));
4360
+ }
4361
+ return () => {
4362
+ if (this.closed) {
4363
+ return;
4364
+ }
4365
+ const currentListeners2 = this.listeners.get(queryToken);
4366
+ currentListeners2.delete(callback);
4367
+ if (currentListeners2.size === 0) {
4368
+ this.listeners.delete(queryToken);
4369
+ }
4370
+ unsubscribe();
4371
+ };
4372
+ },
4373
+ localQueryResult: () => {
4374
+ if (this.cachedSync) {
4375
+ return this.cachedSync.localQueryResult(name, args);
4376
+ }
4377
+ return void 0;
4378
+ },
4379
+ localQueryLogs: () => {
4380
+ if (this.cachedSync) {
4381
+ return this.cachedSync.localQueryLogs(name, args);
4382
+ }
4383
+ return void 0;
4384
+ },
4385
+ journal: () => {
4386
+ if (this.cachedSync) {
4387
+ return this.cachedSync.queryJournal(name, args);
4388
+ }
4389
+ return void 0;
4390
+ }
4391
+ };
4392
+ }
4393
+ // Let's try out a queryOptions-style API.
4394
+ // This method is similar to the React Query API `queryClient.prefetchQuery()`.
4395
+ // In the future an ensureQueryData(): Promise<Data> method could exist.
4396
+ /**
4397
+ * Indicates likely future interest in a query subscription.
4398
+ *
4399
+ * The implementation currently immediately subscribes to a query. In the future this method
4400
+ * may prioritize some queries over others, fetch the query result without subscribing, or
4401
+ * do nothing in slow network connections or high load scenarios.
4402
+ *
4403
+ * To use this in a React component, call useQuery() and ignore the return value.
4404
+ *
4405
+ * @param queryOptions - A query (function reference from an api object) and its args, plus
4406
+ * an optional extendSubscriptionFor for how long to subscribe to the query.
4407
+ */
4408
+ prewarmQuery(queryOptions) {
4409
+ const extendSubscriptionFor = queryOptions.extendSubscriptionFor ?? DEFAULT_EXTEND_SUBSCRIPTION_FOR;
4410
+ const watch = this.watchQuery(queryOptions.query, queryOptions.args || {});
4411
+ const unsubscribe = watch.onUpdate(() => {
4412
+ });
4413
+ setTimeout(unsubscribe, extendSubscriptionFor);
4414
+ }
4415
+ /**
4416
+ * Construct a new {@link PaginatedWatch} on a Convex paginated query function.
4417
+ *
4418
+ * **Most application code should not call this method directly. Instead use
4419
+ * the {@link usePaginatedQuery} hook.**
4420
+ *
4421
+ * The act of creating a watch does nothing, a Watch is stateless.
4422
+ *
4423
+ * @param query - A {@link server.FunctionReference} for the public query to run.
4424
+ * @param args - An arguments object for the query. If this is omitted,
4425
+ * the arguments will be `{}`.
4426
+ * @param options - A {@link WatchPaginatedQueryOptions} options object for this query.
4427
+ *
4428
+ * @returns The {@link PaginatedWatch} object.
4429
+ *
4430
+ * @internal
4431
+ */
4432
+ watchPaginatedQuery(query, args, options) {
4433
+ const name = getFunctionName(query);
4434
+ return {
4435
+ onUpdate: (callback) => {
4436
+ const { paginatedQueryToken, unsubscribe } = this.paginatedQueryClient.subscribe(name, args || {}, options);
4437
+ const currentListeners = this.listeners.get(paginatedQueryToken);
4438
+ if (currentListeners !== void 0) {
4439
+ currentListeners.add(callback);
4440
+ } else {
4441
+ this.listeners.set(paginatedQueryToken, /* @__PURE__ */ new Set([callback]));
4442
+ }
4443
+ return () => {
4444
+ if (this.closed) {
4445
+ return;
4446
+ }
4447
+ const currentListeners2 = this.listeners.get(paginatedQueryToken);
4448
+ currentListeners2.delete(callback);
4449
+ if (currentListeners2.size === 0) {
4450
+ this.listeners.delete(paginatedQueryToken);
4451
+ }
4452
+ unsubscribe();
4453
+ };
4454
+ },
4455
+ localQueryResult: () => {
4456
+ return this.paginatedQueryClient.localQueryResult(name, args, options);
4457
+ }
4458
+ };
4459
+ }
4460
+ /**
4461
+ * Execute a mutation function.
4462
+ *
4463
+ * @param mutation - A {@link server.FunctionReference} for the public mutation
4464
+ * to run.
4465
+ * @param args - An arguments object for the mutation. If this is omitted,
4466
+ * the arguments will be `{}`.
4467
+ * @param options - A {@link MutationOptions} options object for the mutation.
4468
+ * @returns A promise of the mutation's result.
4469
+ */
4470
+ mutation(mutation, ...argsAndOptions) {
4471
+ const [args, options] = argsAndOptions;
4472
+ const name = getFunctionName(mutation);
4473
+ return this.sync.mutation(name, args, options);
4474
+ }
4475
+ /**
4476
+ * Execute an action function.
4477
+ *
4478
+ * @param action - A {@link server.FunctionReference} for the public action
4479
+ * to run.
4480
+ * @param args - An arguments object for the action. If this is omitted,
4481
+ * the arguments will be `{}`.
4482
+ * @returns A promise of the action's result.
4483
+ */
4484
+ action(action, ...args) {
4485
+ const name = getFunctionName(action);
4486
+ return this.sync.action(name, ...args);
4487
+ }
4488
+ /**
4489
+ * Fetch a query result once.
4490
+ *
4491
+ * **Most application code should subscribe to queries instead, using
4492
+ * the {@link useQuery} hook.**
4493
+ *
4494
+ * @param query - A {@link server.FunctionReference} for the public query
4495
+ * to run.
4496
+ * @param args - An arguments object for the query. If this is omitted,
4497
+ * the arguments will be `{}`.
4498
+ * @returns A promise of the query's result.
4499
+ */
4500
+ query(query, ...args) {
4501
+ const watch = this.watchQuery(query, ...args);
4502
+ const existingResult = watch.localQueryResult();
4503
+ if (existingResult !== void 0) {
4504
+ return Promise.resolve(existingResult);
4505
+ }
4506
+ return new Promise((resolve, reject) => {
4507
+ const unsubscribe = watch.onUpdate(() => {
4508
+ unsubscribe();
4509
+ try {
4510
+ resolve(watch.localQueryResult());
4511
+ } catch (e) {
4512
+ reject(e);
4513
+ }
4514
+ });
4515
+ });
4516
+ }
4517
+ /**
4518
+ * Get the current {@link ConnectionState} between the client and the Convex
4519
+ * backend.
4520
+ *
4521
+ * @returns The {@link ConnectionState} with the Convex backend.
4522
+ */
4523
+ connectionState() {
4524
+ return this.sync.connectionState();
4525
+ }
4526
+ /**
4527
+ * Subscribe to the {@link ConnectionState} between the client and the Convex
4528
+ * backend, calling a callback each time it changes.
4529
+ *
4530
+ * Subscribed callbacks will be called when any part of ConnectionState changes.
4531
+ * ConnectionState may grow in future versions (e.g. to provide a array of
4532
+ * inflight requests) in which case callbacks would be called more frequently.
4533
+ * ConnectionState may also *lose* properties in future versions as we figure
4534
+ * out what information is most useful. As such this API is considered unstable.
4535
+ *
4536
+ * @returns An unsubscribe function to stop listening.
4537
+ */
4538
+ subscribeToConnectionState(cb) {
4539
+ return this.sync.subscribeToConnectionState(cb);
4540
+ }
4541
+ /**
4542
+ * Get the logger for this client.
4543
+ *
4544
+ * @returns The {@link Logger} for this client.
4545
+ */
4546
+ get logger() {
4547
+ return this._logger;
4548
+ }
4549
+ /**
4550
+ * Close any network handles associated with this client and stop all subscriptions.
4551
+ *
4552
+ * Call this method when you're done with a {@link ConvexReactClient} to
4553
+ * dispose of its sockets and resources.
4554
+ *
4555
+ * @returns A `Promise` fulfilled when the connection has been completely closed.
4556
+ */
4557
+ async close() {
4558
+ this.closed = true;
4559
+ this.listeners = /* @__PURE__ */ new Map();
4560
+ if (this.cachedPaginatedQueryClient) {
4561
+ this.cachedPaginatedQueryClient = void 0;
4562
+ }
4563
+ if (this.cachedSync) {
4564
+ const sync = this.cachedSync;
4565
+ this.cachedSync = void 0;
4566
+ await sync.close();
4567
+ }
4568
+ }
4569
+ /**
4570
+ * Handle transitions from both base client and paginated client.
4571
+ * This ensures all transitions are processed synchronously and in order.
4572
+ */
4573
+ handleTransition(transition) {
4574
+ const simple = transition.queries.map((q) => q.token);
4575
+ const paginated = transition.paginatedQueries.map((q) => q.token);
4576
+ this.transition([...simple, ...paginated]);
4577
+ }
4578
+ transition(updatedQueries) {
4579
+ for (const queryToken of updatedQueries) {
4580
+ const callbacks = this.listeners.get(queryToken);
4581
+ if (callbacks) {
4582
+ for (const callback of callbacks) {
4583
+ callback();
4584
+ }
4585
+ }
4586
+ }
4587
+ }
4588
+ }
4589
+ const ConvexContext = React.createContext(
4590
+ void 0
4591
+ // in the future this will be a mocked client for testing
4592
+ );
4593
+ function useConvex() {
4594
+ return reactExports.useContext(ConvexContext);
4595
+ }
4596
+ const ConvexProvider = ({ client, children }) => {
4597
+ return React.createElement(
4598
+ ConvexContext.Provider,
4599
+ { value: client },
4600
+ children
4601
+ );
4602
+ };
4603
+ function useQuery(query, ...args) {
4604
+ const skip = args[0] === "skip";
4605
+ const argsObject = args[0] === "skip" ? {} : parseArgs(args[0]);
4606
+ const queryReference = typeof query === "string" ? makeFunctionReference(query) : query;
4607
+ const queryName = getFunctionName(queryReference);
4608
+ const queries = reactExports.useMemo(
4609
+ () => skip ? {} : { query: { query: queryReference, args: argsObject } },
4610
+ // Stringify args so args that are semantically the same don't trigger a
4611
+ // rerender. Saves developers from adding `useMemo` on every args usage.
4612
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4613
+ [JSON.stringify(convexToJson(argsObject)), queryName, skip]
4614
+ );
4615
+ const results = useQueries(queries);
4616
+ const result = results["query"];
4617
+ if (result instanceof Error) {
4618
+ throw result;
4619
+ }
4620
+ return result;
4621
+ }
4622
+ function useMutation(mutation) {
4623
+ const mutationReference = typeof mutation === "string" ? makeFunctionReference(mutation) : mutation;
4624
+ const convex = reactExports.useContext(ConvexContext);
4625
+ if (convex === void 0) {
4626
+ throw new Error(
4627
+ "Could not find Convex client! `useMutation` must be used in the React component tree under `ConvexProvider`. Did you forget it? See https://docs.convex.dev/quick-start#set-up-convex-in-your-react-app"
4628
+ );
4629
+ }
4630
+ return reactExports.useMemo(
4631
+ () => createMutation(mutationReference, convex),
4632
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4633
+ [convex, getFunctionName(mutationReference)]
4634
+ );
4635
+ }
4636
+ function assertNotAccidentalArgument(value) {
4637
+ if (typeof value === "object" && value !== null && "bubbles" in value && "persist" in value && "isDefaultPrevented" in value) {
4638
+ throw new Error(
4639
+ `Convex function called with SyntheticEvent object. Did you use a Convex function as an event handler directly? Event handlers like onClick receive an event object as their first argument. These SyntheticEvent objects are not valid Convex values. Try wrapping the function like \`const handler = () => myMutation();\` and using \`handler\` in the event handler.`
4640
+ );
4641
+ }
4642
+ }
4643
+ var __defProp = Object.defineProperty;
4644
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4645
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4646
+ class QueriesObserver {
4647
+ constructor(createWatch) {
4648
+ __publicField(this, "createWatch");
4649
+ __publicField(this, "queries");
4650
+ __publicField(this, "listeners");
4651
+ this.createWatch = createWatch;
4652
+ this.queries = {};
4653
+ this.listeners = /* @__PURE__ */ new Set();
4654
+ }
4655
+ setQueries(newQueries) {
4656
+ for (const identifier of Object.keys(newQueries)) {
4657
+ const { query, args, paginationOptions } = newQueries[identifier];
4658
+ getFunctionName(query);
4659
+ if (this.queries[identifier] === void 0) {
4660
+ this.addQuery(
4661
+ identifier,
4662
+ query,
4663
+ args,
4664
+ paginationOptions ? { paginationOptions } : {}
4665
+ );
4666
+ } else {
4667
+ const existingInfo = this.queries[identifier];
4668
+ if (getFunctionName(query) !== getFunctionName(existingInfo.query) || JSON.stringify(convexToJson(args)) !== JSON.stringify(convexToJson(existingInfo.args)) || JSON.stringify(paginationOptions) !== JSON.stringify(existingInfo.paginationOptions)) {
4669
+ this.removeQuery(identifier);
4670
+ this.addQuery(
4671
+ identifier,
4672
+ query,
4673
+ args,
4674
+ paginationOptions ? { paginationOptions } : {}
4675
+ );
4676
+ }
4677
+ }
4678
+ }
4679
+ for (const identifier of Object.keys(this.queries)) {
4680
+ if (newQueries[identifier] === void 0) {
4681
+ this.removeQuery(identifier);
4682
+ }
4683
+ }
4684
+ }
4685
+ subscribe(listener) {
4686
+ this.listeners.add(listener);
4687
+ return () => {
4688
+ this.listeners.delete(listener);
4689
+ };
4690
+ }
4691
+ getLocalResults(queries) {
4692
+ const result = {};
4693
+ for (const identifier of Object.keys(queries)) {
4694
+ const { query, args } = queries[identifier];
4695
+ const paginationOptions = queries[identifier].paginationOptions;
4696
+ getFunctionName(query);
4697
+ const watch = this.createWatch(
4698
+ query,
4699
+ args,
4700
+ paginationOptions ? { paginationOptions } : {}
4701
+ );
4702
+ let value;
4703
+ try {
4704
+ value = watch.localQueryResult();
4705
+ } catch (e) {
4706
+ if (e instanceof Error) {
4707
+ value = e;
4708
+ } else {
4709
+ throw e;
4710
+ }
4711
+ }
4712
+ result[identifier] = value;
4713
+ }
4714
+ return result;
4715
+ }
4716
+ setCreateWatch(createWatch) {
4717
+ this.createWatch = createWatch;
4718
+ for (const identifier of Object.keys(this.queries)) {
4719
+ const { query, args, watch, paginationOptions } = this.queries[identifier];
4720
+ const journal = "journal" in watch ? watch.journal() : void 0;
4721
+ this.removeQuery(identifier);
4722
+ this.addQuery(identifier, query, args, {
4723
+ ...journal ? { journal } : [],
4724
+ ...paginationOptions ? { paginationOptions } : {}
4725
+ });
4726
+ }
4727
+ }
4728
+ destroy() {
4729
+ for (const identifier of Object.keys(this.queries)) {
4730
+ this.removeQuery(identifier);
4731
+ }
4732
+ this.listeners = /* @__PURE__ */ new Set();
4733
+ }
4734
+ addQuery(identifier, query, args, {
4735
+ paginationOptions,
4736
+ journal
4737
+ }) {
4738
+ if (this.queries[identifier] !== void 0) {
4739
+ throw new Error(
4740
+ `Tried to add a new query with identifier ${identifier} when it already exists.`
4741
+ );
4742
+ }
4743
+ const watch = this.createWatch(query, args, {
4744
+ ...journal ? { journal } : [],
4745
+ ...paginationOptions ? { paginationOptions } : {}
4746
+ });
4747
+ const unsubscribe = watch.onUpdate(() => this.notifyListeners());
4748
+ this.queries[identifier] = {
4749
+ query,
4750
+ args,
4751
+ watch,
4752
+ unsubscribe,
4753
+ ...paginationOptions ? { paginationOptions } : {}
4754
+ };
4755
+ }
4756
+ removeQuery(identifier) {
4757
+ const info = this.queries[identifier];
4758
+ if (info === void 0) {
4759
+ throw new Error(`No query found with identifier ${identifier}.`);
4760
+ }
4761
+ info.unsubscribe();
4762
+ delete this.queries[identifier];
4763
+ }
4764
+ notifyListeners() {
4765
+ for (const listener of this.listeners) {
4766
+ listener();
4767
+ }
4768
+ }
4769
+ }
4770
+ function useQueries(queries) {
4771
+ const convex = useConvex();
4772
+ if (convex === void 0) {
4773
+ throw new Error(
4774
+ "Could not find Convex client! `useQuery` must be used in the React component tree under `ConvexProvider`. Did you forget it? See https://docs.convex.dev/quick-start#set-up-convex-in-your-react-app"
4775
+ );
4776
+ }
4777
+ const createWatch = reactExports.useMemo(() => {
4778
+ return (query, args, {
4779
+ journal,
4780
+ paginationOptions
4781
+ }) => {
4782
+ if (paginationOptions) {
4783
+ return convex.watchPaginatedQuery(query, args, paginationOptions);
4784
+ } else {
4785
+ return convex.watchQuery(query, args, journal ? { journal } : {});
4786
+ }
4787
+ };
4788
+ }, [convex]);
4789
+ return useQueriesHelper(queries, createWatch);
4790
+ }
4791
+ function useQueriesHelper(queries, createWatch) {
4792
+ const [observer] = reactExports.useState(() => new QueriesObserver(createWatch));
4793
+ if (observer.createWatch !== createWatch) {
4794
+ observer.setCreateWatch(createWatch);
4795
+ }
4796
+ reactExports.useEffect(() => () => observer.destroy(), [observer]);
4797
+ const subscription = reactExports.useMemo(
4798
+ () => ({
4799
+ getCurrentValue: () => {
4800
+ return observer.getLocalResults(queries);
4801
+ },
4802
+ subscribe: (callback) => {
4803
+ observer.setQueries(queries);
4804
+ return observer.subscribe(callback);
4805
+ }
4806
+ }),
4807
+ [observer, queries]
4808
+ );
4809
+ return useSubscription(subscription);
4810
+ }
4811
+ function createChildComponents(root, pathParts) {
4812
+ const handler = {
4813
+ get(_, prop) {
4814
+ if (typeof prop === "string") {
4815
+ const newParts = [...pathParts, prop];
4816
+ return createChildComponents(root, newParts);
4817
+ } else if (prop === toReferencePath) {
4818
+ if (pathParts.length < 1) {
4819
+ const found = [root, ...pathParts].join(".");
4820
+ throw new Error(
4821
+ `API path is expected to be of the form \`${root}.childComponent.functionName\`. Found: \`${found}\``
4822
+ );
4823
+ }
4824
+ return `_reference/childComponent/` + pathParts.join("/");
4825
+ } else {
4826
+ return void 0;
4827
+ }
4828
+ }
4829
+ };
4830
+ return new Proxy({}, handler);
4831
+ }
4832
+ const componentsGeneric = () => createChildComponents("components", []);
4833
+ export {
4834
+ ConvexReactClient as C,
4835
+ ConvexProvider as a,
4836
+ anyApi as b,
4837
+ componentsGeneric as c,
4838
+ useMutation as d,
4839
+ useQuery as u,
4840
+ v
4841
+ };