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,20 +1,24 @@
1
- import { existsSync, mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync as writeFile } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
- import { join } from "node:path";
3
+ import { dirname, join } from "node:path";
4
4
  import { runInNewContext } from "node:vm";
5
5
  import * as zero from "@rocicorp/zero";
6
- import { afterEach, beforeEach, describe, expect, test } from "vitest";
7
- import { generate, generateDrizzleSchemaFile } from "./generate.mjs";
6
+ import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
7
+ import { deriveDataMembership, generate, generateDrizzleSchemaFile, generateDrizzleSchemaInputFile } from "./generate.mjs";
8
8
  const testDir = join(tmpdir(), "on-zero-test-" + Date.now());
9
- beforeEach(() => {
10
- mkdirSync(join(testDir, "models"), {
9
+ function writeFileSync(path, content) {
10
+ mkdirSync(dirname(path), {
11
11
  recursive: true
12
12
  });
13
- mkdirSync(join(testDir, "queries"), {
13
+ writeFile(path, content);
14
+ }
15
+ beforeEach(() => {
16
+ mkdirSync(testDir, {
14
17
  recursive: true
15
18
  });
16
19
  });
17
20
  afterEach(() => {
21
+ vi.restoreAllMocks();
18
22
  rmSync(testDir, {
19
23
  recursive: true,
20
24
  force: true
@@ -22,7 +26,7 @@ afterEach(() => {
22
26
  });
23
27
  describe("generate", () => {
24
28
  test("generates models.ts, types.ts, tables.ts from model files", async () => {
25
- writeFileSync(join(testDir, "models/post.ts"), `
29
+ writeFileSync(join(testDir, "post/mutations.ts"), `
26
30
  import { table, string, boolean } from 'on-zero'
27
31
 
28
32
  export const schema = table('post', {
@@ -31,7 +35,7 @@ export const schema = table('post', {
31
35
  published: boolean(),
32
36
  })
33
37
  `);
34
- writeFileSync(join(testDir, "models/comment.ts"), `
38
+ writeFileSync(join(testDir, "comment/mutations.ts"), `
35
39
  import { table, string } from 'on-zero'
36
40
 
37
41
  export const schema = table('comment', {
@@ -40,8 +44,8 @@ export const schema = table('comment', {
40
44
  body: string(),
41
45
  })
42
46
  `);
43
- writeFileSync(join(testDir, "models/post.test.ts"), `throw new Error('test files must not be generated as models')`);
44
- writeFileSync(join(testDir, "queries/comment.spec.ts"), `throw new Error('spec files must not be generated as queries')`);
47
+ writeFileSync(join(testDir, "post/post.test.ts"), `throw new Error('test files must not be generated as models')`);
48
+ writeFileSync(join(testDir, "comment/comment.spec.ts"), `throw new Error('spec files must not be generated as queries')`);
45
49
  const result = await generate({
46
50
  dir: testDir,
47
51
  silent: true
@@ -53,20 +57,20 @@ export const schema = table('comment', {
53
57
  expect(existsSync(join(testDir, "generated/types.ts"))).toBe(true);
54
58
  expect(existsSync(join(testDir, "generated/tables.ts"))).toBe(true);
55
59
  const modelsContent = readFileSync(join(testDir, "generated/models.ts"), "utf-8");
56
- expect(modelsContent).toContain("import * as comment from '../models/comment'");
57
- expect(modelsContent).toContain("import * as post from '../models/post'");
60
+ expect(modelsContent).toContain("import * as comment from '../comment/mutations'");
61
+ expect(modelsContent).toContain("import * as post from '../post/mutations'");
58
62
  expect(modelsContent).not.toContain("post.test");
59
63
  expect(modelsContent).toContain("export const models = {");
60
64
  const typesContent = readFileSync(join(testDir, "generated/types.ts"), "utf-8");
61
65
  expect(typesContent).toContain("export type Post = TableInsertRow<typeof schema.post>");
62
66
  expect(typesContent).toContain("export type Comment = TableInsertRow<typeof schema.comment>");
63
67
  const tablesContent = readFileSync(join(testDir, "generated/tables.ts"), "utf-8");
64
- expect(tablesContent).toContain("export { schema as post } from '../models/post'");
65
- expect(tablesContent).toContain("export { schema as comment } from '../models/comment'");
68
+ expect(tablesContent).toContain("export { schema as post } from '../post/mutations'");
69
+ expect(tablesContent).toContain("export { schema as comment } from '../comment/mutations'");
66
70
  });
67
71
  test("generates query validators from query files", async () => {
68
- writeFileSync(join(testDir, "models/post.ts"), `export const schema = table('post', { id: string() })`);
69
- writeFileSync(join(testDir, "queries/post.ts"), `
72
+ writeFileSync(join(testDir, "post/mutations.ts"), `export const schema = table('post', { id: string() })`);
73
+ writeFileSync(join(testDir, "post/queries.ts"), `
70
74
  import { zero } from '../zero'
71
75
 
72
76
  export const allPosts = () => zero.query.post
@@ -84,7 +88,8 @@ export const postsByAuthor = ({ authorId, limit }: { authorId: string; limit?: n
84
88
  expect(existsSync(join(testDir, "generated/groupedQueries.ts"))).toBe(true);
85
89
  expect(existsSync(join(testDir, "generated/syncedQueries.ts"))).toBe(true);
86
90
  const groupedContent = readFileSync(join(testDir, "generated/groupedQueries.ts"), "utf-8");
87
- expect(groupedContent).toContain("export * as post from '../queries/post'");
91
+ expect(groupedContent).toContain("import * as postSource from '../post/queries'");
92
+ expect(groupedContent).toContain("postById: postSource.postById");
88
93
  const syncedContent = readFileSync(join(testDir, "generated/syncedQueries.ts"), "utf-8");
89
94
  expect(syncedContent).toContain("allPosts: defineQuery");
90
95
  expect(syncedContent).toContain("postById: defineQuery");
@@ -92,8 +97,8 @@ export const postsByAuthor = ({ authorId, limit }: { authorId: string; limit?: n
92
97
  expect(syncedContent).toContain("v.object");
93
98
  });
94
99
  test("skips permission exports in queries", async () => {
95
- writeFileSync(join(testDir, "models/post.ts"), `export const schema = table('post', { id: string() })`);
96
- writeFileSync(join(testDir, "queries/post.ts"), `
100
+ writeFileSync(join(testDir, "post/mutations.ts"), `export const schema = table('post', { id: string() })`);
101
+ writeFileSync(join(testDir, "post/queries.ts"), `
97
102
  export const permission = () => ({ canRead: true })
98
103
  export const allPosts = () => zero.query.post
99
104
  `);
@@ -107,20 +112,20 @@ export const allPosts = () => zero.query.post
107
112
  expect(syncedContent).not.toContain("permission:");
108
113
  });
109
114
  test("aliases user import without changing the model key", async () => {
110
- writeFileSync(join(testDir, "models/user.ts"), `export const schema = table('user', { id: string(), name: string() })`);
115
+ writeFileSync(join(testDir, "user/mutations.ts"), `export const schema = table('user', { id: string(), name: string() })`);
111
116
  await generate({
112
117
  dir: testDir,
113
118
  silent: true
114
119
  });
115
120
  const modelsContent = readFileSync(join(testDir, "generated/models.ts"), "utf-8");
116
- expect(modelsContent).toContain("import * as userPublic from '../models/user'");
121
+ expect(modelsContent).toContain("import * as userPublic from '../user/mutations'");
117
122
  expect(modelsContent).toContain("user: userPublic,");
118
123
  expect(modelsContent).not.toContain("\n userPublic,");
119
124
  const typesContent = readFileSync(join(testDir, "generated/types.ts"), "utf-8");
120
125
  expect(typesContent).toContain("typeof schema.userPublic");
121
126
  });
122
127
  test("runs after command when files change", async () => {
123
- writeFileSync(join(testDir, "models/post.ts"), `export const schema = table('post', { id: string() })`);
128
+ writeFileSync(join(testDir, "post/mutations.ts"), `export const schema = table('post', { id: string() })`);
124
129
  const markerFile = join(testDir, "after-ran");
125
130
  const result = await generate({
126
131
  dir: testDir,
@@ -131,7 +136,7 @@ export const allPosts = () => zero.query.post
131
136
  expect(existsSync(markerFile)).toBe(true);
132
137
  });
133
138
  test("does not regenerate when nothing changed", async () => {
134
- writeFileSync(join(testDir, "models/post.ts"), `export const schema = table('post', { id: string() })`);
139
+ writeFileSync(join(testDir, "post/mutations.ts"), `export const schema = table('post', { id: string() })`);
135
140
  const first = await generate({
136
141
  dir: testDir,
137
142
  silent: true
@@ -144,8 +149,8 @@ export const allPosts = () => zero.query.post
144
149
  expect(second.filesChanged).toBe(0);
145
150
  });
146
151
  test("force regenerates without source changes", async () => {
147
- writeFileSync(join(testDir, "models/post.ts"), `export const schema = table('post', { id: string() })`);
148
- writeFileSync(join(testDir, "queries/post.ts"), `export const allPosts = () => zero.query.post`);
152
+ writeFileSync(join(testDir, "post/mutations.ts"), `export const schema = table('post', { id: string() })`);
153
+ writeFileSync(join(testDir, "post/queries.ts"), `export const allPosts = () => zero.query.post`);
149
154
  await generate({
150
155
  dir: testDir,
151
156
  silent: true
@@ -160,9 +165,321 @@ export const allPosts = () => zero.query.post
160
165
  expect(existsSync(syncedQueriesPath)).toBe(true);
161
166
  });
162
167
  });
168
+ describe("instance layout", () => {
169
+ const dataDir = () => join(testDir, "src/data");
170
+ test("discovers file and folder namespaces and emits related sync closure", async () => {
171
+ writeFileSync(join(dataDir(), "control/reaction.ts"), `export const allReactions = () => zql.reaction`);
172
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { control: {}, project: { scope: 'projectId' } } })`);
173
+ writeFileSync(join(dataDir(), "project/message/queries.ts"), `
174
+ const unused = () => zql.message.related('notARealRelation')
175
+ const withComments = () => zql.message.related('comments', (q) => q.related('author'))
176
+ export const messages = () => withComments()
177
+ `);
178
+ writeFileSync(join(dataDir(), "project/message/mutations.ts"), `export const schema = table('message').columns({ id: string(), projectId: string() })`);
179
+ writeFileSync(join(dataDir(), "project/message/helpers.ts"), `export const privateHelper = () => 'ignored'`);
180
+ writeFileSync(join(testDir, "src/database/relations.ts"), `
181
+ export const relations = defineRelations(schema, (r) => ({
182
+ message: { comments: r.many.comment({}) },
183
+ comment: { author: r.one.userPublic({}) },
184
+ }))
185
+ `);
186
+ writeFileSync(join(testDir, "src/database/schema.ts"), `
187
+ export const comment = sqliteTable('comment', { id: text(), projectId: text() })
188
+ export const userPublic = sqliteTable('user_public', { id: text(), projectId: text() })
189
+ `);
190
+ const membership = await deriveDataMembership({
191
+ dir: dataDir()
192
+ });
193
+ expect(membership.allTables).toEqual(["comment", "message", "reaction", "userPublic"]);
194
+ expect(membership.instances.project).toEqual({
195
+ tables: ["message"],
196
+ syncTables: ["comment", "message", "userPublic"],
197
+ supportTables: [],
198
+ scope: "projectId"
199
+ });
200
+ await generate({
201
+ dir: dataDir(),
202
+ silent: true
203
+ });
204
+ const grouped = readFileSync(join(dataDir(), "generated/groupedQueries.ts"), "utf8");
205
+ expect(grouped).toContain("from '../control/reaction'");
206
+ expect(grouped).toContain("from '../project/message/queries'");
207
+ expect(grouped).not.toContain("privateHelper");
208
+ const manifest = readFileSync(join(dataDir(), "generated/instances.ts"), "utf8");
209
+ expect(manifest).toContain("control: {");
210
+ expect(manifest).toContain("project: {");
211
+ expect(manifest).toContain('tables: ["message"]');
212
+ expect(manifest).toContain('syncTables: ["comment","message","userPublic"]');
213
+ expect(manifest).toContain(`defaultVisibility: (value: string) => ({ column: "projectId", value })`);
214
+ });
215
+ test("derives single-file namespaces from data exports", async () => {
216
+ writeFileSync(join(dataDir(), "server.ts"), `export const serverRows = () => zql.server`);
217
+ writeFileSync(join(dataDir(), "types.ts"), `export const formatRow = (value: string) => value`);
218
+ writeFileSync(join(dataDir(), "auth.ts"), `export function authId(auth: { id: string }) { return auth.id }`);
219
+ await expect(deriveDataMembership({
220
+ dir: dataDir()
221
+ })).resolves.toEqual({
222
+ instances: {
223
+ default: {
224
+ tables: ["server"],
225
+ syncTables: ["server"],
226
+ supportTables: [],
227
+ scope: null
228
+ }
229
+ },
230
+ allTables: ["server"]
231
+ });
232
+ });
233
+ test("warns once and ignores an unparseable non-data file", async () => {
234
+ writeFileSync(join(dataDir(), "post.ts"), `export const posts = () => zql.post`);
235
+ writeFileSync(join(dataDir(), "types.ts"), `export type Broken = {`);
236
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
237
+ await expect(deriveDataMembership({
238
+ dir: dataDir()
239
+ })).resolves.toMatchObject({
240
+ allTables: ["post"]
241
+ });
242
+ expect(warn).toHaveBeenCalledOnce();
243
+ expect(warn).toHaveBeenCalledWith("[on-zero] ignoring data/types.ts: no recognized data exports");
244
+ warn.mockRestore();
245
+ });
246
+ test("derives fileless support tables through mutation helpers", async () => {
247
+ writeFileSync(join(dataDir(), "post.ts"), `
248
+ import { writeAudit } from './helpers/writeAudit'
249
+ export const posts = () => zql.post
250
+ export const mutate = mutations('post', { save: async (ctx) => writeAudit(ctx.tx) })
251
+ `);
252
+ writeFileSync(join(dataDir(), "helpers/writeAudit.ts"), `
253
+ import { readSettings } from './readSettings'
254
+ export async function writeAudit(tx: Transaction) {
255
+ await tx.mutate.audit.insert({ id: 'audit' })
256
+ await tx.mutate.post.update({ id: 'post' })
257
+ await tx.mutate[tableName].insert({ id: 'dynamic' })
258
+ return readSettings(tx)
259
+ }
260
+ `);
261
+ writeFileSync(join(dataDir(), "helpers/readSettings.ts"), `export const readSettings = (tx: Transaction) => tx.query.settings`);
262
+ await expect(deriveDataMembership({
263
+ dir: dataDir()
264
+ })).resolves.toEqual({
265
+ instances: {
266
+ default: {
267
+ tables: ["post"],
268
+ syncTables: ["post"],
269
+ supportTables: ["audit", "settings"],
270
+ scope: null
271
+ }
272
+ },
273
+ allTables: ["audit", "post", "settings"]
274
+ });
275
+ });
276
+ test("includes a fileless support table in every instance that uses it", async () => {
277
+ writeFileSync(join(dataDir(), "control/account.ts"), `export const mutate = mutations('account', { save: async (ctx) => ctx.tx.mutate.audit.insert({}) })`);
278
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { control: {}, project: { scope: 'projectId' } } })`);
279
+ writeFileSync(join(dataDir(), "project/message.ts"), `
280
+ export const schema = table('message').columns({ id: string(), projectId: string() })
281
+ export const mutate = mutations(schema, permission, {
282
+ save: async (ctx) => ctx.tx.mutate.audit.insert({}),
283
+ })
284
+ `);
285
+ await expect(deriveDataMembership({
286
+ dir: dataDir()
287
+ })).resolves.toMatchObject({
288
+ instances: {
289
+ control: {
290
+ supportTables: ["audit"]
291
+ },
292
+ project: {
293
+ supportTables: ["audit"]
294
+ }
295
+ },
296
+ allTables: ["account", "audit", "message"]
297
+ });
298
+ });
299
+ test("keeps a configured default instance at the data root", async () => {
300
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { default: { dir: '.', supportTables: ['accountGithubOrgLink', 'accountRepo', 'usageLedger'] }, project: { scope: 'projectId' } } })`);
301
+ writeFileSync(join(dataDir(), "account.ts"), `export const accounts = () => zql.account`);
302
+ writeFileSync(join(dataDir(), "project/message.ts"), `export const schema = table('message').columns({ id: string(), projectId: string() })`);
303
+ await expect(deriveDataMembership({
304
+ dir: dataDir()
305
+ })).resolves.toEqual({
306
+ instances: {
307
+ default: {
308
+ tables: ["account"],
309
+ syncTables: ["account"],
310
+ supportTables: ["accountGithubOrgLink", "accountRepo", "usageLedger"],
311
+ scope: null
312
+ },
313
+ project: {
314
+ tables: ["message"],
315
+ syncTables: ["message"],
316
+ supportTables: [],
317
+ scope: "projectId"
318
+ }
319
+ },
320
+ allTables: ["account", "accountGithubOrgLink", "accountRepo", "message", "usageLedger"]
321
+ });
322
+ });
323
+ test("emits only relations whose source and target are derived members", async () => {
324
+ writeFileSync(join(dataDir(), "post.ts"), `export const posts = () => zql.post`);
325
+ writeFileSync(join(dataDir(), "comment.ts"), `export const comments = () => zql.comment`);
326
+ writeFileSync(join(testDir, "src/database/relations.ts"), `
327
+ export const relations = defineRelations(schema, (r) => ({
328
+ post: {
329
+ comments: r.many.comment({}),
330
+ privateNotes: r.many.privateNote({}),
331
+ },
332
+ comment: { post: r.one.post({}), author: r.one.privateUser({}) },
333
+ privateNote: { post: r.one.post({}) },
334
+ }))
335
+ `);
336
+ const generated = await generateDrizzleSchemaInputFile({
337
+ dir: dataDir(),
338
+ schemaImportPath: "../../database/schema"
339
+ });
340
+ const runnable = generated.replace(`import { defineRelations } from 'drizzle-orm'`, "").replace(`import * as schema from "../../database/schema"`, "").replace(/export \{[^\n]+\} from [^\n]+/, "").replace("export const relations =", "globalThis.relations =");
341
+ const context = {
342
+ schema: {
343
+ comment: {},
344
+ post: {}
345
+ },
346
+ defineRelations: (_schema, factory) => factory({
347
+ one: new Proxy({}, {
348
+ get: (_target, table) => () => ({
349
+ table
350
+ })
351
+ }),
352
+ many: new Proxy({}, {
353
+ get: (_target, table) => () => ({
354
+ table
355
+ })
356
+ })
357
+ })
358
+ };
359
+ runInNewContext(runnable, context);
360
+ expect(context.relations).toEqual({
361
+ comment: {
362
+ post: {
363
+ table: "post"
364
+ }
365
+ },
366
+ post: {
367
+ comments: {
368
+ table: "comment"
369
+ }
370
+ }
371
+ });
372
+ });
373
+ test("rejects a relation that crosses instance ownership", async () => {
374
+ writeFileSync(join(dataDir(), "control/userPublic.ts"), `export const users = () => zql.userPublic`);
375
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { control: {}, project: { scope: 'projectId' } } })`);
376
+ writeFileSync(join(dataDir(), "project/message.ts"), `
377
+ export const schema = table('message').columns({ id: string(), projectId: string() })
378
+ export const messages = () => zql.message.related('author')
379
+ `);
380
+ writeFileSync(join(testDir, "src/database/relations.ts"), `export const relations = defineRelations(schema, (r) => ({ message: { author: r.one.userPublic({}) } }))`);
381
+ await expect(generate({
382
+ dir: dataDir(),
383
+ silent: true
384
+ })).rejects.toThrow(/message\.messages.*instance 'project'.*userPublic.*instance 'control'/);
385
+ });
386
+ test("rejects a scoped sync table without the scope column", async () => {
387
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { project: { scope: 'projectId' } } })`);
388
+ writeFileSync(join(dataDir(), "project/message.ts"), `export const schema = table('message').columns({ id: string() })`);
389
+ await expect(generate({
390
+ dir: dataDir(),
391
+ silent: true
392
+ })).rejects.toThrow(/table 'message'.*instance 'project'.*scope column 'projectId'/);
393
+ });
394
+ test("rejects duplicate namespaces across instances", async () => {
395
+ writeFileSync(join(dataDir(), "control/message.ts"), `export const messages = () => zql.message`);
396
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { control: {}, project: { scope: 'projectId' } } })`);
397
+ writeFileSync(join(dataDir(), "project/message.ts"), `export const schema = table('message').columns({ projectId: string() })`);
398
+ await expect(generate({
399
+ dir: dataDir(),
400
+ silent: true
401
+ })).rejects.toThrow(/namespace 'message'.*instances 'control' and 'project'/);
402
+ });
403
+ test("resolves configured instance directories relative to the config file", async () => {
404
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { control: { dir: './planes/control-data', supportTables: ['audit'] }, project: { dir: '../project-data', scope: 'projectId' } } })`);
405
+ writeFileSync(join(dataDir(), "planes/control-data/account.ts"), `export const accounts = () => zql.account`);
406
+ writeFileSync(join(testDir, "src/project-data/message.ts"), `export const schema = table('message').columns({ id: string(), projectId: string() })`);
407
+ await expect(deriveDataMembership({
408
+ dir: dataDir(),
409
+ config: join(dataDir(), "on-zero.config.ts")
410
+ })).resolves.toEqual({
411
+ instances: {
412
+ control: {
413
+ tables: ["account"],
414
+ syncTables: ["account"],
415
+ supportTables: ["audit"],
416
+ scope: null
417
+ },
418
+ project: {
419
+ tables: ["message"],
420
+ syncTables: ["message"],
421
+ supportTables: [],
422
+ scope: "projectId"
423
+ }
424
+ },
425
+ allTables: ["account", "audit", "message"]
426
+ });
427
+ await expect(generate({
428
+ dir: dataDir(),
429
+ config: join(dataDir(), "on-zero.config.ts"),
430
+ silent: true
431
+ })).resolves.toMatchObject({
432
+ modelCount: 2,
433
+ schemaCount: 1
434
+ });
435
+ expect(readFileSync(join(dataDir(), "generated/models.ts"), "utf8")).toContain("from '../../project-data/message'");
436
+ });
437
+ test("rejects missing configured instance directories", async () => {
438
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { project: { dir: './missing' } } })`);
439
+ await expect(deriveDataMembership({
440
+ dir: dataDir()
441
+ })).rejects.toThrow(/instance 'project' directory does not exist.*missing/);
442
+ });
443
+ test("rejects two instances that resolve to the same directory", async () => {
444
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { control: { dir: './shared' }, project: { dir: './shared' } } })`);
445
+ writeFileSync(join(dataDir(), "shared/account.ts"), `export const accounts = () => zql.account`);
446
+ await expect(deriveDataMembership({
447
+ dir: dataDir()
448
+ })).rejects.toThrow(/instances 'control' and 'project' resolve to the same directory/);
449
+ });
450
+ test("rejects root namespaces when instances are configured", async () => {
451
+ writeFileSync(join(dataDir(), "on-zero.config.ts"), `export default defineConfig({ instances: { project: {} } })`);
452
+ writeFileSync(join(dataDir(), "project/message.ts"), `export const rows = () => zql.message`);
453
+ writeFileSync(join(dataDir(), "account.ts"), `export const rows = () => zql.account`);
454
+ await expect(deriveDataMembership({
455
+ dir: dataDir()
456
+ })).rejects.toThrow(/data namespace .*account\.ts.*outside every instance directory/);
457
+ });
458
+ test("rejects removed instance.ts configuration", async () => {
459
+ writeFileSync(join(dataDir(), "post.ts"), `export const posts = () => zql.post`);
460
+ writeFileSync(join(dataDir(), "project/instance.ts"), `export default defineInstance({ scope: 'projectId' })`);
461
+ await expect(deriveDataMembership({
462
+ dir: dataDir()
463
+ })).rejects.toThrow(/uses removed instance\.ts configuration/);
464
+ });
465
+ test("rejects the removed top-level layout", async () => {
466
+ writeFileSync(join(dataDir(), "queries/message.ts"), `export const messages = () => zql.message`);
467
+ await expect(generate({
468
+ dir: dataDir(),
469
+ silent: true
470
+ })).rejects.toThrow(/removed top-level queries\/ layout/);
471
+ });
472
+ test("rejects dynamically named relations", async () => {
473
+ writeFileSync(join(dataDir(), "message.ts"), `export const messages = (relation: string) => zql.message.related(relation)`);
474
+ await expect(generate({
475
+ dir: dataDir(),
476
+ silent: true
477
+ })).rejects.toThrow(/related\(\) without a string literal.*statically derivable/);
478
+ });
479
+ });
163
480
  describe("mutations", () => {
164
481
  test("generates validators for inline mutation param types", async () => {
165
- writeFileSync(join(testDir, "models/post.ts"), `
482
+ writeFileSync(join(testDir, "post/mutations.ts"), `
166
483
  import { table, string } from 'on-zero'
167
484
  import { mutations, serverWhere } from 'on-zero'
168
485
 
@@ -191,7 +508,7 @@ export const mutate = mutations(schema, perm, {
191
508
  expect(content).toContain("v.string()");
192
509
  });
193
510
  test("generates CRUD validators from schema columns", async () => {
194
- writeFileSync(join(testDir, "models/task.ts"), `
511
+ writeFileSync(join(testDir, "task/mutations.ts"), `
195
512
  import { table, string, number, boolean } from 'on-zero'
196
513
  import { mutations, serverWhere } from 'on-zero'
197
514
 
@@ -218,7 +535,7 @@ export const mutate = mutations(schema, perm)
218
535
  expect(content).toContain("delete:");
219
536
  });
220
537
  test("treats models without export const mutate as empty mutations", async () => {
221
- writeFileSync(join(testDir, "models/readonly.ts"), `
538
+ writeFileSync(join(testDir, "readonly/mutations.ts"), `
222
539
  import { table, string } from 'on-zero'
223
540
 
224
541
  export const schema = table('readonly').columns({
@@ -235,7 +552,7 @@ export const schema = table('readonly').columns({
235
552
  expect(content).toContain("readonly: {");
236
553
  });
237
554
  test("extracts custom mutations from bare mutations({})", async () => {
238
- writeFileSync(join(testDir, "models/admin.ts"), `
555
+ writeFileSync(join(testDir, "admin/mutations.ts"), `
239
556
  import { mutations } from 'on-zero'
240
557
 
241
558
  export const mutate = mutations({
@@ -253,7 +570,7 @@ export const mutate = mutations({
253
570
  expect(content).toContain("v.string()");
254
571
  });
255
572
  test("generates validators for string-model multiline mutation params", async () => {
256
- writeFileSync(join(testDir, "models/agentEvent.ts"), `
573
+ writeFileSync(join(testDir, "agentEvent/mutations.ts"), `
257
574
  import { mutations, serverWhere } from 'on-zero'
258
575
 
259
576
  const perm = serverWhere('agentEvent', () => true)
@@ -287,7 +604,7 @@ export const mutate = mutations('agentEvent', perm, {
287
604
  expect(content).not.toContain("claimReviewLease: v.object({})");
288
605
  });
289
606
  test("generates validators for object intersections", async () => {
290
- writeFileSync(join(testDir, "models/agent.ts"), `
607
+ writeFileSync(join(testDir, "agent/mutations.ts"), `
291
608
  import { mutations, serverWhere } from 'on-zero'
292
609
 
293
610
  const perm = serverWhere('agent', () => true)
@@ -320,7 +637,7 @@ export const mutate = mutations('agent', perm, {
320
637
  expect(content).not.toContain("[key");
321
638
  });
322
639
  test("uses v.unknown for untyped mutation payloads", async () => {
323
- writeFileSync(join(testDir, "models/project.ts"), `
640
+ writeFileSync(join(testDir, "project/mutations.ts"), `
324
641
  import { mutations, serverWhere } from 'on-zero'
325
642
 
326
643
  const perm = serverWhere('project', () => true)
@@ -340,7 +657,7 @@ export const mutate = mutations('project', perm, {
340
657
  expect(content).not.toContain("insert: v.void_()");
341
658
  });
342
659
  test("handles mutations with only context param (void)", async () => {
343
- writeFileSync(join(testDir, "models/user.ts"), `
660
+ writeFileSync(join(testDir, "user/mutations.ts"), `
344
661
  import { table, string } from 'on-zero'
345
662
  import { mutations, serverWhere } from 'on-zero'
346
663
 
@@ -365,7 +682,7 @@ export const mutate = mutations(schema, perm, {
365
682
  expect(content).toContain("finishOnboarding");
366
683
  });
367
684
  test("handles primitive param type", async () => {
368
- writeFileSync(join(testDir, "models/user.ts"), `
685
+ writeFileSync(join(testDir, "user/mutations.ts"), `
369
686
  import { table, string } from 'on-zero'
370
687
  import { mutations, serverWhere } from 'on-zero'
371
688
 
@@ -391,7 +708,7 @@ export const mutate = mutations(schema, perm, {
391
708
  expect(content).toContain("v.string()");
392
709
  });
393
710
  test("handles array param type", async () => {
394
- writeFileSync(join(testDir, "models/batch.ts"), `
711
+ writeFileSync(join(testDir, "batch/mutations.ts"), `
395
712
  import { mutations } from 'on-zero'
396
713
 
397
714
  export const mutate = mutations({
@@ -409,7 +726,7 @@ export const mutate = mutations({
409
726
  expect(content).toContain("v.array");
410
727
  });
411
728
  test("populates mutationCount and caching works", async () => {
412
- writeFileSync(join(testDir, "models/item.ts"), `
729
+ writeFileSync(join(testDir, "item/mutations.ts"), `
413
730
  import { table, string } from 'on-zero'
414
731
  import { mutations, serverWhere } from 'on-zero'
415
732
 
@@ -441,14 +758,14 @@ export const mutate = mutations(schema, perm, {
441
758
  });
442
759
  describe("type resolution", () => {
443
760
  test("resolves imported type references for mutations", async () => {
444
- writeFileSync(join(testDir, "models/types.ts"), `
761
+ writeFileSync(join(testDir, "post/types.ts"), `
445
762
  export type ArchiveParams = {
446
763
  id: string
447
764
  reason: string
448
765
  archived: boolean
449
766
  }
450
767
  `);
451
- writeFileSync(join(testDir, "models/post.ts"), `
768
+ writeFileSync(join(testDir, "post/mutations.ts"), `
452
769
  import { table, string, boolean } from 'on-zero'
453
770
  import { mutations } from 'on-zero'
454
771
  import type { ArchiveParams } from './types'
@@ -470,7 +787,7 @@ export const mutate = mutations({
470
787
  expect(content).toContain("archived");
471
788
  });
472
789
  test("resolves utility types like Pick", async () => {
473
- writeFileSync(join(testDir, "models/types.ts"), `
790
+ writeFileSync(join(testDir, "item/types.ts"), `
474
791
  export type Item = {
475
792
  id: string
476
793
  name: string
@@ -478,7 +795,7 @@ export type Item = {
478
795
  count: number
479
796
  }
480
797
  `);
481
- writeFileSync(join(testDir, "models/item.ts"), `
798
+ writeFileSync(join(testDir, "item/mutations.ts"), `
482
799
  import { table, string, number } from 'on-zero'
483
800
  import { mutations, serverWhere } from 'on-zero'
484
801
  import type { Item } from './types'
@@ -509,8 +826,8 @@ export const mutate = mutations(schema, perm, {
509
826
  expect(content).not.toMatch(/rename:[\s\S]*count/);
510
827
  });
511
828
  test("resolves instantiated Zero row fields through Partial and Omit", async () => {
512
- symlinkSync(join(import.meta.dirname, "../../../node_modules"), join(testDir, "node_modules"), "dir");
513
- writeFileSync(join(testDir, "models/types.ts"), `
829
+ symlinkSync(join(import.meta.dirname, "../node_modules"), join(testDir, "node_modules"), "dir");
830
+ writeFileSync(join(testDir, "item/types.ts"), `
514
831
  import type { Row } from '@rocicorp/zero'
515
832
  import { drizzleZeroConfig } from 'drizzle-zero-sqlite'
516
833
  import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
@@ -524,7 +841,7 @@ const schema = drizzleZeroConfig({ item })
524
841
 
525
842
  export type Item = Row<(typeof schema)['tables']['item']>
526
843
  `);
527
- writeFileSync(join(testDir, "models/item.ts"), `
844
+ writeFileSync(join(testDir, "item/mutations.ts"), `
528
845
  import { mutations } from 'on-zero'
529
846
  import type { Item } from './types'
530
847
 
@@ -547,13 +864,13 @@ export const mutate = mutations('item', {
547
864
  expect(content).not.toContain("description: v.optional(v.unknown())");
548
865
  });
549
866
  test("skips symbol-keyed properties when resolving imported mutation param types", async () => {
550
- writeFileSync(join(testDir, "models/types.ts"), `
867
+ writeFileSync(join(testDir, "item/types.ts"), `
551
868
  export type WeirdParams = {
552
869
  id: string
553
870
  [Symbol.iterator]?: () => Iterator<string>
554
871
  }
555
872
  `);
556
- writeFileSync(join(testDir, "models/item.ts"), `
873
+ writeFileSync(join(testDir, "item/mutations.ts"), `
557
874
  import { mutations } from 'on-zero'
558
875
  import type { WeirdParams } from './types'
559
876
 
@@ -573,14 +890,14 @@ export const mutate = mutations({
573
890
  expect(content).not.toContain("__@iterator");
574
891
  });
575
892
  test("resolves imported types in query params", async () => {
576
- writeFileSync(join(testDir, "models/post.ts"), `export const schema = table('post', { id: string() })`);
577
- writeFileSync(join(testDir, "queries/types.ts"), `
893
+ writeFileSync(join(testDir, "post/mutations.ts"), `export const schema = table('post', { id: string() })`);
894
+ writeFileSync(join(testDir, "post/types.ts"), `
578
895
  export type PostFilter = {
579
896
  authorId: string
580
897
  published: boolean
581
898
  }
582
899
  `);
583
- writeFileSync(join(testDir, "queries/post.ts"), `
900
+ writeFileSync(join(testDir, "post/queries.ts"), `
584
901
  import type { PostFilter } from './types'
585
902
 
586
903
  export const filteredPosts = (filter: PostFilter) => zero.query.post