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.
Files changed (94) hide show
  1. package/README.md +103 -140
  2. package/bin/README.md +25 -4
  3. package/bin/counterfact.js +208 -24
  4. package/bin/register-ts-loader.mjs +17 -0
  5. package/bin/ts-loader.mjs +31 -0
  6. package/dist/app.js +31 -21
  7. package/dist/counterfact-types/cookie-options.js +1 -0
  8. package/dist/counterfact-types/counterfact-response.js +7 -0
  9. package/dist/counterfact-types/example-names.js +1 -0
  10. package/dist/counterfact-types/example.js +1 -0
  11. package/dist/counterfact-types/generic-response-builder.js +1 -0
  12. package/dist/counterfact-types/http-status-code.js +1 -0
  13. package/dist/counterfact-types/if-has-key.js +1 -0
  14. package/dist/counterfact-types/index.js +0 -1
  15. package/dist/counterfact-types/maybe-promise.js +1 -0
  16. package/dist/counterfact-types/media-type.js +1 -0
  17. package/dist/counterfact-types/omit-all.js +1 -0
  18. package/dist/counterfact-types/omit-value-when-never.js +1 -0
  19. package/dist/counterfact-types/open-api-content.js +1 -0
  20. package/dist/counterfact-types/open-api-operation.js +1 -0
  21. package/dist/counterfact-types/open-api-parameters.js +1 -0
  22. package/dist/counterfact-types/open-api-response.js +1 -0
  23. package/dist/counterfact-types/random-function.js +1 -0
  24. package/dist/counterfact-types/response-builder-factory.js +1 -0
  25. package/dist/counterfact-types/response-builder.js +1 -0
  26. package/dist/counterfact-types/wide-operation-argument.js +1 -0
  27. package/dist/counterfact-types/wide-response-builder.js +1 -0
  28. package/dist/migrate/update-route-types.js +30 -10
  29. package/dist/repl/raw-http-client.js +14 -14
  30. package/dist/repl/repl.js +119 -4
  31. package/dist/repl/route-builder.js +270 -0
  32. package/dist/server/config.js +1 -1
  33. package/dist/server/context-registry.js +44 -4
  34. package/dist/server/counterfact-types/cookie-options.ts +14 -0
  35. package/dist/server/counterfact-types/counterfact-response.ts +15 -0
  36. package/dist/server/counterfact-types/example-names.ts +13 -0
  37. package/dist/server/counterfact-types/example.ts +10 -0
  38. package/dist/server/counterfact-types/generic-response-builder.ts +164 -0
  39. package/dist/server/counterfact-types/http-status-code.ts +62 -0
  40. package/dist/server/counterfact-types/if-has-key.ts +19 -0
  41. package/dist/server/counterfact-types/index.ts +20 -328
  42. package/dist/server/counterfact-types/maybe-promise.ts +6 -0
  43. package/dist/server/counterfact-types/media-type.ts +6 -0
  44. package/dist/server/counterfact-types/omit-all.ts +11 -0
  45. package/dist/server/counterfact-types/omit-value-when-never.ts +11 -0
  46. package/dist/server/counterfact-types/open-api-content.ts +8 -0
  47. package/dist/server/counterfact-types/open-api-operation.ts +36 -0
  48. package/dist/server/counterfact-types/open-api-parameters.ts +16 -0
  49. package/dist/server/counterfact-types/open-api-response.ts +22 -0
  50. package/dist/server/counterfact-types/random-function.ts +9 -0
  51. package/dist/server/counterfact-types/response-builder-factory.ts +16 -0
  52. package/dist/server/counterfact-types/response-builder.ts +31 -0
  53. package/dist/server/counterfact-types/wide-operation-argument.ts +17 -0
  54. package/dist/server/counterfact-types/wide-response-builder.ts +26 -0
  55. package/dist/server/create-koa-app.js +1 -20
  56. package/dist/server/determine-module-kind.js +1 -1
  57. package/dist/server/dispatcher.js +39 -15
  58. package/dist/server/file-discovery.js +34 -0
  59. package/dist/server/json-to-xml.js +1 -1
  60. package/dist/server/koa-middleware.js +7 -1
  61. package/dist/server/load-openapi-document.js +13 -0
  62. package/dist/server/middleware-detector.js +8 -0
  63. package/dist/server/module-dependency-graph.js +4 -1
  64. package/dist/server/module-loader.js +81 -33
  65. package/dist/server/module-tree.js +26 -23
  66. package/dist/server/openapi-middleware.js +2 -2
  67. package/dist/server/openapi-watcher.js +35 -0
  68. package/dist/server/registry.js +2 -2
  69. package/dist/server/request-validator.js +57 -0
  70. package/dist/server/response-builder.js +3 -0
  71. package/dist/server/response-validator.js +58 -0
  72. package/dist/server/scenario-registry.js +29 -0
  73. package/dist/server/tools.js +2 -2
  74. package/dist/server/transpiler.js +13 -5
  75. package/dist/typescript-generator/coder.js +7 -2
  76. package/dist/typescript-generator/generate.js +155 -0
  77. package/dist/typescript-generator/jsdoc.js +45 -0
  78. package/dist/typescript-generator/operation-coder.js +1 -1
  79. package/dist/typescript-generator/operation-type-coder.js +5 -49
  80. package/dist/typescript-generator/parameters-type-coder.js +5 -1
  81. package/dist/typescript-generator/prune.js +2 -1
  82. package/dist/typescript-generator/read-only-comments.js +1 -1
  83. package/dist/typescript-generator/requirement.js +8 -1
  84. package/dist/typescript-generator/reserved-words.js +50 -0
  85. package/dist/typescript-generator/schema-type-coder.js +7 -1
  86. package/dist/typescript-generator/script.js +5 -3
  87. package/dist/typescript-generator/specification.js +7 -1
  88. package/dist/util/load-config-file.js +44 -0
  89. package/dist/util/runtime-can-execute-erasable-ts.js +22 -0
  90. package/package.json +12 -12
  91. package/dist/client/README.md +0 -14
  92. package/dist/client/index.html.hbs +0 -244
  93. package/dist/client/rapi-doc.html.hbs +0 -36
  94. 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
- import { OpenApiHeader } from "./open-api-header";
2
-
3
- interface OpenApiContent {
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
- CookieOptions,
315
- ExampleNames,
316
- HttpStatusCode,
317
- MaybePromise,
318
- MediaType,
319
- OmitValueWhenNever,
320
- OpenApiOperation,
321
- OpenApiParameters,
322
- OpenApiResponse,
323
- ResponseBuilder,
324
- ResponseBuilderFactory,
325
- WideOperationArgument,
326
- WideResponseBuilder,
327
- OmitAll,
328
- IfHasKey,
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,6 @@
1
+ /**
2
+ * A value that is either `T` directly or a `Promise<T>`.
3
+ * Route handlers may return either synchronous values or promises, and
4
+ * Counterfact will await them transparently.
5
+ */
6
+ export type MaybePromise<T> = T | Promise<T>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Represents an IANA media type string in the format `type/subtype`
3
+ * (e.g. `"application/json"`, `"text/plain"`, `"image/png"`).
4
+ * Used to identify the content type of an HTTP request or response body.
5
+ */
6
+ export type MediaType = `${string}/${string}`;
@@ -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,8 @@
1
+ /**
2
+ * Represents a single content entry in an OpenAPI response object.
3
+ * The `schema` property holds the JSON Schema definition for the body of
4
+ * a response with this media type.
5
+ */
6
+ export interface OpenApiContent {
7
+ schema: unknown;
8
+ }
@@ -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
+ }