gemi 0.109.0 → 0.110.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 (263) hide show
  1. package/dist/ai/index.js +2 -2
  2. package/dist/ai/index.js.map +1 -1
  3. package/dist/app/index.js +2 -2
  4. package/dist/app/index.js.map +1 -1
  5. package/dist/bin/gemi.js +485 -63
  6. package/dist/bin/gemi.js.map +12 -8
  7. package/dist/bun/plugin.js +2 -2
  8. package/dist/bun/plugin.js.map +1 -1
  9. package/dist/bun/preload.js +2 -2
  10. package/dist/bun/preload.js.map +1 -1
  11. package/dist/{chunk-hgz8sx40.js → chunk-09ypnhjv.js} +3 -3
  12. package/dist/{chunk-hgz8sx40.js.map → chunk-09ypnhjv.js.map} +1 -1
  13. package/dist/{chunk-qnq110tw.js → chunk-0d9qsmx2.js} +3 -3
  14. package/dist/{chunk-qnq110tw.js.map → chunk-0d9qsmx2.js.map} +1 -1
  15. package/dist/{chunk-m9609t1y.js → chunk-0sjh5v1n.js} +1 -1
  16. package/dist/{chunk-g5a3ptsa.js → chunk-11fsn5mr.js} +3 -3
  17. package/dist/{chunk-g5a3ptsa.js.map → chunk-11fsn5mr.js.map} +1 -1
  18. package/dist/{chunk-whe0x70j.js → chunk-1c1d0e60.js} +3 -3
  19. package/dist/{chunk-whe0x70j.js.map → chunk-1c1d0e60.js.map} +1 -1
  20. package/dist/{chunk-rgfzqwpg.js → chunk-1kr25rcg.js} +3 -3
  21. package/dist/{chunk-rgfzqwpg.js.map → chunk-1kr25rcg.js.map} +1 -1
  22. package/dist/{chunk-vee4j6ft.js → chunk-1pem26zc.js} +3 -3
  23. package/dist/{chunk-vee4j6ft.js.map → chunk-1pem26zc.js.map} +1 -1
  24. package/dist/{chunk-nxxx0m1a.js → chunk-1va15sfq.js} +2 -2
  25. package/dist/{chunk-nxxx0m1a.js.map → chunk-1va15sfq.js.map} +2 -2
  26. package/dist/{chunk-wvwee7dn.js → chunk-1yx2e0bh.js} +2 -2
  27. package/dist/{chunk-wvwee7dn.js.map → chunk-1yx2e0bh.js.map} +1 -1
  28. package/dist/{chunk-9r3znmqq.js → chunk-303mprnv.js} +2 -2
  29. package/dist/{chunk-9r3znmqq.js.map → chunk-303mprnv.js.map} +1 -1
  30. package/dist/{chunk-grs8dnkd.js → chunk-30xjcyzh.js} +2 -2
  31. package/dist/{chunk-grs8dnkd.js.map → chunk-30xjcyzh.js.map} +1 -1
  32. package/dist/{chunk-h15eae7g.js → chunk-358sdcx9.js} +3 -3
  33. package/dist/{chunk-h15eae7g.js.map → chunk-358sdcx9.js.map} +1 -1
  34. package/dist/{chunk-367kyrdx.js → chunk-3cg7y62b.js} +2 -2
  35. package/dist/{chunk-367kyrdx.js.map → chunk-3cg7y62b.js.map} +1 -1
  36. package/dist/{chunk-t26n9vzw.js → chunk-3y8q8x11.js} +2 -2
  37. package/dist/{chunk-t26n9vzw.js.map → chunk-3y8q8x11.js.map} +1 -1
  38. package/dist/chunk-4mfrgd5m.js +34 -0
  39. package/dist/chunk-4mfrgd5m.js.map +10 -0
  40. package/dist/chunk-5cygrbxv.js +4 -0
  41. package/dist/{chunk-9qw9fa6z.js.map → chunk-5cygrbxv.js.map} +2 -2
  42. package/dist/{chunk-tvy2fqza.js → chunk-5stgtwqw.js} +2 -2
  43. package/dist/{chunk-tvy2fqza.js.map → chunk-5stgtwqw.js.map} +1 -1
  44. package/dist/chunk-61f4m5px.js +6 -0
  45. package/dist/{chunk-fe1pcnw6.js.map → chunk-61f4m5px.js.map} +5 -4
  46. package/dist/chunk-6chz1ktz.js +9 -0
  47. package/dist/chunk-6chz1ktz.js.map +13 -0
  48. package/dist/{chunk-wqsdjweb.js → chunk-6vr7f5fq.js} +4 -4
  49. package/dist/{chunk-wqsdjweb.js.map → chunk-6vr7f5fq.js.map} +1 -1
  50. package/dist/{chunk-g74qwhvf.js → chunk-7tx5y712.js} +2 -2
  51. package/dist/{chunk-g74qwhvf.js.map → chunk-7tx5y712.js.map} +1 -1
  52. package/dist/{chunk-g7fr2cy2.js → chunk-8afxrmdc.js} +3 -3
  53. package/dist/{chunk-g7fr2cy2.js.map → chunk-8afxrmdc.js.map} +1 -1
  54. package/dist/{chunk-vwkdfngg.js → chunk-8b2tw2yp.js} +1 -1
  55. package/dist/{chunk-t3qw9syt.js → chunk-9rchedr4.js} +2 -2
  56. package/dist/{chunk-t3qw9syt.js.map → chunk-9rchedr4.js.map} +1 -1
  57. package/dist/{chunk-jm4jn28j.js → chunk-9s851qz8.js} +2 -2
  58. package/dist/{chunk-jm4jn28j.js.map → chunk-9s851qz8.js.map} +1 -1
  59. package/dist/{chunk-jc4j61xb.js → chunk-a6453d9s.js} +3 -3
  60. package/dist/{chunk-jc4j61xb.js.map → chunk-a6453d9s.js.map} +1 -1
  61. package/dist/{chunk-9m18pknp.js → chunk-bn5yn731.js} +2 -2
  62. package/dist/{chunk-9m18pknp.js.map → chunk-bn5yn731.js.map} +1 -1
  63. package/dist/{chunk-t85rca2p.js → chunk-c098fzvk.js} +2 -2
  64. package/dist/{chunk-t85rca2p.js.map → chunk-c098fzvk.js.map} +1 -1
  65. package/dist/{chunk-mp5krm14.js → chunk-cttmy1jp.js} +4 -4
  66. package/dist/{chunk-mp5krm14.js.map → chunk-cttmy1jp.js.map} +2 -2
  67. package/dist/{chunk-eyg88bgv.js → chunk-cy5qp6mz.js} +3 -3
  68. package/dist/{chunk-eyg88bgv.js.map → chunk-cy5qp6mz.js.map} +1 -1
  69. package/dist/{chunk-zys7kecf.js → chunk-ddr4qvvt.js} +3 -3
  70. package/dist/{chunk-zys7kecf.js.map → chunk-ddr4qvvt.js.map} +1 -1
  71. package/dist/chunk-e1n8zs3h.js +58 -0
  72. package/dist/chunk-e1n8zs3h.js.map +14 -0
  73. package/dist/{chunk-r9gzbjc5.js → chunk-et4pv1b1.js} +1 -1
  74. package/dist/{chunk-a1g0bahx.js → chunk-frerzsxq.js} +2 -2
  75. package/dist/{chunk-a1g0bahx.js.map → chunk-frerzsxq.js.map} +1 -1
  76. package/dist/{chunk-qz9aaw5x.js → chunk-gb37722w.js} +3 -3
  77. package/dist/{chunk-qz9aaw5x.js.map → chunk-gb37722w.js.map} +1 -1
  78. package/dist/chunk-h3864a8z.js +17 -0
  79. package/dist/{chunk-s5aa4hty.js.map → chunk-h3864a8z.js.map} +13 -12
  80. package/dist/{chunk-zhm3qvrc.js → chunk-h4sw6nt3.js} +3 -3
  81. package/dist/{chunk-zhm3qvrc.js.map → chunk-h4sw6nt3.js.map} +1 -1
  82. package/dist/{chunk-5d6eaxab.js → chunk-he7z7y9j.js} +2 -2
  83. package/dist/{chunk-5d6eaxab.js.map → chunk-he7z7y9j.js.map} +1 -1
  84. package/dist/{chunk-d2tngs73.js → chunk-hf7a51s3.js} +2 -2
  85. package/dist/{chunk-d2tngs73.js.map → chunk-hf7a51s3.js.map} +1 -1
  86. package/dist/chunk-hn67spz6.js +5 -0
  87. package/dist/{chunk-z9x8x3wq.js.map → chunk-hn67spz6.js.map} +1 -1
  88. package/dist/{chunk-f7jhkg8x.js → chunk-jbrwt3cs.js} +4 -4
  89. package/dist/{chunk-f7jhkg8x.js.map → chunk-jbrwt3cs.js.map} +1 -1
  90. package/dist/{chunk-k1ezptt8.js → chunk-k1vw22t2.js} +2 -2
  91. package/dist/{chunk-k1ezptt8.js.map → chunk-k1vw22t2.js.map} +1 -1
  92. package/dist/chunk-k1xt2tw7.js +4 -0
  93. package/dist/{chunk-rjcsdazt.js.map → chunk-k1xt2tw7.js.map} +2 -2
  94. package/dist/chunk-k9wgtrc5.js +24 -0
  95. package/dist/{chunk-w3j53r0a.js.map → chunk-k9wgtrc5.js.map} +4 -4
  96. package/dist/{chunk-7mc5e61r.js → chunk-kf71mjxa.js} +3 -3
  97. package/dist/{chunk-7mc5e61r.js.map → chunk-kf71mjxa.js.map} +1 -1
  98. package/dist/{chunk-vna85rdq.js → chunk-m6ystvtk.js} +2 -2
  99. package/dist/{chunk-vna85rdq.js.map → chunk-m6ystvtk.js.map} +1 -1
  100. package/dist/{chunk-qyyxzy04.js → chunk-mb7q7s0a.js} +3 -3
  101. package/dist/{chunk-qyyxzy04.js.map → chunk-mb7q7s0a.js.map} +1 -1
  102. package/dist/{chunk-sp2v357a.js → chunk-mn5xw79b.js} +3 -3
  103. package/dist/{chunk-sp2v357a.js.map → chunk-mn5xw79b.js.map} +1 -1
  104. package/dist/{chunk-q8k7f11z.js → chunk-mwqg079k.js} +2 -2
  105. package/dist/{chunk-q8k7f11z.js.map → chunk-mwqg079k.js.map} +1 -1
  106. package/dist/{chunk-ga533cpz.js → chunk-nncz308h.js} +3 -3
  107. package/dist/{chunk-ga533cpz.js.map → chunk-nncz308h.js.map} +1 -1
  108. package/dist/{chunk-hf32yq23.js → chunk-nsvktvp4.js} +2 -2
  109. package/dist/{chunk-hf32yq23.js.map → chunk-nsvktvp4.js.map} +1 -1
  110. package/dist/{chunk-3x86bhfn.js → chunk-nvv9wej6.js} +3 -3
  111. package/dist/{chunk-3x86bhfn.js.map → chunk-nvv9wej6.js.map} +1 -1
  112. package/dist/chunk-p1aqq0ga.js +16 -0
  113. package/dist/{chunk-d5sbnzng.js.map → chunk-p1aqq0ga.js.map} +5 -9
  114. package/dist/chunk-p7r2w4qw.js +5 -0
  115. package/dist/{chunk-ehasw3qm.js.map → chunk-p7r2w4qw.js.map} +2 -2
  116. package/dist/{chunk-zz7h6tdr.js → chunk-pwmgqq7z.js} +2 -2
  117. package/dist/{chunk-zz7h6tdr.js.map → chunk-pwmgqq7z.js.map} +1 -1
  118. package/dist/chunk-pyj7cd9t.js +4 -0
  119. package/dist/{chunk-gdsby5jh.js.map → chunk-pyj7cd9t.js.map} +2 -2
  120. package/dist/{chunk-h6g9g8qc.js → chunk-q9s7kwgt.js} +3 -3
  121. package/dist/{chunk-h6g9g8qc.js.map → chunk-q9s7kwgt.js.map} +1 -1
  122. package/dist/{chunk-9hbwvcxn.js → chunk-qd2v93y4.js} +2 -2
  123. package/dist/{chunk-9hbwvcxn.js.map → chunk-qd2v93y4.js.map} +1 -1
  124. package/dist/{chunk-tr9mxdth.js → chunk-rfcygmf5.js} +3 -3
  125. package/dist/{chunk-tr9mxdth.js.map → chunk-rfcygmf5.js.map} +1 -1
  126. package/dist/{chunk-vsnmdtrs.js → chunk-s6jjy4y9.js} +2 -2
  127. package/dist/{chunk-vsnmdtrs.js.map → chunk-s6jjy4y9.js.map} +1 -1
  128. package/dist/{chunk-6zekebzt.js → chunk-sq2wkynk.js} +2 -2
  129. package/dist/{chunk-6zekebzt.js.map → chunk-sq2wkynk.js.map} +1 -1
  130. package/dist/{chunk-52vsdnny.js → chunk-td8tha3j.js} +3 -3
  131. package/dist/{chunk-52vsdnny.js.map → chunk-td8tha3j.js.map} +1 -1
  132. package/dist/{chunk-t0bp8nrc.js → chunk-tk5q8hkv.js} +4 -4
  133. package/dist/{chunk-t0bp8nrc.js.map → chunk-tk5q8hkv.js.map} +2 -2
  134. package/dist/{chunk-dpy08xw4.js → chunk-tq85n8zh.js} +2 -2
  135. package/dist/{chunk-dpy08xw4.js.map → chunk-tq85n8zh.js.map} +1 -1
  136. package/dist/{chunk-wdpdqjr1.js → chunk-twnn7r66.js} +2 -2
  137. package/dist/{chunk-wdpdqjr1.js.map → chunk-twnn7r66.js.map} +1 -1
  138. package/dist/chunk-w7jsh3xd.js +5 -0
  139. package/dist/{chunk-1es50p4k.js.map → chunk-w7jsh3xd.js.map} +2 -2
  140. package/dist/{chunk-zh1t33nq.js → chunk-wsttx9rg.js} +2 -2
  141. package/dist/{chunk-zh1t33nq.js.map → chunk-wsttx9rg.js.map} +1 -1
  142. package/dist/{chunk-7ssjzp87.js → chunk-wvsv1jgg.js} +2 -2
  143. package/dist/{chunk-7ssjzp87.js.map → chunk-wvsv1jgg.js.map} +1 -1
  144. package/dist/chunk-x78jrs4y.js +4 -0
  145. package/dist/{chunk-y66ntxbg.js.map → chunk-x78jrs4y.js.map} +2 -2
  146. package/dist/chunk-xk930yaw.js +5 -0
  147. package/dist/{chunk-pa3khk46.js.map → chunk-xk930yaw.js.map} +2 -2
  148. package/dist/chunk-xkc7ftnq.js +9 -0
  149. package/dist/chunk-xkc7ftnq.js.map +10 -0
  150. package/dist/{chunk-564zfdd1.js → chunk-yer1r3t3.js} +2 -2
  151. package/dist/{chunk-564zfdd1.js.map → chunk-yer1r3t3.js.map} +1 -1
  152. package/dist/{chunk-c8dhvdrs.js → chunk-yqavgpwd.js} +3 -3
  153. package/dist/{chunk-c8dhvdrs.js.map → chunk-yqavgpwd.js.map} +1 -1
  154. package/dist/{chunk-hyfzw1fk.js → chunk-z10cas5r.js} +2 -2
  155. package/dist/{chunk-hyfzw1fk.js.map → chunk-z10cas5r.js.map} +1 -1
  156. package/dist/{chunk-jgtean4t.js → chunk-zhs1r1z0.js} +3 -3
  157. package/dist/{chunk-jgtean4t.js.map → chunk-zhs1r1z0.js.map} +1 -1
  158. package/dist/client/index.d.ts +1 -1
  159. package/dist/client/index.d.ts.map +1 -1
  160. package/dist/client/index.js +106 -52
  161. package/dist/client/index.js.map +1 -1
  162. package/dist/client/islands.d.ts +99 -56
  163. package/dist/client/islands.d.ts.map +1 -1
  164. package/dist/config/index.d.ts +8 -1
  165. package/dist/config/index.d.ts.map +1 -1
  166. package/dist/config/index.js +1 -1
  167. package/dist/config/index.js.map +2 -2
  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/Lang.d.ts +7 -1
  177. package/dist/facades/Lang.d.ts.map +1 -1
  178. package/dist/facades/index.js +2 -2
  179. package/dist/facades/index.js.map +1 -1
  180. package/dist/foundation/index.js +2 -2
  181. package/dist/foundation/index.js.map +1 -1
  182. package/dist/http/CorsMiddleware.d.ts +13 -0
  183. package/dist/http/CorsMiddleware.d.ts.map +1 -1
  184. package/dist/http/Middleware.d.ts +11 -0
  185. package/dist/http/Middleware.d.ts.map +1 -1
  186. package/dist/http/ViewRouter.d.ts +29 -0
  187. package/dist/http/ViewRouter.d.ts.map +1 -1
  188. package/dist/http/index.js +2 -2
  189. package/dist/http/index.js.map +1 -1
  190. package/dist/i18n/dictionaryRuntime.js +2 -2
  191. package/dist/i18n/dictionaryRuntime.js.map +1 -1
  192. package/dist/i18n/index.js +2 -2
  193. package/dist/i18n/index.js.map +1 -1
  194. package/dist/internal/islandRuntime.d.ts +45 -0
  195. package/dist/internal/islandRuntime.d.ts.map +1 -0
  196. package/dist/kernel/index.js +2 -2
  197. package/dist/kernel/index.js.map +1 -1
  198. package/dist/orm/context.d.ts +24 -0
  199. package/dist/orm/context.d.ts.map +1 -1
  200. package/dist/orm/index.d.ts +1 -1
  201. package/dist/orm/index.d.ts.map +1 -1
  202. package/dist/orm/index.js +3 -3
  203. package/dist/orm/index.js.map +2 -2
  204. package/dist/server/devFetch.d.ts.map +1 -1
  205. package/dist/server/httpDev.d.ts.map +1 -1
  206. package/dist/server/httpProd.d.ts.map +1 -1
  207. package/dist/server/idleTimeout.d.ts +24 -0
  208. package/dist/server/idleTimeout.d.ts.map +1 -0
  209. package/dist/server/index.js +2 -2
  210. package/dist/server/index.js.map +1 -1
  211. package/dist/server/modulePreloads.d.ts +7 -6
  212. package/dist/server/modulePreloads.d.ts.map +1 -1
  213. package/dist/services/index.js +2 -2
  214. package/dist/services/index.js.map +1 -1
  215. package/dist/services/middleware/MiddlewareRegistry.d.ts +13 -2
  216. package/dist/services/middleware/MiddlewareRegistry.d.ts.map +1 -1
  217. package/dist/services/queue/work.js +2 -2
  218. package/dist/services/queue/work.js.map +1 -1
  219. package/dist/services/router/DomainRouter.d.ts +10 -0
  220. package/dist/services/router/DomainRouter.d.ts.map +1 -1
  221. package/dist/services/router/ViewRouteDispatcher.d.ts +3 -1
  222. package/dist/services/router/ViewRouteDispatcher.d.ts.map +1 -1
  223. package/dist/services/router/staticCache.d.ts +23 -0
  224. package/dist/services/router/staticCache.d.ts.map +1 -0
  225. package/dist/services/router/staticDocument.d.ts +39 -17
  226. package/dist/services/router/staticDocument.d.ts.map +1 -1
  227. package/dist/stats/bundleStats.d.ts +104 -0
  228. package/dist/stats/bundleStats.d.ts.map +1 -0
  229. package/dist/stats/route-table.d.ts +2 -0
  230. package/dist/stats/route-table.d.ts.map +1 -0
  231. package/dist/stats/route-table.js +4 -0
  232. package/dist/stats/route-table.js.map +11 -0
  233. package/dist/stats/routeTable.d.ts +25 -0
  234. package/dist/stats/routeTable.d.ts.map +1 -0
  235. package/dist/stats/run.d.ts +43 -0
  236. package/dist/stats/run.d.ts.map +1 -0
  237. package/dist/support/index.js +2 -2
  238. package/dist/support/index.js.map +1 -1
  239. package/dist/vite/index.mjs +125 -23
  240. package/dist/vitest/index.d.ts +18 -0
  241. package/dist/vitest/index.d.ts.map +1 -1
  242. package/dist/vitest/index.js +2 -2
  243. package/dist/vitest/index.js.map +3 -3
  244. package/package.json +2 -1
  245. package/dist/chunk-1es50p4k.js +0 -5
  246. package/dist/chunk-9qw9fa6z.js +0 -4
  247. package/dist/chunk-d5sbnzng.js +0 -18
  248. package/dist/chunk-ehasw3qm.js +0 -5
  249. package/dist/chunk-fe1pcnw6.js +0 -6
  250. package/dist/chunk-fj6yftm7.js +0 -58
  251. package/dist/chunk-fj6yftm7.js.map +0 -14
  252. package/dist/chunk-gdsby5jh.js +0 -4
  253. package/dist/chunk-ngw4xzrt.js +0 -9
  254. package/dist/chunk-ngw4xzrt.js.map +0 -10
  255. package/dist/chunk-pa3khk46.js +0 -5
  256. package/dist/chunk-rjcsdazt.js +0 -4
  257. package/dist/chunk-s5aa4hty.js +0 -17
  258. package/dist/chunk-w3j53r0a.js +0 -24
  259. package/dist/chunk-y66ntxbg.js +0 -4
  260. package/dist/chunk-z9x8x3wq.js +0 -5
  261. /package/dist/{chunk-m9609t1y.js.map → chunk-0sjh5v1n.js.map} +0 -0
  262. /package/dist/{chunk-vwkdfngg.js.map → chunk-8b2tw2yp.js.map} +0 -0
  263. /package/dist/{chunk-r9gzbjc5.js.map → chunk-et4pv1b1.js.map} +0 -0
@@ -70,7 +70,9 @@ export declare class ViewRouteDispatcher {
70
70
  * a route inside a gated section cannot be more reachable than the section.
71
71
  */
72
72
  private passesFeatureGates;
73
- onRequestEnd(req: HttpRequest): Promise<void>;
73
+ onRequestEnd(req: HttpRequest, options?: {
74
+ mintSession?: boolean;
75
+ }): Promise<void>;
74
76
  /**
75
77
  * Fires the provider's `onStreamComplete` from a stream callback — an
76
78
  * observability hook must never break the response body it observes, so
@@ -1 +1 @@
1
- {"version":3,"file":"ViewRouteDispatcher.d.ts","sourceRoot":"","sources":["../../../services/router/ViewRouteDispatcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ViewRouteDispatcher.d.ts","sourceRoot":"","sources":["../../../services/router/ViewRouteDispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { StaticViewOptions } from "../../http/ViewRouter";
2
+ /**
3
+ * Which of the cookies gemi sets on its own a view request gets.
4
+ *
5
+ * A hydrated view gets all three. A static view (`.static()`) gets none unless
6
+ * it asked: it is one body for every visitor, and a per-visitor `Set-Cookie`
7
+ * is what keeps a CDN from caching it. `i18n-locale` has no opt-in — the url
8
+ * carries a static page's locale.
9
+ */
10
+ export declare function staticCookiePolicy(staticView: StaticViewOptions | undefined): {
11
+ locale: boolean;
12
+ session: boolean;
13
+ csrf: boolean;
14
+ };
15
+ /**
16
+ * Sets a static page's `Cache-Control` from `.static({ cacheControl })`.
17
+ *
18
+ * The handler's own header wins. A response that sets a cookie is never handed
19
+ * to a shared cache, whatever the option says: one visitor's cookie stored with
20
+ * the page would be replayed to everyone who gets that copy.
21
+ */
22
+ export declare function applyStaticCacheControl(headers: Headers, staticView: StaticViewOptions): void;
23
+ //# sourceMappingURL=staticCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staticCache.d.ts","sourceRoot":"","sources":["../../../services/router/staticCache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,iBAAiB,GAAG,SAAS;;;;EAS3E;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,iBAAiB,QAatF"}
@@ -1,44 +1,66 @@
1
- import type { StaticRenderCollector } from "../../client/islands";
1
+ import { type StaticRenderCollector } from "../../client/islands";
2
2
  /**
3
- * Where an island's client module is served from: `src` is imported by the
4
- * loader, `preload` is every chunk that import pulls in (itself first).
3
+ * Where an island's entry is served from: `src` is imported by the loader,
4
+ * `preload` is every chunk that import pulls in (itself first), React
5
+ * included.
5
6
  */
6
7
  export type IslandAsset = {
7
8
  src: string;
8
9
  preload: string[];
9
10
  };
10
- /** Maps an island module's build key (`app/views/site/menu.island.ts`) to its asset. */
11
+ /** Maps an island module's build key (`app/views/site/Counter.tsx`) to its entry. */
11
12
  export type IslandResolver = (moduleKey: string) => IslandAsset | undefined;
12
13
  /** The id of the JSON block the loader reads its island table from. */
13
14
  export declare const ISLAND_DATA_ID = "gemi-islands";
14
15
  /**
15
16
  * The island loader, inlined into a static document that uses islands.
16
17
  *
17
- * Kept byte-for-byte constant — the per-page island table travels in a
18
+ * Kept byte-for-byte constant (the per-page island table travels in a
18
19
  * separate `<script type="application/json">`, which a Content Security Policy
19
- * does not treat as script — so a strict policy can allow it by hash:
20
- * `script-src 'sha256-…'` with `ISLAND_LOADER_CSP_HASH`. Island modules are
21
- * then plain `import()`s of same-origin (or asset-base) files.
20
+ * does not treat as script), so a strict policy can allow it by hash:
21
+ * `script-src 'sha256-…'` with `ISLAND_LOADER_CSP_HASH`. Everything it loads
22
+ * is a plain `import()` of a same-origin (or asset-base) file.
22
23
  *
23
- * Per marker: parse `data-props`, import the module on the island's schedule,
24
- * call its default export once. A failure is logged and leaves the
25
- * server-rendered markup in place.
24
+ * The table is `{ i: [{ s: entry URL, e: export, l: load }] }` and each
25
+ * marker's `data-island` indexes `i`. Per marker, on its schedule: import the
26
+ * island's entry (the module as `m`, the runtime's `h`), then
27
+ * `h(marker, m[export])`, which calls `hydrateRoot`. A failure is logged and
28
+ * leaves the server-rendered markup in place.
26
29
  */
27
30
  export declare const ISLAND_LOADER_SOURCE: string;
28
31
  /**
29
32
  * `'sha256-…'` for the production island loader, ready to put in a
30
33
  * `script-src` directive. The dev loader also installs the React Refresh
31
- * preamble first, so it does not match; a dev policy needs `'unsafe-inline'`
32
- * as Vite itself does.
34
+ * preamble and Vite's HMR client first, so it does not match; a dev policy
35
+ * needs `'unsafe-inline'` as Vite itself does.
33
36
  */
34
37
  export declare const ISLAND_LOADER_CSP_HASH: string;
35
38
  /**
36
- * Adds the island loader to a settled static document — only when the render
39
+ * Adds the island loader to a settled static document, only when the render
37
40
  * recorded an island, so a page without one keeps no script at all.
38
41
  *
39
- * Eager islands get `modulepreload`s in the head for their whole static import
40
- * closure; lazy ones are fetched when their schedule fires, so nothing about
41
- * them is announced up front.
42
+ * Eager islands get `modulepreload`s in the head for their entry's whole
43
+ * static import closure (React included); lazy ones are fetched when their
44
+ * schedule fires, so nothing about them is announced up front.
45
+ *
46
+ * Without a resolver (a test rendering through `app.fetch`), the markup is
47
+ * the whole result: nothing is injected and nothing is logged.
42
48
  */
43
49
  export declare function injectIslands(html: string, collector: StaticRenderCollector, resolveIsland: IslandResolver | undefined, dev: boolean): string;
50
+ /**
51
+ * Moves each island's children into its slot.
52
+ *
53
+ * An island's own render (a root of its own) leaves an empty
54
+ * `<gemi-slot data-slot="i0-">`; the page tree renders the children, with the
55
+ * page's context, right after the marker in `<template data-gemi-slot="i0-">`.
56
+ * Here the template's content replaces the placeholder (as
57
+ * `<gemi-slot style="display:contents">…</gemi-slot>`, what the browser
58
+ * hydrates against) and the template goes away.
59
+ *
60
+ * The last template is spliced first: nothing after it can be inside it, so it
61
+ * holds no other island's children, and an island's children that contain
62
+ * islands are spliced after theirs are. Children the island didn't render are
63
+ * dropped, as a component that ignores `children` drops them anywhere.
64
+ */
65
+ export declare function spliceIslandSlots(html: string): string;
44
66
  //# sourceMappingURL=staticDocument.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"staticDocument.d.ts","sourceRoot":"","sources":["../../../services/router/staticDocument.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGlE;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE7D,wFAAwF;AACxF,MAAM,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;AAE5E,uEAAuE;AACvE,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,oBAAoB,QAMkH,CAAC;AAEpJ;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAEb,CAAC;AAwBvB;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,qBAAqB,EAChC,aAAa,EAAE,cAAc,GAAG,SAAS,EACzC,GAAG,EAAE,OAAO,GACX,MAAM,CAiCR"}
1
+ {"version":3,"file":"staticDocument.d.ts","sourceRoot":"","sources":["../../../services/router/staticDocument.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAG9B;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAE7D,qFAAqF;AACrF,MAAM,MAAM,cAAc,GAAG,CAAC,SAAS,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;AAE5E,uEAAuE;AACvE,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,QAM8G,CAAC;AAEhJ;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAEb,CAAC;AA0BvB;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,qBAAqB,EAChC,aAAa,EAAE,cAAc,GAAG,SAAS,EACzC,GAAG,EAAE,OAAO,GACX,MAAM,CAiCR;AAcD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBtD"}
@@ -0,0 +1,104 @@
1
+ import { type ViteManifest } from "../server/modulePreloads";
2
+ import type { RouteTableEntry } from "./routeTable";
3
+ /**
4
+ * `gemi stats`: the JavaScript each route loads before it can run, from the
5
+ * client build's manifest.
6
+ *
7
+ * A **hydrated** route loads the client entry and every view in its chain
8
+ * (layouts and page), each with its static imports followed transitively: the
9
+ * same walk the server does for the route's `modulepreload` links. Lazy chunks
10
+ * (`import()`) aren't initial and don't count.
11
+ *
12
+ * A **static** route (`.static()`) loads no client entry and no view code, only
13
+ * the islands its views can render. Each island has a client entry of its own,
14
+ * keyed `<module>?gemi-island` in the manifest, that imports the chunk holding
15
+ * the island's module and the island runtime (React, `react-dom/client`). A
16
+ * route can render an island when the chunk holding its module is reachable
17
+ * from the route's views (and the document layout) through static or lazy
18
+ * imports; the route then counts that island entry with its static imports. A
19
+ * page loads only the islands it shows, so this is its most. Chunks the islands
20
+ * share (the runtime, React) count once per route. The island loader is inline
21
+ * in the HTML and not counted.
22
+ *
23
+ * Sizes are raw, gzip -9 and brotli q11, the encodings `gemi build` writes
24
+ * next to each asset; those files are read when present.
25
+ */
26
+ export type Size = {
27
+ raw: number;
28
+ gzip: number;
29
+ brotli: number;
30
+ };
31
+ export type SizeUnit = keyof Size;
32
+ export interface RouteStats extends Size {
33
+ /** View paths that render the route, outermost layout first. */
34
+ views: string[];
35
+ /** Set for a `.static()` route. */
36
+ static?: true;
37
+ /** A static route's island entries (manifest keys, `<module>?gemi-island`). */
38
+ islands?: string[];
39
+ /** The JS chunks counted, by name without the content hash. */
40
+ chunks: string[];
41
+ }
42
+ export interface BuildStats {
43
+ /** The JSON shape, bumped when it changes incompatibly. */
44
+ version: 1;
45
+ /**
46
+ * `routes`: keyed by route path (`/p/:slug`; `<group>:/path` for a host group
47
+ * other than the root). `views`: the route table could not be read, so each
48
+ * view is reported as a hydrated page, keyed by view path.
49
+ */
50
+ by: "routes" | "views";
51
+ routes: Record<string, RouteStats>;
52
+ /** Each island entry (`<module>?gemi-island`) with its static imports. */
53
+ islands: Record<string, Size & {
54
+ chunks: string[];
55
+ }>;
56
+ /** Every JS chunk in the build, by name without the content hash. */
57
+ chunks: Record<string, Size>;
58
+ /** All CSS in the build. */
59
+ css: Size;
60
+ }
61
+ /** `stats` in `gemi.config.ts`. */
62
+ export interface StatsConfig {
63
+ budgets?: StatsBudgets;
64
+ }
65
+ /** Initial-JS budgets in KB (1024 bytes). `gemi stats` fails when a route is over its. */
66
+ export interface StatsBudgets {
67
+ /** Which size the budgets are in. Default `gzip`. */
68
+ unit?: SizeUnit;
69
+ /** Applies to every route without its own budget. Unset: only listed routes are checked. */
70
+ default?: number;
71
+ /** By route path (`/p/:slug`) or by view path (`site/Page`, the route's page view). */
72
+ routes?: Record<string, number>;
73
+ }
74
+ /**
75
+ * A chunk by its name without the content hash, so the same chunk compares
76
+ * across builds: `assets/PageBuilder-C4f9a1Xz.js` is `PageBuilder.js`.
77
+ */
78
+ export declare function chunkName(file: string): string;
79
+ /** The route key in `BuildStats.routes`: the path, prefixed by a non-root host group. */
80
+ export declare function routeKey(entry: Pick<RouteTableEntry, "group" | "path">): string;
81
+ export interface BundleStatsOptions {
82
+ /** The client build, `dist/client`. */
83
+ clientDir: string;
84
+ /** The route table; without it every view is reported as a hydrated page. */
85
+ routes?: RouteTableEntry[] | null;
86
+ /** The manifest, if already read; otherwise `<clientDir>/.vite/manifest.json`. */
87
+ manifest?: ViteManifest;
88
+ }
89
+ export declare function bundleStats(options: BundleStatsOptions): BuildStats;
90
+ /** The budget that applies to a route: its own, its page view's, or the default. */
91
+ export declare function budgetFor(key: string, route: Pick<RouteStats, "views">, budgets: StatsBudgets | undefined): number | undefined;
92
+ /** The routes over their budget, as messages. */
93
+ export declare function overBudget(stats: BuildStats, budgets: StatsBudgets | undefined): string[];
94
+ /** Budget keys that match no route and no route's page view: probably a typo or a removed view. */
95
+ export declare function unusedBudgets(stats: BuildStats, budgets: StatsBudgets | undefined): string[];
96
+ /**
97
+ * The stats as a Markdown table, compared with `base` (another build's JSON,
98
+ * e.g. `main`'s) when given: per-route deltas, then the chunks that came, went
99
+ * or changed. Meant for a PR comment.
100
+ */
101
+ export declare function markdownReport(stats: BuildStats, base: BuildStats | null, budgets: StatsBudgets | undefined): string;
102
+ /** The stats as a plain-text table for the terminal, largest route first. */
103
+ export declare function textReport(stats: BuildStats, budgets: StatsBudgets | undefined): string;
104
+ //# sourceMappingURL=bundleStats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundleStats.d.ts","sourceRoot":"","sources":["../../stats/bundleStats.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=route-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-table.d.ts","sourceRoot":"","sources":["../../stats/route-table.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ // @bun
2
+ import"../chunk-1yx2e0bh.js";import M from"path";import{writeFileSync as Q}from"fs";var L=new Set(["FILE","REDIRECT"]);function H(j){return j.run(()=>{let x=[];for(let{group:z,view:D}of j.domains().viewGroups())for(let[G,B]of Object.entries(D.flatViewRoutes)){let C=D.routeManifest[G]??B.segments.map((K)=>K.viewPath);if(C.length===0||L.has(C.at(-1)))continue;x.push({path:G,group:z,views:C,...B.static?{static:B.static.layout?{layout:B.static.layout}:{}}:{}})}return x})}var J=process.argv[2];async function U(){if(!J)throw Error("usage: route-table <out.json>");let j=M.resolve(process.cwd(),"app/kernel/Kernel.ts"),x=await import(j);if(typeof x.default!=="function")throw Error(`${j} has no default export (the Kernel subclass).`);let z=new x.default;z.boot();try{Q(J,JSON.stringify(H(z)))}finally{z.destroy()}}U().then(()=>process.exit(0),(j)=>{console.error(j?.stack??String(j)),process.exit(1)});
3
+
4
+ //# debugId=2C354352EBF6475164756E2164756E21
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../stats/route-table.ts", "../stats/routeTable.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * The entry `gemi stats` (and `gemi build --stats`) spawns to read the app's\n * route table: `bun --preload gemi/bun/preload stats/route-table.ts <out>`.\n *\n * `gemi build` deliberately never boots the app (see `bin/createRollupInput`).\n * This doesn't either, in the sense that matters: it imports the Kernel and\n * runs only its synchronous `boot()`, which registers providers and constructs\n * nothing that does I/O. No provider `boot()`, no service, no database, no\n * queue claiming and no scheduler. Importing the app's route files is the one\n * side effect, the same one `gemi app:route-manifest` has.\n *\n * Exposed as `gemi/stats/route-table` and resolved from the application's\n * `node_modules`, like `gemi/console/run`: the routers the app's files extend\n * are the app's copy of gemi, so the code reading them has to be as well.\n *\n * The table is written to the file named by the first argument rather than to\n * stdout, which app code is free to log to while it is imported.\n */\nimport path from \"node:path\";\nimport { writeFileSync } from \"node:fs\";\nimport type { Kernel } from \"../kernel/Kernel\";\nimport { collectRouteTable } from \"./routeTable\";\n\nconst out = process.argv[2];\n\nasync function main() {\n if (!out) throw new Error(\"usage: route-table <out.json>\");\n const kernelPath = path.resolve(process.cwd(), \"app/kernel/Kernel.ts\");\n const module: { default?: new () => Kernel } = await import(kernelPath);\n if (typeof module.default !== \"function\") {\n throw new Error(`${kernelPath} has no default export (the Kernel subclass).`);\n }\n const kernel = new module.default();\n kernel.boot();\n try {\n writeFileSync(out, JSON.stringify(collectRouteTable(kernel)));\n } finally {\n kernel.destroy();\n }\n}\n\n// `.then` rather than a top-level `await`; see `console/run.ts`.\nmain().then(\n () => process.exit(0),\n (error) => {\n console.error((error as Error)?.stack ?? String(error));\n process.exit(1);\n },\n);\n",
6
+ "import type { Kernel } from \"../kernel/Kernel\";\n\n/**\n * One document route, as `gemi stats` needs it: which views render it (layouts\n * first, the page last) and whether it is a `.static()` view.\n */\nexport interface RouteTableEntry {\n /** The route pattern, e.g. `/p/:slug`. */\n path: string;\n /** The host group: `\"\"` for the root, a subdomain, `\"*\"` for the custom fallback. */\n group: string;\n /** View paths (`app/views/<path>.tsx`), outermost layout first. */\n views: string[];\n /** Set for a `.static()` route; `layout` is its document layout, if any. */\n static?: { layout?: string };\n}\n\n/** View paths that name no component: file and redirect routes. */\nconst NOT_A_VIEW = new Set([\"FILE\", \"REDIRECT\"]);\n\n/**\n * Every document route the app declares, from a kernel that has only run its\n * synchronous `boot()`: providers have registered, nothing has booted, so no\n * database, queue, scheduler or listener is touched. Reading the routers only\n * constructs them, which is what `app:route-manifest` has always done.\n */\nexport function collectRouteTable(kernel: Kernel): RouteTableEntry[] {\n return kernel.run(() => {\n const entries: RouteTableEntry[] = [];\n for (const { group, view } of kernel.domains().viewGroups()) {\n for (const [path, route] of Object.entries(view.flatViewRoutes)) {\n const views = view.routeManifest[path] ?? route.segments.map((s) => s.viewPath);\n if (views.length === 0 || NOT_A_VIEW.has(views.at(-1)!)) continue;\n entries.push({\n path,\n group,\n views,\n ...(route.static\n ? { static: route.static.layout ? { layout: route.static.layout } : {} }\n : {}),\n });\n }\n }\n return entries;\n });\n}\n"
7
+ ],
8
+ "mappings": ";6BAkBA,oBACA,wBAAS,WCDT,IAAM,EAAa,IAAI,IAAI,CAAC,OAAQ,UAAU,CAAC,EAQxC,SAAS,CAAiB,CAAC,EAAmC,CACnE,OAAO,EAAO,IAAI,IAAM,CACtB,IAAM,EAA6B,CAAC,EACpC,QAAa,QAAO,UAAU,EAAO,QAAQ,EAAE,WAAW,EACxD,QAAY,EAAM,KAAU,OAAO,QAAQ,EAAK,cAAc,EAAG,CAC/D,IAAM,EAAQ,EAAK,cAAc,IAAS,EAAM,SAAS,IAAI,CAAC,IAAM,EAAE,QAAQ,EAC9E,GAAI,EAAM,SAAW,GAAK,EAAW,IAAI,EAAM,GAAG,EAAE,CAAE,EAAG,SACzD,EAAQ,KAAK,CACX,OACA,QACA,WACI,EAAM,OACN,CAAE,OAAQ,EAAM,OAAO,OAAS,CAAE,OAAQ,EAAM,OAAO,MAAO,EAAI,CAAC,CAAE,EACrE,CAAC,CACP,CAAC,EAGL,OAAO,EACR,EDrBH,IAAM,EAAM,QAAQ,KAAK,GAEzB,eAAe,CAAI,EAAG,CACpB,GAAI,CAAC,EAAK,MAAU,MAAM,+BAA+B,EACzD,IAAM,EAAa,EAAK,QAAQ,QAAQ,IAAI,EAAG,sBAAsB,EAC/D,EAAyC,MAAa,UAC5D,GAAI,OAAO,EAAO,UAAY,WAC5B,MAAU,MAAM,GAAG,gDAAyD,EAE9E,IAAM,EAAS,IAAI,EAAO,QAC1B,EAAO,KAAK,EACZ,GAAI,CACF,EAAc,EAAK,KAAK,UAAU,EAAkB,CAAM,CAAC,CAAC,SAC5D,CACA,EAAO,QAAQ,GAKnB,EAAK,EAAE,KACL,IAAM,QAAQ,KAAK,CAAC,EACpB,CAAC,IAAU,CACT,QAAQ,MAAO,GAAiB,OAAS,OAAO,CAAK,CAAC,EACtD,QAAQ,KAAK,CAAC,EAElB",
9
+ "debugId": "2C354352EBF6475164756E2164756E21",
10
+ "names": []
11
+ }
@@ -0,0 +1,25 @@
1
+ import type { Kernel } from "../kernel/Kernel";
2
+ /**
3
+ * One document route, as `gemi stats` needs it: which views render it (layouts
4
+ * first, the page last) and whether it is a `.static()` view.
5
+ */
6
+ export interface RouteTableEntry {
7
+ /** The route pattern, e.g. `/p/:slug`. */
8
+ path: string;
9
+ /** The host group: `""` for the root, a subdomain, `"*"` for the custom fallback. */
10
+ group: string;
11
+ /** View paths (`app/views/<path>.tsx`), outermost layout first. */
12
+ views: string[];
13
+ /** Set for a `.static()` route; `layout` is its document layout, if any. */
14
+ static?: {
15
+ layout?: string;
16
+ };
17
+ }
18
+ /**
19
+ * Every document route the app declares, from a kernel that has only run its
20
+ * synchronous `boot()`: providers have registered, nothing has booted, so no
21
+ * database, queue, scheduler or listener is touched. Reading the routers only
22
+ * constructs them, which is what `app:route-manifest` has always done.
23
+ */
24
+ export declare function collectRouteTable(kernel: Kernel): RouteTableEntry[];
25
+ //# sourceMappingURL=routeTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routeTable.d.ts","sourceRoot":"","sources":["../../stats/routeTable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4EAA4E;IAC5E,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B;AAKD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CAmBnE"}
@@ -0,0 +1,43 @@
1
+ import { type StatsConfig } from "./bundleStats";
2
+ import type { RouteTableEntry } from "./routeTable";
3
+ export interface RunStatsOptions {
4
+ rootDir: string;
5
+ /** `stats` from `gemi.config.ts`. */
6
+ config?: StatsConfig;
7
+ /** Write the stats as JSON here. */
8
+ json?: string;
9
+ /** Another build's JSON to compare with; a missing file is no comparison. */
10
+ base?: string;
11
+ /** Write the Markdown table here. */
12
+ markdown?: string;
13
+ /** `false` skips the route table and reports per view. */
14
+ routes?: boolean;
15
+ /** `bun --preload` args for the app's own preload (see `bin/gemi.ts`). */
16
+ preloadArgs?: string[];
17
+ log?: (line: string) => void;
18
+ error?: (line: string) => void;
19
+ }
20
+ /**
21
+ * Reads the client build in `<rootDir>/dist/client`, prints the initial JS per
22
+ * route, writes the requested files and checks the budgets. Returns the exit
23
+ * code: 1 when a route is over its budget or there is no build to read.
24
+ */
25
+ export declare function runStats(options: RunStatsOptions): Promise<number>;
26
+ export type RouteTableResult = {
27
+ ok: true;
28
+ routes: RouteTableEntry[];
29
+ } | {
30
+ ok: false;
31
+ message: string;
32
+ };
33
+ /**
34
+ * The app's route table, read in a child process (`gemi/stats/route-table`)
35
+ * that imports the Kernel and runs only its synchronous `boot()`, with the same
36
+ * preloads as `gemi start`. A child, because the app's code has to load under
37
+ * the app's own gemi with the request transform registered, and because it
38
+ * must not leave anything running in the build process.
39
+ */
40
+ export declare function loadRouteTable(rootDir: string, preloadArgs: string[], options?: {
41
+ timeoutMs?: number;
42
+ }): Promise<RouteTableResult>;
43
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../stats/run.ts"],"names":[],"mappings":"AAGA,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA6CxE;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,OAAO,CAAC,gBAAgB,CAAC,CAuC3B"}
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{hc as Y}from"../chunk-9hbwvcxn.js";import{ag as M}from"../chunk-9m18pknp.js";import{ah as P,ch as R}from"../chunk-h6g9g8qc.js";import"../chunk-367kyrdx.js";import{lh as Q,mh as U,nh as V,oh as W}from"../chunk-vna85rdq.js";import"../chunk-wvwee7dn.js";class S{static token;async boot(){}static inject(){if(!this.token)throw Error(`Service [${this.name}] does not declare a \`static token\`, so the container has no key to resolve it by.`);try{return R(this)}catch(x){throw Error(`Could not inject [${this.name}]. Services are constructed when the kernel boots, so `+"inject() only works from code that runs after that \u2014 a constructor default or a method "+`body, never module top level. Check that [${this.name}] is listed in \`services\` on your Kernel.`,{cause:x})}}static with(x){let f=new this;for(let[C,g]of Object.entries(x))if(g!==void 0)f[C]=g;return f}}import{readdir as z}from"fs/promises";import{join as B,parse as j}from"path";var H=[".ts",".tsx",".js",".mjs",".jsx"];function J(x={}){let f={};for(let[C,g]of Object.entries(x))f[C]=q(g);return new P(f)}async function L(x,f=new P){let C=[];try{C=await z(x)}catch(D){return f}let g=C.filter((D)=>{let{ext:v,name:F}=j(D);return H.includes(v)&&!F.startsWith(".")}).sort();for(let D of g){let{name:v}=j(D),F=await import(B(x,D));f.set(v,q(F))}return f}function q(x){if(x&&typeof x==="object"&&"default"in x)return x.default;return x}export{M as withDefaults,Q as sourceFiles,W as projectRoot,L as loadConfigFrom,V as discoverClasses,J as createConfigRepository,Y as ServiceProvider,S as Service,P as Repository,U as DiscoveryError};
2
+ import{pc as Y}from"../chunk-qd2v93y4.js";import{ig as M}from"../chunk-bn5yn731.js";import{jh as P,lh as R}from"../chunk-q9s7kwgt.js";import"../chunk-3cg7y62b.js";import{uh as Q,vh as U,wh as V,xh as W}from"../chunk-m6ystvtk.js";import"../chunk-1yx2e0bh.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=654759EB0C4D295264756E2164756E21
4
+ //# debugId=447CF5C12AD6A7A564756E2164756E21
@@ -6,6 +6,6 @@
6
6
  "import { readdir } from \"node:fs/promises\";\nimport { join, parse } from \"node:path\";\n\nimport { Repository } from \"./Repository\";\n\nconst CONFIG_EXTENSIONS = [\".ts\", \".tsx\", \".js\", \".mjs\", \".jsx\"];\n\n// Builds a Repository from an already-imported map of config modules. The map\n// key becomes the top-level config key, so `{ mail: mailModule }` is readable\n// as `config.get(\"mail.driver\")`. Each entry may be either the module namespace\n// (its `default` export is unwrapped) or the config object itself.\nexport function createConfigRepository(\n modules: Record<string, any> = {},\n): Repository {\n const items: Record<string, any> = {};\n\n for (const [key, mod] of Object.entries(modules)) {\n items[key] = unwrap(mod);\n }\n\n return new Repository(items);\n}\n\n// Reads every config module in an app's `app/config` directory into a\n// Repository. The file's basename is the top-level key: `app/config/mail.ts`\n// populates `mail.*`. A missing directory yields an empty Repository so apps\n// that declare no config still boot.\nexport async function loadConfigFrom(\n directory: string,\n repository = new Repository(),\n): Promise<Repository> {\n let entries: string[] = [];\n\n try {\n entries = await readdir(directory);\n } catch (err) {\n return repository;\n }\n\n const files = entries\n .filter((entry) => {\n const { ext, name } = parse(entry);\n return CONFIG_EXTENSIONS.includes(ext) && !name.startsWith(\".\");\n })\n .sort();\n\n for (const file of files) {\n const { name } = parse(file);\n const mod = await import(join(directory, file));\n repository.set(name, unwrap(mod));\n }\n\n return repository;\n}\n\nfunction unwrap(mod: any) {\n if (mod && typeof mod === \"object\" && \"default\" in mod) {\n return mod.default;\n }\n return mod;\n}\n"
7
7
  ],
8
8
  "mappings": ";2RAgCO,CAAe,JAAQ,EAOrB,OAMD,AAAI,EAAkB,QAmBrB,OAAS,EAKX,CACH,GAAI,CAAC,KAAK,MACR,MAAU,MACR,YAAY,KAAK,0FACnB,EAGF,GAAI,CACF,OAAO,EAAI,IAAuB,EAClC,MAAO,EAAO,CACd,MAAU,MACR,qBAAqB,KAAK,6DACxB,+FACA,6CAA6C,KAAK,kDAEpD,CAAE,OAAM,CACV,SAoBG,KAAuB,CAAoB,EAA0B,CAC1E,IAAM,EAAW,IAAI,KACrB,QAAY,EAAK,KAAU,OAAO,QAAQ,CAAS,EACjD,GAAI,IAAU,OAAW,EAAS,GAAO,EAE3C,OAAO,EAEX,CChHA,kBAAS,oBACT,eAAS,WAAM,aAIf,IAAM,EAAoB,CAAC,MAAO,OAAQ,MAAO,OAAQ,MAAM,EAMxD,SAAS,CAAsB,CACpC,EAA+B,CAAC,EACpB,CACZ,IAAM,EAA6B,CAAC,EAEpC,QAAY,EAAK,KAAQ,OAAO,QAAQ,CAAO,EAC7C,EAAM,GAAO,EAAO,CAAG,EAGzB,OAAO,IAAI,EAAW,CAAK,EAO7B,eAAsB,CAAc,CAClC,EACA,EAAa,IAAI,EACI,CACrB,IAAI,EAAoB,CAAC,EAEzB,GAAI,CACF,EAAU,MAAM,EAAQ,CAAS,EACjC,MAAO,EAAK,CACZ,OAAO,EAGT,IAAM,EAAQ,EACX,OAAO,CAAC,IAAU,CACjB,IAAQ,MAAK,QAAS,EAAM,CAAK,EACjC,OAAO,EAAkB,SAAS,CAAG,GAAK,CAAC,EAAK,WAAW,GAAG,EAC/D,EACA,KAAK,EAER,QAAW,KAAQ,EAAO,CACxB,IAAQ,QAAS,EAAM,CAAI,EACrB,EAAM,MAAa,SAAK,EAAW,CAAI,GAC7C,EAAW,IAAI,EAAM,EAAO,CAAG,CAAC,EAGlC,OAAO,EAGT,SAAS,CAAM,CAAC,EAAU,CACxB,GAAI,GAAO,OAAO,IAAQ,UAAY,YAAa,EACjD,OAAO,EAAI,QAEb,OAAO",
9
- "debugId": "654759EB0C4D295264756E2164756E21",
9
+ "debugId": "447CF5C12AD6A7A564756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -1448,12 +1448,74 @@ function documentBase(base) {
1448
1448
  return base.startsWith("/") || /^[a-z][a-z\d+.-]*:\/\//i.test(base) ? normalizeAssetBase(base) : "/";
1449
1449
  }
1450
1450
  //#endregion
1451
+ //#region internal/islandRuntime.ts
1452
+ /**
1453
+ * The browser side of islands, shared by the Vite plugin (which builds it), the
1454
+ * servers (which point the loader at it) and the tests.
1455
+ *
1456
+ * No imports: the Vite plugin is built on its own and the servers load it at
1457
+ * boot, so this file stays plain strings.
1458
+ */
1459
+ /**
1460
+ * The module that hydrates islands: React, `react-dom/client` and the small
1461
+ * `h(marker, Component)` below. A virtual module of gemi's Vite plugin that
1462
+ * every island entry imports, so the islands on a page share one copy of
1463
+ * React, in one chunk.
1464
+ */
1465
+ var ISLAND_RUNTIME_ID = "virtual:gemi-island-runtime";
1466
+ /** What `resolveId` turns `ISLAND_RUNTIME_ID` into (Vite's virtual-module convention). */
1467
+ var RESOLVED_ISLAND_RUNTIME_ID = `\0${ISLAND_RUNTIME_ID}`;
1468
+ /**
1469
+ * The query that turns a module into its island entry: `Counter.tsx?gemi-island`
1470
+ * is a module of the plugin's that re-exports `Counter.tsx` as `m` next to the
1471
+ * runtime's `h`. It is what a static page imports for an island, and so it
1472
+ * is what the client manifest lists, keyed `app/…/Counter.tsx?gemi-island`,
1473
+ * with React and `react-dom/client` among its imports.
1474
+ */
1475
+ var ISLAND_ENTRY_QUERY = "?gemi-island";
1476
+ /** The island entry module for `file` (an absolute path or a root-relative URL). */
1477
+ function islandEntrySource(file) {
1478
+ return `import * as m from ${JSON.stringify(file)};
1479
+ export { m };
1480
+ export { h } from ${JSON.stringify(ISLAND_RUNTIME_ID)};
1481
+ `;
1482
+ }
1483
+ /** The runtime module's source, as the plugin serves and builds it. */
1484
+ var ISLAND_RUNTIME_SOURCE = `import { createElement } from "react";
1485
+ import { hydrateRoot } from "react-dom/client";
1486
+ export function h(marker, Component) {
1487
+ if (typeof Component !== "function" && (typeof Component !== "object" || Component === null)) {
1488
+ throw new Error("gemi: island module has no component export for " + marker.outerHTML.slice(0, 80));
1489
+ }
1490
+ const json = marker.getAttribute("data-props");
1491
+ const props = json ? JSON.parse(json) : {};
1492
+ let slot = null;
1493
+ for (const candidate of marker.querySelectorAll("gemi-slot")) {
1494
+ if (candidate.closest("gemi-island") === marker) {
1495
+ slot = candidate;
1496
+ break;
1497
+ }
1498
+ }
1499
+ const children = slot
1500
+ ? [createElement("gemi-slot", {
1501
+ style: { display: "contents" },
1502
+ suppressHydrationWarning: true,
1503
+ dangerouslySetInnerHTML: { __html: slot.innerHTML },
1504
+ })]
1505
+ : [];
1506
+ return hydrateRoot(marker, createElement(Component, props, ...children), {
1507
+ identifierPrefix: marker.getAttribute("data-uid") || undefined,
1508
+ });
1509
+ }
1510
+ `;
1511
+ //#endregion
1451
1512
  //#region vite/islandPlugin.ts
1452
1513
  /**
1453
- * `() => import("./x.island")` — the loader `island()` takes. The specifier
1454
- * must name a `*.island` module; the extension is optional, as in any import.
1514
+ * `island(() => import("./Counter")`: the call `island()` is declared with.
1515
+ * The loader must be the first argument, written as an arrow with no
1516
+ * parameters returning one `import()` of a string literal.
1455
1517
  */
1456
- var ISLAND_LOADER = /\(\s*\)\s*=>\s*import\(\s*(["'])([^"'\n]+?\.island(?:\.[cm]?[jt]sx?)?)\1\s*\)/g;
1518
+ var ISLAND_CALL = /\bisland\s*\(\s*(\(\s*\)\s*=>\s*import\(\s*(["'])([^"'\n]+)\2\s*\))/g;
1457
1519
  /**
1458
1520
  * Symlinks resolved, so the key is the same path the manifest is keyed on
1459
1521
  * however the project directory was reached (`/var` vs `/private/var` on
@@ -1467,47 +1529,87 @@ function realPath(path) {
1467
1529
  }
1468
1530
  }
1469
1531
  /**
1470
- * Tells the server which built file an island's loader imports.
1532
+ * Islands: `island(() => import("./Counter"))` in `gemi/client`.
1471
1533
  *
1472
- * `island("nav-menu", NavMenuView, () => import("./navMenu.island"))` is
1473
- * rewritten so the loader carries the module's build key — its path from the
1474
- * project root, the key the client manifest uses:
1534
+ * Every such call is rewritten, in the client and the server graph alike, so
1535
+ * the loader carries the module's build key (its path from the project root,
1536
+ * the key the client manifest uses) and the module itself, imported
1537
+ * statically:
1475
1538
  *
1476
1539
  * ```js
1477
- * Object.assign(() => import("./navMenu.island"), { gemiIsland: "app/views/site/navMenu.island.ts" })
1540
+ * import * as __gemi_island_0 from "./Counter";
1541
+ * island(Object.assign(() => Promise.resolve(__gemi_island_0),
1542
+ * { gemiIsland: "app/views/site/Counter.tsx", gemiModule: __gemi_island_0 }))
1478
1543
  * ```
1479
1544
  *
1480
- * The server renders, never calls the loader, and maps the key to a URL. In
1481
- * the SSR graph the import itself is replaced too, so an island's browser code
1482
- * is not bundled into the server build.
1545
+ * The static import is what lets a hydrated view render the component in
1546
+ * place, and a static view render it on the server without waiting on a
1547
+ * dynamic import. The key is what a static page's loader is pointed at.
1548
+ *
1549
+ * In the client build, each island module also gets an entry of its own,
1550
+ * `Counter.tsx?gemi-island`: the module (as `m`) and the island runtime's
1551
+ * hydrate function `h` (from `virtual:gemi-island-runtime`, which imports
1552
+ * React and `react-dom/client`). That entry's import closure, React included,
1553
+ * is exactly what a static page loads for the island, and the manifest shows
1554
+ * it under the entry's key. The runtime is one chunk the islands share. In
1555
+ * dev, Vite serves the same modules from source.
1556
+ *
1557
+ * Also usable on its own, e.g. from `gemi/vitest` in an app's
1558
+ * `vitest.config.ts`, so tests render islands with the same keys as the build.
1483
1559
  */
1484
1560
  function gemiIslandPlugin() {
1485
1561
  let root = process.cwd();
1562
+ let clientBuild = false;
1563
+ const emitted = /* @__PURE__ */ new Set();
1486
1564
  return {
1487
1565
  name: "gemi-plugin-islands",
1488
1566
  enforce: "pre",
1489
1567
  configResolved(config) {
1490
1568
  root = realPath(config.root);
1569
+ clientBuild = config.command === "build" && !config.build.ssr;
1570
+ },
1571
+ buildStart() {
1572
+ emitted.clear();
1573
+ },
1574
+ resolveId(id) {
1575
+ return id === "virtual:gemi-island-runtime" ? RESOLVED_ISLAND_RUNTIME_ID : null;
1491
1576
  },
1492
- async transform(code, id, options) {
1493
- if (id.includes("/node_modules/") || id.startsWith("\0")) return null;
1577
+ load(id) {
1578
+ if (id === RESOLVED_ISLAND_RUNTIME_ID) return ISLAND_RUNTIME_SOURCE;
1579
+ if (id.endsWith("?gemi-island")) return islandEntrySource(id.slice(0, -ISLAND_ENTRY_QUERY.length));
1580
+ return null;
1581
+ },
1582
+ async transform(code, id) {
1583
+ if (id.includes("/node_modules/") || id.startsWith("\0") || id.endsWith("?gemi-island")) return null;
1494
1584
  if (!/\.[cm]?[jt]sx?$/.test(id.split("?")[0])) return null;
1495
- if (!code.includes(".island")) return null;
1496
- const ssr = Boolean(options?.ssr) || this.environment?.config?.consumer === "server";
1585
+ if (!code.includes("island")) return null;
1586
+ const environmentConsumer = this.environment?.config?.consumer;
1587
+ const emitEntries = clientBuild && (environmentConsumer === void 0 || environmentConsumer === "client");
1497
1588
  const s = new MagicString(code);
1498
- let changed = false;
1499
- for (const match of code.matchAll(ISLAND_LOADER)) {
1500
- const [whole, quote, specifier] = match;
1589
+ const imports = [];
1590
+ for (const match of code.matchAll(ISLAND_CALL)) {
1591
+ const [, loader, quote, specifier] = match;
1501
1592
  const resolved = await this.resolve(specifier, id);
1502
1593
  if (!resolved || resolved.external) continue;
1503
1594
  const file = realPath(resolved.id.split("?")[0]);
1504
1595
  const key = relative(root, file).split(sep).join("/");
1505
1596
  if (key.startsWith("..")) continue;
1506
- const loader = ssr ? `() => Promise.reject(new Error("Island modules load in the browser."))` : `() => import(${quote}${specifier}${quote})`;
1507
- s.overwrite(match.index, match.index + whole.length, `Object.assign(${loader}, { gemiIsland: ${JSON.stringify(key)} })`);
1508
- changed = true;
1597
+ const name = `__gemi_island_${imports.length}`;
1598
+ imports.push(`import * as ${name} from ${quote}${specifier}${quote};`);
1599
+ const start = match.index + match[0].length - loader.length;
1600
+ s.overwrite(start, start + loader.length, `Object.assign(() => Promise.resolve(${name}), { gemiIsland: ${JSON.stringify(key)}, gemiModule: ${name} })`);
1601
+ const moduleId = resolved.id.split("?")[0];
1602
+ if (emitEntries && !emitted.has(moduleId)) {
1603
+ emitted.add(moduleId);
1604
+ this.emitFile({
1605
+ type: "chunk",
1606
+ id: `${moduleId}${ISLAND_ENTRY_QUERY}`,
1607
+ preserveSignature: "strict"
1608
+ });
1609
+ }
1509
1610
  }
1510
- if (!changed) return null;
1611
+ if (imports.length === 0) return null;
1612
+ s.prepend(`${imports.join("\n")}\n`);
1511
1613
  return {
1512
1614
  code: s.toString(),
1513
1615
  map: s.generateMap({ hires: true })
@@ -1533,7 +1635,7 @@ var gemi = async () => {
1533
1635
  ssrEmitAssets: true,
1534
1636
  sourcemap: true,
1535
1637
  rollupOptions: {
1536
- input: Array.from(JSON.parse(process.env.GEMI_INPUT ?? "[]")).filter((entry) => !(env.isSsrBuild && /\.island\.[cm]?[jt]sx?$/.test(entry))),
1638
+ input: Array.from(JSON.parse(process.env.GEMI_INPUT ?? "[]")),
1537
1639
  preserveEntrySignatures: "strict",
1538
1640
  ...env.isSsrBuild ? { external: isGemiExternal } : {}
1539
1641
  }
@@ -24,4 +24,22 @@ import type { Plugin } from "vite";
24
24
  * ```
25
25
  */
26
26
  export declare function gemiRequestPlugin(): Plugin;
27
+ /**
28
+ * gemi's island transform, for an app's `vitest.config.ts`: with it, a test
29
+ * that renders a static view through `App.fetch` sees each
30
+ * `island(() => import("./Counter"))` with the same module key as the build,
31
+ * and a hydrated view renders the component in place instead of lazily.
32
+ *
33
+ * Without it islands still render (the component is loaded with the
34
+ * `import()`), but their keys are unknown.
35
+ *
36
+ * ```ts
37
+ * // vitest.config.ts
38
+ * import { defineConfig } from "vitest/config";
39
+ * import { gemiIslandPlugin, gemiRequestPlugin } from "gemi/vitest";
40
+ *
41
+ * export default defineConfig({ plugins: [gemiRequestPlugin(), gemiIslandPlugin()] });
42
+ * ```
43
+ */
44
+ export { gemiIslandPlugin } from "../vite/islandPlugin";
27
45
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../vitest/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAMnC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../vitest/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAMnC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}