typespec-hono 0.22.0 → 0.24.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 +102 -62
- package/dist/src/app.d.ts +95 -43
- package/dist/src/app.js +845 -251
- package/dist/src/emitter.d.ts +3 -3
- package/dist/src/emitter.js +52 -45
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +2 -0
- package/dist/src/lib.d.ts +13 -4
- package/dist/src/lib.js +41 -1
- package/dist/src/linter.d.ts +20 -0
- package/dist/src/linter.js +32 -0
- package/dist/src/rules/regexp-router-unsupported.rule.d.ts +32 -0
- package/dist/src/rules/regexp-router-unsupported.rule.js +65 -0
- package/dist/src/runtime.d.ts +160 -80
- package/dist/src/runtime.js +152 -1
- package/package.json +16 -16
- package/src/runtime.ts +217 -85
- package/dist/src/security.d.ts +0 -29
- package/dist/src/security.js +0 -48
package/README.md
CHANGED
|
@@ -58,10 +58,16 @@ model Widget {
|
|
|
58
58
|
name: string;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
@error
|
|
62
|
+
model NotFound {
|
|
63
|
+
@statusCode statusCode: 404;
|
|
64
|
+
message: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
61
67
|
@route("/widgets")
|
|
62
68
|
interface WidgetRoutes {
|
|
63
69
|
@get list(@query limit?: int32): Widget[];
|
|
64
|
-
@get read(@path id: string): Widget;
|
|
70
|
+
@get read(@path id: string): Widget | NotFound;
|
|
65
71
|
}
|
|
66
72
|
```
|
|
67
73
|
|
|
@@ -71,79 +77,125 @@ pnpm exec tsp compile .
|
|
|
71
77
|
|
|
72
78
|
### `src/index.ts`
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
A handler returns `{ status, body }` for any response its operation declares, the failures included.
|
|
81
|
+
`input` and every declared response are known from the spec, so a handler returning a status the spec
|
|
82
|
+
does not declare, or the wrong body for a status, does not compile:
|
|
76
83
|
|
|
77
84
|
```ts
|
|
78
85
|
import { Hono } from "hono";
|
|
79
|
-
import { registerRoutes } from "./generated/app.gen.js";
|
|
80
|
-
import { deps } from "./deps.js";
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
WidgetRoutes_list: (ctx, input) => widgets.slice(0, input.limit ?? 20),
|
|
84
|
-
WidgetRoutes_read: (ctx, input) =>
|
|
85
|
-
|
|
86
|
+
import { registerRoutes, type Operations } from "./generated/app.gen.js";
|
|
87
|
+
import { deps, type Caller } from "./deps.js";
|
|
88
|
+
|
|
89
|
+
const handlers = {
|
|
90
|
+
WidgetRoutes_list: (ctx, input) => ({ status: 200, body: widgets.slice(0, input.limit ?? 20) }),
|
|
91
|
+
WidgetRoutes_read: (ctx, input) => {
|
|
92
|
+
const widget = widgets.find((w) => w.id === input.id);
|
|
93
|
+
return widget === undefined
|
|
94
|
+
? { status: 404, body: { message: `no widget ${input.id}` } }
|
|
95
|
+
: { status: 200, body: widget };
|
|
96
|
+
},
|
|
97
|
+
} satisfies Operations<Caller>;
|
|
86
98
|
|
|
87
|
-
export default registerRoutes(new Hono(),
|
|
99
|
+
export default registerRoutes(new Hono(), () => handlers, deps);
|
|
88
100
|
```
|
|
89
101
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
102
|
+
`satisfies` keeps each `status` a literal, which is what selects the response it belongs to. Without
|
|
103
|
+
it, `status: 404` widens to `number`, which no declared response admits.
|
|
104
|
+
|
|
105
|
+
The generated route serves each response with the Hono call for it - `c.json(body, 404)` for the
|
|
106
|
+
failure above - after checking the body against the schema the document publishes for that status. So
|
|
107
|
+
Hono's RPC client narrows a response body by its status, and a body the document does not permit
|
|
108
|
+
reaches `app.onError` as a `ResponseContractError` rather than a caller.
|
|
109
|
+
|
|
110
|
+
Leave the factory passed to `registerRoutes` unannotated: annotating it widens the value and disables
|
|
111
|
+
the check that catches a handler for an operation the spec no longer declares. It is a factory rather
|
|
112
|
+
than an object because a Workers service binding lives on `c.env` and exists only for the duration of
|
|
113
|
+
a request.
|
|
93
114
|
|
|
94
115
|
### `src/deps.ts`
|
|
95
116
|
|
|
96
|
-
|
|
117
|
+
Five hooks, each answering something the spec does not contain:
|
|
97
118
|
|
|
98
|
-
| hook | the spec says
|
|
99
|
-
| --------------- |
|
|
100
|
-
| `authorize` | which schemes and scopes an operation needs
|
|
101
|
-
| `context` | whether a caller is required
|
|
102
|
-
| `noContext` |
|
|
103
|
-
| `notAcceptable` | which media types are offered
|
|
104
|
-
| `invalid` | the schema
|
|
105
|
-
| `respond` | every status arm and its schema | which arm this result is |
|
|
119
|
+
| hook | the spec says | you say |
|
|
120
|
+
| --------------- | ---------------------------------------------- | ------------------------------------ |
|
|
121
|
+
| `authorize` | which schemes and scopes an operation needs | whether this caller satisfies them |
|
|
122
|
+
| `context` | whether a caller is none, optional or required | who the caller is |
|
|
123
|
+
| `noContext` | | what to answer when there is not one |
|
|
124
|
+
| `notAcceptable` | which media types are offered | what to answer when none match |
|
|
125
|
+
| `invalid` | the schema | what a validation failure looks like |
|
|
106
126
|
|
|
107
127
|
```ts
|
|
108
|
-
import type { RouteDeps } from "./generated/runtime.gen.js";
|
|
128
|
+
import type { AppEnv, RouteDeps } from "./generated/runtime.gen.js";
|
|
109
129
|
|
|
110
|
-
export
|
|
130
|
+
export interface Caller {
|
|
131
|
+
readonly userId: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export const deps: RouteDeps<AppEnv, Caller> = {
|
|
135
|
+
// The requirements are the document's, verbatim: `[{ BearerAuth: [] }]`. Satisfying any ONE of
|
|
136
|
+
// them authorises; every scheme within one must be satisfied together. Waving a scheme through
|
|
137
|
+
// because you do not check it is how a gated route ends up ungated.
|
|
111
138
|
authorize: (requirements) => async (c, next) => {
|
|
139
|
+
const bearer = /^Bearer\s+(\S+)$/i.exec(c.req.header("authorization") ?? "")?.[1];
|
|
140
|
+
const satisfied = requirements.some((requirement) =>
|
|
141
|
+
Object.entries(requirement).every(
|
|
142
|
+
([scheme, scopes]) =>
|
|
143
|
+
scheme === "BearerAuth" && bearer !== undefined && scopes.length === 0,
|
|
144
|
+
),
|
|
145
|
+
);
|
|
146
|
+
if (!satisfied) return c.json({ error: "unauthorized" }, 401);
|
|
112
147
|
await next();
|
|
148
|
+
return undefined;
|
|
149
|
+
},
|
|
150
|
+
context: (c) => {
|
|
151
|
+
const userId = c.req.header("x-user");
|
|
152
|
+
return userId === undefined ? null : { userId };
|
|
113
153
|
},
|
|
114
|
-
context: (c) => ({ userId: c.req.header("x-user") }),
|
|
115
154
|
noContext: (c) => c.json({ error: "unauthorized" }, 401),
|
|
116
155
|
notAcceptable: (c, offered) => c.json({ error: "not_acceptable", offered }, 406),
|
|
117
156
|
invalid: (result, c) => (result.success ? undefined : c.json({ error: "invalid" }, 400)),
|
|
118
|
-
respond: (c, arms, result) => c.json(result as never, 200),
|
|
119
157
|
};
|
|
120
158
|
```
|
|
121
159
|
|
|
122
|
-
|
|
123
|
-
|
|
160
|
+
**`authorize` is the gate the document publishes, and an empty one is an open door.** A requirement
|
|
161
|
+
naming a scheme you do not check must not be satisfied: `[{}]`, which `@useAuth(NoAuth | X)` publishes
|
|
162
|
+
for its anonymous alternative, is the only requirement every caller satisfies, and it is satisfied by
|
|
163
|
+
`Object.entries({}).every(...)` being vacuously true rather than by a special case.
|
|
164
|
+
|
|
165
|
+
`context` is told `"none"` (the operation needs nobody), `"optional"` (anonymous access is one
|
|
166
|
+
alternative, so read a credential if one was presented) or `"required"`. Whatever it returns is what
|
|
167
|
+
every handler receives as `ctx`. Your Hono environment - bindings
|
|
168
|
+
and variables - is an augmentation of the emitted `AppEnv`:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
declare module "./generated/runtime.gen.js" {
|
|
172
|
+
interface AppEnv {
|
|
173
|
+
Bindings: { DB: D1Database };
|
|
174
|
+
Variables: { requestId: string };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Routing, request validation, the handler types and how each declared response is served come from the
|
|
180
|
+
spec. What is left is the four files above.
|
|
124
181
|
|
|
125
182
|
## What it emits
|
|
126
183
|
|
|
127
184
|
Into your output directory:
|
|
128
185
|
|
|
129
|
-
| file | what it is
|
|
130
|
-
| ---------------------- |
|
|
131
|
-
| `app.gen.ts` | the server: routes, validators, and the
|
|
132
|
-
| `runtime.gen.ts` | the types your `deps` implements against, and the helpers the server calls
|
|
133
|
-
| `schemas.gen.ts` | a Zod schema for every request and response, and the status arms each declares
|
|
134
|
-
| `vocabularies.gen.ts` | shared enums, where the spec declares them
|
|
135
|
-
| `requests.gen.ts` | request types, when `contracts-output-dir` is set
|
|
136
|
-
| `wire-contract.gen.ts` | assertions that the schemas and the types agree, with the same option
|
|
186
|
+
| file | what it is |
|
|
187
|
+
| ---------------------- | -------------------------------------------------------------------------------- |
|
|
188
|
+
| `app.gen.ts` | the server: routes, validators, what each operation may answer, and the handlers |
|
|
189
|
+
| `runtime.gen.ts` | the types your `deps` implements against, and the helpers the server calls |
|
|
190
|
+
| `schemas.gen.ts` | a Zod schema for every request and response, and the status arms each declares |
|
|
191
|
+
| `vocabularies.gen.ts` | shared enums, where the spec declares them |
|
|
192
|
+
| `requests.gen.ts` | request types, when `contracts-output-dir` is set |
|
|
193
|
+
| `wire-contract.gen.ts` | assertions that the schemas and the types agree, with the same option |
|
|
137
194
|
|
|
138
195
|
The last four are `typespec-http-zod`'s; see its README for what they contain.
|
|
139
196
|
|
|
140
|
-
Your own code imports from `
|
|
141
|
-
|
|
142
|
-
```ts
|
|
143
|
-
import type { Ctx, RouteDeps } from "./generated/runtime.gen.js";
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
Setting `runtime-module` replaces it with a module of your own, and it is then not written.
|
|
197
|
+
`runtime.gen.ts` is written on every compile. Your own code imports from it and augments `AppEnv` in
|
|
198
|
+
it, and nothing replaces it.
|
|
147
199
|
|
|
148
200
|
Routes are grouped into a sub-app per resource and mounted with `app.route()`, following
|
|
149
201
|
[Hono's best-practices guide](https://hono.dev/docs/guides/best-practices). Handlers are written
|
|
@@ -152,27 +204,15 @@ handler in another file cannot infer its path parameters. A resource with a sing
|
|
|
152
204
|
sub-app.
|
|
153
205
|
|
|
154
206
|
The output is plain `Hono` and `@hono/zod-validator`, not `@hono/zod-openapi`. That package generates
|
|
155
|
-
a document from the code, which would compete with the one openapi3 publishes from the spec.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
import { registerRoutes } from "./generated/app.gen.js";
|
|
160
|
-
|
|
161
|
-
// Leave handlersFor unannotated. Annotating it widens the value and disables the
|
|
162
|
-
// exhaustiveness check that catches a handler for an operation the spec no longer declares.
|
|
163
|
-
const handlersFor = (c) => backendFor(c.env);
|
|
164
|
-
const routes = registerRoutes(new Hono<AppEnv>(), handlersFor, deps);
|
|
165
|
-
|
|
166
|
-
export default routes;
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
`handlersFor` is a factory rather than an object because a Workers service binding lives on `c.env`
|
|
170
|
-
and exists only for the duration of a request.
|
|
207
|
+
a document from the code, which would compete with the one openapi3 publishes from the spec. The
|
|
208
|
+
responses a route serves are the ones `@hono/zod-openapi` would require of it: across the conformance
|
|
209
|
+
corpus, what Hono's RPC client infers for 619 routes is compared with what `RouteConfigToTypedResponse`
|
|
210
|
+
derives from the published document.
|
|
171
211
|
|
|
172
212
|
## Docs
|
|
173
213
|
|
|
174
|
-
- [Guides](docs/guides.md): middleware, the RPC client, authentication, base
|
|
175
|
-
request bodies, streaming, observability
|
|
214
|
+
- [Guides](docs/guides.md): declared failures, middleware, the RPC client, authentication, base
|
|
215
|
+
paths, HEAD operations, request bodies, streaming, observability, upgrading
|
|
176
216
|
- [Cloudflare Workers](docs/cloudflare-workers.md): which router to pick, and what the bundle costs
|
|
177
217
|
- [Reference](docs/reference.md): every option, every diagnostic, and the known limits
|
|
178
218
|
- [Releasing](docs/releasing.md): rehearsing a two-package release against a local registry,
|
package/dist/src/app.d.ts
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
|
|
1
|
+
import { type EmittedPathSegment, type EmittedRoute, type EmittedService, type StatusKey } from "typespec-http-zod";
|
|
2
|
+
/**
|
|
3
|
+
* Hono's status codes, group by group, exactly as `hono/utils/http-status` declares them.
|
|
4
|
+
*
|
|
5
|
+
* **The generated route needs the LITERALS, not only the type.** A range arm is served from a
|
|
6
|
+
* `switch` on the result's status, and TypeScript narrows the result to one member only through a
|
|
7
|
+
* `case` label per literal: a type guard narrows the status and leaves the result a union, and
|
|
8
|
+
* merging the range into `default` pairs every body with every status. Both measured on hono 4.13.1.
|
|
9
|
+
*
|
|
10
|
+
* `test/status-codes.test.ts` holds these equal to Hono's own unions, so a status Hono adds fails a
|
|
11
|
+
* test rather than silently falling out of a range.
|
|
12
|
+
*/
|
|
13
|
+
export declare const STATUS_GROUPS: {
|
|
14
|
+
readonly 1: {
|
|
15
|
+
readonly type: "InfoStatusCode";
|
|
16
|
+
readonly codes: readonly [100, 101, 102, 103];
|
|
17
|
+
};
|
|
18
|
+
readonly 2: {
|
|
19
|
+
readonly type: "SuccessStatusCode";
|
|
20
|
+
readonly codes: readonly [200, 201, 202, 203, 204, 205, 206, 207, 208, 226];
|
|
21
|
+
};
|
|
22
|
+
readonly 3: {
|
|
23
|
+
readonly type: "RedirectStatusCode";
|
|
24
|
+
readonly codes: readonly [300, 301, 302, 303, 304, 305, 306, 307, 308];
|
|
25
|
+
};
|
|
26
|
+
readonly 4: {
|
|
27
|
+
readonly type: "ClientErrorStatusCode";
|
|
28
|
+
readonly codes: readonly [400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451];
|
|
29
|
+
};
|
|
30
|
+
readonly 5: {
|
|
31
|
+
readonly type: "ServerErrorStatusCode";
|
|
32
|
+
readonly codes: readonly [500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511];
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Where every generated file imports its runtime from: the copy this package writes beside them.
|
|
37
|
+
*
|
|
38
|
+
* Declared here, where the import is rendered, and re-exported by the emitter that writes the file.
|
|
39
|
+
*/
|
|
40
|
+
export declare const DEFAULT_RUNTIME_MODULE = "./runtime.gen.js";
|
|
41
|
+
/** Hono's `ContentlessStatusCode`: a status that cannot carry a body, so `c.json` refuses it. */
|
|
42
|
+
export declare const CONTENTLESS_STATUS_CODES: readonly [101, 204, 205, 304];
|
|
3
43
|
/**
|
|
4
44
|
* The header every emitted file carries.
|
|
5
45
|
*
|
|
@@ -10,46 +50,67 @@ import { type EmittedRoute, type EmittedService } from "typespec-http-zod";
|
|
|
10
50
|
*/
|
|
11
51
|
export declare function generatedBanner(hint: string | undefined): string;
|
|
12
52
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
53
|
+
* The Hono route for a route template, from the segments `typespec-http-zod` reads out of the
|
|
54
|
+
* operation's RFC 6570 `uriTemplate`.
|
|
55
|
+
*
|
|
56
|
+
* **This used to convert `route.path`, which has every operator stripped**, so `array{.param*}`,
|
|
57
|
+
* `array{;param}` and `optional{/name}` were mounted as `array:param` and `optional:name`, which Hono
|
|
58
|
+
* does not match at all. Measured by request: 31 of the URIs `@typespec/http-specs` `routes` and
|
|
59
|
+
* `parameters/path` declare answered 404 from a server generated from them.
|
|
60
|
+
*
|
|
61
|
+
* - A whole-segment expression is `:name`; a reserved or exploding `/` one crosses `/`, so it is
|
|
62
|
+
* `:name{.+}` (Hono's spelling of greedy); an optional last segment is `:name?`.
|
|
63
|
+
* - An expression written beside literal text, or with a label or matrix operator, is a pattern
|
|
64
|
+
* parameter matching the whole segment: `:param{array\.[^\x2F]*}`. The captured text is the
|
|
65
|
+
* segment, and the path validator undoes the expansion. `\x2F` rather than `/`, so the mounted
|
|
66
|
+
* path still splits into its segments on `/` for the ordering and sub-app rules below.
|
|
67
|
+
*
|
|
68
|
+
* **A name Hono cannot carry is REFUSED rather than approximated**, and so is a segment holding two
|
|
69
|
+
* expressions, which no segment router can split. The segment stays literal, so it matches nothing
|
|
70
|
+
* rather than the wrong thing. A space, `+` and `!` are the characters that fail; a hyphen, a dot and
|
|
71
|
+
* a tilde do not.
|
|
72
|
+
*
|
|
73
|
+
* **This runs at RENDER time, not during collection**, so what a request body must look like never
|
|
74
|
+
* depends on whether one framework's router can express the path.
|
|
75
|
+
*/
|
|
76
|
+
export declare function toHonoPath(segments: readonly EmittedPathSegment[], refuse: (template: string, name: string) => void): string;
|
|
77
|
+
/**
|
|
78
|
+
* Whether Hono's `RegExpRouter` can compile this route set, and the route it names if not.
|
|
79
|
+
*
|
|
80
|
+
* **Hono's own router, imported statically.** `hono` is a required peer - `runtime.ts` imports it and
|
|
81
|
+
* the generated server cannot run without it - so there is nothing to degrade gracefully around, and
|
|
82
|
+
* a guarded import would claim a resilience this package does not need. Running the real router is
|
|
83
|
+
* what stops the check drifting from a rule Hono never documented.
|
|
84
|
+
*
|
|
85
|
+
* **`match` as well as `add`.** `RegExpRouter` builds its expressions lazily, so a conflict added
|
|
86
|
+
* through `add` alone can go unreported until the first request. One `match` forces the build.
|
|
34
87
|
*/
|
|
35
|
-
export declare function
|
|
88
|
+
export declare function regExpRouterRefusal(routes: readonly (readonly [string, string])[]): {
|
|
89
|
+
path: string;
|
|
90
|
+
reason: string;
|
|
91
|
+
} | undefined;
|
|
36
92
|
/**
|
|
37
|
-
*
|
|
93
|
+
* **The `[method, path]` pairs a router is given for one service**, exactly as the emitted server
|
|
94
|
+
* registers them.
|
|
38
95
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
96
|
+
* One definition, used by the `regexp-router-unsupported` linter rule, so the rule judges the route
|
|
97
|
+
* set the generated server really mounts. Built from the same helpers the render uses - the verb a
|
|
98
|
+
* route registers under, `app.on` falling back to `GET` as Hono itself does, and `toHonoPath` on the
|
|
99
|
+
* route's segments - and prefixed with each base path the service is served under.
|
|
42
100
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* the template is a derived artefact rather than the source of truth.
|
|
101
|
+
* **The full path, never the one relative to a sub-app.** The relative form is what the emitted
|
|
102
|
+
* text says and not what any router is given. Judging it reports conflicts between routes that are
|
|
103
|
+
* not siblings at all: measured on five fixtures, two were called unmountable that mount perfectly.
|
|
47
104
|
*/
|
|
48
|
-
|
|
105
|
+
export declare function routerTableFor(routes: readonly {
|
|
106
|
+
readonly verb: string;
|
|
107
|
+
readonly pathSegments: readonly EmittedPathSegment[];
|
|
108
|
+
}[], basePaths: readonly string[]): (readonly [string, string])[];
|
|
49
109
|
/** The one thing a Hono server cannot express, handed back rather than thrown. */
|
|
50
110
|
export interface RenderRefusals {
|
|
51
111
|
readonly unsupportedPathTemplate: (route: EmittedRoute, template: string, name: string) => void;
|
|
52
112
|
readonly unvalidatableMediaType: (route: EmittedRoute, types: readonly string[]) => void;
|
|
113
|
+
readonly unvalidatedResponseMediaType: (route: EmittedRoute, status: StatusKey, types: readonly string[]) => void;
|
|
53
114
|
}
|
|
54
115
|
/**
|
|
55
116
|
* The generated Hono server.
|
|
@@ -77,13 +138,4 @@ export declare function renderApp(emitted: EmittedService, refuse: RenderRefusal
|
|
|
77
138
|
* the document publishes `/api/v1/accounts`. Mounting at the root made every client generated from
|
|
78
139
|
* the document, and every "try it" in a rendered document, 404.
|
|
79
140
|
*/
|
|
80
|
-
basePaths?: readonly string[]
|
|
81
|
-
/**
|
|
82
|
-
* What the DOCUMENT says a caller must satisfy, per operation id.
|
|
83
|
-
*
|
|
84
|
-
* **Resolved by the caller rather than read off `EmittedRoute`**, because which schemes an
|
|
85
|
-
* operation accepts is a fact about the HTTP program and not part of the validator IR the library
|
|
86
|
-
* publishes. Keeping it out of that IR is what stops a Hono concern leaking into a package whose
|
|
87
|
-
* audience is wider.
|
|
88
|
-
*/
|
|
89
|
-
securityFor?: (verb: string, path: string) => readonly SecurityRequirement[]): string;
|
|
141
|
+
basePaths?: readonly string[]): string;
|