stratal 0.0.21 → 0.0.23
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.
- package/README.md +2 -2
- package/dist/bin/cloudflare-workers-loader.mjs +80 -7
- package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
- package/dist/bin/quarry.mjs +84 -160
- package/dist/bin/quarry.mjs.map +1 -1
- package/dist/cache/index.d.mts +8 -46
- package/dist/cache/index.d.mts.map +1 -1
- package/dist/cache/index.mjs +134 -97
- package/dist/cache/index.mjs.map +1 -1
- package/dist/{cache.service-DsnKuNyO.d.mts → cache.service-uElmBtdS.d.mts} +29 -39
- package/dist/cache.service-uElmBtdS.d.mts.map +1 -0
- package/dist/{command-BgSlsS4M.mjs → command-BvmUAPPQ.mjs} +15 -4
- package/dist/command-BvmUAPPQ.mjs.map +1 -0
- package/dist/{command-Cmmf0oHX.d.mts → command-CPhFHjG3.d.mts} +3 -2
- package/dist/command-CPhFHjG3.d.mts.map +1 -0
- package/dist/command-not-found.error-ONAZ2Bpk.mjs +14 -0
- package/dist/command-not-found.error-ONAZ2Bpk.mjs.map +1 -0
- package/dist/config/index.d.mts +24 -11
- package/dist/config/index.d.mts.map +1 -1
- package/dist/config/index.mjs +32 -57
- package/dist/config/index.mjs.map +1 -1
- package/dist/{consumer-registry-B7yUNh0q.d.mts → consumer-registry-D3iMTSdy.d.mts} +54 -22
- package/dist/consumer-registry-D3iMTSdy.d.mts.map +1 -0
- package/dist/container-storage-BmOJ4_Na.mjs +52 -0
- package/dist/container-storage-BmOJ4_Na.mjs.map +1 -0
- package/dist/{controller.decorator-B9vwn0zK.mjs → controller.decorator-C5UVeJS3.mjs} +8 -8
- package/dist/controller.decorator-C5UVeJS3.mjs.map +1 -0
- package/dist/cron/index.d.mts +103 -7
- package/dist/cron/index.d.mts.map +1 -1
- package/dist/cron/index.mjs +2 -2
- package/dist/cron-job-NesZRk8F.d.mts +58 -0
- package/dist/cron-job-NesZRk8F.d.mts.map +1 -0
- package/dist/{cron-manager-DQSK8uoV.mjs → cron.module-Bgzq5hiT.mjs} +47 -17
- package/dist/cron.module-Bgzq5hiT.mjs.map +1 -0
- package/dist/decorate-CuAoSZvs.mjs +16 -0
- package/dist/deep-merge-ByiAOZ3r.mjs +18 -0
- package/dist/deep-merge-ByiAOZ3r.mjs.map +1 -0
- package/dist/di/index.d.mts +2 -2
- package/dist/di/index.mjs +4 -3
- package/dist/di-DseMn-z9.mjs +524 -0
- package/dist/di-DseMn-z9.mjs.map +1 -0
- package/dist/email/index.d.mts +40 -122
- package/dist/email/index.d.mts.map +1 -1
- package/dist/email/index.mjs +446 -131
- package/dist/email/index.mjs.map +1 -1
- package/dist/en-CDZBMcc1.mjs +202 -0
- package/dist/en-CDZBMcc1.mjs.map +1 -0
- package/dist/{env-D1rcZ8_r.d.mts → env-ug22bJj7.d.mts} +1 -1
- package/dist/env-ug22bJj7.d.mts.map +1 -0
- package/dist/errors/index.d.mts +2 -2
- package/dist/errors/index.mjs +4 -2
- package/dist/errors-mXYxG0XB.mjs +333 -0
- package/dist/errors-mXYxG0XB.mjs.map +1 -0
- package/dist/events/index.d.mts +14 -3
- package/dist/events/index.d.mts.map +1 -1
- package/dist/events/index.mjs +2 -2
- package/dist/{events-CzCV8jI8.mjs → events-BXJGZjpG.mjs} +23 -13
- package/dist/events-BXJGZjpG.mjs.map +1 -0
- package/dist/exception-context-kEoMFwze.mjs +429 -0
- package/dist/exception-context-kEoMFwze.mjs.map +1 -0
- package/dist/{gateway-context-CXmXtaUP.mjs → gateway-context-TMu_AlJt.mjs} +38 -31
- package/dist/gateway-context-TMu_AlJt.mjs.map +1 -0
- package/dist/guards/index.d.mts +3 -3
- package/dist/guards/index.d.mts.map +1 -1
- package/dist/guards/index.mjs +1 -1
- package/dist/{guards-DU1_J9YA.mjs → guards-DALPXy3_.mjs} +6 -5
- package/dist/guards-DALPXy3_.mjs.map +1 -0
- package/dist/hono-app-CvV3hOfT.mjs +161 -0
- package/dist/hono-app-CvV3hOfT.mjs.map +1 -0
- package/dist/{http-method.decorator-BrgHMdLQ.mjs → http-method.decorator-ByWZb9DO.mjs} +7 -6
- package/dist/http-method.decorator-ByWZb9DO.mjs.map +1 -0
- package/dist/i18n/index.d.mts +238 -3
- package/dist/i18n/index.d.mts.map +1 -0
- package/dist/i18n/index.mjs +39 -3
- package/dist/i18n/index.mjs.map +1 -0
- package/dist/i18n/messages/en/index.d.mts +2 -2
- package/dist/i18n/messages/en/index.mjs +2 -2
- package/dist/i18n/utils/index.d.mts +4 -26
- package/dist/i18n/utils/index.d.mts.map +1 -1
- package/dist/i18n/utils/index.mjs +2 -2
- package/dist/i18n/validation/index.d.mts +3 -2
- package/dist/i18n/validation/index.mjs +4 -2
- package/dist/i18n.module-DRQAZoSZ.mjs +222 -0
- package/dist/i18n.module-DRQAZoSZ.mjs.map +1 -0
- package/dist/i18n.tokens-CZ_v8oyS.mjs +19 -0
- package/dist/i18n.tokens-CZ_v8oyS.mjs.map +1 -0
- package/dist/{index-7-hU3GTV.d.mts → index-0ItCjaqw.d.mts} +1 -1
- package/dist/index-0ItCjaqw.d.mts.map +1 -0
- package/dist/index-B5JBRcWD.d.mts +544 -0
- package/dist/index-B5JBRcWD.d.mts.map +1 -0
- package/dist/index-BUt92sAE.d.mts +124 -0
- package/dist/index-BUt92sAE.d.mts.map +1 -0
- package/dist/{index-ByOyTmqf.d.mts → index-B_JoEl3V.d.mts} +751 -2229
- package/dist/index-B_JoEl3V.d.mts.map +1 -0
- package/dist/index-DtBNIFuP.d.mts +42 -0
- package/dist/index-DtBNIFuP.d.mts.map +1 -0
- package/dist/{index-C1KvMncZ.d.mts → index-HgOLNruQ.d.mts} +3 -108
- package/dist/index-HgOLNruQ.d.mts.map +1 -0
- package/dist/index.d.mts +6 -43
- package/dist/index.mjs +3 -2
- package/dist/{is-command-C6a7WTPw.mjs → is-command-CEPO9n8c.mjs} +2 -2
- package/dist/{is-command-C6a7WTPw.mjs.map → is-command-CEPO9n8c.mjs.map} +1 -1
- package/dist/{is-seeder-CebjZCDn.mjs → is-seeder-Gvh_AM71.mjs} +1 -1
- package/dist/{is-seeder-CebjZCDn.mjs.map → is-seeder-Gvh_AM71.mjs.map} +1 -1
- package/dist/lazy-module-loader-Ib383jH_.d.mts +60 -0
- package/dist/lazy-module-loader-Ib383jH_.d.mts.map +1 -0
- package/dist/locale-path.service-D-dHiIPc.mjs +165 -0
- package/dist/locale-path.service-D-dHiIPc.mjs.map +1 -0
- package/dist/locale-url-nZrZxqJP.mjs +44 -0
- package/dist/locale-url-nZrZxqJP.mjs.map +1 -0
- package/dist/locale-url.service-C2EWmGdq.mjs +41 -0
- package/dist/locale-url.service-C2EWmGdq.mjs.map +1 -0
- package/dist/logger/index.d.mts +2 -2
- package/dist/logger/index.mjs +170 -2
- package/dist/logger/index.mjs.map +1 -0
- package/dist/macroable/index.d.mts +2 -2
- package/dist/macroable/index.mjs +1 -1
- package/dist/{macroable-BmufBshB.mjs → macroable-cvDTFZ_A.mjs} +1 -1
- package/dist/{macroable-BmufBshB.mjs.map → macroable-cvDTFZ_A.mjs.map} +1 -1
- package/dist/metadata-DzzprcID.mjs +39 -0
- package/dist/metadata-DzzprcID.mjs.map +1 -0
- package/dist/module/index.d.mts +7 -24
- package/dist/module/index.d.mts.map +1 -1
- package/dist/module/index.mjs +10 -2
- package/dist/module/index.mjs.map +1 -0
- package/dist/module-registry-Dm-pqHd3.mjs +554 -0
- package/dist/module-registry-Dm-pqHd3.mjs.map +1 -0
- package/dist/module.decorator-CYHY6pG5.mjs +19 -0
- package/dist/module.decorator-CYHY6pG5.mjs.map +1 -0
- package/dist/openapi/index.d.mts +44 -8
- package/dist/openapi/index.d.mts.map +1 -1
- package/dist/openapi/index.mjs +3 -3
- package/dist/openapi-CstuTM8S.mjs +309 -0
- package/dist/openapi-CstuTM8S.mjs.map +1 -0
- package/dist/{openapi-tools.service-Zs-Ewv7F.mjs → openapi-tools.service-BC5EC3R3.mjs} +8 -2
- package/dist/openapi-tools.service-BC5EC3R3.mjs.map +1 -0
- package/dist/{openapi.service-Bt9bCIrd.d.mts → openapi.service-YhTiJ1bO.d.mts} +3 -3
- package/dist/openapi.service-YhTiJ1bO.d.mts.map +1 -0
- package/dist/quarry/index.d.mts +14 -163
- package/dist/quarry/index.d.mts.map +1 -1
- package/dist/quarry/index.mjs +6 -5
- package/dist/quarry/runner.d.mts +184 -0
- package/dist/quarry/runner.d.mts.map +1 -0
- package/dist/quarry/runner.mjs +945 -0
- package/dist/quarry/runner.mjs.map +1 -0
- package/dist/quarry-registry-CXg0RFXq.d.mts +69 -0
- package/dist/quarry-registry-CXg0RFXq.d.mts.map +1 -0
- package/dist/quarry.module-BuRPGMDm.mjs +312 -0
- package/dist/quarry.module-BuRPGMDm.mjs.map +1 -0
- package/dist/queue/index.d.mts +3 -3
- package/dist/queue/index.mjs +57 -48
- package/dist/queue/index.mjs.map +1 -1
- package/dist/queue.module-nddvxzCB.mjs +613 -0
- package/dist/queue.module-nddvxzCB.mjs.map +1 -0
- package/dist/queue.tokens-DjHnFmre.mjs +11 -0
- package/dist/queue.tokens-DjHnFmre.mjs.map +1 -0
- package/dist/{r2-storage.provider-DuonKeYm.mjs → r2-storage.provider-DCxQt9dD.mjs} +6 -6
- package/dist/r2-storage.provider-DCxQt9dD.mjs.map +1 -0
- package/dist/{rate-limit.decorator-6qzNcSOt.mjs → rate-limit.decorator-BPAie_p3.mjs} +6 -11
- package/dist/rate-limit.decorator-BPAie_p3.mjs.map +1 -0
- package/dist/rate-limiter/index.d.mts +11 -50
- package/dist/rate-limiter/index.d.mts.map +1 -1
- package/dist/rate-limiter/index.mjs +33 -42
- package/dist/rate-limiter/index.mjs.map +1 -1
- package/dist/route-name-DGoBOfPg.mjs +171 -0
- package/dist/route-name-DGoBOfPg.mjs.map +1 -0
- package/dist/route-registration.service-D6vSwiKP.mjs +918 -0
- package/dist/route-registration.service-D6vSwiKP.mjs.map +1 -0
- package/dist/route-registry-CYqLp2Nj.mjs +123 -0
- package/dist/route-registry-CYqLp2Nj.mjs.map +1 -0
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.mjs +18 -7
- package/dist/router-CWGBD-Bg.mjs +78 -0
- package/dist/router-CWGBD-Bg.mjs.map +1 -0
- package/dist/router-resolver-D4YlPNlm.mjs +88 -0
- package/dist/router-resolver-D4YlPNlm.mjs.map +1 -0
- package/dist/seeder/index.d.mts +16 -11
- package/dist/seeder/index.d.mts.map +1 -1
- package/dist/seeder/index.mjs +5 -3
- package/dist/seeder-7ubkms-Y.mjs +81 -0
- package/dist/seeder-7ubkms-Y.mjs.map +1 -0
- package/dist/seeder-registry-CyUmKsJq.mjs +57 -0
- package/dist/seeder-registry-CyUmKsJq.mjs.map +1 -0
- package/dist/seeder.module-CYYwk3Qk.mjs +15 -0
- package/dist/seeder.module-CYYwk3Qk.mjs.map +1 -0
- package/dist/{signed-url-BQPbv2In.mjs → signed-url-DIU0sK_6.mjs} +1 -1
- package/dist/{signed-url-BQPbv2In.mjs.map → signed-url-DIU0sK_6.mjs.map} +1 -1
- package/dist/storage/index.d.mts +15 -39
- package/dist/storage/index.d.mts.map +1 -1
- package/dist/storage/index.mjs +3 -3
- package/dist/storage/providers/index.d.mts +2 -2
- package/dist/storage/providers/index.d.mts.map +1 -1
- package/dist/storage/providers/index.mjs +1 -1
- package/dist/{storage-D8CBP72Z.mjs → storage-MDZypIE9.mjs} +66 -59
- package/dist/storage-MDZypIE9.mjs.map +1 -0
- package/dist/{storage-provider.interface-Bd6vA4ak.d.mts → storage-provider.interface-ClUwxz4S.d.mts} +2 -3
- package/dist/storage-provider.interface-ClUwxz4S.d.mts.map +1 -0
- package/dist/storage.error-Dnib4VHc.mjs +8 -0
- package/dist/storage.error-Dnib4VHc.mjs.map +1 -0
- package/dist/stratal-DL9M38_s.mjs +383 -0
- package/dist/stratal-DL9M38_s.mjs.map +1 -0
- package/dist/stratal-DwDJPY9N.d.mts +43 -0
- package/dist/stratal-DwDJPY9N.d.mts.map +1 -0
- package/dist/tiered-cache.service-Dv3BhxxE.d.mts +79 -0
- package/dist/tiered-cache.service-Dv3BhxxE.d.mts.map +1 -0
- package/dist/trailing-slash-CFyw8nYu.mjs +34 -0
- package/dist/trailing-slash-CFyw8nYu.mjs.map +1 -0
- package/dist/{types-cySNS_lp.d.mts → types-CmV_9xBD.d.mts} +1 -1
- package/dist/types-CmV_9xBD.d.mts.map +1 -0
- package/dist/uri-h7Q8Jug9.mjs +251 -0
- package/dist/uri-h7Q8Jug9.mjs.map +1 -0
- package/dist/{usage-generator-BUdlhnCK.mjs → usage-generator-DAWYasuP.mjs} +7 -4
- package/dist/usage-generator-DAWYasuP.mjs.map +1 -0
- package/dist/validation-CpOjviyT.mjs +49 -0
- package/dist/validation-CpOjviyT.mjs.map +1 -0
- package/dist/validation.context-CRvmrhq7.mjs +117 -0
- package/dist/validation.context-CRvmrhq7.mjs.map +1 -0
- package/dist/versioning.service-C6aHky8-.mjs +36 -0
- package/dist/versioning.service-C6aHky8-.mjs.map +1 -0
- package/dist/websocket/index.d.mts +16 -14
- package/dist/websocket/index.d.mts.map +1 -1
- package/dist/websocket/index.mjs +2 -2
- package/dist/workers/index.d.mts +2 -2
- package/dist/workers/index.d.mts.map +1 -1
- package/dist/workers/index.mjs +3 -2
- package/dist/workers/index.mjs.map +1 -1
- package/dist/zod-eKqqhZ5_.mjs +72 -0
- package/dist/zod-eKqqhZ5_.mjs.map +1 -0
- package/dist/{index-Bnpfq6uk.d.mts → zod-wecrEVAs.d.mts} +63 -133
- package/dist/zod-wecrEVAs.d.mts.map +1 -0
- package/package.json +28 -39
- package/dist/base-email.provider-CfQCA08m.mjs +0 -42
- package/dist/base-email.provider-CfQCA08m.mjs.map +0 -1
- package/dist/cache.service-DsnKuNyO.d.mts.map +0 -1
- package/dist/cache.tokens-B7Rw1C9Q.mjs +0 -6
- package/dist/cache.tokens-B7Rw1C9Q.mjs.map +0 -1
- package/dist/colors-DJaRDXoS.mjs +0 -16
- package/dist/colors-DJaRDXoS.mjs.map +0 -1
- package/dist/command-BgSlsS4M.mjs.map +0 -1
- package/dist/command-Cmmf0oHX.d.mts.map +0 -1
- package/dist/consumer-registry-B7yUNh0q.d.mts.map +0 -1
- package/dist/controller.decorator-B9vwn0zK.mjs.map +0 -1
- package/dist/cron-manager-CmTimEjf.d.mts +0 -131
- package/dist/cron-manager-CmTimEjf.d.mts.map +0 -1
- package/dist/cron-manager-DQSK8uoV.mjs.map +0 -1
- package/dist/en-DSH_bhh6.mjs +0 -308
- package/dist/en-DSH_bhh6.mjs.map +0 -1
- package/dist/env-D1rcZ8_r.d.mts.map +0 -1
- package/dist/errors-COW9-Mar.mjs +0 -1739
- package/dist/errors-COW9-Mar.mjs.map +0 -1
- package/dist/errors-ORxu1-Bb.mjs +0 -74
- package/dist/errors-ORxu1-Bb.mjs.map +0 -1
- package/dist/events-CzCV8jI8.mjs.map +0 -1
- package/dist/gateway-context-CXmXtaUP.mjs.map +0 -1
- package/dist/guards-DU1_J9YA.mjs.map +0 -1
- package/dist/http-method.decorator-BrgHMdLQ.mjs.map +0 -1
- package/dist/i18n.module-CzXLW9Hy.mjs +0 -2532
- package/dist/i18n.module-CzXLW9Hy.mjs.map +0 -1
- package/dist/index-7-hU3GTV.d.mts.map +0 -1
- package/dist/index-Bnpfq6uk.d.mts.map +0 -1
- package/dist/index-ByOyTmqf.d.mts.map +0 -1
- package/dist/index-C1KvMncZ.d.mts.map +0 -1
- package/dist/index-DBd_2wv8.d.mts +0 -263
- package/dist/index-DBd_2wv8.d.mts.map +0 -1
- package/dist/index-DUzWs0z7.d.mts +0 -494
- package/dist/index-DUzWs0z7.d.mts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/logger-DlV7NtvD.mjs +0 -440
- package/dist/logger-DlV7NtvD.mjs.map +0 -1
- package/dist/module-BzLg57FK.mjs +0 -866
- package/dist/module-BzLg57FK.mjs.map +0 -1
- package/dist/openapi-tools.service-Zs-Ewv7F.mjs.map +0 -1
- package/dist/openapi.service-Bt9bCIrd.d.mts.map +0 -1
- package/dist/quarry-registry-BwY2hOxm.mjs +0 -699
- package/dist/quarry-registry-BwY2hOxm.mjs.map +0 -1
- package/dist/queue.module-BhCjZp6H.mjs +0 -409
- package/dist/queue.module-BhCjZp6H.mjs.map +0 -1
- package/dist/r2-storage.provider-DuonKeYm.mjs.map +0 -1
- package/dist/rate-limit.decorator-6qzNcSOt.mjs.map +0 -1
- package/dist/resend.provider-DB4IlFjG.mjs +0 -68
- package/dist/resend.provider-DB4IlFjG.mjs.map +0 -1
- package/dist/seeder-zoEfEw9i.mjs +0 -138
- package/dist/seeder-zoEfEw9i.mjs.map +0 -1
- package/dist/setup-CefZKV_e.mjs +0 -37
- package/dist/setup-CefZKV_e.mjs.map +0 -1
- package/dist/smtp.provider-B6D7zuWX.mjs +0 -76
- package/dist/smtp.provider-B6D7zuWX.mjs.map +0 -1
- package/dist/storage-D8CBP72Z.mjs.map +0 -1
- package/dist/storage-provider.interface-Bd6vA4ak.d.mts.map +0 -1
- package/dist/stratal-CNwpbSZl.mjs +0 -535
- package/dist/stratal-CNwpbSZl.mjs.map +0 -1
- package/dist/types-cySNS_lp.d.mts.map +0 -1
- package/dist/usage-generator-BUdlhnCK.mjs.map +0 -1
- package/dist/validation-DtJwAv7O.mjs +0 -248
- package/dist/validation-DtJwAv7O.mjs.map +0 -1
- /package/dist/{chunk-D1SwGrFN.mjs → chunk-BBjsoOtd.mjs} +0 -0
package/README.md
CHANGED
|
@@ -20,14 +20,14 @@ Full guides and examples are available at **[stratal.dev](https://stratal.dev)**
|
|
|
20
20
|
|
|
21
21
|
## Features
|
|
22
22
|
|
|
23
|
-
- **Dependency Injection** — Two-tier DI container (global + request-scoped)
|
|
23
|
+
- **Dependency Injection** — Two-tier DI container (global + request-scoped) with built-in decorator support
|
|
24
24
|
- **OpenAPI Documentation** — Define Zod schemas once and get a full OpenAPI 3.0 spec with interactive docs
|
|
25
25
|
- **Modular Architecture** — NestJS-style modules with lifecycle hooks, dynamic configuration, and middleware
|
|
26
26
|
- **Hono Routing** — Convention-based RESTful controllers with automatic HTTP method mapping
|
|
27
27
|
- **Queue Consumers** — Typed Cloudflare Queue consumers with message-type filtering
|
|
28
28
|
- **Cron Jobs** — Scheduled tasks via Cloudflare Workers cron triggers
|
|
29
29
|
- **Storage** — S3-compatible file storage with presigned URLs and TUS upload support
|
|
30
|
-
- **Email** —
|
|
30
|
+
- **Email** — SMTP provider with React Email template support
|
|
31
31
|
- **i18n** — Type-safe internationalization with locale detection from request headers
|
|
32
32
|
- **Guards and Middleware** — Route protection and per-module middleware configuration
|
|
33
33
|
|
|
@@ -3,18 +3,24 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
//#region src/bin/cloudflare-workers-loader.ts
|
|
5
5
|
/**
|
|
6
|
-
* ESM loader hook that provides
|
|
6
|
+
* ESM loader hook that provides virtual modules for Cloudflare-specific imports
|
|
7
7
|
* and handles Vite-style `?raw` imports (returning file contents as a string).
|
|
8
8
|
*
|
|
9
|
-
* When registered via `node --import` or `register()`, this intercepts
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
9
|
+
* When registered via `node --import` or `register()`, this intercepts:
|
|
10
|
+
* - `cloudflare:workers` — virtual env/waitUntil from `globalThis.__stratalPlatformProxy`
|
|
11
|
+
* - `cloudflare:sockets` — Node.js TCP/TLS implementation of the CF connect() API
|
|
12
|
+
* - `?raw` imports — returns file contents as a default string export
|
|
12
13
|
*/
|
|
13
|
-
const
|
|
14
|
+
const VIRTUAL_WORKERS_URL = "cloudflare-workers:virtual";
|
|
15
|
+
const VIRTUAL_SOCKETS_URL = "cloudflare-sockets:virtual";
|
|
14
16
|
const RAW_SUFFIX = "?raw";
|
|
15
17
|
async function resolve(specifier, context, nextResolve) {
|
|
16
18
|
if (specifier === "cloudflare:workers") return {
|
|
17
|
-
url:
|
|
19
|
+
url: VIRTUAL_WORKERS_URL,
|
|
20
|
+
shortCircuit: true
|
|
21
|
+
};
|
|
22
|
+
if (specifier === "cloudflare:sockets") return {
|
|
23
|
+
url: VIRTUAL_SOCKETS_URL,
|
|
18
24
|
shortCircuit: true
|
|
19
25
|
};
|
|
20
26
|
if (specifier.endsWith(RAW_SUFFIX)) return {
|
|
@@ -32,7 +38,7 @@ async function load(url, context, nextLoad) {
|
|
|
32
38
|
source: `export default ${JSON.stringify(content)}`
|
|
33
39
|
};
|
|
34
40
|
}
|
|
35
|
-
if (url ===
|
|
41
|
+
if (url === VIRTUAL_WORKERS_URL) return {
|
|
36
42
|
format: "module",
|
|
37
43
|
shortCircuit: true,
|
|
38
44
|
source: `
|
|
@@ -56,6 +62,73 @@ export const RpcStub = function(value) { return value; };
|
|
|
56
62
|
export function withEnv(newEnv, fn) { return fn(); }
|
|
57
63
|
export function withExports(newExports, fn) { return fn(); }
|
|
58
64
|
export function withEnvAndExports(newEnv, newExports, fn) { return fn(); }
|
|
65
|
+
`
|
|
66
|
+
};
|
|
67
|
+
if (url === VIRTUAL_SOCKETS_URL) return {
|
|
68
|
+
format: "module",
|
|
69
|
+
shortCircuit: true,
|
|
70
|
+
source: `
|
|
71
|
+
import { connect as netConnect } from 'node:net';
|
|
72
|
+
import { connect as tlsConnect } from 'node:tls';
|
|
73
|
+
|
|
74
|
+
export function connect(address, options) {
|
|
75
|
+
const hostname = typeof address === 'string' ? address : address.hostname;
|
|
76
|
+
const port = typeof address === 'string' ? 443 : address.port;
|
|
77
|
+
const secureTransport = options?.secureTransport ?? 'off';
|
|
78
|
+
|
|
79
|
+
let currentSocket;
|
|
80
|
+
if (secureTransport === 'on') {
|
|
81
|
+
currentSocket = tlsConnect({ host: hostname, port, servername: hostname });
|
|
82
|
+
} else {
|
|
83
|
+
currentSocket = netConnect({ host: hostname, port });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let dataHandler, endHandler, errorHandler;
|
|
87
|
+
|
|
88
|
+
const readable = new ReadableStream({
|
|
89
|
+
start(controller) {
|
|
90
|
+
dataHandler = (chunk) => {
|
|
91
|
+
try { controller.enqueue(new Uint8Array(chunk)); } catch {}
|
|
92
|
+
};
|
|
93
|
+
endHandler = () => {
|
|
94
|
+
try { controller.close(); } catch {}
|
|
95
|
+
};
|
|
96
|
+
errorHandler = (err) => {
|
|
97
|
+
try { controller.error(err); } catch {}
|
|
98
|
+
};
|
|
99
|
+
currentSocket.on('data', dataHandler);
|
|
100
|
+
currentSocket.on('end', endHandler);
|
|
101
|
+
currentSocket.on('error', errorHandler);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const writable = new WritableStream({
|
|
106
|
+
write(chunk) {
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
currentSocket.write(Buffer.from(chunk), (err) => err ? reject(err) : resolve());
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const closedPromise = new Promise((resolve) => currentSocket.on('close', resolve));
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
readable,
|
|
117
|
+
writable,
|
|
118
|
+
startTls() {
|
|
119
|
+
currentSocket.removeListener('data', dataHandler);
|
|
120
|
+
currentSocket.removeListener('end', endHandler);
|
|
121
|
+
currentSocket.removeListener('error', errorHandler);
|
|
122
|
+
const tlsSocket = tlsConnect({ socket: currentSocket, servername: hostname });
|
|
123
|
+
currentSocket = tlsSocket;
|
|
124
|
+
tlsSocket.on('data', dataHandler);
|
|
125
|
+
tlsSocket.on('end', endHandler);
|
|
126
|
+
tlsSocket.on('error', errorHandler);
|
|
127
|
+
},
|
|
128
|
+
close() { currentSocket.destroy(); },
|
|
129
|
+
closed: closedPromise,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
59
132
|
`
|
|
60
133
|
};
|
|
61
134
|
return nextLoad(url, context);
|
|
@@ -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
|
|
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"}
|
package/dist/bin/quarry.mjs
CHANGED
|
@@ -1,115 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env -S node --no-warnings
|
|
2
2
|
import { createRequire, register } from "node:module";
|
|
3
|
-
import "
|
|
4
|
-
import { existsSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
6
4
|
import { dirname, join, resolve } from "node:path";
|
|
7
5
|
import { URL, pathToFileURL } from "node:url";
|
|
8
6
|
import { Command, Option } from "clipanion";
|
|
9
|
-
//#region src/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
userNotAuthenticated: "User is not authenticated",
|
|
36
|
-
insufficientPermissions: "Insufficient permissions to perform this action",
|
|
37
|
-
requestContainerNotInitialized: "Request container has not been initialized",
|
|
38
|
-
requestScopeOperationNotAllowed: "{methodName}() cannot be called on this container scope. Check if you are calling it on the correct container (global vs request-scoped).",
|
|
39
|
-
conditionalBindingFallback: "Conditional binding predicate returned false for token \"{token}\" but no fallback was provided and no existing registration exists.",
|
|
40
|
-
configNotInitialized: "Configuration service has not been initialized",
|
|
41
|
-
configModuleNotInitialized: "ConfigModule.forRoot() was not called before module initialization",
|
|
42
|
-
stratalNotInitialized: "Stratal has not been instantiated. Ensure you export a Stratal instance as the default export.",
|
|
43
|
-
moduleAlreadyRegistered: "Module {moduleName} is already registered",
|
|
44
|
-
moduleDependencyNotFound: "Module dependency {dependency} not found for module {moduleName}",
|
|
45
|
-
moduleCircularDependency: "Circular dependency detected: {cycle}",
|
|
46
|
-
invalidModuleProvider: "Invalid module provider configuration: {provider}",
|
|
47
|
-
databaseGeneric: "Database error occurred",
|
|
48
|
-
databaseRecordNotFound: "Record not found in database",
|
|
49
|
-
databaseUniqueConstraint: "Record already exists",
|
|
50
|
-
databaseForeignKeyConstraint: "Related record not found",
|
|
51
|
-
databaseConnectionFailed: "Failed to connect to database",
|
|
52
|
-
databaseTimeout: "Database query timeout",
|
|
53
|
-
databaseNullConstraint: "Required field is missing",
|
|
54
|
-
databaseTooManyConnections: "Too many database connections",
|
|
55
|
-
databaseTransactionConflict: "Transaction conflict or deadlock",
|
|
56
|
-
databaseConstraintFailed: "A database constraint was violated",
|
|
57
|
-
databaseTableNotFound: "The specified table does not exist in the database",
|
|
58
|
-
databaseColumnNotFound: "The specified column does not exist in the table",
|
|
59
|
-
databaseInvalidQuery: "The database query is invalid or malformed",
|
|
60
|
-
invalidErrorCodeRange: "Invalid error code range: {code}",
|
|
61
|
-
queueBindingNotFound: "Queue binding {queueName} not found in environment",
|
|
62
|
-
queueProviderNotSupported: "Queue provider \"{provider}\" is not supported. Valid providers: cloudflare, sync",
|
|
63
|
-
cronExecutionFailed: "{count} cron job(s) failed for schedule \"{schedule}\": {jobs}",
|
|
64
|
-
localeNotSupported: "Locale '{locale}' is not supported. Supported locales: {supportedLocales}",
|
|
65
|
-
translationMissing: "Translation missing for key '{key}' in locale '{locale}'",
|
|
66
|
-
containerNotInitialized: "Application container has not been initialized. Ensure Application.initialize() has been called.",
|
|
67
|
-
domainMismatch: "The requested domain does not match any configured route",
|
|
68
|
-
invalidSignature: "The URL signature is invalid or has expired",
|
|
69
|
-
schemaValidation: "Schema validation failed",
|
|
70
|
-
responseValidation: "Response validation failed",
|
|
71
|
-
openapiValidation: "OpenAPI validation failed: {details}",
|
|
72
|
-
openapiRouteRegistration: "Failed to register OpenAPI route {path}: {reason}",
|
|
73
|
-
email: {
|
|
74
|
-
resendApiKeyMissing: "Resend API key not configured. Set RESEND_EMAIL_API_KEY environment variable.",
|
|
75
|
-
smtpConfigurationMissing: "SMTP configuration missing. Set SMTP_URL environment variable.",
|
|
76
|
-
smtpHostMissing: "SMTP host not configured. Check SMTP_URL format (smtp://user:pass@host:port).",
|
|
77
|
-
smtpConnectionFailed: "Failed to connect to SMTP server {smtpHost}:{smtpPort}",
|
|
78
|
-
resendApiFailed: "Resend API error",
|
|
79
|
-
providerNotSupported: "Unsupported email provider: {provider}. Supported providers: resend, smtp"
|
|
80
|
-
},
|
|
81
|
-
storage: {
|
|
82
|
-
fileNotFound: "File at path \"{path}\" was not found",
|
|
83
|
-
invalidDisk: "Storage disk \"{disk}\" is not configured",
|
|
84
|
-
invalidFileType: "File type \"{mimeType}\" is not allowed",
|
|
85
|
-
fileTooLarge: "File size {size} exceeds maximum allowed size of {maxSize}",
|
|
86
|
-
presignedUrlInvalidExpiry: "Expiry must be between {min} and {max} seconds",
|
|
87
|
-
diskNotConfigured: "Disk \"{disk}\" is not configured",
|
|
88
|
-
responseBodyMissing: "No body in storage response for path: {path}",
|
|
89
|
-
r2BindingNotFound: "R2 binding \"{binding}\" was not found in the environment",
|
|
90
|
-
r2PresignedUrlSecretMissing: "APP_SECRET environment variable is required for presigned URLs"
|
|
91
|
-
},
|
|
92
|
-
cache: {
|
|
93
|
-
getFailed: "Failed to retrieve value from cache for key '{key}'",
|
|
94
|
-
putFailed: "Failed to store value in cache for key '{key}'",
|
|
95
|
-
deleteFailed: "Failed to delete value from cache for key '{key}'",
|
|
96
|
-
listFailed: "Failed to list cache keys"
|
|
97
|
-
},
|
|
98
|
-
rateLimit: {
|
|
99
|
-
tooManyRequests: "Too Many Requests",
|
|
100
|
-
notDefined: "Rate limiter \"{name}\" is not defined. Register it via RateLimiterRegistry.for(\"{name}\", ...) inside a module's onInitialize hook.",
|
|
101
|
-
notConfigured: "RateLimiterModule.forRoot() was not called. Pass { store: \"kv\" | \"memory\" | { useClass } } to enable rate limiting.",
|
|
102
|
-
moduleNotImported: "Rate limiter \"{name}\" was used (router.throttle / @RateLimit) but RateLimiterModule is not imported in your AppModule. Add RateLimiterModule.forRoot({ store: ... }) to imports."
|
|
103
|
-
},
|
|
104
|
-
seederNameCollision: "Seeder name collision: \"{name}\" is already registered. Use distinct class names for each seeder.",
|
|
105
|
-
seederNotRegistered: "Seeder \"{name}\" is not registered",
|
|
106
|
-
migration: {
|
|
107
|
-
failed: "Migration {migrationName} failed: {error}",
|
|
108
|
-
checksumMismatch: "Migration {migrationName} checksum mismatch (expected: {expected}, actual: {actual})",
|
|
109
|
-
alreadyApplied: "Migration {migrationName} has already been applied",
|
|
110
|
-
notFound: "Migration {migrationName} not found"
|
|
7
|
+
//#region src/bin/argv.ts
|
|
8
|
+
function extractEnvFlag(argv) {
|
|
9
|
+
let env;
|
|
10
|
+
const rest = [];
|
|
11
|
+
for (let i = 0; i < argv.length; i++) {
|
|
12
|
+
const tok = argv[i];
|
|
13
|
+
if (tok === "--") {
|
|
14
|
+
rest.push(...argv.slice(i));
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
const eqMatch = tok.match(/^(?:--env|-e)=(.*)$/);
|
|
18
|
+
if (eqMatch) {
|
|
19
|
+
if (!eqMatch[1]) throw new Error("--env requires a value (e.g. --env staging)");
|
|
20
|
+
if (env !== void 0) throw new Error("--env specified more than once");
|
|
21
|
+
env = eqMatch[1];
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (tok === "--env" || tok === "-e") {
|
|
25
|
+
const next = argv[i + 1];
|
|
26
|
+
if (!next || next.startsWith("-")) throw new Error("--env requires a value (e.g. --env staging)");
|
|
27
|
+
if (env !== void 0) throw new Error("--env specified more than once");
|
|
28
|
+
env = next;
|
|
29
|
+
i++;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
rest.push(tok);
|
|
111
33
|
}
|
|
112
|
-
|
|
34
|
+
return {
|
|
35
|
+
env,
|
|
36
|
+
rest
|
|
37
|
+
};
|
|
38
|
+
}
|
|
113
39
|
//#endregion
|
|
114
40
|
//#region src/bin/commands/dynamic-command.ts
|
|
115
41
|
/** Create Clipanion command classes from Quarry-registered commands. */
|
|
@@ -170,7 +96,16 @@ function createDynamicCommands(quarry, parseSignature, app) {
|
|
|
170
96
|
const require = createRequire(import.meta.url);
|
|
171
97
|
register(pathToFileURL(join(dirname(require.resolve("@swc-node/register")), "esm/esm.mjs")), pathToFileURL("./"));
|
|
172
98
|
register(new URL("./cloudflare-workers-loader.mjs", import.meta.url), pathToFileURL("./"));
|
|
173
|
-
const DEFAULT_ENTRY = "./src/
|
|
99
|
+
const DEFAULT_ENTRY = "./src/quarry.ts";
|
|
100
|
+
let environment;
|
|
101
|
+
try {
|
|
102
|
+
const parsed = extractEnvFlag(process.argv.slice(2));
|
|
103
|
+
environment = parsed.env;
|
|
104
|
+
process.argv.splice(2, process.argv.length - 2, ...parsed.rest);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
console.error(`Error: ${e.message}`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
174
109
|
const firstArg = process.argv[2];
|
|
175
110
|
let entryFile = DEFAULT_ENTRY;
|
|
176
111
|
if (firstArg && (firstArg.includes("/") || firstArg.includes("\\") || /\.(ts|js|mts|mjs)$/.test(firstArg))) {
|
|
@@ -181,69 +116,62 @@ const entryPath = resolve(process.cwd(), entryFile);
|
|
|
181
116
|
if (!existsSync(entryPath)) {
|
|
182
117
|
console.error(`Error: Entry file not found: ${entryFile}`);
|
|
183
118
|
console.error("");
|
|
184
|
-
console.error("Create src/
|
|
119
|
+
console.error("Create src/quarry.ts that exports `QuarryRunner.run({ module, seeders })`, or specify a custom path:");
|
|
185
120
|
console.error(" npx quarry ./path/to/entry.ts <command> [options]");
|
|
186
121
|
process.exit(1);
|
|
187
122
|
}
|
|
188
|
-
function
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
delete envConfig.durable_objects;
|
|
193
|
-
delete envConfig.migrations;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
async function createStrippedConfig(cwdRequire) {
|
|
123
|
+
async function main() {
|
|
124
|
+
const cwdRequire = createRequire(join(process.cwd(), "package.json"));
|
|
125
|
+
const { unstable_readConfig: readConfig, unstable_getMiniflareWorkerOptions: getMiniflareWorkerOptions, unstable_getVarsForDev: getVarsForDev } = await import(cwdRequire.resolve("wrangler"));
|
|
126
|
+
const { Miniflare, getDefaultDevRegistryPath } = await import(cwdRequire.resolve("miniflare"));
|
|
197
127
|
const configName = [
|
|
198
128
|
"wrangler.jsonc",
|
|
199
129
|
"wrangler.json",
|
|
200
130
|
"wrangler.toml"
|
|
201
131
|
].find((c) => existsSync(resolve(process.cwd(), c)));
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (config.env && typeof config.env === "object") {
|
|
214
|
-
for (const envConfig of Object.values(config.env)) if (typeof envConfig.name === "string") envConfig.name = `quarry-${envConfig.name}-${process.pid}`;
|
|
132
|
+
const configPath = configName ? resolve(process.cwd(), configName) : void 0;
|
|
133
|
+
const envFiles = [
|
|
134
|
+
".env",
|
|
135
|
+
".env.local",
|
|
136
|
+
environment ? `.env.${environment}` : null,
|
|
137
|
+
environment ? `.env.${environment}.local` : null
|
|
138
|
+
];
|
|
139
|
+
for (const envFile of envFiles) {
|
|
140
|
+
if (!envFile) continue;
|
|
141
|
+
const envPath = resolve(process.cwd(), envFile);
|
|
142
|
+
if (existsSync(envPath)) process.loadEnvFile(envPath);
|
|
215
143
|
}
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
144
|
+
if (process.env.WRANGLER_REGISTRY_PATH && !process.env.MINIFLARE_REGISTRY_PATH) process.env.MINIFLARE_REGISTRY_PATH = process.env.WRANGLER_REGISTRY_PATH;
|
|
145
|
+
const config = readConfig({
|
|
146
|
+
config: configPath,
|
|
147
|
+
env: environment
|
|
148
|
+
});
|
|
149
|
+
const { workerOptions } = getMiniflareWorkerOptions(config, environment);
|
|
150
|
+
const vars = getVarsForDev(configPath, void 0, config.vars, environment);
|
|
151
|
+
const varsRecord = {};
|
|
152
|
+
for (const [key, binding] of Object.entries(vars)) varsRecord[key] = binding.value;
|
|
153
|
+
workerOptions.bindings = {
|
|
154
|
+
...workerOptions.bindings ?? {},
|
|
155
|
+
...varsRecord,
|
|
156
|
+
QUEUE_PROVIDER: "sync"
|
|
157
|
+
};
|
|
158
|
+
workerOptions.name = config.name ? `quarry-${config.name}-${process.pid}` : `quarry-${process.pid}`;
|
|
159
|
+
const registryPath = getDefaultDevRegistryPath();
|
|
160
|
+
const mf = new Miniflare({
|
|
161
|
+
...workerOptions,
|
|
162
|
+
script: "",
|
|
163
|
+
modules: true,
|
|
164
|
+
unsafeDevRegistryPath: registryPath,
|
|
165
|
+
defaultPersistRoot: join(process.cwd(), ".wrangler/state/v3")
|
|
238
166
|
});
|
|
167
|
+
await mf.ready;
|
|
168
|
+
const env = await mf.getBindings();
|
|
239
169
|
const pendingPromises = [];
|
|
240
170
|
const trackedWaitUntil = (promise) => {
|
|
241
171
|
pendingPromises.push(promise);
|
|
242
|
-
ctx.waitUntil(promise);
|
|
243
172
|
};
|
|
244
173
|
let app;
|
|
245
174
|
try {
|
|
246
|
-
env.QUEUE_PROVIDER = "sync";
|
|
247
175
|
globalThis.__stratalPlatformProxy = {
|
|
248
176
|
env,
|
|
249
177
|
waitUntil: trackedWaitUntil
|
|
@@ -267,16 +195,12 @@ async function main() {
|
|
|
267
195
|
} finally {
|
|
268
196
|
await Promise.allSettled(pendingPromises);
|
|
269
197
|
await app?.shutdown();
|
|
270
|
-
await dispose();
|
|
271
|
-
if (strippedConfigPath) try {
|
|
272
|
-
unlinkSync(strippedConfigPath);
|
|
273
|
-
} catch {}
|
|
198
|
+
await mf.dispose();
|
|
274
199
|
}
|
|
275
200
|
}
|
|
276
201
|
main().catch(async (error) => {
|
|
277
202
|
const { ConfigValidationError } = await import("stratal/config");
|
|
278
|
-
const
|
|
279
|
-
const message = error instanceof StratalNotInitializedError ? errors.stratalNotInitialized : error instanceof Error ? error.message : String(error);
|
|
203
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
280
204
|
console.error("Fatal error:", message);
|
|
281
205
|
if (error instanceof ConfigValidationError) console.error(error.errors.message);
|
|
282
206
|
process.exit(1);
|
package/dist/bin/quarry.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quarry.mjs","names":["errorMessages"],"sources":["../../src/i18n/messages/en/errors.ts","../../src/bin/commands/dynamic-command.ts","../../src/bin/quarry.ts"],"sourcesContent":["/**\n * System Error Messages - English\n *\n * Error messages used by packages/modules infrastructure.\n * These are automatically merged with application-specific messages.\n */\n\nexport const errors = {\n // Generic errors\n internalError: 'An internal error occurred',\n notFound: 'Resource not found',\n unauthorized: 'Unauthorized. Please sign in.',\n forbidden: 'Access denied',\n\n // Router errors\n honoAppAlreadyConfigured: 'HonoApp has already been configured and can only be configured once',\n routeNotFound: 'Route not found: {method} {path}',\n routeAccessDenied: 'Resource not found',\n controllerMethodNotFound: 'Method {methodName} not found on {controllerName}',\n controllerRegistration: 'Failed to register controller {controllerName}: {reason}',\n duplicateRouteName: 'Duplicate route name \"{name}\". Already registered by {existingHandler}, cannot register {newHandler}.',\n routeNameNotFound: 'Route \"{name}\" not found in registry.',\n missingRouteParam: 'Missing required parameter \"{param}\" for route \"{name}\" (path: {path}).',\n routerUseScopeViolation: 'router.use() can only be called on the root Router, not inside group() callbacks. Use router.middleware() for scoped middleware.',\n middlewareNextCalledMultipleTimes: 'next() was called multiple times in \"{middlewareName}\" middleware. Ensure each middleware calls next() at most once.',\n missingEnvironmentVariable: 'Environment variable \"{variable}\" is required but not set.',\n\n // WebSocket errors\n websocketBodyNotAvailable: 'body() is not available in WebSocket gateways. Use WebSocket messages instead.',\n websocketDuplicateEventHandler: '@{decorator}() is already applied to \\'{existingMethod}\\'. Only one method per gateway can handle this event.',\n\n // Context errors\n contextNotInitialized: 'Context has not been initialized',\n userNotAuthenticated: 'User is not authenticated',\n insufficientPermissions: 'Insufficient permissions to perform this action',\n requestContainerNotInitialized: 'Request container has not been initialized',\n requestScopeOperationNotAllowed: '{methodName}() cannot be called on this container scope. Check if you are calling it on the correct container (global vs request-scoped).',\n conditionalBindingFallback: 'Conditional binding predicate returned false for token \"{token}\" but no fallback was provided and no existing registration exists.',\n\n // Configuration errors\n configNotInitialized: 'Configuration service has not been initialized',\n configModuleNotInitialized: 'ConfigModule.forRoot() was not called before module initialization',\n stratalNotInitialized: 'Stratal has not been instantiated. Ensure you export a Stratal instance as the default export.',\n\n // Module errors\n moduleAlreadyRegistered: 'Module {moduleName} is already registered',\n moduleDependencyNotFound: 'Module dependency {dependency} not found for module {moduleName}',\n moduleCircularDependency: 'Circular dependency detected: {cycle}',\n invalidModuleProvider: 'Invalid module provider configuration: {provider}',\n\n // Database errors\n databaseGeneric: 'Database error occurred',\n databaseRecordNotFound: 'Record not found in database',\n databaseUniqueConstraint: 'Record already exists',\n databaseForeignKeyConstraint: 'Related record not found',\n databaseConnectionFailed: 'Failed to connect to database',\n databaseTimeout: 'Database query timeout',\n databaseNullConstraint: 'Required field is missing',\n databaseTooManyConnections: 'Too many database connections',\n databaseTransactionConflict: 'Transaction conflict or deadlock',\n databaseConstraintFailed: 'A database constraint was violated',\n databaseTableNotFound: 'The specified table does not exist in the database',\n databaseColumnNotFound: 'The specified column does not exist in the table',\n databaseInvalidQuery: 'The database query is invalid or malformed',\n invalidErrorCodeRange: 'Invalid error code range: {code}',\n\n // Queue errors\n queueBindingNotFound: 'Queue binding {queueName} not found in environment',\n queueProviderNotSupported: 'Queue provider \"{provider}\" is not supported. Valid providers: cloudflare, sync',\n\n // Cron errors\n cronExecutionFailed: '{count} cron job(s) failed for schedule \"{schedule}\": {jobs}',\n\n // i18n errors\n localeNotSupported: \"Locale '{locale}' is not supported. Supported locales: {supportedLocales}\",\n translationMissing: \"Translation missing for key '{key}' in locale '{locale}'\",\n\n // Container errors\n containerNotInitialized: 'Application container has not been initialized. Ensure Application.initialize() has been called.',\n\n // Domain routing errors\n domainMismatch: 'The requested domain does not match any configured route',\n\n // Signature errors\n invalidSignature: 'The URL signature is invalid or has expired',\n\n // Schema validation errors\n schemaValidation: 'Schema validation failed',\n responseValidation: 'Response validation failed',\n\n // OpenAPI errors\n openapiValidation: 'OpenAPI validation failed: {details}',\n openapiRouteRegistration: 'Failed to register OpenAPI route {path}: {reason}',\n\n // Email errors\n email: {\n resendApiKeyMissing: 'Resend API key not configured. Set RESEND_EMAIL_API_KEY environment variable.',\n smtpConfigurationMissing: 'SMTP configuration missing. Set SMTP_URL environment variable.',\n smtpHostMissing: 'SMTP host not configured. Check SMTP_URL format (smtp://user:pass@host:port).',\n smtpConnectionFailed: 'Failed to connect to SMTP server {smtpHost}:{smtpPort}',\n resendApiFailed: 'Resend API error',\n providerNotSupported: 'Unsupported email provider: {provider}. Supported providers: resend, smtp'\n },\n\n // Storage errors\n storage: {\n fileNotFound: 'File at path \"{path}\" was not found',\n invalidDisk: 'Storage disk \"{disk}\" is not configured',\n invalidFileType: 'File type \"{mimeType}\" is not allowed',\n fileTooLarge: 'File size {size} exceeds maximum allowed size of {maxSize}',\n presignedUrlInvalidExpiry: 'Expiry must be between {min} and {max} seconds',\n diskNotConfigured: 'Disk \"{disk}\" is not configured',\n responseBodyMissing: 'No body in storage response for path: {path}',\n r2BindingNotFound: 'R2 binding \"{binding}\" was not found in the environment',\n r2PresignedUrlSecretMissing: 'APP_SECRET environment variable is required for presigned URLs',\n },\n\n // Cache errors\n cache: {\n getFailed: \"Failed to retrieve value from cache for key '{key}'\",\n putFailed: \"Failed to store value in cache for key '{key}'\",\n deleteFailed: \"Failed to delete value from cache for key '{key}'\",\n listFailed: 'Failed to list cache keys'\n },\n\n // Rate limiter errors\n rateLimit: {\n tooManyRequests: 'Too Many Requests',\n notDefined: 'Rate limiter \"{name}\" is not defined. Register it via RateLimiterRegistry.for(\"{name}\", ...) inside a module\\'s onInitialize hook.',\n notConfigured: 'RateLimiterModule.forRoot() was not called. Pass { store: \"kv\" | \"memory\" | { useClass } } to enable rate limiting.',\n moduleNotImported: 'Rate limiter \"{name}\" was used (router.throttle / @RateLimit) but RateLimiterModule is not imported in your AppModule. Add RateLimiterModule.forRoot({ store: ... }) to imports.',\n },\n\n // Seeder errors\n seederNameCollision: 'Seeder name collision: \"{name}\" is already registered. Use distinct class names for each seeder.',\n seederNotRegistered: 'Seeder \"{name}\" is not registered',\n\n // Migration errors\n migration: {\n failed: 'Migration {migrationName} failed: {error}',\n checksumMismatch: 'Migration {migrationName} checksum mismatch (expected: {expected}, actual: {actual})',\n alreadyApplied: 'Migration {migrationName} has already been applied',\n notFound: 'Migration {migrationName} not found',\n },\n} as const\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 'reflect-metadata'\n\nimport { existsSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { createRequire, register } from 'node:module'\nimport { tmpdir } from 'node:os'\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 { errors as errorMessages } from '../i18n/messages/en/errors'\nimport { createDynamicCommands } from './commands/dynamic-command'\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/index.ts'\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/index.ts with a default Stratal export, or specify a custom path:')\n console.error(' npx quarry ./path/to/entry.ts <command> [options]')\n process.exit(1)\n}\n\nfunction stripDurableObjects(config: Record<string, unknown>): void {\n delete config.durable_objects\n delete config.migrations\n if (config.env && typeof config.env === 'object') {\n for (const envConfig of Object.values(config.env as Record<string, Record<string, unknown>>)) {\n delete envConfig.durable_objects\n delete envConfig.migrations\n }\n }\n}\n\nasync function createStrippedConfig(cwdRequire: NodeRequire): Promise<string | undefined> {\n const candidates = ['wrangler.jsonc', 'wrangler.json', 'wrangler.toml']\n const configName = candidates.find(c => existsSync(resolve(process.cwd(), c)))\n if (!configName) return undefined\n\n const configPath = resolve(process.cwd(), configName)\n const raw = readFileSync(configPath, 'utf-8')\n\n let config: Record<string, unknown>\n if (configName.endsWith('.toml')) {\n const { parse } = await import(cwdRequire.resolve('smol-toml')) as { parse: (input: string) => Record<string, unknown> }\n config = parse(raw)\n } else {\n const { parse: parseJsonc } = await import(cwdRequire.resolve('jsonc-parser')) as { parse: (input: string) => Record<string, unknown> }\n config = parseJsonc(raw)\n }\n\n // Rename so quarry's ephemeral miniflare doesn't claim the running\n // `wrangler dev` session's dev-registry slot. getPlatformProxy registers\n // its worker with empty entrypointAddresses (no direct sockets), and that\n // overwrite makes peer workers route TenantsRpc/BrandingRpc/etc. calls to\n // their fallback service (\"couldn't find a local dev session for the X\n // entrypoint\"). A unique name keeps the running session's entry untouched.\n if (typeof config.name === 'string') {\n config.name = `quarry-${config.name}-${process.pid}`\n }\n if (config.env && typeof config.env === 'object') {\n for (const envConfig of Object.values(config.env as Record<string, Record<string, unknown>>)) {\n if (typeof envConfig.name === 'string') {\n envConfig.name = `quarry-${envConfig.name}-${process.pid}`\n }\n }\n }\n\n stripDurableObjects(config)\n\n const tmpPath = resolve(tmpdir(), `quarry-wrangler-${Date.now()}.json`)\n writeFileSync(tmpPath, JSON.stringify(config, null, 2))\n return tmpPath\n}\n\nfunction discoverEnvFiles(): string[] {\n const cwd = process.cwd()\n const files = readdirSync(cwd)\n return files\n .filter(file => (/^\\.dev\\.vars($|\\.)/.test(file) || /^\\.env($|\\.)/.test(file)) && !file.endsWith('.example') && !file.endsWith('.sample'))\n .sort((a, b) => {\n // Load .env files before .dev.vars so .dev.vars takes precedence\n const aIsDevVars = a.startsWith('.dev.vars')\n const bIsDevVars = b.startsWith('.dev.vars')\n if (aIsDevVars !== bIsDevVars) return aIsDevVars ? 1 : -1\n // Within each group, .local files load last (highest precedence)\n const aIsLocal = a.endsWith('.local')\n const bIsLocal = b.endsWith('.local')\n if (aIsLocal !== bIsLocal) return aIsLocal ? 1 : -1\n return a.localeCompare(b)\n })\n .map(file => join(cwd, file))\n}\n\nasync function main(): Promise<void> {\n const cwdRequire = createRequire(join(process.cwd(), 'package.json'))\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n const { getPlatformProxy } = await import(cwdRequire.resolve('wrangler')) as typeof import('wrangler')\n\n const strippedConfigPath = await createStrippedConfig(cwdRequire)\n\n const envFiles = discoverEnvFiles()\n const { env, ctx, dispose } = await getPlatformProxy({\n envFiles, configPath: strippedConfigPath,\n })\n\n // Track waitUntil promises so we can drain them before shutdown.\n // In Workers runtime, waitUntil keeps the isolate alive. In Quarry (miniflare),\n // dispose() tears down without awaiting pending promises — so we track and drain them.\n const pendingPromises: Promise<unknown>[] = []\n const trackedWaitUntil = (promise: Promise<unknown>) => {\n pendingPromises.push(promise)\n ctx.waitUntil(promise)\n }\n\n let app: Application | undefined\n try {\n env.QUEUE_PROVIDER = 'sync';\n\n // Store platform proxy on globalThis so the cloudflare:workers virtual module can read it\n (globalThis as Record<string, unknown>).__stratalPlatformProxy = {\n env,\n waitUntil: trackedWaitUntil,\n }\n\n // Import user's entry file — triggers `new Stratal(...)` + full Application init\n await import(pathToFileURL(entryPath).href)\n\n // Parallel import of stratal modules\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 // Build Clipanion CLI\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\n await app?.shutdown()\n await dispose()\n\n if (strippedConfigPath) {\n try { unlinkSync(strippedConfigPath) } catch {\n //\n }\n }\n }\n}\n\nmain().catch(async (error: unknown) => {\n const { ConfigValidationError } = await import('stratal/config')\n const { StratalNotInitializedError } = await import('stratal/errors')\n\n const message = error instanceof StratalNotInitializedError\n ? errorMessages.stratalNotInitialized\n : 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/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 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';\n\ninterface WranglerConfig {\n name?: string\n vars?: Record<string, unknown>\n}\n\ninterface MiniflareWorkerResult {\n workerOptions: Record<string, unknown>\n}\n\ninterface WranglerModule {\n unstable_readConfig: (args: { config?: string; env?: string }) => WranglerConfig\n unstable_getMiniflareWorkerOptions: (config: WranglerConfig, env?: string) => MiniflareWorkerResult\n unstable_getVarsForDev: (configPath: string | undefined, envFiles: undefined, vars: unknown, env: string | undefined) => Record<string, { value: string }>\n}\n\ninterface MiniflareModule {\n Miniflare: new (opts: MiniflareOptions) => { ready: Promise<URL>; getBindings: (name?: string) => Promise<Record<string, unknown>>; dispose: () => Promise<void> }\n getDefaultDevRegistryPath: () => string\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 } = await import(cwdRequire.resolve('wrangler')) as WranglerModule\n const { Miniflare, getDefaultDevRegistryPath } = 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 // Bridge the documented `WRANGLER_REGISTRY_PATH` to `MINIFLARE_REGISTRY_PATH`,\n // the variable Miniflare's `getDefaultDevRegistryPath()` actually reads.\n // `wrangler dev` performs the same translation internally; mirroring it here\n // lets a single documented env var redirect the dev service registry for BOTH\n // this CLI's Miniflare (below) AND any vite dev server a command launches\n // (`@cloudflare/vite-plugin` also resolves its registry via\n // `getDefaultDevRegistryPath()`). That allows several isolated dev environments\n // to run in parallel without sharing the global `~/.wrangler/registry`, where\n // their identically-named workers would otherwise overwrite each other and\n // break cross-worker service-binding resolution. Only set when unset so an\n // explicit override still wins.\n if (process.env.WRANGLER_REGISTRY_PATH && !process.env.MINIFLARE_REGISTRY_PATH) {\n process.env.MINIFLARE_REGISTRY_PATH = process.env.WRANGLER_REGISTRY_PATH\n }\n\n const config = readConfig({ config: configPath, env: environment })\n const { workerOptions } = getMiniflareWorkerOptions(config, environment)\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 // Resolve the dev-registry path so Miniflare can discover running\n // `wrangler dev` sessions for service binding resolution.\n const registryPath = getDefaultDevRegistryPath()\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 }\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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"}
|