@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.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
|
|
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
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 };
|