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
@@ -1,7 +1,6 @@
1
- import type { Emitter } from '@take-out/helpers'
2
- import type { ZeroEvent } from '../types'
3
- import type { UpdateNeededReason } from '@rocicorp/zero'
1
+ import type { ZeroEventsEmitter, ZeroRecoveryReasonKey } from '../types'
4
2
  import type { Context, LogLevel, LogSink } from '@rocicorp/logger'
3
+ import type { UpdateNeededReason } from '@rocicorp/zero'
5
4
 
6
5
  // per-reason guard window: the SAME reason re-failing right after its reload is
7
6
  // surfaced as fatal instead of reload-storming on something the reload can't fix.
@@ -24,22 +23,21 @@ const STORE_CLOSED = 'Store is closed'
24
23
  const STORE_CLOSED_REPEAT_MIN_MS = 2_000
25
24
  const STORE_CLOSED_REPEAT_MAX_MS = 60_000
26
25
 
27
- export type ZeroRecoveryLogReason =
28
- | 'indexeddb-not-found'
29
- | 'sqlite-statement-finalized'
30
- | 'store-closed-repeat'
31
- | 'mutation-desync'
32
- | 'connection-cookie-invalid'
33
- | 'client-not-found'
34
- | 'connection-userid-mismatch'
35
-
36
26
  export type ZeroRecoveryLogClassification = {
37
- reason: ZeroRecoveryLogReason
38
- reasonKey: string
27
+ reasonKey: Exclude<
28
+ ZeroRecoveryReasonKey,
29
+ | 'NewClientGroup'
30
+ | 'VersionNotSupported'
31
+ | 'SchemaVersionNotSupported'
32
+ | 'client-state-not-found'
33
+ | 'server-ack-timeout'
34
+ >
39
35
  message: string
40
36
  dropLocalState: boolean
41
37
  }
42
38
 
39
+ export type ZeroLogPattern = string | RegExp
40
+
43
41
  // a minimal synchronous key/value store the cross-reload guard persists into.
44
42
  // web defaults to sessionStorage; native (Hermes) has none, so a consumer can
45
43
  // inject an MMKV/sqlite-backed store to get cross-reload loop protection — the
@@ -54,7 +52,7 @@ export type RecoveryGuardStorage = {
54
52
  // expo-updates reload) while still driving the SAME deletes-then-reload work.
55
53
  export type ScheduleReloadContext = {
56
54
  reason: string
57
- reasonKey: string
55
+ reasonKey: ZeroRecoveryReasonKey
58
56
  dropLocalState: boolean
59
57
  // deletes every affected instance's local store, awaits beforeReload, then
60
58
  // reloads. idempotent — safe to call once the consumer decides to proceed.
@@ -67,7 +65,7 @@ export type ZeroRecoveryDeps = {
67
65
  // EVERY underlying store; the latch below keeps it to one reload.
68
66
  deleteLocalState: () => Promise<unknown>
69
67
  // recovery lifecycle for consumers (preview postMessage, toast, …).
70
- zeroEvents: Emitter<ZeroEvent | null>
68
+ zeroEvents: ZeroEventsEmitter
71
69
  // awaited before the reload — e.g. wait for the dev origin to come back so the
72
70
  // reload doesn't land on a restarting server. optional.
73
71
  beforeReload?: () => Promise<void>
@@ -78,9 +76,11 @@ export type ZeroRecoveryDeps = {
78
76
  // cross-reload guard backing store (defaults to sessionStorage on web). inject
79
77
  // a native KV so Hermes gets real cross-reload loop protection.
80
78
  guardStorage?: RecoveryGuardStorage
81
- // called with the joined log text for a classified recovery signature; return
82
- // true to treat it as benign and NOT recover (soot's cf cold-boot timeout).
83
- benignLogFilter?: (message: string) => boolean
79
+ // classified transport/app messages that are expected and must not recover.
80
+ benignLogPatterns?: readonly ZeroLogPattern[]
81
+ // internal lifecycle fence. recovery invalidates queued and in-flight work
82
+ // before the consumer can defer the reload.
83
+ onRecovery?: (reasonKey: ZeroRecoveryReasonKey) => void
84
84
  // injectable for tests; defaults to a real page reload.
85
85
  reload?: () => void
86
86
  }
@@ -117,8 +117,8 @@ function defaultGuardStorage(): RecoveryGuardStorage | undefined {
117
117
  // survives the reload, so a reason that reloaded then immediately re-fires is
118
118
  // caught as a genuine fatal instead of reload-storming across loads.
119
119
  function recoveryGuardOpen(
120
- reasonKey: string,
121
- guardStorage: RecoveryGuardStorage | undefined,
120
+ reasonKey: ZeroRecoveryReasonKey,
121
+ guardStorage: RecoveryGuardStorage | undefined
122
122
  ): boolean {
123
123
  const key = `on-zero-recover-${reasonKey}`
124
124
  const now = Date.now()
@@ -207,11 +207,12 @@ function performReload(deps: ZeroRecoveryDeps): Promise<void> {
207
207
 
208
208
  function recover(
209
209
  deps: ZeroRecoveryDeps,
210
- reasonKey: string,
210
+ reasonKey: ZeroRecoveryReasonKey,
211
211
  message: string,
212
- dropLocalState: boolean,
212
+ dropLocalState: boolean
213
213
  ): void {
214
214
  if (typeof window === 'undefined') return
215
+ deps.onRecovery?.(reasonKey)
215
216
  // each affected instance drops its OWN stale store, even when a reload is
216
217
  // already queued — otherwise a sibling's store survives the reload and
217
218
  // fatal-loops on the next boot. the single scheduled reload awaits these.
@@ -222,13 +223,13 @@ function recover(
222
223
  if (reloadScheduled) return
223
224
  if (!recoveryGuardOpen(reasonKey, deps.guardStorage)) {
224
225
  console.error(`[on-zero] ${message} — already recovered once, not reloading`)
225
- deps.zeroEvents.emit({ type: 'fatal', reason: message })
226
+ deps.zeroEvents.emit({ type: 'fatal', reasonKey, reason: message })
226
227
  return
227
228
  }
228
229
  reloadScheduled = true
229
230
  armReloadLatchTimeout()
230
231
  console.warn(`[on-zero] ${message} — recovering`)
231
- deps.zeroEvents.emit({ type: 'recovering', reason: message })
232
+ deps.zeroEvents.emit({ type: 'recovering', reasonKey, reason: message })
232
233
 
233
234
  const runReload = () => performReload(deps)
234
235
  if (deps.scheduleReload) {
@@ -261,7 +262,7 @@ export function makeZeroRecovery(deps: ZeroRecoveryDeps) {
261
262
  deps,
262
263
  reason.type,
263
264
  `update needed (${reason.message || reason.type})`,
264
- dropLocalState,
265
+ dropLocalState
265
266
  )
266
267
  },
267
268
  onClientStateNotFound() {
@@ -269,6 +270,18 @@ export function makeZeroRecovery(deps: ZeroRecoveryDeps) {
269
270
  // drop it and reload into a fresh client.
270
271
  recover(deps, 'client-state-not-found', 'client state not found', true)
271
272
  },
273
+ onServerAckTimeout(input: {
274
+ label: string
275
+ timeoutMs: number
276
+ consecutiveTimeouts: number
277
+ }) {
278
+ recover(
279
+ deps,
280
+ 'server-ack-timeout',
281
+ `${input.label} server acknowledgement timed out ${input.consecutiveTimeouts} consecutive times (${input.timeoutMs}ms each)`,
282
+ true
283
+ )
284
+ },
272
285
  }
273
286
  }
274
287
 
@@ -311,16 +324,14 @@ function isBenignStoreClosedLog(text: string): boolean {
311
324
  // the mutation/connection desync class: the local client group is out of sync
312
325
  // with the server's last-mutation-id / cookie / client record, so the store is
313
326
  // unusable and must be dropped + recovered. these surface only through the error
314
- // log, never the structured onClientStateNotFound callback. genuinely app-infra
315
- // signatures (a consumer's synthesized ack-timeout marker, a cold-boot connect
316
- // timeout) are NOT here a consumer keeps those with benignLogFilter / its own
317
- // handling.
327
+ // log, never the structured onClientStateNotFound callback. server acknowledgement
328
+ // timeouts enter through the mutation lifecycle instead of string classification;
329
+ // expected transport startup messages are declared through benignLogPatterns.
318
330
  function classifyMutationDesync(
319
- text: string,
320
- ): { reason: ZeroRecoveryLogReason; reasonKey: string; message: string } | undefined {
331
+ text: string
332
+ ): Pick<ZeroRecoveryLogClassification, 'reasonKey' | 'message'> | undefined {
321
333
  if (text.includes('sent mutation ID') && text.includes('but expected')) {
322
334
  return {
323
- reason: 'mutation-desync',
324
335
  reasonKey: 'mutation-desync',
325
336
  message: 'mutation id desync',
326
337
  }
@@ -330,42 +341,36 @@ function classifyMutationDesync(
330
341
  text.includes('Server reported an out-of-order mutation')
331
342
  ) {
332
343
  return {
333
- reason: 'mutation-desync',
334
344
  reasonKey: 'mutation-desync',
335
345
  message: 'out-of-order mutation',
336
346
  }
337
347
  }
338
348
  if (text.includes('already processed')) {
339
349
  return {
340
- reason: 'mutation-desync',
341
350
  reasonKey: 'mutation-desync',
342
351
  message: 'mutation already processed',
343
352
  }
344
353
  }
345
354
  if (text.includes('InvalidConnectionRequestLastMutationID')) {
346
355
  return {
347
- reason: 'mutation-desync',
348
356
  reasonKey: 'mutation-desync',
349
357
  message: 'invalid connection last mutation id',
350
358
  }
351
359
  }
352
360
  if (text.includes('InvalidConnectionRequestBaseCookie')) {
353
361
  return {
354
- reason: 'connection-cookie-invalid',
355
362
  reasonKey: 'connection-cookie-invalid',
356
363
  message: 'invalid connection base cookie',
357
364
  }
358
365
  }
359
366
  if (text.includes('ClientNotFound') || text.includes('Client not found')) {
360
367
  return {
361
- reason: 'client-not-found',
362
368
  reasonKey: 'client-not-found',
363
369
  message: 'client not found',
364
370
  }
365
371
  }
366
372
  if (text.includes('connection userID mismatch')) {
367
373
  return {
368
- reason: 'connection-userid-mismatch',
369
374
  reasonKey: 'connection-userid-mismatch',
370
375
  message: 'connection user id mismatch',
371
376
  }
@@ -376,21 +381,19 @@ function classifyMutationDesync(
376
381
  export function classifyZeroRecoveryLog(
377
382
  level: LogLevel | string,
378
383
  args: readonly unknown[],
379
- nowMs = Date.now(),
384
+ nowMs = Date.now()
380
385
  ): ZeroRecoveryLogClassification | undefined {
381
386
  if (level !== 'error') return undefined
382
387
  const text = args.map(logArgText).join(' ')
383
388
  if (text.includes(LOCAL_STORE_LOST)) {
384
389
  return {
385
- reason: 'indexeddb-not-found',
386
- reasonKey: 'local-store',
390
+ reasonKey: 'indexeddb-not-found',
387
391
  message: 'local store lost',
388
392
  dropLocalState: true,
389
393
  }
390
394
  }
391
395
  if (text.includes(SQLITE_ERROR_NAME) && text.includes(SQLITE_STATEMENT_FINALIZED)) {
392
396
  return {
393
- reason: 'sqlite-statement-finalized',
394
397
  reasonKey: 'sqlite-statement-finalized',
395
398
  message: 'sqlite statement finalized',
396
399
  dropLocalState: true,
@@ -409,7 +412,6 @@ export function classifyZeroRecoveryLog(
409
412
  nowMs - prevMs <= STORE_CLOSED_REPEAT_MAX_MS
410
413
  ) {
411
414
  return {
412
- reason: 'store-closed-repeat',
413
415
  reasonKey: 'store-closed-repeat',
414
416
  message: 'local store closed repeatedly',
415
417
  dropLocalState: true,
@@ -426,7 +428,7 @@ export function classifyZeroRecoveryLog(
426
428
  // consumer that owns log-based recovery isn't double-fired.
427
429
  export function composeRecoveryLogSink(
428
430
  deps: ZeroRecoveryDeps,
429
- consumerLogSink?: LogSink,
431
+ consumerLogSink?: LogSink
430
432
  ): LogSink {
431
433
  const consumerFlush = consumerLogSink?.flush
432
434
  return {
@@ -435,10 +437,9 @@ export function composeRecoveryLogSink(
435
437
  else logToConsole(level, context, ...args)
436
438
  const recovery = classifyZeroRecoveryLog(level, args)
437
439
  if (!recovery) return
438
- if (deps.benignLogFilter) {
439
- const text = args.map(logArgText).join(' ')
440
- if (deps.benignLogFilter(text)) return
441
- }
440
+ const text = args.map(logArgText).join(' ')
441
+ if (deps.benignLogPatterns?.some((pattern) => matchesLogPattern(text, pattern)))
442
+ return
442
443
  recover(deps, recovery.reasonKey, recovery.message, recovery.dropLocalState)
443
444
  },
444
445
  // call through the consumer sink so a class-based sink keeps its `this`,
@@ -447,6 +448,12 @@ export function composeRecoveryLogSink(
447
448
  }
448
449
  }
449
450
 
451
+ function matchesLogPattern(message: string, pattern: ZeroLogPattern): boolean {
452
+ if (typeof pattern === 'string') return message.includes(pattern)
453
+ pattern.lastIndex = 0
454
+ return pattern.test(message)
455
+ }
456
+
450
457
  // generic Zero stale-poke / stale-cookie signatures: the client's view is behind
451
458
  // the server's snapshot cookie, which a plain reconnect resolves — this is not a
452
459
  // fatal store-loss, so ConnectionMonitor reconnects instead of recovering.
@@ -0,0 +1,8 @@
1
+ import { AbortError } from './errors'
2
+
3
+ export const sleep = async (ms: number, signal?: AbortSignal): Promise<void> => {
4
+ await new Promise((res) => setTimeout(res, ms))
5
+ if (signal?.aborted) {
6
+ throw new AbortError()
7
+ }
8
+ }
@@ -0,0 +1,51 @@
1
+ interface MsFunction {
2
+ (n: number): number
3
+ seconds: (n: number) => number
4
+ minutes: (n: number) => number
5
+ hours: (n: number) => number
6
+ days: (n: number) => number
7
+ weeks: (n: number) => number
8
+ }
9
+
10
+ interface SecondFunction {
11
+ (n: number): number
12
+ minutes: (n: number) => number
13
+ hours: (n: number) => number
14
+ days: (n: number) => number
15
+ weeks: (n: number) => number
16
+ }
17
+
18
+ interface MinuteFunction {
19
+ (n: number): number
20
+ hours: (n: number) => number
21
+ days: (n: number) => number
22
+ weeks: (n: number) => number
23
+ }
24
+
25
+ const ms = ((n: number) => n) as MsFunction
26
+ ms.seconds = (n: number) => n * 1000
27
+ ms.minutes = (n: number) => ms.seconds(n * 60)
28
+ ms.hours = (n: number) => ms.minutes(n * 60)
29
+ ms.days = (n: number) => ms.hours(n * 24)
30
+ ms.weeks = (n: number) => ms.days(n * 7)
31
+
32
+ const second = ((n: number) => n) as SecondFunction
33
+ second.minutes = (n: number) => n * 60
34
+ second.hours = (n: number) => second.minutes(n * 60)
35
+ second.days = (n: number) => second.hours(n * 24)
36
+ second.weeks = (n: number) => second.days(n * 7)
37
+
38
+ const minute = ((n: number) => n * 60) as MinuteFunction
39
+ minute.hours = (n: number) => minute(n * 60)
40
+ minute.days = (n: number) => minute.hours(n * 24)
41
+ minute.weeks = (n: number) => minute.days(n * 7)
42
+
43
+ export const time: {
44
+ ms: MsFunction
45
+ second: SecondFunction
46
+ minute: MinuteFunction
47
+ } = {
48
+ ms,
49
+ second,
50
+ minute,
51
+ }
@@ -0,0 +1 @@
1
+ export type TupleToUnion<T extends any[]> = T[number]
@@ -53,7 +53,7 @@ function emitMutationError(error: MutationError): void {
53
53
 
54
54
  function toMutationError(
55
55
  scope: 'client' | 'server',
56
- details: unknown,
56
+ details: unknown
57
57
  ): MutationError | null {
58
58
  if (!details || typeof details !== 'object') return null
59
59
  const d = details as {
@@ -90,7 +90,7 @@ function rejectionToError(scope: 'client' | 'server', e: unknown): MutationError
90
90
  */
91
91
  export function observeMutation(
92
92
  result: MutatorResultLike,
93
- onError?: (error: MutationError) => void,
93
+ onError?: (error: MutationError) => void
94
94
  ): Promise<void> {
95
95
  let reportedGlobal = false
96
96
  const report = (err: MutationError | null) => {
@@ -128,7 +128,7 @@ export function observeMutation(
128
128
  * transaction, not N calls — that keeps it atomic and a single state.
129
129
  */
130
130
  export function useMutation<Fn extends (...args: any[]) => MutatorResultLike>(
131
- mutator: Fn,
131
+ mutator: Fn
132
132
  ): [Fn, MutationState] {
133
133
  const [pending, setPending] = useState(false)
134
134
  const [error, setError] = useState<MutationError | null>(null)
@@ -1,6 +1,6 @@
1
- import { getCurrentComponentStack } from '@take-out/helpers'
2
1
  import { useEffect, useId } from 'react'
3
2
 
3
+ import { getCurrentComponentStack } from './getCurrentComponentStack'
4
4
  import { prettyFormatZeroQuery } from './prettyFormatZeroQuery'
5
5
 
6
6
  import type { Query } from '@rocicorp/zero'
@@ -42,7 +42,7 @@ export const useZeroDebug = (query: Query<any, any, any>, options: any, results:
42
42
  if (shouldLog) {
43
43
  if (COLLAPSED) {
44
44
  console.groupCollapsed(
45
- `${isPermissionQuery ? `👮‍♂️` : `✨`}${prettyFormatZeroQuery(query, 'minimal')}`,
45
+ `${isPermissionQuery ? `👮‍♂️` : `✨`}${prettyFormatZeroQuery(query, 'minimal')}`
46
46
  )
47
47
  console.info(id, prettyFormatZeroQuery(query, 'full'))
48
48
  console.info('cached result', results)
@@ -80,7 +80,7 @@ export const useZeroDebug = (query: Query<any, any, any>, options: any, results:
80
80
  table,
81
81
  changeCount: history.changeCount,
82
82
  recentAsts: history.asts,
83
- },
83
+ }
84
84
  )
85
85
  }
86
86
  }
package/src/index.ts CHANGED
@@ -24,6 +24,7 @@ export * from './mutations'
24
24
  export * from './where'
25
25
  export * from './serverWhere'
26
26
  export * from './zql'
27
+ export { defineConfig, type DataConfig, type DataInstanceConfig } from './config'
27
28
  export { defineQuery, defineQueries } from '@rocicorp/zero'
28
29
 
29
30
  // drizzle-zero re-exports moved to 'on-zero/drizzle' to avoid pulling
@@ -48,8 +49,19 @@ export {
48
49
  composeRecoveryLogSink,
49
50
  isRecoverableZeroStalePokeMessage,
50
51
  type ZeroRecoveryLogClassification,
51
- type ZeroRecoveryLogReason,
52
52
  type ZeroRecoveryDeps,
53
53
  type ScheduleReloadContext,
54
54
  type RecoveryGuardStorage,
55
+ type ZeroLogPattern,
55
56
  } from './helpers/recoverZeroClient'
57
+
58
+ export {
59
+ isStaleGenerationError,
60
+ mutationErrorMessage,
61
+ MutationResultError,
62
+ MutationTimeoutError,
63
+ StaleGenerationError,
64
+ type BackgroundMutationOptions,
65
+ type MutationLike,
66
+ type MutationPhase,
67
+ } from './helpers/mutationLifecycle'
@@ -7,8 +7,9 @@
7
7
  // stored via globalValue so dual-loaded module copies (cjs/esm) share one map,
8
8
  // matching the package's other cross-module registries.
9
9
 
10
- import { globalValue } from '@take-out/helpers'
10
+ import { globalValue } from './helpers/globalValue'
11
11
  import { getQueryName } from './queryRegistry'
12
+
12
13
  import type { ZeroRunner } from './zeroRunner'
13
14
  import type { AnyQueryRegistry } from '@rocicorp/zero'
14
15
 
@@ -23,15 +24,27 @@ export type ZeroClientInstance = {
23
24
  const getInstancesByNamespace = () =>
24
25
  globalValue<Map<string, ZeroClientInstance>>(
25
26
  'on-zero:instances-by-namespace',
26
- () => new Map(),
27
+ () => new Map()
27
28
  )
28
29
 
29
30
  const getInstancesByQueryName = () =>
30
31
  globalValue<Map<string, ZeroClientInstance>>(
31
32
  'on-zero:instances-by-query-name',
32
- () => new Map(),
33
+ () => new Map()
33
34
  )
34
35
 
36
+ export function releaseClientInstances(names: readonly string[]): void {
37
+ const releasing = new Set(names)
38
+ const instancesByNamespace = getInstancesByNamespace()
39
+ const instancesByQueryName = getInstancesByQueryName()
40
+ for (const [namespace, owner] of instancesByNamespace) {
41
+ if (releasing.has(owner.name)) instancesByNamespace.delete(namespace)
42
+ }
43
+ for (const [queryName, owner] of instancesByQueryName) {
44
+ if (releasing.has(owner.name)) instancesByQueryName.delete(queryName)
45
+ }
46
+ }
47
+
35
48
  export function registerClientInstance({
36
49
  name,
37
50
  namespaces,
@@ -65,7 +78,7 @@ export function registerClientInstance({
65
78
  if (existing) {
66
79
  throw new Error(
67
80
  `[on-zero] namespace '${namespace}' is already claimed by zero client instance '${existing.name}' ` +
68
- `(while creating instance '${name}'). Each query/mutator namespace must belong to exactly one createZeroClient instance.`,
81
+ `(while creating instance '${name}'). Each query/mutator namespace must belong to exactly one createZeroClient instance.`
69
82
  )
70
83
  }
71
84
  instancesByNamespace.set(namespace, instance)
@@ -76,7 +89,7 @@ export function registerClientInstance({
76
89
  if (existing) {
77
90
  throw new Error(
78
91
  `[on-zero] query '${queryName}' is already claimed by zero client instance '${existing.name}' ` +
79
- `(while creating instance '${name}'). Each query function must belong to exactly one createZeroClient instance.`,
92
+ `(while creating instance '${name}'). Each query function must belong to exactly one createZeroClient instance.`
80
93
  )
81
94
  }
82
95
  instancesByQueryName.set(queryName, instance)
@@ -86,7 +99,7 @@ export function registerClientInstance({
86
99
  }
87
100
 
88
101
  export function getInstanceForNamespace(
89
- namespace: string,
102
+ namespace: string
90
103
  ): ZeroClientInstance | undefined {
91
104
  return getInstancesByNamespace().get(namespace)
92
105
  }
package/src/multi.ts CHANGED
@@ -1,9 +1,11 @@
1
+ import { combineZeroClients } from './combineZeroClients'
2
+ import { createUseQueryDirect } from './createUseQueryDirect'
1
3
  import {
2
4
  createZeroClientInternal,
3
5
  type DirectQueryAdapter,
4
6
  type CreateZeroClientOptions,
5
7
  } from './createZeroClient'
6
- import { createUseQueryDirect } from './createUseQueryDirect'
8
+ import { releaseClientInstances } from './instanceRegistry'
7
9
 
8
10
  import type { GenericModels } from './types'
9
11
  import type { Schema as ZeroSchema } from '@rocicorp/zero'
@@ -14,7 +16,7 @@ export function createZeroClientWithDirectQueries<
14
16
  Schema extends ZeroSchema,
15
17
  Models extends GenericModels,
16
18
  >(
17
- options: CreateZeroClientOptions<Schema, Models>,
19
+ options: CreateZeroClientOptions<Schema, Models>
18
20
  ): ReturnType<typeof createZeroClientInternal<Schema, Models>> {
19
21
  const createDirectUseQuery: DirectQueryAdapter<Schema> = createUseQueryDirect
20
22
  return createZeroClientInternal<Schema, Models>({
@@ -23,35 +25,77 @@ export function createZeroClientWithDirectQueries<
23
25
  })
24
26
  }
25
27
 
26
- // fail loud when a generated namespace drifts out of a multi-instance partition.
27
- // multi-instance consumers (control + project, control + server, …) hand-split
28
- // the generated query/model namespaces across instances; a namespace that ends
29
- // up in NEITHER partition silently un-registers its queries (its useQuery throws
30
- // "query not registered" at runtime, error-boundarying a whole screen — the soot
31
- // `planGrant` regression). run this at module-eval over each partitioned group so
32
- // the drift is a build/boot throw instead. also catches a namespace listed in
33
- // MORE than one partition (an ambiguous owner), which the hand-rolled loops did
34
- // not. `partitions` maps a label (e.g. 'control'/'project') to that instance's
35
- // namespace table; every key in `entries` must appear in exactly one.
36
- export function assertZeroInstancePartition(
37
- kind: string,
38
- entries: Record<string, unknown>,
39
- partitions: Record<string, Record<string, unknown>>,
40
- ): void {
41
- const labels = Object.keys(partitions)
42
- for (const name of Object.keys(entries)) {
43
- const owners = labels.filter((label) => name in partitions[label])
44
- if (owners.length === 0) {
45
- throw new Error(
46
- `[on-zero] generated ${kind} "${name}" is missing from the instance partition ` +
47
- `(${labels.join(' / ')}) — add it to exactly one partition table.`,
48
- )
49
- }
50
- if (owners.length > 1) {
51
- throw new Error(
52
- `[on-zero] generated ${kind} "${name}" is claimed by more than one instance partition ` +
53
- `(${owners.join(', ')}) it must belong to exactly one.`,
54
- )
28
+ export type ZeroInstanceManifestEntry<
29
+ Schema extends ZeroSchema = ZeroSchema,
30
+ Models extends GenericModels = GenericModels,
31
+ > = {
32
+ schema: Schema
33
+ queries: CreateZeroClientOptions<Schema, Models>['groupedQueries']
34
+ models: Models
35
+ tables: readonly string[]
36
+ syncTables: readonly string[]
37
+ supportTables: readonly string[]
38
+ scope: string | null
39
+ defaultVisibility: ((value: string) => { column: string; value: string }) | null
40
+ }
41
+
42
+ type ClientFor<Entry> =
43
+ Entry extends ZeroInstanceManifestEntry<infer Schema, infer Models>
44
+ ? ReturnType<typeof createZeroClientInternal<Schema, Models>>
45
+ : never
46
+
47
+ type ClientMap<Instances extends Record<string, ZeroInstanceManifestEntry>> = {
48
+ [Name in keyof Instances]: ClientFor<Instances[Name]>
49
+ }
50
+
51
+ type ClientUnion<Instances extends Record<string, ZeroInstanceManifestEntry>> =
52
+ ClientMap<Instances>[keyof Instances]
53
+
54
+ export function createZeroClients<
55
+ const Instances extends Record<string, ZeroInstanceManifestEntry>,
56
+ >(instances: Instances) {
57
+ const names = Object.keys(instances)
58
+ if (names.length === 0) {
59
+ throw new Error('[on-zero] createZeroClients requires at least one instance')
60
+ }
61
+ if (names.includes('default')) {
62
+ names.splice(names.indexOf('default'), 1)
63
+ names.unshift('default')
64
+ }
65
+
66
+ const innerName = names[names.length - 1]!
67
+ const clients: Record<string, ReturnType<typeof createZeroClientInternal>> = {}
68
+
69
+ // release the complete old partition atomically before any new instance
70
+ // claims namespaces that may have moved during hot reload.
71
+ releaseClientInstances(names)
72
+ for (const name of [...names].reverse()) {
73
+ const instance = instances[name]!
74
+ const options = {
75
+ schema: instance.schema,
76
+ models: instance.models,
77
+ groupedQueries: instance.queries,
78
+ instanceName: name,
55
79
  }
80
+ clients[name] =
81
+ name === innerName
82
+ ? createZeroClientInternal(options)
83
+ : createZeroClientWithDirectQueries(options)
84
+ }
85
+
86
+ const typedClients = clients as ClientMap<Instances>
87
+ // names is checked non-empty above. retain the union of the concrete client
88
+ // types so combineZeroClients can intersect every instance surface.
89
+ const orderedClients = names.map(
90
+ (name) => typedClients[name as keyof Instances]
91
+ ) as unknown as [ClientUnion<Instances>, ...ClientUnion<Instances>[]]
92
+ const providers = Object.fromEntries(
93
+ names.map((name) => [name, clients[name]!.ProvideZero])
94
+ ) as { [Name in keyof Instances]: ClientMap<Instances>[Name]['ProvideZero'] }
95
+
96
+ return {
97
+ clients: typedClients,
98
+ providers,
99
+ combined: combineZeroClients(...orderedClients),
56
100
  }
57
101
  }