typespec-http-zod 0.25.1 → 0.27.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/dist/src/api.d.ts +171 -116
- package/dist/src/api.js +456 -344
- package/dist/src/constraints.d.ts +46 -0
- package/dist/src/constraints.js +233 -10
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/lib.d.ts +32 -22
- package/dist/src/lib.js +53 -2
- package/dist/src/linter.d.ts +15 -0
- package/dist/src/linter.js +23 -0
- package/dist/src/registry.d.ts +1 -1
- package/dist/src/registry.js +158 -36
- package/dist/src/rules/redos-prone-pattern.rule.d.ts +27 -0
- package/dist/src/rules/redos-prone-pattern.rule.js +47 -0
- package/dist/src/runtime.d.ts +20 -34
- package/dist/src/types.d.ts +7 -0
- package/dist/src/types.js +13 -4
- package/dist/src/uri-template.d.ts +106 -0
- package/dist/src/uri-template.js +254 -0
- package/dist/src/zod.d.ts +11 -17
- package/dist/src/zod.js +87 -14
- package/package.json +6 -3
package/dist/src/api.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type EmitContext, type Program, type Type } from "@typespec/compiler";
|
|
2
2
|
import { type HttpOperation, type HttpService } from "@typespec/http";
|
|
3
3
|
import { SchemaRegistry } from "./registry.js";
|
|
4
|
+
import { type EmittedPathSegment } from "./uri-template.js";
|
|
5
|
+
export type { EmittedPathSegment } from "./uri-template.js";
|
|
4
6
|
/**
|
|
5
7
|
* `typespec-http-zod` - Zod validators and framework-free contract types from a TypeSpec HTTP
|
|
6
8
|
* service, agreeing with the OpenAPI document `@typespec/openapi3` publishes from the same source.
|
|
@@ -69,6 +71,79 @@ export declare function successStatusesOf(operation: HttpOperation): number[];
|
|
|
69
71
|
* listed above", and inventing one would be answering a question the contract left open.
|
|
70
72
|
*/
|
|
71
73
|
export type StatusKey = number | "default" | `${1 | 2 | 3 | 4 | 5}XX`;
|
|
74
|
+
/**
|
|
75
|
+
* A header one response declares, as a handler has to supply it.
|
|
76
|
+
*
|
|
77
|
+
* **The WIRE name only.** A result a handler returns is keyed by what the response sets, which is
|
|
78
|
+
* what the document publishes under `responses.<status>.headers`. The TypeSpec property behind it
|
|
79
|
+
* used to be carried beside the name so a runtime could read the value off a flattened result; that
|
|
80
|
+
* made the handler contract depend on a property name the document never states.
|
|
81
|
+
*/
|
|
82
|
+
export interface EmittedResponseHeader {
|
|
83
|
+
readonly name: string;
|
|
84
|
+
/** The TypeScript type of the value, so a server emitter can put it in a signature. */
|
|
85
|
+
readonly type: string;
|
|
86
|
+
/**
|
|
87
|
+
* The Zod expression for the value, so a server can check what it is about to send.
|
|
88
|
+
*
|
|
89
|
+
* The TYPE above constrains what a handler may return at compile time; this constrains what
|
|
90
|
+
* actually goes on the wire, which is the same split `schema` and the contract types already make
|
|
91
|
+
* for a body. A value that crossed a boundary the type system cannot see into - a service binding,
|
|
92
|
+
* a cast - is exactly what it catches.
|
|
93
|
+
*/
|
|
94
|
+
readonly schema: string;
|
|
95
|
+
/** The document's `required: false`. */
|
|
96
|
+
readonly optional: boolean;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* One response the document declares for an operation, keyed the way the document keys it.
|
|
100
|
+
*
|
|
101
|
+
* **Complete on its own, because a server emitter types a handler's return one member per arm.**
|
|
102
|
+
* The route used to carry these facts in five separate projections - a primary status and body, a
|
|
103
|
+
* list of failure arms, headers for numeric statuses only, media types for numeric statuses only,
|
|
104
|
+
* and a selector for choosing between successes - and each projection had a hole the others did not:
|
|
105
|
+
*
|
|
106
|
+
* - a range or `default` arm never carried its headers or media types;
|
|
107
|
+
* - a second success status carried the FIRST status's body, because the selector assumed one model;
|
|
108
|
+
* - a failure's inline body was an expression nothing outside the arm list could name;
|
|
109
|
+
* - an operation whose only success was a `2XX` range was dropped without a diagnostic.
|
|
110
|
+
*
|
|
111
|
+
* One record per status, built in one pass over `@typespec/http`'s own resolution, has no such gaps
|
|
112
|
+
* to keep in step.
|
|
113
|
+
*/
|
|
114
|
+
export interface EmittedResponse {
|
|
115
|
+
readonly status: StatusKey;
|
|
116
|
+
/** This status's body, as an emitted Zod expression, or `undefined` where it declares none. */
|
|
117
|
+
readonly schema: string | undefined;
|
|
118
|
+
/**
|
|
119
|
+
* Every media type the document names for this status, in declaration order.
|
|
120
|
+
*
|
|
121
|
+
* Empty exactly when the response carries no body. **A single type is still carried**, because
|
|
122
|
+
* assuming the one type is JSON is how a `text/plain` arm became indistinguishable from a JSON one.
|
|
123
|
+
*/
|
|
124
|
+
readonly contentTypes: readonly string[];
|
|
125
|
+
readonly headers: readonly EmittedResponseHeader[];
|
|
126
|
+
/**
|
|
127
|
+
* The body is raw binary, so `schema` is `z.unknown()` - see {@link isRawBinaryMediaType}. A server
|
|
128
|
+
* serves such a body as bytes or a stream rather than serialising it.
|
|
129
|
+
*/
|
|
130
|
+
readonly binary: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* The body is a stream of events or lines (`@typespec/streams`). The schema describes the stream as
|
|
133
|
+
* the document does, a string, which is not something a server validates a stream against.
|
|
134
|
+
*/
|
|
135
|
+
readonly streamed: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* The body's type is a string, so under a media type that is not JSON it IS the text served.
|
|
138
|
+
*
|
|
139
|
+
* **The fact a server needs to serve a non-JSON body at all.** A `string` declared as `text/plain`
|
|
140
|
+
* is validated and written as is; a MODEL declared as `application/xml` has no serialisation an
|
|
141
|
+
* emitter can derive from the document, so the text has to come from the application. Forty arms in
|
|
142
|
+
* the conformance corpus are the second kind and three are the first, and a server that could not
|
|
143
|
+
* tell them apart would either refuse the text or validate XML against a JSON schema.
|
|
144
|
+
*/
|
|
145
|
+
readonly textual: boolean;
|
|
146
|
+
}
|
|
72
147
|
/**
|
|
73
148
|
* Whether the operation declares `@useAuth(NoAuth)` - no caller is established for it.
|
|
74
149
|
*
|
|
@@ -153,9 +228,36 @@ export interface EmittedRoute {
|
|
|
153
228
|
* carries one of each.
|
|
154
229
|
*/
|
|
155
230
|
readonly reservedPathParameters: readonly string[];
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
231
|
+
/**
|
|
232
|
+
* **The route as a server has to mount it: one entry per `/` segment, read from the operation's
|
|
233
|
+
* RFC 6570 `uriTemplate`.** `path` cannot say this, because `@typespec/http` strips every operator
|
|
234
|
+
* from it: `array{.param*}` (`array.a.b`), `array{;param}` (`array;param=a,b`) and
|
|
235
|
+
* `array{/param}` (`array/a,b`) all reach `path` as `array{param}`. A router mounted from `path`
|
|
236
|
+
* answered 404 to 31 of the requests `@typespec/http-specs` declares conformant.
|
|
237
|
+
*
|
|
238
|
+
* An expression segment names its parameter's wire name, the literal text around it in the same
|
|
239
|
+
* segment, its operator and explode modifier, and whether it is optional or reserved. A server
|
|
240
|
+
* hands `pathSchema` the TEXT of that segment (for an exploding `/` expression, of every segment
|
|
241
|
+
* after it), and `pathSchema` undoes the expansion. A segment holding more than one expression is
|
|
242
|
+
* `unsupported`: no segment router can split it.
|
|
243
|
+
*/
|
|
244
|
+
readonly pathSegments: readonly EmittedPathSegment[];
|
|
245
|
+
/**
|
|
246
|
+
* A query string written into the route itself, as the pairs it spells:
|
|
247
|
+
* `/items?fixed=true{¶m}` carries `[["fixed", "true"]]`. It identifies the route as much as
|
|
248
|
+
* the path does, and it is never part of `pathSegments`. Empty when there is none.
|
|
249
|
+
*/
|
|
250
|
+
readonly literalQuery: readonly (readonly [string, string])[];
|
|
251
|
+
/**
|
|
252
|
+
* Every response the document declares, one per status key, in OpenAPI's precedence order. See
|
|
253
|
+
* {@link EmittedResponse}.
|
|
254
|
+
*/
|
|
255
|
+
readonly responses: readonly EmittedResponse[];
|
|
256
|
+
/**
|
|
257
|
+
* Media types the lowest exact success status can be served as - the basis for `Accept`
|
|
258
|
+
* negotiation between several operations sharing one route. Empty where that status carries no
|
|
259
|
+
* body, or where the operation declares no exact success status at all.
|
|
260
|
+
*/
|
|
159
261
|
readonly responseContentTypes: readonly string[];
|
|
160
262
|
/**
|
|
161
263
|
* Media types the request body may be SENT as.
|
|
@@ -177,6 +279,20 @@ export interface EmittedRoute {
|
|
|
177
279
|
* writes the server, exactly as `responseContentTypes` leaves negotiation to it.
|
|
178
280
|
*/
|
|
179
281
|
readonly requestContentTypes: readonly string[];
|
|
282
|
+
/**
|
|
283
|
+
* Whether the request body IS the text a caller sends, rather than a structure parsed out of it.
|
|
284
|
+
*
|
|
285
|
+
* **A server cannot answer this from the media type alone**, and `typespec-hono` had no way to ask:
|
|
286
|
+
* `@body body: string` under `text/plain` has no JSON, form or multipart reader, so the body was
|
|
287
|
+
* never read and the handler was handed nothing. The same media type carrying a MODEL has no
|
|
288
|
+
* serialisation this emitter can derive, and must still be refused - so the question is about the
|
|
289
|
+
* TYPE, which only this package resolves.
|
|
290
|
+
*
|
|
291
|
+
* True where the body's type is a string (a scalar based on `string`, a literal, a template, or a
|
|
292
|
+
* union of those - the same rule {@link EmittedResponse.textual} applies to a response) and the
|
|
293
|
+
* document declares no JSON media type for it.
|
|
294
|
+
*/
|
|
295
|
+
readonly requestTextual: boolean;
|
|
180
296
|
readonly summary: string | undefined;
|
|
181
297
|
readonly requestSchema: string | undefined;
|
|
182
298
|
/**
|
|
@@ -191,7 +307,16 @@ export interface EmittedRoute {
|
|
|
191
307
|
* request. It read as "the parameters" and was the field an adopter reached for first.
|
|
192
308
|
*/
|
|
193
309
|
readonly pathSchema: string | undefined;
|
|
310
|
+
/** Cookie parameters, as one object schema, or `undefined` where the operation declares none. */
|
|
311
|
+
readonly cookieSchema: string | undefined;
|
|
194
312
|
readonly querySchema: string | undefined;
|
|
313
|
+
/**
|
|
314
|
+
* The query OBJECT itself, which differs from `querySchema` only where a form-exploded record or
|
|
315
|
+
* model is gathered into it: `querySchema` is then `z.preprocess(gather, <this>)`, the validator a
|
|
316
|
+
* request's raw query goes through, and this is the object with a `.shape` a consumer building
|
|
317
|
+
* arguments from already-structured JSON can spread. Equal to `querySchema` otherwise.
|
|
318
|
+
*/
|
|
319
|
+
readonly queryFieldsSchema: string | undefined;
|
|
195
320
|
readonly headerSchema: string | undefined;
|
|
196
321
|
/** The header schema minus `accept`, used when this route's operations negotiate. */
|
|
197
322
|
readonly negotiatedHeaderSchema: string | undefined;
|
|
@@ -200,21 +325,6 @@ export interface EmittedRoute {
|
|
|
200
325
|
readonly name: string;
|
|
201
326
|
readonly value: string;
|
|
202
327
|
} | undefined;
|
|
203
|
-
/**
|
|
204
|
-
* `undefined` when the operation's success response carries no body - a `204`, or any `@delete`
|
|
205
|
-
* returning `void`.
|
|
206
|
-
*
|
|
207
|
-
* **This used to be required, and requiring it silently deleted routes.** `collectRoutes`
|
|
208
|
-
* skipped any operation `successBodyOf` could not answer for, with no diagnostic: measured across
|
|
209
|
-
* `@typespec/http-specs`, the document declared 540 operations and this emitter mounted 256, with
|
|
210
|
-
* 282 of the 284 missing ones bodyless. `payload/multipart` produced `GENERATED_ROUTES = []`
|
|
211
|
-
* against seventeen declared operations and compiled clean. Even `parameters/path` lost both of
|
|
212
|
-
* its operations, because they answer `NoContentResponse`.
|
|
213
|
-
*
|
|
214
|
-
* A bodyless success is ordinary HTTP, not an edge case. The route is emitted; a server
|
|
215
|
-
* answers the declared status with no body.
|
|
216
|
-
*/
|
|
217
|
-
readonly responseSchema: string | undefined;
|
|
218
328
|
/**
|
|
219
329
|
* The input property that receives the UNPARSED body, when the operation declares one.
|
|
220
330
|
*
|
|
@@ -254,56 +364,19 @@ export interface EmittedRoute {
|
|
|
254
364
|
* permits, in a shape that contract forbids.
|
|
255
365
|
*/
|
|
256
366
|
readonly optionalBody: boolean;
|
|
257
|
-
/** Declared failures, each with the schema for its OWN body, in OpenAPI's precedence order. */
|
|
258
|
-
readonly errorArms: readonly {
|
|
259
|
-
readonly status: StatusKey;
|
|
260
|
-
readonly schema: string | undefined;
|
|
261
|
-
}[];
|
|
262
367
|
/**
|
|
263
|
-
*
|
|
368
|
+
* **Whether the operation needs a caller, in the three states its `security` can say.**
|
|
264
369
|
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* all. Reported as blocking by a consumer, and it is a fact the document already states.
|
|
370
|
+
* - `none`: no requirement asks for anything (`@useAuth(NoAuth)`, or no authentication at all).
|
|
371
|
+
* - `optional`: an anonymous alternative sits beside a real one (`NoAuth | BearerAuth`). A caller
|
|
372
|
+
* who presents a credential is authenticated; one who presents none is still admitted.
|
|
373
|
+
* - `required`: every alternative asks for something.
|
|
270
374
|
*
|
|
271
|
-
* **
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* the wire and `correlationId` in the handler's result, and an emitter given only one of them would
|
|
275
|
-
* have to guess the other.
|
|
375
|
+
* **This replaced `noAuth`, which could not tell the first two apart**, so a server passing it
|
|
376
|
+
* through treated `NoAuth | BearerAuth` as "no caller", and a caller with a valid token was never
|
|
377
|
+
* seen as one.
|
|
276
378
|
*/
|
|
277
|
-
readonly
|
|
278
|
-
readonly status: StatusKey;
|
|
279
|
-
readonly headers: readonly {
|
|
280
|
-
readonly name: string;
|
|
281
|
-
readonly property: string;
|
|
282
|
-
/** The TypeScript type of the value, so a server emitter can put it in a signature. */
|
|
283
|
-
readonly type: string;
|
|
284
|
-
}[];
|
|
285
|
-
}[];
|
|
286
|
-
/**
|
|
287
|
-
* The media types each response status offers.
|
|
288
|
-
*
|
|
289
|
-
* **`responseContentTypes` above carries this for the PRIMARY status only, and an arm carried
|
|
290
|
-
* none at all.** An operation whose one status offers `application/json` and `text/event-stream`
|
|
291
|
-
* emitted a single arm holding the JSON schema, and the alternative was dropped from the list
|
|
292
|
-
* entirely, so `deps.respond` could not tell what it was answering with and a non-JSON operation
|
|
293
|
-
* could not be served faithfully. Reported by two consumers independently.
|
|
294
|
-
*/
|
|
295
|
-
readonly responseMediaTypes: readonly {
|
|
296
|
-
readonly status: StatusKey;
|
|
297
|
-
readonly contentTypes: readonly string[];
|
|
298
|
-
}[];
|
|
299
|
-
/**
|
|
300
|
-
* No caller is established, so the operation receives no `ServiceContext`.
|
|
301
|
-
*
|
|
302
|
-
* Whether a tenant exists follows from whether the request was authenticated - there is no user,
|
|
303
|
-
* account or membership to build one from otherwise. Reading it here is what lets a server
|
|
304
|
-
* derive an operation's call shape rather than a hand-written table restating it per row.
|
|
305
|
-
*/
|
|
306
|
-
readonly noAuth: boolean;
|
|
379
|
+
readonly authentication: "none" | "optional" | "required";
|
|
307
380
|
/**
|
|
308
381
|
* The OAuth scopes the operation requires, from `@useAuth`.
|
|
309
382
|
*
|
|
@@ -317,7 +390,7 @@ export interface EmittedRoute {
|
|
|
317
390
|
/**
|
|
318
391
|
* What the DOCUMENT says a caller must satisfy, in the shape the document says it.
|
|
319
392
|
*
|
|
320
|
-
* **`scopes`
|
|
393
|
+
* **`scopes` is a lossy projection of this (and a boolean `noAuth` was another), and publishing only those was a defect
|
|
321
394
|
* both server emitters had to work around.** A flat scope union cannot say WHICH scheme demanded
|
|
322
395
|
* what, so `@useAuth(BearerAuth)` -- which reaches OpenAPI as `security: [{ "BearerAuth": [] }]`
|
|
323
396
|
* -- arrived here as an empty scope list indistinguishable from no authentication at all. An
|
|
@@ -325,30 +398,12 @@ export interface EmittedRoute {
|
|
|
325
398
|
* again and rebuild this itself, and two of them did.
|
|
326
399
|
*
|
|
327
400
|
* Satisfying **any one** requirement authorises; every scheme within a requirement must be
|
|
328
|
-
* satisfied together.
|
|
329
|
-
*
|
|
401
|
+
* satisfied together. An anonymous alternative is the empty requirement `{}`, exactly as the
|
|
402
|
+
* document publishes it: `NoAuth | BearerAuth` is `[{}, { "BearerAuth": [] }]` and
|
|
403
|
+
* `@useAuth(NoAuth)` is `[{}]`. Empty where the operation declares no authentication at all.
|
|
404
|
+
* Whether a caller is needed is {@link EmittedRoute.authentication}.
|
|
330
405
|
*/
|
|
331
406
|
readonly security: readonly SecurityRequirement[];
|
|
332
|
-
/** Which of two success statuses to answer, and the literal property that decides it. */
|
|
333
|
-
readonly statusBy: {
|
|
334
|
-
property: string;
|
|
335
|
-
value: boolean | string;
|
|
336
|
-
status: number;
|
|
337
|
-
} | undefined;
|
|
338
|
-
/**
|
|
339
|
-
* The property a handler sets to choose between several declared success statuses, and the
|
|
340
|
-
* statuses it may carry - read from a `@statusCode` typed as a union of literals.
|
|
341
|
-
*
|
|
342
|
-
* **Published because the handler has to be able to SAY it.** The property is HTTP metadata, so it
|
|
343
|
-
* is stripped from the body schema (correctly - it is not body), which means a server emitter has
|
|
344
|
-
* to add it back to the type a handler returns or the arms name something unsatisfiable.
|
|
345
|
-
*/
|
|
346
|
-
readonly statusSelector: {
|
|
347
|
-
property: string;
|
|
348
|
-
statuses: readonly number[];
|
|
349
|
-
} | undefined;
|
|
350
|
-
/** The schema for the SECOND success status, when the operation declares two distinct arms. */
|
|
351
|
-
readonly alternateResponseSchema: string | undefined;
|
|
352
407
|
}
|
|
353
408
|
export declare function collectRoutes(program: Program, registry: SchemaRegistry, service: HttpService): EmittedRoute[];
|
|
354
409
|
/** Whether emitted source references `name` as an identifier rather than as part of a longer one. */
|
|
@@ -365,10 +420,36 @@ export interface RouteSchemaNames {
|
|
|
365
420
|
readonly operationId: string;
|
|
366
421
|
readonly path: string | undefined;
|
|
367
422
|
readonly query: string | undefined;
|
|
423
|
+
/**
|
|
424
|
+
* The query object's identifier, with a `.shape`. Equal to `query` except where a form-exploded
|
|
425
|
+
* record or model is gathered, when `query` is `z.preprocess(gather, <queryFields>)` and has no
|
|
426
|
+
* `.shape`. A consumer spreading request fields reads this; a validator of a raw request reads `query`.
|
|
427
|
+
*/
|
|
428
|
+
readonly queryFields: string | undefined;
|
|
368
429
|
readonly header: string | undefined;
|
|
430
|
+
/**
|
|
431
|
+
* Cookie parameters. **Optional on the interface, so a server emitter that does not read it yet
|
|
432
|
+
* still compiles** - this arrived after the other four and two emitters consume this type.
|
|
433
|
+
*/
|
|
434
|
+
readonly cookie?: string | undefined;
|
|
369
435
|
readonly body: string | undefined;
|
|
370
|
-
|
|
371
|
-
|
|
436
|
+
/**
|
|
437
|
+
* The identifier each response's body is declared under, parallel to `EmittedRoute.responses` and
|
|
438
|
+
* in the same order. `schema` is `undefined` exactly where that response carries no body.
|
|
439
|
+
*
|
|
440
|
+
* **An identifier for every arm, failures included.** A success body used to be named and a
|
|
441
|
+
* failure's inline body stayed an expression inside the arm list, so a server emitter could not
|
|
442
|
+
* write `z.infer<typeof ...>` for the one response it most needs a handler to be able to return.
|
|
443
|
+
*/
|
|
444
|
+
readonly arms: readonly {
|
|
445
|
+
readonly status: StatusKey;
|
|
446
|
+
readonly schema: string | undefined;
|
|
447
|
+
/**
|
|
448
|
+
* The identifier holding this status's declared response headers, where it declares any.
|
|
449
|
+
* **Optional on the interface**, so a server emitter that does not check them yet still builds.
|
|
450
|
+
*/
|
|
451
|
+
readonly headers?: string | undefined;
|
|
452
|
+
}[];
|
|
372
453
|
/**
|
|
373
454
|
* The `readonly ResponseArm[]` const - what the operation may answer with, and with which body.
|
|
374
455
|
*
|
|
@@ -407,33 +488,7 @@ export interface ResolvedServiceOptions {
|
|
|
407
488
|
/** Whether every emitted validator is wrapped in `z.compile()`. See the option's own docblock. */
|
|
408
489
|
readonly compileSchemas: boolean;
|
|
409
490
|
readonly keyVocabularies: readonly string[];
|
|
410
|
-
readonly runtimeModule: string;
|
|
411
491
|
/** The command that regenerates, for the banner. `undefined` keeps the generic line. */
|
|
412
492
|
readonly regenerateHint: string | undefined;
|
|
413
493
|
}
|
|
414
|
-
|
|
415
|
-
export declare const DEFAULT_RUNTIME_MODULE = "typespec-http-zod/runtime";
|
|
416
|
-
/**
|
|
417
|
-
* What a WRAPPING emitter may change about this one, without changing what a consumer may set.
|
|
418
|
-
*
|
|
419
|
-
* **`defaultRuntimeModule` is a default, not an override.** A consumer's `runtime-module` still
|
|
420
|
-
* wins; this only decides what `schemas.gen.ts` and any file a wrapper emits beside it import from
|
|
421
|
-
* when the consumer says nothing.
|
|
422
|
-
*
|
|
423
|
-
* **It exists because this package's own default is wrong for a wrapper, and shipped that way.**
|
|
424
|
-
* `typespec-hono` emits `import type { AppEnv, Awaitable, Ctx, Result, RouteDeps }` and
|
|
425
|
-
* `import { selectContentType }` from whatever this resolves to. None of those six is exported here -
|
|
426
|
-
* this module exports `ResponseArm` and `armFor`, and nothing else. Worse, `typespec-http-zod` is a
|
|
427
|
-
* TRANSITIVE dependency of a `typespec-hono` consumer, so under a strict `node_modules` the specifier
|
|
428
|
-
* does not resolve at all whatever it exports. Measured in a fresh project installed from tarballs:
|
|
429
|
-
* `tsp compile` succeeded with zero diagnostics and `tsc` then reported **two `TS2307`s**, one in each
|
|
430
|
-
* generated file.
|
|
431
|
-
*
|
|
432
|
-
* Nothing in either suite saw it, because every compile in both harnesses sets `runtime-module`
|
|
433
|
-
* explicitly. The default branch was ungraded across 240 tests.
|
|
434
|
-
*/
|
|
435
|
-
export interface EmitHttpZodOptions {
|
|
436
|
-
/** The specifier generated files import their runtime contract from when the consumer sets none. */
|
|
437
|
-
readonly defaultRuntimeModule?: string;
|
|
438
|
-
}
|
|
439
|
-
export declare function emitHttpZod(context: EmitContext, wrapper?: EmitHttpZodOptions): Promise<readonly EmittedService[]>;
|
|
494
|
+
export declare function emitHttpZod(context: EmitContext): Promise<readonly EmittedService[]>;
|