@stacksjs/bun-router 0.0.14 → 0.0.15

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 (273) hide show
  1. package/README.md +261 -584
  2. package/bin/cli.ts +9 -0
  3. package/dist/auth.d.ts +134 -0
  4. package/dist/cache/lru-cache.d.ts +139 -0
  5. package/dist/cache/middleware-memoization.d.ts +151 -0
  6. package/dist/cache/route-cache-warmer.d.ts +161 -0
  7. package/dist/cache/sqlite-cache.d.ts +209 -0
  8. package/dist/cache/streaming-cache.d.ts +132 -0
  9. package/dist/chunk-j0e7z7hd.js +18053 -0
  10. package/dist/cli/colors.d.ts +15 -0
  11. package/dist/cli/index.d.ts +10 -0
  12. package/dist/cli/middleware.d.ts +31 -0
  13. package/dist/cli/openapi.d.ts +17 -0
  14. package/dist/cli/router.d.ts +15 -0
  15. package/dist/cli/routes.d.ts +29 -0
  16. package/dist/cli/utils.d.ts +74 -0
  17. package/dist/cli.d.ts +1 -0
  18. package/dist/cli.js +3360 -0
  19. package/dist/config.d.ts +7 -0
  20. package/dist/container/container.d.ts +273 -0
  21. package/dist/container/contextual-binding.d.ts +240 -0
  22. package/dist/container/decorators.d.ts +141 -0
  23. package/dist/container/service-provider.d.ts +285 -0
  24. package/dist/development/hot-reload.d.ts +187 -0
  25. package/dist/development/index.d.ts +167 -0
  26. package/dist/development/performance-profiler.d.ts +217 -0
  27. package/dist/development/route-debugger.d.ts +154 -0
  28. package/dist/development/route-inspector.d.ts +211 -0
  29. package/dist/development/typescript-utilities.d.ts +209 -0
  30. package/dist/docs.d.ts +11 -0
  31. package/dist/errors/circuit-breaker.d.ts +195 -0
  32. package/dist/errors/error-handler.d.ts +88 -0
  33. package/dist/errors/error-reporting.d.ts +144 -0
  34. package/dist/errors/exceptions.d.ts +184 -0
  35. package/dist/errors/graceful-degradation.d.ts +154 -0
  36. package/dist/errors/index.d.ts +9 -0
  37. package/dist/errors/router-errors.d.ts +110 -0
  38. package/dist/file-serving/static-files.d.ts +143 -0
  39. package/dist/index.d.ts +14 -0
  40. package/dist/index.js +13968 -0
  41. package/dist/middleware/auth.d.ts +63 -0
  42. package/dist/middleware/content_security_policy.d.ts +53 -0
  43. package/dist/middleware/cors.d.ts +5 -0
  44. package/dist/middleware/csrf.d.ts +7 -0
  45. package/dist/middleware/ddos_protection.d.ts +39 -0
  46. package/dist/middleware/file_security.d.ts +26 -0
  47. package/dist/middleware/file_upload.d.ts +38 -0
  48. package/dist/middleware/helmet.d.ts +54 -0
  49. package/dist/middleware/index.d.ts +44 -0
  50. package/dist/middleware/input_validation.d.ts +45 -0
  51. package/dist/middleware/json_body.d.ts +4 -0
  52. package/dist/middleware/performance_alerting.d.ts +87 -0
  53. package/dist/middleware/performance_dashboard.d.ts +87 -0
  54. package/dist/middleware/performance_monitor.d.ts +209 -0
  55. package/dist/middleware/pipeline.d.ts +131 -0
  56. package/dist/middleware/rate_limit.d.ts +36 -0
  57. package/dist/middleware/request_id.d.ts +4 -0
  58. package/dist/middleware/request_signing.d.ts +153 -0
  59. package/dist/middleware/request_tracer.d.ts +72 -0
  60. package/dist/middleware/response_cache.d.ts +97 -0
  61. package/dist/middleware/security.d.ts +69 -0
  62. package/dist/middleware/security_suite.d.ts +46 -0
  63. package/dist/middleware/session.d.ts +23 -0
  64. package/dist/model-binding/index.d.ts +2 -0
  65. package/dist/model-binding/model-middleware.d.ts +118 -0
  66. package/dist/model-binding/model-registry.d.ts +164 -0
  67. package/dist/model-binding.d.ts +185 -0
  68. package/dist/model-resolver-factory.d.ts +31 -0
  69. package/dist/observability/correlation.d.ts +187 -0
  70. package/dist/observability/health-checks.d.ts +186 -0
  71. package/dist/observability/index.d.ts +60 -0
  72. package/dist/observability/integration.d.ts +147 -0
  73. package/dist/observability/metrics.d.ts +184 -0
  74. package/dist/observability/tracing.d.ts +187 -0
  75. package/dist/optimization/bun-utilities.d.ts +224 -0
  76. package/dist/query-builder-integration.d.ts +36 -0
  77. package/dist/request/context.d.ts +34 -0
  78. package/dist/request/enhanced-request.d.ts +213 -0
  79. package/dist/request/macros.d.ts +300 -0
  80. package/dist/response/macros.d.ts +256 -0
  81. package/dist/response/response-factory.d.ts +133 -0
  82. package/dist/router/api-routes.d.ts +5 -0
  83. package/dist/router/file-based-routing.d.ts +118 -0
  84. package/dist/router/file-streaming.d.ts +5 -0
  85. package/dist/router/fluent-router.d.ts +315 -0
  86. package/dist/router/fluent-routing.d.ts +271 -0
  87. package/dist/router/group-organization.d.ts +5 -0
  88. package/dist/router/handler-resolver.d.ts +24 -0
  89. package/dist/router/http-methods.d.ts +10 -0
  90. package/dist/router/index.d.ts +114 -0
  91. package/dist/router/middleware-groups.d.ts +94 -0
  92. package/dist/router/middleware-integration.d.ts +112 -0
  93. package/dist/router/middleware.d.ts +5 -0
  94. package/dist/router/model-binding.d.ts +5 -0
  95. package/dist/router/optimized-route-matching.d.ts +6 -0
  96. package/dist/router/route-building.d.ts +5 -0
  97. package/dist/router/route-compiler.d.ts +153 -0
  98. package/dist/router/route-matching.d.ts +5 -0
  99. package/dist/router/route-trie.d.ts +114 -0
  100. package/dist/router/router.d.ts +317 -0
  101. package/dist/router/server.d.ts +5 -0
  102. package/dist/router/validation-integration.d.ts +170 -0
  103. package/dist/router/view-rendering.d.ts +5 -0
  104. package/dist/router/websocket.d.ts +5 -0
  105. package/dist/routing/route-caching.d.ts +129 -0
  106. package/dist/routing/route-throttling.d.ts +150 -0
  107. package/dist/routing/subdomain-routing.d.ts +206 -0
  108. package/dist/session/database-store.d.ts +51 -0
  109. package/dist/session/file-store.d.ts +22 -0
  110. package/dist/session/index.d.ts +106 -0
  111. package/dist/session/memory-store.d.ts +21 -0
  112. package/dist/session/redis-store.d.ts +31 -0
  113. package/dist/streaming/index.d.ts +3 -0
  114. package/dist/streaming/sse-handler.d.ts +138 -0
  115. package/dist/streaming/stream-handler.d.ts +114 -0
  116. package/dist/testing/auth-testing.d.ts +156 -0
  117. package/dist/testing/file-upload-testing.d.ts +190 -0
  118. package/dist/testing/index.d.ts +10 -0
  119. package/dist/testing/middleware-testing.d.ts +138 -0
  120. package/dist/testing/model-binding-testing.d.ts +186 -0
  121. package/dist/testing/performance-testing.d.ts +235 -0
  122. package/dist/testing/test-client.d.ts +117 -0
  123. package/dist/testing/test-request.d.ts +85 -0
  124. package/dist/testing/test-response.d.ts +90 -0
  125. package/dist/testing/types.d.ts +207 -0
  126. package/dist/testing/websocket-testing.d.ts +227 -0
  127. package/dist/types/controller-types.d.ts +208 -0
  128. package/dist/types/core.d.ts +543 -0
  129. package/dist/types/middleware-types.d.ts +227 -0
  130. package/dist/types/request-response-augmentation.d.ts +261 -0
  131. package/dist/types/route-inference.d.ts +168 -0
  132. package/dist/types.d.ts +1794 -0
  133. package/dist/url.d.ts +56 -0
  134. package/dist/utils/index.d.ts +1 -0
  135. package/dist/utils/query-preservation.d.ts +48 -0
  136. package/dist/utils.d.ts +69 -0
  137. package/dist/validation/validator.d.ts +140 -0
  138. package/dist/websocket/clustering.d.ts +185 -0
  139. package/package.json +45 -44
  140. package/src/auth.ts +469 -0
  141. package/src/cache/lru-cache.ts +457 -0
  142. package/src/cache/middleware-memoization.ts +531 -0
  143. package/src/cache/route-cache-warmer.ts +486 -0
  144. package/src/cache/sqlite-cache.ts +783 -0
  145. package/src/cache/streaming-cache.ts +572 -0
  146. package/src/cli/colors.ts +29 -0
  147. package/src/cli/index.ts +287 -0
  148. package/src/cli/middleware.ts +291 -0
  149. package/src/cli/openapi.ts +407 -0
  150. package/src/cli/router.ts +188 -0
  151. package/src/cli/routes.ts +265 -0
  152. package/src/cli/utils.ts +531 -0
  153. package/src/cli.ts +5 -0
  154. package/src/config.ts +322 -0
  155. package/src/container/container.ts +740 -0
  156. package/src/container/contextual-binding.ts +603 -0
  157. package/src/container/decorators.ts +359 -0
  158. package/src/container/service-provider.ts +596 -0
  159. package/src/development/hot-reload.ts +673 -0
  160. package/src/development/index.ts +499 -0
  161. package/src/development/performance-profiler.ts +717 -0
  162. package/src/development/route-debugger.ts +527 -0
  163. package/src/development/route-inspector.ts +749 -0
  164. package/src/development/typescript-utilities.ts +682 -0
  165. package/src/docs.ts +397 -0
  166. package/src/errors/circuit-breaker.ts +732 -0
  167. package/src/errors/error-handler.ts +569 -0
  168. package/src/errors/error-reporting.ts +672 -0
  169. package/src/errors/exceptions.ts +536 -0
  170. package/src/errors/graceful-degradation.ts +621 -0
  171. package/src/errors/index.ts +21 -0
  172. package/src/errors/router-errors.ts +632 -0
  173. package/src/file-serving/static-files.ts +581 -0
  174. package/src/index.ts +14 -0
  175. package/src/middleware/auth.ts +220 -0
  176. package/src/middleware/content_security_policy.ts +215 -0
  177. package/src/middleware/cors.ts +74 -0
  178. package/src/middleware/csrf.ts +108 -0
  179. package/src/middleware/ddos_protection.ts +255 -0
  180. package/src/middleware/file_security.ts +191 -0
  181. package/src/middleware/file_upload.ts +275 -0
  182. package/src/middleware/helmet.ts +268 -0
  183. package/src/middleware/index.ts +117 -0
  184. package/src/middleware/input_validation.ts +449 -0
  185. package/src/middleware/json_body.ts +37 -0
  186. package/src/middleware/performance_alerting.ts +538 -0
  187. package/src/middleware/performance_dashboard.ts +661 -0
  188. package/src/middleware/performance_monitor.ts +943 -0
  189. package/src/middleware/pipeline.ts +489 -0
  190. package/src/middleware/rate_limit.ts +245 -0
  191. package/src/middleware/request_id.ts +36 -0
  192. package/src/middleware/request_signing.ts +636 -0
  193. package/src/middleware/request_tracer.ts +636 -0
  194. package/src/middleware/response_cache.ts +743 -0
  195. package/src/middleware/security.ts +482 -0
  196. package/src/middleware/security_suite.ts +257 -0
  197. package/src/middleware/session.ts +91 -0
  198. package/src/model-binding/index.ts +18 -0
  199. package/src/model-binding/model-middleware.ts +425 -0
  200. package/src/model-binding/model-registry.ts +550 -0
  201. package/src/model-binding.ts +370 -0
  202. package/src/model-resolver-factory.ts +106 -0
  203. package/src/observability/correlation.ts +691 -0
  204. package/src/observability/health-checks.ts +729 -0
  205. package/src/observability/index.ts +184 -0
  206. package/src/observability/integration.ts +548 -0
  207. package/src/observability/metrics.ts +753 -0
  208. package/src/observability/tracing.ts +638 -0
  209. package/src/optimization/bun-utilities.ts +778 -0
  210. package/src/query-builder-integration.ts +137 -0
  211. package/src/request/context.ts +62 -0
  212. package/src/request/enhanced-request.ts +857 -0
  213. package/src/request/macros.ts +688 -0
  214. package/src/response/macros.ts +665 -0
  215. package/src/response/response-factory.ts +596 -0
  216. package/src/router/api-routes.ts +243 -0
  217. package/src/router/file-based-routing.ts +690 -0
  218. package/src/router/file-streaming.ts +383 -0
  219. package/src/router/fluent-router.ts +927 -0
  220. package/src/router/fluent-routing.ts +797 -0
  221. package/src/router/group-organization.ts +213 -0
  222. package/src/router/handler-resolver.ts +291 -0
  223. package/src/router/http-methods.ts +377 -0
  224. package/src/router/index.ts +187 -0
  225. package/src/router/middleware-groups.ts +222 -0
  226. package/src/router/middleware-integration.ts +399 -0
  227. package/src/router/middleware.ts +231 -0
  228. package/src/router/model-binding.ts +215 -0
  229. package/src/router/optimized-route-matching.ts +253 -0
  230. package/src/router/route-building.ts +221 -0
  231. package/src/router/route-compiler.ts +702 -0
  232. package/src/router/route-matching.ts +349 -0
  233. package/src/router/route-trie.ts +464 -0
  234. package/src/router/router.ts +1604 -0
  235. package/src/router/server.ts +462 -0
  236. package/src/router/validation-integration.ts +443 -0
  237. package/src/router/view-rendering.ts +233 -0
  238. package/src/router/websocket.ts +100 -0
  239. package/src/routing/route-caching.ts +402 -0
  240. package/src/routing/route-throttling.ts +469 -0
  241. package/src/routing/subdomain-routing.ts +492 -0
  242. package/src/session/database-store.ts +109 -0
  243. package/src/session/file-store.ts +148 -0
  244. package/src/session/index.ts +244 -0
  245. package/src/session/memory-store.ts +88 -0
  246. package/src/session/redis-store.ts +93 -0
  247. package/src/streaming/index.ts +17 -0
  248. package/src/streaming/sse-handler.ts +482 -0
  249. package/src/streaming/stream-handler.ts +552 -0
  250. package/src/testing/auth-testing.ts +446 -0
  251. package/src/testing/file-upload-testing.ts +543 -0
  252. package/src/testing/index.ts +10 -0
  253. package/src/testing/middleware-testing.ts +322 -0
  254. package/src/testing/model-binding-testing.ts +645 -0
  255. package/src/testing/performance-testing.ts +738 -0
  256. package/src/testing/test-client.ts +310 -0
  257. package/src/testing/test-request.ts +315 -0
  258. package/src/testing/test-response.ts +332 -0
  259. package/src/testing/types.ts +224 -0
  260. package/src/testing/websocket-testing.ts +590 -0
  261. package/src/types/controller-types.ts +385 -0
  262. package/src/types/core.ts +683 -0
  263. package/src/types/middleware-types.ts +419 -0
  264. package/src/types/request-response-augmentation.ts +489 -0
  265. package/src/types/route-inference.ts +357 -0
  266. package/src/types.ts +2067 -0
  267. package/src/url.ts +126 -0
  268. package/src/utils/index.ts +1 -0
  269. package/src/utils/query-preservation.ts +201 -0
  270. package/src/utils.ts +327 -0
  271. package/src/validation/validator.ts +685 -0
  272. package/src/websocket/clustering.ts +762 -0
  273. package/CHANGELOG.md +0 -770
package/dist/cli.js ADDED
@@ -0,0 +1,3360 @@
1
+ // @bun
2
+ import {
3
+ middleware
4
+ } from "./chunk-j0e7z7hd.js";
5
+
6
+ // src/cli/index.ts
7
+ import process15 from "process";
8
+
9
+ // ../../node_modules/@stacksjs/clapp/dist/index.js
10
+ import { existsSync } from "fs";
11
+ import fs from "fs/promises";
12
+ import os from "os";
13
+ import path from "path";
14
+ import process from "process";
15
+ import { EventEmitter } from "events";
16
+ import process5 from "process";
17
+ import process2 from "process";
18
+ import process3 from "process";
19
+ import process4 from "process";
20
+ import process7 from "process";
21
+ import tty from "tty";
22
+ import process8, { stdin, stdout } from "process";
23
+ import process9, { stdin as stdin2, stdout as stdout2 } from "process";
24
+ import readline2 from "readline";
25
+ class Telemetry {
26
+ configPath;
27
+ config = null;
28
+ events = [];
29
+ retryCount = 0;
30
+ maxRetries = 3;
31
+ retryDelayMs = 1000;
32
+ constructor() {
33
+ const homeDir = os.homedir();
34
+ const configDir = path.join(homeDir, ".config", "clapp");
35
+ this.configPath = path.join(configDir, "telemetry.json");
36
+ }
37
+ async isEnabled() {
38
+ if (process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true") {
39
+ return false;
40
+ }
41
+ if (process.env.NO_TELEMETRY === "1" || process.env.NO_TELEMETRY === "true") {
42
+ return false;
43
+ }
44
+ const config = await this.loadConfig();
45
+ return config.enabled;
46
+ }
47
+ async enable() {
48
+ const config = await this.loadConfig();
49
+ config.enabled = true;
50
+ if (!config.userId) {
51
+ config.userId = this.generateUserId();
52
+ }
53
+ await this.saveConfig(config);
54
+ }
55
+ async disable() {
56
+ const config = await this.loadConfig();
57
+ config.enabled = false;
58
+ await this.saveConfig(config);
59
+ }
60
+ async track(event, data) {
61
+ const enabled = await this.isEnabled();
62
+ if (!enabled) {
63
+ return;
64
+ }
65
+ const telemetryEvent = {
66
+ event,
67
+ ...data,
68
+ timestamp: Date.now(),
69
+ platform: os.platform(),
70
+ nodeVersion: process.version
71
+ };
72
+ this.events.push(telemetryEvent);
73
+ if (this.events.length >= 10) {
74
+ await this.send();
75
+ }
76
+ }
77
+ async trackCommand(command, duration) {
78
+ await this.track("command", {
79
+ command,
80
+ duration
81
+ });
82
+ }
83
+ async trackError(error, command) {
84
+ await this.track("error", {
85
+ error,
86
+ command
87
+ });
88
+ }
89
+ async send() {
90
+ const enabled = await this.isEnabled();
91
+ if (!enabled || this.events.length === 0) {
92
+ return true;
93
+ }
94
+ try {
95
+ this.events = [];
96
+ this.retryCount = 0;
97
+ const config = await this.loadConfig();
98
+ config.lastSent = Date.now();
99
+ await this.saveConfig(config);
100
+ return true;
101
+ } catch {
102
+ if (this.retryCount < this.maxRetries) {
103
+ this.retryCount++;
104
+ const delay = this.retryDelayMs * 2 ** (this.retryCount - 1);
105
+ await this.sleep(delay);
106
+ return this.send();
107
+ }
108
+ this.events = [];
109
+ this.retryCount = 0;
110
+ return false;
111
+ }
112
+ }
113
+ async flush() {
114
+ if (this.events.length === 0) {
115
+ return true;
116
+ }
117
+ return this.send();
118
+ }
119
+ sleep(ms) {
120
+ return new Promise((resolve) => setTimeout(resolve, ms));
121
+ }
122
+ async status() {
123
+ const config = await this.loadConfig();
124
+ return {
125
+ enabled: config.enabled,
126
+ doNotTrack: process.env.DO_NOT_TRACK === "1" || process.env.DO_NOT_TRACK === "true",
127
+ eventsQueued: this.events.length,
128
+ lastSent: config.lastSent
129
+ };
130
+ }
131
+ async loadConfig() {
132
+ if (this.config) {
133
+ return this.config;
134
+ }
135
+ try {
136
+ if (existsSync(this.configPath)) {
137
+ const data = await fs.readFile(this.configPath, "utf-8");
138
+ this.config = JSON.parse(data);
139
+ return this.config;
140
+ }
141
+ } catch {}
142
+ this.config = {
143
+ enabled: false
144
+ };
145
+ return this.config;
146
+ }
147
+ async saveConfig(config) {
148
+ this.config = config;
149
+ try {
150
+ const configDir = path.dirname(this.configPath);
151
+ await fs.mkdir(configDir, { recursive: true });
152
+ await fs.writeFile(this.configPath, JSON.stringify(config, null, 2), "utf-8");
153
+ } catch {}
154
+ }
155
+ generateUserId() {
156
+ const random = Math.random().toString(36).substring(2, 15);
157
+ const timestamp = Date.now().toString(36);
158
+ return `${random}-${timestamp}`;
159
+ }
160
+ }
161
+ var telemetry = new Telemetry;
162
+ function parseArgv(argv, opts = {}) {
163
+ const result = { _: [] };
164
+ const alias = opts.alias || {};
165
+ const booleans = new Set(opts.boolean || []);
166
+ const aliasOf = {};
167
+ for (const key of Object.keys(alias)) {
168
+ for (const a of alias[key]) {
169
+ aliasOf[a] = key;
170
+ }
171
+ }
172
+ for (const b of booleans) {
173
+ if (alias[b]) {
174
+ for (const a of alias[b])
175
+ booleans.add(a);
176
+ }
177
+ }
178
+ function setKey(key, value) {
179
+ const canonical = aliasOf[key] || key;
180
+ result[canonical] = value;
181
+ if (alias[canonical]) {
182
+ for (const a of alias[canonical])
183
+ result[a] = value;
184
+ }
185
+ if (aliasOf[key] && alias[aliasOf[key]]) {
186
+ for (const a of alias[aliasOf[key]])
187
+ result[a] = value;
188
+ }
189
+ result[key] = value;
190
+ }
191
+ for (let i = 0;i < argv.length; i++) {
192
+ const arg = argv[i];
193
+ if (arg === "--") {
194
+ result._.push(...argv.slice(i + 1));
195
+ break;
196
+ }
197
+ if (arg.startsWith("--")) {
198
+ const eqIdx = arg.indexOf("=");
199
+ if (eqIdx !== -1) {
200
+ const key = arg.slice(2, eqIdx);
201
+ const value = arg.slice(eqIdx + 1);
202
+ setKey(key, value);
203
+ } else {
204
+ const key = arg.slice(2);
205
+ if (key.startsWith("no-")) {
206
+ const actualKey = key.slice(3);
207
+ setKey(actualKey, false);
208
+ continue;
209
+ }
210
+ const canonical = aliasOf[key] || key;
211
+ if (booleans.has(canonical) || booleans.has(key)) {
212
+ setKey(key, true);
213
+ } else {
214
+ const next = argv[i + 1];
215
+ if (next !== undefined && !next.startsWith("-")) {
216
+ setKey(key, next);
217
+ i++;
218
+ } else {
219
+ setKey(key, true);
220
+ }
221
+ }
222
+ }
223
+ } else if (arg.startsWith("-") && arg.length > 1) {
224
+ const chars = arg.slice(1);
225
+ for (let j = 0;j < chars.length; j++) {
226
+ const ch = chars[j];
227
+ const canonical = aliasOf[ch] || ch;
228
+ if (j === chars.length - 1 && !booleans.has(canonical) && !booleans.has(ch)) {
229
+ const next = argv[i + 1];
230
+ if (next !== undefined && !next.startsWith("-")) {
231
+ setKey(ch, next);
232
+ i++;
233
+ } else {
234
+ setKey(ch, true);
235
+ }
236
+ } else {
237
+ setKey(ch, true);
238
+ }
239
+ }
240
+ } else {
241
+ result._.push(arg);
242
+ }
243
+ }
244
+ return result;
245
+ }
246
+ function removeBrackets(v) {
247
+ return v.replace(/[<[].+/, "").trim();
248
+ }
249
+ function findAllBrackets(v) {
250
+ const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;
251
+ const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g;
252
+ const res = [];
253
+ const parse = (match) => {
254
+ let variadic = false;
255
+ let value = match[1];
256
+ if (value.startsWith("...")) {
257
+ value = value.slice(3);
258
+ variadic = true;
259
+ }
260
+ return {
261
+ required: match[0].startsWith("<"),
262
+ value,
263
+ variadic
264
+ };
265
+ };
266
+ let angledMatch;
267
+ while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) {
268
+ res.push(parse(angledMatch));
269
+ }
270
+ let squareMatch;
271
+ while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) {
272
+ res.push(parse(squareMatch));
273
+ }
274
+ return res;
275
+ }
276
+ function getMriOptions(options) {
277
+ const result = { alias: {}, boolean: [] };
278
+ for (const [index, option] of options.entries()) {
279
+ if (option.names.length > 1) {
280
+ result.alias[option.names[0]] = option.names.slice(1);
281
+ }
282
+ if (option.isBoolean) {
283
+ if (option.negated) {
284
+ const hasStringTypeOption = options.some((o, i) => {
285
+ return i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === "boolean";
286
+ });
287
+ if (!hasStringTypeOption) {
288
+ result.boolean.push(option.names[0]);
289
+ }
290
+ } else {
291
+ result.boolean.push(option.names[0]);
292
+ }
293
+ }
294
+ }
295
+ return result;
296
+ }
297
+ function findLongest(arr) {
298
+ return arr.reduce((a, b) => a.length >= b.length ? a : b, "");
299
+ }
300
+ function padRight(str, length) {
301
+ return str.length >= length ? str : `${str}${" ".repeat(length - str.length)}`;
302
+ }
303
+ function camelcase(input) {
304
+ return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {
305
+ return p1 + p2.toUpperCase();
306
+ });
307
+ }
308
+ function setDotProp(obj, keys, val) {
309
+ let i = 0;
310
+ const length = keys.length;
311
+ let t = obj;
312
+ let x;
313
+ for (;i < length; ++i) {
314
+ x = t[keys[i]];
315
+ t = t[keys[i]] = i === length - 1 ? val : x != null ? x : !!~keys[i + 1].indexOf(".") || !(+keys[i + 1] > -1) ? {} : [];
316
+ }
317
+ }
318
+ function setByType(obj, transforms) {
319
+ for (const key of Object.keys(transforms)) {
320
+ const transform = transforms[key];
321
+ if (transform.shouldTransform) {
322
+ obj[key] = Array.prototype.concat.call([], obj[key]);
323
+ if (typeof transform.transformFunction === "function") {
324
+ obj[key] = obj[key].map(transform.transformFunction);
325
+ }
326
+ }
327
+ }
328
+ }
329
+ function getFileName(input) {
330
+ const m = /([^\\/]+)$/.exec(input);
331
+ return m ? m[1] : "";
332
+ }
333
+ function camelcaseOptionName(name) {
334
+ return name.split(".").map((v, i) => {
335
+ return i === 0 ? camelcase(v) : v;
336
+ }).join(".");
337
+ }
338
+
339
+ class ClappError extends Error {
340
+ exitCode = 2;
341
+ isUsageError = true;
342
+ constructor(message) {
343
+ super(message);
344
+ this.name = this.constructor.name;
345
+ if (typeof Error.captureStackTrace === "function") {
346
+ Error.captureStackTrace(this, this.constructor);
347
+ } else {
348
+ this.stack = new Error(message).stack;
349
+ }
350
+ }
351
+ format(showStack = false) {
352
+ if (showStack && this.stack) {
353
+ return `${this.message}
354
+
355
+ Stack trace:
356
+ ${this.stack}`;
357
+ }
358
+ return this.message;
359
+ }
360
+ }
361
+ function isUnicodeSupported() {
362
+ const { env } = process2;
363
+ const { TERM, TERM_PROGRAM } = env;
364
+ if (process2.platform !== "win32") {
365
+ return TERM !== "linux";
366
+ }
367
+ return Boolean(env.WT_SESSION) || Boolean(env.TERMINUS_SUBLIME) || env.ConEmuTask === "{cmd::Cmder}" || TERM_PROGRAM === "Terminus-Sublime" || TERM_PROGRAM === "vscode" || TERM === "xterm-256color" || TERM === "alacritty" || TERM === "rxvt-unicode" || TERM === "rxvt-unicode-256color" || env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
368
+ }
369
+ var ESC = "\x1B";
370
+ var CSI = `${ESC}[`;
371
+ var cursor = {
372
+ to(x, y) {
373
+ if (!y)
374
+ return `${CSI}${x + 1}G`;
375
+ return `${CSI}${y + 1};${x + 1}H`;
376
+ },
377
+ move(x, y) {
378
+ let ret = "";
379
+ if (x < 0)
380
+ ret += `${CSI}${-x}D`;
381
+ else if (x > 0)
382
+ ret += `${CSI}${x}C`;
383
+ if (y < 0)
384
+ ret += `${CSI}${-y}A`;
385
+ else if (y > 0)
386
+ ret += `${CSI}${y}B`;
387
+ return ret;
388
+ },
389
+ up: (count = 1) => `${CSI}${count}A`,
390
+ down: (count = 1) => `${CSI}${count}B`,
391
+ forward: (count = 1) => `${CSI}${count}C`,
392
+ backward: (count = 1) => `${CSI}${count}D`,
393
+ nextLine: (count = 1) => `${CSI}E`.repeat(count),
394
+ prevLine: (count = 1) => `${CSI}F`.repeat(count),
395
+ left: `${CSI}G`,
396
+ hide: `${CSI}?25l`,
397
+ show: `${CSI}?25h`,
398
+ save: `${ESC}7`,
399
+ restore: `${ESC}8`
400
+ };
401
+ var erase = {
402
+ screen: `${CSI}2J`,
403
+ up: (count = 1) => `${CSI}1J`.repeat(count),
404
+ down: (count = 1) => `${CSI}J`.repeat(count),
405
+ line: `${CSI}2K`,
406
+ lineEnd: `${CSI}K`,
407
+ lineStart: `${CSI}1K`,
408
+ lines(count) {
409
+ let clear = "";
410
+ for (let i = 0;i < count; i++)
411
+ clear += this.line + (i < count - 1 ? cursor.up() : "");
412
+ if (count)
413
+ clear += cursor.left;
414
+ return clear;
415
+ }
416
+ };
417
+ var clear = {
418
+ screen: `${ESC}c`
419
+ };
420
+ function levenshteinDistance(a, b) {
421
+ const matrix = [];
422
+ for (let i = 0;i <= b.length; i++) {
423
+ matrix[i] = [i];
424
+ }
425
+ for (let j = 0;j <= a.length; j++) {
426
+ matrix[0][j] = j;
427
+ }
428
+ for (let i = 1;i <= b.length; i++) {
429
+ for (let j = 1;j <= a.length; j++) {
430
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
431
+ matrix[i][j] = matrix[i - 1][j - 1];
432
+ } else {
433
+ matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
434
+ }
435
+ }
436
+ }
437
+ return matrix[b.length][a.length];
438
+ }
439
+ function findSimilarCommands(input, commands, maxDistance = 2, maxSuggestions = 3) {
440
+ return commands.map((cmd) => ({ cmd, distance: levenshteinDistance(input, cmd) })).filter(({ distance }) => distance <= maxDistance).sort((a, b) => a.distance - b.distance).slice(0, maxSuggestions).map(({ cmd }) => cmd);
441
+ }
442
+
443
+ class Option {
444
+ rawName;
445
+ description;
446
+ name;
447
+ names;
448
+ isBoolean;
449
+ required;
450
+ config;
451
+ negated;
452
+ constructor(rawName, description, config) {
453
+ this.rawName = rawName;
454
+ this.description = description;
455
+ this.config = Object.assign({}, config);
456
+ rawName = rawName.replace(/\.\*/g, "");
457
+ this.negated = false;
458
+ this.names = removeBrackets(rawName).split(",").map((v) => {
459
+ let name = v.trim().replace(/^-{1,2}/, "");
460
+ if (name.startsWith("no-")) {
461
+ this.negated = true;
462
+ name = name.replace(/^no-/, "");
463
+ }
464
+ return camelcaseOptionName(name);
465
+ }).sort((a, b) => a.length > b.length ? 1 : -1);
466
+ this.name = this.names[this.names.length - 1];
467
+ if (this.negated && this.config.default == null) {
468
+ this.config.default = true;
469
+ }
470
+ if (rawName.includes("<")) {
471
+ this.required = true;
472
+ } else if (rawName.includes("[")) {
473
+ this.required = false;
474
+ } else {
475
+ this.isBoolean = true;
476
+ }
477
+ }
478
+ }
479
+ var processArgs = process3.argv;
480
+ var platformInfo = `${process3.platform}-${process3.arch} bun-v${typeof Bun !== "undefined" ? Bun.version : "unknown"}`;
481
+ var processArgs2 = process4.argv;
482
+ var platformInfo2 = `${process4.platform}-${process4.arch} node-${process4.version}`;
483
+
484
+ class Command {
485
+ rawName;
486
+ description;
487
+ config;
488
+ cli;
489
+ options;
490
+ aliasNames;
491
+ name;
492
+ namespace;
493
+ args;
494
+ commandAction;
495
+ usageText;
496
+ versionNumber;
497
+ examples;
498
+ helpCallback;
499
+ globalCommand;
500
+ beforeHooks;
501
+ afterHooks;
502
+ middleware;
503
+ constructor(rawName, description, config, cli) {
504
+ this.rawName = rawName;
505
+ this.description = description;
506
+ this.config = config;
507
+ this.cli = cli;
508
+ this.options = [];
509
+ this.aliasNames = [];
510
+ this.name = removeBrackets(rawName);
511
+ const nameWithoutBrackets = removeBrackets(rawName);
512
+ const colonIndex = nameWithoutBrackets.indexOf(":");
513
+ if (colonIndex > 0) {
514
+ this.namespace = nameWithoutBrackets.substring(0, colonIndex);
515
+ this.name = nameWithoutBrackets.substring(colonIndex + 1);
516
+ }
517
+ this.args = findAllBrackets(rawName);
518
+ this.examples = [];
519
+ this.beforeHooks = [];
520
+ this.afterHooks = [];
521
+ this.middleware = [];
522
+ if (!config) {
523
+ this.config = {};
524
+ }
525
+ }
526
+ usage(text) {
527
+ this.usageText = text;
528
+ return this;
529
+ }
530
+ allowUnknownOptions() {
531
+ this.config.allowUnknownOptions = true;
532
+ return this;
533
+ }
534
+ ignoreOptionDefaultValue() {
535
+ this.config.ignoreOptionDefaultValue = true;
536
+ return this;
537
+ }
538
+ version(version, customFlags = "-v, --version") {
539
+ this.versionNumber = version;
540
+ this.option(customFlags, "Display version number");
541
+ return this;
542
+ }
543
+ example(example) {
544
+ this.examples.push(example);
545
+ return this;
546
+ }
547
+ option(rawName, description, config) {
548
+ const option = new Option(rawName, description, config);
549
+ this.options.push(option);
550
+ return this;
551
+ }
552
+ alias(name) {
553
+ this.aliasNames.push(name);
554
+ return this;
555
+ }
556
+ action(callback) {
557
+ this.commandAction = callback;
558
+ return this;
559
+ }
560
+ before(handler) {
561
+ this.beforeHooks.push(handler);
562
+ return this;
563
+ }
564
+ after(handler) {
565
+ this.afterHooks.push(handler);
566
+ return this;
567
+ }
568
+ use(handler) {
569
+ this.middleware.push(handler);
570
+ return this;
571
+ }
572
+ isMatched(name) {
573
+ if (this.aliasNames.includes(name))
574
+ return true;
575
+ if (this.name === name)
576
+ return true;
577
+ if (this.namespace && `${this.namespace}:${this.name}` === name)
578
+ return true;
579
+ return false;
580
+ }
581
+ get isDefaultCommand() {
582
+ return this.name === "" || this.aliasNames.includes("!");
583
+ }
584
+ get isGlobalCommand() {
585
+ return this instanceof GlobalCommand;
586
+ }
587
+ hasOption(name) {
588
+ name = name.split(".")[0];
589
+ return !!this.options.find((option) => {
590
+ return option.names.includes(name);
591
+ });
592
+ }
593
+ outputHelp() {
594
+ const { name, commands } = this.cli;
595
+ const {
596
+ versionNumber,
597
+ options: globalOptions,
598
+ helpCallback
599
+ } = this.cli.globalCommand;
600
+ let sections = [
601
+ {
602
+ body: `${name}${versionNumber ? `/${versionNumber}` : ""}`
603
+ }
604
+ ];
605
+ sections.push({
606
+ title: "Usage",
607
+ body: ` $ ${name} ${this.usageText || this.rawName}`
608
+ });
609
+ const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
610
+ if (showCommands) {
611
+ const longestCommandName = findLongest(commands.map((command) => command.rawName));
612
+ const namespaceGroups = new Map;
613
+ const noNamespaceCommands = [];
614
+ for (const command of commands) {
615
+ if (command.namespace) {
616
+ if (!namespaceGroups.has(command.namespace)) {
617
+ namespaceGroups.set(command.namespace, []);
618
+ }
619
+ namespaceGroups.get(command.namespace).push(command);
620
+ } else {
621
+ noNamespaceCommands.push(command);
622
+ }
623
+ }
624
+ let commandBody = "";
625
+ if (noNamespaceCommands.length > 0) {
626
+ commandBody += noNamespaceCommands.map((command) => {
627
+ return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;
628
+ }).join(`
629
+ `);
630
+ }
631
+ const sortedNamespaces = Array.from(namespaceGroups.keys()).sort();
632
+ for (const namespace of sortedNamespaces) {
633
+ const namespaceCommands = namespaceGroups.get(namespace);
634
+ if (commandBody.length > 0) {
635
+ commandBody += `
636
+
637
+ `;
638
+ }
639
+ commandBody += ` ${namespace}:
640
+ `;
641
+ commandBody += namespaceCommands.map((command) => {
642
+ return ` ${padRight(command.rawName, longestCommandName.length - 2)} ${command.description}`;
643
+ }).join(`
644
+ `);
645
+ }
646
+ sections.push({
647
+ title: "Commands",
648
+ body: commandBody
649
+ });
650
+ sections.push({
651
+ title: `For more info, run any command with the \`--help\` flag`,
652
+ body: commands.map((command) => ` $ ${name}${command.name === "" ? "" : ` ${command.name}`} --help`).join(`
653
+ `)
654
+ });
655
+ }
656
+ let options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];
657
+ if (!this.isGlobalCommand && !this.isDefaultCommand) {
658
+ options = options.filter((option) => option.name !== "version");
659
+ }
660
+ if (options.length > 0) {
661
+ const longestOptionName = findLongest(options.map((option) => option.rawName));
662
+ sections.push({
663
+ title: "Options",
664
+ body: options.map((option) => {
665
+ return ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === undefined ? "" : `(default: ${option.config.default})`}`;
666
+ }).join(`
667
+ `)
668
+ });
669
+ }
670
+ if (this.examples.length > 0) {
671
+ sections.push({
672
+ title: "Examples",
673
+ body: this.examples.map((example) => {
674
+ if (typeof example === "function") {
675
+ return example(name);
676
+ }
677
+ return example;
678
+ }).join(`
679
+ `)
680
+ });
681
+ }
682
+ if (helpCallback) {
683
+ sections = helpCallback(sections) || sections;
684
+ }
685
+ console.log(sections.map((section) => {
686
+ return section.title ? `${section.title}:
687
+ ${section.body}` : section.body;
688
+ }).join(`
689
+
690
+ `));
691
+ }
692
+ outputVersion() {
693
+ const { name } = this.cli;
694
+ const { versionNumber } = this.cli.globalCommand;
695
+ if (versionNumber) {
696
+ const platformInfo3 = typeof Bun !== "undefined" ? platformInfo : platformInfo2;
697
+ console.log(`${name}/${versionNumber} ${platformInfo3}`);
698
+ }
699
+ }
700
+ checkRequiredArgs() {
701
+ const minimalArgsCount = this.args.filter((arg) => arg.required).length;
702
+ if (this.cli.args.length < minimalArgsCount) {
703
+ const requiredArgs = this.args.filter((arg) => arg.required);
704
+ const missingArgs = requiredArgs.slice(this.cli.args.length);
705
+ const argNames = missingArgs.map((arg) => `<${arg.value}>`).join(" ");
706
+ throw new ClappError(`Missing required argument${missingArgs.length > 1 ? "s" : ""}: ${argNames}
707
+
708
+ ` + `Run \`${this.cli.name} ${this.rawName} --help\` for usage information.`);
709
+ }
710
+ }
711
+ checkUnknownOptions() {
712
+ const { options, globalCommand } = this.cli;
713
+ if (!this.config.allowUnknownOptions) {
714
+ for (const name of Object.keys(options)) {
715
+ if (name !== "--" && !this.hasOption(name) && !globalCommand.hasOption(name)) {
716
+ const allOptions = [...globalCommand.options, ...this.options];
717
+ const allOptionNames = allOptions.flatMap((opt) => opt.names);
718
+ const optionFlag = name.length > 1 ? `--${name}` : `-${name}`;
719
+ const suggestions = findSimilarCommands(name, allOptionNames);
720
+ let errorMsg = `Unknown option \`${optionFlag}\``;
721
+ if (suggestions.length > 0) {
722
+ errorMsg += `
723
+
724
+ Did you mean one of these?`;
725
+ suggestions.forEach((suggestion) => {
726
+ const suggestedFlag = suggestion.length > 1 ? `--${suggestion}` : `-${suggestion}`;
727
+ errorMsg += `
728
+ \u2022 ${suggestedFlag}`;
729
+ });
730
+ }
731
+ errorMsg += `
732
+
733
+ Run \`${this.cli.name} ${this.rawName} --help\` to see available options.`;
734
+ throw new ClappError(errorMsg);
735
+ }
736
+ }
737
+ }
738
+ }
739
+ checkOptionValue() {
740
+ const { options: parsedOptions, globalCommand } = this.cli;
741
+ const options = [...globalCommand.options, ...this.options];
742
+ for (const option of options) {
743
+ const value = parsedOptions[option.name.split(".")[0]];
744
+ if (option.required) {
745
+ const hasNegated = options.some((o) => o.negated && o.names.includes(option.name));
746
+ if (value === true || value === false && !hasNegated) {
747
+ throw new ClappError(`Option \`${option.rawName}\` requires a value.
748
+
749
+ ` + `Example: ${this.cli.name} ${this.rawName} ${option.rawName} <value>`);
750
+ }
751
+ }
752
+ }
753
+ }
754
+ }
755
+
756
+ class GlobalCommand extends Command {
757
+ constructor(cli) {
758
+ super("@@global@@", "", {}, cli);
759
+ }
760
+ }
761
+ var Command_default = Command;
762
+ var codes = {
763
+ red: ["\x1B[31m", "\x1B[39m"],
764
+ green: ["\x1B[32m", "\x1B[39m"],
765
+ blue: ["\x1B[34m", "\x1B[39m"],
766
+ yellow: ["\x1B[33m", "\x1B[39m"],
767
+ cyan: ["\x1B[36m", "\x1B[39m"],
768
+ magenta: ["\x1B[35m", "\x1B[39m"],
769
+ white: ["\x1B[37m", "\x1B[39m"],
770
+ gray: ["\x1B[90m", "\x1B[39m"],
771
+ bgRed: ["\x1B[41m", "\x1B[49m"],
772
+ bgGreen: ["\x1B[42m", "\x1B[49m"],
773
+ bgBlue: ["\x1B[44m", "\x1B[49m"],
774
+ bgYellow: ["\x1B[43m", "\x1B[49m"],
775
+ bgCyan: ["\x1B[46m", "\x1B[49m"],
776
+ bgMagenta: ["\x1B[45m", "\x1B[49m"],
777
+ bold: ["\x1B[1m", "\x1B[22m"],
778
+ italic: ["\x1B[3m", "\x1B[23m"],
779
+ underline: ["\x1B[4m", "\x1B[24m"],
780
+ dim: ["\x1B[2m", "\x1B[22m"],
781
+ inverse: ["\x1B[7m", "\x1B[27m"],
782
+ hidden: ["\x1B[8m", "\x1B[28m"],
783
+ strikethrough: ["\x1B[9m", "\x1B[29m"]
784
+ };
785
+ var theme = {
786
+ primary: "blue",
787
+ secondary: "cyan",
788
+ success: "green",
789
+ warning: "yellow",
790
+ error: "red",
791
+ info: "magenta",
792
+ muted: "gray"
793
+ };
794
+ function detectColorSupport() {
795
+ return true;
796
+ }
797
+ function createStyler() {
798
+ const styler = {};
799
+ styler.supportsColor = detectColorSupport();
800
+ function createStyleFunction(styleName, styles = []) {
801
+ const styleList = styleName === "" ? [] : [...styles, styleName];
802
+ const fn = function(text) {
803
+ if (!styler.supportsColor)
804
+ return text;
805
+ let openCodes = "";
806
+ let closeCodes = "";
807
+ for (const style of styleList) {
808
+ if (style in theme && theme[style] in codes) {
809
+ const themeStyle = theme[style];
810
+ openCodes += codes[themeStyle][0];
811
+ closeCodes = codes[themeStyle][1] + closeCodes;
812
+ } else if (style in codes) {
813
+ openCodes += codes[style][0];
814
+ closeCodes = codes[style][1] + closeCodes;
815
+ }
816
+ }
817
+ return openCodes + text + closeCodes;
818
+ };
819
+ const allStyles2 = [...Object.keys(codes), ...Object.keys(theme)];
820
+ for (const style of allStyles2) {
821
+ if (!(style in fn)) {
822
+ Object.defineProperty(fn, style, {
823
+ get() {
824
+ return createStyleFunction(style, styleList);
825
+ }
826
+ });
827
+ }
828
+ }
829
+ return fn;
830
+ }
831
+ const allStyles = [...Object.keys(codes), ...Object.keys(theme)];
832
+ for (const style of allStyles) {
833
+ if (!(style in styler)) {
834
+ Object.defineProperty(styler, style, {
835
+ get() {
836
+ return createStyleFunction(style);
837
+ }
838
+ });
839
+ }
840
+ }
841
+ return styler;
842
+ }
843
+ var style = createStyler();
844
+ class CLI extends EventEmitter {
845
+ name;
846
+ commands;
847
+ globalCommand;
848
+ matchedCommand;
849
+ matchedCommandName;
850
+ rawArgs;
851
+ args;
852
+ options;
853
+ showHelpOnExit;
854
+ showVersionOnExit;
855
+ enableDidYouMean = true;
856
+ signalHandlersSet = false;
857
+ isVerbose = false;
858
+ isQuiet = false;
859
+ isDebug = false;
860
+ isNoInteraction = false;
861
+ environment;
862
+ isDryRun = false;
863
+ isForce = false;
864
+ useEmoji = true;
865
+ theme;
866
+ isNoCache = false;
867
+ constructor(name = "") {
868
+ super();
869
+ this.name = name;
870
+ this.commands = [];
871
+ this.rawArgs = [];
872
+ this.args = [];
873
+ this.options = {};
874
+ this.globalCommand = new GlobalCommand(this);
875
+ this.globalCommand.usage("<command> [options]");
876
+ }
877
+ handleSignals(cleanup) {
878
+ if (this.signalHandlersSet) {
879
+ return this;
880
+ }
881
+ const handleSignal = async (signal) => {
882
+ console.log(`
883
+
884
+ Received ${signal}, cleaning up...`);
885
+ if (cleanup) {
886
+ try {
887
+ await cleanup();
888
+ } catch (error) {
889
+ console.error("Error during cleanup:", error);
890
+ }
891
+ }
892
+ process5.exit(0);
893
+ };
894
+ process5.on("SIGINT", () => handleSignal("SIGINT"));
895
+ process5.on("SIGTERM", () => handleSignal("SIGTERM"));
896
+ this.signalHandlersSet = true;
897
+ return this;
898
+ }
899
+ didYouMean(enabled = true) {
900
+ this.enableDidYouMean = enabled;
901
+ return this;
902
+ }
903
+ verbose() {
904
+ this.globalCommand.option("-v, --verbose", "Enable verbose output");
905
+ return this;
906
+ }
907
+ quiet() {
908
+ this.globalCommand.option("-q, --quiet", "Suppress non-essential output");
909
+ return this;
910
+ }
911
+ debug() {
912
+ this.globalCommand.option("--debug", "Enable debug mode with detailed error information");
913
+ return this;
914
+ }
915
+ noInteraction() {
916
+ this.globalCommand.option("-n, --no-interaction", "Do not ask any interactive questions (for CI/CD)");
917
+ return this;
918
+ }
919
+ env() {
920
+ this.globalCommand.option("--env <environment>", "Target environment (e.g., production, staging, local)");
921
+ return this;
922
+ }
923
+ dryRun() {
924
+ this.globalCommand.option("--dry-run", "Preview actions without executing them");
925
+ return this;
926
+ }
927
+ force() {
928
+ this.globalCommand.option("-f, --force", "Skip confirmation prompts");
929
+ return this;
930
+ }
931
+ emoji() {
932
+ this.globalCommand.option("--no-emoji", "Disable emoji in output");
933
+ return this;
934
+ }
935
+ themes() {
936
+ this.globalCommand.option("--theme <theme>", "Color theme (default, dracula, nord, solarized, monokai)");
937
+ return this;
938
+ }
939
+ cache() {
940
+ this.globalCommand.option("--no-cache", "Disable caching");
941
+ return this;
942
+ }
943
+ usage(text) {
944
+ this.globalCommand.usage(text);
945
+ return this;
946
+ }
947
+ command(rawName, description, config) {
948
+ if (!config) {
949
+ config = {};
950
+ }
951
+ const command = new Command_default(rawName, description || "", config, this);
952
+ command.globalCommand = this.globalCommand;
953
+ this.commands.push(command);
954
+ return command;
955
+ }
956
+ option(rawName, description, config) {
957
+ this.globalCommand.option(rawName, description, config);
958
+ return this;
959
+ }
960
+ help(callback) {
961
+ this.globalCommand.option("-h, --help", "Display this message");
962
+ this.globalCommand.helpCallback = callback;
963
+ this.showHelpOnExit = true;
964
+ return this;
965
+ }
966
+ version(version, customFlags = "-v, --version") {
967
+ this.globalCommand.version(version, customFlags);
968
+ this.showVersionOnExit = true;
969
+ return this;
970
+ }
971
+ example(example) {
972
+ this.globalCommand.example(example);
973
+ return this;
974
+ }
975
+ outputHelp() {
976
+ if (this.matchedCommand) {
977
+ this.matchedCommand.outputHelp();
978
+ } else {
979
+ this.globalCommand.outputHelp();
980
+ }
981
+ }
982
+ outputVersion() {
983
+ this.globalCommand.outputVersion();
984
+ }
985
+ setParsedInfo({ args, options }, matchedCommand, matchedCommandName) {
986
+ this.args = args;
987
+ this.options = options;
988
+ if (matchedCommand) {
989
+ this.matchedCommand = matchedCommand;
990
+ }
991
+ if (matchedCommandName) {
992
+ this.matchedCommandName = matchedCommandName;
993
+ }
994
+ return this;
995
+ }
996
+ unsetMatchedCommand() {
997
+ this.matchedCommand = undefined;
998
+ this.matchedCommandName = undefined;
999
+ }
1000
+ showCommandNotFound(input) {
1001
+ console.log(style.red(`
1002
+ \u2717 Command "${input}" not found.
1003
+ `));
1004
+ if (this.enableDidYouMean) {
1005
+ const allCommandNames = [];
1006
+ for (const command of this.commands) {
1007
+ if (command.name) {
1008
+ allCommandNames.push(command.name);
1009
+ }
1010
+ if (command.aliasNames) {
1011
+ allCommandNames.push(...command.aliasNames);
1012
+ }
1013
+ }
1014
+ const suggestions = findSimilarCommands(input, allCommandNames);
1015
+ if (suggestions.length > 0) {
1016
+ console.log(style.yellow("Did you mean one of these?"));
1017
+ suggestions.forEach((cmd) => console.log(` ${style.dim("\u2022")} ${this.name} ${cmd}`));
1018
+ console.log("");
1019
+ }
1020
+ }
1021
+ console.log(style.dim("Run"), `${this.name} --help`, style.dim("to see all available commands"));
1022
+ process5.exit(1);
1023
+ }
1024
+ async parse(argv = processArgs2, options = {}) {
1025
+ let { run = true, exitOnError = false } = options;
1026
+ if (exitOnError) {
1027
+ try {
1028
+ return await this.parse(argv, { run });
1029
+ } catch (err) {
1030
+ this.handleUsageError(err);
1031
+ throw err;
1032
+ }
1033
+ }
1034
+ this.rawArgs = argv;
1035
+ if (!this.name) {
1036
+ this.name = argv[1] ? getFileName(argv[1]) : "cli";
1037
+ }
1038
+ let shouldParse = true;
1039
+ const slicedArgv = argv.slice(2);
1040
+ const candidateName = slicedArgv[0];
1041
+ if (candidateName && !candidateName.startsWith("-")) {
1042
+ for (const command of this.commands) {
1043
+ if (command.isMatched(candidateName)) {
1044
+ const parsed = this.mri(slicedArgv, command);
1045
+ shouldParse = false;
1046
+ const parsedInfo = {
1047
+ ...parsed,
1048
+ args: parsed.args.slice(1)
1049
+ };
1050
+ this.setParsedInfo(parsedInfo, command, candidateName);
1051
+ this.emit(`command:${candidateName}`, command);
1052
+ break;
1053
+ }
1054
+ }
1055
+ }
1056
+ if (shouldParse) {
1057
+ for (const command of this.commands) {
1058
+ if (command.name === "") {
1059
+ shouldParse = false;
1060
+ const parsed = this.mri(slicedArgv, command);
1061
+ this.setParsedInfo(parsed, command);
1062
+ this.emit(`command:!`, command);
1063
+ break;
1064
+ }
1065
+ }
1066
+ }
1067
+ if (shouldParse) {
1068
+ const parsed = this.mri(argv.slice(2));
1069
+ this.setParsedInfo(parsed);
1070
+ }
1071
+ if (this.options.verbose) {
1072
+ this.isVerbose = true;
1073
+ }
1074
+ if (this.options.quiet) {
1075
+ this.isQuiet = true;
1076
+ }
1077
+ if (this.options.debug) {
1078
+ this.isDebug = true;
1079
+ }
1080
+ if (this.options.noInteraction) {
1081
+ this.isNoInteraction = true;
1082
+ }
1083
+ if (this.options.env) {
1084
+ this.environment = String(this.options.env);
1085
+ }
1086
+ if (this.options.dryRun) {
1087
+ this.isDryRun = true;
1088
+ }
1089
+ if (this.options.force) {
1090
+ this.isForce = true;
1091
+ }
1092
+ if (this.options.noEmoji !== undefined) {
1093
+ this.useEmoji = !this.options.noEmoji;
1094
+ }
1095
+ if (this.options.theme) {
1096
+ this.theme = String(this.options.theme);
1097
+ }
1098
+ if (this.options.noCache !== undefined) {
1099
+ this.isNoCache = Boolean(this.options.noCache);
1100
+ }
1101
+ if (this.options.help && this.showHelpOnExit) {
1102
+ this.outputHelp();
1103
+ run = false;
1104
+ this.unsetMatchedCommand();
1105
+ }
1106
+ if (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) {
1107
+ this.outputVersion();
1108
+ run = false;
1109
+ this.unsetMatchedCommand();
1110
+ }
1111
+ const parsedArgv = { args: this.args, options: this.options };
1112
+ if (run) {
1113
+ await this.runMatchedCommand();
1114
+ }
1115
+ if (!this.matchedCommand && this.args[0]) {
1116
+ this.emit("command:*");
1117
+ const hasWildcardListener = this.listenerCount("command:*") > 0;
1118
+ if (!hasWildcardListener) {
1119
+ this.showCommandNotFound(this.args[0]);
1120
+ }
1121
+ }
1122
+ return parsedArgv;
1123
+ }
1124
+ mri(argv, command) {
1125
+ const cliOptions = [
1126
+ ...this.globalCommand.options,
1127
+ ...command ? command.options : []
1128
+ ];
1129
+ const mriOptions = getMriOptions(cliOptions);
1130
+ let argsAfterDoubleDashes = [];
1131
+ const doubleDashesIndex = argv.indexOf("--");
1132
+ if (doubleDashesIndex > -1) {
1133
+ argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);
1134
+ argv = argv.slice(0, doubleDashesIndex);
1135
+ }
1136
+ const raw = parseArgv(argv, mriOptions);
1137
+ const parsed = { _: raw._ };
1138
+ for (const name of Object.keys(raw)) {
1139
+ if (name !== "_") {
1140
+ parsed[camelcaseOptionName(name)] = raw[name];
1141
+ }
1142
+ }
1143
+ const args = parsed._;
1144
+ const options = {
1145
+ "--": argsAfterDoubleDashes
1146
+ };
1147
+ const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;
1148
+ const transforms = Object.create(null);
1149
+ for (const cliOption of cliOptions) {
1150
+ if (!ignoreDefault && cliOption.config.default !== undefined) {
1151
+ for (const name of cliOption.names) {
1152
+ options[name] = cliOption.config.default;
1153
+ }
1154
+ }
1155
+ if (Array.isArray(cliOption.config.type)) {
1156
+ if (transforms[cliOption.name] === undefined) {
1157
+ transforms[cliOption.name] = {
1158
+ shouldTransform: true,
1159
+ transformFunction: cliOption.config.type[0]
1160
+ };
1161
+ }
1162
+ }
1163
+ }
1164
+ for (const key of Object.keys(parsed)) {
1165
+ if (key !== "_") {
1166
+ const keys = key.split(".");
1167
+ setDotProp(options, keys, parsed[key]);
1168
+ setByType(options, transforms);
1169
+ }
1170
+ }
1171
+ return {
1172
+ args,
1173
+ options
1174
+ };
1175
+ }
1176
+ async run(argv = processArgs2) {
1177
+ return this.parse(argv, { run: true, exitOnError: true });
1178
+ }
1179
+ handleUsageError(err) {
1180
+ const isClappError = !!err && typeof err === "object" && err.name === "ClappError";
1181
+ const isUsage = isClappError && err.isUsageError !== false;
1182
+ if (!isUsage)
1183
+ return;
1184
+ const e = err;
1185
+ const raw = e.message ?? "command-line error";
1186
+ const label = this.name ? `${this.name}: ` : "";
1187
+ const suffix = /--help/.test(raw) ? "" : `
1188
+ Run \`${this.name ?? "cli"} --help\` for usage.`;
1189
+ process5.stderr.write(`${label}${raw}${suffix}
1190
+ `);
1191
+ process5.exit(e.exitCode ?? 2);
1192
+ }
1193
+ async runMatchedCommand() {
1194
+ const { args, options, matchedCommand: command } = this;
1195
+ if (!command || !command.commandAction)
1196
+ return;
1197
+ command.checkUnknownOptions();
1198
+ command.checkOptionValue();
1199
+ command.checkRequiredArgs();
1200
+ const actionArgs = [];
1201
+ command.args.forEach((arg, index) => {
1202
+ if (arg.variadic) {
1203
+ actionArgs.push(args.slice(index));
1204
+ } else {
1205
+ actionArgs.push(args[index]);
1206
+ }
1207
+ });
1208
+ actionArgs.push(options);
1209
+ const context = {
1210
+ command,
1211
+ args: actionArgs,
1212
+ options
1213
+ };
1214
+ for (const hook of command.beforeHooks) {
1215
+ await hook(context);
1216
+ }
1217
+ let actionResult;
1218
+ const executeAction = async () => {
1219
+ const result = command.commandAction.apply(this, actionArgs);
1220
+ if (result instanceof Promise) {
1221
+ actionResult = await result;
1222
+ } else {
1223
+ actionResult = result;
1224
+ }
1225
+ return actionResult;
1226
+ };
1227
+ if (command.middleware.length > 0) {
1228
+ let index = 0;
1229
+ const next = async () => {
1230
+ if (index < command.middleware.length) {
1231
+ const middleware2 = command.middleware[index++];
1232
+ await middleware2({ ...context, next });
1233
+ } else {
1234
+ await executeAction();
1235
+ }
1236
+ };
1237
+ await next();
1238
+ } else {
1239
+ await executeAction();
1240
+ }
1241
+ for (const hook of command.afterHooks) {
1242
+ await hook(context);
1243
+ }
1244
+ return actionResult;
1245
+ }
1246
+ removeSignalHandlers() {
1247
+ if (!this.signalHandlersSet) {
1248
+ return this;
1249
+ }
1250
+ process5.removeAllListeners("SIGINT");
1251
+ process5.removeAllListeners("SIGTERM");
1252
+ this.signalHandlersSet = false;
1253
+ return this;
1254
+ }
1255
+ destroy() {
1256
+ this.removeSignalHandlers();
1257
+ this.commands = [];
1258
+ this.rawArgs = [];
1259
+ this.args = [];
1260
+ this.options = {};
1261
+ this.matchedCommand = undefined;
1262
+ this.matchedCommandName = undefined;
1263
+ this.removeAllListeners();
1264
+ }
1265
+ }
1266
+ class CLICache {
1267
+ cache;
1268
+ enabled;
1269
+ cleanupInterval = null;
1270
+ hits = 0;
1271
+ misses = 0;
1272
+ constructor() {
1273
+ this.cache = new Map;
1274
+ this.enabled = true;
1275
+ this.startCleanupInterval();
1276
+ }
1277
+ startCleanupInterval() {
1278
+ if (this.cleanupInterval) {
1279
+ return;
1280
+ }
1281
+ this.cleanupInterval = setInterval(() => {
1282
+ this.cleanup();
1283
+ }, 30000);
1284
+ this.cleanupInterval.unref();
1285
+ }
1286
+ stopCleanup() {
1287
+ if (this.cleanupInterval) {
1288
+ clearInterval(this.cleanupInterval);
1289
+ this.cleanupInterval = null;
1290
+ }
1291
+ }
1292
+ isEnabled() {
1293
+ return this.enabled;
1294
+ }
1295
+ get(key) {
1296
+ if (!this.enabled) {
1297
+ this.misses++;
1298
+ return;
1299
+ }
1300
+ const entry = this.cache.get(key);
1301
+ if (!entry) {
1302
+ this.misses++;
1303
+ return;
1304
+ }
1305
+ const now = Date.now();
1306
+ if (now - entry.timestamp > entry.ttl) {
1307
+ this.cache.delete(key);
1308
+ this.misses++;
1309
+ return;
1310
+ }
1311
+ this.hits++;
1312
+ return entry.value;
1313
+ }
1314
+ set(key, value, ttl = 5000) {
1315
+ if (!this.enabled) {
1316
+ return;
1317
+ }
1318
+ this.cache.set(key, {
1319
+ value,
1320
+ timestamp: Date.now(),
1321
+ ttl
1322
+ });
1323
+ }
1324
+ has(key) {
1325
+ if (!this.enabled) {
1326
+ return false;
1327
+ }
1328
+ const entry = this.cache.get(key);
1329
+ if (!entry) {
1330
+ return false;
1331
+ }
1332
+ const now = Date.now();
1333
+ if (now - entry.timestamp > entry.ttl) {
1334
+ this.cache.delete(key);
1335
+ return false;
1336
+ }
1337
+ return true;
1338
+ }
1339
+ delete(key) {
1340
+ this.cache.delete(key);
1341
+ }
1342
+ clear() {
1343
+ this.cache.clear();
1344
+ }
1345
+ disable() {
1346
+ this.enabled = false;
1347
+ this.clear();
1348
+ }
1349
+ enable() {
1350
+ this.enabled = true;
1351
+ }
1352
+ stats() {
1353
+ return {
1354
+ size: this.cache.size,
1355
+ enabled: this.enabled,
1356
+ hits: this.hits,
1357
+ misses: this.misses
1358
+ };
1359
+ }
1360
+ resetStats() {
1361
+ this.hits = 0;
1362
+ this.misses = 0;
1363
+ }
1364
+ keys() {
1365
+ return Array.from(this.cache.keys());
1366
+ }
1367
+ cleanup() {
1368
+ const now = Date.now();
1369
+ for (const [key, entry] of this.cache.entries()) {
1370
+ if (now - entry.timestamp > entry.ttl) {
1371
+ this.cache.delete(key);
1372
+ }
1373
+ }
1374
+ }
1375
+ destroy() {
1376
+ this.stopCleanup();
1377
+ this.clear();
1378
+ this.resetStats();
1379
+ }
1380
+ }
1381
+ var cliCache = new CLICache;
1382
+ function detectColorSupport2() {
1383
+ if ("FORCE_COLOR" in process7.env) {
1384
+ return process7.env.FORCE_COLOR !== "0";
1385
+ }
1386
+ if ("NO_COLOR" in process7.env || process7.env.TERM === "dumb") {
1387
+ return false;
1388
+ }
1389
+ if (process7.platform === "win32") {
1390
+ return true;
1391
+ }
1392
+ return tty.isatty(1) && tty.isatty(2);
1393
+ }
1394
+ var enabled = detectColorSupport2();
1395
+ function wrap(open, close) {
1396
+ if (!enabled)
1397
+ return (text) => text;
1398
+ return (text) => open + text + close;
1399
+ }
1400
+ var reset = wrap("\x1B[0m", "\x1B[0m");
1401
+ var red = wrap("\x1B[31m", "\x1B[39m");
1402
+ var green = wrap("\x1B[32m", "\x1B[39m");
1403
+ var yellow = wrap("\x1B[33m", "\x1B[39m");
1404
+ var blue = wrap("\x1B[34m", "\x1B[39m");
1405
+ var magenta = wrap("\x1B[35m", "\x1B[39m");
1406
+ var cyan = wrap("\x1B[36m", "\x1B[39m");
1407
+ var white = wrap("\x1B[37m", "\x1B[39m");
1408
+ var gray = wrap("\x1B[90m", "\x1B[39m");
1409
+ var bold = wrap("\x1B[1m", "\x1B[22m");
1410
+ var italic = wrap("\x1B[3m", "\x1B[23m");
1411
+ var underline = wrap("\x1B[4m", "\x1B[24m");
1412
+ var dim = wrap("\x1B[2m", "\x1B[22m");
1413
+ var inverse = wrap("\x1B[7m", "\x1B[27m");
1414
+ var hidden = wrap("\x1B[8m", "\x1B[28m");
1415
+ var strikethrough = wrap("\x1B[9m", "\x1B[29m");
1416
+ var bgRed = wrap("\x1B[41m", "\x1B[49m");
1417
+ var bgGreen = wrap("\x1B[42m", "\x1B[49m");
1418
+ var bgYellow = wrap("\x1B[43m", "\x1B[49m");
1419
+ var bgBlue = wrap("\x1B[44m", "\x1B[49m");
1420
+ var bgMagenta = wrap("\x1B[45m", "\x1B[49m");
1421
+ var bgCyan = wrap("\x1B[46m", "\x1B[49m");
1422
+ var bgWhite = wrap("\x1B[47m", "\x1B[49m");
1423
+ var isColorSupported = enabled;
1424
+ var colors = {
1425
+ reset,
1426
+ red,
1427
+ green,
1428
+ yellow,
1429
+ blue,
1430
+ magenta,
1431
+ cyan,
1432
+ white,
1433
+ gray,
1434
+ bold,
1435
+ italic,
1436
+ underline,
1437
+ dim,
1438
+ inverse,
1439
+ hidden,
1440
+ strikethrough,
1441
+ bgRed,
1442
+ bgGreen,
1443
+ bgYellow,
1444
+ bgBlue,
1445
+ bgMagenta,
1446
+ bgCyan,
1447
+ bgWhite,
1448
+ isColorSupported
1449
+ };
1450
+ var colors_default = colors;
1451
+ var actions = ["up", "down", "left", "right", "space", "enter", "cancel"];
1452
+ var settings = {
1453
+ actions: new Set(actions),
1454
+ aliases: new Map([
1455
+ ["k", "up"],
1456
+ ["j", "down"],
1457
+ ["h", "left"],
1458
+ ["l", "right"],
1459
+ ["\x03", "cancel"],
1460
+ ["escape", "cancel"]
1461
+ ]),
1462
+ messages: {
1463
+ cancel: "Canceled",
1464
+ error: "Something went wrong"
1465
+ }
1466
+ };
1467
+ function isActionKey(key, action) {
1468
+ if (typeof key === "string") {
1469
+ return settings.aliases.get(key) === action;
1470
+ }
1471
+ for (const value of key) {
1472
+ if (value === undefined)
1473
+ continue;
1474
+ if (isActionKey(value, action)) {
1475
+ return true;
1476
+ }
1477
+ }
1478
+ return false;
1479
+ }
1480
+ function diffLines(a, b) {
1481
+ if (a === b)
1482
+ return [];
1483
+ const aLines = a.split(`
1484
+ `);
1485
+ const bLines = b.split(`
1486
+ `);
1487
+ const diff = [];
1488
+ for (let i = 0;i < Math.max(aLines.length, bLines.length); i++) {
1489
+ if (aLines[i] !== bLines[i])
1490
+ diff.push(i);
1491
+ }
1492
+ return diff;
1493
+ }
1494
+ var isWindows = process8.platform.startsWith("win");
1495
+ var CANCEL_SYMBOL = Symbol("clapp:cancel");
1496
+ function setRawMode(input, value) {
1497
+ const i = input;
1498
+ if (i.isTTY)
1499
+ i.setRawMode(value);
1500
+ }
1501
+ function stripAnsi(str) {
1502
+ return str.replace(/\x1b\[[0-9;]*m/g, "");
1503
+ }
1504
+ function stringWidth(str) {
1505
+ return stripAnsi(str).length;
1506
+ }
1507
+ function wrapAnsi(text, columns, options) {
1508
+ if (!columns || columns < 1)
1509
+ return text;
1510
+ const hard = options?.hard ?? false;
1511
+ const trim = options?.trim ?? true;
1512
+ const lines = text.split(`
1513
+ `);
1514
+ const result = [];
1515
+ for (const line of lines) {
1516
+ if (stringWidth(line) <= columns) {
1517
+ result.push(trim ? line.trimEnd() : line);
1518
+ continue;
1519
+ }
1520
+ if (hard) {
1521
+ let current = "";
1522
+ let currentWidth = 0;
1523
+ let i = 0;
1524
+ while (i < line.length) {
1525
+ const ansiMatch = line.slice(i).match(/^\x1b\[[0-9;]*m/);
1526
+ if (ansiMatch) {
1527
+ current += ansiMatch[0];
1528
+ i += ansiMatch[0].length;
1529
+ continue;
1530
+ }
1531
+ if (currentWidth >= columns) {
1532
+ result.push(trim ? current.trimEnd() : current);
1533
+ current = "";
1534
+ currentWidth = 0;
1535
+ }
1536
+ current += line[i];
1537
+ currentWidth++;
1538
+ i++;
1539
+ }
1540
+ if (current) {
1541
+ result.push(trim ? current.trimEnd() : current);
1542
+ }
1543
+ } else {
1544
+ result.push(trim ? line.trimEnd() : line);
1545
+ }
1546
+ }
1547
+ return result.join(`
1548
+ `);
1549
+ }
1550
+
1551
+ class Prompt {
1552
+ input;
1553
+ output;
1554
+ _abortSignal;
1555
+ rl;
1556
+ opts;
1557
+ _render;
1558
+ _track = false;
1559
+ _prevFrame = "";
1560
+ _subscribers = new Map;
1561
+ _cursor = 0;
1562
+ _manualLine = "";
1563
+ state = "initial";
1564
+ error = "";
1565
+ value;
1566
+ userInput = "";
1567
+ constructor(options, trackValue = true) {
1568
+ const { input = stdin2, output = stdout2, render, signal, ...opts } = options;
1569
+ this.opts = opts;
1570
+ this.onKeypress = this.onKeypress.bind(this);
1571
+ this.close = this.close.bind(this);
1572
+ this.render = this.render.bind(this);
1573
+ this._render = render.bind(this);
1574
+ this._track = trackValue;
1575
+ this._abortSignal = signal;
1576
+ this.input = input;
1577
+ this.output = output;
1578
+ }
1579
+ unsubscribe() {
1580
+ this._subscribers.clear();
1581
+ }
1582
+ setSubscriber(event, opts) {
1583
+ const params = this._subscribers.get(event) ?? [];
1584
+ params.push(opts);
1585
+ this._subscribers.set(event, params);
1586
+ }
1587
+ on(event, cb) {
1588
+ this.setSubscriber(event, { cb });
1589
+ return this;
1590
+ }
1591
+ once(event, cb) {
1592
+ this.setSubscriber(event, { cb, once: true });
1593
+ return this;
1594
+ }
1595
+ emit(event, ...data) {
1596
+ const cbs = this._subscribers.get(event) ?? [];
1597
+ const cleanup = [];
1598
+ for (const subscriber of cbs) {
1599
+ subscriber.cb(...data);
1600
+ if (subscriber.once) {
1601
+ cleanup.push(() => cbs.splice(cbs.indexOf(subscriber), 1));
1602
+ }
1603
+ }
1604
+ for (const cb of cleanup) {
1605
+ cb();
1606
+ }
1607
+ return this;
1608
+ }
1609
+ prompt() {
1610
+ return new Promise((resolve) => {
1611
+ if (this._abortSignal) {
1612
+ if (this._abortSignal.aborted) {
1613
+ this.state = "cancel";
1614
+ this.close();
1615
+ return resolve(CANCEL_SYMBOL);
1616
+ }
1617
+ this._abortSignal.addEventListener("abort", () => {
1618
+ this.state = "cancel";
1619
+ this.close();
1620
+ }, { once: true });
1621
+ }
1622
+ this.rl = readline2.createInterface({
1623
+ input: this.input,
1624
+ tabSize: 2,
1625
+ prompt: "",
1626
+ escapeCodeTimeout: 50,
1627
+ terminal: true
1628
+ });
1629
+ this.rl.prompt();
1630
+ if (this.opts.initialUserInput !== undefined) {
1631
+ this._setUserInput(this.opts.initialUserInput, true);
1632
+ }
1633
+ this.input.on("keypress", this.onKeypress);
1634
+ setRawMode(this.input, true);
1635
+ this.output.on("resize", this.render);
1636
+ this.render();
1637
+ this.once("submit", () => {
1638
+ this.output.write(cursor.show);
1639
+ this.output.off("resize", this.render);
1640
+ setRawMode(this.input, false);
1641
+ resolve(this.value);
1642
+ });
1643
+ this.once("cancel", () => {
1644
+ this.output.write(cursor.show);
1645
+ this.output.off("resize", this.render);
1646
+ setRawMode(this.input, false);
1647
+ resolve(CANCEL_SYMBOL);
1648
+ });
1649
+ });
1650
+ }
1651
+ _isActionKey(char, _key) {
1652
+ return char === "\t";
1653
+ }
1654
+ _setValue(value) {
1655
+ this.value = value;
1656
+ this.emit("value", this.value);
1657
+ }
1658
+ _setUserInput(value, write) {
1659
+ this.userInput = value ?? "";
1660
+ this.emit("userInput", this.userInput);
1661
+ if (write && this._track && this.rl) {
1662
+ this.rl.write(this.userInput);
1663
+ this._cursor = this.rl.cursor;
1664
+ }
1665
+ }
1666
+ onKeypress(char, key) {
1667
+ if (this._track && key.name !== "return") {
1668
+ if (key.name && this._isActionKey(char, key)) {
1669
+ this.rl?.write(null, { ctrl: true, name: "h" });
1670
+ }
1671
+ this._cursor = this.rl?.cursor ?? 0;
1672
+ const isSpecialKey = key.name === "tab" || key.name === "escape" || key.name === "backspace" || key.name === "delete" || key.name === "enter" || key.name === "return" || key.name && ["up", "down", "left", "right"].includes(key.name);
1673
+ if (char && !isSpecialKey && char.length === 1 && char >= " ") {
1674
+ this._manualLine += char;
1675
+ } else if (key.name === "backspace" && this._manualLine.length > 0) {
1676
+ this._manualLine = this._manualLine.slice(0, -1);
1677
+ }
1678
+ const effectiveLine = this._manualLine.length >= (this.rl?.line?.length || 0) ? this._manualLine : this.rl?.line;
1679
+ this._setUserInput(effectiveLine);
1680
+ }
1681
+ if (this.state === "error") {
1682
+ this.state = "active";
1683
+ this.error = "";
1684
+ }
1685
+ if (key?.name) {
1686
+ if (!this._track && settings.aliases.has(key.name)) {
1687
+ this.emit("cursor", settings.aliases.get(key.name));
1688
+ }
1689
+ if (settings.actions.has(key.name)) {
1690
+ this.emit("cursor", key.name);
1691
+ }
1692
+ }
1693
+ if (char && (char.toLowerCase() === "y" || char.toLowerCase() === "n")) {
1694
+ this.emit("confirm", char.toLowerCase() === "y");
1695
+ }
1696
+ this.emit("key", char?.toLowerCase(), key);
1697
+ if (key?.name === "return") {
1698
+ if (this.opts.validate) {
1699
+ const problem = this.opts.validate(this.value);
1700
+ if (problem) {
1701
+ this.error = problem instanceof Error ? problem.message : problem;
1702
+ this.state = "error";
1703
+ }
1704
+ }
1705
+ if (this.state !== "error") {
1706
+ this.state = "submit";
1707
+ }
1708
+ }
1709
+ if (isActionKey([char, key?.name, key?.sequence], "cancel")) {
1710
+ this.state = "cancel";
1711
+ }
1712
+ if (this.state === "submit" || this.state === "cancel") {
1713
+ this.emit("finalize");
1714
+ }
1715
+ this.render();
1716
+ if (this.state === "submit" || this.state === "cancel") {
1717
+ this.close();
1718
+ }
1719
+ }
1720
+ close() {
1721
+ this.input.unpipe();
1722
+ this.input.removeListener("keypress", this.onKeypress);
1723
+ this.output.write(`
1724
+ `);
1725
+ setRawMode(this.input, false);
1726
+ this.rl?.close();
1727
+ this.rl = undefined;
1728
+ this.emit(`${this.state}`, this.value);
1729
+ if (this.state === "cancel") {
1730
+ setTimeout(() => {
1731
+ this.unsubscribe();
1732
+ }, 10);
1733
+ } else {
1734
+ this.unsubscribe();
1735
+ }
1736
+ }
1737
+ restoreCursor() {
1738
+ const lines = wrapAnsi(this._prevFrame, process9.stdout.columns, { hard: true, trim: false }).split(`
1739
+ `).length - 1;
1740
+ this.output.write(cursor.move(-999, lines * -1));
1741
+ }
1742
+ render() {
1743
+ const frame = wrapAnsi(this._render(this) ?? "", process9.stdout.columns, {
1744
+ hard: true,
1745
+ trim: false
1746
+ });
1747
+ if (frame === this._prevFrame) {
1748
+ return;
1749
+ }
1750
+ if (this.state === "initial") {
1751
+ this.output.write(cursor.hide);
1752
+ } else {
1753
+ const diff = diffLines(this._prevFrame, frame);
1754
+ this.restoreCursor();
1755
+ if (diff && diff?.length === 1) {
1756
+ const diffLine = diff[0];
1757
+ this.output.write(cursor.move(0, diffLine));
1758
+ this.output.write(erase.lines(1));
1759
+ const lines = frame.split(`
1760
+ `);
1761
+ this.output.write(lines[diffLine]);
1762
+ this._prevFrame = frame;
1763
+ this.output.write(cursor.move(0, lines.length - diffLine - 1));
1764
+ return;
1765
+ }
1766
+ if (diff && diff?.length > 1) {
1767
+ const diffLine = diff[0];
1768
+ this.output.write(cursor.move(0, diffLine));
1769
+ this.output.write(erase.down());
1770
+ const lines = frame.split(`
1771
+ `);
1772
+ const newLines = lines.slice(diffLine);
1773
+ this.output.write(newLines.join(`
1774
+ `));
1775
+ this._prevFrame = frame;
1776
+ return;
1777
+ }
1778
+ this.output.write(erase.down());
1779
+ }
1780
+ this.output.write(frame);
1781
+ if (this.state === "initial") {
1782
+ this.state = "active";
1783
+ }
1784
+ this._prevFrame = frame;
1785
+ }
1786
+ }
1787
+ function getCursorForValue(selected, items) {
1788
+ if (selected === undefined) {
1789
+ return 0;
1790
+ }
1791
+ const currLength = items.length;
1792
+ if (currLength === 0) {
1793
+ return 0;
1794
+ }
1795
+ const index = items.findIndex((item) => item.value === selected);
1796
+ return index !== -1 ? index : 0;
1797
+ }
1798
+ function defaultFilter(input, option) {
1799
+ const label = option.label ?? String(option.value);
1800
+ return label.toLowerCase().includes(input.toLowerCase());
1801
+ }
1802
+ function normalisedValue(multiple, values) {
1803
+ if (!values) {
1804
+ return;
1805
+ }
1806
+ if (multiple) {
1807
+ return values;
1808
+ }
1809
+ return values[0];
1810
+ }
1811
+
1812
+ class AutocompletePrompt extends Prompt {
1813
+ filteredOptions;
1814
+ multiple;
1815
+ isNavigating = false;
1816
+ selectedValues = [];
1817
+ focusedValue;
1818
+ #cursor = 0;
1819
+ #lastUserInput = "";
1820
+ #filterFn;
1821
+ #options;
1822
+ get cursor() {
1823
+ return this.#cursor;
1824
+ }
1825
+ get userInputWithCursor() {
1826
+ if (!this.userInput) {
1827
+ return colors_default.inverse(colors_default.hidden("_"));
1828
+ }
1829
+ if (this._cursor >= this.userInput.length) {
1830
+ return `${this.userInput}\u2588`;
1831
+ }
1832
+ const s1 = this.userInput.slice(0, this._cursor);
1833
+ const [s2, ...s3] = this.userInput.slice(this._cursor);
1834
+ return `${s1}${colors_default.inverse(s2)}${s3.join("")}`;
1835
+ }
1836
+ get options() {
1837
+ if (typeof this.#options === "function") {
1838
+ return this.#options();
1839
+ }
1840
+ return this.#options;
1841
+ }
1842
+ constructor(opts) {
1843
+ super(opts);
1844
+ this.#options = opts.options;
1845
+ const options = this.options;
1846
+ this.filteredOptions = [...options];
1847
+ this.multiple = opts.multiple === true;
1848
+ this.#filterFn = opts.filter ?? defaultFilter;
1849
+ let initialValues;
1850
+ if (opts.initialValue && Array.isArray(opts.initialValue)) {
1851
+ if (this.multiple) {
1852
+ initialValues = opts.initialValue;
1853
+ } else {
1854
+ initialValues = opts.initialValue.slice(0, 1);
1855
+ }
1856
+ } else {
1857
+ if (!this.multiple && this.options.length > 0) {
1858
+ initialValues = [this.options[0].value];
1859
+ }
1860
+ }
1861
+ if (initialValues) {
1862
+ for (const selectedValue of initialValues) {
1863
+ const selectedIndex = options.findIndex((opt) => opt.value === selectedValue);
1864
+ if (selectedIndex !== -1) {
1865
+ this.toggleSelected(selectedValue);
1866
+ this.#cursor = selectedIndex;
1867
+ }
1868
+ }
1869
+ }
1870
+ this.focusedValue = this.options[this.#cursor]?.value;
1871
+ this.on("key", (char, key) => this.#onKey(char, key));
1872
+ this.on("userInput", (value) => this.#onUserInputChanged(value));
1873
+ }
1874
+ _isActionKey(char, key) {
1875
+ return char === "\t" || this.multiple && this.isNavigating && key.name === "space" && char !== undefined && char !== "";
1876
+ }
1877
+ #onKey(_char, key) {
1878
+ const isUpKey = key.name === "up";
1879
+ const isDownKey = key.name === "down";
1880
+ const isReturnKey = key.name === "return";
1881
+ if (isUpKey || isDownKey) {
1882
+ this.#cursor = Math.max(0, Math.min(this.#cursor + (isUpKey ? -1 : 1), this.filteredOptions.length - 1));
1883
+ this.focusedValue = this.filteredOptions[this.#cursor]?.value;
1884
+ if (!this.multiple) {
1885
+ this.selectedValues = [this.focusedValue];
1886
+ }
1887
+ this.isNavigating = true;
1888
+ } else if (isReturnKey) {
1889
+ this.value = normalisedValue(this.multiple, this.selectedValues);
1890
+ } else {
1891
+ if (this.multiple) {
1892
+ if (this.focusedValue !== undefined && (key.name === "tab" || this.isNavigating && key.name === "space")) {
1893
+ this.toggleSelected(this.focusedValue);
1894
+ } else {
1895
+ this.isNavigating = false;
1896
+ }
1897
+ } else {
1898
+ if (this.focusedValue) {
1899
+ this.selectedValues = [this.focusedValue];
1900
+ }
1901
+ this.isNavigating = false;
1902
+ }
1903
+ }
1904
+ }
1905
+ deselectAll() {
1906
+ this.selectedValues = [];
1907
+ }
1908
+ toggleSelected(value) {
1909
+ if (this.filteredOptions.length === 0) {
1910
+ return;
1911
+ }
1912
+ if (this.multiple) {
1913
+ if (this.selectedValues.includes(value)) {
1914
+ this.selectedValues = this.selectedValues.filter((v) => v !== value);
1915
+ } else {
1916
+ this.selectedValues = [...this.selectedValues, value];
1917
+ }
1918
+ } else {
1919
+ this.selectedValues = [value];
1920
+ }
1921
+ }
1922
+ #onUserInputChanged(value) {
1923
+ if (value !== this.#lastUserInput) {
1924
+ this.#lastUserInput = value;
1925
+ const options = this.options;
1926
+ if (value) {
1927
+ this.filteredOptions = options.filter((opt) => this.#filterFn(value, opt));
1928
+ } else {
1929
+ this.filteredOptions = [...options];
1930
+ }
1931
+ this.#cursor = getCursorForValue(this.focusedValue, this.filteredOptions);
1932
+ this.focusedValue = this.filteredOptions[this.#cursor]?.value;
1933
+ if (!this.multiple) {
1934
+ if (this.focusedValue !== undefined) {
1935
+ this.toggleSelected(this.focusedValue);
1936
+ } else {
1937
+ this.deselectAll();
1938
+ }
1939
+ }
1940
+ }
1941
+ }
1942
+ }
1943
+ class GroupMultiSelectPrompt extends Prompt {
1944
+ options;
1945
+ cursor = 0;
1946
+ #selectableGroups;
1947
+ getGroupItems(group) {
1948
+ return this.options.filter((o) => o.group === group);
1949
+ }
1950
+ isGroupSelected(group) {
1951
+ const items = this.getGroupItems(group);
1952
+ const value = this.value;
1953
+ if (value === undefined) {
1954
+ return false;
1955
+ }
1956
+ return items.every((i) => value.includes(i.value));
1957
+ }
1958
+ toggleValue() {
1959
+ const item = this.options[this.cursor];
1960
+ if (this.value === undefined) {
1961
+ this.value = [];
1962
+ }
1963
+ if (item.group === true) {
1964
+ const group = item.value;
1965
+ const groupedItems = this.getGroupItems(group);
1966
+ if (this.isGroupSelected(group)) {
1967
+ this.value = this.value.filter((v) => groupedItems.findIndex((i) => i.value === v) === -1);
1968
+ } else {
1969
+ this.value = [...this.value, ...groupedItems.map((i) => i.value)];
1970
+ }
1971
+ this.value = Array.from(new Set(this.value));
1972
+ } else {
1973
+ const selected = this.value.includes(item.value);
1974
+ this.value = selected ? this.value.filter((v) => v !== item.value) : [...this.value, item.value];
1975
+ }
1976
+ }
1977
+ constructor(opts) {
1978
+ super(opts, false);
1979
+ const { options } = opts;
1980
+ this.#selectableGroups = opts.selectableGroups !== false;
1981
+ this.options = Object.entries(options).flatMap(([key, option]) => [
1982
+ { value: key, group: true, label: key },
1983
+ ...option.map((opt) => ({ ...opt, group: key }))
1984
+ ]);
1985
+ this.value = [...opts.initialValues ?? []];
1986
+ this.cursor = Math.max(this.options.findIndex(({ value }) => value === opts.cursorAt), this.#selectableGroups ? 0 : 1);
1987
+ this.on("cursor", (key) => {
1988
+ switch (key) {
1989
+ case "left":
1990
+ case "up": {
1991
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
1992
+ const currentIsGroup = this.options[this.cursor]?.group === true;
1993
+ if (!this.#selectableGroups && currentIsGroup) {
1994
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
1995
+ }
1996
+ break;
1997
+ }
1998
+ case "down":
1999
+ case "right": {
2000
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
2001
+ const currentIsGroup = this.options[this.cursor]?.group === true;
2002
+ if (!this.#selectableGroups && currentIsGroup) {
2003
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
2004
+ }
2005
+ break;
2006
+ }
2007
+ case "space":
2008
+ this.toggleValue();
2009
+ break;
2010
+ }
2011
+ });
2012
+ }
2013
+ }
2014
+ var unicode = isUnicodeSupported();
2015
+ var unicodeOr = (c, fallback) => unicode ? c : fallback;
2016
+ var S_STEP_ACTIVE = unicodeOr("\u25C6", "*");
2017
+ var S_STEP_CANCEL = unicodeOr("\u25A0", "x");
2018
+ var S_STEP_ERROR = unicodeOr("\u25B2", "x");
2019
+ var S_STEP_SUBMIT = unicodeOr("\u25C7", "o");
2020
+ var S_BAR_START = unicodeOr("\u250C", "T");
2021
+ var S_BAR = unicodeOr("\u2502", "|");
2022
+ var S_BAR_END = unicodeOr("\u2514", "\u2014");
2023
+ var S_RADIO_ACTIVE = unicodeOr("\u25CF", ">");
2024
+ var S_RADIO_INACTIVE = unicodeOr("\u25CB", " ");
2025
+ var S_CHECKBOX_ACTIVE = unicodeOr("\u25FB", "[\u2022]");
2026
+ var S_CHECKBOX_SELECTED = unicodeOr("\u25FC", "[+]");
2027
+ var S_CHECKBOX_INACTIVE = unicodeOr("\u25FB", "[ ]");
2028
+ var S_PASSWORD_MASK = unicodeOr("\u25AA", "\u2022");
2029
+ var S_BAR_H = unicodeOr("\u2500", "-");
2030
+ var S_CORNER_TOP_RIGHT = unicodeOr("\u256E", "+");
2031
+ var S_CONNECT_LEFT = unicodeOr("\u251C", "+");
2032
+ var S_CORNER_BOTTOM_RIGHT = unicodeOr("\u256F", "+");
2033
+ var S_INFO = unicodeOr("\u25CF", "\u2022");
2034
+ var S_SUCCESS = unicodeOr("\u25C6", "*");
2035
+ var S_WARN = unicodeOr("\u25B2", "!");
2036
+ var S_ERROR = unicodeOr("\u25A0", "x");
2037
+ var S_PROGRESS_CHAR = {
2038
+ light: unicodeOr("\u2500", "-"),
2039
+ heavy: unicodeOr("\u2501", "="),
2040
+ block: unicodeOr("\u2588", "#")
2041
+ };
2042
+ function getPrefix() {
2043
+ return `${colors_default.gray(S_BAR)} `;
2044
+ }
2045
+ var prefix = getPrefix();
2046
+ // package.json
2047
+ var version = "0.0.15";
2048
+
2049
+ // src/cli/middleware.ts
2050
+ import fs2 from "fs/promises";
2051
+ import path2 from "path";
2052
+ import process6 from "process";
2053
+
2054
+ // src/cli/colors.ts
2055
+ var colors2 = {
2056
+ reset: "\x1B[0m",
2057
+ bold: "\x1B[1m",
2058
+ dim: "\x1B[2m",
2059
+ red: "\x1B[31m",
2060
+ green: "\x1B[32m",
2061
+ yellow: "\x1B[33m",
2062
+ blue: "\x1B[34m",
2063
+ cyan: "\x1B[36m",
2064
+ white: "\x1B[37m",
2065
+ gray: "\x1B[90m"
2066
+ };
2067
+ var chalk = {
2068
+ red: (text) => `${colors2.red}${text}${colors2.reset}`,
2069
+ green: (text) => `${colors2.green}${text}${colors2.reset}`,
2070
+ yellow: (text) => `${colors2.yellow}${text}${colors2.reset}`,
2071
+ blue: (text) => `${colors2.blue}${text}${colors2.reset}`,
2072
+ cyan: (text) => `${colors2.cyan}${text}${colors2.reset}`,
2073
+ white: (text) => `${colors2.white}${text}${colors2.reset}`,
2074
+ gray: (text) => `${colors2.gray}${text}${colors2.reset}`,
2075
+ bold: (text) => `${colors2.bold}${text}${colors2.reset}`,
2076
+ dim: (text) => `${colors2.dim}${text}${colors2.reset}`,
2077
+ hex: (_color) => (text) => text
2078
+ };
2079
+
2080
+ // src/cli/middleware.ts
2081
+ async function generateMiddlewareTypes(outputPath) {
2082
+ const middlewareInfo = Object.entries(middleware).map(([key, instance]) => ({
2083
+ name: key,
2084
+ className: instance.constructor.name
2085
+ }));
2086
+ const typeContent = `/**
2087
+ * This file is auto-generated.
2088
+ * DO NOT EDIT THIS FILE DIRECTLY.
2089
+ * To update, run 'bun router middleware:types'
2090
+ */
2091
+ import type { ${middlewareInfo.map((m) => m.className).join(", ")} } from './middleware'
2092
+
2093
+ /**
2094
+ * Available middleware map with middleware names as keys
2095
+ */
2096
+ export interface MiddlewareMap {
2097
+ ${middlewareInfo.map((m) => ` '${m.name}': ${m.className}`).join(`
2098
+ `)}
2099
+ }
2100
+
2101
+ /**
2102
+ * String literal type of available middleware names
2103
+ */
2104
+ export type MiddlewareName = ${middlewareInfo.map((m) => `'${m.name}'`).join(" | ")}
2105
+
2106
+ /**
2107
+ * Middleware configuration type for router setup
2108
+ */
2109
+ export type MiddlewareConfig = MiddlewareName | ${middlewareInfo.map((m) => m.className).join(" | ")}
2110
+
2111
+ /**
2112
+ * Function to check if a middleware name is valid
2113
+ */
2114
+ export function isValidMiddleware(name: string): name is MiddlewareName {
2115
+ return [${middlewareInfo.map((m) => `'${m.name}'`).join(", ")}].includes(name)
2116
+ }
2117
+ `;
2118
+ await fs2.writeFile(outputPath, typeContent);
2119
+ }
2120
+ async function findTsFiles(dir) {
2121
+ const files = [];
2122
+ const entries = await fs2.readdir(dir, { withFileTypes: true });
2123
+ for (const entry of entries) {
2124
+ const fullPath = path2.join(dir, entry.name);
2125
+ if (entry.isDirectory()) {
2126
+ files.push(...await findTsFiles(fullPath));
2127
+ } else if (entry.isFile() && entry.name.endsWith(".ts")) {
2128
+ files.push(fullPath);
2129
+ }
2130
+ }
2131
+ return files;
2132
+ }
2133
+ async function scanFileForMiddleware(filePath) {
2134
+ const middlewareClasses = [];
2135
+ try {
2136
+ const content = await fs2.readFile(filePath, "utf-8");
2137
+ const classRegex = /export\s+(?:default\s+)?class\s+(\w+)\s+(?:implements\s+Middleware|\{[\s\S]*?handle\s*\([\s\S]*?\))/g;
2138
+ let match = null;
2139
+ while (match = classRegex.exec(content)) {
2140
+ const className = match[1];
2141
+ if (className.includes("Middleware") || match[0].includes("implements Middleware")) {
2142
+ const relativePath = path2.relative(process6.cwd(), filePath);
2143
+ const importPath = relativePath.replace(/\.ts$/, "");
2144
+ middlewareClasses.push({
2145
+ name: className,
2146
+ path: importPath
2147
+ });
2148
+ }
2149
+ }
2150
+ } catch (error) {
2151
+ console.warn(chalk.yellow(`Error scanning file ${filePath}: ${error}`));
2152
+ }
2153
+ return middlewareClasses;
2154
+ }
2155
+ async function generateMiddlewareMap(directoryPath, outputPath) {
2156
+ console.log(chalk.blue(`Scanning directory: ${directoryPath} for middleware classes...`));
2157
+ try {
2158
+ const tsFiles = await findTsFiles(directoryPath);
2159
+ const allMiddleware = [];
2160
+ for (const file of tsFiles) {
2161
+ const middlewareInFile = await scanFileForMiddleware(file);
2162
+ allMiddleware.push(...middlewareInFile);
2163
+ }
2164
+ if (allMiddleware.length === 0) {
2165
+ console.warn(chalk.yellow("No middleware classes found in the specified directory."));
2166
+ return;
2167
+ }
2168
+ const imports = allMiddleware.map((m) => `import { ${m.name} } from '${m.path}'`).join(`
2169
+ `);
2170
+ const interfaceMembers = allMiddleware.map((m) => ` ${m.name}: typeof ${m.name}`).join(`
2171
+ `);
2172
+ const typeNames = allMiddleware.map((m) => m.name).join(" | ");
2173
+ const typeContent = `/**
2174
+ * This file is auto-generated.
2175
+ * DO NOT EDIT THIS FILE DIRECTLY.
2176
+ * To update, run 'bun router middleware:map'
2177
+ */
2178
+
2179
+ ${imports}
2180
+
2181
+ /**
2182
+ * Map of all available middleware in the project
2183
+ */
2184
+ export interface MiddlewareMap {
2185
+ ${interfaceMembers}
2186
+ }
2187
+
2188
+ /**
2189
+ * Type representing all available middleware classes in the project
2190
+ */
2191
+ export type MiddlewareType = ${typeNames}
2192
+
2193
+ /**
2194
+ * Type for a middleware handler function
2195
+ */
2196
+ export type MiddlewareHandler = (req: any, next: () => Promise<Response>) => Promise<Response>
2197
+
2198
+ /**
2199
+ * Ensure the middleware module exports all the middleware classes used in the project
2200
+ */
2201
+ export const middlewareMap: MiddlewareMap = {
2202
+ ${allMiddleware.map((m) => ` ${m.name}: ${m.name}`).join(`,
2203
+ `)}
2204
+ }
2205
+ `;
2206
+ await fs2.writeFile(outputPath, typeContent);
2207
+ console.log(chalk.green(`\u2728 Middleware map generated at ${outputPath} with ${allMiddleware.length} middleware classes`));
2208
+ console.log(chalk.blue("Found middleware classes:"));
2209
+ for (const m of allMiddleware) {
2210
+ console.log(chalk.cyan(` - ${m.name} (${m.path})`));
2211
+ }
2212
+ } catch (error) {
2213
+ console.error(chalk.red(`Error generating middleware map: ${error}`));
2214
+ throw error;
2215
+ }
2216
+ }
2217
+ async function watchDirectoryForMiddleware(directoryPath, outputPath) {
2218
+ try {
2219
+ await fs2.access(directoryPath);
2220
+ } catch {
2221
+ console.error(chalk.red(`Directory not found at ${directoryPath}`));
2222
+ process6.exit(1);
2223
+ }
2224
+ await generateMiddlewareMap(directoryPath, outputPath);
2225
+ console.log(chalk.blue(`Watching for changes in ${directoryPath}...`));
2226
+ let timeoutId = null;
2227
+ const watcher = fs2.watch(directoryPath, { recursive: true });
2228
+ for await (const _event of watcher) {
2229
+ if (timeoutId) {
2230
+ clearTimeout(timeoutId);
2231
+ }
2232
+ timeoutId = setTimeout(async () => {
2233
+ console.log(chalk.yellow(`Changes detected. Regenerating middleware map...`));
2234
+ try {
2235
+ await generateMiddlewareMap(directoryPath, outputPath);
2236
+ } catch (error) {
2237
+ console.error(chalk.red(`Error regenerating middleware map: ${error.message}`));
2238
+ }
2239
+ timeoutId = null;
2240
+ }, 500);
2241
+ }
2242
+ }
2243
+ async function watchMiddlewareDirectory(outputPath) {
2244
+ const middlewarePath = path2.join(process6.cwd(), "src", "middleware");
2245
+ try {
2246
+ await fs2.access(middlewarePath);
2247
+ } catch {
2248
+ console.error(chalk.red(`Middleware directory not found at ${middlewarePath}`));
2249
+ process6.exit(1);
2250
+ }
2251
+ await generateMiddlewareTypes(outputPath);
2252
+ console.log(chalk.green(`\u2728 Middleware types generated at ${outputPath}`));
2253
+ console.log(chalk.blue(`Watching for changes in ${middlewarePath}...`));
2254
+ let timeoutId = null;
2255
+ const watcher = fs2.watch(middlewarePath, { recursive: true });
2256
+ for await (const _event of watcher) {
2257
+ if (timeoutId) {
2258
+ clearTimeout(timeoutId);
2259
+ }
2260
+ timeoutId = setTimeout(async () => {
2261
+ console.log(chalk.yellow(`Changes detected in middleware directory. Regenerating types...`));
2262
+ try {
2263
+ await generateMiddlewareTypes(outputPath);
2264
+ console.log(chalk.green(`\u2728 Middleware types regenerated at ${outputPath}`));
2265
+ } catch (error) {
2266
+ console.error(chalk.red(`Error regenerating types: ${error.message}`));
2267
+ }
2268
+ timeoutId = null;
2269
+ }, 500);
2270
+ }
2271
+ }
2272
+
2273
+ // src/cli/openapi.ts
2274
+ import fs3 from "fs/promises";
2275
+ import process10 from "process";
2276
+ async function generateOpenAPISpec(options) {
2277
+ try {
2278
+ const routesFile = `${process10.cwd()}/routes/index.ts`;
2279
+ const { router } = await import(routesFile);
2280
+ if (!router) {
2281
+ console.error(chalk.red(`Could not find router instance in ${routesFile}.`));
2282
+ process10.exit(1);
2283
+ }
2284
+ const routes = router.routes || [];
2285
+ if (routes.length === 0) {
2286
+ console.log(chalk.yellow("No routes defined. Creating empty OpenAPI specification."));
2287
+ }
2288
+ const apiRoutes = routes.filter((route) => {
2289
+ return route.type === "api" || route.path.startsWith("/api");
2290
+ });
2291
+ const openapi = {
2292
+ openapi: "3.0.3",
2293
+ info: {
2294
+ title: options.title || "API Documentation",
2295
+ version: options.version || "1.0.0",
2296
+ description: options.description || "Generated API documentation"
2297
+ },
2298
+ servers: generateServers(options),
2299
+ paths: {},
2300
+ components: {
2301
+ schemas: {},
2302
+ securitySchemes: {}
2303
+ },
2304
+ tags: []
2305
+ };
2306
+ const uniqueTags = new Set;
2307
+ for (const route of apiRoutes) {
2308
+ const pathItem = openapi.paths[route.path] || {};
2309
+ let tag = "";
2310
+ if (options.tags !== false) {
2311
+ tag = route.tag || extractTagFromPath(route.path);
2312
+ uniqueTags.add(tag);
2313
+ }
2314
+ const operation = {
2315
+ summary: route.summary || `${route.method.toUpperCase()} ${route.path}`,
2316
+ description: route.description || "",
2317
+ operationId: route.name || generateOperationId(route.method, route.path),
2318
+ parameters: generateParameters(route),
2319
+ responses: generateResponses(route)
2320
+ };
2321
+ if (tag) {
2322
+ operation.tags = [tag];
2323
+ }
2324
+ if (["post", "put", "patch"].includes(route.method.toLowerCase())) {
2325
+ operation.requestBody = generateRequestBody(route);
2326
+ }
2327
+ if (options.security !== false && route.middleware) {
2328
+ const securityItems = extractSecurityFromMiddleware(route.middleware);
2329
+ if (securityItems.length > 0) {
2330
+ operation.security = securityItems;
2331
+ }
2332
+ }
2333
+ pathItem[route.method.toLowerCase()] = operation;
2334
+ openapi.paths[route.path] = pathItem;
2335
+ }
2336
+ if (options.tags !== false) {
2337
+ openapi.tags = Array.from(uniqueTags).map((tag) => ({
2338
+ name: tag,
2339
+ description: `Operations related to ${tag}`
2340
+ }));
2341
+ }
2342
+ const outputPath = options.output || "openapi.json";
2343
+ await fs3.writeFile(outputPath, JSON.stringify(openapi, null, 2));
2344
+ console.log(chalk.green(`\u2728 OpenAPI specification generated at ${outputPath}`));
2345
+ console.log(chalk.blue(`Import this file into Postman, Swagger UI, or other API tools to explore your API.`));
2346
+ } catch (error) {
2347
+ if (error.code === "ERR_MODULE_NOT_FOUND") {
2348
+ console.error(chalk.red(`Routes file not found at ${process10.cwd()}/routes/index.ts`));
2349
+ console.error(chalk.yellow('Make sure your routes are defined and exported as "router" in routes/index.ts'));
2350
+ } else {
2351
+ console.error(chalk.red(`Error generating OpenAPI specification: ${error.message}`));
2352
+ }
2353
+ throw error;
2354
+ }
2355
+ }
2356
+ function generateServers(options) {
2357
+ const servers = [];
2358
+ if (options.servers) {
2359
+ const serverUrls = options.servers.split(",").map((url) => url.trim());
2360
+ for (const url of serverUrls) {
2361
+ servers.push({
2362
+ url,
2363
+ description: `Server ${servers.length + 1}`
2364
+ });
2365
+ }
2366
+ }
2367
+ if (servers.length === 0) {
2368
+ servers.push({
2369
+ url: options.basePath || "/",
2370
+ description: "Default server"
2371
+ });
2372
+ }
2373
+ return servers;
2374
+ }
2375
+ function extractTagFromPath(path3) {
2376
+ const segments = path3.split("/").filter(Boolean);
2377
+ if (segments.length > 0) {
2378
+ if (segments[0].toLowerCase() === "api" && segments.length > 1) {
2379
+ return segments[1];
2380
+ }
2381
+ return segments[0];
2382
+ }
2383
+ return "default";
2384
+ }
2385
+ function generateOperationId(method, path3) {
2386
+ const pathWithoutParams = path3.replace(/\{([^}]+)\}/g, "_$1");
2387
+ const segments = pathWithoutParams.split("/").filter(Boolean);
2388
+ if (segments.length === 0) {
2389
+ return method.toLowerCase();
2390
+ }
2391
+ let operationId = method.toLowerCase();
2392
+ for (const segment of segments) {
2393
+ operationId += segment.charAt(0).toUpperCase() + segment.slice(1);
2394
+ }
2395
+ return operationId;
2396
+ }
2397
+ function generateParameters(route) {
2398
+ const parameters = [];
2399
+ const pathParams = route.path.match(/\{([^}]+)\}/g);
2400
+ if (pathParams) {
2401
+ for (const param of pathParams) {
2402
+ const paramName = param.slice(1, -1);
2403
+ parameters.push({
2404
+ name: paramName,
2405
+ in: "path",
2406
+ required: true,
2407
+ schema: {
2408
+ type: "string"
2409
+ },
2410
+ description: `Path parameter: ${paramName}`
2411
+ });
2412
+ }
2413
+ }
2414
+ if (route.params && route.params.query) {
2415
+ for (const [name, schema] of Object.entries(route.params.query)) {
2416
+ parameters.push({
2417
+ name,
2418
+ in: "query",
2419
+ schema: mapSchemaType(schema),
2420
+ required: schema.required === true,
2421
+ description: schema.description || `Query parameter: ${name}`
2422
+ });
2423
+ }
2424
+ }
2425
+ return parameters;
2426
+ }
2427
+ function mapSchemaType(schema) {
2428
+ if (!schema || typeof schema !== "object") {
2429
+ return { type: "string" };
2430
+ }
2431
+ const openApiSchema = {};
2432
+ if (schema.type) {
2433
+ openApiSchema.type = schema.type;
2434
+ }
2435
+ if (schema.format) {
2436
+ openApiSchema.format = schema.format;
2437
+ }
2438
+ if (schema.enum) {
2439
+ openApiSchema.enum = schema.enum;
2440
+ }
2441
+ if (schema.default !== undefined) {
2442
+ openApiSchema.default = schema.default;
2443
+ }
2444
+ return openApiSchema;
2445
+ }
2446
+ function generateResponses(route) {
2447
+ const responses = {
2448
+ 200: {
2449
+ description: "Successful response",
2450
+ content: {
2451
+ "application/json": {
2452
+ schema: {}
2453
+ }
2454
+ }
2455
+ }
2456
+ };
2457
+ responses["400"] = {
2458
+ description: "Bad request",
2459
+ content: {
2460
+ "application/json": {
2461
+ schema: {
2462
+ type: "object",
2463
+ properties: {
2464
+ error: { type: "string" }
2465
+ }
2466
+ }
2467
+ }
2468
+ }
2469
+ };
2470
+ responses["401"] = {
2471
+ description: "Unauthorized",
2472
+ content: {
2473
+ "application/json": {
2474
+ schema: {
2475
+ type: "object",
2476
+ properties: {
2477
+ error: { type: "string" }
2478
+ }
2479
+ }
2480
+ }
2481
+ }
2482
+ };
2483
+ responses["404"] = {
2484
+ description: "Not found",
2485
+ content: {
2486
+ "application/json": {
2487
+ schema: {
2488
+ type: "object",
2489
+ properties: {
2490
+ error: { type: "string" }
2491
+ }
2492
+ }
2493
+ }
2494
+ }
2495
+ };
2496
+ responses["500"] = {
2497
+ description: "Server error",
2498
+ content: {
2499
+ "application/json": {
2500
+ schema: {
2501
+ type: "object",
2502
+ properties: {
2503
+ error: { type: "string" }
2504
+ }
2505
+ }
2506
+ }
2507
+ }
2508
+ };
2509
+ if (route.responses) {
2510
+ for (const [status, response] of Object.entries(route.responses)) {
2511
+ responses[status] = {
2512
+ description: response.description || `Response with status ${status}`,
2513
+ content: {
2514
+ "application/json": {
2515
+ schema: response.schema || {}
2516
+ }
2517
+ }
2518
+ };
2519
+ }
2520
+ }
2521
+ return responses;
2522
+ }
2523
+ function generateRequestBody(route) {
2524
+ const requestBody = {
2525
+ required: true,
2526
+ content: {
2527
+ "application/json": {
2528
+ schema: {
2529
+ type: "object"
2530
+ }
2531
+ }
2532
+ }
2533
+ };
2534
+ if (route.params && route.params.body) {
2535
+ requestBody.content["application/json"].schema = route.params.body;
2536
+ }
2537
+ return requestBody;
2538
+ }
2539
+ function extractSecurityFromMiddleware(middleware2) {
2540
+ const securityItems = [];
2541
+ for (const mw of middleware2) {
2542
+ const name = typeof mw === "string" ? mw : mw.name;
2543
+ if (name && name.toLowerCase().includes("auth")) {
2544
+ if (name.toLowerCase().includes("jwt")) {
2545
+ securityItems.push({ BearerAuth: [] });
2546
+ } else if (name.toLowerCase().includes("apikey")) {
2547
+ securityItems.push({ ApiKeyAuth: [] });
2548
+ } else if (name.toLowerCase().includes("basic")) {
2549
+ securityItems.push({ BasicAuth: [] });
2550
+ } else {
2551
+ securityItems.push({ [name]: [] });
2552
+ }
2553
+ }
2554
+ }
2555
+ return securityItems;
2556
+ }
2557
+
2558
+ // src/cli/router.ts
2559
+ import fs4 from "fs/promises";
2560
+ import path3 from "path";
2561
+ import process12 from "process";
2562
+ async function generateRouterTypes(outputPath) {
2563
+ try {
2564
+ const routesFile = `${process12.cwd()}/routes/index.ts`;
2565
+ const { router } = await import(routesFile);
2566
+ if (!router) {
2567
+ console.error(chalk.red(`Could not find router instance in ${routesFile}.`));
2568
+ process12.exit(1);
2569
+ }
2570
+ const routerMethods = Object.getOwnPropertyNames(Object.getPrototypeOf(router)).filter((method) => !method.startsWith("_") && method !== "constructor" && typeof router[method] === "function");
2571
+ const extendedProperties = Object.keys(router).filter((prop) => !["routes", "middleware", "hooks", "config"].includes(prop) && typeof prop === "string" && !prop.startsWith("_"));
2572
+ const typeContent = `/**
2573
+ * This file is auto-generated.
2574
+ * DO NOT EDIT THIS FILE DIRECTLY.
2575
+ * To update, run 'bun router router:types'
2576
+ */
2577
+ import type { Router, RouteHandler, MiddlewareHandler, RouteDefinition } from '../src/types'
2578
+
2579
+ /**
2580
+ * Extended Router interface with all available methods and properties
2581
+ */
2582
+ export interface ExtendedRouter extends Router {
2583
+ ${routerMethods.map((method) => {
2584
+ if (["get", "post", "put", "delete", "patch", "options", "head"].includes(method)) {
2585
+ return `${method}(path: string, handler: RouteHandler, options?: any): Router`;
2586
+ } else if (method === "use") {
2587
+ return `${method}(middleware: MiddlewareHandler | MiddlewareHandler[]): Router`;
2588
+ } else if (method === "group") {
2589
+ return `${method}(prefix: string, callback: (router: Router) => void): Router`;
2590
+ } else {
2591
+ return `${method}: Function`;
2592
+ }
2593
+ }).join(`
2594
+ `)}
2595
+
2596
+ ${extendedProperties.map((prop) => {
2597
+ const propType = typeof router[prop];
2598
+ return `${prop}: ${propType}`;
2599
+ }).join(`
2600
+ `)}
2601
+ }
2602
+
2603
+ /**
2604
+ * Type for extending the router with custom methods
2605
+ */
2606
+ export type RouterExtension = {
2607
+ [key: string]: Function | any
2608
+ }
2609
+
2610
+ /**
2611
+ * Helper type for correctly typing router extensions
2612
+ *
2613
+ * Example usage:
2614
+ * \`\`\`typescript
2615
+ * import { Router, ExtendRouter } from './router-types'
2616
+ *
2617
+ * // Define extension type
2618
+ * interface MyCustomRouter extends ExtendRouter<{
2619
+ * customMethod(param: string): void
2620
+ * }> {}
2621
+ *
2622
+ * // Create and extend the router
2623
+ * const router = new Router() as MyCustomRouter
2624
+ * router.customMethod = (param: string) => {
2625
+ * console.log(param)
2626
+ * }
2627
+ * \`\`\`
2628
+ */
2629
+ export type ExtendRouter<T extends RouterExtension> = Router & T
2630
+ `;
2631
+ await fs4.writeFile(outputPath, typeContent);
2632
+ console.log(chalk.green(`\u2728 Router types generated at ${outputPath}`));
2633
+ } catch (error) {
2634
+ if (error.code === "ERR_MODULE_NOT_FOUND") {
2635
+ console.error(chalk.red(`Routes file not found at ${process12.cwd()}/routes/index.ts`));
2636
+ console.error(chalk.yellow('Make sure your routes are defined and exported as "router" in routes/index.ts'));
2637
+ } else {
2638
+ console.error(chalk.red(`Error generating router types: ${error.message}`));
2639
+ }
2640
+ throw error;
2641
+ }
2642
+ }
2643
+ async function watchRouterFiles(outputPath) {
2644
+ const routerFiles = [
2645
+ path3.join(process12.cwd(), "routes"),
2646
+ path3.join(process12.cwd(), "src")
2647
+ ];
2648
+ let validPath = false;
2649
+ for (const dirPath of routerFiles) {
2650
+ try {
2651
+ await fs4.access(dirPath);
2652
+ validPath = true;
2653
+ break;
2654
+ } catch {}
2655
+ }
2656
+ if (!validPath) {
2657
+ console.error(chalk.red(`No valid source directories found to watch.`));
2658
+ process12.exit(1);
2659
+ }
2660
+ await generateRouterTypes(outputPath);
2661
+ console.log(chalk.green(`\u2728 Router types generated at ${outputPath}`));
2662
+ console.log(chalk.blue(`Watching for changes in router files...`));
2663
+ let timeoutId = null;
2664
+ for (const dirPath of routerFiles) {
2665
+ try {
2666
+ const watcher = fs4.watch(dirPath, { recursive: true });
2667
+ (async () => {
2668
+ for await (const _event of watcher) {
2669
+ if (timeoutId) {
2670
+ clearTimeout(timeoutId);
2671
+ }
2672
+ timeoutId = setTimeout(async () => {
2673
+ console.log(chalk.yellow(`Changes detected in router files. Regenerating types...`));
2674
+ try {
2675
+ await generateRouterTypes(outputPath);
2676
+ console.log(chalk.green(`\u2728 Router types regenerated at ${outputPath}`));
2677
+ } catch (error) {
2678
+ console.error(chalk.red(`Error regenerating types: ${error.message}`));
2679
+ }
2680
+ timeoutId = null;
2681
+ }, 500);
2682
+ }
2683
+ })();
2684
+ } catch {}
2685
+ }
2686
+ }
2687
+
2688
+ // src/cli/routes.ts
2689
+ import fs5 from "fs/promises";
2690
+ import path4 from "path";
2691
+ import process13 from "process";
2692
+ async function displayRoutes(options) {
2693
+ try {
2694
+ const routesFile = `${process13.cwd()}/routes/index.ts`;
2695
+ const { router } = await import(routesFile);
2696
+ if (!router) {
2697
+ console.error(chalk.red(`Could not find router instance in ${routesFile}.`));
2698
+ process13.exit(1);
2699
+ }
2700
+ const routes = router.routes || [];
2701
+ if (routes.length === 0) {
2702
+ console.log(chalk.yellow("No routes defined."));
2703
+ return;
2704
+ }
2705
+ let filteredRoutes = routes;
2706
+ if (options.path) {
2707
+ filteredRoutes = filteredRoutes.filter((route) => route.path.startsWith(options.path));
2708
+ }
2709
+ console.log(chalk.bold(`
2710
+ Routes:`));
2711
+ console.log(chalk.dim("+-----------------+-------------------------+------------------+----------------+"));
2712
+ console.log(chalk.dim("| ") + chalk.bold("Method") + chalk.dim(" | ") + chalk.bold("URI") + chalk.dim(" | ") + chalk.bold("Name") + chalk.dim(" | ") + chalk.bold("Handler") + chalk.dim(" |"));
2713
+ console.log(chalk.dim("+-----------------+-------------------------+------------------+----------------+"));
2714
+ filteredRoutes.forEach((route) => {
2715
+ const method = padString(route.method, 15);
2716
+ const path5 = padString(route.path, 23);
2717
+ const name = padString(route.name || "", 16);
2718
+ let handler;
2719
+ if (typeof route.handler === "string") {
2720
+ handler = route.handler;
2721
+ } else if (typeof route.handler === "function") {
2722
+ handler = route.handler.name ? `${route.handler.name}()` : "Anonymous Function";
2723
+ } else {
2724
+ handler = "Class Handler";
2725
+ }
2726
+ handler = padString(handler, 14);
2727
+ console.log(chalk.dim("| ") + getMethodColor(route.method)(method) + chalk.dim(" | ") + chalk.green(path5) + chalk.dim(" | ") + chalk.yellow(name) + chalk.dim(" | ") + chalk.blue(handler) + chalk.dim(" |"));
2728
+ if (options.verbose && route.middleware && route.middleware.length > 0) {
2729
+ console.log(chalk.dim("| | ") + chalk.dim("Middleware: ") + route.middleware.map((m) => typeof m === "string" ? m : m.name || "Anonymous").join(", ") + chalk.dim(" |"));
2730
+ }
2731
+ });
2732
+ console.log(chalk.dim("+-----------------+-------------------------+------------------+----------------+"));
2733
+ console.log(`
2734
+ Showing ${filteredRoutes.length} routes`);
2735
+ } catch (error) {
2736
+ console.error(chalk.red(`Error: ${error.message}`));
2737
+ console.error(chalk.yellow(`Make sure your routes are defined in ${process13.cwd()}/routes/index.ts and export a 'router' instance.`));
2738
+ throw error;
2739
+ }
2740
+ }
2741
+ async function generateRouteTypes(outputPath) {
2742
+ try {
2743
+ const routesFile = `${process13.cwd()}/routes/index.ts`;
2744
+ const { router } = await import(routesFile);
2745
+ if (!router) {
2746
+ console.error(chalk.red(`Could not find router instance in ${routesFile}.`));
2747
+ process13.exit(1);
2748
+ }
2749
+ const routes = router.routes || [];
2750
+ if (routes.length === 0) {
2751
+ console.log(chalk.yellow("No routes defined. Creating empty types file."));
2752
+ }
2753
+ const routeNames = routes.map((route) => {
2754
+ if (route.name)
2755
+ return route.name;
2756
+ const methodLower = route.method.toLowerCase();
2757
+ const pathFormatted = route.path.replace(/^\//, "").replace(/\//g, ".").replace(/\{([^}]+)\}/g, ":$1");
2758
+ return pathFormatted ? `${methodLower}.${pathFormatted}` : methodLower;
2759
+ });
2760
+ const uniqueRouteNames = [...new Set(routeNames)];
2761
+ const typeContent = `/**
2762
+ * This file is auto-generated.
2763
+ * DO NOT EDIT THIS FILE DIRECTLY.
2764
+ * To update, run 'bun router route:types'
2765
+ */
2766
+
2767
+ /**
2768
+ * String literal type for all available route names
2769
+ */
2770
+ export type RouteName = ${uniqueRouteNames.length > 0 ? uniqueRouteNames.map((name) => `'${name}'`).join(" | ") : "string"}
2771
+
2772
+ /**
2773
+ * Object type with route names as keys and string (for path generation) as values
2774
+ */
2775
+ export interface RouteNameMap {
2776
+ ${uniqueRouteNames.map((name) => ` '${name}': string`).join(`
2777
+ `)}
2778
+ }
2779
+
2780
+ /**
2781
+ * Type-safe function to generate a URL for a named route
2782
+ */
2783
+ export type RouteFunction = <T extends RouteName>(name: T, params?: Record<string, string>) => string
2784
+
2785
+ /**
2786
+ * Validate that a string is a valid route name
2787
+ */
2788
+ export function isValidRouteName(name: string): name is RouteName {
2789
+ return [${uniqueRouteNames.map((name) => `'${name}'`).join(", ")}].includes(name)
2790
+ }
2791
+ `;
2792
+ await fs5.writeFile(outputPath, typeContent);
2793
+ console.log(chalk.green(`\u2728 Route types generated at ${outputPath}`));
2794
+ } catch (error) {
2795
+ if (error.code === "ERR_MODULE_NOT_FOUND") {
2796
+ console.error(chalk.red(`Routes file not found at ${process13.cwd()}/routes/index.ts`));
2797
+ console.error(chalk.yellow('Make sure your routes are defined and exported as "router" in routes/index.ts'));
2798
+ } else {
2799
+ console.error(chalk.red(`Error generating route types: ${error.message}`));
2800
+ }
2801
+ throw error;
2802
+ }
2803
+ }
2804
+ async function watchRoutesDirectory(outputPath) {
2805
+ const routesPath = path4.join(process13.cwd(), "routes");
2806
+ try {
2807
+ await fs5.access(routesPath);
2808
+ } catch {
2809
+ console.error(chalk.red(`Routes directory not found at ${routesPath}`));
2810
+ process13.exit(1);
2811
+ }
2812
+ await generateRouteTypes(outputPath);
2813
+ console.log(chalk.green(`\u2728 Route types generated at ${outputPath}`));
2814
+ console.log(chalk.blue(`Watching for changes in ${routesPath}...`));
2815
+ let timeoutId = null;
2816
+ const watcher = fs5.watch(routesPath, { recursive: true });
2817
+ for await (const _event of watcher) {
2818
+ if (timeoutId) {
2819
+ clearTimeout(timeoutId);
2820
+ }
2821
+ timeoutId = setTimeout(async () => {
2822
+ console.log(chalk.yellow(`Changes detected in routes directory. Regenerating types...`));
2823
+ try {
2824
+ await generateRouteTypes(outputPath);
2825
+ console.log(chalk.green(`\u2728 Route types regenerated at ${outputPath}`));
2826
+ } catch (error) {
2827
+ console.error(chalk.red(`Error regenerating types: ${error.message}`));
2828
+ }
2829
+ timeoutId = null;
2830
+ }, 500);
2831
+ }
2832
+ }
2833
+ function padString(str, length) {
2834
+ return (str + " ".repeat(length)).substring(0, length);
2835
+ }
2836
+ function getMethodColor(method) {
2837
+ switch (method.toUpperCase()) {
2838
+ case "GET":
2839
+ return chalk.cyan;
2840
+ case "POST":
2841
+ return chalk.green;
2842
+ case "PUT":
2843
+ return chalk.yellow;
2844
+ case "PATCH":
2845
+ return chalk.yellow;
2846
+ case "DELETE":
2847
+ return chalk.red;
2848
+ case "OPTIONS":
2849
+ return chalk.gray;
2850
+ default:
2851
+ return chalk.white;
2852
+ }
2853
+ }
2854
+
2855
+ // src/cli/utils.ts
2856
+ import process14 from "process";
2857
+ var format = {
2858
+ success: (message) => chalk.green(`\u2728 ${message}`),
2859
+ info: (message) => chalk.blue(message),
2860
+ warning: (message) => chalk.yellow(message),
2861
+ error: (message) => chalk.red(message),
2862
+ dim: (message) => chalk.dim(message),
2863
+ bold: (message) => chalk.bold(message)
2864
+ };
2865
+ var logger = {
2866
+ success: (message) => console.log(format.success(message)),
2867
+ info: (message) => console.log(format.info(message)),
2868
+ warning: (message) => console.log(format.warning(message)),
2869
+ error: (message) => console.error(format.error(message)),
2870
+ debug: (message) => console.debug(format.dim(message))
2871
+ };
2872
+ async function loadRouter() {
2873
+ try {
2874
+ const routesFile = `${process14.cwd()}/routes/index.ts`;
2875
+ const { router } = await import(routesFile);
2876
+ if (!router) {
2877
+ logger.error(`Could not find router instance in ${routesFile}.`);
2878
+ process14.exit(1);
2879
+ }
2880
+ return router;
2881
+ } catch (error) {
2882
+ if (error.code === "ERR_MODULE_NOT_FOUND") {
2883
+ logger.error(`Routes file not found at ${process14.cwd()}/routes/index.ts`);
2884
+ logger.warning('Make sure your routes are defined and exported as "router" in routes/index.ts');
2885
+ } else {
2886
+ logger.error(`Error loading router: ${error.message}`);
2887
+ }
2888
+ throw error;
2889
+ }
2890
+ }
2891
+ function getMethodColor2(method) {
2892
+ switch (method.toUpperCase()) {
2893
+ case "GET":
2894
+ return chalk.cyan.toString();
2895
+ case "POST":
2896
+ return chalk.green.toString();
2897
+ case "PUT":
2898
+ return chalk.yellow.toString();
2899
+ case "PATCH":
2900
+ return chalk.yellow.toString();
2901
+ case "DELETE":
2902
+ return chalk.red.toString();
2903
+ case "OPTIONS":
2904
+ return chalk.gray.toString();
2905
+ default:
2906
+ return chalk.white.toString();
2907
+ }
2908
+ }
2909
+ async function checkRouterHealth(options) {
2910
+ logger.info("\uD83D\uDD0D Checking router health...");
2911
+ try {
2912
+ const router = await loadRouter();
2913
+ const routes = router.routes || [];
2914
+ const globalMiddleware = router.globalMiddleware || [];
2915
+ const namedRoutes = router.namedRoutes || new Map;
2916
+ const health = {
2917
+ totalRoutes: routes.length,
2918
+ namedRoutes: namedRoutes.size,
2919
+ globalMiddleware: globalMiddleware.length,
2920
+ routesByMethod: {},
2921
+ duplicateRoutes: [],
2922
+ routesWithMiddleware: 0,
2923
+ staticRoutes: 0,
2924
+ dynamicRoutes: 0
2925
+ };
2926
+ const routeMap = new Map;
2927
+ for (const route of routes) {
2928
+ const key = `${route.method}:${route.path}`;
2929
+ health.routesByMethod[route.method] = (health.routesByMethod[route.method] || 0) + 1;
2930
+ if (!routeMap.has(key)) {
2931
+ routeMap.set(key, []);
2932
+ }
2933
+ routeMap.get(key).push(route.path);
2934
+ if (routeMap.get(key).length > 1) {
2935
+ health.duplicateRoutes.push({ path: route.path, method: route.method });
2936
+ }
2937
+ if (route.middleware && route.middleware.length > 0) {
2938
+ health.routesWithMiddleware++;
2939
+ }
2940
+ if (route.path.includes("{") || route.path.includes("*")) {
2941
+ health.dynamicRoutes++;
2942
+ } else {
2943
+ health.staticRoutes++;
2944
+ }
2945
+ }
2946
+ logger.success(`Router health check completed`);
2947
+ console.log(`\uD83D\uDCCA Routes: ${health.totalRoutes} total (${health.staticRoutes} static, ${health.dynamicRoutes} dynamic)`);
2948
+ console.log(`\uD83D\uDCDB Named routes: ${health.namedRoutes}`);
2949
+ console.log(`\uD83D\uDEE1\uFE0F Global middleware: ${health.globalMiddleware}`);
2950
+ console.log(`\uD83D\uDD27 Routes with middleware: ${health.routesWithMiddleware}`);
2951
+ if (options.verbose) {
2952
+ console.log(`
2953
+ \uD83D\uDCC8 Routes by method:`);
2954
+ for (const [method, count] of Object.entries(health.routesByMethod)) {
2955
+ const color = getMethodColor2(method);
2956
+ console.log(` ${chalk.hex(color)(method.padEnd(8))}: ${count}`);
2957
+ }
2958
+ if (health.duplicateRoutes.length > 0) {
2959
+ logger.warning(`
2960
+ \u26A0\uFE0F Found ${health.duplicateRoutes.length} duplicate route(s):`);
2961
+ for (const duplicate of health.duplicateRoutes) {
2962
+ console.log(` ${duplicate.method} ${duplicate.path}`);
2963
+ }
2964
+ }
2965
+ const issues = [];
2966
+ if (health.totalRoutes === 0) {
2967
+ issues.push("No routes defined");
2968
+ }
2969
+ if (health.duplicateRoutes.length > 0) {
2970
+ issues.push(`${health.duplicateRoutes.length} duplicate routes`);
2971
+ }
2972
+ if (health.routesWithMiddleware === 0 && health.globalMiddleware === 0) {
2973
+ issues.push("No middleware configured");
2974
+ }
2975
+ if (issues.length > 0) {
2976
+ logger.warning(`
2977
+ \u26A0\uFE0F Potential issues:`);
2978
+ for (const issue of issues) {
2979
+ console.log(` \u2022 ${issue}`);
2980
+ }
2981
+ } else {
2982
+ logger.success(`
2983
+ \u2705 No issues detected`);
2984
+ }
2985
+ }
2986
+ } catch (error) {
2987
+ logger.error(`Health check failed: ${error.message}`);
2988
+ throw error;
2989
+ }
2990
+ }
2991
+ async function testRoutes(options) {
2992
+ const baseUrl = options.baseUrl || "http://localhost:3000";
2993
+ const timeout = options.timeout || 5000;
2994
+ const allowedMethods = options.method ? options.method.split(",").map((m) => m.trim().toUpperCase()) : null;
2995
+ logger.info(`\uD83E\uDDEA Testing routes at ${baseUrl}...`);
2996
+ try {
2997
+ const router = await loadRouter();
2998
+ const routes = router.routes || [];
2999
+ let filteredRoutes = routes;
3000
+ if (options.filter) {
3001
+ const pattern = new RegExp(options.filter.replace(/\*/g, ".*"));
3002
+ filteredRoutes = routes.filter((route) => pattern.test(route.path));
3003
+ }
3004
+ if (allowedMethods) {
3005
+ filteredRoutes = filteredRoutes.filter((route) => allowedMethods.includes(route.method));
3006
+ }
3007
+ if (filteredRoutes.length === 0) {
3008
+ logger.warning("No routes match the specified filters");
3009
+ return;
3010
+ }
3011
+ logger.info(`Testing ${filteredRoutes.length} routes...`);
3012
+ const results = {
3013
+ total: 0,
3014
+ passed: 0,
3015
+ failed: 0,
3016
+ errors: []
3017
+ };
3018
+ for (const route of filteredRoutes) {
3019
+ results.total++;
3020
+ if (route.path.includes("{")) {
3021
+ logger.debug(`Skipping parameterized route: ${route.method} ${route.path}`);
3022
+ continue;
3023
+ }
3024
+ try {
3025
+ const url = `${baseUrl}${route.path}`;
3026
+ const response = await fetch(url, {
3027
+ method: route.method,
3028
+ signal: AbortSignal.timeout(timeout)
3029
+ });
3030
+ if (response.status < 500) {
3031
+ results.passed++;
3032
+ logger.debug(`\u2705 ${route.method} ${route.path} \u2192 ${response.status}`);
3033
+ } else {
3034
+ results.failed++;
3035
+ results.errors.push({
3036
+ route: `${route.method} ${route.path}`,
3037
+ error: `HTTP ${response.status}`
3038
+ });
3039
+ }
3040
+ } catch (error) {
3041
+ results.failed++;
3042
+ results.errors.push({
3043
+ route: `${route.method} ${route.path}`,
3044
+ error: error.message
3045
+ });
3046
+ }
3047
+ }
3048
+ console.log(`
3049
+ \uD83D\uDCCA Test Results:`);
3050
+ console.log(` Total: ${results.total}`);
3051
+ console.log(` Passed: ${chalk.green(String(results.passed))}`);
3052
+ console.log(` Failed: ${chalk.red(String(results.failed))}`);
3053
+ if (results.errors.length > 0) {
3054
+ console.log(`
3055
+ \u274C Failures:`);
3056
+ for (const error of results.errors) {
3057
+ console.log(` ${error.route}: ${error.error}`);
3058
+ }
3059
+ }
3060
+ if (results.failed > 0) {
3061
+ process14.exit(1);
3062
+ } else {
3063
+ logger.success("All tests passed!");
3064
+ }
3065
+ } catch (error) {
3066
+ logger.error(`Route testing failed: ${error.message}`);
3067
+ throw error;
3068
+ }
3069
+ }
3070
+ async function debugRoute(path5, options) {
3071
+ const method = options.method?.toUpperCase() || "GET";
3072
+ logger.info(`\uD83D\uDD0D Debugging route matching for: ${method} ${path5}`);
3073
+ try {
3074
+ const router = await loadRouter();
3075
+ const match = router.matchRoute ? router.matchRoute(path5, method) : null;
3076
+ if (match) {
3077
+ logger.success(`\u2705 Route matched!`);
3078
+ console.log(` Route: ${match.route.method} ${match.route.path}`);
3079
+ console.log(` Handler: ${typeof match.route.handler}`);
3080
+ if (Object.keys(match.params || {}).length > 0) {
3081
+ console.log(` Parameters:`);
3082
+ for (const [key, value] of Object.entries(match.params)) {
3083
+ console.log(` ${key}: ${value}`);
3084
+ }
3085
+ }
3086
+ if (match.route.middleware && match.route.middleware.length > 0) {
3087
+ console.log(` Middleware: ${match.route.middleware.length} handler(s)`);
3088
+ }
3089
+ if (match.route.name) {
3090
+ console.log(` Named route: ${match.route.name}`);
3091
+ }
3092
+ } else {
3093
+ logger.error(`\u274C No route matched for ${method} ${path5}`);
3094
+ if (options.verbose) {
3095
+ console.log(`
3096
+ \uD83D\uDCCB Available routes:`);
3097
+ const routes = router.routes || [];
3098
+ const methodRoutes = routes.filter((r) => r.method === method);
3099
+ if (methodRoutes.length === 0) {
3100
+ console.log(` No routes defined for ${method} method`);
3101
+ } else {
3102
+ for (const route of methodRoutes) {
3103
+ console.log(` ${route.method} ${route.path}`);
3104
+ }
3105
+ }
3106
+ }
3107
+ }
3108
+ } catch (error) {
3109
+ logger.error(`Route debugging failed: ${error.message}`);
3110
+ throw error;
3111
+ }
3112
+ }
3113
+ async function clearCaches(options) {
3114
+ logger.info("\uD83D\uDDD1\uFE0F Clearing route caches...");
3115
+ try {
3116
+ const router = await loadRouter();
3117
+ if (options.stats) {
3118
+ if (router.getCacheStats) {
3119
+ const stats = router.getCacheStats();
3120
+ console.log("\uD83D\uDCCA Cache statistics before clearing:");
3121
+ console.log(` Hit rate: ${stats.hitRate}%`);
3122
+ console.log(` Total hits: ${stats.hits}`);
3123
+ console.log(` Total misses: ${stats.misses}`);
3124
+ console.log(` Cache size: ${stats.size}`);
3125
+ }
3126
+ if (router.routeCache) {
3127
+ console.log(` Route cache entries: ${router.routeCache.size}`);
3128
+ }
3129
+ if (router.templateCache) {
3130
+ console.log(` Template cache entries: ${router.templateCache.size}`);
3131
+ }
3132
+ }
3133
+ if (router.clearRouteCache) {
3134
+ router.clearRouteCache();
3135
+ }
3136
+ if (router.routeCache && router.routeCache.clear) {
3137
+ router.routeCache.clear();
3138
+ }
3139
+ if (router.templateCache && router.templateCache.clear) {
3140
+ router.templateCache.clear();
3141
+ }
3142
+ if (router.clearModelCache) {
3143
+ router.clearModelCache();
3144
+ }
3145
+ logger.success("\u2705 Caches cleared successfully");
3146
+ } catch (error) {
3147
+ logger.error(`Cache clearing failed: ${error.message}`);
3148
+ throw error;
3149
+ }
3150
+ }
3151
+ async function validateRoutes(options) {
3152
+ logger.info("\uD83D\uDD0D Validating route definitions...");
3153
+ try {
3154
+ const router = await loadRouter();
3155
+ const routes = router.routes || [];
3156
+ const issues = [];
3157
+ const warnings = [];
3158
+ for (const route of routes) {
3159
+ if (!route.method) {
3160
+ issues.push(`Route missing method: ${route.path}`);
3161
+ }
3162
+ if (!route.path) {
3163
+ issues.push(`Route missing path: ${route.method || "UNKNOWN"}`);
3164
+ }
3165
+ if (!route.handler) {
3166
+ issues.push(`Route missing handler: ${route.method} ${route.path}`);
3167
+ }
3168
+ if (route.path && !route.path.startsWith("/")) {
3169
+ issues.push(`Route path should start with '/': ${route.method} ${route.path}`);
3170
+ }
3171
+ if (route.path && route.path.includes("{")) {
3172
+ const params = route.path.match(/\{[^}]+\}/g) || [];
3173
+ for (const param of params) {
3174
+ if (!param.match(/^\{[a-z_]\w*(\?|:[^}]+)?\}$/i)) {
3175
+ issues.push(`Invalid parameter syntax in ${route.method} ${route.path}: ${param}`);
3176
+ }
3177
+ }
3178
+ }
3179
+ if (options.strict) {
3180
+ if (!route.name && !route.path.includes("{") && route.path !== "/") {
3181
+ warnings.push(`Consider adding a name to route: ${route.method} ${route.path}`);
3182
+ }
3183
+ if (route.path.includes("/admin") && (!route.middleware || route.middleware.length === 0)) {
3184
+ warnings.push(`Admin route missing middleware: ${route.method} ${route.path}`);
3185
+ }
3186
+ }
3187
+ }
3188
+ const routeMap = new Map;
3189
+ for (const route of routes) {
3190
+ const key = `${route.method}:${route.path}`;
3191
+ routeMap.set(key, (routeMap.get(key) || 0) + 1);
3192
+ }
3193
+ for (const [key, count] of routeMap.entries()) {
3194
+ if (count > 1) {
3195
+ issues.push(`Duplicate route detected: ${key} (${count} times)`);
3196
+ }
3197
+ }
3198
+ if (issues.length === 0 && warnings.length === 0) {
3199
+ logger.success("\u2705 All route definitions are valid");
3200
+ return;
3201
+ }
3202
+ if (issues.length > 0) {
3203
+ logger.error(`\u274C Found ${issues.length} validation error(s):`);
3204
+ for (const issue of issues) {
3205
+ console.log(` \u2022 ${issue}`);
3206
+ }
3207
+ }
3208
+ if (warnings.length > 0) {
3209
+ logger.warning(`\u26A0\uFE0F Found ${warnings.length} warning(s):`);
3210
+ for (const warning of warnings) {
3211
+ console.log(` \u2022 ${warning}`);
3212
+ }
3213
+ }
3214
+ if (options.fix) {
3215
+ logger.info("\uD83D\uDD27 Auto-fixing is not yet implemented");
3216
+ }
3217
+ if (issues.length > 0) {
3218
+ process14.exit(1);
3219
+ }
3220
+ } catch (error) {
3221
+ logger.error(`Route validation failed: ${error.message}`);
3222
+ throw error;
3223
+ }
3224
+ }
3225
+
3226
+ // src/cli/index.ts
3227
+ function createCLI() {
3228
+ const cli = new CLI("router");
3229
+ cli.version(version);
3230
+ registerRouteCommands(cli);
3231
+ registerMiddlewareCommands(cli);
3232
+ registerRouterCommands(cli);
3233
+ registerOpenAPICommands(cli);
3234
+ registerUtilityCommands(cli);
3235
+ cli.help();
3236
+ return cli;
3237
+ }
3238
+ function registerRouteCommands(cli) {
3239
+ cli.command("route:list", "List all registered routes").option("-v, --verbose", "Show detailed information including middleware").option("-vv, --extra-verbose", "Show very detailed information").option("--path <path>", "Filter routes by path prefix").option("--except-vendor", "Exclude vendor routes").option("--only-vendor", "Show only vendor routes").example("router route:list").example("router route:list -v").example("router route:list --path=/api").action(async (options) => {
3240
+ try {
3241
+ await displayRoutes(options);
3242
+ } catch (error) {
3243
+ console.error(`Failed to list routes: ${error.message}`);
3244
+ process15.exit(1);
3245
+ }
3246
+ });
3247
+ cli.command("route:types", "Generate TypeScript types for route names").option("--output <file>", "Output file path", { default: "route-types.ts" }).option("--watch", "Watch for changes in routes directory").example("router route:types").example("router route:types --output src/types/routes.ts").example("router route:types --watch").action(async (options) => {
3248
+ try {
3249
+ const outputPath = options.output || "route-types.ts";
3250
+ if (options.watch) {
3251
+ await watchRoutesDirectory(outputPath);
3252
+ } else {
3253
+ await generateRouteTypes(outputPath);
3254
+ }
3255
+ } catch (error) {
3256
+ console.error(`Failed to generate route types: ${error.message}`);
3257
+ process15.exit(1);
3258
+ }
3259
+ });
3260
+ }
3261
+ function registerMiddlewareCommands(cli) {
3262
+ cli.command("middleware:types", "Generate TypeScript types for middleware configurations").option("--output <file>", "Output file path", { default: "middleware-types.ts" }).option("--watch", "Watch for changes in middleware directory").example("router middleware:types").example("router middleware:types --output src/types/middleware.ts").example("router middleware:types --watch").action(async (options) => {
3263
+ try {
3264
+ const outputPath = options.output || "middleware-types.ts";
3265
+ if (options.watch) {
3266
+ await watchMiddlewareDirectory(outputPath);
3267
+ } else {
3268
+ await generateMiddlewareTypes(outputPath);
3269
+ }
3270
+ } catch (error) {
3271
+ console.error(`Failed to generate middleware types: ${error.message}`);
3272
+ process15.exit(1);
3273
+ }
3274
+ });
3275
+ cli.command("middleware:map", "Generate TypeScript types for all middleware in the project").option("--dir <directory>", "Directory to scan for middleware classes", { default: "src" }).option("--output <file>", "Output file path", { default: "middleware-map.ts" }).option("--watch", "Watch for changes in the specified directory").example("router middleware:map").example("router middleware:map --dir app").example("router middleware:map --output src/types/project-middleware.ts").example("router middleware:map --watch").action(async (options) => {
3276
+ try {
3277
+ const outputPath = options.output || "middleware-map.ts";
3278
+ const directoryPath = options.dir || "src";
3279
+ if (options.watch) {
3280
+ await watchDirectoryForMiddleware(directoryPath, outputPath);
3281
+ } else {
3282
+ await generateMiddlewareMap(directoryPath, outputPath);
3283
+ }
3284
+ } catch (error) {
3285
+ console.error(`Failed to generate middleware map: ${error.message}`);
3286
+ process15.exit(1);
3287
+ }
3288
+ });
3289
+ }
3290
+ function registerRouterCommands(cli) {
3291
+ cli.command("router:types", "Generate TypeScript types for router extensions").option("--output <file>", "Output file path", { default: "router-types.ts" }).option("--watch", "Watch for changes in router files").example("router router:types").example("router router:types --output src/types/router.ts").example("router router:types --watch").action(async (options) => {
3292
+ try {
3293
+ const outputPath = options.output || "router-types.ts";
3294
+ if (options.watch) {
3295
+ await watchRouterFiles(outputPath);
3296
+ } else {
3297
+ await generateRouterTypes(outputPath);
3298
+ }
3299
+ } catch (error) {
3300
+ console.error(`Failed to generate router types: ${error.message}`);
3301
+ process15.exit(1);
3302
+ }
3303
+ });
3304
+ }
3305
+ function registerOpenAPICommands(cli) {
3306
+ cli.command("openapi", "Generate OpenAPI specification for API routes").option("--output <file>", "Output file path", { default: "openapi.json" }).option("--title <title>", "API title", { default: "API Documentation" }).option("--version <version>", "API version", { default: "1.0.0" }).option("--description <description>", "API description").option("--base-path <path>", "Base API path", { default: "/" }).option("--servers <urls>", "Comma-separated list of server URLs").option("--tags", "Group endpoints by tags", { default: true }).option("--security", "Include security schemes if available", { default: true }).example("router openapi").example("router openapi --output api-spec.json").example('router openapi --title "My API" --version 2.0').example("router openapi --servers http://localhost:3000,https://api.example.com").action(async (options) => {
3307
+ try {
3308
+ await generateOpenAPISpec(options);
3309
+ } catch (error) {
3310
+ console.error(`Failed to generate OpenAPI specification: ${error.message}`);
3311
+ process15.exit(1);
3312
+ }
3313
+ });
3314
+ }
3315
+ function registerUtilityCommands(cli) {
3316
+ cli.command("health", "Check router health and configuration").option("--verbose", "Show detailed health information").example("router health").example("router health --verbose").action(async (options) => {
3317
+ try {
3318
+ await checkRouterHealth(options);
3319
+ } catch (error) {
3320
+ console.error(`Health check failed: ${error.message}`);
3321
+ process15.exit(1);
3322
+ }
3323
+ });
3324
+ cli.command("test:routes", "Test routes by making HTTP requests").option("--base-url <url>", "Base URL for testing", { default: "http://localhost:3000" }).option("--filter <pattern>", "Filter routes by path pattern").option("--method <methods>", "Test only specific HTTP methods (comma-separated)").option("--timeout <ms>", "Request timeout in milliseconds", { default: 5000 }).example("router test:routes").example("router test:routes --base-url http://localhost:8080").example('router test:routes --filter "/api/*"').example("router test:routes --method GET,POST").action(async (options) => {
3325
+ try {
3326
+ await testRoutes(options);
3327
+ } catch (error) {
3328
+ console.error(`Route testing failed: ${error.message}`);
3329
+ process15.exit(1);
3330
+ }
3331
+ });
3332
+ cli.command("debug:route <path>", "Debug route matching for a specific path").option("--method <method>", "HTTP method to test", { default: "GET" }).option("--verbose", "Show detailed matching information").example("router debug:route /api/users/123").example("router debug:route /api/users/123 --method POST --verbose").action(async (path5, options) => {
3333
+ try {
3334
+ await debugRoute(path5, options);
3335
+ } catch (error) {
3336
+ console.error(`Route debugging failed: ${error.message}`);
3337
+ process15.exit(1);
3338
+ }
3339
+ });
3340
+ cli.command("cache:clear", "Clear route caches").option("--stats", "Show cache statistics before clearing").example("router cache:clear").example("router cache:clear --stats").action(async (options) => {
3341
+ try {
3342
+ await clearCaches(options);
3343
+ } catch (error) {
3344
+ console.error(`Cache clearing failed: ${error.message}`);
3345
+ process15.exit(1);
3346
+ }
3347
+ });
3348
+ cli.command("validate", "Validate route definitions and configuration").option("--strict", "Use strict validation rules").option("--fix", "Automatically fix simple issues").example("router validate").example("router validate --strict --fix").action(async (options) => {
3349
+ try {
3350
+ await validateRoutes(options);
3351
+ } catch (error) {
3352
+ console.error(`Route validation failed: ${error.message}`);
3353
+ process15.exit(1);
3354
+ }
3355
+ });
3356
+ }
3357
+
3358
+ // src/cli.ts
3359
+ var cli = createCLI();
3360
+ cli.parse();