counterfact 2.5.1 → 2.7.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 +103 -140
- package/bin/README.md +25 -4
- package/bin/counterfact.js +208 -24
- package/bin/register-ts-loader.mjs +17 -0
- package/bin/ts-loader.mjs +31 -0
- package/dist/app.js +31 -21
- package/dist/counterfact-types/cookie-options.js +1 -0
- package/dist/counterfact-types/counterfact-response.js +7 -0
- package/dist/counterfact-types/example-names.js +1 -0
- package/dist/counterfact-types/example.js +1 -0
- package/dist/counterfact-types/generic-response-builder.js +1 -0
- package/dist/counterfact-types/http-status-code.js +1 -0
- package/dist/counterfact-types/if-has-key.js +1 -0
- package/dist/counterfact-types/index.js +0 -1
- package/dist/counterfact-types/maybe-promise.js +1 -0
- package/dist/counterfact-types/media-type.js +1 -0
- package/dist/counterfact-types/omit-all.js +1 -0
- package/dist/counterfact-types/omit-value-when-never.js +1 -0
- package/dist/counterfact-types/open-api-content.js +1 -0
- package/dist/counterfact-types/open-api-operation.js +1 -0
- package/dist/counterfact-types/open-api-parameters.js +1 -0
- package/dist/counterfact-types/open-api-response.js +1 -0
- package/dist/counterfact-types/random-function.js +1 -0
- package/dist/counterfact-types/response-builder-factory.js +1 -0
- package/dist/counterfact-types/response-builder.js +1 -0
- package/dist/counterfact-types/wide-operation-argument.js +1 -0
- package/dist/counterfact-types/wide-response-builder.js +1 -0
- package/dist/migrate/update-route-types.js +30 -10
- package/dist/repl/raw-http-client.js +14 -14
- package/dist/repl/repl.js +119 -4
- package/dist/repl/route-builder.js +270 -0
- package/dist/server/config.js +1 -1
- package/dist/server/context-registry.js +44 -4
- package/dist/server/counterfact-types/cookie-options.ts +14 -0
- package/dist/server/counterfact-types/counterfact-response.ts +15 -0
- package/dist/server/counterfact-types/example-names.ts +13 -0
- package/dist/server/counterfact-types/example.ts +10 -0
- package/dist/server/counterfact-types/generic-response-builder.ts +164 -0
- package/dist/server/counterfact-types/http-status-code.ts +62 -0
- package/dist/server/counterfact-types/if-has-key.ts +19 -0
- package/dist/server/counterfact-types/index.ts +20 -328
- package/dist/server/counterfact-types/maybe-promise.ts +6 -0
- package/dist/server/counterfact-types/media-type.ts +6 -0
- package/dist/server/counterfact-types/omit-all.ts +11 -0
- package/dist/server/counterfact-types/omit-value-when-never.ts +11 -0
- package/dist/server/counterfact-types/open-api-content.ts +8 -0
- package/dist/server/counterfact-types/open-api-operation.ts +36 -0
- package/dist/server/counterfact-types/open-api-parameters.ts +16 -0
- package/dist/server/counterfact-types/open-api-response.ts +22 -0
- package/dist/server/counterfact-types/random-function.ts +9 -0
- package/dist/server/counterfact-types/response-builder-factory.ts +16 -0
- package/dist/server/counterfact-types/response-builder.ts +31 -0
- package/dist/server/counterfact-types/wide-operation-argument.ts +17 -0
- package/dist/server/counterfact-types/wide-response-builder.ts +26 -0
- package/dist/server/create-koa-app.js +1 -20
- package/dist/server/determine-module-kind.js +1 -1
- package/dist/server/dispatcher.js +39 -15
- package/dist/server/file-discovery.js +34 -0
- package/dist/server/json-to-xml.js +1 -1
- package/dist/server/koa-middleware.js +7 -1
- package/dist/server/load-openapi-document.js +13 -0
- package/dist/server/middleware-detector.js +8 -0
- package/dist/server/module-dependency-graph.js +4 -1
- package/dist/server/module-loader.js +81 -33
- package/dist/server/module-tree.js +26 -23
- package/dist/server/openapi-middleware.js +2 -2
- package/dist/server/openapi-watcher.js +35 -0
- package/dist/server/registry.js +2 -2
- package/dist/server/request-validator.js +57 -0
- package/dist/server/response-builder.js +3 -0
- package/dist/server/response-validator.js +58 -0
- package/dist/server/scenario-registry.js +29 -0
- package/dist/server/tools.js +2 -2
- package/dist/server/transpiler.js +13 -5
- package/dist/typescript-generator/coder.js +7 -2
- package/dist/typescript-generator/generate.js +155 -0
- package/dist/typescript-generator/jsdoc.js +45 -0
- package/dist/typescript-generator/operation-coder.js +1 -1
- package/dist/typescript-generator/operation-type-coder.js +5 -49
- package/dist/typescript-generator/parameters-type-coder.js +5 -1
- package/dist/typescript-generator/prune.js +2 -1
- package/dist/typescript-generator/read-only-comments.js +1 -1
- package/dist/typescript-generator/requirement.js +8 -1
- package/dist/typescript-generator/reserved-words.js +50 -0
- package/dist/typescript-generator/schema-type-coder.js +7 -1
- package/dist/typescript-generator/script.js +5 -3
- package/dist/typescript-generator/specification.js +7 -1
- package/dist/util/load-config-file.js +44 -0
- package/dist/util/runtime-can-execute-erasable-ts.js +22 -0
- package/package.json +12 -12
- package/dist/client/README.md +0 -14
- package/dist/client/index.html.hbs +0 -244
- package/dist/client/rapi-doc.html.hbs +0 -36
- package/dist/server/page-middleware.js +0 -23
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { COUNTERFACT_RESPONSE } from "./counterfact-response.js";
|
|
2
|
+
import type { CookieOptions } from "./cookie-options.js";
|
|
3
|
+
import type { ExampleNames } from "./example-names.js";
|
|
4
|
+
import type { IfHasKey } from "./if-has-key.js";
|
|
5
|
+
import type { MediaType } from "./media-type.js";
|
|
6
|
+
import type { OmitAll } from "./omit-all.js";
|
|
7
|
+
import type { OmitValueWhenNever } from "./omit-value-when-never.js";
|
|
8
|
+
import type { OpenApiResponse } from "./open-api-response.js";
|
|
9
|
+
import type { RandomFunction } from "./random-function.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns `never` when `Record` is an empty object type (`{}`), signalling
|
|
13
|
+
* that there are no remaining choices available on the response builder.
|
|
14
|
+
*/
|
|
15
|
+
type NeverIfEmpty<Record> = object extends Record ? never : Record;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extracts the union of schema types from a map of media-type content entries.
|
|
19
|
+
* Used to type the body argument of shortcut methods like `.json()` or `.html()`.
|
|
20
|
+
*/
|
|
21
|
+
type SchemasOf<T extends { [key: string]: { schema: unknown } }> = {
|
|
22
|
+
[K in keyof T]: T[K]["schema"];
|
|
23
|
+
}[keyof T];
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Produces a builder method for a shortcut (e.g. `.json()`, `.html()`) when
|
|
27
|
+
* the response contains at least one of the given `ContentTypes`, and `never`
|
|
28
|
+
* otherwise. Calling the method narrows the builder by removing those content
|
|
29
|
+
* types from the remaining options.
|
|
30
|
+
*/
|
|
31
|
+
type MaybeShortcut<
|
|
32
|
+
ContentTypes extends MediaType[],
|
|
33
|
+
Response extends OpenApiResponse,
|
|
34
|
+
> = IfHasKey<
|
|
35
|
+
Response["content"],
|
|
36
|
+
ContentTypes,
|
|
37
|
+
(body: SchemasOf<Response["content"]>) => GenericResponseBuilder<{
|
|
38
|
+
content: NeverIfEmpty<OmitAll<Response["content"], ContentTypes>>;
|
|
39
|
+
headers: Response["headers"];
|
|
40
|
+
requiredHeaders: Response["requiredHeaders"];
|
|
41
|
+
}>,
|
|
42
|
+
never
|
|
43
|
+
>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The type of the `.match(contentType, body)` method on the generic response
|
|
47
|
+
* builder. Calling it narrows the builder by removing the chosen content type
|
|
48
|
+
* from the remaining options.
|
|
49
|
+
*/
|
|
50
|
+
type MatchFunction<Response extends OpenApiResponse> = <
|
|
51
|
+
ContentType extends MediaType & keyof Response["content"],
|
|
52
|
+
>(
|
|
53
|
+
contentType: ContentType,
|
|
54
|
+
body: Response["content"][ContentType]["schema"],
|
|
55
|
+
) => GenericResponseBuilder<{
|
|
56
|
+
content: NeverIfEmpty<Omit<Response["content"], ContentType>>;
|
|
57
|
+
headers: Response["headers"];
|
|
58
|
+
requiredHeaders: Response["requiredHeaders"];
|
|
59
|
+
}>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The type of the `.header(name, value)` method on the generic response
|
|
63
|
+
* builder. Calling it narrows the builder by removing the satisfied header
|
|
64
|
+
* from the set of required headers.
|
|
65
|
+
*/
|
|
66
|
+
type HeaderFunction<Response extends OpenApiResponse> = <
|
|
67
|
+
Header extends string & keyof Response["headers"],
|
|
68
|
+
>(
|
|
69
|
+
header: Header,
|
|
70
|
+
value: Response["headers"][Header]["schema"],
|
|
71
|
+
) => GenericResponseBuilder<{
|
|
72
|
+
content: NeverIfEmpty<Response["content"]>;
|
|
73
|
+
headers: NeverIfEmpty<Omit<Response["headers"], Header>>;
|
|
74
|
+
requiredHeaders: Exclude<Response["requiredHeaders"], Header>;
|
|
75
|
+
}>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The inner shape of the generic response builder, listing all methods that
|
|
79
|
+
* are currently available given the remaining response constraints.
|
|
80
|
+
* Methods whose type resolves to `never` are stripped by `OmitValueWhenNever`.
|
|
81
|
+
*
|
|
82
|
+
* Note: `[T] extends [never]` (non-distributive tuple wrapping) is used
|
|
83
|
+
* alongside `[keyof T] extends [never]` to correctly handle both `T = never`
|
|
84
|
+
* (spec-generated no-body) and `T = {}` (all content types consumed) cases.
|
|
85
|
+
* TypeScript evaluates `keyof never` as `string | number | symbol`, so a
|
|
86
|
+
* direct `[keyof never] extends [never]` check would incorrectly return false.
|
|
87
|
+
*/
|
|
88
|
+
export type GenericResponseBuilderInner<
|
|
89
|
+
Response extends OpenApiResponse = OpenApiResponse,
|
|
90
|
+
> = OmitValueWhenNever<{
|
|
91
|
+
binary: MaybeShortcut<["application/octet-stream"], Response>;
|
|
92
|
+
cookie: (
|
|
93
|
+
name: string,
|
|
94
|
+
value: string,
|
|
95
|
+
options?: CookieOptions,
|
|
96
|
+
) => GenericResponseBuilder<Response>;
|
|
97
|
+
empty: [Response["content"]] extends [never]
|
|
98
|
+
? () => COUNTERFACT_RESPONSE
|
|
99
|
+
: [keyof Response["content"]] extends [never]
|
|
100
|
+
? () => COUNTERFACT_RESPONSE
|
|
101
|
+
: never;
|
|
102
|
+
header: [Response["headers"]] extends [never]
|
|
103
|
+
? never
|
|
104
|
+
: [keyof Response["headers"]] extends [never]
|
|
105
|
+
? never
|
|
106
|
+
: HeaderFunction<Response>;
|
|
107
|
+
html: MaybeShortcut<["text/html"], Response>;
|
|
108
|
+
json: MaybeShortcut<
|
|
109
|
+
[
|
|
110
|
+
"application/json",
|
|
111
|
+
"text/json",
|
|
112
|
+
"text/x-json",
|
|
113
|
+
"application/xml",
|
|
114
|
+
"text/xml",
|
|
115
|
+
],
|
|
116
|
+
Response
|
|
117
|
+
>;
|
|
118
|
+
match: [Response["content"]] extends [never]
|
|
119
|
+
? never
|
|
120
|
+
: [keyof Response["content"]] extends [never]
|
|
121
|
+
? never
|
|
122
|
+
: MatchFunction<Response>;
|
|
123
|
+
random: [Response["content"]] extends [never]
|
|
124
|
+
? never
|
|
125
|
+
: [keyof Response["content"]] extends [never]
|
|
126
|
+
? never
|
|
127
|
+
: RandomFunction;
|
|
128
|
+
example: [ExampleNames<Response>] extends [never]
|
|
129
|
+
? never
|
|
130
|
+
: (name: ExampleNames<Response>) => COUNTERFACT_RESPONSE;
|
|
131
|
+
text: MaybeShortcut<["text/plain"], Response>;
|
|
132
|
+
xml: MaybeShortcut<["application/xml", "text/xml"], Response>;
|
|
133
|
+
}>;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The strongly-typed, fluent response builder generated for each operation in
|
|
137
|
+
* a route handler. Its available methods are derived from the OpenAPI response
|
|
138
|
+
* schema: as methods are called, the builder type narrows until all required
|
|
139
|
+
* content and headers have been provided, at which point it resolves to
|
|
140
|
+
* `COUNTERFACT_RESPONSE`.
|
|
141
|
+
*
|
|
142
|
+
* When a Response type carries an `examples` key it is a spec-generated
|
|
143
|
+
* response (either the initial no-body builder or a builder that still has
|
|
144
|
+
* content/headers to satisfy). Those always go through
|
|
145
|
+
* `GenericResponseBuilderInner`, which exposes `empty()` when `content` is
|
|
146
|
+
* `never`.
|
|
147
|
+
*
|
|
148
|
+
* When a Response type has no `examples` key it is a narrowed type produced
|
|
149
|
+
* by a method call (e.g. `.json()` sets the body and returns a type without
|
|
150
|
+
* `examples`). Those go through the existing collapse logic so that
|
|
151
|
+
* fully-satisfied responses resolve directly to `COUNTERFACT_RESPONSE`.
|
|
152
|
+
*/
|
|
153
|
+
export type GenericResponseBuilder<
|
|
154
|
+
Response extends OpenApiResponse = OpenApiResponse,
|
|
155
|
+
> = "examples" extends keyof Response
|
|
156
|
+
? GenericResponseBuilderInner<Response>
|
|
157
|
+
: object extends OmitValueWhenNever<Omit<Response, "examples">>
|
|
158
|
+
? COUNTERFACT_RESPONSE
|
|
159
|
+
: keyof OmitValueWhenNever<Omit<Response, "examples">> extends "headers"
|
|
160
|
+
? {
|
|
161
|
+
ALL_REMAINING_HEADERS_ARE_OPTIONAL: COUNTERFACT_RESPONSE;
|
|
162
|
+
header: HeaderFunction<Response>;
|
|
163
|
+
}
|
|
164
|
+
: GenericResponseBuilderInner<Response>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A union of all standard HTTP status codes.
|
|
3
|
+
* Used to constrain the status code argument in response builder calls and
|
|
4
|
+
* generated route handler types.
|
|
5
|
+
*/
|
|
6
|
+
export type HttpStatusCode =
|
|
7
|
+
| 100
|
|
8
|
+
| 101
|
|
9
|
+
| 102
|
|
10
|
+
| 200
|
|
11
|
+
| 201
|
|
12
|
+
| 202
|
|
13
|
+
| 203
|
|
14
|
+
| 204
|
|
15
|
+
| 205
|
|
16
|
+
| 206
|
|
17
|
+
| 207
|
|
18
|
+
| 226
|
|
19
|
+
| 300
|
|
20
|
+
| 301
|
|
21
|
+
| 302
|
|
22
|
+
| 303
|
|
23
|
+
| 304
|
|
24
|
+
| 305
|
|
25
|
+
| 307
|
|
26
|
+
| 308
|
|
27
|
+
| 400
|
|
28
|
+
| 401
|
|
29
|
+
| 402
|
|
30
|
+
| 403
|
|
31
|
+
| 404
|
|
32
|
+
| 405
|
|
33
|
+
| 406
|
|
34
|
+
| 407
|
|
35
|
+
| 408
|
|
36
|
+
| 409
|
|
37
|
+
| 410
|
|
38
|
+
| 411
|
|
39
|
+
| 412
|
|
40
|
+
| 413
|
|
41
|
+
| 414
|
|
42
|
+
| 415
|
|
43
|
+
| 416
|
|
44
|
+
| 417
|
|
45
|
+
| 418
|
|
46
|
+
| 422
|
|
47
|
+
| 423
|
|
48
|
+
| 424
|
|
49
|
+
| 426
|
|
50
|
+
| 428
|
|
51
|
+
| 429
|
|
52
|
+
| 431
|
|
53
|
+
| 451
|
|
54
|
+
| 500
|
|
55
|
+
| 501
|
|
56
|
+
| 502
|
|
57
|
+
| 503
|
|
58
|
+
| 504
|
|
59
|
+
| 505
|
|
60
|
+
| 506
|
|
61
|
+
| 507
|
|
62
|
+
| 511;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conditional type that resolves to `Yes` when `SomeObject` has at least one
|
|
3
|
+
* key that contains any string from `Keys` as a substring, and `No` otherwise.
|
|
4
|
+
* Used to determine whether a shortcut method (e.g. `.json()`, `.html()`)
|
|
5
|
+
* should be present on the response builder for a given response type.
|
|
6
|
+
*/
|
|
7
|
+
export type IfHasKey<
|
|
8
|
+
SomeObject,
|
|
9
|
+
Keys extends readonly string[],
|
|
10
|
+
Yes,
|
|
11
|
+
No,
|
|
12
|
+
> = Keys extends [
|
|
13
|
+
infer FirstKey extends string,
|
|
14
|
+
...infer RestKeys extends string[],
|
|
15
|
+
]
|
|
16
|
+
? Extract<keyof SomeObject, `${string}${FirstKey}${string}`> extends never
|
|
17
|
+
? IfHasKey<SomeObject, RestKeys, Yes, No>
|
|
18
|
+
: Yes
|
|
19
|
+
: No;
|
|
@@ -1,329 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
schema: unknown;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
interface Example {
|
|
8
|
-
description: string;
|
|
9
|
-
summary: string;
|
|
10
|
-
value: unknown;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface CookieOptions {
|
|
14
|
-
domain?: string;
|
|
15
|
-
expires?: Date;
|
|
16
|
-
httpOnly?: boolean;
|
|
17
|
-
maxAge?: number;
|
|
18
|
-
path?: string;
|
|
19
|
-
sameSite?: "lax" | "none" | "strict";
|
|
20
|
-
secure?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const counterfactResponse = Symbol("Counterfact Response");
|
|
24
|
-
|
|
25
|
-
type COUNTERFACT_RESPONSE = {
|
|
26
|
-
[counterfactResponse]: typeof counterfactResponse;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
type MediaType = `${string}/${string}`;
|
|
30
|
-
|
|
31
|
-
type MaybePromise<T> = T | Promise<T>;
|
|
32
|
-
|
|
33
|
-
type OmitAll<T, K extends readonly string[]> = {
|
|
34
|
-
[P in keyof T as P extends `${string}${K[number]}${string}`
|
|
35
|
-
? never
|
|
36
|
-
: P]: T[P];
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
type OmitValueWhenNever<Base> = Pick<
|
|
40
|
-
Base,
|
|
41
|
-
{
|
|
42
|
-
[Key in keyof Base]: [Base[Key]] extends [never] ? never : Key;
|
|
43
|
-
}[keyof Base]
|
|
44
|
-
>;
|
|
45
|
-
|
|
46
|
-
interface OpenApiResponse {
|
|
47
|
-
content: { [key: MediaType]: OpenApiContent };
|
|
48
|
-
examples?: { [key: string]: unknown };
|
|
49
|
-
headers: { [key: string]: { schema: unknown } };
|
|
50
|
-
requiredHeaders: string;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface OpenApiResponses {
|
|
54
|
-
[key: string]: OpenApiResponse;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
type IfHasKey<
|
|
58
|
-
SomeObject,
|
|
59
|
-
Keys extends readonly string[],
|
|
60
|
-
Yes,
|
|
61
|
-
No,
|
|
62
|
-
> = Keys extends [
|
|
63
|
-
infer FirstKey extends string,
|
|
64
|
-
...infer RestKeys extends string[],
|
|
65
|
-
]
|
|
66
|
-
? Extract<keyof SomeObject, `${string}${FirstKey}${string}`> extends never
|
|
67
|
-
? IfHasKey<SomeObject, RestKeys, Yes, No>
|
|
68
|
-
: Yes
|
|
69
|
-
: No;
|
|
70
|
-
|
|
71
|
-
type SchemasOf<T extends { [key: string]: { schema: unknown } }> = {
|
|
72
|
-
[K in keyof T]: T[K]["schema"];
|
|
73
|
-
}[keyof T];
|
|
74
|
-
|
|
75
|
-
type MaybeShortcut<
|
|
76
|
-
ContentTypes extends MediaType[],
|
|
77
|
-
Response extends OpenApiResponse,
|
|
78
|
-
> = IfHasKey<
|
|
79
|
-
Response["content"],
|
|
80
|
-
ContentTypes,
|
|
81
|
-
(body: SchemasOf<Response["content"]>) => GenericResponseBuilder<{
|
|
82
|
-
content: NeverIfEmpty<OmitAll<Response["content"], ContentTypes>>;
|
|
83
|
-
headers: Response["headers"];
|
|
84
|
-
requiredHeaders: Response["requiredHeaders"];
|
|
85
|
-
}>,
|
|
86
|
-
never
|
|
87
|
-
>;
|
|
88
|
-
|
|
89
|
-
type NeverIfEmpty<Record> = object extends Record ? never : Record;
|
|
90
|
-
|
|
91
|
-
type MatchFunction<Response extends OpenApiResponse> = <
|
|
92
|
-
ContentType extends MediaType & keyof Response["content"],
|
|
93
|
-
>(
|
|
94
|
-
contentType: ContentType,
|
|
95
|
-
body: Response["content"][ContentType]["schema"],
|
|
96
|
-
) => GenericResponseBuilder<{
|
|
97
|
-
content: NeverIfEmpty<Omit<Response["content"], ContentType>>;
|
|
98
|
-
headers: Response["headers"];
|
|
99
|
-
requiredHeaders: Response["requiredHeaders"];
|
|
100
|
-
}>;
|
|
101
|
-
|
|
102
|
-
type HeaderFunction<Response extends OpenApiResponse> = <
|
|
103
|
-
Header extends string & keyof Response["headers"],
|
|
104
|
-
>(
|
|
105
|
-
header: Header,
|
|
106
|
-
value: Response["headers"][Header]["schema"],
|
|
107
|
-
) => GenericResponseBuilder<{
|
|
108
|
-
content: NeverIfEmpty<Response["content"]>;
|
|
109
|
-
headers: NeverIfEmpty<Omit<Response["headers"], Header>>;
|
|
110
|
-
requiredHeaders: Exclude<Response["requiredHeaders"], Header>;
|
|
111
|
-
}>;
|
|
112
|
-
|
|
113
|
-
type RandomFunction = () => MaybePromise<COUNTERFACT_RESPONSE>;
|
|
114
|
-
|
|
115
|
-
type ExampleNames<Response extends OpenApiResponse> = Response extends {
|
|
116
|
-
examples: infer E;
|
|
117
|
-
}
|
|
118
|
-
? keyof E & string
|
|
119
|
-
: never;
|
|
120
|
-
|
|
121
|
-
interface ResponseBuilder {
|
|
122
|
-
[status: number | `${number} ${string}`]: ResponseBuilder;
|
|
123
|
-
binary: (body: Uint8Array | string) => ResponseBuilder;
|
|
124
|
-
content?: { body: unknown; type: string }[];
|
|
125
|
-
cookie: (
|
|
126
|
-
name: string,
|
|
127
|
-
value: string,
|
|
128
|
-
options?: CookieOptions,
|
|
129
|
-
) => ResponseBuilder;
|
|
130
|
-
example: (name: string) => ResponseBuilder;
|
|
131
|
-
header: (name: string, value: string) => ResponseBuilder;
|
|
132
|
-
headers: { [name: string]: string | string[] };
|
|
133
|
-
html: (body: unknown) => ResponseBuilder;
|
|
134
|
-
json: (body: unknown) => ResponseBuilder;
|
|
135
|
-
match: (contentType: string, body: unknown) => ResponseBuilder;
|
|
136
|
-
random: () => MaybePromise<ResponseBuilder>;
|
|
137
|
-
randomLegacy: () => MaybePromise<ResponseBuilder>;
|
|
138
|
-
status?: number;
|
|
139
|
-
text: (body: unknown) => ResponseBuilder;
|
|
140
|
-
xml: (body: unknown) => ResponseBuilder;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export type GenericResponseBuilderInner<
|
|
144
|
-
Response extends OpenApiResponse = OpenApiResponse,
|
|
145
|
-
> = OmitValueWhenNever<{
|
|
146
|
-
binary: MaybeShortcut<["application/octet-stream"], Response>;
|
|
147
|
-
cookie: (
|
|
148
|
-
name: string,
|
|
149
|
-
value: string,
|
|
150
|
-
options?: CookieOptions,
|
|
151
|
-
) => GenericResponseBuilder<Response>;
|
|
152
|
-
header: [keyof Response["headers"]] extends [never]
|
|
153
|
-
? never
|
|
154
|
-
: HeaderFunction<Response>;
|
|
155
|
-
html: MaybeShortcut<["text/html"], Response>;
|
|
156
|
-
json: MaybeShortcut<
|
|
157
|
-
[
|
|
158
|
-
"application/json",
|
|
159
|
-
"text/json",
|
|
160
|
-
"text/x-json",
|
|
161
|
-
"application/xml",
|
|
162
|
-
"text/xml",
|
|
163
|
-
],
|
|
164
|
-
Response
|
|
165
|
-
>;
|
|
166
|
-
match: [keyof Response["content"]] extends [never]
|
|
167
|
-
? never
|
|
168
|
-
: MatchFunction<Response>;
|
|
169
|
-
random: [keyof Response["content"]] extends [never] ? never : RandomFunction;
|
|
170
|
-
example: [ExampleNames<Response>] extends [never]
|
|
171
|
-
? never
|
|
172
|
-
: (name: ExampleNames<Response>) => COUNTERFACT_RESPONSE;
|
|
173
|
-
text: MaybeShortcut<["text/plain"], Response>;
|
|
174
|
-
xml: MaybeShortcut<["application/xml", "text/xml"], Response>;
|
|
175
|
-
}>;
|
|
176
|
-
|
|
177
|
-
type GenericResponseBuilder<
|
|
178
|
-
Response extends OpenApiResponse = OpenApiResponse,
|
|
179
|
-
> =
|
|
180
|
-
object extends OmitValueWhenNever<Response>
|
|
181
|
-
? COUNTERFACT_RESPONSE
|
|
182
|
-
: keyof OmitValueWhenNever<Response> extends "headers"
|
|
183
|
-
? {
|
|
184
|
-
ALL_REMAINING_HEADERS_ARE_OPTIONAL: COUNTERFACT_RESPONSE;
|
|
185
|
-
header: HeaderFunction<Response>;
|
|
186
|
-
}
|
|
187
|
-
: GenericResponseBuilderInner<Response>;
|
|
188
|
-
|
|
189
|
-
type ResponseBuilderFactory<
|
|
190
|
-
Responses extends OpenApiResponses = OpenApiResponses,
|
|
191
|
-
> = {
|
|
192
|
-
[StatusCode in keyof Responses]: GenericResponseBuilder<
|
|
193
|
-
Responses[StatusCode]
|
|
194
|
-
>;
|
|
195
|
-
} & { [key: string]: GenericResponseBuilder<Responses["default"]> };
|
|
196
|
-
|
|
197
|
-
type HttpStatusCode =
|
|
198
|
-
| 100
|
|
199
|
-
| 101
|
|
200
|
-
| 102
|
|
201
|
-
| 200
|
|
202
|
-
| 201
|
|
203
|
-
| 202
|
|
204
|
-
| 203
|
|
205
|
-
| 204
|
|
206
|
-
| 205
|
|
207
|
-
| 206
|
|
208
|
-
| 207
|
|
209
|
-
| 226
|
|
210
|
-
| 300
|
|
211
|
-
| 301
|
|
212
|
-
| 302
|
|
213
|
-
| 303
|
|
214
|
-
| 304
|
|
215
|
-
| 305
|
|
216
|
-
| 307
|
|
217
|
-
| 308
|
|
218
|
-
| 400
|
|
219
|
-
| 401
|
|
220
|
-
| 402
|
|
221
|
-
| 403
|
|
222
|
-
| 404
|
|
223
|
-
| 405
|
|
224
|
-
| 406
|
|
225
|
-
| 407
|
|
226
|
-
| 408
|
|
227
|
-
| 409
|
|
228
|
-
| 410
|
|
229
|
-
| 411
|
|
230
|
-
| 412
|
|
231
|
-
| 413
|
|
232
|
-
| 414
|
|
233
|
-
| 415
|
|
234
|
-
| 416
|
|
235
|
-
| 417
|
|
236
|
-
| 418
|
|
237
|
-
| 422
|
|
238
|
-
| 423
|
|
239
|
-
| 424
|
|
240
|
-
| 426
|
|
241
|
-
| 428
|
|
242
|
-
| 429
|
|
243
|
-
| 431
|
|
244
|
-
| 451
|
|
245
|
-
| 500
|
|
246
|
-
| 501
|
|
247
|
-
| 502
|
|
248
|
-
| 503
|
|
249
|
-
| 504
|
|
250
|
-
| 505
|
|
251
|
-
| 506
|
|
252
|
-
| 507
|
|
253
|
-
| 511;
|
|
254
|
-
|
|
255
|
-
interface OpenApiParameters {
|
|
256
|
-
in: "body" | "cookie" | "formData" | "header" | "path" | "query";
|
|
257
|
-
name: string;
|
|
258
|
-
schema?: {
|
|
259
|
-
type: string;
|
|
260
|
-
};
|
|
261
|
-
type?: "string" | "number" | "integer" | "boolean";
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
interface OpenApiOperation {
|
|
265
|
-
parameters?: OpenApiParameters[];
|
|
266
|
-
produces?: string[];
|
|
267
|
-
responses: {
|
|
268
|
-
[status: string]: {
|
|
269
|
-
content?: {
|
|
270
|
-
[type: number | string]: {
|
|
271
|
-
examples?: { [key: string]: Example };
|
|
272
|
-
schema: { [key: string]: unknown };
|
|
273
|
-
};
|
|
274
|
-
};
|
|
275
|
-
examples?: { [key: string]: unknown };
|
|
276
|
-
headers?: {
|
|
277
|
-
[name: string]: OpenApiHeader;
|
|
278
|
-
};
|
|
279
|
-
schema?: { [key: string]: unknown };
|
|
280
|
-
};
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
interface WideResponseBuilder {
|
|
285
|
-
binary: (body: Uint8Array | string) => WideResponseBuilder;
|
|
286
|
-
example: (name: string) => WideResponseBuilder;
|
|
287
|
-
cookie: (
|
|
288
|
-
name: string,
|
|
289
|
-
value: string,
|
|
290
|
-
options?: CookieOptions,
|
|
291
|
-
) => WideResponseBuilder;
|
|
292
|
-
header: (body: unknown) => WideResponseBuilder;
|
|
293
|
-
html: (body: unknown) => WideResponseBuilder;
|
|
294
|
-
json: (body: unknown) => WideResponseBuilder;
|
|
295
|
-
match: (contentType: string, body: unknown) => WideResponseBuilder;
|
|
296
|
-
random: () => MaybePromise<WideResponseBuilder>;
|
|
297
|
-
text: (body: unknown) => WideResponseBuilder;
|
|
298
|
-
xml: (body: unknown) => WideResponseBuilder;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
interface WideOperationArgument {
|
|
302
|
-
body: unknown;
|
|
303
|
-
context: unknown;
|
|
304
|
-
headers: { [key: string]: string };
|
|
305
|
-
path: { [key: string]: string };
|
|
306
|
-
proxy: (url: string) => { proxyUrl: string };
|
|
307
|
-
query: { [key: string]: string };
|
|
308
|
-
response: { [key: number]: WideResponseBuilder };
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export type { COUNTERFACT_RESPONSE };
|
|
312
|
-
|
|
1
|
+
export type { CookieOptions } from "./cookie-options.js";
|
|
2
|
+
export type { COUNTERFACT_RESPONSE } from "./counterfact-response.js";
|
|
3
|
+
export type { ExampleNames } from "./example-names.js";
|
|
313
4
|
export type {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
};
|
|
5
|
+
GenericResponseBuilder,
|
|
6
|
+
GenericResponseBuilderInner,
|
|
7
|
+
} from "./generic-response-builder.js";
|
|
8
|
+
export type { HttpStatusCode } from "./http-status-code.js";
|
|
9
|
+
export type { IfHasKey } from "./if-has-key.js";
|
|
10
|
+
export type { MaybePromise } from "./maybe-promise.js";
|
|
11
|
+
export type { MediaType } from "./media-type.js";
|
|
12
|
+
export type { OmitAll } from "./omit-all.js";
|
|
13
|
+
export type { OmitValueWhenNever } from "./omit-value-when-never.js";
|
|
14
|
+
export type { OpenApiHeader } from "./open-api-header.js";
|
|
15
|
+
export type { OpenApiOperation } from "./open-api-operation.js";
|
|
16
|
+
export type { OpenApiParameters } from "./open-api-parameters.js";
|
|
17
|
+
export type { OpenApiResponse } from "./open-api-response.js";
|
|
18
|
+
export type { ResponseBuilder } from "./response-builder.js";
|
|
19
|
+
export type { ResponseBuilderFactory } from "./response-builder-factory.js";
|
|
20
|
+
export type { WideOperationArgument } from "./wide-operation-argument.js";
|
|
21
|
+
export type { WideResponseBuilder } from "./wide-response-builder.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes all keys from `T` whose names contain any of the strings in `K`
|
|
3
|
+
* as a substring (prefix, suffix, or exact match).
|
|
4
|
+
* Used internally to narrow the set of available content-type methods on the
|
|
5
|
+
* response builder after one has already been called.
|
|
6
|
+
*/
|
|
7
|
+
export type OmitAll<T, K extends readonly string[]> = {
|
|
8
|
+
[P in keyof T as P extends `${string}${K[number]}${string}`
|
|
9
|
+
? never
|
|
10
|
+
: P]: T[P];
|
|
11
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a new type from `Base` that omits any keys whose value type is
|
|
3
|
+
* `never`. This is used to strip unavailable builder methods (those that
|
|
4
|
+
* don't apply to the current response shape) from the fluent response builder.
|
|
5
|
+
*/
|
|
6
|
+
export type OmitValueWhenNever<Base> = Pick<
|
|
7
|
+
Base,
|
|
8
|
+
{
|
|
9
|
+
[Key in keyof Base]: [Base[Key]] extends [never] ? never : Key;
|
|
10
|
+
}[keyof Base]
|
|
11
|
+
>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Example } from "./example.js";
|
|
2
|
+
import type { OpenApiHeader } from "./open-api-header.js";
|
|
3
|
+
import type { OpenApiParameters } from "./open-api-parameters.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Describes a single HTTP operation (e.g. `GET /pets`) as defined in an
|
|
7
|
+
* OpenAPI document. Used internally to derive the strongly-typed argument
|
|
8
|
+
* and response builder types for generated route handler functions.
|
|
9
|
+
*/
|
|
10
|
+
export interface OpenApiOperation {
|
|
11
|
+
parameters?: OpenApiParameters[];
|
|
12
|
+
produces?: string[];
|
|
13
|
+
requestBody?: {
|
|
14
|
+
content?: {
|
|
15
|
+
[mediaType: string]: {
|
|
16
|
+
schema: { [key: string]: unknown };
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
required?: boolean;
|
|
20
|
+
};
|
|
21
|
+
responses: {
|
|
22
|
+
[status: string]: {
|
|
23
|
+
content?: {
|
|
24
|
+
[type: number | string]: {
|
|
25
|
+
examples?: { [key: string]: Example };
|
|
26
|
+
schema: { [key: string]: unknown };
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
examples?: { [key: string]: unknown };
|
|
30
|
+
headers?: {
|
|
31
|
+
[name: string]: OpenApiHeader;
|
|
32
|
+
};
|
|
33
|
+
schema?: { [key: string]: unknown };
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describes a single parameter (path, query, header, cookie, body, or
|
|
3
|
+
* formData) as defined in an OpenAPI document. Used internally to type the
|
|
4
|
+
* `path`, `query`, `headers`, and `body` properties of a route handler's
|
|
5
|
+
* argument object.
|
|
6
|
+
*/
|
|
7
|
+
export interface OpenApiParameters {
|
|
8
|
+
in: "body" | "cookie" | "formData" | "header" | "path" | "query";
|
|
9
|
+
name: string;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
schema?: {
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
type?: string;
|
|
14
|
+
};
|
|
15
|
+
type?: "string" | "number" | "integer" | "boolean";
|
|
16
|
+
}
|