openapi-typesafe-fetch 1.0.0-rc.2 → 1.0.0-rc.4

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/src/helpers.ts ADDED
@@ -0,0 +1,437 @@
1
+ // HTTP types
2
+
3
+ export type HttpMethod =
4
+ | "get"
5
+ | "put"
6
+ | "post"
7
+ | "delete"
8
+ | "options"
9
+ | "head"
10
+ | "patch"
11
+ | "trace"
12
+ /** OpenAPI 3.2: a safe, idempotent request with a body. */
13
+ | "query";
14
+ /** 2XX statuses */
15
+ export type OkStatus = 200 | 201 | 202 | 203 | 204 | 206 | 207 | "2XX";
16
+ /** 4XX and 5XX statuses */
17
+ export type ErrorStatus =
18
+ | 500
19
+ | 501
20
+ | 502
21
+ | 503
22
+ | 504
23
+ | 505
24
+ | 506
25
+ | 507
26
+ | 508
27
+ | 510
28
+ | 511
29
+ | "5XX"
30
+ | 400
31
+ | 401
32
+ | 402
33
+ | 403
34
+ | 404
35
+ | 405
36
+ | 406
37
+ | 407
38
+ | 408
39
+ | 409
40
+ | 410
41
+ | 411
42
+ | 412
43
+ | 413
44
+ | 414
45
+ | 415
46
+ | 416
47
+ | 417
48
+ | 418
49
+ | 420
50
+ | 421
51
+ | 422
52
+ | 423
53
+ | 424
54
+ | 425
55
+ | 426
56
+ | 427
57
+ | 428
58
+ | 429
59
+ | 430
60
+ | 431
61
+ | 444
62
+ | 450
63
+ | 451
64
+ | 497
65
+ | 498
66
+ | 499
67
+ | "4XX"
68
+ | "default";
69
+
70
+ /** Get a union of OK Statuses */
71
+ export type OKStatusUnion<T> = FilterKeys<T, OkStatus>;
72
+
73
+ /** Get first error status, in order */
74
+ // biome-ignore format: this is dumb but reliable
75
+ export type FirstErrorStatus<T> =
76
+ T extends { 500: unknown } ? T[500] :
77
+ T extends { 501: unknown } ? T[501] :
78
+ T extends { 502: unknown } ? T[502] :
79
+ T extends { 503: unknown } ? T[503] :
80
+ T extends { 504: unknown } ? T[504] :
81
+ T extends { 505: unknown } ? T[505] :
82
+ T extends { 506: unknown } ? T[506] :
83
+ T extends { 507: unknown } ? T[507] :
84
+ T extends { 508: unknown } ? T[508] :
85
+ T extends { 510: unknown } ? T[510] :
86
+ T extends { 511: unknown } ? T[511] :
87
+ T extends { "5XX": unknown } ? T["5XX"] :
88
+ T extends { 400: unknown } ? T[400] :
89
+ T extends { 401: unknown } ? T[401] :
90
+ T extends { 402: unknown } ? T[402] :
91
+ T extends { 403: unknown } ? T[403] :
92
+ T extends { 404: unknown } ? T[404] :
93
+ T extends { 405: unknown } ? T[405] :
94
+ T extends { 406: unknown } ? T[406] :
95
+ T extends { 407: unknown } ? T[407] :
96
+ T extends { 408: unknown } ? T[408] :
97
+ T extends { 409: unknown } ? T[409] :
98
+ T extends { 410: unknown } ? T[410] :
99
+ T extends { 411: unknown } ? T[411] :
100
+ T extends { 412: unknown } ? T[412] :
101
+ T extends { 413: unknown } ? T[413] :
102
+ T extends { 414: unknown } ? T[414] :
103
+ T extends { 415: unknown } ? T[415] :
104
+ T extends { 416: unknown } ? T[416] :
105
+ T extends { 417: unknown } ? T[417] :
106
+ T extends { 418: unknown } ? T[418] :
107
+ T extends { 420: unknown } ? T[420] :
108
+ T extends { 421: unknown } ? T[421] :
109
+ T extends { 422: unknown } ? T[422] :
110
+ T extends { 423: unknown } ? T[423] :
111
+ T extends { 424: unknown } ? T[424] :
112
+ T extends { 425: unknown } ? T[425] :
113
+ T extends { 426: unknown } ? T[426] :
114
+ T extends { 427: unknown } ? T[427] :
115
+ T extends { 428: unknown } ? T[428] :
116
+ T extends { 429: unknown } ? T[429] :
117
+ T extends { 430: unknown } ? T[430] :
118
+ T extends { 431: unknown } ? T[431] :
119
+ T extends { 444: unknown } ? T[444] :
120
+ T extends { 450: unknown } ? T[450] :
121
+ T extends { 451: unknown } ? T[451] :
122
+ T extends { 497: unknown } ? T[497] :
123
+ T extends { 498: unknown } ? T[498] :
124
+ T extends { 499: unknown } ? T[499] :
125
+ T extends { "4XX": unknown } ? T["4XX"] :
126
+ T extends { default: unknown } ? T["default"] : never;
127
+
128
+ // OpenAPI type helpers
129
+
130
+ /** The paths that have each of the methods: upstream's `PathsWithMethod`. */
131
+ type PathsWithEveryMethod<Paths extends {}, PathnameMethod extends HttpMethod> = {
132
+ [Pathname in keyof Paths]: Paths[Pathname] extends {
133
+ [K in PathnameMethod]: unknown;
134
+ }
135
+ ? Pathname
136
+ : never;
137
+ }[keyof Paths];
138
+
139
+ /** The paths that have at least one method. */
140
+ type PathsWithAnyMethod<Paths extends {}> = {
141
+ [Pathname in keyof Paths]: {
142
+ [Method in HttpMethod]: Paths[Pathname] extends { [K in Method]: unknown } ? Pathname : never;
143
+ }[HttpMethod];
144
+ }[keyof Paths];
145
+
146
+ /**
147
+ * Given an OpenAPI **Paths Object**, find all paths that have the given method. For a union of
148
+ * methods, the paths that have each of them, so a call with either method finds its operation.
149
+ * For `HttpMethod` itself, a method not known yet, the paths that have any method too: TypeScript
150
+ * uses it where a hook's `Method` is not inferred, as in `Parameters<typeof $api.queryOptions>`,
151
+ * and the paths with every method were none (upstream #2178).
152
+ *
153
+ * A union with upstream's type, not a conditional type over the method: code that is generic in
154
+ * the method (`Path extends PathsWithMethod<Paths, Method>`, as swr-openapi has) must still
155
+ * relate one `PathsWithMethod` to another, and TypeScript cannot relate a type to a conditional
156
+ * type that waits for its method (TS2344). For a known method the second member is `never`.
157
+ */
158
+ export type PathsWithMethod<Paths extends {}, PathnameMethod extends HttpMethod> =
159
+ | PathsWithEveryMethod<Paths, PathnameMethod>
160
+ | (HttpMethod extends PathnameMethod ? PathsWithAnyMethod<Paths> : never);
161
+
162
+ /**
163
+ * DO NOT USE!
164
+ * Only used only for OperationObject type inference
165
+ */
166
+ export interface OperationObject {
167
+ // biome-ignore lint/suspicious/noExplicitAny: upstream's type; operations are inferred against it
168
+ parameters: any;
169
+ // biome-ignore lint/suspicious/noExplicitAny: upstream's type; operations are inferred against it
170
+ requestBody: any; // note: "any" will get overridden in inference
171
+ // biome-ignore lint/suspicious/noExplicitAny: upstream's type; operations are inferred against it
172
+ responses: any;
173
+ }
174
+
175
+ /** Internal helper used in PathsWithMethod */
176
+ export type PathItemObject = {
177
+ [M in HttpMethod]: OperationObject;
178
+ } & {
179
+ // biome-ignore lint/suspicious/noExplicitAny: upstream's type; operations are inferred against it
180
+ parameters?: any;
181
+ };
182
+
183
+ /** Return `responses` for an Operation Object */
184
+ // biome-ignore lint/suspicious/noExplicitAny: the result must meet the `Record` constraints below
185
+ export type ResponseObjectMap<T> = T extends { responses: any } ? T["responses"] : unknown;
186
+
187
+ /** Return `content` for a Response Object */
188
+ // biome-ignore lint/suspicious/noExplicitAny: upstream's type; `unknown` changes generic results
189
+ export type ResponseContent<T> = T extends { content: any } ? T["content"] : unknown;
190
+
191
+ /** Return type of `requestBody` for an Operation Object */
192
+ export type OperationRequestBody<T> = "requestBody" extends keyof T ? T["requestBody"] : never;
193
+
194
+ /** Internal helper to get object type with only the `requestBody` property */
195
+ type PickRequestBody<T> = "requestBody" extends keyof T ? Pick<T, "requestBody"> : never;
196
+
197
+ /** Resolve to `true` if request body is optional, else `false` */
198
+ export type IsOperationRequestBodyOptional<T> =
199
+ RequiredKeysOf<PickRequestBody<T>> extends never ? true : false;
200
+
201
+ /** Internal helper used in OperationRequestBodyContent */
202
+ export type OperationRequestBodyMediaContent<T> =
203
+ IsOperationRequestBodyOptional<T> extends true
204
+ ? ResponseContent<NonNullable<OperationRequestBody<T>>> | undefined
205
+ : ResponseContent<OperationRequestBody<T>>;
206
+
207
+ /** Return first `content` from a Request Object Mapping, allowing any media type */
208
+ export type OperationRequestBodyContent<T> =
209
+ FilterKeys<OperationRequestBodyMediaContent<T>, MediaType> extends never
210
+ ? FilterKeys<NonNullable<OperationRequestBodyMediaContent<T>>, MediaType> | undefined
211
+ : FilterKeys<OperationRequestBodyMediaContent<T>, MediaType>;
212
+
213
+ /**
214
+ * The statuses of success responses in a Response Object Map: the 2XX statuses, or `default` when
215
+ * no 2XX status is declared. `default` covers every status the operation does not declare (OpenAPI
216
+ * Responses Object), so then it covers every success (upstream #1862). With a 2XX status declared,
217
+ * `default` is left to the errors, as before.
218
+ */
219
+ type SuccessStatus<T> = [Extract<keyof T, OkStatus>] extends [never] ? "default" : OkStatus;
220
+
221
+ /**
222
+ * Return all 2XX responses from a Response Object Map, or `default` if it declares no 2XX one. For
223
+ * a union of maps (a call with a union of paths), the union of each map's responses: `keyof` of a
224
+ * union is only the shared statuses, so one map of them lost the body of every path that did not
225
+ * share its statuses, and a `default`-only path typed the data `undefined` (upstream).
226
+ */
227
+ export type SuccessResponse<
228
+ // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces
229
+ T extends Record<string | number, any>,
230
+ Media extends MediaType = MediaType,
231
+ > = T extends unknown ? GetResponseContent<T, Media, SuccessStatus<T>> : never;
232
+
233
+ export type GetResponseContent<
234
+ // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces
235
+ T extends Record<string | number, any>,
236
+ Media extends MediaType = MediaType,
237
+ ResponseCode extends keyof T = keyof T,
238
+ > = ResponseCode extends keyof T
239
+ ? {
240
+ // biome-ignore lint/suspicious/noExplicitAny: unknown rejects interface content types
241
+ [K in ResponseCode]: T[K]["content"] extends Record<string, any>
242
+ ? FilterKeys<T[K]["content"], Media> extends never
243
+ ? T[K]["content"]
244
+ : FilterKeys<T[K]["content"], Media>
245
+ : K extends keyof T
246
+ ? T[K]["content"]
247
+ : never;
248
+ }[ResponseCode]
249
+ : never;
250
+
251
+ /**
252
+ * Return all 5XX and 4XX responses (in that order) from a Response Object Map; for a union of maps,
253
+ * the union of each map's responses, as `SuccessResponse`.
254
+ */
255
+ export type ErrorResponse<
256
+ // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces
257
+ T extends Record<string | number, any>,
258
+ Media extends MediaType = MediaType,
259
+ > = T extends unknown ? GetResponseContent<T, Media, ErrorStatus> : never;
260
+
261
+ /** Return first JSON-like 2XX response from a path + HTTP method */
262
+ // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces
263
+ export type SuccessResponseJSON<PathMethod extends Record<string | number, any>> = SuccessResponse<
264
+ ResponseObjectMap<PathMethod>,
265
+ `${string}/json`
266
+ >;
267
+
268
+ /** Return first JSON-like 5XX or 4XX response from a path + HTTP method */
269
+ // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces
270
+ export type ErrorResponseJSON<PathMethod extends Record<string | number, any>> = ErrorResponse<
271
+ ResponseObjectMap<PathMethod>,
272
+ `${string}/json`
273
+ >;
274
+
275
+ /** Return JSON-like request body from a path + HTTP method */
276
+ export type RequestBodyJSON<PathMethod> = JSONLike<
277
+ FilterKeys<OperationRequestBody<PathMethod>, "content">
278
+ >;
279
+
280
+ // Generic TS utils
281
+
282
+ /** Find first match of multiple keys */
283
+ export type FilterKeys<Obj, Matchers> = Obj[keyof Obj & Matchers];
284
+ /**
285
+ * @deprecated Use `FilterKeys` instead
286
+ * Get the type of a value of an input object with a given key. If the key is
287
+ * not found, return a default type. Works with unions of objects too.
288
+ */
289
+ export type GetValueWithDefault<Obj, KeyPattern, Default> = Obj extends unknown
290
+ ? FilterKeys<Obj, KeyPattern> extends never
291
+ ? Default
292
+ : FilterKeys<Obj, KeyPattern>
293
+ : never;
294
+
295
+ /**
296
+ * Return any `[string]/[string]` media type (important because openapi-typesafe-fetch allows any
297
+ * content response, not just JSON-like)
298
+ */
299
+ export type MediaType = `${string}/${string}`;
300
+ /**
301
+ * Return any media type containing "json" (works for "application/json",
302
+ * "application/vnd.api+json", "application/vnd.oai.openapi+json")
303
+ */
304
+ export type JSONLike<T> = FilterKeys<T, `${string}/json`>;
305
+
306
+ /**
307
+ * Filter objects that have required keys
308
+ * @deprecated Use `RequiredKeysOf` instead
309
+ */
310
+ export type FindRequiredKeys<T, K extends keyof T> = K extends unknown
311
+ ? undefined extends T[K]
312
+ ? never
313
+ : K
314
+ : K;
315
+ /**
316
+ * Does this object contain required keys?
317
+ * @deprecated Use `RequiredKeysOf` instead
318
+ */
319
+ export type HasRequiredKeys<T> = FindRequiredKeys<T, keyof T>;
320
+
321
+ /**
322
+ * Helper to get the required keys of an object. If no keys are required, will be `undefined` with
323
+ * strictNullChecks enabled, else `never`
324
+ */
325
+ type RequiredKeysOfHelper<T> = {
326
+ [K in keyof T]: {} extends Pick<T, K> ? never : K;
327
+ }[keyof T];
328
+ /** Get the required keys of an object, or `never` if no keys are required */
329
+ export type RequiredKeysOf<T> =
330
+ RequiredKeysOfHelper<T> extends undefined ? never : RequiredKeysOfHelper<T>;
331
+
332
+ // readOnly/writeOnly visibility markers and helpers
333
+
334
+ /** Marker type for readOnly properties (excluded from request bodies) */
335
+ export type $Read<T> = { readonly $read: T };
336
+
337
+ /** Marker type for writeOnly properties (excluded from response bodies) */
338
+ export type $Write<T> = { readonly $write: T };
339
+
340
+ /** Primitives, also branded ones (`string & { __brand: "Id" }`), which stay unmapped (#2765). */
341
+ type ReadWritePrimitive = string | number | boolean | bigint | symbol | null | undefined;
342
+
343
+ /**
344
+ * Types that stay unmapped. Mapping a function type drops its call signatures, so a `Blob` from
345
+ * `--binary-as-blob` lost its methods (`arrayBuffer()`, `text()`, ...) in response data.
346
+ */
347
+ type ReadWriteLeaf = ReadWritePrimitive | ((...args: never) => unknown);
348
+
349
+ /**
350
+ * Keys of `T` whose value is a `Marker`. A key whose value is only `null` or `undefined` is not
351
+ * marked: `NonNullable` of it is `never`, and `never` extends every marker (upstream #2717). An
352
+ * `any` key is not marked either (`0 extends 1 & T[K]` is true only for `any`): a check on `any`
353
+ * takes both branches, so `Readable` dropped the key and `Writable` typed it `undefined`. The
354
+ * checks are not distributive (their check types are not type parameters), so `never` is seen.
355
+ */
356
+ type ReadWriteMarkedKeys<T, Marker> = {
357
+ [K in keyof T]-?: 0 extends 1 & T[K]
358
+ ? never
359
+ : NonNullable<T[K]> extends never
360
+ ? never
361
+ : NonNullable<T[K]> extends Marker
362
+ ? K
363
+ : never;
364
+ }[keyof T];
365
+
366
+ /**
367
+ * Resolve an array or a tuple element by element. An array uses `T[number]`, not `infer E`: for an
368
+ * intersection of arrays (`allOf`) inference keeps one member and narrowing breaks (upstream
369
+ * #2620). `T` is a plain array when an array of its elements is assignable to it; otherwise it is a
370
+ * tuple (also `[A, ...B[]]`), mapped homomorphically to stay a tuple (upstream #2632). Both keep
371
+ * `readonly` (upstream #2615).
372
+ */
373
+ type ReadWriteResolveArray<
374
+ T extends readonly unknown[],
375
+ Resolved extends "read" | "write",
376
+ > = T[number][] extends T
377
+ ? T extends unknown[]
378
+ ? ReadWriteResolve<T[number], Resolved>[]
379
+ : readonly ReadWriteResolve<T[number], Resolved>[]
380
+ : { [K in keyof T]: ReadWriteResolve<T[K], Resolved> };
381
+
382
+ type ReadWriteResolve<T, Resolved extends "read" | "write"> = Resolved extends "read"
383
+ ? Readable<T>
384
+ : Writable<T>;
385
+
386
+ // The markers are matched with `any`, as in the helper types that the generator writes.
387
+ // biome-ignore-start lint/suspicious/noExplicitAny: the same text as the generated helper types
388
+ /**
389
+ * Resolve type for reading (responses): strips $Write properties, unwraps $Read
390
+ * - $Read<T> → T (readable), continues recursion
391
+ * - $Write<T> → never (excluded from response)
392
+ * - primitives (also branded), functions, arrays and tuples keep their shape; objects resolve
393
+ * recursively
394
+ */
395
+ export type Readable<T> =
396
+ T extends $Write<any>
397
+ ? never
398
+ : T extends $Read<infer U>
399
+ ? Readable<U>
400
+ : T extends ReadWriteLeaf
401
+ ? T
402
+ : T extends readonly unknown[]
403
+ ? ReadWriteResolveArray<T, "read">
404
+ : T extends object
405
+ ? {
406
+ [K in keyof T as K extends ReadWriteMarkedKeys<T, $Write<any>>
407
+ ? never
408
+ : K]: Readable<T[K]>;
409
+ }
410
+ : T;
411
+
412
+ /**
413
+ * Resolve type for writing (requests): strips $Read properties, unwraps $Write
414
+ * - $Write<T> → T (writable), continues recursion
415
+ * - $Read<T> → never (excluded from request)
416
+ * - primitives (also branded), functions, arrays and tuples keep their shape; objects resolve
417
+ * recursively
418
+ */
419
+ export type Writable<T> =
420
+ T extends $Read<any>
421
+ ? never
422
+ : T extends $Write<infer U>
423
+ ? Writable<U>
424
+ : T extends ReadWriteLeaf
425
+ ? T
426
+ : T extends readonly unknown[]
427
+ ? ReadWriteResolveArray<T, "write">
428
+ : T extends object
429
+ ? {
430
+ [K in keyof T as K extends ReadWriteMarkedKeys<T, $Read<any>>
431
+ ? never
432
+ : K]: Writable<T[K]>;
433
+ } & {
434
+ [K in ReadWriteMarkedKeys<T, $Read<any>>]?: never;
435
+ }
436
+ : T;
437
+ // biome-ignore-end lint/suspicious/noExplicitAny: the same text as the generated helper types
package/src/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ // A stream body may be an async iterable (`RawRequestBody`). The reference brings that type into a
2
+ // project whose `lib` is older than ES2018, which fails with TS2583 otherwise. The declaration
3
+ // build copies it into the published declarations (build.config.ts).
4
+ /// <reference lib="es2018.asynciterable" />
1
5
  import type {
2
6
  ErrorResponse,
3
7
  FilterKeys,
@@ -11,7 +15,16 @@ import type {
11
15
  ResponseObjectMap,
12
16
  SuccessResponse,
13
17
  Writable,
14
- } from "openapi-typesafe-helpers";
18
+ } from "./helpers.js";
19
+
20
+ // The client declares the helper types in `./helpers.js`, published as
21
+ // `openapi-typesafe-fetch/helpers`, and `openapi-typesafe-helpers` re-exports them: one
22
+ // declaration, so generic code may mix the names of both packages. Types inferred from the
23
+ // client print them by that path, which a library that uses the client can import, also under
24
+ // pnpm and Yarn PnP (ADR-034). They are not exported here, as in openapi-fetch: a project that
25
+ // writes `export type * from` the client next to its own `ErrorResponse` fails with TS2308. This
26
+ // file has no `export { … }` either, so its other top-level types stay importable from
27
+ // `openapi-typesafe-fetch/src/index.js`, as openapi-fetch's are (`InitParam`).
15
28
 
16
29
  /** Options for each client instance */
17
30
  export interface ClientOptions extends Omit<RequestInit, "headers"> {
@@ -147,7 +160,17 @@ export type RequestBodyOption<T> =
147
160
  ? { body?: Writable<OperationRequestBodyContent<T>> }
148
161
  : { body: Writable<OperationRequestBodyContent<T>> };
149
162
 
150
- export type FetchOptions<T> = RequestOptions<T> & Omit<RequestInit, "body" | "headers">;
163
+ /**
164
+ * The init of a call to the operation `T`; for a union of operations, the union of their inits. It
165
+ * distributes so that the client's init type and a wrapper's `FetchOptions` of a generic path are
166
+ * the same type, which TypeScript can relate: an alias that distributed only inside the client
167
+ * gave a conditional type no `FetchOptions` argument was assignable to (TS2345). The operations
168
+ * of a union are not merged into one deep init type, which gave TS2589 on hundreds of paths
169
+ * (upstream #1882).
170
+ */
171
+ export type FetchOptions<T> = T extends unknown
172
+ ? RequestOptions<T> & Omit<RequestInit, "body" | "headers">
173
+ : never;
151
174
 
152
175
  // Readable<T> strips $Write markers (writeOnly properties excluded from response)
153
176
  export type FetchResponse<
@@ -254,19 +277,16 @@ export type MaybeOptionalInit<Params, Location extends PropertyKey> = OperationI
254
277
  * One conditional type, as openapi-fetch's, not a union with a conditional `undefined`: while the
255
278
  * operation is generic, a union made `FetchResponse` distribute over its members, so the `data` of
256
279
  * a generic wrapper's call no longer related to `FetchResponse<Paths[Path][Method], Init, Media>`.
280
+ * Its check type is not a type parameter, so TypeScript takes a `FetchOptions` of a generic path
281
+ * for it when that type fits both branches. `FetchOptions` itself makes one init per operation:
282
+ * while the path is generic it stays an alias, not an `infer` type, which TypeScript reads as
283
+ * `unknown`, so the init stays the contextual type of an argument and a literal such as
284
+ * `"available"` keeps its type (swr-openapi's `Exact<Init>` checks).
257
285
  */
258
286
  type OperationInits<Operation> =
259
- RequiredKeysOf<OperationFetchOptions<Operation>> extends never
260
- ? OperationFetchOptions<Operation> | undefined
261
- : OperationFetchOptions<Operation>;
262
-
263
- /**
264
- * Each operation's init. A distributive alias, not `extends infer Operation`: while the path is
265
- * not known, TypeScript reads an `infer` type as `unknown`, so the init lost its type as the
266
- * contextual type of an argument and a literal such as `"available"` widened to `string`
267
- * (swr-openapi's `Exact<Init>` checks).
268
- */
269
- type OperationFetchOptions<Operation> = Operation extends unknown ? FetchOptions<Operation> : never;
287
+ RequiredKeysOf<FetchOptions<Operation>> extends never
288
+ ? FetchOptions<Operation> | undefined
289
+ : FetchOptions<Operation>;
270
290
 
271
291
  // The final init param to accept.
272
292
  // - Determines if the param is optional or not.
@@ -294,11 +314,19 @@ type WithAnyKeys<Init> = Init & { [key: string]: unknown };
294
314
  * adds none.
295
315
  */
296
316
  export type PathOperation<Paths, Path, Method> = Extract<
297
- FilterKeys<Paths[Path & keyof Paths], Method>,
317
+ FilterKeys<PathItem<Paths, Path>, Method>,
298
318
  // biome-ignore lint/suspicious/noExplicitAny: unknown rejects the generated interfaces
299
319
  Record<string | number, any>
300
320
  >;
301
321
 
322
+ /**
323
+ * The path item of each path of `Path`. Not `Paths[Path & keyof Paths]`: with template keys
324
+ * (`--path-params-as-types`), `/apps/${string}` intersected with the keys is every key it
325
+ * overlaps, such as `/apps/${string}/logs/${number}`, so a call to one path got the responses of
326
+ * the others too once the responses distribute over the operations.
327
+ */
328
+ type PathItem<Paths, Path> = Path extends keyof Paths ? Paths[Path] : never;
329
+
302
330
  export type ClientMethod<Paths extends {}, Method extends HttpMethod, Media extends MediaType> = <
303
331
  Path extends PathsWithMethod<Paths, Method>,
304
332
  Init extends MaybeOptionalInit<Paths[Path], Method>,
@@ -457,8 +485,18 @@ export declare function defaultPathSerializer(
457
485
  pathParams: Record<string, unknown>,
458
486
  ): string;
459
487
 
460
- /** Bodies that `fetch` sends as they are, so `defaultBodySerializer` returns them unchanged. */
461
- type RawRequestBody = FormData | Blob | URLSearchParams | ArrayBuffer | ArrayBufferView;
488
+ /**
489
+ * Bodies that `fetch` sends as they are, so `defaultBodySerializer` returns them unchanged. A
490
+ * stream is a `ReadableStream` or an async iterable, such as a Node.js `Readable`.
491
+ */
492
+ type RawRequestBody =
493
+ | FormData
494
+ | Blob
495
+ | URLSearchParams
496
+ | ArrayBuffer
497
+ | ArrayBufferView
498
+ | ReadableStream
499
+ | AsyncIterable<unknown>;
462
500
 
463
501
  /**
464
502
  * The result of `defaultBodySerializer` for a body of type `Body`: the body itself when it is raw,
@@ -551,3 +589,9 @@ export declare function mergeHeaders(...allHeaders: (HeadersOptions | undefined)
551
589
 
552
590
  /** Remove trailing slash from url */
553
591
  export declare function removeTrailingSlash(url: string): string;
592
+
593
+ /**
594
+ * Return a new ID, unique within the process: the request `id` that middleware callbacks get.
595
+ * It comes from a counter shared by all clients, not from `Math.random()`; the name is upstream's.
596
+ */
597
+ export declare function randomID(): string;