@velajs/cli 0.3.2 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ksh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -19,6 +19,7 @@ pnpm add -D @velajs/cli
19
19
  | `vela module graph` | Module graph: imports tree with `global`/`lazy` flags and provider counts (`--json` for the raw graph). |
20
20
  | `vela entrypoint list` | Declared entrypoint kinds (websocket, queue, cron, …) and their entries — lazy modules stay unmaterialized. |
21
21
  | `vela openapi dump` | Emit the OpenAPI document (needs `rootModule` in the config; `--out`, `--title`, `--api-version`, `--global-prefix`). |
22
+ | `vela client generate` | Generate an `AppType` for `hc` from the app or `--input openapi.json`; `--out`, `--strict`, and CI `--check`. |
22
23
  | `vela mcp serve` | Run a Model Context Protocol stdio server exposing the introspection above as read-only tools (`route_list`, `module_graph`, `entrypoint_list`, `openapi_dump`, `token_describe`) plus a `vela://openapi` resource — for AI agents. |
23
24
 
24
25
  All introspection commands take `--config <path>`; the four listing/dump commands also take `--json`.
@@ -55,7 +56,7 @@ import { defineVelaConfig } from '@velajs/cli/config';
55
56
  import { AppModule } from './src/app.module';
56
57
 
57
58
  export default defineVelaConfig({
58
- rootModule: AppModule, // optional — needed by `vela openapi dump`
59
+ rootModule: AppModule, // needed by `vela openapi dump` and `vela client generate`
59
60
  async createApp() {
60
61
  const { createCloudflareApp } = await import('@velajs/cloudflare');
61
62
  return createCloudflareApp(AppModule);
@@ -76,3 +77,27 @@ vela db seed --continue-on-error
76
77
  ```
77
78
 
78
79
  Exit code is `0` when all seeders run and `1` if any fail.
80
+
81
+ ## Typed HTTP clients
82
+
83
+ ```sh
84
+ vela client generate --out src/api.generated.ts --strict
85
+ vela client generate --out src/api.generated.ts --strict --check
86
+ # Without bootstrapping an app:
87
+ vela client generate --input openapi.json --out src/api.generated.ts
88
+ ```
89
+
90
+ The generated file contains only types and imports `HttpApp` from `@velajs/client/http`. On the frontend:
91
+
92
+ ```ts
93
+ import { hc } from '@velajs/client/http';
94
+ import type { AppType } from './api.generated';
95
+
96
+ const client = hc<AppType>('https://api.example.com');
97
+ const response = await client.users[':id'].$get({ param: { id: 'u1' } });
98
+ const user = await response.json();
99
+ ```
100
+
101
+ Generate with the current Vela exporter to include global prefixes, route versions, `@HttpCode`, and query DTO fields. Use the server origin for `hc`; prefixes are already in the generated paths. `@Endpoint(defineEndpoint({ input, output, status }))` shares schemas with runtime validation. Named `defineDto` descriptors passed to `ValidationPipe` and `@ApiResponse` also supply documentation types; erased TypeScript interfaces and handler return types cannot be recovered from decorators. Missing schemas produce `unknown` and stderr warnings. `--strict` fails on these warnings before writing, and `--check` verifies the exact generated file without changing it.
102
+
103
+ Supported: JSON bodies, JSON/text responses with status narrowing, string path/query/header inputs, repeated query arrays, component references, object/array/enum/union/intersection/nullable schemas. Unsupported encodings, custom serialization and unresolved references fail with a diagnostic. Global middleware/error responses must be documented or added with Hono's `ApplyGlobalResponse`. Generation does not validate server responses at runtime. Raw Hono mounts and live-query resolver contracts are not inferred.
@@ -0,0 +1,391 @@
1
+ import { z } from "zod";
2
+ //#region src/client-contract-input.ts
3
+ const schemaType = z.enum([
4
+ "null",
5
+ "boolean",
6
+ "object",
7
+ "array",
8
+ "number",
9
+ "integer",
10
+ "string"
11
+ ]);
12
+ const scalar = z.union([
13
+ z.string(),
14
+ z.number().finite(),
15
+ z.boolean(),
16
+ z.null()
17
+ ]);
18
+ const schema = z.lazy(() => z.union([z.boolean(), z.object({
19
+ type: z.union([schemaType, z.array(schemaType).nonempty()]).optional(),
20
+ format: z.string().optional(),
21
+ enum: z.array(scalar).optional(),
22
+ const: scalar.optional(),
23
+ nullable: z.boolean().optional(),
24
+ readOnly: z.boolean().optional(),
25
+ writeOnly: z.boolean().optional(),
26
+ items: schema.optional(),
27
+ properties: z.record(z.string(), schema).optional(),
28
+ required: z.array(z.string()).optional(),
29
+ additionalProperties: schema.optional(),
30
+ oneOf: z.array(schema).optional(),
31
+ anyOf: z.array(schema).optional(),
32
+ allOf: z.array(schema).optional(),
33
+ $ref: z.string().min(1).optional()
34
+ }).passthrough()]));
35
+ const parameter = z.object({
36
+ name: z.string().min(1),
37
+ in: z.enum([
38
+ "path",
39
+ "query",
40
+ "header",
41
+ "cookie"
42
+ ]),
43
+ required: z.boolean().optional(),
44
+ schema: schema.optional(),
45
+ style: z.string().optional(),
46
+ explode: z.boolean().optional(),
47
+ $ref: z.string().optional(),
48
+ content: z.unknown().optional()
49
+ }).passthrough();
50
+ const media = z.object({ schema: schema.optional() }).passthrough();
51
+ const content = z.record(z.string(), media);
52
+ const requestBody = z.object({
53
+ required: z.boolean().optional(),
54
+ content: content.optional(),
55
+ $ref: z.string().optional()
56
+ }).passthrough();
57
+ const response = z.object({
58
+ content: content.optional(),
59
+ $ref: z.string().optional()
60
+ }).passthrough();
61
+ const operation = z.object({
62
+ parameters: z.array(parameter).optional(),
63
+ requestBody: requestBody.optional(),
64
+ responses: z.record(z.string(), response),
65
+ "x-vela-client-unsupported": z.array(z.string()).optional()
66
+ }).passthrough();
67
+ const pathItem = z.object({
68
+ get: operation.optional(),
69
+ post: operation.optional(),
70
+ put: operation.optional(),
71
+ patch: operation.optional(),
72
+ delete: operation.optional(),
73
+ options: operation.optional(),
74
+ head: operation.optional(),
75
+ parameters: z.unknown().optional(),
76
+ $ref: z.string().optional()
77
+ }).passthrough();
78
+ const document = z.object({
79
+ openapi: z.string().regex(/^3\.[01]\.\d+$/, "expected OpenAPI 3.0.x or 3.1.x"),
80
+ paths: z.record(z.string(), pathItem),
81
+ components: z.object({ schemas: z.record(z.string(), schema).optional() }).passthrough().optional()
82
+ });
83
+ /** Read only structurally validated data. Unsupported constructs remain explicit. */
84
+ function parseClientContractDocument(input) {
85
+ checkTree(input, "$", /* @__PURE__ */ new Set(), 0);
86
+ const result = document.safeParse(input);
87
+ if (!result.success) {
88
+ const details = result.error.issues.map((issue) => `${issue.path.join(".") || "$"}: ${issue.message}`);
89
+ throw new Error(`Invalid OpenAPI client contract:\n${details.join("\n")}`);
90
+ }
91
+ return result.data;
92
+ }
93
+ function checkTree(value, at, ancestors, depth) {
94
+ if (value === null || typeof value !== "object") return;
95
+ if (depth > 100) throw new Error(`Invalid OpenAPI client contract: ${at} exceeds 100 nested levels.`);
96
+ if (ancestors.has(value)) throw new Error(`Invalid OpenAPI client contract: ${at} contains a cycle; use $ref.`);
97
+ ancestors.add(value);
98
+ for (const [key, child] of Object.entries(value)) checkTree(child, `${at}.${key}`, ancestors, depth + 1);
99
+ ancestors.delete(value);
100
+ }
101
+ //#endregion
102
+ //#region src/client-contract.ts
103
+ const METHODS = [
104
+ "get",
105
+ "post",
106
+ "put",
107
+ "patch",
108
+ "delete",
109
+ "options",
110
+ "head"
111
+ ];
112
+ const quote = (value) => JSON.stringify(value);
113
+ const HTTP_STATUSES = /* @__PURE__ */ new Set([
114
+ 100,
115
+ 101,
116
+ 102,
117
+ 103,
118
+ 200,
119
+ 201,
120
+ 202,
121
+ 203,
122
+ 204,
123
+ 205,
124
+ 206,
125
+ 207,
126
+ 208,
127
+ 226,
128
+ 300,
129
+ 301,
130
+ 302,
131
+ 303,
132
+ 304,
133
+ 305,
134
+ 306,
135
+ 307,
136
+ 308,
137
+ 400,
138
+ 401,
139
+ 402,
140
+ 403,
141
+ 404,
142
+ 405,
143
+ 406,
144
+ 407,
145
+ 408,
146
+ 409,
147
+ 410,
148
+ 411,
149
+ 412,
150
+ 413,
151
+ 414,
152
+ 415,
153
+ 416,
154
+ 417,
155
+ 418,
156
+ 421,
157
+ 422,
158
+ 423,
159
+ 424,
160
+ 425,
161
+ 426,
162
+ 428,
163
+ 429,
164
+ 431,
165
+ 451,
166
+ 500,
167
+ 501,
168
+ 502,
169
+ 503,
170
+ 504,
171
+ 505,
172
+ 506,
173
+ 507,
174
+ 508,
175
+ 510,
176
+ 511
177
+ ]);
178
+ /** Generate a type-only contract for Hono's hc. No application imports escape into it. */
179
+ function generateClientContract(input) {
180
+ const document = parseClientContractDocument(input);
181
+ const warnings = /* @__PURE__ */ new Set();
182
+ const components = document.components?.schemas ?? {};
183
+ let usesHttpStatus = false;
184
+ const warn = (message) => {
185
+ warnings.add(message);
186
+ };
187
+ function schemaType(schema, at) {
188
+ if (schema === false) return "never";
189
+ if (schema === true) return "unknown";
190
+ if (!schema || Object.keys(schema).length === 0) {
191
+ warn(`${at}: no schema; emitted unknown.`);
192
+ return "unknown";
193
+ }
194
+ if (schema.readOnly || schema.writeOnly) throw new Error(`${at}: readOnly/writeOnly schemas require separate request and response definitions.`);
195
+ for (const keyword of [
196
+ "$dynamicRef",
197
+ "prefixItems",
198
+ "patternProperties",
199
+ "not",
200
+ "if",
201
+ "then",
202
+ "else",
203
+ "dependentSchemas",
204
+ "unevaluatedProperties"
205
+ ]) if (schema[keyword] !== void 0) throw new Error(`${at}: unsupported schema keyword ${keyword}.`);
206
+ const parts = [];
207
+ if (schema.$ref) {
208
+ const name = schema.$ref.startsWith("#/components/schemas/") ? schema.$ref.slice(21).replace(/~1/g, "/").replace(/~0/g, "~") : void 0;
209
+ if (name === void 0 || !Object.hasOwn(components, name)) throw new Error(`${at}: unsupported or unresolved reference ${schema.$ref}. Bundle references into components.schemas first.`);
210
+ parts.push(`Schemas[${quote(name)}]`);
211
+ }
212
+ if ("const" in schema) parts.push(literal(schema.const, at));
213
+ else if (schema.enum) parts.push(schema.enum.map((v) => literal(v, at)).join(" | ") || "never");
214
+ for (const key of [
215
+ "oneOf",
216
+ "anyOf",
217
+ "allOf"
218
+ ]) {
219
+ const members = schema[key];
220
+ if (members) parts.push(members.map((s) => `(${schemaType(s, at)})`).join(key === "allOf" ? " & " : " | ") || "never");
221
+ }
222
+ if (Array.isArray(schema.type)) parts.push(schema.type.map((type) => schemaType({
223
+ ...schema,
224
+ type,
225
+ nullable: false,
226
+ $ref: void 0,
227
+ enum: void 0,
228
+ oneOf: void 0,
229
+ anyOf: void 0,
230
+ allOf: void 0
231
+ }, at)).join(" | "));
232
+ else if (schema.type === "object" || schema.type === void 0 && (schema.properties || schema.additionalProperties)) {
233
+ const required = new Set(schema.required ?? []);
234
+ const fields = Object.entries(schema.properties ?? {}).toSorted(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${quote(key)}${required.has(key) ? "" : "?"}: ${schemaType(value, `${at}.${key}`)};`);
235
+ if (schema.additionalProperties !== false) {
236
+ const additional = typeof schema.additionalProperties === "object" && fields.length === 0 ? schemaType(schema.additionalProperties, `${at}.*`) : "unknown";
237
+ if (typeof schema.additionalProperties === "object" && fields.length > 0) warn(`${at}: additionalProperties alongside named properties is widened to unknown.`);
238
+ fields.push(`[key: string]: ${additional};`);
239
+ }
240
+ parts.push(fields.length ? `{ ${fields.join(" ")} }` : "Record<string, never>");
241
+ } else if (schema.type === "array") parts.push(`Array<${schemaType(schema.items, `${at}[]`)}>`);
242
+ else if (schema.type === "string") parts.push("string");
243
+ else if (schema.type === "number" || schema.type === "integer") parts.push("number");
244
+ else if (schema.type === "boolean" || schema.type === "null") parts.push(schema.type);
245
+ else if (schema.type) throw new Error(`${at}: unsupported schema type ${schema.type}.`);
246
+ if (!parts.length) {
247
+ warn(`${at}: schema has no representable type; emitted unknown.`);
248
+ return "unknown";
249
+ }
250
+ const value = parts.map((part) => `(${part})`).join(" & ");
251
+ return schema.nullable ? `(${value}) | null` : value;
252
+ }
253
+ function wireType(value, at, seen = /* @__PURE__ */ new Set()) {
254
+ if (value === false) return "never";
255
+ const schema = value === true ? void 0 : value;
256
+ if (schema?.$ref) {
257
+ schemaType(schema, at);
258
+ if (seen.has(schema.$ref)) throw new Error(`${at}: recursive parameter schemas are unsupported.`);
259
+ const name = schema.$ref.slice(21).replace(/~1/g, "/").replace(/~0/g, "~");
260
+ return wireType(components[name], at, new Set(seen).add(schema.$ref));
261
+ }
262
+ if (schema?.type === "array") {
263
+ const item = wireType(schema.items, at, seen);
264
+ if (item.startsWith("Array<")) throw new Error(`${at}: nested query arrays are unsupported.`);
265
+ return `Array<${item}>`;
266
+ }
267
+ if (schema?.type === "object" || schema?.properties || schema?.oneOf || schema?.anyOf || schema?.allOf || Array.isArray(schema?.type)) throw new Error(`${at}: structured parameters need a custom serializer and are not supported by this generator.`);
268
+ if (schema?.enum) return schema.enum.map((v) => quote(String(v))).join(" | ") || "never";
269
+ return "string";
270
+ }
271
+ function inputType(path, operation, at) {
272
+ const parameters = [...operation.parameters ?? []];
273
+ for (const p of parameters) if (![
274
+ "path",
275
+ "query",
276
+ "header",
277
+ "cookie"
278
+ ].includes(p.in) || typeof p.name !== "string") throw new Error(`${at}: unresolved or invalid parameter.`);
279
+ for (const match of path.matchAll(/:([A-Za-z_][A-Za-z0-9_]*)/g)) {
280
+ const name = match[1];
281
+ if (!parameters.some((p) => p.in === "path" && p.name === name)) parameters.push({
282
+ name,
283
+ in: "path",
284
+ required: true
285
+ });
286
+ }
287
+ const fields = [];
288
+ for (const [location, key] of [
289
+ ["path", "param"],
290
+ ["query", "query"],
291
+ ["header", "header"]
292
+ ]) {
293
+ const group = parameters.filter((p) => p.in === location);
294
+ if (!group.length) continue;
295
+ const required = location === "path" || group.some((p) => p.required);
296
+ fields.push(`${key}${required ? "" : "?"}: { ${group.map((p) => parameterType(p, location, at)).join(" ")} };`);
297
+ }
298
+ if (parameters.some((p) => p.in === "cookie")) throw new Error(`${at}: cookie parameters are unsupported; configure browser credentials through hc options.`);
299
+ if (operation.requestBody) {
300
+ const body = operation.requestBody;
301
+ if (body.$ref) throw new Error(`${at}: resolve requestBody references before generating a client.`);
302
+ const content = body.content ?? {};
303
+ const media = Object.keys(content);
304
+ if (media.length !== 1 || media[0] !== "application/json") throw new Error(`${at}: request bodies must declare exactly application/json.`);
305
+ fields.push(`json${body.required ? "" : "?"}: ${schemaType(content["application/json"]?.schema, `${at} request body`)};`);
306
+ }
307
+ return fields.length ? `{ ${fields.join(" ")} }` : "{}";
308
+ }
309
+ function parameterType(p, location, at) {
310
+ if (p.$ref || p.style || p.explode === false || p.content !== void 0) throw new Error(`${at}: custom parameter serialization/references are unsupported (${p.name}).`);
311
+ const type = wireType(p.schema, `${at} parameter ${p.name}`);
312
+ if (location !== "query" && type.startsWith("Array<")) throw new Error(`${at}: only query parameters support arrays.`);
313
+ return `${quote(p.name)}${location === "path" || p.required ? "" : "?"}: ${type};`;
314
+ }
315
+ const paths = [];
316
+ for (const [openApiPath, item] of Object.entries(document.paths).toSorted(([a], [b]) => a.localeCompare(b))) {
317
+ if (!openApiPath.startsWith("/") || openApiPath.slice(1).split("/").some((segment) => segment !== "" && !/^(?:[A-Za-z0-9_.~-]+|\{[A-Za-z_][A-Za-z0-9_]*\})$/.test(segment)) || openApiPath.includes("//") || openApiPath !== "/" && openApiPath.endsWith("/")) throw new Error(`Unsupported client path: ${openApiPath}`);
318
+ const path = openApiPath.replace(/\{([^}]+)\}/g, ":$1");
319
+ if (path.split("/").some((segment) => [
320
+ "index",
321
+ "then",
322
+ ".",
323
+ ".."
324
+ ].includes(segment) || segment.startsWith("$"))) throw new Error(`Reserved hc path segment: ${path}`);
325
+ if ("parameters" in item || "$ref" in item) throw new Error(`${path}: resolve path-level parameters/references into operations first.`);
326
+ const methods = [];
327
+ for (const method of METHODS) {
328
+ const operation = item[method];
329
+ if (!operation) continue;
330
+ const at = `${method.toUpperCase()} ${path}`;
331
+ const unsupported = operation["x-vela-client-unsupported"];
332
+ if (unsupported?.length) throw new Error(`${at}: ${unsupported.join(" ")}`);
333
+ const input = inputType(path, operation, at);
334
+ const explicitStatuses = Object.keys(operation.responses).filter((s) => /^\d{3}$/.test(s));
335
+ const variants = [];
336
+ for (const [status, response] of Object.entries(operation.responses).toSorted(([a], [b]) => a.localeCompare(b))) {
337
+ if (response.$ref) throw new Error(`${at}: resolve response references before generating a client.`);
338
+ let statusType;
339
+ if (/^[1-5]\d\d$/.test(status) && HTTP_STATUSES.has(Number(status))) statusType = status;
340
+ else if (status === "default") statusType = `Exclude<HttpStatus, ${Object.keys(operation.responses).filter((s) => s !== "default").map((s) => /^[1-5]XX$/.test(s) ? rangeStatus(s) : s).join(" | ") || "never"}>`;
341
+ else if (/^[1-5]XX$/.test(status)) statusType = `Exclude<${rangeStatus(status)}, ${explicitStatuses.join(" | ") || "never"}>`;
342
+ else throw new Error(`${at}: unsupported response status ${status}.`);
343
+ if (statusType.includes("HttpStatus")) usesHttpStatus = true;
344
+ const content = response.content ?? {};
345
+ const media = Object.keys(content);
346
+ if (media.length > 1 || media.length === 1 && media[0] !== "application/json" && media[0] !== "text/plain") throw new Error(`${at}: responses must declare one JSON or text media type.`);
347
+ const format = media[0] === "text/plain" ? "text" : "json";
348
+ const bodyType = [
349
+ "101",
350
+ "204",
351
+ "205",
352
+ "304"
353
+ ].includes(status) || method === "head" ? "never" : schemaType(content[media[0] ?? ""]?.schema, `${at} response ${status}`);
354
+ const output = format === "text" ? `Extract<${bodyType}, string> extends never ? string : Extract<${bodyType}, string>` : bodyType;
355
+ variants.push(`{ input: ${input}; output: ${output}; outputFormat: '${format}'; status: ${statusType} }`);
356
+ }
357
+ if (!variants.length) throw new Error(`${at}: at least one response is required.`);
358
+ methods.push(` $${method}: ${variants.join(" | ")};`);
359
+ }
360
+ if (methods.length) paths.push(` ${quote(path)}: {\n${methods.join("\n")}\n };`);
361
+ }
362
+ const schemas = Object.entries(components).toSorted(([a], [b]) => a.localeCompare(b)).map(([name, schema]) => ` ${quote(name)}: ${schemaType(schema, `schema ${name}`)};`);
363
+ return {
364
+ source: [
365
+ "// Generated by vela client generate. Do not edit.",
366
+ `import type { HttpApp${usesHttpStatus ? ", HttpStatus" : ""} } from '@velajs/client/http';`,
367
+ "",
368
+ `export type Schemas = {\n${schemas.join("\n")}\n};`,
369
+ "",
370
+ `export type AppType = HttpApp<{\n${paths.join("\n")}\n}>;`,
371
+ ""
372
+ ].join("\n"),
373
+ warnings: [...warnings]
374
+ };
375
+ }
376
+ function literal(value, at) {
377
+ if (value === null || [
378
+ "string",
379
+ "boolean",
380
+ "number"
381
+ ].includes(typeof value)) return JSON.stringify(value);
382
+ throw new Error(`${at}: object/array const values are not supported.`);
383
+ }
384
+ function rangeStatus(status) {
385
+ const start = Number(status[0]) * 100;
386
+ return `Extract<HttpStatus, ${Array.from({ length: 100 }, (_, i) => start + i).join(" | ")}>`;
387
+ }
388
+ //#endregion
389
+ export { generateClientContract as t };
390
+
391
+ //# sourceMappingURL=client-contract-C7P2btFE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-contract-C7P2btFE.js","names":[],"sources":["../src/client-contract-input.ts","../src/client-contract.ts"],"sourcesContent":["import { z } from 'zod';\n\n// This is the projection consumed by code generation, not a claim that an\n// arbitrary document satisfies every OpenAPI requirement. Decode both JSON\n// input and runtime-generated metadata before accessing their nested fields.\nconst schemaType = z.enum(['null', 'boolean', 'object', 'array', 'number', 'integer', 'string']);\ntype SchemaType = z.infer<typeof schemaType>;\ntype Scalar = string | number | boolean | null;\n\nexport type ContractSchema = boolean | ContractSchemaObject;\nexport interface ContractSchemaObject {\n type?: SchemaType | SchemaType[];\n format?: string;\n enum?: Scalar[];\n const?: unknown;\n nullable?: boolean;\n readOnly?: boolean;\n writeOnly?: boolean;\n items?: ContractSchema;\n properties?: Record<string, ContractSchema>;\n required?: string[];\n additionalProperties?: ContractSchema;\n oneOf?: ContractSchema[];\n anyOf?: ContractSchema[];\n allOf?: ContractSchema[];\n $ref?: string;\n [keyword: string]: unknown;\n}\n\nconst scalar = z.union([z.string(), z.number().finite(), z.boolean(), z.null()]);\nconst schema: z.ZodType<ContractSchema> = z.lazy(() =>\n z.union([\n z.boolean(),\n z\n .object({\n type: z.union([schemaType, z.array(schemaType).nonempty()]).optional(),\n format: z.string().optional(),\n enum: z.array(scalar).optional(),\n const: scalar.optional(),\n nullable: z.boolean().optional(),\n readOnly: z.boolean().optional(),\n writeOnly: z.boolean().optional(),\n items: schema.optional(),\n properties: z.record(z.string(), schema).optional(),\n required: z.array(z.string()).optional(),\n additionalProperties: schema.optional(),\n oneOf: z.array(schema).optional(),\n anyOf: z.array(schema).optional(),\n allOf: z.array(schema).optional(),\n $ref: z.string().min(1).optional(),\n })\n .passthrough(),\n ]),\n);\n\nconst parameter = z\n .object({\n name: z.string().min(1),\n in: z.enum(['path', 'query', 'header', 'cookie']),\n required: z.boolean().optional(),\n schema: schema.optional(),\n style: z.string().optional(),\n explode: z.boolean().optional(),\n // Keep unsupported representations explicit so they cannot disappear\n // during projection and accidentally become a fabricated string input.\n $ref: z.string().optional(),\n content: z.unknown().optional(),\n })\n .passthrough();\nexport type ContractParameter = z.infer<typeof parameter>;\n\nconst media = z.object({ schema: schema.optional() }).passthrough();\nconst content = z.record(z.string(), media);\nconst requestBody = z\n .object({\n required: z.boolean().optional(),\n content: content.optional(),\n $ref: z.string().optional(),\n })\n .passthrough();\nconst response = z\n .object({\n content: content.optional(),\n $ref: z.string().optional(),\n })\n .passthrough();\nconst operation = z\n .object({\n parameters: z.array(parameter).optional(),\n requestBody: requestBody.optional(),\n responses: z.record(z.string(), response),\n 'x-vela-client-unsupported': z.array(z.string()).optional(),\n })\n .passthrough();\nexport type ContractOperation = z.infer<typeof operation>;\n\nconst pathItem = z\n .object({\n get: operation.optional(),\n post: operation.optional(),\n put: operation.optional(),\n patch: operation.optional(),\n delete: operation.optional(),\n options: operation.optional(),\n head: operation.optional(),\n parameters: z.unknown().optional(),\n $ref: z.string().optional(),\n })\n .passthrough();\n\nconst document = z.object({\n openapi: z.string().regex(/^3\\.[01]\\.\\d+$/, 'expected OpenAPI 3.0.x or 3.1.x'),\n paths: z.record(z.string(), pathItem),\n components: z\n .object({ schemas: z.record(z.string(), schema).optional() })\n .passthrough()\n .optional(),\n});\n\n/** Read only structurally validated data. Unsupported constructs remain explicit. */\nexport function parseClientContractDocument(input: unknown): z.infer<typeof document> {\n // Zod recursively walks schemas. Refuse cyclic/excessively deep object input\n // (JSON files cannot contain cycles) with a diagnostic rather than overflowing.\n checkTree(input, '$', new Set<object>(), 0);\n const result = document.safeParse(input);\n if (!result.success) {\n const details = result.error.issues.map(\n (issue) => `${issue.path.join('.') || '$'}: ${issue.message}`,\n );\n throw new Error(`Invalid OpenAPI client contract:\\n${details.join('\\n')}`);\n }\n return result.data;\n}\n\nfunction checkTree(value: unknown, at: string, ancestors: Set<object>, depth: number): void {\n if (value === null || typeof value !== 'object') return;\n if (depth > 100)\n throw new Error(`Invalid OpenAPI client contract: ${at} exceeds 100 nested levels.`);\n if (ancestors.has(value))\n throw new Error(`Invalid OpenAPI client contract: ${at} contains a cycle; use $ref.`);\n ancestors.add(value);\n for (const [key, child] of Object.entries(value))\n checkTree(child, `${at}.${key}`, ancestors, depth + 1);\n ancestors.delete(value);\n}\n","import type { HttpVerb } from '@velajs/vela';\nimport { parseClientContractDocument } from './client-contract-input.js';\nimport type {\n ContractOperation,\n ContractParameter,\n ContractSchema,\n} from './client-contract-input.js';\n\nconst METHODS: HttpVerb[] = ['get', 'post', 'put', 'patch', 'delete', 'options', 'head'];\nconst quote = (value: string): string => JSON.stringify(value);\n// Hono uses -1 for unofficial statuses. Reject those here so the generated\n// status literals always satisfy its public StatusCode contract.\nconst HTTP_STATUSES = new Set([\n 100, 101, 102, 103, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304,\n 305, 306, 307, 308, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,\n 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504,\n 505, 506, 507, 508, 510, 511,\n]);\n\nexport interface GeneratedClientContract {\n source: string;\n warnings: string[];\n}\n\n/** Generate a type-only contract for Hono's hc. No application imports escape into it. */\nexport function generateClientContract(input: unknown): GeneratedClientContract {\n const document = parseClientContractDocument(input);\n const warnings = new Set<string>();\n const components = document.components?.schemas ?? {};\n let usesHttpStatus = false;\n const warn = (message: string): void => {\n warnings.add(message);\n };\n\n function schemaType(schema: ContractSchema | undefined, at: string): string {\n if (schema === false) return 'never';\n if (schema === true) return 'unknown';\n if (!schema || Object.keys(schema).length === 0) {\n warn(`${at}: no schema; emitted unknown.`);\n return 'unknown';\n }\n if (schema.readOnly || schema.writeOnly) {\n throw new Error(\n `${at}: readOnly/writeOnly schemas require separate request and response definitions.`,\n );\n }\n for (const keyword of [\n '$dynamicRef',\n 'prefixItems',\n 'patternProperties',\n 'not',\n 'if',\n 'then',\n 'else',\n 'dependentSchemas',\n 'unevaluatedProperties',\n ] as const) {\n if (schema[keyword] !== undefined)\n throw new Error(`${at}: unsupported schema keyword ${keyword}.`);\n }\n const parts: string[] = [];\n if (schema.$ref) {\n const prefix = '#/components/schemas/';\n const name = schema.$ref.startsWith(prefix)\n ? schema.$ref.slice(prefix.length).replace(/~1/g, '/').replace(/~0/g, '~')\n : undefined;\n if (name === undefined || !Object.hasOwn(components, name)) {\n throw new Error(\n `${at}: unsupported or unresolved reference ${schema.$ref}. Bundle references into components.schemas first.`,\n );\n }\n parts.push(`Schemas[${quote(name)}]`);\n }\n if ('const' in schema) parts.push(literal(schema.const, at));\n else if (schema.enum) parts.push(schema.enum.map((v) => literal(v, at)).join(' | ') || 'never');\n for (const key of ['oneOf', 'anyOf', 'allOf'] as const) {\n const members = schema[key];\n if (members)\n parts.push(\n members.map((s) => `(${schemaType(s, at)})`).join(key === 'allOf' ? ' & ' : ' | ') ||\n 'never',\n );\n }\n if (Array.isArray(schema.type)) {\n parts.push(\n schema.type\n .map((type) =>\n schemaType(\n {\n ...schema,\n type,\n nullable: false,\n $ref: undefined,\n enum: undefined,\n oneOf: undefined,\n anyOf: undefined,\n allOf: undefined,\n },\n at,\n ),\n )\n .join(' | '),\n );\n } else if (\n schema.type === 'object' ||\n (schema.type === undefined && (schema.properties || schema.additionalProperties))\n ) {\n const required = new Set(schema.required ?? []);\n const fields = Object.entries(schema.properties ?? {})\n .toSorted(([a], [b]) => a.localeCompare(b))\n .map(\n ([key, value]) =>\n `${quote(key)}${required.has(key) ? '' : '?'}: ${schemaType(value, `${at}.${key}`)};`,\n );\n if (schema.additionalProperties !== false) {\n // Unknown is intentional when properties coexist with a dictionary:\n // a narrow index signature could make declared properties impossible.\n const additional =\n typeof schema.additionalProperties === 'object' && fields.length === 0\n ? schemaType(schema.additionalProperties, `${at}.*`)\n : 'unknown';\n if (typeof schema.additionalProperties === 'object' && fields.length > 0)\n warn(`${at}: additionalProperties alongside named properties is widened to unknown.`);\n fields.push(`[key: string]: ${additional};`);\n }\n parts.push(fields.length ? `{ ${fields.join(' ')} }` : 'Record<string, never>');\n } else if (schema.type === 'array') {\n parts.push(`Array<${schemaType(schema.items, `${at}[]`)}>`);\n } else if (schema.type === 'string') {\n parts.push('string');\n } else if (schema.type === 'number' || schema.type === 'integer') {\n parts.push('number');\n } else if (schema.type === 'boolean' || schema.type === 'null') {\n parts.push(schema.type);\n } else if (schema.type) {\n throw new Error(`${at}: unsupported schema type ${schema.type}.`);\n }\n if (!parts.length) {\n warn(`${at}: schema has no representable type; emitted unknown.`);\n return 'unknown';\n }\n const value = parts.map((part) => `(${part})`).join(' & ');\n return schema.nullable ? `(${value}) | null` : value;\n }\n\n function wireType(\n value: ContractSchema | undefined,\n at: string,\n seen = new Set<string>(),\n ): string {\n if (value === false) return 'never';\n const schema = value === true ? undefined : value;\n if (schema?.$ref) {\n schemaType(schema, at); // validate reference\n if (seen.has(schema.$ref))\n throw new Error(`${at}: recursive parameter schemas are unsupported.`);\n const name = schema.$ref\n .slice('#/components/schemas/'.length)\n .replace(/~1/g, '/')\n .replace(/~0/g, '~');\n return wireType(components[name], at, new Set(seen).add(schema.$ref));\n }\n if (schema?.type === 'array') {\n const item = wireType(schema.items, at, seen);\n if (item.startsWith('Array<')) throw new Error(`${at}: nested query arrays are unsupported.`);\n return `Array<${item}>`;\n }\n if (\n schema?.type === 'object' ||\n schema?.properties ||\n schema?.oneOf ||\n schema?.anyOf ||\n schema?.allOf ||\n Array.isArray(schema?.type)\n ) {\n throw new Error(\n `${at}: structured parameters need a custom serializer and are not supported by this generator.`,\n );\n }\n if (schema?.enum) return schema.enum.map((v) => quote(String(v))).join(' | ') || 'never';\n return 'string';\n }\n\n function inputType(path: string, operation: ContractOperation, at: string): string {\n const parameters = [...(operation.parameters ?? [])];\n for (const p of parameters) {\n if (!['path', 'query', 'header', 'cookie'].includes(p.in) || typeof p.name !== 'string')\n throw new Error(`${at}: unresolved or invalid parameter.`);\n }\n for (const match of path.matchAll(/:([A-Za-z_][A-Za-z0-9_]*)/g)) {\n const name = match[1]!;\n if (!parameters.some((p) => p.in === 'path' && p.name === name))\n parameters.push({ name, in: 'path', required: true });\n }\n const fields: string[] = [];\n for (const [location, key] of [\n ['path', 'param'],\n ['query', 'query'],\n ['header', 'header'],\n ] as const) {\n const group = parameters.filter((p) => p.in === location);\n if (!group.length) continue;\n const required = location === 'path' || group.some((p) => p.required);\n fields.push(\n `${key}${required ? '' : '?'}: { ${group.map((p) => parameterType(p, location, at)).join(' ')} };`,\n );\n }\n if (parameters.some((p) => p.in === 'cookie'))\n throw new Error(\n `${at}: cookie parameters are unsupported; configure browser credentials through hc options.`,\n );\n if (operation.requestBody) {\n const body = operation.requestBody;\n if (body.$ref)\n throw new Error(`${at}: resolve requestBody references before generating a client.`);\n const content = body.content ?? {};\n const media = Object.keys(content);\n if (media.length !== 1 || media[0] !== 'application/json')\n throw new Error(`${at}: request bodies must declare exactly application/json.`);\n fields.push(\n `json${body.required ? '' : '?'}: ${schemaType(content['application/json']?.schema, `${at} request body`)};`,\n );\n }\n return fields.length ? `{ ${fields.join(' ')} }` : '{}';\n }\n\n function parameterType(p: ContractParameter, location: string, at: string): string {\n if (p.$ref || p.style || p.explode === false || p.content !== undefined)\n throw new Error(\n `${at}: custom parameter serialization/references are unsupported (${p.name}).`,\n );\n const type = wireType(p.schema, `${at} parameter ${p.name}`);\n if (location !== 'query' && type.startsWith('Array<'))\n throw new Error(`${at}: only query parameters support arrays.`);\n return `${quote(p.name)}${location === 'path' || p.required ? '' : '?'}: ${type};`;\n }\n\n const paths: string[] = [];\n for (const [openApiPath, item] of Object.entries(document.paths).toSorted(([a], [b]) =>\n a.localeCompare(b),\n )) {\n // Hono's proxy consumes one path segment per property. Reject templates it\n // cannot faithfully round-trip rather than generate a misleading client.\n if (\n !openApiPath.startsWith('/') ||\n openApiPath\n .slice(1)\n .split('/')\n .some(\n (segment) =>\n segment !== '' && !/^(?:[A-Za-z0-9_.~-]+|\\{[A-Za-z_][A-Za-z0-9_]*\\})$/.test(segment),\n ) ||\n openApiPath.includes('//') ||\n (openApiPath !== '/' && openApiPath.endsWith('/'))\n )\n throw new Error(`Unsupported client path: ${openApiPath}`);\n const path = openApiPath.replace(/\\{([^}]+)\\}/g, ':$1');\n if (\n path\n .split('/')\n .some(\n (segment) => ['index', 'then', '.', '..'].includes(segment) || segment.startsWith('$'),\n )\n )\n throw new Error(`Reserved hc path segment: ${path}`);\n if ('parameters' in item || '$ref' in item)\n throw new Error(`${path}: resolve path-level parameters/references into operations first.`);\n const methods: string[] = [];\n for (const method of METHODS) {\n const operation = item[method];\n if (!operation) continue;\n const at = `${method.toUpperCase()} ${path}`;\n const unsupported = operation['x-vela-client-unsupported'];\n if (unsupported?.length) throw new Error(`${at}: ${unsupported.join(' ')}`);\n const input = inputType(path, operation, at);\n const explicitStatuses = Object.keys(operation.responses).filter((s) => /^\\d{3}$/.test(s));\n const variants: string[] = [];\n for (const [status, response] of Object.entries(operation.responses).toSorted(([a], [b]) =>\n a.localeCompare(b),\n )) {\n if (response.$ref)\n throw new Error(`${at}: resolve response references before generating a client.`);\n let statusType: string;\n if (/^[1-5]\\d\\d$/.test(status) && HTTP_STATUSES.has(Number(status))) statusType = status;\n else if (status === 'default')\n statusType = `Exclude<HttpStatus, ${\n Object.keys(operation.responses)\n .filter((s) => s !== 'default')\n .map((s) => (/^[1-5]XX$/.test(s) ? rangeStatus(s) : s))\n .join(' | ') || 'never'\n }>`;\n else if (/^[1-5]XX$/.test(status))\n statusType = `Exclude<${rangeStatus(status)}, ${explicitStatuses.join(' | ') || 'never'}>`;\n else throw new Error(`${at}: unsupported response status ${status}.`);\n if (statusType.includes('HttpStatus')) usesHttpStatus = true;\n const content = response.content ?? {};\n const media = Object.keys(content);\n if (\n media.length > 1 ||\n (media.length === 1 && media[0] !== 'application/json' && media[0] !== 'text/plain')\n )\n throw new Error(`${at}: responses must declare one JSON or text media type.`);\n const format = media[0] === 'text/plain' ? 'text' : 'json';\n const bodyType =\n ['101', '204', '205', '304'].includes(status) || method === 'head'\n ? 'never'\n : schemaType(content[media[0] ?? '']?.schema, `${at} response ${status}`);\n // text() always returns a string, even if the document describes a\n // numeric or unconstrained text payload. Preserve string literals.\n const output =\n format === 'text'\n ? `Extract<${bodyType}, string> extends never ? string : Extract<${bodyType}, string>`\n : bodyType;\n variants.push(\n `{ input: ${input}; output: ${output}; outputFormat: '${format}'; status: ${statusType} }`,\n );\n }\n if (!variants.length) throw new Error(`${at}: at least one response is required.`);\n methods.push(` $${method}: ${variants.join(' | ')};`);\n }\n if (methods.length) paths.push(` ${quote(path)}: {\\n${methods.join('\\n')}\\n };`);\n }\n\n const schemas = Object.entries(components)\n .toSorted(([a], [b]) => a.localeCompare(b))\n .map(([name, schema]) => ` ${quote(name)}: ${schemaType(schema, `schema ${name}`)};`);\n const source = [\n '// Generated by vela client generate. Do not edit.',\n `import type { HttpApp${usesHttpStatus ? ', HttpStatus' : ''} } from '@velajs/client/http';`,\n '',\n `export type Schemas = {\\n${schemas.join('\\n')}\\n};`,\n '',\n `export type AppType = HttpApp<{\\n${paths.join('\\n')}\\n}>;`,\n '',\n ].join('\\n');\n return { source, warnings: [...warnings] };\n}\n\nfunction literal(value: unknown, at: string): string {\n if (value === null || ['string', 'boolean', 'number'].includes(typeof value))\n return JSON.stringify(value);\n throw new Error(`${at}: object/array const values are not supported.`);\n}\n\nfunction rangeStatus(status: string): string {\n const start = Number(status[0]) * 100;\n return `Extract<HttpStatus, ${Array.from({ length: 100 }, (_, i) => start + i).join(' | ')}>`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ //#region src/client-contract.d.ts
2
+ export interface GeneratedClientContract {
3
+ source: string;
4
+ warnings: string[];
5
+ }
6
+ /** Generate a type-only contract for Hono's hc. No application imports escape into it. */
7
+ export declare function generateClientContract(input: unknown): GeneratedClientContract;
8
+ //#endregion
9
+ //# sourceMappingURL=client-contract.d.ts.map
@@ -0,0 +1,2 @@
1
+ import { t as generateClientContract } from "./client-contract-C7P2btFE.js";
2
+ export { generateClientContract };
package/dist/config.d.ts CHANGED
@@ -16,22 +16,21 @@ import { Type, VelaApplication } from "@velajs/vela";
16
16
  * });
17
17
  * ```
18
18
  */
19
- interface VelaConfig {
19
+ export interface VelaConfig {
20
20
  createApp(): Promise<VelaApplication> | VelaApplication;
21
21
  /**
22
22
  * The app's root module class — needed only by commands that work from
23
- * module metadata rather than the built app (`vela openapi dump`).
23
+ * module metadata rather than the built app (`vela openapi dump`, `vela client generate`).
24
24
  */
25
25
  rootModule?: Type;
26
26
  }
27
27
  /** Identity helper for type-safe config files. */
28
- declare function defineVelaConfig(config: VelaConfig): VelaConfig;
28
+ export declare function defineVelaConfig(config: VelaConfig): VelaConfig;
29
29
  /**
30
30
  * Locate + import the vela config. `.ts` requires a runtime that strips types
31
31
  * (Node 22+ `--experimental-strip-types`, or tsx/ts-node); `.js`/`.mjs` load
32
32
  * directly.
33
33
  */
34
- declare function loadConfig(cwd?: string, explicitPath?: string): Promise<VelaConfig>;
34
+ export declare function loadConfig(cwd?: string, explicitPath?: string): Promise<VelaConfig>;
35
35
  //#endregion
36
- export { VelaConfig, defineVelaConfig, loadConfig };
37
36
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { access } from 'node:fs/promises';\nimport { isAbsolute, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { Type, VelaApplication } from '@velajs/vela';\n\n/**\n * A `vela.config.{js,mjs,ts}` default-exports (or exports `config`) this shape.\n * You wire your runtime bindings inside `createApp` — e.g. via miniflare for a\n * Cloudflare Worker, or a plain Node adapter — and return a built app.\n *\n * ```ts\n * // vela.config.ts\n * import { defineVelaConfig } from '@velajs/cli/config';\n * export default defineVelaConfig({\n * async createApp() {\n * const { createCloudflareApp } = await import('@velajs/cloudflare');\n * return createCloudflareApp(AppModule);\n * },\n * });\n * ```\n */\nexport interface VelaConfig {\n createApp(): Promise<VelaApplication> | VelaApplication;\n /**\n * The app's root module class — needed only by commands that work from\n * module metadata rather than the built app (`vela openapi dump`).\n */\n rootModule?: Type;\n}\n\n/** Identity helper for type-safe config files. */\nexport function defineVelaConfig(config: VelaConfig): VelaConfig {\n return config;\n}\n\nconst CANDIDATES = ['vela.config.js', 'vela.config.mjs', 'vela.config.ts'];\n\n/**\n * Locate + import the vela config. `.ts` requires a runtime that strips types\n * (Node 22+ `--experimental-strip-types`, or tsx/ts-node); `.js`/`.mjs` load\n * directly.\n */\nexport async function loadConfig(\n cwd: string = process.cwd(),\n explicitPath?: string,\n): Promise<VelaConfig> {\n const path = explicitPath\n ? isAbsolute(explicitPath)\n ? explicitPath\n : resolve(cwd, explicitPath)\n : await findConfig(cwd);\n\n if (!path) {\n throw new Error(\n `No vela config found. Create one of: ${CANDIDATES.join(', ')} (or pass --config <path>).`,\n );\n }\n\n const mod = (await import(pathToFileURL(path).href)) as {\n default?: VelaConfig;\n config?: VelaConfig;\n };\n const config = mod.default ?? mod.config;\n if (!config || typeof config.createApp !== 'function') {\n throw new Error(\n `Config at ${path} must export { createApp(): Promise<VelaApplication> } (default export or a named 'config').`,\n );\n }\n return config;\n}\n\nasync function findConfig(cwd: string): Promise<string | undefined> {\n for (const name of CANDIDATES) {\n const candidate = join(cwd, name);\n try {\n await access(candidate);\n return candidate;\n } catch {\n // try next\n }\n }\n return undefined;\n}\n"],"mappings":";;;;;AA+BA,SAAgB,iBAAiB,QAAgC;CAC/D,OAAO;AACT;AAEA,MAAM,aAAa;CAAC;CAAkB;CAAmB;AAAgB;;;;;;AAOzE,eAAsB,WACpB,MAAc,QAAQ,IAAI,GAC1B,cACqB;CACrB,MAAM,OAAO,eACT,WAAW,YAAY,IACrB,eACA,QAAQ,KAAK,YAAY,IAC3B,MAAM,WAAW,GAAG;CAExB,IAAI,CAAC,MACH,MAAM,IAAI,MACR,wCAAwC,WAAW,KAAK,IAAI,EAAE,4BAChE;CAGF,MAAM,MAAO,MAAM,OAAO,cAAc,IAAI,CAAC,CAAC;CAI9C,MAAM,SAAS,IAAI,WAAW,IAAI;CAClC,IAAI,CAAC,UAAU,OAAO,OAAO,cAAc,YACzC,MAAM,IAAI,MACR,aAAa,KAAK,6FACpB;CAEF,OAAO;AACT;AAEA,eAAe,WAAW,KAA0C;CAClE,KAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,YAAY,KAAK,KAAK,IAAI;EAChC,IAAI;GACF,MAAM,OAAO,SAAS;GACtB,OAAO;EACT,QAAQ,CAER;CACF;AAEF"}
1
+ {"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { access } from 'node:fs/promises';\nimport { isAbsolute, join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { Type, VelaApplication } from '@velajs/vela';\n\n/**\n * A `vela.config.{js,mjs,ts}` default-exports (or exports `config`) this shape.\n * You wire your runtime bindings inside `createApp` — e.g. via miniflare for a\n * Cloudflare Worker, or a plain Node adapter — and return a built app.\n *\n * ```ts\n * // vela.config.ts\n * import { defineVelaConfig } from '@velajs/cli/config';\n * export default defineVelaConfig({\n * async createApp() {\n * const { createCloudflareApp } = await import('@velajs/cloudflare');\n * return createCloudflareApp(AppModule);\n * },\n * });\n * ```\n */\nexport interface VelaConfig {\n createApp(): Promise<VelaApplication> | VelaApplication;\n /**\n * The app's root module class — needed only by commands that work from\n * module metadata rather than the built app (`vela openapi dump`, `vela client generate`).\n */\n rootModule?: Type;\n}\n\n/** Identity helper for type-safe config files. */\nexport function defineVelaConfig(config: VelaConfig): VelaConfig {\n return config;\n}\n\nconst CANDIDATES = ['vela.config.js', 'vela.config.mjs', 'vela.config.ts'];\n\n/**\n * Locate + import the vela config. `.ts` requires a runtime that strips types\n * (Node 22+ `--experimental-strip-types`, or tsx/ts-node); `.js`/`.mjs` load\n * directly.\n */\nexport async function loadConfig(\n cwd: string = process.cwd(),\n explicitPath?: string,\n): Promise<VelaConfig> {\n const path = explicitPath\n ? isAbsolute(explicitPath)\n ? explicitPath\n : resolve(cwd, explicitPath)\n : await findConfig(cwd);\n\n if (!path) {\n throw new Error(\n `No vela config found. Create one of: ${CANDIDATES.join(', ')} (or pass --config <path>).`,\n );\n }\n\n const mod = (await import(pathToFileURL(path).href)) as {\n default?: VelaConfig;\n config?: VelaConfig;\n };\n const config = mod.default ?? mod.config;\n if (!config || typeof config.createApp !== 'function') {\n throw new Error(\n `Config at ${path} must export { createApp(): Promise<VelaApplication> } (default export or a named 'config').`,\n );\n }\n return config;\n}\n\nasync function findConfig(cwd: string): Promise<string | undefined> {\n for (const name of CANDIDATES) {\n const candidate = join(cwd, name);\n try {\n await access(candidate);\n return candidate;\n } catch {\n // try next\n }\n }\n return undefined;\n}\n"],"mappings":";;;;;AA+BA,SAAgB,iBAAiB,QAAgC;CAC/D,OAAO;AACT;AAEA,MAAM,aAAa;CAAC;CAAkB;CAAmB;AAAgB;;;;;;AAOzE,eAAsB,WACpB,MAAc,QAAQ,IAAI,GAC1B,cACqB;CACrB,MAAM,OAAO,eACT,WAAW,YAAY,IACrB,eACA,QAAQ,KAAK,YAAY,IAC3B,MAAM,WAAW,GAAG;CAExB,IAAI,CAAC,MACH,MAAM,IAAI,MACR,wCAAwC,WAAW,KAAK,IAAI,EAAE,4BAChE;CAGF,MAAM,MAAO,MAAM,OAAO,cAAc,IAAI,CAAC,CAAC;CAI9C,MAAM,SAAS,IAAI,WAAW,IAAI;CAClC,IAAI,CAAC,UAAU,OAAO,OAAO,cAAc,YACzC,MAAM,IAAI,MACR,aAAa,KAAK,6FACpB;CAEF,OAAO;AACT;AAEA,eAAe,WAAW,KAA0C;CAClE,KAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,YAAY,KAAK,KAAK,IAAI;EAChC,IAAI;GACF,MAAM,OAAO,SAAS;GACtB,OAAO;EACT,QAAQ,CAER;CACF;AAEF"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
+ import { GeneratedClientContract, generateClientContract } from "./client-contract.js";
1
2
  import { VelaConfig, defineVelaConfig, loadConfig } from "./config.js";
2
3
  import { Command } from "clipanion";
3
4
  import { ModuleDescription, VelaApplication } from "@velajs/vela";
4
5
  import { SeederResult } from "@velajs/vela/seeder";
5
6
  //#region src/commands/seed.command.d.ts
6
7
  /** `vela db seed` — build the app from vela.config and run its seeders. */
7
- declare class SeedCommand extends Command {
8
+ export declare class SeedCommand extends Command {
8
9
  static paths: string[][];
9
10
  static usage: import("clipanion").Usage;
10
11
  config: string | undefined;
@@ -22,25 +23,25 @@ declare abstract class AppCommand extends Command {
22
23
  protected print(text: string): void;
23
24
  }
24
25
  /** `vela route list` — the app's HTTP route table. */
25
- declare class RouteListCommand extends AppCommand {
26
+ export declare class RouteListCommand extends AppCommand {
26
27
  static paths: string[][];
27
28
  static usage: import("clipanion").Usage;
28
29
  protected run(app: VelaApplication): Promise<number>;
29
30
  }
30
31
  /** `vela module graph` — the loaded module graph. */
31
- declare class ModuleGraphCommand extends AppCommand {
32
+ export declare class ModuleGraphCommand extends AppCommand {
32
33
  static paths: string[][];
33
34
  static usage: import("clipanion").Usage;
34
35
  protected run(app: VelaApplication): Promise<number>;
35
36
  }
36
37
  /** `vela entrypoint list` — declared entrypoint kinds and their entries. */
37
- declare class EntrypointListCommand extends AppCommand {
38
+ export declare class EntrypointListCommand extends AppCommand {
38
39
  static paths: string[][];
39
40
  static usage: import("clipanion").Usage;
40
41
  protected run(app: VelaApplication): Promise<number>;
41
42
  }
42
43
  /** `vela openapi dump` — emit the OpenAPI document. */
43
- declare class OpenApiDumpCommand extends Command {
44
+ export declare class OpenApiDumpCommand extends Command {
44
45
  static paths: string[][];
45
46
  static usage: import("clipanion").Usage;
46
47
  config: string | undefined;
@@ -62,13 +63,48 @@ declare class OpenApiDumpCommand extends Command {
62
63
  * the transport closes. stdout is reserved for JSON-RPC framing; every human
63
64
  * message goes to stderr.
64
65
  */
65
- declare class McpServeCommand extends Command {
66
+ export declare class McpServeCommand extends Command {
66
67
  static paths: string[][];
67
68
  static usage: import("clipanion").Usage;
68
69
  config: string | undefined;
69
70
  execute(): Promise<number>;
70
71
  }
71
72
  //#endregion
73
+ //#region src/commands/studio.command.d.ts
74
+ /**
75
+ * `vela studio` — start the loopback dev host that serves Vela Studio and proxies
76
+ * the admin API to a running app.
77
+ *
78
+ * App-origin resolution (v1): the target app is taken from `--url <origin>`,
79
+ * which is REQUIRED. The host proxies `{--path}/*` to that origin, injecting the
80
+ * admin token as `Authorization: Bearer` server-side (the browser never holds
81
+ * it). Booting the app in-process from `vela.config` (via `loadConfig`) is a
82
+ * planned follow-up; requiring `--url` keeps v1 simple and adapter-agnostic.
83
+ */
84
+ export declare class StudioCommand extends Command {
85
+ static paths: string[][];
86
+ static usage: import("clipanion").Usage;
87
+ url: string | undefined;
88
+ token: string | undefined;
89
+ port: string | undefined;
90
+ adminPath: string | undefined;
91
+ execute(): Promise<number>;
92
+ }
93
+ //#endregion
94
+ //#region src/commands/client.command.d.ts
95
+ export declare class ClientGenerateCommand extends Command {
96
+ static paths: string[][];
97
+ static usage: import("clipanion").Usage;
98
+ config: string | undefined;
99
+ input: string | undefined;
100
+ out: string | undefined;
101
+ check: boolean;
102
+ strict: boolean;
103
+ execute(): Promise<number>;
104
+ private readDocument;
105
+ private fromApp;
106
+ }
107
+ //#endregion
72
108
  //#region src/introspect.d.ts
73
109
  /** One row of `vela route list`. */
74
110
  interface RouteRow {
@@ -84,10 +120,10 @@ interface RouteRow {
84
120
  * plus everything else present on the Hono router, deduped and labeled
85
121
  * `(mounted)`. Returns null when the app never built HTTP routes.
86
122
  */
87
- declare function collectRoutes(app: VelaApplication): RouteRow[] | null;
123
+ export declare function collectRoutes(app: VelaApplication): RouteRow[] | null;
88
124
  /** `vela module graph` tree lines (or raw descriptions for --json). */
89
- declare function collectModules(app: VelaApplication): ModuleDescription[];
90
- declare function renderModuleTree(modules: ModuleDescription[]): string[];
125
+ export declare function collectModules(app: VelaApplication): ModuleDescription[];
126
+ export declare function renderModuleTree(modules: ModuleDescription[]): string[];
91
127
  /** One row of `vela entrypoint list`. */
92
128
  interface EntrypointRow {
93
129
  kind: string;
@@ -99,16 +135,16 @@ interface EntrypointRow {
99
135
  * with zero entries) joined with the app's entries. Metadata-only entries of
100
136
  * lazy modules list fine; nothing materializes.
101
137
  */
102
- declare function collectEntrypoints(app: VelaApplication): EntrypointRow[];
138
+ export declare function collectEntrypoints(app: VelaApplication): EntrypointRow[];
103
139
  //#endregion
104
140
  //#region src/format.d.ts
105
141
  /**
106
142
  * Render seeder results to a logger and return a process exit code
107
143
  * (0 = all ran, 1 = at least one failed). Pure — no I/O beyond the logger.
108
144
  */
109
- declare function formatSeedResults(results: SeederResult[], log?: (message: string) => void): number;
145
+ export declare function formatSeedResults(results: SeederResult[], log?: (message: string) => void): number;
110
146
  /** Aligned plain-text table. Pure; returns lines. */
111
- declare function renderTable(headers: string[], rows: string[][]): string[];
147
+ export declare function renderTable(headers: string[], rows: string[][]): string[];
112
148
  //#endregion
113
- export { EntrypointListCommand, type EntrypointRow, McpServeCommand, ModuleGraphCommand, OpenApiDumpCommand, RouteListCommand, type RouteRow, SeedCommand, type VelaConfig, collectEntrypoints, collectModules, collectRoutes, defineVelaConfig, formatSeedResults, loadConfig, renderModuleTree, renderTable };
149
+ export { type EntrypointRow, type GeneratedClientContract, type RouteRow, type VelaConfig, defineVelaConfig, generateClientContract, loadConfig };
114
150
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { defineVelaConfig, loadConfig } from "./config.js";
3
+ import { t as generateClientContract } from "./client-contract-C7P2btFE.js";
3
4
  import { Builtins, Cli, Command, Option } from "clipanion";
4
- import { readFile, writeFile } from "node:fs/promises";
5
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
5
6
  import { createOpenApiDocument, describeToken, getEntrypointKinds } from "@velajs/vela";
6
7
  import { dirname, join } from "node:path";
7
8
  import { fileURLToPath } from "node:url";
@@ -468,6 +469,163 @@ var SeedCommand = class extends Command {
468
469
  }
469
470
  };
470
471
  //#endregion
472
+ //#region src/commands/studio.command.ts
473
+ /**
474
+ * The optional peer that does the real work. It is Node-only and heavy, so it is
475
+ * NOT a hard dependency of the CLI — it is lazily imported here and, when it
476
+ * isn't installed, the command prints an install hint (mirroring how
477
+ * `mcp.command` lazily loads its optional peer).
478
+ */
479
+ const HOST_PACKAGE = "@velajs/studio-host";
480
+ /** True for a failed dynamic `import()` of a missing module (ESM or CJS code). */
481
+ function isModuleNotFound(error, specifier) {
482
+ const code = error.code;
483
+ if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") return true;
484
+ return (error instanceof Error ? error.message : "").includes(specifier);
485
+ }
486
+ /**
487
+ * `vela studio` — start the loopback dev host that serves Vela Studio and proxies
488
+ * the admin API to a running app.
489
+ *
490
+ * App-origin resolution (v1): the target app is taken from `--url <origin>`,
491
+ * which is REQUIRED. The host proxies `{--path}/*` to that origin, injecting the
492
+ * admin token as `Authorization: Bearer` server-side (the browser never holds
493
+ * it). Booting the app in-process from `vela.config` (via `loadConfig`) is a
494
+ * planned follow-up; requiring `--url` keeps v1 simple and adapter-agnostic.
495
+ */
496
+ var StudioCommand = class extends Command {
497
+ static paths = [["studio"]];
498
+ static usage = Command.Usage({
499
+ category: "Studio",
500
+ description: "Serve Vela Studio locally and proxy the admin API to a running app.",
501
+ details: "Starts a loopback dev host (from the optional @velajs/studio-host peer) that serves the prebuilt Studio SPA and proxies {--path}/* to the app at --url, injecting the admin token as a Bearer server-side so the browser never receives it. The token comes from --token or the VELA_STUDIO_TOKEN environment variable. Runs until interrupted (Ctrl+C).",
502
+ examples: [["Serve against a local worker", "vela studio --url http://127.0.0.1:8787"], ["With an explicit token + port", "vela studio --url http://127.0.0.1:8787 --token $TOKEN --port 4000"]]
503
+ });
504
+ url = Option.String("--url", { description: "Origin of the running app to proxy the admin API to (required)." });
505
+ token = Option.String("--token", { description: "Admin bearer token (falls back to VELA_STUDIO_TOKEN). Never sent to the browser." });
506
+ port = Option.String("--port", { description: "Loopback port to bind (default: an ephemeral port)." });
507
+ adminPath = Option.String("--path", { description: "Server admin-mount prefix to proxy (default: /_vela/admin)." });
508
+ async execute() {
509
+ const workerOrigin = this.url;
510
+ if (workerOrigin === void 0 || workerOrigin === "") {
511
+ this.context.stderr.write("vela studio: --url <origin> is required — the running app to proxy the admin API to.\n Example: vela studio --url http://127.0.0.1:8787\n");
512
+ return 1;
513
+ }
514
+ if (!URL.canParse(workerOrigin)) {
515
+ this.context.stderr.write(`vela studio: --url is not a valid origin: ${workerOrigin}\n`);
516
+ return 1;
517
+ }
518
+ let port;
519
+ if (this.port !== void 0) {
520
+ port = Number.parseInt(this.port, 10);
521
+ if (Number.isNaN(port) || port < 0 || port > 65535) {
522
+ this.context.stderr.write(`vela studio: --port must be a number 0-65535, got: ${this.port}\n`);
523
+ return 1;
524
+ }
525
+ }
526
+ const adminToken = this.token ?? process.env.VELA_STUDIO_TOKEN;
527
+ let host;
528
+ try {
529
+ host = await import(HOST_PACKAGE);
530
+ } catch (error) {
531
+ if (isModuleNotFound(error, HOST_PACKAGE)) {
532
+ this.context.stderr.write(`vela studio needs the optional "${HOST_PACKAGE}" package, which isn't installed.\n Install it: pnpm add -D ${HOST_PACKAGE}\n (it also needs the prebuilt UI: pnpm add -D @velajs/studio-ui)\n`);
533
+ return 1;
534
+ }
535
+ throw error;
536
+ }
537
+ const server = await host.startStudioServer({
538
+ workerOrigin,
539
+ adminToken,
540
+ port,
541
+ adminPath: this.adminPath,
542
+ cwd: process.cwd()
543
+ });
544
+ this.context.stdout.write(`\n Vela Studio ${server.url}\n Proxying ${workerOrigin}${this.adminPath ?? "/_vela/admin"}/*\n Admin token ${adminToken !== void 0 ? "set (injected server-side)" : "none (app requires none)"}\n\n Press Ctrl+C to stop.
545
+ `);
546
+ await new Promise((resolvePromise) => {
547
+ const onSignal = () => {
548
+ process.off("SIGINT", onSignal);
549
+ process.off("SIGTERM", onSignal);
550
+ resolvePromise();
551
+ };
552
+ process.on("SIGINT", onSignal);
553
+ process.on("SIGTERM", onSignal);
554
+ });
555
+ await server.close();
556
+ this.context.stdout.write("\nVela Studio stopped.\n");
557
+ return 0;
558
+ }
559
+ };
560
+ //#endregion
561
+ //#region src/commands/client.command.ts
562
+ var ClientGenerateCommand = class extends Command {
563
+ static paths = [["client", "generate"]];
564
+ static usage = Command.Usage({
565
+ category: "Client",
566
+ description: "Generate a typed HTTP contract for Hono's hc client.",
567
+ details: "Uses rootModule and createApp from vela.config, or an OpenAPI JSON file with --input. Missing schemas emit unknown and a warning; --strict makes those warnings an error.",
568
+ examples: [
569
+ ["Generate from an app", "vela client generate --out src/api.generated.ts"],
570
+ ["Generate from a document", "vela client generate --input openapi.json --out src/api.generated.ts"],
571
+ ["Check a committed contract", "vela client generate --out src/api.generated.ts --check"]
572
+ ]
573
+ });
574
+ config = Option.String("--config", { description: "Path to the vela config file." });
575
+ input = Option.String("--input", { description: "Read an OpenAPI JSON file without bootstrapping the app." });
576
+ out = Option.String("--out", { description: "Output TypeScript file (stdout when omitted)." });
577
+ check = Option.Boolean("--check", false, { description: "Fail if --out differs from the generated contract; do not write." });
578
+ strict = Option.Boolean("--strict", false, { description: "Fail on missing or lossy schemas." });
579
+ async execute() {
580
+ if (this.input && this.config) throw new Error("Use either --input or --config, not both.");
581
+ if (this.check && !this.out) throw new Error("--check requires --out.");
582
+ const document = this.input ? await this.readDocument(this.input) : await this.fromApp();
583
+ const { source, warnings } = generateClientContract(document);
584
+ for (const warning of warnings) this.context.stderr.write(`Warning: ${warning}\n`);
585
+ if (this.strict && warnings.length) return 1;
586
+ if (this.check) {
587
+ let existing;
588
+ try {
589
+ existing = await readFile(this.out, "utf8");
590
+ } catch (error) {
591
+ if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") throw error;
592
+ }
593
+ if (existing !== source) {
594
+ this.context.stderr.write(`Client contract is missing or stale: ${this.out}. Run vela client generate without --check.\n`);
595
+ return 1;
596
+ }
597
+ } else if (this.out) {
598
+ await mkdir(dirname(this.out), { recursive: true });
599
+ await writeFile(this.out, source, "utf8");
600
+ this.context.stdout.write(`Wrote ${this.out}\n`);
601
+ } else this.context.stdout.write(source);
602
+ return 0;
603
+ }
604
+ async readDocument(file) {
605
+ return JSON.parse(await readFile(file, "utf8"));
606
+ }
607
+ async fromApp() {
608
+ const config = await loadConfig(process.cwd(), this.config);
609
+ if (!config.rootModule) throw new Error("client generate needs rootModule in vela.config, or pass --input openapi.json.");
610
+ const app = await config.createApp();
611
+ try {
612
+ const document = createOpenApiDocument(config.rootModule, { globalPrefix: app.getGlobalPrefix() });
613
+ for (const route of app.describeRoutes()) {
614
+ const path = route.path.replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, "{$1}");
615
+ const item = document.paths[path];
616
+ if (!item || !Object.hasOwn(item, route.method.toLowerCase())) throw new Error(`OpenAPI is missing ${route.method} ${route.path}. Update Vela or pass a complete document with --input.`);
617
+ }
618
+ return document;
619
+ } finally {
620
+ try {
621
+ await app.dispose();
622
+ } catch (error) {
623
+ this.context.stderr.write(`Warning: teardown failed: ${String(error)}\n`);
624
+ }
625
+ }
626
+ }
627
+ };
628
+ //#endregion
471
629
  //#region src/index.ts
472
630
  const cli = new Cli({
473
631
  binaryName: "vela",
@@ -482,8 +640,10 @@ cli.register(ModuleGraphCommand);
482
640
  cli.register(EntrypointListCommand);
483
641
  cli.register(OpenApiDumpCommand);
484
642
  cli.register(McpServeCommand);
643
+ cli.register(StudioCommand);
644
+ cli.register(ClientGenerateCommand);
485
645
  cli.runExit(process.argv.slice(2));
486
646
  //#endregion
487
- export { EntrypointListCommand, McpServeCommand, ModuleGraphCommand, OpenApiDumpCommand, RouteListCommand, SeedCommand, collectEntrypoints, collectModules, collectRoutes, defineVelaConfig, formatSeedResults, loadConfig, renderModuleTree, renderTable };
647
+ export { ClientGenerateCommand, EntrypointListCommand, McpServeCommand, ModuleGraphCommand, OpenApiDumpCommand, RouteListCommand, SeedCommand, StudioCommand, collectEntrypoints, collectModules, collectRoutes, defineVelaConfig, formatSeedResults, generateClientContract, loadConfig, renderModuleTree, renderTable };
488
648
 
489
649
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["describeToken"],"sources":["../src/format.ts","../src/introspect.ts","../src/commands/introspect.commands.ts","../src/commands/mcp.command.ts","../src/commands/seed.command.ts","../src/index.ts"],"sourcesContent":["import type { SeederResult } from '@velajs/vela/seeder';\n\n/**\n * Render seeder results to a logger and return a process exit code\n * (0 = all ran, 1 = at least one failed). Pure — no I/O beyond the logger.\n */\nexport function formatSeedResults(\n results: SeederResult[],\n log: (message: string) => void = (m) => console.log(m),\n): number {\n if (results.length === 0) {\n log('No seeders found.');\n return 0;\n }\n\n let failed = 0;\n for (const result of results) {\n if (result.ok) {\n log(` ✓ ${result.name}`);\n } else {\n failed++;\n log(` ✗ ${result.name}${result.error ? `: ${errorMessage(result.error)}` : ''}`);\n }\n }\n\n const total = results.length;\n log(`\\n${total - failed}/${total} seeders ran successfully.`);\n return failed > 0 ? 1 : 0;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Aligned plain-text table. Pure; returns lines. */\nexport function renderTable(headers: string[], rows: string[][]): string[] {\n const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)));\n const line = (cells: string[]): string =>\n cells\n .map((c, i) => (c ?? '').padEnd(widths[i]!))\n .join(' ')\n .trimEnd();\n return [line(headers), line(widths.map((w) => '-'.repeat(w))), ...rows.map(line)];\n}\n","import type { VelaApplication } from '@velajs/vela';\nimport { describeToken, getEntrypointKinds } from '@velajs/vela';\nimport type { ModuleDescription, RouteDescription } from '@velajs/vela';\n\n/** One row of `vela route list`. */\nexport interface RouteRow {\n method: string;\n path: string;\n /** `Controller#handler`, or `(mounted)` for routes vela did not compose\n * itself (RouteContributor/CRUD, OpenAPI UI mounts, manual Hono routes). */\n handler: string;\n source: 'controller' | 'mounted';\n}\n\n/**\n * The app's route table: `describeRoutes()` rows (framework-composed truth)\n * plus everything else present on the Hono router, deduped and labeled\n * `(mounted)`. Returns null when the app never built HTTP routes.\n */\nexport function collectRoutes(app: VelaApplication): RouteRow[] | null {\n let described: RouteDescription[];\n try {\n described = app.describeRoutes();\n } catch {\n return null; // no HTTP routes built (slim/non-HTTP app)\n }\n\n const rows: RouteRow[] = described.map((r) => ({\n method: r.method,\n path: r.path,\n handler: `${r.controller}#${r.handler}`,\n source: 'controller',\n }));\n\n const covered = new Set(described.map((r) => `${r.method} ${r.path}`));\n for (const r of described) {\n // @Head handlers are served by Hono under GET — claim that row too so it\n // doesn't reappear as a mounted duplicate.\n if (r.method === 'HEAD') covered.add(`GET ${r.path}`);\n }\n\n const seenMounted = new Set<string>();\n for (const honoRoute of app.getHonoApp().routes) {\n // 'ALL' entries are middleware mounts (framework-internal disposal/context\n // wrappers, global + scoped middleware) — not endpoints.\n if (honoRoute.method === 'ALL') continue;\n const key = `${honoRoute.method} ${honoRoute.path}`;\n if (covered.has(key) || seenMounted.has(key)) continue;\n seenMounted.add(key);\n rows.push({\n method: honoRoute.method,\n path: honoRoute.path,\n handler: '(mounted)',\n source: 'mounted',\n });\n }\n\n return rows.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));\n}\n\n/** `vela module graph` tree lines (or raw descriptions for --json). */\nexport function collectModules(app: VelaApplication): ModuleDescription[] {\n return app.getContainer().getModuleDescriptions();\n}\n\nexport function renderModuleTree(modules: ModuleDescription[]): string[] {\n const byId = new Map(modules.map((m) => [m.moduleId, m]));\n const imported = new Set(modules.flatMap((m) => m.imports));\n const roots = modules.filter((m) => !imported.has(m.moduleId));\n\n const lines: string[] = [];\n const render = (id: string, depth: number, trail: Set<string>): void => {\n const mod = byId.get(id);\n const flags = mod\n ? [mod.isGlobal ? 'global' : null, mod.lazy ? 'lazy' : null].filter(Boolean)\n : [];\n const suffix = flags.length > 0 ? ` (${flags.join(', ')})` : '';\n const providers = mod\n ? ` — ${mod.providers.length} provider${mod.providers.length === 1 ? '' : 's'}`\n : '';\n lines.push(`${' '.repeat(depth)}${id}${suffix}${providers}`);\n if (!mod || trail.has(id)) return;\n const nextTrail = new Set(trail).add(id);\n for (const child of mod.imports) render(child, depth + 1, nextTrail);\n };\n\n for (const root of roots) render(root.moduleId, 0, new Set());\n return lines;\n}\n\n/** One row of `vela entrypoint list`. */\nexport interface EntrypointRow {\n kind: string;\n target: string;\n meta: string;\n}\n\nfunction safeMeta(meta: unknown): string {\n try {\n return (\n JSON.stringify(meta, (_key, value: unknown) =>\n typeof value === 'function'\n ? '[function]'\n : typeof value === 'object' &&\n value !== null &&\n value.constructor !== Object &&\n !Array.isArray(value)\n ? `[${(value as object).constructor.name}]`\n : value,\n ) ?? 'undefined'\n );\n } catch {\n return '[unserializable]';\n }\n}\n\n/**\n * Every DECLARED entrypoint kind (from the global kind store — includes kinds\n * with zero entries) joined with the app's entries. Metadata-only entries of\n * lazy modules list fine; nothing materializes.\n */\nexport function collectEntrypoints(app: VelaApplication): EntrypointRow[] {\n const rows: EntrypointRow[] = [];\n const declared = getEntrypointKinds().map((k: { kind: string }) => k.kind);\n const populated = app.entrypoints.kinds();\n const kinds = [...new Set([...declared, ...populated])];\n\n for (const kind of kinds) {\n const entries = app.entrypoints.ofKind(kind);\n if (entries.length === 0) {\n rows.push({ kind, target: '(no entrypoints)', meta: '' });\n continue;\n }\n for (const ep of entries) {\n const method = ep.methodName !== undefined ? `#${String(ep.methodName)}` : '';\n rows.push({ kind, target: `${describeToken(ep.token)}${method}`, meta: safeMeta(ep.meta) });\n }\n }\n return rows;\n}\n","import { writeFile } from 'node:fs/promises';\nimport { createOpenApiDocument } from '@velajs/vela';\nimport type { VelaApplication } from '@velajs/vela';\nimport { Command, Option } from 'clipanion';\nimport { loadConfig } from '../config.js';\nimport { renderTable } from '../format.js';\nimport {\n collectEntrypoints,\n collectModules,\n collectRoutes,\n renderModuleTree,\n} from '../introspect.js';\n\n/** Shared shell: load config → createApp → run → best-effort dispose. */\nabstract class AppCommand extends Command {\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n json = Option.Boolean('--json', false, { description: 'Emit machine-readable JSON.' });\n\n protected abstract run(app: VelaApplication): Promise<number>;\n\n async execute(): Promise<number> {\n const velaConfig = await loadConfig(process.cwd(), this.config);\n const app = await velaConfig.createApp();\n try {\n return await this.run(app);\n } finally {\n const dispose = (app as { dispose?: () => Promise<void> }).dispose;\n if (typeof dispose === 'function') {\n try {\n await dispose.call(app);\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed: ${String(error)}\\n`);\n }\n }\n }\n }\n\n protected print(text: string): void {\n this.context.stdout.write(`${text}\\n`);\n }\n}\n\n/** `vela route list` — the app's HTTP route table. */\nexport class RouteListCommand extends AppCommand {\n static override paths = [['route', 'list']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'List the HTTP routes of the Vela app.',\n details:\n 'Framework-composed controller routes (method, full path, controller#handler) plus ' +\n 'everything else mounted on the router (CRUD/contributed routes, doc UIs) labeled (mounted).',\n examples: [\n ['List routes', 'vela route list'],\n ['As JSON', 'vela route list --json'],\n ],\n });\n\n protected async run(app: VelaApplication): Promise<number> {\n const rows = collectRoutes(app);\n if (rows === null) {\n this.print('This app builds no HTTP routes — nothing to list.');\n return 0;\n }\n if (this.json) {\n this.print(JSON.stringify(rows, null, 2));\n return 0;\n }\n for (const line of renderTable(\n ['METHOD', 'PATH', 'HANDLER'],\n rows.map((r) => [r.method, r.path, r.handler]),\n )) {\n this.print(line);\n }\n return 0;\n }\n}\n\n/** `vela module graph` — the loaded module graph. */\nexport class ModuleGraphCommand extends AppCommand {\n static override paths = [['module', 'graph']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'Print the module graph of the Vela app.',\n details:\n 'Module instances with their imports (indented tree), global/lazy flags, and provider ' +\n 'counts. --json emits the raw descriptions (providers, exports, imports per module).',\n examples: [\n ['Print the graph', 'vela module graph'],\n ['As JSON', 'vela module graph --json'],\n ],\n });\n\n protected async run(app: VelaApplication): Promise<number> {\n const modules = collectModules(app);\n if (this.json) {\n this.print(JSON.stringify(modules, null, 2));\n return 0;\n }\n for (const line of renderModuleTree(modules)) this.print(line);\n return 0;\n }\n}\n\n/** `vela entrypoint list` — declared entrypoint kinds and their entries. */\nexport class EntrypointListCommand extends AppCommand {\n static override paths = [['entrypoint', 'list']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'List entrypoint kinds and entries (websocket, queue, cron, …).',\n details:\n 'Every declared kind — including kinds with zero entries — with the contributing ' +\n 'class (and method for method-level kinds) and its metadata.',\n examples: [['List entrypoints', 'vela entrypoint list']],\n });\n\n protected async run(app: VelaApplication): Promise<number> {\n const rows = collectEntrypoints(app);\n if (this.json) {\n this.print(JSON.stringify(rows, null, 2));\n return 0;\n }\n for (const line of renderTable(\n ['KIND', 'TARGET', 'META'],\n rows.map((r) => [r.kind, r.target, r.meta]),\n )) {\n this.print(line);\n }\n return 0;\n }\n}\n\n/** `vela openapi dump` — emit the OpenAPI document. */\nexport class OpenApiDumpCommand extends Command {\n static override paths = [['openapi', 'dump']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'Emit the OpenAPI document for the Vela app.',\n details:\n 'Requires `rootModule` in vela.config (createOpenApiDocument works from the module ' +\n \"class). The app's global prefix is applied automatically; --global-prefix overrides.\",\n examples: [\n ['Print to stdout', 'vela openapi dump'],\n ['Write to a file', 'vela openapi dump --out openapi.json'],\n ],\n });\n\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n out = Option.String('--out', {\n description: 'Write the document to this file instead of stdout.',\n });\n title = Option.String('--title', { description: 'info.title override.' });\n apiVersion = Option.String('--api-version', { description: 'info.version override.' });\n globalPrefix = Option.String('--global-prefix', {\n description: \"Path prefix override (defaults to the app's global prefix).\",\n });\n\n async execute(): Promise<number> {\n const velaConfig = await loadConfig(process.cwd(), this.config);\n if (!velaConfig.rootModule) {\n this.context.stderr.write(\n 'openapi dump needs the root module. Add it to your vela.config:\\n\\n' +\n ' export default defineVelaConfig({\\n' +\n ' rootModule: AppModule,\\n' +\n ' async createApp() { ... },\\n' +\n ' });\\n',\n );\n return 1;\n }\n\n const app = await velaConfig.createApp();\n try {\n const info: Record<string, string> = {};\n if (this.title) info.title = this.title;\n if (this.apiVersion) info.version = this.apiVersion;\n\n const document = createOpenApiDocument(velaConfig.rootModule, {\n globalPrefix: this.globalPrefix ?? app.getGlobalPrefix(),\n ...(Object.keys(info).length > 0 ? { info } : {}),\n });\n\n const text = JSON.stringify(document, null, 2);\n if (this.out) {\n await writeFile(this.out, `${text}\\n`, 'utf8');\n this.context.stdout.write(`Wrote ${this.out}\\n`);\n } else {\n this.context.stdout.write(`${text}\\n`);\n }\n return 0;\n } finally {\n const dispose = (app as { dispose?: () => Promise<void> }).dispose;\n if (typeof dispose === 'function') {\n try {\n await dispose.call(app);\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed: ${String(error)}\\n`);\n }\n }\n }\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createOpenApiDocument } from '@velajs/vela';\nimport type { Type, VelaApplication } from '@velajs/vela';\nimport { Command, Option } from 'clipanion';\nimport { z } from 'zod';\nimport { loadConfig } from '../config.js';\nimport {\n collectEntrypoints,\n collectModules,\n collectRoutes,\n renderModuleTree,\n} from '../introspect.js';\n\nconst OPENAPI_URI = 'vela://openapi';\n\n/** A single JSON text block — the shape every tool/resource result uses. */\nfunction jsonText(data: unknown): { content: { type: 'text'; text: string }[] } {\n return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };\n}\n\n/** An MCP tool error result (JSON-RPC stays 2.0; the failure is in-band). */\nfunction toolError(message: string): { isError: true; content: { type: 'text'; text: string }[] } {\n return { isError: true, content: [{ type: 'text', text: message }] };\n}\n\n/** Name + version for the MCP server handshake, read from the CLI's own package.json. */\nasync function readCliIdentity(): Promise<{ name: string; version: string }> {\n const here = dirname(fileURLToPath(import.meta.url));\n // tsdown bundles this module into dist/index.js; source-mode tests load it\n // from src/commands/mcp.command.ts. Support both locations without relying\n // on a fixed output depth.\n for (const pkgPath of [\n join(here, '..', 'package.json'),\n join(here, '..', '..', 'package.json'),\n ]) {\n try {\n const pkg = JSON.parse(await readFile(pkgPath, 'utf8')) as {\n name?: string;\n version?: string;\n };\n return { name: pkg.name ?? '@velajs/cli', version: pkg.version ?? '0.0.0' };\n } catch (error) {\n if ((error as { code?: string }).code !== 'ENOENT') throw error;\n }\n }\n return { name: '@velajs/cli', version: '0.0.0' };\n}\n\n/**\n * String-label lookup for a DI token across the module graph. Reads only the\n * serializable descriptions (`collectModules`) — never resolves the token or\n * constructs anything. Reports which modules provide/export it and their scope\n * flags, plus whether the string names a module itself.\n */\nfunction describeToken(app: VelaApplication, token: string): unknown {\n const modules = collectModules(app);\n const providedBy = modules\n .filter((m) => m.providers.includes(token))\n .map((m) => ({\n moduleId: m.moduleId,\n isGlobal: m.isGlobal,\n lazy: m.lazy,\n exported: m.exports.includes(token),\n }));\n const matchesModule = modules.find((m) => m.moduleId === token);\n return {\n token,\n found: providedBy.length > 0 || matchesModule !== undefined,\n providedBy,\n module: matchesModule\n ? {\n moduleId: matchesModule.moduleId,\n isGlobal: matchesModule.isGlobal,\n lazy: matchesModule.lazy,\n }\n : null,\n };\n}\n\n/**\n * `vela mcp serve` — an MCP stdio server exposing the same READ-ONLY\n * introspection as the `route`/`module`/`entrypoint`/`openapi` commands, so an\n * AI agent can query a Vela app's shape over the Model Context Protocol.\n *\n * Deliberately does NOT extend `AppCommand`: that base disposes the app in its\n * `finally` the moment `run()` returns, but an MCP server must stay alive until\n * the transport closes. stdout is reserved for JSON-RPC framing; every human\n * message goes to stderr.\n */\nexport class McpServeCommand extends Command {\n static override paths = [['mcp', 'serve']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'Serve Vela introspection as MCP tools over stdio (for AI agents).',\n details:\n 'Builds the app from vela.config and runs a Model Context Protocol stdio server. Exposes ' +\n 'read-only tools (route_list, module_graph, entrypoint_list, openapi_dump, token_describe) ' +\n 'and — when the config declares a rootModule — a `vela://openapi` resource. stdout carries ' +\n 'only JSON-RPC; all logging goes to stderr. The server runs until the client disconnects.',\n examples: [\n ['Serve over stdio', 'vela mcp serve'],\n ['Use a specific config', 'vela mcp serve --config ./config/vela.config.js'],\n ],\n });\n\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n\n async execute(): Promise<number> {\n const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');\n const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');\n\n const log = (message: string): void => {\n this.context.stderr.write(`${message}\\n`);\n };\n\n const velaConfig = await loadConfig(process.cwd(), this.config);\n const app = await velaConfig.createApp();\n const rootModule: Type | undefined = velaConfig.rootModule;\n\n try {\n const identity = await readCliIdentity();\n const server = new McpServer(identity);\n\n server.registerTool(\n 'route_list',\n {\n description:\n \"The app's HTTP route table: framework-composed controller routes (method, full \" +\n 'path, Controller#handler) plus everything else mounted on the router, labeled ' +\n '(mounted). Empty when the app builds no HTTP routes.',\n inputSchema: {},\n },\n () => jsonText(collectRoutes(app) ?? []),\n );\n\n server.registerTool(\n 'module_graph',\n {\n description:\n 'The loaded module graph as serializable descriptions (providers, exports, imports, ' +\n 'global/lazy flags). Pass tree=true to also get the rendered import tree lines.',\n inputSchema: { tree: z.boolean().optional() },\n },\n ({ tree }) => {\n const modules = collectModules(app);\n return jsonText(tree ? { modules, tree: renderModuleTree(modules) } : modules);\n },\n );\n\n server.registerTool(\n 'entrypoint_list',\n {\n description:\n 'Every declared entrypoint kind (websocket, queue, cron, …) with its entries and ' +\n 'metadata — including kinds with zero entries. Lazy modules stay unmaterialized.',\n inputSchema: {},\n },\n () => jsonText(collectEntrypoints(app)),\n );\n\n server.registerTool(\n 'openapi_dump',\n {\n description:\n 'The OpenAPI 3.1 document for the app. Requires a rootModule in vela.config. ' +\n 'globalPrefix/title/apiVersion override the defaults (the app global prefix and ' +\n 'the module-derived info).',\n inputSchema: {\n globalPrefix: z.string().optional(),\n title: z.string().optional(),\n apiVersion: z.string().optional(),\n },\n },\n ({ globalPrefix, title, apiVersion }) => {\n if (!rootModule) {\n return toolError(\n 'openapi_dump needs the root module. Add `rootModule: AppModule` to your vela.config.',\n );\n }\n const info: Record<string, string> = {};\n if (title) info.title = title;\n if (apiVersion) info.version = apiVersion;\n const document = createOpenApiDocument(rootModule, {\n globalPrefix: globalPrefix ?? app.getGlobalPrefix(),\n ...(Object.keys(info).length > 0 ? { info } : {}),\n });\n return jsonText(document);\n },\n );\n\n server.registerTool(\n 'token_describe',\n {\n description:\n 'Look a DI token STRING LABEL up across the module graph: which modules provide/export ' +\n 'it and their scope flags, plus whether the string names a module. Read-only string ' +\n 'match — does not resolve or construct the token.',\n inputSchema: { token: z.string() },\n },\n ({ token }) => jsonText(describeToken(app, token)),\n );\n\n if (rootModule) {\n server.registerResource(\n 'openapi',\n OPENAPI_URI,\n { description: 'The OpenAPI 3.1 document for the app.', mimeType: 'application/json' },\n () => ({\n contents: [\n {\n uri: OPENAPI_URI,\n mimeType: 'application/json',\n text: JSON.stringify(\n createOpenApiDocument(rootModule, { globalPrefix: app.getGlobalPrefix() }),\n null,\n 2,\n ),\n },\n ],\n }),\n );\n }\n\n const transport = new StdioServerTransport();\n const closed = new Promise<void>((resolvePromise) => {\n transport.onclose = resolvePromise;\n });\n await server.connect(transport);\n log(\n `vela mcp serve — ready (5 tools${rootModule ? ' + vela://openapi resource' : ''}). ` +\n 'Awaiting client on stdio; stdout is JSON-RPC only.',\n );\n\n // Keep the process alive until the client disconnects; only then dispose.\n await closed;\n return 0;\n } finally {\n const dispose = (app as { dispose?: () => Promise<void> }).dispose;\n if (typeof dispose === 'function') {\n try {\n await dispose.call(app);\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed: ${String(error)}\\n`);\n }\n }\n }\n }\n}\n","import { runSeeders } from '@velajs/vela/seeder';\nimport { Command, Option } from 'clipanion';\nimport { loadConfig } from '../config.js';\nimport { formatSeedResults } from '../format.js';\n\n/** `vela db seed` — build the app from vela.config and run its seeders. */\nexport class SeedCommand extends Command {\n static override paths = [['db', 'seed']];\n static override usage = Command.Usage({\n category: 'Database',\n description: 'Run database seeders for the Vela app.',\n details:\n 'Loads vela.config.{js,mjs,ts}, builds the app, and runs all @Seeder() classes in order.',\n examples: [\n ['Run all seeders', 'vela db seed'],\n ['Use a specific config', 'vela db seed --config ./config/vela.config.js'],\n ],\n });\n\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n continueOnError = Option.Boolean('--continue-on-error', false, {\n description: 'Run all seeders even if one fails.',\n });\n\n async execute(): Promise<number> {\n const { createApp } = await loadConfig(process.cwd(), this.config);\n const app = await createApp();\n this.context.stdout.write('Running seeders…\\n');\n\n const results = await runSeeders(app, { stopOnError: !this.continueOnError });\n const code = formatSeedResults(results, (message) => this.context.stdout.write(`${message}\\n`));\n\n // Best-effort teardown (VelaApplication.dispose exists on recent versions).\n // Must not clobber the computed exit code if a shutdown hook throws.\n const dispose = (app as { dispose?: () => Promise<void> }).dispose;\n if (typeof dispose === 'function') {\n try {\n await dispose.call(app);\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed after seeding: ${String(error)}\\n`);\n }\n }\n\n return code;\n }\n}\n","#!/usr/bin/env node\nimport { Builtins, Cli } from 'clipanion';\nimport {\n EntrypointListCommand,\n ModuleGraphCommand,\n OpenApiDumpCommand,\n RouteListCommand,\n} from './commands/introspect.commands.js';\nimport { McpServeCommand } from './commands/mcp.command.js';\nimport { SeedCommand } from './commands/seed.command.js';\n\nconst cli = new Cli({\n binaryName: 'vela',\n binaryLabel: 'Vela CLI',\n binaryVersion: '0.2.0',\n});\n\ncli.register(Builtins.HelpCommand);\ncli.register(Builtins.VersionCommand);\ncli.register(SeedCommand);\ncli.register(RouteListCommand);\ncli.register(ModuleGraphCommand);\ncli.register(EntrypointListCommand);\ncli.register(OpenApiDumpCommand);\ncli.register(McpServeCommand);\n\nvoid cli.runExit(process.argv.slice(2));\n\nexport { SeedCommand } from './commands/seed.command.js';\nexport {\n EntrypointListCommand,\n ModuleGraphCommand,\n OpenApiDumpCommand,\n RouteListCommand,\n} from './commands/introspect.commands.js';\nexport { McpServeCommand } from './commands/mcp.command.js';\nexport {\n collectRoutes,\n collectModules,\n collectEntrypoints,\n renderModuleTree,\n} from './introspect.js';\nexport type { RouteRow, EntrypointRow } from './introspect.js';\nexport { renderTable } from './format.js';\nexport { loadConfig, defineVelaConfig } from './config.js';\nexport type { VelaConfig } from './config.js';\nexport { formatSeedResults } from './format.js';\n"],"mappings":";;;;;;;;;;;;;;AAMA,SAAgB,kBACd,SACA,OAAkC,MAAM,QAAQ,IAAI,CAAC,GAC7C;CACR,IAAI,QAAQ,WAAW,GAAG;EACxB,IAAI,mBAAmB;EACvB,OAAO;CACT;CAEA,IAAI,SAAS;CACb,KAAK,MAAM,UAAU,SACnB,IAAI,OAAO,IACT,IAAI,OAAO,OAAO,MAAM;MACnB;EACL;EACA,IAAI,OAAO,OAAO,OAAO,OAAO,QAAQ,KAAK,aAAa,OAAO,KAAK,MAAM,IAAI;CAClF;CAGF,MAAM,QAAQ,QAAQ;CACtB,IAAI,KAAK,QAAQ,OAAO,GAAG,MAAM,2BAA2B;CAC5D,OAAO,SAAS,IAAI,IAAI;AAC1B;AAEA,SAAS,aAAa,OAAwB;CAC5C,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;;AAGA,SAAgB,YAAY,SAAmB,MAA4B;CACzE,MAAM,SAAS,QAAQ,KAAK,GAAG,MAAM,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,KAAK,OAAO,EAAE,MAAM,GAAA,CAAI,MAAM,CAAC,CAAC;CAChG,MAAM,QAAQ,UACZ,MACG,KAAK,GAAG,OAAO,KAAK,GAAA,CAAI,OAAO,OAAO,EAAG,CAAC,CAAC,CAC3C,KAAK,IAAI,CAAC,CACV,QAAQ;CACb,OAAO;EAAC,KAAK,OAAO;EAAG,KAAK,OAAO,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC;EAAG,GAAG,KAAK,IAAI,IAAI;CAAC;AAClF;;;;;;;;ACxBA,SAAgB,cAAc,KAAyC;CACrE,IAAI;CACJ,IAAI;EACF,YAAY,IAAI,eAAe;CACjC,QAAQ;EACN,OAAO;CACT;CAEA,MAAM,OAAmB,UAAU,KAAK,OAAO;EAC7C,QAAQ,EAAE;EACV,MAAM,EAAE;EACR,SAAS,GAAG,EAAE,WAAW,GAAG,EAAE;EAC9B,QAAQ;CACV,EAAE;CAEF,MAAM,UAAU,IAAI,IAAI,UAAU,KAAK,MAAM,GAAG,EAAE,OAAO,GAAG,EAAE,MAAM,CAAC;CACrE,KAAK,MAAM,KAAK,WAGd,IAAI,EAAE,WAAW,QAAQ,QAAQ,IAAI,OAAO,EAAE,MAAM;CAGtD,MAAM,8BAAc,IAAI,IAAY;CACpC,KAAK,MAAM,aAAa,IAAI,WAAW,CAAC,CAAC,QAAQ;EAG/C,IAAI,UAAU,WAAW,OAAO;EAChC,MAAM,MAAM,GAAG,UAAU,OAAO,GAAG,UAAU;EAC7C,IAAI,QAAQ,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,GAAG;EAC9C,YAAY,IAAI,GAAG;EACnB,KAAK,KAAK;GACR,QAAQ,UAAU;GAClB,MAAM,UAAU;GAChB,SAAS;GACT,QAAQ;EACV,CAAC;CACH;CAEA,OAAO,KAAK,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,KAAK,EAAE,OAAO,cAAc,EAAE,MAAM,CAAC;AAC7F;;AAGA,SAAgB,eAAe,KAA2C;CACxE,OAAO,IAAI,aAAa,CAAC,CAAC,sBAAsB;AAClD;AAEA,SAAgB,iBAAiB,SAAwC;CACvE,MAAM,OAAO,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;CACxD,MAAM,WAAW,IAAI,IAAI,QAAQ,SAAS,MAAM,EAAE,OAAO,CAAC;CAC1D,MAAM,QAAQ,QAAQ,QAAQ,MAAM,CAAC,SAAS,IAAI,EAAE,QAAQ,CAAC;CAE7D,MAAM,QAAkB,CAAC;CACzB,MAAM,UAAU,IAAY,OAAe,UAA6B;EACtE,MAAM,MAAM,KAAK,IAAI,EAAE;EACvB,MAAM,QAAQ,MACV,CAAC,IAAI,WAAW,WAAW,MAAM,IAAI,OAAO,SAAS,IAAI,CAAC,CAAC,OAAO,OAAO,IACzE,CAAC;EACL,MAAM,SAAS,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK,IAAI,EAAE,KAAK;EAC7D,MAAM,YAAY,MACd,MAAM,IAAI,UAAU,OAAO,WAAW,IAAI,UAAU,WAAW,IAAI,KAAK,QACxE;EACJ,MAAM,KAAK,GAAG,KAAK,OAAO,KAAK,IAAI,KAAK,SAAS,WAAW;EAC5D,IAAI,CAAC,OAAO,MAAM,IAAI,EAAE,GAAG;EAC3B,MAAM,YAAY,IAAI,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE;EACvC,KAAK,MAAM,SAAS,IAAI,SAAS,OAAO,OAAO,QAAQ,GAAG,SAAS;CACrE;CAEA,KAAK,MAAM,QAAQ,OAAO,OAAO,KAAK,UAAU,mBAAG,IAAI,IAAI,CAAC;CAC5D,OAAO;AACT;AASA,SAAS,SAAS,MAAuB;CACvC,IAAI;EACF,OACE,KAAK,UAAU,OAAO,MAAM,UAC1B,OAAO,UAAU,aACb,eACA,OAAO,UAAU,YACf,UAAU,QACV,MAAM,gBAAgB,UACtB,CAAC,MAAM,QAAQ,KAAK,IACpB,IAAK,MAAiB,YAAY,KAAK,KACvC,KACR,KAAK;CAET,QAAQ;EACN,OAAO;CACT;AACF;;;;;;AAOA,SAAgB,mBAAmB,KAAuC;CACxE,MAAM,OAAwB,CAAC;CAC/B,MAAM,WAAW,mBAAmB,CAAC,CAAC,KAAK,MAAwB,EAAE,IAAI;CACzE,MAAM,YAAY,IAAI,YAAY,MAAM;CACxC,MAAM,QAAQ,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC;CAEtD,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,IAAI,YAAY,OAAO,IAAI;EAC3C,IAAI,QAAQ,WAAW,GAAG;GACxB,KAAK,KAAK;IAAE;IAAM,QAAQ;IAAoB,MAAM;GAAG,CAAC;GACxD;EACF;EACA,KAAK,MAAM,MAAM,SAAS;GACxB,MAAM,SAAS,GAAG,eAAe,KAAA,IAAY,IAAI,OAAO,GAAG,UAAU,MAAM;GAC3E,KAAK,KAAK;IAAE;IAAM,QAAQ,GAAG,cAAc,GAAG,KAAK,IAAI;IAAU,MAAM,SAAS,GAAG,IAAI;GAAE,CAAC;EAC5F;CACF;CACA,OAAO;AACT;;;;AC7HA,IAAe,aAAf,cAAkC,QAAQ;CACxC,SAAS,OAAO,OAAO,YAAY,EAAE,aAAa,gCAAgC,CAAC;CACnF,OAAO,OAAO,QAAQ,UAAU,OAAO,EAAE,aAAa,8BAA8B,CAAC;CAIrF,MAAM,UAA2B;EAE/B,MAAM,MAAM,OAAM,MADO,WAAW,QAAQ,IAAI,GAAG,KAAK,MAAM,EAAA,CACjC,UAAU;EACvC,IAAI;GACF,OAAO,MAAM,KAAK,IAAI,GAAG;EAC3B,UAAU;GACR,MAAM,UAAW,IAA0C;GAC3D,IAAI,OAAO,YAAY,YACrB,IAAI;IACF,MAAM,QAAQ,KAAK,GAAG;GACxB,SAAS,OAAO;IACd,KAAK,QAAQ,OAAO,MAAM,6BAA6B,OAAO,KAAK,EAAE,GAAG;GAC1E;EAEJ;CACF;CAEA,MAAgB,MAAoB;EAClC,KAAK,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG;CACvC;AACF;;AAGA,IAAa,mBAAb,cAAsC,WAAW;CAC/C,OAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC;CAC1C,OAAgB,QAAQ,QAAQ,MAAM;EACpC,UAAU;EACV,aAAa;EACb,SACE;EAEF,UAAU,CACR,CAAC,eAAe,iBAAiB,GACjC,CAAC,WAAW,wBAAwB,CACtC;CACF,CAAC;CAED,MAAgB,IAAI,KAAuC;EACzD,MAAM,OAAO,cAAc,GAAG;EAC9B,IAAI,SAAS,MAAM;GACjB,KAAK,MAAM,mDAAmD;GAC9D,OAAO;EACT;EACA,IAAI,KAAK,MAAM;GACb,KAAK,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;GACxC,OAAO;EACT;EACA,KAAK,MAAM,QAAQ,YACjB;GAAC;GAAU;GAAQ;EAAS,GAC5B,KAAK,KAAK,MAAM;GAAC,EAAE;GAAQ,EAAE;GAAM,EAAE;EAAO,CAAC,CAC/C,GACE,KAAK,MAAM,IAAI;EAEjB,OAAO;CACT;AACF;;AAGA,IAAa,qBAAb,cAAwC,WAAW;CACjD,OAAgB,QAAQ,CAAC,CAAC,UAAU,OAAO,CAAC;CAC5C,OAAgB,QAAQ,QAAQ,MAAM;EACpC,UAAU;EACV,aAAa;EACb,SACE;EAEF,UAAU,CACR,CAAC,mBAAmB,mBAAmB,GACvC,CAAC,WAAW,0BAA0B,CACxC;CACF,CAAC;CAED,MAAgB,IAAI,KAAuC;EACzD,MAAM,UAAU,eAAe,GAAG;EAClC,IAAI,KAAK,MAAM;GACb,KAAK,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;GAC3C,OAAO;EACT;EACA,KAAK,MAAM,QAAQ,iBAAiB,OAAO,GAAG,KAAK,MAAM,IAAI;EAC7D,OAAO;CACT;AACF;;AAGA,IAAa,wBAAb,cAA2C,WAAW;CACpD,OAAgB,QAAQ,CAAC,CAAC,cAAc,MAAM,CAAC;CAC/C,OAAgB,QAAQ,QAAQ,MAAM;EACpC,UAAU;EACV,aAAa;EACb,SACE;EAEF,UAAU,CAAC,CAAC,oBAAoB,sBAAsB,CAAC;CACzD,CAAC;CAED,MAAgB,IAAI,KAAuC;EACzD,MAAM,OAAO,mBAAmB,GAAG;EACnC,IAAI,KAAK,MAAM;GACb,KAAK,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;GACxC,OAAO;EACT;EACA,KAAK,MAAM,QAAQ,YACjB;GAAC;GAAQ;GAAU;EAAM,GACzB,KAAK,KAAK,MAAM;GAAC,EAAE;GAAM,EAAE;GAAQ,EAAE;EAAI,CAAC,CAC5C,GACE,KAAK,MAAM,IAAI;EAEjB,OAAO;CACT;AACF;;AAGA,IAAa,qBAAb,cAAwC,QAAQ;CAC9C,OAAgB,QAAQ,CAAC,CAAC,WAAW,MAAM,CAAC;CAC5C,OAAgB,QAAQ,QAAQ,MAAM;EACpC,UAAU;EACV,aAAa;EACb,SACE;EAEF,UAAU,CACR,CAAC,mBAAmB,mBAAmB,GACvC,CAAC,mBAAmB,sCAAsC,CAC5D;CACF,CAAC;CAED,SAAS,OAAO,OAAO,YAAY,EAAE,aAAa,gCAAgC,CAAC;CACnF,MAAM,OAAO,OAAO,SAAS,EAC3B,aAAa,qDACf,CAAC;CACD,QAAQ,OAAO,OAAO,WAAW,EAAE,aAAa,uBAAuB,CAAC;CACxE,aAAa,OAAO,OAAO,iBAAiB,EAAE,aAAa,yBAAyB,CAAC;CACrF,eAAe,OAAO,OAAO,mBAAmB,EAC9C,aAAa,8DACf,CAAC;CAED,MAAM,UAA2B;EAC/B,MAAM,aAAa,MAAM,WAAW,QAAQ,IAAI,GAAG,KAAK,MAAM;EAC9D,IAAI,CAAC,WAAW,YAAY;GAC1B,KAAK,QAAQ,OAAO,MAClB,6KAKF;GACA,OAAO;EACT;EAEA,MAAM,MAAM,MAAM,WAAW,UAAU;EACvC,IAAI;GACF,MAAM,OAA+B,CAAC;GACtC,IAAI,KAAK,OAAO,KAAK,QAAQ,KAAK;GAClC,IAAI,KAAK,YAAY,KAAK,UAAU,KAAK;GAEzC,MAAM,WAAW,sBAAsB,WAAW,YAAY;IAC5D,cAAc,KAAK,gBAAgB,IAAI,gBAAgB;IACvD,GAAI,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC;GACjD,CAAC;GAED,MAAM,OAAO,KAAK,UAAU,UAAU,MAAM,CAAC;GAC7C,IAAI,KAAK,KAAK;IACZ,MAAM,UAAU,KAAK,KAAK,GAAG,KAAK,KAAK,MAAM;IAC7C,KAAK,QAAQ,OAAO,MAAM,SAAS,KAAK,IAAI,GAAG;GACjD,OACE,KAAK,QAAQ,OAAO,MAAM,GAAG,KAAK,GAAG;GAEvC,OAAO;EACT,UAAU;GACR,MAAM,UAAW,IAA0C;GAC3D,IAAI,OAAO,YAAY,YACrB,IAAI;IACF,MAAM,QAAQ,KAAK,GAAG;GACxB,SAAS,OAAO;IACd,KAAK,QAAQ,OAAO,MAAM,6BAA6B,OAAO,KAAK,EAAE,GAAG;GAC1E;EAEJ;CACF;AACF;;;ACxLA,MAAM,cAAc;;AAGpB,SAAS,SAAS,MAA8D;CAC9E,OAAO,EAAE,SAAS,CAAC;EAAE,MAAM;EAAQ,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC;CAAE,CAAC,EAAE;AAC5E;;AAGA,SAAS,UAAU,SAA+E;CAChG,OAAO;EAAE,SAAS;EAAM,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM;EAAQ,CAAC;CAAE;AACrE;;AAGA,eAAe,kBAA8D;CAC3E,MAAM,OAAO,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;CAInD,KAAK,MAAM,WAAW,CACpB,KAAK,MAAM,MAAM,cAAc,GAC/B,KAAK,MAAM,MAAM,MAAM,cAAc,CACvC,GACE,IAAI;EACF,MAAM,MAAM,KAAK,MAAM,MAAM,SAAS,SAAS,MAAM,CAAC;EAItD,OAAO;GAAE,MAAM,IAAI,QAAQ;GAAe,SAAS,IAAI,WAAW;EAAQ;CAC5E,SAAS,OAAO;EACd,IAAK,MAA4B,SAAS,UAAU,MAAM;CAC5D;CAEF,OAAO;EAAE,MAAM;EAAe,SAAS;CAAQ;AACjD;;;;;;;AAQA,SAASA,gBAAc,KAAsB,OAAwB;CACnE,MAAM,UAAU,eAAe,GAAG;CAClC,MAAM,aAAa,QAChB,QAAQ,MAAM,EAAE,UAAU,SAAS,KAAK,CAAC,CAAC,CAC1C,KAAK,OAAO;EACX,UAAU,EAAE;EACZ,UAAU,EAAE;EACZ,MAAM,EAAE;EACR,UAAU,EAAE,QAAQ,SAAS,KAAK;CACpC,EAAE;CACJ,MAAM,gBAAgB,QAAQ,MAAM,MAAM,EAAE,aAAa,KAAK;CAC9D,OAAO;EACL;EACA,OAAO,WAAW,SAAS,KAAK,kBAAkB,KAAA;EAClD;EACA,QAAQ,gBACJ;GACE,UAAU,cAAc;GACxB,UAAU,cAAc;GACxB,MAAM,cAAc;EACtB,IACA;CACN;AACF;;;;;;;;;;;AAYA,IAAa,kBAAb,cAAqC,QAAQ;CAC3C,OAAgB,QAAQ,CAAC,CAAC,OAAO,OAAO,CAAC;CACzC,OAAgB,QAAQ,QAAQ,MAAM;EACpC,UAAU;EACV,aAAa;EACb,SACE;EAIF,UAAU,CACR,CAAC,oBAAoB,gBAAgB,GACrC,CAAC,yBAAyB,iDAAiD,CAC7E;CACF,CAAC;CAED,SAAS,OAAO,OAAO,YAAY,EAAE,aAAa,gCAAgC,CAAC;CAEnF,MAAM,UAA2B;EAC/B,MAAM,EAAE,cAAc,MAAM,OAAO;EACnC,MAAM,EAAE,yBAAyB,MAAM,OAAO;EAE9C,MAAM,OAAO,YAA0B;GACrC,KAAK,QAAQ,OAAO,MAAM,GAAG,QAAQ,GAAG;EAC1C;EAEA,MAAM,aAAa,MAAM,WAAW,QAAQ,IAAI,GAAG,KAAK,MAAM;EAC9D,MAAM,MAAM,MAAM,WAAW,UAAU;EACvC,MAAM,aAA+B,WAAW;EAEhD,IAAI;GAEF,MAAM,SAAS,IAAI,UAAU,MADN,gBAAgB,CACF;GAErC,OAAO,aACL,cACA;IACE,aACE;IAGF,aAAa,CAAC;GAChB,SACM,SAAS,cAAc,GAAG,KAAK,CAAC,CAAC,CACzC;GAEA,OAAO,aACL,gBACA;IACE,aACE;IAEF,aAAa,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,SAAS,EAAE;GAC9C,IACC,EAAE,WAAW;IACZ,MAAM,UAAU,eAAe,GAAG;IAClC,OAAO,SAAS,OAAO;KAAE;KAAS,MAAM,iBAAiB,OAAO;IAAE,IAAI,OAAO;GAC/E,CACF;GAEA,OAAO,aACL,mBACA;IACE,aACE;IAEF,aAAa,CAAC;GAChB,SACM,SAAS,mBAAmB,GAAG,CAAC,CACxC;GAEA,OAAO,aACL,gBACA;IACE,aACE;IAGF,aAAa;KACX,cAAc,EAAE,OAAO,CAAC,CAAC,SAAS;KAClC,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;KAC3B,YAAY,EAAE,OAAO,CAAC,CAAC,SAAS;IAClC;GACF,IACC,EAAE,cAAc,OAAO,iBAAiB;IACvC,IAAI,CAAC,YACH,OAAO,UACL,sFACF;IAEF,MAAM,OAA+B,CAAC;IACtC,IAAI,OAAO,KAAK,QAAQ;IACxB,IAAI,YAAY,KAAK,UAAU;IAK/B,OAAO,SAJU,sBAAsB,YAAY;KACjD,cAAc,gBAAgB,IAAI,gBAAgB;KAClD,GAAI,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,IAAI,EAAE,KAAK,IAAI,CAAC;IACjD,CACuB,CAAC;GAC1B,CACF;GAEA,OAAO,aACL,kBACA;IACE,aACE;IAGF,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE;GACnC,IACC,EAAE,YAAY,SAASA,gBAAc,KAAK,KAAK,CAAC,CACnD;GAEA,IAAI,YACF,OAAO,iBACL,WACA,aACA;IAAE,aAAa;IAAyC,UAAU;GAAmB,UAC9E,EACL,UAAU,CACR;IACE,KAAK;IACL,UAAU;IACV,MAAM,KAAK,UACT,sBAAsB,YAAY,EAAE,cAAc,IAAI,gBAAgB,EAAE,CAAC,GACzE,MACA,CACF;GACF,CACF,EACF,EACF;GAGF,MAAM,YAAY,IAAI,qBAAqB;GAC3C,MAAM,SAAS,IAAI,SAAe,mBAAmB;IACnD,UAAU,UAAU;GACtB,CAAC;GACD,MAAM,OAAO,QAAQ,SAAS;GAC9B,IACE,kCAAkC,aAAa,+BAA+B,GAAG,sDAEnF;GAGA,MAAM;GACN,OAAO;EACT,UAAU;GACR,MAAM,UAAW,IAA0C;GAC3D,IAAI,OAAO,YAAY,YACrB,IAAI;IACF,MAAM,QAAQ,KAAK,GAAG;GACxB,SAAS,OAAO;IACd,KAAK,QAAQ,OAAO,MAAM,6BAA6B,OAAO,KAAK,EAAE,GAAG;GAC1E;EAEJ;CACF;AACF;;;;ACnPA,IAAa,cAAb,cAAiC,QAAQ;CACvC,OAAgB,QAAQ,CAAC,CAAC,MAAM,MAAM,CAAC;CACvC,OAAgB,QAAQ,QAAQ,MAAM;EACpC,UAAU;EACV,aAAa;EACb,SACE;EACF,UAAU,CACR,CAAC,mBAAmB,cAAc,GAClC,CAAC,yBAAyB,+CAA+C,CAC3E;CACF,CAAC;CAED,SAAS,OAAO,OAAO,YAAY,EAAE,aAAa,gCAAgC,CAAC;CACnF,kBAAkB,OAAO,QAAQ,uBAAuB,OAAO,EAC7D,aAAa,qCACf,CAAC;CAED,MAAM,UAA2B;EAC/B,MAAM,EAAE,cAAc,MAAM,WAAW,QAAQ,IAAI,GAAG,KAAK,MAAM;EACjE,MAAM,MAAM,MAAM,UAAU;EAC5B,KAAK,QAAQ,OAAO,MAAM,oBAAoB;EAG9C,MAAM,OAAO,kBAAkB,MADT,WAAW,KAAK,EAAE,aAAa,CAAC,KAAK,gBAAgB,CAAC,IACnC,YAAY,KAAK,QAAQ,OAAO,MAAM,GAAG,QAAQ,GAAG,CAAC;EAI9F,MAAM,UAAW,IAA0C;EAC3D,IAAI,OAAO,YAAY,YACrB,IAAI;GACF,MAAM,QAAQ,KAAK,GAAG;EACxB,SAAS,OAAO;GACd,KAAK,QAAQ,OAAO,MAAM,2CAA2C,OAAO,KAAK,EAAE,GAAG;EACxF;EAGF,OAAO;CACT;AACF;;;AClCA,MAAM,MAAM,IAAI,IAAI;CAClB,YAAY;CACZ,aAAa;CACb,eAAe;AACjB,CAAC;AAED,IAAI,SAAS,SAAS,WAAW;AACjC,IAAI,SAAS,SAAS,cAAc;AACpC,IAAI,SAAS,WAAW;AACxB,IAAI,SAAS,gBAAgB;AAC7B,IAAI,SAAS,kBAAkB;AAC/B,IAAI,SAAS,qBAAqB;AAClC,IAAI,SAAS,kBAAkB;AAC/B,IAAI,SAAS,eAAe;AAEvB,IAAI,QAAQ,QAAQ,KAAK,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","names":["describeToken"],"sources":["../src/format.ts","../src/introspect.ts","../src/commands/introspect.commands.ts","../src/commands/mcp.command.ts","../src/commands/seed.command.ts","../src/commands/studio.command.ts","../src/commands/client.command.ts","../src/index.ts"],"sourcesContent":["import type { SeederResult } from '@velajs/vela/seeder';\n\n/**\n * Render seeder results to a logger and return a process exit code\n * (0 = all ran, 1 = at least one failed). Pure — no I/O beyond the logger.\n */\nexport function formatSeedResults(\n results: SeederResult[],\n log: (message: string) => void = (m) => console.log(m),\n): number {\n if (results.length === 0) {\n log('No seeders found.');\n return 0;\n }\n\n let failed = 0;\n for (const result of results) {\n if (result.ok) {\n log(` ✓ ${result.name}`);\n } else {\n failed++;\n log(` ✗ ${result.name}${result.error ? `: ${errorMessage(result.error)}` : ''}`);\n }\n }\n\n const total = results.length;\n log(`\\n${total - failed}/${total} seeders ran successfully.`);\n return failed > 0 ? 1 : 0;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** Aligned plain-text table. Pure; returns lines. */\nexport function renderTable(headers: string[], rows: string[][]): string[] {\n const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)));\n const line = (cells: string[]): string =>\n cells\n .map((c, i) => (c ?? '').padEnd(widths[i]!))\n .join(' ')\n .trimEnd();\n return [line(headers), line(widths.map((w) => '-'.repeat(w))), ...rows.map(line)];\n}\n","import type { VelaApplication } from '@velajs/vela';\nimport { describeToken, getEntrypointKinds } from '@velajs/vela';\nimport type { ModuleDescription, RouteDescription } from '@velajs/vela';\n\n/** One row of `vela route list`. */\nexport interface RouteRow {\n method: string;\n path: string;\n /** `Controller#handler`, or `(mounted)` for routes vela did not compose\n * itself (RouteContributor/CRUD, OpenAPI UI mounts, manual Hono routes). */\n handler: string;\n source: 'controller' | 'mounted';\n}\n\n/**\n * The app's route table: `describeRoutes()` rows (framework-composed truth)\n * plus everything else present on the Hono router, deduped and labeled\n * `(mounted)`. Returns null when the app never built HTTP routes.\n */\nexport function collectRoutes(app: VelaApplication): RouteRow[] | null {\n let described: RouteDescription[];\n try {\n described = app.describeRoutes();\n } catch {\n return null; // no HTTP routes built (slim/non-HTTP app)\n }\n\n const rows: RouteRow[] = described.map((r) => ({\n method: r.method,\n path: r.path,\n handler: `${r.controller}#${r.handler}`,\n source: 'controller',\n }));\n\n const covered = new Set(described.map((r) => `${r.method} ${r.path}`));\n for (const r of described) {\n // @Head handlers are served by Hono under GET — claim that row too so it\n // doesn't reappear as a mounted duplicate.\n if (r.method === 'HEAD') covered.add(`GET ${r.path}`);\n }\n\n const seenMounted = new Set<string>();\n for (const honoRoute of app.getHonoApp().routes) {\n // 'ALL' entries are middleware mounts (framework-internal disposal/context\n // wrappers, global + scoped middleware) — not endpoints.\n if (honoRoute.method === 'ALL') continue;\n const key = `${honoRoute.method} ${honoRoute.path}`;\n if (covered.has(key) || seenMounted.has(key)) continue;\n seenMounted.add(key);\n rows.push({\n method: honoRoute.method,\n path: honoRoute.path,\n handler: '(mounted)',\n source: 'mounted',\n });\n }\n\n return rows.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));\n}\n\n/** `vela module graph` tree lines (or raw descriptions for --json). */\nexport function collectModules(app: VelaApplication): ModuleDescription[] {\n return app.getContainer().getModuleDescriptions();\n}\n\nexport function renderModuleTree(modules: ModuleDescription[]): string[] {\n const byId = new Map(modules.map((m) => [m.moduleId, m]));\n const imported = new Set(modules.flatMap((m) => m.imports));\n const roots = modules.filter((m) => !imported.has(m.moduleId));\n\n const lines: string[] = [];\n const render = (id: string, depth: number, trail: Set<string>): void => {\n const mod = byId.get(id);\n const flags = mod\n ? [mod.isGlobal ? 'global' : null, mod.lazy ? 'lazy' : null].filter(Boolean)\n : [];\n const suffix = flags.length > 0 ? ` (${flags.join(', ')})` : '';\n const providers = mod\n ? ` — ${mod.providers.length} provider${mod.providers.length === 1 ? '' : 's'}`\n : '';\n lines.push(`${' '.repeat(depth)}${id}${suffix}${providers}`);\n if (!mod || trail.has(id)) return;\n const nextTrail = new Set(trail).add(id);\n for (const child of mod.imports) render(child, depth + 1, nextTrail);\n };\n\n for (const root of roots) render(root.moduleId, 0, new Set());\n return lines;\n}\n\n/** One row of `vela entrypoint list`. */\nexport interface EntrypointRow {\n kind: string;\n target: string;\n meta: string;\n}\n\nfunction safeMeta(meta: unknown): string {\n try {\n return (\n JSON.stringify(meta, (_key, value: unknown) =>\n typeof value === 'function'\n ? '[function]'\n : typeof value === 'object' &&\n value !== null &&\n value.constructor !== Object &&\n !Array.isArray(value)\n ? `[${(value as object).constructor.name}]`\n : value,\n ) ?? 'undefined'\n );\n } catch {\n return '[unserializable]';\n }\n}\n\n/**\n * Every DECLARED entrypoint kind (from the global kind store — includes kinds\n * with zero entries) joined with the app's entries. Metadata-only entries of\n * lazy modules list fine; nothing materializes.\n */\nexport function collectEntrypoints(app: VelaApplication): EntrypointRow[] {\n const rows: EntrypointRow[] = [];\n const declared = getEntrypointKinds().map((k: { kind: string }) => k.kind);\n const populated = app.entrypoints.kinds();\n const kinds = [...new Set([...declared, ...populated])];\n\n for (const kind of kinds) {\n const entries = app.entrypoints.ofKind(kind);\n if (entries.length === 0) {\n rows.push({ kind, target: '(no entrypoints)', meta: '' });\n continue;\n }\n for (const ep of entries) {\n const method = ep.methodName !== undefined ? `#${String(ep.methodName)}` : '';\n rows.push({ kind, target: `${describeToken(ep.token)}${method}`, meta: safeMeta(ep.meta) });\n }\n }\n return rows;\n}\n","import { writeFile } from 'node:fs/promises';\nimport { createOpenApiDocument } from '@velajs/vela';\nimport type { VelaApplication } from '@velajs/vela';\nimport { Command, Option } from 'clipanion';\nimport { loadConfig } from '../config.js';\nimport { renderTable } from '../format.js';\nimport {\n collectEntrypoints,\n collectModules,\n collectRoutes,\n renderModuleTree,\n} from '../introspect.js';\n\n/** Shared shell: load config → createApp → run → best-effort dispose. */\nabstract class AppCommand extends Command {\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n json = Option.Boolean('--json', false, { description: 'Emit machine-readable JSON.' });\n\n protected abstract run(app: VelaApplication): Promise<number>;\n\n async execute(): Promise<number> {\n const velaConfig = await loadConfig(process.cwd(), this.config);\n const app = await velaConfig.createApp();\n try {\n return await this.run(app);\n } finally {\n const dispose = (app as { dispose?: () => Promise<void> }).dispose;\n if (typeof dispose === 'function') {\n try {\n await dispose.call(app);\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed: ${String(error)}\\n`);\n }\n }\n }\n }\n\n protected print(text: string): void {\n this.context.stdout.write(`${text}\\n`);\n }\n}\n\n/** `vela route list` — the app's HTTP route table. */\nexport class RouteListCommand extends AppCommand {\n static override paths = [['route', 'list']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'List the HTTP routes of the Vela app.',\n details:\n 'Framework-composed controller routes (method, full path, controller#handler) plus ' +\n 'everything else mounted on the router (CRUD/contributed routes, doc UIs) labeled (mounted).',\n examples: [\n ['List routes', 'vela route list'],\n ['As JSON', 'vela route list --json'],\n ],\n });\n\n protected async run(app: VelaApplication): Promise<number> {\n const rows = collectRoutes(app);\n if (rows === null) {\n this.print('This app builds no HTTP routes — nothing to list.');\n return 0;\n }\n if (this.json) {\n this.print(JSON.stringify(rows, null, 2));\n return 0;\n }\n for (const line of renderTable(\n ['METHOD', 'PATH', 'HANDLER'],\n rows.map((r) => [r.method, r.path, r.handler]),\n )) {\n this.print(line);\n }\n return 0;\n }\n}\n\n/** `vela module graph` — the loaded module graph. */\nexport class ModuleGraphCommand extends AppCommand {\n static override paths = [['module', 'graph']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'Print the module graph of the Vela app.',\n details:\n 'Module instances with their imports (indented tree), global/lazy flags, and provider ' +\n 'counts. --json emits the raw descriptions (providers, exports, imports per module).',\n examples: [\n ['Print the graph', 'vela module graph'],\n ['As JSON', 'vela module graph --json'],\n ],\n });\n\n protected async run(app: VelaApplication): Promise<number> {\n const modules = collectModules(app);\n if (this.json) {\n this.print(JSON.stringify(modules, null, 2));\n return 0;\n }\n for (const line of renderModuleTree(modules)) this.print(line);\n return 0;\n }\n}\n\n/** `vela entrypoint list` — declared entrypoint kinds and their entries. */\nexport class EntrypointListCommand extends AppCommand {\n static override paths = [['entrypoint', 'list']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'List entrypoint kinds and entries (websocket, queue, cron, …).',\n details:\n 'Every declared kind — including kinds with zero entries — with the contributing ' +\n 'class (and method for method-level kinds) and its metadata.',\n examples: [['List entrypoints', 'vela entrypoint list']],\n });\n\n protected async run(app: VelaApplication): Promise<number> {\n const rows = collectEntrypoints(app);\n if (this.json) {\n this.print(JSON.stringify(rows, null, 2));\n return 0;\n }\n for (const line of renderTable(\n ['KIND', 'TARGET', 'META'],\n rows.map((r) => [r.kind, r.target, r.meta]),\n )) {\n this.print(line);\n }\n return 0;\n }\n}\n\n/** `vela openapi dump` — emit the OpenAPI document. */\nexport class OpenApiDumpCommand extends Command {\n static override paths = [['openapi', 'dump']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'Emit the OpenAPI document for the Vela app.',\n details:\n 'Requires `rootModule` in vela.config (createOpenApiDocument works from the module ' +\n \"class). The app's global prefix is applied automatically; --global-prefix overrides.\",\n examples: [\n ['Print to stdout', 'vela openapi dump'],\n ['Write to a file', 'vela openapi dump --out openapi.json'],\n ],\n });\n\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n out = Option.String('--out', {\n description: 'Write the document to this file instead of stdout.',\n });\n title = Option.String('--title', { description: 'info.title override.' });\n apiVersion = Option.String('--api-version', { description: 'info.version override.' });\n globalPrefix = Option.String('--global-prefix', {\n description: \"Path prefix override (defaults to the app's global prefix).\",\n });\n\n async execute(): Promise<number> {\n const velaConfig = await loadConfig(process.cwd(), this.config);\n if (!velaConfig.rootModule) {\n this.context.stderr.write(\n 'openapi dump needs the root module. Add it to your vela.config:\\n\\n' +\n ' export default defineVelaConfig({\\n' +\n ' rootModule: AppModule,\\n' +\n ' async createApp() { ... },\\n' +\n ' });\\n',\n );\n return 1;\n }\n\n const app = await velaConfig.createApp();\n try {\n const info: Record<string, string> = {};\n if (this.title) info.title = this.title;\n if (this.apiVersion) info.version = this.apiVersion;\n\n const document = createOpenApiDocument(velaConfig.rootModule, {\n globalPrefix: this.globalPrefix ?? app.getGlobalPrefix(),\n ...(Object.keys(info).length > 0 ? { info } : {}),\n });\n\n const text = JSON.stringify(document, null, 2);\n if (this.out) {\n await writeFile(this.out, `${text}\\n`, 'utf8');\n this.context.stdout.write(`Wrote ${this.out}\\n`);\n } else {\n this.context.stdout.write(`${text}\\n`);\n }\n return 0;\n } finally {\n const dispose = (app as { dispose?: () => Promise<void> }).dispose;\n if (typeof dispose === 'function') {\n try {\n await dispose.call(app);\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed: ${String(error)}\\n`);\n }\n }\n }\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createOpenApiDocument } from '@velajs/vela';\nimport type { Type, VelaApplication } from '@velajs/vela';\nimport { Command, Option } from 'clipanion';\nimport { z } from 'zod';\nimport { loadConfig } from '../config.js';\nimport {\n collectEntrypoints,\n collectModules,\n collectRoutes,\n renderModuleTree,\n} from '../introspect.js';\n\nconst OPENAPI_URI = 'vela://openapi';\n\n/** A single JSON text block — the shape every tool/resource result uses. */\nfunction jsonText(data: unknown): { content: { type: 'text'; text: string }[] } {\n return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };\n}\n\n/** An MCP tool error result (JSON-RPC stays 2.0; the failure is in-band). */\nfunction toolError(message: string): { isError: true; content: { type: 'text'; text: string }[] } {\n return { isError: true, content: [{ type: 'text', text: message }] };\n}\n\n/** Name + version for the MCP server handshake, read from the CLI's own package.json. */\nasync function readCliIdentity(): Promise<{ name: string; version: string }> {\n const here = dirname(fileURLToPath(import.meta.url));\n // tsdown bundles this module into dist/index.js; source-mode tests load it\n // from src/commands/mcp.command.ts. Support both locations without relying\n // on a fixed output depth.\n for (const pkgPath of [\n join(here, '..', 'package.json'),\n join(here, '..', '..', 'package.json'),\n ]) {\n try {\n const pkg = JSON.parse(await readFile(pkgPath, 'utf8')) as {\n name?: string;\n version?: string;\n };\n return { name: pkg.name ?? '@velajs/cli', version: pkg.version ?? '0.0.0' };\n } catch (error) {\n if ((error as { code?: string }).code !== 'ENOENT') throw error;\n }\n }\n return { name: '@velajs/cli', version: '0.0.0' };\n}\n\n/**\n * String-label lookup for a DI token across the module graph. Reads only the\n * serializable descriptions (`collectModules`) — never resolves the token or\n * constructs anything. Reports which modules provide/export it and their scope\n * flags, plus whether the string names a module itself.\n */\nfunction describeToken(app: VelaApplication, token: string): unknown {\n const modules = collectModules(app);\n const providedBy = modules\n .filter((m) => m.providers.includes(token))\n .map((m) => ({\n moduleId: m.moduleId,\n isGlobal: m.isGlobal,\n lazy: m.lazy,\n exported: m.exports.includes(token),\n }));\n const matchesModule = modules.find((m) => m.moduleId === token);\n return {\n token,\n found: providedBy.length > 0 || matchesModule !== undefined,\n providedBy,\n module: matchesModule\n ? {\n moduleId: matchesModule.moduleId,\n isGlobal: matchesModule.isGlobal,\n lazy: matchesModule.lazy,\n }\n : null,\n };\n}\n\n/**\n * `vela mcp serve` — an MCP stdio server exposing the same READ-ONLY\n * introspection as the `route`/`module`/`entrypoint`/`openapi` commands, so an\n * AI agent can query a Vela app's shape over the Model Context Protocol.\n *\n * Deliberately does NOT extend `AppCommand`: that base disposes the app in its\n * `finally` the moment `run()` returns, but an MCP server must stay alive until\n * the transport closes. stdout is reserved for JSON-RPC framing; every human\n * message goes to stderr.\n */\nexport class McpServeCommand extends Command {\n static override paths = [['mcp', 'serve']];\n static override usage = Command.Usage({\n category: 'Introspection',\n description: 'Serve Vela introspection as MCP tools over stdio (for AI agents).',\n details:\n 'Builds the app from vela.config and runs a Model Context Protocol stdio server. Exposes ' +\n 'read-only tools (route_list, module_graph, entrypoint_list, openapi_dump, token_describe) ' +\n 'and — when the config declares a rootModule — a `vela://openapi` resource. stdout carries ' +\n 'only JSON-RPC; all logging goes to stderr. The server runs until the client disconnects.',\n examples: [\n ['Serve over stdio', 'vela mcp serve'],\n ['Use a specific config', 'vela mcp serve --config ./config/vela.config.js'],\n ],\n });\n\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n\n async execute(): Promise<number> {\n const { McpServer } = await import('@modelcontextprotocol/sdk/server/mcp.js');\n const { StdioServerTransport } = await import('@modelcontextprotocol/sdk/server/stdio.js');\n\n const log = (message: string): void => {\n this.context.stderr.write(`${message}\\n`);\n };\n\n const velaConfig = await loadConfig(process.cwd(), this.config);\n const app = await velaConfig.createApp();\n const rootModule: Type | undefined = velaConfig.rootModule;\n\n try {\n const identity = await readCliIdentity();\n const server = new McpServer(identity);\n\n server.registerTool(\n 'route_list',\n {\n description:\n \"The app's HTTP route table: framework-composed controller routes (method, full \" +\n 'path, Controller#handler) plus everything else mounted on the router, labeled ' +\n '(mounted). Empty when the app builds no HTTP routes.',\n inputSchema: {},\n },\n () => jsonText(collectRoutes(app) ?? []),\n );\n\n server.registerTool(\n 'module_graph',\n {\n description:\n 'The loaded module graph as serializable descriptions (providers, exports, imports, ' +\n 'global/lazy flags). Pass tree=true to also get the rendered import tree lines.',\n inputSchema: { tree: z.boolean().optional() },\n },\n ({ tree }) => {\n const modules = collectModules(app);\n return jsonText(tree ? { modules, tree: renderModuleTree(modules) } : modules);\n },\n );\n\n server.registerTool(\n 'entrypoint_list',\n {\n description:\n 'Every declared entrypoint kind (websocket, queue, cron, …) with its entries and ' +\n 'metadata — including kinds with zero entries. Lazy modules stay unmaterialized.',\n inputSchema: {},\n },\n () => jsonText(collectEntrypoints(app)),\n );\n\n server.registerTool(\n 'openapi_dump',\n {\n description:\n 'The OpenAPI 3.1 document for the app. Requires a rootModule in vela.config. ' +\n 'globalPrefix/title/apiVersion override the defaults (the app global prefix and ' +\n 'the module-derived info).',\n inputSchema: {\n globalPrefix: z.string().optional(),\n title: z.string().optional(),\n apiVersion: z.string().optional(),\n },\n },\n ({ globalPrefix, title, apiVersion }) => {\n if (!rootModule) {\n return toolError(\n 'openapi_dump needs the root module. Add `rootModule: AppModule` to your vela.config.',\n );\n }\n const info: Record<string, string> = {};\n if (title) info.title = title;\n if (apiVersion) info.version = apiVersion;\n const document = createOpenApiDocument(rootModule, {\n globalPrefix: globalPrefix ?? app.getGlobalPrefix(),\n ...(Object.keys(info).length > 0 ? { info } : {}),\n });\n return jsonText(document);\n },\n );\n\n server.registerTool(\n 'token_describe',\n {\n description:\n 'Look a DI token STRING LABEL up across the module graph: which modules provide/export ' +\n 'it and their scope flags, plus whether the string names a module. Read-only string ' +\n 'match — does not resolve or construct the token.',\n inputSchema: { token: z.string() },\n },\n ({ token }) => jsonText(describeToken(app, token)),\n );\n\n if (rootModule) {\n server.registerResource(\n 'openapi',\n OPENAPI_URI,\n { description: 'The OpenAPI 3.1 document for the app.', mimeType: 'application/json' },\n () => ({\n contents: [\n {\n uri: OPENAPI_URI,\n mimeType: 'application/json',\n text: JSON.stringify(\n createOpenApiDocument(rootModule, { globalPrefix: app.getGlobalPrefix() }),\n null,\n 2,\n ),\n },\n ],\n }),\n );\n }\n\n const transport = new StdioServerTransport();\n const closed = new Promise<void>((resolvePromise) => {\n transport.onclose = resolvePromise;\n });\n await server.connect(transport);\n log(\n `vela mcp serve — ready (5 tools${rootModule ? ' + vela://openapi resource' : ''}). ` +\n 'Awaiting client on stdio; stdout is JSON-RPC only.',\n );\n\n // Keep the process alive until the client disconnects; only then dispose.\n await closed;\n return 0;\n } finally {\n const dispose = (app as { dispose?: () => Promise<void> }).dispose;\n if (typeof dispose === 'function') {\n try {\n await dispose.call(app);\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed: ${String(error)}\\n`);\n }\n }\n }\n }\n}\n","import { runSeeders } from '@velajs/vela/seeder';\nimport { Command, Option } from 'clipanion';\nimport { loadConfig } from '../config.js';\nimport { formatSeedResults } from '../format.js';\n\n/** `vela db seed` — build the app from vela.config and run its seeders. */\nexport class SeedCommand extends Command {\n static override paths = [['db', 'seed']];\n static override usage = Command.Usage({\n category: 'Database',\n description: 'Run database seeders for the Vela app.',\n details:\n 'Loads vela.config.{js,mjs,ts}, builds the app, and runs all @Seeder() classes in order.',\n examples: [\n ['Run all seeders', 'vela db seed'],\n ['Use a specific config', 'vela db seed --config ./config/vela.config.js'],\n ],\n });\n\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n continueOnError = Option.Boolean('--continue-on-error', false, {\n description: 'Run all seeders even if one fails.',\n });\n\n async execute(): Promise<number> {\n const { createApp } = await loadConfig(process.cwd(), this.config);\n const app = await createApp();\n this.context.stdout.write('Running seeders…\\n');\n\n const results = await runSeeders(app, { stopOnError: !this.continueOnError });\n const code = formatSeedResults(results, (message) => this.context.stdout.write(`${message}\\n`));\n\n // Best-effort teardown (VelaApplication.dispose exists on recent versions).\n // Must not clobber the computed exit code if a shutdown hook throws.\n const dispose = (app as { dispose?: () => Promise<void> }).dispose;\n if (typeof dispose === 'function') {\n try {\n await dispose.call(app);\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed after seeding: ${String(error)}\\n`);\n }\n }\n\n return code;\n }\n}\n","import { Command, Option } from 'clipanion';\n\n/**\n * The optional peer that does the real work. It is Node-only and heavy, so it is\n * NOT a hard dependency of the CLI — it is lazily imported here and, when it\n * isn't installed, the command prints an install hint (mirroring how\n * `mcp.command` lazily loads its optional peer).\n */\nconst HOST_PACKAGE = '@velajs/studio-host';\n\n/** The slice of `@velajs/studio-host`'s surface this command uses. */\ninterface StudioHostModule {\n startStudioServer(options: {\n workerOrigin: string;\n adminToken?: string;\n port?: number;\n adminPath?: string;\n cwd?: string;\n }): Promise<{ readonly url: string; readonly port: number; close(): Promise<void> }>;\n}\n\n/** True for a failed dynamic `import()` of a missing module (ESM or CJS code). */\nfunction isModuleNotFound(error: unknown, specifier: string): boolean {\n const code = (error as { code?: string }).code;\n if (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') {\n return true;\n }\n // Some resolvers surface only a message; match the specifier defensively.\n const message = error instanceof Error ? error.message : '';\n return message.includes(specifier);\n}\n\n/**\n * `vela studio` — start the loopback dev host that serves Vela Studio and proxies\n * the admin API to a running app.\n *\n * App-origin resolution (v1): the target app is taken from `--url <origin>`,\n * which is REQUIRED. The host proxies `{--path}/*` to that origin, injecting the\n * admin token as `Authorization: Bearer` server-side (the browser never holds\n * it). Booting the app in-process from `vela.config` (via `loadConfig`) is a\n * planned follow-up; requiring `--url` keeps v1 simple and adapter-agnostic.\n */\nexport class StudioCommand extends Command {\n static override paths = [['studio']];\n static override usage = Command.Usage({\n category: 'Studio',\n description: 'Serve Vela Studio locally and proxy the admin API to a running app.',\n details:\n 'Starts a loopback dev host (from the optional @velajs/studio-host peer) that serves the ' +\n 'prebuilt Studio SPA and proxies {--path}/* to the app at --url, injecting the admin token ' +\n 'as a Bearer server-side so the browser never receives it. The token comes from --token or ' +\n 'the VELA_STUDIO_TOKEN environment variable. Runs until interrupted (Ctrl+C).',\n examples: [\n ['Serve against a local worker', 'vela studio --url http://127.0.0.1:8787'],\n [\n 'With an explicit token + port',\n 'vela studio --url http://127.0.0.1:8787 --token $TOKEN --port 4000',\n ],\n ],\n });\n\n url = Option.String('--url', {\n description: 'Origin of the running app to proxy the admin API to (required).',\n });\n token = Option.String('--token', {\n description: 'Admin bearer token (falls back to VELA_STUDIO_TOKEN). Never sent to the browser.',\n });\n port = Option.String('--port', {\n description: 'Loopback port to bind (default: an ephemeral port).',\n });\n adminPath = Option.String('--path', {\n description: 'Server admin-mount prefix to proxy (default: /_vela/admin).',\n });\n\n async execute(): Promise<number> {\n const workerOrigin = this.url;\n if (workerOrigin === undefined || workerOrigin === '') {\n this.context.stderr.write(\n 'vela studio: --url <origin> is required — the running app to proxy the admin API to.\\n' +\n ' Example: vela studio --url http://127.0.0.1:8787\\n',\n );\n return 1;\n }\n if (!URL.canParse(workerOrigin)) {\n this.context.stderr.write(`vela studio: --url is not a valid origin: ${workerOrigin}\\n`);\n return 1;\n }\n\n let port: number | undefined;\n if (this.port !== undefined) {\n port = Number.parseInt(this.port, 10);\n if (Number.isNaN(port) || port < 0 || port > 65_535) {\n this.context.stderr.write(\n `vela studio: --port must be a number 0-65535, got: ${this.port}\\n`,\n );\n return 1;\n }\n }\n\n const adminToken = this.token ?? process.env.VELA_STUDIO_TOKEN;\n\n let host: StudioHostModule;\n try {\n host = (await import(HOST_PACKAGE)) as StudioHostModule;\n } catch (error) {\n if (isModuleNotFound(error, HOST_PACKAGE)) {\n this.context.stderr.write(\n `vela studio needs the optional \"${HOST_PACKAGE}\" package, which isn't installed.\\n` +\n ` Install it: pnpm add -D ${HOST_PACKAGE}\\n` +\n ` (it also needs the prebuilt UI: pnpm add -D @velajs/studio-ui)\\n`,\n );\n return 1;\n }\n throw error;\n }\n\n const server = await host.startStudioServer({\n workerOrigin,\n adminToken,\n port,\n adminPath: this.adminPath,\n cwd: process.cwd(),\n });\n\n this.context.stdout.write(\n `\\n Vela Studio ${server.url}\\n` +\n ` Proxying ${workerOrigin}${this.adminPath ?? '/_vela/admin'}/*\\n` +\n ` Admin token ${adminToken !== undefined ? 'set (injected server-side)' : 'none (app requires none)'}\\n\\n` +\n ' Press Ctrl+C to stop.\\n',\n );\n\n // Run until interrupted. The listener is removed on trigger so a second\n // Ctrl+C during shutdown falls through to Node's default (force-exit).\n await new Promise<void>((resolvePromise) => {\n const onSignal = (): void => {\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n resolvePromise();\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n });\n\n await server.close();\n this.context.stdout.write('\\nVela Studio stopped.\\n');\n return 0;\n }\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { createOpenApiDocument } from '@velajs/vela';\nimport type { OpenApiDocument } from '@velajs/vela';\nimport { Command, Option } from 'clipanion';\nimport { generateClientContract } from '../client-contract.js';\nimport { loadConfig } from '../config.js';\n\nexport class ClientGenerateCommand extends Command {\n static override paths = [['client', 'generate']];\n static override usage = Command.Usage({\n category: 'Client',\n description: \"Generate a typed HTTP contract for Hono's hc client.\",\n details:\n 'Uses rootModule and createApp from vela.config, or an OpenAPI JSON file with --input. Missing schemas emit unknown and a warning; --strict makes those warnings an error.',\n examples: [\n ['Generate from an app', 'vela client generate --out src/api.generated.ts'],\n [\n 'Generate from a document',\n 'vela client generate --input openapi.json --out src/api.generated.ts',\n ],\n ['Check a committed contract', 'vela client generate --out src/api.generated.ts --check'],\n ],\n });\n\n config = Option.String('--config', { description: 'Path to the vela config file.' });\n input = Option.String('--input', {\n description: 'Read an OpenAPI JSON file without bootstrapping the app.',\n });\n out = Option.String('--out', { description: 'Output TypeScript file (stdout when omitted).' });\n check = Option.Boolean('--check', false, {\n description: 'Fail if --out differs from the generated contract; do not write.',\n });\n strict = Option.Boolean('--strict', false, { description: 'Fail on missing or lossy schemas.' });\n\n async execute(): Promise<number> {\n if (this.input && this.config) throw new Error('Use either --input or --config, not both.');\n if (this.check && !this.out) throw new Error('--check requires --out.');\n const document = this.input ? await this.readDocument(this.input) : await this.fromApp();\n const { source, warnings } = generateClientContract(document);\n for (const warning of warnings) this.context.stderr.write(`Warning: ${warning}\\n`);\n if (this.strict && warnings.length) return 1;\n if (this.check) {\n let existing: string | undefined;\n try {\n existing = await readFile(this.out!, 'utf8');\n } catch (error) {\n if (!(error instanceof Error) || !('code' in error) || error.code !== 'ENOENT') throw error;\n }\n if (existing !== source) {\n this.context.stderr.write(\n `Client contract is missing or stale: ${this.out}. Run vela client generate without --check.\\n`,\n );\n return 1;\n }\n } else if (this.out) {\n await mkdir(dirname(this.out), { recursive: true });\n await writeFile(this.out, source, 'utf8');\n this.context.stdout.write(`Wrote ${this.out}\\n`);\n } else {\n this.context.stdout.write(source);\n }\n return 0;\n }\n\n private async readDocument(file: string): Promise<unknown> {\n const value: unknown = JSON.parse(await readFile(file, 'utf8'));\n // generateClientContract validates the complete consumed projection for\n // both file inputs and documents produced by the running application.\n return value;\n }\n\n private async fromApp(): Promise<OpenApiDocument> {\n const config = await loadConfig(process.cwd(), this.config);\n if (!config.rootModule)\n throw new Error(\n 'client generate needs rootModule in vela.config, or pass --input openapi.json.',\n );\n const app = await config.createApp();\n try {\n const document = createOpenApiDocument(config.rootModule, {\n globalPrefix: app.getGlobalPrefix(),\n });\n // Detect older Vela exporters which omit versioned controller routes.\n // Never silently ship a contract which points at a different endpoint.\n for (const route of app.describeRoutes()) {\n const path = route.path.replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, '{$1}');\n const item = document.paths[path];\n if (!item || !Object.hasOwn(item, route.method.toLowerCase())) {\n throw new Error(\n `OpenAPI is missing ${route.method} ${route.path}. Update Vela or pass a complete document with --input.`,\n );\n }\n }\n return document;\n } finally {\n try {\n await app.dispose();\n } catch (error) {\n this.context.stderr.write(`Warning: teardown failed: ${String(error)}\\n`);\n }\n }\n }\n}\n","#!/usr/bin/env node\nimport { Builtins, Cli } from 'clipanion';\nimport {\n EntrypointListCommand,\n ModuleGraphCommand,\n OpenApiDumpCommand,\n RouteListCommand,\n} from './commands/introspect.commands.js';\nimport { McpServeCommand } from './commands/mcp.command.js';\nimport { SeedCommand } from './commands/seed.command.js';\nimport { StudioCommand } from './commands/studio.command.js';\nimport { ClientGenerateCommand } from './commands/client.command.js';\n\nconst cli = new Cli({\n binaryName: 'vela',\n binaryLabel: 'Vela CLI',\n binaryVersion: '0.2.0',\n});\n\ncli.register(Builtins.HelpCommand);\ncli.register(Builtins.VersionCommand);\ncli.register(SeedCommand);\ncli.register(RouteListCommand);\ncli.register(ModuleGraphCommand);\ncli.register(EntrypointListCommand);\ncli.register(OpenApiDumpCommand);\ncli.register(McpServeCommand);\ncli.register(StudioCommand);\ncli.register(ClientGenerateCommand);\n\nvoid cli.runExit(process.argv.slice(2));\n\nexport { SeedCommand } from './commands/seed.command.js';\nexport {\n EntrypointListCommand,\n ModuleGraphCommand,\n OpenApiDumpCommand,\n RouteListCommand,\n} from './commands/introspect.commands.js';\nexport { McpServeCommand } from './commands/mcp.command.js';\nexport { StudioCommand } from './commands/studio.command.js';\nexport { ClientGenerateCommand } from './commands/client.command.js';\nexport { generateClientContract } from './client-contract.js';\nexport type { GeneratedClientContract } from './client-contract.js';\nexport {\n collectRoutes,\n collectModules,\n collectEntrypoints,\n renderModuleTree,\n} from './introspect.js';\nexport type { RouteRow, EntrypointRow } from './introspect.js';\nexport { renderTable } from './format.js';\nexport { loadConfig, defineVelaConfig } from './config.js';\nexport type { VelaConfig } from './config.js';\nexport { formatSeedResults } from './format.js';\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velajs/cli",
3
- "version": "0.3.2",
3
+ "version": "1.22.0",
4
4
  "description": "CLI for Vela apps — seeding and project tasks (Node-side; not bundled into the edge Worker)",
5
5
  "keywords": [
6
6
  "cli",
@@ -12,7 +12,8 @@
12
12
  "license": "MIT",
13
13
  "repository": {
14
14
  "type": "git",
15
- "url": "git+https://github.com/velajs/cli.git"
15
+ "url": "git+https://github.com/velajs/vela.git",
16
+ "directory": "packages/cli"
16
17
  },
17
18
  "bin": {
18
19
  "vela": "./dist/index.js"
@@ -25,6 +26,10 @@
25
26
  "main": "./dist/index.js",
26
27
  "types": "./dist/index.d.ts",
27
28
  "exports": {
29
+ "./client": {
30
+ "types": "./dist/client-contract.d.ts",
31
+ "import": "./dist/client-contract.js"
32
+ },
28
33
  ".": {
29
34
  "types": "./dist/index.d.ts",
30
35
  "import": "./dist/index.js"
@@ -37,28 +42,40 @@
37
42
  "dependencies": {
38
43
  "@modelcontextprotocol/sdk": "^1.29.0",
39
44
  "clipanion": "^4.0.0-rc.4",
40
- "zod": "^3.25.76"
45
+ "zod": "4.4.3"
41
46
  },
42
47
  "devDependencies": {
43
- "@arethetypeswrong/cli": "^0.18.5",
44
- "@changesets/cli": "^2.31.0",
45
- "@swc/core": "^1.15.43",
46
- "@types/node": "^24.13.3",
47
- "@velajs/vela": "^1.15.0",
48
- "oxfmt": "^0.58.0",
49
- "oxlint": "^1.73.0",
50
- "publint": "^0.3.21",
51
- "tsdown": "^0.22.4",
52
- "typescript": "^7.0.2",
53
- "unplugin-swc": "^1.5.9",
54
- "vitest": "^4.1.10"
48
+ "@arethetypeswrong/cli": "0.18.5",
49
+ "@changesets/cli": "3.0.1",
50
+ "@swc/core": "1.15.43",
51
+ "@types/node": "24.13.3",
52
+ "hono": "4.13.8",
53
+ "oxfmt": "0.58.0",
54
+ "oxlint": "1.73.0",
55
+ "publint": "0.3.21",
56
+ "tsdown": "0.23.0",
57
+ "typescript": "7.0.2",
58
+ "unplugin-swc": "1.5.9",
59
+ "vitest": "4.1.10",
60
+ "@velajs/client": "1.22.0",
61
+ "@velajs/vela": "1.22.0"
55
62
  },
56
63
  "peerDependencies": {
57
- "@velajs/vela": ">=1.15.0"
64
+ "@velajs/vela": "^1.22.0"
65
+ },
66
+ "optionalDependencies": {
67
+ "@velajs/studio-host": "1.22.0"
58
68
  },
59
69
  "engines": {
60
70
  "node": ">=24"
61
71
  },
72
+ "publishConfig": {
73
+ "access": "public"
74
+ },
75
+ "homepage": "https://github.com/velajs/vela/tree/main/packages/cli#readme",
76
+ "bugs": {
77
+ "url": "https://github.com/velajs/vela/issues"
78
+ },
62
79
  "scripts": {
63
80
  "build": "tsdown",
64
81
  "typecheck": "tsc --noEmit",
@@ -68,9 +85,6 @@
68
85
  "format:check": "oxfmt --check .",
69
86
  "publint": "publint",
70
87
  "attw": "attw --pack . --profile esm-only",
71
- "changeset": "changeset",
72
- "version-packages": "changeset version",
73
- "release": "pnpm build && changeset publish",
74
88
  "verify": "pnpm lint && pnpm format:check && pnpm build && pnpm typecheck && pnpm test && pnpm publint && pnpm attw"
75
89
  }
76
90
  }