stratal 0.0.15 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/{application-Du0d8O_e.d.mts → application-zG8b-pol.d.mts} +4 -4
  2. package/dist/{application-Du0d8O_e.d.mts.map → application-zG8b-pol.d.mts.map} +1 -1
  3. package/dist/{base-email.provider-CNwsPbwm.mjs → base-email.provider-Cuw4OAB0.mjs} +1 -1
  4. package/dist/{base-email.provider-CNwsPbwm.mjs.map → base-email.provider-Cuw4OAB0.mjs.map} +1 -1
  5. package/dist/bin/quarry.mjs +47 -43
  6. package/dist/bin/quarry.mjs.map +1 -1
  7. package/dist/cache/index.d.mts +2 -2
  8. package/dist/cache/index.mjs +7 -6
  9. package/dist/cache/index.mjs.map +1 -1
  10. package/dist/colors-DJaRDXoS.mjs +16 -0
  11. package/dist/colors-DJaRDXoS.mjs.map +1 -0
  12. package/dist/{command-DcebcSrL.d.mts → command-B-QH-Vu3.d.mts} +2 -2
  13. package/dist/{command-DcebcSrL.d.mts.map → command-B-QH-Vu3.d.mts.map} +1 -1
  14. package/dist/{command-DG_u5ob2.mjs → command-BvCOD6df.mjs} +10 -9
  15. package/dist/{command-DG_u5ob2.mjs.map → command-BvCOD6df.mjs.map} +1 -1
  16. package/dist/config/index.d.mts +2 -2
  17. package/dist/config/index.mjs +7 -6
  18. package/dist/config/index.mjs.map +1 -1
  19. package/dist/cron/index.d.mts +1 -1
  20. package/dist/cron/index.mjs +1 -1
  21. package/dist/{cron-manager-BRh86QCS.mjs → cron-manager-DR7fiG6o.mjs} +1 -1
  22. package/dist/{cron-manager-BRh86QCS.mjs.map → cron-manager-DR7fiG6o.mjs.map} +1 -1
  23. package/dist/di/index.d.mts +1 -1
  24. package/dist/email/index.d.mts +3 -3
  25. package/dist/email/index.mjs +13 -11
  26. package/dist/email/index.mjs.map +1 -1
  27. package/dist/{en-uVIaxFXR.mjs → en-DaewN8hc.mjs} +1 -1
  28. package/dist/{en-uVIaxFXR.mjs.map → en-DaewN8hc.mjs.map} +1 -1
  29. package/dist/errors/index.d.mts +1 -1
  30. package/dist/errors-H3TZnVeX.mjs +67 -0
  31. package/dist/errors-H3TZnVeX.mjs.map +1 -0
  32. package/dist/events/index.d.mts +2 -2
  33. package/dist/{gateway-context-90CQEQDR.mjs → gateway-context-BkZ4UKaX.mjs} +2 -2
  34. package/dist/{gateway-context-90CQEQDR.mjs.map → gateway-context-BkZ4UKaX.mjs.map} +1 -1
  35. package/dist/guards/index.d.mts +3 -3
  36. package/dist/guards/index.mjs +1 -1
  37. package/dist/{guards-DMbsAxSX.mjs → guards-DUk_Kzst.mjs} +1 -1
  38. package/dist/{guards-DMbsAxSX.mjs.map → guards-DUk_Kzst.mjs.map} +1 -1
  39. package/dist/i18n/index.d.mts +2 -2
  40. package/dist/i18n/index.mjs +11 -10
  41. package/dist/i18n/messages/en/index.d.mts +1 -1
  42. package/dist/i18n/messages/en/index.mjs +1 -1
  43. package/dist/i18n/validation/index.d.mts +1 -1
  44. package/dist/i18n/validation/index.mjs +1 -1
  45. package/dist/{i18n.module-qNrpIVts.mjs → i18n.module-W8OJxg3d.mjs} +8 -8
  46. package/dist/{i18n.module-qNrpIVts.mjs.map → i18n.module-W8OJxg3d.mjs.map} +1 -1
  47. package/dist/{index-D69rxo8H.d.mts → index-BJWm863C.d.mts} +5 -5
  48. package/dist/{index-D69rxo8H.d.mts.map → index-BJWm863C.d.mts.map} +1 -1
  49. package/dist/{index-H-Su81aK.d.mts → index-D9iYu2Yc.d.mts} +3 -3
  50. package/dist/{index-H-Su81aK.d.mts.map → index-D9iYu2Yc.d.mts.map} +1 -1
  51. package/dist/{index-CpAN9ENH.d.mts → index-DVhdhLvE.d.mts} +2 -2
  52. package/dist/{index-CpAN9ENH.d.mts.map → index-DVhdhLvE.d.mts.map} +1 -1
  53. package/dist/{index-CSuHOJc3.d.mts → index-D_w_Rmtd.d.mts} +1 -1
  54. package/dist/{index-CSuHOJc3.d.mts.map → index-D_w_Rmtd.d.mts.map} +1 -1
  55. package/dist/{index-Cfkie8JM.d.mts → index-Dp6A5ywM.d.mts} +1 -1
  56. package/dist/{index-Cfkie8JM.d.mts.map → index-Dp6A5ywM.d.mts.map} +1 -1
  57. package/dist/index.d.mts +3 -3
  58. package/dist/index.mjs +16 -15
  59. package/dist/{is-command-MZDCH-0T.mjs → is-command-BfCgWAcQ.mjs} +2 -2
  60. package/dist/{is-command-MZDCH-0T.mjs.map → is-command-BfCgWAcQ.mjs.map} +1 -1
  61. package/dist/{is-seeder-BN9Ej1r7.mjs → is-seeder-CebjZCDn.mjs} +1 -1
  62. package/dist/{is-seeder-BN9Ej1r7.mjs.map → is-seeder-CebjZCDn.mjs.map} +1 -1
  63. package/dist/logger/index.d.mts +1 -1
  64. package/dist/middleware/index.d.mts +1 -1
  65. package/dist/middleware/index.mjs +2 -2
  66. package/dist/{middleware-iRhNjsPH.mjs → middleware-C0Ebzswy.mjs} +2 -2
  67. package/dist/{middleware-iRhNjsPH.mjs.map → middleware-C0Ebzswy.mjs.map} +1 -1
  68. package/dist/module/index.d.mts +3 -3
  69. package/dist/module/index.mjs +7 -6
  70. package/dist/{module-BH7t7BGG.mjs → module-BgdxxzBe.mjs} +4 -4
  71. package/dist/{module-BH7t7BGG.mjs.map → module-BgdxxzBe.mjs.map} +1 -1
  72. package/dist/openapi/index.d.mts +3 -3
  73. package/dist/openapi/index.mjs +11 -10
  74. package/dist/quarry/index.d.mts +12 -4
  75. package/dist/quarry/index.d.mts.map +1 -1
  76. package/dist/quarry/index.mjs +5 -4
  77. package/dist/{quarry-registry-BPmKVjhG.mjs → quarry-registry-DCwqVcRp.mjs} +11 -3
  78. package/dist/{quarry-registry-BPmKVjhG.mjs.map → quarry-registry-DCwqVcRp.mjs.map} +1 -1
  79. package/dist/queue/index.d.mts +1 -1
  80. package/dist/queue/index.mjs +8 -7
  81. package/dist/queue/index.mjs.map +1 -1
  82. package/dist/{queue.module-BdXWUvIM.mjs → queue.module-BZvmeAMj.mjs} +2 -2
  83. package/dist/{queue.module-BdXWUvIM.mjs.map → queue.module-BZvmeAMj.mjs.map} +1 -1
  84. package/dist/{resend.provider-CQT5be5E.mjs → resend.provider-BCCACQAU.mjs} +2 -2
  85. package/dist/{resend.provider-CQT5be5E.mjs.map → resend.provider-BCCACQAU.mjs.map} +1 -1
  86. package/dist/router/index.d.mts +1 -1
  87. package/dist/router/index.mjs +11 -10
  88. package/dist/{router-context-BLn4PrRG.mjs → router-context-BEJe9HEB.mjs} +1 -1
  89. package/dist/{router-context-BLn4PrRG.mjs.map → router-context-BEJe9HEB.mjs.map} +1 -1
  90. package/dist/s3-storage.provider-BLlzQYiJ.mjs +336 -0
  91. package/dist/s3-storage.provider-BLlzQYiJ.mjs.map +1 -0
  92. package/dist/seeder/index.d.mts +4 -4
  93. package/dist/seeder/index.mjs +4 -3
  94. package/dist/{seeder-DatfjJvU.mjs → seeder-Cupi5jl-.mjs} +3 -3
  95. package/dist/{seeder-DatfjJvU.mjs.map → seeder-Cupi5jl-.mjs.map} +1 -1
  96. package/dist/{smtp.provider-Cj7BUFbJ.mjs → smtp.provider-B8XtOcHU.mjs} +2 -2
  97. package/dist/{smtp.provider-Cj7BUFbJ.mjs.map → smtp.provider-B8XtOcHU.mjs.map} +1 -1
  98. package/dist/storage/index.d.mts +6 -272
  99. package/dist/storage/index.d.mts.map +1 -1
  100. package/dist/storage/index.mjs +11 -9
  101. package/dist/{storage-BtcfgibD.mjs → storage-By_ow2o_.mjs} +34 -410
  102. package/dist/storage-By_ow2o_.mjs.map +1 -0
  103. package/dist/{stratal-Cm0Yy8v4.mjs → stratal-CE0iTz4f.mjs} +7 -7
  104. package/dist/{stratal-Cm0Yy8v4.mjs.map → stratal-CE0iTz4f.mjs.map} +1 -1
  105. package/dist/{types-N84Ak6YT.d.mts → types-CLhOhYsQ.d.mts} +1 -1
  106. package/dist/{types-N84Ak6YT.d.mts.map → types-CLhOhYsQ.d.mts.map} +1 -1
  107. package/dist/{types-Cu4jkeiH.d.mts → types-DahElfUw.d.mts} +1 -1
  108. package/dist/types-DahElfUw.d.mts.map +1 -0
  109. package/dist/usage-generator-C9hWziY4.mjs +158 -0
  110. package/dist/usage-generator-C9hWziY4.mjs.map +1 -0
  111. package/dist/{validation-Dbt-snjx.mjs → validation-Bh875Lyg.mjs} +1 -1
  112. package/dist/{validation-Dbt-snjx.mjs.map → validation-Bh875Lyg.mjs.map} +1 -1
  113. package/dist/websocket/index.d.mts +2 -2
  114. package/dist/websocket/index.mjs +2 -2
  115. package/dist/workers/index.d.mts +1 -1
  116. package/dist/workers/index.mjs +16 -15
  117. package/dist/workers/index.mjs.map +1 -1
  118. package/package.json +3 -7
  119. package/dist/storage-BtcfgibD.mjs.map +0 -1
  120. package/dist/types-Cu4jkeiH.d.mts.map +0 -1
  121. package/dist/usage-generator-BTZDk5zx.mjs +0 -75
  122. package/dist/usage-generator-BTZDk5zx.mjs.map +0 -1
@@ -1,6 +1,6 @@
1
- import { $t as Container, Ht as StratalEnv, It as VersioningOptions, Tt as RouterContext, U as HonoApp, ct as ModuleClass, it as DynamicModule } from "./index-D69rxo8H.mjs";
2
- import { l as LogLevel } from "./index-Cfkie8JM.mjs";
3
- import { r as CommandResult, t as CommandInput } from "./types-N84Ak6YT.mjs";
1
+ import { $t as Container, Ht as StratalEnv, It as VersioningOptions, Tt as RouterContext, U as HonoApp, ct as ModuleClass, it as DynamicModule } from "./index-BJWm863C.mjs";
2
+ import { l as LogLevel } from "./index-Dp6A5ywM.mjs";
3
+ import { r as CommandResult, t as CommandInput } from "./types-CLhOhYsQ.mjs";
4
4
 
5
5
  //#region src/execution-context.d.ts
6
6
  interface StratalExecutionContext {
@@ -113,4 +113,4 @@ declare class Application {
113
113
  }
114
114
  //#endregion
115
115
  export { StratalExecutionContext as i, ApplicationConfig as n, ApplicationOptions as r, Application as t };
116
- //# sourceMappingURL=application-Du0d8O_e.d.mts.map
116
+ //# sourceMappingURL=application-zG8b-pol.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"application-Du0d8O_e.d.mts","names":[],"sources":["../src/execution-context.ts","../src/application.ts"],"mappings":";;;;;UAAiB,uBAAA;EACf,SAAA,CAAU,OAAA,EAAS,OAAA;AAAA;;;UC6BJ,iBAAA;ED7BI;EC+BnB,MAAA,EAAQ,WAAA,GAAc,aAAA;ED/Ba;ECiCnC,OAAA;IACE,KAAA,GAAQ,QAAA;IACR,SAAA;EAAA;EANa;;;;EAYf,UAAA,GAAa,iBAAA;AAAA;AAAA,UAGE,kBAAA,SAA2B,iBAAA;EAC1C,GAAA,EAAK,UAAA;EACL,GAAA,EAAK,uBAAA;AAAA;;;;;;;;;;;AAFP;;;;;;;;;;cAyBa,WAAA;EAvBX;;;EAAA,QA2BQ,UAAA;EAAA,QAEA,OAAA;EAAA,QACA,cAAA;EAAA,QACA,gBAAA;EAAA,QACA,WAAA;EAAA,QACA,MAAA;EAAA,QACA,WAAA;EAAA,SAEC,GAAA,EAAK,UAAA;EAAA,iBACG,SAAA;;IAEH,GAAA;IAAK,GAAA;IAAA,GAAQ;EAAA,GAAU,kBAAA;EA0CjB;;;EAAA,IAXhB,SAAA,CAAA,GAAa,SAAA;EAwFiB;;;EAAA,IAjF9B,IAAA,CAAA,GAAQ,OAAA;EAIN,UAAA,CAAA,GAAc,OAAA;EAqH6C;;;EAzEjE,OAAA,GAAA,CAAW,KAAA,WAAgB,CAAA;EAlGnB;;;EA+GF,WAAA,CAAY,KAAA,EAAO,YAAA,EAAc,SAAA,WAAoB,OAAA;EA1GnD;;;EA8HF,eAAA,CAAgB,UAAA,EAAY,mBAAA,GAAsB,OAAA;EA1H1C;;;EA2Id,uBAAA,CAAwB,MAAA,YAAgB,aAAA;EAQlC,QAAA,CAAA,GAAY,OAAA;EAhJC;;;EA+Jb,aAAA,CAAc,IAAA,UAAc,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,aAAA;EAAA,QAOzD,gBAAA;EAAA,QAoBA,eAAA;EAAA,QASA,sBAAA;EAAA,QAOA,gBAAA;EAhKF;;;EAAA,QA0KE,sBAAA;EA9HG;;;EAAA,QAmJH,qBAAA;EAtIU;;;EAAA,QA0JV,oBAAA;AAAA"}
1
+ {"version":3,"file":"application-zG8b-pol.d.mts","names":[],"sources":["../src/execution-context.ts","../src/application.ts"],"mappings":";;;;;UAAiB,uBAAA;EACf,SAAA,CAAU,OAAA,EAAS,OAAA;AAAA;;;UC6BJ,iBAAA;ED7BI;EC+BnB,MAAA,EAAQ,WAAA,GAAc,aAAA;ED/Ba;ECiCnC,OAAA;IACE,KAAA,GAAQ,QAAA;IACR,SAAA;EAAA;EANa;;;;EAYf,UAAA,GAAa,iBAAA;AAAA;AAAA,UAGE,kBAAA,SAA2B,iBAAA;EAC1C,GAAA,EAAK,UAAA;EACL,GAAA,EAAK,uBAAA;AAAA;;;;;;;;;;;AAFP;;;;;;;;;;cAyBa,WAAA;EAvBX;;;EAAA,QA2BQ,UAAA;EAAA,QAEA,OAAA;EAAA,QACA,cAAA;EAAA,QACA,gBAAA;EAAA,QACA,WAAA;EAAA,QACA,MAAA;EAAA,QACA,WAAA;EAAA,SAEC,GAAA,EAAK,UAAA;EAAA,iBACG,SAAA;;IAEH,GAAA;IAAK,GAAA;IAAA,GAAQ;EAAA,GAAU,kBAAA;EA0CjB;;;EAAA,IAXhB,SAAA,CAAA,GAAa,SAAA;EAwFiB;;;EAAA,IAjF9B,IAAA,CAAA,GAAQ,OAAA;EAIN,UAAA,CAAA,GAAc,OAAA;EAqH6C;;;EAzEjE,OAAA,GAAA,CAAW,KAAA,WAAgB,CAAA;EAlGnB;;;EA+GF,WAAA,CAAY,KAAA,EAAO,YAAA,EAAc,SAAA,WAAoB,OAAA;EA1GnD;;;EA8HF,eAAA,CAAgB,UAAA,EAAY,mBAAA,GAAsB,OAAA;EA1H1C;;;EA2Id,uBAAA,CAAwB,MAAA,YAAgB,aAAA;EAQlC,QAAA,CAAA,GAAY,OAAA;EAhJC;;;EA+Jb,aAAA,CAAc,IAAA,UAAc,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,aAAA;EAAA,QAOzD,gBAAA;EAAA,QAoBA,eAAA;EAAA,QASA,sBAAA;EAAA,QAOA,gBAAA;EAhKF;;;EAAA,QA0KE,sBAAA;EA9HG;;;EAAA,QAmJH,qBAAA;EAtIU;;;EAAA,QA0JV,oBAAA;AAAA"}
@@ -39,4 +39,4 @@ var BaseEmailProvider = class {
39
39
  //#endregion
40
40
  export { BaseEmailProvider as t };
41
41
 
42
- //# sourceMappingURL=base-email.provider-CNwsPbwm.mjs.map
42
+ //# sourceMappingURL=base-email.provider-Cuw4OAB0.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-email.provider-CNwsPbwm.mjs","names":[],"sources":["../src/email/providers/base-email.provider.ts"],"sourcesContent":["import type { ResolvedEmailMessage } from '../contracts'\nimport type { EmailBatchSendResult, EmailSendResult, IEmailProvider } from './email-provider.interface'\n\n/**\n * Base Email Provider\n *\n * Abstract base class for email providers.\n * Provides shared implementation of sendBatch() to reduce code duplication.\n */\nexport abstract class BaseEmailProvider implements IEmailProvider {\n /**\n * Send a single email - must be implemented by concrete providers\n */\n abstract send(message: ResolvedEmailMessage): Promise<EmailSendResult>\n\n /**\n * Send multiple emails in a batch\n *\n * Default implementation sends emails sequentially.\n * Concrete providers can override for optimized batch sending.\n */\n async sendBatch(messages: ResolvedEmailMessage[]): Promise<EmailBatchSendResult> {\n const results: EmailSendResult[] = []\n let successful = 0\n let failed = 0\n\n for (const message of messages) {\n try {\n const result = await this.send(message)\n results.push(result)\n successful++\n }\n catch (error) {\n results.push({\n messageId: '',\n accepted: false,\n metadata: {\n error: error instanceof Error ? error.message : 'Unknown error',\n },\n })\n failed++\n }\n }\n\n return {\n total: messages.length,\n successful,\n failed,\n results,\n }\n }\n}\n"],"mappings":";;;;;;;AASA,IAAsB,oBAAtB,MAAkE;;;;;;;CAYhE,MAAM,UAAU,UAAiE;EAC/E,MAAM,UAA6B,EAAE;EACrC,IAAI,aAAa;EACjB,IAAI,SAAS;AAEb,OAAK,MAAM,WAAW,SACpB,KAAI;GACF,MAAM,SAAS,MAAM,KAAK,KAAK,QAAQ;AACvC,WAAQ,KAAK,OAAO;AACpB;WAEK,OAAO;AACZ,WAAQ,KAAK;IACX,WAAW;IACX,UAAU;IACV,UAAU,EACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU,iBACjD;IACF,CAAC;AACF;;AAIJ,SAAO;GACL,OAAO,SAAS;GAChB;GACA;GACA;GACD"}
1
+ {"version":3,"file":"base-email.provider-Cuw4OAB0.mjs","names":[],"sources":["../src/email/providers/base-email.provider.ts"],"sourcesContent":["import type { ResolvedEmailMessage } from '../contracts'\nimport type { EmailBatchSendResult, EmailSendResult, IEmailProvider } from './email-provider.interface'\n\n/**\n * Base Email Provider\n *\n * Abstract base class for email providers.\n * Provides shared implementation of sendBatch() to reduce code duplication.\n */\nexport abstract class BaseEmailProvider implements IEmailProvider {\n /**\n * Send a single email - must be implemented by concrete providers\n */\n abstract send(message: ResolvedEmailMessage): Promise<EmailSendResult>\n\n /**\n * Send multiple emails in a batch\n *\n * Default implementation sends emails sequentially.\n * Concrete providers can override for optimized batch sending.\n */\n async sendBatch(messages: ResolvedEmailMessage[]): Promise<EmailBatchSendResult> {\n const results: EmailSendResult[] = []\n let successful = 0\n let failed = 0\n\n for (const message of messages) {\n try {\n const result = await this.send(message)\n results.push(result)\n successful++\n }\n catch (error) {\n results.push({\n messageId: '',\n accepted: false,\n metadata: {\n error: error instanceof Error ? error.message : 'Unknown error',\n },\n })\n failed++\n }\n }\n\n return {\n total: messages.length,\n successful,\n failed,\n results,\n }\n }\n}\n"],"mappings":";;;;;;;AASA,IAAsB,oBAAtB,MAAkE;;;;;;;CAYhE,MAAM,UAAU,UAAiE;EAC/E,MAAM,UAA6B,EAAE;EACrC,IAAI,aAAa;EACjB,IAAI,SAAS;AAEb,OAAK,MAAM,WAAW,SACpB,KAAI;GACF,MAAM,SAAS,MAAM,KAAK,KAAK,QAAQ;AACvC,WAAQ,KAAK,OAAO;AACpB;WAEK,OAAO;AACZ,WAAQ,KAAK;IACX,WAAW;IACX,UAAU;IACV,UAAU,EACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU,iBACjD;IACF,CAAC;AACF;;AAIJ,SAAO;GACL,OAAO,SAAS;GAChB;GACA;GACA;GACD"}
@@ -6,6 +6,7 @@ import { dirname, join, resolve } from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
7
  import { Command, Option } from "clipanion";
8
8
  //#region src/bin/commands/dynamic-command.ts
9
+ /** Create Clipanion command classes from Quarry-registered commands. */
9
10
  function createDynamicCommands(quarry, parseSignature, app) {
10
11
  const commands = [];
11
12
  for (const entry of quarry.list()) {
@@ -43,65 +44,70 @@ function createDynamicCommands(quarry, parseSignature, app) {
43
44
  });
44
45
  for (const opt of signature.options) {
45
46
  const optName = opt.alias ? `-${opt.alias},--${opt.name}` : `--${opt.name}`;
46
- if (opt.isFlag) proto[opt.name] = Option.Boolean(optName, { description: opt.description });
47
- else if (opt.isArray) proto[opt.name] = Option.Array(optName, { description: opt.description });
48
- else proto[opt.name] = Option.String(optName, { description: opt.description });
47
+ const optDescParts = [];
48
+ if (opt.description) optDescParts.push(opt.description);
49
+ if (opt.default !== void 0) optDescParts.push(`(default: ${opt.default})`);
50
+ const optDesc = optDescParts.length > 0 ? optDescParts.join(" ") : void 0;
51
+ if (opt.isFlag) proto[opt.name] = Option.Boolean(optName, { description: optDesc });
52
+ else if (opt.isArray) if (opt.default !== void 0) proto[opt.name] = Option.Array(optName, [opt.default], { description: optDesc });
53
+ else proto[opt.name] = Option.Array(optName, { description: optDesc });
54
+ else if (opt.default !== void 0) proto[opt.name] = Option.String(optName, opt.default, { description: optDesc });
55
+ else proto[opt.name] = Option.String(optName, { description: optDesc });
49
56
  }
50
57
  commands.push(DynCmd);
51
58
  }
52
59
  return commands;
53
60
  }
54
61
  //#endregion
62
+ //#region src/quarry/errors/command-not-found.error.ts
63
+ /**
64
+ * Thrown when a command is not found in the Quarry registry.
65
+ */
66
+ var CommandNotFoundError = class extends Error {
67
+ constructor(name) {
68
+ super(`Command "${name}" is not registered.`);
69
+ this.name = "CommandNotFoundError";
70
+ }
71
+ };
72
+ //#endregion
55
73
  //#region src/bin/commands/help-command.ts
56
- function createHelpCommand() {
74
+ /** Create the built-in `help`/`list` Clipanion command that delegates to Quarry's usage generator. */
75
+ function createHelpCommand(quarry) {
57
76
  class HelpCommand extends Command {
58
- static paths = [["help"]];
77
+ static paths = [
78
+ [],
79
+ ["help"],
80
+ ["list"]
81
+ ];
59
82
  static usage = Command.Usage({ description: "Show help for a command" });
60
83
  commandPath = Option.Rest();
61
- execute() {
84
+ async execute() {
62
85
  const commandName = this.commandPath.join(" ");
63
86
  if (this.help || !commandName) {
64
- this.context.stdout.write(this.cli.usage());
65
- return Promise.resolve(0);
87
+ const listing = await quarry.listUsage({
88
+ binaryName: this.cli.binaryName,
89
+ binaryLabel: this.cli.binaryLabel,
90
+ binaryVersion: this.cli.binaryVersion
91
+ });
92
+ this.context.stdout.write(listing + "\n");
93
+ return 0;
66
94
  }
67
95
  try {
68
- const command = this.cli.process(this.commandPath);
69
- this.context.stdout.write(this.cli.usage(command, { detailed: true }));
70
- return Promise.resolve(0);
71
- } catch {
72
- this.context.stderr.write(`Unknown command: ${commandName}\n`);
73
- return Promise.resolve(1);
96
+ const usage = await quarry.usage(commandName);
97
+ this.context.stdout.write(usage + "\n");
98
+ return 0;
99
+ } catch (error) {
100
+ if (error instanceof CommandNotFoundError) {
101
+ this.context.stderr.write(`Unknown command: ${commandName}\n`);
102
+ return 1;
103
+ }
104
+ throw error;
74
105
  }
75
106
  }
76
107
  }
77
108
  return HelpCommand;
78
109
  }
79
110
  //#endregion
80
- //#region src/bin/commands/list-command.ts
81
- function createListCommand(quarry) {
82
- class ListCommand extends Command {
83
- static paths = [["list"]];
84
- static usage = Command.Usage({ description: "List all registered commands" });
85
- execute() {
86
- const commands = quarry.list();
87
- if (commands.length === 0) {
88
- this.context.stdout.write("No registered commands.\n");
89
- return Promise.resolve(0);
90
- }
91
- this.context.stdout.write("\nRegistered commands:\n\n");
92
- const maxName = Math.max(...commands.map((c) => c.name.length));
93
- for (const cmd of commands) {
94
- const aliasStr = cmd.aliases.length > 0 ? ` (${cmd.aliases.join(", ")})` : "";
95
- const desc = cmd.description ?? "";
96
- this.context.stdout.write(` ${cmd.name.padEnd(maxName + 4)}${desc}${aliasStr}\n`);
97
- }
98
- this.context.stdout.write("\n");
99
- return Promise.resolve(0);
100
- }
101
- }
102
- return ListCommand;
103
- }
104
- //#endregion
105
111
  //#region src/bin/quarry.ts
106
112
  const require = createRequire(import.meta.url);
107
113
  register(pathToFileURL(join(dirname(require.resolve("@swc-node/register")), "esm/esm.mjs")), pathToFileURL("./"));
@@ -138,15 +144,13 @@ async function main() {
138
144
  ]);
139
145
  app = await Stratal.resolveApplication();
140
146
  const quarry = app.container.resolve(DI_TOKENS.Quarry);
141
- const { Builtins, Cli } = await import("clipanion");
147
+ const { Cli } = await import("clipanion");
142
148
  const cli = new Cli({
143
149
  binaryName: "quarry",
144
150
  binaryLabel: "Quarry CLI",
145
151
  binaryVersion: require("../../package.json").version
146
152
  });
147
- cli.register(Builtins.HelpCommand);
148
- cli.register(createListCommand(quarry));
149
- cli.register(createHelpCommand());
153
+ cli.register(createHelpCommand(quarry));
150
154
  for (const cmd of createDynamicCommands(quarry, parseSignature, app)) cli.register(cmd);
151
155
  await cli.runExit(process.argv.slice(2), { ...Cli.defaultContext });
152
156
  } finally {
@@ -1 +1 @@
1
- {"version":3,"file":"quarry.mjs","names":[],"sources":["../../src/bin/commands/dynamic-command.ts","../../src/bin/commands/help-command.ts","../../src/bin/commands/list-command.ts","../../src/bin/quarry.ts"],"sourcesContent":["import { Command, type CommandClass, Option, type Usage } from 'clipanion'\n\nimport type { Application } from 'stratal'\nimport type { QuarryRegistry } from 'stratal/quarry'\nimport type { ParsedSignature } from 'stratal/quarry'\n\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 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\n if (opt.isFlag) {\n proto[opt.name] = Option.Boolean(optName, { description: opt.description })\n } else if (opt.isArray) {\n proto[opt.name] = Option.Array(optName, { description: opt.description })\n } else {\n proto[opt.name] = Option.String(optName, { description: opt.description })\n }\n }\n\n commands.push(DynCmd)\n }\n\n return commands\n}\n","import { Command, Option, type Usage } from 'clipanion'\n\nexport function createHelpCommand() {\n class HelpCommand extends Command {\n static override paths = [['help']]\n static override usage: Usage = Command.Usage({ description: 'Show help for a command' })\n\n commandPath = Option.Rest()\n\n execute(): Promise<number> {\n const commandName = this.commandPath.join(' ')\n\n if (this.help || !commandName) {\n this.context.stdout.write(this.cli.usage())\n return Promise.resolve(0)\n }\n\n try {\n const command = this.cli.process(this.commandPath)\n this.context.stdout.write(this.cli.usage(command, { detailed: true }))\n return Promise.resolve(0)\n } catch {\n this.context.stderr.write(`Unknown command: ${commandName}\\n`)\n return Promise.resolve(1)\n }\n }\n }\n\n return HelpCommand\n}\n","import { Command, type Usage } from 'clipanion'\n\nimport type { QuarryRegistry } from 'stratal/quarry'\n\nexport function createListCommand(quarry: QuarryRegistry) {\n class ListCommand extends Command {\n static override paths = [['list']]\n static override usage: Usage = Command.Usage({ description: 'List all registered commands' })\n\n execute(): Promise<number> {\n const commands = quarry.list()\n\n if (commands.length === 0) {\n this.context.stdout.write('No registered commands.\\n')\n return Promise.resolve(0)\n }\n\n this.context.stdout.write('\\nRegistered commands:\\n\\n')\n\n const maxName = Math.max(...commands.map((c) => c.name.length))\n for (const cmd of commands) {\n const aliasStr = cmd.aliases.length > 0 ? ` (${cmd.aliases.join(', ')})` : ''\n const desc = cmd.description ?? ''\n this.context.stdout.write(` ${cmd.name.padEnd(maxName + 4)}${desc}${aliasStr}\\n`)\n }\n\n this.context.stdout.write('\\n')\n return Promise.resolve(0)\n }\n }\n\n return ListCommand\n}\n","import 'reflect-metadata'\n\nimport { existsSync } from 'node:fs'\nimport { createRequire, register } from 'node:module'\nimport { dirname, join, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport type { QuarryRegistry } from 'stratal/quarry'\n\nimport { type Application } from '../application'\nimport { createDynamicCommands } from './commands/dynamic-command'\nimport { createHelpCommand } from './commands/help-command'\nimport { createListCommand } from './commands/list-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\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 const { env, ctx, dispose } = await getPlatformProxy()\n\n let app: Application | undefined\n try {\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: ctx.waitUntil.bind(ctx),\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 { Builtins, 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 cli.register(Builtins.HelpCommand)\n cli.register(createListCommand(quarry))\n cli.register(createHelpCommand())\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 app?.shutdown()\n await dispose()\n }\n}\n\nmain().catch((error: unknown) => {\n console.error('Fatal error:', error instanceof Error ? error.message : String(error))\n process.exit(1)\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"quarry.mjs","names":[],"sources":["../../src/bin/commands/dynamic-command.ts","../../src/quarry/errors/command-not-found.error.ts","../../src/bin/commands/help-command.ts","../../src/bin/quarry.ts"],"sourcesContent":["import { Command, type CommandClass, Option, type Usage } from 'clipanion'\n\nimport type { Application } from 'stratal'\nimport type { QuarryRegistry } from 'stratal/quarry'\nimport type { ParsedSignature } 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 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","/**\n * Thrown when a command is not found in the Quarry registry.\n */\nexport class CommandNotFoundError extends Error {\n constructor(name: string) {\n super(`Command \"${name}\" is not registered.`)\n this.name = 'CommandNotFoundError'\n }\n}\n","import { Command, Option, type Usage } from 'clipanion'\nimport { CommandNotFoundError } from '../../quarry/errors/command-not-found.error'\nimport type { QuarryRegistry } from '../../quarry/quarry-registry'\n\n/** Create the built-in `help`/`list` Clipanion command that delegates to Quarry's usage generator. */\nexport function createHelpCommand(quarry: QuarryRegistry) {\n class HelpCommand extends Command {\n static override paths = [[], ['help'], ['list']]\n static override usage: Usage = Command.Usage({ description: 'Show help for a command' })\n\n commandPath = Option.Rest()\n\n async execute(): Promise<number> {\n const commandName = this.commandPath.join(' ')\n\n if (this.help || !commandName) {\n const listing = await quarry.listUsage({\n binaryName: this.cli.binaryName,\n binaryLabel: this.cli.binaryLabel,\n binaryVersion: this.cli.binaryVersion,\n })\n this.context.stdout.write(listing + '\\n')\n return 0\n }\n\n try {\n const usage = await quarry.usage(commandName)\n this.context.stdout.write(usage + '\\n')\n return 0\n } catch (error) {\n if (error instanceof CommandNotFoundError) {\n this.context.stderr.write(`Unknown command: ${commandName}\\n`)\n return 1\n }\n throw error\n }\n }\n }\n\n return HelpCommand\n}\n","import 'reflect-metadata'\n\nimport { existsSync } from 'node:fs'\nimport { createRequire, register } from 'node:module'\nimport { dirname, join, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport type { QuarryRegistry } from 'stratal/quarry'\n\nimport { type Application } from '../application'\nimport { createDynamicCommands } from './commands/dynamic-command'\nimport { createHelpCommand } from './commands/help-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\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 const { env, ctx, dispose } = await getPlatformProxy()\n\n let app: Application | undefined\n try {\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: ctx.waitUntil.bind(ctx),\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 cli.register(createHelpCommand(quarry))\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 app?.shutdown()\n await dispose()\n }\n}\n\nmain().catch((error: unknown) => {\n console.error('Fatal error:', error instanceof Error ? error.message : String(error))\n process.exit(1)\n})\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { Ht as StratalEnv, s as ApplicationError } from "../index-D69rxo8H.mjs";
2
- import { i as LoggerService } from "../index-Cfkie8JM.mjs";
1
+ import { Ht as StratalEnv, s as ApplicationError } from "../index-BJWm863C.mjs";
2
+ import { i as LoggerService } from "../index-Dp6A5ywM.mjs";
3
3
 
4
4
  //#region src/cache/cache.module.d.ts
5
5
  /**
@@ -1,13 +1,14 @@
1
1
  import { S as ApplicationError, b as ERROR_CODES } from "../errors-CtCi1wn6.mjs";
2
2
  import { i as Transient, l as DI_TOKENS, n as __decorateParam, r as __decorateMetadata, t as __decorate } from "../decorate-D5j-d9_z.mjs";
3
3
  import { s as LOGGER_TOKENS } from "../logger-BR1-s1Um.mjs";
4
- import { r as Module } from "../module-BH7t7BGG.mjs";
4
+ import { r as Module } from "../module-BgdxxzBe.mjs";
5
5
  import "../events-CXl-o1Ad.mjs";
6
- import "../command-DG_u5ob2.mjs";
7
- import "../is-command-MZDCH-0T.mjs";
8
- import "../is-seeder-BN9Ej1r7.mjs";
9
- import "../middleware-iRhNjsPH.mjs";
10
- import "../router-context-BLn4PrRG.mjs";
6
+ import "../colors-DJaRDXoS.mjs";
7
+ import "../command-BvCOD6df.mjs";
8
+ import "../is-command-BfCgWAcQ.mjs";
9
+ import "../is-seeder-CebjZCDn.mjs";
10
+ import "../middleware-C0Ebzswy.mjs";
11
+ import "../router-context-BEJe9HEB.mjs";
11
12
  import { inject } from "tsyringe";
12
13
  //#region src/cache/cache.tokens.ts
13
14
  const CACHE_TOKENS = { CacheService: Symbol.for("stratal:cache:service") };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/cache/cache.tokens.ts","../../src/cache/errors/cache-get.error.ts","../../src/cache/errors/cache-put.error.ts","../../src/cache/errors/cache-delete.error.ts","../../src/cache/errors/cache-list.error.ts","../../src/cache/services/cache.service.ts","../../src/cache/cache.module.ts"],"sourcesContent":["export const CACHE_TOKENS = {\n CacheService: Symbol.for('stratal:cache:service'),\n} as const\n\nexport type CacheToken = (typeof CACHE_TOKENS)[keyof typeof CACHE_TOKENS]\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache get operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CacheGetError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.getFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache put operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CachePutError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.putFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache delete operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CacheDeleteError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.deleteFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache list operation fails\n *\n * Raw error details are logged via LoggerService for security.\n */\nexport class CacheListError extends ApplicationError {\n constructor() {\n super('errors.cache.listFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, {})\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { DI_TOKENS } from '../../di/tokens'\nimport { type StratalEnv } from '../../env'\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger'\nimport { CACHE_TOKENS } from '../cache.tokens'\nimport {\n CacheDeleteError,\n CacheGetError,\n CacheListError,\n CachePutError,\n} from '../errors'\n\n/**\n * Cache Service\n *\n * Type-safe wrapper around Cloudflare KV namespaces for caching operations.\n *\n * **Features:**\n * - Mirrors all KVNamespace methods with full type safety\n * - Supports multiple KV bindings via `withBinding()`\n * - Automatic error handling with logging\n * - Security: Raw errors are logged, not exposed to users\n *\n * **Usage:**\n * ```typescript\n * class MyService {\n * private readonly uploadsCache: CacheService\n *\n * constructor(\n * @inject(CACHE_TOKENS.CacheService) private readonly cache: CacheService,\n * @inject(DI_TOKENS.CloudflareEnv) private readonly env: Env\n * ) {\n * // Initialize specialized caches in constructor\n * this.uploadsCache = this.cache.withBinding(this.env.UPLOADS_CACHE)\n * }\n *\n * async cacheData(key: string, value: string) {\n * await this.cache.put(key, value, { expirationTtl: 3600 })\n * await this.uploadsCache.put(`upload:${key}`, value)\n * }\n * }\n * ```\n *\n * @see https://developers.cloudflare.com/kv/api/\n */\n@Transient(CACHE_TOKENS.CacheService)\nexport class CacheService {\n private kv: KVNamespace\n\n constructor(\n @inject(DI_TOKENS.CloudflareEnv) private readonly env: StratalEnv,\n @inject(LOGGER_TOKENS.LoggerService) private readonly logger: LoggerService\n ) {\n this.kv = env.CACHE\n }\n\n /**\n * Set the KV namespace binding\n *\n * Used internally by `withBinding()` to configure different KV instances.\n *\n * @param kv - KV namespace to use\n */\n setKV(kv: KVNamespace): void {\n this.kv = kv\n }\n\n /**\n * Create a new CacheService instance with a different KV binding\n *\n * **Pattern:** Returns a new instance (immutable)\n *\n * **Best Practice:** Initialize specialized caches as class properties in constructor\n *\n * @example\n * ```typescript\n * class MyService {\n * private readonly uploadsCache: CacheService\n * private readonly systemCache: CacheService\n *\n * constructor(\n * @inject(CACHE_TOKENS.CacheService) private readonly cache: CacheService,\n * @inject(DI_TOKENS.CloudflareEnv) private readonly env: Env\n * ) {\n * this.uploadsCache = this.cache.withBinding(this.env.UPLOADS_CACHE)\n * this.systemCache = this.cache.withBinding(this.env.SYSTEM_CONFIG_KV)\n * }\n * }\n * ```\n *\n * @param kv - KV namespace to use\n * @returns New CacheService instance with the specified binding\n */\n withBinding(kv: KVNamespace): CacheService {\n const instance = new CacheService(this.env, this.logger)\n instance.setKV(kv)\n return instance\n }\n\n // ==================== GET METHODS ====================\n\n /**\n * Get a value from cache\n *\n * @param key - Cache key\n * @param typeOrOptions - Type string or options object (defaults to 'text')\n * @returns Value in specified type, or null if not found\n * @throws {CacheGetError} If operation fails\n */\n async get(key: string, typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>): Promise<string | null>\n async get<ExpectedValue = unknown>(key: string, typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>): Promise<ExpectedValue | null>\n async get(key: string, typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>): Promise<ArrayBuffer | null>\n async get(key: string, typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>): Promise<ReadableStream | null>\n\n async get<ExpectedValue = unknown>(\n key: string,\n typeOrOptions?: string | KVNamespaceGetOptions<'text' | 'json' | 'arrayBuffer' | 'stream'>\n ): Promise<string | ExpectedValue | ArrayBuffer | ReadableStream | null> {\n try {\n if (typeof typeOrOptions === 'string') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.get(key, typeOrOptions as any)\n }\n\n if (typeOrOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.get(key, typeOrOptions as any)\n }\n\n return await this.kv.get(key)\n } catch (error) {\n this.logger.error('Cache get operation failed', { key, error })\n throw new CacheGetError(key)\n }\n }\n\n // ==================== GET WITH METADATA METHODS ====================\n\n /**\n * Get a value with metadata from cache\n *\n * @param key - Cache key\n * @param typeOrOptions - Type string or options object (defaults to 'text')\n * @returns Object with value, metadata, and cacheStatus\n * @throws {CacheGetError} If operation fails\n */\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>\n ): Promise<KVNamespaceGetWithMetadataResult<string, Metadata>>\n async getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(\n key: string,\n typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>\n ): Promise<KVNamespaceGetWithMetadataResult<ExpectedValue, Metadata>>\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>\n ): Promise<KVNamespaceGetWithMetadataResult<ArrayBuffer, Metadata>>\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>\n ): Promise<KVNamespaceGetWithMetadataResult<ReadableStream, Metadata>>\n\n async getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(\n key: string,\n typeOrOptions?: string | KVNamespaceGetOptions<'text' | 'json' | 'arrayBuffer' | 'stream'>\n ): Promise<\n KVNamespaceGetWithMetadataResult<\n string | ExpectedValue | ArrayBuffer | ReadableStream,\n Metadata\n >\n > {\n try {\n if (typeof typeOrOptions === 'string') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.getWithMetadata(key, typeOrOptions as any)\n }\n\n if (typeOrOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.getWithMetadata(key, typeOrOptions as any)\n }\n\n return await this.kv.getWithMetadata(key)\n } catch (error) {\n this.logger.error('Cache getWithMetadata operation failed', { key, error })\n throw new CacheGetError(key)\n }\n }\n\n // ==================== PUT METHOD ====================\n\n /**\n * Store a value in cache\n *\n * @param key - Cache key\n * @param value - Value to store (string, ArrayBuffer, ArrayBufferView, or ReadableStream)\n * @param options - Put options (expiration, expirationTtl, metadata)\n * @throws {CachePutError} If operation fails\n *\n * @example\n * ```typescript\n * // Simple put\n * await cache.put('key', 'value')\n *\n * // With TTL\n * await cache.put('key', 'value', { expirationTtl: 3600 })\n *\n * // With metadata\n * await cache.put('key', 'value', { metadata: { created: Date.now() } })\n * ```\n */\n async put(\n key: string,\n value: string | ArrayBuffer | ArrayBufferView | ReadableStream,\n options?: KVNamespacePutOptions\n ): Promise<void> {\n try {\n await this.kv.put(key, value as string, options)\n } catch (error) {\n this.logger.error('Cache put operation failed', { key, error })\n throw new CachePutError(key)\n }\n }\n\n // ==================== DELETE METHODS ====================\n\n /**\n * Delete a value from cache\n *\n * @param key - Cache key to delete\n * @throws {CacheDeleteError} If operation fails\n */\n async delete(key: string): Promise<void> {\n try {\n await this.kv.delete(key)\n } catch (error) {\n this.logger.error('Cache delete operation failed', { key, error })\n throw new CacheDeleteError(key)\n }\n }\n\n\n // ==================== LIST METHOD ====================\n\n /**\n * List keys in cache\n *\n * @param options - List options (limit, prefix, cursor)\n * @returns List result with keys and pagination info\n * @throws {CacheListError} If operation fails\n *\n * @example\n * ```typescript\n * // List all keys\n * const result = await cache.list()\n *\n * // List with prefix\n * const result = await cache.list({ prefix: 'user:' })\n *\n * // Paginated list\n * const result = await cache.list({ limit: 100 })\n * if (!result.list_complete) {\n * const nextPage = await cache.list({ cursor: result.cursor })\n * }\n * ```\n */\n async list<Metadata = unknown>(\n options?: KVNamespaceListOptions\n ): Promise<KVNamespaceListResult<Metadata>> {\n try {\n return await this.kv.list<Metadata>(options)\n } catch (error) {\n this.logger.error('Cache list operation failed', { options, error })\n throw new CacheListError()\n }\n }\n}\n","/**\n * Cache Module\n *\n * Provides key-value caching capabilities using Cloudflare KV namespaces.\n *\n * **Features:**\n * - Type-safe KV wrapper with full method coverage\n * - Multiple KV binding support via `withBinding()`\n * - Automatic error handling with security-focused logging\n * - Singleton service for optimal performance\n */\n\nimport { Module } from '../module'\nimport { CACHE_TOKENS } from './cache.tokens'\nimport { CacheService } from './services'\n\n@Module({\n providers: [\n // Singleton - CacheService has no request dependencies\n { provide: CACHE_TOKENS.CacheService, useClass: CacheService },\n ],\n})\nexport class CacheModule {}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/cache/cache.tokens.ts","../../src/cache/errors/cache-get.error.ts","../../src/cache/errors/cache-put.error.ts","../../src/cache/errors/cache-delete.error.ts","../../src/cache/errors/cache-list.error.ts","../../src/cache/services/cache.service.ts","../../src/cache/cache.module.ts"],"sourcesContent":["export const CACHE_TOKENS = {\n CacheService: Symbol.for('stratal:cache:service'),\n} as const\n\nexport type CacheToken = (typeof CACHE_TOKENS)[keyof typeof CACHE_TOKENS]\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache get operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CacheGetError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.getFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache put operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CachePutError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.putFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache delete operation fails\n *\n * Raw error details are logged via LoggerService for security.\n * Only the key is included in the user-facing error message.\n */\nexport class CacheDeleteError extends ApplicationError {\n constructor(key: string) {\n super('errors.cache.deleteFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, { key })\n }\n}\n","import { ERROR_CODES } from '../../errors'\nimport { ApplicationError } from '../../errors'\n\n/**\n * Error thrown when a cache list operation fails\n *\n * Raw error details are logged via LoggerService for security.\n */\nexport class CacheListError extends ApplicationError {\n constructor() {\n super('errors.cache.listFailed', ERROR_CODES.SYSTEM.INFRASTRUCTURE_ERROR, {})\n }\n}\n","import { inject } from 'tsyringe'\nimport { Transient } from '../../di/decorators'\nimport { DI_TOKENS } from '../../di/tokens'\nimport { type StratalEnv } from '../../env'\nimport { LOGGER_TOKENS, type LoggerService } from '../../logger'\nimport { CACHE_TOKENS } from '../cache.tokens'\nimport {\n CacheDeleteError,\n CacheGetError,\n CacheListError,\n CachePutError,\n} from '../errors'\n\n/**\n * Cache Service\n *\n * Type-safe wrapper around Cloudflare KV namespaces for caching operations.\n *\n * **Features:**\n * - Mirrors all KVNamespace methods with full type safety\n * - Supports multiple KV bindings via `withBinding()`\n * - Automatic error handling with logging\n * - Security: Raw errors are logged, not exposed to users\n *\n * **Usage:**\n * ```typescript\n * class MyService {\n * private readonly uploadsCache: CacheService\n *\n * constructor(\n * @inject(CACHE_TOKENS.CacheService) private readonly cache: CacheService,\n * @inject(DI_TOKENS.CloudflareEnv) private readonly env: Env\n * ) {\n * // Initialize specialized caches in constructor\n * this.uploadsCache = this.cache.withBinding(this.env.UPLOADS_CACHE)\n * }\n *\n * async cacheData(key: string, value: string) {\n * await this.cache.put(key, value, { expirationTtl: 3600 })\n * await this.uploadsCache.put(`upload:${key}`, value)\n * }\n * }\n * ```\n *\n * @see https://developers.cloudflare.com/kv/api/\n */\n@Transient(CACHE_TOKENS.CacheService)\nexport class CacheService {\n private kv: KVNamespace\n\n constructor(\n @inject(DI_TOKENS.CloudflareEnv) private readonly env: StratalEnv,\n @inject(LOGGER_TOKENS.LoggerService) private readonly logger: LoggerService\n ) {\n this.kv = env.CACHE\n }\n\n /**\n * Set the KV namespace binding\n *\n * Used internally by `withBinding()` to configure different KV instances.\n *\n * @param kv - KV namespace to use\n */\n setKV(kv: KVNamespace): void {\n this.kv = kv\n }\n\n /**\n * Create a new CacheService instance with a different KV binding\n *\n * **Pattern:** Returns a new instance (immutable)\n *\n * **Best Practice:** Initialize specialized caches as class properties in constructor\n *\n * @example\n * ```typescript\n * class MyService {\n * private readonly uploadsCache: CacheService\n * private readonly systemCache: CacheService\n *\n * constructor(\n * @inject(CACHE_TOKENS.CacheService) private readonly cache: CacheService,\n * @inject(DI_TOKENS.CloudflareEnv) private readonly env: Env\n * ) {\n * this.uploadsCache = this.cache.withBinding(this.env.UPLOADS_CACHE)\n * this.systemCache = this.cache.withBinding(this.env.SYSTEM_CONFIG_KV)\n * }\n * }\n * ```\n *\n * @param kv - KV namespace to use\n * @returns New CacheService instance with the specified binding\n */\n withBinding(kv: KVNamespace): CacheService {\n const instance = new CacheService(this.env, this.logger)\n instance.setKV(kv)\n return instance\n }\n\n // ==================== GET METHODS ====================\n\n /**\n * Get a value from cache\n *\n * @param key - Cache key\n * @param typeOrOptions - Type string or options object (defaults to 'text')\n * @returns Value in specified type, or null if not found\n * @throws {CacheGetError} If operation fails\n */\n async get(key: string, typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>): Promise<string | null>\n async get<ExpectedValue = unknown>(key: string, typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>): Promise<ExpectedValue | null>\n async get(key: string, typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>): Promise<ArrayBuffer | null>\n async get(key: string, typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>): Promise<ReadableStream | null>\n\n async get<ExpectedValue = unknown>(\n key: string,\n typeOrOptions?: string | KVNamespaceGetOptions<'text' | 'json' | 'arrayBuffer' | 'stream'>\n ): Promise<string | ExpectedValue | ArrayBuffer | ReadableStream | null> {\n try {\n if (typeof typeOrOptions === 'string') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.get(key, typeOrOptions as any)\n }\n\n if (typeOrOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.get(key, typeOrOptions as any)\n }\n\n return await this.kv.get(key)\n } catch (error) {\n this.logger.error('Cache get operation failed', { key, error })\n throw new CacheGetError(key)\n }\n }\n\n // ==================== GET WITH METADATA METHODS ====================\n\n /**\n * Get a value with metadata from cache\n *\n * @param key - Cache key\n * @param typeOrOptions - Type string or options object (defaults to 'text')\n * @returns Object with value, metadata, and cacheStatus\n * @throws {CacheGetError} If operation fails\n */\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions?: 'text' | KVNamespaceGetOptions<'text'>\n ): Promise<KVNamespaceGetWithMetadataResult<string, Metadata>>\n async getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(\n key: string,\n typeOrOptions: 'json' | KVNamespaceGetOptions<'json'>\n ): Promise<KVNamespaceGetWithMetadataResult<ExpectedValue, Metadata>>\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions: 'arrayBuffer' | KVNamespaceGetOptions<'arrayBuffer'>\n ): Promise<KVNamespaceGetWithMetadataResult<ArrayBuffer, Metadata>>\n async getWithMetadata<Metadata = unknown>(\n key: string,\n typeOrOptions: 'stream' | KVNamespaceGetOptions<'stream'>\n ): Promise<KVNamespaceGetWithMetadataResult<ReadableStream, Metadata>>\n\n async getWithMetadata<ExpectedValue = unknown, Metadata = unknown>(\n key: string,\n typeOrOptions?: string | KVNamespaceGetOptions<'text' | 'json' | 'arrayBuffer' | 'stream'>\n ): Promise<\n KVNamespaceGetWithMetadataResult<\n string | ExpectedValue | ArrayBuffer | ReadableStream,\n Metadata\n >\n > {\n try {\n if (typeof typeOrOptions === 'string') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.getWithMetadata(key, typeOrOptions as any)\n }\n\n if (typeOrOptions) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any -- bridging KV overloaded API\n return await this.kv.getWithMetadata(key, typeOrOptions as any)\n }\n\n return await this.kv.getWithMetadata(key)\n } catch (error) {\n this.logger.error('Cache getWithMetadata operation failed', { key, error })\n throw new CacheGetError(key)\n }\n }\n\n // ==================== PUT METHOD ====================\n\n /**\n * Store a value in cache\n *\n * @param key - Cache key\n * @param value - Value to store (string, ArrayBuffer, ArrayBufferView, or ReadableStream)\n * @param options - Put options (expiration, expirationTtl, metadata)\n * @throws {CachePutError} If operation fails\n *\n * @example\n * ```typescript\n * // Simple put\n * await cache.put('key', 'value')\n *\n * // With TTL\n * await cache.put('key', 'value', { expirationTtl: 3600 })\n *\n * // With metadata\n * await cache.put('key', 'value', { metadata: { created: Date.now() } })\n * ```\n */\n async put(\n key: string,\n value: string | ArrayBuffer | ArrayBufferView | ReadableStream,\n options?: KVNamespacePutOptions\n ): Promise<void> {\n try {\n await this.kv.put(key, value as string, options)\n } catch (error) {\n this.logger.error('Cache put operation failed', { key, error })\n throw new CachePutError(key)\n }\n }\n\n // ==================== DELETE METHODS ====================\n\n /**\n * Delete a value from cache\n *\n * @param key - Cache key to delete\n * @throws {CacheDeleteError} If operation fails\n */\n async delete(key: string): Promise<void> {\n try {\n await this.kv.delete(key)\n } catch (error) {\n this.logger.error('Cache delete operation failed', { key, error })\n throw new CacheDeleteError(key)\n }\n }\n\n\n // ==================== LIST METHOD ====================\n\n /**\n * List keys in cache\n *\n * @param options - List options (limit, prefix, cursor)\n * @returns List result with keys and pagination info\n * @throws {CacheListError} If operation fails\n *\n * @example\n * ```typescript\n * // List all keys\n * const result = await cache.list()\n *\n * // List with prefix\n * const result = await cache.list({ prefix: 'user:' })\n *\n * // Paginated list\n * const result = await cache.list({ limit: 100 })\n * if (!result.list_complete) {\n * const nextPage = await cache.list({ cursor: result.cursor })\n * }\n * ```\n */\n async list<Metadata = unknown>(\n options?: KVNamespaceListOptions\n ): Promise<KVNamespaceListResult<Metadata>> {\n try {\n return await this.kv.list<Metadata>(options)\n } catch (error) {\n this.logger.error('Cache list operation failed', { options, error })\n throw new CacheListError()\n }\n }\n}\n","/**\n * Cache Module\n *\n * Provides key-value caching capabilities using Cloudflare KV namespaces.\n *\n * **Features:**\n * - Type-safe KV wrapper with full method coverage\n * - Multiple KV binding support via `withBinding()`\n * - Automatic error handling with security-focused logging\n * - Singleton service for optimal performance\n */\n\nimport { Module } from '../module'\nimport { CACHE_TOKENS } from './cache.tokens'\nimport { CacheService } from './services'\n\n@Module({\n providers: [\n // Singleton - CacheService has no request dependencies\n { provide: CACHE_TOKENS.CacheService, useClass: CacheService },\n ],\n})\nexport class CacheModule {}\n"],"mappings":";;;;;;;;;;;;;AAAA,MAAa,eAAe,EAC1B,cAAc,OAAO,IAAI,wBAAwB,EAClD;;;;;;;;;ACOD,IAAa,gBAAb,cAAmC,iBAAiB;CAClD,YAAY,KAAa;AACvB,QAAM,0BAA0B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;;ACFrF,IAAa,gBAAb,cAAmC,iBAAiB;CAClD,YAAY,KAAa;AACvB,QAAM,0BAA0B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;;ACFrF,IAAa,mBAAb,cAAsC,iBAAiB;CACrD,YAAY,KAAa;AACvB,QAAM,6BAA6B,YAAY,OAAO,sBAAsB,EAAE,KAAK,CAAC;;;;;;;;;;ACHxF,IAAa,iBAAb,cAAoC,iBAAiB;CACnD,cAAc;AACZ,QAAM,2BAA2B,YAAY,OAAO,sBAAsB,EAAE,CAAC;;;;;;ACqC1E,IAAA,eAAA,gBAAA,MAAM,aAAa;CACxB;CAEA,YACE,KACA,QACA;AAFkD,OAAA,MAAA;AACI,OAAA,SAAA;AAEtD,OAAK,KAAK,IAAI;;;;;;;;;CAUhB,MAAM,IAAuB;AAC3B,OAAK,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BZ,YAAY,IAA+B;EACzC,MAAM,WAAW,IAAA,cAAiB,KAAK,KAAK,KAAK,OAAO;AACxD,WAAS,MAAM,GAAG;AAClB,SAAO;;CAkBT,MAAM,IACJ,KACA,eACuE;AACvE,MAAI;AACF,OAAI,OAAO,kBAAkB,SAE3B,QAAO,MAAM,KAAK,GAAG,IAAI,KAAK,cAAqB;AAGrD,OAAI,cAEF,QAAO,MAAM,KAAK,GAAG,IAAI,KAAK,cAAqB;AAGrD,UAAO,MAAM,KAAK,GAAG,IAAI,IAAI;WACtB,OAAO;AACd,QAAK,OAAO,MAAM,8BAA8B;IAAE;IAAK;IAAO,CAAC;AAC/D,SAAM,IAAI,cAAc,IAAI;;;CA+BhC,MAAM,gBACJ,KACA,eAMA;AACA,MAAI;AACF,OAAI,OAAO,kBAAkB,SAE3B,QAAO,MAAM,KAAK,GAAG,gBAAgB,KAAK,cAAqB;AAGjE,OAAI,cAEF,QAAO,MAAM,KAAK,GAAG,gBAAgB,KAAK,cAAqB;AAGjE,UAAO,MAAM,KAAK,GAAG,gBAAgB,IAAI;WAClC,OAAO;AACd,QAAK,OAAO,MAAM,0CAA0C;IAAE;IAAK;IAAO,CAAC;AAC3E,SAAM,IAAI,cAAc,IAAI;;;;;;;;;;;;;;;;;;;;;;;CA0BhC,MAAM,IACJ,KACA,OACA,SACe;AACf,MAAI;AACF,SAAM,KAAK,GAAG,IAAI,KAAK,OAAiB,QAAQ;WACzC,OAAO;AACd,QAAK,OAAO,MAAM,8BAA8B;IAAE;IAAK;IAAO,CAAC;AAC/D,SAAM,IAAI,cAAc,IAAI;;;;;;;;;CAYhC,MAAM,OAAO,KAA4B;AACvC,MAAI;AACF,SAAM,KAAK,GAAG,OAAO,IAAI;WAClB,OAAO;AACd,QAAK,OAAO,MAAM,iCAAiC;IAAE;IAAK;IAAO,CAAC;AAClE,SAAM,IAAI,iBAAiB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;CA6BnC,MAAM,KACJ,SAC0C;AAC1C,MAAI;AACF,UAAO,MAAM,KAAK,GAAG,KAAe,QAAQ;WACrC,OAAO;AACd,QAAK,OAAO,MAAM,+BAA+B;IAAE;IAAS;IAAO,CAAC;AACpE,SAAM,IAAI,gBAAgB;;;;;CArO/B,UAAU,aAAa,aAAa;oBAKhC,OAAO,UAAU,cAAc,CAAA;oBAC/B,OAAO,cAAc,cAAc,CAAA;;;;;;;;;;;;;;;;AC9BjC,IAAA,cAAA,MAAM,YAAY;0BANxB,OAAO,EACN,WAAW,CAET;CAAE,SAAS,aAAa;CAAc,UAAU;CAAc,CAC/D,EACF,CAAC,CAAA,EAAA,YAAA"}
@@ -0,0 +1,16 @@
1
+ //#region src/quarry/colors.ts
2
+ /** Minimal ANSI color helpers that respect the `NO_COLOR` convention. */
3
+ const isEnabled = () => typeof process !== "undefined" ? !process.env.NO_COLOR : true;
4
+ /** Create an ANSI formatter that wraps text with the given open/close SGR codes. */
5
+ const code = (open, close) => (s) => isEnabled() ? `\x1b[${open}m${s}\x1b[${close}m` : s;
6
+ const bold = code(1, 22);
7
+ const dim = code(2, 22);
8
+ const cyan = code(36, 39);
9
+ const green = code(32, 39);
10
+ const red = code(31, 39);
11
+ const yellow = code(33, 39);
12
+ const dimWhite = (s) => isEnabled() ? `\x1b[2;37m${s}\x1b[22;39m` : s;
13
+ //#endregion
14
+ export { green as a, dimWhite as i, cyan as n, red as o, dim as r, yellow as s, bold as t };
15
+
16
+ //# sourceMappingURL=colors-DJaRDXoS.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors-DJaRDXoS.mjs","names":[],"sources":["../src/quarry/colors.ts"],"sourcesContent":["/** Minimal ANSI color helpers that respect the `NO_COLOR` convention. */\nconst isEnabled = () => typeof process !== 'undefined' ? !process.env.NO_COLOR : true\n\n/** Create an ANSI formatter that wraps text with the given open/close SGR codes. */\nconst code = (open: number, close: number) => (s: string) =>\n isEnabled() ? `\\x1b[${open}m${s}\\x1b[${close}m` : s\n\nexport const bold = code(1, 22)\nexport const dim = code(2, 22)\nexport const cyan = code(36, 39)\nexport const green = code(32, 39)\nexport const red = code(31, 39)\nexport const yellow = code(33, 39)\nexport const dimWhite = (s: string) =>\n isEnabled() ? `\\x1b[2;37m${s}\\x1b[22;39m` : s\n"],"mappings":";;AACA,MAAM,kBAAkB,OAAO,YAAY,cAAc,CAAC,QAAQ,IAAI,WAAW;;AAGjF,MAAM,QAAQ,MAAc,WAAmB,MAC7C,WAAW,GAAG,QAAQ,KAAK,GAAG,EAAE,OAAO,MAAM,KAAK;AAEpD,MAAa,OAAO,KAAK,GAAG,GAAG;AAC/B,MAAa,MAAM,KAAK,GAAG,GAAG;AAC9B,MAAa,OAAO,KAAK,IAAI,GAAG;AAChC,MAAa,QAAQ,KAAK,IAAI,GAAG;AACjC,MAAa,MAAM,KAAK,IAAI,GAAG;AAC/B,MAAa,SAAS,KAAK,IAAI,GAAG;AAClC,MAAa,YAAY,MACvB,WAAW,GAAG,aAAa,EAAE,eAAe"}
@@ -1,4 +1,4 @@
1
- import { n as CommandInternals, r as CommandResult, t as CommandInput } from "./types-N84Ak6YT.mjs";
1
+ import { n as CommandInternals, r as CommandResult, t as CommandInput } from "./types-CLhOhYsQ.mjs";
2
2
  //#region src/quarry/constants.d.ts
3
3
  /**
4
4
  * Symbol key for storing internal mutable state on Command instances.
@@ -117,4 +117,4 @@ declare abstract class Command {
117
117
  }
118
118
  //#endregion
119
119
  export { Command as t };
120
- //# sourceMappingURL=command-DcebcSrL.d.mts.map
120
+ //# sourceMappingURL=command-B-QH-Vu3.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"command-DcebcSrL.d.mts","names":[],"sources":["../src/quarry/constants.ts","../src/quarry/command.ts"],"mappings":";;;;;;cAIa,iBAAA;;;;AAAb;;;;;;;;ACqBA;;;;;;;;;;uBAAsB,OAAA;EA8LmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAA,OA7JhD,OAAA;EA4HC;EAAA,OA1HD,WAAA;EA+HD;EAAA,OA7HC,OAAA;EAAA,CAEN,iBAAA,GAAoB,gBAAA;;EA4IC;;;;EAAA,SA3Hb,MAAA,CAAA,mBAA0B,OAAA;EAsIa;;;EA/HhD,KAAA,GAAA,CAAS,IAAA,WAAe,CAAA;;;;EAOxB,MAAA,CAAO,IAAA;;;;EAcP,OAAA,CAAQ,IAAA;;;;EAcR,MAAA,CAAO,IAAA;;;;EAeP,KAAA,CAAM,IAAA;;EAcN,IAAA,CAAK,OAAA;;EAKL,OAAA,CAAQ,OAAA;;EAKR,IAAA,CAAK,OAAA;;EAKL,KAAA,CAAM,OAAA;;EAKN,IAAA,CAAK,OAAA;;EAKL,OAAA,CAAA;;EAKA,OAAA,CAAQ,OAAA;;EAKR,KAAA,CAAM,OAAA,YAAmB,IAAA;;EAiBzB,IAAA,CAAK,OAAA,UAAiB,QAAA;;;;;EAWhB,IAAA,CAAK,IAAA,UAAc,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,aAAA;AAAA"}
1
+ {"version":3,"file":"command-B-QH-Vu3.d.mts","names":[],"sources":["../src/quarry/constants.ts","../src/quarry/command.ts"],"mappings":";;;;;;cAIa,iBAAA;;;;AAAb;;;;;;;;ACsBA;;;;;;;;;;uBAAsB,OAAA;EA8LmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAA,OA7JhD,OAAA;EA4HC;EAAA,OA1HD,WAAA;EA+HD;EAAA,OA7HC,OAAA;EAAA,CAEN,iBAAA,GAAoB,gBAAA;;EA4IC;;;;EAAA,SA3Hb,MAAA,CAAA,mBAA0B,OAAA;EAsIa;;;EA/HhD,KAAA,GAAA,CAAS,IAAA,WAAe,CAAA;;;;EAOxB,MAAA,CAAO,IAAA;;;;EAcP,OAAA,CAAQ,IAAA;;;;EAcR,MAAA,CAAO,IAAA;;;;EAeP,KAAA,CAAM,IAAA;;EAcN,IAAA,CAAK,OAAA;;EAKL,OAAA,CAAQ,OAAA;;EAKR,IAAA,CAAK,OAAA;;EAKL,KAAA,CAAM,OAAA;;EAKN,IAAA,CAAK,OAAA;;EAKL,OAAA,CAAA;;EAKA,OAAA,CAAQ,OAAA;;EAKR,KAAA,CAAM,OAAA,YAAmB,IAAA;;EAiBzB,IAAA,CAAK,OAAA,UAAiB,QAAA;;;;;EAWhB,IAAA,CAAK,IAAA,UAAc,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,aAAA;AAAA"}
@@ -1,3 +1,4 @@
1
+ import { a as green, n as cyan, o as red, r as dim, s as yellow, t as bold } from "./colors-DJaRDXoS.mjs";
1
2
  import "reflect-metadata";
2
3
  //#region src/quarry/constants.ts
3
4
  /**
@@ -134,19 +135,19 @@ var Command = class {
134
135
  }
135
136
  /** Write an informational message to output */
136
137
  info(message) {
137
- this[COMMAND_INTERNALS].output.push(message);
138
+ this[COMMAND_INTERNALS].output.push(cyan(message));
138
139
  }
139
140
  /** Write a success message to output */
140
141
  success(message) {
141
- this[COMMAND_INTERNALS].output.push(message);
142
+ this[COMMAND_INTERNALS].output.push(`${green(bold("✔"))} ${green(message)}`);
142
143
  }
143
144
  /** Write a warning message to output */
144
145
  warn(message) {
145
- this[COMMAND_INTERNALS].output.push(`Warning: ${message}`);
146
+ this[COMMAND_INTERNALS].output.push(`${yellow(bold("⚠"))} ${yellow(message)}`);
146
147
  }
147
148
  /** Write an error message to errors */
148
149
  error(message) {
149
- this[COMMAND_INTERNALS].errors.push(message);
150
+ this[COMMAND_INTERNALS].errors.push(red(message));
150
151
  }
151
152
  /** Write a plain line to output */
152
153
  line(message) {
@@ -158,7 +159,7 @@ var Command = class {
158
159
  }
159
160
  /** Write a comment-style line to output */
160
161
  comment(message) {
161
- this[COMMAND_INTERNALS].output.push(`// ${message}`);
162
+ this[COMMAND_INTERNALS].output.push(dim(`// ${message}`));
162
163
  }
163
164
  /** Write a formatted table to output */
164
165
  table(headers, rows) {
@@ -167,13 +168,13 @@ var Command = class {
167
168
  return Math.max(h.length, maxRow);
168
169
  });
169
170
  const formatRow = (cells) => cells.map((cell, i) => cell.padEnd(colWidths[i])).join(" ");
170
- this[COMMAND_INTERNALS].output.push(formatRow(headers));
171
- this[COMMAND_INTERNALS].output.push(colWidths.map((w) => "-".repeat(w)).join(" "));
171
+ this[COMMAND_INTERNALS].output.push(bold(formatRow(headers)));
172
+ this[COMMAND_INTERNALS].output.push(dim(colWidths.map((w) => "-".repeat(w)).join(" ")));
172
173
  for (const row of rows) this[COMMAND_INTERNALS].output.push(formatRow(row));
173
174
  }
174
175
  /** Write an error message and set exit code */
175
176
  fail(message, exitCode = 1) {
176
- this[COMMAND_INTERNALS].errors.push(message);
177
+ this[COMMAND_INTERNALS].errors.push(`${red(bold("✖"))} ${red(message)}`);
177
178
  this[COMMAND_INTERNALS].exitCode = exitCode;
178
179
  }
179
180
  /**
@@ -189,4 +190,4 @@ var Command = class {
189
190
  //#endregion
190
191
  export { CommandError as n, COMMAND_INTERNALS as r, Command as t };
191
192
 
192
- //# sourceMappingURL=command-DG_u5ob2.mjs.map
193
+ //# sourceMappingURL=command-BvCOD6df.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"command-DG_u5ob2.mjs","names":[],"sources":["../src/quarry/constants.ts","../src/quarry/errors/command.error.ts","../src/quarry/command.ts"],"sourcesContent":["/**\n * Symbol key for storing internal mutable state on Command instances.\n * Keeps internal state hidden from user-facing autocomplete.\n */\nexport const COMMAND_INTERNALS = Symbol.for('stratal:command:internals')\n","/**\n * User-facing command error with a plain English message.\n *\n * Quarry catches this in `call()` and puts the message into `CommandResult.errors`.\n * Does NOT extend `ApplicationError` (which requires i18n keys + error codes).\n * Not routed through GlobalErrorHandler.\n */\nexport class CommandError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'CommandError'\n }\n}\n","import 'reflect-metadata'\n\nimport { COMMAND_INTERNALS } from './constants'\nimport { CommandError } from './errors/command.error'\nimport type { CommandInput, CommandInternals, CommandResult } from './types'\n\n/**\n * Abstract base class for Quarry commands.\n *\n * Subclasses define a static `command` signature string and implement `handle()`.\n *\n * @example\n * ```typescript\n * export class GreetCommand extends Command {\n * static command = 'greet {name : The name to greet} {--loud}'\n * static description = 'Greet someone'\n *\n * async handle(): Promise<void> {\n * const name = this.string('name')\n * const loud = this.boolean('loud')\n * this.info(loud ? `HELLO, ${name.toUpperCase()}!` : `Hello, ${name}!`)\n * }\n * }\n * ```\n */\nexport abstract class Command {\n /**\n * Laravel-style command signature string.\n *\n * **Command names:**\n * - `'greet'` — flat command (`quarry greet`)\n * - `'task add'` — subcommand hierarchy via spaces (`quarry task add`)\n * - `'task:add'` — namespaced flat command via colons (`quarry task:add`)\n *\n * **Arguments:**\n * - `{name}` — required argument\n * - `{name?}` — optional argument\n * - `{name=default}` — argument with default value\n * - `{name*}` — array/variadic argument\n * - `{name : description}` — argument with description\n *\n * **Options:**\n * - `{--flag}` — boolean flag\n * - `{--name=}` — option that accepts a value\n * - `{--name=default}` — option with default value\n * - `{--name=*}` — array option (multiple values)\n * - `{--A|name}` — option with single-char alias\n * - `{--name= : description}` — option with description\n *\n * @example\n * ```typescript\n * // Namespaced flat command: `quarry users:create ...`\n * static command = 'users:create {email : The user email} {--A|admin} {--R|role= : Assign a role}'\n *\n * // Subcommand hierarchy: `quarry users create ...`\n * static command = 'users create {email : The user email} {--A|admin} {--R|role= : Assign a role}'\n * ```\n */\n static command: string\n /** Human-readable description */\n static description?: string\n /** Alternative command names */\n static aliases?: string[];\n\n [COMMAND_INTERNALS]: CommandInternals\n\n constructor() {\n this[COMMAND_INTERNALS] = {\n inputs: {},\n output: [],\n errors: [],\n exitCode: 0,\n quarry: null,\n }\n }\n\n /**\n * Implement this method with the command's logic.\n * Return a number to set the exit code, or void for exit code 0.\n */\n // eslint-disable-next-line @typescript-eslint/no-invalid-void-type\n abstract handle(): number | void | Promise<number | void>\n\n // ── Input Accessors ──────────────────────────────────────────────\n\n /**\n * Get an input value with generic type.\n */\n input<T>(name: string): T {\n return this[COMMAND_INTERNALS].inputs[name] as T\n }\n\n /**\n * Get a string input. Throws CommandError if present but not a string.\n */\n string(name: string): string {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return ''\n }\n if (typeof value !== 'string') {\n throw new CommandError(`Input \"${name}\" expected a string, got ${typeof value}`)\n }\n return value\n }\n\n /**\n * Get a boolean input. Throws CommandError if present but not a boolean.\n */\n boolean(name: string): boolean {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return false\n }\n if (typeof value !== 'boolean') {\n throw new CommandError(`Input \"${name}\" expected a boolean, got ${typeof value}`)\n }\n return value\n }\n\n /**\n * Get a number input. Coerces strings to numbers. Throws CommandError on NaN.\n */\n number(name: string): number {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return 0\n }\n const num = typeof value === 'string' ? Number(value) : value\n if (typeof num !== 'number' || Number.isNaN(num)) {\n throw new CommandError(`Input \"${name}\" expected a number, got ${typeof value}`)\n }\n return num\n }\n\n /**\n * Get an array input. Throws CommandError if present but not an array.\n */\n array(name: string): string[] {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return []\n }\n if (!Array.isArray(value)) {\n throw new CommandError(`Input \"${name}\" expected an array, got ${typeof value}`)\n }\n return value as string[]\n }\n\n // ── Output Helpers ───────────────────────────────────────────────\n\n /** Write an informational message to output */\n info(message: string): void {\n this[COMMAND_INTERNALS].output.push(message)\n }\n\n /** Write a success message to output */\n success(message: string): void {\n this[COMMAND_INTERNALS].output.push(message)\n }\n\n /** Write a warning message to output */\n warn(message: string): void {\n this[COMMAND_INTERNALS].output.push(`Warning: ${message}`)\n }\n\n /** Write an error message to errors */\n error(message: string): void {\n this[COMMAND_INTERNALS].errors.push(message)\n }\n\n /** Write a plain line to output */\n line(message?: string): void {\n this[COMMAND_INTERNALS].output.push(message ?? '')\n }\n\n /** Write an empty line to output */\n newLine(): void {\n this[COMMAND_INTERNALS].output.push('')\n }\n\n /** Write a comment-style line to output */\n comment(message: string): void {\n this[COMMAND_INTERNALS].output.push(`// ${message}`)\n }\n\n /** Write a formatted table to output */\n table(headers: string[], rows: string[][]): void {\n const colWidths = headers.map((h, i) => {\n const maxRow = rows.reduce((max, row) => Math.max(max, (row[i] ?? '').length), 0)\n return Math.max(h.length, maxRow)\n })\n\n const formatRow = (cells: string[]) =>\n cells.map((cell, i) => cell.padEnd(colWidths[i])).join(' ')\n\n this[COMMAND_INTERNALS].output.push(formatRow(headers))\n this[COMMAND_INTERNALS].output.push(colWidths.map((w) => '-'.repeat(w)).join(' '))\n for (const row of rows) {\n this[COMMAND_INTERNALS].output.push(formatRow(row))\n }\n }\n\n /** Write an error message and set exit code */\n fail(message: string, exitCode = 1): void {\n this[COMMAND_INTERNALS].errors.push(message)\n this[COMMAND_INTERNALS].exitCode = exitCode\n }\n\n // ── Command Calling ──────────────────────────────────────────────\n\n /**\n * Call another command from within this command.\n * Delegates to Quarry.call() via internal reference.\n */\n async call(name: string, input?: CommandInput): Promise<CommandResult> {\n const internals = this[COMMAND_INTERNALS]\n if (!internals.quarry) {\n throw new CommandError('Cannot call commands: Quarry reference not set')\n }\n return internals.quarry.call(name, input)\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"command-BvCOD6df.mjs","names":[],"sources":["../src/quarry/constants.ts","../src/quarry/errors/command.error.ts","../src/quarry/command.ts"],"sourcesContent":["/**\n * Symbol key for storing internal mutable state on Command instances.\n * Keeps internal state hidden from user-facing autocomplete.\n */\nexport const COMMAND_INTERNALS = Symbol.for('stratal:command:internals')\n","/**\n * User-facing command error with a plain English message.\n *\n * Quarry catches this in `call()` and puts the message into `CommandResult.errors`.\n * Does NOT extend `ApplicationError` (which requires i18n keys + error codes).\n * Not routed through GlobalErrorHandler.\n */\nexport class CommandError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'CommandError'\n }\n}\n","import 'reflect-metadata'\n\nimport { bold, cyan, dim, green, red, yellow } from './colors'\nimport { COMMAND_INTERNALS } from './constants'\nimport { CommandError } from './errors/command.error'\nimport type { CommandInput, CommandInternals, CommandResult } from './types'\n\n/**\n * Abstract base class for Quarry commands.\n *\n * Subclasses define a static `command` signature string and implement `handle()`.\n *\n * @example\n * ```typescript\n * export class GreetCommand extends Command {\n * static command = 'greet {name : The name to greet} {--loud}'\n * static description = 'Greet someone'\n *\n * async handle(): Promise<void> {\n * const name = this.string('name')\n * const loud = this.boolean('loud')\n * this.info(loud ? `HELLO, ${name.toUpperCase()}!` : `Hello, ${name}!`)\n * }\n * }\n * ```\n */\nexport abstract class Command {\n /**\n * Laravel-style command signature string.\n *\n * **Command names:**\n * - `'greet'` — flat command (`quarry greet`)\n * - `'task add'` — subcommand hierarchy via spaces (`quarry task add`)\n * - `'task:add'` — namespaced flat command via colons (`quarry task:add`)\n *\n * **Arguments:**\n * - `{name}` — required argument\n * - `{name?}` — optional argument\n * - `{name=default}` — argument with default value\n * - `{name*}` — array/variadic argument\n * - `{name : description}` — argument with description\n *\n * **Options:**\n * - `{--flag}` — boolean flag\n * - `{--name=}` — option that accepts a value\n * - `{--name=default}` — option with default value\n * - `{--name=*}` — array option (multiple values)\n * - `{--A|name}` — option with single-char alias\n * - `{--name= : description}` — option with description\n *\n * @example\n * ```typescript\n * // Namespaced flat command: `quarry users:create ...`\n * static command = 'users:create {email : The user email} {--A|admin} {--R|role= : Assign a role}'\n *\n * // Subcommand hierarchy: `quarry users create ...`\n * static command = 'users create {email : The user email} {--A|admin} {--R|role= : Assign a role}'\n * ```\n */\n static command: string\n /** Human-readable description */\n static description?: string\n /** Alternative command names */\n static aliases?: string[];\n\n [COMMAND_INTERNALS]: CommandInternals\n\n constructor() {\n this[COMMAND_INTERNALS] = {\n inputs: {},\n output: [],\n errors: [],\n exitCode: 0,\n quarry: null,\n }\n }\n\n /**\n * Implement this method with the command's logic.\n * Return a number to set the exit code, or void for exit code 0.\n */\n // eslint-disable-next-line @typescript-eslint/no-invalid-void-type\n abstract handle(): number | void | Promise<number | void>\n\n // ── Input Accessors ──────────────────────────────────────────────\n\n /**\n * Get an input value with generic type.\n */\n input<T>(name: string): T {\n return this[COMMAND_INTERNALS].inputs[name] as T\n }\n\n /**\n * Get a string input. Throws CommandError if present but not a string.\n */\n string(name: string): string {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return ''\n }\n if (typeof value !== 'string') {\n throw new CommandError(`Input \"${name}\" expected a string, got ${typeof value}`)\n }\n return value\n }\n\n /**\n * Get a boolean input. Throws CommandError if present but not a boolean.\n */\n boolean(name: string): boolean {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return false\n }\n if (typeof value !== 'boolean') {\n throw new CommandError(`Input \"${name}\" expected a boolean, got ${typeof value}`)\n }\n return value\n }\n\n /**\n * Get a number input. Coerces strings to numbers. Throws CommandError on NaN.\n */\n number(name: string): number {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return 0\n }\n const num = typeof value === 'string' ? Number(value) : value\n if (typeof num !== 'number' || Number.isNaN(num)) {\n throw new CommandError(`Input \"${name}\" expected a number, got ${typeof value}`)\n }\n return num\n }\n\n /**\n * Get an array input. Throws CommandError if present but not an array.\n */\n array(name: string): string[] {\n const value = this[COMMAND_INTERNALS].inputs[name]\n if (value === undefined || value === null) {\n return []\n }\n if (!Array.isArray(value)) {\n throw new CommandError(`Input \"${name}\" expected an array, got ${typeof value}`)\n }\n return value as string[]\n }\n\n // ── Output Helpers ───────────────────────────────────────────────\n\n /** Write an informational message to output */\n info(message: string): void {\n this[COMMAND_INTERNALS].output.push(cyan(message))\n }\n\n /** Write a success message to output */\n success(message: string): void {\n this[COMMAND_INTERNALS].output.push(`${green(bold('✔'))} ${green(message)}`)\n }\n\n /** Write a warning message to output */\n warn(message: string): void {\n this[COMMAND_INTERNALS].output.push(`${yellow(bold('⚠'))} ${yellow(message)}`)\n }\n\n /** Write an error message to errors */\n error(message: string): void {\n this[COMMAND_INTERNALS].errors.push(red(message))\n }\n\n /** Write a plain line to output */\n line(message?: string): void {\n this[COMMAND_INTERNALS].output.push(message ?? '')\n }\n\n /** Write an empty line to output */\n newLine(): void {\n this[COMMAND_INTERNALS].output.push('')\n }\n\n /** Write a comment-style line to output */\n comment(message: string): void {\n this[COMMAND_INTERNALS].output.push(dim(`// ${message}`))\n }\n\n /** Write a formatted table to output */\n table(headers: string[], rows: string[][]): void {\n const colWidths = headers.map((h, i) => {\n const maxRow = rows.reduce((max, row) => Math.max(max, (row[i] ?? '').length), 0)\n return Math.max(h.length, maxRow)\n })\n\n const formatRow = (cells: string[]) =>\n cells.map((cell, i) => cell.padEnd(colWidths[i])).join(' ')\n\n this[COMMAND_INTERNALS].output.push(bold(formatRow(headers)))\n this[COMMAND_INTERNALS].output.push(dim(colWidths.map((w) => '-'.repeat(w)).join(' ')))\n for (const row of rows) {\n this[COMMAND_INTERNALS].output.push(formatRow(row))\n }\n }\n\n /** Write an error message and set exit code */\n fail(message: string, exitCode = 1): void {\n this[COMMAND_INTERNALS].errors.push(`${red(bold('✖'))} ${red(message)}`)\n this[COMMAND_INTERNALS].exitCode = exitCode\n }\n\n // ── Command Calling ──────────────────────────────────────────────\n\n /**\n * Call another command from within this command.\n * Delegates to Quarry.call() via internal reference.\n */\n async call(name: string, input?: CommandInput): Promise<CommandResult> {\n const internals = this[COMMAND_INTERNALS]\n if (!internals.quarry) {\n throw new CommandError('Cannot call commands: Quarry reference not set')\n }\n return internals.quarry.call(name, input)\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { dt as OnInitialize, it as DynamicModule, lt as ModuleContext, ot as FactoryProvider } from "../index-D69rxo8H.mjs";
2
- import { o as z } from "../index-CpAN9ENH.mjs";
1
+ import { dt as OnInitialize, it as DynamicModule, lt as ModuleContext, ot as FactoryProvider } from "../index-BJWm863C.mjs";
2
+ import { o as z } from "../index-DVhdhLvE.mjs";
3
3
  import { InjectionToken } from "tsyringe";
4
4
 
5
5
  //#region src/config/config.tokens.d.ts
@@ -1,13 +1,14 @@
1
1
  import { S as ApplicationError, b as ERROR_CODES, s as Scope } from "../errors-CtCi1wn6.mjs";
2
2
  import { i as Transient, l as DI_TOKENS, t as __decorate } from "../decorate-D5j-d9_z.mjs";
3
3
  import "../logger-BR1-s1Um.mjs";
4
- import { r as Module } from "../module-BH7t7BGG.mjs";
4
+ import { r as Module } from "../module-BgdxxzBe.mjs";
5
5
  import "../events-CXl-o1Ad.mjs";
6
- import "../command-DG_u5ob2.mjs";
7
- import "../is-command-MZDCH-0T.mjs";
8
- import "../is-seeder-BN9Ej1r7.mjs";
9
- import "../middleware-iRhNjsPH.mjs";
10
- import "../router-context-BLn4PrRG.mjs";
6
+ import "../colors-DJaRDXoS.mjs";
7
+ import "../command-BvCOD6df.mjs";
8
+ import "../is-command-BfCgWAcQ.mjs";
9
+ import "../is-seeder-CebjZCDn.mjs";
10
+ import "../middleware-C0Ebzswy.mjs";
11
+ import "../router-context-BEJe9HEB.mjs";
11
12
  //#region src/config/config.tokens.ts
12
13
  const CONFIG_TOKENS = { ConfigService: Symbol.for("stratal:config:service") };
13
14
  //#endregion