@shipworthy/openapi-fetch 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- //#region src/headers.ts
5
+ // src/headers.ts
6
6
  /** Iterate any `HeadersOptions` form (plain object, `Headers`, or `[name, value]` tuples) as entries */
7
7
  function headerEntries(h) {
8
8
  if (h instanceof Headers) return h.entries();
@@ -20,8 +20,166 @@ function mergeHeaders(...allHeaders) {
20
20
  }
21
21
  return finalHeaders;
22
22
  }
23
- //#endregion
24
- //#region src/serializers/body.ts
23
+ // src/middleware/transform-casing.ts
24
+ function expandSchemas(schemas, mapping, visited = /* @__PURE__ */ new Set()) {
25
+ return schemas.flatMap((schema) => {
26
+ const nested = schema.variants ?? [];
27
+ if (!schema.ref || visited.has(schema.ref)) return [schema, ...expandSchemas(nested, mapping, visited)];
28
+ const referenced = mapping.schemas?.[schema.ref];
29
+ const next = new Set(visited).add(schema.ref);
30
+ return [schema, ...expandSchemas(referenced ? [referenced, ...nested] : nested, mapping, next)];
31
+ });
32
+ }
33
+ function createConverter(mapping) {
34
+ const schemaIds = /* @__PURE__ */ new WeakMap();
35
+ const plans = /* @__PURE__ */ new Map();
36
+ let nextId = 0;
37
+ function planFor(schemas, direction) {
38
+ if (schemas.length === 0) return void 0;
39
+ const key = `${direction}:${schemas.map((schema) => {
40
+ let id = schemaIds.get(schema);
41
+ if (id === void 0) {
42
+ id = ++nextId;
43
+ schemaIds.set(schema, id);
44
+ }
45
+ return id;
46
+ }).join(",")}`;
47
+ const existing = plans.get(key);
48
+ if (existing) return existing;
49
+ const expanded = expandSchemas(schemas, mapping);
50
+ const fields = /* @__PURE__ */ new Map();
51
+ for (const schema of expanded) for (const [wireName, field] of Object.entries(schema.properties ?? {})) {
52
+ const sourceName = direction === "toApi" ? field.name : wireName;
53
+ const targetName = direction === "toApi" ? wireName : field.name;
54
+ const current = fields.get(sourceName);
55
+ if (current) {
56
+ if (current.name !== targetName) throw new Error(`Conflicting case mapping for ${sourceName}`);
57
+ if (field.schema) current.schemas.push(field.schema);
58
+ } else fields.set(sourceName, {
59
+ name: targetName,
60
+ schemas: field.schema ? [field.schema] : []
61
+ });
62
+ }
63
+ const plan = {
64
+ expanded,
65
+ fields,
66
+ declared: new Set(expanded.flatMap((schema) => schema.declared ?? [])),
67
+ patterns: expanded.flatMap((schema) => Object.entries(schema.patternProperties ?? {}).map(([pattern, nested]) => ({
68
+ regex: new RegExp(pattern),
69
+ schema: nested
70
+ }))),
71
+ additional: expanded.flatMap((schema) => schema.additionalProperties ? [schema.additionalProperties] : []),
72
+ prefixLength: expanded.reduce((max, schema) => Math.max(max, schema.prefixItems?.length ?? 0), 0)
73
+ };
74
+ plans.set(key, plan);
75
+ return plan;
76
+ }
77
+ function itemPlan(plan, index, direction) {
78
+ if (index >= plan.prefixLength) {
79
+ if (plan.items === void 0) plan.items = planFor(plan.expanded.flatMap((schema) => schema.items ? [schema.items] : []), direction) ?? null;
80
+ return plan.items ?? void 0;
81
+ }
82
+ const prefixItems = plan.prefixItems ??= [];
83
+ if (prefixItems[index] === void 0) prefixItems[index] = planFor(plan.expanded.flatMap((schema) => {
84
+ const prefix = schema.prefixItems;
85
+ const item = prefix && index < prefix.length ? prefix[index] : schema.items;
86
+ return item ? [item] : [];
87
+ }), direction) ?? null;
88
+ return prefixItems[index] ?? void 0;
89
+ }
90
+ function convertWithPlan(value, plan, direction) {
91
+ if (!plan || value === null || value === void 0) return value;
92
+ if (Array.isArray(value)) return value.map((item, index) => convertWithPlan(item, itemPlan(plan, index, direction), direction));
93
+ if (typeof value !== "object") return value;
94
+ const prototype = Object.getPrototypeOf(value);
95
+ if (prototype !== Object.prototype && prototype !== null) return value;
96
+ const convertedNames = /* @__PURE__ */ new Set();
97
+ const entries = Object.entries(value).map(([name, item]) => {
98
+ const field = plan.fields.get(name);
99
+ const matched = [];
100
+ let hasPattern = false;
101
+ for (const pattern of plan.patterns) if (pattern.regex.test(name)) {
102
+ hasPattern = true;
103
+ if (pattern.schema) matched.push(pattern.schema);
104
+ }
105
+ let nested;
106
+ if (matched.length > 0) nested = planFor([...field?.schemas ?? [], ...matched], direction);
107
+ else if (field) {
108
+ if (field.nested === void 0) field.nested = planFor(field.schemas, direction) ?? null;
109
+ nested = field.nested ?? void 0;
110
+ } else if (!plan.declared.has(name) && !hasPattern) {
111
+ if (plan.additionalPlan === void 0) plan.additionalPlan = planFor(plan.additional, direction) ?? null;
112
+ nested = plan.additionalPlan ?? void 0;
113
+ }
114
+ const targetName = field?.name ?? name;
115
+ if (convertedNames.has(targetName)) throw new Error(`Conflicting case mapping for ${targetName}`);
116
+ convertedNames.add(targetName);
117
+ return [targetName, convertWithPlan(item, nested, direction)];
118
+ });
119
+ return Object.fromEntries(entries);
120
+ }
121
+ return (value, schemas, direction) => {
122
+ if (schemas.length === 0 || value === null || value === void 0) return value;
123
+ return convertWithPlan(value, planFor(schemas, direction), direction);
124
+ };
125
+ }
126
+ function isJsonMediaType(mediaType) {
127
+ return mediaType === "application/json" || mediaType.endsWith("+json");
128
+ }
129
+ function mediaSchema(media, contentType) {
130
+ if (!media) return void 0;
131
+ const type = contentType?.split(";", 1)[0]?.trim().toLowerCase();
132
+ if (type && !isJsonMediaType(type)) return void 0;
133
+ const entries = Object.entries(media).filter(([name]) => isJsonMediaType(name.toLowerCase()));
134
+ const exact = entries.find(([name]) => name.toLowerCase() === type);
135
+ if (exact) return exact[1] ?? void 0;
136
+ const json = entries.find(([name]) => name.toLowerCase() === "application/json");
137
+ if (json) return json[1] ?? void 0;
138
+ return entries.length === 1 ? entries[0]?.[1] ?? void 0 : void 0;
139
+ }
140
+ function responseMedia(operation, response) {
141
+ const responses = operation.responses;
142
+ if (!responses) return void 0;
143
+ const status = String(response.status);
144
+ const range = `${status[0]}XX`;
145
+ return mediaSchema(Object.hasOwn(responses, status) ? responses[status] : Object.hasOwn(responses, range) ? responses[range] : responses.default, response.headers.get("content-type") ?? void 0);
146
+ }
147
+ function convertRequest(input, operation, convertValue, headers) {
148
+ const parameters = operation.parameters;
149
+ const params = input.params;
150
+ const bodySchema = mediaSchema(operation.requestBodies, headers.get("content-type") ?? void 0);
151
+ return {
152
+ params: parameters ? {
153
+ ...params,
154
+ path: convertValue(params.path, parameters.path ? [parameters.path] : [], "toApi"),
155
+ query: convertValue(params.query, parameters.query ? [parameters.query] : [], "toApi"),
156
+ header: convertValue(params.header, parameters.header ? [parameters.header] : [], "toApi"),
157
+ cookie: convertValue(params.cookie, parameters.cookie ? [parameters.cookie] : [], "toApi")
158
+ } : params,
159
+ body: bodySchema && input.body !== void 0 ? convertValue(input.body, [bodySchema], "toApi") : input.body
160
+ };
161
+ }
162
+ /** Convert generated camelCase values at the openapi-fetch request and result stages. */
163
+ function createCaseMappingMiddleware(mapping) {
164
+ const convertValue = createConverter(mapping);
165
+ return {
166
+ onRequestInit({ method, schemaPath, input, headers }) {
167
+ const operation = mapping.operations?.[`${method} ${schemaPath}`];
168
+ return operation ? convertRequest(input, operation, convertValue, headers) : void 0;
169
+ },
170
+ onResult({ method, schemaPath, result, options }) {
171
+ const operation = mapping.operations?.[`${method} ${schemaPath}`];
172
+ if (!operation) return;
173
+ const schema = responseMedia(operation, result.response);
174
+ if (!schema) return;
175
+ return {
176
+ ...options.parseAs === "json" && result.data !== void 0 ? { data: convertValue(result.data, [schema], "fromApi") } : {},
177
+ ...result.error !== void 0 ? { error: convertValue(result.error, [schema], "fromApi") } : {}
178
+ };
179
+ }
180
+ };
181
+ }
182
+ // src/serializers/body.ts
25
183
  /** Serialize body object to string */
26
184
  function defaultBodySerializer(body, headers) {
27
185
  if (body instanceof FormData) return body;
@@ -30,8 +188,7 @@ function defaultBodySerializer(body, headers) {
30
188
  }
31
189
  return JSON.stringify(body);
32
190
  }
33
- //#endregion
34
- //#region src/serializers/param.ts
191
+ // src/serializers/param.ts
35
192
  /** Serialize primitive params to string */
36
193
  function serializePrimitiveParam(name, value, options) {
37
194
  if (value === void 0 || value === null) return "";
@@ -91,8 +248,7 @@ function serializeArrayParam(name, value, options) {
91
248
  else values.push(serializePrimitiveParam(name, v, options));
92
249
  return options.style === "label" || options.style === "matrix" ? `${joiner}${values.join(joiner)}` : values.join(joiner);
93
250
  }
94
- //#endregion
95
- //#region src/serializers/cookie.ts
251
+ // src/serializers/cookie.ts
96
252
  /**
97
253
  * Serialize cookie params to a `Cookie` header value using the OpenAPI default
98
254
  * (style: form, explode: true). Arrays repeat the name, objects emit one pair per key,
@@ -114,8 +270,7 @@ function serializeCookieParams(cookieParams) {
114
270
  }
115
271
  return pairs.join("; ");
116
272
  }
117
- //#endregion
118
- //#region src/serializers/path.ts
273
+ // src/serializers/path.ts
119
274
  const PATH_PARAM_RE = /\{[^{}]+\}/g;
120
275
  /**
121
276
  * Handle different OpenAPI 3.x serialization styles
@@ -162,8 +317,7 @@ function defaultPathSerializer(pathname, pathParams) {
162
317
  }
163
318
  return nextURL;
164
319
  }
165
- //#endregion
166
- //#region src/serializers/query.ts
320
+ // src/serializers/query.ts
167
321
  /** Serialize query params to string */
168
322
  function createQuerySerializer(options) {
169
323
  return function querySerializer(queryParams) {
@@ -195,8 +349,7 @@ function createQuerySerializer(options) {
195
349
  return search.join("&");
196
350
  };
197
351
  }
198
- //#endregion
199
- //#region src/serializers/url.ts
352
+ // src/serializers/url.ts
200
353
  /** Construct URL string from baseUrl and handle path and query params */
201
354
  function createFinalURL(pathname, options) {
202
355
  let finalURL = `${options.baseUrl}${pathname}`;
@@ -211,8 +364,7 @@ function removeTrailingSlash(url) {
211
364
  if (url.endsWith("/")) return url.substring(0, url.length - 1);
212
365
  return url;
213
366
  }
214
- //#endregion
215
- //#region src/client.ts
367
+ // src/client.ts
216
368
  function supportsRequestInitExt() {
217
369
  const nodeProcess = globalThis.process;
218
370
  return typeof nodeProcess === "object" && Number.parseInt(nodeProcess?.versions?.node?.substring(0, 2) ?? "") >= 18 && nodeProcess?.versions?.undici;
@@ -225,15 +377,16 @@ function randomID() {
225
377
  * Create an openapi-fetch client.
226
378
  */
227
379
  function createClient(clientOptions) {
228
- let { baseUrl = "", Request: CustomRequest = globalThis.Request, fetch: baseFetch = globalThis.fetch, querySerializer: globalQuerySerializer, bodySerializer: globalBodySerializer, pathSerializer: globalPathSerializer, headers: baseHeaders, requestInitExt, ...baseOptions } = { ...clientOptions };
380
+ let { baseUrl = "", Request: CustomRequest = globalThis.Request, fetch: baseFetch = globalThis.fetch, querySerializer: globalQuerySerializer, bodySerializer: globalBodySerializer, pathSerializer: globalPathSerializer, caseMapping, headers: baseHeaders, requestInitExt, ...baseOptions } = { ...clientOptions };
229
381
  requestInitExt = supportsRequestInitExt() ? requestInitExt : void 0;
230
382
  baseUrl = removeTrailingSlash(baseUrl);
231
383
  const globalMiddlewares = [];
384
+ if (caseMapping !== void 0) globalMiddlewares.push(createCaseMappingMiddleware(caseMapping));
232
385
  /**
233
386
  * Per-request fetch (keeps settings created in createClient()
234
387
  */
235
388
  async function coreFetch(schemaPath, fetchOptions) {
236
- const { baseUrl: localBaseUrl, fetch = baseFetch, Request = CustomRequest, headers, params = {}, parseAs = "json", querySerializer: requestQuerySerializer, bodySerializer = globalBodySerializer ?? defaultBodySerializer, pathSerializer: requestPathSerializer, body, middleware: requestMiddlewares = [], ...init } = fetchOptions || {};
389
+ const { baseUrl: localBaseUrl, fetch = baseFetch, Request = CustomRequest, headers, params: initialParams = {}, parseAs = "json", querySerializer: requestQuerySerializer, bodySerializer = globalBodySerializer ?? defaultBodySerializer, pathSerializer: requestPathSerializer, body: initialBody, middleware: requestMiddlewares = [], ...init } = fetchOptions || {};
237
390
  let finalBaseUrl = baseUrl;
238
391
  if (localBaseUrl) finalBaseUrl = removeTrailingSlash(localBaseUrl) ?? baseUrl;
239
392
  let querySerializer = typeof globalQuerySerializer === "function" ? globalQuerySerializer : createQuerySerializer(globalQuerySerializer);
@@ -242,6 +395,41 @@ function createClient(clientOptions) {
242
395
  ...requestQuerySerializer
243
396
  });
244
397
  const pathSerializer = requestPathSerializer || globalPathSerializer || defaultPathSerializer;
398
+ const finalMiddlewares = [...globalMiddlewares, ...requestMiddlewares];
399
+ const method = String(init.method ?? "GET").toUpperCase();
400
+ let id;
401
+ let options;
402
+ let params = initialParams;
403
+ let body = initialBody;
404
+ if (finalMiddlewares.length) {
405
+ id = randomID();
406
+ options = Object.freeze({
407
+ baseUrl: finalBaseUrl,
408
+ fetch,
409
+ parseAs,
410
+ querySerializer,
411
+ bodySerializer,
412
+ pathSerializer
413
+ });
414
+ for (const m of finalMiddlewares) if (m && typeof m === "object" && typeof m.onRequestInit === "function") {
415
+ const result = await m.onRequestInit({
416
+ schemaPath,
417
+ method,
418
+ input: {
419
+ params,
420
+ body
421
+ },
422
+ headers: mergeHeaders(baseHeaders, headers, params.header),
423
+ options,
424
+ id
425
+ });
426
+ if (result !== void 0) {
427
+ if (!result || typeof result !== "object" || !("params" in result) || !("body" in result)) throw new Error("onRequestInit: must return request input when modifying it");
428
+ params = result.params;
429
+ body = result.body;
430
+ }
431
+ }
432
+ }
245
433
  const serializedBody = body === void 0 ? void 0 : bodySerializer(body, mergeHeaders(baseHeaders, headers, params.header));
246
434
  const finalHeaders = mergeHeaders(serializedBody === void 0 || serializedBody instanceof FormData ? {} : { "Content-Type": "application/json" }, baseHeaders, headers, params.header);
247
435
  const serializedCookies = serializeCookieParams(params.cookie);
@@ -249,7 +437,6 @@ function createClient(clientOptions) {
249
437
  const existingCookie = finalHeaders.get("Cookie");
250
438
  finalHeaders.set("Cookie", existingCookie ? `${existingCookie}; ${serializedCookies}` : serializedCookies);
251
439
  }
252
- const finalMiddlewares = [...globalMiddlewares, ...requestMiddlewares];
253
440
  const requestInit = {
254
441
  redirect: "follow",
255
442
  ...baseOptions,
@@ -257,8 +444,6 @@ function createClient(clientOptions) {
257
444
  body: serializedBody,
258
445
  headers: finalHeaders
259
446
  };
260
- let id;
261
- let options;
262
447
  let request = new Request(createFinalURL(schemaPath, {
263
448
  baseUrl: finalBaseUrl,
264
449
  params,
@@ -269,15 +454,6 @@ function createClient(clientOptions) {
269
454
  /** Add custom parameters to Request object */
270
455
  for (const key in init) if (!(key in request)) request[key] = init[key];
271
456
  if (finalMiddlewares.length) {
272
- id = randomID();
273
- options = Object.freeze({
274
- baseUrl: finalBaseUrl,
275
- fetch,
276
- parseAs,
277
- querySerializer,
278
- bodySerializer,
279
- pathSerializer
280
- });
281
457
  for (const m of finalMiddlewares) if (m && typeof m === "object" && typeof m.onRequest === "function") {
282
458
  const result = await m.onRequest({
283
459
  request,
@@ -346,14 +522,15 @@ function createClient(clientOptions) {
346
522
  }
347
523
  const finalResponse = response;
348
524
  const contentLength = finalResponse.headers.get("Content-Length");
349
- if (finalResponse.status === 204 || request.method === "HEAD" || contentLength === "0" && !finalResponse.headers.get("Transfer-Encoding")?.includes("chunked")) return finalResponse.ok ? {
525
+ let parsedResult;
526
+ if (finalResponse.status === 204 || request.method === "HEAD" || contentLength === "0" && !finalResponse.headers.get("Transfer-Encoding")?.includes("chunked")) parsedResult = finalResponse.ok ? {
350
527
  data: void 0,
351
528
  response: finalResponse
352
529
  } : {
353
530
  error: void 0,
354
531
  response: finalResponse
355
532
  };
356
- if (finalResponse.ok) {
533
+ else if (finalResponse.ok) {
357
534
  const getResponseData = async () => {
358
535
  if (parseAs === "stream") return finalResponse.body;
359
536
  if (parseAs === "json" && !contentLength) {
@@ -362,24 +539,50 @@ function createClient(clientOptions) {
362
539
  }
363
540
  return await finalResponse[parseAs]();
364
541
  };
365
- return {
542
+ parsedResult = {
366
543
  data: await getResponseData(),
367
544
  response: finalResponse
368
545
  };
546
+ } else {
547
+ const raw = await finalResponse.text();
548
+ if (!raw) parsedResult = {
549
+ error: void 0,
550
+ response: finalResponse
551
+ };
552
+ else {
553
+ let error = raw;
554
+ try {
555
+ error = JSON.parse(raw);
556
+ } catch {}
557
+ parsedResult = {
558
+ error,
559
+ response: finalResponse
560
+ };
561
+ }
369
562
  }
370
- const raw = await finalResponse.text();
371
- if (!raw) return {
372
- error: void 0,
373
- response: finalResponse
374
- };
375
- let error = raw;
376
- try {
377
- error = JSON.parse(raw);
378
- } catch {}
379
- return {
380
- error,
381
- response: finalResponse
382
- };
563
+ for (let index = finalMiddlewares.length - 1; index >= 0; index--) {
564
+ const m = finalMiddlewares[index];
565
+ if (m && typeof m === "object" && typeof m.onResult === "function") {
566
+ const update = await m.onResult({
567
+ request,
568
+ schemaPath,
569
+ method,
570
+ params,
571
+ options,
572
+ id,
573
+ result: parsedResult
574
+ });
575
+ if (update !== void 0) {
576
+ if (!update || typeof update !== "object" || Object.keys(update).some((key) => key !== "data" && key !== "error")) throw new Error("onResult: must return data and/or error when modifying the result");
577
+ parsedResult = {
578
+ ...parsedResult,
579
+ ...update,
580
+ response: finalResponse
581
+ };
582
+ }
583
+ }
584
+ }
585
+ return parsedResult;
383
586
  }
384
587
  return {
385
588
  request(method, url, init) {
@@ -448,7 +651,7 @@ function createClient(clientOptions) {
448
651
  use(...middleware) {
449
652
  for (const m of middleware) {
450
653
  if (!m) continue;
451
- if (typeof m !== "object" || !("onRequest" in m || "onResponse" in m || "onError" in m)) throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");
654
+ if (typeof m !== "object" || !("onRequestInit" in m || "onRequest" in m || "onResponse" in m || "onError" in m || "onResult" in m)) throw new Error("Middleware must be an object with a supported hook");
452
655
  globalMiddlewares.push(m);
453
656
  }
454
657
  },
@@ -461,8 +664,7 @@ function createClient(clientOptions) {
461
664
  }
462
665
  };
463
666
  }
464
- //#endregion
465
- //#region src/path-client.ts
667
+ // src/path-client.ts
466
668
  var PathCallForwarder = class {
467
669
  client;
468
670
  url;
@@ -522,7 +724,6 @@ function wrapAsPathBasedClient(coreClient) {
522
724
  function createPathBasedClient(clientOptions) {
523
725
  return wrapAsPathBasedClient(createClient(clientOptions));
524
726
  }
525
- //#endregion
526
727
  exports.createClient = createClient;
527
728
  exports.createFinalURL = createFinalURL;
528
729
  exports.createPathBasedClient = createPathBasedClient;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,3 @@
1
- //#region src/helpers.d.ts
2
1
  type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace";
3
2
  /** 2XX statuses */
4
3
  type OkStatus = 200 | 201 | 202 | 203 | 204 | 206 | 207 | "2XX";
@@ -190,8 +189,29 @@ type Readable<T> = T extends $Write<any> ? never : T extends $Read<infer U> ? Re
190
189
  * - object → recursively resolve
191
190
  */
192
191
  type Writable<T> = T extends $Read<any> ? never : T extends $Write<infer U> ? Writable<U> : T extends (infer E)[] ? Writable<E>[] : T extends object ? { [K in keyof T as NonNullable<T[K]> extends $Read<any> ? never : K]: Writable<T[K]>; } & { [K in keyof T as NonNullable<T[K]> extends $Read<any> ? K : never]?: never; } : T;
193
- //#endregion
194
- //#region src/types.d.ts
192
+ interface CaseSchema {
193
+ readonly ref?: string;
194
+ readonly properties?: Readonly<Record<string, {
195
+ readonly name: string;
196
+ readonly schema?: CaseSchema;
197
+ }>>;
198
+ readonly declared?: readonly string[];
199
+ readonly items?: CaseSchema;
200
+ readonly prefixItems?: readonly (CaseSchema | null)[];
201
+ readonly additionalProperties?: CaseSchema;
202
+ readonly patternProperties?: Readonly<Record<string, CaseSchema | null>>;
203
+ readonly variants?: readonly CaseSchema[];
204
+ }
205
+ type CaseMediaMap = Readonly<Record<string, CaseSchema | null>>;
206
+ interface CaseOperation {
207
+ readonly parameters?: Readonly<Partial<Record<"path" | "query" | "header" | "cookie", CaseSchema>>>;
208
+ readonly requestBodies?: CaseMediaMap;
209
+ readonly responses?: Readonly<Record<string, CaseMediaMap | null>>;
210
+ }
211
+ interface CaseMapping {
212
+ readonly schemas?: Readonly<Record<string, CaseSchema>>;
213
+ readonly operations?: Readonly<Record<string, CaseOperation>>;
214
+ }
195
215
  /** Options for each client instance */
196
216
  interface ClientOptions extends Omit<RequestInit, "headers"> {
197
217
  /** set the common root URL for all API requests */
@@ -206,6 +226,8 @@ interface ClientOptions extends Omit<RequestInit, "headers"> {
206
226
  bodySerializer?: BodySerializer<unknown>;
207
227
  /** global pathSerializer */
208
228
  pathSerializer?: PathSerializer;
229
+ /** schema-based field mapping applied to every request and parsed result */
230
+ caseMapping?: CaseMapping;
209
231
  headers?: HeadersOptions;
210
232
  /** RequestInit extension object to pass as 2nd argument to fetch when supported (defaults to undefined) */
211
233
  requestInitExt?: Record<string, unknown>;
@@ -301,10 +323,28 @@ type MergedOptions<T = unknown> = {
301
323
  };
302
324
  interface MiddlewareRequestParams {
303
325
  query?: Record<string, unknown>;
304
- header?: Record<string, unknown>;
326
+ header?: HeadersOptions;
305
327
  path?: Record<string, unknown>;
306
328
  cookie?: Record<string, unknown>;
307
329
  }
330
+ interface MiddlewareRequestInput {
331
+ readonly params: MiddlewareRequestParams;
332
+ readonly body: unknown;
333
+ }
334
+ interface MiddlewareRequestInitParams {
335
+ readonly schemaPath: string;
336
+ readonly method: string;
337
+ readonly input: MiddlewareRequestInput;
338
+ /** Client, request, and parameter headers merged before serialization. */
339
+ readonly headers: Headers;
340
+ readonly id: string;
341
+ readonly options: MergedOptions;
342
+ }
343
+ interface MiddlewareResult {
344
+ readonly data?: unknown;
345
+ readonly error?: unknown;
346
+ readonly response: Response;
347
+ }
308
348
  interface MiddlewareCallbackParams {
309
349
  /** Current Request object */
310
350
  request: Request;
@@ -317,6 +357,12 @@ interface MiddlewareCallbackParams {
317
357
  /** createClient options (read-only) */
318
358
  readonly options: MergedOptions;
319
359
  }
360
+ interface MiddlewareResultParams extends MiddlewareCallbackParams {
361
+ /** The method requested through the client, before HTTP middleware can replace the Request. */
362
+ readonly method: string;
363
+ readonly result: MiddlewareResult;
364
+ }
365
+ type MiddlewareOnRequestInit = (options: MiddlewareRequestInitParams) => void | MiddlewareRequestInput | Promise<MiddlewareRequestInput | void>;
320
366
  type MiddlewareOnRequest = (options: MiddlewareCallbackParams) => void | Request | Response | undefined | Promise<Request | Response | undefined | void>;
321
367
  type MiddlewareOnResponse = (options: MiddlewareCallbackParams & {
322
368
  response: Response;
@@ -324,19 +370,25 @@ type MiddlewareOnResponse = (options: MiddlewareCallbackParams & {
324
370
  type MiddlewareOnError = (options: MiddlewareCallbackParams & {
325
371
  error: unknown;
326
372
  }) => void | Response | Error | Promise<void | Response | Error>;
327
- type Middleware = {
328
- onRequest: MiddlewareOnRequest;
373
+ type MiddlewareOnResult = (options: MiddlewareResultParams) => void | Partial<Pick<MiddlewareResult, "data" | "error">> | Promise<Partial<Pick<MiddlewareResult, "data" | "error">> | void>;
374
+ interface MiddlewareHooks {
375
+ onRequestInit?: MiddlewareOnRequestInit;
376
+ onRequest?: MiddlewareOnRequest;
329
377
  onResponse?: MiddlewareOnResponse;
330
378
  onError?: MiddlewareOnError;
379
+ onResult?: MiddlewareOnResult;
380
+ }
381
+ type Middleware = MiddlewareHooks & ({
382
+ onRequestInit: MiddlewareOnRequestInit;
383
+ } | {
384
+ onRequest: MiddlewareOnRequest;
331
385
  } | {
332
- onRequest?: MiddlewareOnRequest;
333
386
  onResponse: MiddlewareOnResponse;
334
- onError?: MiddlewareOnError;
335
387
  } | {
336
- onRequest?: MiddlewareOnRequest;
337
- onResponse?: MiddlewareOnResponse;
338
388
  onError: MiddlewareOnError;
339
- };
389
+ } | {
390
+ onResult: MiddlewareOnResult;
391
+ });
340
392
  /** This type helper makes the 2nd function param required if params/requestBody are required; otherwise, optional */
341
393
  type MaybeOptionalInit<Params, Location extends keyof Params> = RequiredKeysOf<FetchOptions<FilterKeys<Params, Location>>> extends never ? FetchOptions<FilterKeys<Params, Location>> | undefined : FetchOptions<FilterKeys<Params, Location>>;
342
394
  type InitParam<Init> = RequiredKeysOf<Init> extends never ? [(Init & {
@@ -375,14 +427,10 @@ type MethodResponse<CreatedClient extends Client<any, any>, Method extends HttpM
375
427
  [key: string]: any;
376
428
  }, infer Media extends MediaType> ? NonNullable<FetchResponse<Paths[Path][Method], Options, Media>["data"]> : never;
377
429
  type PathBasedClient<Paths extends Record<string | number, any>, Media extends MediaType = MediaType> = { [Path in keyof Paths]: ClientForPath<Paths[Path], Media>; };
378
- //#endregion
379
- //#region src/client.d.ts
380
430
  /**
381
431
  * Create an openapi-fetch client.
382
432
  */
383
433
  export default function createClient<Paths extends {}, Media extends MediaType = MediaType>(clientOptions?: ClientOptions): Client<Paths, Media>;
384
- //#endregion
385
- //#region src/path-client.d.ts
386
434
  /**
387
435
  * Wrap openapi-fetch client to support a path based API.
388
436
  */
@@ -392,12 +440,8 @@ export declare function wrapAsPathBasedClient<Paths extends {}, Media extends Me
392
440
  * Strictly equivalent to `wrapAsPathBasedClient(createClient(...))`.
393
441
  */
394
442
  export declare function createPathBasedClient<Paths extends {}, Media extends MediaType = MediaType>(clientOptions?: ClientOptions): PathBasedClient<Paths, Media>;
395
- //#endregion
396
- //#region src/headers.d.ts
397
443
  /** Merge headers a and b, with b taking priority */
398
444
  export declare function mergeHeaders(...allHeaders: (HeadersOptions | undefined)[]): Headers;
399
- //#endregion
400
- //#region src/serializers/param.d.ts
401
445
  type SerializePrimitiveOptions = {
402
446
  allowReserved?: boolean;
403
447
  };
@@ -417,23 +461,15 @@ type SerializeArrayOptions = {
417
461
  };
418
462
  /** Serialize array param (shallow only) */
419
463
  export declare function serializeArrayParam(name: string, value: unknown[], options: SerializeArrayOptions): string;
420
- //#endregion
421
- //#region src/serializers/query.d.ts
422
464
  /** Serialize query params to string */
423
465
  export declare function createQuerySerializer<T = unknown>(options?: QuerySerializerOptions): (queryParams: T) => string;
424
- //#endregion
425
- //#region src/serializers/path.d.ts
426
466
  /**
427
467
  * Handle different OpenAPI 3.x serialization styles
428
468
  * @see https://swagger.io/docs/specification/serialization/#path
429
469
  */
430
470
  export declare function defaultPathSerializer(pathname: string, pathParams: Record<string, unknown>): string;
431
- //#endregion
432
- //#region src/serializers/body.d.ts
433
471
  /** Serialize body object to string */
434
472
  export declare function defaultBodySerializer<T>(body: T, headers?: Headers | Record<string, unknown>): string | FormData;
435
- //#endregion
436
- //#region src/serializers/url.d.ts
437
473
  /** Construct URL string from baseUrl and handle path and query params */
438
474
  export declare function createFinalURL<O>(pathname: string, options: {
439
475
  baseUrl: string;
@@ -446,5 +482,4 @@ export declare function createFinalURL<O>(pathname: string, options: {
446
482
  }): string;
447
483
  /** Remove trailing slash from url */
448
484
  export declare function removeTrailingSlash(url: string): string;
449
- //#endregion
450
- export { type $Read, type $Write, type BodySerializer, type Client, type ClientForPath, type ClientMethod, type ClientOptions, type ClientPathsWithMethod, type ClientRequestMethod, type DefaultParamsOption, type ErrorResponse, type ErrorResponseJSON, type ErrorStatus, type FetchOptions, type FetchResponse, type FilterKeys, type FirstErrorStatus, type GetResponseContent, type HeadersOptions, type HttpMethod, type IsOperationRequestBodyOptional, type JSONLike, type MaybeOptionalInit, type MediaType, type MergedOptions, type MethodResponse, type Middleware, type MiddlewareCallbackParams, type MiddlewareRequestParams, type OKStatusUnion, type OkStatus, type OperationObject, type OperationRequestBody, type OperationRequestBodyContent, type OperationRequestBodyMediaContent, type ParamsOption, type ParseAs, type ParseAsResponse, type PathBasedClient, type PathItemObject, type PathSerializer, type PathsWithMethod, type QuerySerializer, type QuerySerializerOptions, type Readable, type RequestBodyJSON, type RequestBodyOption, type RequestOptions, type RequiredKeysOf, type ResponseContent, type ResponseObjectMap, type SuccessResponse, type SuccessResponseJSON, type Writable, createClient };
485
+ export { type $Read, type $Write, type BodySerializer, type Client, type ClientForPath, type ClientMethod, type ClientOptions, type ClientPathsWithMethod, type ClientRequestMethod, type DefaultParamsOption, type ErrorResponse, type ErrorResponseJSON, type ErrorStatus, type FetchOptions, type FetchResponse, type FilterKeys, type FirstErrorStatus, type GetResponseContent, type HeadersOptions, type HttpMethod, type IsOperationRequestBodyOptional, type JSONLike, type MaybeOptionalInit, type MediaType, type MergedOptions, type MethodResponse, type Middleware, type MiddlewareCallbackParams, type MiddlewareRequestInitParams, type MiddlewareRequestInput, type MiddlewareRequestParams, type MiddlewareResult, type MiddlewareResultParams, type OKStatusUnion, type OkStatus, type OperationObject, type OperationRequestBody, type OperationRequestBodyContent, type OperationRequestBodyMediaContent, type ParamsOption, type ParseAs, type ParseAsResponse, type PathBasedClient, type PathItemObject, type PathSerializer, type PathsWithMethod, type QuerySerializer, type QuerySerializerOptions, type Readable, type RequestBodyJSON, type RequestBodyOption, type RequestOptions, type RequiredKeysOf, type ResponseContent, type ResponseObjectMap, type SuccessResponse, type SuccessResponseJSON, type Writable, createClient };