on-zero 0.7.10 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. package/{readme.md → README.md} +172 -231
  2. package/dist/cjs/cli.cjs +5 -2
  3. package/dist/cjs/cli.native.js +5 -2
  4. package/dist/cjs/cli.native.js.map +1 -1
  5. package/dist/cjs/combineZeroClients.cjs +2 -2
  6. package/dist/cjs/combineZeroClients.native.js +6 -6
  7. package/dist/cjs/combineZeroClients.native.js.map +1 -1
  8. package/dist/cjs/config.cjs +30 -0
  9. package/dist/cjs/config.native.js +33 -0
  10. package/dist/cjs/config.native.js.map +1 -0
  11. package/dist/cjs/createPermissions.cjs +2 -2
  12. package/dist/cjs/createPermissions.native.js +17 -27
  13. package/dist/cjs/createPermissions.native.js.map +1 -1
  14. package/dist/cjs/createUseQuery.cjs +3 -3
  15. package/dist/cjs/createUseQuery.native.js +4 -4
  16. package/dist/cjs/createUseQuery.native.js.map +1 -1
  17. package/dist/cjs/createUseQueryDirect.cjs +4 -3
  18. package/dist/cjs/createUseQueryDirect.native.js +14 -18
  19. package/dist/cjs/createUseQueryDirect.native.js.map +1 -1
  20. package/dist/cjs/createZeroClient.cjs +29 -9
  21. package/dist/cjs/createZeroClient.connection.test.cjs +11 -0
  22. package/dist/cjs/createZeroClient.connection.test.native.js +14 -7
  23. package/dist/cjs/createZeroClient.connection.test.native.js.map +1 -1
  24. package/dist/cjs/createZeroClient.native.js +58 -32
  25. package/dist/cjs/createZeroClient.native.js.map +1 -1
  26. package/dist/cjs/createZeroClient.recovery.test.cjs +90 -3
  27. package/dist/cjs/createZeroClient.recovery.test.native.js +109 -19
  28. package/dist/cjs/createZeroClient.recovery.test.native.js.map +1 -1
  29. package/dist/cjs/generate-helpers.cjs +70 -17
  30. package/dist/cjs/generate-helpers.native.js +110 -23
  31. package/dist/cjs/generate-helpers.native.js.map +1 -1
  32. package/dist/cjs/generate-layout.cjs +586 -0
  33. package/dist/cjs/generate-layout.native.js +1275 -0
  34. package/dist/cjs/generate-layout.native.js.map +1 -0
  35. package/dist/cjs/generate-lite.cjs +295 -27
  36. package/dist/cjs/generate-lite.native.js +854 -102
  37. package/dist/cjs/generate-lite.native.js.map +1 -1
  38. package/dist/cjs/generate-lite.test.cjs +433 -41
  39. package/dist/cjs/generate-lite.test.native.js +446 -41
  40. package/dist/cjs/generate-lite.test.native.js.map +1 -1
  41. package/dist/cjs/generate.cjs +172 -94
  42. package/dist/cjs/generate.native.js +324 -148
  43. package/dist/cjs/generate.native.js.map +1 -1
  44. package/dist/cjs/generate.test.cjs +362 -45
  45. package/dist/cjs/generate.test.native.js +374 -45
  46. package/dist/cjs/generate.test.native.js.map +1 -1
  47. package/dist/cjs/helpers/NullToOptional.cjs +18 -0
  48. package/dist/cjs/helpers/NullToOptional.native.js +21 -0
  49. package/dist/cjs/helpers/NullToOptional.native.js.map +1 -0
  50. package/dist/cjs/helpers/asyncContext.cjs +128 -0
  51. package/dist/cjs/helpers/asyncContext.native.js +87 -0
  52. package/dist/cjs/helpers/asyncContext.native.js.map +1 -0
  53. package/dist/cjs/helpers/batchQuery.cjs +2 -2
  54. package/dist/cjs/helpers/batchQuery.native.js +2 -2
  55. package/dist/cjs/helpers/batchQuery.native.js.map +1 -1
  56. package/dist/cjs/helpers/createMutators.cjs +7 -4
  57. package/dist/cjs/helpers/createMutators.native.js +12 -9
  58. package/dist/cjs/helpers/createMutators.native.js.map +1 -1
  59. package/dist/cjs/helpers/createMutators.test.native.js +2 -2
  60. package/dist/cjs/helpers/createMutators.test.native.js.map +1 -1
  61. package/dist/cjs/helpers/ellipsis.cjs +35 -0
  62. package/dist/cjs/helpers/ellipsis.native.js +38 -0
  63. package/dist/cjs/helpers/ellipsis.native.js.map +1 -0
  64. package/dist/cjs/helpers/emitter.cjs +99 -0
  65. package/dist/cjs/helpers/emitter.native.js +125 -0
  66. package/dist/cjs/helpers/emitter.native.js.map +1 -0
  67. package/dist/cjs/helpers/ensure.cjs +33 -0
  68. package/dist/cjs/helpers/ensure.native.js +37 -0
  69. package/dist/cjs/helpers/ensure.native.js.map +1 -0
  70. package/dist/cjs/helpers/ensureLoggedIn.cjs +2 -2
  71. package/dist/cjs/helpers/ensureLoggedIn.native.js +3 -3
  72. package/dist/cjs/helpers/ensureLoggedIn.native.js.map +1 -1
  73. package/dist/cjs/helpers/errors.cjs +40 -0
  74. package/dist/cjs/helpers/errors.native.js +152 -0
  75. package/dist/cjs/helpers/errors.native.js.map +1 -0
  76. package/dist/cjs/helpers/getCurrentComponentStack.cjs +71 -0
  77. package/dist/cjs/helpers/getCurrentComponentStack.native.js +93 -0
  78. package/dist/cjs/helpers/getCurrentComponentStack.native.js.map +1 -0
  79. package/dist/cjs/helpers/globalValue.cjs +39 -0
  80. package/dist/cjs/helpers/globalValue.native.js +42 -0
  81. package/dist/cjs/helpers/globalValue.native.js.map +1 -0
  82. package/dist/cjs/helpers/mapObject.cjs +36 -0
  83. package/dist/cjs/helpers/mapObject.native.js +39 -0
  84. package/dist/cjs/helpers/mapObject.native.js.map +1 -0
  85. package/dist/cjs/helpers/mutationLifecycle.cjs +251 -0
  86. package/dist/cjs/helpers/mutationLifecycle.native.js +392 -0
  87. package/dist/cjs/helpers/mutationLifecycle.native.js.map +1 -0
  88. package/dist/cjs/helpers/mutationLifecycle.test.cjs +174 -0
  89. package/dist/cjs/helpers/mutationLifecycle.test.native.js +182 -0
  90. package/dist/cjs/helpers/mutationLifecycle.test.native.js.map +1 -0
  91. package/dist/cjs/helpers/mutatorContext.cjs +3 -3
  92. package/dist/cjs/helpers/mutatorContext.native.js +5 -5
  93. package/dist/cjs/helpers/mutatorContext.native.js.map +1 -1
  94. package/dist/cjs/helpers/platform.cjs +31 -0
  95. package/dist/cjs/helpers/platform.native.js +33 -0
  96. package/dist/cjs/helpers/platform.native.js.map +1 -0
  97. package/dist/cjs/helpers/prettyFormatZeroQuery.cjs +2 -2
  98. package/dist/cjs/helpers/prettyFormatZeroQuery.native.js +7 -7
  99. package/dist/cjs/helpers/prettyFormatZeroQuery.native.js.map +1 -1
  100. package/dist/cjs/helpers/queryContext.cjs +2 -2
  101. package/dist/cjs/helpers/queryContext.native.js +4 -4
  102. package/dist/cjs/helpers/queryContext.native.js.map +1 -1
  103. package/dist/cjs/helpers/recoverZeroClient.cjs +14 -15
  104. package/dist/cjs/helpers/recoverZeroClient.native.js +26 -23
  105. package/dist/cjs/helpers/recoverZeroClient.native.js.map +1 -1
  106. package/dist/cjs/helpers/recoverZeroClient.test.cjs +10 -8
  107. package/dist/cjs/helpers/recoverZeroClient.test.native.js +17 -21
  108. package/dist/cjs/helpers/recoverZeroClient.test.native.js.map +1 -1
  109. package/dist/cjs/helpers/sleep.cjs +34 -0
  110. package/dist/cjs/helpers/sleep.native.js +39 -0
  111. package/dist/cjs/helpers/sleep.native.js.map +1 -0
  112. package/dist/cjs/helpers/time.cjs +47 -0
  113. package/dist/cjs/helpers/time.native.js +80 -0
  114. package/dist/cjs/helpers/time.native.js.map +1 -0
  115. package/dist/cjs/helpers/tuple.cjs +18 -0
  116. package/dist/cjs/helpers/tuple.native.js +21 -0
  117. package/dist/cjs/helpers/tuple.native.js.map +1 -0
  118. package/dist/cjs/helpers/useMutation.native.js +5 -5
  119. package/dist/cjs/helpers/useMutation.native.js.map +1 -1
  120. package/dist/cjs/helpers/useMutation.test.native.js +1 -1
  121. package/dist/cjs/helpers/useMutation.test.native.js.map +1 -1
  122. package/dist/cjs/helpers/useZeroDebug.cjs +2 -2
  123. package/dist/cjs/helpers/useZeroDebug.native.js +7 -8
  124. package/dist/cjs/helpers/useZeroDebug.native.js.map +1 -1
  125. package/dist/cjs/index.cjs +9 -1
  126. package/dist/cjs/index.native.js +8 -0
  127. package/dist/cjs/index.native.js.map +1 -1
  128. package/dist/cjs/instanceRegistry.cjs +16 -4
  129. package/dist/cjs/instanceRegistry.native.js +56 -6
  130. package/dist/cjs/instanceRegistry.native.js.map +1 -1
  131. package/dist/cjs/multi.cjs +34 -13
  132. package/dist/cjs/multi.native.js +39 -17
  133. package/dist/cjs/multi.native.js.map +1 -1
  134. package/dist/cjs/multiInstance.test.cjs +6 -2
  135. package/dist/cjs/multiInstance.test.native.js +13 -9
  136. package/dist/cjs/multiInstance.test.native.js.map +1 -1
  137. package/dist/cjs/multiInstanceNested.test.native.js +10 -10
  138. package/dist/cjs/multiInstanceNested.test.native.js.map +1 -1
  139. package/dist/cjs/multiPartition.test.cjs +85 -36
  140. package/dist/cjs/multiPartition.test.native.js +102 -39
  141. package/dist/cjs/multiPartition.test.native.js.map +1 -1
  142. package/dist/cjs/mutations.cjs +2 -2
  143. package/dist/cjs/mutations.native.js +4 -4
  144. package/dist/cjs/mutations.native.js.map +1 -1
  145. package/dist/cjs/mutations.test.native.js +3 -3
  146. package/dist/cjs/mutations.test.native.js.map +1 -1
  147. package/dist/cjs/provideZero.hydration.test.cjs +3 -3
  148. package/dist/cjs/provideZero.hydration.test.native.js +4 -4
  149. package/dist/cjs/provideZero.hydration.test.native.js.map +1 -1
  150. package/dist/cjs/run.cjs +1 -1
  151. package/dist/cjs/run.native.js +3 -3
  152. package/dist/cjs/run.native.js.map +1 -1
  153. package/dist/cjs/server.cjs +20 -16
  154. package/dist/cjs/server.native.js +50 -57
  155. package/dist/cjs/server.native.js.map +1 -1
  156. package/dist/cjs/server.test.cjs +129 -6
  157. package/dist/cjs/server.test.native.js +141 -10
  158. package/dist/cjs/server.test.native.js.map +1 -1
  159. package/dist/cjs/serverWhere.test.native.js +3 -3
  160. package/dist/cjs/serverWhere.test.native.js.map +1 -1
  161. package/dist/cjs/state.cjs +2 -2
  162. package/dist/cjs/state.native.js +10 -10
  163. package/dist/cjs/state.native.js.map +1 -1
  164. package/dist/cjs/usePermission.test.native.js +3 -3
  165. package/dist/cjs/usePermission.test.native.js.map +1 -1
  166. package/dist/cjs/useQuery.empty.test.cjs +3 -3
  167. package/dist/cjs/useQuery.empty.test.native.js +6 -6
  168. package/dist/cjs/useQuery.empty.test.native.js.map +1 -1
  169. package/dist/cjs/useQuery.ssr.test.native.js +2 -2
  170. package/dist/cjs/useQuery.ssr.test.native.js.map +1 -1
  171. package/dist/cjs/vite-plugin.cjs +7 -8
  172. package/dist/cjs/vite-plugin.native.js +11 -11
  173. package/dist/cjs/vite-plugin.native.js.map +1 -1
  174. package/dist/cjs/where.cjs +3 -3
  175. package/dist/cjs/where.native.js +4 -4
  176. package/dist/cjs/where.native.js.map +1 -1
  177. package/dist/esm/cli.mjs +6 -3
  178. package/dist/esm/cli.mjs.map +1 -1
  179. package/dist/esm/cli.native.js +6 -3
  180. package/dist/esm/cli.native.js.map +1 -1
  181. package/dist/esm/combineZeroClients.mjs +1 -1
  182. package/dist/esm/combineZeroClients.mjs.map +1 -1
  183. package/dist/esm/combineZeroClients.native.js +5 -5
  184. package/dist/esm/combineZeroClients.native.js.map +1 -1
  185. package/dist/esm/config.mjs +5 -0
  186. package/dist/esm/config.mjs.map +1 -0
  187. package/dist/esm/config.native.js +5 -0
  188. package/dist/esm/config.native.js.map +1 -0
  189. package/dist/esm/createPermissions.mjs +1 -1
  190. package/dist/esm/createPermissions.mjs.map +1 -1
  191. package/dist/esm/createPermissions.native.js +16 -26
  192. package/dist/esm/createPermissions.native.js.map +1 -1
  193. package/dist/esm/createUseQuery.mjs +2 -2
  194. package/dist/esm/createUseQuery.mjs.map +1 -1
  195. package/dist/esm/createUseQuery.native.js +3 -3
  196. package/dist/esm/createUseQuery.native.js.map +1 -1
  197. package/dist/esm/createUseQueryDirect.mjs +2 -1
  198. package/dist/esm/createUseQueryDirect.mjs.map +1 -1
  199. package/dist/esm/createUseQueryDirect.native.js +12 -16
  200. package/dist/esm/createUseQueryDirect.native.js.map +1 -1
  201. package/dist/esm/createZeroClient.connection.test.mjs +11 -0
  202. package/dist/esm/createZeroClient.connection.test.mjs.map +1 -1
  203. package/dist/esm/createZeroClient.connection.test.native.js +14 -7
  204. package/dist/esm/createZeroClient.connection.test.native.js.map +1 -1
  205. package/dist/esm/createZeroClient.mjs +25 -5
  206. package/dist/esm/createZeroClient.mjs.map +1 -1
  207. package/dist/esm/createZeroClient.native.js +54 -28
  208. package/dist/esm/createZeroClient.native.js.map +1 -1
  209. package/dist/esm/createZeroClient.recovery.test.mjs +90 -3
  210. package/dist/esm/createZeroClient.recovery.test.mjs.map +1 -1
  211. package/dist/esm/createZeroClient.recovery.test.native.js +109 -19
  212. package/dist/esm/createZeroClient.recovery.test.native.js.map +1 -1
  213. package/dist/esm/generate-helpers.mjs +70 -18
  214. package/dist/esm/generate-helpers.mjs.map +1 -1
  215. package/dist/esm/generate-helpers.native.js +110 -24
  216. package/dist/esm/generate-helpers.native.js.map +1 -1
  217. package/dist/esm/generate-layout.mjs +560 -0
  218. package/dist/esm/generate-layout.mjs.map +1 -0
  219. package/dist/esm/generate-layout.native.js +1246 -0
  220. package/dist/esm/generate-layout.native.js.map +1 -0
  221. package/dist/esm/generate-lite.mjs +296 -28
  222. package/dist/esm/generate-lite.mjs.map +1 -1
  223. package/dist/esm/generate-lite.native.js +855 -103
  224. package/dist/esm/generate-lite.native.js.map +1 -1
  225. package/dist/esm/generate-lite.test.mjs +434 -42
  226. package/dist/esm/generate-lite.test.mjs.map +1 -1
  227. package/dist/esm/generate-lite.test.native.js +447 -42
  228. package/dist/esm/generate-lite.test.native.js.map +1 -1
  229. package/dist/esm/generate.mjs +172 -96
  230. package/dist/esm/generate.mjs.map +1 -1
  231. package/dist/esm/generate.native.js +324 -150
  232. package/dist/esm/generate.native.js.map +1 -1
  233. package/dist/esm/generate.test.mjs +366 -49
  234. package/dist/esm/generate.test.mjs.map +1 -1
  235. package/dist/esm/generate.test.native.js +378 -49
  236. package/dist/esm/generate.test.native.js.map +1 -1
  237. package/dist/esm/helpers/NullToOptional.mjs +2 -0
  238. package/dist/esm/helpers/NullToOptional.mjs.map +1 -0
  239. package/dist/esm/helpers/NullToOptional.native.js +2 -0
  240. package/dist/esm/helpers/NullToOptional.native.js.map +1 -0
  241. package/dist/esm/helpers/asyncContext.mjs +102 -0
  242. package/dist/esm/helpers/asyncContext.mjs.map +1 -0
  243. package/dist/esm/helpers/asyncContext.native.js +58 -0
  244. package/dist/esm/helpers/asyncContext.native.js.map +1 -0
  245. package/dist/esm/helpers/batchQuery.mjs +1 -1
  246. package/dist/esm/helpers/batchQuery.native.js +1 -1
  247. package/dist/esm/helpers/createMutators.mjs +5 -2
  248. package/dist/esm/helpers/createMutators.mjs.map +1 -1
  249. package/dist/esm/helpers/createMutators.native.js +10 -7
  250. package/dist/esm/helpers/createMutators.native.js.map +1 -1
  251. package/dist/esm/helpers/createMutators.test.native.js +2 -2
  252. package/dist/esm/helpers/createMutators.test.native.js.map +1 -1
  253. package/dist/esm/helpers/ellipsis.mjs +10 -0
  254. package/dist/esm/helpers/ellipsis.mjs.map +1 -0
  255. package/dist/esm/helpers/ellipsis.native.js +10 -0
  256. package/dist/esm/helpers/ellipsis.native.js.map +1 -0
  257. package/dist/esm/helpers/emitter.mjs +72 -0
  258. package/dist/esm/helpers/emitter.mjs.map +1 -0
  259. package/dist/esm/helpers/emitter.native.js +95 -0
  260. package/dist/esm/helpers/emitter.native.js.map +1 -0
  261. package/dist/esm/helpers/ensure.mjs +8 -0
  262. package/dist/esm/helpers/ensure.mjs.map +1 -0
  263. package/dist/esm/helpers/ensure.native.js +9 -0
  264. package/dist/esm/helpers/ensure.native.js.map +1 -0
  265. package/dist/esm/helpers/ensureLoggedIn.mjs +1 -1
  266. package/dist/esm/helpers/ensureLoggedIn.mjs.map +1 -1
  267. package/dist/esm/helpers/ensureLoggedIn.native.js +2 -2
  268. package/dist/esm/helpers/ensureLoggedIn.native.js.map +1 -1
  269. package/dist/esm/helpers/errors.mjs +14 -0
  270. package/dist/esm/helpers/errors.mjs.map +1 -0
  271. package/dist/esm/helpers/errors.native.js +123 -0
  272. package/dist/esm/helpers/errors.native.js.map +1 -0
  273. package/dist/esm/helpers/getCurrentComponentStack.mjs +35 -0
  274. package/dist/esm/helpers/getCurrentComponentStack.mjs.map +1 -0
  275. package/dist/esm/helpers/getCurrentComponentStack.native.js +54 -0
  276. package/dist/esm/helpers/getCurrentComponentStack.native.js.map +1 -0
  277. package/dist/esm/helpers/globalValue.mjs +14 -0
  278. package/dist/esm/helpers/globalValue.mjs.map +1 -0
  279. package/dist/esm/helpers/globalValue.native.js +14 -0
  280. package/dist/esm/helpers/globalValue.native.js.map +1 -0
  281. package/dist/esm/helpers/mapObject.mjs +11 -0
  282. package/dist/esm/helpers/mapObject.mjs.map +1 -0
  283. package/dist/esm/helpers/mapObject.native.js +11 -0
  284. package/dist/esm/helpers/mapObject.native.js.map +1 -0
  285. package/dist/esm/helpers/mutationLifecycle.mjs +221 -0
  286. package/dist/esm/helpers/mutationLifecycle.mjs.map +1 -0
  287. package/dist/esm/helpers/mutationLifecycle.native.js +359 -0
  288. package/dist/esm/helpers/mutationLifecycle.native.js.map +1 -0
  289. package/dist/esm/helpers/mutationLifecycle.test.mjs +175 -0
  290. package/dist/esm/helpers/mutationLifecycle.test.mjs.map +1 -0
  291. package/dist/esm/helpers/mutationLifecycle.test.native.js +180 -0
  292. package/dist/esm/helpers/mutationLifecycle.test.native.js.map +1 -0
  293. package/dist/esm/helpers/mutatorContext.mjs +1 -1
  294. package/dist/esm/helpers/mutatorContext.native.js +4 -4
  295. package/dist/esm/helpers/mutatorContext.native.js.map +1 -1
  296. package/dist/esm/helpers/platform.mjs +5 -0
  297. package/dist/esm/helpers/platform.mjs.map +1 -0
  298. package/dist/esm/helpers/platform.native.js +4 -0
  299. package/dist/esm/helpers/platform.native.js.map +1 -0
  300. package/dist/esm/helpers/prettyFormatZeroQuery.mjs +1 -1
  301. package/dist/esm/helpers/prettyFormatZeroQuery.native.js +6 -6
  302. package/dist/esm/helpers/prettyFormatZeroQuery.native.js.map +1 -1
  303. package/dist/esm/helpers/queryContext.mjs +1 -1
  304. package/dist/esm/helpers/queryContext.native.js +3 -3
  305. package/dist/esm/helpers/queryContext.native.js.map +1 -1
  306. package/dist/esm/helpers/recoverZeroClient.mjs +14 -15
  307. package/dist/esm/helpers/recoverZeroClient.mjs.map +1 -1
  308. package/dist/esm/helpers/recoverZeroClient.native.js +26 -23
  309. package/dist/esm/helpers/recoverZeroClient.native.js.map +1 -1
  310. package/dist/esm/helpers/recoverZeroClient.test.mjs +8 -6
  311. package/dist/esm/helpers/recoverZeroClient.test.mjs.map +1 -1
  312. package/dist/esm/helpers/recoverZeroClient.test.native.js +15 -19
  313. package/dist/esm/helpers/recoverZeroClient.test.native.js.map +1 -1
  314. package/dist/esm/helpers/sleep.mjs +9 -0
  315. package/dist/esm/helpers/sleep.mjs.map +1 -0
  316. package/dist/esm/helpers/sleep.native.js +11 -0
  317. package/dist/esm/helpers/sleep.native.js.map +1 -0
  318. package/dist/esm/helpers/time.mjs +22 -0
  319. package/dist/esm/helpers/time.mjs.map +1 -0
  320. package/dist/esm/helpers/time.native.js +52 -0
  321. package/dist/esm/helpers/time.native.js.map +1 -0
  322. package/dist/esm/helpers/tuple.mjs +2 -0
  323. package/dist/esm/helpers/tuple.mjs.map +1 -0
  324. package/dist/esm/helpers/tuple.native.js +2 -0
  325. package/dist/esm/helpers/tuple.native.js.map +1 -0
  326. package/dist/esm/helpers/useMutation.native.js +5 -5
  327. package/dist/esm/helpers/useMutation.native.js.map +1 -1
  328. package/dist/esm/helpers/useMutation.test.native.js +1 -1
  329. package/dist/esm/helpers/useMutation.test.native.js.map +1 -1
  330. package/dist/esm/helpers/useZeroDebug.mjs +1 -1
  331. package/dist/esm/helpers/useZeroDebug.mjs.map +1 -1
  332. package/dist/esm/helpers/useZeroDebug.native.js +6 -7
  333. package/dist/esm/helpers/useZeroDebug.native.js.map +1 -1
  334. package/dist/esm/index.js +3 -1
  335. package/dist/esm/index.js.map +1 -1
  336. package/dist/esm/index.mjs +3 -1
  337. package/dist/esm/index.mjs.map +1 -1
  338. package/dist/esm/index.native.js +3 -1
  339. package/dist/esm/index.native.js.map +1 -1
  340. package/dist/esm/instanceRegistry.mjs +13 -2
  341. package/dist/esm/instanceRegistry.mjs.map +1 -1
  342. package/dist/esm/instanceRegistry.native.js +53 -4
  343. package/dist/esm/instanceRegistry.native.js.map +1 -1
  344. package/dist/esm/multi.mjs +33 -12
  345. package/dist/esm/multi.mjs.map +1 -1
  346. package/dist/esm/multi.native.js +38 -16
  347. package/dist/esm/multi.native.js.map +1 -1
  348. package/dist/esm/multiInstance.test.mjs +5 -1
  349. package/dist/esm/multiInstance.test.mjs.map +1 -1
  350. package/dist/esm/multiInstance.test.native.js +12 -8
  351. package/dist/esm/multiInstance.test.native.js.map +1 -1
  352. package/dist/esm/multiInstanceNested.test.native.js +10 -10
  353. package/dist/esm/multiInstanceNested.test.native.js.map +1 -1
  354. package/dist/esm/multiPartition.test.mjs +86 -37
  355. package/dist/esm/multiPartition.test.mjs.map +1 -1
  356. package/dist/esm/multiPartition.test.native.js +103 -40
  357. package/dist/esm/multiPartition.test.native.js.map +1 -1
  358. package/dist/esm/mutations.mjs +1 -1
  359. package/dist/esm/mutations.mjs.map +1 -1
  360. package/dist/esm/mutations.native.js +3 -3
  361. package/dist/esm/mutations.native.js.map +1 -1
  362. package/dist/esm/mutations.test.native.js +3 -3
  363. package/dist/esm/mutations.test.native.js.map +1 -1
  364. package/dist/esm/provideZero.hydration.test.mjs +1 -1
  365. package/dist/esm/provideZero.hydration.test.mjs.map +1 -1
  366. package/dist/esm/provideZero.hydration.test.native.js +2 -2
  367. package/dist/esm/provideZero.hydration.test.native.js.map +1 -1
  368. package/dist/esm/run.mjs +1 -1
  369. package/dist/esm/run.mjs.map +1 -1
  370. package/dist/esm/run.native.js +3 -3
  371. package/dist/esm/run.native.js.map +1 -1
  372. package/dist/esm/server.mjs +20 -15
  373. package/dist/esm/server.mjs.map +1 -1
  374. package/dist/esm/server.native.js +50 -56
  375. package/dist/esm/server.native.js.map +1 -1
  376. package/dist/esm/server.test.mjs +130 -7
  377. package/dist/esm/server.test.mjs.map +1 -1
  378. package/dist/esm/server.test.native.js +142 -11
  379. package/dist/esm/server.test.native.js.map +1 -1
  380. package/dist/esm/serverWhere.test.mjs.map +1 -1
  381. package/dist/esm/serverWhere.test.native.js +3 -3
  382. package/dist/esm/serverWhere.test.native.js.map +1 -1
  383. package/dist/esm/state.mjs +1 -1
  384. package/dist/esm/state.mjs.map +1 -1
  385. package/dist/esm/state.native.js +9 -9
  386. package/dist/esm/state.native.js.map +1 -1
  387. package/dist/esm/usePermission.test.native.js +3 -3
  388. package/dist/esm/usePermission.test.native.js.map +1 -1
  389. package/dist/esm/useQuery.empty.test.mjs +1 -1
  390. package/dist/esm/useQuery.empty.test.mjs.map +1 -1
  391. package/dist/esm/useQuery.empty.test.native.js +4 -4
  392. package/dist/esm/useQuery.empty.test.native.js.map +1 -1
  393. package/dist/esm/useQuery.ssr.test.native.js +2 -2
  394. package/dist/esm/useQuery.ssr.test.native.js.map +1 -1
  395. package/dist/esm/vite-plugin.mjs +7 -8
  396. package/dist/esm/vite-plugin.mjs.map +1 -1
  397. package/dist/esm/vite-plugin.native.js +11 -11
  398. package/dist/esm/vite-plugin.native.js.map +1 -1
  399. package/dist/esm/where.mjs +1 -1
  400. package/dist/esm/where.mjs.map +1 -1
  401. package/dist/esm/where.native.js +2 -2
  402. package/dist/esm/where.native.js.map +1 -1
  403. package/package.json +18 -6
  404. package/src/cli.ts +11 -3
  405. package/src/combineZeroClients.tsx +18 -10
  406. package/src/config.ts +72 -0
  407. package/src/createPermissions.ts +3 -4
  408. package/src/createUseQuery.tsx +8 -8
  409. package/src/createUseQueryDirect.tsx +11 -10
  410. package/src/createZeroClient.authData.test.tsx +1 -1
  411. package/src/createZeroClient.connection.test.tsx +13 -2
  412. package/src/createZeroClient.recovery.test.tsx +100 -4
  413. package/src/createZeroClient.tsx +87 -30
  414. package/src/generate-helpers.ts +108 -31
  415. package/src/generate-layout.ts +841 -0
  416. package/src/generate-lite.test.ts +421 -42
  417. package/src/generate-lite.ts +479 -43
  418. package/src/generate.test.ts +552 -90
  419. package/src/generate.ts +360 -163
  420. package/src/helpers/NullToOptional.ts +5 -0
  421. package/src/helpers/asyncContext.native.ts +90 -0
  422. package/src/helpers/asyncContext.ts +159 -0
  423. package/src/helpers/batchQuery.ts +2 -2
  424. package/src/helpers/createMutators.ts +11 -8
  425. package/src/helpers/ellipsis.ts +9 -0
  426. package/src/helpers/emitter.tsx +106 -0
  427. package/src/helpers/ensure.ts +10 -0
  428. package/src/helpers/ensureLoggedIn.ts +1 -2
  429. package/src/helpers/errors.ts +13 -0
  430. package/src/helpers/getCurrentComponentStack.ts +56 -0
  431. package/src/helpers/globalValue.ts +40 -0
  432. package/src/helpers/mapObject.ts +14 -0
  433. package/src/helpers/mutationLifecycle.test.ts +180 -0
  434. package/src/helpers/mutationLifecycle.ts +313 -0
  435. package/src/helpers/mutatorContext.ts +3 -3
  436. package/src/helpers/platform.native.ts +2 -0
  437. package/src/helpers/platform.ts +16 -0
  438. package/src/helpers/prettyFormatZeroQuery.ts +2 -2
  439. package/src/helpers/queryContext.ts +2 -2
  440. package/src/helpers/recoverZeroClient.test.ts +23 -21
  441. package/src/helpers/recoverZeroClient.ts +56 -49
  442. package/src/helpers/sleep.ts +8 -0
  443. package/src/helpers/time.ts +51 -0
  444. package/src/helpers/tuple.ts +1 -0
  445. package/src/helpers/useMutation.tsx +3 -3
  446. package/src/helpers/useZeroDebug.ts +3 -3
  447. package/src/index.ts +13 -1
  448. package/src/instanceRegistry.ts +19 -6
  449. package/src/multi.ts +75 -31
  450. package/src/multiInstance.test.tsx +31 -13
  451. package/src/multiInstanceNested.test.tsx +2 -2
  452. package/src/multiPartition.test.ts +62 -27
  453. package/src/mutations.ts +10 -10
  454. package/src/provideZero.hydration.test.tsx +1 -1
  455. package/src/resolveQuery.ts +2 -2
  456. package/src/run.ts +7 -7
  457. package/src/server.test.ts +117 -18
  458. package/src/server.ts +70 -43
  459. package/src/serverWhere.ts +2 -2
  460. package/src/state.ts +2 -2
  461. package/src/types.ts +47 -6
  462. package/src/useQuery.empty.test.tsx +3 -3
  463. package/src/useQuery.ssr.test.ts +1 -1
  464. package/src/vite-plugin.ts +12 -9
  465. package/src/where.ts +6 -7
  466. package/src/zeroRunner.ts +2 -2
  467. package/types/combineZeroClients.d.ts +11 -5
  468. package/types/combineZeroClients.d.ts.map +1 -1
  469. package/types/config.d.ts +62 -0
  470. package/types/config.d.ts.map +1 -0
  471. package/types/createPermissions.d.ts.map +1 -1
  472. package/types/createUseQuery.d.ts.map +1 -1
  473. package/types/createUseQueryDirect.d.ts +1 -1
  474. package/types/createUseQueryDirect.d.ts.map +1 -1
  475. package/types/createZeroClient.d.ts +22 -12
  476. package/types/createZeroClient.d.ts.map +1 -1
  477. package/types/createZeroClient.recovery.test.d.ts.map +1 -1
  478. package/types/generate-helpers.d.ts +17 -2
  479. package/types/generate-helpers.d.ts.map +1 -1
  480. package/types/generate-layout.d.ts +26 -0
  481. package/types/generate-layout.d.ts.map +1 -0
  482. package/types/generate-lite.d.ts +29 -1
  483. package/types/generate-lite.d.ts.map +1 -1
  484. package/types/generate.d.ts +20 -0
  485. package/types/generate.d.ts.map +1 -1
  486. package/types/helpers/NullToOptional.d.ts +6 -0
  487. package/types/helpers/NullToOptional.d.ts.map +1 -0
  488. package/types/helpers/asyncContext.d.ts +15 -0
  489. package/types/helpers/asyncContext.d.ts.map +1 -0
  490. package/types/helpers/asyncContext.native.d.ts +8 -0
  491. package/types/helpers/asyncContext.native.d.ts.map +1 -0
  492. package/types/helpers/createMutators.d.ts +2 -1
  493. package/types/helpers/createMutators.d.ts.map +1 -1
  494. package/types/helpers/ellipsis.d.ts +2 -0
  495. package/types/helpers/ellipsis.d.ts.map +1 -0
  496. package/types/helpers/emitter.d.ts +21 -0
  497. package/types/helpers/emitter.d.ts.map +1 -0
  498. package/types/helpers/ensure.d.ts +2 -0
  499. package/types/helpers/ensure.d.ts.map +1 -0
  500. package/types/helpers/ensureLoggedIn.d.ts.map +1 -1
  501. package/types/helpers/errors.d.ts +7 -0
  502. package/types/helpers/errors.d.ts.map +1 -0
  503. package/types/helpers/getCurrentComponentStack.d.ts +2 -0
  504. package/types/helpers/getCurrentComponentStack.d.ts.map +1 -0
  505. package/types/helpers/globalValue.d.ts +23 -0
  506. package/types/helpers/globalValue.d.ts.map +1 -0
  507. package/types/helpers/mapObject.d.ts +4 -0
  508. package/types/helpers/mapObject.d.ts.map +1 -0
  509. package/types/helpers/mutationLifecycle.d.ts +44 -0
  510. package/types/helpers/mutationLifecycle.d.ts.map +1 -0
  511. package/types/helpers/mutationLifecycle.test.d.ts +2 -0
  512. package/types/helpers/mutationLifecycle.test.d.ts.map +1 -0
  513. package/types/helpers/platform.d.ts +3 -0
  514. package/types/helpers/platform.d.ts.map +1 -0
  515. package/types/helpers/platform.native.d.ts +3 -0
  516. package/types/helpers/platform.native.d.ts.map +1 -0
  517. package/types/helpers/recoverZeroClient.d.ts +13 -9
  518. package/types/helpers/recoverZeroClient.d.ts.map +1 -1
  519. package/types/helpers/sleep.d.ts +2 -0
  520. package/types/helpers/sleep.d.ts.map +1 -0
  521. package/types/helpers/time.d.ts +28 -0
  522. package/types/helpers/time.d.ts.map +1 -0
  523. package/types/helpers/tuple.d.ts +2 -0
  524. package/types/helpers/tuple.d.ts.map +1 -0
  525. package/types/index.d.ts +3 -1
  526. package/types/index.d.ts.map +1 -1
  527. package/types/instanceRegistry.d.ts +1 -0
  528. package/types/instanceRegistry.d.ts.map +1 -1
  529. package/types/multi.d.ts +23 -1
  530. package/types/multi.d.ts.map +1 -1
  531. package/types/mutations.d.ts +1 -1
  532. package/types/mutations.d.ts.map +1 -1
  533. package/types/run.d.ts.map +1 -1
  534. package/types/server.d.ts +12 -8
  535. package/types/server.d.ts.map +1 -1
  536. package/types/state.d.ts +1 -1
  537. package/types/state.d.ts.map +1 -1
  538. package/types/types.d.ts +23 -1
  539. package/types/types.d.ts.map +1 -1
  540. package/types/vite-plugin.d.ts.map +1 -1
  541. package/types/where.d.ts.map +1 -1
  542. package/lint/ssr-guards.js +0 -165
  543. package/test-fixtures/server-return-types.ts +0 -58
  544. package/test-fixtures/tsconfig.json +0 -13
  545. package/tsconfig.json +0 -26
  546. package/vitest.config.ts +0 -8
@@ -0,0 +1,841 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
2
+ import { basename, dirname, relative, resolve, sep } from 'node:path'
3
+
4
+ import type ts from 'typescript'
5
+
6
+ export type DataNamespace = {
7
+ name: string
8
+ instance: string
9
+ queryPath: string | null
10
+ modelPath: string | null
11
+ sourcePaths: string[]
12
+ }
13
+
14
+ export type DataInstance = {
15
+ name: string
16
+ dir: string
17
+ scope: string | null
18
+ namespaces: DataNamespace[]
19
+ syncTables: string[]
20
+ supportTables: string[]
21
+ /** `supportTables` declared in `on-zero.config.ts`. */
22
+ declaredSupportTables: string[]
23
+ }
24
+
25
+ export type DataLayout = {
26
+ instances: DataInstance[]
27
+ namespaces: DataNamespace[]
28
+ metadataPaths: string[]
29
+ sourceRoots: string[]
30
+ }
31
+
32
+ const isSourceFile = (name: string) =>
33
+ name.endsWith('.ts') &&
34
+ !name.endsWith('.d.ts') &&
35
+ !name.endsWith('.test.ts') &&
36
+ !name.endsWith('.spec.ts')
37
+
38
+ const toImportPath = (baseDir: string, path: string) =>
39
+ relative(baseDir, path).split(sep).join('/').replace(/\.ts$/, '')
40
+
41
+ const isWithin = (root: string, path: string) => {
42
+ const child = relative(root, path)
43
+ return child === '' || (child !== '..' && !child.startsWith(`..${sep}`))
44
+ }
45
+
46
+ type ParsedInstanceConfig = {
47
+ name: string
48
+ dir: string
49
+ scope: string | null
50
+ supportTables: string[]
51
+ }
52
+
53
+ function propertyName(
54
+ ts: typeof import('typescript'),
55
+ name: ts.PropertyName
56
+ ): string | null {
57
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) {
58
+ return name.text
59
+ }
60
+ return null
61
+ }
62
+
63
+ function readDataConfig(
64
+ ts: typeof import('typescript'),
65
+ baseDir: string,
66
+ configPath: string | undefined
67
+ ): { path: string; instances: ParsedInstanceConfig[] } | null {
68
+ const path = configPath ? resolve(configPath) : resolve(baseDir, 'on-zero.config.ts')
69
+ if (!existsSync(path)) {
70
+ if (configPath) throw new Error(`[on-zero] config file does not exist: ${path}`)
71
+ return null
72
+ }
73
+ if (dirname(path) !== baseDir) {
74
+ throw new Error(`[on-zero] ${path} must be at the data root ${baseDir}`)
75
+ }
76
+ const source = ts.createSourceFile(
77
+ path,
78
+ readFileSync(path, 'utf8'),
79
+ ts.ScriptTarget.Latest,
80
+ true
81
+ )
82
+ if (hasParseErrors(source)) throw new Error(`[on-zero] unable to parse ${path}`)
83
+
84
+ let config: ts.ObjectLiteralExpression | null = null
85
+ for (const statement of source.statements) {
86
+ if (!ts.isExportAssignment(statement) || statement.isExportEquals) continue
87
+ const call = statement.expression
88
+ if (
89
+ !ts.isCallExpression(call) ||
90
+ call.expression.getText(source) !== 'defineConfig'
91
+ ) {
92
+ continue
93
+ }
94
+ const value = call.arguments[0]
95
+ if (value && ts.isObjectLiteralExpression(value)) config = value
96
+ }
97
+ if (!config) {
98
+ throw new Error(
99
+ `[on-zero] ${path} must default export defineConfig({ instances: { ... } })`
100
+ )
101
+ }
102
+
103
+ const rootOptions = new Map<string, ts.Expression>()
104
+ for (const option of config.properties) {
105
+ if (!ts.isPropertyAssignment(option)) {
106
+ throw new Error(`[on-zero] ${path} options must use explicit property assignments`)
107
+ }
108
+ const name = propertyName(ts, option.name)
109
+ if (!name) throw new Error(`[on-zero] ${path} has an unsupported option name`)
110
+ if (rootOptions.has(name))
111
+ throw new Error(`[on-zero] ${path} repeats option '${name}'`)
112
+ rootOptions.set(name, option.initializer)
113
+ }
114
+ for (const name of rootOptions.keys()) {
115
+ if (name !== 'instances')
116
+ throw new Error(`[on-zero] ${path} has unknown option '${name}'`)
117
+ }
118
+ const instancesNode = rootOptions.get('instances')
119
+ if (!instancesNode || !ts.isObjectLiteralExpression(instancesNode)) {
120
+ throw new Error(`[on-zero] ${path} must declare a non-empty instances object`)
121
+ }
122
+
123
+ const instances: ParsedInstanceConfig[] = []
124
+ for (const property of instancesNode.properties) {
125
+ if (!ts.isPropertyAssignment(property)) {
126
+ throw new Error(
127
+ `[on-zero] ${path} instances must use explicit property assignments`
128
+ )
129
+ }
130
+ const name = propertyName(ts, property.name)
131
+ if (!name) throw new Error(`[on-zero] ${path} has an unsupported instance name`)
132
+ if (!ts.isObjectLiteralExpression(property.initializer)) {
133
+ throw new Error(`[on-zero] instance '${name}' must be an object`)
134
+ }
135
+ if (instances.some((instance) => instance.name === name)) {
136
+ throw new Error(`[on-zero] duplicate instance name '${name}'`)
137
+ }
138
+ let dir = resolve(dirname(path), name)
139
+ let scope: string | null = null
140
+ const supportTables: string[] = []
141
+ const seen = new Set<string>()
142
+ for (const option of property.initializer.properties) {
143
+ if (!ts.isPropertyAssignment(option)) {
144
+ throw new Error(`[on-zero] instance '${name}' options must be assignments`)
145
+ }
146
+ const optionName = propertyName(ts, option.name)
147
+ if (!optionName)
148
+ throw new Error(`[on-zero] instance '${name}' has an invalid option`)
149
+ if (seen.has(optionName)) {
150
+ throw new Error(`[on-zero] instance '${name}' repeats option '${optionName}'`)
151
+ }
152
+ seen.add(optionName)
153
+ if (optionName === 'dir') {
154
+ if (!ts.isStringLiteral(option.initializer)) {
155
+ throw new Error(`[on-zero] instance '${name}' dir must be a string literal`)
156
+ }
157
+ if (option.initializer.text.startsWith('/')) {
158
+ throw new Error(`[on-zero] instance '${name}' dir must be relative to ${path}`)
159
+ }
160
+ dir = resolve(dirname(path), option.initializer.text)
161
+ continue
162
+ }
163
+ if (optionName === 'scope') {
164
+ if (!ts.isStringLiteral(option.initializer)) {
165
+ throw new Error(`[on-zero] instance '${name}' scope must be a string literal`)
166
+ }
167
+ if (!option.initializer.text) {
168
+ throw new Error(`[on-zero] instance '${name}' scope cannot be empty`)
169
+ }
170
+ scope = option.initializer.text
171
+ continue
172
+ }
173
+ if (optionName === 'supportTables') {
174
+ if (!ts.isArrayLiteralExpression(option.initializer)) {
175
+ throw new Error(`[on-zero] instance '${name}' supportTables must be an array`)
176
+ }
177
+ for (const table of option.initializer.elements) {
178
+ if (!ts.isStringLiteral(table)) {
179
+ throw new Error(
180
+ `[on-zero] instance '${name}' supportTables must contain string literals`
181
+ )
182
+ }
183
+ if (!table.text) {
184
+ throw new Error(
185
+ `[on-zero] instance '${name}' supportTables cannot contain an empty table name`
186
+ )
187
+ }
188
+ supportTables.push(table.text)
189
+ }
190
+ continue
191
+ }
192
+ throw new Error(`[on-zero] instance '${name}' has unknown option '${optionName}'`)
193
+ }
194
+ if (!existsSync(dir) || !statSync(dir).isDirectory()) {
195
+ throw new Error(`[on-zero] instance '${name}' directory does not exist: ${dir}`)
196
+ }
197
+ instances.push({ name, dir, scope, supportTables })
198
+ }
199
+ if (instances.length === 0) {
200
+ throw new Error(`[on-zero] ${path} must declare at least one instance`)
201
+ }
202
+ for (const instance of instances) {
203
+ const duplicate = instances.find(
204
+ (candidate) => candidate !== instance && candidate.dir === instance.dir
205
+ )
206
+ if (duplicate) {
207
+ throw new Error(
208
+ `[on-zero] instances '${instance.name}' and '${duplicate.name}' resolve to the same directory: ${instance.dir}`
209
+ )
210
+ }
211
+ }
212
+ return { path, instances }
213
+ }
214
+
215
+ function hasParseErrors(source: ts.SourceFile): boolean {
216
+ // typescript keeps syntax diagnostics on SourceFile but does not expose them
217
+ // in its public type.
218
+ return Boolean(
219
+ (
220
+ source as unknown as {
221
+ parseDiagnostics?: readonly unknown[]
222
+ }
223
+ ).parseDiagnostics?.length
224
+ )
225
+ }
226
+
227
+ function hasNamespaceExports(
228
+ ts: typeof import('typescript'),
229
+ baseDir: string,
230
+ path: string
231
+ ): boolean {
232
+ const source = ts.createSourceFile(
233
+ path,
234
+ readFileSync(path, 'utf8'),
235
+ ts.ScriptTarget.Latest,
236
+ true
237
+ )
238
+ if (hasParseErrors(source)) {
239
+ const displayPath = relative(dirname(baseDir), path).split(sep).join('/')
240
+ console.warn(`[on-zero] ignoring ${displayPath}: no recognized data exports`)
241
+ return false
242
+ }
243
+ const functions = new Map<string, ts.ConciseBody>()
244
+ const exported = new Set<string>()
245
+
246
+ for (const statement of source.statements) {
247
+ if (ts.isVariableStatement(statement)) {
248
+ const isExported = statement.modifiers?.some(
249
+ (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword
250
+ )
251
+ for (const declaration of statement.declarationList.declarations) {
252
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue
253
+ const name = declaration.name.text
254
+ const initializer = declaration.initializer
255
+ if (isExported && ts.isCallExpression(initializer)) {
256
+ const initializerText = initializer.getText(source)
257
+ if (
258
+ (name === 'mutate' && initializerText.startsWith('mutations(')) ||
259
+ (name === 'where' && initializerText.startsWith('serverWhere(')) ||
260
+ (name === 'schema' && initializerText.startsWith('table('))
261
+ ) {
262
+ return true
263
+ }
264
+ }
265
+ if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) {
266
+ functions.set(name, initializer.body)
267
+ if (isExported) exported.add(name)
268
+ }
269
+ }
270
+ continue
271
+ }
272
+ if (ts.isFunctionDeclaration(statement) && statement.name && statement.body) {
273
+ functions.set(statement.name.text, statement.body)
274
+ if (
275
+ statement.modifiers?.some(
276
+ (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword
277
+ )
278
+ ) {
279
+ exported.add(statement.name.text)
280
+ }
281
+ }
282
+ }
283
+
284
+ const visiting = new Set<string>()
285
+ const reachesQuery = (node: ts.Node): boolean => {
286
+ if (ts.isPropertyAccessExpression(node)) {
287
+ if (ts.isIdentifier(node.expression) && node.expression.text === 'zql') return true
288
+ if (
289
+ ts.isPropertyAccessExpression(node.expression) &&
290
+ node.expression.name.text === 'query'
291
+ )
292
+ return true
293
+ }
294
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
295
+ const name = node.expression.text
296
+ const helper = functions.get(name)
297
+ if (helper && !visiting.has(name)) {
298
+ visiting.add(name)
299
+ const found = reachesQuery(helper)
300
+ visiting.delete(name)
301
+ if (found) return true
302
+ }
303
+ }
304
+ let found = false
305
+ ts.forEachChild(node, (child) => {
306
+ if (!found && reachesQuery(child)) found = true
307
+ })
308
+ return found
309
+ }
310
+
311
+ return [...exported].some((name) => reachesQuery(functions.get(name)!))
312
+ }
313
+
314
+ function discoverNamespaces(
315
+ ts: typeof import('typescript'),
316
+ baseDir: string,
317
+ instance: DataInstance,
318
+ instanceDirs: Set<string>
319
+ ) {
320
+ const namespaces: DataNamespace[] = []
321
+ for (const entry of readdirSync(instance.dir, { withFileTypes: true }).sort((a, b) =>
322
+ a.name.localeCompare(b.name)
323
+ )) {
324
+ if (entry.isFile()) {
325
+ if (!isSourceFile(entry.name) || entry.name === 'on-zero.config.ts') continue
326
+ const path = resolve(instance.dir, entry.name)
327
+ if (!hasNamespaceExports(ts, baseDir, path)) continue
328
+ const name = basename(entry.name, '.ts')
329
+ namespaces.push({
330
+ name,
331
+ instance: instance.name,
332
+ queryPath: path,
333
+ modelPath: path,
334
+ sourcePaths: [path],
335
+ })
336
+ continue
337
+ }
338
+ if (!entry.isDirectory()) continue
339
+ const folder = resolve(instance.dir, entry.name)
340
+ if (entry.name === 'generated' || instanceDirs.has(folder)) continue
341
+
342
+ const queryPath = resolve(folder, 'queries.ts')
343
+ const modelPath = resolve(folder, 'mutations.ts')
344
+ const hasQueries = existsSync(queryPath)
345
+ const hasMutations = existsSync(modelPath)
346
+ if (!hasQueries && !hasMutations) {
347
+ if (
348
+ ['models', 'mutations', 'queries'].includes(entry.name) &&
349
+ readdirSync(folder).some(isSourceFile)
350
+ ) {
351
+ throw new Error(
352
+ `[on-zero] ${folder} uses the removed top-level ${entry.name}/ layout; ` +
353
+ `move each namespace to <name>.ts or <name>/queries.ts + mutations.ts`
354
+ )
355
+ }
356
+ continue
357
+ }
358
+ namespaces.push({
359
+ name: entry.name,
360
+ instance: instance.name,
361
+ queryPath: hasQueries ? queryPath : null,
362
+ modelPath: hasMutations ? modelPath : null,
363
+ sourcePaths: [hasQueries && queryPath, hasMutations && modelPath].filter(
364
+ (path): path is string => Boolean(path)
365
+ ),
366
+ })
367
+ }
368
+ return namespaces
369
+ }
370
+
371
+ function metadataPaths(baseDir: string): string[] {
372
+ const paths: string[] = []
373
+ const relations = resolve(baseDir, 'relations.ts')
374
+ if (existsSync(relations)) paths.push(relations)
375
+
376
+ const databaseDir = resolve(dirname(baseDir), 'database')
377
+ if (!existsSync(databaseDir)) return paths
378
+ for (const entry of readdirSync(databaseDir, { withFileTypes: true })) {
379
+ if (!entry.isFile() || !isSourceFile(entry.name)) continue
380
+ if (
381
+ entry.name === 'relations.ts' ||
382
+ entry.name === 'zeroSchemaInput.ts' ||
383
+ entry.name.startsWith('schema')
384
+ ) {
385
+ paths.push(resolve(databaseDir, entry.name))
386
+ }
387
+ }
388
+ return paths.sort()
389
+ }
390
+
391
+ function relationTargets(
392
+ ts: typeof import('typescript'),
393
+ paths: string[]
394
+ ): Map<string, Map<string, string>> {
395
+ const relations = new Map<string, Map<string, string>>()
396
+ for (const path of paths.filter((path) => basename(path) === 'relations.ts')) {
397
+ const source = ts.createSourceFile(
398
+ path,
399
+ readFileSync(path, 'utf8'),
400
+ ts.ScriptTarget.Latest,
401
+ true
402
+ )
403
+ const visit = (node: ts.Node) => {
404
+ if (
405
+ !ts.isCallExpression(node) ||
406
+ node.expression.getText(source) !== 'defineRelations'
407
+ ) {
408
+ ts.forEachChild(node, visit)
409
+ return
410
+ }
411
+ const factory = node.arguments[1]
412
+ if (!factory || (!ts.isArrowFunction(factory) && !ts.isFunctionExpression(factory)))
413
+ return
414
+ const body = ts.isParenthesizedExpression(factory.body)
415
+ ? factory.body.expression
416
+ : factory.body
417
+ if (!ts.isObjectLiteralExpression(body)) return
418
+ for (const tableProperty of body.properties) {
419
+ if (
420
+ !ts.isPropertyAssignment(tableProperty) ||
421
+ !ts.isObjectLiteralExpression(tableProperty.initializer)
422
+ ) {
423
+ continue
424
+ }
425
+ const table = tableProperty.name.getText(source).replace(/^['"]|['"]$/g, '')
426
+ const tableRelations = relations.get(table) ?? new Map<string, string>()
427
+ for (const relationProperty of tableProperty.initializer.properties) {
428
+ if (
429
+ !ts.isPropertyAssignment(relationProperty) ||
430
+ !ts.isCallExpression(relationProperty.initializer)
431
+ ) {
432
+ continue
433
+ }
434
+ const expression = relationProperty.initializer.expression
435
+ if (!ts.isPropertyAccessExpression(expression)) continue
436
+ const name = relationProperty.name.getText(source).replace(/^['"]|['"]$/g, '')
437
+ tableRelations.set(name, expression.name.text)
438
+ }
439
+ relations.set(table, tableRelations)
440
+ }
441
+ }
442
+ visit(source)
443
+ }
444
+ return relations
445
+ }
446
+
447
+ function tableColumns(
448
+ ts: typeof import('typescript'),
449
+ paths: string[],
450
+ namespaces: DataNamespace[]
451
+ ): Map<string, Set<string>> {
452
+ const columns = new Map<string, Set<string>>()
453
+ const sources = new Set([
454
+ ...paths,
455
+ ...namespaces.flatMap((namespace) => namespace.sourcePaths),
456
+ ])
457
+ for (const path of sources) {
458
+ const source = ts.createSourceFile(
459
+ path,
460
+ readFileSync(path, 'utf8'),
461
+ ts.ScriptTarget.Latest,
462
+ true
463
+ )
464
+ const visit = (node: ts.Node) => {
465
+ if (
466
+ !ts.isVariableDeclaration(node) ||
467
+ !ts.isIdentifier(node.name) ||
468
+ !node.initializer
469
+ ) {
470
+ ts.forEachChild(node, visit)
471
+ return
472
+ }
473
+ const tableNames = new Set([node.name.text])
474
+ let foundColumns: ts.ObjectLiteralExpression | null = null
475
+ const inspect = (candidate: ts.Node) => {
476
+ if (!ts.isCallExpression(candidate)) {
477
+ ts.forEachChild(candidate, inspect)
478
+ return
479
+ }
480
+ for (const argument of candidate.arguments) {
481
+ if (
482
+ ts.isStringLiteral(argument) &&
483
+ /table/i.test(candidate.expression.getText(source))
484
+ ) {
485
+ tableNames.add(argument.text)
486
+ }
487
+ if (ts.isObjectLiteralExpression(argument)) foundColumns = argument
488
+ }
489
+ inspect(candidate.expression)
490
+ }
491
+ inspect(node.initializer)
492
+ if (foundColumns) {
493
+ const names = new Set(
494
+ (foundColumns as ts.ObjectLiteralExpression).properties
495
+ .map((property) => property.name?.getText(source).replace(/^['"]|['"]$/g, ''))
496
+ .filter((name): name is string => Boolean(name))
497
+ )
498
+ for (const tableName of tableNames) columns.set(tableName, names)
499
+ }
500
+ ts.forEachChild(node, visit)
501
+ }
502
+ visit(source)
503
+ }
504
+ return columns
505
+ }
506
+
507
+ function relatedTables(
508
+ ts: typeof import('typescript'),
509
+ namespace: DataNamespace,
510
+ relations: Map<string, Map<string, string>>
511
+ ): Array<{ table: string; query: string }> {
512
+ if (!namespace.queryPath) return []
513
+ const source = ts.createSourceFile(
514
+ namespace.queryPath,
515
+ readFileSync(namespace.queryPath, 'utf8'),
516
+ ts.ScriptTarget.Latest,
517
+ true
518
+ )
519
+ const reached: Array<{ table: string; query: string }> = []
520
+ const functions = new Map<string, ts.ConciseBody>()
521
+ const exported = new Set<string>()
522
+
523
+ for (const statement of source.statements) {
524
+ if (ts.isVariableStatement(statement)) {
525
+ const isExported = statement.modifiers?.some(
526
+ (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword
527
+ )
528
+ for (const declaration of statement.declarationList.declarations) {
529
+ if (
530
+ ts.isIdentifier(declaration.name) &&
531
+ declaration.initializer &&
532
+ (ts.isArrowFunction(declaration.initializer) ||
533
+ ts.isFunctionExpression(declaration.initializer))
534
+ ) {
535
+ functions.set(declaration.name.text, declaration.initializer.body)
536
+ if (isExported) exported.add(declaration.name.text)
537
+ }
538
+ }
539
+ } else if (ts.isFunctionDeclaration(statement) && statement.name && statement.body) {
540
+ functions.set(statement.name.text, statement.body)
541
+ if (
542
+ statement.modifiers?.some(
543
+ (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword
544
+ )
545
+ ) {
546
+ exported.add(statement.name.text)
547
+ }
548
+ }
549
+ }
550
+
551
+ const rootTable = (node: ts.Node): string | null => {
552
+ const text = node.getText(source)
553
+ return text.match(/(?:\bzql|\.query)\.([A-Za-z_$][\w$]*)/)?.[1] ?? null
554
+ }
555
+
556
+ const visiting = new Set<string>()
557
+ const visit = (node: ts.Node, currentTable: string, query: string) => {
558
+ if (
559
+ ts.isCallExpression(node) &&
560
+ ts.isPropertyAccessExpression(node.expression) &&
561
+ node.expression.name.text === 'related'
562
+ ) {
563
+ const nameArg = node.arguments[0]
564
+ if (!nameArg || !ts.isStringLiteral(nameArg)) {
565
+ throw new Error(
566
+ `[on-zero] ${namespace.name}.${query} uses related() without a string literal; ` +
567
+ `sync membership must be statically derivable`
568
+ )
569
+ }
570
+ const sourceTable = rootTable(node.expression.expression) ?? currentTable
571
+ const target = relations.get(sourceTable)?.get(nameArg.text)
572
+ if (!target) {
573
+ throw new Error(
574
+ `[on-zero] ${namespace.name}.${query} related('${nameArg.text}') cannot be resolved ` +
575
+ `from table '${sourceTable}' through relations.ts`
576
+ )
577
+ }
578
+ reached.push({ table: target, query })
579
+ visit(node.expression.expression, currentTable, query)
580
+ const callback = node.arguments[1]
581
+ if (
582
+ callback &&
583
+ (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback))
584
+ ) {
585
+ visit(callback.body, target, query)
586
+ }
587
+ return
588
+ }
589
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
590
+ const helper = functions.get(node.expression.text)
591
+ const key = `${query}:${node.expression.text}`
592
+ if (helper && !visiting.has(key)) {
593
+ visiting.add(key)
594
+ visit(helper, currentTable, query)
595
+ visiting.delete(key)
596
+ }
597
+ }
598
+ ts.forEachChild(node, (child) => visit(child, currentTable, query))
599
+ }
600
+
601
+ for (const name of exported) {
602
+ if (['mutate', 'schema', 'where'].includes(name)) continue
603
+ visit(functions.get(name)!, namespace.name, name)
604
+ }
605
+ return reached
606
+ }
607
+
608
+ function mutationSupportTables(
609
+ ts: typeof import('typescript'),
610
+ baseDir: string,
611
+ sourceRoots: string[],
612
+ namespace: DataNamespace
613
+ ): string[] {
614
+ if (!namespace.modelPath) return []
615
+ const tables = new Set<string>()
616
+ const visited = new Set<string>()
617
+
618
+ const scan = (path: string) => {
619
+ if (visited.has(path)) return
620
+ visited.add(path)
621
+ const source = ts.createSourceFile(
622
+ path,
623
+ readFileSync(path, 'utf8'),
624
+ ts.ScriptTarget.Latest,
625
+ true
626
+ )
627
+
628
+ const visit = (node: ts.Node) => {
629
+ if (
630
+ ts.isPropertyAccessExpression(node) &&
631
+ ts.isPropertyAccessExpression(node.expression) &&
632
+ ['mutate', 'query'].includes(node.expression.name.text)
633
+ ) {
634
+ const transaction = node.expression.expression
635
+ if (
636
+ (ts.isIdentifier(transaction) && transaction.text === 'tx') ||
637
+ (ts.isPropertyAccessExpression(transaction) && transaction.name.text === 'tx')
638
+ ) {
639
+ tables.add(node.name.text)
640
+ }
641
+ }
642
+
643
+ if (
644
+ (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
645
+ node.moduleSpecifier &&
646
+ ts.isStringLiteral(node.moduleSpecifier)
647
+ ) {
648
+ const specifier = node.moduleSpecifier.text
649
+ const unresolved = specifier.startsWith('~/data/')
650
+ ? resolve(baseDir, specifier.slice('~/data/'.length))
651
+ : specifier.startsWith('.')
652
+ ? resolve(dirname(path), specifier)
653
+ : null
654
+ if (unresolved) {
655
+ for (const candidate of [
656
+ unresolved.endsWith('.ts') ? unresolved : `${unresolved}.ts`,
657
+ resolve(unresolved, 'index.ts'),
658
+ ]) {
659
+ if (
660
+ existsSync(candidate) &&
661
+ sourceRoots.some((root) => isWithin(root, candidate))
662
+ ) {
663
+ scan(candidate)
664
+ break
665
+ }
666
+ }
667
+ }
668
+ }
669
+
670
+ ts.forEachChild(node, visit)
671
+ }
672
+ visit(source)
673
+ }
674
+
675
+ scan(namespace.modelPath)
676
+ return [...tables].sort()
677
+ }
678
+
679
+ function assertNoInstanceFiles(roots: string[]) {
680
+ const visited = new Set<string>()
681
+ const walk = (dir: string) => {
682
+ if (visited.has(dir) || !existsSync(dir)) return
683
+ visited.add(dir)
684
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
685
+ if (entry.name === 'node_modules' || entry.name === 'generated') continue
686
+ const path = resolve(dir, entry.name)
687
+ if (entry.isDirectory()) {
688
+ walk(path)
689
+ } else if (entry.isFile() && entry.name === 'instance.ts') {
690
+ throw new Error(
691
+ `[on-zero] ${path} uses removed instance.ts configuration; delete it and configure instances in on-zero.config.ts`
692
+ )
693
+ }
694
+ }
695
+ }
696
+ for (const root of roots) walk(root)
697
+ }
698
+
699
+ function assertNoUnclaimedNamespaces(
700
+ ts: typeof import('typescript'),
701
+ baseDir: string,
702
+ configPath: string,
703
+ instanceDirs: string[]
704
+ ) {
705
+ const walk = (dir: string) => {
706
+ if (instanceDirs.some((instanceDir) => isWithin(instanceDir, dir))) return
707
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
708
+ if (entry.name === 'node_modules' || entry.name === 'generated') continue
709
+ const path = resolve(dir, entry.name)
710
+ if (entry.isDirectory()) {
711
+ walk(path)
712
+ continue
713
+ }
714
+ if (
715
+ !entry.isFile() ||
716
+ !isSourceFile(entry.name) ||
717
+ path === configPath ||
718
+ entry.name === 'instance.ts'
719
+ ) {
720
+ continue
721
+ }
722
+ if (hasNamespaceExports(ts, baseDir, path)) {
723
+ throw new Error(
724
+ `[on-zero] data namespace ${path} is outside every instance directory declared in ${configPath}`
725
+ )
726
+ }
727
+ }
728
+ }
729
+ walk(baseDir)
730
+ }
731
+
732
+ export function discoverDataLayout(
733
+ ts: typeof import('typescript'),
734
+ baseDir: string,
735
+ configPath?: string
736
+ ): DataLayout {
737
+ const config = readDataConfig(ts, baseDir, configPath)
738
+ const configured =
739
+ config?.instances ??
740
+ ([
741
+ { name: 'default', dir: baseDir, scope: null, supportTables: [] },
742
+ ] satisfies ParsedInstanceConfig[])
743
+ const sourceRoots = [
744
+ ...new Set([baseDir, ...configured.map((instance) => instance.dir)]),
745
+ ]
746
+ assertNoInstanceFiles(sourceRoots)
747
+ if (config) {
748
+ assertNoUnclaimedNamespaces(
749
+ ts,
750
+ baseDir,
751
+ config.path,
752
+ configured.map((instance) => instance.dir)
753
+ )
754
+ }
755
+ const instances: DataInstance[] = configured.map((instance) => ({
756
+ name: instance.name,
757
+ dir: instance.dir,
758
+ scope: instance.scope,
759
+ namespaces: [],
760
+ syncTables: [],
761
+ supportTables: [],
762
+ declaredSupportTables: instance.supportTables,
763
+ }))
764
+ const instanceDirs = new Set(instances.map((instance) => instance.dir))
765
+
766
+ for (const instance of instances) {
767
+ instance.namespaces = discoverNamespaces(ts, baseDir, instance, instanceDirs)
768
+ }
769
+ const namespaces = instances.flatMap((instance) => instance.namespaces)
770
+ const owners = new Map<string, string>()
771
+ for (const namespace of namespaces) {
772
+ const owner = owners.get(namespace.name)
773
+ if (owner) {
774
+ throw new Error(
775
+ `[on-zero] namespace '${namespace.name}' is claimed by instances '${owner}' and '${namespace.instance}'`
776
+ )
777
+ }
778
+ owners.set(namespace.name, namespace.instance)
779
+ }
780
+
781
+ const metadata = metadataPaths(baseDir)
782
+ const relations = relationTargets(ts, metadata)
783
+ const columns = tableColumns(ts, metadata, namespaces)
784
+ const relatedOwners = new Map<string, string>()
785
+ for (const instance of instances) {
786
+ const syncTables = new Set(instance.namespaces.map((namespace) => namespace.name))
787
+ for (const namespace of instance.namespaces) {
788
+ for (const reached of relatedTables(ts, namespace, relations)) {
789
+ const owner = owners.get(reached.table) ?? relatedOwners.get(reached.table)
790
+ if (owner && owner !== instance.name) {
791
+ throw new Error(
792
+ `[on-zero] ${namespace.name}.${reached.query} in instance '${instance.name}' reaches ` +
793
+ `table '${reached.table}' owned by instance '${owner}'`
794
+ )
795
+ }
796
+ relatedOwners.set(reached.table, instance.name)
797
+ syncTables.add(reached.table)
798
+ }
799
+ }
800
+ instance.syncTables = [...syncTables].sort()
801
+ if (instance.scope) {
802
+ for (const table of instance.syncTables) {
803
+ if (!columns.get(table)?.has(instance.scope)) {
804
+ throw new Error(
805
+ `[on-zero] table '${table}' in instance '${instance.name}' is missing scope column '${instance.scope}'`
806
+ )
807
+ }
808
+ }
809
+ }
810
+ }
811
+
812
+ for (const instance of instances) {
813
+ // declared entries deliberately bypass the owner guard below: a table owned
814
+ // by another instance can still be written here (a control transaction that
815
+ // seeds project-owned rows), and that write has to stay mappable in THIS
816
+ // instance's change log or every later pull throws on it.
817
+ const supportTables = new Set<string>(instance.declaredSupportTables)
818
+ for (const namespace of instance.namespaces) {
819
+ for (const table of mutationSupportTables(ts, baseDir, sourceRoots, namespace)) {
820
+ if (owners.has(table) || relatedOwners.has(table)) continue
821
+ if (!instance.syncTables.includes(table)) {
822
+ supportTables.add(table)
823
+ }
824
+ }
825
+ }
826
+ instance.supportTables = [...supportTables]
827
+ .filter((table) => !instance.syncTables.includes(table))
828
+ .sort()
829
+ }
830
+
831
+ return {
832
+ instances,
833
+ namespaces,
834
+ metadataPaths: config ? [...metadata, config.path].sort() : metadata,
835
+ sourceRoots,
836
+ }
837
+ }
838
+
839
+ export function namespaceImportPath(baseDir: string, path: string): string {
840
+ return `../${toImportPath(baseDir, path)}`
841
+ }