@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/README.md +93 -33
- package/dist/index.cjs +250 -49
- package/dist/index.d.cts +64 -29
- package/dist/index.d.ts +64 -29
- package/dist/index.js +250 -49
- package/dist/transform-casing.cjs +161 -0
- package/dist/transform-casing.d.cts +138 -0
- package/dist/transform-casing.d.ts +138 -0
- package/dist/transform-casing.js +160 -0
- package/package.json +14 -4
package/dist/index.d.ts
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
|
-
|
|
194
|
-
|
|
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?:
|
|
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
|
|
328
|
-
|
|
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
|
-
|
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/headers.ts
|
|
2
2
|
/** Iterate any `HeadersOptions` form (plain object, `Headers`, or `[name, value]` tuples) as entries */
|
|
3
3
|
function headerEntries(h) {
|
|
4
4
|
if (h instanceof Headers) return h.entries();
|
|
@@ -16,8 +16,166 @@ function mergeHeaders(...allHeaders) {
|
|
|
16
16
|
}
|
|
17
17
|
return finalHeaders;
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
// src/middleware/transform-casing.ts
|
|
20
|
+
function expandSchemas(schemas, mapping, visited = /* @__PURE__ */ new Set()) {
|
|
21
|
+
return schemas.flatMap((schema) => {
|
|
22
|
+
const nested = schema.variants ?? [];
|
|
23
|
+
if (!schema.ref || visited.has(schema.ref)) return [schema, ...expandSchemas(nested, mapping, visited)];
|
|
24
|
+
const referenced = mapping.schemas?.[schema.ref];
|
|
25
|
+
const next = new Set(visited).add(schema.ref);
|
|
26
|
+
return [schema, ...expandSchemas(referenced ? [referenced, ...nested] : nested, mapping, next)];
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function createConverter(mapping) {
|
|
30
|
+
const schemaIds = /* @__PURE__ */ new WeakMap();
|
|
31
|
+
const plans = /* @__PURE__ */ new Map();
|
|
32
|
+
let nextId = 0;
|
|
33
|
+
function planFor(schemas, direction) {
|
|
34
|
+
if (schemas.length === 0) return void 0;
|
|
35
|
+
const key = `${direction}:${schemas.map((schema) => {
|
|
36
|
+
let id = schemaIds.get(schema);
|
|
37
|
+
if (id === void 0) {
|
|
38
|
+
id = ++nextId;
|
|
39
|
+
schemaIds.set(schema, id);
|
|
40
|
+
}
|
|
41
|
+
return id;
|
|
42
|
+
}).join(",")}`;
|
|
43
|
+
const existing = plans.get(key);
|
|
44
|
+
if (existing) return existing;
|
|
45
|
+
const expanded = expandSchemas(schemas, mapping);
|
|
46
|
+
const fields = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const schema of expanded) for (const [wireName, field] of Object.entries(schema.properties ?? {})) {
|
|
48
|
+
const sourceName = direction === "toApi" ? field.name : wireName;
|
|
49
|
+
const targetName = direction === "toApi" ? wireName : field.name;
|
|
50
|
+
const current = fields.get(sourceName);
|
|
51
|
+
if (current) {
|
|
52
|
+
if (current.name !== targetName) throw new Error(`Conflicting case mapping for ${sourceName}`);
|
|
53
|
+
if (field.schema) current.schemas.push(field.schema);
|
|
54
|
+
} else fields.set(sourceName, {
|
|
55
|
+
name: targetName,
|
|
56
|
+
schemas: field.schema ? [field.schema] : []
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const plan = {
|
|
60
|
+
expanded,
|
|
61
|
+
fields,
|
|
62
|
+
declared: new Set(expanded.flatMap((schema) => schema.declared ?? [])),
|
|
63
|
+
patterns: expanded.flatMap((schema) => Object.entries(schema.patternProperties ?? {}).map(([pattern, nested]) => ({
|
|
64
|
+
regex: new RegExp(pattern),
|
|
65
|
+
schema: nested
|
|
66
|
+
}))),
|
|
67
|
+
additional: expanded.flatMap((schema) => schema.additionalProperties ? [schema.additionalProperties] : []),
|
|
68
|
+
prefixLength: expanded.reduce((max, schema) => Math.max(max, schema.prefixItems?.length ?? 0), 0)
|
|
69
|
+
};
|
|
70
|
+
plans.set(key, plan);
|
|
71
|
+
return plan;
|
|
72
|
+
}
|
|
73
|
+
function itemPlan(plan, index, direction) {
|
|
74
|
+
if (index >= plan.prefixLength) {
|
|
75
|
+
if (plan.items === void 0) plan.items = planFor(plan.expanded.flatMap((schema) => schema.items ? [schema.items] : []), direction) ?? null;
|
|
76
|
+
return plan.items ?? void 0;
|
|
77
|
+
}
|
|
78
|
+
const prefixItems = plan.prefixItems ??= [];
|
|
79
|
+
if (prefixItems[index] === void 0) prefixItems[index] = planFor(plan.expanded.flatMap((schema) => {
|
|
80
|
+
const prefix = schema.prefixItems;
|
|
81
|
+
const item = prefix && index < prefix.length ? prefix[index] : schema.items;
|
|
82
|
+
return item ? [item] : [];
|
|
83
|
+
}), direction) ?? null;
|
|
84
|
+
return prefixItems[index] ?? void 0;
|
|
85
|
+
}
|
|
86
|
+
function convertWithPlan(value, plan, direction) {
|
|
87
|
+
if (!plan || value === null || value === void 0) return value;
|
|
88
|
+
if (Array.isArray(value)) return value.map((item, index) => convertWithPlan(item, itemPlan(plan, index, direction), direction));
|
|
89
|
+
if (typeof value !== "object") return value;
|
|
90
|
+
const prototype = Object.getPrototypeOf(value);
|
|
91
|
+
if (prototype !== Object.prototype && prototype !== null) return value;
|
|
92
|
+
const convertedNames = /* @__PURE__ */ new Set();
|
|
93
|
+
const entries = Object.entries(value).map(([name, item]) => {
|
|
94
|
+
const field = plan.fields.get(name);
|
|
95
|
+
const matched = [];
|
|
96
|
+
let hasPattern = false;
|
|
97
|
+
for (const pattern of plan.patterns) if (pattern.regex.test(name)) {
|
|
98
|
+
hasPattern = true;
|
|
99
|
+
if (pattern.schema) matched.push(pattern.schema);
|
|
100
|
+
}
|
|
101
|
+
let nested;
|
|
102
|
+
if (matched.length > 0) nested = planFor([...field?.schemas ?? [], ...matched], direction);
|
|
103
|
+
else if (field) {
|
|
104
|
+
if (field.nested === void 0) field.nested = planFor(field.schemas, direction) ?? null;
|
|
105
|
+
nested = field.nested ?? void 0;
|
|
106
|
+
} else if (!plan.declared.has(name) && !hasPattern) {
|
|
107
|
+
if (plan.additionalPlan === void 0) plan.additionalPlan = planFor(plan.additional, direction) ?? null;
|
|
108
|
+
nested = plan.additionalPlan ?? void 0;
|
|
109
|
+
}
|
|
110
|
+
const targetName = field?.name ?? name;
|
|
111
|
+
if (convertedNames.has(targetName)) throw new Error(`Conflicting case mapping for ${targetName}`);
|
|
112
|
+
convertedNames.add(targetName);
|
|
113
|
+
return [targetName, convertWithPlan(item, nested, direction)];
|
|
114
|
+
});
|
|
115
|
+
return Object.fromEntries(entries);
|
|
116
|
+
}
|
|
117
|
+
return (value, schemas, direction) => {
|
|
118
|
+
if (schemas.length === 0 || value === null || value === void 0) return value;
|
|
119
|
+
return convertWithPlan(value, planFor(schemas, direction), direction);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function isJsonMediaType(mediaType) {
|
|
123
|
+
return mediaType === "application/json" || mediaType.endsWith("+json");
|
|
124
|
+
}
|
|
125
|
+
function mediaSchema(media, contentType) {
|
|
126
|
+
if (!media) return void 0;
|
|
127
|
+
const type = contentType?.split(";", 1)[0]?.trim().toLowerCase();
|
|
128
|
+
if (type && !isJsonMediaType(type)) return void 0;
|
|
129
|
+
const entries = Object.entries(media).filter(([name]) => isJsonMediaType(name.toLowerCase()));
|
|
130
|
+
const exact = entries.find(([name]) => name.toLowerCase() === type);
|
|
131
|
+
if (exact) return exact[1] ?? void 0;
|
|
132
|
+
const json = entries.find(([name]) => name.toLowerCase() === "application/json");
|
|
133
|
+
if (json) return json[1] ?? void 0;
|
|
134
|
+
return entries.length === 1 ? entries[0]?.[1] ?? void 0 : void 0;
|
|
135
|
+
}
|
|
136
|
+
function responseMedia(operation, response) {
|
|
137
|
+
const responses = operation.responses;
|
|
138
|
+
if (!responses) return void 0;
|
|
139
|
+
const status = String(response.status);
|
|
140
|
+
const range = `${status[0]}XX`;
|
|
141
|
+
return mediaSchema(Object.hasOwn(responses, status) ? responses[status] : Object.hasOwn(responses, range) ? responses[range] : responses.default, response.headers.get("content-type") ?? void 0);
|
|
142
|
+
}
|
|
143
|
+
function convertRequest(input, operation, convertValue, headers) {
|
|
144
|
+
const parameters = operation.parameters;
|
|
145
|
+
const params = input.params;
|
|
146
|
+
const bodySchema = mediaSchema(operation.requestBodies, headers.get("content-type") ?? void 0);
|
|
147
|
+
return {
|
|
148
|
+
params: parameters ? {
|
|
149
|
+
...params,
|
|
150
|
+
path: convertValue(params.path, parameters.path ? [parameters.path] : [], "toApi"),
|
|
151
|
+
query: convertValue(params.query, parameters.query ? [parameters.query] : [], "toApi"),
|
|
152
|
+
header: convertValue(params.header, parameters.header ? [parameters.header] : [], "toApi"),
|
|
153
|
+
cookie: convertValue(params.cookie, parameters.cookie ? [parameters.cookie] : [], "toApi")
|
|
154
|
+
} : params,
|
|
155
|
+
body: bodySchema && input.body !== void 0 ? convertValue(input.body, [bodySchema], "toApi") : input.body
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/** Convert generated camelCase values at the openapi-fetch request and result stages. */
|
|
159
|
+
function createCaseMappingMiddleware(mapping) {
|
|
160
|
+
const convertValue = createConverter(mapping);
|
|
161
|
+
return {
|
|
162
|
+
onRequestInit({ method, schemaPath, input, headers }) {
|
|
163
|
+
const operation = mapping.operations?.[`${method} ${schemaPath}`];
|
|
164
|
+
return operation ? convertRequest(input, operation, convertValue, headers) : void 0;
|
|
165
|
+
},
|
|
166
|
+
onResult({ method, schemaPath, result, options }) {
|
|
167
|
+
const operation = mapping.operations?.[`${method} ${schemaPath}`];
|
|
168
|
+
if (!operation) return;
|
|
169
|
+
const schema = responseMedia(operation, result.response);
|
|
170
|
+
if (!schema) return;
|
|
171
|
+
return {
|
|
172
|
+
...options.parseAs === "json" && result.data !== void 0 ? { data: convertValue(result.data, [schema], "fromApi") } : {},
|
|
173
|
+
...result.error !== void 0 ? { error: convertValue(result.error, [schema], "fromApi") } : {}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// src/serializers/body.ts
|
|
21
179
|
/** Serialize body object to string */
|
|
22
180
|
function defaultBodySerializer(body, headers) {
|
|
23
181
|
if (body instanceof FormData) return body;
|
|
@@ -26,8 +184,7 @@ function defaultBodySerializer(body, headers) {
|
|
|
26
184
|
}
|
|
27
185
|
return JSON.stringify(body);
|
|
28
186
|
}
|
|
29
|
-
|
|
30
|
-
//#region src/serializers/param.ts
|
|
187
|
+
// src/serializers/param.ts
|
|
31
188
|
/** Serialize primitive params to string */
|
|
32
189
|
function serializePrimitiveParam(name, value, options) {
|
|
33
190
|
if (value === void 0 || value === null) return "";
|
|
@@ -87,8 +244,7 @@ function serializeArrayParam(name, value, options) {
|
|
|
87
244
|
else values.push(serializePrimitiveParam(name, v, options));
|
|
88
245
|
return options.style === "label" || options.style === "matrix" ? `${joiner}${values.join(joiner)}` : values.join(joiner);
|
|
89
246
|
}
|
|
90
|
-
|
|
91
|
-
//#region src/serializers/cookie.ts
|
|
247
|
+
// src/serializers/cookie.ts
|
|
92
248
|
/**
|
|
93
249
|
* Serialize cookie params to a `Cookie` header value using the OpenAPI default
|
|
94
250
|
* (style: form, explode: true). Arrays repeat the name, objects emit one pair per key,
|
|
@@ -110,8 +266,7 @@ function serializeCookieParams(cookieParams) {
|
|
|
110
266
|
}
|
|
111
267
|
return pairs.join("; ");
|
|
112
268
|
}
|
|
113
|
-
|
|
114
|
-
//#region src/serializers/path.ts
|
|
269
|
+
// src/serializers/path.ts
|
|
115
270
|
const PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
116
271
|
/**
|
|
117
272
|
* Handle different OpenAPI 3.x serialization styles
|
|
@@ -158,8 +313,7 @@ function defaultPathSerializer(pathname, pathParams) {
|
|
|
158
313
|
}
|
|
159
314
|
return nextURL;
|
|
160
315
|
}
|
|
161
|
-
|
|
162
|
-
//#region src/serializers/query.ts
|
|
316
|
+
// src/serializers/query.ts
|
|
163
317
|
/** Serialize query params to string */
|
|
164
318
|
function createQuerySerializer(options) {
|
|
165
319
|
return function querySerializer(queryParams) {
|
|
@@ -191,8 +345,7 @@ function createQuerySerializer(options) {
|
|
|
191
345
|
return search.join("&");
|
|
192
346
|
};
|
|
193
347
|
}
|
|
194
|
-
|
|
195
|
-
//#region src/serializers/url.ts
|
|
348
|
+
// src/serializers/url.ts
|
|
196
349
|
/** Construct URL string from baseUrl and handle path and query params */
|
|
197
350
|
function createFinalURL(pathname, options) {
|
|
198
351
|
let finalURL = `${options.baseUrl}${pathname}`;
|
|
@@ -207,8 +360,7 @@ function removeTrailingSlash(url) {
|
|
|
207
360
|
if (url.endsWith("/")) return url.substring(0, url.length - 1);
|
|
208
361
|
return url;
|
|
209
362
|
}
|
|
210
|
-
|
|
211
|
-
//#region src/client.ts
|
|
363
|
+
// src/client.ts
|
|
212
364
|
function supportsRequestInitExt() {
|
|
213
365
|
const nodeProcess = globalThis.process;
|
|
214
366
|
return typeof nodeProcess === "object" && Number.parseInt(nodeProcess?.versions?.node?.substring(0, 2) ?? "") >= 18 && nodeProcess?.versions?.undici;
|
|
@@ -221,15 +373,16 @@ function randomID() {
|
|
|
221
373
|
* Create an openapi-fetch client.
|
|
222
374
|
*/
|
|
223
375
|
function createClient(clientOptions) {
|
|
224
|
-
let { baseUrl = "", Request: CustomRequest = globalThis.Request, fetch: baseFetch = globalThis.fetch, querySerializer: globalQuerySerializer, bodySerializer: globalBodySerializer, pathSerializer: globalPathSerializer, headers: baseHeaders, requestInitExt, ...baseOptions } = { ...clientOptions };
|
|
376
|
+
let { baseUrl = "", Request: CustomRequest = globalThis.Request, fetch: baseFetch = globalThis.fetch, querySerializer: globalQuerySerializer, bodySerializer: globalBodySerializer, pathSerializer: globalPathSerializer, caseMapping, headers: baseHeaders, requestInitExt, ...baseOptions } = { ...clientOptions };
|
|
225
377
|
requestInitExt = supportsRequestInitExt() ? requestInitExt : void 0;
|
|
226
378
|
baseUrl = removeTrailingSlash(baseUrl);
|
|
227
379
|
const globalMiddlewares = [];
|
|
380
|
+
if (caseMapping !== void 0) globalMiddlewares.push(createCaseMappingMiddleware(caseMapping));
|
|
228
381
|
/**
|
|
229
382
|
* Per-request fetch (keeps settings created in createClient()
|
|
230
383
|
*/
|
|
231
384
|
async function coreFetch(schemaPath, fetchOptions) {
|
|
232
|
-
const { baseUrl: localBaseUrl, fetch = baseFetch, Request = CustomRequest, headers, params = {}, parseAs = "json", querySerializer: requestQuerySerializer, bodySerializer = globalBodySerializer ?? defaultBodySerializer, pathSerializer: requestPathSerializer, body, middleware: requestMiddlewares = [], ...init } = fetchOptions || {};
|
|
385
|
+
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 || {};
|
|
233
386
|
let finalBaseUrl = baseUrl;
|
|
234
387
|
if (localBaseUrl) finalBaseUrl = removeTrailingSlash(localBaseUrl) ?? baseUrl;
|
|
235
388
|
let querySerializer = typeof globalQuerySerializer === "function" ? globalQuerySerializer : createQuerySerializer(globalQuerySerializer);
|
|
@@ -238,6 +391,41 @@ function createClient(clientOptions) {
|
|
|
238
391
|
...requestQuerySerializer
|
|
239
392
|
});
|
|
240
393
|
const pathSerializer = requestPathSerializer || globalPathSerializer || defaultPathSerializer;
|
|
394
|
+
const finalMiddlewares = [...globalMiddlewares, ...requestMiddlewares];
|
|
395
|
+
const method = String(init.method ?? "GET").toUpperCase();
|
|
396
|
+
let id;
|
|
397
|
+
let options;
|
|
398
|
+
let params = initialParams;
|
|
399
|
+
let body = initialBody;
|
|
400
|
+
if (finalMiddlewares.length) {
|
|
401
|
+
id = randomID();
|
|
402
|
+
options = Object.freeze({
|
|
403
|
+
baseUrl: finalBaseUrl,
|
|
404
|
+
fetch,
|
|
405
|
+
parseAs,
|
|
406
|
+
querySerializer,
|
|
407
|
+
bodySerializer,
|
|
408
|
+
pathSerializer
|
|
409
|
+
});
|
|
410
|
+
for (const m of finalMiddlewares) if (m && typeof m === "object" && typeof m.onRequestInit === "function") {
|
|
411
|
+
const result = await m.onRequestInit({
|
|
412
|
+
schemaPath,
|
|
413
|
+
method,
|
|
414
|
+
input: {
|
|
415
|
+
params,
|
|
416
|
+
body
|
|
417
|
+
},
|
|
418
|
+
headers: mergeHeaders(baseHeaders, headers, params.header),
|
|
419
|
+
options,
|
|
420
|
+
id
|
|
421
|
+
});
|
|
422
|
+
if (result !== void 0) {
|
|
423
|
+
if (!result || typeof result !== "object" || !("params" in result) || !("body" in result)) throw new Error("onRequestInit: must return request input when modifying it");
|
|
424
|
+
params = result.params;
|
|
425
|
+
body = result.body;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
241
429
|
const serializedBody = body === void 0 ? void 0 : bodySerializer(body, mergeHeaders(baseHeaders, headers, params.header));
|
|
242
430
|
const finalHeaders = mergeHeaders(serializedBody === void 0 || serializedBody instanceof FormData ? {} : { "Content-Type": "application/json" }, baseHeaders, headers, params.header);
|
|
243
431
|
const serializedCookies = serializeCookieParams(params.cookie);
|
|
@@ -245,7 +433,6 @@ function createClient(clientOptions) {
|
|
|
245
433
|
const existingCookie = finalHeaders.get("Cookie");
|
|
246
434
|
finalHeaders.set("Cookie", existingCookie ? `${existingCookie}; ${serializedCookies}` : serializedCookies);
|
|
247
435
|
}
|
|
248
|
-
const finalMiddlewares = [...globalMiddlewares, ...requestMiddlewares];
|
|
249
436
|
const requestInit = {
|
|
250
437
|
redirect: "follow",
|
|
251
438
|
...baseOptions,
|
|
@@ -253,8 +440,6 @@ function createClient(clientOptions) {
|
|
|
253
440
|
body: serializedBody,
|
|
254
441
|
headers: finalHeaders
|
|
255
442
|
};
|
|
256
|
-
let id;
|
|
257
|
-
let options;
|
|
258
443
|
let request = new Request(createFinalURL(schemaPath, {
|
|
259
444
|
baseUrl: finalBaseUrl,
|
|
260
445
|
params,
|
|
@@ -265,15 +450,6 @@ function createClient(clientOptions) {
|
|
|
265
450
|
/** Add custom parameters to Request object */
|
|
266
451
|
for (const key in init) if (!(key in request)) request[key] = init[key];
|
|
267
452
|
if (finalMiddlewares.length) {
|
|
268
|
-
id = randomID();
|
|
269
|
-
options = Object.freeze({
|
|
270
|
-
baseUrl: finalBaseUrl,
|
|
271
|
-
fetch,
|
|
272
|
-
parseAs,
|
|
273
|
-
querySerializer,
|
|
274
|
-
bodySerializer,
|
|
275
|
-
pathSerializer
|
|
276
|
-
});
|
|
277
453
|
for (const m of finalMiddlewares) if (m && typeof m === "object" && typeof m.onRequest === "function") {
|
|
278
454
|
const result = await m.onRequest({
|
|
279
455
|
request,
|
|
@@ -342,14 +518,15 @@ function createClient(clientOptions) {
|
|
|
342
518
|
}
|
|
343
519
|
const finalResponse = response;
|
|
344
520
|
const contentLength = finalResponse.headers.get("Content-Length");
|
|
345
|
-
|
|
521
|
+
let parsedResult;
|
|
522
|
+
if (finalResponse.status === 204 || request.method === "HEAD" || contentLength === "0" && !finalResponse.headers.get("Transfer-Encoding")?.includes("chunked")) parsedResult = finalResponse.ok ? {
|
|
346
523
|
data: void 0,
|
|
347
524
|
response: finalResponse
|
|
348
525
|
} : {
|
|
349
526
|
error: void 0,
|
|
350
527
|
response: finalResponse
|
|
351
528
|
};
|
|
352
|
-
if (finalResponse.ok) {
|
|
529
|
+
else if (finalResponse.ok) {
|
|
353
530
|
const getResponseData = async () => {
|
|
354
531
|
if (parseAs === "stream") return finalResponse.body;
|
|
355
532
|
if (parseAs === "json" && !contentLength) {
|
|
@@ -358,24 +535,50 @@ function createClient(clientOptions) {
|
|
|
358
535
|
}
|
|
359
536
|
return await finalResponse[parseAs]();
|
|
360
537
|
};
|
|
361
|
-
|
|
538
|
+
parsedResult = {
|
|
362
539
|
data: await getResponseData(),
|
|
363
540
|
response: finalResponse
|
|
364
541
|
};
|
|
542
|
+
} else {
|
|
543
|
+
const raw = await finalResponse.text();
|
|
544
|
+
if (!raw) parsedResult = {
|
|
545
|
+
error: void 0,
|
|
546
|
+
response: finalResponse
|
|
547
|
+
};
|
|
548
|
+
else {
|
|
549
|
+
let error = raw;
|
|
550
|
+
try {
|
|
551
|
+
error = JSON.parse(raw);
|
|
552
|
+
} catch {}
|
|
553
|
+
parsedResult = {
|
|
554
|
+
error,
|
|
555
|
+
response: finalResponse
|
|
556
|
+
};
|
|
557
|
+
}
|
|
365
558
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
559
|
+
for (let index = finalMiddlewares.length - 1; index >= 0; index--) {
|
|
560
|
+
const m = finalMiddlewares[index];
|
|
561
|
+
if (m && typeof m === "object" && typeof m.onResult === "function") {
|
|
562
|
+
const update = await m.onResult({
|
|
563
|
+
request,
|
|
564
|
+
schemaPath,
|
|
565
|
+
method,
|
|
566
|
+
params,
|
|
567
|
+
options,
|
|
568
|
+
id,
|
|
569
|
+
result: parsedResult
|
|
570
|
+
});
|
|
571
|
+
if (update !== void 0) {
|
|
572
|
+
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");
|
|
573
|
+
parsedResult = {
|
|
574
|
+
...parsedResult,
|
|
575
|
+
...update,
|
|
576
|
+
response: finalResponse
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return parsedResult;
|
|
379
582
|
}
|
|
380
583
|
return {
|
|
381
584
|
request(method, url, init) {
|
|
@@ -444,7 +647,7 @@ function createClient(clientOptions) {
|
|
|
444
647
|
use(...middleware) {
|
|
445
648
|
for (const m of middleware) {
|
|
446
649
|
if (!m) continue;
|
|
447
|
-
if (typeof m !== "object" || !("onRequest" in m || "onResponse" in m || "onError" in m)) throw new Error("Middleware must be an object with
|
|
650
|
+
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");
|
|
448
651
|
globalMiddlewares.push(m);
|
|
449
652
|
}
|
|
450
653
|
},
|
|
@@ -457,8 +660,7 @@ function createClient(clientOptions) {
|
|
|
457
660
|
}
|
|
458
661
|
};
|
|
459
662
|
}
|
|
460
|
-
|
|
461
|
-
//#region src/path-client.ts
|
|
663
|
+
// src/path-client.ts
|
|
462
664
|
var PathCallForwarder = class {
|
|
463
665
|
client;
|
|
464
666
|
url;
|
|
@@ -518,5 +720,4 @@ function wrapAsPathBasedClient(coreClient) {
|
|
|
518
720
|
function createPathBasedClient(clientOptions) {
|
|
519
721
|
return wrapAsPathBasedClient(createClient(clientOptions));
|
|
520
722
|
}
|
|
521
|
-
//#endregion
|
|
522
723
|
export { createClient, createClient as default, createFinalURL, createPathBasedClient, createQuerySerializer, defaultBodySerializer, defaultPathSerializer, mergeHeaders, removeTrailingSlash, serializeArrayParam, serializeObjectParam, serializePrimitiveParam, wrapAsPathBasedClient };
|