@server/next 0.14.0 → 0.15.2
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/package.json +21 -28
- package/readme.md +67 -67
- package/src/RequestLogger.js +77 -0
- package/src/ServerUrl.js +64 -0
- package/src/ServerUrl.test.js +63 -0
- package/src/color.js +26 -0
- package/src/index.js +289 -0
- package/src/parseBody.js +96 -0
- package/src/parseBody.test.js +69 -0
- package/src/pathPattern.js +24 -0
- package/src/pathPattern.test.js +72 -0
- package/index.js +0 -799
package/index.js
DELETED
|
@@ -1,799 +0,0 @@
|
|
|
1
|
-
import formidable from 'formidable';
|
|
2
|
-
import http from 'http';
|
|
3
|
-
import zlib from 'zlib';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Tokenize input string.
|
|
7
|
-
*/
|
|
8
|
-
function lexer(str) {
|
|
9
|
-
var tokens = [];
|
|
10
|
-
var i = 0;
|
|
11
|
-
while (i < str.length) {
|
|
12
|
-
var char = str[i];
|
|
13
|
-
if (char === "*" || char === "+" || char === "?") {
|
|
14
|
-
tokens.push({ type: "MODIFIER", index: i, value: str[i++] });
|
|
15
|
-
continue;
|
|
16
|
-
}
|
|
17
|
-
if (char === "\\") {
|
|
18
|
-
tokens.push({ type: "ESCAPED_CHAR", index: i++, value: str[i++] });
|
|
19
|
-
continue;
|
|
20
|
-
}
|
|
21
|
-
if (char === "{") {
|
|
22
|
-
tokens.push({ type: "OPEN", index: i, value: str[i++] });
|
|
23
|
-
continue;
|
|
24
|
-
}
|
|
25
|
-
if (char === "}") {
|
|
26
|
-
tokens.push({ type: "CLOSE", index: i, value: str[i++] });
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
if (char === ":") {
|
|
30
|
-
var name = "";
|
|
31
|
-
var j = i + 1;
|
|
32
|
-
while (j < str.length) {
|
|
33
|
-
var code = str.charCodeAt(j);
|
|
34
|
-
if (
|
|
35
|
-
// `0-9`
|
|
36
|
-
(code >= 48 && code <= 57) ||
|
|
37
|
-
// `A-Z`
|
|
38
|
-
(code >= 65 && code <= 90) ||
|
|
39
|
-
// `a-z`
|
|
40
|
-
(code >= 97 && code <= 122) ||
|
|
41
|
-
// `_`
|
|
42
|
-
code === 95) {
|
|
43
|
-
name += str[j++];
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
if (!name)
|
|
49
|
-
throw new TypeError("Missing parameter name at " + i);
|
|
50
|
-
tokens.push({ type: "NAME", index: i, value: name });
|
|
51
|
-
i = j;
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (char === "(") {
|
|
55
|
-
var count = 1;
|
|
56
|
-
var pattern = "";
|
|
57
|
-
var j = i + 1;
|
|
58
|
-
if (str[j] === "?") {
|
|
59
|
-
throw new TypeError("Pattern cannot start with \"?\" at " + j);
|
|
60
|
-
}
|
|
61
|
-
while (j < str.length) {
|
|
62
|
-
if (str[j] === "\\") {
|
|
63
|
-
pattern += str[j++] + str[j++];
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (str[j] === ")") {
|
|
67
|
-
count--;
|
|
68
|
-
if (count === 0) {
|
|
69
|
-
j++;
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
else if (str[j] === "(") {
|
|
74
|
-
count++;
|
|
75
|
-
if (str[j + 1] !== "?") {
|
|
76
|
-
throw new TypeError("Capturing groups are not allowed at " + j);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
pattern += str[j++];
|
|
80
|
-
}
|
|
81
|
-
if (count)
|
|
82
|
-
throw new TypeError("Unbalanced pattern at " + i);
|
|
83
|
-
if (!pattern)
|
|
84
|
-
throw new TypeError("Missing pattern at " + i);
|
|
85
|
-
tokens.push({ type: "PATTERN", index: i, value: pattern });
|
|
86
|
-
i = j;
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
tokens.push({ type: "CHAR", index: i, value: str[i++] });
|
|
90
|
-
}
|
|
91
|
-
tokens.push({ type: "END", index: i, value: "" });
|
|
92
|
-
return tokens;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Parse a string for the raw tokens.
|
|
96
|
-
*/
|
|
97
|
-
function parse(str, options) {
|
|
98
|
-
if (options === void 0) { options = {}; }
|
|
99
|
-
var tokens = lexer(str);
|
|
100
|
-
var _a = options.prefixes, prefixes = _a === void 0 ? "./" : _a;
|
|
101
|
-
var defaultPattern = "[^" + escapeString(options.delimiter || "/#?") + "]+?";
|
|
102
|
-
var result = [];
|
|
103
|
-
var key = 0;
|
|
104
|
-
var i = 0;
|
|
105
|
-
var path = "";
|
|
106
|
-
var tryConsume = function (type) {
|
|
107
|
-
if (i < tokens.length && tokens[i].type === type)
|
|
108
|
-
return tokens[i++].value;
|
|
109
|
-
};
|
|
110
|
-
var mustConsume = function (type) {
|
|
111
|
-
var value = tryConsume(type);
|
|
112
|
-
if (value !== undefined)
|
|
113
|
-
return value;
|
|
114
|
-
var _a = tokens[i], nextType = _a.type, index = _a.index;
|
|
115
|
-
throw new TypeError("Unexpected " + nextType + " at " + index + ", expected " + type);
|
|
116
|
-
};
|
|
117
|
-
var consumeText = function () {
|
|
118
|
-
var result = "";
|
|
119
|
-
var value;
|
|
120
|
-
// tslint:disable-next-line
|
|
121
|
-
while ((value = tryConsume("CHAR") || tryConsume("ESCAPED_CHAR"))) {
|
|
122
|
-
result += value;
|
|
123
|
-
}
|
|
124
|
-
return result;
|
|
125
|
-
};
|
|
126
|
-
while (i < tokens.length) {
|
|
127
|
-
var char = tryConsume("CHAR");
|
|
128
|
-
var name = tryConsume("NAME");
|
|
129
|
-
var pattern = tryConsume("PATTERN");
|
|
130
|
-
if (name || pattern) {
|
|
131
|
-
var prefix = char || "";
|
|
132
|
-
if (prefixes.indexOf(prefix) === -1) {
|
|
133
|
-
path += prefix;
|
|
134
|
-
prefix = "";
|
|
135
|
-
}
|
|
136
|
-
if (path) {
|
|
137
|
-
result.push(path);
|
|
138
|
-
path = "";
|
|
139
|
-
}
|
|
140
|
-
result.push({
|
|
141
|
-
name: name || key++,
|
|
142
|
-
prefix: prefix,
|
|
143
|
-
suffix: "",
|
|
144
|
-
pattern: pattern || defaultPattern,
|
|
145
|
-
modifier: tryConsume("MODIFIER") || ""
|
|
146
|
-
});
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
var value = char || tryConsume("ESCAPED_CHAR");
|
|
150
|
-
if (value) {
|
|
151
|
-
path += value;
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
if (path) {
|
|
155
|
-
result.push(path);
|
|
156
|
-
path = "";
|
|
157
|
-
}
|
|
158
|
-
var open = tryConsume("OPEN");
|
|
159
|
-
if (open) {
|
|
160
|
-
var prefix = consumeText();
|
|
161
|
-
var name_1 = tryConsume("NAME") || "";
|
|
162
|
-
var pattern_1 = tryConsume("PATTERN") || "";
|
|
163
|
-
var suffix = consumeText();
|
|
164
|
-
mustConsume("CLOSE");
|
|
165
|
-
result.push({
|
|
166
|
-
name: name_1 || (pattern_1 ? key++ : ""),
|
|
167
|
-
pattern: name_1 && !pattern_1 ? defaultPattern : pattern_1,
|
|
168
|
-
prefix: prefix,
|
|
169
|
-
suffix: suffix,
|
|
170
|
-
modifier: tryConsume("MODIFIER") || ""
|
|
171
|
-
});
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
mustConsume("END");
|
|
175
|
-
}
|
|
176
|
-
return result;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Compile a string to a template function for the path.
|
|
180
|
-
*/
|
|
181
|
-
function compile(str, options) {
|
|
182
|
-
return tokensToFunction(parse(str, options), options);
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Expose a method for transforming tokens into the path function.
|
|
186
|
-
*/
|
|
187
|
-
function tokensToFunction(tokens, options) {
|
|
188
|
-
if (options === void 0) { options = {}; }
|
|
189
|
-
var reFlags = flags(options);
|
|
190
|
-
var _a = options.encode, encode = _a === void 0 ? function (x) { return x; } : _a, _b = options.validate, validate = _b === void 0 ? true : _b;
|
|
191
|
-
// Compile all the tokens into regexps.
|
|
192
|
-
var matches = tokens.map(function (token) {
|
|
193
|
-
if (typeof token === "object") {
|
|
194
|
-
return new RegExp("^(?:" + token.pattern + ")$", reFlags);
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
return function (data) {
|
|
198
|
-
var path = "";
|
|
199
|
-
for (var i = 0; i < tokens.length; i++) {
|
|
200
|
-
var token = tokens[i];
|
|
201
|
-
if (typeof token === "string") {
|
|
202
|
-
path += token;
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
var value = data ? data[token.name] : undefined;
|
|
206
|
-
var optional = token.modifier === "?" || token.modifier === "*";
|
|
207
|
-
var repeat = token.modifier === "*" || token.modifier === "+";
|
|
208
|
-
if (Array.isArray(value)) {
|
|
209
|
-
if (!repeat) {
|
|
210
|
-
throw new TypeError("Expected \"" + token.name + "\" to not repeat, but got an array");
|
|
211
|
-
}
|
|
212
|
-
if (value.length === 0) {
|
|
213
|
-
if (optional)
|
|
214
|
-
continue;
|
|
215
|
-
throw new TypeError("Expected \"" + token.name + "\" to not be empty");
|
|
216
|
-
}
|
|
217
|
-
for (var j = 0; j < value.length; j++) {
|
|
218
|
-
var segment = encode(value[j], token);
|
|
219
|
-
if (validate && !matches[i].test(segment)) {
|
|
220
|
-
throw new TypeError("Expected all \"" + token.name + "\" to match \"" + token.pattern + "\", but got \"" + segment + "\"");
|
|
221
|
-
}
|
|
222
|
-
path += token.prefix + segment + token.suffix;
|
|
223
|
-
}
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
if (typeof value === "string" || typeof value === "number") {
|
|
227
|
-
var segment = encode(String(value), token);
|
|
228
|
-
if (validate && !matches[i].test(segment)) {
|
|
229
|
-
throw new TypeError("Expected \"" + token.name + "\" to match \"" + token.pattern + "\", but got \"" + segment + "\"");
|
|
230
|
-
}
|
|
231
|
-
path += token.prefix + segment + token.suffix;
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
if (optional)
|
|
235
|
-
continue;
|
|
236
|
-
var typeOfMessage = repeat ? "an array" : "a string";
|
|
237
|
-
throw new TypeError("Expected \"" + token.name + "\" to be " + typeOfMessage);
|
|
238
|
-
}
|
|
239
|
-
return path;
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Create path match function from `path-to-regexp` spec.
|
|
244
|
-
*/
|
|
245
|
-
function match(str, options) {
|
|
246
|
-
var keys = [];
|
|
247
|
-
var re = pathToRegexp(str, keys, options);
|
|
248
|
-
return regexpToFunction(re, keys, options);
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Create a path match function from `path-to-regexp` output.
|
|
252
|
-
*/
|
|
253
|
-
function regexpToFunction(re, keys, options) {
|
|
254
|
-
if (options === void 0) { options = {}; }
|
|
255
|
-
var _a = options.decode, decode = _a === void 0 ? function (x) { return x; } : _a;
|
|
256
|
-
return function (pathname) {
|
|
257
|
-
var m = re.exec(pathname);
|
|
258
|
-
if (!m)
|
|
259
|
-
return false;
|
|
260
|
-
var path = m[0], index = m.index;
|
|
261
|
-
var params = Object.create(null);
|
|
262
|
-
var _loop_1 = function (i) {
|
|
263
|
-
// tslint:disable-next-line
|
|
264
|
-
if (m[i] === undefined)
|
|
265
|
-
return "continue";
|
|
266
|
-
var key = keys[i - 1];
|
|
267
|
-
if (key.modifier === "*" || key.modifier === "+") {
|
|
268
|
-
params[key.name] = m[i].split(key.prefix + key.suffix).map(function (value) {
|
|
269
|
-
return decode(value, key);
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
params[key.name] = decode(m[i], key);
|
|
274
|
-
}
|
|
275
|
-
};
|
|
276
|
-
for (var i = 1; i < m.length; i++) {
|
|
277
|
-
_loop_1(i);
|
|
278
|
-
}
|
|
279
|
-
return { path: path, index: index, params: params };
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Escape a regular expression string.
|
|
284
|
-
*/
|
|
285
|
-
function escapeString(str) {
|
|
286
|
-
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Get the flags for a regexp from the options.
|
|
290
|
-
*/
|
|
291
|
-
function flags(options) {
|
|
292
|
-
return options && options.sensitive ? "" : "i";
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Pull out keys from a regexp.
|
|
296
|
-
*/
|
|
297
|
-
function regexpToRegexp(path, keys) {
|
|
298
|
-
if (!keys)
|
|
299
|
-
return path;
|
|
300
|
-
// Use a negative lookahead to match only capturing groups.
|
|
301
|
-
var groups = path.source.match(/\((?!\?)/g);
|
|
302
|
-
if (groups) {
|
|
303
|
-
for (var i = 0; i < groups.length; i++) {
|
|
304
|
-
keys.push({
|
|
305
|
-
name: i,
|
|
306
|
-
prefix: "",
|
|
307
|
-
suffix: "",
|
|
308
|
-
modifier: "",
|
|
309
|
-
pattern: ""
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return path;
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Transform an array into a regexp.
|
|
317
|
-
*/
|
|
318
|
-
function arrayToRegexp(paths, keys, options) {
|
|
319
|
-
var parts = paths.map(function (path) { return pathToRegexp(path, keys, options).source; });
|
|
320
|
-
return new RegExp("(?:" + parts.join("|") + ")", flags(options));
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Create a path regexp from string input.
|
|
324
|
-
*/
|
|
325
|
-
function stringToRegexp(path, keys, options) {
|
|
326
|
-
return tokensToRegexp(parse(path, options), keys, options);
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* Expose a function for taking tokens and returning a RegExp.
|
|
330
|
-
*/
|
|
331
|
-
function tokensToRegexp(tokens, keys, options) {
|
|
332
|
-
if (options === void 0) { options = {}; }
|
|
333
|
-
var _a = options.strict, strict = _a === void 0 ? false : _a, _b = options.start, start = _b === void 0 ? true : _b, _c = options.end, end = _c === void 0 ? true : _c, _d = options.encode, encode = _d === void 0 ? function (x) { return x; } : _d;
|
|
334
|
-
var endsWith = "[" + escapeString(options.endsWith || "") + "]|$";
|
|
335
|
-
var delimiter = "[" + escapeString(options.delimiter || "/#?") + "]";
|
|
336
|
-
var route = start ? "^" : "";
|
|
337
|
-
// Iterate over the tokens and create our regexp string.
|
|
338
|
-
for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) {
|
|
339
|
-
var token = tokens_1[_i];
|
|
340
|
-
if (typeof token === "string") {
|
|
341
|
-
route += escapeString(encode(token));
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
var prefix = escapeString(encode(token.prefix));
|
|
345
|
-
var suffix = escapeString(encode(token.suffix));
|
|
346
|
-
if (token.pattern) {
|
|
347
|
-
if (keys)
|
|
348
|
-
keys.push(token);
|
|
349
|
-
if (prefix || suffix) {
|
|
350
|
-
if (token.modifier === "+" || token.modifier === "*") {
|
|
351
|
-
var mod = token.modifier === "*" ? "?" : "";
|
|
352
|
-
route += "(?:" + prefix + "((?:" + token.pattern + ")(?:" + suffix + prefix + "(?:" + token.pattern + "))*)" + suffix + ")" + mod;
|
|
353
|
-
}
|
|
354
|
-
else {
|
|
355
|
-
route += "(?:" + prefix + "(" + token.pattern + ")" + suffix + ")" + token.modifier;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
route += "(" + token.pattern + ")" + token.modifier;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
route += "(?:" + prefix + suffix + ")" + token.modifier;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
if (end) {
|
|
368
|
-
if (!strict)
|
|
369
|
-
route += delimiter + "?";
|
|
370
|
-
route += !options.endsWith ? "$" : "(?=" + endsWith + ")";
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
373
|
-
var endToken = tokens[tokens.length - 1];
|
|
374
|
-
var isEndDelimited = typeof endToken === "string"
|
|
375
|
-
? delimiter.indexOf(endToken[endToken.length - 1]) > -1
|
|
376
|
-
: // tslint:disable-next-line
|
|
377
|
-
endToken === undefined;
|
|
378
|
-
if (!strict) {
|
|
379
|
-
route += "(?:" + delimiter + "(?=" + endsWith + "))?";
|
|
380
|
-
}
|
|
381
|
-
if (!isEndDelimited) {
|
|
382
|
-
route += "(?=" + delimiter + "|" + endsWith + ")";
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
return new RegExp(route, flags(options));
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Normalize the given path string, returning a regular expression.
|
|
389
|
-
*
|
|
390
|
-
* An empty array can be passed in for the keys, which will hold the
|
|
391
|
-
* placeholder key descriptions. For example, using `/user/:id`, `keys` will
|
|
392
|
-
* contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
|
|
393
|
-
*/
|
|
394
|
-
function pathToRegexp(path, keys, options) {
|
|
395
|
-
if (path instanceof RegExp)
|
|
396
|
-
return regexpToRegexp(path, keys);
|
|
397
|
-
if (Array.isArray(path))
|
|
398
|
-
return arrayToRegexp(path, keys, options);
|
|
399
|
-
return stringToRegexp(path, keys, options);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
var pathToRegex = /*#__PURE__*/Object.freeze({
|
|
403
|
-
__proto__: null,
|
|
404
|
-
parse: parse,
|
|
405
|
-
compile: compile,
|
|
406
|
-
tokensToFunction: tokensToFunction,
|
|
407
|
-
match: match,
|
|
408
|
-
regexpToFunction: regexpToFunction,
|
|
409
|
-
tokensToRegexp: tokensToRegexp,
|
|
410
|
-
pathToRegexp: pathToRegexp
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
const match$1 = undefined;
|
|
414
|
-
|
|
415
|
-
const decode = decodeURIComponent;
|
|
416
|
-
|
|
417
|
-
// This returns false if the path does not match the query
|
|
418
|
-
var params = (query, path) => match$1(query, { decode })(path).params || false;
|
|
419
|
-
|
|
420
|
-
// Put an undetermined number of callbacks together
|
|
421
|
-
// Stops when one of them returns something
|
|
422
|
-
var reduce = (...cbs) => {
|
|
423
|
-
const handlers = cbs.flat(Infinity);
|
|
424
|
-
|
|
425
|
-
return async (ctx) => {
|
|
426
|
-
try {
|
|
427
|
-
for (let cb of handlers) {
|
|
428
|
-
const data = await cb(ctx);
|
|
429
|
-
if (data) return data;
|
|
430
|
-
}
|
|
431
|
-
} catch (error) {
|
|
432
|
-
return error;
|
|
433
|
-
}
|
|
434
|
-
};
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
var parser = (path, ...cbs) => {
|
|
438
|
-
// Accept a path first and then a list of callbacks
|
|
439
|
-
if (typeof path !== "string") {
|
|
440
|
-
cbs.unshift(path);
|
|
441
|
-
path = false;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
return [path, reduce(cbs)];
|
|
445
|
-
};
|
|
446
|
-
|
|
447
|
-
// Normalize the reply to return always an object in the same format
|
|
448
|
-
const cors = {
|
|
449
|
-
"Access-Control-Allow-Origin": "*",
|
|
450
|
-
"Access-Control-Allow-Headers":
|
|
451
|
-
"Authorization, Origin, X-Requested-With, Content-Type, Accept",
|
|
452
|
-
"Access-Control-Allow-Methods": "GET, PUT, PATCH, POST, DELETE, HEAD",
|
|
453
|
-
};
|
|
454
|
-
|
|
455
|
-
// https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_request_setheader_name_value
|
|
456
|
-
// "Use an array of strings here to send multiple headers with the same name"
|
|
457
|
-
const generateCookies = (cookies) => {
|
|
458
|
-
return Object.entries(cookies).map((p) => p.join("="));
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
var reply = async (handler, ctx) => {
|
|
462
|
-
const data = await handler(ctx);
|
|
463
|
-
const headers = {};
|
|
464
|
-
if (ctx.options.cors === true) {
|
|
465
|
-
for (let key in cors) {
|
|
466
|
-
headers[key] = cors[key];
|
|
467
|
-
}
|
|
468
|
-
// Quick reply for the OPTIONS CORS
|
|
469
|
-
if (ctx.method === "OPTIONS") {
|
|
470
|
-
return { body: "", headers, status: 200 };
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// Did no throw, but did not resolve === not found
|
|
475
|
-
if (!data) return { body: "Not found", headers, status: 404 };
|
|
476
|
-
|
|
477
|
-
// The function means the hanlder knows what it's doing and wants a raw reply
|
|
478
|
-
if (typeof data === "function") {
|
|
479
|
-
const reply = await data(ctx);
|
|
480
|
-
if (reply.cookies) {
|
|
481
|
-
headers["set-cookie"] = generateCookies(reply.cookies);
|
|
482
|
-
}
|
|
483
|
-
return { ...reply, status: 200, headers: { ...reply.headers, ...headers } };
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// A plain string response
|
|
487
|
-
if (typeof data === "string") return { body: data, headers, status: 200 };
|
|
488
|
-
|
|
489
|
-
// A status number response
|
|
490
|
-
if (typeof data === "number") return { body: "", headers, status: data };
|
|
491
|
-
|
|
492
|
-
// Most basic of error handling, anything higher level should be on user code
|
|
493
|
-
if (data instanceof Error) {
|
|
494
|
-
console.error(data);
|
|
495
|
-
return { status: data.status || 500, headers, body: data.message };
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// Treat it as a plain object
|
|
499
|
-
return {
|
|
500
|
-
body: JSON.stringify(data),
|
|
501
|
-
status: data.status || 200,
|
|
502
|
-
headers: { ...headers, "content-type": "application/json" },
|
|
503
|
-
};
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
const decode$1 = str => {
|
|
507
|
-
try {
|
|
508
|
-
return decodeURIComponent(str).catch(err => str);
|
|
509
|
-
} catch (e) {
|
|
510
|
-
return str;
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
// Extracted originally from npm's "cookie"
|
|
515
|
-
const parse$1 = str => {
|
|
516
|
-
if (typeof str !== "string") {
|
|
517
|
-
throw new TypeError("argument str must be a string");
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
return str.split(/; */).reduce((cookies, pair) => {
|
|
521
|
-
const eq_idx = pair.indexOf("=");
|
|
522
|
-
|
|
523
|
-
// skip things that don't look like key=value
|
|
524
|
-
if (eq_idx < 0) return cookies;
|
|
525
|
-
|
|
526
|
-
const key = pair.substr(0, eq_idx).trim();
|
|
527
|
-
const val = pair.substr(eq_idx + 1).trim();
|
|
528
|
-
|
|
529
|
-
// unquote any quoted value
|
|
530
|
-
if ('"' == val[0]) {
|
|
531
|
-
val = val.slice(1, -1);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// only assign once; the first time
|
|
535
|
-
if (undefined == cookies[key]) {
|
|
536
|
-
cookies[key] = decode$1(val);
|
|
537
|
-
}
|
|
538
|
-
return cookies;
|
|
539
|
-
}, {});
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
var cookieParser = ctx => {
|
|
543
|
-
ctx.cookies = {};
|
|
544
|
-
if (!ctx.headers.cookie) return;
|
|
545
|
-
ctx.cookies = parse$1(ctx.headers.cookie);
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
var fileUpload = async (ctx) => {
|
|
549
|
-
// These cannot have a body at all, so don't even attempt it
|
|
550
|
-
if (ctx.method === "GET" || ctx.method === "DELETE") return;
|
|
551
|
-
|
|
552
|
-
// Extensions by default are nice
|
|
553
|
-
const form = new formidable.IncomingForm({ keepExtensions: true });
|
|
554
|
-
|
|
555
|
-
await new Promise((done, fail) => {
|
|
556
|
-
form.parse(ctx.req, (err, fields, files) => {
|
|
557
|
-
if (err) fail(err);
|
|
558
|
-
ctx.body = fields;
|
|
559
|
-
ctx.files = {};
|
|
560
|
-
for (let file in files) {
|
|
561
|
-
ctx.files[file] = {
|
|
562
|
-
path: files[file].path,
|
|
563
|
-
name: files[file].name,
|
|
564
|
-
type: files[file].type,
|
|
565
|
-
size: files[file].size,
|
|
566
|
-
modified: files[file].lastModifiedDate,
|
|
567
|
-
};
|
|
568
|
-
}
|
|
569
|
-
done();
|
|
570
|
-
});
|
|
571
|
-
});
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
const decode$2 = decodeURIComponent;
|
|
575
|
-
|
|
576
|
-
// Parse the query from the url (without the `?`)
|
|
577
|
-
const parseQuery = (query = "") => {
|
|
578
|
-
return query
|
|
579
|
-
.replace(/^\?/, "")
|
|
580
|
-
.split("&")
|
|
581
|
-
.filter(Boolean)
|
|
582
|
-
.map((p) => p.split("="))
|
|
583
|
-
.reduce((all, [key, val]) => ({ ...all, [decode$2(key)]: decode$2(val) }), {});
|
|
584
|
-
};
|
|
585
|
-
|
|
586
|
-
// Available in Node globally since 10.0.0
|
|
587
|
-
// https://nodejs.org/api/globals.html#globals_url
|
|
588
|
-
var urlParser = (ctx) => {
|
|
589
|
-
const url = new URL(ctx.url);
|
|
590
|
-
ctx.protocol = url.protocol;
|
|
591
|
-
ctx.host = url.host;
|
|
592
|
-
ctx.port = url.port;
|
|
593
|
-
ctx.hostname = url.hostname;
|
|
594
|
-
ctx.password = url.password;
|
|
595
|
-
ctx.username = url.username;
|
|
596
|
-
ctx.origin = url.origin;
|
|
597
|
-
ctx.path = url.pathname;
|
|
598
|
-
ctx.query = parseQuery(url.search);
|
|
599
|
-
};
|
|
600
|
-
|
|
601
|
-
var middle = [urlParser, fileUpload, cookieParser];
|
|
602
|
-
|
|
603
|
-
const runtime = "node";
|
|
604
|
-
|
|
605
|
-
const getUrl = ({ protocol = "http", headers, url = "/" }) => {
|
|
606
|
-
return protocol + "://" + headers["host"] + url;
|
|
607
|
-
};
|
|
608
|
-
|
|
609
|
-
// https://stackoverflow.com/a/19524949/938236
|
|
610
|
-
const getIp = (req) => {
|
|
611
|
-
return (
|
|
612
|
-
(req.headers["x-forwarded-for"] || "").split(",").pop() ||
|
|
613
|
-
req.connection.remoteAddress ||
|
|
614
|
-
req.socket.remoteAddress ||
|
|
615
|
-
req.connection.socket.remoteAddress
|
|
616
|
-
);
|
|
617
|
-
};
|
|
618
|
-
|
|
619
|
-
// Launch the server for the Node.js environment
|
|
620
|
-
var node = async (handler, options = {}) => {
|
|
621
|
-
const compress = (data, headers) => {
|
|
622
|
-
// Don't compress it if it's tiny
|
|
623
|
-
if (data.length < 1000) {
|
|
624
|
-
return data;
|
|
625
|
-
}
|
|
626
|
-
headers["Content-Encoding"] = "gzip";
|
|
627
|
-
return new Promise((done, fail) => {
|
|
628
|
-
const buffer = Buffer.from(data || "", "utf-8");
|
|
629
|
-
zlib.gzip(buffer, (error, result) => {
|
|
630
|
-
if (error) return fail(error);
|
|
631
|
-
return done(result);
|
|
632
|
-
});
|
|
633
|
-
});
|
|
634
|
-
};
|
|
635
|
-
|
|
636
|
-
const server = http.createServer(async (req, res) => {
|
|
637
|
-
// Handle each of the API calls here:
|
|
638
|
-
const { status = 200, body = "", headers = {} } = await handler({
|
|
639
|
-
url: getUrl(req),
|
|
640
|
-
method: req.method,
|
|
641
|
-
headers: req.headers,
|
|
642
|
-
ip: getIp(req),
|
|
643
|
-
runtime,
|
|
644
|
-
req,
|
|
645
|
-
options,
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
res.statusCode = status;
|
|
649
|
-
const compressed = await compress(body, headers);
|
|
650
|
-
for (let key in headers) {
|
|
651
|
-
// https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_request_setheader_name_value
|
|
652
|
-
// "Use an array of strings here to send multiple headers with the same name"
|
|
653
|
-
res.setHeader(key, headers[key]);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
res.end(compressed);
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
return new Promise((resolve, reject) => {
|
|
660
|
-
server.listen(options.port, (error) => {
|
|
661
|
-
if (error) reject(error);
|
|
662
|
-
resolve({ options, handler, runtime, close: () => server.close() });
|
|
663
|
-
});
|
|
664
|
-
});
|
|
665
|
-
};
|
|
666
|
-
|
|
667
|
-
var index = (...args) => {
|
|
668
|
-
const [path, handler] = parser(...args);
|
|
669
|
-
|
|
670
|
-
return (ctx) => {
|
|
671
|
-
// The parameters are defined only if the path matches the query
|
|
672
|
-
ctx.params = params(path, ctx.path);
|
|
673
|
-
|
|
674
|
-
// Run this handler only if it's the right path
|
|
675
|
-
if (ctx.params) {
|
|
676
|
-
return handler(ctx);
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
};
|
|
680
|
-
|
|
681
|
-
var index$1 = (...args) => {
|
|
682
|
-
const [path, handler] = parser(...args);
|
|
683
|
-
|
|
684
|
-
return (ctx) => {
|
|
685
|
-
// The parameters are defined only if the path matches the query
|
|
686
|
-
ctx.params = params(path, ctx.path);
|
|
687
|
-
|
|
688
|
-
// Run this handler only if it's the right method and path
|
|
689
|
-
if (ctx.method === "DELETE" && ctx.params) {
|
|
690
|
-
return handler(ctx);
|
|
691
|
-
}
|
|
692
|
-
};
|
|
693
|
-
};
|
|
694
|
-
|
|
695
|
-
var index$2 = (...args) => {
|
|
696
|
-
const [path, handler] = parser(...args);
|
|
697
|
-
|
|
698
|
-
return (ctx) => {
|
|
699
|
-
// The parameters are defined only if the path matches the query
|
|
700
|
-
ctx.params = params(path, ctx.path);
|
|
701
|
-
|
|
702
|
-
// Run this handler only if it's the right method and path
|
|
703
|
-
if (ctx.method === "GET" && ctx.params) {
|
|
704
|
-
return handler(ctx);
|
|
705
|
-
}
|
|
706
|
-
};
|
|
707
|
-
};
|
|
708
|
-
|
|
709
|
-
var index$3 = (...args) => {
|
|
710
|
-
const [path, handler] = parser(...args);
|
|
711
|
-
|
|
712
|
-
return (ctx) => {
|
|
713
|
-
// The parameters are defined only if the path matches the query
|
|
714
|
-
ctx.params = params(path, ctx.path);
|
|
715
|
-
|
|
716
|
-
// Run this handler only if it's the right method and path
|
|
717
|
-
if (ctx.method === "HEAD" && ctx.params) {
|
|
718
|
-
return handler(ctx);
|
|
719
|
-
}
|
|
720
|
-
};
|
|
721
|
-
};
|
|
722
|
-
|
|
723
|
-
var index$4 = (...args) => {
|
|
724
|
-
const [path, handler] = parser(...args);
|
|
725
|
-
|
|
726
|
-
return (ctx) => {
|
|
727
|
-
// The parameters are defined only if the path matches the query
|
|
728
|
-
ctx.params = params(path, ctx.path);
|
|
729
|
-
|
|
730
|
-
// Run this handler only if it's the right method and path
|
|
731
|
-
if (ctx.method === "OPTIONS" && ctx.params) {
|
|
732
|
-
return handler(ctx);
|
|
733
|
-
}
|
|
734
|
-
};
|
|
735
|
-
};
|
|
736
|
-
|
|
737
|
-
var index$5 = (...args) => {
|
|
738
|
-
const [path, handler] = parser(...args);
|
|
739
|
-
|
|
740
|
-
return (ctx) => {
|
|
741
|
-
// The parameters are defined only if the path matches the query
|
|
742
|
-
ctx.params = params(path, ctx.path);
|
|
743
|
-
|
|
744
|
-
// Run this handler only if it's the right method and path
|
|
745
|
-
if (ctx.method === "PATCH" && ctx.params) {
|
|
746
|
-
return handler(ctx);
|
|
747
|
-
}
|
|
748
|
-
};
|
|
749
|
-
};
|
|
750
|
-
|
|
751
|
-
var index$6 = (...args) => {
|
|
752
|
-
const [path, handler] = parser(...args);
|
|
753
|
-
|
|
754
|
-
return (ctx) => {
|
|
755
|
-
// The parameters are defined only if the path matches the query
|
|
756
|
-
ctx.params = params(path, ctx.path);
|
|
757
|
-
|
|
758
|
-
// Run this handler only if it's the right method and path
|
|
759
|
-
if (ctx.method === "POST" && ctx.params) {
|
|
760
|
-
return handler(ctx);
|
|
761
|
-
}
|
|
762
|
-
};
|
|
763
|
-
};
|
|
764
|
-
|
|
765
|
-
var index$7 = (...args) => {
|
|
766
|
-
const [path, handler] = parser(...args);
|
|
767
|
-
|
|
768
|
-
return (ctx) => {
|
|
769
|
-
// The parameters are defined only if the path matches the query
|
|
770
|
-
ctx.params = params(path, ctx.path);
|
|
771
|
-
|
|
772
|
-
// Run this handler only if it's the right method and path
|
|
773
|
-
if (ctx.method === "PUT" && ctx.params) {
|
|
774
|
-
return handler(ctx);
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
};
|
|
778
|
-
|
|
779
|
-
// Some other, non-HTTP methods but routers nonetheless
|
|
780
|
-
// export { default as socket } from "./socket";
|
|
781
|
-
// export { default as domain } from "./domain";
|
|
782
|
-
|
|
783
|
-
// The main function that runs the whole thing
|
|
784
|
-
var index$8 = async (options = {}, ...middleware) => {
|
|
785
|
-
if (typeof options === "function") {
|
|
786
|
-
middleware.unshift(options);
|
|
787
|
-
options = {};
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
const engine = options.engine || node;
|
|
791
|
-
|
|
792
|
-
// Generate a single callback with all the middleware
|
|
793
|
-
const handler = reduce(middle, middleware);
|
|
794
|
-
|
|
795
|
-
return engine((ctx) => reply(handler, ctx), options);
|
|
796
|
-
};
|
|
797
|
-
|
|
798
|
-
export default index$8;
|
|
799
|
-
export { index as any, index$1 as del, index$2 as get, index$3 as head, index$4 as options, index$5 as patch, index$6 as post, index$7 as put };
|