httpsnippet-client-api 7.0.0-beta.0 → 7.0.0-beta.12
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 +35 -9
- package/dist/index.cjs +234 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -18
- package/dist/index.d.ts +20 -18
- package/dist/index.js +230 -23
- package/dist/index.js.map +1 -1
- package/package.json +12 -10
- package/src/index.ts +63 -43
- package/tsup.config.ts +10 -0
package/src/index.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
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/
|
|
2
|
+
import type { Client, ClientPlugin } from '@readme/httpsnippet/targets';
|
|
3
|
+
import type { Operation } from 'oas/operation';
|
|
4
|
+
import type { HttpMethods, OASDocument } from 'oas/types';
|
|
5
5
|
|
|
6
6
|
import { CodeBuilder } from '@readme/httpsnippet/helpers/code-builder';
|
|
7
|
+
import camelCase from 'camelcase'; // eslint-disable-line import/no-extraneous-dependencies
|
|
7
8
|
import contentType from 'content-type';
|
|
8
9
|
import Oas from 'oas';
|
|
9
10
|
import { matchesMimeType } from 'oas/utils';
|
|
10
|
-
import
|
|
11
|
+
import { isReservedOrBuiltinsLC } from 'reserved2';
|
|
12
|
+
import stringifyObject from 'stringify-object'; // eslint-disable-line import/no-extraneous-dependencies
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* @note This regex also exists in `api/fetcher`.
|
|
@@ -34,7 +36,7 @@ function stringify(obj: any, opts = {}) {
|
|
|
34
36
|
return stringifyObject(obj, { indent: ' ', ...opts });
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
function buildAuthSnippet(authKey: string | string
|
|
39
|
+
function buildAuthSnippet(sdkVariable: string, authKey: string[] | string) {
|
|
38
40
|
// Auth key will be an array for Basic auth cases.
|
|
39
41
|
if (Array.isArray(authKey)) {
|
|
40
42
|
const auth: string[] = [];
|
|
@@ -47,10 +49,10 @@ function buildAuthSnippet(authKey: string | string[]) {
|
|
|
47
49
|
auth.push(`'${token.replace(/'/g, "\\'")}'`);
|
|
48
50
|
});
|
|
49
51
|
|
|
50
|
-
return
|
|
52
|
+
return `${sdkVariable}.auth(${auth.join(', ')});`;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
return
|
|
55
|
+
return `${sdkVariable}.auth('${authKey.replace(/'/g, "\\'")}');`;
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
function getAuthSources(operation: Operation) {
|
|
@@ -95,21 +97,25 @@ function getAuthSources(operation: Operation) {
|
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
interface APIOptions {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
api?: {
|
|
101
|
+
definition: OASDocument;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The string to identify this SDK as. This is used in the `import sdk from '<identifier>'`
|
|
105
|
+
* sample as well as the the variable name we attach the SDK to.
|
|
106
|
+
*
|
|
107
|
+
* @example `@api/developers`
|
|
108
|
+
*/
|
|
109
|
+
identifier?: string;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The URI that is used to download this API definition from `npx api install`.
|
|
113
|
+
*
|
|
114
|
+
* @example `@developers/v2.0#17273l2glm9fq4l5`
|
|
115
|
+
*/
|
|
116
|
+
registryURI: string;
|
|
117
|
+
};
|
|
105
118
|
escapeBrackets?: boolean;
|
|
106
|
-
/**
|
|
107
|
-
* The string to identify this SDK as. This is used in the `import sdk from '@api/<identifier>'`
|
|
108
|
-
* sample as well as the the variable name we attach the SDK to.
|
|
109
|
-
*
|
|
110
|
-
* @example developers
|
|
111
|
-
*/
|
|
112
|
-
identifier?: string;
|
|
113
119
|
indent?: string | false;
|
|
114
120
|
}
|
|
115
121
|
|
|
@@ -120,36 +126,45 @@ const client: Client<APIOptions> = {
|
|
|
120
126
|
link: 'https://npm.im/api',
|
|
121
127
|
description: 'Automatic SDK generation from an OpenAPI definition.',
|
|
122
128
|
extname: '.js',
|
|
129
|
+
installation: 'npx api install "{packageName}"',
|
|
123
130
|
},
|
|
124
131
|
convert: ({ cookiesObj, headersObj, postData, queryObj, url, ...source }, options) => {
|
|
125
132
|
const opts = {
|
|
126
133
|
...options,
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (!
|
|
130
|
-
throw new Error('This
|
|
131
|
-
} else if (!
|
|
132
|
-
throw new Error('This
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (!opts?.api) {
|
|
137
|
+
throw new Error('This HTTPSnippet client must have an `api` config supplied to it.');
|
|
138
|
+
} else if (!opts?.api?.definition) {
|
|
139
|
+
throw new Error('This HTTPSnippet client must have an `api.definition` option supplied to it.');
|
|
140
|
+
} else if (!opts?.api?.registryURI) {
|
|
141
|
+
throw new Error('This HTTPSnippet client must have an `api.registryURI` option supplied to it.');
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
const method = source.method.toLowerCase() as HttpMethods;
|
|
136
|
-
const oas = new Oas(opts.
|
|
145
|
+
const oas = new Oas(opts.api.definition);
|
|
137
146
|
const apiDefinition = oas.getDefinition();
|
|
138
147
|
const foundOperation = oas.findOperation(url, method);
|
|
139
148
|
if (!foundOperation) {
|
|
140
149
|
throw new Error(
|
|
141
|
-
`Unable to locate a matching operation in the supplied \`
|
|
150
|
+
`Unable to locate a matching operation in the supplied \`api.definition\` for: ${source.method} ${url}`,
|
|
142
151
|
);
|
|
143
152
|
}
|
|
144
153
|
|
|
145
|
-
let sdkPackageName;
|
|
146
|
-
let sdkVariable;
|
|
147
|
-
if (opts.identifier) {
|
|
148
|
-
sdkPackageName = opts.identifier;
|
|
149
|
-
|
|
154
|
+
let sdkPackageName: string | undefined;
|
|
155
|
+
let sdkVariable: string;
|
|
156
|
+
if (opts.api.identifier) {
|
|
157
|
+
sdkPackageName = opts.api.identifier;
|
|
158
|
+
|
|
159
|
+
sdkVariable = camelCase(opts.api.identifier);
|
|
160
|
+
if (isReservedOrBuiltinsLC(sdkVariable)) {
|
|
161
|
+
// If this identifier is a reserved JS word then we should prefix it with an underscore so
|
|
162
|
+
// this snippet can be valid code.
|
|
163
|
+
sdkVariable = `_${sdkVariable}`;
|
|
164
|
+
}
|
|
150
165
|
} else {
|
|
151
|
-
sdkPackageName = getProjectPrefixFromRegistryUUID(opts.
|
|
152
|
-
sdkVariable = 'sdk';
|
|
166
|
+
sdkPackageName = getProjectPrefixFromRegistryUUID(opts.api.registryURI);
|
|
167
|
+
sdkVariable = camelCase(sdkPackageName || 'sdk');
|
|
153
168
|
}
|
|
154
169
|
|
|
155
170
|
const operationSlugs = foundOperation.url.slugs;
|
|
@@ -176,14 +191,14 @@ const client: Client<APIOptions> = {
|
|
|
176
191
|
const serverVars = oas.splitVariables(baseUrl);
|
|
177
192
|
const serverUrl = serverVars ? oas.url(serverVars.selected, serverVars.variables) : baseUrl;
|
|
178
193
|
|
|
179
|
-
configData.push(
|
|
194
|
+
configData.push(`${sdkVariable}.server('${serverUrl}');`);
|
|
180
195
|
}
|
|
181
196
|
}
|
|
182
197
|
|
|
183
|
-
let metadata: Record<string, string | string
|
|
198
|
+
let metadata: Record<string, string[] | string> = {};
|
|
184
199
|
Object.keys(queryObj).forEach(param => {
|
|
185
200
|
if (authSources.query.includes(param)) {
|
|
186
|
-
authData.push(buildAuthSnippet(queryObj[param]));
|
|
201
|
+
authData.push(buildAuthSnippet(sdkVariable, queryObj[param]));
|
|
187
202
|
|
|
188
203
|
// If this query param is part of an auth source then we don't want it doubled up in the
|
|
189
204
|
// snippet.
|
|
@@ -195,7 +210,7 @@ const client: Client<APIOptions> = {
|
|
|
195
210
|
|
|
196
211
|
Object.keys(cookiesObj).forEach(cookie => {
|
|
197
212
|
if (authSources.cookie.includes(cookie)) {
|
|
198
|
-
authData.push(buildAuthSnippet(cookiesObj[cookie]));
|
|
213
|
+
authData.push(buildAuthSnippet(sdkVariable, cookiesObj[cookie]));
|
|
199
214
|
|
|
200
215
|
// If this cookie is part of an auth source then we don't want it doubled up.
|
|
201
216
|
return;
|
|
@@ -241,7 +256,7 @@ const client: Client<APIOptions> = {
|
|
|
241
256
|
// into our auth data so we can build up an `.auth()` snippet for the SDK.
|
|
242
257
|
const authScheme = authSources.header[headerLower];
|
|
243
258
|
if (authScheme === '*') {
|
|
244
|
-
authData.push(buildAuthSnippet(headers[header]));
|
|
259
|
+
authData.push(buildAuthSnippet(sdkVariable, headers[header]));
|
|
245
260
|
} else {
|
|
246
261
|
// @ts-expect-error `headers[header]` is typed improperly in HTTPSnippet.
|
|
247
262
|
let authKey = headers[header].replace(`${authSources.header[headerLower]} `, '');
|
|
@@ -250,7 +265,7 @@ const client: Client<APIOptions> = {
|
|
|
250
265
|
authKey = authKey.split(':');
|
|
251
266
|
}
|
|
252
267
|
|
|
253
|
-
authData.push(buildAuthSnippet(authKey));
|
|
268
|
+
authData.push(buildAuthSnippet(sdkVariable, authKey));
|
|
254
269
|
}
|
|
255
270
|
|
|
256
271
|
delete headers[header];
|
|
@@ -361,4 +376,9 @@ const client: Client<APIOptions> = {
|
|
|
361
376
|
},
|
|
362
377
|
};
|
|
363
378
|
|
|
364
|
-
|
|
379
|
+
const plugin: ClientPlugin<APIOptions> = {
|
|
380
|
+
target: 'node',
|
|
381
|
+
client,
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
export default plugin;
|
package/tsup.config.ts
CHANGED
|
@@ -11,5 +11,15 @@ export default defineConfig((options: Options) => ({
|
|
|
11
11
|
...config,
|
|
12
12
|
|
|
13
13
|
entry: ['src/index.ts'],
|
|
14
|
+
|
|
15
|
+
noExternal: [
|
|
16
|
+
// These dependencies are ESM-only but because we're building for ESM **and** CJS we can't
|
|
17
|
+
// treat them as external dependencies as CJS libraries can't load ESM code that uses `export`.
|
|
18
|
+
// `noExternal` will instead treeshake these dependencies down and include them in our compiled
|
|
19
|
+
// dists.
|
|
20
|
+
'camelcase',
|
|
21
|
+
'stringify-object',
|
|
22
|
+
],
|
|
23
|
+
|
|
14
24
|
silent: !options.watch,
|
|
15
25
|
}));
|