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
@@ -16,6 +16,7 @@
16
16
 
17
17
  import {
18
18
  generateGroupedQueriesFile,
19
+ generateInstancesFile,
19
20
  generateModelsFile,
20
21
  generateReadmeFile,
21
22
  generateSyncedMutationsFile,
@@ -25,11 +26,12 @@ import {
25
26
  parseColumnType,
26
27
  parseTypeString,
27
28
  } from './generate-helpers'
29
+
28
30
  import type { ModelMutations, SchemaColumn } from './generate-helpers'
29
31
 
30
32
  // public types
31
33
 
32
- // minimal ast info about a single mutation handler file (e.g. `models/post.ts`)
34
+ // minimal ast info about a namespace mutation module (e.g. `post/mutations.ts`)
33
35
  export type LiteMutationExport = {
34
36
  // the first arg to `mutations('NAME', ...)` — string literal from the source.
35
37
  // not currently emitted anywhere in the output; the model file basename is
@@ -69,6 +71,31 @@ export type LiteQueryExport = {
69
71
  // e.g. 'string' | '{ id: string }' | null. null means the query takes no
70
72
  // args and is treated as a void query in the generated output.
71
73
  paramTypeText: string | null
74
+ // relation-name paths starting at this namespace's table. nested related()
75
+ // calls are one path, e.g. [['comments', 'author']].
76
+ relatedPaths?: string[][]
77
+ }
78
+
79
+ export type LiteRelationInfo = {
80
+ sourceTable: string
81
+ name: string
82
+ targetTable: string
83
+ }
84
+
85
+ export type LiteTableInfo = {
86
+ name: string
87
+ columns: string[]
88
+ }
89
+
90
+ export type LiteDataConfig = {
91
+ instances: Record<
92
+ string,
93
+ {
94
+ dir?: string
95
+ scope?: string
96
+ supportTables?: string[]
97
+ }
98
+ >
72
99
  }
73
100
 
74
101
  // what the caller returns for each source file.
@@ -77,6 +104,17 @@ export type LiteParsedFile = {
77
104
  // keeps the shape uniform and leaves room for future multi-export support.
78
105
  mutations: LiteMutationExport[]
79
106
  queries: LiteQueryExport[]
107
+ relations?: LiteRelationInfo[]
108
+ tables?: LiteTableInfo[]
109
+ // static table names reached through tx.mutate.<table> or tx.query.<table>.
110
+ // element access such as tx.mutate[name] is intentionally omitted.
111
+ supportTables?: string[]
112
+ // static import/export module specifiers used to follow mutation helpers.
113
+ imports?: string[]
114
+ // present only for an on-zero.config.ts default defineConfig export.
115
+ dataConfig?: LiteDataConfig
116
+ // parser syntax failure. the membership pass warns and ignores this file.
117
+ parseError?: string
80
118
  }
81
119
 
82
120
  // the parser function signature the caller provides. pure: given source text
@@ -84,18 +122,14 @@ export type LiteParsedFile = {
84
122
  export type LiteParseFn = (sourceCode: string, filePath: string) => LiteParsedFile
85
123
 
86
124
  export type LiteGenerateOptions = {
87
- // file path → source content. paths are treated as opaque keys; generate-lite
88
- // matches them by prefix against `{dir}/{modelsDir}/` and `{dir}/queries/`
89
- // using forward-slash string comparison. pass whatever path shape you have
90
- // (absolute, virtual, etc.), as long as you're consistent with `dir`.
125
+ // file path → source content. pass whatever path shape you have (absolute,
126
+ // virtual, etc.), as long as you're consistent with `dir`.
91
127
  files: Record<string, string>
92
- // base data directory, e.g. '/proj/src/data'. generate-lite scans `files`
93
- // for keys matching `{dir}/{modelsDir}/*.ts` and `{dir}/queries/*.ts`.
128
+ // base data directory, e.g. '/proj/src/data'. namespaces are direct .ts
129
+ // files or folders with queries.ts / mutations.ts.
94
130
  dir: string
95
- // 'mutations' if `{dir}/mutations` exists, else 'models'. if the caller
96
- // knows, they pass it; else generate-lite infers it from the file keys
97
- // (prefers 'mutations' if any file is under it).
98
- modelsDir?: 'mutations' | 'models'
131
+ // explicit on-zero.config.ts path. auto-discovered in `dir` when omitted.
132
+ config?: string
99
133
  parse: LiteParseFn
100
134
  }
101
135
 
@@ -103,6 +137,10 @@ export type LiteGenerateResult = {
103
137
  // relative paths under `{dir}/generated/`, e.g. 'models.ts',
104
138
  // 'syncedMutations.ts'. callers decide where to write.
105
139
  files: Record<string, string>
140
+ // per-instance table membership, exactly as serialized into instances.ts.
141
+ // callers that need membership (e.g. a host deriving its Zero schema tables)
142
+ // read it here instead of re-parsing the emitted source.
143
+ instances: Array<{ name: string; syncTables: string[]; supportTables: string[] }>
106
144
  modelCount: number
107
145
  queryCount: number
108
146
  mutationCount: number
@@ -124,6 +162,35 @@ function baseName(path: string, ext?: string): string {
124
162
  return base
125
163
  }
126
164
 
165
+ function resolvePath(path: string): string {
166
+ const absolute = path.startsWith('/')
167
+ const parts: string[] = []
168
+ for (const part of path.split('/')) {
169
+ if (!part || part === '.') continue
170
+ if (part === '..') parts.pop()
171
+ else parts.push(part)
172
+ }
173
+ return `${absolute ? '/' : ''}${parts.join('/')}`
174
+ }
175
+
176
+ function parentDir(path: string): string {
177
+ return path.slice(0, path.lastIndexOf('/'))
178
+ }
179
+
180
+ function relativePath(from: string, to: string): string {
181
+ const fromParts = resolvePath(from).split('/').filter(Boolean)
182
+ const toParts = resolvePath(to).split('/').filter(Boolean)
183
+ let common = 0
184
+ while (fromParts[common] === toParts[common] && common < fromParts.length) common++
185
+ return [
186
+ ...Array.from({ length: fromParts.length - common }, () => '..'),
187
+ ...toParts.slice(common),
188
+ ].join('/')
189
+ }
190
+
191
+ const isWithin = (root: string, path: string) =>
192
+ path === root || path.startsWith(`${root}/`)
193
+
127
194
  // returns files whose path is an immediate child of `dirPrefix` and ends in
128
195
  // `.ts` (but not `.d.ts`, test files, or anything nested further down).
129
196
  function listDirectTsFiles(files: Record<string, string>, dirPrefix: string): string[] {
@@ -142,35 +209,261 @@ function listDirectTsFiles(files: Record<string, string>, dirPrefix: string): st
142
209
  return out.sort()
143
210
  }
144
211
 
212
+ type LiteNamespace = {
213
+ name: string
214
+ instance: string
215
+ queryPath: string | null
216
+ modelPath: string | null
217
+ }
218
+
219
+ type LiteInstance = {
220
+ name: string
221
+ dir: string
222
+ scope: string | null
223
+ declaredSupportTables: string[]
224
+ namespaces: LiteNamespace[]
225
+ }
226
+
227
+ function discoverLiteLayout(
228
+ files: Record<string, string>,
229
+ baseDir: string,
230
+ parse: LiteParseFn,
231
+ explicitConfigPath?: string
232
+ ) {
233
+ const paths = Object.keys(files)
234
+ const configPath = resolvePath(explicitConfigPath ?? `${baseDir}/on-zero.config.ts`)
235
+ const configSource = files[configPath]
236
+ let config: LiteDataConfig | undefined
237
+ if (configSource !== undefined) {
238
+ const parsed = parse(configSource, configPath)
239
+ if (parsed.parseError) {
240
+ throw new Error(`[on-zero] unable to parse ${configPath}: ${parsed.parseError}`)
241
+ }
242
+ config = parsed.dataConfig
243
+ if (!config) {
244
+ throw new Error(
245
+ `[on-zero] ${configPath} must default export defineConfig({ instances: { ... } })`
246
+ )
247
+ }
248
+ } else if (explicitConfigPath) {
249
+ throw new Error(`[on-zero] config file does not exist: ${configPath}`)
250
+ }
251
+ if (explicitConfigPath && parentDir(configPath) !== baseDir) {
252
+ throw new Error(`[on-zero] ${configPath} must be at the data root ${baseDir}`)
253
+ }
254
+
255
+ const instances: LiteInstance[] = config
256
+ ? Object.entries(config.instances).map(([name, options]) => {
257
+ if (options.dir?.startsWith('/')) {
258
+ throw new Error(
259
+ `[on-zero] instance '${name}' dir must be relative to ${configPath}`
260
+ )
261
+ }
262
+ if (options.scope === '') {
263
+ throw new Error(`[on-zero] instance '${name}' scope cannot be empty`)
264
+ }
265
+ if (options.supportTables?.some((table) => table === '')) {
266
+ throw new Error(
267
+ `[on-zero] instance '${name}' supportTables cannot contain an empty table name`
268
+ )
269
+ }
270
+ return {
271
+ name,
272
+ dir: resolvePath(`${parentDir(configPath)}/${options.dir ?? name}`),
273
+ scope: options.scope ?? null,
274
+ declaredSupportTables: [...(options.supportTables ?? [])],
275
+ namespaces: [],
276
+ }
277
+ })
278
+ : [
279
+ {
280
+ name: 'default',
281
+ dir: baseDir,
282
+ scope: null,
283
+ declaredSupportTables: [],
284
+ namespaces: [],
285
+ },
286
+ ]
287
+ if (config && instances.length === 0) {
288
+ throw new Error(`[on-zero] ${configPath} must declare at least one instance`)
289
+ }
290
+ for (const instance of instances) {
291
+ if (!paths.some((path) => isWithin(instance.dir, path))) {
292
+ throw new Error(
293
+ `[on-zero] instance '${instance.name}' directory does not exist: ${instance.dir}`
294
+ )
295
+ }
296
+ const duplicate = instances.find(
297
+ (candidate) => candidate !== instance && candidate.dir === instance.dir
298
+ )
299
+ if (duplicate) {
300
+ throw new Error(
301
+ `[on-zero] instances '${instance.name}' and '${duplicate.name}' resolve to the same directory: ${instance.dir}`
302
+ )
303
+ }
304
+ }
305
+ const instanceDirs = new Set(instances.map((instance) => instance.dir))
306
+ const sourceRoots = [baseDir, ...instances.map((instance) => instance.dir)]
307
+ const remnant = paths.find(
308
+ (path) =>
309
+ baseName(path) === 'instance.ts' && sourceRoots.some((root) => isWithin(root, path))
310
+ )
311
+ if (remnant) {
312
+ throw new Error(
313
+ `[on-zero] ${remnant} uses removed instance.ts configuration; delete it and configure instances in on-zero.config.ts`
314
+ )
315
+ }
316
+
317
+ const parseDataFile = (path: string): LiteParsedFile | null => {
318
+ let parsed: LiteParsedFile
319
+ try {
320
+ parsed = parse(files[path]!, path)
321
+ } catch {
322
+ console.warn(
323
+ `[on-zero] ignoring ${path.slice(baseDir.lastIndexOf('/') + 1)}: no recognized data exports`
324
+ )
325
+ return null
326
+ }
327
+ if (parsed.parseError) {
328
+ console.warn(
329
+ `[on-zero] ignoring ${path.slice(baseDir.lastIndexOf('/') + 1)}: no recognized data exports`
330
+ )
331
+ return null
332
+ }
333
+ return parsed
334
+ }
335
+ const hasDataExport = (source: string, parsed: LiteParsedFile) =>
336
+ parsed.queries.length > 0 ||
337
+ parsed.mutations.length > 0 ||
338
+ (parsed.tables?.length ?? 0) > 0 ||
339
+ /export\s+const\s+(?:mutate|schema|where)\s*=\s*(?:mutations|serverWhere|table)\s*\(/.test(
340
+ source
341
+ )
342
+
343
+ if (config) {
344
+ for (const path of paths) {
345
+ if (
346
+ path === configPath ||
347
+ !isWithin(baseDir, path) ||
348
+ instances.some((instance) => isWithin(instance.dir, path)) ||
349
+ isWithin(`${baseDir}/generated`, path) ||
350
+ !path.endsWith('.ts') ||
351
+ path.endsWith('.d.ts') ||
352
+ path.endsWith('.test.ts') ||
353
+ path.endsWith('.spec.ts') ||
354
+ baseName(path) === 'instance.ts'
355
+ ) {
356
+ continue
357
+ }
358
+ const parsed = parseDataFile(path)
359
+ if (parsed && hasDataExport(files[path]!, parsed)) {
360
+ throw new Error(
361
+ `[on-zero] data namespace ${path} is outside every instance directory declared in ${configPath}`
362
+ )
363
+ }
364
+ }
365
+ }
366
+
367
+ for (const instance of instances) {
368
+ const directFiles = listDirectTsFiles(files, instance.dir).filter(
369
+ (path) => baseName(path) !== 'on-zero.config.ts'
370
+ )
371
+ for (const path of directFiles) {
372
+ const source = files[path]!
373
+ const parsed = parseDataFile(path)
374
+ if (!parsed || !hasDataExport(source, parsed)) continue
375
+ instance.namespaces.push({
376
+ name: baseName(path, '.ts'),
377
+ instance: instance.name,
378
+ queryPath: path,
379
+ modelPath: path,
380
+ })
381
+ }
382
+
383
+ const prefix = `${instance.dir}/`
384
+ const folders = new Set<string>()
385
+ for (const path of paths) {
386
+ if (!path.startsWith(prefix)) continue
387
+ const rest = path.slice(prefix.length)
388
+ const slash = rest.indexOf('/')
389
+ if (slash > 0) folders.add(`${instance.dir}/${rest.slice(0, slash)}`)
390
+ }
391
+ for (const folder of [...folders].sort()) {
392
+ if (folder === `${baseDir}/generated` || instanceDirs.has(folder)) continue
393
+ const queries = `${folder}/queries.ts`
394
+ const mutations = `${folder}/mutations.ts`
395
+ if (!(queries in files) && !(mutations in files)) {
396
+ const oldName = baseName(folder)
397
+ if (
398
+ ['models', 'mutations', 'queries'].includes(oldName) &&
399
+ listDirectTsFiles(files, folder).length > 0
400
+ ) {
401
+ throw new Error(
402
+ `[on-zero] ${folder} uses the removed top-level ${oldName}/ layout; ` +
403
+ `move each namespace to <name>.ts or <name>/queries.ts + mutations.ts`
404
+ )
405
+ }
406
+ continue
407
+ }
408
+ instance.namespaces.push({
409
+ name: baseName(folder),
410
+ instance: instance.name,
411
+ queryPath: queries in files ? queries : null,
412
+ modelPath: mutations in files ? mutations : null,
413
+ })
414
+ }
415
+ }
416
+
417
+ const owners = new Map<string, string>()
418
+ for (const namespace of instances.flatMap((instance) => instance.namespaces)) {
419
+ const owner = owners.get(namespace.name)
420
+ if (owner) {
421
+ throw new Error(
422
+ `[on-zero] namespace '${namespace.name}' is claimed by instances '${owner}' and '${namespace.instance}'`
423
+ )
424
+ }
425
+ owners.set(namespace.name, namespace.instance)
426
+ }
427
+ return instances
428
+ }
429
+
145
430
  // main entry point
146
431
 
147
432
  export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
148
433
  const { files, parse } = opts
149
- const baseDir = stripTrailingSlash(opts.dir)
150
-
151
- // determine models dir (mutations vs models)
152
- let modelsDirName: 'mutations' | 'models'
153
- if (opts.modelsDir) {
154
- modelsDirName = opts.modelsDir
155
- } else {
156
- // infer: prefer 'mutations' if any file lives under {dir}/mutations/
157
- const mutationsPrefix = `${baseDir}/mutations/`
158
- const hasMutationsDir = Object.keys(files).some((p) => p.startsWith(mutationsPrefix))
159
- modelsDirName = hasMutationsDir ? 'mutations' : 'models'
434
+ const baseDir = resolvePath(stripTrailingSlash(opts.dir))
435
+ const instances = discoverLiteLayout(files, baseDir, parse, opts.config)
436
+ const sourceRoots = [baseDir, ...instances.map((instance) => instance.dir)]
437
+ const namespaces = instances.flatMap((instance) => instance.namespaces)
438
+ const modelNamespaces = namespaces.filter(
439
+ (namespace): namespace is LiteNamespace & { modelPath: string } =>
440
+ namespace.modelPath !== null
441
+ )
442
+ const relations = new Map<string, Map<string, string>>()
443
+ const tableColumns = new Map<string, Set<string>>()
444
+ for (const path of Object.keys(files).filter(
445
+ (path) =>
446
+ path.endsWith('/relations.ts') ||
447
+ /\/database\/(?:schema[^/]*|zeroSchemaInput)\.ts$/.test(path)
448
+ )) {
449
+ const parsed = parse(files[path]!, path)
450
+ for (const relation of parsed.relations ?? []) {
451
+ const tableRelations = relations.get(relation.sourceTable) ?? new Map()
452
+ tableRelations.set(relation.name, relation.targetTable)
453
+ relations.set(relation.sourceTable, tableRelations)
454
+ }
455
+ for (const table of parsed.tables ?? []) {
456
+ tableColumns.set(table.name, new Set(table.columns))
457
+ }
160
458
  }
161
459
 
162
- const modelsDirPath = `${baseDir}/${modelsDirName}`
163
- const queriesDirPath = `${baseDir}/queries`
164
-
165
- const modelFilePaths = listDirectTsFiles(files, modelsDirPath)
166
- const queryFilePaths = listDirectTsFiles(files, queriesDirPath)
167
-
168
460
  // parse each model file and build ModelMutations records for the emitter
169
461
  const allModelMutations: ModelMutations[] = []
170
462
  const modelNamesWithSchema: string[] = []
171
463
 
172
- for (const filePath of modelFilePaths) {
173
- const modelName = baseName(filePath, '.ts')
464
+ for (const namespace of modelNamespaces) {
465
+ const filePath = namespace.modelPath
466
+ const modelName = namespace.name
174
467
  const content = files[filePath]!
175
468
  const parsed = parse(content, filePath)
176
469
 
@@ -189,6 +482,9 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
189
482
  for (const col of mutationExport.schema.columns) {
190
483
  columns[col.name] = parseColumnType(col.builderText)
191
484
  }
485
+ const names = new Set(mutationExport.schema.columns.map((column) => column.name))
486
+ tableColumns.set(modelName, names)
487
+ tableColumns.set(mutationExport.schema.tableName, names)
192
488
  }
193
489
 
194
490
  // a model participates in crud only when it has a schema AND its mutate
@@ -246,16 +542,34 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
246
542
  params: string
247
543
  valibotCode: string
248
544
  sourceFile: string
545
+ importPath: string
249
546
  }> = []
250
-
251
- for (const filePath of queryFilePaths) {
252
- const fileBaseName = baseName(filePath, '.ts')
547
+ const relatedPaths = new Map<string, Array<{ query: string; paths: string[][] }>>()
548
+
549
+ for (const namespace of namespaces.filter(
550
+ (namespace): namespace is LiteNamespace & { queryPath: string } =>
551
+ namespace.queryPath !== null
552
+ )) {
553
+ const filePath = namespace.queryPath
554
+ const fileBaseName = namespace.name
253
555
  const content = files[filePath]!
254
556
  const parsed = parse(content, filePath)
557
+ if (
558
+ content.includes('.related(') &&
559
+ !parsed.queries.some((query) => query.relatedPaths)
560
+ ) {
561
+ throw new Error(
562
+ `[on-zero] ${filePath} uses related(), but the lite parser did not return relatedPaths`
563
+ )
564
+ }
255
565
 
256
566
  for (const q of parsed.queries) {
257
- // permission exports are filtered upstream in existing behavior
258
- if (q.name === 'permission') continue
567
+ if (['mutate', 'permission', 'schema', 'where'].includes(q.name)) continue
568
+ if (q.relatedPaths?.length) {
569
+ const entries = relatedPaths.get(namespace.name) ?? []
570
+ entries.push({ query: q.name, paths: q.relatedPaths })
571
+ relatedPaths.set(namespace.name, entries)
572
+ }
259
573
 
260
574
  // null annotation → no first arg → void query
261
575
  if (q.paramTypeText == null) {
@@ -264,6 +578,7 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
264
578
  params: 'void',
265
579
  valibotCode: '',
266
580
  sourceFile: fileBaseName,
581
+ importPath: `../${relativePath(baseDir, filePath).replace(/\.ts$/, '')}`,
267
582
  })
268
583
  continue
269
584
  }
@@ -287,27 +602,143 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
287
602
  params: paramType,
288
603
  valibotCode: valibotCode ?? 'v.unknown()',
289
604
  sourceFile: fileBaseName,
605
+ importPath: `../${relativePath(baseDir, filePath).replace(/\.ts$/, '')}`,
290
606
  })
291
607
  }
292
608
  }
293
609
 
610
+ const owners = new Map(
611
+ namespaces.map((namespace) => [namespace.name, namespace.instance])
612
+ )
613
+ const relatedOwners = new Map<string, string>()
614
+ const syncTables = new Map<string, string[]>()
615
+ for (const instance of instances) {
616
+ const synced = new Set(instance.namespaces.map((namespace) => namespace.name))
617
+ for (const namespace of instance.namespaces) {
618
+ for (const query of relatedPaths.get(namespace.name) ?? []) {
619
+ for (const path of query.paths) {
620
+ let sourceTable = namespace.name
621
+ for (const relationName of path) {
622
+ const target = relations.get(sourceTable)?.get(relationName)
623
+ if (!target) {
624
+ throw new Error(
625
+ `[on-zero] ${namespace.name}.${query.query} related('${relationName}') cannot be resolved ` +
626
+ `from table '${sourceTable}' through relations.ts`
627
+ )
628
+ }
629
+ const owner = owners.get(target) ?? relatedOwners.get(target)
630
+ if (owner && owner !== instance.name) {
631
+ throw new Error(
632
+ `[on-zero] ${namespace.name}.${query.query} in instance '${instance.name}' reaches ` +
633
+ `table '${target}' owned by instance '${owner}'`
634
+ )
635
+ }
636
+ relatedOwners.set(target, instance.name)
637
+ synced.add(target)
638
+ sourceTable = target
639
+ }
640
+ }
641
+ }
642
+ }
643
+ const tables = [...synced].sort()
644
+ if (instance.scope) {
645
+ for (const table of tables) {
646
+ if (!tableColumns.get(table)?.has(instance.scope)) {
647
+ throw new Error(
648
+ `[on-zero] table '${table}' in instance '${instance.name}' is missing scope column '${instance.scope}'`
649
+ )
650
+ }
651
+ }
652
+ }
653
+ syncTables.set(instance.name, tables)
654
+ }
655
+
656
+ const supportTables = new Map<string, string[]>()
657
+ for (const instance of instances) {
658
+ const supported = new Set<string>(instance.declaredSupportTables)
659
+ for (const namespace of instance.namespaces) {
660
+ if (!namespace.modelPath) continue
661
+ const visited = new Set<string>()
662
+ const scan = (path: string) => {
663
+ if (visited.has(path)) return
664
+ visited.add(path)
665
+ const parsed = parse(files[path]!, path)
666
+ if (parsed.parseError) {
667
+ throw new Error(
668
+ `[on-zero] unable to derive mutation dependencies from ${path}: ${parsed.parseError}`
669
+ )
670
+ }
671
+ for (const table of parsed.supportTables ?? []) {
672
+ if (owners.has(table) || relatedOwners.has(table)) continue
673
+ if (!syncTables.get(instance.name)!.includes(table)) {
674
+ supported.add(table)
675
+ }
676
+ }
677
+ for (const specifier of parsed.imports ?? []) {
678
+ const unresolved = specifier.startsWith('~/data/')
679
+ ? `${baseDir}/${specifier.slice('~/data/'.length)}`
680
+ : specifier.startsWith('.')
681
+ ? `${parentDir(path)}/${specifier}`
682
+ : null
683
+ if (!unresolved) continue
684
+ const normalized = resolvePath(unresolved)
685
+ const dependency = [
686
+ normalized.endsWith('.ts') ? normalized : `${normalized}.ts`,
687
+ `${normalized}/index.ts`,
688
+ ].find(
689
+ (candidate) =>
690
+ candidate in files && sourceRoots.some((root) => isWithin(root, candidate))
691
+ )
692
+ if (dependency) scan(dependency)
693
+ }
694
+ }
695
+ scan(namespace.modelPath)
696
+ }
697
+ supportTables.set(instance.name, [...supported].sort())
698
+ }
699
+
294
700
  // emit files
295
- const modelNames = modelFilePaths.map((p) => baseName(p, '.ts'))
701
+ const modelNames = modelNamespaces.map((namespace) => namespace.name)
296
702
  const out: Record<string, string> = {}
297
703
 
298
- out['models.ts'] = generateModelsFile(modelNames, modelsDirName)
704
+ out['models.ts'] = generateModelsFile(
705
+ modelNamespaces.map((namespace) => ({
706
+ name: namespace.name,
707
+ importPath: `../${relativePath(baseDir, namespace.modelPath).replace(/\.ts$/, '')}`,
708
+ }))
709
+ )
299
710
 
300
711
  if (modelNamesWithSchema.length > 0) {
301
712
  out['types.ts'] = generateTypesFile(modelNamesWithSchema)
302
- out['tables.ts'] = generateTablesFile(modelNamesWithSchema, modelsDirName)
713
+ out['tables.ts'] = generateTablesFile(
714
+ modelNamespaces
715
+ .filter((namespace) => modelNamesWithSchema.includes(namespace.name))
716
+ .map((namespace) => ({
717
+ name: namespace.name,
718
+ importPath: `../${relativePath(baseDir, namespace.modelPath).replace(/\.ts$/, '')}`,
719
+ }))
720
+ )
303
721
  }
304
722
 
305
723
  out['README.md'] = generateReadmeFile()
306
724
 
307
- if (queryFilePaths.length > 0) {
308
- out['groupedQueries.ts'] = generateGroupedQueriesFile(allQueries)
309
- out['syncedQueries.ts'] = generateSyncedQueriesFile(allQueries)
310
- }
725
+ out['groupedQueries.ts'] = generateGroupedQueriesFile(allQueries)
726
+ out['syncedQueries.ts'] = generateSyncedQueriesFile(allQueries)
727
+ out['instances.ts'] = generateInstancesFile(
728
+ instances.map((instance) => ({
729
+ name: instance.name,
730
+ scope: instance.scope,
731
+ queryNames: instance.namespaces
732
+ .map((namespace) => namespace.name)
733
+ .filter((name) => allQueries.some((query) => query.sourceFile === name)),
734
+ modelNames: instance.namespaces
735
+ .filter((namespace) => namespace.modelPath)
736
+ .map((namespace) => namespace.name),
737
+ tables: instance.namespaces.map((namespace) => namespace.name),
738
+ syncTables: syncTables.get(instance.name)!,
739
+ supportTables: supportTables.get(instance.name)!,
740
+ }))
741
+ )
311
742
 
312
743
  if (allModelMutations.length > 0) {
313
744
  out['syncedMutations.ts'] = generateSyncedMutationsFile(allModelMutations)
@@ -319,12 +750,17 @@ export function generateLite(opts: LiteGenerateOptions): LiteGenerateResult {
319
750
  for (const m of allModelMutations) {
320
751
  if (m.hasCRUD) mutationCount += 3
321
752
  mutationCount += m.custom.filter(
322
- (mut) => !m.hasCRUD || !['insert', 'update', 'delete', 'upsert'].includes(mut.name),
753
+ (mut) => !m.hasCRUD || !['insert', 'update', 'delete', 'upsert'].includes(mut.name)
323
754
  ).length
324
755
  }
325
756
 
326
757
  return {
327
758
  files: out,
759
+ instances: instances.map((instance) => ({
760
+ name: instance.name,
761
+ syncTables: syncTables.get(instance.name)!,
762
+ supportTables: supportTables.get(instance.name)!,
763
+ })),
328
764
  modelCount: modelNames.length,
329
765
  queryCount: allQueries.length,
330
766
  mutationCount,