@mapples/api-import 1.5.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 +18 -0
- package/dist/bodyCredentials.d.ts +19 -0
- package/dist/bodyCredentials.d.ts.map +1 -0
- package/dist/bodyCredentials.js +77 -0
- package/dist/bodyCredentials.js.map +1 -0
- package/dist/curl.d.ts +19 -0
- package/dist/curl.d.ts.map +1 -0
- package/dist/curl.js +313 -0
- package/dist/curl.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/merge.d.ts +33 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +68 -0
- package/dist/merge.js.map +1 -0
- package/dist/names.d.ts +7 -0
- package/dist/names.d.ts.map +1 -0
- package/dist/names.js +24 -0
- package/dist/names.js.map +1 -0
- package/dist/openapi.d.ts +25 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +299 -0
- package/dist/openapi.js.map +1 -0
- package/dist/postman.d.ts +11 -0
- package/dist/postman.d.ts.map +1 -0
- package/dist/postman.js +260 -0
- package/dist/postman.js.map +1 -0
- package/dist/swagger.d.ts +17 -0
- package/dist/swagger.d.ts.map +1 -0
- package/dist/swagger.js +171 -0
- package/dist/swagger.js.map +1 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# @mapples/api-import
|
|
2
|
+
|
|
3
|
+
Turns API descriptions into Mapples API requests (`ApiRequest` from `@mapples/types`) and
|
|
4
|
+
merges them into a project's API document. Pure and runtime-neutral — no network, no
|
|
5
|
+
filesystem — so the Creator's import dialog and the `mapples` CLI share one implementation.
|
|
6
|
+
|
|
7
|
+
| Input | Function |
|
|
8
|
+
| ----------------------------------------- | ----------------------------------- |
|
|
9
|
+
| cURL command | `importCurl(text)` |
|
|
10
|
+
| OpenAPI 3.x or Swagger 2.0 (JSON or YAML) | `importOpenApi(text, { baseUrl? })` |
|
|
11
|
+
| Postman collection v2.0 / v2.1 | `importPostman(text)` |
|
|
12
|
+
| any of the above | `importApiText(text)` |
|
|
13
|
+
|
|
14
|
+
`mergeApiImport(document, result, { mintId, onConflict: 'rename' | 'replace' })` folds an
|
|
15
|
+
import into an `ApiDocument` and returns a new one.
|
|
16
|
+
|
|
17
|
+
Credentials are never imported: tokens, API keys and credential-looking variables become
|
|
18
|
+
the _name_ of a secret to store (`auth.secretRef`) plus a warning.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BodyCredential } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Finds credential-like string fields in a JSON body and replaces each value
|
|
4
|
+
* with a `state` source (`vars.<field>`): a password or token pasted with a
|
|
5
|
+
* cURL command must not land verbatim in the project document, and a sign-in
|
|
6
|
+
* request reads it from the form at runtime anyway. Returns the rewritten
|
|
7
|
+
* template and what was taken out — the values, so the import dialog can put
|
|
8
|
+
* them back when the author explicitly asks to keep them.
|
|
9
|
+
*/
|
|
10
|
+
export declare const stripBodyCredentials: (template: unknown, requestIndex: number) => {
|
|
11
|
+
template: unknown;
|
|
12
|
+
credentials: BodyCredential[];
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Puts a stripped credential back at its path in a body template — only on
|
|
16
|
+
* the author's explicit choice in the import preview.
|
|
17
|
+
*/
|
|
18
|
+
export declare const restoreBodyCredential: (template: unknown, credential: BodyCredential) => unknown;
|
|
19
|
+
//# sourceMappingURL=bodyCredentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyCredentials.d.ts","sourceRoot":"","sources":["../src/bodyCredentials.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAwBjD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAC/B,UAAU,OAAO,EACjB,cAAc,MAAM,KACnB;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,cAAc,EAAE,CAAA;CA8BpD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAChC,UAAU,OAAO,EACjB,YAAY,cAAc,KACzB,OAqBF,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Body field names whose value is a credential. Matched on the whole key,
|
|
3
|
+
* case-insensitively, `-`/`_` optional — `password`, `client_secret`,
|
|
4
|
+
* `refresh-token`, `apiKey`. A plain `email` or `username` is an identifier,
|
|
5
|
+
* not a credential, so it stays.
|
|
6
|
+
*/
|
|
7
|
+
const CREDENTIAL_KEY = /^(pass(word|wd)?|secret|client_?secret|api_?key|access_?token|refresh_?token|id_?token|token|private_?key|otp|pin)$/;
|
|
8
|
+
const normalizeKey = (key) => key.toLowerCase().replace(/-/g, '_');
|
|
9
|
+
const isCredentialKey = (key) => CREDENTIAL_KEY.test(normalizeKey(key));
|
|
10
|
+
/**
|
|
11
|
+
* The state variable a stripped field reads from at runtime: `vars.<key>`
|
|
12
|
+
* with the key made a valid variable name.
|
|
13
|
+
*/
|
|
14
|
+
const variablePath = (key) => `vars.${key.replace(/[^A-Za-z0-9_]/g, '_')}`;
|
|
15
|
+
/**
|
|
16
|
+
* Finds credential-like string fields in a JSON body and replaces each value
|
|
17
|
+
* with a `state` source (`vars.<field>`): a password or token pasted with a
|
|
18
|
+
* cURL command must not land verbatim in the project document, and a sign-in
|
|
19
|
+
* request reads it from the form at runtime anyway. Returns the rewritten
|
|
20
|
+
* template and what was taken out — the values, so the import dialog can put
|
|
21
|
+
* them back when the author explicitly asks to keep them.
|
|
22
|
+
*/
|
|
23
|
+
export const stripBodyCredentials = (template, requestIndex) => {
|
|
24
|
+
const credentials = [];
|
|
25
|
+
const visit = (node, path) => {
|
|
26
|
+
if (Array.isArray(node)) {
|
|
27
|
+
return node.map((item, index) => visit(item, [...path, String(index)]));
|
|
28
|
+
}
|
|
29
|
+
if (node === null || typeof node !== 'object')
|
|
30
|
+
return node;
|
|
31
|
+
const out = {};
|
|
32
|
+
for (const [key, value] of Object.entries(node)) {
|
|
33
|
+
if (typeof value === 'string' && value !== '' && isCredentialKey(key)) {
|
|
34
|
+
const source = {
|
|
35
|
+
kind: 'state',
|
|
36
|
+
dataProp: variablePath(key),
|
|
37
|
+
};
|
|
38
|
+
credentials.push({
|
|
39
|
+
requestIndex,
|
|
40
|
+
path: [...path, key],
|
|
41
|
+
value,
|
|
42
|
+
replacement: source,
|
|
43
|
+
});
|
|
44
|
+
out[key] = source;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
out[key] = visit(value, [...path, key]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
};
|
|
52
|
+
return { template: visit(template, []), credentials };
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Puts a stripped credential back at its path in a body template — only on
|
|
56
|
+
* the author's explicit choice in the import preview.
|
|
57
|
+
*/
|
|
58
|
+
export const restoreBodyCredential = (template, credential) => {
|
|
59
|
+
const [head, ...rest] = credential.path;
|
|
60
|
+
if (head === undefined)
|
|
61
|
+
return credential.value;
|
|
62
|
+
if (Array.isArray(template)) {
|
|
63
|
+
const index = Number(head);
|
|
64
|
+
return template.map((item, i) => i === index
|
|
65
|
+
? restoreBodyCredential(item, { ...credential, path: rest })
|
|
66
|
+
: item);
|
|
67
|
+
}
|
|
68
|
+
if (template === null || typeof template !== 'object') {
|
|
69
|
+
throw new Error(`The body has no field at "${credential.path.join('.')}" to restore`);
|
|
70
|
+
}
|
|
71
|
+
const node = template;
|
|
72
|
+
return {
|
|
73
|
+
...node,
|
|
74
|
+
[head]: restoreBodyCredential(node[head], { ...credential, path: rest }),
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=bodyCredentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyCredentials.js","sourceRoot":"","sources":["../src/bodyCredentials.ts"],"names":[],"mappings":"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"}
|
package/dist/curl.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ApiImportResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Splits a shell command line into words: single quotes (literal), double
|
|
4
|
+
* quotes (backslash escapes `"`, `\`, `$` and the backtick), ANSI-C `$'…'`
|
|
5
|
+
* (what Chrome's "Copy as cURL" emits for bodies), backslash escapes, and
|
|
6
|
+
* backslash-newline continuations.
|
|
7
|
+
*/
|
|
8
|
+
export declare const tokenizeShell: (input: string) => string[];
|
|
9
|
+
/** Whether the text is a cURL command (leading `$` prompt tolerated). */
|
|
10
|
+
export declare const looksLikeCurl: (text: string) => boolean;
|
|
11
|
+
/**
|
|
12
|
+
* One cURL command → one request. Credentials in the command (a bearer token,
|
|
13
|
+
* an API-key header, `-u`) become `auth` naming a secret; the value itself is
|
|
14
|
+
* dropped and reported in `warnings`. Anything that would change what the
|
|
15
|
+
* request sends and can't be represented (a form upload, a non-JSON body)
|
|
16
|
+
* throws rather than importing a different request.
|
|
17
|
+
*/
|
|
18
|
+
export declare const importCurl: (text: string) => ApiImportResult;
|
|
19
|
+
//# sourceMappingURL=curl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../src/curl.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,YAAY,CAAC;AAgElE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,MAAM,EAsFnD,CAAC;AAOF,yEAAyE;AACzE,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,OACR,CAAC;AAEtC;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,eAsJzC,CAAC"}
|
package/dist/curl.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { stripBodyCredentials } from './bodyCredentials.js';
|
|
2
|
+
import { nameFromRoute } from './names.js';
|
|
3
|
+
const METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
|
4
|
+
/** Headers whose value is a credential: imported as auth, never as text. */
|
|
5
|
+
const API_KEY_HEADERS = ['x-api-key', 'api-key', 'apikey', 'x-auth-token'];
|
|
6
|
+
/** Flags that take a value we have no use for. */
|
|
7
|
+
const IGNORED_WITH_VALUE = new Set([
|
|
8
|
+
'-A',
|
|
9
|
+
'--user-agent',
|
|
10
|
+
'-e',
|
|
11
|
+
'--referer',
|
|
12
|
+
'-b',
|
|
13
|
+
'--cookie',
|
|
14
|
+
'-o',
|
|
15
|
+
'--output',
|
|
16
|
+
'-m',
|
|
17
|
+
'--max-time',
|
|
18
|
+
'--connect-timeout',
|
|
19
|
+
'-w',
|
|
20
|
+
'--write-out',
|
|
21
|
+
'--retry',
|
|
22
|
+
]);
|
|
23
|
+
/** Flags that change nothing about the request itself. */
|
|
24
|
+
const IGNORED = new Set([
|
|
25
|
+
'--compressed',
|
|
26
|
+
'-s',
|
|
27
|
+
'--silent',
|
|
28
|
+
'-S',
|
|
29
|
+
'--show-error',
|
|
30
|
+
'-k',
|
|
31
|
+
'--insecure',
|
|
32
|
+
'-L',
|
|
33
|
+
'--location',
|
|
34
|
+
'-i',
|
|
35
|
+
'--include',
|
|
36
|
+
'-v',
|
|
37
|
+
'--verbose',
|
|
38
|
+
'-g',
|
|
39
|
+
'--globoff',
|
|
40
|
+
'--http1.1',
|
|
41
|
+
'--http2',
|
|
42
|
+
]);
|
|
43
|
+
const DATA_FLAGS = new Set([
|
|
44
|
+
'-d',
|
|
45
|
+
'--data',
|
|
46
|
+
'--data-raw',
|
|
47
|
+
'--data-binary',
|
|
48
|
+
'--data-ascii',
|
|
49
|
+
'--json',
|
|
50
|
+
]);
|
|
51
|
+
const ANSI_C_ESCAPES = {
|
|
52
|
+
n: '\n',
|
|
53
|
+
t: '\t',
|
|
54
|
+
r: '\r',
|
|
55
|
+
'\\': '\\',
|
|
56
|
+
"'": "'",
|
|
57
|
+
'"': '"',
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Splits a shell command line into words: single quotes (literal), double
|
|
61
|
+
* quotes (backslash escapes `"`, `\`, `$` and the backtick), ANSI-C `$'…'`
|
|
62
|
+
* (what Chrome's "Copy as cURL" emits for bodies), backslash escapes, and
|
|
63
|
+
* backslash-newline continuations.
|
|
64
|
+
*/
|
|
65
|
+
export const tokenizeShell = (input) => {
|
|
66
|
+
const tokens = [];
|
|
67
|
+
let current = '';
|
|
68
|
+
let inToken = false;
|
|
69
|
+
let index = 0;
|
|
70
|
+
const fail = (what) => {
|
|
71
|
+
throw new Error(`The cURL command has an unterminated ${what}`);
|
|
72
|
+
};
|
|
73
|
+
while (index < input.length) {
|
|
74
|
+
const char = input[index];
|
|
75
|
+
if (char === '\\') {
|
|
76
|
+
const next = input[index + 1];
|
|
77
|
+
if (next === '\n') {
|
|
78
|
+
index += 2;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (next === '\r' && input[index + 2] === '\n') {
|
|
82
|
+
index += 3;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (next === undefined)
|
|
86
|
+
fail('escape');
|
|
87
|
+
current += next;
|
|
88
|
+
inToken = true;
|
|
89
|
+
index += 2;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (char === "'" || (char === '$' && input[index + 1] === "'")) {
|
|
93
|
+
const ansi = char === '$';
|
|
94
|
+
index += ansi ? 2 : 1;
|
|
95
|
+
inToken = true;
|
|
96
|
+
for (;;) {
|
|
97
|
+
const inner = input[index];
|
|
98
|
+
if (inner === undefined)
|
|
99
|
+
fail('single quote');
|
|
100
|
+
if (inner === "'")
|
|
101
|
+
break;
|
|
102
|
+
if (ansi && inner === '\\') {
|
|
103
|
+
const escaped = input[index + 1];
|
|
104
|
+
if (escaped === undefined)
|
|
105
|
+
fail('escape');
|
|
106
|
+
current += ANSI_C_ESCAPES[escaped] ?? `\\${escaped}`;
|
|
107
|
+
index += 2;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
current += inner;
|
|
111
|
+
index += 1;
|
|
112
|
+
}
|
|
113
|
+
index += 1;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (char === '"') {
|
|
117
|
+
index += 1;
|
|
118
|
+
inToken = true;
|
|
119
|
+
for (;;) {
|
|
120
|
+
const inner = input[index];
|
|
121
|
+
if (inner === undefined)
|
|
122
|
+
fail('double quote');
|
|
123
|
+
if (inner === '"')
|
|
124
|
+
break;
|
|
125
|
+
if (inner === '\\' && '"\\$`'.includes(input[index + 1] ?? '')) {
|
|
126
|
+
current += input[index + 1];
|
|
127
|
+
index += 2;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
current += inner;
|
|
131
|
+
index += 1;
|
|
132
|
+
}
|
|
133
|
+
index += 1;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (/\s/.test(char)) {
|
|
137
|
+
if (inToken)
|
|
138
|
+
tokens.push(current);
|
|
139
|
+
current = '';
|
|
140
|
+
inToken = false;
|
|
141
|
+
index += 1;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
current += char;
|
|
145
|
+
inToken = true;
|
|
146
|
+
index += 1;
|
|
147
|
+
}
|
|
148
|
+
if (inToken)
|
|
149
|
+
tokens.push(current);
|
|
150
|
+
return tokens;
|
|
151
|
+
};
|
|
152
|
+
const staticSource = (value) => ({
|
|
153
|
+
kind: 'static',
|
|
154
|
+
value,
|
|
155
|
+
});
|
|
156
|
+
/** Whether the text is a cURL command (leading `$` prompt tolerated). */
|
|
157
|
+
export const looksLikeCurl = (text) => /^\s*(\$\s+)?curl(\s|$)/.test(text);
|
|
158
|
+
/**
|
|
159
|
+
* One cURL command → one request. Credentials in the command (a bearer token,
|
|
160
|
+
* an API-key header, `-u`) become `auth` naming a secret; the value itself is
|
|
161
|
+
* dropped and reported in `warnings`. Anything that would change what the
|
|
162
|
+
* request sends and can't be represented (a form upload, a non-JSON body)
|
|
163
|
+
* throws rather than importing a different request.
|
|
164
|
+
*/
|
|
165
|
+
export const importCurl = (text) => {
|
|
166
|
+
const tokens = tokenizeShell(text.trim().replace(/^\$\s+/, ''));
|
|
167
|
+
if (tokens[0] !== 'curl') {
|
|
168
|
+
throw new Error('The text is not a cURL command');
|
|
169
|
+
}
|
|
170
|
+
let method;
|
|
171
|
+
let url;
|
|
172
|
+
let asQuery = false;
|
|
173
|
+
const data = [];
|
|
174
|
+
const headers = {};
|
|
175
|
+
const warnings = [];
|
|
176
|
+
let auth;
|
|
177
|
+
for (let index = 1; index < tokens.length; index += 1) {
|
|
178
|
+
const token = tokens[index];
|
|
179
|
+
const value = () => {
|
|
180
|
+
index += 1;
|
|
181
|
+
const next = tokens[index];
|
|
182
|
+
if (next === undefined) {
|
|
183
|
+
throw new Error(`cURL option "${token}" is missing its value`);
|
|
184
|
+
}
|
|
185
|
+
return next;
|
|
186
|
+
};
|
|
187
|
+
if (token === '-X' || token === '--request') {
|
|
188
|
+
method = value().toUpperCase();
|
|
189
|
+
}
|
|
190
|
+
else if (token === '-H' || token === '--header') {
|
|
191
|
+
const header = value();
|
|
192
|
+
const colon = header.indexOf(':');
|
|
193
|
+
if (colon === -1)
|
|
194
|
+
throw new Error(`Header "${header}" has no ":"`);
|
|
195
|
+
headers[header.slice(0, colon).trim()] = header.slice(colon + 1).trim();
|
|
196
|
+
}
|
|
197
|
+
else if (DATA_FLAGS.has(token)) {
|
|
198
|
+
data.push(value());
|
|
199
|
+
if (token === '--json')
|
|
200
|
+
headers['Content-Type'] = 'application/json';
|
|
201
|
+
}
|
|
202
|
+
else if (token === '--url') {
|
|
203
|
+
url = value();
|
|
204
|
+
}
|
|
205
|
+
else if (token === '-G' || token === '--get') {
|
|
206
|
+
asQuery = true;
|
|
207
|
+
}
|
|
208
|
+
else if (token === '-u' || token === '--user') {
|
|
209
|
+
value();
|
|
210
|
+
auth = {
|
|
211
|
+
kind: 'header',
|
|
212
|
+
header: 'Authorization',
|
|
213
|
+
secretRef: 'BASIC_AUTH',
|
|
214
|
+
};
|
|
215
|
+
warnings.push('The -u credentials were not imported. Store "Basic <base64 user:password>" as the secret BASIC_AUTH.');
|
|
216
|
+
}
|
|
217
|
+
else if (IGNORED_WITH_VALUE.has(token)) {
|
|
218
|
+
value();
|
|
219
|
+
}
|
|
220
|
+
else if (IGNORED.has(token)) {
|
|
221
|
+
// Transport details with no place in a request definition.
|
|
222
|
+
}
|
|
223
|
+
else if (token.startsWith('-')) {
|
|
224
|
+
throw new Error(`cURL option "${token}" is not supported by the import`);
|
|
225
|
+
}
|
|
226
|
+
else if (url === undefined) {
|
|
227
|
+
url = token;
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
throw new Error(`Unexpected argument "${token}" — one URL per command`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!url)
|
|
234
|
+
throw new Error('The cURL command has no URL');
|
|
235
|
+
const parsed = new URL(/^https?:\/\//i.test(url) ? url : `https://${url}`);
|
|
236
|
+
for (const [name, headerValue] of Object.entries(headers)) {
|
|
237
|
+
const lower = name.toLowerCase();
|
|
238
|
+
if (lower === 'authorization') {
|
|
239
|
+
const bearer = /^bearer\s+/i.test(headerValue);
|
|
240
|
+
auth = bearer
|
|
241
|
+
? { kind: 'bearer', secretRef: 'API_TOKEN' }
|
|
242
|
+
: { kind: 'header', header: name, secretRef: 'API_TOKEN' };
|
|
243
|
+
warnings.push(bearer
|
|
244
|
+
? 'The bearer token was not imported. Store it as the secret API_TOKEN.'
|
|
245
|
+
: 'The Authorization header value was not imported. Store it as the secret API_TOKEN.');
|
|
246
|
+
delete headers[name];
|
|
247
|
+
}
|
|
248
|
+
else if (API_KEY_HEADERS.includes(lower)) {
|
|
249
|
+
auth = { kind: 'header', header: name, secretRef: 'API_KEY' };
|
|
250
|
+
warnings.push(`The ${name} value was not imported. Store it as the secret API_KEY.`);
|
|
251
|
+
delete headers[name];
|
|
252
|
+
}
|
|
253
|
+
else if (lower === 'cookie') {
|
|
254
|
+
warnings.push('The Cookie header was not imported.');
|
|
255
|
+
delete headers[name];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const params = {};
|
|
259
|
+
parsed.searchParams.forEach((paramValue, key) => {
|
|
260
|
+
params[key] = staticSource(paramValue);
|
|
261
|
+
});
|
|
262
|
+
let template;
|
|
263
|
+
if (data.length > 0 && asQuery) {
|
|
264
|
+
for (const pair of data.join('&').split('&')) {
|
|
265
|
+
const [key, ...rest] = pair.split('=');
|
|
266
|
+
params[decodeURIComponent(key)] = staticSource(decodeURIComponent(rest.join('=')));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else if (data.length > 0) {
|
|
270
|
+
const raw = data.join('&');
|
|
271
|
+
try {
|
|
272
|
+
template = JSON.parse(raw);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
throw new Error('The cURL body is not JSON — only JSON bodies can be imported');
|
|
276
|
+
}
|
|
277
|
+
delete headers['Content-Type'];
|
|
278
|
+
delete headers['content-type'];
|
|
279
|
+
}
|
|
280
|
+
// A password or token in the body is a credential like a bearer header:
|
|
281
|
+
// it reads from state instead. The preview lists each one (and lets the
|
|
282
|
+
// author keep the literal on purpose).
|
|
283
|
+
let bodyCredentials = [];
|
|
284
|
+
if (template !== undefined) {
|
|
285
|
+
const stripped = stripBodyCredentials(template, 0);
|
|
286
|
+
template = stripped.template;
|
|
287
|
+
bodyCredentials = stripped.credentials;
|
|
288
|
+
}
|
|
289
|
+
const resolvedMethod = method ?? (template === undefined ? 'GET' : 'POST');
|
|
290
|
+
if (!METHODS.includes(resolvedMethod)) {
|
|
291
|
+
throw new Error(`HTTP method "${resolvedMethod}" is not supported`);
|
|
292
|
+
}
|
|
293
|
+
const path = decodeURI(parsed.pathname);
|
|
294
|
+
return {
|
|
295
|
+
format: 'curl',
|
|
296
|
+
baseUrl: parsed.origin,
|
|
297
|
+
environmentName: parsed.host,
|
|
298
|
+
requests: [
|
|
299
|
+
{
|
|
300
|
+
name: nameFromRoute(resolvedMethod, path),
|
|
301
|
+
method: resolvedMethod,
|
|
302
|
+
path,
|
|
303
|
+
headers: Object.keys(headers).length > 0 ? headers : undefined,
|
|
304
|
+
params: Object.keys(params).length > 0 ? params : undefined,
|
|
305
|
+
body: template === undefined ? undefined : { kind: 'json', template },
|
|
306
|
+
auth,
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
warnings,
|
|
310
|
+
bodyCredentials: bodyCredentials.length > 0 ? bodyCredentials : undefined,
|
|
311
|
+
};
|
|
312
|
+
};
|
|
313
|
+
//# sourceMappingURL=curl.js.map
|
package/dist/curl.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"curl.js","sourceRoot":"","sources":["../src/curl.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ApiImportResult } from './types.js';
|
|
2
|
+
export { restoreBodyCredential } from './bodyCredentials.js';
|
|
3
|
+
export { importCurl, looksLikeCurl } from './curl.js';
|
|
4
|
+
export { mergeApiImport } from './merge.js';
|
|
5
|
+
export type { MergeApiImportOptions, MergeApiImportResult } from './merge.js';
|
|
6
|
+
export { nameFromRoute, toRequestName, uniqueName } from './names.js';
|
|
7
|
+
export { importOpenApi, looksLikeOpenApi } from './openapi.js';
|
|
8
|
+
export type { OpenApiImportOptions } from './openapi.js';
|
|
9
|
+
export { importPostman, looksLikePostman } from './postman.js';
|
|
10
|
+
export { swaggerToOpenApi } from './swagger.js';
|
|
11
|
+
export type { ApiImportResult, BodyCredential, ImportedRequest, } from './types.js';
|
|
12
|
+
/** Imports `text` as whichever format it is; anything else throws. */
|
|
13
|
+
export declare const importApiText: (text: string) => ApiImportResult;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,YAAY,EACV,eAAe,EACf,cAAc,EACd,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,sEAAsE;AACtE,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,eAO5C,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Turns API descriptions — a cURL command, an OpenAPI 3 or
|
|
3
|
+
* Swagger 2 document, a Postman collection — into Mapples API requests, and
|
|
4
|
+
* folds them into a project API document. Pure and runtime-neutral: no Node
|
|
5
|
+
* or browser APIs, nothing fetched. Shared by the Creator's import dialog and
|
|
6
|
+
* the `mapples` CLI.
|
|
7
|
+
*/
|
|
8
|
+
import { importCurl, looksLikeCurl } from './curl.js';
|
|
9
|
+
import { importOpenApi, looksLikeOpenApi } from './openapi.js';
|
|
10
|
+
import { importPostman, looksLikePostman } from './postman.js';
|
|
11
|
+
export { restoreBodyCredential } from './bodyCredentials.js';
|
|
12
|
+
export { importCurl, looksLikeCurl } from './curl.js';
|
|
13
|
+
export { mergeApiImport } from './merge.js';
|
|
14
|
+
export { nameFromRoute, toRequestName, uniqueName } from './names.js';
|
|
15
|
+
export { importOpenApi, looksLikeOpenApi } from './openapi.js';
|
|
16
|
+
export { importPostman, looksLikePostman } from './postman.js';
|
|
17
|
+
export { swaggerToOpenApi } from './swagger.js';
|
|
18
|
+
/** Imports `text` as whichever format it is; anything else throws. */
|
|
19
|
+
export const importApiText = (text) => {
|
|
20
|
+
if (looksLikeCurl(text))
|
|
21
|
+
return importCurl(text);
|
|
22
|
+
if (looksLikePostman(text))
|
|
23
|
+
return importPostman(text);
|
|
24
|
+
if (looksLikeOpenApi(text))
|
|
25
|
+
return importOpenApi(text);
|
|
26
|
+
throw new Error('Paste a cURL command, an OpenAPI 3 / Swagger 2 document (JSON or YAML) or a Postman collection');
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAOhD,sEAAsE;AACtE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAmB,EAAE;IAC7D,IAAI,aAAa,CAAC,IAAI,CAAC;QAAE,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,gBAAgB,CAAC,IAAI,CAAC;QAAE,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IACvD,IAAI,gBAAgB,CAAC,IAAI,CAAC;QAAE,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,IAAI,KAAK,CACb,gGAAgG,CACjG,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/merge.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Folds an import into a project API document — the one rule
|
|
3
|
+
* the Creator's import dialog and the `mapples api import` command share.
|
|
4
|
+
*/
|
|
5
|
+
import type { ApiDocument } from '@mapples/types';
|
|
6
|
+
import type { ApiImportResult } from './types.js';
|
|
7
|
+
export interface MergeApiImportOptions {
|
|
8
|
+
/** Mints request and environment ids (the caller's uuid source). */
|
|
9
|
+
mintId: () => string;
|
|
10
|
+
/**
|
|
11
|
+
* A request named like an existing one: `rename` adds it next to it
|
|
12
|
+
* (`users2`, the Creator dialog's behaviour); `replace` updates the
|
|
13
|
+
* existing request in place, keeping its id — re-running an import is then
|
|
14
|
+
* idempotent and bindings to it keep working.
|
|
15
|
+
*/
|
|
16
|
+
onConflict: 'rename' | 'replace';
|
|
17
|
+
}
|
|
18
|
+
export interface MergeApiImportResult {
|
|
19
|
+
document: ApiDocument;
|
|
20
|
+
/** The ids of the imported requests, in import order. */
|
|
21
|
+
requestIds: string[];
|
|
22
|
+
/** The environment the requests' relative paths hang off, when one is used. */
|
|
23
|
+
environmentId: string | null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns a new document with `batch` folded in; `document` is not touched.
|
|
27
|
+
* An empty document gets an environment from the import's base URL. When
|
|
28
|
+
* the active environment already points at that base URL the paths stay
|
|
29
|
+
* relative to it; otherwise they are made absolute, so an import never
|
|
30
|
+
* silently retargets requests already in the project.
|
|
31
|
+
*/
|
|
32
|
+
export declare const mergeApiImport: (document: ApiDocument, batch: Pick<ApiImportResult, "baseUrl" | "environmentName" | "requests" | "variables">, { mintId, onConflict }: MergeApiImportOptions) => MergeApiImportResult;
|
|
33
|
+
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,qBAAqB;IACpC,oEAAoE;IACpE,MAAM,EAAE,MAAM,MAAM,CAAC;IACrB;;;;;OAKG;IACH,UAAU,EAAE,QAAQ,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,WAAW,CAAC;IACtB,yDAAyD;IACzD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,+EAA+E;IAC/E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GACzB,UAAU,WAAW,EACrB,OAAO,IAAI,CACT,eAAe,EACf,SAAS,GAAG,iBAAiB,GAAG,UAAU,GAAG,WAAW,CACzD,EACD,wBAAwB,qBAAqB,KAC5C,oBA8DF,CAAC"}
|
package/dist/merge.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { uniqueName } from './names.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a new document with `batch` folded in; `document` is not touched.
|
|
4
|
+
* An empty document gets an environment from the import's base URL. When
|
|
5
|
+
* the active environment already points at that base URL the paths stay
|
|
6
|
+
* relative to it; otherwise they are made absolute, so an import never
|
|
7
|
+
* silently retargets requests already in the project.
|
|
8
|
+
*/
|
|
9
|
+
export const mergeApiImport = (document, batch, { mintId, onConflict }) => {
|
|
10
|
+
// A JSON document: a JSON copy (structuredClone is not on every RN engine).
|
|
11
|
+
const doc = JSON.parse(JSON.stringify(document));
|
|
12
|
+
const baseUrl = batch.baseUrl.replace(/\/$/, '');
|
|
13
|
+
let environmentId = doc.activeEnvironmentId ?? null;
|
|
14
|
+
const active = environmentId ? doc.environments[environmentId] : undefined;
|
|
15
|
+
let relative = active?.baseUrl.replace(/\/$/, '') === baseUrl;
|
|
16
|
+
if (Object.keys(doc.environments).length === 0) {
|
|
17
|
+
environmentId = mintId();
|
|
18
|
+
doc.environments[environmentId] = {
|
|
19
|
+
id: environmentId,
|
|
20
|
+
name: batch.environmentName,
|
|
21
|
+
baseUrl,
|
|
22
|
+
...(batch.variables ? { variables: { ...batch.variables } } : {}),
|
|
23
|
+
};
|
|
24
|
+
doc.activeEnvironmentId = environmentId;
|
|
25
|
+
relative = true;
|
|
26
|
+
}
|
|
27
|
+
else if (relative && active && batch.variables) {
|
|
28
|
+
// Values already set in the project win over the import's.
|
|
29
|
+
active.variables = { ...batch.variables, ...active.variables };
|
|
30
|
+
}
|
|
31
|
+
const byName = new Map(Object.values(doc.requests).map((request) => [request.name, request]));
|
|
32
|
+
const taken = new Set(byName.keys());
|
|
33
|
+
const requestIds = [];
|
|
34
|
+
for (const request of batch.requests) {
|
|
35
|
+
const isAbsolute = /^https?:\/\//i.test(request.path);
|
|
36
|
+
const path = relative || isAbsolute
|
|
37
|
+
? request.path
|
|
38
|
+
: `${baseUrl}${request.path.startsWith('/') ? '' : '/'}${request.path}`;
|
|
39
|
+
const existing = byName.get(request.name);
|
|
40
|
+
if (existing && onConflict === 'replace') {
|
|
41
|
+
doc.requests[existing.id] = {
|
|
42
|
+
...request,
|
|
43
|
+
id: existing.id,
|
|
44
|
+
name: existing.name,
|
|
45
|
+
path,
|
|
46
|
+
// What the project chose or captured for this request stays its own.
|
|
47
|
+
...(existing.stateKey ? { stateKey: existing.stateKey } : {}),
|
|
48
|
+
responseSample: request.responseSample ?? existing.responseSample,
|
|
49
|
+
};
|
|
50
|
+
requestIds.push(existing.id);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const id = mintId();
|
|
54
|
+
doc.requests[id] = {
|
|
55
|
+
...request,
|
|
56
|
+
id,
|
|
57
|
+
name: uniqueName(request.name, taken),
|
|
58
|
+
path,
|
|
59
|
+
};
|
|
60
|
+
requestIds.push(id);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
document: doc,
|
|
64
|
+
requestIds,
|
|
65
|
+
environmentId: relative ? environmentId : null,
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"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"}
|