on-zero 0.7.10 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. package/{readme.md → README.md} +172 -231
  2. package/dist/cjs/cli.cjs +5 -2
  3. package/dist/cjs/cli.native.js +5 -2
  4. package/dist/cjs/cli.native.js.map +1 -1
  5. package/dist/cjs/combineZeroClients.cjs +2 -2
  6. package/dist/cjs/combineZeroClients.native.js +6 -6
  7. package/dist/cjs/combineZeroClients.native.js.map +1 -1
  8. package/dist/cjs/config.cjs +30 -0
  9. package/dist/cjs/config.native.js +33 -0
  10. package/dist/cjs/config.native.js.map +1 -0
  11. package/dist/cjs/createPermissions.cjs +2 -2
  12. package/dist/cjs/createPermissions.native.js +17 -27
  13. package/dist/cjs/createPermissions.native.js.map +1 -1
  14. package/dist/cjs/createUseQuery.cjs +3 -3
  15. package/dist/cjs/createUseQuery.native.js +4 -4
  16. package/dist/cjs/createUseQuery.native.js.map +1 -1
  17. package/dist/cjs/createUseQueryDirect.cjs +4 -3
  18. package/dist/cjs/createUseQueryDirect.native.js +14 -18
  19. package/dist/cjs/createUseQueryDirect.native.js.map +1 -1
  20. package/dist/cjs/createZeroClient.cjs +29 -9
  21. package/dist/cjs/createZeroClient.connection.test.cjs +11 -0
  22. package/dist/cjs/createZeroClient.connection.test.native.js +14 -7
  23. package/dist/cjs/createZeroClient.connection.test.native.js.map +1 -1
  24. package/dist/cjs/createZeroClient.native.js +58 -32
  25. package/dist/cjs/createZeroClient.native.js.map +1 -1
  26. package/dist/cjs/createZeroClient.recovery.test.cjs +90 -3
  27. package/dist/cjs/createZeroClient.recovery.test.native.js +109 -19
  28. package/dist/cjs/createZeroClient.recovery.test.native.js.map +1 -1
  29. package/dist/cjs/generate-helpers.cjs +70 -17
  30. package/dist/cjs/generate-helpers.native.js +110 -23
  31. package/dist/cjs/generate-helpers.native.js.map +1 -1
  32. package/dist/cjs/generate-layout.cjs +586 -0
  33. package/dist/cjs/generate-layout.native.js +1275 -0
  34. package/dist/cjs/generate-layout.native.js.map +1 -0
  35. package/dist/cjs/generate-lite.cjs +295 -27
  36. package/dist/cjs/generate-lite.native.js +854 -102
  37. package/dist/cjs/generate-lite.native.js.map +1 -1
  38. package/dist/cjs/generate-lite.test.cjs +433 -41
  39. package/dist/cjs/generate-lite.test.native.js +446 -41
  40. package/dist/cjs/generate-lite.test.native.js.map +1 -1
  41. package/dist/cjs/generate.cjs +172 -94
  42. package/dist/cjs/generate.native.js +324 -148
  43. package/dist/cjs/generate.native.js.map +1 -1
  44. package/dist/cjs/generate.test.cjs +362 -45
  45. package/dist/cjs/generate.test.native.js +374 -45
  46. package/dist/cjs/generate.test.native.js.map +1 -1
  47. package/dist/cjs/helpers/NullToOptional.cjs +18 -0
  48. package/dist/cjs/helpers/NullToOptional.native.js +21 -0
  49. package/dist/cjs/helpers/NullToOptional.native.js.map +1 -0
  50. package/dist/cjs/helpers/asyncContext.cjs +128 -0
  51. package/dist/cjs/helpers/asyncContext.native.js +87 -0
  52. package/dist/cjs/helpers/asyncContext.native.js.map +1 -0
  53. package/dist/cjs/helpers/batchQuery.cjs +2 -2
  54. package/dist/cjs/helpers/batchQuery.native.js +2 -2
  55. package/dist/cjs/helpers/batchQuery.native.js.map +1 -1
  56. package/dist/cjs/helpers/createMutators.cjs +7 -4
  57. package/dist/cjs/helpers/createMutators.native.js +12 -9
  58. package/dist/cjs/helpers/createMutators.native.js.map +1 -1
  59. package/dist/cjs/helpers/createMutators.test.native.js +2 -2
  60. package/dist/cjs/helpers/createMutators.test.native.js.map +1 -1
  61. package/dist/cjs/helpers/ellipsis.cjs +35 -0
  62. package/dist/cjs/helpers/ellipsis.native.js +38 -0
  63. package/dist/cjs/helpers/ellipsis.native.js.map +1 -0
  64. package/dist/cjs/helpers/emitter.cjs +99 -0
  65. package/dist/cjs/helpers/emitter.native.js +125 -0
  66. package/dist/cjs/helpers/emitter.native.js.map +1 -0
  67. package/dist/cjs/helpers/ensure.cjs +33 -0
  68. package/dist/cjs/helpers/ensure.native.js +37 -0
  69. package/dist/cjs/helpers/ensure.native.js.map +1 -0
  70. package/dist/cjs/helpers/ensureLoggedIn.cjs +2 -2
  71. package/dist/cjs/helpers/ensureLoggedIn.native.js +3 -3
  72. package/dist/cjs/helpers/ensureLoggedIn.native.js.map +1 -1
  73. package/dist/cjs/helpers/errors.cjs +40 -0
  74. package/dist/cjs/helpers/errors.native.js +152 -0
  75. package/dist/cjs/helpers/errors.native.js.map +1 -0
  76. package/dist/cjs/helpers/getCurrentComponentStack.cjs +71 -0
  77. package/dist/cjs/helpers/getCurrentComponentStack.native.js +93 -0
  78. package/dist/cjs/helpers/getCurrentComponentStack.native.js.map +1 -0
  79. package/dist/cjs/helpers/globalValue.cjs +39 -0
  80. package/dist/cjs/helpers/globalValue.native.js +42 -0
  81. package/dist/cjs/helpers/globalValue.native.js.map +1 -0
  82. package/dist/cjs/helpers/mapObject.cjs +36 -0
  83. package/dist/cjs/helpers/mapObject.native.js +39 -0
  84. package/dist/cjs/helpers/mapObject.native.js.map +1 -0
  85. package/dist/cjs/helpers/mutationLifecycle.cjs +251 -0
  86. package/dist/cjs/helpers/mutationLifecycle.native.js +392 -0
  87. package/dist/cjs/helpers/mutationLifecycle.native.js.map +1 -0
  88. package/dist/cjs/helpers/mutationLifecycle.test.cjs +174 -0
  89. package/dist/cjs/helpers/mutationLifecycle.test.native.js +182 -0
  90. package/dist/cjs/helpers/mutationLifecycle.test.native.js.map +1 -0
  91. package/dist/cjs/helpers/mutatorContext.cjs +3 -3
  92. package/dist/cjs/helpers/mutatorContext.native.js +5 -5
  93. package/dist/cjs/helpers/mutatorContext.native.js.map +1 -1
  94. package/dist/cjs/helpers/platform.cjs +31 -0
  95. package/dist/cjs/helpers/platform.native.js +33 -0
  96. package/dist/cjs/helpers/platform.native.js.map +1 -0
  97. package/dist/cjs/helpers/prettyFormatZeroQuery.cjs +2 -2
  98. package/dist/cjs/helpers/prettyFormatZeroQuery.native.js +7 -7
  99. package/dist/cjs/helpers/prettyFormatZeroQuery.native.js.map +1 -1
  100. package/dist/cjs/helpers/queryContext.cjs +2 -2
  101. package/dist/cjs/helpers/queryContext.native.js +4 -4
  102. package/dist/cjs/helpers/queryContext.native.js.map +1 -1
  103. package/dist/cjs/helpers/recoverZeroClient.cjs +14 -15
  104. package/dist/cjs/helpers/recoverZeroClient.native.js +26 -23
  105. package/dist/cjs/helpers/recoverZeroClient.native.js.map +1 -1
  106. package/dist/cjs/helpers/recoverZeroClient.test.cjs +10 -8
  107. package/dist/cjs/helpers/recoverZeroClient.test.native.js +17 -21
  108. package/dist/cjs/helpers/recoverZeroClient.test.native.js.map +1 -1
  109. package/dist/cjs/helpers/sleep.cjs +34 -0
  110. package/dist/cjs/helpers/sleep.native.js +39 -0
  111. package/dist/cjs/helpers/sleep.native.js.map +1 -0
  112. package/dist/cjs/helpers/time.cjs +47 -0
  113. package/dist/cjs/helpers/time.native.js +80 -0
  114. package/dist/cjs/helpers/time.native.js.map +1 -0
  115. package/dist/cjs/helpers/tuple.cjs +18 -0
  116. package/dist/cjs/helpers/tuple.native.js +21 -0
  117. package/dist/cjs/helpers/tuple.native.js.map +1 -0
  118. package/dist/cjs/helpers/useMutation.native.js +5 -5
  119. package/dist/cjs/helpers/useMutation.native.js.map +1 -1
  120. package/dist/cjs/helpers/useMutation.test.native.js +1 -1
  121. package/dist/cjs/helpers/useMutation.test.native.js.map +1 -1
  122. package/dist/cjs/helpers/useZeroDebug.cjs +2 -2
  123. package/dist/cjs/helpers/useZeroDebug.native.js +7 -8
  124. package/dist/cjs/helpers/useZeroDebug.native.js.map +1 -1
  125. package/dist/cjs/index.cjs +9 -1
  126. package/dist/cjs/index.native.js +8 -0
  127. package/dist/cjs/index.native.js.map +1 -1
  128. package/dist/cjs/instanceRegistry.cjs +16 -4
  129. package/dist/cjs/instanceRegistry.native.js +56 -6
  130. package/dist/cjs/instanceRegistry.native.js.map +1 -1
  131. package/dist/cjs/multi.cjs +34 -13
  132. package/dist/cjs/multi.native.js +39 -17
  133. package/dist/cjs/multi.native.js.map +1 -1
  134. package/dist/cjs/multiInstance.test.cjs +6 -2
  135. package/dist/cjs/multiInstance.test.native.js +13 -9
  136. package/dist/cjs/multiInstance.test.native.js.map +1 -1
  137. package/dist/cjs/multiInstanceNested.test.native.js +10 -10
  138. package/dist/cjs/multiInstanceNested.test.native.js.map +1 -1
  139. package/dist/cjs/multiPartition.test.cjs +85 -36
  140. package/dist/cjs/multiPartition.test.native.js +102 -39
  141. package/dist/cjs/multiPartition.test.native.js.map +1 -1
  142. package/dist/cjs/mutations.cjs +2 -2
  143. package/dist/cjs/mutations.native.js +4 -4
  144. package/dist/cjs/mutations.native.js.map +1 -1
  145. package/dist/cjs/mutations.test.native.js +3 -3
  146. package/dist/cjs/mutations.test.native.js.map +1 -1
  147. package/dist/cjs/provideZero.hydration.test.cjs +3 -3
  148. package/dist/cjs/provideZero.hydration.test.native.js +4 -4
  149. package/dist/cjs/provideZero.hydration.test.native.js.map +1 -1
  150. package/dist/cjs/run.cjs +1 -1
  151. package/dist/cjs/run.native.js +3 -3
  152. package/dist/cjs/run.native.js.map +1 -1
  153. package/dist/cjs/server.cjs +20 -16
  154. package/dist/cjs/server.native.js +50 -57
  155. package/dist/cjs/server.native.js.map +1 -1
  156. package/dist/cjs/server.test.cjs +129 -6
  157. package/dist/cjs/server.test.native.js +141 -10
  158. package/dist/cjs/server.test.native.js.map +1 -1
  159. package/dist/cjs/serverWhere.test.native.js +3 -3
  160. package/dist/cjs/serverWhere.test.native.js.map +1 -1
  161. package/dist/cjs/state.cjs +2 -2
  162. package/dist/cjs/state.native.js +10 -10
  163. package/dist/cjs/state.native.js.map +1 -1
  164. package/dist/cjs/usePermission.test.native.js +3 -3
  165. package/dist/cjs/usePermission.test.native.js.map +1 -1
  166. package/dist/cjs/useQuery.empty.test.cjs +3 -3
  167. package/dist/cjs/useQuery.empty.test.native.js +6 -6
  168. package/dist/cjs/useQuery.empty.test.native.js.map +1 -1
  169. package/dist/cjs/useQuery.ssr.test.native.js +2 -2
  170. package/dist/cjs/useQuery.ssr.test.native.js.map +1 -1
  171. package/dist/cjs/vite-plugin.cjs +7 -8
  172. package/dist/cjs/vite-plugin.native.js +11 -11
  173. package/dist/cjs/vite-plugin.native.js.map +1 -1
  174. package/dist/cjs/where.cjs +3 -3
  175. package/dist/cjs/where.native.js +4 -4
  176. package/dist/cjs/where.native.js.map +1 -1
  177. package/dist/esm/cli.mjs +6 -3
  178. package/dist/esm/cli.mjs.map +1 -1
  179. package/dist/esm/cli.native.js +6 -3
  180. package/dist/esm/cli.native.js.map +1 -1
  181. package/dist/esm/combineZeroClients.mjs +1 -1
  182. package/dist/esm/combineZeroClients.mjs.map +1 -1
  183. package/dist/esm/combineZeroClients.native.js +5 -5
  184. package/dist/esm/combineZeroClients.native.js.map +1 -1
  185. package/dist/esm/config.mjs +5 -0
  186. package/dist/esm/config.mjs.map +1 -0
  187. package/dist/esm/config.native.js +5 -0
  188. package/dist/esm/config.native.js.map +1 -0
  189. package/dist/esm/createPermissions.mjs +1 -1
  190. package/dist/esm/createPermissions.mjs.map +1 -1
  191. package/dist/esm/createPermissions.native.js +16 -26
  192. package/dist/esm/createPermissions.native.js.map +1 -1
  193. package/dist/esm/createUseQuery.mjs +2 -2
  194. package/dist/esm/createUseQuery.mjs.map +1 -1
  195. package/dist/esm/createUseQuery.native.js +3 -3
  196. package/dist/esm/createUseQuery.native.js.map +1 -1
  197. package/dist/esm/createUseQueryDirect.mjs +2 -1
  198. package/dist/esm/createUseQueryDirect.mjs.map +1 -1
  199. package/dist/esm/createUseQueryDirect.native.js +12 -16
  200. package/dist/esm/createUseQueryDirect.native.js.map +1 -1
  201. package/dist/esm/createZeroClient.connection.test.mjs +11 -0
  202. package/dist/esm/createZeroClient.connection.test.mjs.map +1 -1
  203. package/dist/esm/createZeroClient.connection.test.native.js +14 -7
  204. package/dist/esm/createZeroClient.connection.test.native.js.map +1 -1
  205. package/dist/esm/createZeroClient.mjs +25 -5
  206. package/dist/esm/createZeroClient.mjs.map +1 -1
  207. package/dist/esm/createZeroClient.native.js +54 -28
  208. package/dist/esm/createZeroClient.native.js.map +1 -1
  209. package/dist/esm/createZeroClient.recovery.test.mjs +90 -3
  210. package/dist/esm/createZeroClient.recovery.test.mjs.map +1 -1
  211. package/dist/esm/createZeroClient.recovery.test.native.js +109 -19
  212. package/dist/esm/createZeroClient.recovery.test.native.js.map +1 -1
  213. package/dist/esm/generate-helpers.mjs +70 -18
  214. package/dist/esm/generate-helpers.mjs.map +1 -1
  215. package/dist/esm/generate-helpers.native.js +110 -24
  216. package/dist/esm/generate-helpers.native.js.map +1 -1
  217. package/dist/esm/generate-layout.mjs +560 -0
  218. package/dist/esm/generate-layout.mjs.map +1 -0
  219. package/dist/esm/generate-layout.native.js +1246 -0
  220. package/dist/esm/generate-layout.native.js.map +1 -0
  221. package/dist/esm/generate-lite.mjs +296 -28
  222. package/dist/esm/generate-lite.mjs.map +1 -1
  223. package/dist/esm/generate-lite.native.js +855 -103
  224. package/dist/esm/generate-lite.native.js.map +1 -1
  225. package/dist/esm/generate-lite.test.mjs +434 -42
  226. package/dist/esm/generate-lite.test.mjs.map +1 -1
  227. package/dist/esm/generate-lite.test.native.js +447 -42
  228. package/dist/esm/generate-lite.test.native.js.map +1 -1
  229. package/dist/esm/generate.mjs +172 -96
  230. package/dist/esm/generate.mjs.map +1 -1
  231. package/dist/esm/generate.native.js +324 -150
  232. package/dist/esm/generate.native.js.map +1 -1
  233. package/dist/esm/generate.test.mjs +366 -49
  234. package/dist/esm/generate.test.mjs.map +1 -1
  235. package/dist/esm/generate.test.native.js +378 -49
  236. package/dist/esm/generate.test.native.js.map +1 -1
  237. package/dist/esm/helpers/NullToOptional.mjs +2 -0
  238. package/dist/esm/helpers/NullToOptional.mjs.map +1 -0
  239. package/dist/esm/helpers/NullToOptional.native.js +2 -0
  240. package/dist/esm/helpers/NullToOptional.native.js.map +1 -0
  241. package/dist/esm/helpers/asyncContext.mjs +102 -0
  242. package/dist/esm/helpers/asyncContext.mjs.map +1 -0
  243. package/dist/esm/helpers/asyncContext.native.js +58 -0
  244. package/dist/esm/helpers/asyncContext.native.js.map +1 -0
  245. package/dist/esm/helpers/batchQuery.mjs +1 -1
  246. package/dist/esm/helpers/batchQuery.native.js +1 -1
  247. package/dist/esm/helpers/createMutators.mjs +5 -2
  248. package/dist/esm/helpers/createMutators.mjs.map +1 -1
  249. package/dist/esm/helpers/createMutators.native.js +10 -7
  250. package/dist/esm/helpers/createMutators.native.js.map +1 -1
  251. package/dist/esm/helpers/createMutators.test.native.js +2 -2
  252. package/dist/esm/helpers/createMutators.test.native.js.map +1 -1
  253. package/dist/esm/helpers/ellipsis.mjs +10 -0
  254. package/dist/esm/helpers/ellipsis.mjs.map +1 -0
  255. package/dist/esm/helpers/ellipsis.native.js +10 -0
  256. package/dist/esm/helpers/ellipsis.native.js.map +1 -0
  257. package/dist/esm/helpers/emitter.mjs +72 -0
  258. package/dist/esm/helpers/emitter.mjs.map +1 -0
  259. package/dist/esm/helpers/emitter.native.js +95 -0
  260. package/dist/esm/helpers/emitter.native.js.map +1 -0
  261. package/dist/esm/helpers/ensure.mjs +8 -0
  262. package/dist/esm/helpers/ensure.mjs.map +1 -0
  263. package/dist/esm/helpers/ensure.native.js +9 -0
  264. package/dist/esm/helpers/ensure.native.js.map +1 -0
  265. package/dist/esm/helpers/ensureLoggedIn.mjs +1 -1
  266. package/dist/esm/helpers/ensureLoggedIn.mjs.map +1 -1
  267. package/dist/esm/helpers/ensureLoggedIn.native.js +2 -2
  268. package/dist/esm/helpers/ensureLoggedIn.native.js.map +1 -1
  269. package/dist/esm/helpers/errors.mjs +14 -0
  270. package/dist/esm/helpers/errors.mjs.map +1 -0
  271. package/dist/esm/helpers/errors.native.js +123 -0
  272. package/dist/esm/helpers/errors.native.js.map +1 -0
  273. package/dist/esm/helpers/getCurrentComponentStack.mjs +35 -0
  274. package/dist/esm/helpers/getCurrentComponentStack.mjs.map +1 -0
  275. package/dist/esm/helpers/getCurrentComponentStack.native.js +54 -0
  276. package/dist/esm/helpers/getCurrentComponentStack.native.js.map +1 -0
  277. package/dist/esm/helpers/globalValue.mjs +14 -0
  278. package/dist/esm/helpers/globalValue.mjs.map +1 -0
  279. package/dist/esm/helpers/globalValue.native.js +14 -0
  280. package/dist/esm/helpers/globalValue.native.js.map +1 -0
  281. package/dist/esm/helpers/mapObject.mjs +11 -0
  282. package/dist/esm/helpers/mapObject.mjs.map +1 -0
  283. package/dist/esm/helpers/mapObject.native.js +11 -0
  284. package/dist/esm/helpers/mapObject.native.js.map +1 -0
  285. package/dist/esm/helpers/mutationLifecycle.mjs +221 -0
  286. package/dist/esm/helpers/mutationLifecycle.mjs.map +1 -0
  287. package/dist/esm/helpers/mutationLifecycle.native.js +359 -0
  288. package/dist/esm/helpers/mutationLifecycle.native.js.map +1 -0
  289. package/dist/esm/helpers/mutationLifecycle.test.mjs +175 -0
  290. package/dist/esm/helpers/mutationLifecycle.test.mjs.map +1 -0
  291. package/dist/esm/helpers/mutationLifecycle.test.native.js +180 -0
  292. package/dist/esm/helpers/mutationLifecycle.test.native.js.map +1 -0
  293. package/dist/esm/helpers/mutatorContext.mjs +1 -1
  294. package/dist/esm/helpers/mutatorContext.native.js +4 -4
  295. package/dist/esm/helpers/mutatorContext.native.js.map +1 -1
  296. package/dist/esm/helpers/platform.mjs +5 -0
  297. package/dist/esm/helpers/platform.mjs.map +1 -0
  298. package/dist/esm/helpers/platform.native.js +4 -0
  299. package/dist/esm/helpers/platform.native.js.map +1 -0
  300. package/dist/esm/helpers/prettyFormatZeroQuery.mjs +1 -1
  301. package/dist/esm/helpers/prettyFormatZeroQuery.native.js +6 -6
  302. package/dist/esm/helpers/prettyFormatZeroQuery.native.js.map +1 -1
  303. package/dist/esm/helpers/queryContext.mjs +1 -1
  304. package/dist/esm/helpers/queryContext.native.js +3 -3
  305. package/dist/esm/helpers/queryContext.native.js.map +1 -1
  306. package/dist/esm/helpers/recoverZeroClient.mjs +14 -15
  307. package/dist/esm/helpers/recoverZeroClient.mjs.map +1 -1
  308. package/dist/esm/helpers/recoverZeroClient.native.js +26 -23
  309. package/dist/esm/helpers/recoverZeroClient.native.js.map +1 -1
  310. package/dist/esm/helpers/recoverZeroClient.test.mjs +8 -6
  311. package/dist/esm/helpers/recoverZeroClient.test.mjs.map +1 -1
  312. package/dist/esm/helpers/recoverZeroClient.test.native.js +15 -19
  313. package/dist/esm/helpers/recoverZeroClient.test.native.js.map +1 -1
  314. package/dist/esm/helpers/sleep.mjs +9 -0
  315. package/dist/esm/helpers/sleep.mjs.map +1 -0
  316. package/dist/esm/helpers/sleep.native.js +11 -0
  317. package/dist/esm/helpers/sleep.native.js.map +1 -0
  318. package/dist/esm/helpers/time.mjs +22 -0
  319. package/dist/esm/helpers/time.mjs.map +1 -0
  320. package/dist/esm/helpers/time.native.js +52 -0
  321. package/dist/esm/helpers/time.native.js.map +1 -0
  322. package/dist/esm/helpers/tuple.mjs +2 -0
  323. package/dist/esm/helpers/tuple.mjs.map +1 -0
  324. package/dist/esm/helpers/tuple.native.js +2 -0
  325. package/dist/esm/helpers/tuple.native.js.map +1 -0
  326. package/dist/esm/helpers/useMutation.native.js +5 -5
  327. package/dist/esm/helpers/useMutation.native.js.map +1 -1
  328. package/dist/esm/helpers/useMutation.test.native.js +1 -1
  329. package/dist/esm/helpers/useMutation.test.native.js.map +1 -1
  330. package/dist/esm/helpers/useZeroDebug.mjs +1 -1
  331. package/dist/esm/helpers/useZeroDebug.mjs.map +1 -1
  332. package/dist/esm/helpers/useZeroDebug.native.js +6 -7
  333. package/dist/esm/helpers/useZeroDebug.native.js.map +1 -1
  334. package/dist/esm/index.js +3 -1
  335. package/dist/esm/index.js.map +1 -1
  336. package/dist/esm/index.mjs +3 -1
  337. package/dist/esm/index.mjs.map +1 -1
  338. package/dist/esm/index.native.js +3 -1
  339. package/dist/esm/index.native.js.map +1 -1
  340. package/dist/esm/instanceRegistry.mjs +13 -2
  341. package/dist/esm/instanceRegistry.mjs.map +1 -1
  342. package/dist/esm/instanceRegistry.native.js +53 -4
  343. package/dist/esm/instanceRegistry.native.js.map +1 -1
  344. package/dist/esm/multi.mjs +33 -12
  345. package/dist/esm/multi.mjs.map +1 -1
  346. package/dist/esm/multi.native.js +38 -16
  347. package/dist/esm/multi.native.js.map +1 -1
  348. package/dist/esm/multiInstance.test.mjs +5 -1
  349. package/dist/esm/multiInstance.test.mjs.map +1 -1
  350. package/dist/esm/multiInstance.test.native.js +12 -8
  351. package/dist/esm/multiInstance.test.native.js.map +1 -1
  352. package/dist/esm/multiInstanceNested.test.native.js +10 -10
  353. package/dist/esm/multiInstanceNested.test.native.js.map +1 -1
  354. package/dist/esm/multiPartition.test.mjs +86 -37
  355. package/dist/esm/multiPartition.test.mjs.map +1 -1
  356. package/dist/esm/multiPartition.test.native.js +103 -40
  357. package/dist/esm/multiPartition.test.native.js.map +1 -1
  358. package/dist/esm/mutations.mjs +1 -1
  359. package/dist/esm/mutations.mjs.map +1 -1
  360. package/dist/esm/mutations.native.js +3 -3
  361. package/dist/esm/mutations.native.js.map +1 -1
  362. package/dist/esm/mutations.test.native.js +3 -3
  363. package/dist/esm/mutations.test.native.js.map +1 -1
  364. package/dist/esm/provideZero.hydration.test.mjs +1 -1
  365. package/dist/esm/provideZero.hydration.test.mjs.map +1 -1
  366. package/dist/esm/provideZero.hydration.test.native.js +2 -2
  367. package/dist/esm/provideZero.hydration.test.native.js.map +1 -1
  368. package/dist/esm/run.mjs +1 -1
  369. package/dist/esm/run.mjs.map +1 -1
  370. package/dist/esm/run.native.js +3 -3
  371. package/dist/esm/run.native.js.map +1 -1
  372. package/dist/esm/server.mjs +20 -15
  373. package/dist/esm/server.mjs.map +1 -1
  374. package/dist/esm/server.native.js +50 -56
  375. package/dist/esm/server.native.js.map +1 -1
  376. package/dist/esm/server.test.mjs +130 -7
  377. package/dist/esm/server.test.mjs.map +1 -1
  378. package/dist/esm/server.test.native.js +142 -11
  379. package/dist/esm/server.test.native.js.map +1 -1
  380. package/dist/esm/serverWhere.test.mjs.map +1 -1
  381. package/dist/esm/serverWhere.test.native.js +3 -3
  382. package/dist/esm/serverWhere.test.native.js.map +1 -1
  383. package/dist/esm/state.mjs +1 -1
  384. package/dist/esm/state.mjs.map +1 -1
  385. package/dist/esm/state.native.js +9 -9
  386. package/dist/esm/state.native.js.map +1 -1
  387. package/dist/esm/usePermission.test.native.js +3 -3
  388. package/dist/esm/usePermission.test.native.js.map +1 -1
  389. package/dist/esm/useQuery.empty.test.mjs +1 -1
  390. package/dist/esm/useQuery.empty.test.mjs.map +1 -1
  391. package/dist/esm/useQuery.empty.test.native.js +4 -4
  392. package/dist/esm/useQuery.empty.test.native.js.map +1 -1
  393. package/dist/esm/useQuery.ssr.test.native.js +2 -2
  394. package/dist/esm/useQuery.ssr.test.native.js.map +1 -1
  395. package/dist/esm/vite-plugin.mjs +7 -8
  396. package/dist/esm/vite-plugin.mjs.map +1 -1
  397. package/dist/esm/vite-plugin.native.js +11 -11
  398. package/dist/esm/vite-plugin.native.js.map +1 -1
  399. package/dist/esm/where.mjs +1 -1
  400. package/dist/esm/where.mjs.map +1 -1
  401. package/dist/esm/where.native.js +2 -2
  402. package/dist/esm/where.native.js.map +1 -1
  403. package/package.json +18 -6
  404. package/src/cli.ts +11 -3
  405. package/src/combineZeroClients.tsx +18 -10
  406. package/src/config.ts +72 -0
  407. package/src/createPermissions.ts +3 -4
  408. package/src/createUseQuery.tsx +8 -8
  409. package/src/createUseQueryDirect.tsx +11 -10
  410. package/src/createZeroClient.authData.test.tsx +1 -1
  411. package/src/createZeroClient.connection.test.tsx +13 -2
  412. package/src/createZeroClient.recovery.test.tsx +100 -4
  413. package/src/createZeroClient.tsx +87 -30
  414. package/src/generate-helpers.ts +108 -31
  415. package/src/generate-layout.ts +841 -0
  416. package/src/generate-lite.test.ts +421 -42
  417. package/src/generate-lite.ts +479 -43
  418. package/src/generate.test.ts +552 -90
  419. package/src/generate.ts +360 -163
  420. package/src/helpers/NullToOptional.ts +5 -0
  421. package/src/helpers/asyncContext.native.ts +90 -0
  422. package/src/helpers/asyncContext.ts +159 -0
  423. package/src/helpers/batchQuery.ts +2 -2
  424. package/src/helpers/createMutators.ts +11 -8
  425. package/src/helpers/ellipsis.ts +9 -0
  426. package/src/helpers/emitter.tsx +106 -0
  427. package/src/helpers/ensure.ts +10 -0
  428. package/src/helpers/ensureLoggedIn.ts +1 -2
  429. package/src/helpers/errors.ts +13 -0
  430. package/src/helpers/getCurrentComponentStack.ts +56 -0
  431. package/src/helpers/globalValue.ts +40 -0
  432. package/src/helpers/mapObject.ts +14 -0
  433. package/src/helpers/mutationLifecycle.test.ts +180 -0
  434. package/src/helpers/mutationLifecycle.ts +313 -0
  435. package/src/helpers/mutatorContext.ts +3 -3
  436. package/src/helpers/platform.native.ts +2 -0
  437. package/src/helpers/platform.ts +16 -0
  438. package/src/helpers/prettyFormatZeroQuery.ts +2 -2
  439. package/src/helpers/queryContext.ts +2 -2
  440. package/src/helpers/recoverZeroClient.test.ts +23 -21
  441. package/src/helpers/recoverZeroClient.ts +56 -49
  442. package/src/helpers/sleep.ts +8 -0
  443. package/src/helpers/time.ts +51 -0
  444. package/src/helpers/tuple.ts +1 -0
  445. package/src/helpers/useMutation.tsx +3 -3
  446. package/src/helpers/useZeroDebug.ts +3 -3
  447. package/src/index.ts +13 -1
  448. package/src/instanceRegistry.ts +19 -6
  449. package/src/multi.ts +75 -31
  450. package/src/multiInstance.test.tsx +31 -13
  451. package/src/multiInstanceNested.test.tsx +2 -2
  452. package/src/multiPartition.test.ts +62 -27
  453. package/src/mutations.ts +10 -10
  454. package/src/provideZero.hydration.test.tsx +1 -1
  455. package/src/resolveQuery.ts +2 -2
  456. package/src/run.ts +7 -7
  457. package/src/server.test.ts +117 -18
  458. package/src/server.ts +70 -43
  459. package/src/serverWhere.ts +2 -2
  460. package/src/state.ts +2 -2
  461. package/src/types.ts +47 -6
  462. package/src/useQuery.empty.test.tsx +3 -3
  463. package/src/useQuery.ssr.test.ts +1 -1
  464. package/src/vite-plugin.ts +12 -9
  465. package/src/where.ts +6 -7
  466. package/src/zeroRunner.ts +2 -2
  467. package/types/combineZeroClients.d.ts +11 -5
  468. package/types/combineZeroClients.d.ts.map +1 -1
  469. package/types/config.d.ts +62 -0
  470. package/types/config.d.ts.map +1 -0
  471. package/types/createPermissions.d.ts.map +1 -1
  472. package/types/createUseQuery.d.ts.map +1 -1
  473. package/types/createUseQueryDirect.d.ts +1 -1
  474. package/types/createUseQueryDirect.d.ts.map +1 -1
  475. package/types/createZeroClient.d.ts +22 -12
  476. package/types/createZeroClient.d.ts.map +1 -1
  477. package/types/createZeroClient.recovery.test.d.ts.map +1 -1
  478. package/types/generate-helpers.d.ts +17 -2
  479. package/types/generate-helpers.d.ts.map +1 -1
  480. package/types/generate-layout.d.ts +26 -0
  481. package/types/generate-layout.d.ts.map +1 -0
  482. package/types/generate-lite.d.ts +29 -1
  483. package/types/generate-lite.d.ts.map +1 -1
  484. package/types/generate.d.ts +20 -0
  485. package/types/generate.d.ts.map +1 -1
  486. package/types/helpers/NullToOptional.d.ts +6 -0
  487. package/types/helpers/NullToOptional.d.ts.map +1 -0
  488. package/types/helpers/asyncContext.d.ts +15 -0
  489. package/types/helpers/asyncContext.d.ts.map +1 -0
  490. package/types/helpers/asyncContext.native.d.ts +8 -0
  491. package/types/helpers/asyncContext.native.d.ts.map +1 -0
  492. package/types/helpers/createMutators.d.ts +2 -1
  493. package/types/helpers/createMutators.d.ts.map +1 -1
  494. package/types/helpers/ellipsis.d.ts +2 -0
  495. package/types/helpers/ellipsis.d.ts.map +1 -0
  496. package/types/helpers/emitter.d.ts +21 -0
  497. package/types/helpers/emitter.d.ts.map +1 -0
  498. package/types/helpers/ensure.d.ts +2 -0
  499. package/types/helpers/ensure.d.ts.map +1 -0
  500. package/types/helpers/ensureLoggedIn.d.ts.map +1 -1
  501. package/types/helpers/errors.d.ts +7 -0
  502. package/types/helpers/errors.d.ts.map +1 -0
  503. package/types/helpers/getCurrentComponentStack.d.ts +2 -0
  504. package/types/helpers/getCurrentComponentStack.d.ts.map +1 -0
  505. package/types/helpers/globalValue.d.ts +23 -0
  506. package/types/helpers/globalValue.d.ts.map +1 -0
  507. package/types/helpers/mapObject.d.ts +4 -0
  508. package/types/helpers/mapObject.d.ts.map +1 -0
  509. package/types/helpers/mutationLifecycle.d.ts +44 -0
  510. package/types/helpers/mutationLifecycle.d.ts.map +1 -0
  511. package/types/helpers/mutationLifecycle.test.d.ts +2 -0
  512. package/types/helpers/mutationLifecycle.test.d.ts.map +1 -0
  513. package/types/helpers/platform.d.ts +3 -0
  514. package/types/helpers/platform.d.ts.map +1 -0
  515. package/types/helpers/platform.native.d.ts +3 -0
  516. package/types/helpers/platform.native.d.ts.map +1 -0
  517. package/types/helpers/recoverZeroClient.d.ts +13 -9
  518. package/types/helpers/recoverZeroClient.d.ts.map +1 -1
  519. package/types/helpers/sleep.d.ts +2 -0
  520. package/types/helpers/sleep.d.ts.map +1 -0
  521. package/types/helpers/time.d.ts +28 -0
  522. package/types/helpers/time.d.ts.map +1 -0
  523. package/types/helpers/tuple.d.ts +2 -0
  524. package/types/helpers/tuple.d.ts.map +1 -0
  525. package/types/index.d.ts +3 -1
  526. package/types/index.d.ts.map +1 -1
  527. package/types/instanceRegistry.d.ts +1 -0
  528. package/types/instanceRegistry.d.ts.map +1 -1
  529. package/types/multi.d.ts +23 -1
  530. package/types/multi.d.ts.map +1 -1
  531. package/types/mutations.d.ts +1 -1
  532. package/types/mutations.d.ts.map +1 -1
  533. package/types/run.d.ts.map +1 -1
  534. package/types/server.d.ts +12 -8
  535. package/types/server.d.ts.map +1 -1
  536. package/types/state.d.ts +1 -1
  537. package/types/state.d.ts.map +1 -1
  538. package/types/types.d.ts +23 -1
  539. package/types/types.d.ts.map +1 -1
  540. package/types/vite-plugin.d.ts.map +1 -1
  541. package/types/where.d.ts.map +1 -1
  542. package/lint/ssr-guards.js +0 -165
  543. package/test-fixtures/server-return-types.ts +0 -58
  544. package/test-fixtures/tsconfig.json +0 -13
  545. package/tsconfig.json +0 -26
  546. package/vitest.config.ts +0 -8
@@ -0,0 +1,180 @@
1
+ import { beforeEach, describe, expect, test, vi } from 'vitest'
2
+
3
+ import {
4
+ createMutationLifecycle,
5
+ MutationTimeoutError,
6
+ StaleGenerationError,
7
+ } from './mutationLifecycle'
8
+
9
+ function deferred<T>() {
10
+ let resolve!: (value: T | PromiseLike<T>) => void
11
+ let reject!: (error: unknown) => void
12
+ const promise = new Promise<T>((resolvePromise, rejectPromise) => {
13
+ resolve = resolvePromise
14
+ reject = rejectPromise
15
+ })
16
+ return { promise, reject, resolve }
17
+ }
18
+
19
+ function setup(threshold = 2) {
20
+ const recoverFromAckTimeout = vi.fn()
21
+ const lifecycle = createMutationLifecycle({
22
+ ackTimeoutRecoveryThreshold: threshold,
23
+ recoverFromAckTimeout,
24
+ })
25
+ lifecycle.activate()
26
+ return { lifecycle, recoverFromAckTimeout }
27
+ }
28
+
29
+ beforeEach(() => {
30
+ vi.restoreAllMocks()
31
+ })
32
+
33
+ describe('mutation lifecycle', () => {
34
+ test('extracts typed mutation errors and times out each settlement phase', async () => {
35
+ vi.useFakeTimers()
36
+ try {
37
+ const { lifecycle } = setup()
38
+ await expect(
39
+ lifecycle.awaitMutationClient(
40
+ { client: Promise.resolve({ type: 'error', error: { message: 'denied' } }) },
41
+ 'save note'
42
+ )
43
+ ).rejects.toMatchObject({
44
+ name: 'MutationResultError',
45
+ label: 'save note',
46
+ phase: 'client',
47
+ })
48
+
49
+ const waiting = lifecycle.awaitMutationClient(
50
+ { client: new Promise(() => {}) },
51
+ 'stuck note',
52
+ 20
53
+ )
54
+ const timedOut = expect(waiting).rejects.toMatchObject({
55
+ name: 'MutationTimeoutError',
56
+ phase: 'client',
57
+ timeoutMs: 20,
58
+ })
59
+ await vi.advanceTimersByTimeAsync(20)
60
+ await timedOut
61
+ } finally {
62
+ vi.useRealTimers()
63
+ }
64
+ })
65
+
66
+ test('serializes work and skips superseded coalesced writes', async () => {
67
+ const { lifecycle } = setup()
68
+ const blocker = deferred<void>()
69
+ const first = lifecycle.enqueueBackgroundMutation('blocker', () => blocker.promise)
70
+ const superseded = vi.fn()
71
+ const latest = vi.fn(async () => {})
72
+ const oldWrite = lifecycle.enqueueBackgroundMutation('old row', superseded, {
73
+ coalesceKey: 'message:1',
74
+ })
75
+ const newWrite = lifecycle.enqueueBackgroundMutation('new row', latest, {
76
+ coalesceKey: 'message:1',
77
+ })
78
+
79
+ blocker.resolve()
80
+ await Promise.all([first, oldWrite, newWrite])
81
+ expect(superseded).not.toHaveBeenCalled()
82
+ expect(latest).toHaveBeenCalledOnce()
83
+ })
84
+
85
+ test('one failed background mutation does not poison later work', async () => {
86
+ const { lifecycle } = setup()
87
+ vi.spyOn(console, 'warn').mockImplementation(() => {})
88
+ const denied = lifecycle.enqueueBackgroundMutation('stamp', async () => {
89
+ throw new Error('PermissionError: stale task')
90
+ })
91
+ await expect(denied).rejects.toThrow('PermissionError')
92
+
93
+ const next = vi.fn(async () => {})
94
+ await lifecycle.enqueueBackgroundMutation('clear stamp', next)
95
+ expect(next).toHaveBeenCalledOnce()
96
+ })
97
+
98
+ test('recovery or close quietly drops in-flight and queued background work', async () => {
99
+ const { lifecycle } = setup()
100
+ const client = deferred<unknown>()
101
+ const queuedCreate = vi.fn(async () => {})
102
+ const inFlight = lifecycle.enqueueBackgroundMutation('in flight', () => ({
103
+ client: client.promise,
104
+ }))
105
+ const queued = lifecycle.enqueueBackgroundMutation('queued', queuedCreate)
106
+
107
+ lifecycle.fence()
108
+ await expect(inFlight).resolves.toBeUndefined()
109
+ await expect(queued).resolves.toBeUndefined()
110
+ expect(queuedCreate).not.toHaveBeenCalled()
111
+
112
+ const direct = lifecycle.awaitMutationClient(
113
+ { client: Promise.resolve({}) },
114
+ 'direct after close'
115
+ )
116
+ await expect(direct).rejects.toBeInstanceOf(StaleGenerationError)
117
+ })
118
+
119
+ test('recovers only after consecutive server acknowledgement timeouts', async () => {
120
+ vi.useFakeTimers()
121
+ try {
122
+ const { lifecycle, recoverFromAckTimeout } = setup()
123
+ const timeout = async (label: string) => {
124
+ const result = lifecycle.awaitMutationServer(
125
+ { client: Promise.resolve({}), server: new Promise(() => {}) },
126
+ label,
127
+ 10
128
+ )
129
+ const timedOut = expect(result).rejects.toMatchObject({
130
+ name: 'MutationTimeoutError',
131
+ phase: 'server',
132
+ })
133
+ await vi.advanceTimersByTimeAsync(10)
134
+ await timedOut
135
+ }
136
+
137
+ await timeout('first')
138
+ expect(recoverFromAckTimeout).not.toHaveBeenCalled()
139
+ await timeout('second')
140
+ expect(recoverFromAckTimeout).toHaveBeenCalledOnce()
141
+ expect(recoverFromAckTimeout).toHaveBeenCalledWith({
142
+ label: 'second',
143
+ timeoutMs: 10,
144
+ consecutiveTimeouts: 2,
145
+ })
146
+ } finally {
147
+ vi.useRealTimers()
148
+ }
149
+ })
150
+
151
+ test('a server response resets the consecutive timeout count', async () => {
152
+ vi.useFakeTimers()
153
+ try {
154
+ const { lifecycle, recoverFromAckTimeout } = setup()
155
+ const timeout = async () => {
156
+ const result = lifecycle.awaitMutationServer(
157
+ { client: Promise.resolve({}), server: new Promise(() => {}) },
158
+ 'write',
159
+ 10
160
+ )
161
+ const timedOut = expect(result).rejects.toBeInstanceOf(MutationTimeoutError)
162
+ await vi.advanceTimersByTimeAsync(10)
163
+ await timedOut
164
+ }
165
+
166
+ await timeout()
167
+ await expect(
168
+ lifecycle.awaitMutationServer(
169
+ { client: Promise.resolve({}), server: Promise.resolve({}) },
170
+ 'acked write',
171
+ 10
172
+ )
173
+ ).resolves.toEqual({})
174
+ await timeout()
175
+ expect(recoverFromAckTimeout).not.toHaveBeenCalled()
176
+ } finally {
177
+ vi.useRealTimers()
178
+ }
179
+ })
180
+ })
@@ -0,0 +1,313 @@
1
+ export type MutationLike = {
2
+ client: Promise<unknown>
3
+ server?: Promise<unknown>
4
+ }
5
+
6
+ export type BackgroundMutationOptions = {
7
+ coalesceKey?: string
8
+ settle?: 'client' | 'server'
9
+ timeoutMs?: number
10
+ }
11
+
12
+ export type MutationPhase = 'client' | 'server'
13
+
14
+ export class StaleGenerationError extends Error {
15
+ readonly label: string
16
+
17
+ constructor(label: string) {
18
+ super(`${label} stopped because its Zero instance was replaced or recovered`)
19
+ this.name = 'StaleGenerationError'
20
+ this.label = label
21
+ }
22
+ }
23
+
24
+ export class MutationTimeoutError extends Error {
25
+ readonly label: string
26
+ readonly phase: MutationPhase
27
+ readonly timeoutMs: number
28
+
29
+ constructor(label: string, phase: MutationPhase, timeoutMs: number) {
30
+ super(
31
+ phase === 'server'
32
+ ? `${label} server acknowledgement did not complete within ${timeoutMs}ms`
33
+ : `${label} did not complete within ${timeoutMs}ms`
34
+ )
35
+ this.name = 'MutationTimeoutError'
36
+ this.label = label
37
+ this.phase = phase
38
+ this.timeoutMs = timeoutMs
39
+ }
40
+ }
41
+
42
+ export class MutationResultError extends Error {
43
+ readonly label: string
44
+ readonly phase: MutationPhase
45
+ readonly result: unknown
46
+
47
+ constructor(label: string, phase: MutationPhase, result: unknown, message: string) {
48
+ super(`${label} failed${phase === 'server' ? ' on server' : ''}: ${message}`)
49
+ this.name = 'MutationResultError'
50
+ this.label = label
51
+ this.phase = phase
52
+ this.result = result
53
+ }
54
+ }
55
+
56
+ export function isStaleGenerationError(error: unknown): error is StaleGenerationError {
57
+ return error instanceof StaleGenerationError
58
+ }
59
+
60
+ export function mutationErrorMessage(result: unknown): string | null {
61
+ if (!result || typeof result !== 'object') return null
62
+ const typed = result as { type?: unknown; error?: unknown }
63
+ if (typed.type !== 'error') return null
64
+ return describeMutationError(typed.error)
65
+ }
66
+
67
+ function describeMutationError(error: unknown): string {
68
+ if (error instanceof Error) return error.message
69
+ if (error && typeof error === 'object') {
70
+ const typed = error as { type?: unknown; message?: unknown }
71
+ const parts = [typed.type, typed.message].filter(
72
+ (part): part is string => typeof part === 'string' && part.length > 0
73
+ )
74
+ if (parts.length) return parts.join(': ')
75
+ }
76
+ return String(error)
77
+ }
78
+
79
+ type GenerationWaiter = {
80
+ reject: () => void
81
+ }
82
+
83
+ type BackgroundMutationQueue = {
84
+ tail: Promise<void>
85
+ lastErrorMessage: string | null
86
+ coalesceSequence: Map<string, number>
87
+ }
88
+
89
+ export type MutationLifecycle = ReturnType<typeof createMutationLifecycle>
90
+
91
+ export function createMutationLifecycle(options: {
92
+ ackTimeoutRecoveryThreshold: number
93
+ recoverFromAckTimeout: (input: {
94
+ label: string
95
+ timeoutMs: number
96
+ consecutiveTimeouts: number
97
+ }) => void
98
+ }) {
99
+ const queue: BackgroundMutationQueue = {
100
+ tail: Promise.resolve(),
101
+ lastErrorMessage: null,
102
+ coalesceSequence: new Map(),
103
+ }
104
+ const waiters = new Set<GenerationWaiter>()
105
+ let generation = 0
106
+ let active = false
107
+ let consecutiveServerAckTimeouts = 0
108
+
109
+ function stale(label: string): StaleGenerationError {
110
+ return new StaleGenerationError(label)
111
+ }
112
+
113
+ function fence() {
114
+ if (!active) return
115
+ active = false
116
+ generation += 1
117
+ consecutiveServerAckTimeouts = 0
118
+ queue.coalesceSequence.clear()
119
+ for (const waiter of [...waiters]) {
120
+ waiters.delete(waiter)
121
+ waiter.reject()
122
+ }
123
+ }
124
+
125
+ function activate() {
126
+ if (active) return
127
+ generation += 1
128
+ active = true
129
+ consecutiveServerAckTimeouts = 0
130
+ queue.lastErrorMessage = null
131
+ }
132
+
133
+ function observeGeneration(capturedGeneration: number, label: string) {
134
+ let waiter: GenerationWaiter | undefined
135
+ const promise = new Promise<never>((_, reject) => {
136
+ if (!active || capturedGeneration !== generation) {
137
+ reject(stale(label))
138
+ return
139
+ }
140
+ waiter = {
141
+ reject: () => reject(stale(label)),
142
+ }
143
+ waiters.add(waiter)
144
+ if (!active || capturedGeneration !== generation) {
145
+ waiters.delete(waiter)
146
+ waiter = undefined
147
+ reject(stale(label))
148
+ }
149
+ })
150
+ return {
151
+ promise,
152
+ dispose() {
153
+ if (waiter) waiters.delete(waiter)
154
+ },
155
+ }
156
+ }
157
+
158
+ async function awaitInGeneration<T>(input: {
159
+ promise: Promise<T>
160
+ label: string
161
+ phase: MutationPhase
162
+ timeoutMs: number
163
+ generation: number
164
+ }): Promise<T> {
165
+ if (!active || input.generation !== generation) throw stale(input.label)
166
+ let timer: ReturnType<typeof setTimeout> | undefined
167
+ const generationChange = observeGeneration(input.generation, input.label)
168
+ try {
169
+ return await Promise.race([
170
+ input.promise,
171
+ generationChange.promise,
172
+ new Promise<never>((_, reject) => {
173
+ timer = setTimeout(
174
+ () =>
175
+ reject(new MutationTimeoutError(input.label, input.phase, input.timeoutMs)),
176
+ input.timeoutMs
177
+ )
178
+ }),
179
+ ])
180
+ } finally {
181
+ generationChange.dispose()
182
+ if (timer) clearTimeout(timer)
183
+ }
184
+ }
185
+
186
+ async function settleMutationClient(
187
+ mutation: MutationLike,
188
+ label: string,
189
+ timeoutMs: number,
190
+ capturedGeneration: number,
191
+ observeServerFailure: boolean
192
+ ): Promise<unknown> {
193
+ const result = await awaitInGeneration({
194
+ promise: mutation.client,
195
+ label,
196
+ phase: 'client',
197
+ timeoutMs,
198
+ generation: capturedGeneration,
199
+ })
200
+ const message = mutationErrorMessage(result)
201
+ if (message) throw new MutationResultError(label, 'client', result, message)
202
+ if (observeServerFailure) {
203
+ mutation.server?.catch((error: unknown) => {
204
+ if (!active || capturedGeneration !== generation) return
205
+ console.warn(`[on-zero] ${label} server replication failed:`, error)
206
+ })
207
+ }
208
+ return result
209
+ }
210
+
211
+ function awaitMutationClient(
212
+ mutation: MutationLike,
213
+ label: string,
214
+ timeoutMs = 30_000
215
+ ): Promise<unknown> {
216
+ return settleMutationClient(mutation, label, timeoutMs, generation, true)
217
+ }
218
+
219
+ async function awaitMutationServer(
220
+ mutation: MutationLike,
221
+ label: string,
222
+ timeoutMs = 30_000
223
+ ): Promise<unknown> {
224
+ const capturedGeneration = generation
225
+ const clientResult = await settleMutationClient(
226
+ mutation,
227
+ label,
228
+ timeoutMs,
229
+ capturedGeneration,
230
+ false
231
+ )
232
+ if (!mutation.server) return clientResult
233
+
234
+ try {
235
+ const serverResult = await awaitInGeneration({
236
+ promise: mutation.server,
237
+ label,
238
+ phase: 'server',
239
+ timeoutMs,
240
+ generation: capturedGeneration,
241
+ })
242
+ consecutiveServerAckTimeouts = 0
243
+ const message = mutationErrorMessage(serverResult)
244
+ if (message) throw new MutationResultError(label, 'server', serverResult, message)
245
+ return serverResult
246
+ } catch (error) {
247
+ if (error instanceof MutationTimeoutError && error.phase === 'server') {
248
+ consecutiveServerAckTimeouts += 1
249
+ if (consecutiveServerAckTimeouts >= options.ackTimeoutRecoveryThreshold) {
250
+ options.recoverFromAckTimeout({
251
+ label,
252
+ timeoutMs,
253
+ consecutiveTimeouts: consecutiveServerAckTimeouts,
254
+ })
255
+ }
256
+ }
257
+ throw error
258
+ }
259
+ }
260
+
261
+ function enqueueBackgroundMutation(
262
+ label: string,
263
+ create: () => unknown,
264
+ mutationOptions: BackgroundMutationOptions = {}
265
+ ): Promise<void> {
266
+ const capturedGeneration = generation
267
+ const { coalesceKey = '', settle = 'client', timeoutMs = 120_000 } = mutationOptions
268
+ const sequence = coalesceKey ? (queue.coalesceSequence.get(coalesceKey) ?? 0) + 1 : 0
269
+ if (coalesceKey) queue.coalesceSequence.set(coalesceKey, sequence)
270
+
271
+ const queued = queue.tail.then(async () => {
272
+ if (!active || capturedGeneration !== generation) throw stale(label)
273
+ if (coalesceKey) {
274
+ if (queue.coalesceSequence.get(coalesceKey) !== sequence) return
275
+ queue.coalesceSequence.delete(coalesceKey)
276
+ }
277
+ const result = await create()
278
+ if (result && typeof result === 'object' && 'client' in result) {
279
+ const mutation = result as MutationLike
280
+ if (settle === 'server' && mutation.server) {
281
+ await awaitMutationServer(mutation, label, timeoutMs)
282
+ } else {
283
+ await settleMutationClient(mutation, label, timeoutMs, capturedGeneration, true)
284
+ }
285
+ } else {
286
+ await result
287
+ }
288
+ queue.lastErrorMessage = null
289
+ })
290
+
291
+ const result = queued.catch((error: unknown) => {
292
+ if (isStaleGenerationError(error)) return
293
+ if (!active || capturedGeneration !== generation) return
294
+ const message = describeMutationError(error)
295
+ const alreadyLogged = queue.lastErrorMessage === message
296
+ queue.lastErrorMessage = message
297
+ if (!alreadyLogged) {
298
+ console.warn(`[on-zero] ${label} background mutation failed:`, error)
299
+ }
300
+ throw error
301
+ })
302
+ queue.tail = result.catch(() => {})
303
+ return result
304
+ }
305
+
306
+ return {
307
+ activate,
308
+ fence,
309
+ enqueueBackgroundMutation,
310
+ awaitMutationClient,
311
+ awaitMutationServer,
312
+ }
313
+ }
@@ -1,4 +1,4 @@
1
- import { createAsyncContext } from '@take-out/helpers'
1
+ import { createAsyncContext } from './asyncContext'
2
2
 
3
3
  import type { AuthData, MutatorContext } from '../types'
4
4
 
@@ -33,7 +33,7 @@ export function isInZeroMutation() {
33
33
 
34
34
  export function runWithContext<T>(
35
35
  context: MutatorContext,
36
- fn: () => T | Promise<T>,
36
+ fn: () => T | Promise<T>
37
37
  ): Promise<T> {
38
38
  return asyncContext.run(context, fn)
39
39
  }
@@ -48,7 +48,7 @@ export function getScopedAuthData(): AuthData | null | undefined {
48
48
 
49
49
  export function runWithAuthScope<T>(
50
50
  authData: AuthData | null,
51
- fn: () => T | Promise<T>,
51
+ fn: () => T | Promise<T>
52
52
  ): Promise<T> {
53
53
  return authScopeContext.run(authData, fn)
54
54
  }
@@ -0,0 +1,2 @@
1
+ export const IS_SERVER = false
2
+ export const IS_SERVER_RUNTIME = false
@@ -0,0 +1,16 @@
1
+ export const IS_SERVER_RUNTIME: boolean =
2
+ process.env.VITE_ENVIRONMENT === 'ssr' ||
3
+ (process.env.VITE_ENVIRONMENT !== 'client' &&
4
+ typeof process !== 'undefined' &&
5
+ !!process.versions &&
6
+ !!(process.versions.node || (process.versions as any).bun))
7
+
8
+ const isBrowser =
9
+ process.env.VITE_ENVIRONMENT === 'client' ||
10
+ (process.env.VITE_ENVIRONMENT !== 'ssr' &&
11
+ typeof navigator !== 'undefined' &&
12
+ typeof location !== 'undefined')
13
+
14
+ export const IS_SERVER: boolean =
15
+ process.env.VITE_ENVIRONMENT === 'ssr' ||
16
+ (process.env.VITE_ENVIRONMENT !== 'client' && !isBrowser)
@@ -1,10 +1,10 @@
1
- import { ellipsis } from '@take-out/helpers'
1
+ import { ellipsis } from './ellipsis'
2
2
 
3
3
  import type { Query } from '@rocicorp/zero'
4
4
 
5
5
  export const prettyFormatZeroQuery = (
6
6
  query: Query<any, any, any>,
7
- mode: 'full' | 'minimal' = 'full',
7
+ mode: 'full' | 'minimal' = 'full'
8
8
  ): string => {
9
9
  const astObject = query['_completeAst']?.()
10
10
 
@@ -1,4 +1,4 @@
1
- import { createAsyncContext } from '@take-out/helpers'
1
+ import { createAsyncContext } from './asyncContext'
2
2
 
3
3
  import type { AuthData } from '../types'
4
4
 
@@ -14,7 +14,7 @@ export function isInQueryContext() {
14
14
 
15
15
  export function runWithQueryContext<T>(
16
16
  context: { authData: AuthData | null },
17
- fn: () => T | Promise<T>,
17
+ fn: () => T | Promise<T>
18
18
  ): Promise<T> {
19
19
  return asyncContext.run(context, fn)
20
20
  }
@@ -1,8 +1,8 @@
1
- // @vitest-environment jsdom
2
- import { createEmitter } from '@take-out/helpers'
3
1
  import { UpdateNeededReasonType } from '@rocicorp/zero'
4
2
  import { beforeEach, describe, expect, test, vi } from 'vitest'
5
3
 
4
+ // @vitest-environment jsdom
5
+ import { createEmitter } from './emitter'
6
6
  import {
7
7
  classifyZeroRecoveryLog,
8
8
  composeRecoveryLogSink,
@@ -11,8 +11,8 @@ import {
11
11
  resetRecoveryStateForTests,
12
12
  } from './recoverZeroClient'
13
13
 
14
- import type { ScheduleReloadContext, ZeroRecoveryDeps } from './recoverZeroClient'
15
14
  import type { ZeroEvent } from '../types'
15
+ import type { ScheduleReloadContext, ZeroRecoveryDeps } from './recoverZeroClient'
16
16
 
17
17
  let emitterSeq = 0
18
18
 
@@ -48,6 +48,7 @@ describe('zero recovery', () => {
48
48
  expect(events).toEqual([
49
49
  {
50
50
  type: 'recovering',
51
+ reasonKey: 'SchemaVersionNotSupported',
51
52
  reason: expect.stringContaining('SchemaVersionNotSupported'),
52
53
  },
53
54
  ])
@@ -208,23 +209,23 @@ describe('zero recovery', () => {
208
209
  const sqliteError = new Error('This statement has been finalized')
209
210
  sqliteError.name = 'SqliteError'
210
211
  expect(
211
- classifyZeroRecoveryLog('error', ['Error running.', sqliteError]),
212
+ classifyZeroRecoveryLog('error', ['Error running.', sqliteError])
212
213
  ).toMatchObject({
213
- reason: 'sqlite-statement-finalized',
214
+ reasonKey: 'sqlite-statement-finalized',
214
215
  dropLocalState: true,
215
216
  })
216
217
  expect(
217
218
  classifyZeroRecoveryLog('error', [
218
219
  { name: 'SqliteError', message: 'database is locked' },
219
- ]),
220
+ ])
220
221
  ).toBeUndefined()
221
222
  expect(
222
- classifyZeroRecoveryLog('warn', ['Expected IndexedDB not found']),
223
+ classifyZeroRecoveryLog('warn', ['Expected IndexedDB not found'])
223
224
  ).toBeUndefined()
224
225
  expect(classifyZeroRecoveryLog('error', ['Store is closed'], 10_000)).toBeUndefined()
225
226
  expect(classifyZeroRecoveryLog('error', ['Store is closed'], 11_000)).toBeUndefined()
226
227
  expect(classifyZeroRecoveryLog('error', ['Store is closed'], 14_000)).toMatchObject({
227
- reason: 'store-closed-repeat',
228
+ reasonKey: 'store-closed-repeat',
228
229
  dropLocalState: true,
229
230
  })
230
231
  resetRecoveryStateForTests()
@@ -232,8 +233,8 @@ describe('zero recovery', () => {
232
233
  classifyZeroRecoveryLog(
233
234
  'error',
234
235
  ['Mutator "send" error on server', 'Store is closed'],
235
- 20_000,
236
- ),
236
+ 20_000
237
+ )
237
238
  ).toBeUndefined()
238
239
  })
239
240
 
@@ -246,7 +247,7 @@ describe('zero recovery', () => {
246
247
  const events: ZeroEvent[] = []
247
248
  const zeroEvents = createEmitter<ZeroEvent | null>(
248
249
  `test-recover-${emitterSeq++}`,
249
- null,
250
+ null
250
251
  )
251
252
  zeroEvents.listen((event) => {
252
253
  if (event) events.push(event)
@@ -272,6 +273,7 @@ describe('zero recovery', () => {
272
273
  expect(deleteLocalState).toHaveBeenCalledTimes(1)
273
274
  expect(events).toContainEqual({
274
275
  type: 'recovering',
276
+ reasonKey: 'client-state-not-found',
275
277
  reason: 'client state not found',
276
278
  })
277
279
  })
@@ -436,23 +438,23 @@ describe('zero recovery', () => {
436
438
  ]
437
439
  for (const [args, reason] of cases) {
438
440
  expect(classifyZeroRecoveryLog('error', args)).toMatchObject({
439
- reason,
441
+ reasonKey: reason,
440
442
  dropLocalState: true,
441
443
  })
442
444
  }
443
- // still narrow: app-infra strings and non-error levels do NOT classify.
445
+ // ack timeouts use the typed mutation path; synthetic strings do not classify.
444
446
  expect(
445
- classifyZeroRecoveryLog('error', ['consecutive server-ack timeouts']),
447
+ classifyZeroRecoveryLog('error', ['consecutive server-ack timeouts'])
446
448
  ).toBeUndefined()
447
449
  expect(
448
- classifyZeroRecoveryLog('error', ['Connection attempt timed out after 10 seconds']),
450
+ classifyZeroRecoveryLog('error', ['Connection attempt timed out after 10 seconds'])
449
451
  ).toBeUndefined()
450
452
  expect(classifyZeroRecoveryLog('warn', ['ClientNotFound'])).toBeUndefined()
451
453
  })
452
454
 
453
- test('benignLogFilter suppresses recovery for a matching classified log', async () => {
455
+ test('benignLogPatterns suppress recovery for matching classified logs', async () => {
454
456
  const { deps, deleteLocalState, reload } = setup()
455
- deps.benignLogFilter = (message) => message.includes('ClientNotFound')
457
+ deps.benignLogPatterns = ['ClientNotFound']
456
458
  const sink = composeRecoveryLogSink(deps)
457
459
  sink.log('error', undefined, 'ClientNotFound: gone')
458
460
  await flush()
@@ -467,13 +469,13 @@ describe('zero recovery', () => {
467
469
  test('isRecoverableZeroStalePokeMessage matches only the stale-cookie signatures', () => {
468
470
  expect(
469
471
  isRecoverableZeroStalePokeMessage(
470
- 'Server returned unexpected base cookie during sync',
471
- ),
472
+ 'Server returned unexpected base cookie during sync'
473
+ )
472
474
  ).toBe(true)
473
475
  expect(
474
476
  isRecoverableZeroStalePokeMessage(
475
- 'Received cookie 5 is < than last snapshot cookie 9, ignoring client view',
476
- ),
477
+ 'Received cookie 5 is < than last snapshot cookie 9, ignoring client view'
478
+ )
477
479
  ).toBe(true)
478
480
  expect(isRecoverableZeroStalePokeMessage('client state not found')).toBe(false)
479
481
  })