@velajs/cli 1.23.0 → 1.25.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/README.md +80 -13
- package/dist/{client-contract-C7P2btFE.js → client-contract-R3_sMYFQ.js} +91 -9
- package/dist/client-contract-R3_sMYFQ.js.map +1 -0
- package/dist/client-contract.d.ts +1 -1
- package/dist/client-contract.js +1 -1
- package/dist/config.d.ts +18 -9
- package/dist/config.js +48 -17
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +29 -8
- package/dist/index.js +516 -73
- package/dist/index.js.map +1 -1
- package/package.json +14 -12
- package/templates/worker/README.md +15 -0
- package/templates/worker/src/app.controller.ts +8 -2
- package/templates/worker/vela.config.mjs +9 -0
- package/dist/client-contract-C7P2btFE.js.map +0 -1
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ pnpm add -D @velajs/cli
|
|
|
15
15
|
| Command | What it does |
|
|
16
16
|
| --- | --- |
|
|
17
17
|
| `vela new my-api` | Create a minimal Workers project with a module, controller, injected service, and a working local development setup. |
|
|
18
|
+
| `vela doctor` | Explain config resolution without importing it; `--app` opts into application graph snapshots and teardown. Supports `--json`. |
|
|
19
|
+
| `vela deploy check` | Check an explicit Wrangler config/environment against a saved entrypoint snapshot without bootstrapping, building or deploying. See the [deployment guide](../../docs/deployment.md). |
|
|
18
20
|
| `vela db seed` | Build the app and run all `@Seeder()` classes in order. |
|
|
19
21
|
| `vela route list` | HTTP route table: framework-composed controller routes (`Controller#handler`, full paths incl. prefix/version) plus `(mounted)` extras (CRUD/contributed, doc UIs). |
|
|
20
22
|
| `vela module graph` | Module graph: imports tree with `global`/`lazy` flags and provider counts (`--json` for the raw graph). |
|
|
@@ -22,8 +24,9 @@ pnpm add -D @velajs/cli
|
|
|
22
24
|
| `vela openapi dump` | Emit the OpenAPI document (needs `rootModule` in the config; `--out`, `--title`, `--api-version`, `--global-prefix`). |
|
|
23
25
|
| `vela client generate` | Generate an `AppType` for `hc` from the app or `--input openapi.json`; `--out`, `--strict`, and CI `--check`. |
|
|
24
26
|
| `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. |
|
|
27
|
+
| `vela studio` | Serve the optional Studio UI through a local host, proxying the app selected by `--url`. |
|
|
25
28
|
|
|
26
|
-
All introspection commands take `--config <path>`; the
|
|
29
|
+
All introspection commands take `--config <path>`; the listing commands also take `--json`.
|
|
27
30
|
|
|
28
31
|
### Create a project
|
|
29
32
|
|
|
@@ -76,25 +79,74 @@ the client disconnects, then disposes the app.
|
|
|
76
79
|
## Configure
|
|
77
80
|
|
|
78
81
|
Create a `vela.config.{js,mjs,ts}` at your project root that builds your app.
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
Import compiled application JavaScript, including its decorator metadata. The
|
|
83
|
+
starter's SWC build produces these files in `dist/`; run `pnpm build` first.
|
|
84
|
+
This minimal config uses the portable factory in Node:
|
|
81
85
|
|
|
82
|
-
```
|
|
83
|
-
// vela.config.
|
|
86
|
+
```js
|
|
87
|
+
// vela.config.mjs
|
|
84
88
|
import { defineVelaConfig } from '@velajs/cli/config';
|
|
85
|
-
import {
|
|
89
|
+
import { VelaFactory } from '@velajs/vela';
|
|
90
|
+
import { AppModule } from './dist/app.module.js';
|
|
86
91
|
|
|
87
92
|
export default defineVelaConfig({
|
|
88
93
|
rootModule: AppModule, // needed by `vela openapi dump` and `vela client generate`
|
|
89
|
-
|
|
90
|
-
const { createCloudflareApp } = await import('@velajs/cloudflare');
|
|
91
|
-
return createCloudflareApp(AppModule);
|
|
92
|
-
},
|
|
94
|
+
createApp: () => VelaFactory.create(AppModule),
|
|
93
95
|
});
|
|
94
96
|
```
|
|
95
97
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
Supply local runtime bindings inside `createApp` if the application needs them.
|
|
99
|
+
Do not import the Worker entrypoint into Node when it uses native
|
|
100
|
+
`cloudflare:workers` APIs. A plain default-exported object or named `config`
|
|
101
|
+
export also works; `defineVelaConfig` preserves the inferred app subtype and
|
|
102
|
+
custom fields. The loader validates `createApp` and optional `rootModule` before
|
|
103
|
+
commands use them. Command teardown awaits application disposal even when work
|
|
104
|
+
fails, and cleanup warnings do not replace the command's exit result.
|
|
105
|
+
|
|
106
|
+
Node 24 can strip erasable types in a `.ts` config, but it does not transform
|
|
107
|
+
legacy decorators, emit constructor metadata, or resolve `tsconfig` path
|
|
108
|
+
aliases. A `.ts` config should therefore also import the compiled `.js` graph
|
|
109
|
+
with explicit extensions. Use SWC's `legacyDecorator` and `decoratorMetadata`
|
|
110
|
+
settings from the starter, or a compiler with equivalent output. The CLI adds
|
|
111
|
+
no compiler hooks. See [Node's TypeScript documentation](https://nodejs.org/docs/latest-v24.x/api/typescript.html#typescript-features).
|
|
112
|
+
|
|
113
|
+
The loader checks `vela.config.js`, then `.mjs`, then `.ts` in the current
|
|
114
|
+
directory; it does not search parents. `--config` selects exactly that path,
|
|
115
|
+
relative to the current directory or absolute, with no fallback to another file.
|
|
116
|
+
`resolveConfig()` from `@velajs/cli/config` returns the selected absolute path,
|
|
117
|
+
the `explicit`/`discovered` source and the candidates actually checked, without
|
|
118
|
+
importing user code.
|
|
119
|
+
|
|
120
|
+
### Diagnose configuration
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
vela doctor --json
|
|
124
|
+
pnpm build
|
|
125
|
+
vela doctor --app --config vela.config.mjs --json
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The default only resolves the config file. `--app` imports it and runs normal
|
|
129
|
+
application bootstrap and shutdown hooks, which may perform application-defined
|
|
130
|
+
work. It then reads existing module, route and entrypoint descriptions without
|
|
131
|
+
resolving providers or materializing lazy modules for inspection. Reports omit
|
|
132
|
+
provider values, environment values and arbitrary entrypoint metadata, and show
|
|
133
|
+
only entrypoints belonging to that app. `--json` uses `schemaVersion: 1`; missing
|
|
134
|
+
configs, bootstrap/snapshot errors or cleanup warnings return exit code 1.
|
|
135
|
+
Send application startup logs to stderr when consuming JSON output.
|
|
136
|
+
|
|
137
|
+
For breakpoints and source maps, see the [debugging guide](../../docs/debugging.md).
|
|
138
|
+
|
|
139
|
+
### Studio
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
vela studio --url http://127.0.0.1:8787 --port 4000
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The optional `@velajs/studio-host` and `@velajs/studio-ui` packages provide the
|
|
146
|
+
host and UI. `--port` accepts a decimal integer from 0 to 65535 (0 asks the OS
|
|
147
|
+
for an available port). Tokens come from `--token` or `VELA_STUDIO_TOKEN` and are
|
|
148
|
+
injected by the host. The CLI config and client-generation entrypoints remain
|
|
149
|
+
usable without Studio installed.
|
|
98
150
|
|
|
99
151
|
## Commands
|
|
100
152
|
|
|
@@ -103,9 +155,14 @@ export default defineVelaConfig({
|
|
|
103
155
|
vela db seed
|
|
104
156
|
vela db seed --config ./config/vela.config.js
|
|
105
157
|
vela db seed --continue-on-error
|
|
158
|
+
# Inspect registration owners without running seeders:
|
|
159
|
+
vela db seed --list --json
|
|
106
160
|
```
|
|
107
161
|
|
|
108
162
|
Exit code is `0` when all seeders run and `1` if any fail.
|
|
163
|
+
Seeders registered in multiple modules run once per owner, including async
|
|
164
|
+
providers. Invocations finish their managed deferred work and dispose request
|
|
165
|
+
resources before the next seeder starts. See [seeding](../../docs/seeding.md).
|
|
109
166
|
|
|
110
167
|
## Typed HTTP clients
|
|
111
168
|
|
|
@@ -116,7 +173,7 @@ vela client generate --out src/api.generated.ts --strict --check
|
|
|
116
173
|
vela client generate --input openapi.json --out src/api.generated.ts
|
|
117
174
|
```
|
|
118
175
|
|
|
119
|
-
The generated file
|
|
176
|
+
The generated file imports `HttpApp` from `@velajs/client/http`. JSON-only contracts contain only types; form contracts also export `formEncodings`. On the frontend:
|
|
120
177
|
|
|
121
178
|
```ts
|
|
122
179
|
import { hc } from '@velajs/client/http';
|
|
@@ -129,4 +186,14 @@ const user = await response.json();
|
|
|
129
186
|
|
|
130
187
|
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.
|
|
131
188
|
|
|
189
|
+
Form endpoints use `input.form` with `body.contentType` set to
|
|
190
|
+
`multipart/form-data` or `application/x-www-form-urlencoded`. The generator emits
|
|
191
|
+
string/file fields and repeated arrays with required/optional properties, retaining
|
|
192
|
+
all response variants. Files become `File | Blob` only for multipart contracts.
|
|
193
|
+
Use `fetch: withFormEncoding(formEncodings, suppliedFetch)` from
|
|
194
|
+
`@velajs/client/http` so URL-encoded routes use their declared encoding;
|
|
195
|
+
bare `hc` always serializes forms as multipart. Wrap per-call fetch overrides too.
|
|
196
|
+
Custom part encodings, nested form values, and binary JSON bodies fail generation
|
|
197
|
+
with diagnostics. See the [HTTP guide](../../docs/client/HTTP.md#form-bodies-and-uploads).
|
|
198
|
+
|
|
132
199
|
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.
|
|
@@ -47,7 +47,10 @@ const parameter = z.object({
|
|
|
47
47
|
$ref: z.string().optional(),
|
|
48
48
|
content: z.unknown().optional()
|
|
49
49
|
}).passthrough();
|
|
50
|
-
const media = z.object({
|
|
50
|
+
const media = z.object({
|
|
51
|
+
schema: schema.optional(),
|
|
52
|
+
encoding: z.unknown().optional()
|
|
53
|
+
}).passthrough();
|
|
51
54
|
const content = z.record(z.string(), media);
|
|
52
55
|
const requestBody = z.object({
|
|
53
56
|
required: z.boolean().optional(),
|
|
@@ -175,11 +178,12 @@ const HTTP_STATUSES = /* @__PURE__ */ new Set([
|
|
|
175
178
|
510,
|
|
176
179
|
511
|
|
177
180
|
]);
|
|
178
|
-
/** Generate
|
|
181
|
+
/** Generate hc types and optional form encoding metadata, without application imports. */
|
|
179
182
|
function generateClientContract(input) {
|
|
180
183
|
const document = parseClientContractDocument(input);
|
|
181
184
|
const warnings = /* @__PURE__ */ new Set();
|
|
182
185
|
const components = document.components?.schemas ?? {};
|
|
186
|
+
const formEncodings = [];
|
|
183
187
|
let usesHttpStatus = false;
|
|
184
188
|
const warn = (message) => {
|
|
185
189
|
warnings.add(message);
|
|
@@ -239,7 +243,7 @@ function generateClientContract(input) {
|
|
|
239
243
|
}
|
|
240
244
|
parts.push(fields.length ? `{ ${fields.join(" ")} }` : "Record<string, never>");
|
|
241
245
|
} else if (schema.type === "array") parts.push(`Array<${schemaType(schema.items, `${at}[]`)}>`);
|
|
242
|
-
else if (schema.type === "string") parts.push("string");
|
|
246
|
+
else if (schema.type === "string") parts.push(schema.format === "binary" ? "File | Blob" : "string");
|
|
243
247
|
else if (schema.type === "number" || schema.type === "integer") parts.push("number");
|
|
244
248
|
else if (schema.type === "boolean" || schema.type === "null") parts.push(schema.type);
|
|
245
249
|
else if (schema.type) throw new Error(`${at}: unsupported schema type ${schema.type}.`);
|
|
@@ -250,6 +254,60 @@ function generateClientContract(input) {
|
|
|
250
254
|
const value = parts.map((part) => `(${part})`).join(" & ");
|
|
251
255
|
return schema.nullable ? `(${value}) | null` : value;
|
|
252
256
|
}
|
|
257
|
+
function resolveFormSchema(value, at, seen = /* @__PURE__ */ new Set()) {
|
|
258
|
+
if (!value || typeof value !== "object") throw new Error(`${at}: form fields require concrete schemas.`);
|
|
259
|
+
if (!value.$ref) return value;
|
|
260
|
+
const name = value.$ref.startsWith("#/components/schemas/") ? value.$ref.slice(21).replace(/~1/g, "/").replace(/~0/g, "~") : "";
|
|
261
|
+
if (!Object.hasOwn(components, name)) throw new Error(`${at}: unsupported or unresolved reference ${value.$ref}.`);
|
|
262
|
+
if (seen.has(value.$ref)) throw new Error(`${at}: recursive form schemas are unsupported.`);
|
|
263
|
+
if (Object.keys(value).some((key) => ![
|
|
264
|
+
"$ref",
|
|
265
|
+
"description",
|
|
266
|
+
"title"
|
|
267
|
+
].includes(key))) throw new Error(`${at}: form references with schema siblings are unsupported.`);
|
|
268
|
+
return resolveFormSchema(components[name], at, new Set(seen).add(value.$ref));
|
|
269
|
+
}
|
|
270
|
+
function formType(value, encoding, contentType, at) {
|
|
271
|
+
const schema = resolveFormSchema(value, at);
|
|
272
|
+
schemaType(schema, at);
|
|
273
|
+
if (schema.type !== "object" || !schema.properties || schema.oneOf || schema.anyOf || schema.allOf || schema.nullable || schema.additionalProperties !== void 0 && schema.additionalProperties !== false) throw new Error(`${at}: form bodies require an object with named fields and no additionalProperties schema.`);
|
|
274
|
+
if (encoding !== void 0) {
|
|
275
|
+
if (encoding === null || typeof encoding !== "object" || Array.isArray(encoding)) throw new Error(`${at}: invalid form encoding.`);
|
|
276
|
+
for (const [name, entry] of Object.entries(encoding)) if (!Object.hasOwn(schema.properties, name) || !entry || typeof entry !== "object" || Array.isArray(entry) || Object.entries(entry).some(([key, value]) => !(key === "style" && value === "form" || key === "explode" && value === true))) throw new Error(`${at}: unsupported form serialization for ${name}; use repeated fields with style form and explode true.`);
|
|
277
|
+
}
|
|
278
|
+
const fieldType = (value, name, array = false) => {
|
|
279
|
+
const field = resolveFormSchema(value, `${at}.${name}`);
|
|
280
|
+
schemaType(field, `${at}.${name}`);
|
|
281
|
+
if (field.oneOf || field.anyOf || field.allOf || field.nullable || field.readOnly || field.writeOnly) throw new Error(`${at}.${name}: ambiguous form wire schema.`);
|
|
282
|
+
if (field.type === "array" && !array) return `Array<${fieldType(field.items, name, true)}>`;
|
|
283
|
+
if (field.type !== "string") throw new Error(`${at}.${name}: form wire fields must be strings, binary files, or arrays of these.`);
|
|
284
|
+
const file = field.format === "binary";
|
|
285
|
+
if (file && contentType !== "multipart/form-data") throw new Error(`${at}.${name}: files require multipart/form-data.`);
|
|
286
|
+
if (field.contentEncoding !== void 0 && !(file && field.contentEncoding === "binary")) throw new Error(`${at}.${name}: unsupported contentEncoding.`);
|
|
287
|
+
if (field.enum && field.enum.some((entry) => typeof entry !== "string") || "const" in field && typeof field.const !== "string" || file && (field.enum || "const" in field)) throw new Error(`${at}.${name}: invalid form scalar literal.`);
|
|
288
|
+
return schemaType(field, `${at}.${name}`);
|
|
289
|
+
};
|
|
290
|
+
const required = new Set(schema.required ?? []);
|
|
291
|
+
const fields = Object.entries(schema.properties).toSorted(([a], [b]) => a.localeCompare(b)).map(([name, value]) => `${quote(name)}${required.has(name) ? "" : "?"}: ${fieldType(value, name)};`);
|
|
292
|
+
return fields.length ? `{ ${fields.join(" ")} }` : "Record<string, never>";
|
|
293
|
+
}
|
|
294
|
+
function rejectBinaryJson(value, at, seen = /* @__PURE__ */ new Set()) {
|
|
295
|
+
if (!value || typeof value !== "object") return;
|
|
296
|
+
if (value.format === "binary") throw new Error(`${at}: binary files require multipart form fields; JSON/text serialization is unsupported.`);
|
|
297
|
+
if (value.$ref && !seen.has(value.$ref)) {
|
|
298
|
+
seen.add(value.$ref);
|
|
299
|
+
const name = value.$ref.slice(21).replace(/~1/g, "/").replace(/~0/g, "~");
|
|
300
|
+
rejectBinaryJson(components[name], at, seen);
|
|
301
|
+
}
|
|
302
|
+
for (const child of [
|
|
303
|
+
...Object.values(value.properties ?? {}),
|
|
304
|
+
value.items,
|
|
305
|
+
typeof value.additionalProperties === "object" ? value.additionalProperties : void 0,
|
|
306
|
+
...value.oneOf ?? [],
|
|
307
|
+
...value.anyOf ?? [],
|
|
308
|
+
...value.allOf ?? []
|
|
309
|
+
]) rejectBinaryJson(child, at, seen);
|
|
310
|
+
}
|
|
253
311
|
function wireType(value, at, seen = /* @__PURE__ */ new Set()) {
|
|
254
312
|
if (value === false) return "never";
|
|
255
313
|
const schema = value === true ? void 0 : value;
|
|
@@ -268,7 +326,7 @@ function generateClientContract(input) {
|
|
|
268
326
|
if (schema?.enum) return schema.enum.map((v) => quote(String(v))).join(" | ") || "never";
|
|
269
327
|
return "string";
|
|
270
328
|
}
|
|
271
|
-
function inputType(path, operation, at) {
|
|
329
|
+
function inputType(path, operation, at, method) {
|
|
272
330
|
const parameters = [...operation.parameters ?? []];
|
|
273
331
|
for (const p of parameters) if (![
|
|
274
332
|
"path",
|
|
@@ -301,8 +359,25 @@ function generateClientContract(input) {
|
|
|
301
359
|
if (body.$ref) throw new Error(`${at}: resolve requestBody references before generating a client.`);
|
|
302
360
|
const content = body.content ?? {};
|
|
303
361
|
const media = Object.keys(content);
|
|
304
|
-
|
|
305
|
-
|
|
362
|
+
const contentType = media[0];
|
|
363
|
+
if (media.length !== 1 || !contentType || ![
|
|
364
|
+
"application/json",
|
|
365
|
+
"multipart/form-data",
|
|
366
|
+
"application/x-www-form-urlencoded"
|
|
367
|
+
].includes(contentType)) throw new Error(`${at}: request bodies must declare exactly one supported media type: application/json, multipart/form-data, or application/x-www-form-urlencoded.`);
|
|
368
|
+
if (method === "get" || method === "head") throw new Error(`${at}: hc cannot send a request body for GET or HEAD.`);
|
|
369
|
+
const entry = content[contentType];
|
|
370
|
+
if (contentType === "application/json") {
|
|
371
|
+
rejectBinaryJson(entry?.schema, `${at} request body`);
|
|
372
|
+
fields.push(`json${body.required ? "" : "?"}: ${schemaType(entry?.schema, `${at} request body`)};`);
|
|
373
|
+
} else {
|
|
374
|
+
fields.push(`form${body.required ? "" : "?"}: ${formType(entry?.schema, entry?.encoding, contentType, `${at} request body`)};`);
|
|
375
|
+
formEncodings.push({
|
|
376
|
+
path,
|
|
377
|
+
method: method.toUpperCase(),
|
|
378
|
+
contentType
|
|
379
|
+
});
|
|
380
|
+
}
|
|
306
381
|
}
|
|
307
382
|
return fields.length ? `{ ${fields.join(" ")} }` : "{}";
|
|
308
383
|
}
|
|
@@ -330,7 +405,7 @@ function generateClientContract(input) {
|
|
|
330
405
|
const at = `${method.toUpperCase()} ${path}`;
|
|
331
406
|
const unsupported = operation["x-vela-client-unsupported"];
|
|
332
407
|
if (unsupported?.length) throw new Error(`${at}: ${unsupported.join(" ")}`);
|
|
333
|
-
const input = inputType(path, operation, at);
|
|
408
|
+
const input = inputType(path, operation, at, method);
|
|
334
409
|
const explicitStatuses = Object.keys(operation.responses).filter((s) => /^\d{3}$/.test(s));
|
|
335
410
|
const variants = [];
|
|
336
411
|
for (const [status, response] of Object.entries(operation.responses).toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
@@ -345,6 +420,7 @@ function generateClientContract(input) {
|
|
|
345
420
|
const media = Object.keys(content);
|
|
346
421
|
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
422
|
const format = media[0] === "text/plain" ? "text" : "json";
|
|
423
|
+
rejectBinaryJson(content[media[0] ?? ""]?.schema, `${at} response ${status}`);
|
|
348
424
|
const bodyType = [
|
|
349
425
|
"101",
|
|
350
426
|
"204",
|
|
@@ -363,11 +439,17 @@ function generateClientContract(input) {
|
|
|
363
439
|
return {
|
|
364
440
|
source: [
|
|
365
441
|
"// Generated by vela client generate. Do not edit.",
|
|
366
|
-
`import type { HttpApp${usesHttpStatus ? ", HttpStatus" : ""} } from '@velajs/client/http';`,
|
|
442
|
+
`import type { HttpApp${usesHttpStatus ? ", HttpStatus" : ""}${formEncodings.length ? ", HttpFormEncoding" : ""} } from '@velajs/client/http';`,
|
|
367
443
|
"",
|
|
368
444
|
`export type Schemas = {\n${schemas.join("\n")}\n};`,
|
|
369
445
|
"",
|
|
370
446
|
`export type AppType = HttpApp<{\n${paths.join("\n")}\n}>;`,
|
|
447
|
+
...formEncodings.length ? [
|
|
448
|
+
"",
|
|
449
|
+
"// hc sends multipart by default. Use fetch: withFormEncoding(formEncodings, yourFetch)",
|
|
450
|
+
"// from @velajs/client/http to honor URL-encoded routes. Wrap per-call fetch overrides too.",
|
|
451
|
+
`export const formEncodings = ${JSON.stringify(formEncodings, null, 2)} as const satisfies readonly HttpFormEncoding[];`
|
|
452
|
+
] : [],
|
|
371
453
|
""
|
|
372
454
|
].join("\n"),
|
|
373
455
|
warnings: [...warnings]
|
|
@@ -388,4 +470,4 @@ function rangeStatus(status) {
|
|
|
388
470
|
//#endregion
|
|
389
471
|
export { generateClientContract as t };
|
|
390
472
|
|
|
391
|
-
//# sourceMappingURL=client-contract-
|
|
473
|
+
//# sourceMappingURL=client-contract-R3_sMYFQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-contract-R3_sMYFQ.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\n .object({ schema: schema.optional(), encoding: z.unknown().optional() })\n .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 hc types and optional form encoding metadata, without application imports. */\nexport function generateClientContract(input: unknown): GeneratedClientContract {\n const document = parseClientContractDocument(input);\n const warnings = new Set<string>();\n const components = document.components?.schemas ?? {};\n const formEncodings: { path: string; method: string; contentType: string }[] = [];\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(schema.format === 'binary' ? 'File | Blob' : '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 resolveFormSchema(\n value: ContractSchema | undefined,\n at: string,\n seen = new Set<string>(),\n ): Exclude<ContractSchema, boolean> {\n if (!value || typeof value !== 'object')\n throw new Error(`${at}: form fields require concrete schemas.`);\n if (!value.$ref) return value;\n const prefix = '#/components/schemas/';\n const name = value.$ref.startsWith(prefix)\n ? value.$ref.slice(prefix.length).replace(/~1/g, '/').replace(/~0/g, '~')\n : '';\n if (!Object.hasOwn(components, name))\n throw new Error(`${at}: unsupported or unresolved reference ${value.$ref}.`);\n if (seen.has(value.$ref)) throw new Error(`${at}: recursive form schemas are unsupported.`);\n if (Object.keys(value).some((key) => !['$ref', 'description', 'title'].includes(key)))\n throw new Error(`${at}: form references with schema siblings are unsupported.`);\n return resolveFormSchema(components[name], at, new Set(seen).add(value.$ref));\n }\n\n function formType(\n value: ContractSchema | undefined,\n encoding: unknown,\n contentType: string,\n at: string,\n ): string {\n const schema = resolveFormSchema(value, at);\n schemaType(schema, at); // Retain the generator's structural-keyword checks.\n if (\n schema.type !== 'object' ||\n !schema.properties ||\n schema.oneOf ||\n schema.anyOf ||\n schema.allOf ||\n schema.nullable ||\n (schema.additionalProperties !== undefined && schema.additionalProperties !== false)\n )\n throw new Error(\n `${at}: form bodies require an object with named fields and no additionalProperties schema.`,\n );\n if (encoding !== undefined) {\n if (encoding === null || typeof encoding !== 'object' || Array.isArray(encoding))\n throw new Error(`${at}: invalid form encoding.`);\n for (const [name, entry] of Object.entries(encoding)) {\n if (\n !Object.hasOwn(schema.properties, name) ||\n !entry ||\n typeof entry !== 'object' ||\n Array.isArray(entry) ||\n Object.entries(entry).some(\n ([key, value]) =>\n !((key === 'style' && value === 'form') || (key === 'explode' && value === true)),\n )\n )\n throw new Error(\n `${at}: unsupported form serialization for ${name}; use repeated fields with style form and explode true.`,\n );\n }\n }\n const fieldType = (value: ContractSchema | undefined, name: string, array = false): string => {\n const field = resolveFormSchema(value, `${at}.${name}`);\n schemaType(field, `${at}.${name}`);\n if (\n field.oneOf ||\n field.anyOf ||\n field.allOf ||\n field.nullable ||\n field.readOnly ||\n field.writeOnly\n )\n throw new Error(`${at}.${name}: ambiguous form wire schema.`);\n if (field.type === 'array' && !array) return `Array<${fieldType(field.items, name, true)}>`;\n if (field.type !== 'string')\n throw new Error(\n `${at}.${name}: form wire fields must be strings, binary files, or arrays of these.`,\n );\n const file = field.format === 'binary';\n if (file && contentType !== 'multipart/form-data')\n throw new Error(`${at}.${name}: files require multipart/form-data.`);\n if (field.contentEncoding !== undefined && !(file && field.contentEncoding === 'binary'))\n throw new Error(`${at}.${name}: unsupported contentEncoding.`);\n if (\n (field.enum && field.enum.some((entry) => typeof entry !== 'string')) ||\n ('const' in field && typeof field.const !== 'string') ||\n (file && (field.enum || 'const' in field))\n )\n throw new Error(`${at}.${name}: invalid form scalar literal.`);\n return schemaType(field, `${at}.${name}`);\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 ([name, value]) =>\n `${quote(name)}${required.has(name) ? '' : '?'}: ${fieldType(value, name)};`,\n );\n return fields.length ? `{ ${fields.join(' ')} }` : 'Record<string, never>';\n }\n\n function rejectBinaryJson(\n value: ContractSchema | undefined,\n at: string,\n seen = new Set<string>(),\n ): void {\n if (!value || typeof value !== 'object') return;\n if (value.format === 'binary')\n throw new Error(\n `${at}: binary files require multipart form fields; JSON/text serialization is unsupported.`,\n );\n if (value.$ref && !seen.has(value.$ref)) {\n seen.add(value.$ref);\n const name = value.$ref\n .slice('#/components/schemas/'.length)\n .replace(/~1/g, '/')\n .replace(/~0/g, '~');\n rejectBinaryJson(components[name], at, seen);\n }\n for (const child of [\n ...Object.values(value.properties ?? {}),\n value.items,\n typeof value.additionalProperties === 'object' ? value.additionalProperties : undefined,\n ...(value.oneOf ?? []),\n ...(value.anyOf ?? []),\n ...(value.allOf ?? []),\n ])\n rejectBinaryJson(child, at, seen);\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(\n path: string,\n operation: ContractOperation,\n at: string,\n method: string,\n ): 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 const contentType = media[0];\n if (\n media.length !== 1 ||\n !contentType ||\n !['application/json', 'multipart/form-data', 'application/x-www-form-urlencoded'].includes(\n contentType,\n )\n )\n throw new Error(\n `${at}: request bodies must declare exactly one supported media type: application/json, multipart/form-data, or application/x-www-form-urlencoded.`,\n );\n if (method === 'get' || method === 'head')\n throw new Error(`${at}: hc cannot send a request body for GET or HEAD.`);\n const entry = content[contentType];\n if (contentType === 'application/json') {\n rejectBinaryJson(entry?.schema, `${at} request body`);\n fields.push(\n `json${body.required ? '' : '?'}: ${schemaType(entry?.schema, `${at} request body`)};`,\n );\n } else {\n fields.push(\n `form${body.required ? '' : '?'}: ${formType(entry?.schema, entry?.encoding, contentType, `${at} request body`)};`,\n );\n formEncodings.push({ path, method: method.toUpperCase(), contentType });\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, method);\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 rejectBinaryJson(content[media[0] ?? '']?.schema, `${at} response ${status}`);\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' : ''}${formEncodings.length ? ', HttpFormEncoding' : ''} } 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 ...(formEncodings.length\n ? [\n '',\n '// hc sends multipart by default. Use fetch: withFormEncoding(formEncodings, yourFetch)',\n '// from @velajs/client/http to honor URL-encoded routes. Wrap per-call fetch overrides too.',\n `export const formEncodings = ${JSON.stringify(formEncodings, null, 2)} as const satisfies readonly HttpFormEncoding[];`,\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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"}
|
|
@@ -3,7 +3,7 @@ export interface GeneratedClientContract {
|
|
|
3
3
|
source: string;
|
|
4
4
|
warnings: string[];
|
|
5
5
|
}
|
|
6
|
-
/** Generate
|
|
6
|
+
/** Generate hc types and optional form encoding metadata, without application imports. */
|
|
7
7
|
export declare function generateClientContract(input: unknown): GeneratedClientContract;
|
|
8
8
|
//#endregion
|
|
9
9
|
//# sourceMappingURL=client-contract.d.ts.map
|
package/dist/client-contract.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as generateClientContract } from "./client-contract-
|
|
1
|
+
import { t as generateClientContract } from "./client-contract-R3_sMYFQ.js";
|
|
2
2
|
export { generateClientContract };
|
package/dist/config.d.ts
CHANGED
|
@@ -6,13 +6,13 @@ import { Type, VelaApplication } from "@velajs/vela";
|
|
|
6
6
|
* Cloudflare Worker, or a plain Node adapter — and return a built app.
|
|
7
7
|
*
|
|
8
8
|
* ```ts
|
|
9
|
-
* // vela.config.
|
|
9
|
+
* // vela.config.mjs — run `pnpm build` before using app-aware commands.
|
|
10
10
|
* import { defineVelaConfig } from '@velajs/cli/config';
|
|
11
|
+
* import { VelaFactory } from '@velajs/vela';
|
|
12
|
+
* import { AppModule } from './dist/app.module.js';
|
|
11
13
|
* export default defineVelaConfig({
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* return createCloudflareApp(AppModule);
|
|
15
|
-
* },
|
|
14
|
+
* rootModule: AppModule,
|
|
15
|
+
* createApp: () => VelaFactory.create(AppModule),
|
|
16
16
|
* });
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
@@ -25,12 +25,21 @@ export interface VelaConfig {
|
|
|
25
25
|
rootModule?: Type;
|
|
26
26
|
}
|
|
27
27
|
/** Identity helper for type-safe config files. */
|
|
28
|
-
export declare function defineVelaConfig(config:
|
|
28
|
+
export declare function defineVelaConfig<const Config extends VelaConfig>(config: Config): Config;
|
|
29
29
|
/**
|
|
30
|
-
* Locate
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* Locate and import a config using Node's loader. Node 24 can strip erasable
|
|
31
|
+
* types in `.ts` configs, but does not emit legacy decorators or DI metadata.
|
|
32
|
+
* Import compiled application `.js` from the config (e.g. the SWC build used
|
|
33
|
+
* by Wrangler). This loader does not install compiler or path-alias hooks.
|
|
33
34
|
*/
|
|
34
35
|
export declare function loadConfig(cwd?: string, explicitPath?: string): Promise<VelaConfig>;
|
|
36
|
+
export interface ConfigResolution {
|
|
37
|
+
readonly path: string;
|
|
38
|
+
readonly source: 'explicit' | 'discovered';
|
|
39
|
+
/** Absolute paths checked in order, ending at the selected file. */
|
|
40
|
+
readonly candidates: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
/** Resolve provenance without importing application code or walking parent directories. */
|
|
43
|
+
export declare function resolveConfig(cwd?: string, explicitPath?: string): Promise<ConfigResolution>;
|
|
35
44
|
//#endregion
|
|
36
45
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
//#region src/config.ts
|
|
5
5
|
/** Identity helper for type-safe config files. */
|
|
@@ -12,28 +12,59 @@ const CANDIDATES = [
|
|
|
12
12
|
"vela.config.ts"
|
|
13
13
|
];
|
|
14
14
|
/**
|
|
15
|
-
* Locate
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Locate and import a config using Node's loader. Node 24 can strip erasable
|
|
16
|
+
* types in `.ts` configs, but does not emit legacy decorators or DI metadata.
|
|
17
|
+
* Import compiled application `.js` from the config (e.g. the SWC build used
|
|
18
|
+
* by Wrangler). This loader does not install compiler or path-alias hooks.
|
|
18
19
|
*/
|
|
19
20
|
async function loadConfig(cwd = process.cwd(), explicitPath) {
|
|
20
|
-
const path =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const { path } = await resolveConfig(cwd, explicitPath);
|
|
22
|
+
let mod;
|
|
23
|
+
try {
|
|
24
|
+
mod = await import(pathToFileURL(path).href);
|
|
25
|
+
} catch (cause) {
|
|
26
|
+
throw new Error(`Could not import config at ${path}: ${cause instanceof Error ? cause.message : String(cause)}\nConfigs run in Node. Compile decorated application source with SWC (legacyDecorator + decoratorMetadata) or an equivalent metadata-emitting compiler, then import its compiled .js files with explicit extensions. Run your application build first; native TypeScript stripping does not transform decorators or tsconfig paths.`, { cause });
|
|
27
|
+
}
|
|
28
|
+
const config = isRecord(mod) ? mod.default ?? mod.config : void 0;
|
|
29
|
+
if (!isVelaConfig(config)) throw new Error(`Config at ${path} must export an object with createApp(): VelaApplication | Promise<VelaApplication> (default export or a named 'config'); rootModule, when provided, must be a constructor.`);
|
|
25
30
|
return config;
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
/** Resolve provenance without importing application code or walking parent directories. */
|
|
33
|
+
async function resolveConfig(cwd = process.cwd(), explicitPath) {
|
|
34
|
+
if (explicitPath !== void 0 && explicitPath.trim() === "") throw new Error("--config must name a file.");
|
|
35
|
+
const candidates = explicitPath === void 0 ? CANDIDATES.map((name) => join(resolve(cwd), name)) : [resolve(cwd, explicitPath)];
|
|
36
|
+
const checked = [];
|
|
37
|
+
for (const candidate of candidates) {
|
|
38
|
+
checked.push(candidate);
|
|
30
39
|
try {
|
|
31
|
-
await
|
|
32
|
-
return
|
|
33
|
-
|
|
40
|
+
if (!(await stat(candidate)).isFile()) throw new Error(`Config at ${candidate} must be a file.`);
|
|
41
|
+
return {
|
|
42
|
+
path: candidate,
|
|
43
|
+
source: explicitPath === void 0 ? "discovered" : "explicit",
|
|
44
|
+
candidates: checked
|
|
45
|
+
};
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (!isRecord(error) || error.code !== "ENOENT") throw error;
|
|
48
|
+
}
|
|
34
49
|
}
|
|
50
|
+
throw new Error(`No vela config found. Checked: ${checked.join(", ")}. Create one of: ${CANDIDATES.join(", ")} (or pass --config <path>).`);
|
|
51
|
+
}
|
|
52
|
+
function isRecord(value) {
|
|
53
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
54
|
+
}
|
|
55
|
+
function isConstructor(value) {
|
|
56
|
+
if (typeof value !== "function") return false;
|
|
57
|
+
try {
|
|
58
|
+
Reflect.construct(Object, [], value);
|
|
59
|
+
return true;
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function isVelaConfig(value) {
|
|
65
|
+
return isRecord(value) && typeof value.createApp === "function" && (value.rootModule === void 0 || isConstructor(value.rootModule));
|
|
35
66
|
}
|
|
36
67
|
//#endregion
|
|
37
|
-
export { defineVelaConfig, loadConfig };
|
|
68
|
+
export { defineVelaConfig, loadConfig, resolveConfig };
|
|
38
69
|
|
|
39
70
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"config.js","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { 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.mjs — run `pnpm build` before using app-aware commands.\n * import { defineVelaConfig } from '@velajs/cli/config';\n * import { VelaFactory } from '@velajs/vela';\n * import { AppModule } from './dist/app.module.js';\n * export default defineVelaConfig({\n * rootModule: AppModule,\n * createApp: () => VelaFactory.create(AppModule),\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<const Config extends VelaConfig>(config: Config): Config {\n return config;\n}\n\nconst CANDIDATES = ['vela.config.js', 'vela.config.mjs', 'vela.config.ts'];\n\n/**\n * Locate and import a config using Node's loader. Node 24 can strip erasable\n * types in `.ts` configs, but does not emit legacy decorators or DI metadata.\n * Import compiled application `.js` from the config (e.g. the SWC build used\n * by Wrangler). This loader does not install compiler or path-alias hooks.\n */\nexport async function loadConfig(\n cwd: string = process.cwd(),\n explicitPath?: string,\n): Promise<VelaConfig> {\n const { path } = await resolveConfig(cwd, explicitPath);\n let mod: unknown;\n try {\n mod = await import(pathToFileURL(path).href);\n } catch (cause) {\n throw new Error(\n `Could not import config at ${path}: ${cause instanceof Error ? cause.message : String(cause)}\\n` +\n 'Configs run in Node. Compile decorated application source with SWC (legacyDecorator + decoratorMetadata) ' +\n 'or an equivalent metadata-emitting compiler, then import its compiled .js files with explicit extensions. ' +\n 'Run your application build first; native TypeScript stripping does not transform decorators or tsconfig paths.',\n { cause },\n );\n }\n const config = isRecord(mod) ? (mod.default ?? mod.config) : undefined;\n if (!isVelaConfig(config)) {\n throw new Error(\n `Config at ${path} must export an object with createApp(): VelaApplication | Promise<VelaApplication> ` +\n \"(default export or a named 'config'); rootModule, when provided, must be a constructor.\",\n );\n }\n return config;\n}\n\nexport interface ConfigResolution {\n readonly path: string;\n readonly source: 'explicit' | 'discovered';\n /** Absolute paths checked in order, ending at the selected file. */\n readonly candidates: readonly string[];\n}\n\n/** Resolve provenance without importing application code or walking parent directories. */\nexport async function resolveConfig(\n cwd: string = process.cwd(),\n explicitPath?: string,\n): Promise<ConfigResolution> {\n if (explicitPath !== undefined && explicitPath.trim() === '') {\n throw new Error('--config must name a file.');\n }\n const candidates =\n explicitPath === undefined\n ? CANDIDATES.map((name) => join(resolve(cwd), name))\n : [resolve(cwd, explicitPath)];\n const checked: string[] = [];\n for (const candidate of candidates) {\n checked.push(candidate);\n try {\n if (!(await stat(candidate)).isFile()) {\n throw new Error(`Config at ${candidate} must be a file.`);\n }\n return {\n path: candidate,\n source: explicitPath === undefined ? 'discovered' : 'explicit',\n candidates: checked,\n };\n } catch (error) {\n if (!isRecord(error) || error.code !== 'ENOENT') throw error;\n }\n }\n throw new Error(\n `No vela config found. Checked: ${checked.join(', ')}. Create one of: ${CANDIDATES.join(', ')} (or pass --config <path>).`,\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isConstructor(value: unknown): value is Type {\n if (typeof value !== 'function') return false;\n try {\n // Validate constructability without invoking the user's constructor.\n Reflect.construct(Object, [], value);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isVelaConfig(value: unknown): value is VelaConfig {\n return (\n isRecord(value) &&\n typeof value.createApp === 'function' &&\n (value.rootModule === undefined || isConstructor(value.rootModule))\n );\n}\n"],"mappings":";;;;;AA+BA,SAAgB,iBAAkD,QAAwB;CACxF,OAAO;AACT;AAEA,MAAM,aAAa;CAAC;CAAkB;CAAmB;AAAgB;;;;;;;AAQzE,eAAsB,WACpB,MAAc,QAAQ,IAAI,GAC1B,cACqB;CACrB,MAAM,EAAE,SAAS,MAAM,cAAc,KAAK,YAAY;CACtD,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,OAAO,cAAc,IAAI,CAAC,CAAC;CACzC,SAAS,OAAO;EACd,MAAM,IAAI,MACR,8BAA8B,KAAK,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,sUAI9F,EAAE,MAAM,CACV;CACF;CACA,MAAM,SAAS,SAAS,GAAG,IAAK,IAAI,WAAW,IAAI,SAAU,KAAA;CAC7D,IAAI,CAAC,aAAa,MAAM,GACtB,MAAM,IAAI,MACR,aAAa,KAAK,4KAEpB;CAEF,OAAO;AACT;;AAUA,eAAsB,cACpB,MAAc,QAAQ,IAAI,GAC1B,cAC2B;CAC3B,IAAI,iBAAiB,KAAA,KAAa,aAAa,KAAK,MAAM,IACxD,MAAM,IAAI,MAAM,4BAA4B;CAE9C,MAAM,aACJ,iBAAiB,KAAA,IACb,WAAW,KAAK,SAAS,KAAK,QAAQ,GAAG,GAAG,IAAI,CAAC,IACjD,CAAC,QAAQ,KAAK,YAAY,CAAC;CACjC,MAAM,UAAoB,CAAC;CAC3B,KAAK,MAAM,aAAa,YAAY;EAClC,QAAQ,KAAK,SAAS;EACtB,IAAI;GACF,IAAI,EAAE,MAAM,KAAK,SAAS,EAAA,CAAG,OAAO,GAClC,MAAM,IAAI,MAAM,aAAa,UAAU,iBAAiB;GAE1D,OAAO;IACL,MAAM;IACN,QAAQ,iBAAiB,KAAA,IAAY,eAAe;IACpD,YAAY;GACd;EACF,SAAS,OAAO;GACd,IAAI,CAAC,SAAS,KAAK,KAAK,MAAM,SAAS,UAAU,MAAM;EACzD;CACF;CACA,MAAM,IAAI,MACR,kCAAkC,QAAQ,KAAK,IAAI,EAAE,mBAAmB,WAAW,KAAK,IAAI,EAAE,4BAChG;AACF;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,cAAc,OAA+B;CACpD,IAAI,OAAO,UAAU,YAAY,OAAO;CACxC,IAAI;EAEF,QAAQ,UAAU,QAAQ,CAAC,GAAG,KAAK;EACnC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,aAAa,OAAqC;CACzD,OACE,SAAS,KAAK,KACd,OAAO,MAAM,cAAc,eAC1B,MAAM,eAAe,KAAA,KAAa,cAAc,MAAM,UAAU;AAErE"}
|