gemi 0.82.0 → 0.84.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 (274) hide show
  1. package/dist/ai/Agent.d.ts +64 -1
  2. package/dist/ai/Agent.d.ts.map +1 -1
  3. package/dist/ai/generate.d.ts +177 -0
  4. package/dist/ai/generate.d.ts.map +1 -0
  5. package/dist/ai/index.d.ts +2 -0
  6. package/dist/ai/index.d.ts.map +1 -1
  7. package/dist/ai/index.js +11 -11
  8. package/dist/ai/index.js.map +8 -6
  9. package/dist/ai/providers/request.d.ts +1 -1
  10. package/dist/ai/providers/request.d.ts.map +1 -1
  11. package/dist/ai/runtime.d.ts +115 -0
  12. package/dist/ai/runtime.d.ts.map +1 -0
  13. package/dist/ai/types.d.ts +4 -0
  14. package/dist/ai/types.d.ts.map +1 -1
  15. package/dist/app/App.d.ts +0 -5
  16. package/dist/app/App.d.ts.map +1 -1
  17. package/dist/app/index.js +1 -1
  18. package/dist/auth/AuthController.d.ts.map +1 -1
  19. package/dist/auth/accessToken.d.ts +45 -0
  20. package/dist/auth/accessToken.d.ts.map +1 -0
  21. package/dist/auth/config.d.ts +3 -3
  22. package/dist/auth/signInRedirect.d.ts +1 -1
  23. package/dist/bin/gemi.js +2 -33
  24. package/dist/bin/gemi.js.map +6 -6
  25. package/dist/bin/migrate/index.d.ts.map +1 -1
  26. package/dist/bin/migrate/tables.d.ts.map +1 -1
  27. package/dist/bun/plugin.js +1 -1
  28. package/dist/bun/preload.js +1 -1
  29. package/dist/{chunk-7dk4b1fn.js → chunk-159hyeng.js} +2 -2
  30. package/dist/{chunk-7dk4b1fn.js.map → chunk-159hyeng.js.map} +1 -1
  31. package/dist/{chunk-fya5147b.js → chunk-1cebv3h8.js} +2 -2
  32. package/dist/{chunk-fya5147b.js.map → chunk-1cebv3h8.js.map} +1 -1
  33. package/dist/{chunk-gzx3rskd.js → chunk-1evk2pma.js} +4 -4
  34. package/dist/{chunk-gzx3rskd.js.map → chunk-1evk2pma.js.map} +1 -1
  35. package/dist/{chunk-hfxx52vr.js → chunk-1s914cdj.js} +3 -3
  36. package/dist/{chunk-hfxx52vr.js.map → chunk-1s914cdj.js.map} +1 -1
  37. package/dist/chunk-302mkqeq.js +7 -0
  38. package/dist/{chunk-817dxq6w.js.map → chunk-302mkqeq.js.map} +4 -4
  39. package/dist/{chunk-03xrgp1m.js → chunk-3z6wkvwj.js} +2 -2
  40. package/dist/{chunk-03xrgp1m.js.map → chunk-3z6wkvwj.js.map} +1 -1
  41. package/dist/{chunk-2gprnzc3.js → chunk-3zb2ycxj.js} +2 -2
  42. package/dist/{chunk-2gprnzc3.js.map → chunk-3zb2ycxj.js.map} +1 -1
  43. package/dist/{chunk-9146818v.js → chunk-495qwteq.js} +3 -3
  44. package/dist/{chunk-9146818v.js.map → chunk-495qwteq.js.map} +1 -1
  45. package/dist/chunk-49akdtfe.js +17 -0
  46. package/dist/{chunk-rs0xmd64.js.map → chunk-49akdtfe.js.map} +11 -12
  47. package/dist/{chunk-0e5z1x9w.js → chunk-53we503k.js} +2 -2
  48. package/dist/{chunk-0e5z1x9w.js.map → chunk-53we503k.js.map} +3 -3
  49. package/dist/{chunk-q7ngq6c5.js → chunk-57ryyhh3.js} +2 -2
  50. package/dist/{chunk-q7ngq6c5.js.map → chunk-57ryyhh3.js.map} +1 -1
  51. package/dist/{chunk-mc1xsz8j.js → chunk-73dk6k4p.js} +3 -3
  52. package/dist/{chunk-mc1xsz8j.js.map → chunk-73dk6k4p.js.map} +1 -1
  53. package/dist/{chunk-t2htq1v0.js → chunk-82nn71zs.js} +2 -2
  54. package/dist/{chunk-t2htq1v0.js.map → chunk-82nn71zs.js.map} +1 -1
  55. package/dist/{chunk-bwwjkdts.js → chunk-87x692j7.js} +2 -2
  56. package/dist/{chunk-bwwjkdts.js.map → chunk-87x692j7.js.map} +1 -1
  57. package/dist/{chunk-zv7417j0.js → chunk-8mmfpqgs.js} +2 -2
  58. package/dist/{chunk-v0j7spj5.js.map → chunk-8mmfpqgs.js.map} +1 -1
  59. package/dist/{chunk-d2tpgkg2.js → chunk-ah9ajys0.js} +1 -1
  60. package/dist/{chunk-zbhqa2z7.js → chunk-ash9e6fn.js} +2 -2
  61. package/dist/{chunk-zbhqa2z7.js.map → chunk-ash9e6fn.js.map} +1 -1
  62. package/dist/{chunk-mmq47yh3.js → chunk-aztkrzvf.js} +2 -2
  63. package/dist/{chunk-mmq47yh3.js.map → chunk-aztkrzvf.js.map} +1 -1
  64. package/dist/chunk-b9dejyaq.js +6 -0
  65. package/dist/{chunk-kghwayjv.js.map → chunk-b9dejyaq.js.map} +2 -2
  66. package/dist/{chunk-actjm3wr.js → chunk-bn9pzgww.js} +2 -2
  67. package/dist/{chunk-actjm3wr.js.map → chunk-bn9pzgww.js.map} +1 -1
  68. package/dist/{chunk-2frgq249.js → chunk-cfvq30n4.js} +2 -2
  69. package/dist/{chunk-2frgq249.js.map → chunk-cfvq30n4.js.map} +1 -1
  70. package/dist/{chunk-egw90hq5.js → chunk-cg4k40zy.js} +2 -2
  71. package/dist/{chunk-egw90hq5.js.map → chunk-cg4k40zy.js.map} +1 -1
  72. package/dist/{chunk-1dgab0qn.js → chunk-d0qwdeza.js} +2 -2
  73. package/dist/{chunk-1dgab0qn.js.map → chunk-d0qwdeza.js.map} +1 -1
  74. package/dist/{chunk-1k783c44.js → chunk-dvpxkzms.js} +2 -2
  75. package/dist/{chunk-1k783c44.js.map → chunk-dvpxkzms.js.map} +1 -1
  76. package/dist/chunk-e43drft2.js +5 -0
  77. package/dist/{chunk-z9x8fx21.js.map → chunk-e43drft2.js.map} +5 -7
  78. package/dist/{chunk-3k2asp5z.js → chunk-ekppwzyg.js} +2 -2
  79. package/dist/{chunk-3k2asp5z.js.map → chunk-ekppwzyg.js.map} +1 -1
  80. package/dist/{chunk-3h1pd6ec.js → chunk-en3mtnsg.js} +2 -2
  81. package/dist/{chunk-3h1pd6ec.js.map → chunk-en3mtnsg.js.map} +1 -1
  82. package/dist/{chunk-v8s1dmc2.js → chunk-enf9mdac.js} +2 -2
  83. package/dist/{chunk-v8s1dmc2.js.map → chunk-enf9mdac.js.map} +1 -1
  84. package/dist/{chunk-gppm9gkg.js → chunk-eysexnqb.js} +2 -2
  85. package/dist/{chunk-gppm9gkg.js.map → chunk-eysexnqb.js.map} +1 -1
  86. package/dist/{chunk-06p4zq4m.js → chunk-g6qe6wyb.js} +2 -2
  87. package/dist/{chunk-06p4zq4m.js.map → chunk-g6qe6wyb.js.map} +1 -1
  88. package/dist/{chunk-fpy7m803.js → chunk-gr61ymse.js} +2 -2
  89. package/dist/{chunk-fpy7m803.js.map → chunk-gr61ymse.js.map} +1 -1
  90. package/dist/{chunk-0kpvbnz0.js → chunk-j9wqzemf.js} +2 -2
  91. package/dist/{chunk-0kpvbnz0.js.map → chunk-j9wqzemf.js.map} +1 -1
  92. package/dist/{chunk-9z5g1rf6.js → chunk-jg9eqd3r.js} +1 -1
  93. package/dist/{chunk-6sd7an1r.js → chunk-k2qh3hvd.js} +2 -2
  94. package/dist/{chunk-6sd7an1r.js.map → chunk-k2qh3hvd.js.map} +1 -1
  95. package/dist/{chunk-d2esms7y.js → chunk-kb3xk9r8.js} +2 -2
  96. package/dist/{chunk-d2esms7y.js.map → chunk-kb3xk9r8.js.map} +1 -1
  97. package/dist/{chunk-2c89p8pf.js → chunk-kfavcgv2.js} +2 -2
  98. package/dist/{chunk-2c89p8pf.js.map → chunk-kfavcgv2.js.map} +1 -1
  99. package/dist/{chunk-5krm6p9w.js → chunk-m0zba09s.js} +3 -3
  100. package/dist/{chunk-5krm6p9w.js.map → chunk-m0zba09s.js.map} +1 -1
  101. package/dist/{chunk-wmbpdjvs.js → chunk-m4xw99vm.js} +2 -2
  102. package/dist/{chunk-wmbpdjvs.js.map → chunk-m4xw99vm.js.map} +1 -1
  103. package/dist/{chunk-6c0s1mb7.js → chunk-ng8pp9k2.js} +2 -2
  104. package/dist/{chunk-6c0s1mb7.js.map → chunk-ng8pp9k2.js.map} +1 -1
  105. package/dist/{chunk-zbpgt20r.js → chunk-nvj1z2rs.js} +2 -2
  106. package/dist/{chunk-zbpgt20r.js.map → chunk-nvj1z2rs.js.map} +1 -1
  107. package/dist/{chunk-qff26x59.js → chunk-pa0ya991.js} +2 -2
  108. package/dist/{chunk-qff26x59.js.map → chunk-pa0ya991.js.map} +1 -1
  109. package/dist/{chunk-a3mgkrb2.js → chunk-pgpqsgzx.js} +1 -1
  110. package/dist/{chunk-sexaj89x.js → chunk-pt59xjfc.js} +2 -2
  111. package/dist/{chunk-sexaj89x.js.map → chunk-pt59xjfc.js.map} +1 -1
  112. package/dist/{chunk-8vnb3hfz.js → chunk-r5e4vpa1.js} +2 -2
  113. package/dist/{chunk-8vnb3hfz.js.map → chunk-r5e4vpa1.js.map} +1 -1
  114. package/dist/{chunk-vxxk4syx.js → chunk-r8nhndzb.js} +2 -2
  115. package/dist/{chunk-vxxk4syx.js.map → chunk-r8nhndzb.js.map} +1 -1
  116. package/dist/{chunk-vax2fp2k.js → chunk-rmv1jp9p.js} +2 -2
  117. package/dist/{chunk-vax2fp2k.js.map → chunk-rmv1jp9p.js.map} +1 -1
  118. package/dist/{chunk-d07y2ddw.js → chunk-rqh2wdhb.js} +2 -2
  119. package/dist/{chunk-d07y2ddw.js.map → chunk-rqh2wdhb.js.map} +1 -1
  120. package/dist/{chunk-9hbwvcxn.js → chunk-rv7da58g.js} +2 -2
  121. package/dist/chunk-rv7da58g.js.map +10 -0
  122. package/dist/{chunk-2y9haf48.js → chunk-tdnfhe7x.js} +3 -3
  123. package/dist/{chunk-2y9haf48.js.map → chunk-tdnfhe7x.js.map} +1 -1
  124. package/dist/chunk-tmwsvf02.js +5 -0
  125. package/dist/{chunk-nc82trtm.js.map → chunk-tmwsvf02.js.map} +1 -1
  126. package/dist/{chunk-0zr926cf.js → chunk-v1nm4tcq.js} +2 -2
  127. package/dist/{chunk-0zr926cf.js.map → chunk-v1nm4tcq.js.map} +1 -1
  128. package/dist/{chunk-mwrh96hx.js → chunk-v27a4se1.js} +3 -3
  129. package/dist/chunk-v27a4se1.js.map +12 -0
  130. package/dist/chunk-vfrrzr10.js +4 -0
  131. package/dist/chunk-vfrrzr10.js.map +10 -0
  132. package/dist/{chunk-s7rhttvd.js → chunk-vmpzg4z5.js} +3 -3
  133. package/dist/{chunk-s7rhttvd.js.map → chunk-vmpzg4z5.js.map} +1 -1
  134. package/dist/{chunk-aecx542w.js → chunk-w099t7zj.js} +2 -2
  135. package/dist/{chunk-aecx542w.js.map → chunk-w099t7zj.js.map} +1 -1
  136. package/dist/chunk-wh728wd6.js +5 -0
  137. package/dist/chunk-wh728wd6.js.map +10 -0
  138. package/dist/{chunk-vqexqkfk.js → chunk-wkdzz0rx.js} +3 -3
  139. package/dist/chunk-wkdzz0rx.js.map +10 -0
  140. package/dist/{chunk-vngyybzh.js → chunk-wsx3j5ws.js} +2 -2
  141. package/dist/{chunk-vngyybzh.js.map → chunk-wsx3j5ws.js.map} +1 -1
  142. package/dist/{chunk-7y6gpg08.js → chunk-wwdaswxh.js} +3 -3
  143. package/dist/{chunk-7y6gpg08.js.map → chunk-wwdaswxh.js.map} +1 -1
  144. package/dist/{chunk-nq2hm5xm.js → chunk-xhha1gb3.js} +2 -2
  145. package/dist/{chunk-nq2hm5xm.js.map → chunk-xhha1gb3.js.map} +1 -1
  146. package/dist/{chunk-dk0kdrkm.js → chunk-yk8s5egf.js} +2 -2
  147. package/dist/{chunk-dk0kdrkm.js.map → chunk-yk8s5egf.js.map} +1 -1
  148. package/dist/{chunk-y7gfg6tj.js → chunk-ys4fejmx.js} +2 -2
  149. package/dist/{chunk-y7gfg6tj.js.map → chunk-ys4fejmx.js.map} +1 -1
  150. package/dist/{chunk-6eprvf4s.js → chunk-z409rk5j.js} +2 -2
  151. package/dist/{chunk-6eprvf4s.js.map → chunk-z409rk5j.js.map} +1 -1
  152. package/dist/{chunk-t6yzarvt.js → chunk-z7442w3q.js} +2 -2
  153. package/dist/{chunk-t6yzarvt.js.map → chunk-z7442w3q.js.map} +1 -1
  154. package/dist/{chunk-v0j7spj5.js → chunk-zfch4da5.js} +2 -2
  155. package/dist/{chunk-zv7417j0.js.map → chunk-zfch4da5.js.map} +1 -1
  156. package/dist/{chunk-f46ntdj3.js → chunk-zp971jp2.js} +3 -3
  157. package/dist/{chunk-f46ntdj3.js.map → chunk-zp971jp2.js.map} +1 -1
  158. package/dist/chunks/{ThemeProvider-BiNFL6l7.js → ThemeProvider-Dn3UREDn.js} +64 -90
  159. package/dist/chunks/ThemeProvider-Dn3UREDn.js.map +1 -0
  160. package/dist/client/ClientRouter.d.ts.map +1 -1
  161. package/dist/client/QueryResource.d.ts +14 -0
  162. package/dist/client/QueryResource.d.ts.map +1 -1
  163. package/dist/client/index.d.ts +0 -2
  164. package/dist/client/index.d.ts.map +1 -1
  165. package/dist/client/index.js +4 -29
  166. package/dist/client/index.js.map +1 -1
  167. package/dist/config/index.js +1 -1
  168. package/dist/console/run.js +2 -2
  169. package/dist/console/run.js.map +1 -1
  170. package/dist/container/index.js +2 -2
  171. package/dist/container/index.js.map +1 -1
  172. package/dist/database/index.js +2 -2
  173. package/dist/database/index.js.map +1 -1
  174. package/dist/email/index.js +2 -2
  175. package/dist/email/index.js.map +1 -1
  176. package/dist/facades/Auth.d.ts +14 -0
  177. package/dist/facades/Auth.d.ts.map +1 -1
  178. package/dist/facades/index.d.ts +0 -1
  179. package/dist/facades/index.d.ts.map +1 -1
  180. package/dist/facades/index.js +2 -2
  181. package/dist/facades/index.js.map +1 -1
  182. package/dist/foundation/Application.d.ts +7 -3
  183. package/dist/foundation/Application.d.ts.map +1 -1
  184. package/dist/foundation/app.d.ts +1 -1
  185. package/dist/foundation/index.js +2 -2
  186. package/dist/foundation/index.js.map +1 -1
  187. package/dist/http/AuthenticationMiddlware.d.ts +4 -3
  188. package/dist/http/AuthenticationMiddlware.d.ts.map +1 -1
  189. package/dist/http/HttpRequest.d.ts.map +1 -1
  190. package/dist/http/index.js +2 -2
  191. package/dist/http/index.js.map +1 -1
  192. package/dist/i18n/dictionaryRuntime.js +2 -2
  193. package/dist/i18n/dictionaryRuntime.js.map +1 -1
  194. package/dist/i18n/index.js +2 -2
  195. package/dist/i18n/index.js.map +1 -1
  196. package/dist/internal/gemiExternals.d.ts +1 -1
  197. package/dist/internal/gemiExternals.d.ts.map +1 -1
  198. package/dist/kernel/Kernel.d.ts +0 -2
  199. package/dist/kernel/Kernel.d.ts.map +1 -1
  200. package/dist/kernel/context.d.ts +3 -4
  201. package/dist/kernel/context.d.ts.map +1 -1
  202. package/dist/kernel/index.js +3 -3
  203. package/dist/kernel/index.js.map +5 -5
  204. package/dist/kernel/providers.d.ts.map +1 -1
  205. package/dist/orm/context.d.ts +1 -2
  206. package/dist/orm/context.d.ts.map +1 -1
  207. package/dist/orm/index.js +2 -2
  208. package/dist/orm/index.js.map +1 -1
  209. package/dist/server/index.js +2 -2
  210. package/dist/server/index.js.map +1 -1
  211. package/dist/services/cron/ScheduleServiceProvider.d.ts +7 -2
  212. package/dist/services/cron/ScheduleServiceProvider.d.ts.map +1 -1
  213. package/dist/services/index.d.ts +0 -3
  214. package/dist/services/index.d.ts.map +1 -1
  215. package/dist/services/index.js +3 -3
  216. package/dist/services/index.js.map +2 -2
  217. package/dist/services/logging/LogManager.d.ts.map +1 -1
  218. package/dist/services/queue/QueueServiceProvider.d.ts +8 -2
  219. package/dist/services/queue/QueueServiceProvider.d.ts.map +1 -1
  220. package/dist/services/queue/work.js +2 -2
  221. package/dist/services/queue/work.js.map +1 -1
  222. package/dist/services/router/ApiRouteDispatcher.d.ts.map +1 -1
  223. package/dist/services/router/globalMiddleware.d.ts +5 -3
  224. package/dist/services/router/globalMiddleware.d.ts.map +1 -1
  225. package/dist/support/ServiceProvider.d.ts +14 -1
  226. package/dist/support/ServiceProvider.d.ts.map +1 -1
  227. package/dist/support/index.d.ts +1 -1
  228. package/dist/support/index.d.ts.map +1 -1
  229. package/dist/support/index.js +2 -2
  230. package/dist/support/index.js.map +1 -1
  231. package/dist/testing/Page.d.ts.map +1 -1
  232. package/dist/testing/index.js +16 -24
  233. package/dist/testing/index.js.map +1 -1
  234. package/package.json +1 -2
  235. package/dist/broadcasting/BroadcastingChannel.d.ts +0 -5
  236. package/dist/broadcasting/BroadcastingChannel.d.ts.map +0 -1
  237. package/dist/broadcasting/index.d.ts +0 -2
  238. package/dist/broadcasting/index.d.ts.map +0 -1
  239. package/dist/broadcasting/index.js +0 -4
  240. package/dist/broadcasting/index.js.map +0 -10
  241. package/dist/chunk-817dxq6w.js +0 -7
  242. package/dist/chunk-9hbwvcxn.js.map +0 -10
  243. package/dist/chunk-f9mwxne0.js +0 -4
  244. package/dist/chunk-f9mwxne0.js.map +0 -10
  245. package/dist/chunk-fffph77x.js +0 -5
  246. package/dist/chunk-fffph77x.js.map +0 -10
  247. package/dist/chunk-kghwayjv.js +0 -6
  248. package/dist/chunk-mwrh96hx.js.map +0 -12
  249. package/dist/chunk-nc82trtm.js +0 -5
  250. package/dist/chunk-rs0xmd64.js +0 -17
  251. package/dist/chunk-vqexqkfk.js.map +0 -10
  252. package/dist/chunk-z9x8fx21.js +0 -5
  253. package/dist/chunks/ThemeProvider-BiNFL6l7.js.map +0 -1
  254. package/dist/client/WebsocketContext.d.ts +0 -10
  255. package/dist/client/WebsocketContext.d.ts.map +0 -1
  256. package/dist/client/useBroadcast.d.ts +0 -4
  257. package/dist/client/useBroadcast.d.ts.map +0 -1
  258. package/dist/client/useSubscription.d.ts +0 -5
  259. package/dist/client/useSubscription.d.ts.map +0 -1
  260. package/dist/facades/Broadcast.d.ts +0 -9
  261. package/dist/facades/Broadcast.d.ts.map +0 -1
  262. package/dist/http/BroadcastingRouter.d.ts +0 -8
  263. package/dist/http/BroadcastingRouter.d.ts.map +0 -1
  264. package/dist/services/pubsub/BroadcastManager.d.ts +0 -24
  265. package/dist/services/pubsub/BroadcastManager.d.ts.map +0 -1
  266. package/dist/services/pubsub/BroadcastServiceProvider.d.ts +0 -5
  267. package/dist/services/pubsub/BroadcastServiceProvider.d.ts.map +0 -1
  268. package/dist/services/pubsub/config.d.ts +0 -7
  269. package/dist/services/pubsub/config.d.ts.map +0 -1
  270. package/dist/services/pubsub/types.d.ts +0 -6
  271. package/dist/services/pubsub/types.d.ts.map +0 -1
  272. /package/dist/{chunk-d2tpgkg2.js.map → chunk-ah9ajys0.js.map} +0 -0
  273. /package/dist/{chunk-9z5g1rf6.js.map → chunk-jg9eqd3r.js.map} +0 -0
  274. /package/dist/{chunk-a3mgkrb2.js.map → chunk-pgpqsgzx.js.map} +0 -0
@@ -29,9 +29,11 @@ export interface GlobalMiddlewareOutcome {
29
29
  * Headers and cookies reach the response through `apply`, and the user is
30
30
  * `carried` into the route's context, so a gate that looked the user up does
31
31
  * not make `auth` or `Auth.user()` look them up again. Both trust a user they
32
- * find on the context without checking it against a session (`auth` checks only
33
- * that a token is present), so whatever a global middleware sets is treated as
34
- * authenticated by the route. The rest stays behind:
32
+ * find on the context without checking it against a session or asking for a
33
+ * token, so whatever a global middleware sets is treated as authenticated by
34
+ * the route — which is what lets one sign a user in by SSO header or API key
35
+ * (#577), and why it must set only a user it has verified. The rest stays
36
+ * behind:
35
37
  * the locale, because the dispatchers decide it for the route, from its url,
36
38
  * and the feature evaluations, made against a request with no route and maybe
37
39
  * before a user was known.
@@ -1 +1 @@
1
- {"version":3,"file":"globalMiddleware.d.ts","sourceRoot":"","sources":["../../../services/router/globalMiddleware.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,2BAA2B,CAAC;AAShF,MAAM,WAAW,uBAAuB;IACtC,+EAA+E;IAC/E,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB;;;;;;OAMG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACpC;;;OAGG;IACH,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;CAChC;AAsBD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAuDxF"}
1
+ {"version":3,"file":"globalMiddleware.d.ts","sourceRoot":"","sources":["../../../services/router/globalMiddleware.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAkB,MAAM,2BAA2B,CAAC;AAShF,MAAM,WAAW,uBAAuB;IACtC,+EAA+E;IAC/E,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB;;;;;;OAMG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACpC;;;OAGG;IACH,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;CAChC;AAsBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAuDxF"}
@@ -1,4 +1,11 @@
1
1
  import type { Application } from "../foundation/Application";
2
+ /**
3
+ * What a provider's `shutdown()` may resolve: nothing, or whether it
4
+ * abandoned work at the deadline. See `ServiceProvider` below.
5
+ */
6
+ export type ProviderShutdownResult = void | {
7
+ abandoned: boolean;
8
+ };
2
9
  /**
3
10
  * Every hook defaults to a no-op. `register()` binds services into the
4
11
  * container and must not resolve any of them; `boot()` runs after every
@@ -25,6 +32,12 @@ import type { Application } from "../foundation/Application";
25
32
  * is still the one to report what it gave up on. Ignoring it is fine; the
26
33
  * provider is then simply abandoned at the deadline, with only a generic line
27
34
  * from `Application` to say so.
35
+ *
36
+ * A provider that bounds its own wait and gives up on work it was waiting for
37
+ * resolves `{ abandoned: true }`. `Application` then reports it in `timedOut`
38
+ * as if it had overrun, and the process exits `1` — the work was cut off just
39
+ * the same, and an orchestrator or a log alert has to be able to see that from
40
+ * the exit code. The provider names what it abandoned in its own log line.
28
41
  */
29
42
  export declare abstract class ServiceProvider {
30
43
  protected app: Application;
@@ -33,6 +46,6 @@ export declare abstract class ServiceProvider {
33
46
  boot(): void | Promise<void>;
34
47
  shutdown(options?: {
35
48
  timeoutMs: number;
36
- }): void | Promise<void>;
49
+ }): ProviderShutdownResult | Promise<ProviderShutdownResult>;
37
50
  }
38
51
  //# sourceMappingURL=ServiceProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceProvider.d.ts","sourceRoot":"","sources":["../../support/ServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,8BAAsB,eAAe;IACvB,SAAS,CAAC,GAAG,EAAE,WAAW;gBAAhB,GAAG,EAAE,WAAW;IAEtC,QAAQ,IAAI,IAAI;IAEhB,IAAI,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE5B,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CAChE"}
1
+ {"version":3,"file":"ServiceProvider.d.ts","sourceRoot":"","sources":["../../support/ServiceProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,8BAAsB,eAAe;IACvB,SAAS,CAAC,GAAG,EAAE,WAAW;gBAAhB,GAAG,EAAE,WAAW;IAEtC,QAAQ,IAAI,IAAI;IAEhB,IAAI,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE5B,QAAQ,CAAC,OAAO,CAAC,EAAE;QACjB,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC;CAC7D"}
@@ -1,4 +1,4 @@
1
- export { ServiceProvider } from "./ServiceProvider";
1
+ export { ServiceProvider, type ProviderShutdownResult } from "./ServiceProvider";
2
2
  export { Service, type ServiceConstructor } from "./Service";
3
3
  export { Repository, type ConfigItems } from "./Repository";
4
4
  export { createConfigRepository, loadConfigFrom } from "./loadConfig";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../support/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../support/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,WAAW,GACZ,MAAM,YAAY,CAAC"}
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{hc as Y}from"../chunk-9hbwvcxn.js";import{wf as R}from"../chunk-wmbpdjvs.js";import{pg as F,rg as q}from"../chunk-mwrh96hx.js";import"../chunk-fffph77x.js";import"../chunk-vxxk4syx.js";import{Bg as S,Cg as U,Dg as V,Eg as W}from"../chunk-8vnb3hfz.js";import"../chunk-v0j7spj5.js";class v{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 q(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 H}from"fs/promises";import{join as J,parse as z}from"path";var L=[".ts",".tsx",".js",".mjs",".jsx"];function M(x={}){let f={};for(let[C,g]of Object.entries(x))f[C]=B(g);return new F(f)}async function Q(x,f=new F){let C=[];try{C=await H(x)}catch(D){return f}let g=C.filter((D)=>{let{ext:P,name:j}=z(D);return L.includes(P)&&!j.startsWith(".")}).sort();for(let D of g){let{name:P}=z(D),j=await import(J(x,D));f.set(P,B(j))}return f}function B(x){if(x&&typeof x==="object"&&"default"in x)return x.default;return x}export{R as withDefaults,S as sourceFiles,W as projectRoot,Q as loadConfigFrom,V as discoverClasses,M as createConfigRepository,Y as ServiceProvider,v as Service,F as Repository,U as DiscoveryError};
2
+ import{ec as Y}from"../chunk-rv7da58g.js";import{bg as M}from"../chunk-m4xw99vm.js";import{jg as P,lg as R}from"../chunk-v27a4se1.js";import"../chunk-wh728wd6.js";import"../chunk-r8nhndzb.js";import{vg as Q,wg as U,xg as V,yg as W}from"../chunk-r5e4vpa1.js";import"../chunk-zfch4da5.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=EAB25302C527DBAC64756E2164756E21
4
+ //# debugId=F40EDAE73CCB75F364756E2164756E21
@@ -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": ";6TAgCO,CAAe,JAAQ,EAOrB,OAMD,AAAI,HAAkB,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": "EAB25302C527DBAC64756E2164756E21",
9
+ "debugId": "F40EDAE73CCB75F364756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../testing/Page.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGzE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAI1C,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,+BAA+B,CAAC;AAYvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAM3D;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,kEAAkE;IAClE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC5B,iDAAiD;IACjD,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;IACT;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC7C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;CACjE;AA6ID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,IAAI,GAAI,OAAO,iBAAiB,CAAC,SAAS,CAAC,4CAqRvD,CAAC"}
1
+ {"version":3,"file":"Page.d.ts","sourceRoot":"","sources":["../../testing/Page.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGzE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAI1C,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,+BAA+B,CAAC;AAYvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAK3D;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,kEAAkE;IAClE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC5B,iDAAiD;IACjD,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,IAAI,CAAC;IACT;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC7C;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;CACjE;AA6ID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,IAAI,GAAI,OAAO,iBAAiB,CAAC,SAAS,CAAC,4CA6QvD,CAAC"}
@@ -1,4 +1,4 @@
1
- import { E as ServerDataContext, F as applyParams, K as Subject, L as QueryManagerContext, M as Action, N as createMemoryHistory, P as toVariantKey, R as QueryManagerProvider, T as I18nProvider, a as m, c as ClientRouterContext, j as ProgressManager, o as RouteTransitionProvider, r as WebSocketContext, t as ThemeProvider } from "../chunks/ThemeProvider-BiNFL6l7.js";
1
+ import { A as Action, C as I18nProvider, F as QueryManagerContext, I as QueryManagerProvider, M as toVariantKey, N as applyParams, W as Subject, i as RouteTransitionProvider, j as createMemoryHistory, k as ProgressManager, o as ClientRouterContext, r as m, t as ThemeProvider, w as ServerDataContext } from "../chunks/ThemeProvider-Dn3UREDn.js";
2
2
  import { r as RouteStateProvider } from "../chunks/useParams-BN3XXfmG.js";
3
3
  import { Suspense, useContext, useMemo, useRef, useState } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
@@ -301,33 +301,25 @@ var Page = (props) => {
301
301
  routerSubject,
302
302
  urlLocaleSegment
303
303
  ]);
304
- const [websocket] = useState(() => ({
305
- subscribe: async () => {},
306
- unsubscribe: async () => {},
307
- broadcast: () => {}
308
- }));
309
304
  return /* @__PURE__ */ jsx(ThemeProvider, {
310
305
  theme,
311
306
  children: /* @__PURE__ */ jsx(ServerDataContext.Provider, {
312
307
  value: serverData,
313
- children: /* @__PURE__ */ jsx(I18nProvider, { children: /* @__PURE__ */ jsx(WebSocketContext.Provider, {
314
- value: websocket,
315
- children: /* @__PURE__ */ jsx(QueryManagerProvider, {
316
- queryConfig,
317
- children: /* @__PURE__ */ jsx(ClientRouterContext.Provider, {
318
- value: routerContext,
319
- children: /* @__PURE__ */ jsx(RouteTransitionProvider, {
320
- isPending: false,
321
- isFetching: false,
322
- transitionPath: ["", pathname],
323
- children: /* @__PURE__ */ jsx(RouteStateProvider, {
324
- state: routeState,
325
- children: /* @__PURE__ */ jsx(Boundary, {
326
- errorFallback,
327
- fallback,
328
- resetKey: pathname,
329
- children
330
- })
308
+ children: /* @__PURE__ */ jsx(I18nProvider, { children: /* @__PURE__ */ jsx(QueryManagerProvider, {
309
+ queryConfig,
310
+ children: /* @__PURE__ */ jsx(ClientRouterContext.Provider, {
311
+ value: routerContext,
312
+ children: /* @__PURE__ */ jsx(RouteTransitionProvider, {
313
+ isPending: false,
314
+ isFetching: false,
315
+ transitionPath: ["", pathname],
316
+ children: /* @__PURE__ */ jsx(RouteStateProvider, {
317
+ state: routeState,
318
+ children: /* @__PURE__ */ jsx(Boundary, {
319
+ errorFallback,
320
+ fallback,
321
+ resetKey: pathname,
322
+ children
331
323
  })
332
324
  })
333
325
  })
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../testing/Page.tsx"],"sourcesContent":["import {\n Suspense,\n useContext,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\nimport { ErrorBoundary, type FallbackProps } from \"react-error-boundary\";\nimport { Action, createMemoryHistory } from \"history\";\n\nimport type { User } from \"../auth/types\";\nimport { ClientRouterContext } from \"../client/ClientRouterContext\";\nimport { I18nProvider } from \"../client/I18nContext\";\nimport { ProgressManager } from \"../client/ProgressManager\";\nimport {\n QueryManagerContext,\n QueryManagerProvider,\n type QueryConfig,\n} from \"../client/QueryManagerContext\";\nimport {\n RouteStateProvider,\n type PageData,\n type RouteState,\n} from \"../client/RouteStateContext\";\nimport { RouteTransitionProvider } from \"../client/RouteTransitionProvider\";\nimport {\n ServerDataContext,\n type ServerDataContextValue,\n} from \"../client/ServerDataProvider\";\nimport { ThemeProvider } from \"../client/ThemeProvider\";\nimport type { ClientFeatureKey } from \"../client/rpc\";\nimport type { Breadcrumb } from \"../client/useBreadcrumbs\";\nimport { WebSocketContext } from \"../client/WebsocketContext\";\nimport { applyParams } from \"../utils/applyParams\";\nimport { Subject } from \"../utils/Subject\";\nimport { toVariantKey } from \"../utils/variantKey\";\n\n/**\n * A dictionary as `Dictionary.create` produces it: a name and a\n * `{ key: { locale: string } }` map.\n *\n * Typed structurally rather than as `Dictionary<T>` for two reasons. It keeps\n * `gemi/testing` from importing `gemi/i18n` — a server entry, which reaches the\n * `Lang` facade and through it the container. And it means an object literal of\n * the same shape is accepted, so a test never *has* to import the app's\n * dictionaries at all.\n *\n * Only `name` and `dictionary` are read — both plain data. `Dictionary`'s\n * server-only methods (`render`, `reference`, which throw once `window` is\n * defined) are never called from here.\n */\nexport interface PageDictionary {\n name: string;\n dictionary: Record<string, Record<string, string>>;\n}\n\nexport interface PageProps {\n /**\n * The URL the view is mounted at. A template (`/app/:orgId/chat`) is resolved\n * against `params`, so the same string can be pasted from the router.\n */\n pathname?: string;\n /** Route params, as the router would have parsed them out of `pathname`. */\n params?: Record<string, string>;\n /** `\"?tab=recent\"`, `\"tab=recent\"`, or `{ tab: \"recent\" }`. */\n searchParams?: string | Record<string, string | number | boolean>;\n hash?: string;\n /** The locale `useTranslator` and `useLocale` report. */\n locale?: string;\n /**\n * The app's default locale. Links and `useNavigate` omit the locale segment\n * for it, so leaving this equal to `locale` (the default) keeps hrefs\n * unprefixed — set it to seed a page being viewed in a non-default locale.\n */\n defaultLocale?: string;\n supportedLocales?: string[];\n /**\n * Dictionaries the components under test translate against — the app's own,\n * or literals of the same shape.\n *\n * Note what importing the app's costs: `app/i18n/index.ts` imports\n * `gemi/i18n`, a server entry, so the test file pulls the container and\n * `node:async_hooks` into its module graph. Nothing there runs (and nothing\n * here calls it), so it is fine under any runner that has Node builtins —\n * vitest, `bun test` — and not under one that renders in a real browser. Use\n * `translations` there, which is the shape the client actually receives.\n */\n dictionaries?: PageDictionary[];\n /**\n * Translations for the current locale, already resolved: dictionary name →\n * key → string. This is the shape the server serializes onto the page, so it\n * is what the client reads at runtime — and it imports nothing.\n *\n * ```tsx\n * <Page translations={{ Chat: { greeting: \"Hello {{name}}\" } }}>\n * ```\n *\n * Merged over `dictionaries`, so the two compose: seed from the app's real\n * dictionary and override the one key a test is about.\n */\n translations?: Record<string, Record<string, string>>;\n /**\n * Data `useQuery` finds already cached, keyed by API path — the path passed\n * to `useQuery`, without the `/api` prefix the client adds when it fetches.\n * A key may carry a query string (`\"/lists?page=2\"`) to seed one search\n * variant.\n *\n * The cache is keyed by the *resolved* path, so a key's `:params` are\n * resolved against the page's `params` — and a key naming one the page does\n * not carry is an error, naming the key. That case is common enough to be\n * worth the loud failure: a query often takes its params from the call site\n * rather than the route (`useQuery(\"/orgs/:orgId/lists\", { params: { orgId } })`\n * with `orgId` in component state), and the right seed for it is the resolved\n * path, `\"/orgs/abc/lists\"`.\n *\n * Seeded at mount only: a component that mutates or refetches its data owns\n * the cache from then on.\n */\n queryData?: Record<string, unknown>;\n /** App-wide `useQuery` defaults, as `createRoot` threads them. */\n queryConfig?: QueryConfig;\n /**\n * What `useUser()` reports. Defaults to `null` — an anonymous visitor — and\n * either way the hook resolves from here without issuing a request.\n */\n user?: Partial<User> | null;\n /** What `useBreadcrumbs()` returns, in order. */\n breadcrumbs?: Breadcrumb[];\n /**\n * The `route.domains` group the page is served under, as `useDomain()`\n * reports it. Left out, `useDomain()` reads empty — the shape an app without\n * `route.domains` sees — and `useDomain().url()` throws, exactly as it does\n * there.\n *\n * `root` and `origin` default off the host, so the common case is one field:\n * `domain={{ host: \"acme.example.com\", params: { tenant: \"acme\" } }}`.\n */\n domain?: {\n host: string;\n group?: string;\n params?: Record<string, string>;\n custom?: boolean;\n root?: string;\n origin?: string;\n } | null;\n /**\n * What `useFeature()` reports, keyed by feature key. Anything left out reads\n * as off, exactly as an undeclared key does in a real request.\n *\n * A test seeds the *outcome*, not the declaration: `app/features` owns the\n * targeting and the rollout, and re-deriving those here would mean building a\n * request context — a user, a `session_id`, a bot verdict — to assert a\n * branch that only cares which way the feature came out. Cover the targeting\n * where it lives, with a server test.\n */\n features?: Partial<Record<ClientFeatureKey, boolean>>;\n /**\n * The theme `useTheme()` starts on. The app reads a visitor's stored choice\n * out of `localStorage`; a test has no session to have made one in, so this\n * seeds it without writing to storage. `setTheme` works from either.\n */\n theme?: \"light\" | \"dark\" | \"system\";\n /**\n * Fallback for the `Suspense` boundary wrapped around the children — the\n * stand-in for the view's own `Loading` export, which the real router\n * supplies. Defaults to `null`.\n */\n fallback?: ReactNode;\n /**\n * Renders in place of the children when one throws, mirroring a view's\n * `Error` export. Without it a thrown render (an errored suspense query,\n * say) propagates out of `render()` and fails the test, which is usually\n * what you want.\n */\n errorFallback?: ComponentType<FallbackProps>;\n /**\n * Called when something navigates — a `Link` click, `useNavigate().push`.\n * The navigation is reported, not performed: `<Page>` renders one route and\n * does not re-resolve the tree, so `useLocation()` keeps reporting the\n * pathname it was given.\n */\n onNavigate?: (href: string, action: \"push\" | \"replace\") => void;\n}\n\n/** `\"?a=b\"` (or `\"\"`) from any of the shapes `searchParams` accepts. */\nfunction toSearchString(search: PageProps[\"searchParams\"]): string {\n if (!search) return \"\";\n const query =\n typeof search === \"string\"\n ? search.replace(/^\\?/, \"\")\n : new URLSearchParams(\n Object.entries(search).map(([key, value]) => [key, String(value)]),\n ).toString();\n return query ? `?${query}` : \"\";\n}\n\n/**\n * The `:params` a seed key needs supplied. Wildcards (`:rest*`) are excluded —\n * `applyParams` drops those when missing, which is a resolution rather than a\n * failure.\n *\n * Optional params (`:id?`) cannot reach here at all: a key is split at its\n * first `?` to separate the search string, so `\"/lists/:folderId?\"` arrives as\n * the path `/lists/:folderId`. Seed the resolved path for those.\n */\nfunction requiredParamsOf(path: string): string[] {\n return Array.from(path.matchAll(/:([^/]+)/g), ([, name]) => name).filter(\n (name) => !name.endsWith(\"*\"),\n );\n}\n\n/**\n * Fails a `queryData` key whose `:params` the page does not carry, saying so\n * in terms of the key.\n *\n * Without this the two documented runners disagree, and neither is legible.\n * `applyParams` throws `Missing parameter: orgId` under `import.meta.env.DEV`\n * (vitest) — a router-utility stack trace out of `<Page>`'s render, before\n * anything mounts, naming nothing that appears in the test. Under `bun test`\n * that flag is falsy, so it logs and seeds the literal `/orgs/undefined/lists`\n * instead: the seed misses, the query goes to the network, and the assertion\n * runs against a loading state.\n *\n * The case is common because a query's params often come from the call site\n * rather than the route — `useQuery(\"/orgs/:orgId/lists\", { params: { orgId } })`\n * with `orgId` in component state. The cache is keyed by the *resolved* path,\n * so the way out is to seed that path directly.\n */\nfunction resolveSeedPath(\n key: string,\n rawPath: string,\n params: Record<string, string>,\n): string {\n const missing = requiredParamsOf(rawPath).filter(\n (name) => params[name] === undefined,\n );\n if (missing.length > 0) {\n throw new Error(\n `[gemi] <Page> cannot resolve the queryData key \"${key}\": no value for ` +\n `${missing.map((name) => `:${name}`).join(\", \")}. The query cache is ` +\n `keyed by the resolved path, so either add ${missing\n .map((name) => `\\`${name}\\``)\n .join(\", \")} to the page's \\`params\\`, or seed the resolved path ` +\n `(e.g. \"${applyParams(\n rawPath,\n Object.fromEntries(missing.map((name) => [name, \"123\"])),\n )}\") — which is what a query taking its params from component state ` +\n `reads under.`,\n );\n }\n return applyParams(rawPath, params);\n}\n\n/**\n * `queryData` in the shape the query cache seeds from: `{ [path]: { [variant]:\n * data } }`, the same payload `Query.prefetch` puts on a server-rendered page.\n */\nfunction toPrefetchedData(\n queryData: Record<string, unknown>,\n params: Record<string, string>,\n warned: Set<string>,\n) {\n const prefetchedData: Record<string, Record<string, unknown>> = {};\n for (const [key, data] of Object.entries(queryData)) {\n const [rawPath, rawSearch = \"\"] = key.split(\"?\");\n // Once per key per page, not once per render: this runs again on every\n // re-render, and a duplicated warning reads as a second mistake.\n if (rawPath.startsWith(\"/api/\") && !warned.has(key)) {\n warned.add(key);\n console.warn(\n `[gemi] queryData key \"${key}\" starts with /api. useQuery is keyed by ` +\n `the path you pass it — the /api prefix is added when it fetches — ` +\n `so this entry seeds a path no query reads.`,\n );\n }\n const path = resolveSeedPath(key, rawPath, params);\n prefetchedData[path] = {\n ...prefetchedData[path],\n [toVariantKey(rawSearch)]: data,\n };\n }\n return prefetchedData;\n}\n\n/**\n * `{ [locale]: { [dictionary]: { [key]: string } } }` — the payload\n * `Translator` serializes onto the page, which is the only form the client\n * ever sees. `dictionaries` are transposed into it (they are keyed the other\n * way round, by key then locale); `translations` is already in it and lands\n * under `locale`, last, so it wins.\n */\nfunction toClientDictionary(\n dictionaries: PageDictionary[],\n locales: string[],\n locale: string,\n translations: Record<string, Record<string, string>>,\n): Record<string, Record<string, Record<string, string>>> {\n const clientDictionary: Record<\n string,\n Record<string, Record<string, string>>\n > = {};\n for (const supported of locales) {\n clientDictionary[supported] ??= {};\n }\n for (const { name, dictionary } of dictionaries) {\n for (const [key, byLocale] of Object.entries(dictionary ?? {})) {\n for (const [dictLocale, translation] of Object.entries(byLocale ?? {})) {\n clientDictionary[dictLocale] ??= {};\n clientDictionary[dictLocale][name] ??= {};\n clientDictionary[dictLocale][name][key] = translation;\n }\n }\n }\n for (const [name, keys] of Object.entries(translations)) {\n clientDictionary[locale] ??= {};\n clientDictionary[locale][name] = {\n ...clientDictionary[locale][name],\n ...keys,\n };\n }\n return clientDictionary;\n}\n\n/**\n * Mounts a component with the inputs a view normally arrives with — route\n * params, the current locale and its dictionaries, prefetched query data, the\n * signed-in user — so a unit test can assert what it renders rather than only\n * its empty state.\n *\n * ```tsx\n * import { render, screen } from \"@testing-library/react\";\n * import { Page } from \"gemi/testing\";\n *\n * render(\n * <Page\n * pathname=\"/app/:orgId/chat\"\n * params={{ orgId: \"abc\" }}\n * queryData={{ \"/organizations/:orgId/messages\": [{ id: 1, body: \"hi\" }] }}\n * dictionaries={[ChatDictionary]}\n * >\n * <OrgChat />\n * </Page>,\n * );\n *\n * expect(screen.getByText(\"hi\")).toBeDefined();\n * ```\n *\n * It is a plain component, so it composes with any renderer — Testing\n * Library's `render`, `react-test-renderer`, or `renderToString`.\n *\n * Two things it does not do.\n *\n * It does not route: there is no view tree and no route manifest behind it, so\n * a navigation is reported through `onNavigate` rather than resolved. To\n * assert the page *after* one, render a second `<Page>`.\n *\n * And under `renderToString` it renders the server's own no-data branch for an\n * *unseeded* query rather than suspending — deliberately, because suspending\n * there is the streaming server's job: `createRoot` threads the request's\n * `ServerQueryStore` through `ServerQueryContext`, and that store is what runs\n * the route handler. A harness has no request and no handler to run, so there\n * is nothing to suspend on. Seeded queries render their data on the server\n * exactly as they do in the browser; unseeded ones behave as a route with no\n * `Query.prefetch` does, framework warning included.\n */\nexport const Page = (props: PropsWithChildren<PageProps>) => {\n const {\n children,\n pathname: routePath = \"/\",\n params = {},\n searchParams,\n hash = \"\",\n locale = \"en-US\",\n defaultLocale = locale,\n dictionaries = [],\n translations = {},\n queryData = {},\n queryConfig,\n user = null,\n breadcrumbs = [],\n domain = null,\n features = {},\n theme,\n fallback = null,\n errorFallback,\n onNavigate,\n } = props;\n\n // The caller's list, in the caller's order — a language switcher maps over\n // it, so hoisting the page's own locale to the front would reorder the\n // rendered options. The defaults are appended, only to guarantee presence.\n const supportedLocales = useMemo(\n () =>\n Array.from(\n new Set([...(props.supportedLocales ?? []), defaultLocale, locale]),\n ),\n [props.supportedLocales, defaultLocale, locale],\n );\n const pathname = applyParams(routePath, params) || \"/\";\n // `root` defaults to the host minus its first label, so a tenant subdomain\n // needs only its host; `origin` to https on that host. Either can be given\n // outright when the test is about the other.\n const domainValue = useMemo(() => {\n if (!domain) {\n return null;\n }\n const labels = domain.host.split(\".\");\n return {\n host: domain.host,\n group: domain.group ?? \"\",\n params: domain.params ?? {},\n custom: domain.custom ?? false,\n root:\n domain.root ?? (labels.length > 2 ? labels.slice(1).join(\".\") : domain.host),\n origin: domain.origin ?? `https://${domain.host}`,\n };\n }, [domain]);\n const search = toSearchString(searchParams);\n // The URL's locale segment, which the default locale does not get.\n const urlLocaleSegment = locale === defaultLocale ? null : locale;\n\n const dictionary = useMemo(\n () =>\n toClientDictionary(dictionaries, supportedLocales, locale, translations),\n [dictionaries, supportedLocales, locale, translations],\n );\n\n // Keys that have already drawn a warning, so a re-render does not repeat it.\n const warnedRef = useRef<Set<string>>(new Set());\n const prefetchedData = useMemo(() => {\n const seeded = toPrefetchedData(queryData, params, warnedRef.current);\n // `useUser` reads `/auth/me` like any other query. Seeding it — with `null`\n // for the anonymous default — is what keeps a component test off the\n // network for a hook nothing in the test asked for.\n seeded[\"/auth/me\"] ??= { \"\": user ?? null };\n return seeded;\n }, [queryData, params, user]);\n\n // Keyed by `${view}:${pathname}` in the router's cache; the view names are\n // ours to choose here, and only their order reaches `useBreadcrumbs`.\n const { breadcrumbViews, breadcrumbsCache, breadcrumbsRecord } =\n useMemo(() => {\n const views = breadcrumbs.map((_, index) => `breadcrumb-${index}`);\n const cache = new Map<string, Breadcrumb>(\n breadcrumbs.map((breadcrumb, index) => [\n `${views[index]}:${pathname}`,\n breadcrumb,\n ]),\n );\n return {\n breadcrumbViews: views,\n breadcrumbsCache: cache,\n breadcrumbsRecord: Object.fromEntries(cache),\n };\n }, [breadcrumbs, pathname]);\n\n const [isNavigatingSubject] = useState(() => new Subject<boolean>(false));\n const [progressManager] = useState(\n () => new ProgressManager(isNavigatingSubject),\n );\n const [history] = useState(() =>\n createMemoryHistory({ initialEntries: [`${pathname}${search}${hash}`] }),\n );\n\n const routeState: RouteState & PageData = useMemo(\n () => ({\n views: [],\n params,\n search,\n state: {},\n pathname,\n hash,\n action: null,\n routePath,\n locale: urlLocaleSegment,\n data: {},\n i18n: { currentLocale: locale, dictionary, supportedLocales },\n prefetchedData,\n breadcrumbs: breadcrumbsRecord,\n features: features as Record<string, boolean>,\n appId: \"test\",\n }),\n [\n params,\n search,\n pathname,\n hash,\n routePath,\n urlLocaleSegment,\n locale,\n dictionary,\n supportedLocales,\n prefetchedData,\n breadcrumbsRecord,\n features,\n ],\n );\n\n const [routerSubject] = useState(() => new Subject<RouteState>(routeState));\n\n const onNavigateRef = useRef(onNavigate);\n onNavigateRef.current = onNavigate;\n // Subscribed during render, not in an effect, because React flushes child\n // effects before parent ones — and mount-time navigation is a real pattern:\n // `<Redirect>` pushes from its own mount effect, as does any auth guard. A\n // listener registered in `<Page>`'s effect is not there yet when those fire,\n // so `onNavigate` would silently miss exactly the redirects a test most\n // wants to assert. Ref-guarded, so React's double-invoke registers one.\n //\n // Nothing unsubscribes: this history is created per `<Page>` and reachable\n // from nowhere else, so it is collected with the page it belongs to.\n const listeningRef = useRef(false);\n if (!listeningRef.current) {\n listeningRef.current = true;\n history.listen(({ location, action }) => {\n const href = `${location.pathname}${location.search}${location.hash}`;\n onNavigateRef.current?.(\n href,\n action === Action.Replace ? \"replace\" : \"push\",\n );\n });\n }\n\n const serverData: ServerDataContextValue = useMemo(\n () => ({\n routeManifest: {},\n pageData: {},\n breadcrumbs: breadcrumbsRecord,\n prefetchedData,\n router: {\n pathname,\n params,\n currentPath: routePath,\n is404: false,\n searchParams: search,\n urlLocaleSegment,\n domain: domainValue,\n },\n i18n: {\n dictionary,\n currentLocale: locale,\n supportedLocales,\n defaultLocale,\n },\n componentTree: [],\n auth: { user: user as User },\n features: features as Record<string, boolean>,\n __csrf: \"test-csrf-token\",\n cssManifest: {},\n modulePreloadManifest: {},\n meta: {},\n appId: \"test\",\n }),\n [\n breadcrumbsRecord,\n prefetchedData,\n pathname,\n params,\n routePath,\n search,\n urlLocaleSegment,\n dictionary,\n locale,\n supportedLocales,\n defaultLocale,\n user,\n features,\n ],\n );\n\n // Everything the router hooks read, inert: nothing here fetches, preloads or\n // resolves a route, but every hook finds the shape it expects rather than an\n // empty context to crash on.\n const [viewEntriesSubject] = useState(() => new Subject<string[]>([]));\n const routerContext = useMemo(\n () => ({\n viewEntriesSubject,\n history,\n updatePageData: () => {},\n getPageData: () => ({}),\n getScrollPosition: () => 0,\n getViewPathsFromPathname: () => breadcrumbViews,\n getRoutePathnameFromHref: (href: string) => href,\n isNavigatingSubject,\n setNavigationAbortController: () => {},\n progressManager,\n fetchRouteCSS: async () => {},\n preloadRouteModules: () => {},\n prefetchRoute: async () => {},\n takePrefetched: () => null,\n clearPrefetchCache: () => {},\n breadcrumbsCache,\n routerSubject,\n urlLocaleSegment,\n }),\n [\n viewEntriesSubject,\n history,\n breadcrumbViews,\n isNavigatingSubject,\n progressManager,\n breadcrumbsCache,\n routerSubject,\n urlLocaleSegment,\n ],\n );\n\n const [websocket] = useState(() => ({\n subscribe: async () => {},\n unsubscribe: async () => {},\n broadcast: () => {},\n }));\n\n return (\n <ThemeProvider theme={theme}>\n <ServerDataContext.Provider value={serverData}>\n <I18nProvider>\n <WebSocketContext.Provider value={websocket}>\n <QueryManagerProvider queryConfig={queryConfig}>\n <ClientRouterContext.Provider value={routerContext}>\n <RouteTransitionProvider\n isPending={false}\n isFetching={false}\n transitionPath={[\"\", pathname]}\n >\n <RouteStateProvider state={routeState}>\n <Boundary\n errorFallback={errorFallback}\n fallback={fallback}\n resetKey={pathname}\n >\n {children}\n </Boundary>\n </RouteStateProvider>\n </RouteTransitionProvider>\n </ClientRouterContext.Provider>\n </QueryManagerProvider>\n </WebSocketContext.Provider>\n </I18nProvider>\n </ServerDataContext.Provider>\n </ThemeProvider>\n );\n};\n\n/**\n * The `Suspense` boundary every view renders inside, and — when the test\n * supplies a fallback for it — the error boundary too.\n *\n * `onReset={clearErrors}` is the part that has to be here rather than inline\n * above: it needs `QueryManagerContext`, and it is what makes a view's real\n * `Error` export testable. A fallback whose \"Try again\" calls\n * `resetErrorBoundary()` re-renders the child, and `useQuery` reads the\n * failure still stored on the `QueryResource` and throws it straight back —\n * so without this the fallback never goes away and the retry path that works\n * in the app cannot be exercised. `ClientRouter`'s own boundary wires exactly\n * this pair.\n */\nconst Boundary = (\n props: PropsWithChildren<{\n errorFallback?: ComponentType<FallbackProps>;\n fallback: ReactNode;\n resetKey: string;\n }>,\n) => {\n const { errorFallback: ErrorFallback, fallback, resetKey, children } = props;\n const { clearErrors } = useContext(QueryManagerContext);\n const content = <Suspense fallback={fallback}>{children}</Suspense>;\n\n if (!ErrorFallback) {\n return content;\n }\n\n return (\n <ErrorBoundary\n FallbackComponent={ErrorFallback}\n resetKeys={[resetKey]}\n onReset={clearErrors}\n >\n {content}\n </ErrorBoundary>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../testing/Page.tsx"],"sourcesContent":["import {\n Suspense,\n useContext,\n useMemo,\n useRef,\n useState,\n type ComponentType,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\nimport { ErrorBoundary, type FallbackProps } from \"react-error-boundary\";\nimport { Action, createMemoryHistory } from \"history\";\n\nimport type { User } from \"../auth/types\";\nimport { ClientRouterContext } from \"../client/ClientRouterContext\";\nimport { I18nProvider } from \"../client/I18nContext\";\nimport { ProgressManager } from \"../client/ProgressManager\";\nimport {\n QueryManagerContext,\n QueryManagerProvider,\n type QueryConfig,\n} from \"../client/QueryManagerContext\";\nimport {\n RouteStateProvider,\n type PageData,\n type RouteState,\n} from \"../client/RouteStateContext\";\nimport { RouteTransitionProvider } from \"../client/RouteTransitionProvider\";\nimport {\n ServerDataContext,\n type ServerDataContextValue,\n} from \"../client/ServerDataProvider\";\nimport { ThemeProvider } from \"../client/ThemeProvider\";\nimport type { ClientFeatureKey } from \"../client/rpc\";\nimport type { Breadcrumb } from \"../client/useBreadcrumbs\";\nimport { applyParams } from \"../utils/applyParams\";\nimport { Subject } from \"../utils/Subject\";\nimport { toVariantKey } from \"../utils/variantKey\";\n\n/**\n * A dictionary as `Dictionary.create` produces it: a name and a\n * `{ key: { locale: string } }` map.\n *\n * Typed structurally rather than as `Dictionary<T>` for two reasons. It keeps\n * `gemi/testing` from importing `gemi/i18n` — a server entry, which reaches the\n * `Lang` facade and through it the container. And it means an object literal of\n * the same shape is accepted, so a test never *has* to import the app's\n * dictionaries at all.\n *\n * Only `name` and `dictionary` are read — both plain data. `Dictionary`'s\n * server-only methods (`render`, `reference`, which throw once `window` is\n * defined) are never called from here.\n */\nexport interface PageDictionary {\n name: string;\n dictionary: Record<string, Record<string, string>>;\n}\n\nexport interface PageProps {\n /**\n * The URL the view is mounted at. A template (`/app/:orgId/chat`) is resolved\n * against `params`, so the same string can be pasted from the router.\n */\n pathname?: string;\n /** Route params, as the router would have parsed them out of `pathname`. */\n params?: Record<string, string>;\n /** `\"?tab=recent\"`, `\"tab=recent\"`, or `{ tab: \"recent\" }`. */\n searchParams?: string | Record<string, string | number | boolean>;\n hash?: string;\n /** The locale `useTranslator` and `useLocale` report. */\n locale?: string;\n /**\n * The app's default locale. Links and `useNavigate` omit the locale segment\n * for it, so leaving this equal to `locale` (the default) keeps hrefs\n * unprefixed — set it to seed a page being viewed in a non-default locale.\n */\n defaultLocale?: string;\n supportedLocales?: string[];\n /**\n * Dictionaries the components under test translate against — the app's own,\n * or literals of the same shape.\n *\n * Note what importing the app's costs: `app/i18n/index.ts` imports\n * `gemi/i18n`, a server entry, so the test file pulls the container and\n * `node:async_hooks` into its module graph. Nothing there runs (and nothing\n * here calls it), so it is fine under any runner that has Node builtins —\n * vitest, `bun test` — and not under one that renders in a real browser. Use\n * `translations` there, which is the shape the client actually receives.\n */\n dictionaries?: PageDictionary[];\n /**\n * Translations for the current locale, already resolved: dictionary name →\n * key → string. This is the shape the server serializes onto the page, so it\n * is what the client reads at runtime — and it imports nothing.\n *\n * ```tsx\n * <Page translations={{ Chat: { greeting: \"Hello {{name}}\" } }}>\n * ```\n *\n * Merged over `dictionaries`, so the two compose: seed from the app's real\n * dictionary and override the one key a test is about.\n */\n translations?: Record<string, Record<string, string>>;\n /**\n * Data `useQuery` finds already cached, keyed by API path — the path passed\n * to `useQuery`, without the `/api` prefix the client adds when it fetches.\n * A key may carry a query string (`\"/lists?page=2\"`) to seed one search\n * variant.\n *\n * The cache is keyed by the *resolved* path, so a key's `:params` are\n * resolved against the page's `params` — and a key naming one the page does\n * not carry is an error, naming the key. That case is common enough to be\n * worth the loud failure: a query often takes its params from the call site\n * rather than the route (`useQuery(\"/orgs/:orgId/lists\", { params: { orgId } })`\n * with `orgId` in component state), and the right seed for it is the resolved\n * path, `\"/orgs/abc/lists\"`.\n *\n * Seeded at mount only: a component that mutates or refetches its data owns\n * the cache from then on.\n */\n queryData?: Record<string, unknown>;\n /** App-wide `useQuery` defaults, as `createRoot` threads them. */\n queryConfig?: QueryConfig;\n /**\n * What `useUser()` reports. Defaults to `null` — an anonymous visitor — and\n * either way the hook resolves from here without issuing a request.\n */\n user?: Partial<User> | null;\n /** What `useBreadcrumbs()` returns, in order. */\n breadcrumbs?: Breadcrumb[];\n /**\n * The `route.domains` group the page is served under, as `useDomain()`\n * reports it. Left out, `useDomain()` reads empty — the shape an app without\n * `route.domains` sees — and `useDomain().url()` throws, exactly as it does\n * there.\n *\n * `root` and `origin` default off the host, so the common case is one field:\n * `domain={{ host: \"acme.example.com\", params: { tenant: \"acme\" } }}`.\n */\n domain?: {\n host: string;\n group?: string;\n params?: Record<string, string>;\n custom?: boolean;\n root?: string;\n origin?: string;\n } | null;\n /**\n * What `useFeature()` reports, keyed by feature key. Anything left out reads\n * as off, exactly as an undeclared key does in a real request.\n *\n * A test seeds the *outcome*, not the declaration: `app/features` owns the\n * targeting and the rollout, and re-deriving those here would mean building a\n * request context — a user, a `session_id`, a bot verdict — to assert a\n * branch that only cares which way the feature came out. Cover the targeting\n * where it lives, with a server test.\n */\n features?: Partial<Record<ClientFeatureKey, boolean>>;\n /**\n * The theme `useTheme()` starts on. The app reads a visitor's stored choice\n * out of `localStorage`; a test has no session to have made one in, so this\n * seeds it without writing to storage. `setTheme` works from either.\n */\n theme?: \"light\" | \"dark\" | \"system\";\n /**\n * Fallback for the `Suspense` boundary wrapped around the children — the\n * stand-in for the view's own `Loading` export, which the real router\n * supplies. Defaults to `null`.\n */\n fallback?: ReactNode;\n /**\n * Renders in place of the children when one throws, mirroring a view's\n * `Error` export. Without it a thrown render (an errored suspense query,\n * say) propagates out of `render()` and fails the test, which is usually\n * what you want.\n */\n errorFallback?: ComponentType<FallbackProps>;\n /**\n * Called when something navigates — a `Link` click, `useNavigate().push`.\n * The navigation is reported, not performed: `<Page>` renders one route and\n * does not re-resolve the tree, so `useLocation()` keeps reporting the\n * pathname it was given.\n */\n onNavigate?: (href: string, action: \"push\" | \"replace\") => void;\n}\n\n/** `\"?a=b\"` (or `\"\"`) from any of the shapes `searchParams` accepts. */\nfunction toSearchString(search: PageProps[\"searchParams\"]): string {\n if (!search) return \"\";\n const query =\n typeof search === \"string\"\n ? search.replace(/^\\?/, \"\")\n : new URLSearchParams(\n Object.entries(search).map(([key, value]) => [key, String(value)]),\n ).toString();\n return query ? `?${query}` : \"\";\n}\n\n/**\n * The `:params` a seed key needs supplied. Wildcards (`:rest*`) are excluded —\n * `applyParams` drops those when missing, which is a resolution rather than a\n * failure.\n *\n * Optional params (`:id?`) cannot reach here at all: a key is split at its\n * first `?` to separate the search string, so `\"/lists/:folderId?\"` arrives as\n * the path `/lists/:folderId`. Seed the resolved path for those.\n */\nfunction requiredParamsOf(path: string): string[] {\n return Array.from(path.matchAll(/:([^/]+)/g), ([, name]) => name).filter(\n (name) => !name.endsWith(\"*\"),\n );\n}\n\n/**\n * Fails a `queryData` key whose `:params` the page does not carry, saying so\n * in terms of the key.\n *\n * Without this the two documented runners disagree, and neither is legible.\n * `applyParams` throws `Missing parameter: orgId` under `import.meta.env.DEV`\n * (vitest) — a router-utility stack trace out of `<Page>`'s render, before\n * anything mounts, naming nothing that appears in the test. Under `bun test`\n * that flag is falsy, so it logs and seeds the literal `/orgs/undefined/lists`\n * instead: the seed misses, the query goes to the network, and the assertion\n * runs against a loading state.\n *\n * The case is common because a query's params often come from the call site\n * rather than the route — `useQuery(\"/orgs/:orgId/lists\", { params: { orgId } })`\n * with `orgId` in component state. The cache is keyed by the *resolved* path,\n * so the way out is to seed that path directly.\n */\nfunction resolveSeedPath(\n key: string,\n rawPath: string,\n params: Record<string, string>,\n): string {\n const missing = requiredParamsOf(rawPath).filter(\n (name) => params[name] === undefined,\n );\n if (missing.length > 0) {\n throw new Error(\n `[gemi] <Page> cannot resolve the queryData key \"${key}\": no value for ` +\n `${missing.map((name) => `:${name}`).join(\", \")}. The query cache is ` +\n `keyed by the resolved path, so either add ${missing\n .map((name) => `\\`${name}\\``)\n .join(\", \")} to the page's \\`params\\`, or seed the resolved path ` +\n `(e.g. \"${applyParams(\n rawPath,\n Object.fromEntries(missing.map((name) => [name, \"123\"])),\n )}\") — which is what a query taking its params from component state ` +\n `reads under.`,\n );\n }\n return applyParams(rawPath, params);\n}\n\n/**\n * `queryData` in the shape the query cache seeds from: `{ [path]: { [variant]:\n * data } }`, the same payload `Query.prefetch` puts on a server-rendered page.\n */\nfunction toPrefetchedData(\n queryData: Record<string, unknown>,\n params: Record<string, string>,\n warned: Set<string>,\n) {\n const prefetchedData: Record<string, Record<string, unknown>> = {};\n for (const [key, data] of Object.entries(queryData)) {\n const [rawPath, rawSearch = \"\"] = key.split(\"?\");\n // Once per key per page, not once per render: this runs again on every\n // re-render, and a duplicated warning reads as a second mistake.\n if (rawPath.startsWith(\"/api/\") && !warned.has(key)) {\n warned.add(key);\n console.warn(\n `[gemi] queryData key \"${key}\" starts with /api. useQuery is keyed by ` +\n `the path you pass it — the /api prefix is added when it fetches — ` +\n `so this entry seeds a path no query reads.`,\n );\n }\n const path = resolveSeedPath(key, rawPath, params);\n prefetchedData[path] = {\n ...prefetchedData[path],\n [toVariantKey(rawSearch)]: data,\n };\n }\n return prefetchedData;\n}\n\n/**\n * `{ [locale]: { [dictionary]: { [key]: string } } }` — the payload\n * `Translator` serializes onto the page, which is the only form the client\n * ever sees. `dictionaries` are transposed into it (they are keyed the other\n * way round, by key then locale); `translations` is already in it and lands\n * under `locale`, last, so it wins.\n */\nfunction toClientDictionary(\n dictionaries: PageDictionary[],\n locales: string[],\n locale: string,\n translations: Record<string, Record<string, string>>,\n): Record<string, Record<string, Record<string, string>>> {\n const clientDictionary: Record<\n string,\n Record<string, Record<string, string>>\n > = {};\n for (const supported of locales) {\n clientDictionary[supported] ??= {};\n }\n for (const { name, dictionary } of dictionaries) {\n for (const [key, byLocale] of Object.entries(dictionary ?? {})) {\n for (const [dictLocale, translation] of Object.entries(byLocale ?? {})) {\n clientDictionary[dictLocale] ??= {};\n clientDictionary[dictLocale][name] ??= {};\n clientDictionary[dictLocale][name][key] = translation;\n }\n }\n }\n for (const [name, keys] of Object.entries(translations)) {\n clientDictionary[locale] ??= {};\n clientDictionary[locale][name] = {\n ...clientDictionary[locale][name],\n ...keys,\n };\n }\n return clientDictionary;\n}\n\n/**\n * Mounts a component with the inputs a view normally arrives with — route\n * params, the current locale and its dictionaries, prefetched query data, the\n * signed-in user — so a unit test can assert what it renders rather than only\n * its empty state.\n *\n * ```tsx\n * import { render, screen } from \"@testing-library/react\";\n * import { Page } from \"gemi/testing\";\n *\n * render(\n * <Page\n * pathname=\"/app/:orgId/chat\"\n * params={{ orgId: \"abc\" }}\n * queryData={{ \"/organizations/:orgId/messages\": [{ id: 1, body: \"hi\" }] }}\n * dictionaries={[ChatDictionary]}\n * >\n * <OrgChat />\n * </Page>,\n * );\n *\n * expect(screen.getByText(\"hi\")).toBeDefined();\n * ```\n *\n * It is a plain component, so it composes with any renderer — Testing\n * Library's `render`, `react-test-renderer`, or `renderToString`.\n *\n * Two things it does not do.\n *\n * It does not route: there is no view tree and no route manifest behind it, so\n * a navigation is reported through `onNavigate` rather than resolved. To\n * assert the page *after* one, render a second `<Page>`.\n *\n * And under `renderToString` it renders the server's own no-data branch for an\n * *unseeded* query rather than suspending — deliberately, because suspending\n * there is the streaming server's job: `createRoot` threads the request's\n * `ServerQueryStore` through `ServerQueryContext`, and that store is what runs\n * the route handler. A harness has no request and no handler to run, so there\n * is nothing to suspend on. Seeded queries render their data on the server\n * exactly as they do in the browser; unseeded ones behave as a route with no\n * `Query.prefetch` does, framework warning included.\n */\nexport const Page = (props: PropsWithChildren<PageProps>) => {\n const {\n children,\n pathname: routePath = \"/\",\n params = {},\n searchParams,\n hash = \"\",\n locale = \"en-US\",\n defaultLocale = locale,\n dictionaries = [],\n translations = {},\n queryData = {},\n queryConfig,\n user = null,\n breadcrumbs = [],\n domain = null,\n features = {},\n theme,\n fallback = null,\n errorFallback,\n onNavigate,\n } = props;\n\n // The caller's list, in the caller's order — a language switcher maps over\n // it, so hoisting the page's own locale to the front would reorder the\n // rendered options. The defaults are appended, only to guarantee presence.\n const supportedLocales = useMemo(\n () =>\n Array.from(\n new Set([...(props.supportedLocales ?? []), defaultLocale, locale]),\n ),\n [props.supportedLocales, defaultLocale, locale],\n );\n const pathname = applyParams(routePath, params) || \"/\";\n // `root` defaults to the host minus its first label, so a tenant subdomain\n // needs only its host; `origin` to https on that host. Either can be given\n // outright when the test is about the other.\n const domainValue = useMemo(() => {\n if (!domain) {\n return null;\n }\n const labels = domain.host.split(\".\");\n return {\n host: domain.host,\n group: domain.group ?? \"\",\n params: domain.params ?? {},\n custom: domain.custom ?? false,\n root:\n domain.root ?? (labels.length > 2 ? labels.slice(1).join(\".\") : domain.host),\n origin: domain.origin ?? `https://${domain.host}`,\n };\n }, [domain]);\n const search = toSearchString(searchParams);\n // The URL's locale segment, which the default locale does not get.\n const urlLocaleSegment = locale === defaultLocale ? null : locale;\n\n const dictionary = useMemo(\n () =>\n toClientDictionary(dictionaries, supportedLocales, locale, translations),\n [dictionaries, supportedLocales, locale, translations],\n );\n\n // Keys that have already drawn a warning, so a re-render does not repeat it.\n const warnedRef = useRef<Set<string>>(new Set());\n const prefetchedData = useMemo(() => {\n const seeded = toPrefetchedData(queryData, params, warnedRef.current);\n // `useUser` reads `/auth/me` like any other query. Seeding it — with `null`\n // for the anonymous default — is what keeps a component test off the\n // network for a hook nothing in the test asked for.\n seeded[\"/auth/me\"] ??= { \"\": user ?? null };\n return seeded;\n }, [queryData, params, user]);\n\n // Keyed by `${view}:${pathname}` in the router's cache; the view names are\n // ours to choose here, and only their order reaches `useBreadcrumbs`.\n const { breadcrumbViews, breadcrumbsCache, breadcrumbsRecord } =\n useMemo(() => {\n const views = breadcrumbs.map((_, index) => `breadcrumb-${index}`);\n const cache = new Map<string, Breadcrumb>(\n breadcrumbs.map((breadcrumb, index) => [\n `${views[index]}:${pathname}`,\n breadcrumb,\n ]),\n );\n return {\n breadcrumbViews: views,\n breadcrumbsCache: cache,\n breadcrumbsRecord: Object.fromEntries(cache),\n };\n }, [breadcrumbs, pathname]);\n\n const [isNavigatingSubject] = useState(() => new Subject<boolean>(false));\n const [progressManager] = useState(\n () => new ProgressManager(isNavigatingSubject),\n );\n const [history] = useState(() =>\n createMemoryHistory({ initialEntries: [`${pathname}${search}${hash}`] }),\n );\n\n const routeState: RouteState & PageData = useMemo(\n () => ({\n views: [],\n params,\n search,\n state: {},\n pathname,\n hash,\n action: null,\n routePath,\n locale: urlLocaleSegment,\n data: {},\n i18n: { currentLocale: locale, dictionary, supportedLocales },\n prefetchedData,\n breadcrumbs: breadcrumbsRecord,\n features: features as Record<string, boolean>,\n appId: \"test\",\n }),\n [\n params,\n search,\n pathname,\n hash,\n routePath,\n urlLocaleSegment,\n locale,\n dictionary,\n supportedLocales,\n prefetchedData,\n breadcrumbsRecord,\n features,\n ],\n );\n\n const [routerSubject] = useState(() => new Subject<RouteState>(routeState));\n\n const onNavigateRef = useRef(onNavigate);\n onNavigateRef.current = onNavigate;\n // Subscribed during render, not in an effect, because React flushes child\n // effects before parent ones — and mount-time navigation is a real pattern:\n // `<Redirect>` pushes from its own mount effect, as does any auth guard. A\n // listener registered in `<Page>`'s effect is not there yet when those fire,\n // so `onNavigate` would silently miss exactly the redirects a test most\n // wants to assert. Ref-guarded, so React's double-invoke registers one.\n //\n // Nothing unsubscribes: this history is created per `<Page>` and reachable\n // from nowhere else, so it is collected with the page it belongs to.\n const listeningRef = useRef(false);\n if (!listeningRef.current) {\n listeningRef.current = true;\n history.listen(({ location, action }) => {\n const href = `${location.pathname}${location.search}${location.hash}`;\n onNavigateRef.current?.(\n href,\n action === Action.Replace ? \"replace\" : \"push\",\n );\n });\n }\n\n const serverData: ServerDataContextValue = useMemo(\n () => ({\n routeManifest: {},\n pageData: {},\n breadcrumbs: breadcrumbsRecord,\n prefetchedData,\n router: {\n pathname,\n params,\n currentPath: routePath,\n is404: false,\n searchParams: search,\n urlLocaleSegment,\n domain: domainValue,\n },\n i18n: {\n dictionary,\n currentLocale: locale,\n supportedLocales,\n defaultLocale,\n },\n componentTree: [],\n auth: { user: user as User },\n features: features as Record<string, boolean>,\n __csrf: \"test-csrf-token\",\n cssManifest: {},\n modulePreloadManifest: {},\n meta: {},\n appId: \"test\",\n }),\n [\n breadcrumbsRecord,\n prefetchedData,\n pathname,\n params,\n routePath,\n search,\n urlLocaleSegment,\n dictionary,\n locale,\n supportedLocales,\n defaultLocale,\n user,\n features,\n ],\n );\n\n // Everything the router hooks read, inert: nothing here fetches, preloads or\n // resolves a route, but every hook finds the shape it expects rather than an\n // empty context to crash on.\n const [viewEntriesSubject] = useState(() => new Subject<string[]>([]));\n const routerContext = useMemo(\n () => ({\n viewEntriesSubject,\n history,\n updatePageData: () => {},\n getPageData: () => ({}),\n getScrollPosition: () => 0,\n getViewPathsFromPathname: () => breadcrumbViews,\n getRoutePathnameFromHref: (href: string) => href,\n isNavigatingSubject,\n setNavigationAbortController: () => {},\n progressManager,\n fetchRouteCSS: async () => {},\n preloadRouteModules: () => {},\n prefetchRoute: async () => {},\n takePrefetched: () => null,\n clearPrefetchCache: () => {},\n breadcrumbsCache,\n routerSubject,\n urlLocaleSegment,\n }),\n [\n viewEntriesSubject,\n history,\n breadcrumbViews,\n isNavigatingSubject,\n progressManager,\n breadcrumbsCache,\n routerSubject,\n urlLocaleSegment,\n ],\n );\n\n return (\n <ThemeProvider theme={theme}>\n <ServerDataContext.Provider value={serverData}>\n <I18nProvider>\n <QueryManagerProvider queryConfig={queryConfig}>\n <ClientRouterContext.Provider value={routerContext}>\n <RouteTransitionProvider\n isPending={false}\n isFetching={false}\n transitionPath={[\"\", pathname]}\n >\n <RouteStateProvider state={routeState}>\n <Boundary\n errorFallback={errorFallback}\n fallback={fallback}\n resetKey={pathname}\n >\n {children}\n </Boundary>\n </RouteStateProvider>\n </RouteTransitionProvider>\n </ClientRouterContext.Provider>\n </QueryManagerProvider>\n </I18nProvider>\n </ServerDataContext.Provider>\n </ThemeProvider>\n );\n};\n\n/**\n * The `Suspense` boundary every view renders inside, and — when the test\n * supplies a fallback for it — the error boundary too.\n *\n * `onReset={clearErrors}` is the part that has to be here rather than inline\n * above: it needs `QueryManagerContext`, and it is what makes a view's real\n * `Error` export testable. A fallback whose \"Try again\" calls\n * `resetErrorBoundary()` re-renders the child, and `useQuery` reads the\n * failure still stored on the `QueryResource` and throws it straight back —\n * so without this the fallback never goes away and the retry path that works\n * in the app cannot be exercised. `ClientRouter`'s own boundary wires exactly\n * this pair.\n */\nconst Boundary = (\n props: PropsWithChildren<{\n errorFallback?: ComponentType<FallbackProps>;\n fallback: ReactNode;\n resetKey: string;\n }>,\n) => {\n const { errorFallback: ErrorFallback, fallback, resetKey, children } = props;\n const { clearErrors } = useContext(QueryManagerContext);\n const content = <Suspense fallback={fallback}>{children}</Suspense>;\n\n if (!ErrorFallback) {\n return content;\n }\n\n return (\n <ErrorBoundary\n FallbackComponent={ErrorFallback}\n resetKeys={[resetKey]}\n onReset={clearErrors}\n >\n {content}\n </ErrorBoundary>\n );\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gemi",
3
- "version": "0.82.0",
3
+ "version": "0.84.0",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Enes Tufekci <enes@gemijs.dev>",
@@ -31,7 +31,6 @@
31
31
  "./vite": "./dist/vite/index.mjs",
32
32
  "./kernel": "./dist/kernel/index.js",
33
33
  "./services": "./dist/services/index.js",
34
- "./broadcasting": "./dist/broadcasting/index.js",
35
34
  "./i18n": "./dist/i18n/index.js",
36
35
  "./dictionary": "./dist/i18n/dictionaryRuntime.js",
37
36
  "./server": "./dist/server/index.js",
@@ -1,5 +0,0 @@
1
- export declare class BroadcastingChannel {
2
- subscribe(user: any): Promise<boolean>;
3
- publish(input: any): any;
4
- }
5
- //# sourceMappingURL=BroadcastingChannel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BroadcastingChannel.d.ts","sourceRoot":"","sources":["../../broadcasting/BroadcastingChannel.ts"],"names":[],"mappings":"AAAA,qBAAa,mBAAmB;IACxB,SAAS,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5C,OAAO,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG;CAGzB"}
@@ -1,2 +0,0 @@
1
- export { BroadcastingChannel } from "./BroadcastingChannel";
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../broadcasting/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1,4 +0,0 @@
1
- // @bun
2
- import"../chunk-v0j7spj5.js";class n{async subscribe(r){return!0}publish(r){return{}}}export{n as BroadcastingChannel};
3
-
4
- //# debugId=3E2D2EBC3796AA1A64756E2164756E21
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../broadcasting/BroadcastingChannel.ts"],
4
- "sourcesContent": [
5
- "export class BroadcastingChannel {\n async subscribe(user: any): Promise<boolean> {\n return true;\n }\n\n publish(input: any): any {\n return {};\n }\n}\n"
6
- ],
7
- "mappings": ";6BAAO,MAAM,CAAoB,MACzB,UAAS,CAAC,EAA6B,CAC3C,MAAO,GAGT,OAAO,CAAC,EAAiB,CACvB,MAAO,CAAC,EAEZ",
8
- "debugId": "3E2D2EBC3796AA1A64756E2164756E21",
9
- "names": []
10
- }
@@ -1,7 +0,0 @@
1
- // @bun
2
- import{vf as W}from"./chunk-vax2fp2k.js";import{rg as i}from"./chunk-mwrh96hx.js";import{Eg as j}from"./chunk-8vnb3hfz.js";import{Lg as XH}from"./chunk-v0j7spj5.js";class k{static kind="controller";constructor(){}}class l extends k{}function A(H){let R=new Map;if(!H)return R;for(let K of H.split(";")){let T=K.indexOf("=");if(T===-1)continue;let J=K.slice(0,T).trim();if(!J)continue;R.set(J,K.slice(T+1).trim())}return R}function PH(H){return A(H.headers.get("cookie"))}function P(H){if(!/^\d+$/.test(H))return null;let R=Number(H);return Number.isSafeInteger(R)?R:null}function c(H){if(!H)return null;let R=H.trim();if(!/^bytes=/i.test(R))return null;let T=R.slice(6).split(",").map((Z)=>Z.trim()).filter((Z)=>Z!=="");if(T.length!==1)return null;let J=T[0],G=J.indexOf("-");if(G===-1)return null;let O=J.slice(0,G),X=J.slice(G+1);if(O===""){let Z=P(X);if(Z===null)return null;return{kind:"suffix",suffixLength:Z}}let Q=P(O);if(Q===null)return null;if(X==="")return{kind:"offset",start:Q,end:null};let Y=P(X);if(Y===null||Y<Q)return null;return{kind:"offset",start:Q,end:Y}}function b(H,R){if(!Number.isFinite(R)||R<=0)return null;let K,T;if(H.kind==="suffix"){if(H.suffixLength<=0)return null;K=Math.max(0,R-H.suffixLength),T=R-1}else{if(H.start>=R)return null;if(K=H.start,T=H.end===null?R-1:Math.min(H.end,R-1),T<K)return null}return{start:K,end:T,length:T-K+1}}function LH(H){if(H.kind==="suffix")return`bytes=-${H.suffixLength}`;return H.end===null?`bytes=${H.start}-`:`bytes=${H.start}-${H.end}`}function jH(H){if(!H)return null;let R=/^bytes\s+(\d+)-(\d+)\/(\d+)$/i.exec(H.trim());if(!R)return null;let K=P(R[1]),T=P(R[2]),J=P(R[3]);if(K===null||T===null||J===null||T<K)return null;return{start:K,end:T,total:J}}function MH(H,R,K){return`bytes ${H}-${R}/${K}`}function f(H){return`bytes */${H}`}var xH="GEMI_REQUEST_BREAKER_ERROR";class $ extends Error{kind="GEMI_REQUEST_BREAKER_ERROR";payload={api:{},view:{}}}class B extends ${errors={};constructor(H){super("Validation error");this.name="ValidationError",this.errors=H,this.payload={api:{status:400,data:{error:{kind:"validation_error",messages:H}},headers:{"Content-Type":"application/json"}},view:{status:400}}}}function r(H){let[R,K]=H.match(/\d+|\D+/g)??[];if(!R||!K)return 0;let T=Number.parseInt(R);switch(K){case"B":return T;case"KB":return T*1024;case"MB":return T*1024*1024;case"GB":return T*1024*1024*1024;case"TB":return T*1024*1024*1024*1024;default:return 0}}function a(H){switch(H){case"image":return"image";case"png":return"image/png";case"jpg":return"image/jpeg";case"jpeg":return"image/jpeg";case"ttf":return"font/ttf";case"excel":return"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";case"csv":return"text/csv";case"word":return"application/vnd.openxmlformats-officedocument.wordprocessingml.document";case"pdf":return"application/pdf";case"json":return"application/json";default:return H}}function g(H){if(typeof H==="string"||Array.isArray(H))return H.length;return}function F(H){return typeof H==="number"&&!Number.isNaN(H)}var e=["required","string","boolean","number","email","password","min","max","gte","lte","file","fileType","fileSize"];class D extends Error{name="InvalidValidationRuleError"}function x(H,R){let K=R===void 0||R.trim()===""?Number.NaN:Number(R);if(Number.isNaN(K))throw new D(`Validation rule "${H}:${R??""}" needs a number, e.g. "${H}:3"`);return K}function v(H){let[R,K]=H.split(":");switch(R){case"required":return(T)=>{if(T instanceof Blob)return T.size>0;if(T===null||T===void 0)return!1;if(typeof T==="string"||Array.isArray(T))return T.length>0;return!0};case"string":return(T)=>typeof T==="string";case"boolean":return(T)=>typeof T==="boolean";case"number":return(T)=>F(T);case"password":return(T)=>{return typeof T==="string"&&/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/.test(T)};case"min":{let T=x(R,K);return(J)=>{let G=g(J);return G!==void 0&&G>=T}}case"max":{let T=x(R,K);return(J)=>{let G=g(J);return G!==void 0&&G<=T}}case"gte":{let T=x(R,K);return(J)=>F(J)&&J>=T}case"lte":{let T=x(R,K);return(J)=>F(J)&&J<=T}case"email":return(T)=>{return typeof T==="string"&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(T)};case"file":return(T)=>{return T instanceof Blob};case"fileType":{if(!K)throw new D('Validation rule "fileType" needs a type, e.g. "fileType:png" or "fileType:image"');let T=a(K);return(J)=>J instanceof Blob&&J.type.startsWith(T)}case"fileSize":{let T=r(K??"");if(T===0&&!/^0+(B|KB|MB|GB|TB)$/.test(K??""))throw new D(`Validation rule "fileSize:${K??""}" needs a whole size in B, KB, MB, GB or TB, e.g. "fileSize:5MB"`);return(J)=>J instanceof Blob&&J.size<=T}default:throw new D(`Unknown validation rule "${H}". Known rules: ${e.join(", ")}`)}}var N=new WeakMap;function VH(H,R){N.set(H,{clientAddress:R})}function h(H){return N.has(H)}function SH(H){return N.get(H)?.clientAddress}var m=new WeakMap;function _H(H,R){m.set(H,R)}function d(H){return m.get(H)??null}var V=new WeakMap;function EH(H,R){let K=V.get(H)??[];if(!K.includes(R))V.set(H,[...K,R])}function IH(H){return V.get(H)??[]}class C{data;constructor(H){this.data=H}get(H){return this.data[H]}has(H){return this.data[H]!==void 0}toJSON(){return this.data}}class HH{kind;rawRequest;headers;cookies;search;schema={};routePath;params;domain;constructor(H,R,K,T){if(!H){let Q=W.getStore().req;this.params=Q.params,this.rawRequest=Q.rawRequest,this.kind=Q.kind,this.routePath=Q.routePath,this.domain=Q.domain??null}else this.params=R,this.rawRequest=H,this.routePath=T,this.kind=K??"api",this.domain=d(H);this.headers=this.rawRequest.headers;let J=A(this.rawRequest.headers.get("Cookie")),G=new URL(this.rawRequest.url),O=new Map;for(let[Q,Y]of G.searchParams)if(O.has(Q)){let Z=O.get(Q);if(Array.isArray(Z))Z.push(Y),O.set(Q,Z);else O.set(Q,[Z,Y])}else O.set(Q,Y);let X=Object.fromEntries(O.entries());this.search=new C(X),this.cookies=J}locale(){return W.getStore().locale}ctx(){return W.getStore()}isModelOriginated(){return h(this.rawRequest)}range(){return c(this.rawRequest.headers.get("Range"))}refine(H){return{}}async parseBody(){let H=new C({});if(this.rawRequest.headers.get("Content-Type")==="application/json"){let R=await this.rawRequest.json();H=new C(R)}if(this.rawRequest.headers.get("Content-Type")==="application/x-www-form-urlencoded"){let R=await this.rawRequest.formData();H=new C(R)}if(this.rawRequest.headers.get("Content-Type")?.startsWith("multipart/form-data")){let R=await this.rawRequest.formData(),K=new Map;for(let[T,J]of R.entries())if(K.has(T)){let G=K.get(T);if(Array.isArray(G))G.push(J),K.set(T,G);else K.set(T,[G,J])}else K.set(T,J);H=new C(Object.fromEntries(K.entries()))}return H}validateInput(H){let R={},K=Object.entries(this.schema).map(([T,J])=>({key:T,rules:Object.entries(J).map(([G,O])=>({rule:G,message:O,check:typeof O==="function"?null:this.ruleFor(T,G)}))}));for(let{key:T,rules:J}of K){let G=H.get(T),O=J.some(({rule:Y})=>Y==="required"),X=G===void 0||G===null||G==="",Q=[];for(let{rule:Y,message:Z,check:t}of J){let M=Z,z=!1;if(typeof Z==="function")M=Z(G),z=typeof M>"u";else z=t(G);if(z)continue;if(X&&!O)continue;if(Y==="required"){Q.splice(0,Q.length,String(M));break}Q.push(String(M))}if(Q.length>0)R[T]=Q}for(let[T,J]of Object.entries(this.refine(H.toJSON())??{})){if(!R[T])R[T]=[];R[T]=[...R[T]??[],J]}if(Object.keys(R).length>0)throw new B(R);return H}ruleFor(H,R){try{return v(R)}catch(K){if(K instanceof D)throw new D(`${this.constructor.name}.schema.${H}: ${K.message}`);throw K}}async input(){return this.validateInput(await this.parseBody())}async safeInput(){let H=await this.parseBody();try{return this.validateInput(H),{isValid:!0,errors:{},input:H}}catch(R){if(!(R instanceof B))throw R;return{isValid:!1,errors:R.errors,input:H}}}}class RH extends ${error;constructor(H="Not authorized"){super(H);this.name="AuthorizationError",this.error=H,this.payload={api:{status:401,data:{error:this.error}},view:{}}}}class p extends ${static apiStatus=403;error;constructor(H="Insufficient permissions"){super(H);this.name="InsufficientPermissionsError",this.error=H,this.payload={api:{status:p.apiStatus,data:{error:this.error}},view:{status:403}}}}class S extends ${total;constructor(H){super("Range not satisfiable");this.total=H;this.name="RangeNotSatisfiableError",this.payload={api:{status:416,data:{error:{message:"Range not satisfiable"}},headers:{"Content-Range":f(H),"Accept-Ranges":"bytes","Cache-Control":"no-store"}},view:{}}}}class U extends ${fileName;constructor(H){super("File not found");this.fileName=H;this.name="FileNotFoundError",this.payload={api:{status:404,data:{error:{message:"Not found"}},headers:{"Cache-Control":"no-store"}},view:{}}}}class TH extends ${constructor(H={}){super("Authentication error");this.name="AuthenticationError";let R=H.redirectTo??"/auth/sign-in";this.payload={api:{status:401,data:{error:"Authentication error"}},viewData:{status:200,data:{},headers:{"Cache-Control":"private, no-cache, no-store, max-age=0, must-revalidate"},directive:{kind:"Redirect",path:R}},view:{status:302,headers:{"Cache-Control":"private, no-cache, no-store, max-age=0, must-revalidate",Location:R}}}}}class L{static getFacadeAccessor(){throw Error(`Facade [${this.name}] does not implement getFacadeAccessor().`)}static getFacadeRoot(){return i(this.getFacadeAccessor())}}class w{async delete(H){throw Error(`${this.constructor.name} does not implement delete(). Override it to remove objects from this backend.`)}async read(H){let R=typeof H==="string"?{name:H}:H,K=await this.fetch({name:R.name,bucket:R.bucket});if(!K.ok)throw new U(R.name);let T=K.headers.get("Content-Type")??"application/octet-stream",J=K.headers.get("ETag")??void 0,G=K.headers.get("Last-Modified"),O=G?new Date(G):void 0;if(R.range){let Y=await K.blob();return{body:Y,start:0,end:Y.size-1,total:Y.size,partial:!1,type:T,etag:J,lastModified:O,name:R.name}}let X=Number(K.headers.get("Content-Length")),Q=Number.isFinite(X)?X:0;return{body:K.body,start:0,end:Q-1,total:Q,partial:!1,type:T,etag:J,lastModified:O,name:R.name}}async size(H){let R=typeof H==="string"?H:H.name,K=typeof H==="string"?void 0:H.bucket,T=await this.fetch({name:R,bucket:K});if(!T.ok)throw new U(R);let J=Number(T.headers.get("Content-Length"));if(Number.isFinite(J))return await T.body?.cancel(),J;return(await T.blob()).size}}function u(H,R){if(!R)return H;let K=H.getReader(),T=!1,J,G=()=>{if(T=!0,J)R.removeEventListener("abort",J)};return new ReadableStream({start(O){if(J=()=>{if(T)return;G(),O.error(R.reason),K.cancel(R.reason).catch(()=>{})},R.aborted)J();else R.addEventListener("abort",J,{once:!0})},async pull(O){let X;try{X=await K.read()}catch(Q){if(T)return;G(),O.error(Q);return}if(T)return;if(X.done){G(),O.close();return}O.enqueue(X.value)},cancel(O){return G(),K.cancel(O)}},{highWaterMark:0})}import{readdir as KH,unlink as JH}from"fs/promises";import{isAbsolute as GH,relative as OH,resolve as n,sep as QH}from"path";class _ extends w{configured;constructor(H){super();this.configured=H}get folderPath(){return this.configured??`${j()}/storage`}async put(H,{signal:R}={}){R?.throwIfAborted();let K,T;if(H instanceof Blob)K=H,T=`${Bun.randomUUIDv7()}.${H.type.split("/")[1].split(";")[0]}`;else K=H.body,T=H.name;let J=K instanceof Buffer?K:K instanceof Blob||K instanceof File?Buffer.from(await K.arrayBuffer()):"",G=`${this.folderPath}/${T}`;return R?.throwIfAborted(),await Bun.write(G,J),T}async fetch(H,{signal:R}={}){R?.throwIfAborted();let K=process.env.BUCKET_NAME,T;if(typeof H==="string")T=H;else K=H.bucket??K,T=H.name;if(!T)throw Error("Object name has to be specified");let J=`${this.folderPath}/${T}`,G=Bun.file(J),O=u(Bun.file(J).stream(),R),X=new Date(G.lastModified).toUTCString();return new Response(O,{headers:{"Content-Type":G.type,"Content-Length":String(G.size),"Cache-Control":"private, max-age=12000, must-revalidate","Last-Modified":X}})}async read(H){let R=typeof H==="string"?{name:H}:H,{name:K,range:T=null}=R;if(!K)throw Error("Object name has to be specified");let J=Bun.file(`${this.folderPath}/${K}`);if(!await J.exists())throw new U(K);let G=J.size,O=T?b(T,G):null;if(T&&!O)throw new S(G);let X=O?.start??0,Q=O?O.end:G-1;return{body:O?J.slice(X,Q+1):J,start:X,end:Q,total:G,partial:Boolean(O),type:J.type||"application/octet-stream",lastModified:new Date(J.lastModified),name:K}}async size(H){let R=typeof H==="string"?H:H.name,K=Bun.file(`${this.folderPath}/${R}`);if(!await K.exists())throw new U(R);return K.size}async delete(H){let R=typeof H==="string"?H:H.name;if(!R)throw Error("Object name has to be specified");let K=n(this.folderPath),T=n(K,R),J=OH(K,T);if(!J||J===".."||J.startsWith(`..${QH}`)||GH(J))throw Error(`Refusing to delete "${R}": it is outside the storage folder`);try{await JH(T)}catch(G){if(G?.code==="ENOENT")return;throw G}}async list(){return await KH(this.folderPath)}}function JR(H){return H}function o(){return{driver:new _}}class E{static token="filesystem";driver;constructor(H={}){this.driver=H.driver??o().driver}}import{Buffer as YH}from"buffer";async function s(H){try{return(await import("sharp")).default}catch(R){throw Error(`${H} requires the 'sharp' package. Install it with \`bun add sharp\`.`,{cause:R})}}class ZH extends L{static getFacadeAccessor(){return E}static async put(H,R={}){return this.getFacadeRoot().driver.put(H,R)}static async metadata(H){let R=YH.from(await H.arrayBuffer()),K=await s("Storage.metadata()");try{return await K(R).metadata()}catch{return{}}}static async fetch(H,R={}){return R.signal?.throwIfAborted(),this.getFacadeRoot().driver.fetch(H,R)}static async read(H,R={}){let K=typeof H==="string"?{name:H}:{...H},T="range"in R?R.range??null:K.range!==void 0?K.range:W.getStore()?.rangeRequest??null;return this.getFacadeRoot().driver.read({...K,range:T})}static list(H){return this.getFacadeRoot().driver.list(H)}static async delete(H){return this.getFacadeRoot().driver.delete(H)}}import{mkdir as I,readdir as $H,access as DH}from"fs/promises";async function y(H){try{return await DH(H),!0}catch{return!1}}class q{config;static token="log";writer;isReady=!1;flushTimeout;fileSize=0;writerSize=0;isCreatingFile=!1;bootPromise=null;currentLogFilePath;get logsDirPath(){return`${j()}/storage/logs`}constructor(H){this.config=H}boot(){if(!this.bootPromise)this.bootPromise=this.createStorage().catch((H)=>{console.error("Log storage unavailable, file logging disabled",H)}).then(()=>{this.isReady=!0});return this.bootPromise}async createStorage(){let H=`${j()}/storage`;if(!await y(H))await I(H);if(!await y(this.logsDirPath))await I(this.logsDirPath);await this.newLogFile()}async newLogFile(){if(!await y(this.logsDirPath))await I(this.logsDirPath);if(this.isCreatingFile=!0,this.currentLogFilePath){this.writer.flush(),this.writer.end(),this.writer=null;let K=new File([await Bun.file(this.currentLogFilePath).arrayBuffer()],this.currentLogFilePath.split("/").pop(),{type:"text/plain"});this.config.onLogFileClosed(K),this.fileSize=0,this.writerSize=0}let R=(await $H(this.logsDirPath)).sort().reverse()[0];if(R){let K=Bun.file(`${this.logsDirPath}/${R}`);if(K.size<this.config.maxFileSize)this.currentLogFilePath=`${this.logsDirPath}/${R}`,this.writer=K.writer(),this.writer.write(await K.text()),this.writer.write(`
3
- `),this.writer.flush(),this.fileSize=K.size}if(!this.writer){let K=`${new Date(Date.now()).toISOString()}.log`.replaceAll(":","-");this.currentLogFilePath=`${this.logsDirPath}/${K}`;let T=Bun.file(`${this.logsDirPath}/${K}`);this.writer=T.writer(),this.fileSize=0,this.writerSize=0}this.isCreatingFile=!1}async log(H,R,K={}){if(!this.isReady)await this.boot();let T=W.getStore(),J={};if(T)J={url:T.req.rawRequest.url,method:T.req.rawRequest.method,headers:T.req.rawRequest.headers,body:T.req.rawRequest.body};let G={timestamp:new Date(Date.now()).toISOString(),env:Bun.env.NODE_ENV,level:H,message:R,metadata:{...J,...K}},O="";try{O=JSON.stringify(G)}catch(X){console.log("Error parsing log object",X)}try{let X=this.config.onLogCreated(G);if(X instanceof Promise)X.catch((Q)=>console.error("Error in onLogCreated",Q))}catch(X){console.error("Error in onLogCreated",X)}if(!this.writer)return;this.writerSize+=O.length,this.fileSize+=O.length;try{this.writer.write(O),this.writer.write(`
4
- `),this.tryFlush()}catch(X){console.error("Error writing log",X)}}async tryFlush(){if(this.fileSize>this.config.maxFileSize){if(!this.isCreatingFile)await this.newLogFile()}if(this.writerSize>this.config.maxFileSize/2)await this.writer.flush(),this.writerSize=0,await this.newLogFile();else clearTimeout(this.flushTimeout),this.flushTimeout=setTimeout(async()=>{await this.writer.flush(),this.writerSize=0},100)}}class WH extends L{static getFacadeAccessor(){return q}static debug(H,R){this.getFacadeRoot().log("debug",H,R)}static info(H,R){this.getFacadeRoot().log("info",H,R)}static notice(H,R){this.getFacadeRoot().log("notice",H,R)}static warning(H,R){this.getFacadeRoot().log("warning",H,R)}static error(H,R){this.getFacadeRoot().log("error",H,R)}static critical(H,R){this.getFacadeRoot().log("critical",H,R)}static alert(H,R){this.getFacadeRoot().log("alert",H,R)}static emergency(H,R){this.getFacadeRoot().log("emergency",H,R)}}
5
- export{k as Ke,l as Le,A as Me,PH as Ne,VH as Oe,SH as Pe,c as Qe,b as Re,LH as Se,jH as Te,MH as Ue,f as Ve,_H as We,d as Xe,EH as Ye,IH as Ze,xH as _e,$ as $e,B as af,D as bf,HH as cf,RH as df,p as ef,S as ff,U as gf,TH as hf,L as if,s as jf,w as kf,u as lf,_ as mf,JR as nf,o as of,E as pf,ZH as qf,q as rf,WH as sf};
6
-
7
- //# debugId=C06EF1FC40EB69B364756E2164756E21
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../support/ServiceProvider.ts"],
4
- "sourcesContent": [
5
- "import type { Application } from \"../foundation/Application\";\n\n/**\n * Every hook defaults to a no-op. `register()` binds services into the\n * container and must not resolve any of them; `boot()` runs after every\n * provider has registered, so it may resolve freely.\n *\n * `shutdown()` runs once when a production server is told to stop (`SIGTERM`\n * or `SIGINT`), after it has stopped accepting requests and the in-flight ones\n * have finished or run out of grace — so nothing a request needs is torn down\n * under it. Providers shut down in reverse registration order, so one\n * registered after another may still use it. Each is awaited, but under a\n * shared deadline (`GEMI_SHUTDOWN_PROVIDER_TIMEOUT`): one that overruns is\n * abandoned and the next begins, and one that throws is logged and does not\n * stop the rest. See `Application.shutdown`.\n *\n * Under `gemi dev` it also runs on every `bun --hot` reload, for the\n * application the reload replaced, once the new one is serving and the old\n * one's requests have finished (see `server/devReload.ts`). A hook that closes\n * something kept on `globalThis` across reloads would close it for the new\n * application too.\n *\n * `timeoutMs` is what is left of that shared deadline when this provider is\n * reached. A provider that waits for something — jobs finishing, a queue\n * draining — should bound its own wait by a little less than this, so that it\n * is still the one to report what it gave up on. Ignoring it is fine; the\n * provider is then simply abandoned at the deadline, with only a generic line\n * from `Application` to say so.\n */\nexport abstract class ServiceProvider {\n constructor(protected app: Application) {}\n\n register(): void {}\n\n boot(): void | Promise<void> {}\n\n shutdown(options?: { timeoutMs: number }): void | Promise<void> {}\n}\n"
6
- ],
7
- "mappings": ";AA6BO,MAAe,CAAgB,CACd,IAAtB,WAAW,CAAW,EAAkB,CAAlB,WAEtB,QAAQ,EAAS,EAEjB,IAAI,EAAyB,EAE7B,QAAQ,CAAC,EAAuD,EAClE",
8
- "debugId": "E85534E036CAEBF564756E2164756E21",
9
- "names": []
10
- }
@@ -1,4 +0,0 @@
1
- // @bun
2
- import{Fg as J}from"./chunk-d2esms7y.js";class L{kernel;onException;constructor(z){this.kernel=new z.kernel,this.kernel.boot.call(this.kernel),this.onException=z.onException??((B)=>{console.error("Unhandled exception in App:",B)})}async waitForBoot(){await this.kernel.waitForBoot()}getComponentTree(){return this.kernel.viewRoutes().componentTree}getFlatComponentTree(){let z=new Set;for(let B of this.kernel.domains().viewDispatchers())for(let C of B.flatComponentTree)z.add(C);return Array.from(z)}devAllowedHosts(){let z=this.kernel.domains();if(!z.resolver)return[];return z.acceptsCustomDomains?!0:[`.${z.resolver.root}`]}getRouteManifest(){return this.kernel.viewRoutes().routeManifest}globallyGated=new WeakMap;async withGlobalMiddleware(z,B,C){let A;try{A=await this.kernel.run.call(this.kernel,()=>this.kernel.globalMiddleware(z))}catch(F){return await C(F)}if(A.refusal)return A.refusal;return this.globallyGated.set(z,A.carried),A.apply(await B(z))}async fetch(z){let B=new URL(z.url);return this.kernel.run.call(this.kernel,async()=>{let C=this.globallyGated.has(z),A=C?null:await this.kernel.globalMiddleware(z),F=C?this.globallyGated.get(z):A.carried;if(A?.refusal)return A.refusal;let I=this.kernel.domains(),D=await I.ask(z)??await I.route(z);if(D instanceof Response)return A?A.apply(D):D;if(!D){let H=new Response("Unknown host",{status:404});return A?A.apply(H):H}let G=J(B.pathname)?await D.api.handleApiRequest(z,F):await D.view.handleViewRequest(z,F);if(!A)return G;if(typeof G==="function"){let H=G;return async(...M)=>A.apply(await H(...M))}return A.apply(G)})}websocket={message:(z,B)=>{this.kernel.run.bind(this.kernel)(()=>{let A=this.kernel.broadcast();A.run(z.data.headers,()=>{A.handleMessage(z,B)})})},open:(z)=>{},close:(z)=>{console.log("closed ws"),z.terminate()}};onPublish(z){this.kernel.run.bind(this.kernel)(()=>{this.kernel.broadcast().onPublish(z)})}dispatchJob(z,B){return this.kernel.run.bind(this.kernel)(()=>{return this.kernel.queue().dispatchJob(z,B)})}shutdown(z){return this.kernel.shutdown(z)}destroy(){this.kernel.destroy()}clone(){return Object.assign(Object.create(Object.getPrototypeOf(this)),this)}}export{L as xa};
3
-
4
- //# debugId=896A20015EF929BE64756E2164756E21
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../app/App.ts"],
4
- "sourcesContent": [
5
- "import type { WebSocketHandler } from \"bun\";\nimport type { Kernel } from \"../kernel\";\nimport type { CarriedContext } from \"../http/requestContext\";\nimport { isApiPath } from \"../services/router/apiPath\";\n\ninterface AppParams {\n kernel: new () => Kernel;\n onException?: (error: Error) => void;\n}\n\nexport class App {\n private kernel: Kernel;\n public onException?: (error: Error) => void;\n\n constructor(params: AppParams) {\n this.kernel = new params.kernel();\n this.kernel.boot.call(this.kernel);\n this.onException =\n params.onException ??\n ((error: Error) => {\n console.error(\"Unhandled exception in App:\", error);\n });\n }\n\n // Every service this class touches is resolved through a `this.kernel.*`\n // accessor rather than by importing the service class and calling `app()`\n // here. That is deliberate: the built bin (`dist/bin/gemi.js`) bundles its own\n // copy of gemi, while the app's Kernel is loaded from source and resolves\n // `gemi/*` to the source modules — so the two copies have *different*\n // `kernelContext` AsyncLocalStorage instances and different `Application`\n // class objects. A method call on the Kernel executes in the app's copy and\n // reads the app's container; a resolution attempted here would not. Service\n // *tokens* still cross the boundary safely (they are plain strings), which is\n // why `kernel.resolve()` works from either side.\n public async waitForBoot() {\n await this.kernel.waitForBoot();\n }\n\n public getComponentTree() {\n return this.kernel.viewRoutes().componentTree;\n }\n\n // Every host group's views, not just the root's: the servers load these\n // modules up front, and a view only an `admin.` group routes to still has\n // to be among them.\n public getFlatComponentTree() {\n const views = new Set<string>();\n for (const dispatcher of this.kernel.domains().viewDispatchers()) {\n for (const view of dispatcher.flatComponentTree) {\n views.add(view);\n }\n }\n return Array.from(views);\n }\n\n /**\n * The hosts the dev server's Vite may answer: the `route.domains` root and\n * its subdomains, or any host when custom domains are on, since those are\n * only known to the app's resolver.\n */\n public devAllowedHosts(): true | string[] {\n const domains = this.kernel.domains();\n if (!domains.resolver) {\n return [];\n }\n return domains.acceptsCustomDomains ? true : [`.${domains.resolver.root}`];\n }\n\n public getRouteManifest() {\n return this.kernel.viewRoutes().routeManifest;\n }\n\n // Requests `withGlobalMiddleware` already ran the global middleware for, so\n // `fetch` inside it does not run the list a second time, and can still hand\n // the route what the list carried. Keyed by the Request object: the servers\n // hand `fetch` the same one they gated.\n private globallyGated = new WeakMap<Request, CarriedContext | null>();\n\n /**\n * Runs the `global` middleware list, then `next` — what the servers put in\n * front of everything they serve, so the list covers static files, which\n * never reach `fetch`, as well as routes. A refusal is answered without\n * calling `next`. A global middleware that throws something other than a\n * break is answered by `onError` rather than by `next`, since a gate that\n * failed must not let a static file through.\n */\n public async withGlobalMiddleware(\n req: Request,\n next: (req: Request) => Promise<Response>,\n onError: (err: unknown) => Response | Promise<Response>,\n ): Promise<Response> {\n let outcome: Awaited<ReturnType<Kernel[\"globalMiddleware\"]>>;\n try {\n outcome = await this.kernel.run.call(this.kernel, () => this.kernel.globalMiddleware(req));\n } catch (err) {\n return await onError(err);\n }\n if (outcome.refusal) {\n return outcome.refusal;\n }\n this.globallyGated.set(req, outcome.carried);\n return outcome.apply(await next(req));\n }\n\n public async fetch(req: Request): Promise<Response> {\n const url = new URL(req.url);\n return this.kernel.run.call(this.kernel, async () => {\n // Run here too for a caller that is not one of the servers, a test or an\n // app's own `Bun.serve`, so the list is not skipped by calling `fetch`.\n const gated = this.globallyGated.has(req);\n const outcome = gated ? null : await this.kernel.globalMiddleware(req);\n const carried = gated ? this.globallyGated.get(req) : outcome.carried;\n if (outcome?.refusal) {\n return outcome.refusal;\n }\n const domains = this.kernel.domains();\n const dispatchers = (await domains.ask(req)) ?? (await domains.route(req));\n if (dispatchers instanceof Response) {\n return outcome ? outcome.apply(dispatchers) : dispatchers;\n }\n if (!dispatchers) {\n const unknown = new Response(\"Unknown host\", { status: 404 });\n return outcome ? outcome.apply(unknown) : unknown;\n }\n const result = isApiPath(url.pathname)\n ? await dispatchers.api.handleApiRequest(req, carried)\n : await dispatchers.view.handleViewRequest(req, carried);\n if (!outcome) {\n return result;\n }\n // A document comes back as a render function the server calls with its\n // manifests, and the Response only exists once it has.\n if (typeof result === \"function\") {\n const render = result as (...args: any[]) => Promise<Response>;\n return (async (...args: any[]) => outcome.apply(await render(...args))) as any;\n }\n return outcome.apply(result);\n });\n }\n\n public websocket: WebSocketHandler<{ headers: Headers }> = {\n message: (ws, message) => {\n const kernelRun = this.kernel.run.bind(this.kernel);\n kernelRun(() => {\n const broadcast = this.kernel.broadcast();\n broadcast.run(ws.data.headers, () => {\n broadcast.handleMessage(ws, message);\n });\n });\n },\n open: (_ws) => {},\n close: (ws) => {\n console.log(\"closed ws\");\n ws.terminate();\n },\n };\n\n public onPublish(\n fn: (\n topic: string,\n data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,\n compress?: boolean,\n ) => void,\n ) {\n const kernelRun = this.kernel.run.bind(this.kernel);\n kernelRun(() => {\n this.kernel.broadcast().onPublish(fn);\n });\n }\n\n public dispatchJob(jobName: string, args: string) {\n const kernelRun = this.kernel.run.bind(this.kernel);\n return kernelRun(() => {\n return this.kernel.queue().dispatchJob(jobName, args);\n });\n }\n\n /** Every provider's `shutdown()`; see `Kernel.shutdown`. */\n public shutdown(options?: { timeoutMs?: number }) {\n return this.kernel.shutdown(options);\n }\n\n public destroy() {\n this.kernel.destroy();\n }\n\n public clone() {\n return Object.assign(Object.create(Object.getPrototypeOf(this)), this);\n }\n}\n\nexport type FetchHandler = InstanceType<typeof App>[\"fetch\"];\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "896A20015EF929BE64756E2164756E21",
9
- "names": []
10
- }
@@ -1,5 +0,0 @@
1
- // @bun
2
- import{AsyncLocalStorage as z}from"async_hooks";var G=new z;
3
- export{G as sg};
4
-
5
- //# debugId=3FBFA12C42C7A1A564756E2164756E21
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../kernel/context.ts"],
4
- "sourcesContent": [
5
- "import { AsyncLocalStorage } from \"async_hooks\";\n\n/**\n * The kernel's AsyncLocalStorage. It holds the Application, and nothing else —\n * `Kernel.run()` enters it once per request, websocket message or cron tick,\n * and `foundation/app.ts` reads it to resolve services.\n *\n * \"The framework's only AsyncLocalStorage\" is a claim that used to sit here. It\n * was already not true — the *kernel's* is the only one, but `http/`, `pubsub/`\n * and now the ORM each keep their own. Four in the shipped framework (a fifth\n * sits in `rfc/workflow.ts`, an unreferenced design sketch that is outside\n * `package.json`'s exports and that nothing imports):\n *\n * kernel kernel/context.ts the Application\n * request http/requestContext.ts req, user, cookies, locale\n * broadcast services/pubsub/BroadcastManager.ts headers, cookies\n * orm orm/context.ts an open transaction\n *\n * The pattern is one store per scope with one owner, entered by that owner and\n * read through its own accessor — `app()`, `RequestContext.getStore()`,\n * `currentTransaction()`. What matters is that this one holds the Application\n * and nothing else, because `foundation/app.ts` reads it unconditionally.\n *\n * The ORM's, added in iteration 5, holds an open transaction handle and its\n * nesting depth. It is deliberately separate rather than merged into this one:\n *\n * - A transaction scope nests *inside* an Application scope without replacing\n * it. Re-entering this store with a `{ app, tx }` wrapper would mean every\n * reader of it — `app()` above all — has to handle two shapes forever, and a\n * miss there is not a transaction bug, it is a service resolving off the\n * wrong Application.\n * - The alternative of hanging the handle off the Application is worse than a\n * style question: one Application serves every concurrent request, so two\n * overlapping transactions would overwrite each other's handle and statements\n * would land in the wrong one. That is silent data corruption.\n *\n * The cost is honest: one more store on the hot path of every query. The ORM's\n * is shallow — one small object, entered only inside `Model.transaction` or\n * `DB.transaction`, never per request — so a query outside a transaction pays\n * one `getStore()` returning undefined.\n *\n * If another is ever proposed, this is the note to read first: the bar is that\n * the state is genuinely per-async-scope *and* cannot live in an existing store\n * without making that store's readers ambiguous.\n */\nexport const kernelContext = new AsyncLocalStorage();\n"
6
- ],
7
- "mappings": ";AAAA,4BAAS,oBA6CF,IAAM,EAAgB,IAAI",
8
- "debugId": "3FBFA12C42C7A1A564756E2164756E21",
9
- "names": []
10
- }
@@ -1,6 +0,0 @@
1
- // @bun
2
- import{va as j}from"./chunk-8z37k28d.js";import{createElement as x}from"react";function h(i,n){let s=Object.keys(n).sort((u,r)=>r.length-u.length).map((u)=>u.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")),b=new RegExp(s.join("|"),"g");return i.replace(b,(u)=>n[u])}async function J(i,n,s=[]){let b=[...s.map((t)=>`${i}/views/${t}.tsx`),`${i}/views/RootLayout.tsx`],u=new Set;for(let t of b){let e=n.moduleGraph.getModulesByFile(t);if(e)for(let l of e)u.add(l)}let r=[],p=[],g={};for(let t of u)if(t)for(let e of t.importedModules){if(e.file.includes("module.css"))g[e.file]=e.ssrTransformResult.map.sourcesContent.join("");if(e.file.includes(".css"))p.push(e.file)}for(let t of p){let e=await n.transformRequest(t+"?direct"),l=t.includes("module.css"),o="";if(l)o=h(g[t],e.default);r.push({isDev:!0,id:t,content:l?o:e.code})}return r.map((t,e)=>{return x("style",{key:e,type:"text/css","data-vite-dev-id":t.id,dangerouslySetInnerHTML:{__html:t.content}})})}async function L(i=[]){return i.map((n,s)=>{return x("style",{key:s,id:n?.id,type:"text/css",dangerouslySetInnerHTML:{__html:n.content}})})}import{existsSync as v}from"fs";import{basename as f}from"path";import{networkInterfaces as k}from"os";var y={name:"gemi",version:"0.82.0",private:!1,license:"MIT",author:"Enes Tufekci <enes@gemijs.dev>",repository:{type:"git",url:"git+https://github.com/nstfkc/gemi.git",directory:"packages/gemi"},bin:{gemi:"./dist/bin/gemi.js","gemi-orm-generator":"./dist/bin/orm-generator.js"},files:["dist/**/*","ide/typescript-plugin/package.json","skills/**/*"],module:!0,exports:{"./http":"./http/index.ts","./client":"./client/index.ts","./ai":"./ai/index.ts","./ai/client":"./ai/client/index.ts","./testing":"./testing/index.ts","./app":"./app/index.ts","./facades":"./facades/index.ts","./email":"./email/index.ts","./vite":"./dist/vite/index.mjs","./kernel":"./kernel/index.ts","./services":"./services/index.ts","./broadcasting":"./broadcasting/index.ts","./i18n":"./i18n/index.ts","./dictionary":"./i18n/dictionaryRuntime.ts","./server":"./server/index.ts","./config":"./config/index.ts","./container":"./container/index.ts","./foundation":"./foundation/index.ts","./database":"./database/index.ts","./orm":"./orm/index.ts","./support":"./support/index.ts","./console/run":"./console/run.ts","./queue/work":"./services/queue/work.ts","./ide/typescript-plugin":"./ide/typescript-plugin/index.ts","./bun/preload":"./bun/preload.ts","./bun/plugin":"./bun/plugin.ts"},scripts:{lint:"oxlint",typecheck:"tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.browser.json && tsc --noEmit -p ide/typescript-plugin/tsconfig.json",build:"NODE_ENV=production bun run build:core && bun run build:bin && bun run build:types && bun run build:client && bun run build:plugin && bun run build:ts-plugin && bun run build:client-types && bun run build:augmentation","build:core":"bun ./scripts/build.ts","build:bin":"bun build --outdir=./dist/bin --target=bun --external=vite --external=react-dom --external=react/jsx-runtime --external=bun --external=sharp --external=@azure/storage-blob --external=typescript --sourcemap ./bin/gemi.ts ./bin/orm-generator.ts && bun ./scripts/prepare-bin.ts","build:client":"rm -rf dist/client dist/testing dist/ai/client dist/chunks && vite build -c vite.client.config.mts","build:plugin":"vite build -c vite.plugin.config.mts","build:ts-plugin":"bun ./scripts/build-ts-plugin.ts","build:types":"tsc -p tsconfig.build.json","build:client-types":"tsc -p tsconfig.browser.json",test:"bun --bun vitest","test:types":"vitest run --typecheck.only","test:live":"bun --bun vitest run ai/live","test:packaging":"bun --bun vitest run --config vitest.packaging.config.ts","build:publish":"bun scripts/build-publish.ts",prepublishOnly:"echo 'Do not publish from this directory \u2014 its exports point at TS source. Run: bun run build:publish, then publish from .publish/' && exit 1","build:augmentation":"bun ./scripts/wire-augmentation.ts"},dependencies:{"@aws-sdk/client-s3":"^3.629.0","@aws-sdk/s3-request-presigner":"^3.629.0","ast-types":"^0.14.2",commander:"^12.1.0",history:"^5.3.0","jsx-email":"2.0.0-rc2.1","magic-string":"^0.30.17",open:"^10.1.0","react-error-boundary":"^6.0.0",recast:"^0.23.9",resend:"^6.12.3",satori:"^0.12.2","temporal-polyfill":"^0.2.5","twitter-api-v2":"^1.20.2","urlpattern-polyfill":"^10.0.0",uuid:"^9.0.1"},devDependencies:{"@babel/parser":"^7.25.4","@prisma/generator-helper":"^6.5.0","@repo/typescript-config":"*","@testing-library/react":"^16.3.2","@types/bun":"^1.3.14","@types/eslint":"^8.56.5","@types/node":"^20.11.24","@types/react":"^19.0.2","@types/react-dom":"^19.0.2",eslint:"^8.57.0",jsdom:"^30.0.1",oxlint:"^1.39.0",react:"19.2.3","react-dom":"19.2.3",typescript:"^5.7.3",vitest:"^4.0.0"},peerDependencies:{"@azure/storage-blob":"^12.28.0",react:">=19","react-dom":">=19",sharp:"^0.34.2",typescript:">=5",vite:"^8.0.0"},peerDependenciesMeta:{"@azure/storage-blob":{optional:!0},typescript:{optional:!0}}};var q=[" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2557","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551","\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551","\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551"," \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D"],z=Boolean(process.stdout.isTTY)&&!process.env.NO_COLOR,c=(i,n)=>z?`\x1B[${i}m${n}\x1B[0m`:n,E=(i)=>c("1",i),d=(i)=>c("2",i),a=(i)=>c("36",i),O=(i)=>c("32",i),T=(i)=>c("35",i);function R(){return y.version??"?"}function _(i){for(let n of Object.values(k()))for(let s of n??[])if((s.family==="IPv4"||s.family===4)&&!s.internal)return`http://${s.address}:${i}`;return null}function G(i){return j(i).filter((n)=>v(n)).map((n)=>f(n))}function A(i){let{port:n,rootDir:s}=i,b=`http://localhost:${n}`,u=_(n),r=G(s),p=(t,e)=>` ${O("\u279C")} ${E(t.padEnd(9))}${e}`,g=["",...q.map((t)=>T(t)),"",` ${d("gemi")} ${a(`v${R()}`)}`,"",p("Local:",a(b)),p("Network:",u?a(u):d("unavailable")),p("Env:",r.length?r.join(", "):d("none")),""];console.log(g.join(`
3
- `))}
4
- export{J as h,L as i,A as j};
5
-
6
- //# debugId=1CEA80587159A74064756E2164756E21