gemi 0.122.0 → 0.124.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 (304) hide show
  1. package/dist/ai/index.js +2 -2
  2. package/dist/ai/index.js.map +1 -1
  3. package/dist/app/App.d.ts +9 -0
  4. package/dist/app/App.d.ts.map +1 -1
  5. package/dist/app/index.js +1 -1
  6. package/dist/auth/AuthController.d.ts.map +1 -1
  7. package/dist/bin/gemi.js +4 -1
  8. package/dist/bin/gemi.js.map +3 -3
  9. package/dist/bun/plugin.js +1 -1
  10. package/dist/bun/preload.js +1 -1
  11. package/dist/{chunk-7ftj43vp.js → chunk-019wz697.js} +2 -2
  12. package/dist/{chunk-7ftj43vp.js.map → chunk-019wz697.js.map} +1 -1
  13. package/dist/{chunk-s5k3yq6t.js → chunk-121p4g9j.js} +2 -2
  14. package/dist/{chunk-s5k3yq6t.js.map → chunk-121p4g9j.js.map} +1 -1
  15. package/dist/{chunk-tewhms9w.js → chunk-17dndh5z.js} +2 -2
  16. package/dist/{chunk-3gsv1vv1.js.map → chunk-17dndh5z.js.map} +1 -1
  17. package/dist/{chunk-r01aqf0q.js → chunk-1qwhty9p.js} +2 -2
  18. package/dist/{chunk-r01aqf0q.js.map → chunk-1qwhty9p.js.map} +1 -1
  19. package/dist/{chunk-471htqmz.js → chunk-1rnh9qrp.js} +2 -2
  20. package/dist/{chunk-471htqmz.js.map → chunk-1rnh9qrp.js.map} +1 -1
  21. package/dist/{chunk-dedqr5wb.js → chunk-2affxmkn.js} +2 -2
  22. package/dist/{chunk-dedqr5wb.js.map → chunk-2affxmkn.js.map} +1 -1
  23. package/dist/{chunk-19dpzp4y.js → chunk-2n4490pk.js} +3 -3
  24. package/dist/{chunk-19dpzp4y.js.map → chunk-2n4490pk.js.map} +1 -1
  25. package/dist/{chunk-9xyxbxgk.js → chunk-30xxc6r7.js} +2 -2
  26. package/dist/{chunk-9xyxbxgk.js.map → chunk-30xxc6r7.js.map} +1 -1
  27. package/dist/{chunk-vx7hvyvq.js → chunk-34fkx6kb.js} +2 -2
  28. package/dist/{chunk-vx7hvyvq.js.map → chunk-34fkx6kb.js.map} +1 -1
  29. package/dist/{chunk-5nj94s66.js → chunk-3hqwz48c.js} +4 -4
  30. package/dist/{chunk-5nj94s66.js.map → chunk-3hqwz48c.js.map} +1 -1
  31. package/dist/{chunk-dhbgrv58.js → chunk-3j6s5bmx.js} +1 -1
  32. package/dist/{chunk-cskqet01.js → chunk-3y294mb8.js} +2 -2
  33. package/dist/{chunk-cskqet01.js.map → chunk-3y294mb8.js.map} +1 -1
  34. package/dist/{chunk-qsz9241c.js → chunk-4drnyymm.js} +2 -2
  35. package/dist/{chunk-qsz9241c.js.map → chunk-4drnyymm.js.map} +1 -1
  36. package/dist/{chunk-zg6hmc48.js → chunk-5e22tm7m.js} +1 -1
  37. package/dist/chunk-5j50q4g8.js +57 -0
  38. package/dist/{chunk-3s21p9n2.js.map → chunk-5j50q4g8.js.map} +19 -9
  39. package/dist/{chunk-0k02tza1.js → chunk-65s834td.js} +1 -1
  40. package/dist/{chunk-7mmw0jr2.js → chunk-675kzd7z.js} +2 -2
  41. package/dist/{chunk-7mmw0jr2.js.map → chunk-675kzd7z.js.map} +1 -1
  42. package/dist/{chunk-gy81nd9a.js → chunk-6bgb1nhq.js} +2 -2
  43. package/dist/{chunk-gy81nd9a.js.map → chunk-6bgb1nhq.js.map} +1 -1
  44. package/dist/chunk-70nnh0y7.js +5 -0
  45. package/dist/{chunk-htgmy3x7.js.map → chunk-70nnh0y7.js.map} +1 -1
  46. package/dist/{chunk-er8acmch.js → chunk-75ewjc4a.js} +2 -2
  47. package/dist/{chunk-er8acmch.js.map → chunk-75ewjc4a.js.map} +1 -1
  48. package/dist/{chunk-2c0s0561.js → chunk-7gfdts60.js} +2 -2
  49. package/dist/{chunk-2c0s0561.js.map → chunk-7gfdts60.js.map} +1 -1
  50. package/dist/{chunk-zefs2b6h.js → chunk-8m2htvjn.js} +2 -2
  51. package/dist/{chunk-zefs2b6h.js.map → chunk-8m2htvjn.js.map} +1 -1
  52. package/dist/{chunk-dwedx1jb.js → chunk-92sk56n0.js} +3 -3
  53. package/dist/{chunk-dwedx1jb.js.map → chunk-92sk56n0.js.map} +1 -1
  54. package/dist/{chunk-yds7zwc3.js → chunk-96a1459v.js} +2 -2
  55. package/dist/{chunk-yds7zwc3.js.map → chunk-96a1459v.js.map} +1 -1
  56. package/dist/{chunk-c7qs1xp3.js → chunk-9tr92nwy.js} +2 -2
  57. package/dist/{chunk-c7qs1xp3.js.map → chunk-9tr92nwy.js.map} +1 -1
  58. package/dist/{chunk-1wnnkde0.js → chunk-a3g7y70h.js} +3 -3
  59. package/dist/{chunk-1wnnkde0.js.map → chunk-a3g7y70h.js.map} +1 -1
  60. package/dist/{chunk-zrcd9hxr.js → chunk-b5afy6k9.js} +2 -2
  61. package/dist/{chunk-zrcd9hxr.js.map → chunk-b5afy6k9.js.map} +1 -1
  62. package/dist/{chunk-c0v61fp5.js → chunk-bnt8kx6x.js} +2 -2
  63. package/dist/{chunk-c0v61fp5.js.map → chunk-bnt8kx6x.js.map} +1 -1
  64. package/dist/{chunk-5tdxbwzg.js → chunk-bt9qv2jj.js} +3 -3
  65. package/dist/{chunk-5tdxbwzg.js.map → chunk-bt9qv2jj.js.map} +1 -1
  66. package/dist/{chunk-y6wt5b6t.js → chunk-c4jnxmf2.js} +1 -1
  67. package/dist/{chunk-ep0baa9g.js → chunk-cfdwsvtx.js} +2 -2
  68. package/dist/{chunk-ep0baa9g.js.map → chunk-cfdwsvtx.js.map} +1 -1
  69. package/dist/{chunk-51w5ktv2.js → chunk-dxfhhw5h.js} +2 -2
  70. package/dist/{chunk-51w5ktv2.js.map → chunk-dxfhhw5h.js.map} +1 -1
  71. package/dist/{chunk-pn2x59ge.js → chunk-f29pktad.js} +3 -3
  72. package/dist/{chunk-pn2x59ge.js.map → chunk-f29pktad.js.map} +1 -1
  73. package/dist/chunk-f4cmz31h.js +58 -0
  74. package/dist/{chunk-3rvn9a76.js.map → chunk-f4cmz31h.js.map} +3 -3
  75. package/dist/{chunk-0ejjgzwc.js → chunk-fn2qfwgx.js} +2 -2
  76. package/dist/{chunk-0ejjgzwc.js.map → chunk-fn2qfwgx.js.map} +1 -1
  77. package/dist/{chunk-pemhmjzp.js → chunk-fvrmptd0.js} +3 -3
  78. package/dist/{chunk-pemhmjzp.js.map → chunk-fvrmptd0.js.map} +1 -1
  79. package/dist/{chunk-qy8c0gzr.js → chunk-fw7ds23a.js} +2 -2
  80. package/dist/{chunk-qy8c0gzr.js.map → chunk-fw7ds23a.js.map} +1 -1
  81. package/dist/{chunk-fenc5tpv.js → chunk-h3p8qzft.js} +2 -2
  82. package/dist/{chunk-fenc5tpv.js.map → chunk-h3p8qzft.js.map} +1 -1
  83. package/dist/{chunk-wjkh2gem.js → chunk-j7v7dft7.js} +1 -1
  84. package/dist/chunk-jctb7v53.js +4 -0
  85. package/dist/chunk-jctb7v53.js.map +10 -0
  86. package/dist/{chunk-wqe47c0j.js → chunk-jys8y39p.js} +2 -2
  87. package/dist/{chunk-wqe47c0j.js.map → chunk-jys8y39p.js.map} +1 -1
  88. package/dist/{chunk-m83zm86m.js → chunk-kc924zjz.js} +2 -2
  89. package/dist/{chunk-m83zm86m.js.map → chunk-kc924zjz.js.map} +1 -1
  90. package/dist/{chunk-32n8t8x6.js → chunk-kzsjyvvc.js} +2 -2
  91. package/dist/{chunk-32n8t8x6.js.map → chunk-kzsjyvvc.js.map} +1 -1
  92. package/dist/{chunk-meg8rtr6.js → chunk-mqtfaqx5.js} +2 -2
  93. package/dist/{chunk-meg8rtr6.js.map → chunk-mqtfaqx5.js.map} +1 -1
  94. package/dist/{chunk-7g649j8h.js → chunk-mrswc6qw.js} +2 -2
  95. package/dist/{chunk-7g649j8h.js.map → chunk-mrswc6qw.js.map} +1 -1
  96. package/dist/{chunk-gc2dz11k.js → chunk-mvkz22p4.js} +2 -2
  97. package/dist/{chunk-gc2dz11k.js.map → chunk-mvkz22p4.js.map} +1 -1
  98. package/dist/{chunk-4acpw92g.js → chunk-n0r5xyk2.js} +3 -3
  99. package/dist/{chunk-4acpw92g.js.map → chunk-n0r5xyk2.js.map} +1 -1
  100. package/dist/{chunk-cca0grq3.js → chunk-n1a2zj5z.js} +2 -2
  101. package/dist/{chunk-cca0grq3.js.map → chunk-n1a2zj5z.js.map} +1 -1
  102. package/dist/{chunk-d5f1m3d2.js → chunk-nkzmk7v3.js} +2 -2
  103. package/dist/{chunk-d5f1m3d2.js.map → chunk-nkzmk7v3.js.map} +1 -1
  104. package/dist/{chunk-3gsv1vv1.js → chunk-nn2jeat2.js} +2 -2
  105. package/dist/{chunk-tewhms9w.js.map → chunk-nn2jeat2.js.map} +1 -1
  106. package/dist/chunk-nnarmbjv.js +5 -0
  107. package/dist/chunk-nnarmbjv.js.map +10 -0
  108. package/dist/{chunk-h43jp8ws.js → chunk-pe46a5a5.js} +2 -2
  109. package/dist/{chunk-h43jp8ws.js.map → chunk-pe46a5a5.js.map} +1 -1
  110. package/dist/{chunk-6yhpprzs.js → chunk-pmyh33v5.js} +2 -2
  111. package/dist/{chunk-6yhpprzs.js.map → chunk-pmyh33v5.js.map} +1 -1
  112. package/dist/{chunk-mr94nfp1.js → chunk-pya4rqm2.js} +3 -3
  113. package/dist/{chunk-mr94nfp1.js.map → chunk-pya4rqm2.js.map} +1 -1
  114. package/dist/{chunk-jaa6xkeh.js → chunk-qdj8ek8z.js} +2 -2
  115. package/dist/{chunk-jaa6xkeh.js.map → chunk-qdj8ek8z.js.map} +1 -1
  116. package/dist/{chunk-0yj0s1pn.js → chunk-qhz0x97z.js} +2 -2
  117. package/dist/{chunk-0yj0s1pn.js.map → chunk-qhz0x97z.js.map} +1 -1
  118. package/dist/chunk-qycwjzsv.js +9 -0
  119. package/dist/chunk-qycwjzsv.js.map +10 -0
  120. package/dist/{chunk-nz8z8jr1.js → chunk-rpyczdta.js} +3 -3
  121. package/dist/{chunk-nz8z8jr1.js.map → chunk-rpyczdta.js.map} +1 -1
  122. package/dist/{chunk-9rr5h818.js → chunk-rtawbqec.js} +3 -3
  123. package/dist/{chunk-9rr5h818.js.map → chunk-rtawbqec.js.map} +1 -1
  124. package/dist/{chunk-3wnghdsx.js → chunk-rttrpjqk.js} +2 -2
  125. package/dist/{chunk-3wnghdsx.js.map → chunk-rttrpjqk.js.map} +1 -1
  126. package/dist/{chunk-m53fgf20.js → chunk-s5jxc63j.js} +3 -3
  127. package/dist/{chunk-m53fgf20.js.map → chunk-s5jxc63j.js.map} +1 -1
  128. package/dist/{chunk-48gmyaxc.js → chunk-sd0c2001.js} +2 -2
  129. package/dist/{chunk-48gmyaxc.js.map → chunk-sd0c2001.js.map} +1 -1
  130. package/dist/chunk-skf89vrv.js +5 -0
  131. package/dist/chunk-skf89vrv.js.map +10 -0
  132. package/dist/chunk-szn2n976.js +24 -0
  133. package/dist/{chunk-2yw4yezc.js.map → chunk-szn2n976.js.map} +3 -3
  134. package/dist/{chunk-gemzbw7f.js → chunk-v2ggafz1.js} +2 -2
  135. package/dist/{chunk-gemzbw7f.js.map → chunk-v2ggafz1.js.map} +1 -1
  136. package/dist/{chunk-rhek27sj.js → chunk-v8v5qfnh.js} +3 -3
  137. package/dist/{chunk-rhek27sj.js.map → chunk-v8v5qfnh.js.map} +1 -1
  138. package/dist/{chunk-d2c3947c.js → chunk-w3812s34.js} +2 -2
  139. package/dist/{chunk-d2c3947c.js.map → chunk-w3812s34.js.map} +1 -1
  140. package/dist/{chunk-tk135gmj.js → chunk-w4z6x54b.js} +3 -3
  141. package/dist/{chunk-tk135gmj.js.map → chunk-w4z6x54b.js.map} +1 -1
  142. package/dist/{chunk-65beps2q.js → chunk-w61sphn5.js} +3 -3
  143. package/dist/{chunk-65beps2q.js.map → chunk-w61sphn5.js.map} +1 -1
  144. package/dist/{chunk-cvr5624r.js → chunk-wbg2tza5.js} +1 -1
  145. package/dist/{chunk-9d2d08qm.js → chunk-y434jc1c.js} +2 -2
  146. package/dist/{chunk-9d2d08qm.js.map → chunk-y434jc1c.js.map} +1 -1
  147. package/dist/{chunk-shfe0b22.js → chunk-ykz38t0t.js} +2 -2
  148. package/dist/{chunk-shfe0b22.js.map → chunk-ykz38t0t.js.map} +1 -1
  149. package/dist/{chunk-krk7mcgm.js → chunk-yzhv93b0.js} +3 -3
  150. package/dist/{chunk-krk7mcgm.js.map → chunk-yzhv93b0.js.map} +1 -1
  151. package/dist/{chunk-rhvc1axc.js → chunk-z5jydj5r.js} +2 -2
  152. package/dist/{chunk-rhvc1axc.js.map → chunk-z5jydj5r.js.map} +1 -1
  153. package/dist/chunk-zmf3vhex.js +10 -0
  154. package/dist/{chunk-dyp0wg9e.js.map → chunk-zmf3vhex.js.map} +8 -4
  155. package/dist/{chunk-sx340k85.js → chunk-zsfwcdqn.js} +2 -2
  156. package/dist/{chunk-sx340k85.js.map → chunk-zsfwcdqn.js.map} +1 -1
  157. package/dist/{chunk-4fx8p02c.js → chunk-zsvav1dk.js} +2 -2
  158. package/dist/{chunk-4fx8p02c.js.map → chunk-zsvav1dk.js.map} +1 -1
  159. package/dist/chunks/{ThemeProvider-BLI4zpLu.js → ThemeProvider-CbOx8IRl.js} +581 -2
  160. package/dist/chunks/ThemeProvider-CbOx8IRl.js.map +1 -0
  161. package/dist/client/auth/useEmailCode.d.ts.map +1 -1
  162. package/dist/client/auth/useSignIn.d.ts.map +1 -1
  163. package/dist/client/auth/useSignOut.d.ts.map +1 -1
  164. package/dist/client/index.d.ts +5 -1
  165. package/dist/client/index.d.ts.map +1 -1
  166. package/dist/client/index.js +216 -8
  167. package/dist/client/index.js.map +1 -1
  168. package/dist/client/init.d.ts +8 -0
  169. package/dist/client/init.d.ts.map +1 -1
  170. package/dist/client/realtime/FakeSocket.d.ts +47 -0
  171. package/dist/client/realtime/FakeSocket.d.ts.map +1 -0
  172. package/dist/client/realtime/RealtimeClient.d.ts +169 -0
  173. package/dist/client/realtime/RealtimeClient.d.ts.map +1 -0
  174. package/dist/client/realtime/RealtimeContext.d.ts +8 -0
  175. package/dist/client/realtime/RealtimeContext.d.ts.map +1 -0
  176. package/dist/client/realtime/useChannelSubscription.d.ts +32 -0
  177. package/dist/client/realtime/useChannelSubscription.d.ts.map +1 -0
  178. package/dist/client/rpc.d.ts +11 -0
  179. package/dist/client/rpc.d.ts.map +1 -1
  180. package/dist/client/useChannel.d.ts +87 -0
  181. package/dist/client/useChannel.d.ts.map +1 -0
  182. package/dist/client/useMutation.d.ts.map +1 -1
  183. package/dist/client/useQuery.d.ts +13 -0
  184. package/dist/client/useQuery.d.ts.map +1 -1
  185. package/dist/config/index.js +1 -1
  186. package/dist/console/run.js +2 -2
  187. package/dist/console/run.js.map +1 -1
  188. package/dist/container/index.js +2 -2
  189. package/dist/container/index.js.map +1 -1
  190. package/dist/database/index.js +2 -2
  191. package/dist/database/index.js.map +1 -1
  192. package/dist/email/index.js +2 -2
  193. package/dist/email/index.js.map +1 -1
  194. package/dist/facades/Broadcast.d.ts +68 -0
  195. package/dist/facades/Broadcast.d.ts.map +1 -0
  196. package/dist/facades/index.d.ts +1 -0
  197. package/dist/facades/index.d.ts.map +1 -1
  198. package/dist/facades/index.js +2 -2
  199. package/dist/facades/index.js.map +1 -1
  200. package/dist/foundation/index.js +2 -2
  201. package/dist/foundation/index.js.map +1 -1
  202. package/dist/gemi.d.ts +19 -6
  203. package/dist/http/ChannelRouter.d.ts +171 -0
  204. package/dist/http/ChannelRouter.d.ts.map +1 -0
  205. package/dist/http/index.d.ts +1 -0
  206. package/dist/http/index.d.ts.map +1 -1
  207. package/dist/http/index.js +2 -2
  208. package/dist/http/index.js.map +1 -1
  209. package/dist/i18n/dictionaryRuntime.js +2 -2
  210. package/dist/i18n/dictionaryRuntime.js.map +1 -1
  211. package/dist/i18n/index.js +2 -2
  212. package/dist/i18n/index.js.map +2 -2
  213. package/dist/kernel/Kernel.d.ts +6 -0
  214. package/dist/kernel/Kernel.d.ts.map +1 -1
  215. package/dist/kernel/index.js +3 -3
  216. package/dist/kernel/index.js.map +5 -6
  217. package/dist/kernel/providers.d.ts +2 -2
  218. package/dist/kernel/providers.d.ts.map +1 -1
  219. package/dist/orm/context.d.ts.map +1 -1
  220. package/dist/orm/index.js +2 -2
  221. package/dist/orm/index.js.map +1 -1
  222. package/dist/server/Server.d.ts.map +1 -1
  223. package/dist/server/httpDev.d.ts +1 -2
  224. package/dist/server/httpDev.d.ts.map +1 -1
  225. package/dist/server/httpProd.d.ts +1 -1
  226. package/dist/server/httpProd.d.ts.map +1 -1
  227. package/dist/server/index.js +2 -2
  228. package/dist/server/index.js.map +3 -3
  229. package/dist/server/shutdown.d.ts +9 -0
  230. package/dist/server/shutdown.d.ts.map +1 -1
  231. package/dist/services/broadcast/BroadcastDriver.d.ts +75 -0
  232. package/dist/services/broadcast/BroadcastDriver.d.ts.map +1 -0
  233. package/dist/services/broadcast/BroadcastEvent.d.ts +67 -0
  234. package/dist/services/broadcast/BroadcastEvent.d.ts.map +1 -0
  235. package/dist/services/broadcast/BroadcastManager.d.ts +148 -0
  236. package/dist/services/broadcast/BroadcastManager.d.ts.map +1 -0
  237. package/dist/services/broadcast/BroadcastServiceProvider.d.ts +26 -0
  238. package/dist/services/broadcast/BroadcastServiceProvider.d.ts.map +1 -0
  239. package/dist/services/broadcast/FakeBroadcastManager.d.ts +45 -0
  240. package/dist/services/broadcast/FakeBroadcastManager.d.ts.map +1 -0
  241. package/dist/services/broadcast/MemoryBroadcastDriver.d.ts +23 -0
  242. package/dist/services/broadcast/MemoryBroadcastDriver.d.ts.map +1 -0
  243. package/dist/services/broadcast/RedisBroadcastDriver.d.ts +155 -0
  244. package/dist/services/broadcast/RedisBroadcastDriver.d.ts.map +1 -0
  245. package/dist/services/broadcast/SocketHub.d.ts +201 -0
  246. package/dist/services/broadcast/SocketHub.d.ts.map +1 -0
  247. package/dist/services/broadcast/brand.d.ts +16 -0
  248. package/dist/services/broadcast/brand.d.ts.map +1 -0
  249. package/dist/services/broadcast/channels.d.ts +77 -0
  250. package/dist/services/broadcast/channels.d.ts.map +1 -0
  251. package/dist/services/broadcast/config.d.ts +106 -0
  252. package/dist/services/broadcast/config.d.ts.map +1 -0
  253. package/dist/services/broadcast/protocol.d.ts +123 -0
  254. package/dist/services/broadcast/protocol.d.ts.map +1 -0
  255. package/dist/services/broadcast/socketTag.d.ts +17 -0
  256. package/dist/services/broadcast/socketTag.d.ts.map +1 -0
  257. package/dist/services/broadcast/types.d.ts +27 -0
  258. package/dist/services/broadcast/types.d.ts.map +1 -0
  259. package/dist/services/broadcast/wire.d.ts +35 -0
  260. package/dist/services/broadcast/wire.d.ts.map +1 -0
  261. package/dist/services/broadcast/workerWarning.d.ts +10 -0
  262. package/dist/services/broadcast/workerWarning.d.ts.map +1 -0
  263. package/dist/services/events/EventManager.d.ts +6 -0
  264. package/dist/services/events/EventManager.d.ts.map +1 -1
  265. package/dist/services/index.d.ts +10 -0
  266. package/dist/services/index.d.ts.map +1 -1
  267. package/dist/services/index.js +9 -9
  268. package/dist/services/index.js.map +4 -3
  269. package/dist/services/queue/WorkerProcess.d.ts.map +1 -1
  270. package/dist/services/queue/work.js +2 -2
  271. package/dist/services/queue/work.js.map +5 -4
  272. package/dist/services/router/config.d.ts +7 -0
  273. package/dist/services/router/config.d.ts.map +1 -1
  274. package/dist/stats/route-table.js +1 -1
  275. package/dist/support/index.js +2 -2
  276. package/dist/support/index.js.map +1 -1
  277. package/dist/testing/Page.d.ts +8 -0
  278. package/dist/testing/Page.d.ts.map +1 -1
  279. package/dist/testing/index.d.ts +2 -0
  280. package/dist/testing/index.d.ts.map +1 -1
  281. package/dist/testing/index.js +174 -8
  282. package/dist/testing/index.js.map +1 -1
  283. package/dist/vitest/index.js +1 -1
  284. package/package.json +1 -1
  285. package/skills/gemi-react-best-practices/SKILL.md +3 -1
  286. package/skills/gemi-react-best-practices/rules/query-live-over-polling.md +56 -0
  287. package/dist/chunk-2n3pgfnb.js +0 -5
  288. package/dist/chunk-2n3pgfnb.js.map +0 -10
  289. package/dist/chunk-2yw4yezc.js +0 -24
  290. package/dist/chunk-3rvn9a76.js +0 -58
  291. package/dist/chunk-3s21p9n2.js +0 -57
  292. package/dist/chunk-dyp0wg9e.js +0 -10
  293. package/dist/chunk-htgmy3x7.js +0 -5
  294. package/dist/chunk-krtybgz1.js +0 -4
  295. package/dist/chunk-krtybgz1.js.map +0 -10
  296. package/dist/chunk-s07v65x6.js +0 -9
  297. package/dist/chunk-s07v65x6.js.map +0 -10
  298. package/dist/chunks/ThemeProvider-BLI4zpLu.js.map +0 -1
  299. /package/dist/{chunk-dhbgrv58.js.map → chunk-3j6s5bmx.js.map} +0 -0
  300. /package/dist/{chunk-zg6hmc48.js.map → chunk-5e22tm7m.js.map} +0 -0
  301. /package/dist/{chunk-0k02tza1.js.map → chunk-65s834td.js.map} +0 -0
  302. /package/dist/{chunk-y6wt5b6t.js.map → chunk-c4jnxmf2.js.map} +0 -0
  303. /package/dist/{chunk-wjkh2gem.js.map → chunk-j7v7dft7.js.map} +0 -0
  304. /package/dist/{chunk-cvr5624r.js.map → chunk-wbg2tza5.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"WorkerProcess.d.ts","sourceRoot":"","sources":["../../../services/queue/WorkerProcess.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAsC,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGlG,8CAA8C;AAC9C,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACrE,CAAC;AAEF;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,SAAwB;CAC7B;AAED;;;;;;;;;GASG;AACH,qBAAa,WAAW;IAWpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAE5C;;;;OAIG;gBAEgB,MAAM,EAAE,YAAY,EACrC,QAAQ,GAAE,OAAO,CAAC,gBAAgB,CAAM;IAK1C;;;;;;;;;;;OAWG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC5B;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,QAAQ,GAAE,OAAO,CAAC,gBAAgB,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAKjD,KAAK;CAqBpB"}
1
+ {"version":3,"file":"WorkerProcess.d.ts","sourceRoot":"","sources":["../../../services/queue/WorkerProcess.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAsC,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIlG,8CAA8C;AAC9C,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACrE,CAAC;AAEF;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,SAAwB;CAC7B;AAED;;;;;;;;;GASG;AACH,qBAAa,WAAW;IAWpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAE5C;;;;OAIG;gBAEgB,MAAM,EAAE,YAAY,EACrC,QAAQ,GAAE,OAAO,CAAC,gBAAgB,CAAM;IAK1C;;;;;;;;;;;OAWG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0C5B;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,QAAQ,GAAE,OAAO,CAAC,gBAAgB,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAKjD,KAAK;CAqBpB"}
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{Mc as E,Pc as T}from"../../chunk-dwedx1jb.js";import"../../chunk-meg8rtr6.js";import"../../chunk-h43jp8ws.js";import"../../chunk-s07v65x6.js";import"../../chunk-gc2dz11k.js";import"../../chunk-nz8z8jr1.js";import"../../chunk-4fx8p02c.js";import{Zi as I,_i as J,bj as O}from"../../chunk-2n3pgfnb.js";import{fj as N}from"../../chunk-d5f1m3d2.js";import"../../chunk-tewhms9w.js";import L from"path";class F extends Error{name="QueueWorkerRefused"}class H{kernel;stopping;keepAlive;settings;constructor(y,z={}){this.kernel=y;this.settings={...J(),...z}}async start(){if(await this.kernel.waitForBoot(),this.stopping)return;let y=this.kernel.app;if(!y.bound(E))throw new F("[gemi] `gemi queue:work` has no queue to claim from: this application does not register QueueServiceProvider.");let z=y.make(E);if(!z.durable)throw new F('[gemi] `gemi queue:work` refuses to start: the queue uses the memory driver, which keeps each job in the process that dispatched it, so a worker never sees one. Set `driver: "database"` (or another driver every process can reach) in app/config/queue.ts, or run jobs in the server and drop the worker.');z.start(),this.keepAlive=setInterval(()=>{},1073741824),console.log(`[gemi] Queue worker started: claiming up to ${z.config.concurrency} job(s) at a time.`)}stop(y={}){return this.stopping??=this.drain({...this.settings,...y}),this.stopping}async drain(y){I();let z=this.kernel.app,A=z.resolved(E)?z.make(E):void 0;if(A)console.log(`[gemi] Shutting down: waiting for ${A.running} running job(s) (up to ${y.timeoutMs/1000}s).`),await A.drain(y.timeoutMs);let B=await this.kernel.shutdown({timeoutMs:y.providerTimeoutMs});clearInterval(this.keepAlive);let C=(A?.running??0)===0&&B.failed.length===0&&B.timedOut.length===0;return console.log(`[gemi] Shutdown ${C?"complete":"finished with errors"}.`),C?0:1}}async function U(){let y=N();process.env.ROOT_DIR=y,process.env.APP_DIR=L.join(y,"app"),T();let z=L.join(y,"app/kernel/Kernel.ts"),{default:A}=await import(z);if(typeof A!=="function")return console.error(`[gemi] ${z} has no default export to boot the worker from.`),1;let B=new A;B.boot();let C=new H(B);O(()=>C.stop());try{await C.start()}catch(G){if(!(G instanceof F))throw G;return console.error(G.message),1}return}U().then((y)=>{if(y!==void 0)process.exit(y)},(y)=>{console.error("[gemi] The queue worker failed to start:",y),process.exit(1)});
2
+ import{Rc as H,Uc as _}from"../../chunk-92sk56n0.js";import{gi as O}from"../../chunk-skf89vrv.js";import"../../chunk-mqtfaqx5.js";import"../../chunk-pe46a5a5.js";import"../../chunk-qycwjzsv.js";import"../../chunk-mvkz22p4.js";import"../../chunk-rpyczdta.js";import"../../chunk-zsvav1dk.js";import{Cj as Z,yj as U,zj as V}from"../../chunk-nnarmbjv.js";import{Gj as Y}from"../../chunk-nkzmk7v3.js";import"../../chunk-17dndh5z.js";import X from"path";function T(z){if(!z.config.get("route.channels"))return null;let C=z.config.get("broadcast",{}).driver;if(!(C===void 0||C==="memory"||C instanceof O))return null;return'[gemi] Broadcasts from this worker reach no one: the broadcast driver is "memory", which delivers to the sockets of the process that emits, and a worker has none. Set `driver: "redis"` in app/config/broadcast.ts.'}class J extends Error{name="QueueWorkerRefused"}class N{kernel;stopping;keepAlive;settings;constructor(z,C={}){this.kernel=z;this.settings={...V(),...C}}async start(){if(await this.kernel.waitForBoot(),this.stopping)return;let z=this.kernel.app;if(!z.bound(H))throw new J("[gemi] `gemi queue:work` has no queue to claim from: this application does not register QueueServiceProvider.");let C=z.make(H);if(!C.durable)throw new J('[gemi] `gemi queue:work` refuses to start: the queue uses the memory driver, which keeps each job in the process that dispatched it, so a worker never sees one. Set `driver: "database"` (or another driver every process can reach) in app/config/queue.ts, or run jobs in the server and drop the worker.');C.start(),this.keepAlive=setInterval(()=>{},1073741824),console.log(`[gemi] Queue worker started: claiming up to ${C.config.concurrency} job(s) at a time.`);let E=T(z);if(E)console.warn(E)}stop(z={}){return this.stopping??=this.drain({...this.settings,...z}),this.stopping}async drain(z){U();let C=this.kernel.app,E=C.resolved(H)?C.make(H):void 0;if(E)console.log(`[gemi] Shutting down: waiting for ${E.running} running job(s) (up to ${z.timeoutMs/1000}s).`),await E.drain(z.timeoutMs);let F=await this.kernel.shutdown({timeoutMs:z.providerTimeoutMs});clearInterval(this.keepAlive);let G=(E?.running??0)===0&&F.failed.length===0&&F.timedOut.length===0;return console.log(`[gemi] Shutdown ${G?"complete":"finished with errors"}.`),G?0:1}}async function $(){let z=Y();process.env.ROOT_DIR=z,process.env.APP_DIR=X.join(z,"app"),_();let C=X.join(z,"app/kernel/Kernel.ts"),{default:E}=await import(C);if(typeof E!=="function")return console.error(`[gemi] ${C} has no default export to boot the worker from.`),1;let F=new E;F.boot();let G=new N(F);Z(()=>G.stop());try{await G.start()}catch(L){if(!(L instanceof J))throw L;return console.error(L.message),1}return}$().then((z)=>{if(z!==void 0)process.exit(z)},(z)=>{console.error("[gemi] The queue worker failed to start:",z),process.exit(1)});
3
3
 
4
- //# debugId=6BB0BA54803EFE8864756E2164756E21
4
+ //# debugId=FEF3202E4247CD0A64756E2164756E21
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../services/queue/work.ts", "../services/queue/WorkerProcess.ts"],
3
+ "sources": ["../services/queue/work.ts", "../services/broadcast/workerWarning.ts", "../services/queue/WorkerProcess.ts"],
4
4
  "sourcesContent": [
5
5
  "/**\n * The entry point `gemi queue:work` spawns.\n *\n * Exposed as `gemi/queue/work` and resolved by the CLI out of the\n * *application's* `node_modules`, for the reason `gemi/console/run` is: the\n * application's kernel, providers and jobs are built from its copy of gemi,\n * and the worker that drives them should be the same copy, not one bundled\n * into the CLI.\n *\n * Everything worth testing is in `QueueWorker`; this file is the order the\n * process does things in.\n */\nimport path from \"node:path\";\n\nimport { installShutdownSignals } from \"../../server/shutdown\";\nimport { projectRoot } from \"../../support/discover\";\nimport { markQueueWorker } from \"./QueueManager\";\nimport { QueueWorker, QueueWorkerRefused, type WorkerKernel } from \"./WorkerProcess\";\n\nasync function main(): Promise<number | undefined> {\n const rootDir = projectRoot();\n // What `Server.start` and `httpProd` set, and for the same readers: a\n // `worker = true` job's thread finds the application through them, and the\n // log provider resolves its paths from `ROOT_DIR`.\n process.env.ROOT_DIR = rootDir;\n process.env.APP_DIR = path.join(rootDir, \"app\");\n // Before the kernel is imported, so no claim rule can be asked first.\n markQueueWorker();\n\n const kernelPath = path.join(rootDir, \"app/kernel/Kernel.ts\");\n const { default: Kernel } = (await import(kernelPath)) as {\n default?: new () => WorkerKernel & { boot(): void };\n };\n if (typeof Kernel !== \"function\") {\n console.error(`[gemi] ${kernelPath} has no default export to boot the worker from.`);\n return 1;\n }\n const kernel = new Kernel();\n kernel.boot();\n\n const worker = new QueueWorker(kernel);\n // Before the boot, as `Server.start` does in production: the boot is the\n // slow part, and a signal that lands in it would otherwise kill the process\n // on the spot. In development too, unlike a server — no `bun --hot` re-runs\n // this, and a Ctrl+C that lets the jobs finish is what a worker is for.\n installShutdownSignals(() => worker.stop());\n\n try {\n await worker.start();\n } catch (error) {\n if (!(error instanceof QueueWorkerRefused)) throw error;\n console.error(error.message);\n return 1;\n }\n // Running: the signal handler exits the process once it has drained.\n return undefined;\n}\n\nmain().then(\n (code) => {\n if (code !== undefined) process.exit(code);\n },\n (error) => {\n console.error(\"[gemi] The queue worker failed to start:\", error);\n process.exit(1);\n },\n);\n",
6
- "import type { Application, ShutdownReport } from \"../../foundation/Application\";\nimport { markShuttingDown, shutdownSettings, type ShutdownSettings } from \"../../server/shutdown\";\nimport { QueueManager } from \"./QueueManager\";\n\n/** The part of a `Kernel` a worker drives. */\nexport type WorkerKernel = {\n readonly app: Application;\n waitForBoot(): Promise<void>;\n shutdown(options?: { timeoutMs?: number }): Promise<ShutdownReport>;\n};\n\n/**\n * A worker that was told to start in an application it cannot claim for. The\n * message is written for the operator reading the deploy's logs.\n */\nexport class QueueWorkerRefused extends Error {\n name = \"QueueWorkerRefused\";\n}\n\n/**\n * The process `gemi queue:work` runs: the application booted as a server boots\n * it, claiming from the queue, and no `Bun.serve`. It exists so job capacity\n * can be scaled apart from request traffic, which needs a driver both kinds of\n * process can reach; see `start` for why the memory driver is refused.\n *\n * The caller marks the process as a worker (`markQueueWorker`) before the\n * kernel registers, so every claim rule that asks `claimsInThisProcess` sees a\n * process that claims, whatever `GEMI_QUEUE_CLAIM` says.\n */\nexport class QueueWorker {\n private stopping: Promise<number> | undefined;\n private keepAlive: ReturnType<typeof setInterval> | undefined;\n private readonly settings: ShutdownSettings;\n\n /**\n * `settings` default to the `GEMI_SHUTDOWN_*` variables, read here rather\n * than at the signal so a bad value is warned about while the deploy is\n * being watched, as `Server.start` does.\n */\n constructor(\n private readonly kernel: WorkerKernel,\n settings: Partial<ShutdownSettings> = {},\n ) {\n this.settings = { ...shutdownSettings(), ...settings };\n }\n\n /**\n * Boots the application and starts claiming. Rejects with\n * `QueueWorkerRefused` when the application has no queue, or its queue uses\n * the memory driver.\n *\n * Refused rather than warned about, because a memory worker can never do\n * anything: its jobs live in a `Map` in the process that dispatched them,\n * so a worker's is always empty. Left running, it looks like a healthy\n * deploy — a process up, no errors — that runs nothing, and scaling it out\n * adds no capacity. An exit the platform reports as a crash loop is a form\n * of the mistake someone will see.\n */\n async start(): Promise<void> {\n await this.kernel.waitForBoot();\n // A signal during the boot has already drained and cleared the handle\n // below. Going on would start the loop again and arm a handle nothing\n // clears, holding open a worker that has finished shutting down.\n if (this.stopping) return;\n\n const application = this.kernel.app;\n // `bound`, not `make` in a try: an application built without the queue\n // provider is a configuration to name, not an unbound-token stack trace.\n if (!application.bound(QueueManager)) {\n throw new QueueWorkerRefused(\n \"[gemi] `gemi queue:work` has no queue to claim from: this application \" +\n \"does not register QueueServiceProvider.\",\n );\n }\n const queue = application.make(QueueManager);\n if (!queue.durable) {\n throw new QueueWorkerRefused(\n \"[gemi] `gemi queue:work` refuses to start: the queue uses the memory \" +\n \"driver, which keeps each job in the process that dispatched it, so \" +\n 'a worker never sees one. Set `driver: \"database\"` (or another driver ' +\n \"every process can reach) in app/config/queue.ts, or run jobs in the \" +\n \"server and drop the worker.\",\n );\n }\n\n // Idempotent: a production boot with a durable driver has already started\n // it (`startClaimingIfServing`). Development has not, and a worker claims\n // in either.\n queue.start();\n // The queue's poll timer is unref'd, so that a script's queue does not\n // hold it open; here the queue is the process, and without a handle of its\n // own an idle worker would exit 0 as soon as it booted.\n this.keepAlive = setInterval(() => {}, 1 << 30);\n console.log(\n `[gemi] Queue worker started: claiming up to ${queue.config.concurrency} job(s) at a time.`,\n );\n }\n\n /**\n * Stops claiming, waits for the running jobs, runs every provider's\n * `shutdown()`, and resolves with the exit code: 0 when no job was left\n * running and every provider finished in time, 1 otherwise. Idempotent.\n *\n * `gemi start`'s drain, with the jobs where the requests were:\n * `isShuttingDown()` turns true, which stops a durable queue claiming;\n * running jobs get `timeoutMs` (`GEMI_SHUTDOWN_TIMEOUT`), which a server\n * spends on requests; then `Application.shutdown` gets `providerTimeoutMs`,\n * and in it the queue provider waits for whatever is still running and\n * names it. The two budgets add up as they do for a server, so a worker\n * fits the same grace period. `delayMs` is not waited: it is for a load\n * balancer, and nothing routes to a worker.\n */\n stop(settings: Partial<ShutdownSettings> = {}): Promise<number> {\n this.stopping ??= this.drain({ ...this.settings, ...settings });\n return this.stopping;\n }\n\n private async drain(settings: ShutdownSettings): Promise<number> {\n markShuttingDown();\n const application = this.kernel.app;\n // Resolving the manager now would build a driver only to stop it, which\n // is what a signal during the boot, before the provider resolved it, finds.\n const queue = application.resolved(QueueManager) ? application.make(QueueManager) : undefined;\n if (queue) {\n console.log(\n `[gemi] Shutting down: waiting for ${queue.running} running job(s) ` +\n `(up to ${settings.timeoutMs / 1000}s).`,\n );\n await queue.drain(settings.timeoutMs);\n }\n\n const report = await this.kernel.shutdown({ timeoutMs: settings.providerTimeoutMs });\n clearInterval(this.keepAlive);\n const clean =\n (queue?.running ?? 0) === 0 && report.failed.length === 0 && report.timedOut.length === 0;\n console.log(`[gemi] Shutdown ${clean ? \"complete\" : \"finished with errors\"}.`);\n return clean ? 0 : 1;\n }\n}\n"
6
+ "import type { Application } from \"../../foundation/Application\";\nimport type { BroadcastConfig } from \"./config\";\nimport { MemoryBroadcastDriver } from \"./MemoryBroadcastDriver\";\n\n/**\n * What `gemi queue:work` warns at boot when the app declares channels but\n * broadcasts with the memory driver, or `null`. A worker has no sockets, so\n * with the memory driver its jobs' emits reach no one, with nothing else to\n * say so. A warning, not a refusal as for a memory queue: the worker still\n * runs its jobs, only their broadcasts are lost.\n */\nexport function memoryBroadcastInWorker(application: Application): string | null {\n if (!application.config.get(\"route.channels\")) return null;\n const driver = application.config.get<BroadcastConfig>(\"broadcast\", {}).driver;\n const memory =\n driver === undefined || driver === \"memory\" || driver instanceof MemoryBroadcastDriver;\n if (!memory) return null;\n return (\n \"[gemi] Broadcasts from this worker reach no one: the broadcast driver is \" +\n '\"memory\", which delivers to the sockets of the process that emits, and a ' +\n 'worker has none. Set `driver: \"redis\"` in app/config/broadcast.ts.'\n );\n}\n",
7
+ "import type { Application, ShutdownReport } from \"../../foundation/Application\";\nimport { markShuttingDown, shutdownSettings, type ShutdownSettings } from \"../../server/shutdown\";\nimport { memoryBroadcastInWorker } from \"../broadcast/workerWarning\";\nimport { QueueManager } from \"./QueueManager\";\n\n/** The part of a `Kernel` a worker drives. */\nexport type WorkerKernel = {\n readonly app: Application;\n waitForBoot(): Promise<void>;\n shutdown(options?: { timeoutMs?: number }): Promise<ShutdownReport>;\n};\n\n/**\n * A worker that was told to start in an application it cannot claim for. The\n * message is written for the operator reading the deploy's logs.\n */\nexport class QueueWorkerRefused extends Error {\n name = \"QueueWorkerRefused\";\n}\n\n/**\n * The process `gemi queue:work` runs: the application booted as a server boots\n * it, claiming from the queue, and no `Bun.serve`. It exists so job capacity\n * can be scaled apart from request traffic, which needs a driver both kinds of\n * process can reach; see `start` for why the memory driver is refused.\n *\n * The caller marks the process as a worker (`markQueueWorker`) before the\n * kernel registers, so every claim rule that asks `claimsInThisProcess` sees a\n * process that claims, whatever `GEMI_QUEUE_CLAIM` says.\n */\nexport class QueueWorker {\n private stopping: Promise<number> | undefined;\n private keepAlive: ReturnType<typeof setInterval> | undefined;\n private readonly settings: ShutdownSettings;\n\n /**\n * `settings` default to the `GEMI_SHUTDOWN_*` variables, read here rather\n * than at the signal so a bad value is warned about while the deploy is\n * being watched, as `Server.start` does.\n */\n constructor(\n private readonly kernel: WorkerKernel,\n settings: Partial<ShutdownSettings> = {},\n ) {\n this.settings = { ...shutdownSettings(), ...settings };\n }\n\n /**\n * Boots the application and starts claiming. Rejects with\n * `QueueWorkerRefused` when the application has no queue, or its queue uses\n * the memory driver.\n *\n * Refused rather than warned about, because a memory worker can never do\n * anything: its jobs live in a `Map` in the process that dispatched them,\n * so a worker's is always empty. Left running, it looks like a healthy\n * deploy — a process up, no errors — that runs nothing, and scaling it out\n * adds no capacity. An exit the platform reports as a crash loop is a form\n * of the mistake someone will see.\n */\n async start(): Promise<void> {\n await this.kernel.waitForBoot();\n // A signal during the boot has already drained and cleared the handle\n // below. Going on would start the loop again and arm a handle nothing\n // clears, holding open a worker that has finished shutting down.\n if (this.stopping) return;\n\n const application = this.kernel.app;\n // `bound`, not `make` in a try: an application built without the queue\n // provider is a configuration to name, not an unbound-token stack trace.\n if (!application.bound(QueueManager)) {\n throw new QueueWorkerRefused(\n \"[gemi] `gemi queue:work` has no queue to claim from: this application \" +\n \"does not register QueueServiceProvider.\",\n );\n }\n const queue = application.make(QueueManager);\n if (!queue.durable) {\n throw new QueueWorkerRefused(\n \"[gemi] `gemi queue:work` refuses to start: the queue uses the memory \" +\n \"driver, which keeps each job in the process that dispatched it, so \" +\n 'a worker never sees one. Set `driver: \"database\"` (or another driver ' +\n \"every process can reach) in app/config/queue.ts, or run jobs in the \" +\n \"server and drop the worker.\",\n );\n }\n\n // Idempotent: a production boot with a durable driver has already started\n // it (`startClaimingIfServing`). Development has not, and a worker claims\n // in either.\n queue.start();\n // The queue's poll timer is unref'd, so that a script's queue does not\n // hold it open; here the queue is the process, and without a handle of its\n // own an idle worker would exit 0 as soon as it booted.\n this.keepAlive = setInterval(() => {}, 1 << 30);\n console.log(\n `[gemi] Queue worker started: claiming up to ${queue.config.concurrency} job(s) at a time.`,\n );\n const broadcastWarning = memoryBroadcastInWorker(application);\n if (broadcastWarning) console.warn(broadcastWarning);\n }\n\n /**\n * Stops claiming, waits for the running jobs, runs every provider's\n * `shutdown()`, and resolves with the exit code: 0 when no job was left\n * running and every provider finished in time, 1 otherwise. Idempotent.\n *\n * `gemi start`'s drain, with the jobs where the requests were:\n * `isShuttingDown()` turns true, which stops a durable queue claiming;\n * running jobs get `timeoutMs` (`GEMI_SHUTDOWN_TIMEOUT`), which a server\n * spends on requests; then `Application.shutdown` gets `providerTimeoutMs`,\n * and in it the queue provider waits for whatever is still running and\n * names it. The two budgets add up as they do for a server, so a worker\n * fits the same grace period. `delayMs` is not waited: it is for a load\n * balancer, and nothing routes to a worker.\n */\n stop(settings: Partial<ShutdownSettings> = {}): Promise<number> {\n this.stopping ??= this.drain({ ...this.settings, ...settings });\n return this.stopping;\n }\n\n private async drain(settings: ShutdownSettings): Promise<number> {\n markShuttingDown();\n const application = this.kernel.app;\n // Resolving the manager now would build a driver only to stop it, which\n // is what a signal during the boot, before the provider resolved it, finds.\n const queue = application.resolved(QueueManager) ? application.make(QueueManager) : undefined;\n if (queue) {\n console.log(\n `[gemi] Shutting down: waiting for ${queue.running} running job(s) ` +\n `(up to ${settings.timeoutMs / 1000}s).`,\n );\n await queue.drain(settings.timeoutMs);\n }\n\n const report = await this.kernel.shutdown({ timeoutMs: settings.providerTimeoutMs });\n clearInterval(this.keepAlive);\n const clean =\n (queue?.running ?? 0) === 0 && report.failed.length === 0 && report.timedOut.length === 0;\n console.log(`[gemi] Shutdown ${clean ? \"complete\" : \"finished with errors\"}.`);\n return clean ? 0 : 1;\n }\n}\n"
7
8
  ],
8
- "mappings": ";iZAYA,kBCGO,IAAM,QAA2B,GAAM,DAC5C,GAAO,kBACT,DAYO,IAAM,CAAY,CAWJ,OAVX,SACA,UACS,SAOjB,WAAW,CACQ,EACjB,EAAsC,CAAC,EACvC,CAFiB,cAGjB,KAAK,SAAW,IAAK,EAAiB,KAAM,CAAS,OAejD,MAAK,EAAkB,CAK3B,GAJA,MAAM,KAAK,OAAO,YAAY,EAI1B,KAAK,SAAU,OAEnB,IAAM,EAAc,KAAK,OAAO,IAGhC,GAAI,CAAC,EAAY,MAAM,CAAY,EACjC,MAAM,IAAI,EACR,+GAEF,EAEF,IAAM,EAAQ,EAAY,KAAK,CAAY,EAC3C,GAAI,CAAC,EAAM,QACT,MAAM,IAAI,EACR,8SAKF,EAMF,EAAM,MAAM,EAIZ,KAAK,UAAY,YAAY,IAAM,GAAI,UAAO,EAC9C,QAAQ,IACN,+CAA+C,EAAM,OAAO,+BAC9D,EAiBF,IAAI,CAAC,EAAsC,CAAC,EAAoB,CAE9D,OADA,KAAK,WAAa,KAAK,MAAM,IAAK,KAAK,YAAa,CAAS,CAAC,EACvD,KAAK,cAGA,MAAK,CAAC,EAA6C,CAC/D,EAAiB,EACjB,IAAM,EAAc,KAAK,OAAO,IAG1B,EAAQ,EAAY,SAAS,CAAY,EAAI,EAAY,KAAK,CAAY,EAAI,OACpF,GAAI,EACF,QAAQ,IACN,qCAAqC,EAAM,iCAC/B,EAAS,UAAY,SACnC,EACA,MAAM,EAAM,MAAM,EAAS,SAAS,EAGtC,IAAM,EAAS,MAAM,KAAK,OAAO,SAAS,CAAE,UAAW,EAAS,iBAAkB,CAAC,EACnF,cAAc,KAAK,SAAS,EAC5B,IAAM,GACH,GAAO,SAAW,KAAO,GAAK,EAAO,OAAO,SAAW,GAAK,EAAO,SAAS,SAAW,EAE1F,OADA,QAAQ,IAAI,mBAAmB,EAAQ,WAAa,yBAAyB,EACtE,EAAQ,EAAI,EAEvB,CDvHA,eAAe,CAAI,EAAgC,CACjD,IAAM,EAAU,EAAY,EAI5B,QAAQ,IAAI,SAAW,EACvB,QAAQ,IAAI,QAAU,EAAK,KAAK,EAAS,KAAK,EAE9C,EAAgB,EAEhB,IAAM,EAAa,EAAK,KAAK,EAAS,sBAAsB,GACpD,QAAS,GAAY,MAAa,UAG1C,GAAI,OAAO,IAAW,WAEpB,OADA,QAAQ,MAAM,UAAU,kDAA2D,EAC5E,EAET,IAAM,EAAS,IAAI,EACnB,EAAO,KAAK,EAEZ,IAAM,EAAS,IAAI,EAAY,CAAM,EAKrC,EAAuB,IAAM,EAAO,KAAK,CAAC,EAE1C,GAAI,CACF,MAAM,EAAO,MAAM,EACnB,MAAO,EAAO,CACd,GAAI,EAAE,aAAiB,GAAqB,MAAM,EAElD,OADA,QAAQ,MAAM,EAAM,OAAO,EACpB,EAGT,OAGF,EAAK,EAAE,KACL,CAAC,IAAS,CACR,GAAI,IAAS,OAAW,QAAQ,KAAK,CAAI,GAE3C,CAAC,IAAU,CACT,QAAQ,MAAM,2CAA4C,CAAK,EAC/D,QAAQ,KAAK,CAAC,EAElB",
9
- "debugId": "6BB0BA54803EFE8864756E2164756E21",
9
+ "mappings": ";gcAYA,kBCDO,OAAS,DAAuB,DAAC,AAAyC,DAC/E,CAAI,DAAC,AAAY,KAAO,IAAI,gBAAgB,EAAG,OAAO,KACtD,IAAM,EAAS,EAAY,OAAO,IAAqB,YAAa,CAAC,CAAC,EAAE,OAGxE,GAAI,EADF,IAAW,QAAa,IAAW,UAAY,aAAkB,GACtD,OAAO,KACpB,MACE,uNCFG,MAAM,UAA2B,KAAM,CAC5C,KAAO,oBACT,CAYO,MAAM,CAAY,CAWJ,OAVX,SACA,UACS,SAOjB,WAAW,CACQ,EACjB,EAAsC,CAAC,EACvC,CAFiB,cAGjB,KAAK,SAAW,IAAK,EAAiB,KAAM,CAAS,OAejD,MAAK,EAAkB,CAK3B,GAJA,MAAM,KAAK,OAAO,YAAY,EAI1B,KAAK,SAAU,OAEnB,IAAM,EAAc,KAAK,OAAO,IAGhC,GAAI,CAAC,EAAY,MAAM,CAAY,EACjC,MAAM,IAAI,EACR,+GAEF,EAEF,IAAM,EAAQ,EAAY,KAAK,CAAY,EAC3C,GAAI,CAAC,EAAM,QACT,MAAM,IAAI,EACR,8SAKF,EAMF,EAAM,MAAM,EAIZ,KAAK,UAAY,YAAY,IAAM,GAAI,UAAO,EAC9C,QAAQ,IACN,+CAA+C,EAAM,OAAO,+BAC9D,EACA,IAAM,EAAmB,EAAwB,CAAW,EAC5D,GAAI,EAAkB,QAAQ,KAAK,CAAgB,EAiBrD,IAAI,CAAC,EAAsC,CAAC,EAAoB,CAE9D,OADA,KAAK,WAAa,KAAK,MAAM,IAAK,KAAK,YAAa,CAAS,CAAC,EACvD,KAAK,cAGA,MAAK,CAAC,EAA6C,CAC/D,EAAiB,EACjB,IAAM,EAAc,KAAK,OAAO,IAG1B,EAAQ,EAAY,SAAS,CAAY,EAAI,EAAY,KAAK,CAAY,EAAI,OACpF,GAAI,EACF,QAAQ,IACN,qCAAqC,EAAM,iCAC/B,EAAS,UAAY,SACnC,EACA,MAAM,EAAM,MAAM,EAAS,SAAS,EAGtC,IAAM,EAAS,MAAM,KAAK,OAAO,SAAS,CAAE,UAAW,EAAS,iBAAkB,CAAC,EACnF,cAAc,KAAK,SAAS,EAC5B,IAAM,GACH,GAAO,SAAW,KAAO,GAAK,EAAO,OAAO,SAAW,GAAK,EAAO,SAAS,SAAW,EAE1F,OADA,QAAQ,IAAI,mBAAmB,EAAQ,WAAa,yBAAyB,EACtE,EAAQ,EAAI,EAEvB,CF1HA,eAAe,CAAI,EAAgC,CACjD,IAAM,EAAU,EAAY,EAI5B,QAAQ,IAAI,SAAW,EACvB,QAAQ,IAAI,QAAU,EAAK,KAAK,EAAS,KAAK,EAE9C,EAAgB,EAEhB,IAAM,EAAa,EAAK,KAAK,EAAS,sBAAsB,GACpD,QAAS,GAAY,MAAa,UAG1C,GAAI,OAAO,IAAW,WAEpB,OADA,QAAQ,MAAM,UAAU,kDAA2D,EAC5E,EAET,IAAM,EAAS,IAAI,EACnB,EAAO,KAAK,EAEZ,IAAM,EAAS,IAAI,EAAY,CAAM,EAKrC,EAAuB,IAAM,EAAO,KAAK,CAAC,EAE1C,GAAI,CACF,MAAM,EAAO,MAAM,EACnB,MAAO,EAAO,CACd,GAAI,EAAE,aAAiB,GAAqB,MAAM,EAElD,OADA,QAAQ,MAAM,EAAM,OAAO,EACpB,EAGT,OAGF,EAAK,EAAE,KACL,CAAC,IAAS,CACR,GAAI,IAAS,OAAW,QAAQ,KAAK,CAAI,GAE3C,CAAC,IAAU,CACT,QAAQ,MAAM,2CAA4C,CAAK,EAC/D,QAAQ,KAAK,CAAC,EAElB",
10
+ "debugId": "FEF3202E4247CD0A64756E2164756E21",
10
11
  "names": []
11
12
  }
@@ -1,6 +1,7 @@
1
1
  import type { JSX } from "react";
2
2
  import type { HttpRequest } from "../../http/HttpRequest";
3
3
  import type { ApiRouter } from "../../http/ApiRouter";
4
+ import type { ChannelRouterClass } from "../../http/ChannelRouter";
4
5
  import type { McpRouter } from "../../http/McpRouter";
5
6
  import type { McpRemoteFileOptions } from "../mcp/McpRegistry";
6
7
  import type { McpRemoteHttpConfig } from "../mcp/http/McpHttpServer";
@@ -198,6 +199,12 @@ export interface RouteConfig {
198
199
  view: ViewRouteConfig;
199
200
  mcp?: McpRouteConfig;
200
201
  domains?: DomainsConfig;
202
+ /**
203
+ * The app's `ChannelRouter`, normally `app/http/routes/channels.ts`: the
204
+ * broadcast channels clients may subscribe to. Optional: without it every
205
+ * subscription is refused, and emits still work.
206
+ */
207
+ channels?: ChannelRouterClass;
201
208
  }
202
209
  export declare function defineRouteConfig(config: RouteConfig): RouteConfig;
203
210
  export declare function apiRouteConfigDefaults(): Omit<Required<ApiRouteConfig>, "rootRouter">;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../services/router/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../services/router/config.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import"../chunk-tewhms9w.js";import M from"path";import{writeFileSync as Q}from"fs";var L=new Set(["FILE","REDIRECT"]);function H(j){return j.run(()=>{let x=[];for(let{group:z,view:D}of j.domains().viewGroups())for(let[G,B]of Object.entries(D.flatViewRoutes)){let C=D.routeManifest[G]??B.segments.map((K)=>K.viewPath);if(C.length===0||L.has(C.at(-1)))continue;x.push({path:G,group:z,views:C,...B.static?{static:{...B.static.layout?{layout:B.static.layout}:{},...B.static.navigation?{navigation:!0}:{}}}:{}})}return x})}var J=process.argv[2];async function U(){if(!J)throw Error("usage: route-table <out.json>");let j=M.resolve(process.cwd(),"app/kernel/Kernel.ts"),x=await import(j);if(typeof x.default!=="function")throw Error(`${j} has no default export (the Kernel subclass).`);let z=new x.default;z.boot();try{Q(J,JSON.stringify(H(z)))}finally{z.destroy()}}U().then(()=>process.exit(0),(j)=>{console.error(j?.stack??String(j)),process.exit(1)});
2
+ import"../chunk-17dndh5z.js";import M from"path";import{writeFileSync as Q}from"fs";var L=new Set(["FILE","REDIRECT"]);function H(j){return j.run(()=>{let x=[];for(let{group:z,view:D}of j.domains().viewGroups())for(let[G,B]of Object.entries(D.flatViewRoutes)){let C=D.routeManifest[G]??B.segments.map((K)=>K.viewPath);if(C.length===0||L.has(C.at(-1)))continue;x.push({path:G,group:z,views:C,...B.static?{static:{...B.static.layout?{layout:B.static.layout}:{},...B.static.navigation?{navigation:!0}:{}}}:{}})}return x})}var J=process.argv[2];async function U(){if(!J)throw Error("usage: route-table <out.json>");let j=M.resolve(process.cwd(),"app/kernel/Kernel.ts"),x=await import(j);if(typeof x.default!=="function")throw Error(`${j} has no default export (the Kernel subclass).`);let z=new x.default;z.boot();try{Q(J,JSON.stringify(H(z)))}finally{z.destroy()}}U().then(()=>process.exit(0),(j)=>{console.error(j?.stack??String(j)),process.exit(1)});
3
3
 
4
4
  //# debugId=05EB0087C5A2060D64756E2164756E21
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{Tc as Y}from"../chunk-9xyxbxgk.js";import{Lh as M}from"../chunk-h43jp8ws.js";import{Ni as P,Pi as R}from"../chunk-nz8z8jr1.js";import"../chunk-4fx8p02c.js";import{cj as Q,dj as U,ej as V,fj as W}from"../chunk-d5f1m3d2.js";import"../chunk-tewhms9w.js";class S{static token;async boot(){}static inject(){if(!this.token)throw Error(`Service [${this.name}] does not declare a \`static token\`, so the container has no key to resolve it by.`);try{return R(this)}catch(x){throw Error(`Could not inject [${this.name}]. Services are constructed when the kernel boots, so `+"inject() only works from code that runs after that \u2014 a constructor default or a method "+`body, never module top level. Check that [${this.name}] is listed in \`services\` on your Kernel.`,{cause:x})}}static with(x){let f=new this;for(let[C,g]of Object.entries(x))if(g!==void 0)f[C]=g;return f}}import{readdir as z}from"fs/promises";import{join as B,parse as j}from"path";var H=[".ts",".tsx",".js",".mjs",".jsx"];function J(x={}){let f={};for(let[C,g]of Object.entries(x))f[C]=q(g);return new P(f)}async function L(x,f=new P){let C=[];try{C=await z(x)}catch(D){return f}let g=C.filter((D)=>{let{ext:v,name:F}=j(D);return H.includes(v)&&!F.startsWith(".")}).sort();for(let D of g){let{name:v}=j(D),F=await import(B(x,D));f.set(v,q(F))}return f}function q(x){if(x&&typeof x==="object"&&"default"in x)return x.default;return x}export{M as withDefaults,Q as sourceFiles,W as projectRoot,L as loadConfigFrom,V as discoverClasses,J as createConfigRepository,Y as ServiceProvider,S as Service,P as Repository,U as DiscoveryError};
2
+ import{Yc as Y}from"../chunk-30xxc6r7.js";import{ki as M}from"../chunk-pe46a5a5.js";import{mj as P,oj as R}from"../chunk-rpyczdta.js";import"../chunk-zsvav1dk.js";import{Dj as Q,Ej as U,Fj as V,Gj as W}from"../chunk-nkzmk7v3.js";import"../chunk-17dndh5z.js";class S{static token;async boot(){}static inject(){if(!this.token)throw Error(`Service [${this.name}] does not declare a \`static token\`, so the container has no key to resolve it by.`);try{return R(this)}catch(x){throw Error(`Could not inject [${this.name}]. Services are constructed when the kernel boots, so `+"inject() only works from code that runs after that \u2014 a constructor default or a method "+`body, never module top level. Check that [${this.name}] is listed in \`services\` on your Kernel.`,{cause:x})}}static with(x){let f=new this;for(let[C,g]of Object.entries(x))if(g!==void 0)f[C]=g;return f}}import{readdir as z}from"fs/promises";import{join as B,parse as j}from"path";var H=[".ts",".tsx",".js",".mjs",".jsx"];function J(x={}){let f={};for(let[C,g]of Object.entries(x))f[C]=q(g);return new P(f)}async function L(x,f=new P){let C=[];try{C=await z(x)}catch(D){return f}let g=C.filter((D)=>{let{ext:v,name:F}=j(D);return H.includes(v)&&!F.startsWith(".")}).sort();for(let D of g){let{name:v}=j(D),F=await import(B(x,D));f.set(v,q(F))}return f}function q(x){if(x&&typeof x==="object"&&"default"in x)return x.default;return x}export{M as withDefaults,Q as sourceFiles,W as projectRoot,L as loadConfigFrom,V as discoverClasses,J as createConfigRepository,Y as ServiceProvider,S as Service,P as Repository,U as DiscoveryError};
3
3
 
4
- //# debugId=FD3C9F750E2A58A164756E2164756E21
4
+ //# debugId=B8296DBCE0424B4764756E2164756E21
@@ -6,6 +6,6 @@
6
6
  "import { readdir } from \"node:fs/promises\";\nimport { join, parse } from \"node:path\";\n\nimport { Repository } from \"./Repository\";\n\nconst CONFIG_EXTENSIONS = [\".ts\", \".tsx\", \".js\", \".mjs\", \".jsx\"];\n\n// Builds a Repository from an already-imported map of config modules. The map\n// key becomes the top-level config key, so `{ mail: mailModule }` is readable\n// as `config.get(\"mail.driver\")`. Each entry may be either the module namespace\n// (its `default` export is unwrapped) or the config object itself.\nexport function createConfigRepository(\n modules: Record<string, any> = {},\n): Repository {\n const items: Record<string, any> = {};\n\n for (const [key, mod] of Object.entries(modules)) {\n items[key] = unwrap(mod);\n }\n\n return new Repository(items);\n}\n\n// Reads every config module in an app's `app/config` directory into a\n// Repository. The file's basename is the top-level key: `app/config/mail.ts`\n// populates `mail.*`. A missing directory yields an empty Repository so apps\n// that declare no config still boot.\nexport async function loadConfigFrom(\n directory: string,\n repository = new Repository(),\n): Promise<Repository> {\n let entries: string[] = [];\n\n try {\n entries = await readdir(directory);\n } catch (err) {\n return repository;\n }\n\n const files = entries\n .filter((entry) => {\n const { ext, name } = parse(entry);\n return CONFIG_EXTENSIONS.includes(ext) && !name.startsWith(\".\");\n })\n .sort();\n\n for (const file of files) {\n const { name } = parse(file);\n const mod = await import(join(directory, file));\n repository.set(name, unwrap(mod));\n }\n\n return repository;\n}\n\nfunction unwrap(mod: any) {\n if (mod && typeof mod === \"object\" && \"default\" in mod) {\n return mod.default;\n }\n return mod;\n}\n"
7
7
  ],
8
8
  "mappings": ";2RAgCO,CAAe,JAAQ,EAOrB,OAMD,AAAI,EAAkB,QAmBrB,OAAS,EAKX,CACH,GAAI,CAAC,KAAK,MACR,MAAU,MACR,YAAY,KAAK,0FACnB,EAGF,GAAI,CACF,OAAO,EAAI,IAAuB,EAClC,MAAO,EAAO,CACd,MAAU,MACR,qBAAqB,KAAK,6DACxB,+FACA,6CAA6C,KAAK,kDAEpD,CAAE,OAAM,CACV,SAoBG,KAAuB,CAAoB,EAA0B,CAC1E,IAAM,EAAW,IAAI,KACrB,QAAY,EAAK,KAAU,OAAO,QAAQ,CAAS,EACjD,GAAI,IAAU,OAAW,EAAS,GAAO,EAE3C,OAAO,EAEX,CChHA,kBAAS,oBACT,eAAS,WAAM,aAIf,IAAM,EAAoB,CAAC,MAAO,OAAQ,MAAO,OAAQ,MAAM,EAMxD,SAAS,CAAsB,CACpC,EAA+B,CAAC,EACpB,CACZ,IAAM,EAA6B,CAAC,EAEpC,QAAY,EAAK,KAAQ,OAAO,QAAQ,CAAO,EAC7C,EAAM,GAAO,EAAO,CAAG,EAGzB,OAAO,IAAI,EAAW,CAAK,EAO7B,eAAsB,CAAc,CAClC,EACA,EAAa,IAAI,EACI,CACrB,IAAI,EAAoB,CAAC,EAEzB,GAAI,CACF,EAAU,MAAM,EAAQ,CAAS,EACjC,MAAO,EAAK,CACZ,OAAO,EAGT,IAAM,EAAQ,EACX,OAAO,CAAC,IAAU,CACjB,IAAQ,MAAK,QAAS,EAAM,CAAK,EACjC,OAAO,EAAkB,SAAS,CAAG,GAAK,CAAC,EAAK,WAAW,GAAG,EAC/D,EACA,KAAK,EAER,QAAW,KAAQ,EAAO,CACxB,IAAQ,QAAS,EAAM,CAAI,EACrB,EAAM,MAAa,SAAK,EAAW,CAAI,GAC7C,EAAW,IAAI,EAAM,EAAO,CAAG,CAAC,EAGlC,OAAO,EAGT,SAAS,CAAM,CAAC,EAAU,CACxB,GAAI,GAAO,OAAO,IAAQ,UAAY,YAAa,EACjD,OAAO,EAAI,QAEb,OAAO",
9
- "debugId": "FD3C9F750E2A58A164756E2164756E21",
9
+ "debugId": "B8296DBCE0424B4764756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -3,6 +3,7 @@ import { type FallbackProps } from "react-error-boundary";
3
3
  import type { User } from "../auth/types";
4
4
  import { type QueryConfig } from "../client/QueryManagerContext";
5
5
  import type { ClientFeatureKey } from "../client/rpc";
6
+ import { FakeSocket } from "../client/realtime/FakeSocket";
6
7
  import type { Breadcrumb } from "../client/useBreadcrumbs";
7
8
  /**
8
9
  * A dictionary as `Dictionary.create` produces it: a name and a
@@ -150,6 +151,13 @@ export interface PageProps {
150
151
  * pathname it was given.
151
152
  */
152
153
  onNavigate?: (href: string, action: "push" | "replace") => void;
154
+ /**
155
+ * The socket `useChannel`, `useChannelInvalidate` and `useQuery({ live })`
156
+ * subscribe through: a `fakeSocket()` the test pushes events and resyncs
157
+ * into. Left out, a fake of the page's own is used, so a component test
158
+ * never opens a WebSocket.
159
+ */
160
+ socket?: FakeSocket;
153
161
  }
154
162
  /**
155
163
  * Mounts a component with the inputs a view normally arrives with — route
@@ -1 +1 @@
1
- {"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../testing/Page.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../testing/Page.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  export { Page } from "./Page";
2
2
  export type { PageProps, PageDictionary } from "./Page";
3
+ export { fakeSocket, FakeSocket } from "../client/realtime/FakeSocket";
4
+ export type { FakeSubscription } from "../client/realtime/FakeSocket";
3
5
  /**
4
6
  * The recorder `Event.fake()` installs, published here as a **type only**.
5
7
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,GACf,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AACvE,YAAY,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEtE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,GACf,MAAM,kBAAkB,CAAC"}
@@ -1,8 +1,170 @@
1
- import { B as QueryManagerProvider, D as I18nProvider, F as createMemoryHistory, I as toVariantKey, J as Subject, L as applyParams, N as ProgressManager, O as ServerDataContext, P as Action, i as RouteTransitionProvider, o as ClientRouterContext, r as m, t as ThemeProvider, z as QueryManagerContext } from "../chunks/ThemeProvider-BLI4zpLu.js";
1
+ import { D as I18nProvider, F as createMemoryHistory, I as RealtimeContext, K as QueryManagerContext, L as channelKey, N as ProgressManager, O as ServerDataContext, P as Action, U as toVariantKey, W as applyParams, i as RouteTransitionProvider, o as ClientRouterContext, q as QueryManagerProvider, r as m, t as ThemeProvider, tt as Subject } from "../chunks/ThemeProvider-CbOx8IRl.js";
2
2
  import { r as RouteStateProvider } from "../chunks/useParams-BN3XXfmG.js";
3
3
  import { Suspense, createElement, useContext, useMemo, useRef, useState } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { hydrateRoot } from "react-dom/client";
6
+ var LITERAL_SEGMENT = /^[A-Za-z0-9_-]+$/;
7
+ var PARAM_SEGMENT = /^:[A-Za-z_][A-Za-z0-9_]*$/;
8
+ var PARAM_VALUE = /^[A-Za-z0-9_-]{1,128}$/;
9
+ /** A pattern, topic or param was refused. The message says which and why. */
10
+ var InvalidChannelError = class extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = "InvalidChannelError";
14
+ }
15
+ };
16
+ /** The segments of a pattern, checked. Throws `InvalidChannelError`. */
17
+ function parsePattern(pattern) {
18
+ if (typeof pattern !== "string" || pattern.length === 0) throw new InvalidChannelError("A channel pattern must be a non-empty string.");
19
+ if (pattern.length > 255) throw new InvalidChannelError(`The channel pattern "${pattern.slice(0, 40)}…" is longer than 255 characters.`);
20
+ const segments = pattern.split(".");
21
+ const seen = /* @__PURE__ */ new Set();
22
+ for (const segment of segments) {
23
+ if (PARAM_SEGMENT.test(segment)) {
24
+ const name = segment.slice(1);
25
+ if (seen.has(name)) throw new InvalidChannelError(`The channel pattern "${pattern}" names the param "${name}" twice.`);
26
+ seen.add(name);
27
+ continue;
28
+ }
29
+ if (segment.startsWith("__")) throw new InvalidChannelError(`The channel "${pattern}" has the segment "${segment}". Segments starting with "__" are reserved for gemi (driver control messages).`);
30
+ if (!LITERAL_SEGMENT.test(segment)) throw new InvalidChannelError(`The channel pattern "${pattern}" has an invalid segment "${segment}". Segments are separated by dots and are either letters, digits, "_" and "-", or a param such as ":siteId".`);
31
+ }
32
+ return segments;
33
+ }
34
+ /**
35
+ * The topic `pattern` names with `params` filled in. Every param must be
36
+ * given, and nothing else: a missing one, an extra one, or a value outside
37
+ * `[A-Za-z0-9_-]` throws `InvalidChannelError`, so a client can never steer a
38
+ * subscription onto a topic its pattern does not describe.
39
+ */
40
+ function buildTopic(pattern, params = {}) {
41
+ const segments = parsePattern(pattern);
42
+ const expected = /* @__PURE__ */ new Set();
43
+ const topic = segments.map((segment) => {
44
+ if (!segment.startsWith(":")) return segment;
45
+ const name = segment.slice(1);
46
+ expected.add(name);
47
+ const value = params[name];
48
+ if (value === void 0 || value === null) throw new InvalidChannelError(`The channel "${pattern}" needs the param "${name}".`);
49
+ const text = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
50
+ if (typeof text !== "string" || !PARAM_VALUE.test(text)) throw new InvalidChannelError(`The param "${name}" of the channel "${pattern}" must be 1 to 128 letters, digits, "_" or "-". Use a public id in a channel name.`);
51
+ return text;
52
+ }).join(".");
53
+ for (const key of Object.keys(params)) if (!expected.has(key)) throw new InvalidChannelError(`The channel "${pattern}" has no param "${key}".`);
54
+ if (topic.length > 255) throw new InvalidChannelError(`The topic built from "${pattern}" is longer than 255 characters.`);
55
+ return topic;
56
+ }
57
+ /**
58
+ * Whether `topic` is one `pattern` builds. A pattern without params matches
59
+ * only itself, except `"user"`, which also matches every `user.<id>`: that is
60
+ * the topic the router's `user` channel resolves to.
61
+ */
62
+ function topicMatches(pattern, topic) {
63
+ if (pattern === topic) return true;
64
+ if (pattern === "user") return topic.startsWith(`user.`) && topic.split(".").length === 2;
65
+ const patternSegments = pattern.split(".");
66
+ const topicSegments = topic.split(".");
67
+ if (patternSegments.length !== topicSegments.length) return false;
68
+ return patternSegments.every((segment, i) => segment === topicSegments[i] || segment.startsWith(":") && PARAM_VALUE.test(topicSegments[i]));
69
+ }
70
+ //#endregion
71
+ //#region client/realtime/FakeSocket.ts
72
+ /**
73
+ * A socket for component tests: what `<Page socket={...}>` hands the
74
+ * channel hooks instead of a WebSocket. Every subscription is `open` at
75
+ * once; the test pushes events and resyncs by hand.
76
+ *
77
+ * ```tsx
78
+ * const socket = fakeSocket();
79
+ * render(<Page socket={socket}><SiteEditor /></Page>);
80
+ * act(() => socket.emit("site.:siteId", "changed", { pages: ["/about"] }));
81
+ * act(() => socket.resync());
82
+ * ```
83
+ *
84
+ * No resync is run on subscribe, unlike the real socket's ack: a test says
85
+ * when one happens.
86
+ */
87
+ var FakeSocket = class {
88
+ entries = /* @__PURE__ */ new Map();
89
+ status = "open";
90
+ subscribe(pattern, params, listener) {
91
+ const key = channelKey(pattern, params);
92
+ let entry = this.entries.get(key);
93
+ if (!entry) {
94
+ entry = {
95
+ key,
96
+ pattern,
97
+ params: { ...params },
98
+ status: this.status,
99
+ code: null,
100
+ listeners: /* @__PURE__ */ new Set()
101
+ };
102
+ this.entries.set(key, entry);
103
+ }
104
+ entry.listeners.add(listener);
105
+ listener.onStatus?.(entry.status, entry.code);
106
+ return () => {
107
+ entry.listeners.delete(listener);
108
+ if (entry.listeners.size === 0) this.entries.delete(key);
109
+ };
110
+ }
111
+ /** The channels subscribed to right now. */
112
+ get subscriptions() {
113
+ return Array.from(this.entries.values()).map(({ pattern, params, status, code }) => ({
114
+ pattern,
115
+ params,
116
+ status,
117
+ code
118
+ }));
119
+ }
120
+ /**
121
+ * Delivers `event` to the open subscriptions `channel` names: a pattern
122
+ * (`"site.:siteId"`, every subscription to it, or only those with `params`
123
+ * when given), or a concrete topic (`"site.abc"`).
124
+ */
125
+ emit(channel, event, data, params) {
126
+ for (const entry of this.matching(channel, params)) {
127
+ if (entry.status !== "open") continue;
128
+ for (const listener of Array.from(entry.listeners)) listener.onEvent?.(event, data);
129
+ }
130
+ }
131
+ /** Runs every matching subscription's resync (all when `channel` is left out). */
132
+ resync(channel, params) {
133
+ for (const entry of channel ? this.matching(channel, params) : this.entries.values()) {
134
+ if (entry.status !== "open") continue;
135
+ for (const listener of Array.from(entry.listeners)) listener.onResync?.();
136
+ }
137
+ }
138
+ /** Sets every subscription's status (and the status new ones start in). */
139
+ setStatus(status) {
140
+ this.status = status;
141
+ for (const entry of this.entries.values()) this.update(entry, status, null);
142
+ }
143
+ /** Refuses the matching subscriptions with `code`. */
144
+ deny(channel, code = "denied", params) {
145
+ for (const entry of this.matching(channel, params)) this.update(entry, "denied", code);
146
+ }
147
+ update(entry, status, code) {
148
+ entry.status = status;
149
+ entry.code = code;
150
+ for (const listener of Array.from(entry.listeners)) listener.onStatus?.(status, code);
151
+ }
152
+ matching(channel, params) {
153
+ return Array.from(this.entries.values()).filter((entry) => {
154
+ if (entry.pattern === channel) return !params || channelKey(channel, params) === entry.key;
155
+ try {
156
+ return (Object.keys(entry.params).length > 0 ? buildTopic(entry.pattern, entry.params) : entry.pattern) === channel || entry.pattern === "user" && topicMatches("user", channel);
157
+ } catch {
158
+ return false;
159
+ }
160
+ });
161
+ }
162
+ };
163
+ /** A `FakeSocket` for `<Page socket={...}>`. */
164
+ function fakeSocket() {
165
+ return new FakeSocket();
166
+ }
167
+ //#endregion
6
168
  //#region testing/Page.tsx
7
169
  /** `"?a=b"` (or `""`) from any of the shapes `searchParams` accepts. */
8
170
  function toSearchString(search) {
@@ -131,7 +293,8 @@ function toClientDictionary(dictionaries, locales, locale, translations) {
131
293
  * `Query.prefetch` does, framework warning included.
132
294
  */
133
295
  var Page = (props) => {
134
- const { children, pathname: routePath = "/", params = {}, searchParams, hash = "", locale = "en-US", defaultLocale = locale, timeZone = "UTC", dictionaries = [], translations = {}, queryData = {}, queryConfig, user = null, breadcrumbs = [], domain = null, features = {}, theme, fallback = null, errorFallback, onNavigate } = props;
296
+ const { children, pathname: routePath = "/", params = {}, searchParams, hash = "", locale = "en-US", defaultLocale = locale, timeZone = "UTC", dictionaries = [], translations = {}, queryData = {}, queryConfig, user = null, breadcrumbs = [], domain = null, features = {}, theme, fallback = null, errorFallback, onNavigate, socket } = props;
297
+ const [ownSocket] = useState(() => new FakeSocket());
135
298
  const supportedLocales = useMemo(() => Array.from(/* @__PURE__ */ new Set([
136
299
  ...props.supportedLocales ?? [],
137
300
  defaultLocale,
@@ -322,11 +485,14 @@ var Page = (props) => {
322
485
  transitionPath: ["", pathname],
323
486
  children: /* @__PURE__ */ jsx(RouteStateProvider, {
324
487
  state: routeState,
325
- children: /* @__PURE__ */ jsx(Boundary, {
326
- errorFallback,
327
- fallback,
328
- resetKey: pathname,
329
- children
488
+ children: /* @__PURE__ */ jsx(RealtimeContext.Provider, {
489
+ value: socket ?? ownSocket,
490
+ children: /* @__PURE__ */ jsx(Boundary, {
491
+ errorFallback,
492
+ fallback,
493
+ resetKey: pathname,
494
+ children
495
+ })
330
496
  })
331
497
  })
332
498
  })
@@ -546,6 +712,6 @@ function renderStaticDocument(html, options = {}) {
546
712
  };
547
713
  }
548
714
  //#endregion
549
- export { Page, renderStaticDocument };
715
+ export { FakeSocket, Page, fakeSocket, renderStaticDocument };
550
716
 
551
717
  //# sourceMappingURL=index.js.map