stratal 0.0.20 → 0.0.22
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 +1 -1
- package/dist/{base-email.provider-CfQCA08m.mjs → base-email.provider-BWZHIjt8.mjs} +1 -1
- package/dist/{base-email.provider-CfQCA08m.mjs.map → base-email.provider-BWZHIjt8.mjs.map} +1 -1
- package/dist/bin/cloudflare-workers-loader.mjs.map +1 -1
- package/dist/bin/quarry.mjs +46 -109
- package/dist/bin/quarry.mjs.map +1 -1
- package/dist/cache/index.d.mts +6 -46
- package/dist/cache/index.d.mts.map +1 -1
- package/dist/cache/index.mjs +22 -67
- package/dist/cache/index.mjs.map +1 -1
- package/dist/{cache.service-DsnKuNyO.d.mts → cache.service-e34gV6tz.d.mts} +8 -8
- package/dist/{cache.service-DsnKuNyO.d.mts.map → cache.service-e34gV6tz.d.mts.map} +1 -1
- package/dist/{cache.tokens-B7Rw1C9Q.mjs → cache.tokens-ovi_c52J.mjs} +1 -1
- package/dist/{cache.tokens-B7Rw1C9Q.mjs.map → cache.tokens-ovi_c52J.mjs.map} +1 -1
- package/dist/{colors-DJaRDXoS.mjs → colors-axmupKdp.mjs} +1 -1
- package/dist/{colors-DJaRDXoS.mjs.map → colors-axmupKdp.mjs.map} +1 -1
- package/dist/{command-BgSlsS4M.mjs → command-BU4ApTo5.mjs} +2 -3
- package/dist/command-BU4ApTo5.mjs.map +1 -0
- package/dist/{command-Bu-PjJrX.d.mts → command-wXfvHbBZ.d.mts} +3 -2
- package/dist/command-wXfvHbBZ.d.mts.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 +33 -57
- package/dist/config/index.mjs.map +1 -1
- package/dist/{consumer-registry-B7yUNh0q.d.mts → consumer-registry-DHQtypr1.d.mts} +1 -1
- package/dist/{consumer-registry-B7yUNh0q.d.mts.map → consumer-registry-DHQtypr1.d.mts.map} +1 -1
- package/dist/container-storage-GpNNz79X.mjs +52 -0
- package/dist/container-storage-GpNNz79X.mjs.map +1 -0
- package/dist/{controller.decorator-DQzenvSN.mjs → controller.decorator-DIUazNU7.mjs} +8 -8
- package/dist/controller.decorator-DIUazNU7.mjs.map +1 -0
- package/dist/cron/index.d.mts +26 -5
- package/dist/cron/index.d.mts.map +1 -1
- package/dist/cron/index.mjs +1 -1
- package/dist/{cron-manager-7Symz_TE.mjs → cron-manager-9bpN9bu4.mjs} +42 -16
- package/dist/cron-manager-9bpN9bu4.mjs.map +1 -0
- package/dist/{cron-manager-BEsH1mjW.d.mts → cron-manager-CSTIBPcM.d.mts} +6 -13
- package/dist/cron-manager-CSTIBPcM.d.mts.map +1 -0
- package/dist/decorate-HgTKAYK8.mjs +16 -0
- package/dist/deep-merge-C8NgcXw4.mjs +18 -0
- package/dist/deep-merge-C8NgcXw4.mjs.map +1 -0
- package/dist/di/index.d.mts +2 -2
- package/dist/di/index.mjs +4 -3
- package/dist/di-BO1QIb5H.mjs +415 -0
- package/dist/di-BO1QIb5H.mjs.map +1 -0
- package/dist/email/index.d.mts +14 -89
- package/dist/email/index.d.mts.map +1 -1
- package/dist/email/index.mjs +30 -125
- package/dist/email/index.mjs.map +1 -1
- package/dist/en-BPP6h6y5.mjs +202 -0
- package/dist/en-BPP6h6y5.mjs.map +1 -0
- package/dist/{env-D1rcZ8_r.d.mts → env-DKSbuBi5.d.mts} +1 -1
- package/dist/env-DKSbuBi5.d.mts.map +1 -0
- package/dist/errors/index.d.mts +2 -2
- package/dist/errors/index.mjs +4 -2
- package/dist/errors-BBZTnjdq.mjs +333 -0
- package/dist/errors-BBZTnjdq.mjs.map +1 -0
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.d.mts.map +1 -1
- package/dist/events/index.mjs +1 -1
- package/dist/{events-COKixqnG.mjs → events-D1KdDaiP.mjs} +13 -11
- package/dist/events-D1KdDaiP.mjs.map +1 -0
- package/dist/exception-context-B4kM-M53.mjs +429 -0
- package/dist/exception-context-B4kM-M53.mjs.map +1 -0
- package/dist/{gateway-context-CdJjpUCW.mjs → gateway-context-CFe6a9gz.mjs} +20 -31
- package/dist/gateway-context-CFe6a9gz.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-DUk_Kzst.mjs → guards-Ced-uNIF.mjs} +7 -5
- package/dist/guards-Ced-uNIF.mjs.map +1 -0
- package/dist/{http-method.decorator-DXwxAfb_.mjs → http-method.decorator-CdjKFJZZ.mjs} +7 -6
- package/dist/http-method.decorator-CdjKFJZZ.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-BlXrtAlV.mjs +219 -0
- package/dist/i18n.module-BlXrtAlV.mjs.map +1 -0
- package/dist/i18n.tokens-hwRpmjRq.mjs +19 -0
- package/dist/i18n.tokens-hwRpmjRq.mjs.map +1 -0
- package/dist/{index-7-hU3GTV.d.mts → index-B4UBK-2T.d.mts} +1 -1
- package/dist/{index-7-hU3GTV.d.mts.map → index-B4UBK-2T.d.mts.map} +1 -1
- package/dist/index-BtlE9RuO.d.mts +124 -0
- package/dist/index-BtlE9RuO.d.mts.map +1 -0
- package/dist/{index-CjaQ6_tZ.d.mts → index-CW1YHSft.d.mts} +71 -167
- package/dist/index-CW1YHSft.d.mts.map +1 -0
- package/dist/{index-D0US0X14.d.mts → index-DEncMcC6.d.mts} +559 -2239
- package/dist/index-DEncMcC6.d.mts.map +1 -0
- package/dist/index-Dj5IMwtr.d.mts +44 -0
- package/dist/index-Dj5IMwtr.d.mts.map +1 -0
- package/dist/{index-C1KvMncZ.d.mts → index-KMgSCSM7.d.mts} +3 -108
- package/dist/index-KMgSCSM7.d.mts.map +1 -0
- package/dist/index.d.mts +5 -43
- package/dist/index.mjs +1 -1
- package/dist/{is-command-C6a7WTPw.mjs → is-command-CX5rAfZW.mjs} +2 -2
- package/dist/{is-command-C6a7WTPw.mjs.map → is-command-CX5rAfZW.mjs.map} +1 -1
- package/dist/{is-seeder-CebjZCDn.mjs → is-seeder-CYCtELlm.mjs} +1 -1
- package/dist/{is-seeder-CebjZCDn.mjs.map → is-seeder-CYCtELlm.mjs.map} +1 -1
- 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 +1 -1
- package/dist/macroable/index.mjs +1 -1
- package/dist/{macroable-BmufBshB.mjs → macroable-DzlfzT50.mjs} +1 -1
- package/dist/{macroable-BmufBshB.mjs.map → macroable-DzlfzT50.mjs.map} +1 -1
- package/dist/metadata-BVkc4aUu.mjs +39 -0
- package/dist/metadata-BVkc4aUu.mjs.map +1 -0
- package/dist/module/index.d.mts +6 -24
- package/dist/module/index.d.mts.map +1 -1
- package/dist/module/index.mjs +2 -2
- package/dist/module-xYoHba6B.mjs +422 -0
- package/dist/module-xYoHba6B.mjs.map +1 -0
- package/dist/openapi/index.d.mts +3 -3
- package/dist/openapi/index.d.mts.map +1 -1
- package/dist/openapi/index.mjs +1 -2
- package/dist/openapi-C6lm0RmV.mjs +483 -0
- package/dist/openapi-C6lm0RmV.mjs.map +1 -0
- package/dist/{openapi.service-BLgvn3hJ.d.mts → openapi.service-CrLlsXAd.d.mts} +3 -3
- package/dist/openapi.service-CrLlsXAd.d.mts.map +1 -0
- package/dist/quarry/index.d.mts +5 -163
- package/dist/quarry/index.d.mts.map +1 -1
- package/dist/quarry/index.mjs +5 -5
- package/dist/quarry/runner.d.mts +184 -0
- package/dist/quarry/runner.d.mts.map +1 -0
- package/dist/quarry/runner.mjs +775 -0
- package/dist/quarry/runner.mjs.map +1 -0
- package/dist/quarry-registry-D4hIGScf.d.mts +69 -0
- package/dist/quarry-registry-D4hIGScf.d.mts.map +1 -0
- package/dist/quarry-registry-DkraZNwn.mjs +311 -0
- package/dist/quarry-registry-DkraZNwn.mjs.map +1 -0
- package/dist/queue/index.d.mts +3 -3
- package/dist/queue/index.mjs +27 -28
- package/dist/queue/index.mjs.map +1 -1
- package/dist/{queue.module-BCdCiySt.mjs → queue.module-DeWJ0tQM.mjs} +67 -112
- package/dist/queue.module-DeWJ0tQM.mjs.map +1 -0
- package/dist/{r2-storage.provider-Co6F0ZYV.mjs → r2-storage.provider-Hfm6LdZQ.mjs} +8 -5
- package/dist/r2-storage.provider-Hfm6LdZQ.mjs.map +1 -0
- package/dist/{rate-limit.decorator--o6Q6p9w.mjs → rate-limit.decorator-D69zdZbp.mjs} +6 -11
- package/dist/rate-limit.decorator-D69zdZbp.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 +25 -30
- package/dist/rate-limiter/index.mjs.map +1 -1
- package/dist/{resend.provider-M6qRLrcy.mjs → resend.provider-Ur6tU7fK.mjs} +8 -7
- package/dist/resend.provider-Ur6tU7fK.mjs.map +1 -0
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.mjs +8 -7
- package/dist/{i18n.module-BBlNNlcG.mjs → router-Cy6DjkvP.mjs} +215 -855
- package/dist/router-Cy6DjkvP.mjs.map +1 -0
- package/dist/seeder/index.d.mts +6 -11
- package/dist/seeder/index.d.mts.map +1 -1
- package/dist/seeder/index.mjs +3 -3
- package/dist/{seeder-CJAOHEIo.mjs → seeder-BADTig4n.mjs} +17 -22
- package/dist/seeder-BADTig4n.mjs.map +1 -0
- package/dist/{signed-url-BQPbv2In.mjs → signed-url-BqUqt5dF.mjs} +1 -1
- package/dist/{signed-url-BQPbv2In.mjs.map → signed-url-BqUqt5dF.mjs.map} +1 -1
- package/dist/{smtp.provider-w0Ve52Xg.mjs → smtp.provider-C129sNBT.mjs} +7 -6
- package/dist/smtp.provider-C129sNBT.mjs.map +1 -0
- 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.mjs +1 -1
- package/dist/{storage-1zw-6Yiz.mjs → storage-BA3ppVYM.mjs} +70 -59
- package/dist/storage-BA3ppVYM.mjs.map +1 -0
- package/dist/{storage-provider.interface-Bd6vA4ak.d.mts → storage-provider.interface-DQMtT42e.d.mts} +2 -3
- package/dist/storage-provider.interface-DQMtT42e.d.mts.map +1 -0
- package/dist/storage.error-C6FY037a.mjs +8 -0
- package/dist/storage.error-C6FY037a.mjs.map +1 -0
- package/dist/{stratal-DeEcGgdq.mjs → stratal-Bdq4IdB3.mjs} +31 -183
- package/dist/stratal-Bdq4IdB3.mjs.map +1 -0
- package/dist/stratal-BsKmvP6J.d.mts +43 -0
- package/dist/stratal-BsKmvP6J.d.mts.map +1 -0
- package/dist/{types-cySNS_lp.d.mts → types-BaeHi67f.d.mts} +1 -1
- package/dist/types-BaeHi67f.d.mts.map +1 -0
- package/dist/{usage-generator-BUdlhnCK.mjs → usage-generator-DTqaUMR9.mjs} +6 -3
- package/dist/usage-generator-DTqaUMR9.mjs.map +1 -0
- package/dist/validation-DUzcjb8Q.mjs +49 -0
- package/dist/validation-DUzcjb8Q.mjs.map +1 -0
- package/dist/validation.context-XTysWJ3b.mjs +117 -0
- package/dist/validation.context-XTysWJ3b.mjs.map +1 -0
- package/dist/websocket/index.d.mts +7 -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.mjs +3 -2
- package/dist/workers/index.mjs.map +1 -1
- package/dist/{index-Bnpfq6uk.d.mts → zod-DvWTfRpI.d.mts} +58 -133
- package/dist/zod-DvWTfRpI.d.mts.map +1 -0
- package/dist/zod-hMa3rSHV.mjs +72 -0
- package/dist/zod-hMa3rSHV.mjs.map +1 -0
- package/package.json +20 -20
- package/dist/command-BgSlsS4M.mjs.map +0 -1
- package/dist/command-Bu-PjJrX.d.mts.map +0 -1
- package/dist/controller.decorator-DQzenvSN.mjs.map +0 -1
- package/dist/cron-manager-7Symz_TE.mjs.map +0 -1
- package/dist/cron-manager-BEsH1mjW.d.mts.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-BdyV5PnY.mjs +0 -1725
- package/dist/errors-BdyV5PnY.mjs.map +0 -1
- package/dist/errors-Da3Pz2X7.mjs +0 -74
- package/dist/errors-Da3Pz2X7.mjs.map +0 -1
- package/dist/events-COKixqnG.mjs.map +0 -1
- package/dist/gateway-context-CdJjpUCW.mjs.map +0 -1
- package/dist/guards-DUk_Kzst.mjs.map +0 -1
- package/dist/http-method.decorator-DXwxAfb_.mjs.map +0 -1
- package/dist/i18n.module-BBlNNlcG.mjs.map +0 -1
- package/dist/index-Bnpfq6uk.d.mts.map +0 -1
- package/dist/index-C1KvMncZ.d.mts.map +0 -1
- package/dist/index-CjaQ6_tZ.d.mts.map +0 -1
- package/dist/index-D0US0X14.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.d.mts.map +0 -1
- package/dist/logger-V6Ms3QnQ.mjs +0 -436
- package/dist/logger-V6Ms3QnQ.mjs.map +0 -1
- package/dist/module-Dk2qTa77.mjs +0 -860
- package/dist/module-Dk2qTa77.mjs.map +0 -1
- package/dist/openapi-tools.service-Zs-Ewv7F.mjs +0 -200
- package/dist/openapi-tools.service-Zs-Ewv7F.mjs.map +0 -1
- package/dist/openapi.service-BLgvn3hJ.d.mts.map +0 -1
- package/dist/quarry-registry-DNEej-Db.mjs +0 -688
- package/dist/quarry-registry-DNEej-Db.mjs.map +0 -1
- package/dist/queue.module-BCdCiySt.mjs.map +0 -1
- package/dist/r2-storage.provider-Co6F0ZYV.mjs.map +0 -1
- package/dist/rate-limit.decorator--o6Q6p9w.mjs.map +0 -1
- package/dist/resend.provider-M6qRLrcy.mjs.map +0 -1
- package/dist/seeder-CJAOHEIo.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-w0Ve52Xg.mjs.map +0 -1
- package/dist/storage-1zw-6Yiz.mjs.map +0 -1
- package/dist/storage-provider.interface-Bd6vA4ak.d.mts.map +0 -1
- package/dist/stratal-DeEcGgdq.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
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
import { c as DI_TOKENS, m as inject, o as ROUTER_TOKENS } from "../di-BO1QIb5H.mjs";
|
|
2
|
+
import { n as __decorateParam, t as __decorate } from "../decorate-HgTKAYK8.mjs";
|
|
3
|
+
import "../logger/index.mjs";
|
|
4
|
+
import { f as Module } from "../module-xYoHba6B.mjs";
|
|
5
|
+
import { r as getListenerHandlers } from "../events-D1KdDaiP.mjs";
|
|
6
|
+
import { a as green, n as cyan, o as red, s as yellow, t as bold } from "../colors-axmupKdp.mjs";
|
|
7
|
+
import { t as Command } from "../command-BU4ApTo5.mjs";
|
|
8
|
+
import { t as I18N_TOKENS } from "../i18n.tokens-hwRpmjRq.mjs";
|
|
9
|
+
import { a as OPENAPI_TOKENS, t as OpenApiToolsService } from "../openapi-C6lm0RmV.mjs";
|
|
10
|
+
import { r as CommandNotFoundError } from "../quarry-registry-DkraZNwn.mjs";
|
|
11
|
+
import { t as Stratal } from "../stratal-Bdq4IdB3.mjs";
|
|
12
|
+
import { n as DbSeedListCommand, t as DbSeedCommand } from "../seeder-BADTig4n.mjs";
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import { writeFileSync } from "node:fs";
|
|
15
|
+
import { resolve } from "node:path";
|
|
16
|
+
//#region src/quarry/commands/api.command.ts
|
|
17
|
+
let ApiCommand = class ApiCommand extends Command {
|
|
18
|
+
app;
|
|
19
|
+
static command = "api {route?} {--method= : HTTP method} {--data= : JSON request body} {--header=* : Headers (Key:Value)} {--query=* : Query params (key=value)}";
|
|
20
|
+
static description = "Call an API route directly";
|
|
21
|
+
static aliases = ["api:call"];
|
|
22
|
+
constructor(app) {
|
|
23
|
+
super();
|
|
24
|
+
this.app = app;
|
|
25
|
+
}
|
|
26
|
+
async handle() {
|
|
27
|
+
const route = this.string("route");
|
|
28
|
+
if (!route) return (await this.call("route:list")).exitCode;
|
|
29
|
+
return this.callRoute(route);
|
|
30
|
+
}
|
|
31
|
+
async callRoute(route) {
|
|
32
|
+
const method = (this.string("method") || "GET").toUpperCase();
|
|
33
|
+
const data = this.string("data");
|
|
34
|
+
const headerArgs = this.array("header");
|
|
35
|
+
const queryArgs = this.array("query");
|
|
36
|
+
const headers = {};
|
|
37
|
+
if (data) headers["Content-Type"] = "application/json";
|
|
38
|
+
for (const h of headerArgs) {
|
|
39
|
+
const colonIdx = h.indexOf(":");
|
|
40
|
+
if (colonIdx > 0) headers[h.slice(0, colonIdx).trim()] = h.slice(colonIdx + 1).trim();
|
|
41
|
+
}
|
|
42
|
+
let url = route;
|
|
43
|
+
if (queryArgs.length > 0) {
|
|
44
|
+
const parts = queryArgs.map((q) => {
|
|
45
|
+
const eqIdx = q.indexOf("=");
|
|
46
|
+
if (eqIdx > 0) return `${encodeURIComponent(q.slice(0, eqIdx))}=${encodeURIComponent(q.slice(eqIdx + 1))}`;
|
|
47
|
+
return encodeURIComponent(q);
|
|
48
|
+
});
|
|
49
|
+
url += `?${parts.join("&")}`;
|
|
50
|
+
}
|
|
51
|
+
const request = new Request(`http://localhost${url}`, {
|
|
52
|
+
method,
|
|
53
|
+
headers,
|
|
54
|
+
body: data || void 0
|
|
55
|
+
});
|
|
56
|
+
const response = await (await this.app.ensureHono()).fetch(request, this.app.env);
|
|
57
|
+
const body = await response.text();
|
|
58
|
+
const statusText = `${response.status} ${response.statusText}`;
|
|
59
|
+
let coloredStatus;
|
|
60
|
+
if (response.status >= 200 && response.status < 300) coloredStatus = green(bold(statusText));
|
|
61
|
+
else if (response.status >= 300 && response.status < 400) coloredStatus = yellow(bold(statusText));
|
|
62
|
+
else coloredStatus = red(bold(statusText));
|
|
63
|
+
this.line(`${cyan(method)} ${route} ${coloredStatus}`);
|
|
64
|
+
this.newLine();
|
|
65
|
+
const headerLines = [];
|
|
66
|
+
response.headers.forEach((value, key) => {
|
|
67
|
+
headerLines.push(` ${key}: ${value}`);
|
|
68
|
+
});
|
|
69
|
+
if (headerLines.length > 0) {
|
|
70
|
+
this.line(bold("Headers:"));
|
|
71
|
+
for (const hl of headerLines) this.line(hl);
|
|
72
|
+
this.newLine();
|
|
73
|
+
}
|
|
74
|
+
if (body) {
|
|
75
|
+
this.line(bold("Body:"));
|
|
76
|
+
try {
|
|
77
|
+
this.line(JSON.stringify(JSON.parse(body), null, 2));
|
|
78
|
+
} catch {
|
|
79
|
+
this.line(body);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return response.status >= 400 ? 1 : 0;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
ApiCommand = __decorate([__decorateParam(0, inject(DI_TOKENS.Application))], ApiCommand);
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/quarry/commands/event-list.command.ts
|
|
88
|
+
let EventListCommand = class EventListCommand extends Command {
|
|
89
|
+
modules;
|
|
90
|
+
static command = "event:list";
|
|
91
|
+
static description = "List all registered event listeners";
|
|
92
|
+
constructor(modules) {
|
|
93
|
+
super();
|
|
94
|
+
this.modules = modules;
|
|
95
|
+
}
|
|
96
|
+
handle() {
|
|
97
|
+
const listeners = this.modules.getAllListeners();
|
|
98
|
+
if (listeners.length === 0) {
|
|
99
|
+
this.info("No event listeners found");
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
const rows = [];
|
|
103
|
+
for (const ListenerClass of listeners) {
|
|
104
|
+
const handlers = getListenerHandlers(ListenerClass);
|
|
105
|
+
for (const { methodName, event, options } of handlers) rows.push([
|
|
106
|
+
event,
|
|
107
|
+
ListenerClass.name,
|
|
108
|
+
methodName,
|
|
109
|
+
String(options?.priority ?? 0),
|
|
110
|
+
options?.blocking ? "Yes" : "No"
|
|
111
|
+
]);
|
|
112
|
+
}
|
|
113
|
+
if (rows.length === 0) {
|
|
114
|
+
this.info("No event handlers found");
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
this.table([
|
|
118
|
+
"Event",
|
|
119
|
+
"Listener",
|
|
120
|
+
"Method",
|
|
121
|
+
"Priority",
|
|
122
|
+
"Blocking"
|
|
123
|
+
], rows);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
EventListCommand = __decorate([__decorateParam(0, inject(DI_TOKENS.ModuleRegistry))], EventListCommand);
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/quarry/commands/help.command.ts
|
|
129
|
+
let HelpCommand = class HelpCommand extends Command {
|
|
130
|
+
quarryRegistry;
|
|
131
|
+
static command = "help {command?}";
|
|
132
|
+
static description = "Show help for a command or list all commands";
|
|
133
|
+
static aliases = ["list"];
|
|
134
|
+
constructor(quarryRegistry) {
|
|
135
|
+
super();
|
|
136
|
+
this.quarryRegistry = quarryRegistry;
|
|
137
|
+
}
|
|
138
|
+
async handle() {
|
|
139
|
+
const commandName = this.string("command");
|
|
140
|
+
if (!commandName) {
|
|
141
|
+
const listing = await this.quarryRegistry.listUsage();
|
|
142
|
+
this.line(listing);
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const usage = await this.quarryRegistry.usage(commandName);
|
|
147
|
+
this.line(usage);
|
|
148
|
+
return 0;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (error instanceof CommandNotFoundError) {
|
|
151
|
+
this.fail(`Unknown command: ${commandName}`);
|
|
152
|
+
return 1;
|
|
153
|
+
}
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
HelpCommand = __decorate([__decorateParam(0, inject(DI_TOKENS.Quarry))], HelpCommand);
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/quarry/commands/i18n-utils.ts
|
|
161
|
+
function computeKeyDiff(baseKeys, targetKeys) {
|
|
162
|
+
const missing = [];
|
|
163
|
+
const extra = [];
|
|
164
|
+
for (const key of baseKeys) if (!targetKeys.has(key)) missing.push(key);
|
|
165
|
+
for (const key of targetKeys) if (!baseKeys.has(key)) extra.push(key);
|
|
166
|
+
return {
|
|
167
|
+
missing: missing.sort(),
|
|
168
|
+
extra: extra.sort()
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function extractNamespace(key, depth) {
|
|
172
|
+
return key.split(".").slice(0, depth).join(".");
|
|
173
|
+
}
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/quarry/commands/i18n-check.command.ts
|
|
176
|
+
let I18nCheckCommand = class I18nCheckCommand extends Command {
|
|
177
|
+
loader;
|
|
178
|
+
static command = "i18n:check {--locale= : Check a specific locale only} {--prefix= : Filter by namespace prefix}";
|
|
179
|
+
static description = "Check i18n translations for missing or extra keys";
|
|
180
|
+
constructor(loader) {
|
|
181
|
+
super();
|
|
182
|
+
this.loader = loader;
|
|
183
|
+
}
|
|
184
|
+
handle() {
|
|
185
|
+
const localeFilter = this.string("locale");
|
|
186
|
+
const prefix = this.string("prefix");
|
|
187
|
+
const filterOptions = prefix ? { only: [prefix] } : void 0;
|
|
188
|
+
const enKeys = new Set(Object.keys(this.loader.getFilteredMessages("en", filterOptions)));
|
|
189
|
+
if (enKeys.size === 0) {
|
|
190
|
+
this.info("No message keys found");
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
const locales = this.loader.getAvailableLocales().filter((l) => l !== "en");
|
|
194
|
+
const targets = localeFilter ? locales.filter((l) => l === localeFilter) : locales;
|
|
195
|
+
if (targets.length === 0) {
|
|
196
|
+
this.info(localeFilter ? `Locale "${localeFilter}" not found` : "No non-en locales configured");
|
|
197
|
+
return 0;
|
|
198
|
+
}
|
|
199
|
+
let totalIssues = 0;
|
|
200
|
+
const summaryRows = [];
|
|
201
|
+
for (const locale of targets) {
|
|
202
|
+
const { missing, extra } = computeKeyDiff(enKeys, new Set(Object.keys(this.loader.getFilteredMessages(locale, filterOptions))));
|
|
203
|
+
this.newLine();
|
|
204
|
+
this.info(`Locale: ${locale}`);
|
|
205
|
+
if (missing.length > 0) {
|
|
206
|
+
this.warn(` Missing (${missing.length}):`);
|
|
207
|
+
for (const key of missing) this.line(` ${key}`);
|
|
208
|
+
} else this.line(" Missing (0)");
|
|
209
|
+
if (extra.length > 0) {
|
|
210
|
+
this.warn(` Extra (${extra.length}):`);
|
|
211
|
+
for (const key of extra) this.line(` ${key}`);
|
|
212
|
+
} else this.line(" Extra (0)");
|
|
213
|
+
totalIssues += missing.length + extra.length;
|
|
214
|
+
summaryRows.push([
|
|
215
|
+
locale,
|
|
216
|
+
String(enKeys.size),
|
|
217
|
+
String(missing.length),
|
|
218
|
+
String(extra.length)
|
|
219
|
+
]);
|
|
220
|
+
}
|
|
221
|
+
this.newLine();
|
|
222
|
+
this.table([
|
|
223
|
+
"Locale",
|
|
224
|
+
"Total",
|
|
225
|
+
"Missing",
|
|
226
|
+
"Extra"
|
|
227
|
+
], summaryRows);
|
|
228
|
+
if (totalIssues > 0) {
|
|
229
|
+
this.newLine();
|
|
230
|
+
this.fail(`${totalIssues} issue(s) found`);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
this.newLine();
|
|
234
|
+
this.success("All translations are complete");
|
|
235
|
+
return 0;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
I18nCheckCommand = __decorate([__decorateParam(0, inject(I18N_TOKENS.MessageLoader))], I18nCheckCommand);
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/quarry/commands/i18n-duplicates.command.ts
|
|
241
|
+
let I18nDuplicatesCommand = class I18nDuplicatesCommand extends Command {
|
|
242
|
+
loader;
|
|
243
|
+
static command = "i18n:duplicates {--locale= : Locale to check (default: en)} {--prefix= : Filter by namespace prefix}";
|
|
244
|
+
static description = "Find i18n keys with duplicate translation values";
|
|
245
|
+
constructor(loader) {
|
|
246
|
+
super();
|
|
247
|
+
this.loader = loader;
|
|
248
|
+
}
|
|
249
|
+
handle() {
|
|
250
|
+
const locale = this.string("locale") || "en";
|
|
251
|
+
const prefix = this.string("prefix");
|
|
252
|
+
const filterOptions = prefix ? { only: [prefix] } : void 0;
|
|
253
|
+
const messages = this.loader.getFilteredMessages(locale, filterOptions);
|
|
254
|
+
const valueToKeys = /* @__PURE__ */ new Map();
|
|
255
|
+
for (const [key, value] of Object.entries(messages)) {
|
|
256
|
+
const existing = valueToKeys.get(value);
|
|
257
|
+
if (existing) existing.push(key);
|
|
258
|
+
else valueToKeys.set(value, [key]);
|
|
259
|
+
}
|
|
260
|
+
const duplicates = [];
|
|
261
|
+
for (const [value, keys] of valueToKeys) if (keys.length > 1) duplicates.push([value, keys.sort().join(", ")]);
|
|
262
|
+
if (duplicates.length === 0) {
|
|
263
|
+
this.info("No duplicate values found");
|
|
264
|
+
return 0;
|
|
265
|
+
}
|
|
266
|
+
duplicates.sort((a, b) => a[0].localeCompare(b[0]));
|
|
267
|
+
this.table(["Value", "Keys"], duplicates);
|
|
268
|
+
return 0;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
I18nDuplicatesCommand = __decorate([__decorateParam(0, inject(I18N_TOKENS.MessageLoader))], I18nDuplicatesCommand);
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/quarry/commands/i18n-list.command.ts
|
|
274
|
+
let I18nListCommand = class I18nListCommand extends Command {
|
|
275
|
+
loader;
|
|
276
|
+
static command = "i18n:list {--locale= : Show keys for a specific locale} {--prefix= : Filter by namespace prefix} {--values : Show translated values}";
|
|
277
|
+
static description = "List all i18n message keys";
|
|
278
|
+
constructor(loader) {
|
|
279
|
+
super();
|
|
280
|
+
this.loader = loader;
|
|
281
|
+
}
|
|
282
|
+
handle() {
|
|
283
|
+
const localeFilter = this.string("locale");
|
|
284
|
+
const prefix = this.string("prefix");
|
|
285
|
+
const showValues = this.boolean("values");
|
|
286
|
+
const filterOptions = prefix ? { only: [prefix] } : void 0;
|
|
287
|
+
const enMessages = this.loader.getFilteredMessages("en", filterOptions);
|
|
288
|
+
const enKeys = Object.keys(enMessages).sort();
|
|
289
|
+
if (enKeys.length === 0) {
|
|
290
|
+
this.info("No message keys found");
|
|
291
|
+
return 0;
|
|
292
|
+
}
|
|
293
|
+
if (localeFilter && showValues) {
|
|
294
|
+
const localeMessages = this.loader.getFilteredMessages(localeFilter, filterOptions);
|
|
295
|
+
const rows = enKeys.map((key) => [key, localeMessages[key] ?? "-"]);
|
|
296
|
+
this.table(["Key", "Value"], rows);
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
const locales = localeFilter ? [localeFilter] : this.loader.getAvailableLocales();
|
|
300
|
+
const localeMessages = /* @__PURE__ */ new Map();
|
|
301
|
+
for (const locale of locales) localeMessages.set(locale, new Set(Object.keys(this.loader.getFilteredMessages(locale, filterOptions))));
|
|
302
|
+
const headers = ["Key", ...locales];
|
|
303
|
+
const rows = enKeys.map((key) => {
|
|
304
|
+
return [key, ...locales.map((locale) => localeMessages.get(locale).has(key) ? "Y" : "N")];
|
|
305
|
+
});
|
|
306
|
+
this.table(headers, rows);
|
|
307
|
+
return 0;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
I18nListCommand = __decorate([__decorateParam(0, inject(I18N_TOKENS.MessageLoader))], I18nListCommand);
|
|
311
|
+
//#endregion
|
|
312
|
+
//#region src/quarry/commands/i18n-namespaces.command.ts
|
|
313
|
+
let I18nNamespacesCommand = class I18nNamespacesCommand extends Command {
|
|
314
|
+
loader;
|
|
315
|
+
static command = "i18n:namespaces {--depth= : Namespace depth (default: 1)} {--locale= : Show counts for a specific locale}";
|
|
316
|
+
static description = "List i18n message namespaces with key counts";
|
|
317
|
+
constructor(loader) {
|
|
318
|
+
super();
|
|
319
|
+
this.loader = loader;
|
|
320
|
+
}
|
|
321
|
+
handle() {
|
|
322
|
+
const depth = this.number("depth") || 1;
|
|
323
|
+
const localeFilter = this.string("locale");
|
|
324
|
+
const locales = localeFilter ? [localeFilter] : this.loader.getAvailableLocales();
|
|
325
|
+
const namespaceCounts = /* @__PURE__ */ new Map();
|
|
326
|
+
for (const locale of locales) {
|
|
327
|
+
const messages = this.loader.getFilteredMessages(locale);
|
|
328
|
+
for (const key of Object.keys(messages)) {
|
|
329
|
+
const ns = extractNamespace(key, depth);
|
|
330
|
+
if (!namespaceCounts.has(ns)) namespaceCounts.set(ns, /* @__PURE__ */ new Map());
|
|
331
|
+
const counts = namespaceCounts.get(ns);
|
|
332
|
+
counts.set(locale, (counts.get(locale) ?? 0) + 1);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (namespaceCounts.size === 0) {
|
|
336
|
+
this.info("No namespaces found");
|
|
337
|
+
return 0;
|
|
338
|
+
}
|
|
339
|
+
const sortedNamespaces = [...namespaceCounts.keys()].sort();
|
|
340
|
+
const headers = ["Namespace", ...locales];
|
|
341
|
+
const rows = sortedNamespaces.map((ns) => {
|
|
342
|
+
const counts = namespaceCounts.get(ns);
|
|
343
|
+
return [ns, ...locales.map((locale) => String(counts.get(locale) ?? 0))];
|
|
344
|
+
});
|
|
345
|
+
this.table(headers, rows);
|
|
346
|
+
return 0;
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
I18nNamespacesCommand = __decorate([__decorateParam(0, inject(I18N_TOKENS.MessageLoader))], I18nNamespacesCommand);
|
|
350
|
+
//#endregion
|
|
351
|
+
//#region src/quarry/commands/i18n-search.command.ts
|
|
352
|
+
let I18nSearchCommand = class I18nSearchCommand extends Command {
|
|
353
|
+
loader;
|
|
354
|
+
static command = "i18n:search {query : Search term (substring match)} {--locale= : Locale to search in (default: en)} {--keys-only : Only match key names, not values}";
|
|
355
|
+
static description = "Search for i18n message keys or values";
|
|
356
|
+
constructor(loader) {
|
|
357
|
+
super();
|
|
358
|
+
this.loader = loader;
|
|
359
|
+
}
|
|
360
|
+
handle() {
|
|
361
|
+
const query = this.string("query").toLowerCase();
|
|
362
|
+
const locale = this.string("locale") || "en";
|
|
363
|
+
const keysOnly = this.boolean("keys-only");
|
|
364
|
+
const messages = this.loader.getFilteredMessages(locale);
|
|
365
|
+
const matches = [];
|
|
366
|
+
for (const [key, value] of Object.entries(messages)) {
|
|
367
|
+
const keyMatch = key.toLowerCase().includes(query);
|
|
368
|
+
const valueMatch = !keysOnly && value.toLowerCase().includes(query);
|
|
369
|
+
if (keyMatch || valueMatch) matches.push([key, value]);
|
|
370
|
+
}
|
|
371
|
+
if (matches.length === 0) {
|
|
372
|
+
this.info(`No keys matching "${this.string("query")}" found`);
|
|
373
|
+
return 0;
|
|
374
|
+
}
|
|
375
|
+
matches.sort((a, b) => a[0].localeCompare(b[0]));
|
|
376
|
+
this.table(["Key", "Value"], matches);
|
|
377
|
+
return 0;
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
I18nSearchCommand = __decorate([__decorateParam(0, inject(I18N_TOKENS.MessageLoader))], I18nSearchCommand);
|
|
381
|
+
//#endregion
|
|
382
|
+
//#region src/quarry/commands/i18n-stats.command.ts
|
|
383
|
+
let I18nStatsCommand = class I18nStatsCommand extends Command {
|
|
384
|
+
loader;
|
|
385
|
+
static command = "i18n:stats {--prefix= : Filter by namespace prefix}";
|
|
386
|
+
static description = "Show i18n translation coverage statistics";
|
|
387
|
+
constructor(loader) {
|
|
388
|
+
super();
|
|
389
|
+
this.loader = loader;
|
|
390
|
+
}
|
|
391
|
+
handle() {
|
|
392
|
+
const prefix = this.string("prefix");
|
|
393
|
+
const filterOptions = prefix ? { only: [prefix] } : void 0;
|
|
394
|
+
const enKeys = new Set(Object.keys(this.loader.getFilteredMessages("en", filterOptions)));
|
|
395
|
+
if (enKeys.size === 0) {
|
|
396
|
+
this.info("No message keys found");
|
|
397
|
+
return 0;
|
|
398
|
+
}
|
|
399
|
+
const locales = this.loader.getAvailableLocales();
|
|
400
|
+
const rows = [];
|
|
401
|
+
for (const locale of locales) {
|
|
402
|
+
const localeKeys = new Set(Object.keys(this.loader.getFilteredMessages(locale, filterOptions)));
|
|
403
|
+
const isBase = locale === "en";
|
|
404
|
+
let translated = 0;
|
|
405
|
+
for (const key of enKeys) if (localeKeys.has(key)) translated++;
|
|
406
|
+
const missing = enKeys.size - translated;
|
|
407
|
+
let extra = 0;
|
|
408
|
+
for (const key of localeKeys) if (!enKeys.has(key)) extra++;
|
|
409
|
+
const coverage = (translated / enKeys.size * 100).toFixed(1) + "%";
|
|
410
|
+
rows.push([
|
|
411
|
+
locale,
|
|
412
|
+
String(enKeys.size),
|
|
413
|
+
String(translated),
|
|
414
|
+
String(missing),
|
|
415
|
+
isBase ? "-" : String(extra),
|
|
416
|
+
coverage
|
|
417
|
+
]);
|
|
418
|
+
}
|
|
419
|
+
this.table([
|
|
420
|
+
"Locale",
|
|
421
|
+
"Keys",
|
|
422
|
+
"Translated",
|
|
423
|
+
"Missing",
|
|
424
|
+
"Extra",
|
|
425
|
+
"Coverage"
|
|
426
|
+
], rows);
|
|
427
|
+
return 0;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
I18nStatsCommand = __decorate([__decorateParam(0, inject(I18N_TOKENS.MessageLoader))], I18nStatsCommand);
|
|
431
|
+
//#endregion
|
|
432
|
+
//#region src/quarry/commands/mcp-serve.command.ts
|
|
433
|
+
let McpServeCommand = class McpServeCommand extends Command {
|
|
434
|
+
app;
|
|
435
|
+
openAPIService;
|
|
436
|
+
static command = "mcp:serve {--url= : Base URL for external dispatch} {--header=* : Headers (Key:Value)} {--tag=* : Only expose routes with these OpenAPI tags} {--path= : Only expose routes matching this path prefix}";
|
|
437
|
+
static description = "Start an MCP stdio server exposing API routes as tools";
|
|
438
|
+
constructor(app, openAPIService) {
|
|
439
|
+
super();
|
|
440
|
+
this.app = app;
|
|
441
|
+
this.openAPIService = openAPIService;
|
|
442
|
+
}
|
|
443
|
+
async handle() {
|
|
444
|
+
const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js");
|
|
445
|
+
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
446
|
+
const baseUrl = this.string("url");
|
|
447
|
+
const headerArgs = this.array("header");
|
|
448
|
+
const tags = this.array("tag");
|
|
449
|
+
const pathPrefix = this.string("path");
|
|
450
|
+
const headers = {};
|
|
451
|
+
for (const h of headerArgs) {
|
|
452
|
+
const colonIdx = h.indexOf(":");
|
|
453
|
+
if (colonIdx > 0) headers[h.slice(0, colonIdx).trim()] = h.slice(colonIdx + 1).trim();
|
|
454
|
+
}
|
|
455
|
+
const hono = await this.app.ensureHono();
|
|
456
|
+
const spec = this.openAPIService.getSpec(hono, this.app.container);
|
|
457
|
+
const service = new OpenApiToolsService(spec, { dispatcher: baseUrl ? async (method, url, opts) => {
|
|
458
|
+
const fullUrl = `${baseUrl}${url}`;
|
|
459
|
+
try {
|
|
460
|
+
return await fetch(fullUrl, {
|
|
461
|
+
method,
|
|
462
|
+
headers: {
|
|
463
|
+
"Content-Type": "application/json",
|
|
464
|
+
...headers,
|
|
465
|
+
...opts?.headers
|
|
466
|
+
},
|
|
467
|
+
body: opts?.body !== void 0 ? JSON.stringify(opts.body) : void 0
|
|
468
|
+
});
|
|
469
|
+
} catch (error) {
|
|
470
|
+
throw new Error(`MCP dispatch failed: ${method} ${fullUrl} — ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
471
|
+
}
|
|
472
|
+
} : async (method, url, opts) => {
|
|
473
|
+
const request = new Request(`http://localhost${url}`, {
|
|
474
|
+
method,
|
|
475
|
+
headers: {
|
|
476
|
+
"Content-Type": "application/json",
|
|
477
|
+
...headers,
|
|
478
|
+
...opts?.headers
|
|
479
|
+
},
|
|
480
|
+
body: opts?.body !== void 0 ? JSON.stringify(opts.body) : void 0
|
|
481
|
+
});
|
|
482
|
+
try {
|
|
483
|
+
return await hono.fetch(request, this.app.env);
|
|
484
|
+
} catch (error) {
|
|
485
|
+
throw new Error(`MCP dispatch failed: ${method} ${url} — ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
486
|
+
}
|
|
487
|
+
} });
|
|
488
|
+
const filter = {
|
|
489
|
+
tags: tags.length > 0 ? tags : void 0,
|
|
490
|
+
pathPrefix: pathPrefix || void 0
|
|
491
|
+
};
|
|
492
|
+
const tools = service.getTools(filter);
|
|
493
|
+
const config = this.app.container.resolve(OPENAPI_TOKENS.ConfigService).getEffectiveConfig();
|
|
494
|
+
const server = new McpServer({
|
|
495
|
+
name: config.info.title,
|
|
496
|
+
version: config.info.version
|
|
497
|
+
});
|
|
498
|
+
for (const tool of tools) {
|
|
499
|
+
const inputSchema = z.fromJSONSchema(tool.inputSchema);
|
|
500
|
+
server.registerTool(tool.name, {
|
|
501
|
+
description: tool.description,
|
|
502
|
+
inputSchema
|
|
503
|
+
}, async (args) => {
|
|
504
|
+
const result = await service.executeTool(tool.name, args);
|
|
505
|
+
return { content: [{
|
|
506
|
+
type: "text",
|
|
507
|
+
text: `Status: ${result.status}\n\n${result.body}`
|
|
508
|
+
}] };
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
server.registerResource("openapi-spec", "openapi://spec", {
|
|
512
|
+
description: "Full OpenAPI specification",
|
|
513
|
+
mimeType: "application/json"
|
|
514
|
+
}, () => ({ contents: [{
|
|
515
|
+
uri: "openapi://spec",
|
|
516
|
+
mimeType: "application/json",
|
|
517
|
+
text: JSON.stringify(spec, null, 2)
|
|
518
|
+
}] }));
|
|
519
|
+
const transport = new StdioServerTransport();
|
|
520
|
+
const closed = new Promise((resolve) => {
|
|
521
|
+
transport.onclose = resolve;
|
|
522
|
+
});
|
|
523
|
+
await server.connect(transport);
|
|
524
|
+
process.stderr.write(`MCP server started with ${tools.length} tool(s)\n`);
|
|
525
|
+
await closed;
|
|
526
|
+
return 0;
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
McpServeCommand = __decorate([__decorateParam(0, inject(DI_TOKENS.Application)), __decorateParam(1, inject(OPENAPI_TOKENS.OpenAPIService))], McpServeCommand);
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region src/quarry/commands/mcp-tools.command.ts
|
|
532
|
+
let McpToolsCommand = class McpToolsCommand extends Command {
|
|
533
|
+
app;
|
|
534
|
+
openAPIService;
|
|
535
|
+
static command = "mcp:tools {--tag=* : Filter by OpenAPI tags} {--path= : Filter by path prefix}";
|
|
536
|
+
static description = "List API routes that would be exposed as MCP tools";
|
|
537
|
+
constructor(app, openAPIService) {
|
|
538
|
+
super();
|
|
539
|
+
this.app = app;
|
|
540
|
+
this.openAPIService = openAPIService;
|
|
541
|
+
}
|
|
542
|
+
async handle() {
|
|
543
|
+
const tags = this.array("tag");
|
|
544
|
+
const pathPrefix = this.string("path");
|
|
545
|
+
const hono = await this.app.ensureHono();
|
|
546
|
+
const service = new OpenApiToolsService(this.openAPIService.getSpec(hono, this.app.container));
|
|
547
|
+
const filter = {
|
|
548
|
+
tags: tags.length > 0 ? tags : void 0,
|
|
549
|
+
pathPrefix: pathPrefix || void 0
|
|
550
|
+
};
|
|
551
|
+
const tools = service.getTools(filter);
|
|
552
|
+
if (tools.length === 0) {
|
|
553
|
+
this.info("No tools found");
|
|
554
|
+
return 0;
|
|
555
|
+
}
|
|
556
|
+
this.table([
|
|
557
|
+
"Name",
|
|
558
|
+
"Method",
|
|
559
|
+
"Path",
|
|
560
|
+
"Description"
|
|
561
|
+
], tools.map((t) => [
|
|
562
|
+
t.name,
|
|
563
|
+
t.method,
|
|
564
|
+
t.path,
|
|
565
|
+
t.description
|
|
566
|
+
]));
|
|
567
|
+
return 0;
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
McpToolsCommand = __decorate([__decorateParam(0, inject(DI_TOKENS.Application)), __decorateParam(1, inject(OPENAPI_TOKENS.OpenAPIService))], McpToolsCommand);
|
|
571
|
+
//#endregion
|
|
572
|
+
//#region src/quarry/commands/queue-list.command.ts
|
|
573
|
+
let QueueListCommand = class QueueListCommand extends Command {
|
|
574
|
+
consumers;
|
|
575
|
+
static command = "queue:list";
|
|
576
|
+
static description = "List all registered queue consumers";
|
|
577
|
+
constructor(consumers) {
|
|
578
|
+
super();
|
|
579
|
+
this.consumers = consumers;
|
|
580
|
+
}
|
|
581
|
+
handle() {
|
|
582
|
+
const consumers = this.consumers.getAllConsumers();
|
|
583
|
+
if (consumers.length === 0) {
|
|
584
|
+
this.info("No queue consumers found");
|
|
585
|
+
return 0;
|
|
586
|
+
}
|
|
587
|
+
this.table(["Consumer", "Message Types"], consumers.map((c) => [c.constructor.name, c.messageTypes.join(", ")]));
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
QueueListCommand = __decorate([__decorateParam(0, inject(DI_TOKENS.ConsumerRegistry))], QueueListCommand);
|
|
591
|
+
//#endregion
|
|
592
|
+
//#region src/quarry/commands/route-list.command.ts
|
|
593
|
+
let RouteListCommand = class RouteListCommand extends Command {
|
|
594
|
+
registry;
|
|
595
|
+
static command = "route:list {--method= : Filter by HTTP method} {--path= : Filter by path substring} {--name= : Filter by route name} {--hidden : Include hidden routes}";
|
|
596
|
+
static description = "List all registered routes";
|
|
597
|
+
constructor(registry) {
|
|
598
|
+
super();
|
|
599
|
+
this.registry = registry;
|
|
600
|
+
}
|
|
601
|
+
handle() {
|
|
602
|
+
const methodFilter = this.string("method").toUpperCase();
|
|
603
|
+
const pathFilter = this.string("path");
|
|
604
|
+
const nameFilter = this.string("name");
|
|
605
|
+
const showHidden = this.boolean("hidden");
|
|
606
|
+
let routes = this.registry.all();
|
|
607
|
+
if (!showHidden) routes = routes.filter((r) => !r.hidden);
|
|
608
|
+
if (methodFilter) routes = routes.filter((r) => r.method.toUpperCase() === methodFilter);
|
|
609
|
+
if (pathFilter) routes = routes.filter((r) => r.path.includes(pathFilter));
|
|
610
|
+
if (nameFilter) routes = routes.filter((r) => r.name?.includes(nameFilter));
|
|
611
|
+
if (routes.length === 0) {
|
|
612
|
+
this.info("No routes found");
|
|
613
|
+
return 0;
|
|
614
|
+
}
|
|
615
|
+
this.table([
|
|
616
|
+
"Method",
|
|
617
|
+
"Path",
|
|
618
|
+
"Name",
|
|
619
|
+
"Handler",
|
|
620
|
+
"Domain"
|
|
621
|
+
], routes.map((r) => this.formatRow(r)));
|
|
622
|
+
}
|
|
623
|
+
formatRow(route) {
|
|
624
|
+
return [
|
|
625
|
+
route.method.toUpperCase(),
|
|
626
|
+
route.path,
|
|
627
|
+
route.name ?? "-",
|
|
628
|
+
`${route.controller}.${route.action}`,
|
|
629
|
+
route.domain ?? "-"
|
|
630
|
+
];
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
RouteListCommand = __decorate([__decorateParam(0, inject(ROUTER_TOKENS.RouteRegistry))], RouteListCommand);
|
|
634
|
+
//#endregion
|
|
635
|
+
//#region src/quarry/commands/route-types.command.ts
|
|
636
|
+
let RouteTypesCommand = class RouteTypesCommand extends Command {
|
|
637
|
+
registry;
|
|
638
|
+
localePathService;
|
|
639
|
+
static command = "route:types {--output=src/stratal.d.ts : Output file path}";
|
|
640
|
+
static description = "Generate TypeScript types for named routes";
|
|
641
|
+
constructor(registry, localePathService) {
|
|
642
|
+
super();
|
|
643
|
+
this.registry = registry;
|
|
644
|
+
this.localePathService = localePathService;
|
|
645
|
+
}
|
|
646
|
+
handle() {
|
|
647
|
+
const outputPath = resolve(this.string("output") || "src/stratal.d.ts");
|
|
648
|
+
const namedRoutes = this.registry.named();
|
|
649
|
+
if (namedRoutes.length === 0) {
|
|
650
|
+
this.warn("No named routes found. Add name to your @Route() or @Get()/@Post() decorators.");
|
|
651
|
+
return 0;
|
|
652
|
+
}
|
|
653
|
+
writeFileSync(outputPath, this.generateDeclaration(namedRoutes), "utf-8");
|
|
654
|
+
this.info(`Generated route types for ${namedRoutes.length} named routes → ${outputPath}`);
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Generate the StratalRouteMap declaration content.
|
|
658
|
+
*/
|
|
659
|
+
generateDeclaration(routes) {
|
|
660
|
+
const localeConfig = this.localePathService.enabled ? this.localePathService.localePathConfig : null;
|
|
661
|
+
const localeType = localeConfig ? localeConfig.allLocales.map((l) => `'${l}'`).join(" | ") : null;
|
|
662
|
+
const localeOptional = localeConfig ? this.localePathService.prefixDefaultLocale !== true : false;
|
|
663
|
+
const entries = routes.filter((r) => r.name !== void 0).sort((a, b) => a.name.localeCompare(b.name)).map((route) => {
|
|
664
|
+
const paramEntries = [...route.paramNames.map((p) => `${p}: string`), ...route.domainParamNames.map((p) => `${p}: string`)];
|
|
665
|
+
if (localeType && route.localePaths?.length) {
|
|
666
|
+
const optionalMarker = localeOptional ? "?" : "";
|
|
667
|
+
paramEntries.push(`locale${optionalMarker}: StratalLocale`);
|
|
668
|
+
}
|
|
669
|
+
const indexSignature = localeType && route.localePaths?.length ? "[key: string]: string | StratalLocale | undefined" : "[key: string]: string | undefined";
|
|
670
|
+
paramEntries.push(indexSignature);
|
|
671
|
+
const paramsType = `{ ${paramEntries.join("; ")} }`;
|
|
672
|
+
return ` '${route.name}': { params: ${paramsType} }`;
|
|
673
|
+
}).join("\n");
|
|
674
|
+
const lines = ["// Auto-generated by `quarry route:types` — do not edit manually", "declare module 'stratal/router' {"];
|
|
675
|
+
if (localeType) {
|
|
676
|
+
lines.push(` type StratalLocale = ${localeType}`);
|
|
677
|
+
lines.push("");
|
|
678
|
+
}
|
|
679
|
+
lines.push(" interface StratalRouteMap {", entries, " }", "}");
|
|
680
|
+
return [
|
|
681
|
+
...lines,
|
|
682
|
+
"",
|
|
683
|
+
"export {}",
|
|
684
|
+
""
|
|
685
|
+
].join("\n");
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
RouteTypesCommand = __decorate([__decorateParam(0, inject(ROUTER_TOKENS.RouteRegistry)), __decorateParam(1, inject(ROUTER_TOKENS.LocalePathService))], RouteTypesCommand);
|
|
689
|
+
//#endregion
|
|
690
|
+
//#region src/quarry/commands/schedule-list.command.ts
|
|
691
|
+
let ScheduleListCommand = class ScheduleListCommand extends Command {
|
|
692
|
+
cron;
|
|
693
|
+
static command = "schedule:list";
|
|
694
|
+
static description = "List all registered cron jobs";
|
|
695
|
+
constructor(cron) {
|
|
696
|
+
super();
|
|
697
|
+
this.cron = cron;
|
|
698
|
+
}
|
|
699
|
+
handle() {
|
|
700
|
+
const schedules = this.cron.getAllSchedules();
|
|
701
|
+
if (schedules.length === 0) {
|
|
702
|
+
this.info("No cron jobs found");
|
|
703
|
+
return 0;
|
|
704
|
+
}
|
|
705
|
+
const rows = [];
|
|
706
|
+
for (const schedule of schedules) {
|
|
707
|
+
const jobs = this.cron.getJobsForSchedule(schedule);
|
|
708
|
+
for (const { jobClass } of jobs) rows.push([schedule, jobClass.name]);
|
|
709
|
+
}
|
|
710
|
+
this.table(["Schedule", "Job"], rows);
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
ScheduleListCommand = __decorate([__decorateParam(0, inject(DI_TOKENS.Cron))], ScheduleListCommand);
|
|
714
|
+
//#endregion
|
|
715
|
+
//#region src/quarry/builtin-quarry.module.ts
|
|
716
|
+
let BuiltinQuarryModule = class BuiltinQuarryModule {};
|
|
717
|
+
BuiltinQuarryModule = __decorate([Module({ providers: [
|
|
718
|
+
HelpCommand,
|
|
719
|
+
DbSeedCommand,
|
|
720
|
+
DbSeedListCommand,
|
|
721
|
+
RouteListCommand,
|
|
722
|
+
RouteTypesCommand,
|
|
723
|
+
EventListCommand,
|
|
724
|
+
ScheduleListCommand,
|
|
725
|
+
QueueListCommand,
|
|
726
|
+
McpServeCommand,
|
|
727
|
+
McpToolsCommand,
|
|
728
|
+
ApiCommand,
|
|
729
|
+
I18nCheckCommand,
|
|
730
|
+
I18nDuplicatesCommand,
|
|
731
|
+
I18nListCommand,
|
|
732
|
+
I18nNamespacesCommand,
|
|
733
|
+
I18nSearchCommand,
|
|
734
|
+
I18nStatsCommand
|
|
735
|
+
] })], BuiltinQuarryModule);
|
|
736
|
+
//#endregion
|
|
737
|
+
//#region src/quarry/quarry-runner.ts
|
|
738
|
+
/**
|
|
739
|
+
* Builds a `Stratal` instance for the quarry CLI entry (`src/quarry.ts`).
|
|
740
|
+
*
|
|
741
|
+
* Synthesizes a wrapper module from the given `imports` and `providers`,
|
|
742
|
+
* so CLI-only classes (seeders, ecosystem CLI commands) stay out of the
|
|
743
|
+
* worker bundle — `src/index.ts` doesn't reference any of them. Forces
|
|
744
|
+
* CLI-friendly logging defaults (`level: 'error'`, `formatter: 'pretty'`).
|
|
745
|
+
*
|
|
746
|
+
* @example
|
|
747
|
+
* ```ts
|
|
748
|
+
* // src/quarry.ts
|
|
749
|
+
* export default QuarryRunner.run({
|
|
750
|
+
* imports: [AppModule, InertiaQuarryModule],
|
|
751
|
+
* providers: [GeoSeeder, DemoSeeder],
|
|
752
|
+
* })
|
|
753
|
+
* ```
|
|
754
|
+
*/
|
|
755
|
+
var QuarryRunner = class {
|
|
756
|
+
static run(options) {
|
|
757
|
+
let QuarryEntryModule = class QuarryEntryModule {};
|
|
758
|
+
QuarryEntryModule = __decorate([Module({
|
|
759
|
+
imports: [BuiltinQuarryModule, ...options.imports],
|
|
760
|
+
providers: options.providers ?? []
|
|
761
|
+
})], QuarryEntryModule);
|
|
762
|
+
return new Stratal({
|
|
763
|
+
module: QuarryEntryModule,
|
|
764
|
+
exceptionHandler: options.exceptionHandler,
|
|
765
|
+
logging: {
|
|
766
|
+
level: "error",
|
|
767
|
+
formatter: "pretty"
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
//#endregion
|
|
773
|
+
export { ApiCommand, BuiltinQuarryModule, EventListCommand, HelpCommand, McpServeCommand, McpToolsCommand, QuarryRunner, QueueListCommand, RouteListCommand, RouteTypesCommand, ScheduleListCommand };
|
|
774
|
+
|
|
775
|
+
//# sourceMappingURL=runner.mjs.map
|