httpsnippet-client-api 6.1.1 → 7.0.0-alpha.5
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/LICENSE +1 -1
- package/dist/index.cjs +219 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +204 -301
- package/dist/index.js.map +1 -0
- package/package.json +27 -19
- package/src/index.ts +14 -16
- package/tsconfig.json +2 -6
- package/tsup.config.ts +15 -0
package/LICENSE
CHANGED
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/index.ts
|
|
2
|
+
var _codebuilder = require('@readme/httpsnippet/helpers/code-builder');
|
|
3
|
+
var _contenttype = require('content-type'); var _contenttype2 = _interopRequireDefault(_contenttype);
|
|
4
|
+
var _oas = require('oas'); var _oas2 = _interopRequireDefault(_oas);
|
|
5
|
+
var _utils = require('oas/utils');
|
|
6
|
+
var _stringifyobject = require('stringify-object'); var _stringifyobject2 = _interopRequireDefault(_stringifyobject);
|
|
7
|
+
function stringify(obj, opts = {}) {
|
|
8
|
+
return _stringifyobject2.default.call(void 0, obj, { indent: " ", ...opts });
|
|
9
|
+
}
|
|
10
|
+
function buildAuthSnippet(authKey) {
|
|
11
|
+
if (Array.isArray(authKey)) {
|
|
12
|
+
const auth = [];
|
|
13
|
+
authKey.forEach((token, i) => {
|
|
14
|
+
if (token.length === 0 && authKey.length > 1 && i === authKey.length - 1) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
auth.push(`'${token.replace(/'/g, "\\'")}'`);
|
|
18
|
+
});
|
|
19
|
+
return `sdk.auth(${auth.join(", ")});`;
|
|
20
|
+
}
|
|
21
|
+
return `sdk.auth('${authKey.replace(/'/g, "\\'")}');`;
|
|
22
|
+
}
|
|
23
|
+
function getAuthSources(operation) {
|
|
24
|
+
const matchers = {
|
|
25
|
+
header: {},
|
|
26
|
+
query: [],
|
|
27
|
+
cookie: []
|
|
28
|
+
};
|
|
29
|
+
if (operation.getSecurity().length === 0) {
|
|
30
|
+
return matchers;
|
|
31
|
+
}
|
|
32
|
+
Object.entries(operation.prepareSecurity()).forEach(([, schemes]) => {
|
|
33
|
+
schemes.forEach((scheme) => {
|
|
34
|
+
if (scheme.type === "http") {
|
|
35
|
+
if (scheme.scheme === "basic") {
|
|
36
|
+
matchers.header.authorization = "Basic";
|
|
37
|
+
} else if (scheme.scheme === "bearer") {
|
|
38
|
+
matchers.header.authorization = "Bearer";
|
|
39
|
+
}
|
|
40
|
+
} else if (scheme.type === "oauth2") {
|
|
41
|
+
matchers.header.authorization = "Bearer";
|
|
42
|
+
} else if (scheme.type === "apiKey") {
|
|
43
|
+
if (scheme.in === "query") {
|
|
44
|
+
matchers.query.push(scheme.name);
|
|
45
|
+
} else if (scheme.in === "header") {
|
|
46
|
+
matchers.header[scheme.name.toLowerCase()] = "*";
|
|
47
|
+
} else if (scheme.in === "cookie") {
|
|
48
|
+
matchers.cookie.push(scheme.name);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
return matchers;
|
|
54
|
+
}
|
|
55
|
+
var client = {
|
|
56
|
+
info: {
|
|
57
|
+
key: "api",
|
|
58
|
+
title: "API",
|
|
59
|
+
link: "https://npm.im/api",
|
|
60
|
+
description: "Automatic SDK generation from an OpenAPI definition.",
|
|
61
|
+
extname: ".js"
|
|
62
|
+
},
|
|
63
|
+
convert: ({ cookiesObj, headersObj, postData, queryObj, url, ...source }, options) => {
|
|
64
|
+
const opts = {
|
|
65
|
+
...options
|
|
66
|
+
};
|
|
67
|
+
if (!("apiDefinitionUri" in opts)) {
|
|
68
|
+
throw new Error("This HTTP Snippet client must have an `apiDefinitionUri` option supplied to it.");
|
|
69
|
+
} else if (!("apiDefinition" in opts)) {
|
|
70
|
+
throw new Error("This HTTP Snippet client must have an `apiDefinition` option supplied to it.");
|
|
71
|
+
}
|
|
72
|
+
const method = source.method.toLowerCase();
|
|
73
|
+
const oas = new (0, _oas2.default)(opts.apiDefinition);
|
|
74
|
+
const apiDefinition = oas.getDefinition();
|
|
75
|
+
const foundOperation = oas.findOperation(url, method);
|
|
76
|
+
if (!foundOperation) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Unable to locate a matching operation in the supplied \`apiDefinition\` for: ${source.method} ${url}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
const operationSlugs = foundOperation.url.slugs;
|
|
82
|
+
const operation = oas.operation(foundOperation.url.nonNormalizedPath, method);
|
|
83
|
+
const operationPathParameters = operation.getParameters().filter((param) => param.in === "path");
|
|
84
|
+
const path = operation.path;
|
|
85
|
+
const authData = [];
|
|
86
|
+
const authSources = getAuthSources(operation);
|
|
87
|
+
const { blank, push, join } = new (0, _codebuilder.CodeBuilder)({ indent: opts.indent || " " });
|
|
88
|
+
push(`const sdk = require('api')('${opts.apiDefinitionUri}');`);
|
|
89
|
+
blank();
|
|
90
|
+
const configData = [];
|
|
91
|
+
if ((apiDefinition.servers || []).length > 1) {
|
|
92
|
+
const stockUrl = oas.url();
|
|
93
|
+
const baseUrl = url.replace(path, "");
|
|
94
|
+
if (baseUrl !== stockUrl) {
|
|
95
|
+
const serverVars = oas.splitVariables(baseUrl);
|
|
96
|
+
const serverUrl = serverVars ? oas.url(serverVars.selected, serverVars.variables) : baseUrl;
|
|
97
|
+
configData.push(`sdk.server('${serverUrl}');`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
let metadata = {};
|
|
101
|
+
Object.keys(queryObj).forEach((param) => {
|
|
102
|
+
if (authSources.query.includes(param)) {
|
|
103
|
+
authData.push(buildAuthSnippet(queryObj[param]));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
metadata[param] = queryObj[param];
|
|
107
|
+
});
|
|
108
|
+
Object.keys(cookiesObj).forEach((cookie) => {
|
|
109
|
+
if (authSources.cookie.includes(cookie)) {
|
|
110
|
+
authData.push(buildAuthSnippet(cookiesObj[cookie]));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
metadata[cookie] = cookiesObj[cookie];
|
|
114
|
+
});
|
|
115
|
+
Array.from(Object.entries(operationSlugs)).forEach(([param, value]) => {
|
|
116
|
+
const cleanedParam = param.substring(1);
|
|
117
|
+
const unsanitizedParam = operationPathParameters.find((p) => {
|
|
118
|
+
return p.name.includes("-") && p.name.replace(/-/g, "") === cleanedParam ? p.name : false;
|
|
119
|
+
});
|
|
120
|
+
if (unsanitizedParam) {
|
|
121
|
+
metadata[unsanitizedParam.name] = value;
|
|
122
|
+
} else {
|
|
123
|
+
metadata[cleanedParam] = value;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
if (Object.keys(headersObj).length) {
|
|
127
|
+
const headers = headersObj;
|
|
128
|
+
const requestHeaders = {};
|
|
129
|
+
Object.keys(headers).forEach((header) => {
|
|
130
|
+
const headerLower = header.toLowerCase();
|
|
131
|
+
if (headerLower in authSources.header) {
|
|
132
|
+
const authScheme = authSources.header[headerLower];
|
|
133
|
+
if (authScheme === "*") {
|
|
134
|
+
authData.push(buildAuthSnippet(headers[header]));
|
|
135
|
+
} else {
|
|
136
|
+
let authKey = headers[header].replace(`${authSources.header[headerLower]} `, "");
|
|
137
|
+
if (authScheme.toLowerCase() === "basic") {
|
|
138
|
+
authKey = Buffer.from(authKey, "base64").toString("ascii");
|
|
139
|
+
authKey = authKey.split(":");
|
|
140
|
+
}
|
|
141
|
+
authData.push(buildAuthSnippet(authKey));
|
|
142
|
+
}
|
|
143
|
+
delete headers[header];
|
|
144
|
+
return;
|
|
145
|
+
} else if (headerLower === "content-type") {
|
|
146
|
+
const parsedContentType = _contenttype2.default.parse(headers[header]);
|
|
147
|
+
if (!Object.keys(parsedContentType.parameters).length) {
|
|
148
|
+
delete headers[header];
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
} else if (headerLower === "accept") {
|
|
152
|
+
if (_utils.matchesMimeType.json(headers[header])) {
|
|
153
|
+
delete headers[header];
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
requestHeaders[headerLower] = headers[header];
|
|
158
|
+
});
|
|
159
|
+
if (Object.keys(requestHeaders).length > 0) {
|
|
160
|
+
metadata = Object.assign(metadata, requestHeaders);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
let body;
|
|
164
|
+
switch (postData.mimeType) {
|
|
165
|
+
case "application/x-www-form-urlencoded":
|
|
166
|
+
body = postData.paramsObj;
|
|
167
|
+
break;
|
|
168
|
+
case "application/json":
|
|
169
|
+
if (postData.jsonObj) {
|
|
170
|
+
body = postData.jsonObj;
|
|
171
|
+
}
|
|
172
|
+
break;
|
|
173
|
+
case "multipart/form-data":
|
|
174
|
+
if (postData.params) {
|
|
175
|
+
body = {};
|
|
176
|
+
if ("content-type" in metadata && metadata["content-type"].indexOf("multipart/form-data") === 0) {
|
|
177
|
+
delete metadata["content-type"];
|
|
178
|
+
}
|
|
179
|
+
postData.params.forEach((param) => {
|
|
180
|
+
if (param.fileName) {
|
|
181
|
+
body[param.name] = param.fileName;
|
|
182
|
+
} else {
|
|
183
|
+
body[param.name] = param.value;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
if (postData.text) {
|
|
190
|
+
body = postData.text;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const args = [];
|
|
194
|
+
const accessor = operation.getOperationId({ camelCase: true });
|
|
195
|
+
const inlineCharacterLimit = typeof body !== "undefined" && Object.keys(metadata).length > 0 ? 40 : 80;
|
|
196
|
+
if (typeof body !== "undefined") {
|
|
197
|
+
args.push(stringify(body, { inlineCharacterLimit }));
|
|
198
|
+
}
|
|
199
|
+
if (Object.keys(metadata).length > 0) {
|
|
200
|
+
args.push(stringify(metadata, { inlineCharacterLimit }));
|
|
201
|
+
}
|
|
202
|
+
if (authData.length) {
|
|
203
|
+
push(authData.join("\n"));
|
|
204
|
+
}
|
|
205
|
+
if (configData.length) {
|
|
206
|
+
push(configData.join("\n"));
|
|
207
|
+
}
|
|
208
|
+
push(`sdk.${accessor}(${args.join(", ")})`);
|
|
209
|
+
push(".then(({ data }) => console.log(data))", 1);
|
|
210
|
+
push(".catch(err => console.error(err));", 1);
|
|
211
|
+
return join();
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
var src_default = client;
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
exports.default = src_default;
|
|
218
|
+
|
|
219
|
+
module.exports = exports.default//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReducedHelperObject } from '@readme/httpsnippet/helpers/reducer';\nimport type { Client } from '@readme/httpsnippet/targets';\nimport type Operation from 'oas/operation';\nimport type { HttpMethods, OASDocument } from 'oas/rmoas.types';\n\nimport { CodeBuilder } from '@readme/httpsnippet/helpers/code-builder';\nimport contentType from 'content-type';\nimport Oas from 'oas';\nimport { matchesMimeType } from 'oas/utils';\nimport stringifyObject from 'stringify-object';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction stringify(obj: any, opts = {}) {\n return stringifyObject(obj, { indent: ' ', ...opts });\n}\n\nfunction buildAuthSnippet(authKey: string | string[]) {\n // Auth key will be an array for Basic auth cases.\n if (Array.isArray(authKey)) {\n const auth: string[] = [];\n authKey.forEach((token, i) => {\n // If the token part is the last part of the key and it's empty, don't add it to the snippet.\n if (token.length === 0 && authKey.length > 1 && i === authKey.length - 1) {\n return;\n }\n\n auth.push(`'${token.replace(/'/g, \"\\\\'\")}'`);\n });\n\n return `sdk.auth(${auth.join(', ')});`;\n }\n\n return `sdk.auth('${authKey.replace(/'/g, \"\\\\'\")}');`;\n}\n\nfunction getAuthSources(operation: Operation) {\n const matchers: { cookie: string[]; header: Record<string, string>; query: string[] } = {\n header: {},\n query: [],\n cookie: [],\n };\n\n if (operation.getSecurity().length === 0) {\n return matchers;\n }\n\n Object.entries(operation.prepareSecurity()).forEach(([, schemes]) => {\n schemes.forEach(scheme => {\n if (scheme.type === 'http') {\n if (scheme.scheme === 'basic') {\n matchers.header.authorization = 'Basic';\n } else if (scheme.scheme === 'bearer') {\n matchers.header.authorization = 'Bearer';\n }\n } else if (scheme.type === 'oauth2') {\n matchers.header.authorization = 'Bearer';\n } else if (scheme.type === 'apiKey') {\n if (scheme.in === 'query') {\n matchers.query.push(scheme.name);\n } else if (scheme.in === 'header') {\n // The way that this asterisk header matcher works is that since this `apiKey` goes in a\n // named header (`scheme.name`) because the header is the key, we're matching against the\n // entire header -- counter to the way that the HTTP basic matcher above works where we\n // match and extract the API key from everything after `Basic ` in the `Authorization`\n // header.\n matchers.header[scheme.name.toLowerCase()] = '*';\n } else if (scheme.in === 'cookie') {\n matchers.cookie.push(scheme.name);\n }\n }\n });\n });\n\n return matchers;\n}\n\ninterface APIOptions {\n apiDefinition: OASDocument;\n apiDefinitionUri: string;\n escapeBrackets?: boolean;\n indent?: string | false;\n}\n\nconst client: Client<APIOptions> = {\n info: {\n key: 'api',\n title: 'API',\n link: 'https://npm.im/api',\n description: 'Automatic SDK generation from an OpenAPI definition.',\n extname: '.js',\n },\n convert: ({ cookiesObj, headersObj, postData, queryObj, url, ...source }, options) => {\n const opts = {\n ...options,\n } as APIOptions;\n\n if (!('apiDefinitionUri' in opts)) {\n throw new Error('This HTTP Snippet client must have an `apiDefinitionUri` option supplied to it.');\n } else if (!('apiDefinition' in opts)) {\n throw new Error('This HTTP Snippet client must have an `apiDefinition` option supplied to it.');\n }\n\n const method = source.method.toLowerCase() as HttpMethods;\n const oas = new Oas(opts.apiDefinition);\n const apiDefinition = oas.getDefinition();\n const foundOperation = oas.findOperation(url, method);\n if (!foundOperation) {\n throw new Error(\n `Unable to locate a matching operation in the supplied \\`apiDefinition\\` for: ${source.method} ${url}`,\n );\n }\n\n const operationSlugs = foundOperation.url.slugs;\n const operation = oas.operation(foundOperation.url.nonNormalizedPath, method);\n const operationPathParameters = operation.getParameters().filter(param => param.in === 'path');\n const path = operation.path;\n const authData: string[] = [];\n const authSources = getAuthSources(operation);\n\n const { blank, push, join } = new CodeBuilder({ indent: opts.indent || ' ' });\n\n push(`const sdk = require('api')('${opts.apiDefinitionUri}');`);\n blank();\n\n // If we have multiple servers configured and our source URL differs from the stock URL that we\n // receive from our `oas` library then the URL either has server variables contained in it (that\n // don't match the defaults), or the OAS offers alternate server URLs and we should expose that\n // in the generated snippet.\n const configData = [];\n if ((apiDefinition.servers || []).length > 1) {\n const stockUrl = oas.url();\n const baseUrl = url.replace(path, '');\n if (baseUrl !== stockUrl) {\n const serverVars = oas.splitVariables(baseUrl);\n const serverUrl = serverVars ? oas.url(serverVars.selected, serverVars.variables) : baseUrl;\n\n configData.push(`sdk.server('${serverUrl}');`);\n }\n }\n\n let metadata: Record<string, string | string[]> = {};\n Object.keys(queryObj).forEach(param => {\n if (authSources.query.includes(param)) {\n authData.push(buildAuthSnippet(queryObj[param]));\n\n // If this query param is part of an auth source then we don't want it doubled up in the\n // snippet.\n return;\n }\n\n metadata[param] = queryObj[param];\n });\n\n Object.keys(cookiesObj).forEach(cookie => {\n if (authSources.cookie.includes(cookie)) {\n authData.push(buildAuthSnippet(cookiesObj[cookie]));\n\n // If this cookie is part of an auth source then we don't want it doubled up.\n return;\n }\n\n // Note that we may have the potential to overlap any cookie that also shares the name as\n // another metadata parameter. This problem is currently inherent to `api` and not this\n // snippet generator.\n metadata[cookie] = cookiesObj[cookie];\n });\n\n // If we have path parameters present we should add them into the metadata object.\n Array.from(Object.entries(operationSlugs)).forEach(([param, value]) => {\n // The keys in `operationSlugs` will always be prefixed with a `:` in the `oas` library so\n // we can safely do this substring here without asserting this context.\n const cleanedParam = param.substring(1);\n\n // If our incoming path slug out of `oas.findOperation()` has been sanitized and is missing\n // a hyphen, but there is a parameter in the OpenAPI definition that matches what our\n // hyphen-less slug is then we should use that for the snippet.\n const unsanitizedParam = operationPathParameters.find(p => {\n return p.name.includes('-') && p.name.replace(/-/g, '') === cleanedParam ? p.name : false;\n });\n\n if (unsanitizedParam) {\n metadata[unsanitizedParam.name] = value;\n } else {\n metadata[cleanedParam] = value;\n }\n });\n\n if (Object.keys(headersObj).length) {\n const headers = headersObj;\n const requestHeaders: ReducedHelperObject = {};\n\n Object.keys(headers).forEach(header => {\n // Headers in HTTPSnippet are case-insensitive so we need to add in some special handling to\n // make sure we're able to match them properly.\n const headerLower = header.toLowerCase();\n\n if (headerLower in authSources.header) {\n // If this header has been set up as an authentication header, let's remove it and add it\n // into our auth data so we can build up an `.auth()` snippet for the SDK.\n const authScheme = authSources.header[headerLower];\n if (authScheme === '*') {\n authData.push(buildAuthSnippet(headers[header]));\n } else {\n // @ts-expect-error `headers[header]` is typed improperly in HTTPSnippet.\n let authKey = headers[header].replace(`${authSources.header[headerLower]} `, '');\n if (authScheme.toLowerCase() === 'basic') {\n authKey = Buffer.from(authKey, 'base64').toString('ascii');\n authKey = authKey.split(':');\n }\n\n authData.push(buildAuthSnippet(authKey));\n }\n\n delete headers[header];\n return;\n } else if (headerLower === 'content-type') {\n // `Content-Type` headers are automatically added within the SDK so we can filter them out\n // if they don't have parameters attached to them.\n // @ts-expect-error `headers[header]` is typed improperly in HTTPSnippet.\n const parsedContentType = contentType.parse(headers[header]);\n if (!Object.keys(parsedContentType.parameters).length) {\n delete headers[header];\n return;\n }\n } else if (headerLower === 'accept') {\n // If the `Accept` header here is JSON-like header then we can remove it from the code\n // snippet because `api` natively supports and prioritizes JSON over any other mime type.\n if (matchesMimeType.json(headers[header] as string)) {\n delete headers[header];\n return;\n }\n }\n\n // If we haven't used our header anywhere else, or we've deleted it from the payload\n // because it'll be handled internally by `api` then we should add the lowercased version\n // of our header into the generated code snippet.\n requestHeaders[headerLower] = headers[header];\n });\n\n if (Object.keys(requestHeaders).length > 0) {\n metadata = Object.assign(metadata, requestHeaders);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let body: any;\n switch (postData.mimeType) {\n case 'application/x-www-form-urlencoded':\n body = postData.paramsObj;\n break;\n\n case 'application/json':\n if (postData.jsonObj) {\n body = postData.jsonObj;\n }\n break;\n\n case 'multipart/form-data':\n if (postData.params) {\n body = {};\n\n // If there's a `Content-Type` header present in the metadata, but it's for the\n // `multipart/form-data` request then dump it off the snippet. We shouldn't offload that\n // unnecessary bloat of multipart boundaries to the user, instead letting the SDK handle it\n // automatically.\n if ('content-type' in metadata && metadata['content-type'].indexOf('multipart/form-data') === 0) {\n delete metadata['content-type'];\n }\n\n postData.params.forEach(param => {\n if (param.fileName) {\n body[param.name] = param.fileName;\n } else {\n body[param.name] = param.value;\n }\n });\n }\n break;\n\n default:\n if (postData.text) {\n body = postData.text;\n }\n }\n\n const args = [];\n\n const accessor = operation.getOperationId({ camelCase: true });\n\n // If we're going to be rendering out body params and metadata we should cut their character\n // limit in half because we'll be rendering them in their own lines.\n const inlineCharacterLimit = typeof body !== 'undefined' && Object.keys(metadata).length > 0 ? 40 : 80;\n if (typeof body !== 'undefined') {\n args.push(stringify(body, { inlineCharacterLimit }));\n }\n\n if (Object.keys(metadata).length > 0) {\n args.push(stringify(metadata, { inlineCharacterLimit }));\n }\n\n if (authData.length) {\n push(authData.join('\\n'));\n }\n\n if (configData.length) {\n push(configData.join('\\n'));\n }\n\n push(`sdk.${accessor}(${args.join(', ')})`);\n push('.then(({ data }) => console.log(data))', 1);\n push('.catch(err => console.error(err));', 1);\n\n return join();\n },\n};\n\nexport default client;\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Client } from '@readme/httpsnippet/targets';
|
|
2
|
+
import { OASDocument } from 'oas/rmoas.types';
|
|
3
|
+
|
|
4
|
+
interface APIOptions {
|
|
5
|
+
apiDefinition: OASDocument;
|
|
6
|
+
apiDefinitionUri: string;
|
|
7
|
+
escapeBrackets?: boolean;
|
|
8
|
+
indent?: string | false;
|
|
9
|
+
}
|
|
10
|
+
declare const client: Client<APIOptions>;
|
|
11
|
+
|
|
12
|
+
export = client;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import { Client } from '@readme/httpsnippet/targets';
|
|
2
|
+
import { OASDocument } from 'oas/rmoas.types';
|
|
3
|
+
|
|
4
|
+
interface APIOptions {
|
|
4
5
|
apiDefinition: OASDocument;
|
|
5
6
|
apiDefinitionUri: string;
|
|
6
7
|
escapeBrackets?: boolean;
|
|
7
8
|
indent?: string | false;
|
|
8
9
|
}
|
|
9
10
|
declare const client: Client<APIOptions>;
|
|
10
|
-
|
|
11
|
+
|
|
12
|
+
export { client as default };
|
package/dist/index.js
CHANGED
|
@@ -1,315 +1,218 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return t;
|
|
10
|
-
};
|
|
11
|
-
return __assign.apply(this, arguments);
|
|
12
|
-
};
|
|
13
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
-
if (k2 === undefined) k2 = k;
|
|
15
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
-
}
|
|
19
|
-
Object.defineProperty(o, k2, desc);
|
|
20
|
-
}) : (function(o, m, k, k2) {
|
|
21
|
-
if (k2 === undefined) k2 = k;
|
|
22
|
-
o[k2] = m[k];
|
|
23
|
-
}));
|
|
24
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
-
}) : function(o, v) {
|
|
27
|
-
o["default"] = v;
|
|
28
|
-
});
|
|
29
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
30
|
-
if (mod && mod.__esModule) return mod;
|
|
31
|
-
var result = {};
|
|
32
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
33
|
-
__setModuleDefault(result, mod);
|
|
34
|
-
return result;
|
|
35
|
-
};
|
|
36
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
37
|
-
var t = {};
|
|
38
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
39
|
-
t[p] = s[p];
|
|
40
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
41
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
42
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
43
|
-
t[p[i]] = s[p[i]];
|
|
44
|
-
}
|
|
45
|
-
return t;
|
|
46
|
-
};
|
|
47
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
48
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
49
|
-
};
|
|
50
|
-
exports.__esModule = true;
|
|
51
|
-
var code_builder_1 = require("@readme/httpsnippet/dist/helpers/code-builder");
|
|
52
|
-
var content_type_1 = __importDefault(require("content-type"));
|
|
53
|
-
var oas_1 = __importStar(require("oas"));
|
|
54
|
-
var stringify_object_1 = __importDefault(require("stringify-object"));
|
|
55
|
-
var matchesMimeType = oas_1.utils.matchesMimeType;
|
|
56
|
-
function stringify(obj, opts) {
|
|
57
|
-
if (opts === void 0) { opts = {}; }
|
|
58
|
-
return (0, stringify_object_1["default"])(obj, __assign({ indent: ' ' }, opts));
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { CodeBuilder } from "@readme/httpsnippet/helpers/code-builder";
|
|
3
|
+
import contentType from "content-type";
|
|
4
|
+
import Oas from "oas";
|
|
5
|
+
import { matchesMimeType } from "oas/utils";
|
|
6
|
+
import stringifyObject from "stringify-object";
|
|
7
|
+
function stringify(obj, opts = {}) {
|
|
8
|
+
return stringifyObject(obj, { indent: " ", ...opts });
|
|
59
9
|
}
|
|
60
10
|
function buildAuthSnippet(authKey) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
return "sdk.auth('".concat(authKey.replace(/'/g, "\\'"), "');");
|
|
11
|
+
if (Array.isArray(authKey)) {
|
|
12
|
+
const auth = [];
|
|
13
|
+
authKey.forEach((token, i) => {
|
|
14
|
+
if (token.length === 0 && authKey.length > 1 && i === authKey.length - 1) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
auth.push(`'${token.replace(/'/g, "\\'")}'`);
|
|
18
|
+
});
|
|
19
|
+
return `sdk.auth(${auth.join(", ")});`;
|
|
20
|
+
}
|
|
21
|
+
return `sdk.auth('${authKey.replace(/'/g, "\\'")}');`;
|
|
74
22
|
}
|
|
75
23
|
function getAuthSources(operation) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return matchers;
|
|
83
|
-
}
|
|
84
|
-
var security = operation.prepareSecurity();
|
|
85
|
-
Object.keys(security).forEach(function (id) {
|
|
86
|
-
security[id].forEach(function (scheme) {
|
|
87
|
-
if (scheme.type === 'http') {
|
|
88
|
-
if (scheme.scheme === 'basic') {
|
|
89
|
-
matchers.header.authorization = 'Basic';
|
|
90
|
-
}
|
|
91
|
-
else if (scheme.scheme === 'bearer') {
|
|
92
|
-
matchers.header.authorization = 'Bearer';
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else if (scheme.type === 'oauth2') {
|
|
96
|
-
matchers.header.authorization = 'Bearer';
|
|
97
|
-
}
|
|
98
|
-
else if (scheme.type === 'apiKey') {
|
|
99
|
-
if (scheme["in"] === 'query') {
|
|
100
|
-
matchers.query.push(scheme.name);
|
|
101
|
-
}
|
|
102
|
-
else if (scheme["in"] === 'header') {
|
|
103
|
-
// The way that this asterisk header matcher works is that since this `apiKey` goes in a
|
|
104
|
-
// named header (`scheme.name`) because the header is the key, we're matching against the
|
|
105
|
-
// entire header -- counter to the way that the HTTP basic matcher above works where we
|
|
106
|
-
// match and extract the API key from everything after `Basic ` in the `Authorization`
|
|
107
|
-
// header.
|
|
108
|
-
matchers.header[scheme.name.toLowerCase()] = '*';
|
|
109
|
-
}
|
|
110
|
-
else if (scheme["in"] === 'cookie') {
|
|
111
|
-
matchers.cookie.push(scheme.name);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
});
|
|
24
|
+
const matchers = {
|
|
25
|
+
header: {},
|
|
26
|
+
query: [],
|
|
27
|
+
cookie: []
|
|
28
|
+
};
|
|
29
|
+
if (operation.getSecurity().length === 0) {
|
|
116
30
|
return matchers;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
convert: function (_a, options) {
|
|
126
|
-
var cookiesObj = _a.cookiesObj, headersObj = _a.headersObj, postData = _a.postData, queryObj = _a.queryObj, url = _a.url, source = __rest(_a, ["cookiesObj", "headersObj", "postData", "queryObj", "url"]);
|
|
127
|
-
var opts = __assign({}, options);
|
|
128
|
-
if (!('apiDefinitionUri' in opts)) {
|
|
129
|
-
throw new Error('This HTTP Snippet client must have an `apiDefinitionUri` option supplied to it.');
|
|
130
|
-
}
|
|
131
|
-
else if (!('apiDefinition' in opts)) {
|
|
132
|
-
throw new Error('This HTTP Snippet client must have an `apiDefinition` option supplied to it.');
|
|
31
|
+
}
|
|
32
|
+
Object.entries(operation.prepareSecurity()).forEach(([, schemes]) => {
|
|
33
|
+
schemes.forEach((scheme) => {
|
|
34
|
+
if (scheme.type === "http") {
|
|
35
|
+
if (scheme.scheme === "basic") {
|
|
36
|
+
matchers.header.authorization = "Basic";
|
|
37
|
+
} else if (scheme.scheme === "bearer") {
|
|
38
|
+
matchers.header.authorization = "Bearer";
|
|
133
39
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
40
|
+
} else if (scheme.type === "oauth2") {
|
|
41
|
+
matchers.header.authorization = "Bearer";
|
|
42
|
+
} else if (scheme.type === "apiKey") {
|
|
43
|
+
if (scheme.in === "query") {
|
|
44
|
+
matchers.query.push(scheme.name);
|
|
45
|
+
} else if (scheme.in === "header") {
|
|
46
|
+
matchers.header[scheme.name.toLowerCase()] = "*";
|
|
47
|
+
} else if (scheme.in === "cookie") {
|
|
48
|
+
matchers.cookie.push(scheme.name);
|
|
140
49
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
// `Content-Type` headers are automatically added within the SDK so we can filter them out
|
|
232
|
-
// if they don't have parameters attached to them.
|
|
233
|
-
// @ts-expect-error `headers[header]` is typed improperly in HTTPSnippet.
|
|
234
|
-
var parsedContentType = content_type_1["default"].parse(headers_1[header]);
|
|
235
|
-
if (!Object.keys(parsedContentType.parameters).length) {
|
|
236
|
-
delete headers_1[header];
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
else if (headerLower === 'accept') {
|
|
241
|
-
// If the `Accept` header here is JSON-like header then we can remove it from the code
|
|
242
|
-
// snippet because `api` natively supports and prioritizes JSON over any other mime type.
|
|
243
|
-
if (matchesMimeType.json(headers_1[header])) {
|
|
244
|
-
delete headers_1[header];
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
// If we haven't used our header anywhere else, or we've deleted it from the payload
|
|
249
|
-
// because it'll be handled internally by `api` then we should add the lowercased version
|
|
250
|
-
// of our header into the generated code snippet.
|
|
251
|
-
requestHeaders_1[headerLower] = headers_1[header];
|
|
252
|
-
});
|
|
253
|
-
if (Object.keys(requestHeaders_1).length > 0) {
|
|
254
|
-
metadata = Object.assign(metadata, requestHeaders_1);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
return matchers;
|
|
54
|
+
}
|
|
55
|
+
var client = {
|
|
56
|
+
info: {
|
|
57
|
+
key: "api",
|
|
58
|
+
title: "API",
|
|
59
|
+
link: "https://npm.im/api",
|
|
60
|
+
description: "Automatic SDK generation from an OpenAPI definition.",
|
|
61
|
+
extname: ".js"
|
|
62
|
+
},
|
|
63
|
+
convert: ({ cookiesObj, headersObj, postData, queryObj, url, ...source }, options) => {
|
|
64
|
+
const opts = {
|
|
65
|
+
...options
|
|
66
|
+
};
|
|
67
|
+
if (!("apiDefinitionUri" in opts)) {
|
|
68
|
+
throw new Error("This HTTP Snippet client must have an `apiDefinitionUri` option supplied to it.");
|
|
69
|
+
} else if (!("apiDefinition" in opts)) {
|
|
70
|
+
throw new Error("This HTTP Snippet client must have an `apiDefinition` option supplied to it.");
|
|
71
|
+
}
|
|
72
|
+
const method = source.method.toLowerCase();
|
|
73
|
+
const oas = new Oas(opts.apiDefinition);
|
|
74
|
+
const apiDefinition = oas.getDefinition();
|
|
75
|
+
const foundOperation = oas.findOperation(url, method);
|
|
76
|
+
if (!foundOperation) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Unable to locate a matching operation in the supplied \`apiDefinition\` for: ${source.method} ${url}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
const operationSlugs = foundOperation.url.slugs;
|
|
82
|
+
const operation = oas.operation(foundOperation.url.nonNormalizedPath, method);
|
|
83
|
+
const operationPathParameters = operation.getParameters().filter((param) => param.in === "path");
|
|
84
|
+
const path = operation.path;
|
|
85
|
+
const authData = [];
|
|
86
|
+
const authSources = getAuthSources(operation);
|
|
87
|
+
const { blank, push, join } = new CodeBuilder({ indent: opts.indent || " " });
|
|
88
|
+
push(`const sdk = require('api')('${opts.apiDefinitionUri}');`);
|
|
89
|
+
blank();
|
|
90
|
+
const configData = [];
|
|
91
|
+
if ((apiDefinition.servers || []).length > 1) {
|
|
92
|
+
const stockUrl = oas.url();
|
|
93
|
+
const baseUrl = url.replace(path, "");
|
|
94
|
+
if (baseUrl !== stockUrl) {
|
|
95
|
+
const serverVars = oas.splitVariables(baseUrl);
|
|
96
|
+
const serverUrl = serverVars ? oas.url(serverVars.selected, serverVars.variables) : baseUrl;
|
|
97
|
+
configData.push(`sdk.server('${serverUrl}');`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
let metadata = {};
|
|
101
|
+
Object.keys(queryObj).forEach((param) => {
|
|
102
|
+
if (authSources.query.includes(param)) {
|
|
103
|
+
authData.push(buildAuthSnippet(queryObj[param]));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
metadata[param] = queryObj[param];
|
|
107
|
+
});
|
|
108
|
+
Object.keys(cookiesObj).forEach((cookie) => {
|
|
109
|
+
if (authSources.cookie.includes(cookie)) {
|
|
110
|
+
authData.push(buildAuthSnippet(cookiesObj[cookie]));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
metadata[cookie] = cookiesObj[cookie];
|
|
114
|
+
});
|
|
115
|
+
Array.from(Object.entries(operationSlugs)).forEach(([param, value]) => {
|
|
116
|
+
const cleanedParam = param.substring(1);
|
|
117
|
+
const unsanitizedParam = operationPathParameters.find((p) => {
|
|
118
|
+
return p.name.includes("-") && p.name.replace(/-/g, "") === cleanedParam ? p.name : false;
|
|
119
|
+
});
|
|
120
|
+
if (unsanitizedParam) {
|
|
121
|
+
metadata[unsanitizedParam.name] = value;
|
|
122
|
+
} else {
|
|
123
|
+
metadata[cleanedParam] = value;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
if (Object.keys(headersObj).length) {
|
|
127
|
+
const headers = headersObj;
|
|
128
|
+
const requestHeaders = {};
|
|
129
|
+
Object.keys(headers).forEach((header) => {
|
|
130
|
+
const headerLower = header.toLowerCase();
|
|
131
|
+
if (headerLower in authSources.header) {
|
|
132
|
+
const authScheme = authSources.header[headerLower];
|
|
133
|
+
if (authScheme === "*") {
|
|
134
|
+
authData.push(buildAuthSnippet(headers[header]));
|
|
135
|
+
} else {
|
|
136
|
+
let authKey = headers[header].replace(`${authSources.header[headerLower]} `, "");
|
|
137
|
+
if (authScheme.toLowerCase() === "basic") {
|
|
138
|
+
authKey = Buffer.from(authKey, "base64").toString("ascii");
|
|
139
|
+
authKey = authKey.split(":");
|
|
255
140
|
}
|
|
141
|
+
authData.push(buildAuthSnippet(authKey));
|
|
142
|
+
}
|
|
143
|
+
delete headers[header];
|
|
144
|
+
return;
|
|
145
|
+
} else if (headerLower === "content-type") {
|
|
146
|
+
const parsedContentType = contentType.parse(headers[header]);
|
|
147
|
+
if (!Object.keys(parsedContentType.parameters).length) {
|
|
148
|
+
delete headers[header];
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
} else if (headerLower === "accept") {
|
|
152
|
+
if (matchesMimeType.json(headers[header])) {
|
|
153
|
+
delete headers[header];
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
256
156
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
// `multipart/form-data` request then dump it off the snippet. We shouldn't offload that
|
|
272
|
-
// unnecessary bloat of multipart boundaries to the user, instead letting the SDK handle it
|
|
273
|
-
// automatically.
|
|
274
|
-
if ('content-type' in metadata && metadata['content-type'].indexOf('multipart/form-data') === 0) {
|
|
275
|
-
delete metadata['content-type'];
|
|
276
|
-
}
|
|
277
|
-
postData.params.forEach(function (param) {
|
|
278
|
-
if (param.fileName) {
|
|
279
|
-
body[param.name] = param.fileName;
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
body[param.name] = param.value;
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
break;
|
|
287
|
-
default:
|
|
288
|
-
if (postData.text) {
|
|
289
|
-
body = postData.text;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
var args = [];
|
|
293
|
-
var accessor = operation.getOperationId({ camelCase: true });
|
|
294
|
-
// If we're going to be rendering out body params and metadata we should cut their character
|
|
295
|
-
// limit in half because we'll be rendering them in their own lines.
|
|
296
|
-
var inlineCharacterLimit = typeof body !== 'undefined' && Object.keys(metadata).length > 0 ? 40 : 80;
|
|
297
|
-
if (typeof body !== 'undefined') {
|
|
298
|
-
args.push(stringify(body, { inlineCharacterLimit: inlineCharacterLimit }));
|
|
299
|
-
}
|
|
300
|
-
if (Object.keys(metadata).length > 0) {
|
|
301
|
-
args.push(stringify(metadata, { inlineCharacterLimit: inlineCharacterLimit }));
|
|
157
|
+
requestHeaders[headerLower] = headers[header];
|
|
158
|
+
});
|
|
159
|
+
if (Object.keys(requestHeaders).length > 0) {
|
|
160
|
+
metadata = Object.assign(metadata, requestHeaders);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
let body;
|
|
164
|
+
switch (postData.mimeType) {
|
|
165
|
+
case "application/x-www-form-urlencoded":
|
|
166
|
+
body = postData.paramsObj;
|
|
167
|
+
break;
|
|
168
|
+
case "application/json":
|
|
169
|
+
if (postData.jsonObj) {
|
|
170
|
+
body = postData.jsonObj;
|
|
302
171
|
}
|
|
303
|
-
|
|
304
|
-
|
|
172
|
+
break;
|
|
173
|
+
case "multipart/form-data":
|
|
174
|
+
if (postData.params) {
|
|
175
|
+
body = {};
|
|
176
|
+
if ("content-type" in metadata && metadata["content-type"].indexOf("multipart/form-data") === 0) {
|
|
177
|
+
delete metadata["content-type"];
|
|
178
|
+
}
|
|
179
|
+
postData.params.forEach((param) => {
|
|
180
|
+
if (param.fileName) {
|
|
181
|
+
body[param.name] = param.fileName;
|
|
182
|
+
} else {
|
|
183
|
+
body[param.name] = param.value;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
305
186
|
}
|
|
306
|
-
|
|
307
|
-
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
if (postData.text) {
|
|
190
|
+
body = postData.text;
|
|
308
191
|
}
|
|
309
|
-
push("sdk.".concat(accessor, "(").concat(args.join(', '), ")"));
|
|
310
|
-
push('.then(({ data }) => console.log(data))', 1);
|
|
311
|
-
push('.catch(err => console.error(err));', 1);
|
|
312
|
-
return join();
|
|
313
192
|
}
|
|
193
|
+
const args = [];
|
|
194
|
+
const accessor = operation.getOperationId({ camelCase: true });
|
|
195
|
+
const inlineCharacterLimit = typeof body !== "undefined" && Object.keys(metadata).length > 0 ? 40 : 80;
|
|
196
|
+
if (typeof body !== "undefined") {
|
|
197
|
+
args.push(stringify(body, { inlineCharacterLimit }));
|
|
198
|
+
}
|
|
199
|
+
if (Object.keys(metadata).length > 0) {
|
|
200
|
+
args.push(stringify(metadata, { inlineCharacterLimit }));
|
|
201
|
+
}
|
|
202
|
+
if (authData.length) {
|
|
203
|
+
push(authData.join("\n"));
|
|
204
|
+
}
|
|
205
|
+
if (configData.length) {
|
|
206
|
+
push(configData.join("\n"));
|
|
207
|
+
}
|
|
208
|
+
push(`sdk.${accessor}(${args.join(", ")})`);
|
|
209
|
+
push(".then(({ data }) => console.log(data))", 1);
|
|
210
|
+
push(".catch(err => console.error(err));", 1);
|
|
211
|
+
return join();
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
var src_default = client;
|
|
215
|
+
export {
|
|
216
|
+
src_default as default
|
|
314
217
|
};
|
|
315
|
-
|
|
218
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { ReducedHelperObject } from '@readme/httpsnippet/helpers/reducer';\nimport type { Client } from '@readme/httpsnippet/targets';\nimport type Operation from 'oas/operation';\nimport type { HttpMethods, OASDocument } from 'oas/rmoas.types';\n\nimport { CodeBuilder } from '@readme/httpsnippet/helpers/code-builder';\nimport contentType from 'content-type';\nimport Oas from 'oas';\nimport { matchesMimeType } from 'oas/utils';\nimport stringifyObject from 'stringify-object';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction stringify(obj: any, opts = {}) {\n return stringifyObject(obj, { indent: ' ', ...opts });\n}\n\nfunction buildAuthSnippet(authKey: string | string[]) {\n // Auth key will be an array for Basic auth cases.\n if (Array.isArray(authKey)) {\n const auth: string[] = [];\n authKey.forEach((token, i) => {\n // If the token part is the last part of the key and it's empty, don't add it to the snippet.\n if (token.length === 0 && authKey.length > 1 && i === authKey.length - 1) {\n return;\n }\n\n auth.push(`'${token.replace(/'/g, \"\\\\'\")}'`);\n });\n\n return `sdk.auth(${auth.join(', ')});`;\n }\n\n return `sdk.auth('${authKey.replace(/'/g, \"\\\\'\")}');`;\n}\n\nfunction getAuthSources(operation: Operation) {\n const matchers: { cookie: string[]; header: Record<string, string>; query: string[] } = {\n header: {},\n query: [],\n cookie: [],\n };\n\n if (operation.getSecurity().length === 0) {\n return matchers;\n }\n\n Object.entries(operation.prepareSecurity()).forEach(([, schemes]) => {\n schemes.forEach(scheme => {\n if (scheme.type === 'http') {\n if (scheme.scheme === 'basic') {\n matchers.header.authorization = 'Basic';\n } else if (scheme.scheme === 'bearer') {\n matchers.header.authorization = 'Bearer';\n }\n } else if (scheme.type === 'oauth2') {\n matchers.header.authorization = 'Bearer';\n } else if (scheme.type === 'apiKey') {\n if (scheme.in === 'query') {\n matchers.query.push(scheme.name);\n } else if (scheme.in === 'header') {\n // The way that this asterisk header matcher works is that since this `apiKey` goes in a\n // named header (`scheme.name`) because the header is the key, we're matching against the\n // entire header -- counter to the way that the HTTP basic matcher above works where we\n // match and extract the API key from everything after `Basic ` in the `Authorization`\n // header.\n matchers.header[scheme.name.toLowerCase()] = '*';\n } else if (scheme.in === 'cookie') {\n matchers.cookie.push(scheme.name);\n }\n }\n });\n });\n\n return matchers;\n}\n\ninterface APIOptions {\n apiDefinition: OASDocument;\n apiDefinitionUri: string;\n escapeBrackets?: boolean;\n indent?: string | false;\n}\n\nconst client: Client<APIOptions> = {\n info: {\n key: 'api',\n title: 'API',\n link: 'https://npm.im/api',\n description: 'Automatic SDK generation from an OpenAPI definition.',\n extname: '.js',\n },\n convert: ({ cookiesObj, headersObj, postData, queryObj, url, ...source }, options) => {\n const opts = {\n ...options,\n } as APIOptions;\n\n if (!('apiDefinitionUri' in opts)) {\n throw new Error('This HTTP Snippet client must have an `apiDefinitionUri` option supplied to it.');\n } else if (!('apiDefinition' in opts)) {\n throw new Error('This HTTP Snippet client must have an `apiDefinition` option supplied to it.');\n }\n\n const method = source.method.toLowerCase() as HttpMethods;\n const oas = new Oas(opts.apiDefinition);\n const apiDefinition = oas.getDefinition();\n const foundOperation = oas.findOperation(url, method);\n if (!foundOperation) {\n throw new Error(\n `Unable to locate a matching operation in the supplied \\`apiDefinition\\` for: ${source.method} ${url}`,\n );\n }\n\n const operationSlugs = foundOperation.url.slugs;\n const operation = oas.operation(foundOperation.url.nonNormalizedPath, method);\n const operationPathParameters = operation.getParameters().filter(param => param.in === 'path');\n const path = operation.path;\n const authData: string[] = [];\n const authSources = getAuthSources(operation);\n\n const { blank, push, join } = new CodeBuilder({ indent: opts.indent || ' ' });\n\n push(`const sdk = require('api')('${opts.apiDefinitionUri}');`);\n blank();\n\n // If we have multiple servers configured and our source URL differs from the stock URL that we\n // receive from our `oas` library then the URL either has server variables contained in it (that\n // don't match the defaults), or the OAS offers alternate server URLs and we should expose that\n // in the generated snippet.\n const configData = [];\n if ((apiDefinition.servers || []).length > 1) {\n const stockUrl = oas.url();\n const baseUrl = url.replace(path, '');\n if (baseUrl !== stockUrl) {\n const serverVars = oas.splitVariables(baseUrl);\n const serverUrl = serverVars ? oas.url(serverVars.selected, serverVars.variables) : baseUrl;\n\n configData.push(`sdk.server('${serverUrl}');`);\n }\n }\n\n let metadata: Record<string, string | string[]> = {};\n Object.keys(queryObj).forEach(param => {\n if (authSources.query.includes(param)) {\n authData.push(buildAuthSnippet(queryObj[param]));\n\n // If this query param is part of an auth source then we don't want it doubled up in the\n // snippet.\n return;\n }\n\n metadata[param] = queryObj[param];\n });\n\n Object.keys(cookiesObj).forEach(cookie => {\n if (authSources.cookie.includes(cookie)) {\n authData.push(buildAuthSnippet(cookiesObj[cookie]));\n\n // If this cookie is part of an auth source then we don't want it doubled up.\n return;\n }\n\n // Note that we may have the potential to overlap any cookie that also shares the name as\n // another metadata parameter. This problem is currently inherent to `api` and not this\n // snippet generator.\n metadata[cookie] = cookiesObj[cookie];\n });\n\n // If we have path parameters present we should add them into the metadata object.\n Array.from(Object.entries(operationSlugs)).forEach(([param, value]) => {\n // The keys in `operationSlugs` will always be prefixed with a `:` in the `oas` library so\n // we can safely do this substring here without asserting this context.\n const cleanedParam = param.substring(1);\n\n // If our incoming path slug out of `oas.findOperation()` has been sanitized and is missing\n // a hyphen, but there is a parameter in the OpenAPI definition that matches what our\n // hyphen-less slug is then we should use that for the snippet.\n const unsanitizedParam = operationPathParameters.find(p => {\n return p.name.includes('-') && p.name.replace(/-/g, '') === cleanedParam ? p.name : false;\n });\n\n if (unsanitizedParam) {\n metadata[unsanitizedParam.name] = value;\n } else {\n metadata[cleanedParam] = value;\n }\n });\n\n if (Object.keys(headersObj).length) {\n const headers = headersObj;\n const requestHeaders: ReducedHelperObject = {};\n\n Object.keys(headers).forEach(header => {\n // Headers in HTTPSnippet are case-insensitive so we need to add in some special handling to\n // make sure we're able to match them properly.\n const headerLower = header.toLowerCase();\n\n if (headerLower in authSources.header) {\n // If this header has been set up as an authentication header, let's remove it and add it\n // into our auth data so we can build up an `.auth()` snippet for the SDK.\n const authScheme = authSources.header[headerLower];\n if (authScheme === '*') {\n authData.push(buildAuthSnippet(headers[header]));\n } else {\n // @ts-expect-error `headers[header]` is typed improperly in HTTPSnippet.\n let authKey = headers[header].replace(`${authSources.header[headerLower]} `, '');\n if (authScheme.toLowerCase() === 'basic') {\n authKey = Buffer.from(authKey, 'base64').toString('ascii');\n authKey = authKey.split(':');\n }\n\n authData.push(buildAuthSnippet(authKey));\n }\n\n delete headers[header];\n return;\n } else if (headerLower === 'content-type') {\n // `Content-Type` headers are automatically added within the SDK so we can filter them out\n // if they don't have parameters attached to them.\n // @ts-expect-error `headers[header]` is typed improperly in HTTPSnippet.\n const parsedContentType = contentType.parse(headers[header]);\n if (!Object.keys(parsedContentType.parameters).length) {\n delete headers[header];\n return;\n }\n } else if (headerLower === 'accept') {\n // If the `Accept` header here is JSON-like header then we can remove it from the code\n // snippet because `api` natively supports and prioritizes JSON over any other mime type.\n if (matchesMimeType.json(headers[header] as string)) {\n delete headers[header];\n return;\n }\n }\n\n // If we haven't used our header anywhere else, or we've deleted it from the payload\n // because it'll be handled internally by `api` then we should add the lowercased version\n // of our header into the generated code snippet.\n requestHeaders[headerLower] = headers[header];\n });\n\n if (Object.keys(requestHeaders).length > 0) {\n metadata = Object.assign(metadata, requestHeaders);\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let body: any;\n switch (postData.mimeType) {\n case 'application/x-www-form-urlencoded':\n body = postData.paramsObj;\n break;\n\n case 'application/json':\n if (postData.jsonObj) {\n body = postData.jsonObj;\n }\n break;\n\n case 'multipart/form-data':\n if (postData.params) {\n body = {};\n\n // If there's a `Content-Type` header present in the metadata, but it's for the\n // `multipart/form-data` request then dump it off the snippet. We shouldn't offload that\n // unnecessary bloat of multipart boundaries to the user, instead letting the SDK handle it\n // automatically.\n if ('content-type' in metadata && metadata['content-type'].indexOf('multipart/form-data') === 0) {\n delete metadata['content-type'];\n }\n\n postData.params.forEach(param => {\n if (param.fileName) {\n body[param.name] = param.fileName;\n } else {\n body[param.name] = param.value;\n }\n });\n }\n break;\n\n default:\n if (postData.text) {\n body = postData.text;\n }\n }\n\n const args = [];\n\n const accessor = operation.getOperationId({ camelCase: true });\n\n // If we're going to be rendering out body params and metadata we should cut their character\n // limit in half because we'll be rendering them in their own lines.\n const inlineCharacterLimit = typeof body !== 'undefined' && Object.keys(metadata).length > 0 ? 40 : 80;\n if (typeof body !== 'undefined') {\n args.push(stringify(body, { inlineCharacterLimit }));\n }\n\n if (Object.keys(metadata).length > 0) {\n args.push(stringify(metadata, { inlineCharacterLimit }));\n }\n\n if (authData.length) {\n push(authData.join('\\n'));\n }\n\n if (configData.length) {\n push(configData.join('\\n'));\n }\n\n push(`sdk.${accessor}(${args.join(', ')})`);\n push('.then(({ data }) => console.log(data))', 1);\n push('.catch(err => console.error(err));', 1);\n\n return join();\n },\n};\n\nexport default client;\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "httpsnippet-client-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0-alpha.5",
|
|
4
4
|
"description": "An HTTPSnippet client for generating snippets for the `api` module.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./dist/index.cjs",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"main": "dist/index.cjs",
|
|
15
|
+
"module": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.cts",
|
|
7
17
|
"scripts": {
|
|
8
|
-
"
|
|
18
|
+
"attw": "attw --pack --format table-flipped",
|
|
19
|
+
"build": "tsup",
|
|
9
20
|
"lint:types": "tsc --noEmit",
|
|
10
21
|
"prebuild": "rm -rf dist/",
|
|
11
22
|
"prepack": "npm run build",
|
|
12
|
-
"test": "vitest --coverage"
|
|
23
|
+
"test": "vitest run --coverage"
|
|
13
24
|
},
|
|
14
25
|
"repository": {
|
|
15
26
|
"type": "git",
|
|
@@ -22,28 +33,25 @@
|
|
|
22
33
|
"author": "Jon Ursenbach <jon@readme.io>",
|
|
23
34
|
"license": "MIT",
|
|
24
35
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
36
|
+
"node": ">=18"
|
|
26
37
|
},
|
|
27
38
|
"dependencies": {
|
|
28
39
|
"content-type": "^1.0.5",
|
|
29
40
|
"stringify-object": "^3.3.0"
|
|
30
41
|
},
|
|
31
42
|
"peerDependencies": {
|
|
32
|
-
"@readme/httpsnippet": ">=
|
|
33
|
-
"oas": "^
|
|
43
|
+
"@readme/httpsnippet": ">=8",
|
|
44
|
+
"oas": "^23.0.0"
|
|
34
45
|
},
|
|
35
46
|
"devDependencies": {
|
|
36
|
-
"@readme/oas-examples": "^5.
|
|
37
|
-
"@readme/openapi-parser": "^2.
|
|
38
|
-
"@types/content-type": "^1.1.
|
|
39
|
-
"@types/stringify-object": "^
|
|
40
|
-
"@vitest/coverage-v8": "^0.34.
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"isomorphic-fetch": "^3.0.0",
|
|
44
|
-
"typescript": "^4.9.5",
|
|
45
|
-
"vitest": "^0.34.1"
|
|
47
|
+
"@readme/oas-examples": "^5.12.0",
|
|
48
|
+
"@readme/openapi-parser": "^2.5.0",
|
|
49
|
+
"@types/content-type": "^1.1.6",
|
|
50
|
+
"@types/stringify-object": "^3.3.1",
|
|
51
|
+
"@vitest/coverage-v8": "^0.34.4",
|
|
52
|
+
"typescript": "^5.2.2",
|
|
53
|
+
"vitest": "^0.34.5"
|
|
46
54
|
},
|
|
47
55
|
"prettier": "@readme/eslint-config/prettier",
|
|
48
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "b1e705dddedd223f360f1dfe620ae721f54af88b"
|
|
49
57
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
import type { ReducedHelperObject } from '@readme/httpsnippet/
|
|
2
|
-
import type { Client } from '@readme/httpsnippet/
|
|
3
|
-
import type
|
|
4
|
-
import type { HttpMethods, OASDocument } from 'oas/
|
|
1
|
+
import type { ReducedHelperObject } from '@readme/httpsnippet/helpers/reducer';
|
|
2
|
+
import type { Client } from '@readme/httpsnippet/targets';
|
|
3
|
+
import type Operation from 'oas/operation';
|
|
4
|
+
import type { HttpMethods, OASDocument } from 'oas/rmoas.types';
|
|
5
5
|
|
|
6
|
-
import { CodeBuilder } from '@readme/httpsnippet/
|
|
6
|
+
import { CodeBuilder } from '@readme/httpsnippet/helpers/code-builder';
|
|
7
7
|
import contentType from 'content-type';
|
|
8
|
-
import Oas
|
|
8
|
+
import Oas from 'oas';
|
|
9
|
+
import { matchesMimeType } from 'oas/utils';
|
|
9
10
|
import stringifyObject from 'stringify-object';
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// This should really be an exported type in `oas`.
|
|
14
|
-
type SecurityType = 'Basic' | 'Bearer' | 'Query' | 'Header' | 'Cookie' | 'OAuth2' | 'http' | 'apiKey';
|
|
15
|
-
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
13
|
function stringify(obj: any, opts = {}) {
|
|
17
14
|
return stringifyObject(obj, { indent: ' ', ...opts });
|
|
18
15
|
}
|
|
@@ -47,9 +44,8 @@ function getAuthSources(operation: Operation) {
|
|
|
47
44
|
return matchers;
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
security[id].forEach(scheme => {
|
|
47
|
+
Object.entries(operation.prepareSecurity()).forEach(([, schemes]) => {
|
|
48
|
+
schemes.forEach(scheme => {
|
|
53
49
|
if (scheme.type === 'http') {
|
|
54
50
|
if (scheme.scheme === 'basic') {
|
|
55
51
|
matchers.header.authorization = 'Basic';
|
|
@@ -78,7 +74,7 @@ function getAuthSources(operation: Operation) {
|
|
|
78
74
|
return matchers;
|
|
79
75
|
}
|
|
80
76
|
|
|
81
|
-
|
|
77
|
+
interface APIOptions {
|
|
82
78
|
apiDefinition: OASDocument;
|
|
83
79
|
apiDefinitionUri: string;
|
|
84
80
|
escapeBrackets?: boolean;
|
|
@@ -91,11 +87,12 @@ const client: Client<APIOptions> = {
|
|
|
91
87
|
title: 'API',
|
|
92
88
|
link: 'https://npm.im/api',
|
|
93
89
|
description: 'Automatic SDK generation from an OpenAPI definition.',
|
|
90
|
+
extname: '.js',
|
|
94
91
|
},
|
|
95
92
|
convert: ({ cookiesObj, headersObj, postData, queryObj, url, ...source }, options) => {
|
|
96
93
|
const opts = {
|
|
97
94
|
...options,
|
|
98
|
-
};
|
|
95
|
+
} as APIOptions;
|
|
99
96
|
|
|
100
97
|
if (!('apiDefinitionUri' in opts)) {
|
|
101
98
|
throw new Error('This HTTP Snippet client must have an `apiDefinitionUri` option supplied to it.');
|
|
@@ -245,6 +242,7 @@ const client: Client<APIOptions> = {
|
|
|
245
242
|
}
|
|
246
243
|
}
|
|
247
244
|
|
|
245
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
248
246
|
let body: any;
|
|
249
247
|
switch (postData.mimeType) {
|
|
250
248
|
case 'application/x-www-form-urlencoded':
|
package/tsconfig.json
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
2
3
|
"compilerOptions": {
|
|
3
|
-
"
|
|
4
|
-
"baseUrl": "./src",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"esModuleInterop": true,
|
|
7
|
-
"lib": ["dom", "es2020"],
|
|
8
|
-
"noImplicitAny": true,
|
|
4
|
+
"lib": ["DOM", "ES2023"],
|
|
9
5
|
"outDir": "dist/"
|
|
10
6
|
},
|
|
11
7
|
"include": ["./src/**/*"]
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Options } from 'tsup';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
4
|
+
import { defineConfig } from 'tsup';
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line import/no-relative-packages
|
|
7
|
+
import config from '../../tsup.config.js';
|
|
8
|
+
|
|
9
|
+
export default defineConfig((options: Options) => ({
|
|
10
|
+
...options,
|
|
11
|
+
...config,
|
|
12
|
+
|
|
13
|
+
entry: ['src/index.ts'],
|
|
14
|
+
silent: !options.watch,
|
|
15
|
+
}));
|