stratal 0.0.27 → 0.1.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 (284) hide show
  1. package/CHANGELOG.md +912 -0
  2. package/README.md +96 -14
  3. package/dist/bin/cloudflare-workers-loader.mjs +18 -3
  4. package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
  5. package/dist/bin/quarry.mjs +73 -12
  6. package/dist/bin/quarry.mjs.map +1 -1
  7. package/dist/cache/index.d.mts +8 -9
  8. package/dist/cache/index.d.mts.map +1 -1
  9. package/dist/cache/index.mjs +56 -17
  10. package/dist/cache/index.mjs.map +1 -1
  11. package/dist/{cache.service-uElmBtdS.d.mts → cache.service-Dg0Hj0gp.d.mts} +27 -12
  12. package/dist/cache.service-Dg0Hj0gp.d.mts.map +1 -0
  13. package/dist/{command-DoBD2Cwl.d.mts → command-BXMccV_9.d.mts} +6 -3
  14. package/dist/command-BXMccV_9.d.mts.map +1 -0
  15. package/dist/{command-BvmUAPPQ.mjs → command-Bb820B6W.mjs} +36 -13
  16. package/dist/command-Bb820B6W.mjs.map +1 -0
  17. package/dist/common.schemas-BigQCwYB.mjs +89 -0
  18. package/dist/common.schemas-BigQCwYB.mjs.map +1 -0
  19. package/dist/config/index.d.mts +15 -15
  20. package/dist/config/index.d.mts.map +1 -1
  21. package/dist/config/index.mjs +4 -6
  22. package/dist/config/index.mjs.map +1 -1
  23. package/dist/{consumer-registry-D3iMTSdy.d.mts → consumer-registry-i9oCdarv.d.mts} +2 -3
  24. package/dist/consumer-registry-i9oCdarv.d.mts.map +1 -0
  25. package/dist/{container-storage-BmOJ4_Na.mjs → container-storage-DfF7SXdV.mjs} +11 -1
  26. package/dist/container-storage-DfF7SXdV.mjs.map +1 -0
  27. package/dist/{controller.decorator-YSTPQntu.mjs → controller.decorator-BB0JcwMg.mjs} +18 -9
  28. package/dist/controller.decorator-BB0JcwMg.mjs.map +1 -0
  29. package/dist/cron/index.d.mts +6 -7
  30. package/dist/cron/index.d.mts.map +1 -1
  31. package/dist/cron/index.mjs +1 -1
  32. package/dist/{cron-job-NesZRk8F.d.mts → cron-job-DAgNw4Bn.d.mts} +1 -2
  33. package/dist/cron-job-DAgNw4Bn.d.mts.map +1 -0
  34. package/dist/{cron.module-C81HTzR7.mjs → cron.module-Dnyl9sFk.mjs} +6 -7
  35. package/dist/{cron.module-C81HTzR7.mjs.map → cron.module-Dnyl9sFk.mjs.map} +1 -1
  36. package/dist/{decorate-CuAoSZvs.mjs → decorate-C79yt3Wt.mjs} +2 -2
  37. package/dist/di/index.d.mts +1 -1
  38. package/dist/di/index.mjs +2 -3
  39. package/dist/{di-D7qmrAir.mjs → di-DQ3xbjgf.mjs} +48 -6
  40. package/dist/di-DQ3xbjgf.mjs.map +1 -0
  41. package/dist/email/index.d.mts +158 -133
  42. package/dist/email/index.d.mts.map +1 -1
  43. package/dist/email/index.mjs +66 -78
  44. package/dist/email/index.mjs.map +1 -1
  45. package/dist/{en-CDZBMcc1.mjs → en-CCL84z4k.mjs} +2 -2
  46. package/dist/{en-CDZBMcc1.mjs.map → en-CCL84z4k.mjs.map} +1 -1
  47. package/dist/env-ug22bJj7.d.mts.map +1 -1
  48. package/dist/errors/index.d.mts +1 -1
  49. package/dist/errors/index.mjs +3 -3
  50. package/dist/{errors-C01O2T-n.mjs → errors-CrOXI_y5.mjs} +6 -8
  51. package/dist/errors-CrOXI_y5.mjs.map +1 -0
  52. package/dist/events/index.d.mts +8 -9
  53. package/dist/events/index.d.mts.map +1 -1
  54. package/dist/events/index.mjs +1 -1
  55. package/dist/{events-BhEQuT1X.mjs → events-GtwGEHyT.mjs} +5 -6
  56. package/dist/events-GtwGEHyT.mjs.map +1 -0
  57. package/dist/{exception-context-D-kvney-.mjs → exception-context-CdnGTQNF.mjs} +13 -7
  58. package/dist/exception-context-CdnGTQNF.mjs.map +1 -0
  59. package/dist/{gateway-context-m7kEzRa2.mjs → gateway-context-Cmc1NRS0.mjs} +7 -7
  60. package/dist/{gateway-context-m7kEzRa2.mjs.map → gateway-context-Cmc1NRS0.mjs.map} +1 -1
  61. package/dist/gateway-mode-0rUaeW3g.mjs +53 -0
  62. package/dist/gateway-mode-0rUaeW3g.mjs.map +1 -0
  63. package/dist/guards/index.d.mts +38 -20
  64. package/dist/guards/index.d.mts.map +1 -1
  65. package/dist/guards/index.mjs +2 -2
  66. package/dist/{guards-DALPXy3_.mjs → guards-DOGly9IF.mjs} +34 -11
  67. package/dist/guards-DOGly9IF.mjs.map +1 -0
  68. package/dist/hono-app-IhdqL0Fk.mjs +399 -0
  69. package/dist/hono-app-IhdqL0Fk.mjs.map +1 -0
  70. package/dist/{http-method.decorator-BljM8BDj.mjs → http-method.decorator-BDi9LTWj.mjs} +9 -8
  71. package/dist/http-method.decorator-BDi9LTWj.mjs.map +1 -0
  72. package/dist/i18n/index.d.mts +26 -137
  73. package/dist/i18n/index.d.mts.map +1 -1
  74. package/dist/i18n/index.mjs +4 -5
  75. package/dist/i18n/index.mjs.map +1 -1
  76. package/dist/i18n/messages/en/index.d.mts +1 -1
  77. package/dist/i18n/messages/en/index.mjs +1 -1
  78. package/dist/i18n/utils/index.d.mts +1 -2
  79. package/dist/i18n/utils/index.d.mts.map +1 -1
  80. package/dist/i18n/validation/index.d.mts +80 -5
  81. package/dist/i18n/validation/index.d.mts.map +1 -0
  82. package/dist/i18n/validation/index.mjs +4 -5
  83. package/dist/{i18n.module-B2DvWUPa.mjs → i18n.module-Bm3xlViA.mjs} +28 -13
  84. package/dist/i18n.module-Bm3xlViA.mjs.map +1 -0
  85. package/dist/index-0ItCjaqw.d.mts.map +1 -1
  86. package/dist/{index-CNuFQSNj.d.mts → index-3HJfhLlE.d.mts} +9 -11
  87. package/dist/index-3HJfhLlE.d.mts.map +1 -0
  88. package/dist/{index-uybm0bhQ.d.mts → index-B2WtEagR.d.mts} +1187 -234
  89. package/dist/index-B2WtEagR.d.mts.map +1 -0
  90. package/dist/index-BUt92sAE.d.mts.map +1 -1
  91. package/dist/index-CAHNCpvr.d.mts +203 -0
  92. package/dist/index-CAHNCpvr.d.mts.map +1 -0
  93. package/dist/index.d.mts +4 -4
  94. package/dist/index.mjs +2 -2
  95. package/dist/{is-command-CEPO9n8c.mjs → is-command-CSVv14wh.mjs} +2 -2
  96. package/dist/{is-command-CEPO9n8c.mjs.map → is-command-CSVv14wh.mjs.map} +1 -1
  97. package/dist/{is-seeder-Gvh_AM71.mjs → is-seeder-gLgXYbqC.mjs} +2 -2
  98. package/dist/is-seeder-gLgXYbqC.mjs.map +1 -0
  99. package/dist/{lazy-module-loader-M6YKudNL.d.mts → lazy-module-loader-C3OHoUnR.d.mts} +4 -5
  100. package/dist/lazy-module-loader-C3OHoUnR.d.mts.map +1 -0
  101. package/dist/limit-BE0HNAF6.mjs +116 -0
  102. package/dist/limit-BE0HNAF6.mjs.map +1 -0
  103. package/dist/locale-path.service-BqzDIrgy.mjs +213 -0
  104. package/dist/locale-path.service-BqzDIrgy.mjs.map +1 -0
  105. package/dist/locale-url-nZrZxqJP.mjs.map +1 -1
  106. package/dist/{locale-url.service-6bgia24_.mjs → locale-url.service-H8PH6GGh.mjs} +15 -5
  107. package/dist/{locale-url.service-6bgia24_.mjs.map → locale-url.service-H8PH6GGh.mjs.map} +1 -1
  108. package/dist/logger/index.mjs +3 -5
  109. package/dist/logger/index.mjs.map +1 -1
  110. package/dist/macroable-cvDTFZ_A.mjs.map +1 -1
  111. package/dist/metadata-Ba8Fxs1F.mjs +48 -0
  112. package/dist/metadata-Ba8Fxs1F.mjs.map +1 -0
  113. package/dist/module/index.d.mts +8 -9
  114. package/dist/module/index.d.mts.map +1 -1
  115. package/dist/module/index.mjs +3 -4
  116. package/dist/module/index.mjs.map +1 -1
  117. package/dist/{module-registry-NxX5O0Qk.mjs → module-registry-lkQPDuQe.mjs} +17 -15
  118. package/dist/module-registry-lkQPDuQe.mjs.map +1 -0
  119. package/dist/{module.decorator-CYHY6pG5.mjs → module.decorator-CYbrOlX9.mjs} +2 -2
  120. package/dist/{module.decorator-CYHY6pG5.mjs.map → module.decorator-CYbrOlX9.mjs.map} +1 -1
  121. package/dist/openapi/index.d.mts +19 -16
  122. package/dist/openapi/index.d.mts.map +1 -1
  123. package/dist/openapi/index.mjs +2 -2
  124. package/dist/{openapi-CMwuCp31.mjs → openapi-DBfBa5Qh.mjs} +41 -65
  125. package/dist/openapi-DBfBa5Qh.mjs.map +1 -0
  126. package/dist/openapi-generator-CCwiu8AU.mjs +134 -0
  127. package/dist/openapi-generator-CCwiu8AU.mjs.map +1 -0
  128. package/dist/{openapi-tools.service-BC5EC3R3.mjs → openapi-tools.service-VKZJlTIX.mjs} +12 -4
  129. package/dist/openapi-tools.service-VKZJlTIX.mjs.map +1 -0
  130. package/dist/openapi.service-Ds-R1tih.d.mts +43 -0
  131. package/dist/openapi.service-Ds-R1tih.d.mts.map +1 -0
  132. package/dist/quarry/index.d.mts +10 -11
  133. package/dist/quarry/index.d.mts.map +1 -1
  134. package/dist/quarry/index.mjs +4 -4
  135. package/dist/quarry/runner.d.mts +19 -20
  136. package/dist/quarry/runner.d.mts.map +1 -1
  137. package/dist/quarry/runner.mjs +16 -13
  138. package/dist/quarry/runner.mjs.map +1 -1
  139. package/dist/{quarry-registry-DRnV-DDa.d.mts → quarry-registry-Ci4k58FZ.d.mts} +3 -4
  140. package/dist/quarry-registry-Ci4k58FZ.d.mts.map +1 -0
  141. package/dist/{quarry.module-CcGxU2dJ.mjs → quarry.module-BssRR8f0.mjs} +20 -37
  142. package/dist/quarry.module-BssRR8f0.mjs.map +1 -0
  143. package/dist/queue/index.d.mts +2 -2
  144. package/dist/queue/index.mjs +3 -3
  145. package/dist/queue/index.mjs.map +1 -1
  146. package/dist/{queue.module-CEs4_kEM.mjs → queue.module-DnAdSbR-.mjs} +40 -41
  147. package/dist/queue.module-DnAdSbR-.mjs.map +1 -0
  148. package/dist/{r2-storage.provider-BoZmR6Ut.mjs → r2-storage.provider-wU_6api4.mjs} +45 -6
  149. package/dist/r2-storage.provider-wU_6api4.mjs.map +1 -0
  150. package/dist/{rate-limit.decorator-Djs4oYDB.mjs → rate-limit.decorator-PYQ9EYqs.mjs} +10 -5
  151. package/dist/{rate-limit.decorator-Djs4oYDB.mjs.map → rate-limit.decorator-PYQ9EYqs.mjs.map} +1 -1
  152. package/dist/rate-limiter/index.d.mts +64 -19
  153. package/dist/rate-limiter/index.d.mts.map +1 -1
  154. package/dist/rate-limiter/index.mjs +67 -83
  155. package/dist/rate-limiter/index.mjs.map +1 -1
  156. package/dist/response-cache/index.d.mts +326 -0
  157. package/dist/response-cache/index.d.mts.map +1 -0
  158. package/dist/response-cache/index.mjs +511 -0
  159. package/dist/response-cache/index.mjs.map +1 -0
  160. package/dist/response-cache.error-B4D0zy9W.mjs +24 -0
  161. package/dist/response-cache.error-B4D0zy9W.mjs.map +1 -0
  162. package/dist/response-headers-BqA57S_X.mjs +158 -0
  163. package/dist/response-headers-BqA57S_X.mjs.map +1 -0
  164. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  165. package/dist/route-cache-binding-CrLh8tB6.mjs +390 -0
  166. package/dist/route-cache-binding-CrLh8tB6.mjs.map +1 -0
  167. package/dist/route-metadata-QQhbed1i.mjs +17 -0
  168. package/dist/route-metadata-QQhbed1i.mjs.map +1 -0
  169. package/dist/{route-name-DGoBOfPg.mjs → route-name-BslSbmMP.mjs} +15 -11
  170. package/dist/route-name-BslSbmMP.mjs.map +1 -0
  171. package/dist/route-registration.service-COKBZTsn.mjs +1265 -0
  172. package/dist/route-registration.service-COKBZTsn.mjs.map +1 -0
  173. package/dist/{route-registry-BvLJisvK.mjs → route-registry-DFz9_-N6.mjs} +6 -6
  174. package/dist/{route-registry-BvLJisvK.mjs.map → route-registry-DFz9_-N6.mjs.map} +1 -1
  175. package/dist/router/index.d.mts +2 -2
  176. package/dist/router/index.mjs +16 -15
  177. package/dist/{router-resolver-sUV_jTrU.mjs → router-resolver-B-dMSMIG.mjs} +7 -3
  178. package/dist/router-resolver-B-dMSMIG.mjs.map +1 -0
  179. package/dist/{router-DwyqEXgf.mjs → router-wlsVkGkM.mjs} +5 -14
  180. package/dist/{router-DwyqEXgf.mjs.map → router-wlsVkGkM.mjs.map} +1 -1
  181. package/dist/seeder/index.d.mts +12 -13
  182. package/dist/seeder/index.d.mts.map +1 -1
  183. package/dist/seeder/index.mjs +4 -4
  184. package/dist/{seeder-BPGY5rUb.mjs → seeder-BrAk7XIj.mjs} +5 -6
  185. package/dist/{seeder-BPGY5rUb.mjs.map → seeder-BrAk7XIj.mjs.map} +1 -1
  186. package/dist/{seeder-registry-DEvCycsT.mjs → seeder-registry-Bo5BgLbC.mjs} +5 -6
  187. package/dist/{seeder-registry-DEvCycsT.mjs.map → seeder-registry-Bo5BgLbC.mjs.map} +1 -1
  188. package/dist/{seeder.module-CIwQbdN4.mjs → seeder.module-DOoVgTsK.mjs} +5 -5
  189. package/dist/{seeder.module-CIwQbdN4.mjs.map → seeder.module-DOoVgTsK.mjs.map} +1 -1
  190. package/dist/signed-url-DIU0sK_6.mjs.map +1 -1
  191. package/dist/storage/index.d.mts +63 -13
  192. package/dist/storage/index.d.mts.map +1 -1
  193. package/dist/storage/index.mjs +2 -2
  194. package/dist/storage/providers/index.d.mts +18 -16
  195. package/dist/storage/providers/index.d.mts.map +1 -1
  196. package/dist/storage/providers/index.mjs +1 -1
  197. package/dist/{storage-C30X81CS.mjs → storage-DBWVYMnn.mjs} +167 -49
  198. package/dist/storage-DBWVYMnn.mjs.map +1 -0
  199. package/dist/storage-provider.interface-CinHpjl1.d.mts +315 -0
  200. package/dist/storage-provider.interface-CinHpjl1.d.mts.map +1 -0
  201. package/dist/storage.error-Ao38Qdjx.mjs +7 -0
  202. package/dist/storage.error-Ao38Qdjx.mjs.map +1 -0
  203. package/dist/{stratal-D5j_I14G.d.mts → stratal-Bs1_E8GQ.d.mts} +13 -3
  204. package/dist/stratal-Bs1_E8GQ.d.mts.map +1 -0
  205. package/dist/{stratal-BL6FKUM_.mjs → stratal-CiwNpWy2.mjs} +56 -23
  206. package/dist/stratal-CiwNpWy2.mjs.map +1 -0
  207. package/dist/{tiered-cache.service-Dv3BhxxE.d.mts → tiered-cache.service-Bz8bbvyb.d.mts} +16 -3
  208. package/dist/tiered-cache.service-Bz8bbvyb.d.mts.map +1 -0
  209. package/dist/trailing-slash-2SctvePW.mjs.map +1 -1
  210. package/dist/types-CmV_9xBD.d.mts.map +1 -1
  211. package/dist/{uri-iwofWJ_T.mjs → uri-BrOq148R.mjs} +13 -9
  212. package/dist/{uri-iwofWJ_T.mjs.map → uri-BrOq148R.mjs.map} +1 -1
  213. package/dist/{usage-generator-DAWYasuP.mjs → usage-generator-BW7EcO-C.mjs} +3 -3
  214. package/dist/{usage-generator-DAWYasuP.mjs.map → usage-generator-BW7EcO-C.mjs.map} +1 -1
  215. package/dist/{zod-eKqqhZ5_.mjs → validation-CZ_B0aXY.mjs} +38 -17
  216. package/dist/validation-CZ_B0aXY.mjs.map +1 -0
  217. package/dist/{validation.context-CRvmrhq7.mjs → validation.context-CdbwQWIr.mjs} +2 -2
  218. package/dist/{validation.context-CRvmrhq7.mjs.map → validation.context-CdbwQWIr.mjs.map} +1 -1
  219. package/dist/{versioning.service-CCa2oYMJ.mjs → versioning.service-DnF_4Lnd.mjs} +5 -5
  220. package/dist/{versioning.service-CCa2oYMJ.mjs.map → versioning.service-DnF_4Lnd.mjs.map} +1 -1
  221. package/dist/websocket/index.d.mts +12 -13
  222. package/dist/websocket/index.d.mts.map +1 -1
  223. package/dist/websocket/index.mjs +1 -1
  224. package/dist/workers/index.d.mts +70 -7
  225. package/dist/workers/index.d.mts.map +1 -1
  226. package/dist/workers/index.mjs +72 -3
  227. package/dist/workers/index.mjs.map +1 -1
  228. package/dist/{zod-wecrEVAs.d.mts → zod-BGisqLs3.d.mts} +9 -16
  229. package/dist/zod-BGisqLs3.d.mts.map +1 -0
  230. package/package.json +33 -25
  231. package/dist/cache.service-uElmBtdS.d.mts.map +0 -1
  232. package/dist/chunk-BBjsoOtd.mjs +0 -27
  233. package/dist/command-BvmUAPPQ.mjs.map +0 -1
  234. package/dist/command-DoBD2Cwl.d.mts.map +0 -1
  235. package/dist/consumer-registry-D3iMTSdy.d.mts.map +0 -1
  236. package/dist/container-storage-BmOJ4_Na.mjs.map +0 -1
  237. package/dist/controller.decorator-YSTPQntu.mjs.map +0 -1
  238. package/dist/cron-job-NesZRk8F.d.mts.map +0 -1
  239. package/dist/di-D7qmrAir.mjs.map +0 -1
  240. package/dist/errors-C01O2T-n.mjs.map +0 -1
  241. package/dist/events-BhEQuT1X.mjs.map +0 -1
  242. package/dist/exception-context-D-kvney-.mjs.map +0 -1
  243. package/dist/guards-DALPXy3_.mjs.map +0 -1
  244. package/dist/hono-app-COAgmutc.mjs +0 -168
  245. package/dist/hono-app-COAgmutc.mjs.map +0 -1
  246. package/dist/http-method.decorator-BljM8BDj.mjs.map +0 -1
  247. package/dist/i18n.module-B2DvWUPa.mjs.map +0 -1
  248. package/dist/index-CNuFQSNj.d.mts.map +0 -1
  249. package/dist/index-DtBNIFuP.d.mts +0 -42
  250. package/dist/index-DtBNIFuP.d.mts.map +0 -1
  251. package/dist/index-HgOLNruQ.d.mts +0 -203
  252. package/dist/index-HgOLNruQ.d.mts.map +0 -1
  253. package/dist/index-uybm0bhQ.d.mts.map +0 -1
  254. package/dist/is-seeder-Gvh_AM71.mjs.map +0 -1
  255. package/dist/lazy-module-loader-M6YKudNL.d.mts.map +0 -1
  256. package/dist/locale-path.service-CH0CaxwH.mjs +0 -165
  257. package/dist/locale-path.service-CH0CaxwH.mjs.map +0 -1
  258. package/dist/metadata-DzzprcID.mjs +0 -39
  259. package/dist/metadata-DzzprcID.mjs.map +0 -1
  260. package/dist/module-registry-NxX5O0Qk.mjs.map +0 -1
  261. package/dist/openapi-CMwuCp31.mjs.map +0 -1
  262. package/dist/openapi-tools.service-BC5EC3R3.mjs.map +0 -1
  263. package/dist/openapi.service-2rvJBCEg.d.mts +0 -50
  264. package/dist/openapi.service-2rvJBCEg.d.mts.map +0 -1
  265. package/dist/quarry-registry-DRnV-DDa.d.mts.map +0 -1
  266. package/dist/quarry.module-CcGxU2dJ.mjs.map +0 -1
  267. package/dist/queue.module-CEs4_kEM.mjs.map +0 -1
  268. package/dist/r2-storage.provider-BoZmR6Ut.mjs.map +0 -1
  269. package/dist/route-name-DGoBOfPg.mjs.map +0 -1
  270. package/dist/route-registration.service-CDPQKpm4.mjs +0 -918
  271. package/dist/route-registration.service-CDPQKpm4.mjs.map +0 -1
  272. package/dist/router-resolver-sUV_jTrU.mjs.map +0 -1
  273. package/dist/storage-C30X81CS.mjs.map +0 -1
  274. package/dist/storage-provider.interface-ClUwxz4S.d.mts +0 -201
  275. package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +0 -1
  276. package/dist/storage.error-BStXPmO4.mjs +0 -8
  277. package/dist/storage.error-BStXPmO4.mjs.map +0 -1
  278. package/dist/stratal-BL6FKUM_.mjs.map +0 -1
  279. package/dist/stratal-D5j_I14G.d.mts.map +0 -1
  280. package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +0 -1
  281. package/dist/validation-CpOjviyT.mjs +0 -49
  282. package/dist/validation-CpOjviyT.mjs.map +0 -1
  283. package/dist/zod-eKqqhZ5_.mjs.map +0 -1
  284. package/dist/zod-wecrEVAs.d.mts.map +0 -1
package/README.md CHANGED
@@ -4,7 +4,6 @@ A modular framework for building Cloudflare Workers with dependency injection, O
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/stratal)](https://www.npmjs.com/package/stratal)
6
6
  [![CI](https://github.com/strataljs/stratal/actions/workflows/ci.yml/badge.svg)](https://github.com/strataljs/stratal/actions/workflows/ci.yml)
7
- [![Benchmark](https://github.com/strataljs/stratal/actions/workflows/benchmark.yml/badge.svg)](https://github.com/strataljs/stratal/actions/workflows/benchmark.yml)
8
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
8
  [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/strataljs/stratal/badge)](https://securityscorecards.dev/viewer/?uri=github.com/strataljs/stratal)
10
9
  [![Known Vulnerabilities](https://snyk.io/test/github/strataljs/stratal/badge.svg)](https://snyk.io/test/github/strataljs/stratal)
@@ -20,18 +19,27 @@ Full guides and examples are available at **[stratal.dev](https://stratal.dev)**
20
19
 
21
20
  ## Features
22
21
 
23
- - **Dependency Injection** — Two-tier DI container (global + request-scoped) with built-in decorator support
24
- - **OpenAPI Documentation** — Define Zod schemas once and get a full OpenAPI 3.0 spec with interactive docs
25
- - **Modular Architecture** — NestJS-style modules with lifecycle hooks, dynamic configuration, and middleware
26
- - **Hono Routing** — Convention-based RESTful controllers with automatic HTTP method mapping
27
- - **Queue Consumers** — Typed Cloudflare Queue consumers with message-type filtering
28
- - **Cron Jobs** — Scheduled tasks via Cloudflare Workers cron triggers
29
- - **Storage** — S3-compatible file storage with presigned URLs and TUS upload support
30
- - **Email** — SMTP provider with React Email template support
22
+ - **Dependency Injection** — Two-tier DI container (global + request-scoped) with decorator-based injection
23
+ - **Modular Architecture** — NestJS-style modules with lifecycle hooks, dynamic configuration, and lazy loading
24
+ - **Routing** — Convention-based RESTful controllers on Hono, plus explicit method decorators, named routes, versioning, and domain routing
25
+ - **OpenAPI Documentation** — Define Zod schemas once and get an OpenAPI 3.0 spec with Swagger UI
26
+ - **Queues and Cron** — Typed Cloudflare Queue consumers with message-type filtering, and scheduled jobs via cron triggers
27
+ - **Events** — In-process and queue-backed event listeners with `@Listener` / `@On`
28
+ - **WebSockets and SSE** — Gateway classes with `@OnMessage` / `@OnClose` / `@OnError`, and server-sent event streams
29
+ - **Caching** — KV-backed cache with optional isolate-level L1 tiering, plus `@Cacheable` / `@PurgesCache` response caching on the Workers Cache API
30
+ - **Rate Limiting** — Declarative `@RateLimit` with named limiters
31
+ - **Storage** — Cloudflare R2 file storage with presigned URLs and resumable multipart uploads (TUS-compatible)
32
+ - **Email** — SMTP provider with React Email template support and queued delivery
31
33
  - **i18n** — Type-safe internationalization with locale detection from request headers
34
+ - **Configuration** — Namespaced, validated config with typed dot-path access
32
35
  - **Guards and Middleware** — Route protection and per-module middleware configuration
36
+ - **Seeders** — Ordered database seeders with `db:seed` commands
37
+ - **Quarry CLI** — Built-in commands for routes, queues, events, i18n and schedules — and `mcp:serve`, which exposes your API routes to an AI agent as MCP tools
33
38
 
34
- > **Note:** Stratal is in active development and APIs may change before v1. It is okay to use in projects, but consider pinning your dependency version so that a new patch does not break your existing code.
39
+ ## Requirements
40
+
41
+ - Node.js ≥ 22
42
+ - A Cloudflare Workers project
35
43
 
36
44
  ## Installation
37
45
 
@@ -58,7 +66,7 @@ Available templates:
58
66
  | `scheduled-tasks` | Cron job scheduling with the CronJob interface | [Source](https://github.com/strataljs/examples/tree/main/07-scheduled-tasks) |
59
67
  | `openapi` | OpenAPI docs with Swagger UI and Zod schema integration | [Source](https://github.com/strataljs/examples/tree/main/08-openapi) |
60
68
 
61
- For benchmarks, see the [main README](https://github.com/strataljs/stratal#benchmarks).
69
+ More runnable examples — seeders, events, auth, database, access control, factories, Workers bindings, commands and Inertia — live at [strataljs/examples](https://github.com/strataljs/examples).
62
70
 
63
71
  You can also specify a template directly:
64
72
 
@@ -82,7 +90,7 @@ npx skills add strataljs/stratal
82
90
 
83
91
  | Skill | Description |
84
92
  |---|---|
85
- | `stratal` | Build Cloudflare Workers apps with the Stratal framework — modules, DI, controllers, routing, OpenAPI, queues, cron, events, seeders, CLI, auth, database, RBAC, testing, and more |
93
+ | `stratal` | Build Cloudflare Workers apps with the Stratal framework — modules, DI, controllers, routing, OpenAPI, queues, cron, events, seeders, CLI, auth, database, access control, testing, and more |
86
94
 
87
95
  ## Quick Start
88
96
 
@@ -92,14 +100,14 @@ Define a module with a controller and wire it up as a Cloudflare Worker:
92
100
  import { Stratal } from 'stratal'
93
101
  import { Module } from 'stratal/module'
94
102
  import { Controller, Route, type RouterContext } from 'stratal/router'
95
- import { z } from 'stratal/validation'
103
+ import { object, string } from 'zod/mini'
96
104
 
97
105
  // Define a controller
98
106
  @Controller('/api/greetings')
99
107
  class GreetingsController {
100
108
  @Route({
101
109
  summary: 'Say hello',
102
- response: z.object({ message: z.string() }),
110
+ response: object({ message: string() }),
103
111
  })
104
112
  async index(ctx: RouterContext) {
105
113
  return ctx.json({ message: 'Hello from Stratal!' })
@@ -116,10 +124,84 @@ class AppModule {}
116
124
  export default new Stratal({ module: AppModule })
117
125
  ```
118
126
 
127
+ ### Routing conventions
128
+
129
+ `@Route()` derives the HTTP method, path and status code from the method name:
130
+
131
+ | Method | HTTP | Path | Status |
132
+ |---|---|---|---|
133
+ | `index()` | GET | `/base-path` | 200 |
134
+ | `show()` | GET | `/base-path/:id` | 200 |
135
+ | `create()` | POST | `/base-path` | 201 |
136
+ | `update()` | PUT | `/base-path/:id` | 200 |
137
+ | `patch()` | PATCH | `/base-path/:id` | 200 |
138
+ | `destroy()` | DELETE | `/base-path/:id` | 200 |
139
+
140
+ When the convention doesn't fit, use the explicit decorators instead — `@Get()`, `@Post()`, `@Put()`, `@Patch()`, `@Delete()`, `@All()`. A controller uses one style or the other, not both.
141
+
142
+ ```typescript
143
+ import { Controller, Get, Post, type RouterContext } from 'stratal/router'
144
+ import { object, string, uuid } from 'zod/mini'
145
+
146
+ @Controller('/notes', { tags: ['Notes'], version: '1' })
147
+ export class NotesController {
148
+ @Get('/:id', { params: object({ id: uuid() }), response: noteSchema })
149
+ async getNote(ctx: RouterContext) {
150
+ return ctx.json(await this.notes.find(ctx.param('id')))
151
+ }
152
+
153
+ @Post('/', { body: createNoteSchema, response: noteSchema, statusCode: 201 })
154
+ async createNote(ctx: RouterContext) {
155
+ return ctx.json(await this.notes.create(await ctx.body()), 201)
156
+ }
157
+ }
158
+ ```
159
+
160
+ ### Versioning
161
+
162
+ Don't hard-code the version into the path. Configure it once and the router builds the prefixed paths for you:
163
+
164
+ ```typescript
165
+ export default new Stratal({
166
+ module: AppModule,
167
+ versioning: { prefix: 'api/v', defaultVersion: '1' },
168
+ })
169
+ ```
170
+
171
+ ```typescript
172
+ @Controller('/notes', { version: '1' }) // → /api/v1/notes
173
+ @Controller('/notes', { version: ['1', '2'] }) // → /api/v1/notes and /api/v2/notes
174
+ @Controller('/health', { version: VERSION_NEUTRAL }) // → /health, unprefixed
175
+ ```
176
+
177
+ A controller with no `version` picks up `defaultVersion`. `router.version('2')` in a module's `configureRoutes()` applies a version to every controller in that module.
178
+
179
+ ### Validation
180
+
181
+ Schemas come from `zod/mini` directly — named imports keep them tree-shakeable. `stratal/validation` adds the framework's own helpers on top (schema metadata, localized error messages, and shared types):
182
+
183
+ ```typescript
184
+ import { describe, named, cuid2 } from 'stratal/validation'
185
+ import { object, string } from 'zod/mini'
186
+
187
+ const noteSchema = named(object({
188
+ id: cuid2(),
189
+ title: describe(string(), 'Note title'),
190
+ }), 'Note')
191
+ ```
192
+
193
+ ## Support the project
194
+
195
+ If Stratal is useful to you, **[star the repository](https://github.com/strataljs/stratal)** — it is the simplest way to help others find it.
196
+
119
197
  ## Contributing
120
198
 
121
199
  Contributions are welcome! Please see [CONTRIBUTING.md](https://github.com/strataljs/stratal/blob/main/CONTRIBUTING.md) for guidelines.
122
200
 
201
+ ## Maintainer
202
+
203
+ Built and maintained by **Temitayo Fadojutimi** — [@adesege_](https://x.com/adesege_).
204
+
123
205
  ## License
124
206
 
125
207
  MIT
@@ -31,7 +31,9 @@ async function resolve(specifier, context, nextResolve) {
31
31
  }
32
32
  async function load(url, context, nextLoad) {
33
33
  if (url.endsWith(RAW_SUFFIX)) {
34
- const content = readFileSync(fileURLToPath(url.slice(0, -4)), "utf-8");
34
+ const fileUrl = url.slice(0, -4);
35
+ const filePath = fileURLToPath(fileUrl);
36
+ const content = readFileSync(filePath, "utf-8");
35
37
  return {
36
38
  format: "module",
37
39
  shortCircuit: true,
@@ -112,7 +114,7 @@ export function connect(address, options) {
112
114
 
113
115
  const closedPromise = new Promise((resolve) => currentSocket.on('close', resolve));
114
116
 
115
- return {
117
+ const socket = {
116
118
  readable,
117
119
  writable,
118
120
  startTls() {
@@ -124,10 +126,23 @@ export function connect(address, options) {
124
126
  tlsSocket.on('data', dataHandler);
125
127
  tlsSocket.on('end', endHandler);
126
128
  tlsSocket.on('error', errorHandler);
129
+ // CF's Socket.startTls() returns a brand-new Socket. The same readable/writable
130
+ // stay valid because they read from / write to the reassigned currentSocket, so
131
+ // returning this object preserves the caller's re-derived reader/writer.
132
+ return socket;
133
+ },
134
+ // CF's Socket.close() returns Promise<void>. Resolve once the socket is closed
135
+ // (or immediately if already destroyed) so callers can await socket.close().
136
+ close() {
137
+ return new Promise((resolve) => {
138
+ if (currentSocket.destroyed) { resolve(); return; }
139
+ currentSocket.once('close', () => resolve());
140
+ currentSocket.destroy();
141
+ });
127
142
  },
128
- close() { currentSocket.destroy(); },
129
143
  closed: closedPromise,
130
144
  };
145
+ return socket;
131
146
  }
132
147
  `
133
148
  };
@@ -1 +1 @@
1
- {"version":3,"file":"cloudflare-workers-loader.mjs","names":[],"sources":["../../src/bin/cloudflare-workers-loader.ts"],"sourcesContent":["/**\n * ESM loader hook that provides virtual modules for Cloudflare-specific imports\n * and handles Vite-style `?raw` imports (returning file contents as a string).\n *\n * When registered via `node --import` or `register()`, this intercepts:\n * - `cloudflare:workers` — virtual env/waitUntil from `globalThis.__stratalPlatformProxy`\n * - `cloudflare:sockets` — Node.js TCP/TLS implementation of the CF connect() API\n * - `?raw` imports — returns file contents as a default string export\n */\n\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nconst VIRTUAL_WORKERS_URL = 'cloudflare-workers:virtual'\nconst VIRTUAL_SOCKETS_URL = 'cloudflare-sockets:virtual'\nconst RAW_SUFFIX = '?raw'\n\ninterface ResolveContext {\n parentURL?: string\n conditions: string[]\n}\n\ninterface ResolveResult {\n url: string\n shortCircuit?: boolean\n}\n\ntype NextResolve = (specifier: string, context: ResolveContext) => Promise<ResolveResult>\n\nexport async function resolve(\n specifier: string,\n context: ResolveContext,\n nextResolve: NextResolve,\n): Promise<ResolveResult> {\n if (specifier === 'cloudflare:workers') {\n return { url: VIRTUAL_WORKERS_URL, shortCircuit: true }\n }\n if (specifier === 'cloudflare:sockets') {\n return { url: VIRTUAL_SOCKETS_URL, shortCircuit: true }\n }\n if (specifier.endsWith(RAW_SUFFIX)) {\n const base = specifier.slice(0, -RAW_SUFFIX.length)\n const resolved = await nextResolve(base, context)\n return { url: resolved.url + RAW_SUFFIX, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n}\n\ninterface LoadContext {\n format?: string\n conditions: string[]\n}\n\ninterface LoadResult {\n format: string\n source: string\n shortCircuit?: boolean\n}\n\ntype NextLoad = (url: string, context: LoadContext) => Promise<LoadResult>\n\nexport async function load(\n url: string,\n context: LoadContext,\n nextLoad: NextLoad,\n): Promise<LoadResult> {\n if (url.endsWith(RAW_SUFFIX)) {\n const fileUrl = url.slice(0, -RAW_SUFFIX.length)\n const filePath = fileURLToPath(fileUrl)\n const content = readFileSync(filePath, 'utf-8')\n return {\n format: 'module',\n shortCircuit: true,\n source: `export default ${JSON.stringify(content)}`,\n }\n }\n if (url === VIRTUAL_WORKERS_URL) {\n return {\n format: 'module',\n shortCircuit: true,\n source: `\nconst proxy = globalThis.__stratalPlatformProxy;\nif (!proxy) throw new Error('globalThis.__stratalPlatformProxy not set — Quarry CLI must initialize it before importing the app entry.');\nexport const env = proxy.env;\nexport const waitUntil = proxy.waitUntil;\nexport const exports = {}\nexport class DurableObject {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkerEntrypoint {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkflowEntrypoint {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkflowStep {}\nexport class RpcTarget {}\nexport const RpcStub = function(value) { return value; };\nexport function withEnv(newEnv, fn) { return fn(); }\nexport function withExports(newExports, fn) { return fn(); }\nexport function withEnvAndExports(newEnv, newExports, fn) { return fn(); }\n`,\n }\n }\n if (url === VIRTUAL_SOCKETS_URL) {\n return {\n format: 'module',\n shortCircuit: true,\n source: `\nimport { connect as netConnect } from 'node:net';\nimport { connect as tlsConnect } from 'node:tls';\n\nexport function connect(address, options) {\n const hostname = typeof address === 'string' ? address : address.hostname;\n const port = typeof address === 'string' ? 443 : address.port;\n const secureTransport = options?.secureTransport ?? 'off';\n\n let currentSocket;\n if (secureTransport === 'on') {\n currentSocket = tlsConnect({ host: hostname, port, servername: hostname });\n } else {\n currentSocket = netConnect({ host: hostname, port });\n }\n\n let dataHandler, endHandler, errorHandler;\n\n const readable = new ReadableStream({\n start(controller) {\n dataHandler = (chunk) => {\n try { controller.enqueue(new Uint8Array(chunk)); } catch {}\n };\n endHandler = () => {\n try { controller.close(); } catch {}\n };\n errorHandler = (err) => {\n try { controller.error(err); } catch {}\n };\n currentSocket.on('data', dataHandler);\n currentSocket.on('end', endHandler);\n currentSocket.on('error', errorHandler);\n }\n });\n\n const writable = new WritableStream({\n write(chunk) {\n return new Promise((resolve, reject) => {\n currentSocket.write(Buffer.from(chunk), (err) => err ? reject(err) : resolve());\n });\n }\n });\n\n const closedPromise = new Promise((resolve) => currentSocket.on('close', resolve));\n\n return {\n readable,\n writable,\n startTls() {\n currentSocket.removeListener('data', dataHandler);\n currentSocket.removeListener('end', endHandler);\n currentSocket.removeListener('error', errorHandler);\n const tlsSocket = tlsConnect({ socket: currentSocket, servername: hostname });\n currentSocket = tlsSocket;\n tlsSocket.on('data', dataHandler);\n tlsSocket.on('end', endHandler);\n tlsSocket.on('error', errorHandler);\n },\n close() { currentSocket.destroy(); },\n closed: closedPromise,\n };\n}\n`,\n }\n }\n return nextLoad(url, context)\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAC5B,MAAM,aAAa;AAcnB,eAAsB,QACpB,WACA,SACA,aACwB;CACxB,IAAI,cAAc,sBAChB,OAAO;EAAE,KAAK;EAAqB,cAAc;CAAK;CAExD,IAAI,cAAc,sBAChB,OAAO;EAAE,KAAK;EAAqB,cAAc;CAAK;CAExD,IAAI,UAAU,SAAS,UAAU,GAG/B,OAAO;EAAE,MAAK,MADS,YADV,UAAU,MAAM,GAAG,EACM,GAAG,OAAO,GACzB,MAAM;EAAY,cAAc;CAAK;CAE9D,OAAO,YAAY,WAAW,OAAO;AACvC;AAeA,eAAsB,KACpB,KACA,SACA,UACqB;CACrB,IAAI,IAAI,SAAS,UAAU,GAAG;EAG5B,MAAM,UAAU,aADC,cADD,IAAI,MAAM,GAAG,EACQ,CACD,GAAG,OAAO;EAC9C,OAAO;GACL,QAAQ;GACR,cAAc;GACd,QAAQ,kBAAkB,KAAK,UAAU,OAAO;EAClD;CACF;CACA,IAAI,QAAQ,qBACV,OAAO;EACL,QAAQ;EACR,cAAc;EACd,QAAQ;;;;;;;;;;;;;;;;;;;;;;CAsBV;CAEF,IAAI,QAAQ,qBACV,OAAO;EACL,QAAQ;EACR,cAAc;EACd,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+DV;CAEF,OAAO,SAAS,KAAK,OAAO;AAC9B"}
1
+ {"version":3,"file":"cloudflare-workers-loader.mjs","names":[],"sources":["../../src/bin/cloudflare-workers-loader.ts"],"sourcesContent":["/**\n * ESM loader hook that provides virtual modules for Cloudflare-specific imports\n * and handles Vite-style `?raw` imports (returning file contents as a string).\n *\n * When registered via `node --import` or `register()`, this intercepts:\n * - `cloudflare:workers` — virtual env/waitUntil from `globalThis.__stratalPlatformProxy`\n * - `cloudflare:sockets` — Node.js TCP/TLS implementation of the CF connect() API\n * - `?raw` imports — returns file contents as a default string export\n */\n\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nconst VIRTUAL_WORKERS_URL = 'cloudflare-workers:virtual'\nconst VIRTUAL_SOCKETS_URL = 'cloudflare-sockets:virtual'\nconst RAW_SUFFIX = '?raw'\n\ninterface ResolveContext {\n parentURL?: string\n conditions: string[]\n}\n\ninterface ResolveResult {\n url: string\n shortCircuit?: boolean\n}\n\ntype NextResolve = (specifier: string, context: ResolveContext) => Promise<ResolveResult>\n\nexport async function resolve(\n specifier: string,\n context: ResolveContext,\n nextResolve: NextResolve,\n): Promise<ResolveResult> {\n if (specifier === 'cloudflare:workers') {\n return { url: VIRTUAL_WORKERS_URL, shortCircuit: true }\n }\n if (specifier === 'cloudflare:sockets') {\n return { url: VIRTUAL_SOCKETS_URL, shortCircuit: true }\n }\n if (specifier.endsWith(RAW_SUFFIX)) {\n const base = specifier.slice(0, -RAW_SUFFIX.length)\n const resolved = await nextResolve(base, context)\n return { url: resolved.url + RAW_SUFFIX, shortCircuit: true }\n }\n return nextResolve(specifier, context)\n}\n\ninterface LoadContext {\n format?: string\n conditions: string[]\n}\n\ninterface LoadResult {\n format: string\n source: string\n shortCircuit?: boolean\n}\n\ntype NextLoad = (url: string, context: LoadContext) => Promise<LoadResult>\n\nexport async function load(\n url: string,\n context: LoadContext,\n nextLoad: NextLoad,\n): Promise<LoadResult> {\n if (url.endsWith(RAW_SUFFIX)) {\n const fileUrl = url.slice(0, -RAW_SUFFIX.length)\n const filePath = fileURLToPath(fileUrl)\n const content = readFileSync(filePath, 'utf-8')\n return {\n format: 'module',\n shortCircuit: true,\n source: `export default ${JSON.stringify(content)}`,\n }\n }\n if (url === VIRTUAL_WORKERS_URL) {\n return {\n format: 'module',\n shortCircuit: true,\n source: `\nconst proxy = globalThis.__stratalPlatformProxy;\nif (!proxy) throw new Error('globalThis.__stratalPlatformProxy not set — Quarry CLI must initialize it before importing the app entry.');\nexport const env = proxy.env;\nexport const waitUntil = proxy.waitUntil;\nexport const exports = {}\nexport class DurableObject {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkerEntrypoint {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkflowEntrypoint {\n constructor(ctx, env) { this.ctx = ctx; this.env = env; }\n}\nexport class WorkflowStep {}\nexport class RpcTarget {}\nexport const RpcStub = function(value) { return value; };\nexport function withEnv(newEnv, fn) { return fn(); }\nexport function withExports(newExports, fn) { return fn(); }\nexport function withEnvAndExports(newEnv, newExports, fn) { return fn(); }\n`,\n }\n }\n if (url === VIRTUAL_SOCKETS_URL) {\n return {\n format: 'module',\n shortCircuit: true,\n source: `\nimport { connect as netConnect } from 'node:net';\nimport { connect as tlsConnect } from 'node:tls';\n\nexport function connect(address, options) {\n const hostname = typeof address === 'string' ? address : address.hostname;\n const port = typeof address === 'string' ? 443 : address.port;\n const secureTransport = options?.secureTransport ?? 'off';\n\n let currentSocket;\n if (secureTransport === 'on') {\n currentSocket = tlsConnect({ host: hostname, port, servername: hostname });\n } else {\n currentSocket = netConnect({ host: hostname, port });\n }\n\n let dataHandler, endHandler, errorHandler;\n\n const readable = new ReadableStream({\n start(controller) {\n dataHandler = (chunk) => {\n try { controller.enqueue(new Uint8Array(chunk)); } catch {}\n };\n endHandler = () => {\n try { controller.close(); } catch {}\n };\n errorHandler = (err) => {\n try { controller.error(err); } catch {}\n };\n currentSocket.on('data', dataHandler);\n currentSocket.on('end', endHandler);\n currentSocket.on('error', errorHandler);\n }\n });\n\n const writable = new WritableStream({\n write(chunk) {\n return new Promise((resolve, reject) => {\n currentSocket.write(Buffer.from(chunk), (err) => err ? reject(err) : resolve());\n });\n }\n });\n\n const closedPromise = new Promise((resolve) => currentSocket.on('close', resolve));\n\n const socket = {\n readable,\n writable,\n startTls() {\n currentSocket.removeListener('data', dataHandler);\n currentSocket.removeListener('end', endHandler);\n currentSocket.removeListener('error', errorHandler);\n const tlsSocket = tlsConnect({ socket: currentSocket, servername: hostname });\n currentSocket = tlsSocket;\n tlsSocket.on('data', dataHandler);\n tlsSocket.on('end', endHandler);\n tlsSocket.on('error', errorHandler);\n // CF's Socket.startTls() returns a brand-new Socket. The same readable/writable\n // stay valid because they read from / write to the reassigned currentSocket, so\n // returning this object preserves the caller's re-derived reader/writer.\n return socket;\n },\n // CF's Socket.close() returns Promise<void>. Resolve once the socket is closed\n // (or immediately if already destroyed) so callers can await socket.close().\n close() {\n return new Promise((resolve) => {\n if (currentSocket.destroyed) { resolve(); return; }\n currentSocket.once('close', () => resolve());\n currentSocket.destroy();\n });\n },\n closed: closedPromise,\n };\n return socket;\n}\n`,\n }\n }\n return nextLoad(url, context)\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAM,sBAAsB;AAC5B,MAAM,sBAAsB;AAC5B,MAAM,aAAa;AAcnB,eAAsB,QACpB,WACA,SACA,aACwB;CACxB,IAAI,cAAc,sBAChB,OAAO;EAAE,KAAK;EAAqB,cAAc;CAAK;CAExD,IAAI,cAAc,sBAChB,OAAO;EAAE,KAAK;EAAqB,cAAc;CAAK;CAExD,IAAI,UAAU,SAAS,UAAU,GAG/B,OAAO;EAAE,MAAK,MADS,YADV,UAAU,MAAM,GAAG,EACM,GAAG,OAAO,EAAA,CACzB,MAAM;EAAY,cAAc;CAAK;CAE9D,OAAO,YAAY,WAAW,OAAO;AACvC;AAeA,eAAsB,KACpB,KACA,SACA,UACqB;CACrB,IAAI,IAAI,SAAS,UAAU,GAAG;EAC5B,MAAM,UAAU,IAAI,MAAM,GAAG,EAAkB;EAC/C,MAAM,WAAW,cAAc,OAAO;EACtC,MAAM,UAAU,aAAa,UAAU,OAAO;EAC9C,OAAO;GACL,QAAQ;GACR,cAAc;GACd,QAAQ,kBAAkB,KAAK,UAAU,OAAO;EAClD;CACF;CACA,IAAI,QAAQ,qBACV,OAAO;EACL,QAAQ;EACR,cAAc;EACd,QAAQ;;;;;;;;;;;;;;;;;;;;;;CAsBV;CAEF,IAAI,QAAQ,qBACV,OAAO;EACL,QAAQ;EACR,cAAc;EACd,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4EV;CAEF,OAAO,SAAS,KAAK,OAAO;AAC9B"}
@@ -60,10 +60,7 @@ function createDynamicCommands(quarry, parseSignature, app) {
60
60
  const value = this[opt.name];
61
61
  if (value !== void 0) input[opt.name] = value;
62
62
  }
63
- const result = await app.handleCommand(entry.name, input);
64
- for (const line of result.output) this.context.stdout.write(line + "\n");
65
- for (const err of result.errors) this.context.stderr.write(err + "\n");
66
- return result.exitCode;
63
+ return (await app.handleCommand(entry.name, input)).exitCode;
67
64
  }
68
65
  }
69
66
  const proto = DynCmd.prototype;
@@ -82,9 +79,10 @@ function createDynamicCommands(quarry, parseSignature, app) {
82
79
  if (opt.default !== void 0) optDescParts.push(`(default: ${opt.default})`);
83
80
  const optDesc = optDescParts.length > 0 ? optDescParts.join(" ") : void 0;
84
81
  if (opt.isFlag) proto[opt.name] = Option.Boolean(optName, { description: optDesc });
85
- else if (opt.isArray) if (opt.default !== void 0) proto[opt.name] = Option.Array(optName, [opt.default], { description: optDesc });
86
- else proto[opt.name] = Option.Array(optName, { description: optDesc });
87
- else if (opt.default !== void 0) proto[opt.name] = Option.String(optName, opt.default, { description: optDesc });
82
+ else if (opt.isArray) {
83
+ if (opt.default !== void 0) proto[opt.name] = Option.Array(optName, [opt.default], { description: optDesc });
84
+ else proto[opt.name] = Option.Array(optName, { description: optDesc });
85
+ } else if (opt.default !== void 0) proto[opt.name] = Option.String(optName, opt.default, { description: optDesc });
88
86
  else proto[opt.name] = Option.String(optName, { description: optDesc });
89
87
  }
90
88
  commands.push(DynCmd);
@@ -92,6 +90,36 @@ function createDynamicCommands(quarry, parseSignature, app) {
92
90
  return commands;
93
91
  }
94
92
  //#endregion
93
+ //#region src/bin/module-rules.ts
94
+ /**
95
+ * Remove `modulesRules` from a sourceless quarry worker's Miniflare options,
96
+ * returning whether anything was removed.
97
+ *
98
+ * `modulesRules` tells Miniflare how to interpret files it pulls off disk when
99
+ * it assembles a worker's module graph (`.sql` as Text, `.wasm` as CompiledWasm,
100
+ * and so on). The quarry CLI host has no module graph: it runs an
101
+ * empty script (`script: ''`) purely to own a worker's bindings for command code
102
+ * executing in Node, so no file is ever matched against a rule and the option
103
+ * cannot change how this host behaves.
104
+ *
105
+ * It has to be dropped rather than passed through. Miniflare 5 replaced the flat
106
+ * v4 worker shape with a `workers` array, and its `convertV4MiniflareOptions()`
107
+ * bridge refuses any input carrying `modulesRules` — it has no v5 equivalent to
108
+ * map onto, so converting would silently lose behaviour and it throws instead.
109
+ * Wrangler's `unstable_getMiniflareWorkerOptions()` always emits the key
110
+ * (`config.rules` concatenated with its own defaults, so never empty), which
111
+ * means every quarry boot on wrangler ≥4.124 hits that guard and dies before the
112
+ * command runs.
113
+ *
114
+ * Dropping it is only sound *because* the host is sourceless — a worker that
115
+ * actually loads modules would need these rules honoured, not discarded.
116
+ */
117
+ function stripModuleRules(workerOptions) {
118
+ if (workerOptions.modulesRules === void 0) return false;
119
+ delete workerOptions.modulesRules;
120
+ return true;
121
+ }
122
+ //#endregion
95
123
  //#region src/bin/registry.ts
96
124
  const LOCKFILES = [
97
125
  "yarn.lock",
@@ -145,9 +173,38 @@ function resolveDevRegistryPath(env, cwd) {
145
173
  return join(findProjectRoot(cwd) ?? cwd, ".wrangler", "registry");
146
174
  }
147
175
  //#endregion
176
+ //#region src/bin/workflow-bindings.ts
177
+ /**
178
+ * Remove Workflow bindings from a sourceless quarry worker's Miniflare options,
179
+ * returning the names removed so the caller can surface them.
180
+ *
181
+ * The quarry CLI worker runs an empty script (`script: ''`): it exists to host a
182
+ * worker's bindings for command code running in Node, but defines no worker
183
+ * module. A Workflow's engine binds to the `class_name` entrypoint of the worker
184
+ * that declares it (Miniflare wires `USER_WORKFLOW` as a service binding to
185
+ * `core:user:<scriptName>`, validated at boot), and an empty script exposes no
186
+ * such entrypoint — so the runtime refuses to start.
187
+ *
188
+ * Redirecting the binding cross-script to the defining worker does not help in
189
+ * local development: the quarry host boots its own Miniflare instance *before*
190
+ * that worker exists (a worker's `dev` script boots the quarry host, then spawns
191
+ * the worker), so the cross-script service is undefined at boot. Workflows also
192
+ * cannot be remote bindings. A sourceless host therefore cannot run or reach a
193
+ * Workflow; the binding is dropped here. Triggering a Workflow must happen from
194
+ * the worker that defines it (e.g. an HTTP/queue handler), not the CLI host.
195
+ */
196
+ function stripWorkflowBindings(workerOptions) {
197
+ const workflows = workerOptions.workflows;
198
+ if (!workflows) return [];
199
+ const names = Object.keys(workflows);
200
+ delete workerOptions.workflows;
201
+ return names;
202
+ }
203
+ //#endregion
148
204
  //#region src/bin/quarry.ts
149
205
  const require = createRequire(import.meta.url);
150
- register(pathToFileURL(join(dirname(require.resolve("@swc-node/register")), "esm/esm.mjs")), pathToFileURL("./"));
206
+ const swcRegisterPath = join(dirname(require.resolve("@swc-node/register")), "esm/esm.mjs");
207
+ register(pathToFileURL(swcRegisterPath), pathToFileURL("./"));
151
208
  register(new URL("./cloudflare-workers-loader.mjs", import.meta.url), pathToFileURL("./"));
152
209
  const DEFAULT_ENTRY = "./src/quarry.ts";
153
210
  let environment;
@@ -176,7 +233,7 @@ if (!existsSync(entryPath)) {
176
233
  async function main() {
177
234
  const cwdRequire = createRequire(join(process.cwd(), "package.json"));
178
235
  const { unstable_readConfig: readConfig, unstable_getMiniflareWorkerOptions: getMiniflareWorkerOptions, unstable_getVarsForDev: getVarsForDev, maybeStartOrUpdateRemoteProxySession } = await import(cwdRequire.resolve("wrangler"));
179
- const { Miniflare } = await import(cwdRequire.resolve("miniflare"));
236
+ const { Miniflare, convertV4MiniflareOptions } = await import(cwdRequire.resolve("miniflare"));
180
237
  const configName = [
181
238
  "wrangler.jsonc",
182
239
  "wrangler.json",
@@ -213,6 +270,7 @@ async function main() {
213
270
  console.log(`Remote bindings: proxying ${remoteNames.length} binding(s) to deployed resources (${remoteNames.join(", ")})`);
214
271
  }
215
272
  const { workerOptions } = getMiniflareWorkerOptions(config, environment, { remoteProxyConnectionString: remoteProxy?.session.remoteProxyConnectionString });
273
+ process.env.CLOUDFLARE_INCLUDE_PROCESS_ENV = "true";
216
274
  const vars = getVarsForDev(configPath, void 0, config.vars, environment);
217
275
  const varsRecord = {};
218
276
  for (const [key, binding] of Object.entries(vars)) varsRecord[key] = binding.value;
@@ -221,14 +279,17 @@ async function main() {
221
279
  ...varsRecord,
222
280
  QUEUE_PROVIDER: "sync"
223
281
  };
282
+ const strippedWorkflows = stripWorkflowBindings(workerOptions);
283
+ if (strippedWorkflows.length > 0) console.log(`Workflow binding(s) unavailable to CLI commands (defined on the worker, not this host): ${strippedWorkflows.join(", ")}`);
224
284
  workerOptions.name = config.name ? `quarry-${config.name}-${process.pid}` : `quarry-${process.pid}`;
225
- const mf = new Miniflare({
285
+ stripModuleRules(workerOptions);
286
+ const mf = new Miniflare(convertV4MiniflareOptions({
226
287
  ...workerOptions,
227
288
  script: "",
228
289
  modules: true,
229
290
  unsafeDevRegistryPath: registryPath,
230
- defaultPersistRoot: join(process.cwd(), ".wrangler/state/v3")
231
- });
291
+ resourcePersistencePath: join(process.cwd(), ".wrangler/state/v3")
292
+ }));
232
293
  await mf.ready;
233
294
  const env = await mf.getBindings();
234
295
  const pendingPromises = [];
@@ -1 +1 @@
1
- {"version":3,"file":"quarry.mjs","names":[],"sources":["../../src/bin/argv.ts","../../src/bin/commands/dynamic-command.ts","../../src/bin/registry.ts","../../src/bin/quarry.ts"],"sourcesContent":["export function extractEnvFlag(argv: string[]): { env: string | undefined; rest: string[] } {\n let env: string | undefined\n const rest: string[] = []\n for (let i = 0; i < argv.length; i++) {\n const tok = argv[i]\n if (tok === '--') {\n rest.push(...argv.slice(i))\n break\n }\n const eqMatch = tok.match(/^(?:--env|-e)=(.*)$/)\n if (eqMatch) {\n if (!eqMatch[1]) throw new Error('--env requires a value (e.g. --env staging)')\n if (env !== undefined) throw new Error('--env specified more than once')\n env = eqMatch[1]\n continue\n }\n if (tok === '--env' || tok === '-e') {\n const next = argv[i + 1]\n if (!next || next.startsWith('-')) throw new Error('--env requires a value (e.g. --env staging)')\n if (env !== undefined) throw new Error('--env specified more than once')\n env = next\n i++\n continue\n }\n rest.push(tok)\n }\n return { env, rest }\n}\n","import { Command, type CommandClass, Option, type Usage } from 'clipanion'\n\nimport type { Application } from 'stratal'\nimport type { ParsedSignature, QuarryRegistry } from 'stratal/quarry'\n\n/** Create Clipanion command classes from Quarry-registered commands. */\nexport function createDynamicCommands(\n quarry: QuarryRegistry,\n parseSignature: (command: string) => ParsedSignature,\n app: Application,\n) {\n const commands: CommandClass[] = []\n\n for (const entry of quarry.list()) {\n const commandClass = quarry.get(entry.name)! as unknown as { command: string; description?: string; aliases?: string[] }\n const signature = parseSignature(commandClass.command)\n\n const paths: string[][] = [entry.name.split(' ')]\n if (commandClass.aliases) {\n for (const alias of commandClass.aliases) {\n paths.push(alias.split(' '))\n }\n }\n\n // Allow bare `npx quarry` (no arguments) to invoke the help command\n if (entry.name === 'help') {\n paths.push([])\n }\n\n class DynCmd extends Command {\n static override paths = paths\n static override usage: Usage | undefined = commandClass.description\n ? Command.Usage({ description: commandClass.description })\n : undefined\n\n async execute(): Promise<number> {\n const input: Record<string, unknown> = {}\n\n for (const arg of signature.arguments) {\n const value = (this as Record<string, unknown>)[arg.name]\n if (value !== undefined) input[arg.name] = value\n }\n\n for (const opt of signature.options) {\n const value = (this as Record<string, unknown>)[opt.name]\n if (value !== undefined) input[opt.name] = value\n }\n\n const result = await app.handleCommand(entry.name, input)\n\n for (const line of result.output) {\n this.context.stdout.write(line + '\\n')\n }\n\n for (const err of result.errors) {\n this.context.stderr.write(err + '\\n')\n }\n\n return result.exitCode\n }\n }\n\n // Define Clipanion options/arguments as class property defaults\n const proto = DynCmd.prototype as unknown as Record<string, unknown>\n for (const arg of signature.arguments) {\n if (arg.isArray) {\n proto[arg.name] = Option.Rest({ name: arg.name, required: arg.required ? 1 : 0 })\n } else {\n proto[arg.name] = Option.String({ name: arg.name, required: arg.required })\n }\n }\n\n for (const opt of signature.options) {\n const optName = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n const optDescParts: string[] = []\n if (opt.description) optDescParts.push(opt.description)\n if (opt.default !== undefined) optDescParts.push(`(default: ${opt.default})`)\n const optDesc = optDescParts.length > 0 ? optDescParts.join(' ') : undefined\n\n if (opt.isFlag) {\n proto[opt.name] = Option.Boolean(optName, { description: optDesc })\n } else if (opt.isArray) {\n if (opt.default !== undefined) {\n proto[opt.name] = Option.Array(optName, [opt.default], { description: optDesc })\n } else {\n proto[opt.name] = Option.Array(optName, { description: optDesc })\n }\n } else {\n if (opt.default !== undefined) {\n proto[opt.name] = Option.String(optName, opt.default, { description: optDesc })\n } else {\n proto[opt.name] = Option.String(optName, { description: optDesc })\n }\n }\n }\n\n commands.push(DynCmd)\n }\n\n return commands\n}\n","import { existsSync } from 'node:fs'\nimport { dirname, join, parse, resolve } from 'node:path'\n\nconst LOCKFILES = [\n 'yarn.lock',\n 'package-lock.json',\n 'pnpm-lock.yaml',\n 'bun.lock',\n 'bun.lockb',\n]\n\n/**\n * Walk up from `startDir` to the project root.\n *\n * The root is the nearest ancestor containing a package-manager lockfile —\n * lockfiles exist only at install roots, so the marker is immune to nested\n * workspace `package.json`s and to stray `.git` directories tools sometimes\n * leave behind. When no lockfile exists (e.g. a project before its first\n * install), the outermost ancestor containing a `package.json` is used —\n * every project has one, monorepo or not, git or not.\n *\n * Returns `undefined` when neither marker is found.\n */\nexport function findProjectRoot(startDir: string): string | undefined {\n // A relative `startDir` would never equal its parsed root (`''`) — `dirname`\n // converges to `'.'` and the walk never terminates. Resolve up front so the\n // traversal (and the returned path) is always absolute.\n let dir = resolve(startDir)\n const { root } = parse(dir)\n let outermostPackageJson: string | undefined\n while (true) {\n if (LOCKFILES.some(lockfile => existsSync(join(dir, lockfile)))) return dir\n if (existsSync(join(dir, 'package.json'))) outermostPackageJson = dir\n if (dir === root) return outermostPackageJson\n dir = dirname(dir)\n }\n}\n\nexport interface DevRegistryEnv {\n MINIFLARE_REGISTRY_PATH?: string\n WRANGLER_REGISTRY_PATH?: string\n}\n\n/**\n * Resolve the Miniflare dev-registry path for a quarry run.\n *\n * Precedence:\n * 1. an explicit `MINIFLARE_REGISTRY_PATH` (the variable Miniflare actually\n * reads) or `WRANGLER_REGISTRY_PATH` (the variable `wrangler dev` reads —\n * honoured here too so one override redirects every tool the same way)\n * 2. `<projectRoot>/.wrangler/registry` (see `findProjectRoot`) — so every\n * process in a checkout (dev servers, quarry CLI runs) deterministically\n * shares one registry, and parallel checkouts (git worktrees) each get\n * their own.\n *\n * The global `~/.wrangler/registry` is deliberately never used: a registry\n * shared across checkouts lets identically-named workers from parallel dev\n * environments overwrite each other and breaks service-binding resolution.\n */\nexport function resolveDevRegistryPath(env: DevRegistryEnv, cwd: string): string {\n const explicit = env.MINIFLARE_REGISTRY_PATH ?? env.WRANGLER_REGISTRY_PATH\n if (explicit) return explicit\n return join(findProjectRoot(cwd) ?? cwd, '.wrangler', 'registry')\n}\n","import type { MiniflareOptions } from 'miniflare';\nimport { existsSync } from 'node:fs';\nimport { createRequire, register } from 'node:module';\nimport { dirname, join, resolve } from 'node:path';\nimport { URL, pathToFileURL } from 'node:url';\nimport type { QuarryRegistry } from 'stratal/quarry';\nimport { type Application } from '../application';\nimport { extractEnvFlag } from './argv';\nimport { createDynamicCommands } from './commands/dynamic-command';\nimport { resolveDevRegistryPath } from './registry';\n\ninterface WranglerConfig {\n name?: string\n vars?: Record<string, unknown>\n}\n\ninterface MiniflareWorkerResult {\n workerOptions: Record<string, unknown>\n}\n\ninterface RemoteProxySessionData {\n session: {\n ready: Promise<unknown>\n dispose: () => Promise<void>\n remoteProxyConnectionString: unknown\n }\n remoteBindings: Record<string, unknown>\n}\n\ninterface WranglerModule {\n unstable_readConfig: (args: { config?: string; env?: string }) => WranglerConfig\n unstable_getMiniflareWorkerOptions: (config: WranglerConfig, env?: string, options?: { remoteProxyConnectionString?: unknown }) => MiniflareWorkerResult\n unstable_getVarsForDev: (configPath: string | undefined, envFiles: undefined, vars: unknown, env: string | undefined) => Record<string, { value: string }>\n maybeStartOrUpdateRemoteProxySession: (config: { path: string; environment?: string }) => Promise<RemoteProxySessionData | null>\n}\n\ninterface MiniflareModule {\n Miniflare: new (opts: MiniflareOptions) => { ready: Promise<URL>; getBindings: (name?: string) => Promise<Record<string, unknown>>; dispose: () => Promise<void> }\n}\n\nconst require = createRequire(import.meta.url)\n\n// Register @swc-node/register for TypeScript + decorator support\nconst swcRegisterPath = join(dirname(require.resolve('@swc-node/register')), 'esm/esm.mjs')\nregister(pathToFileURL(swcRegisterPath), pathToFileURL('./'))\n\n// Register cloudflare:workers virtual module loader\nregister(new URL('./cloudflare-workers-loader.mjs', import.meta.url), pathToFileURL('./'))\n\nconst DEFAULT_ENTRY = './src/quarry.ts'\n\nlet environment: string | undefined\ntry {\n const parsed = extractEnvFlag(process.argv.slice(2))\n environment = parsed.env\n process.argv.splice(2, process.argv.length - 2, ...parsed.rest)\n} catch (e) {\n console.error(`Error: ${(e as Error).message}`)\n process.exit(1)\n}\n\n// Determine entry file: if first arg looks like a file path, use it; otherwise use default\nconst firstArg = process.argv[2]\nlet entryFile = DEFAULT_ENTRY\n\nif (firstArg && (firstArg.includes('/') || firstArg.includes('\\\\') || /\\.(ts|js|mts|mjs)$/.test(firstArg))) {\n entryFile = firstArg\n // Remove the entry file from argv so Clipanion sees: [node, script, command, ...options]\n process.argv.splice(2, 1)\n}\n\n// Resolve and validate the entry file\nconst entryPath = resolve(process.cwd(), entryFile)\n\nif (!existsSync(entryPath)) {\n console.error(`Error: Entry file not found: ${entryFile}`)\n console.error('')\n console.error('Create src/quarry.ts that exports `QuarryRunner.run({ module, seeders })`, or specify a custom path:')\n console.error(' npx quarry ./path/to/entry.ts <command> [options]')\n process.exit(1)\n}\n\nasync function main(): Promise<void> {\n const cwdRequire = createRequire(join(process.cwd(), 'package.json'))\n\n const { unstable_readConfig: readConfig, unstable_getMiniflareWorkerOptions: getMiniflareWorkerOptions, unstable_getVarsForDev: getVarsForDev, maybeStartOrUpdateRemoteProxySession } = await import(cwdRequire.resolve('wrangler')) as WranglerModule\n const { Miniflare } = await import(cwdRequire.resolve('miniflare')) as MiniflareModule\n\n const candidates = ['wrangler.jsonc', 'wrangler.json', 'wrangler.toml']\n const configName = candidates.find(c => existsSync(resolve(process.cwd(), c)))\n const configPath = configName ? resolve(process.cwd(), configName) : undefined\n\n // Load .env into process.env before building Miniflare options, mirroring\n // `wrangler dev`'s precedence: base `.env`, then `.env.local`, then the\n // env-specific `.env.<environment>` and `.env.<environment>.local` (later\n // load wins).\n const envFiles = [\n '.env',\n '.env.local',\n environment ? `.env.${environment}` : null,\n environment ? `.env.${environment}.local` : null,\n ]\n for (const envFile of envFiles) {\n if (!envFile) continue\n const envPath = resolve(process.cwd(), envFile)\n if (existsSync(envPath)) process.loadEnvFile(envPath)\n }\n\n // Deterministically resolve the dev service registry from the project root\n // (`<projectRoot>/.wrangler/registry`) so a bare `quarry` invocation shares\n // the SAME project-local registry every other process in this checkout uses —\n // never the global `~/.wrangler/registry`, where parallel checkouts'\n // identically-named workers would overwrite each other and break cross-worker\n // service-binding resolution. An explicit `WRANGLER_REGISTRY_PATH` /\n // `MINIFLARE_REGISTRY_PATH` (from the shell or the `.env` files above) wins.\n //\n // Exported as `MINIFLARE_REGISTRY_PATH` — the variable Miniflare's\n // `getDefaultDevRegistryPath()` reads at call time — so any child process a\n // command spawns (notably the vite dev server launched by `inertia:dev`,\n // whose `@cloudflare/vite-plugin` resolves its registry the same way) lands\n // in the identical registry.\n const registryPath = resolveDevRegistryPath({\n MINIFLARE_REGISTRY_PATH: process.env.MINIFLARE_REGISTRY_PATH,\n WRANGLER_REGISTRY_PATH: process.env.WRANGLER_REGISTRY_PATH,\n }, process.cwd())\n process.env.MINIFLARE_REGISTRY_PATH = registryPath\n\n const config = readConfig({ config: configPath, env: environment })\n\n // Honor `remote: true` bindings (wrangler remote bindings): start a proxy\n // session against the deployed Cloudflare resources and thread its\n // connection string into the Miniflare worker options, so e.g. a service\n // binding marked remote calls the deployed worker instead of the local dev\n // registry. Returns null when the resolved config declares no remote\n // bindings — plain local runs are untouched. Requires wrangler credentials\n // (`wrangler login` / CLOUDFLARE_API_TOKEN) when a session does start.\n const remoteProxy = configPath\n ? await maybeStartOrUpdateRemoteProxySession({ path: configPath, environment })\n : null\n if (remoteProxy) {\n await remoteProxy.session.ready\n const remoteNames = Object.keys(remoteProxy.remoteBindings)\n console.log(`Remote bindings: proxying ${remoteNames.length} binding(s) to deployed resources (${remoteNames.join(', ')})`)\n }\n\n const { workerOptions } = getMiniflareWorkerOptions(config, environment, {\n remoteProxyConnectionString: remoteProxy?.session.remoteProxyConnectionString,\n })\n\n const vars = getVarsForDev(configPath, undefined, config.vars, environment)\n const varsRecord: Record<string, string> = {}\n for (const [key, binding] of Object.entries(vars)) {\n varsRecord[key] = binding.value\n }\n\n const existingBindings = workerOptions.bindings as Record<string, unknown> ?? {}\n workerOptions.bindings = {\n ...existingBindings,\n ...varsRecord,\n QUEUE_PROVIDER: 'sync',\n }\n\n // Rename so quarry doesn't overwrite a running `wrangler dev` session's\n // dev-registry entry. The registry is how Miniflare discovers peer workers\n // for service binding resolution — a collision would break the running session.\n const workerName = config.name ? `quarry-${config.name}-${process.pid}` : `quarry-${process.pid}`\n workerOptions.name = workerName\n\n const mf = new Miniflare({\n ...workerOptions,\n script: '',\n modules: true,\n unsafeDevRegistryPath: registryPath,\n // Persist every durable plugin (KV, D1, R2, Durable Objects, cache) under\n // the same root `wrangler dev` uses, so state survives across `quarry`\n // invocations and is shared with a running `wrangler dev` session.\n defaultPersistRoot: join(process.cwd(), '.wrangler/state/v3'),\n })\n\n await mf.ready\n const env = await mf.getBindings()\n\n const pendingPromises: Promise<unknown>[] = []\n const trackedWaitUntil = (promise: Promise<unknown>) => {\n pendingPromises.push(promise)\n }\n\n let app: Application | undefined\n try {\n (globalThis as Record<string, unknown>).__stratalPlatformProxy = {\n env,\n waitUntil: trackedWaitUntil,\n }\n\n await import(pathToFileURL(entryPath).href)\n\n const [\n { Stratal },\n { DI_TOKENS },\n { parseSignature },\n ] = await Promise.all([\n import('stratal'),\n import('stratal/di'),\n import('stratal/quarry'),\n ])\n\n app = await Stratal.resolveApplication()\n const quarry = app.container.resolve<QuarryRegistry>(DI_TOKENS.Quarry)\n\n const { Cli } = await import('clipanion')\n const pkg = require('../../package.json') as { version: string }\n\n const cli = new Cli({\n binaryName: 'quarry',\n binaryLabel: 'Quarry CLI',\n binaryVersion: pkg.version,\n })\n\n for (const cmd of createDynamicCommands(quarry, parseSignature, app)) {\n cli.register(cmd)\n }\n\n await cli.runExit(process.argv.slice(2), { ...Cli.defaultContext })\n } finally {\n await Promise.allSettled(pendingPromises)\n await app?.shutdown()\n await mf.dispose()\n await remoteProxy?.session.dispose()\n }\n}\n\nmain().catch(async (error: unknown) => {\n const { ConfigValidationError } = await import('stratal/config')\n\n const message = error instanceof Error ? error.message : String(error)\n console.error('Fatal error:', message)\n if (error instanceof ConfigValidationError) {\n console.error(error.errors.message)\n }\n process.exit(1)\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"quarry.mjs","names":[],"sources":["../../src/bin/argv.ts","../../src/bin/commands/dynamic-command.ts","../../src/bin/module-rules.ts","../../src/bin/registry.ts","../../src/bin/workflow-bindings.ts","../../src/bin/quarry.ts"],"sourcesContent":["export function extractEnvFlag(argv: string[]): { env: string | undefined; rest: string[] } {\n let env: string | undefined\n const rest: string[] = []\n for (let i = 0; i < argv.length; i++) {\n const tok = argv[i]\n if (tok === '--') {\n rest.push(...argv.slice(i))\n break\n }\n const eqMatch = tok.match(/^(?:--env|-e)=(.*)$/)\n if (eqMatch) {\n if (!eqMatch[1]) throw new Error('--env requires a value (e.g. --env staging)')\n if (env !== undefined) throw new Error('--env specified more than once')\n env = eqMatch[1]\n continue\n }\n if (tok === '--env' || tok === '-e') {\n const next = argv[i + 1]\n if (!next || next.startsWith('-')) throw new Error('--env requires a value (e.g. --env staging)')\n if (env !== undefined) throw new Error('--env specified more than once')\n env = next\n i++\n continue\n }\n rest.push(tok)\n }\n return { env, rest }\n}\n","import { Command, type CommandClass, Option, type Usage } from 'clipanion'\n\nimport type { Application } from 'stratal'\nimport type { ParsedSignature, QuarryRegistry } from 'stratal/quarry'\n\n/** Create Clipanion command classes from Quarry-registered commands. */\nexport function createDynamicCommands(\n quarry: QuarryRegistry,\n parseSignature: (command: string) => ParsedSignature,\n app: Application,\n) {\n const commands: CommandClass[] = []\n\n for (const entry of quarry.list()) {\n const commandClass = quarry.get(entry.name)! as unknown as { command: string; description?: string; aliases?: string[] }\n const signature = parseSignature(commandClass.command)\n\n const paths: string[][] = [entry.name.split(' ')]\n if (commandClass.aliases) {\n for (const alias of commandClass.aliases) {\n paths.push(alias.split(' '))\n }\n }\n\n // Allow bare `npx quarry` (no arguments) to invoke the help command\n if (entry.name === 'help') {\n paths.push([])\n }\n\n class DynCmd extends Command {\n static override paths = paths\n static override usage: Usage | undefined = commandClass.description\n ? Command.Usage({ description: commandClass.description })\n : undefined\n\n async execute(): Promise<number> {\n const input: Record<string, unknown> = {}\n\n for (const arg of signature.arguments) {\n const value = (this as Record<string, unknown>)[arg.name]\n if (value !== undefined) input[arg.name] = value\n }\n\n for (const opt of signature.options) {\n const value = (this as Record<string, unknown>)[opt.name]\n if (value !== undefined) input[opt.name] = value\n }\n\n // Output and errors stream live via the command's helpers\n // (Command.emit/emitError) and via quarry.call on failure, so there is\n // nothing to flush here — just return the exit code.\n const result = await app.handleCommand(entry.name, input)\n return result.exitCode\n }\n }\n\n // Define Clipanion options/arguments as class property defaults\n const proto = DynCmd.prototype as unknown as Record<string, unknown>\n for (const arg of signature.arguments) {\n if (arg.isArray) {\n proto[arg.name] = Option.Rest({ name: arg.name, required: arg.required ? 1 : 0 })\n } else {\n proto[arg.name] = Option.String({ name: arg.name, required: arg.required })\n }\n }\n\n for (const opt of signature.options) {\n const optName = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`\n const optDescParts: string[] = []\n if (opt.description) optDescParts.push(opt.description)\n if (opt.default !== undefined) optDescParts.push(`(default: ${opt.default})`)\n const optDesc = optDescParts.length > 0 ? optDescParts.join(' ') : undefined\n\n if (opt.isFlag) {\n proto[opt.name] = Option.Boolean(optName, { description: optDesc })\n } else if (opt.isArray) {\n if (opt.default !== undefined) {\n proto[opt.name] = Option.Array(optName, [opt.default], { description: optDesc })\n } else {\n proto[opt.name] = Option.Array(optName, { description: optDesc })\n }\n } else {\n if (opt.default !== undefined) {\n proto[opt.name] = Option.String(optName, opt.default, { description: optDesc })\n } else {\n proto[opt.name] = Option.String(optName, { description: optDesc })\n }\n }\n }\n\n commands.push(DynCmd)\n }\n\n return commands\n}\n","/**\n * Remove `modulesRules` from a sourceless quarry worker's Miniflare options,\n * returning whether anything was removed.\n *\n * `modulesRules` tells Miniflare how to interpret files it pulls off disk when\n * it assembles a worker's module graph (`.sql` as Text, `.wasm` as CompiledWasm,\n * and so on). The quarry CLI host has no module graph: it runs an\n * empty script (`script: ''`) purely to own a worker's bindings for command code\n * executing in Node, so no file is ever matched against a rule and the option\n * cannot change how this host behaves.\n *\n * It has to be dropped rather than passed through. Miniflare 5 replaced the flat\n * v4 worker shape with a `workers` array, and its `convertV4MiniflareOptions()`\n * bridge refuses any input carrying `modulesRules` — it has no v5 equivalent to\n * map onto, so converting would silently lose behaviour and it throws instead.\n * Wrangler's `unstable_getMiniflareWorkerOptions()` always emits the key\n * (`config.rules` concatenated with its own defaults, so never empty), which\n * means every quarry boot on wrangler ≥4.124 hits that guard and dies before the\n * command runs.\n *\n * Dropping it is only sound *because* the host is sourceless — a worker that\n * actually loads modules would need these rules honoured, not discarded.\n */\nexport function stripModuleRules(workerOptions: Record<string, unknown>): boolean {\n if (workerOptions.modulesRules === undefined) return false\n delete workerOptions.modulesRules\n return true\n}\n","import { existsSync } from 'node:fs'\nimport { dirname, join, parse, resolve } from 'node:path'\n\nconst LOCKFILES = [\n 'yarn.lock',\n 'package-lock.json',\n 'pnpm-lock.yaml',\n 'bun.lock',\n 'bun.lockb',\n]\n\n/**\n * Walk up from `startDir` to the project root.\n *\n * The root is the nearest ancestor containing a package-manager lockfile —\n * lockfiles exist only at install roots, so the marker is immune to nested\n * workspace `package.json`s and to stray `.git` directories tools sometimes\n * leave behind. When no lockfile exists (e.g. a project before its first\n * install), the outermost ancestor containing a `package.json` is used —\n * every project has one, monorepo or not, git or not.\n *\n * Returns `undefined` when neither marker is found.\n */\nexport function findProjectRoot(startDir: string): string | undefined {\n // A relative `startDir` would never equal its parsed root (`''`) — `dirname`\n // converges to `'.'` and the walk never terminates. Resolve up front so the\n // traversal (and the returned path) is always absolute.\n let dir = resolve(startDir)\n const { root } = parse(dir)\n let outermostPackageJson: string | undefined\n while (true) {\n if (LOCKFILES.some(lockfile => existsSync(join(dir, lockfile)))) return dir\n if (existsSync(join(dir, 'package.json'))) outermostPackageJson = dir\n if (dir === root) return outermostPackageJson\n dir = dirname(dir)\n }\n}\n\nexport interface DevRegistryEnv {\n MINIFLARE_REGISTRY_PATH?: string\n WRANGLER_REGISTRY_PATH?: string\n}\n\n/**\n * Resolve the Miniflare dev-registry path for a quarry run.\n *\n * Precedence:\n * 1. an explicit `MINIFLARE_REGISTRY_PATH` (the variable Miniflare actually\n * reads) or `WRANGLER_REGISTRY_PATH` (the variable `wrangler dev` reads —\n * honoured here too so one override redirects every tool the same way)\n * 2. `<projectRoot>/.wrangler/registry` (see `findProjectRoot`) — so every\n * process in a checkout (dev servers, quarry CLI runs) deterministically\n * shares one registry, and parallel checkouts (git worktrees) each get\n * their own.\n *\n * The global `~/.wrangler/registry` is deliberately never used: a registry\n * shared across checkouts lets identically-named workers from parallel dev\n * environments overwrite each other and breaks service-binding resolution.\n */\nexport function resolveDevRegistryPath(env: DevRegistryEnv, cwd: string): string {\n const explicit = env.MINIFLARE_REGISTRY_PATH ?? env.WRANGLER_REGISTRY_PATH\n if (explicit) return explicit\n return join(findProjectRoot(cwd) ?? cwd, '.wrangler', 'registry')\n}\n","/**\n * Remove Workflow bindings from a sourceless quarry worker's Miniflare options,\n * returning the names removed so the caller can surface them.\n *\n * The quarry CLI worker runs an empty script (`script: ''`): it exists to host a\n * worker's bindings for command code running in Node, but defines no worker\n * module. A Workflow's engine binds to the `class_name` entrypoint of the worker\n * that declares it (Miniflare wires `USER_WORKFLOW` as a service binding to\n * `core:user:<scriptName>`, validated at boot), and an empty script exposes no\n * such entrypoint — so the runtime refuses to start.\n *\n * Redirecting the binding cross-script to the defining worker does not help in\n * local development: the quarry host boots its own Miniflare instance *before*\n * that worker exists (a worker's `dev` script boots the quarry host, then spawns\n * the worker), so the cross-script service is undefined at boot. Workflows also\n * cannot be remote bindings. A sourceless host therefore cannot run or reach a\n * Workflow; the binding is dropped here. Triggering a Workflow must happen from\n * the worker that defines it (e.g. an HTTP/queue handler), not the CLI host.\n */\nexport function stripWorkflowBindings(workerOptions: Record<string, unknown>): string[] {\n const workflows = workerOptions.workflows as Record<string, unknown> | undefined\n if (!workflows) return []\n const names = Object.keys(workflows)\n delete workerOptions.workflows\n return names\n}\n","import type { MiniflareOptions, V4MiniflareOptions } from 'miniflare';\nimport { existsSync } from 'node:fs';\nimport { createRequire, register } from 'node:module';\nimport { dirname, join, resolve } from 'node:path';\nimport { URL, pathToFileURL } from 'node:url';\nimport type { QuarryRegistry } from 'stratal/quarry';\nimport { type Application } from '../application';\nimport { extractEnvFlag } from './argv';\nimport { createDynamicCommands } from './commands/dynamic-command';\nimport { stripModuleRules } from './module-rules';\nimport { resolveDevRegistryPath } from './registry';\nimport { stripWorkflowBindings } from './workflow-bindings';\n\ninterface WranglerConfig {\n name?: string\n vars?: Record<string, unknown>\n}\n\ninterface MiniflareWorkerResult {\n workerOptions: Record<string, unknown>\n}\n\ninterface RemoteProxySessionData {\n session: {\n ready: Promise<unknown>\n dispose: () => Promise<void>\n remoteProxyConnectionString: unknown\n }\n remoteBindings: Record<string, unknown>\n}\n\ninterface WranglerModule {\n unstable_readConfig: (args: { config?: string; env?: string }) => WranglerConfig\n unstable_getMiniflareWorkerOptions: (config: WranglerConfig, env?: string, options?: { remoteProxyConnectionString?: unknown }) => MiniflareWorkerResult\n unstable_getVarsForDev: (configPath: string | undefined, envFiles: undefined, vars: unknown, env: string | undefined) => Record<string, { value: string }>\n maybeStartOrUpdateRemoteProxySession: (config: { path: string; environment?: string }) => Promise<RemoteProxySessionData | null>\n}\n\ninterface MiniflareModule {\n Miniflare: new (opts: MiniflareOptions) => { ready: Promise<URL>; getBindings: (name?: string) => Promise<Record<string, unknown>>; dispose: () => Promise<void> }\n // Miniflare 5 takes a `workers` array; wrangler's `unstable_getMiniflareWorkerOptions`\n // still returns the flat v4 shape, so this converter is the supported bridge\n // between them — see the `new Miniflare(...)` call below.\n convertV4MiniflareOptions: (opts: V4MiniflareOptions) => MiniflareOptions\n}\n\nconst require = createRequire(import.meta.url)\n\n// Register @swc-node/register for TypeScript + decorator support\nconst swcRegisterPath = join(dirname(require.resolve('@swc-node/register')), 'esm/esm.mjs')\nregister(pathToFileURL(swcRegisterPath), pathToFileURL('./'))\n\n// Register cloudflare:workers virtual module loader\nregister(new URL('./cloudflare-workers-loader.mjs', import.meta.url), pathToFileURL('./'))\n\nconst DEFAULT_ENTRY = './src/quarry.ts'\n\nlet environment: string | undefined\ntry {\n const parsed = extractEnvFlag(process.argv.slice(2))\n environment = parsed.env\n process.argv.splice(2, process.argv.length - 2, ...parsed.rest)\n} catch (e) {\n console.error(`Error: ${(e as Error).message}`)\n process.exit(1)\n}\n\n// Determine entry file: if first arg looks like a file path, use it; otherwise use default\nconst firstArg = process.argv[2]\nlet entryFile = DEFAULT_ENTRY\n\nif (firstArg && (firstArg.includes('/') || firstArg.includes('\\\\') || /\\.(ts|js|mts|mjs)$/.test(firstArg))) {\n entryFile = firstArg\n // Remove the entry file from argv so Clipanion sees: [node, script, command, ...options]\n process.argv.splice(2, 1)\n}\n\n// Resolve and validate the entry file\nconst entryPath = resolve(process.cwd(), entryFile)\n\nif (!existsSync(entryPath)) {\n console.error(`Error: Entry file not found: ${entryFile}`)\n console.error('')\n console.error('Create src/quarry.ts that exports `QuarryRunner.run({ module, seeders })`, or specify a custom path:')\n console.error(' npx quarry ./path/to/entry.ts <command> [options]')\n process.exit(1)\n}\n\nasync function main(): Promise<void> {\n const cwdRequire = createRequire(join(process.cwd(), 'package.json'))\n\n const { unstable_readConfig: readConfig, unstable_getMiniflareWorkerOptions: getMiniflareWorkerOptions, unstable_getVarsForDev: getVarsForDev, maybeStartOrUpdateRemoteProxySession } = await import(cwdRequire.resolve('wrangler')) as WranglerModule\n const { Miniflare, convertV4MiniflareOptions } = await import(cwdRequire.resolve('miniflare')) as MiniflareModule\n\n const candidates = ['wrangler.jsonc', 'wrangler.json', 'wrangler.toml']\n const configName = candidates.find(c => existsSync(resolve(process.cwd(), c)))\n const configPath = configName ? resolve(process.cwd(), configName) : undefined\n\n // Load .env into process.env before building Miniflare options, mirroring\n // `wrangler dev`'s precedence: base `.env`, then `.env.local`, then the\n // env-specific `.env.<environment>` and `.env.<environment>.local` (later\n // load wins).\n const envFiles = [\n '.env',\n '.env.local',\n environment ? `.env.${environment}` : null,\n environment ? `.env.${environment}.local` : null,\n ]\n for (const envFile of envFiles) {\n if (!envFile) continue\n const envPath = resolve(process.cwd(), envFile)\n if (existsSync(envPath)) process.loadEnvFile(envPath)\n }\n\n // Deterministically resolve the dev service registry from the project root\n // (`<projectRoot>/.wrangler/registry`) so a bare `quarry` invocation shares\n // the SAME project-local registry every other process in this checkout uses —\n // never the global `~/.wrangler/registry`, where parallel checkouts'\n // identically-named workers would overwrite each other and break cross-worker\n // service-binding resolution. An explicit `WRANGLER_REGISTRY_PATH` /\n // `MINIFLARE_REGISTRY_PATH` (from the shell or the `.env` files above) wins.\n //\n // Exported as `MINIFLARE_REGISTRY_PATH` — the variable Miniflare's\n // `getDefaultDevRegistryPath()` reads at call time — so any child process a\n // command spawns (notably the vite dev server launched by `inertia:dev`,\n // whose `@cloudflare/vite-plugin` resolves its registry the same way) lands\n // in the identical registry.\n const registryPath = resolveDevRegistryPath({\n MINIFLARE_REGISTRY_PATH: process.env.MINIFLARE_REGISTRY_PATH,\n WRANGLER_REGISTRY_PATH: process.env.WRANGLER_REGISTRY_PATH,\n }, process.cwd())\n process.env.MINIFLARE_REGISTRY_PATH = registryPath\n\n const config = readConfig({ config: configPath, env: environment })\n\n // Honor `remote: true` bindings (wrangler remote bindings): start a proxy\n // session against the deployed Cloudflare resources and thread its\n // connection string into the Miniflare worker options, so e.g. a service\n // binding marked remote calls the deployed worker instead of the local dev\n // registry. Returns null when the resolved config declares no remote\n // bindings — plain local runs are untouched. Requires wrangler credentials\n // (`wrangler login` / CLOUDFLARE_API_TOKEN) when a session does start.\n const remoteProxy = configPath\n ? await maybeStartOrUpdateRemoteProxySession({ path: configPath, environment })\n : null\n if (remoteProxy) {\n await remoteProxy.session.ready\n const remoteNames = Object.keys(remoteProxy.remoteBindings)\n console.log(`Remote bindings: proxying ${remoteNames.length} binding(s) to deployed resources (${remoteNames.join(', ')})`)\n }\n\n const { workerOptions } = getMiniflareWorkerOptions(config, environment, {\n remoteProxyConnectionString: remoteProxy?.session.remoteProxyConnectionString,\n })\n\n // Always source `process.env` into the worker vars/secrets — quarry is a CLI/CI tool, so config passed\n // through the environment must resolve like any other binding. `getVarsForDev` (and the vite build\n // quarry spawns for `inertia:build`, which inherits this process env) only merges `process.env` when\n // `CLOUDFLARE_INCLUDE_PROCESS_ENV` is set, and it defaults OFF — and only when no `.dev.vars` shadows\n // it, so local runs (which have a `.dev.vars`) are unchanged while CI runs (no `.dev.vars`) resolve\n // env-provided config instead of failing validation on a missing binding.\n process.env.CLOUDFLARE_INCLUDE_PROCESS_ENV = 'true'\n const vars = getVarsForDev(configPath, undefined, config.vars, environment)\n const varsRecord: Record<string, string> = {}\n for (const [key, binding] of Object.entries(vars)) {\n varsRecord[key] = binding.value\n }\n\n const existingBindings = workerOptions.bindings as Record<string, unknown> ?? {}\n workerOptions.bindings = {\n ...existingBindings,\n ...varsRecord,\n QUEUE_PROVIDER: 'sync',\n }\n\n // The quarry worker runs an empty script (see the Miniflare options below), so it can't own\n // a Workflow entrypoint, and a sourceless CLI host can't reach a Workflow\n // defined in another worker either (it boots before that worker exists, and\n // Workflows can't be remote bindings). Drop the Workflow bindings so Miniflare\n // doesn't stand up an engine demanding an entrypoint this host can't provide —\n // see stripWorkflowBindings. Surfaced (not silent) so a command that expects\n // one sees why it's absent; triggering must happen from the defining worker.\n const strippedWorkflows = stripWorkflowBindings(workerOptions)\n if (strippedWorkflows.length > 0) {\n console.log(`Workflow binding(s) unavailable to CLI commands (defined on the worker, not this host): ${strippedWorkflows.join(', ')}`)\n }\n\n // Rename so quarry doesn't overwrite a running `wrangler dev` session's\n // dev-registry entry. The registry is how Miniflare discovers peer workers\n // for service binding resolution — a collision would break the running session.\n const workerName = config.name ? `quarry-${config.name}-${process.pid}` : `quarry-${process.pid}`\n workerOptions.name = workerName\n\n // Wrangler always emits `modulesRules`, and the v4→v5 converter below rejects\n // any input carrying it. A sourceless host loads no modules, so the rules can\n // never apply here — see stripModuleRules.\n stripModuleRules(workerOptions)\n\n // Miniflare 5 dropped the flat `script`/`modules` options for a `workers`\n // array, but wrangler still hands back v4-shaped worker options, so the\n // options are built in the v4 shape and converted. Miniflare owns that\n // mapping; hand-rolling it here would drift from whatever wrangler emits.\n const mf = new Miniflare(convertV4MiniflareOptions({\n ...workerOptions,\n script: '',\n modules: true,\n unsafeDevRegistryPath: registryPath,\n // Persist every durable plugin (KV, D1, R2, Durable Objects, cache) under\n // the same root `wrangler dev` uses, so state survives across `quarry`\n // invocations and is shared with a running `wrangler dev` session. Layout is\n // `<root>/<plugin>`, unchanged from v4.\n //\n // Deliberately the v5 key in an otherwise v4-shaped object: the converter\n // maps the worker options SHAPE, not option names, and `defaultPersistRoot`\n // no longer exists anywhere in Miniflare 5 — its v4-compatibility input\n // already spells this `resourcePersistencePath`. The v4 name is accepted and\n // then ignored, which would leave no persistence path at all and silently\n // discard local state between runs.\n resourcePersistencePath: join(process.cwd(), '.wrangler/state/v3'),\n }))\n\n await mf.ready\n const env = await mf.getBindings()\n\n const pendingPromises: Promise<unknown>[] = []\n const trackedWaitUntil = (promise: Promise<unknown>) => {\n pendingPromises.push(promise)\n }\n\n let app: Application | undefined\n try {\n (globalThis as Record<string, unknown>).__stratalPlatformProxy = {\n env,\n waitUntil: trackedWaitUntil,\n }\n\n await import(pathToFileURL(entryPath).href)\n\n const [\n { Stratal },\n { DI_TOKENS },\n { parseSignature },\n ] = await Promise.all([\n import('stratal'),\n import('stratal/di'),\n import('stratal/quarry'),\n ])\n\n app = await Stratal.resolveApplication()\n const quarry = app.container.resolve<QuarryRegistry>(DI_TOKENS.Quarry)\n\n const { Cli } = await import('clipanion')\n const pkg = require('../../package.json') as { version: string }\n\n const cli = new Cli({\n binaryName: 'quarry',\n binaryLabel: 'Quarry CLI',\n binaryVersion: pkg.version,\n })\n\n for (const cmd of createDynamicCommands(quarry, parseSignature, app)) {\n cli.register(cmd)\n }\n\n await cli.runExit(process.argv.slice(2), { ...Cli.defaultContext })\n } finally {\n await Promise.allSettled(pendingPromises)\n await app?.shutdown()\n await mf.dispose()\n await remoteProxy?.session.dispose()\n }\n}\n\nmain().catch(async (error: unknown) => {\n const { ConfigValidationError } = await import('stratal/config')\n\n const message = error instanceof Error ? error.message : String(error)\n console.error('Fatal error:', message)\n if (error instanceof ConfigValidationError) {\n console.error(error.errors.message)\n }\n process.exit(1)\n})\n"],"mappings":"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"}
@@ -1,9 +1,8 @@
1
- import { Ir as ApplicationError } from "../index-uybm0bhQ.mjs";
2
- import { t as CacheService } from "../cache.service-uElmBtdS.mjs";
3
- import { t as TieredCacheService } from "../tiered-cache.service-Dv3BhxxE.mjs";
4
-
1
+ import { li as ApplicationError } from "../index-B2WtEagR.mjs";
2
+ import { t as CacheService } from "../cache.service-Dg0Hj0gp.mjs";
3
+ import { t as TieredCacheService } from "../tiered-cache.service-Bz8bbvyb.mjs";
5
4
  //#region src/cache/cache.error.d.ts
6
- declare class CacheError extends ApplicationError {}
5
+ export declare class CacheError extends ApplicationError {}
7
6
  //#endregion
8
7
  //#region src/cache/cache.module.d.ts
9
8
  /**
@@ -17,14 +16,14 @@ declare class CacheError extends ApplicationError {}
17
16
  * - Automatic error handling with security-focused logging
18
17
  * - Singleton service for optimal performance
19
18
  */
20
- declare class CacheModule {}
19
+ export declare class CacheModule {}
21
20
  //#endregion
22
21
  //#region src/cache/cache.tokens.d.ts
23
- declare const CACHE_TOKENS: {
22
+ export declare const CACHE_TOKENS: {
24
23
  readonly CacheService: symbol;
25
24
  readonly TieredCacheService: symbol;
26
25
  };
27
- type CacheToken = (typeof CACHE_TOKENS)[keyof typeof CACHE_TOKENS];
26
+ export type CacheToken = (typeof CACHE_TOKENS)[keyof typeof CACHE_TOKENS];
28
27
  //#endregion
29
- export { CACHE_TOKENS, CacheError, CacheModule, CacheService, CacheToken, TieredCacheService };
28
+ export { CacheService, TieredCacheService };
30
29
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/cache/cache.error.ts","../../src/cache/cache.module.ts","../../src/cache/cache.tokens.ts"],"mappings":";;;;;cAEa,UAAA,SAAmB,gBAAgB;;;;;;;;AAAhD;;;;AAAgD;;cCsBnC,WAAA;;;cCxBA,YAAA;EAAA,SAGH,YAAA;EAAA,SAAA,kBAAA;AAAA;AAAA,KAEE,UAAA,WAAqB,YAAA,eAA2B,YAAY"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/cache/cache.error.ts","../../src/cache/cache.module.ts","../../src/cache/cache.tokens.ts"],"mappings":";;;;qBAEa,mBAAmB;;;;;;;;;;;;;;qBCsBnB;;;qBCxBA;WACX;WACA;;YAGU,qBAAqB,2BAA2B"}