@server/next 0.12.1 → 0.15.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/package.json +29 -51
- package/readme.md +66 -67
- package/src/RequestLogger.js +77 -0
- package/src/ServerUrl.js +32 -0
- package/src/ServerUrl.test.js +45 -0
- package/src/color.js +26 -0
- package/src/index.js +280 -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 -515
package/index.js
DELETED
|
@@ -1,515 +0,0 @@
|
|
|
1
|
-
var params = (query, path) => {
|
|
2
|
-
// They are different and there's no matching in the query
|
|
3
|
-
if (!/\:/.test(query) && query !== path) return;
|
|
4
|
-
|
|
5
|
-
// If one fails, fail it all
|
|
6
|
-
return (
|
|
7
|
-
query.split("/").reduce((params, part, i) => {
|
|
8
|
-
if (!params) return;
|
|
9
|
-
const value = path.split("/")[i];
|
|
10
|
-
|
|
11
|
-
// If there's no param in this segment, value has to match exactly
|
|
12
|
-
if (!/^\:/.test(part)) return part === value ? params : false;
|
|
13
|
-
|
|
14
|
-
const name = part.replace(/^\:/, "");
|
|
15
|
-
if (!value) return;
|
|
16
|
-
params[name] = value;
|
|
17
|
-
return params;
|
|
18
|
-
}, {}) || false
|
|
19
|
-
);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// Put an undetermined number of callbacks together
|
|
23
|
-
// Stops when one of them returns something
|
|
24
|
-
var reduce = (...cbs) => {
|
|
25
|
-
const handlers = cbs.flat(Infinity);
|
|
26
|
-
|
|
27
|
-
return async ctx => {
|
|
28
|
-
try {
|
|
29
|
-
for (let cb of handlers) {
|
|
30
|
-
const data = await cb(ctx);
|
|
31
|
-
if (data) return data;
|
|
32
|
-
}
|
|
33
|
-
} catch (error) {
|
|
34
|
-
return error;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Normalize the reply to return always an object in the same format
|
|
40
|
-
const cors = {
|
|
41
|
-
"Access-Control-Allow-Origin": "*",
|
|
42
|
-
"Access-Control-Allow-Headers":
|
|
43
|
-
"Authorization, Origin, X-Requested-With, Content-Type, Accept",
|
|
44
|
-
"Access-Control-Allow-Methods": "GET, PUT, PATCH, POST, DELETE, HEAD"
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_request_setheader_name_value
|
|
48
|
-
// "Use an array of strings here to send multiple headers with the same name"
|
|
49
|
-
const generateCookies = cookies => {
|
|
50
|
-
return Object.entries(cookies).map(p => p.join("="));
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
var reply = async (handler, ctx) => {
|
|
54
|
-
const data = await handler(ctx);
|
|
55
|
-
const headers = {};
|
|
56
|
-
if (ctx.options.cors === true) {
|
|
57
|
-
for (let key in cors) {
|
|
58
|
-
headers[key] = cors[key];
|
|
59
|
-
}
|
|
60
|
-
// Quick reply for the OPTIONS CORS
|
|
61
|
-
if (ctx.method === "OPTIONS") {
|
|
62
|
-
return { body: "", headers, status: 200 };
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Did no throw, but did not resolve === not found
|
|
67
|
-
if (!data) return { body: "Not found", headers, status: 404 };
|
|
68
|
-
|
|
69
|
-
// The function means the hanlder knows what it's doing and wants a raw reply
|
|
70
|
-
if (typeof data === "function") {
|
|
71
|
-
const reply = await data(ctx);
|
|
72
|
-
if (reply.cookies) {
|
|
73
|
-
headers["set-cookie"] = generateCookies(reply.cookies);
|
|
74
|
-
}
|
|
75
|
-
return { ...reply, status: 200, headers: { ...reply.headers, ...headers } };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// A plain string response
|
|
79
|
-
if (typeof data === "string") return { body: data, headers, status: 200 };
|
|
80
|
-
|
|
81
|
-
// A status number response
|
|
82
|
-
if (typeof data === "number") return { body: "", headers, status: data };
|
|
83
|
-
|
|
84
|
-
// Most basic of error handling, anything higher level should be on user code
|
|
85
|
-
if (data instanceof Error) {
|
|
86
|
-
return { status: data.status || 500, headers, body: data.message };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Treat it as a plain object
|
|
90
|
-
return {
|
|
91
|
-
body: JSON.stringify(data),
|
|
92
|
-
status: data.status || 200,
|
|
93
|
-
headers: { ...headers, "content-type": "application/json" }
|
|
94
|
-
};
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// Node native body parser
|
|
98
|
-
const parseBody = async req => {
|
|
99
|
-
return new Promise((done, fail) => {
|
|
100
|
-
const type = req.headers["content-type"];
|
|
101
|
-
const parser = /application\/json/.test(type)
|
|
102
|
-
? data => JSON.parse(data)
|
|
103
|
-
: data => data;
|
|
104
|
-
const data = [];
|
|
105
|
-
req
|
|
106
|
-
.on("data", chunk => {
|
|
107
|
-
data.push(chunk);
|
|
108
|
-
})
|
|
109
|
-
.on("end", () => {
|
|
110
|
-
const raw = Buffer.concat(data).toString();
|
|
111
|
-
try {
|
|
112
|
-
done(parser(raw));
|
|
113
|
-
} catch (error) {
|
|
114
|
-
fail(error);
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
.on("error", fail);
|
|
118
|
-
});
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
// Cloudflare body parser as https://developers.cloudflare.com/workers/templates/snippets/post_data/
|
|
122
|
-
async function readRequestBody(request) {
|
|
123
|
-
const { headers } = request;
|
|
124
|
-
const contentType = headers.get("content-type") || "text/html";
|
|
125
|
-
if (contentType.includes("application/json")) {
|
|
126
|
-
const body = await request.json();
|
|
127
|
-
return JSON.stringify(body);
|
|
128
|
-
} else if (contentType.includes("application/text")) {
|
|
129
|
-
const body = await request.text();
|
|
130
|
-
return body;
|
|
131
|
-
} else if (contentType.includes("text/html")) {
|
|
132
|
-
const body = await request.text();
|
|
133
|
-
return body;
|
|
134
|
-
} else if (contentType.includes("form")) {
|
|
135
|
-
const formData = await request.formData();
|
|
136
|
-
let body = {};
|
|
137
|
-
for (let entry of formData.entries()) {
|
|
138
|
-
body[entry[0]] = entry[1];
|
|
139
|
-
}
|
|
140
|
-
return JSON.stringify(body);
|
|
141
|
-
} else {
|
|
142
|
-
let myBlob = await request.blob();
|
|
143
|
-
var objectURL = URL.createObjectURL(myBlob);
|
|
144
|
-
return objectURL;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
var bodyParser = async ctx => {
|
|
149
|
-
// No parsing for now
|
|
150
|
-
if (!ctx.req) return;
|
|
151
|
-
|
|
152
|
-
// Parsing it out of the request's text() method
|
|
153
|
-
if (ctx.req.text) {
|
|
154
|
-
ctx.body = await readRequestBody(ctx.req);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
ctx.body = await parseBody(ctx.req);
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const decode = str => {
|
|
161
|
-
try {
|
|
162
|
-
return decodeURIComponent(str).catch(err => str);
|
|
163
|
-
} catch (e) {
|
|
164
|
-
return str;
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
// Extracted originally from npm's "cookie"
|
|
169
|
-
const parse = str => {
|
|
170
|
-
if (typeof str !== "string") {
|
|
171
|
-
throw new TypeError("argument str must be a string");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return str.split(/; */).reduce((cookies, pair) => {
|
|
175
|
-
const eq_idx = pair.indexOf("=");
|
|
176
|
-
|
|
177
|
-
// skip things that don't look like key=value
|
|
178
|
-
if (eq_idx < 0) return cookies;
|
|
179
|
-
|
|
180
|
-
const key = pair.substr(0, eq_idx).trim();
|
|
181
|
-
const val = pair.substr(eq_idx + 1).trim();
|
|
182
|
-
|
|
183
|
-
// unquote any quoted value
|
|
184
|
-
if ('"' == val[0]) {
|
|
185
|
-
val = val.slice(1, -1);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// only assign once; the first time
|
|
189
|
-
if (undefined == cookies[key]) {
|
|
190
|
-
cookies[key] = decode(val);
|
|
191
|
-
}
|
|
192
|
-
return cookies;
|
|
193
|
-
}, {});
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
var cookieParser = ctx => {
|
|
197
|
-
ctx.cookies = {};
|
|
198
|
-
if (!ctx.headers.cookie) return;
|
|
199
|
-
ctx.cookies = parse(ctx.headers.cookie);
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
const decode$1 = decodeURIComponent;
|
|
203
|
-
|
|
204
|
-
// Parse the query from the url (without the `?`)
|
|
205
|
-
const parseQuery = (query = "") => {
|
|
206
|
-
return query
|
|
207
|
-
.replace(/^\?/, "")
|
|
208
|
-
.split("&")
|
|
209
|
-
.filter(Boolean)
|
|
210
|
-
.map(p => p.split("="))
|
|
211
|
-
.reduce((all, [key, val]) => ({ ...all, [decode$1(key)]: decode$1(val) }), {});
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// Available in Node globally since 10.0.0
|
|
215
|
-
// https://nodejs.org/api/globals.html#globals_url
|
|
216
|
-
var urlParser = ctx => {
|
|
217
|
-
const url = new URL(ctx.url);
|
|
218
|
-
ctx.protocol = url.protocol;
|
|
219
|
-
ctx.host = url.host;
|
|
220
|
-
ctx.port = url.port;
|
|
221
|
-
ctx.hostname = url.hostname;
|
|
222
|
-
ctx.password = url.password;
|
|
223
|
-
ctx.username = url.username;
|
|
224
|
-
ctx.origin = url.origin;
|
|
225
|
-
ctx.path = url.pathname;
|
|
226
|
-
ctx.query = parseQuery(url.search);
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
var middle = [urlParser, bodyParser, cookieParser];
|
|
230
|
-
|
|
231
|
-
const runtime = "node";
|
|
232
|
-
|
|
233
|
-
const getUrl = ({ protocol = "http", headers, url = "/" }) => {
|
|
234
|
-
return protocol + "://" + headers["host"] + url;
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
// https://stackoverflow.com/a/19524949/938236
|
|
238
|
-
const getIp = req => {
|
|
239
|
-
return (
|
|
240
|
-
(req.headers["x-forwarded-for"] || "").split(",").pop() ||
|
|
241
|
-
req.connection.remoteAddress ||
|
|
242
|
-
req.socket.remoteAddress ||
|
|
243
|
-
req.connection.socket.remoteAddress
|
|
244
|
-
);
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
// Launch the server for the Node.js environment
|
|
248
|
-
var node = async (handler, options = {}) => {
|
|
249
|
-
// This code runs ONE time on the first cold start, and we know that it runs
|
|
250
|
-
// in the Node.js environment. So we can import Node.js libraries here safely
|
|
251
|
-
const [http, zlib] = await Promise.all([import('http'), import('zlib')]);
|
|
252
|
-
|
|
253
|
-
const compress = (data, headers) => {
|
|
254
|
-
// Don't compress it if it's tiny
|
|
255
|
-
if (data.length < 1000) {
|
|
256
|
-
return data;
|
|
257
|
-
}
|
|
258
|
-
headers["Content-Encoding"] = "gzip";
|
|
259
|
-
return new Promise((done, fail) => {
|
|
260
|
-
const buffer = Buffer.from(data || "", "utf-8");
|
|
261
|
-
zlib.gzip(buffer, (error, result) => {
|
|
262
|
-
if (error) return fail(error);
|
|
263
|
-
return done(result);
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
const server = http.createServer(async (req, res) => {
|
|
269
|
-
// Handle each of the API calls here:
|
|
270
|
-
const { status = 200, body = "", headers = {} } = await handler({
|
|
271
|
-
url: getUrl(req),
|
|
272
|
-
method: req.method,
|
|
273
|
-
headers: req.headers,
|
|
274
|
-
ip: getIp(req),
|
|
275
|
-
runtime,
|
|
276
|
-
req
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
res.statusCode = status;
|
|
280
|
-
const compressed = await compress(body, headers);
|
|
281
|
-
for (let key in headers) {
|
|
282
|
-
// https://nodejs.org/dist/latest-v12.x/docs/api/http.html#http_request_setheader_name_value
|
|
283
|
-
// "Use an array of strings here to send multiple headers with the same name"
|
|
284
|
-
res.setHeader(key, headers[key]);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
res.end(compressed);
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
return new Promise((resolve, reject) => {
|
|
291
|
-
server.listen(options.port, error => {
|
|
292
|
-
if (error) reject(error);
|
|
293
|
-
resolve({ options, handler, runtime, close: () => server.close() });
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
const runtime$1 = "cloudflare";
|
|
299
|
-
|
|
300
|
-
const getUrl$1 = ({ url }) => decodeURI(url);
|
|
301
|
-
|
|
302
|
-
const getIp$1 = req => req.headers.get("CF-Connecting-IP");
|
|
303
|
-
|
|
304
|
-
// At least one header has to be read first so that .entries() works
|
|
305
|
-
const getHeaders = ({ headers }) => {
|
|
306
|
-
const plain = {};
|
|
307
|
-
for (let entry of headers.entries()) {
|
|
308
|
-
headers[entry[0]] = entry[1];
|
|
309
|
-
}
|
|
310
|
-
return plain;
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
// Launch the server in a Cloudflare Worker
|
|
314
|
-
var cloudflare = (handler, options = {}) => {
|
|
315
|
-
addEventListener("fetch", e => {
|
|
316
|
-
const response = handler({
|
|
317
|
-
url: getUrl$1(e.request),
|
|
318
|
-
method: e.request.method,
|
|
319
|
-
headers: getHeaders(e.request),
|
|
320
|
-
ip: getIp$1(e.request),
|
|
321
|
-
runtime: runtime$1,
|
|
322
|
-
req: e.request
|
|
323
|
-
}).then(({ status, body, headers }) => {
|
|
324
|
-
return new Response(body, { status, headers });
|
|
325
|
-
});
|
|
326
|
-
return e.respondWith(response);
|
|
327
|
-
});
|
|
328
|
-
return Promise.resolve({ options, handler, runtime: runtime$1, close: () => {} });
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
// Loosely find which one is the correct runtime through ducktyping
|
|
332
|
-
var getEngine = () => {
|
|
333
|
-
if (typeof addEventListener !== "undefined" && typeof fetch !== "undefined") {
|
|
334
|
-
return cloudflare;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
// It is Node.js by default
|
|
338
|
-
return node;
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
var index = (path, ...cbs) => {
|
|
342
|
-
// Accept a path first and then a list of callbacks
|
|
343
|
-
if (typeof path !== "string") {
|
|
344
|
-
cbs.unshift(path);
|
|
345
|
-
path = "*";
|
|
346
|
-
}
|
|
347
|
-
const handler = reduce(cbs);
|
|
348
|
-
|
|
349
|
-
return ctx => {
|
|
350
|
-
if (path === "*") return handler(ctx);
|
|
351
|
-
|
|
352
|
-
// Make sure the URL matches
|
|
353
|
-
ctx.params = params(path, ctx.path);
|
|
354
|
-
if (!ctx.params) return;
|
|
355
|
-
return handler(ctx);
|
|
356
|
-
};
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
var index$1 = (path, ...cbs) => {
|
|
360
|
-
// Accept a path first and then a list of callbacks
|
|
361
|
-
if (typeof path !== "string") {
|
|
362
|
-
cbs.unshift(path);
|
|
363
|
-
path = "*";
|
|
364
|
-
}
|
|
365
|
-
const handler = reduce(cbs);
|
|
366
|
-
|
|
367
|
-
return ctx => {
|
|
368
|
-
if (ctx.method !== "GET") return;
|
|
369
|
-
if (path === "*") return handler(ctx);
|
|
370
|
-
|
|
371
|
-
// Make sure the URL matches
|
|
372
|
-
ctx.params = params(path, ctx.path);
|
|
373
|
-
if (!ctx.params) return;
|
|
374
|
-
return handler(ctx);
|
|
375
|
-
};
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
var index$2 = (path, ...cbs) => {
|
|
379
|
-
// Accept a path first and then a list of callbacks
|
|
380
|
-
if (typeof path !== "string") {
|
|
381
|
-
cbs.unshift(path);
|
|
382
|
-
path = "*";
|
|
383
|
-
}
|
|
384
|
-
const handler = reduce(cbs);
|
|
385
|
-
|
|
386
|
-
return ctx => {
|
|
387
|
-
if (ctx.method !== "POST") return;
|
|
388
|
-
if (path === "*") return handler(ctx);
|
|
389
|
-
|
|
390
|
-
// Make sure the URL matches
|
|
391
|
-
ctx.params = params(path, ctx.path);
|
|
392
|
-
if (!ctx.params) return;
|
|
393
|
-
return handler(ctx);
|
|
394
|
-
};
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
var index$3 = (path, ...cbs) => {
|
|
398
|
-
// Accept a path first and then a list of callbacks
|
|
399
|
-
if (typeof path !== "string") {
|
|
400
|
-
cbs.unshift(path);
|
|
401
|
-
path = "*";
|
|
402
|
-
}
|
|
403
|
-
const handler = reduce(cbs);
|
|
404
|
-
|
|
405
|
-
return ctx => {
|
|
406
|
-
if (ctx.method !== "PUT") return;
|
|
407
|
-
if (path === "*") return handler(ctx);
|
|
408
|
-
|
|
409
|
-
// Make sure the URL matches
|
|
410
|
-
ctx.params = params(path, ctx.path);
|
|
411
|
-
if (!ctx.params) return;
|
|
412
|
-
return handler(ctx);
|
|
413
|
-
};
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
var index$4 = (path, ...cbs) => {
|
|
417
|
-
// Accept a path first and then a list of callbacks
|
|
418
|
-
if (typeof path !== "string") {
|
|
419
|
-
cbs.unshift(path);
|
|
420
|
-
path = "*";
|
|
421
|
-
}
|
|
422
|
-
const handler = reduce(cbs);
|
|
423
|
-
|
|
424
|
-
return ctx => {
|
|
425
|
-
if (ctx.method !== "PATCH") return;
|
|
426
|
-
if (path === "*") return handler(ctx);
|
|
427
|
-
|
|
428
|
-
// Make sure the URL matches
|
|
429
|
-
ctx.params = params(path, ctx.path);
|
|
430
|
-
if (!ctx.params) return;
|
|
431
|
-
return handler(ctx);
|
|
432
|
-
};
|
|
433
|
-
};
|
|
434
|
-
|
|
435
|
-
var index$5 = (path, ...cbs) => {
|
|
436
|
-
// Accept a path first and then a list of callbacks
|
|
437
|
-
if (typeof path !== "string") {
|
|
438
|
-
cbs.unshift(path);
|
|
439
|
-
path = "*";
|
|
440
|
-
}
|
|
441
|
-
const handler = reduce(cbs);
|
|
442
|
-
|
|
443
|
-
return ctx => {
|
|
444
|
-
if (ctx.method !== "DELETE") return;
|
|
445
|
-
if (path === "*") return handler(ctx);
|
|
446
|
-
|
|
447
|
-
// Make sure the URL matches
|
|
448
|
-
ctx.params = params(path, ctx.path);
|
|
449
|
-
if (!ctx.params) return;
|
|
450
|
-
return handler(ctx);
|
|
451
|
-
};
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
var index$6 = (path, ...cbs) => {
|
|
455
|
-
// Accept a path first and then a list of callbacks
|
|
456
|
-
if (typeof path !== "string") {
|
|
457
|
-
cbs.unshift(path);
|
|
458
|
-
path = "*";
|
|
459
|
-
}
|
|
460
|
-
const handler = reduce(cbs);
|
|
461
|
-
|
|
462
|
-
return ctx => {
|
|
463
|
-
if (ctx.method !== "HEAD") return;
|
|
464
|
-
if (path === "*") return handler(ctx);
|
|
465
|
-
|
|
466
|
-
// Make sure the URL matches
|
|
467
|
-
ctx.params = params(path, ctx.path);
|
|
468
|
-
if (!ctx.params) return;
|
|
469
|
-
return handler(ctx);
|
|
470
|
-
};
|
|
471
|
-
};
|
|
472
|
-
|
|
473
|
-
var index$7 = (path, ...cbs) => {
|
|
474
|
-
// Accept a path first and then a list of callbacks
|
|
475
|
-
if (typeof path !== "string") {
|
|
476
|
-
cbs.unshift(path);
|
|
477
|
-
path = "*";
|
|
478
|
-
}
|
|
479
|
-
const handler = reduce(cbs);
|
|
480
|
-
|
|
481
|
-
return ctx => {
|
|
482
|
-
if (ctx.method !== "OPTIONS") return;
|
|
483
|
-
if (path === "*") return handler(ctx);
|
|
484
|
-
|
|
485
|
-
// Make sure the URL matches
|
|
486
|
-
ctx.params = params(path, ctx.path);
|
|
487
|
-
if (!ctx.params) return;
|
|
488
|
-
return handler(ctx);
|
|
489
|
-
};
|
|
490
|
-
};
|
|
491
|
-
|
|
492
|
-
// Some other, non-HTTP methods but routers nonetheless
|
|
493
|
-
// export { default as socket } from "./socket";
|
|
494
|
-
// export { default as domain } from "./domain";
|
|
495
|
-
|
|
496
|
-
// The main function that runs the whole thing
|
|
497
|
-
var index$8 = async (options = {}, ...middleware) => {
|
|
498
|
-
if (typeof options === "function") {
|
|
499
|
-
middleware.unshift(options);
|
|
500
|
-
options = { port: 3000 };
|
|
501
|
-
}
|
|
502
|
-
options.engine = options.engine || getEngine();
|
|
503
|
-
|
|
504
|
-
const addOptions = ctx => {
|
|
505
|
-
ctx.options = options;
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
// Generate a single callback with all the middleware
|
|
509
|
-
const callback = reduce(addOptions, middle, middleware);
|
|
510
|
-
|
|
511
|
-
return options.engine(ctx => reply(callback, ctx), options);
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
export default index$8;
|
|
515
|
-
export { index as any, index$5 as del, index$1 as get, index$6 as head, index$7 as options, index$4 as patch, index$2 as post, index$3 as put };
|