@wooksjs/event-http 0.5.20 → 0.6.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/LICENSE +21 -0
- package/dist/index.cjs +1118 -954
- package/dist/index.d.ts +38 -293
- package/dist/index.mjs +1060 -925
- package/package.json +12 -5
package/dist/index.mjs
CHANGED
|
@@ -1,1001 +1,1136 @@
|
|
|
1
|
-
import { createAsyncEventContext, useAsyncEventContext, useEventId,
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { attachHook, createAsyncEventContext, useAsyncEventContext, useEventId, useEventLogger, useRouteParams } from "@wooksjs/event-core";
|
|
2
|
+
import { Buffer as Buffer$1 } from "buffer";
|
|
3
|
+
import { Readable, pipeline } from "node:stream";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { createBrotliCompress, createBrotliDecompress, createDeflate, createGunzip, createGzip, createInflate } from "node:zlib";
|
|
6
|
+
import { URLSearchParams } from "url";
|
|
7
|
+
import http from "http";
|
|
8
|
+
import { WooksAdapterBase } from "wooks";
|
|
9
|
+
import { Readable as Readable$1 } from "stream";
|
|
7
10
|
|
|
11
|
+
//#region packages/event-http/src/event-http.ts
|
|
8
12
|
function createHttpContext(data, options) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
return createAsyncEventContext({
|
|
14
|
+
event: {
|
|
15
|
+
...data,
|
|
16
|
+
type: "HTTP"
|
|
17
|
+
},
|
|
18
|
+
options
|
|
19
|
+
});
|
|
16
20
|
}
|
|
17
21
|
function useHttpContext() {
|
|
18
|
-
|
|
22
|
+
return useAsyncEventContext("HTTP");
|
|
19
23
|
}
|
|
20
24
|
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region packages/event-http/src/utils/helpers.ts
|
|
21
27
|
function escapeRegex(s) {
|
|
22
|
-
|
|
28
|
+
return s.replace(/[$()*+\-./?[\\\]^{|}]/gu, "\\$&");
|
|
23
29
|
}
|
|
24
30
|
function safeDecode(f, v) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
+
try {
|
|
32
|
+
return f(v);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return v;
|
|
35
|
+
}
|
|
31
36
|
}
|
|
32
37
|
function safeDecodeURIComponent(uri) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
return safeDecode(decodeURIComponent, uri);
|
|
38
|
+
if (!uri.includes("%")) return uri;
|
|
39
|
+
return safeDecode(decodeURIComponent, uri);
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
return t / units[unit];
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region packages/event-http/src/utils/time.ts
|
|
44
|
+
function convertTime(time, unit = "ms") {
|
|
45
|
+
if (typeof time === "number") return time / units[unit];
|
|
46
|
+
const rg = /(\d+)(\w+)/gu;
|
|
47
|
+
let t = 0;
|
|
48
|
+
let r;
|
|
49
|
+
while (r = rg.exec(time)) t += Number(r[1]) * (units[r[2]] || 0);
|
|
50
|
+
return t / units[unit];
|
|
50
51
|
}
|
|
51
52
|
const units = {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
ms: 1,
|
|
54
|
+
s: 1e3,
|
|
55
|
+
m: 6e4,
|
|
56
|
+
h: 36e5,
|
|
57
|
+
d: 864e5,
|
|
58
|
+
w: 6048e5,
|
|
59
|
+
M: 2592e6,
|
|
60
|
+
Y: 31536e6
|
|
60
61
|
};
|
|
61
62
|
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region packages/event-http/src/utils/set-cookie.ts
|
|
62
65
|
function renderCookie(key, data) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return `${key}=${encodeURIComponent(data.value)}${attrs}`;
|
|
66
|
+
let attrs = "";
|
|
67
|
+
for (const [a, v] of Object.entries(data.attrs)) {
|
|
68
|
+
const func = cookieAttrFunc[a];
|
|
69
|
+
if (typeof func === "function") {
|
|
70
|
+
const val = func(v);
|
|
71
|
+
attrs += val ? `; ${val}` : "";
|
|
72
|
+
} else throw new TypeError(`Unknown Set-Cookie attribute ${a}`);
|
|
73
|
+
}
|
|
74
|
+
return `${key}=${encodeURIComponent(data.value)}${attrs}`;
|
|
75
75
|
}
|
|
76
76
|
const cookieAttrFunc = {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
expires: (v) => `Expires=${typeof v === "string" || typeof v === "number" ? new Date(v).toUTCString() : v.toUTCString()}`,
|
|
78
|
+
maxAge: (v) => `Max-Age=${convertTime(v, "s").toString()}`,
|
|
79
|
+
domain: (v) => `Domain=${v}`,
|
|
80
|
+
path: (v) => `Path=${v}`,
|
|
81
|
+
secure: (v) => v ? "Secure" : "",
|
|
82
|
+
httpOnly: (v) => v ? "HttpOnly" : "",
|
|
83
|
+
sameSite: (v) => v ? `SameSite=${typeof v === "string" ? v : "Strict"}` : ""
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region packages/event-http/src/compressor/body-compressor.ts
|
|
88
|
+
const compressors = { identity: {
|
|
89
|
+
compress: (v) => v,
|
|
90
|
+
uncompress: (v) => v,
|
|
91
|
+
stream: {
|
|
92
|
+
compress: (data) => data,
|
|
93
|
+
uncompress: (data) => data
|
|
94
|
+
}
|
|
95
|
+
} };
|
|
96
|
+
function encodingSupportsStream(encodings) {
|
|
97
|
+
return encodings.every((enc) => compressors[enc]?.stream);
|
|
98
|
+
}
|
|
99
|
+
async function uncompressBody(encodings, compressed) {
|
|
100
|
+
let buf = compressed;
|
|
101
|
+
for (const enc of encodings.slice().reverse()) {
|
|
102
|
+
const c = compressors[enc];
|
|
103
|
+
if (!c) throw new Error(`Unsupported compression type "${enc}".`);
|
|
104
|
+
buf = await c.uncompress(buf);
|
|
105
|
+
}
|
|
106
|
+
return buf;
|
|
107
|
+
}
|
|
108
|
+
async function uncompressBodyStream(encodings, src) {
|
|
109
|
+
if (!encodingSupportsStream(encodings)) throw new Error("Some encodings lack a streaming decompressor");
|
|
110
|
+
let out = src;
|
|
111
|
+
for (const enc of Array.from(encodings).reverse()) out = await compressors[enc].stream.uncompress(out);
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region packages/event-http/src/compressor/zlib-compressors.ts
|
|
117
|
+
const pipeline$1 = pipeline;
|
|
118
|
+
function iterableToReadable(src) {
|
|
119
|
+
return Readable.from(src, { objectMode: false });
|
|
120
|
+
}
|
|
121
|
+
function pump(src, transform) {
|
|
122
|
+
pipeline$1(iterableToReadable(src), transform, (err) => {
|
|
123
|
+
if (err) transform.destroy(err);
|
|
124
|
+
});
|
|
125
|
+
return transform;
|
|
126
|
+
}
|
|
127
|
+
function addStreamCodec(name, createDeflater, createInflater) {
|
|
128
|
+
const c = compressors[name] ?? (compressors[name] = {
|
|
129
|
+
compress: (v) => v,
|
|
130
|
+
uncompress: (v) => v
|
|
131
|
+
});
|
|
132
|
+
c.stream = {
|
|
133
|
+
compress: async (src) => pump(src, createDeflater()),
|
|
134
|
+
uncompress: async (src) => pump(src, createInflater())
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
addStreamCodec("gzip", createGzip, createGunzip);
|
|
138
|
+
addStreamCodec("deflate", createDeflate, createInflate);
|
|
139
|
+
addStreamCodec("br", createBrotliCompress, createBrotliDecompress);
|
|
140
|
+
let zp;
|
|
141
|
+
async function zlib() {
|
|
142
|
+
if (!zp) {
|
|
143
|
+
const { gzip, gunzip, deflate, inflate, brotliCompress, brotliDecompress } = await import("node:zlib");
|
|
144
|
+
zp = {
|
|
145
|
+
gzip: promisify(gzip),
|
|
146
|
+
gunzip: promisify(gunzip),
|
|
147
|
+
deflate: promisify(deflate),
|
|
148
|
+
inflate: promisify(inflate),
|
|
149
|
+
brotliCompress: promisify(brotliCompress),
|
|
150
|
+
brotliDecompress: promisify(brotliDecompress)
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return zp;
|
|
154
|
+
}
|
|
155
|
+
compressors.gzip.compress = async (b) => (await zlib()).gzip(b);
|
|
156
|
+
compressors.gzip.uncompress = async (b) => (await zlib()).gunzip(b);
|
|
157
|
+
compressors.deflate.compress = async (b) => (await zlib()).deflate(b);
|
|
158
|
+
compressors.deflate.uncompress = async (b) => (await zlib()).inflate(b);
|
|
159
|
+
compressors.br.compress = async (b) => (await zlib()).brotliCompress(b);
|
|
160
|
+
compressors.br.uncompress = async (b) => (await zlib()).brotliDecompress(b);
|
|
161
|
+
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region packages/event-http/src/response/renderer.ts
|
|
164
|
+
var BaseHttpResponseRenderer = class {
|
|
165
|
+
render(response) {
|
|
166
|
+
if (typeof response.body === "string" || typeof response.body === "boolean" || typeof response.body === "number") {
|
|
167
|
+
if (!response.getContentType()) response.setContentType("text/plain");
|
|
168
|
+
return response.body.toString();
|
|
169
|
+
}
|
|
170
|
+
if (response.body === undefined) return "";
|
|
171
|
+
if (response.body instanceof Uint8Array) return response.body;
|
|
172
|
+
if (typeof response.body === "object") {
|
|
173
|
+
if (!response.getContentType()) response.setContentType("application/json");
|
|
174
|
+
return JSON.stringify(response.body);
|
|
175
|
+
}
|
|
176
|
+
throw new Error(`Unsupported body format "${typeof response.body}"`);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region packages/event-http/src/utils/status-codes.ts
|
|
182
|
+
const httpStatusCodes = {
|
|
183
|
+
100: "Continue",
|
|
184
|
+
101: "Switching protocols",
|
|
185
|
+
102: "Processing",
|
|
186
|
+
103: "Early Hints",
|
|
187
|
+
200: "OK",
|
|
188
|
+
201: "Created",
|
|
189
|
+
202: "Accepted",
|
|
190
|
+
203: "Non-Authoritative Information",
|
|
191
|
+
204: "No Content",
|
|
192
|
+
205: "Reset Content",
|
|
193
|
+
206: "Partial Content",
|
|
194
|
+
207: "Multi-Status",
|
|
195
|
+
208: "Already Reported",
|
|
196
|
+
226: "IM Used",
|
|
197
|
+
300: "Multiple Choices",
|
|
198
|
+
301: "Moved Permanently",
|
|
199
|
+
302: "Found (Previously \"Moved Temporarily\")",
|
|
200
|
+
303: "See Other",
|
|
201
|
+
304: "Not Modified",
|
|
202
|
+
305: "Use Proxy",
|
|
203
|
+
306: "Switch Proxy",
|
|
204
|
+
307: "Temporary Redirect",
|
|
205
|
+
308: "Permanent Redirect",
|
|
206
|
+
400: "Bad Request",
|
|
207
|
+
401: "Unauthorized",
|
|
208
|
+
402: "Payment Required",
|
|
209
|
+
403: "Forbidden",
|
|
210
|
+
404: "Not Found",
|
|
211
|
+
405: "Method Not Allowed",
|
|
212
|
+
406: "Not Acceptable",
|
|
213
|
+
407: "Proxy Authentication Required",
|
|
214
|
+
408: "Request Timeout",
|
|
215
|
+
409: "Conflict",
|
|
216
|
+
410: "Gone",
|
|
217
|
+
411: "Length Required",
|
|
218
|
+
412: "Precondition Failed",
|
|
219
|
+
413: "Payload Too Large",
|
|
220
|
+
414: "URI Too Long",
|
|
221
|
+
415: "Unsupported Media Type",
|
|
222
|
+
416: "Range Not Satisfiable",
|
|
223
|
+
417: "Expectation Failed",
|
|
224
|
+
418: "I'm a Teapot",
|
|
225
|
+
421: "Misdirected Request",
|
|
226
|
+
422: "Unprocessable Entity",
|
|
227
|
+
423: "Locked",
|
|
228
|
+
424: "Failed Dependency",
|
|
229
|
+
425: "Too Early",
|
|
230
|
+
426: "Upgrade Required",
|
|
231
|
+
428: "Precondition Required",
|
|
232
|
+
429: "Too Many Requests",
|
|
233
|
+
431: "Request Header Fields Too Large",
|
|
234
|
+
451: "Unavailable For Legal Reasons",
|
|
235
|
+
500: "Internal Server Error",
|
|
236
|
+
501: "Not Implemented",
|
|
237
|
+
502: "Bad Gateway",
|
|
238
|
+
503: "Service Unavailable",
|
|
239
|
+
504: "Gateway Timeout",
|
|
240
|
+
505: "HTTP Version Not Supported",
|
|
241
|
+
506: "Variant Also Negotiates",
|
|
242
|
+
507: "Insufficient Storage",
|
|
243
|
+
508: "Loop Detected",
|
|
244
|
+
510: "Not Extended",
|
|
245
|
+
511: "Network Authentication Required"
|
|
246
|
+
};
|
|
247
|
+
let EHttpStatusCode = function(EHttpStatusCode$1) {
|
|
248
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Continue"] = 100] = "Continue";
|
|
249
|
+
EHttpStatusCode$1[EHttpStatusCode$1["SwitchingProtocols"] = 101] = "SwitchingProtocols";
|
|
250
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Processing"] = 102] = "Processing";
|
|
251
|
+
EHttpStatusCode$1[EHttpStatusCode$1["EarlyHints"] = 103] = "EarlyHints";
|
|
252
|
+
EHttpStatusCode$1[EHttpStatusCode$1["OK"] = 200] = "OK";
|
|
253
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Created"] = 201] = "Created";
|
|
254
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Accepted"] = 202] = "Accepted";
|
|
255
|
+
EHttpStatusCode$1[EHttpStatusCode$1["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
|
|
256
|
+
EHttpStatusCode$1[EHttpStatusCode$1["NoContent"] = 204] = "NoContent";
|
|
257
|
+
EHttpStatusCode$1[EHttpStatusCode$1["ResetContent"] = 205] = "ResetContent";
|
|
258
|
+
EHttpStatusCode$1[EHttpStatusCode$1["PartialContent"] = 206] = "PartialContent";
|
|
259
|
+
EHttpStatusCode$1[EHttpStatusCode$1["MultiStatus"] = 207] = "MultiStatus";
|
|
260
|
+
EHttpStatusCode$1[EHttpStatusCode$1["AlreadyReported"] = 208] = "AlreadyReported";
|
|
261
|
+
EHttpStatusCode$1[EHttpStatusCode$1["IMUsed"] = 226] = "IMUsed";
|
|
262
|
+
EHttpStatusCode$1[EHttpStatusCode$1["MultipleChoices"] = 300] = "MultipleChoices";
|
|
263
|
+
EHttpStatusCode$1[EHttpStatusCode$1["MovedPermanently"] = 301] = "MovedPermanently";
|
|
264
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Found"] = 302] = "Found";
|
|
265
|
+
EHttpStatusCode$1[EHttpStatusCode$1["SeeOther"] = 303] = "SeeOther";
|
|
266
|
+
EHttpStatusCode$1[EHttpStatusCode$1["NotModified"] = 304] = "NotModified";
|
|
267
|
+
EHttpStatusCode$1[EHttpStatusCode$1["UseProxy"] = 305] = "UseProxy";
|
|
268
|
+
EHttpStatusCode$1[EHttpStatusCode$1["SwitchProxy"] = 306] = "SwitchProxy";
|
|
269
|
+
EHttpStatusCode$1[EHttpStatusCode$1["TemporaryRedirect"] = 307] = "TemporaryRedirect";
|
|
270
|
+
EHttpStatusCode$1[EHttpStatusCode$1["PermanentRedirect"] = 308] = "PermanentRedirect";
|
|
271
|
+
EHttpStatusCode$1[EHttpStatusCode$1["BadRequest"] = 400] = "BadRequest";
|
|
272
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Unauthorized"] = 401] = "Unauthorized";
|
|
273
|
+
EHttpStatusCode$1[EHttpStatusCode$1["PaymentRequired"] = 402] = "PaymentRequired";
|
|
274
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Forbidden"] = 403] = "Forbidden";
|
|
275
|
+
EHttpStatusCode$1[EHttpStatusCode$1["NotFound"] = 404] = "NotFound";
|
|
276
|
+
EHttpStatusCode$1[EHttpStatusCode$1["MethodNotAllowed"] = 405] = "MethodNotAllowed";
|
|
277
|
+
EHttpStatusCode$1[EHttpStatusCode$1["NotAcceptable"] = 406] = "NotAcceptable";
|
|
278
|
+
EHttpStatusCode$1[EHttpStatusCode$1["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
|
|
279
|
+
EHttpStatusCode$1[EHttpStatusCode$1["RequestTimeout"] = 408] = "RequestTimeout";
|
|
280
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Conflict"] = 409] = "Conflict";
|
|
281
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Gone"] = 410] = "Gone";
|
|
282
|
+
EHttpStatusCode$1[EHttpStatusCode$1["LengthRequired"] = 411] = "LengthRequired";
|
|
283
|
+
EHttpStatusCode$1[EHttpStatusCode$1["PreconditionFailed"] = 412] = "PreconditionFailed";
|
|
284
|
+
EHttpStatusCode$1[EHttpStatusCode$1["PayloadTooLarge"] = 413] = "PayloadTooLarge";
|
|
285
|
+
EHttpStatusCode$1[EHttpStatusCode$1["URITooLong"] = 414] = "URITooLong";
|
|
286
|
+
EHttpStatusCode$1[EHttpStatusCode$1["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
|
|
287
|
+
EHttpStatusCode$1[EHttpStatusCode$1["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
|
|
288
|
+
EHttpStatusCode$1[EHttpStatusCode$1["ExpectationFailed"] = 417] = "ExpectationFailed";
|
|
289
|
+
EHttpStatusCode$1[EHttpStatusCode$1["ImATeapot"] = 418] = "ImATeapot";
|
|
290
|
+
EHttpStatusCode$1[EHttpStatusCode$1["MisdirectedRequest"] = 421] = "MisdirectedRequest";
|
|
291
|
+
EHttpStatusCode$1[EHttpStatusCode$1["UnprocessableEntity"] = 422] = "UnprocessableEntity";
|
|
292
|
+
EHttpStatusCode$1[EHttpStatusCode$1["Locked"] = 423] = "Locked";
|
|
293
|
+
EHttpStatusCode$1[EHttpStatusCode$1["FailedDependency"] = 424] = "FailedDependency";
|
|
294
|
+
EHttpStatusCode$1[EHttpStatusCode$1["TooEarly"] = 425] = "TooEarly";
|
|
295
|
+
EHttpStatusCode$1[EHttpStatusCode$1["UpgradeRequired"] = 426] = "UpgradeRequired";
|
|
296
|
+
EHttpStatusCode$1[EHttpStatusCode$1["PreconditionRequired"] = 428] = "PreconditionRequired";
|
|
297
|
+
EHttpStatusCode$1[EHttpStatusCode$1["TooManyRequests"] = 429] = "TooManyRequests";
|
|
298
|
+
EHttpStatusCode$1[EHttpStatusCode$1["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
|
|
299
|
+
EHttpStatusCode$1[EHttpStatusCode$1["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
|
|
300
|
+
EHttpStatusCode$1[EHttpStatusCode$1["InternalServerError"] = 500] = "InternalServerError";
|
|
301
|
+
EHttpStatusCode$1[EHttpStatusCode$1["NotImplemented"] = 501] = "NotImplemented";
|
|
302
|
+
EHttpStatusCode$1[EHttpStatusCode$1["BadGateway"] = 502] = "BadGateway";
|
|
303
|
+
EHttpStatusCode$1[EHttpStatusCode$1["ServiceUnavailable"] = 503] = "ServiceUnavailable";
|
|
304
|
+
EHttpStatusCode$1[EHttpStatusCode$1["GatewayTimeout"] = 504] = "GatewayTimeout";
|
|
305
|
+
EHttpStatusCode$1[EHttpStatusCode$1["HTTPVersionNotSupported"] = 505] = "HTTPVersionNotSupported";
|
|
306
|
+
EHttpStatusCode$1[EHttpStatusCode$1["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
|
|
307
|
+
EHttpStatusCode$1[EHttpStatusCode$1["InsufficientStorage"] = 507] = "InsufficientStorage";
|
|
308
|
+
EHttpStatusCode$1[EHttpStatusCode$1["LoopDetected"] = 508] = "LoopDetected";
|
|
309
|
+
EHttpStatusCode$1[EHttpStatusCode$1["NotExtended"] = 510] = "NotExtended";
|
|
310
|
+
EHttpStatusCode$1[EHttpStatusCode$1["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
|
|
311
|
+
return EHttpStatusCode$1;
|
|
312
|
+
}({});
|
|
313
|
+
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region packages/event-http/src/errors/error-renderer.ts
|
|
316
|
+
const preStyles = "font-family: monospace;width: 100%;max-width: 900px;padding: 10px;margin: 20px auto;border-radius: 8px;background-color: #494949;box-shadow: 0px 0px 3px 2px rgb(255 255 255 / 20%);";
|
|
317
|
+
var HttpErrorRenderer = class extends BaseHttpResponseRenderer {
|
|
318
|
+
renderHtml(response) {
|
|
319
|
+
const data = response.body || {};
|
|
320
|
+
response.setContentType("text/html");
|
|
321
|
+
const keys = Object.keys(data).filter((key) => ![
|
|
322
|
+
"statusCode",
|
|
323
|
+
"error",
|
|
324
|
+
"message"
|
|
325
|
+
].includes(key));
|
|
326
|
+
return "<html style=\"background-color: #333; color: #bbb;\">" + `<head><title>${data.statusCode} ${httpStatusCodes[data.statusCode]}</title></head>` + `<body><center><h1>${data.statusCode} ${httpStatusCodes[data.statusCode]}</h1></center>` + `<center><h4>${data.message}</h1></center><hr color="#666">` + `<center style="color: #666;"> Wooks v${"0.5.25"} </center>` + `${keys.length > 0 ? `<pre style="${preStyles}">${JSON.stringify({
|
|
327
|
+
...data,
|
|
328
|
+
statusCode: undefined,
|
|
329
|
+
message: undefined,
|
|
330
|
+
error: undefined
|
|
331
|
+
}, null, " ")}</pre>` : ""}` + "</body></html>";
|
|
332
|
+
}
|
|
333
|
+
renderText(response) {
|
|
334
|
+
const data = response.body || {};
|
|
335
|
+
response.setContentType("text/plain");
|
|
336
|
+
const keys = Object.keys(data).filter((key) => ![
|
|
337
|
+
"statusCode",
|
|
338
|
+
"error",
|
|
339
|
+
"message"
|
|
340
|
+
].includes(key));
|
|
341
|
+
return `${data.statusCode} ${httpStatusCodes[data.statusCode]}\n${data.message}` + `\n\n${keys.length > 0 ? `${JSON.stringify({
|
|
342
|
+
...data,
|
|
343
|
+
statusCode: undefined,
|
|
344
|
+
message: undefined,
|
|
345
|
+
error: undefined
|
|
346
|
+
}, null, " ")}` : ""}`;
|
|
347
|
+
}
|
|
348
|
+
renderJson(response) {
|
|
349
|
+
const data = response.body || {};
|
|
350
|
+
response.setContentType("application/json");
|
|
351
|
+
const keys = Object.keys(data).filter((key) => ![
|
|
352
|
+
"statusCode",
|
|
353
|
+
"error",
|
|
354
|
+
"message"
|
|
355
|
+
].includes(key));
|
|
356
|
+
return `{"statusCode":${escapeQuotes(data.statusCode)},` + `"error":"${escapeQuotes(data.error)}",` + `"message":"${escapeQuotes(data.message)}"` + `${keys.length > 0 ? `,${keys.map((k) => `"${escapeQuotes(k)}":${JSON.stringify(data[k])}`).join(",")}` : ""}}`;
|
|
357
|
+
}
|
|
358
|
+
render(response) {
|
|
359
|
+
const { acceptsJson, acceptsText, acceptsHtml } = useAccept();
|
|
360
|
+
response.status = response.body?.statusCode || 500;
|
|
361
|
+
if (acceptsJson()) return this.renderJson(response);
|
|
362
|
+
else if (acceptsHtml()) return this.renderHtml(response);
|
|
363
|
+
else if (acceptsText()) return this.renderText(response);
|
|
364
|
+
else return this.renderJson(response);
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
function escapeQuotes(s) {
|
|
368
|
+
return (typeof s === "number" ? s : s || "").toString().replace(/"/gu, "\\\"");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region packages/event-http/src/errors/http-error.ts
|
|
373
|
+
var HttpError = class extends Error {
|
|
374
|
+
name = "HttpError";
|
|
375
|
+
constructor(code = 500, _body = "") {
|
|
376
|
+
super(typeof _body === "string" ? _body : _body.message);
|
|
377
|
+
this.code = code;
|
|
378
|
+
this._body = _body;
|
|
379
|
+
}
|
|
380
|
+
get body() {
|
|
381
|
+
return typeof this._body === "string" ? {
|
|
382
|
+
statusCode: this.code,
|
|
383
|
+
message: this.message,
|
|
384
|
+
error: httpStatusCodes[this.code]
|
|
385
|
+
} : {
|
|
386
|
+
...this._body,
|
|
387
|
+
statusCode: this.code,
|
|
388
|
+
message: this.message,
|
|
389
|
+
error: httpStatusCodes[this.code]
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
renderer;
|
|
393
|
+
attachRenderer(renderer) {
|
|
394
|
+
this.renderer = renderer;
|
|
395
|
+
}
|
|
396
|
+
getRenderer() {
|
|
397
|
+
return this.renderer;
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
//#endregion
|
|
402
|
+
//#region packages/event-http/src/composables/request.ts
|
|
403
|
+
const xForwardedFor = "x-forwarded-for";
|
|
404
|
+
const DEFAULT_LIMITS = {
|
|
405
|
+
maxCompressed: 1048576,
|
|
406
|
+
maxInflated: 10485760,
|
|
407
|
+
maxRatio: 100,
|
|
408
|
+
readTimeoutMs: 1e4
|
|
409
|
+
};
|
|
87
410
|
function useRequest() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
411
|
+
const { store } = useHttpContext();
|
|
412
|
+
const { init, get, set } = store("request");
|
|
413
|
+
const event = store("event");
|
|
414
|
+
const req = event.get("req");
|
|
415
|
+
const contentEncoding = req.headers["content-encoding"];
|
|
416
|
+
const contentEncodings = () => init("contentEncodings", () => (contentEncoding || "").split(",").map((p) => p.trim()).filter((p) => !!p));
|
|
417
|
+
const isCompressed = () => init("isCompressed", () => {
|
|
418
|
+
const parts = contentEncodings();
|
|
419
|
+
for (const p of parts) if ([
|
|
420
|
+
"deflate",
|
|
421
|
+
"gzip",
|
|
422
|
+
"br"
|
|
423
|
+
].includes(p)) return true;
|
|
424
|
+
return false;
|
|
425
|
+
});
|
|
426
|
+
const getMaxCompressed = () => get("maxCompressed") ?? DEFAULT_LIMITS.maxCompressed;
|
|
427
|
+
const setMaxCompressed = (limit) => set("maxCompressed", limit);
|
|
428
|
+
const getReadTimeoutMs = () => get("readTimeoutMs") ?? DEFAULT_LIMITS.readTimeoutMs;
|
|
429
|
+
const setReadTimeoutMs = (limit) => set("readTimeoutMs", limit);
|
|
430
|
+
const getMaxInflated = () => get("maxInflated") ?? DEFAULT_LIMITS.maxInflated;
|
|
431
|
+
const setMaxInflated = (limit) => set("maxInflated", limit);
|
|
432
|
+
const rawBody = () => init("rawBody", async () => {
|
|
433
|
+
const encs = contentEncodings();
|
|
434
|
+
const isZip = isCompressed();
|
|
435
|
+
const streamable = isZip && encodingSupportsStream(encs);
|
|
436
|
+
const maxCompressed = getMaxCompressed();
|
|
437
|
+
const maxInflated = getMaxInflated();
|
|
438
|
+
const timeoutMs = getReadTimeoutMs();
|
|
439
|
+
const cl = Number(req.headers["content-length"] ?? 0);
|
|
440
|
+
const upfrontLimit = isZip ? maxCompressed : maxInflated;
|
|
441
|
+
if (cl && cl > upfrontLimit) throw new HttpError(413, "Payload Too Large");
|
|
442
|
+
for (const enc of encs) if (!compressors[enc]) throw new HttpError(415, `Unsupported Content-Encoding "${enc}"`);
|
|
443
|
+
let timer = null;
|
|
444
|
+
function resetTimer() {
|
|
445
|
+
if (timeoutMs === 0) return;
|
|
446
|
+
clearTimer();
|
|
447
|
+
timer = setTimeout(() => {
|
|
448
|
+
clearTimer();
|
|
449
|
+
req.destroy();
|
|
450
|
+
}, timeoutMs);
|
|
451
|
+
}
|
|
452
|
+
function clearTimer() {
|
|
453
|
+
if (timer) {
|
|
454
|
+
clearTimeout(timer);
|
|
455
|
+
timer = null;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
let rawBytes = 0;
|
|
459
|
+
async function* limitedCompressed() {
|
|
460
|
+
resetTimer();
|
|
461
|
+
try {
|
|
462
|
+
for await (const chunk of req) {
|
|
463
|
+
rawBytes += chunk.length;
|
|
464
|
+
if (rawBytes > upfrontLimit) {
|
|
465
|
+
req.destroy();
|
|
466
|
+
throw new HttpError(413, "Payload Too Large");
|
|
467
|
+
}
|
|
468
|
+
resetTimer();
|
|
469
|
+
yield chunk;
|
|
470
|
+
}
|
|
471
|
+
} finally {
|
|
472
|
+
clearTimer();
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
let stream = limitedCompressed();
|
|
476
|
+
if (streamable) stream = await uncompressBodyStream(encs, stream);
|
|
477
|
+
const chunks = [];
|
|
478
|
+
let inflatedBytes = 0;
|
|
479
|
+
try {
|
|
480
|
+
for await (const chunk of stream) {
|
|
481
|
+
inflatedBytes += chunk.length;
|
|
482
|
+
if (inflatedBytes > maxInflated) throw new HttpError(413, "Inflated body too large");
|
|
483
|
+
chunks.push(chunk);
|
|
484
|
+
}
|
|
485
|
+
} catch (error) {
|
|
486
|
+
if (error instanceof HttpError) throw error;
|
|
487
|
+
throw new HttpError(408, "Request body timeout");
|
|
488
|
+
}
|
|
489
|
+
let body = Buffer$1.concat(chunks);
|
|
490
|
+
if (!streamable && isZip) {
|
|
491
|
+
body = await uncompressBody(encs, body);
|
|
492
|
+
inflatedBytes = body.byteLength;
|
|
493
|
+
if (inflatedBytes > maxInflated) throw new HttpError(413, "Inflated body too large");
|
|
494
|
+
}
|
|
495
|
+
return body;
|
|
496
|
+
});
|
|
497
|
+
const reqId = useEventId().getId;
|
|
498
|
+
const forwardedIp = () => init("forwardedIp", () => {
|
|
499
|
+
if (typeof req.headers[xForwardedFor] === "string" && req.headers[xForwardedFor]) return req.headers[xForwardedFor].split(",").shift()?.trim();
|
|
500
|
+
else return "";
|
|
501
|
+
});
|
|
502
|
+
const remoteIp = () => init("remoteIp", () => req.socket.remoteAddress || req.connection.remoteAddress || "");
|
|
503
|
+
function getIp(options) {
|
|
504
|
+
if (options?.trustProxy) return forwardedIp() || getIp();
|
|
505
|
+
else return remoteIp();
|
|
506
|
+
}
|
|
507
|
+
const getIpList = () => init("ipList", () => ({
|
|
508
|
+
remoteIp: req.socket.remoteAddress || req.connection.remoteAddress || "",
|
|
509
|
+
forwarded: (req.headers[xForwardedFor] || "").split(",").map((s) => s.trim())
|
|
510
|
+
}));
|
|
511
|
+
return {
|
|
512
|
+
rawRequest: req,
|
|
513
|
+
url: req.url,
|
|
514
|
+
method: req.method,
|
|
515
|
+
headers: req.headers,
|
|
516
|
+
rawBody,
|
|
517
|
+
reqId,
|
|
518
|
+
getIp,
|
|
519
|
+
getIpList,
|
|
520
|
+
isCompressed,
|
|
521
|
+
getMaxCompressed,
|
|
522
|
+
setMaxCompressed,
|
|
523
|
+
getReadTimeoutMs,
|
|
524
|
+
setReadTimeoutMs,
|
|
525
|
+
getMaxInflated,
|
|
526
|
+
setMaxInflated
|
|
527
|
+
};
|
|
136
528
|
}
|
|
137
529
|
|
|
530
|
+
//#endregion
|
|
531
|
+
//#region packages/event-http/src/composables/headers.ts
|
|
138
532
|
function useHeaders() {
|
|
139
|
-
|
|
533
|
+
return useRequest().headers;
|
|
140
534
|
}
|
|
141
535
|
function useSetHeaders() {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
536
|
+
const { store } = useHttpContext();
|
|
537
|
+
const setHeaderStore = store("setHeader");
|
|
538
|
+
function setHeader(name, value) {
|
|
539
|
+
setHeaderStore.set(name, value.toString());
|
|
540
|
+
}
|
|
541
|
+
function setContentType(value) {
|
|
542
|
+
setHeader("content-type", value);
|
|
543
|
+
}
|
|
544
|
+
function enableCors(origin = "*") {
|
|
545
|
+
setHeader("access-control-allow-origin", origin);
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
setHeader,
|
|
549
|
+
getHeader: setHeaderStore.get,
|
|
550
|
+
removeHeader: setHeaderStore.del,
|
|
551
|
+
setContentType,
|
|
552
|
+
headers: () => setHeaderStore.value || {},
|
|
553
|
+
enableCors
|
|
554
|
+
};
|
|
161
555
|
}
|
|
162
556
|
function useSetHeader(name) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
557
|
+
const { store } = useHttpContext();
|
|
558
|
+
const { hook } = store("setHeader");
|
|
559
|
+
return hook(name);
|
|
166
560
|
}
|
|
167
561
|
|
|
562
|
+
//#endregion
|
|
563
|
+
//#region packages/event-http/src/composables/cookies.ts
|
|
168
564
|
function useCookies() {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
rawCookies: cookie,
|
|
183
|
-
getCookie,
|
|
184
|
-
};
|
|
565
|
+
const { store } = useHttpContext();
|
|
566
|
+
const { cookie } = useHeaders();
|
|
567
|
+
const { init } = store("cookies");
|
|
568
|
+
const getCookie = (name) => init(name, () => {
|
|
569
|
+
if (cookie) {
|
|
570
|
+
const result = new RegExp(`(?:^|; )${escapeRegex(name)}=(.*?)(?:;?$|; )`, "i").exec(cookie);
|
|
571
|
+
return result?.[1] ? safeDecodeURIComponent(result[1]) : null;
|
|
572
|
+
} else return null;
|
|
573
|
+
});
|
|
574
|
+
return {
|
|
575
|
+
rawCookies: cookie,
|
|
576
|
+
getCookie
|
|
577
|
+
};
|
|
185
578
|
}
|
|
186
579
|
function useSetCookies() {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
clearCookies: cookiesStore.clear,
|
|
206
|
-
cookies,
|
|
207
|
-
};
|
|
580
|
+
const { store } = useHttpContext();
|
|
581
|
+
const cookiesStore = store("setCookies");
|
|
582
|
+
function setCookie(name, value, attrs) {
|
|
583
|
+
cookiesStore.set(name, {
|
|
584
|
+
value,
|
|
585
|
+
attrs: attrs || {}
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
function cookies() {
|
|
589
|
+
return cookiesStore.entries().filter((a) => !!a[1]).map(([key, value]) => renderCookie(key, value));
|
|
590
|
+
}
|
|
591
|
+
return {
|
|
592
|
+
setCookie,
|
|
593
|
+
getCookie: cookiesStore.get,
|
|
594
|
+
removeCookie: cookiesStore.del,
|
|
595
|
+
clearCookies: cookiesStore.clear,
|
|
596
|
+
cookies
|
|
597
|
+
};
|
|
208
598
|
}
|
|
209
599
|
function useSetCookie(name) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
600
|
+
const { setCookie, getCookie } = useSetCookies();
|
|
601
|
+
const valueHook = attachHook({
|
|
602
|
+
name,
|
|
603
|
+
type: "cookie"
|
|
604
|
+
}, {
|
|
605
|
+
get: () => getCookie(name)?.value,
|
|
606
|
+
set: (value) => {
|
|
607
|
+
setCookie(name, value, getCookie(name)?.attrs);
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
return attachHook(valueHook, {
|
|
611
|
+
get: () => getCookie(name)?.attrs,
|
|
612
|
+
set: (attrs) => {
|
|
613
|
+
setCookie(name, getCookie(name)?.value || "", attrs);
|
|
614
|
+
}
|
|
615
|
+
}, "attrs");
|
|
226
616
|
}
|
|
227
617
|
|
|
618
|
+
//#endregion
|
|
619
|
+
//#region packages/event-http/src/composables/header-accept.ts
|
|
228
620
|
function useAccept() {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
acceptsHtml: () => accepts('text/html'),
|
|
245
|
-
};
|
|
621
|
+
const { store } = useHttpContext();
|
|
622
|
+
const { accept } = useHeaders();
|
|
623
|
+
const accepts = (mime) => {
|
|
624
|
+
const { set, get, has } = store("accept");
|
|
625
|
+
if (!has(mime)) return set(mime, !!(accept && (accept === "*/*" || accept.includes(mime))));
|
|
626
|
+
return get(mime);
|
|
627
|
+
};
|
|
628
|
+
return {
|
|
629
|
+
accept,
|
|
630
|
+
accepts,
|
|
631
|
+
acceptsJson: () => accepts("application/json"),
|
|
632
|
+
acceptsXml: () => accepts("application/xml"),
|
|
633
|
+
acceptsText: () => accepts("text/plain"),
|
|
634
|
+
acceptsHtml: () => accepts("text/html")
|
|
635
|
+
};
|
|
246
636
|
}
|
|
247
637
|
|
|
638
|
+
//#endregion
|
|
639
|
+
//#region packages/event-http/src/composables/header-authorization.ts
|
|
248
640
|
function useAuthorization() {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
641
|
+
const { store } = useHttpContext();
|
|
642
|
+
const { authorization } = useHeaders();
|
|
643
|
+
const { init } = store("authorization");
|
|
644
|
+
const authType = () => init("type", () => {
|
|
645
|
+
if (authorization) {
|
|
646
|
+
const space = authorization.indexOf(" ");
|
|
647
|
+
return authorization.slice(0, space);
|
|
648
|
+
}
|
|
649
|
+
return null;
|
|
650
|
+
});
|
|
651
|
+
const authRawCredentials = () => init("credentials", () => {
|
|
652
|
+
if (authorization) {
|
|
653
|
+
const space = authorization.indexOf(" ");
|
|
654
|
+
return authorization.slice(space + 1);
|
|
655
|
+
}
|
|
656
|
+
return null;
|
|
657
|
+
});
|
|
658
|
+
return {
|
|
659
|
+
authorization,
|
|
660
|
+
authType,
|
|
661
|
+
authRawCredentials,
|
|
662
|
+
isBasic: () => authType()?.toLocaleLowerCase() === "basic",
|
|
663
|
+
isBearer: () => authType()?.toLocaleLowerCase() === "bearer",
|
|
664
|
+
basicCredentials: () => init("basicCredentials", () => {
|
|
665
|
+
if (authorization) {
|
|
666
|
+
const type = authType();
|
|
667
|
+
if (type?.toLocaleLowerCase() === "basic") {
|
|
668
|
+
const creds = Buffer$1.from(authRawCredentials() || "", "base64").toString("ascii");
|
|
669
|
+
const [username, password] = creds.split(":");
|
|
670
|
+
return {
|
|
671
|
+
username,
|
|
672
|
+
password
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return null;
|
|
677
|
+
})
|
|
678
|
+
};
|
|
284
679
|
}
|
|
285
680
|
|
|
681
|
+
//#endregion
|
|
682
|
+
//#region packages/event-http/src/utils/cache-control.ts
|
|
286
683
|
function renderCacheControl(data) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
throw new TypeError(`Unknown Cache-Control attribute ${a}`);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
return attrs;
|
|
684
|
+
let attrs = "";
|
|
685
|
+
for (const [a, v] of Object.entries(data)) {
|
|
686
|
+
if (v === undefined) continue;
|
|
687
|
+
const func = cacheControlFunc[a];
|
|
688
|
+
if (typeof func === "function") {
|
|
689
|
+
const val = func(v);
|
|
690
|
+
if (val) attrs += attrs ? `, ${val}` : val;
|
|
691
|
+
} else throw new TypeError(`Unknown Cache-Control attribute ${a}`);
|
|
692
|
+
}
|
|
693
|
+
return attrs;
|
|
304
694
|
}
|
|
305
695
|
const cacheControlFunc = {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
696
|
+
mustRevalidate: (v) => v ? "must-revalidate" : "",
|
|
697
|
+
noCache: (v) => v ? typeof v === "string" ? `no-cache="${v}"` : "no-cache" : "",
|
|
698
|
+
noStore: (v) => v ? "no-store" : "",
|
|
699
|
+
noTransform: (v) => v ? "no-transform" : "",
|
|
700
|
+
public: (v) => v ? "public" : "",
|
|
701
|
+
private: (v) => v ? typeof v === "string" ? `private="${v}"` : "private" : "",
|
|
702
|
+
proxyRevalidate: (v) => v ? "proxy-revalidate" : "",
|
|
703
|
+
maxAge: (v) => `max-age=${convertTime(v, "s").toString()}`,
|
|
704
|
+
sMaxage: (v) => `s-maxage=${convertTime(v, "s").toString()}`
|
|
315
705
|
};
|
|
316
706
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const
|
|
707
|
+
//#endregion
|
|
708
|
+
//#region packages/event-http/src/composables/header-set-cache-control.ts
|
|
709
|
+
const renderAge = (v) => convertTime(v, "s").toString();
|
|
710
|
+
const renderExpires = (v) => typeof v === "string" || typeof v === "number" ? new Date(v).toUTCString() : v.toUTCString();
|
|
711
|
+
const renderPragmaNoCache = (v) => v ? "no-cache" : "";
|
|
320
712
|
function useSetCacheControl() {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
713
|
+
const { setHeader } = useSetHeaders();
|
|
714
|
+
const setAge = (value) => {
|
|
715
|
+
setHeader("age", renderAge(value));
|
|
716
|
+
};
|
|
717
|
+
const setExpires = (value) => {
|
|
718
|
+
setHeader("expires", renderExpires(value));
|
|
719
|
+
};
|
|
720
|
+
const setPragmaNoCache = (value = true) => {
|
|
721
|
+
setHeader("pragma", renderPragmaNoCache(value));
|
|
722
|
+
};
|
|
723
|
+
const setCacheControl = (data) => {
|
|
724
|
+
setHeader("cache-control", renderCacheControl(data));
|
|
725
|
+
};
|
|
726
|
+
return {
|
|
727
|
+
setExpires,
|
|
728
|
+
setAge,
|
|
729
|
+
setPragmaNoCache,
|
|
730
|
+
setCacheControl
|
|
731
|
+
};
|
|
340
732
|
}
|
|
341
733
|
|
|
734
|
+
//#endregion
|
|
735
|
+
//#region packages/event-http/src/composables/response.ts
|
|
342
736
|
function useResponse() {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}),
|
|
364
|
-
};
|
|
737
|
+
const { store } = useHttpContext();
|
|
738
|
+
const event = store("event");
|
|
739
|
+
const res = event.get("res");
|
|
740
|
+
const responded = store("response").hook("responded");
|
|
741
|
+
const statusCode = store("status").hook("code");
|
|
742
|
+
function status(code) {
|
|
743
|
+
return statusCode.value = code ? code : statusCode.value;
|
|
744
|
+
}
|
|
745
|
+
const rawResponse = (options) => {
|
|
746
|
+
if (!options || !options.passthrough) responded.value = true;
|
|
747
|
+
return res;
|
|
748
|
+
};
|
|
749
|
+
return {
|
|
750
|
+
rawResponse,
|
|
751
|
+
hasResponded: () => responded.value || !res.writable || res.writableEnded,
|
|
752
|
+
status: attachHook(status, {
|
|
753
|
+
get: () => statusCode.value,
|
|
754
|
+
set: (code) => statusCode.value = code
|
|
755
|
+
})
|
|
756
|
+
};
|
|
365
757
|
}
|
|
366
758
|
function useStatus() {
|
|
367
|
-
|
|
368
|
-
|
|
759
|
+
const { store } = useHttpContext();
|
|
760
|
+
return store("status").hook("code");
|
|
369
761
|
}
|
|
370
762
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
763
|
+
//#endregion
|
|
764
|
+
//#region packages/event-http/src/utils/url-search-params.ts
|
|
765
|
+
var WooksURLSearchParams = class extends URLSearchParams {
|
|
766
|
+
toJson() {
|
|
767
|
+
const json = Object.create(null);
|
|
768
|
+
for (const [key, value] of this.entries()) if (isArrayParam(key)) {
|
|
769
|
+
const a = json[key] = json[key] || [];
|
|
770
|
+
a.push(value);
|
|
771
|
+
} else {
|
|
772
|
+
if (key === "__proto__") throw new HttpError(400, `Illegal key name "${key}"`);
|
|
773
|
+
if (key in json) throw new HttpError(400, `Duplicate key "${key}"`);
|
|
774
|
+
json[key] = value;
|
|
775
|
+
}
|
|
776
|
+
return json;
|
|
777
|
+
}
|
|
778
|
+
};
|
|
386
779
|
function isArrayParam(name) {
|
|
387
|
-
|
|
780
|
+
return name.endsWith("[]");
|
|
388
781
|
}
|
|
389
782
|
|
|
783
|
+
//#endregion
|
|
784
|
+
//#region packages/event-http/src/composables/search-params.ts
|
|
390
785
|
function useSearchParams() {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
class BaseHttpResponseRenderer {
|
|
407
|
-
render(response) {
|
|
408
|
-
if (typeof response.body === 'string' ||
|
|
409
|
-
typeof response.body === 'boolean' ||
|
|
410
|
-
typeof response.body === 'number') {
|
|
411
|
-
if (!response.getContentType()) {
|
|
412
|
-
response.setContentType('text/plain');
|
|
413
|
-
}
|
|
414
|
-
return response.body.toString();
|
|
415
|
-
}
|
|
416
|
-
if (response.body === undefined) {
|
|
417
|
-
return '';
|
|
418
|
-
}
|
|
419
|
-
if (response.body instanceof Uint8Array) {
|
|
420
|
-
return response.body;
|
|
421
|
-
}
|
|
422
|
-
if (typeof response.body === 'object') {
|
|
423
|
-
if (!response.getContentType()) {
|
|
424
|
-
response.setContentType('application/json');
|
|
425
|
-
}
|
|
426
|
-
return JSON.stringify(response.body);
|
|
427
|
-
}
|
|
428
|
-
throw new Error(`Unsupported body format "${typeof response.body}"`);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
const httpStatusCodes = {
|
|
433
|
-
100: 'Continue',
|
|
434
|
-
101: 'Switching protocols',
|
|
435
|
-
102: 'Processing',
|
|
436
|
-
103: 'Early Hints',
|
|
437
|
-
200: 'OK',
|
|
438
|
-
201: 'Created',
|
|
439
|
-
202: 'Accepted',
|
|
440
|
-
203: 'Non-Authoritative Information',
|
|
441
|
-
204: 'No Content',
|
|
442
|
-
205: 'Reset Content',
|
|
443
|
-
206: 'Partial Content',
|
|
444
|
-
207: 'Multi-Status',
|
|
445
|
-
208: 'Already Reported',
|
|
446
|
-
226: 'IM Used',
|
|
447
|
-
300: 'Multiple Choices',
|
|
448
|
-
301: 'Moved Permanently',
|
|
449
|
-
302: 'Found (Previously "Moved Temporarily")',
|
|
450
|
-
303: 'See Other',
|
|
451
|
-
304: 'Not Modified',
|
|
452
|
-
305: 'Use Proxy',
|
|
453
|
-
306: 'Switch Proxy',
|
|
454
|
-
307: 'Temporary Redirect',
|
|
455
|
-
308: 'Permanent Redirect',
|
|
456
|
-
400: 'Bad Request',
|
|
457
|
-
401: 'Unauthorized',
|
|
458
|
-
402: 'Payment Required',
|
|
459
|
-
403: 'Forbidden',
|
|
460
|
-
404: 'Not Found',
|
|
461
|
-
405: 'Method Not Allowed',
|
|
462
|
-
406: 'Not Acceptable',
|
|
463
|
-
407: 'Proxy Authentication Required',
|
|
464
|
-
408: 'Request Timeout',
|
|
465
|
-
409: 'Conflict',
|
|
466
|
-
410: 'Gone',
|
|
467
|
-
411: 'Length Required',
|
|
468
|
-
412: 'Precondition Failed',
|
|
469
|
-
413: 'Payload Too Large',
|
|
470
|
-
414: 'URI Too Long',
|
|
471
|
-
415: 'Unsupported Media Type',
|
|
472
|
-
416: 'Range Not Satisfiable',
|
|
473
|
-
417: 'Expectation Failed',
|
|
474
|
-
418: "I'm a Teapot",
|
|
475
|
-
421: 'Misdirected Request',
|
|
476
|
-
422: 'Unprocessable Entity',
|
|
477
|
-
423: 'Locked',
|
|
478
|
-
424: 'Failed Dependency',
|
|
479
|
-
425: 'Too Early',
|
|
480
|
-
426: 'Upgrade Required',
|
|
481
|
-
428: 'Precondition Required',
|
|
482
|
-
429: 'Too Many Requests',
|
|
483
|
-
431: 'Request Header Fields Too Large',
|
|
484
|
-
451: 'Unavailable For Legal Reasons',
|
|
485
|
-
500: 'Internal Server Error',
|
|
486
|
-
501: 'Not Implemented',
|
|
487
|
-
502: 'Bad Gateway',
|
|
488
|
-
503: 'Service Unavailable',
|
|
489
|
-
504: 'Gateway Timeout',
|
|
490
|
-
505: 'HTTP Version Not Supported',
|
|
491
|
-
506: 'Variant Also Negotiates',
|
|
492
|
-
507: 'Insufficient Storage',
|
|
493
|
-
508: 'Loop Detected',
|
|
494
|
-
510: 'Not Extended',
|
|
495
|
-
511: 'Network Authentication Required',
|
|
496
|
-
};
|
|
497
|
-
var EHttpStatusCode;
|
|
498
|
-
(function (EHttpStatusCode) {
|
|
499
|
-
EHttpStatusCode[EHttpStatusCode["Continue"] = 100] = "Continue";
|
|
500
|
-
EHttpStatusCode[EHttpStatusCode["SwitchingProtocols"] = 101] = "SwitchingProtocols";
|
|
501
|
-
EHttpStatusCode[EHttpStatusCode["Processing"] = 102] = "Processing";
|
|
502
|
-
EHttpStatusCode[EHttpStatusCode["EarlyHints"] = 103] = "EarlyHints";
|
|
503
|
-
EHttpStatusCode[EHttpStatusCode["OK"] = 200] = "OK";
|
|
504
|
-
EHttpStatusCode[EHttpStatusCode["Created"] = 201] = "Created";
|
|
505
|
-
EHttpStatusCode[EHttpStatusCode["Accepted"] = 202] = "Accepted";
|
|
506
|
-
EHttpStatusCode[EHttpStatusCode["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
|
|
507
|
-
EHttpStatusCode[EHttpStatusCode["NoContent"] = 204] = "NoContent";
|
|
508
|
-
EHttpStatusCode[EHttpStatusCode["ResetContent"] = 205] = "ResetContent";
|
|
509
|
-
EHttpStatusCode[EHttpStatusCode["PartialContent"] = 206] = "PartialContent";
|
|
510
|
-
EHttpStatusCode[EHttpStatusCode["MultiStatus"] = 207] = "MultiStatus";
|
|
511
|
-
EHttpStatusCode[EHttpStatusCode["AlreadyReported"] = 208] = "AlreadyReported";
|
|
512
|
-
EHttpStatusCode[EHttpStatusCode["IMUsed"] = 226] = "IMUsed";
|
|
513
|
-
EHttpStatusCode[EHttpStatusCode["MultipleChoices"] = 300] = "MultipleChoices";
|
|
514
|
-
EHttpStatusCode[EHttpStatusCode["MovedPermanently"] = 301] = "MovedPermanently";
|
|
515
|
-
EHttpStatusCode[EHttpStatusCode["Found"] = 302] = "Found";
|
|
516
|
-
EHttpStatusCode[EHttpStatusCode["SeeOther"] = 303] = "SeeOther";
|
|
517
|
-
EHttpStatusCode[EHttpStatusCode["NotModified"] = 304] = "NotModified";
|
|
518
|
-
EHttpStatusCode[EHttpStatusCode["UseProxy"] = 305] = "UseProxy";
|
|
519
|
-
EHttpStatusCode[EHttpStatusCode["SwitchProxy"] = 306] = "SwitchProxy";
|
|
520
|
-
EHttpStatusCode[EHttpStatusCode["TemporaryRedirect"] = 307] = "TemporaryRedirect";
|
|
521
|
-
EHttpStatusCode[EHttpStatusCode["PermanentRedirect"] = 308] = "PermanentRedirect";
|
|
522
|
-
EHttpStatusCode[EHttpStatusCode["BadRequest"] = 400] = "BadRequest";
|
|
523
|
-
EHttpStatusCode[EHttpStatusCode["Unauthorized"] = 401] = "Unauthorized";
|
|
524
|
-
EHttpStatusCode[EHttpStatusCode["PaymentRequired"] = 402] = "PaymentRequired";
|
|
525
|
-
EHttpStatusCode[EHttpStatusCode["Forbidden"] = 403] = "Forbidden";
|
|
526
|
-
EHttpStatusCode[EHttpStatusCode["NotFound"] = 404] = "NotFound";
|
|
527
|
-
EHttpStatusCode[EHttpStatusCode["MethodNotAllowed"] = 405] = "MethodNotAllowed";
|
|
528
|
-
EHttpStatusCode[EHttpStatusCode["NotAcceptable"] = 406] = "NotAcceptable";
|
|
529
|
-
EHttpStatusCode[EHttpStatusCode["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
|
|
530
|
-
EHttpStatusCode[EHttpStatusCode["RequestTimeout"] = 408] = "RequestTimeout";
|
|
531
|
-
EHttpStatusCode[EHttpStatusCode["Conflict"] = 409] = "Conflict";
|
|
532
|
-
EHttpStatusCode[EHttpStatusCode["Gone"] = 410] = "Gone";
|
|
533
|
-
EHttpStatusCode[EHttpStatusCode["LengthRequired"] = 411] = "LengthRequired";
|
|
534
|
-
EHttpStatusCode[EHttpStatusCode["PreconditionFailed"] = 412] = "PreconditionFailed";
|
|
535
|
-
EHttpStatusCode[EHttpStatusCode["PayloadTooLarge"] = 413] = "PayloadTooLarge";
|
|
536
|
-
EHttpStatusCode[EHttpStatusCode["URITooLong"] = 414] = "URITooLong";
|
|
537
|
-
EHttpStatusCode[EHttpStatusCode["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
|
|
538
|
-
EHttpStatusCode[EHttpStatusCode["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
|
|
539
|
-
EHttpStatusCode[EHttpStatusCode["ExpectationFailed"] = 417] = "ExpectationFailed";
|
|
540
|
-
EHttpStatusCode[EHttpStatusCode["ImATeapot"] = 418] = "ImATeapot";
|
|
541
|
-
EHttpStatusCode[EHttpStatusCode["MisdirectedRequest"] = 421] = "MisdirectedRequest";
|
|
542
|
-
EHttpStatusCode[EHttpStatusCode["UnprocessableEntity"] = 422] = "UnprocessableEntity";
|
|
543
|
-
EHttpStatusCode[EHttpStatusCode["Locked"] = 423] = "Locked";
|
|
544
|
-
EHttpStatusCode[EHttpStatusCode["FailedDependency"] = 424] = "FailedDependency";
|
|
545
|
-
EHttpStatusCode[EHttpStatusCode["TooEarly"] = 425] = "TooEarly";
|
|
546
|
-
EHttpStatusCode[EHttpStatusCode["UpgradeRequired"] = 426] = "UpgradeRequired";
|
|
547
|
-
EHttpStatusCode[EHttpStatusCode["PreconditionRequired"] = 428] = "PreconditionRequired";
|
|
548
|
-
EHttpStatusCode[EHttpStatusCode["TooManyRequests"] = 429] = "TooManyRequests";
|
|
549
|
-
EHttpStatusCode[EHttpStatusCode["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
|
|
550
|
-
EHttpStatusCode[EHttpStatusCode["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
|
|
551
|
-
EHttpStatusCode[EHttpStatusCode["InternalServerError"] = 500] = "InternalServerError";
|
|
552
|
-
EHttpStatusCode[EHttpStatusCode["NotImplemented"] = 501] = "NotImplemented";
|
|
553
|
-
EHttpStatusCode[EHttpStatusCode["BadGateway"] = 502] = "BadGateway";
|
|
554
|
-
EHttpStatusCode[EHttpStatusCode["ServiceUnavailable"] = 503] = "ServiceUnavailable";
|
|
555
|
-
EHttpStatusCode[EHttpStatusCode["GatewayTimeout"] = 504] = "GatewayTimeout";
|
|
556
|
-
EHttpStatusCode[EHttpStatusCode["HTTPVersionNotSupported"] = 505] = "HTTPVersionNotSupported";
|
|
557
|
-
EHttpStatusCode[EHttpStatusCode["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
|
|
558
|
-
EHttpStatusCode[EHttpStatusCode["InsufficientStorage"] = 507] = "InsufficientStorage";
|
|
559
|
-
EHttpStatusCode[EHttpStatusCode["LoopDetected"] = 508] = "LoopDetected";
|
|
560
|
-
EHttpStatusCode[EHttpStatusCode["NotExtended"] = 510] = "NotExtended";
|
|
561
|
-
EHttpStatusCode[EHttpStatusCode["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
|
|
562
|
-
})(EHttpStatusCode || (EHttpStatusCode = {}));
|
|
563
|
-
|
|
564
|
-
const preStyles = 'font-family: monospace;' +
|
|
565
|
-
'width: 100%;' +
|
|
566
|
-
'max-width: 900px;' +
|
|
567
|
-
'padding: 10px;' +
|
|
568
|
-
'margin: 20px auto;' +
|
|
569
|
-
'border-radius: 8px;' +
|
|
570
|
-
'background-color: #494949;' +
|
|
571
|
-
'box-shadow: 0px 0px 3px 2px rgb(255 255 255 / 20%);';
|
|
572
|
-
class HttpErrorRenderer extends BaseHttpResponseRenderer {
|
|
573
|
-
renderHtml(response) {
|
|
574
|
-
const data = response.body || {};
|
|
575
|
-
response.setContentType('text/html');
|
|
576
|
-
const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
|
|
577
|
-
return ('<html style="background-color: #333; color: #bbb;">' +
|
|
578
|
-
`<head><title>${data.statusCode} ${httpStatusCodes[data.statusCode]}</title></head>` +
|
|
579
|
-
`<body><center><h1>${data.statusCode} ${httpStatusCodes[data.statusCode]}</h1></center>` +
|
|
580
|
-
`<center><h4>${data.message}</h1></center><hr color="#666">` +
|
|
581
|
-
`<center style="color: #666;"> Wooks v${"0.5.20"} </center>` +
|
|
582
|
-
`${keys.length > 0
|
|
583
|
-
? `<pre style="${preStyles}">${JSON.stringify({
|
|
584
|
-
...data,
|
|
585
|
-
statusCode: undefined,
|
|
586
|
-
message: undefined,
|
|
587
|
-
error: undefined,
|
|
588
|
-
}, null, ' ')}</pre>`
|
|
589
|
-
: ''}` +
|
|
590
|
-
'</body></html>');
|
|
591
|
-
}
|
|
592
|
-
renderText(response) {
|
|
593
|
-
const data = response.body || {};
|
|
594
|
-
response.setContentType('text/plain');
|
|
595
|
-
const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
|
|
596
|
-
return (`${data.statusCode} ${httpStatusCodes[data.statusCode]}\n${data.message}` +
|
|
597
|
-
`\n\n${keys.length > 0
|
|
598
|
-
? `${JSON.stringify({
|
|
599
|
-
...data,
|
|
600
|
-
statusCode: undefined,
|
|
601
|
-
message: undefined,
|
|
602
|
-
error: undefined,
|
|
603
|
-
}, null, ' ')}`
|
|
604
|
-
: ''}`);
|
|
605
|
-
}
|
|
606
|
-
renderJson(response) {
|
|
607
|
-
const data = response.body || {};
|
|
608
|
-
response.setContentType('application/json');
|
|
609
|
-
const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
|
|
610
|
-
return (`{"statusCode":${escapeQuotes(data.statusCode)},` +
|
|
611
|
-
`"error":"${escapeQuotes(data.error)}",` +
|
|
612
|
-
`"message":"${escapeQuotes(data.message)}"` +
|
|
613
|
-
`${keys.length > 0
|
|
614
|
-
? `,${keys.map(k => `"${escapeQuotes(k)}":${JSON.stringify(data[k])}`).join(',')}`
|
|
615
|
-
: ''}}`);
|
|
616
|
-
}
|
|
617
|
-
render(response) {
|
|
618
|
-
const { acceptsJson, acceptsText, acceptsHtml } = useAccept();
|
|
619
|
-
response.status = response.body?.statusCode || 500;
|
|
620
|
-
if (acceptsJson()) {
|
|
621
|
-
return this.renderJson(response);
|
|
622
|
-
}
|
|
623
|
-
else if (acceptsHtml()) {
|
|
624
|
-
return this.renderHtml(response);
|
|
625
|
-
}
|
|
626
|
-
else if (acceptsText()) {
|
|
627
|
-
return this.renderText(response);
|
|
628
|
-
}
|
|
629
|
-
else {
|
|
630
|
-
return this.renderJson(response);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
function escapeQuotes(s) {
|
|
635
|
-
return (typeof s === 'number' ? s : s || '').toString().replace(/"/g, '\\"');
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
class HttpError extends Error {
|
|
639
|
-
constructor(code = 500, _body = '') {
|
|
640
|
-
super(typeof _body === 'string' ? _body : _body.message);
|
|
641
|
-
this.code = code;
|
|
642
|
-
this._body = _body;
|
|
643
|
-
this.name = 'HttpError';
|
|
644
|
-
}
|
|
645
|
-
get body() {
|
|
646
|
-
return typeof this._body === 'string'
|
|
647
|
-
? {
|
|
648
|
-
statusCode: this.code,
|
|
649
|
-
message: this.message,
|
|
650
|
-
error: httpStatusCodes[this.code],
|
|
651
|
-
}
|
|
652
|
-
: {
|
|
653
|
-
...this._body,
|
|
654
|
-
statusCode: this.code,
|
|
655
|
-
message: this.message,
|
|
656
|
-
error: httpStatusCodes[this.code],
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
attachRenderer(renderer) {
|
|
660
|
-
this.renderer = renderer;
|
|
661
|
-
}
|
|
662
|
-
getRenderer() {
|
|
663
|
-
return this.renderer;
|
|
664
|
-
}
|
|
786
|
+
const { store } = useHttpContext();
|
|
787
|
+
const url = useRequest().url || "";
|
|
788
|
+
const { init } = store("searchParams");
|
|
789
|
+
const rawSearchParams = () => init("raw", () => {
|
|
790
|
+
const i = url.indexOf("?");
|
|
791
|
+
return i >= 0 ? url.slice(i) : "";
|
|
792
|
+
});
|
|
793
|
+
const urlSearchParams = () => init("urlSearchParams", () => new WooksURLSearchParams(rawSearchParams()));
|
|
794
|
+
return {
|
|
795
|
+
rawSearchParams,
|
|
796
|
+
urlSearchParams,
|
|
797
|
+
jsonSearchParams: () => urlSearchParams().toJson()
|
|
798
|
+
};
|
|
665
799
|
}
|
|
666
800
|
|
|
801
|
+
//#endregion
|
|
802
|
+
//#region packages/event-http/src/response/core.ts
|
|
667
803
|
const defaultStatus = {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
804
|
+
GET: EHttpStatusCode.OK,
|
|
805
|
+
POST: EHttpStatusCode.Created,
|
|
806
|
+
PUT: EHttpStatusCode.Created,
|
|
807
|
+
PATCH: EHttpStatusCode.Accepted,
|
|
808
|
+
DELETE: EHttpStatusCode.Accepted
|
|
673
809
|
};
|
|
674
810
|
const baseRenderer = new BaseHttpResponseRenderer();
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
res.writeHead(this.status, {
|
|
821
|
-
...additionalHeaders,
|
|
822
|
-
...this._headers,
|
|
823
|
-
});
|
|
824
|
-
await respondWithFetch(this.body.body, res);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
else {
|
|
828
|
-
const renderedBody = this.renderer.render(this);
|
|
829
|
-
this.mergeStatus(renderedBody);
|
|
830
|
-
res
|
|
831
|
-
.writeHead(this.status, {
|
|
832
|
-
'content-length': Buffer.byteLength(renderedBody),
|
|
833
|
-
...this._headers,
|
|
834
|
-
})
|
|
835
|
-
.end(method === 'HEAD' ? '' : renderedBody);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
}
|
|
811
|
+
var BaseHttpResponse = class {
|
|
812
|
+
constructor(renderer = baseRenderer) {
|
|
813
|
+
this.renderer = renderer;
|
|
814
|
+
}
|
|
815
|
+
_status = 0;
|
|
816
|
+
_body;
|
|
817
|
+
_headers = {};
|
|
818
|
+
get status() {
|
|
819
|
+
return this._status;
|
|
820
|
+
}
|
|
821
|
+
set status(value) {
|
|
822
|
+
this._status = value;
|
|
823
|
+
}
|
|
824
|
+
get body() {
|
|
825
|
+
return this._body;
|
|
826
|
+
}
|
|
827
|
+
set body(value) {
|
|
828
|
+
this._body = value;
|
|
829
|
+
}
|
|
830
|
+
setStatus(value) {
|
|
831
|
+
this.status = value;
|
|
832
|
+
return this;
|
|
833
|
+
}
|
|
834
|
+
setBody(value) {
|
|
835
|
+
this.body = value;
|
|
836
|
+
return this;
|
|
837
|
+
}
|
|
838
|
+
getContentType() {
|
|
839
|
+
return this._headers["content-type"];
|
|
840
|
+
}
|
|
841
|
+
setContentType(value) {
|
|
842
|
+
this._headers["content-type"] = value;
|
|
843
|
+
return this;
|
|
844
|
+
}
|
|
845
|
+
enableCors(origin = "*") {
|
|
846
|
+
this._headers["Access-Control-Allow-Origin"] = origin;
|
|
847
|
+
return this;
|
|
848
|
+
}
|
|
849
|
+
setCookie(name, value, attrs) {
|
|
850
|
+
const cookies = this._headers["set-cookie"] = this._headers["set-cookie"] || [];
|
|
851
|
+
cookies.push(renderCookie(name, {
|
|
852
|
+
value,
|
|
853
|
+
attrs: attrs || {}
|
|
854
|
+
}));
|
|
855
|
+
return this;
|
|
856
|
+
}
|
|
857
|
+
setCacheControl(data) {
|
|
858
|
+
this.setHeader("cache-control", renderCacheControl(data));
|
|
859
|
+
}
|
|
860
|
+
setCookieRaw(rawValue) {
|
|
861
|
+
const cookies = this._headers["set-cookie"] = this._headers["set-cookie"] || [];
|
|
862
|
+
cookies.push(rawValue);
|
|
863
|
+
return this;
|
|
864
|
+
}
|
|
865
|
+
header(name, value) {
|
|
866
|
+
this._headers[name] = value;
|
|
867
|
+
return this;
|
|
868
|
+
}
|
|
869
|
+
setHeader(name, value) {
|
|
870
|
+
return this.header(name, value);
|
|
871
|
+
}
|
|
872
|
+
getHeader(name) {
|
|
873
|
+
return this._headers[name];
|
|
874
|
+
}
|
|
875
|
+
mergeHeaders() {
|
|
876
|
+
const { headers } = useSetHeaders();
|
|
877
|
+
const { cookies, removeCookie } = useSetCookies();
|
|
878
|
+
const newCookies = this._headers["set-cookie"] || [];
|
|
879
|
+
for (const cookie of newCookies) removeCookie(cookie.slice(0, cookie.indexOf("=")));
|
|
880
|
+
this._headers = {
|
|
881
|
+
...headers(),
|
|
882
|
+
...this._headers
|
|
883
|
+
};
|
|
884
|
+
const setCookie = [...newCookies, ...cookies()];
|
|
885
|
+
if (setCookie.length > 0) this._headers["set-cookie"] = setCookie;
|
|
886
|
+
return this;
|
|
887
|
+
}
|
|
888
|
+
mergeStatus(renderedBody) {
|
|
889
|
+
this.status = this.status || useResponse().status();
|
|
890
|
+
if (!this.status) {
|
|
891
|
+
const { method } = useRequest();
|
|
892
|
+
this.status = renderedBody ? defaultStatus[method] || EHttpStatusCode.OK : EHttpStatusCode.NoContent;
|
|
893
|
+
}
|
|
894
|
+
return this;
|
|
895
|
+
}
|
|
896
|
+
mergeFetchStatus(fetchStatus) {
|
|
897
|
+
this.status = this.status || useResponse().status() || fetchStatus;
|
|
898
|
+
}
|
|
899
|
+
panic(text, logger) {
|
|
900
|
+
const error = new Error(text);
|
|
901
|
+
logger.error(error);
|
|
902
|
+
throw error;
|
|
903
|
+
}
|
|
904
|
+
async respond() {
|
|
905
|
+
const { rawResponse, hasResponded } = useResponse();
|
|
906
|
+
const { method, rawRequest } = useRequest();
|
|
907
|
+
const logger = useEventLogger("http-response") || console;
|
|
908
|
+
if (hasResponded()) this.panic("The response was already sent.", logger);
|
|
909
|
+
this.mergeHeaders();
|
|
910
|
+
const res = rawResponse();
|
|
911
|
+
if (this.body instanceof Readable$1) {
|
|
912
|
+
const stream = this.body;
|
|
913
|
+
this.mergeStatus("ok");
|
|
914
|
+
res.writeHead(this.status, { ...this._headers });
|
|
915
|
+
rawRequest.once("close", () => {
|
|
916
|
+
stream.destroy();
|
|
917
|
+
});
|
|
918
|
+
if (method === "HEAD") {
|
|
919
|
+
stream.destroy();
|
|
920
|
+
res.end();
|
|
921
|
+
} else return new Promise((resolve, reject) => {
|
|
922
|
+
stream.on("error", (e) => {
|
|
923
|
+
stream.destroy();
|
|
924
|
+
res.end();
|
|
925
|
+
reject(e);
|
|
926
|
+
});
|
|
927
|
+
stream.on("close", () => {
|
|
928
|
+
stream.destroy();
|
|
929
|
+
resolve(undefined);
|
|
930
|
+
});
|
|
931
|
+
stream.pipe(res);
|
|
932
|
+
});
|
|
933
|
+
} else if (globalThis.Response && this.body instanceof Response) {
|
|
934
|
+
this.mergeFetchStatus(this.body.status);
|
|
935
|
+
if (method === "HEAD") res.end();
|
|
936
|
+
else {
|
|
937
|
+
const additionalHeaders = {};
|
|
938
|
+
if (this.body.headers.get("content-length")) additionalHeaders["content-length"] = this.body.headers.get("content-length");
|
|
939
|
+
if (this.body.headers.get("content-type")) additionalHeaders["content-type"] = this.body.headers.get("content-type");
|
|
940
|
+
res.writeHead(this.status, {
|
|
941
|
+
...additionalHeaders,
|
|
942
|
+
...this._headers
|
|
943
|
+
});
|
|
944
|
+
await respondWithFetch(this.body.body, res);
|
|
945
|
+
}
|
|
946
|
+
} else {
|
|
947
|
+
const renderedBody = this.renderer.render(this);
|
|
948
|
+
this.mergeStatus(renderedBody);
|
|
949
|
+
res.writeHead(this.status, {
|
|
950
|
+
"content-length": Buffer.byteLength(renderedBody),
|
|
951
|
+
...this._headers
|
|
952
|
+
}).end(method === "HEAD" ? "" : renderedBody);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
};
|
|
839
956
|
async function respondWithFetch(fetchBody, res) {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
catch (error) {
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
res.end();
|
|
957
|
+
if (fetchBody) try {
|
|
958
|
+
for await (const chunk of fetchBody) res.write(chunk);
|
|
959
|
+
} catch (error) {}
|
|
960
|
+
res.end();
|
|
850
961
|
}
|
|
851
962
|
|
|
963
|
+
//#endregion
|
|
964
|
+
//#region packages/event-http/src/response/factory.ts
|
|
852
965
|
function createWooksResponder(renderer = new BaseHttpResponseRenderer(), errorRenderer = new HttpErrorRenderer()) {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
else if (data instanceof BaseHttpResponse) {
|
|
871
|
-
return data;
|
|
872
|
-
}
|
|
873
|
-
else {
|
|
874
|
-
return new BaseHttpResponse(renderer).setBody(data);
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
return {
|
|
878
|
-
createResponse,
|
|
879
|
-
respond: (data) => createResponse(data)?.respond(),
|
|
880
|
-
};
|
|
966
|
+
function createResponse(data) {
|
|
967
|
+
const { hasResponded } = useResponse();
|
|
968
|
+
if (hasResponded()) return null;
|
|
969
|
+
if (data instanceof Error) {
|
|
970
|
+
const r = new BaseHttpResponse(errorRenderer);
|
|
971
|
+
let httpError;
|
|
972
|
+
if (data instanceof HttpError) httpError = data;
|
|
973
|
+
else httpError = new HttpError(500, data.message);
|
|
974
|
+
r.setBody(httpError.body);
|
|
975
|
+
return r;
|
|
976
|
+
} else if (data instanceof BaseHttpResponse) return data;
|
|
977
|
+
else return new BaseHttpResponse(renderer).setBody(data);
|
|
978
|
+
}
|
|
979
|
+
return {
|
|
980
|
+
createResponse,
|
|
981
|
+
respond: (data) => createResponse(data)?.respond()
|
|
982
|
+
};
|
|
881
983
|
}
|
|
882
984
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
}
|
|
985
|
+
//#endregion
|
|
986
|
+
//#region packages/event-http/src/http-adapter.ts
|
|
987
|
+
var WooksHttp = class extends WooksAdapterBase {
|
|
988
|
+
logger;
|
|
989
|
+
constructor(opts, wooks) {
|
|
990
|
+
super(wooks, opts?.logger, opts?.router);
|
|
991
|
+
this.opts = opts;
|
|
992
|
+
this.logger = opts?.logger || this.getLogger(`${"\x1B[96m"}[wooks-http]`);
|
|
993
|
+
}
|
|
994
|
+
all(path, handler) {
|
|
995
|
+
return this.on("*", path, handler);
|
|
996
|
+
}
|
|
997
|
+
get(path, handler) {
|
|
998
|
+
return this.on("GET", path, handler);
|
|
999
|
+
}
|
|
1000
|
+
post(path, handler) {
|
|
1001
|
+
return this.on("POST", path, handler);
|
|
1002
|
+
}
|
|
1003
|
+
put(path, handler) {
|
|
1004
|
+
return this.on("PUT", path, handler);
|
|
1005
|
+
}
|
|
1006
|
+
patch(path, handler) {
|
|
1007
|
+
return this.on("PATCH", path, handler);
|
|
1008
|
+
}
|
|
1009
|
+
delete(path, handler) {
|
|
1010
|
+
return this.on("DELETE", path, handler);
|
|
1011
|
+
}
|
|
1012
|
+
head(path, handler) {
|
|
1013
|
+
return this.on("HEAD", path, handler);
|
|
1014
|
+
}
|
|
1015
|
+
options(path, handler) {
|
|
1016
|
+
return this.on("OPTIONS", path, handler);
|
|
1017
|
+
}
|
|
1018
|
+
server;
|
|
1019
|
+
async listen(port, hostname, backlog, listeningListener) {
|
|
1020
|
+
const server = this.server = http.createServer(this.getServerCb());
|
|
1021
|
+
return new Promise((resolve, reject) => {
|
|
1022
|
+
server.once("listening", resolve);
|
|
1023
|
+
server.once("error", reject);
|
|
1024
|
+
let args = [
|
|
1025
|
+
port,
|
|
1026
|
+
hostname,
|
|
1027
|
+
backlog,
|
|
1028
|
+
listeningListener
|
|
1029
|
+
];
|
|
1030
|
+
const ui = args.indexOf(undefined);
|
|
1031
|
+
if (ui >= 0) args = args.slice(0, ui);
|
|
1032
|
+
server.listen(...args);
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Stops the server if it was attached or passed via argument
|
|
1037
|
+
* @param server
|
|
1038
|
+
*/
|
|
1039
|
+
close(server) {
|
|
1040
|
+
const srv = server || this.server;
|
|
1041
|
+
return new Promise((resolve, reject) => {
|
|
1042
|
+
srv?.close((err) => {
|
|
1043
|
+
if (err) {
|
|
1044
|
+
reject(err);
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
resolve(srv);
|
|
1048
|
+
});
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
/**
|
|
1052
|
+
* Returns http(s) server that was attached to Wooks
|
|
1053
|
+
*
|
|
1054
|
+
* See attachServer method docs
|
|
1055
|
+
* @returns Server
|
|
1056
|
+
*/
|
|
1057
|
+
getServer() {
|
|
1058
|
+
return this.server;
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Attaches http(s) server instance
|
|
1062
|
+
* to Wooks.
|
|
1063
|
+
*
|
|
1064
|
+
* Use it only if you want to `close` method to stop the server.
|
|
1065
|
+
* @param server Server
|
|
1066
|
+
*/
|
|
1067
|
+
attachServer(server) {
|
|
1068
|
+
this.server = server;
|
|
1069
|
+
}
|
|
1070
|
+
responder = createWooksResponder();
|
|
1071
|
+
respond(data) {
|
|
1072
|
+
void this.responder.respond(data)?.catch((e) => {
|
|
1073
|
+
this.logger.error("Uncaught response exception", e);
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Returns server callback function
|
|
1078
|
+
* that can be passed to any node server:
|
|
1079
|
+
* ```js
|
|
1080
|
+
* import { createHttpApp } from '@wooksjs/event-http'
|
|
1081
|
+
* import http from 'http'
|
|
1082
|
+
*
|
|
1083
|
+
* const app = createHttpApp()
|
|
1084
|
+
* const server = http.createServer(app.getServerCb())
|
|
1085
|
+
* server.listen(3000)
|
|
1086
|
+
* ```
|
|
1087
|
+
*/
|
|
1088
|
+
getServerCb() {
|
|
1089
|
+
return (req, res) => {
|
|
1090
|
+
const runInContext = createHttpContext({
|
|
1091
|
+
req,
|
|
1092
|
+
res
|
|
1093
|
+
}, this.mergeEventOptions(this.opts?.eventOptions));
|
|
1094
|
+
runInContext(async () => {
|
|
1095
|
+
const { handlers } = this.wooks.lookup(req.method, req.url);
|
|
1096
|
+
if (handlers || this.opts?.onNotFound) try {
|
|
1097
|
+
return await this.processHandlers(handlers || [this.opts?.onNotFound]);
|
|
1098
|
+
} catch (error) {
|
|
1099
|
+
this.logger.error("Internal error, please report", error);
|
|
1100
|
+
this.respond(error);
|
|
1101
|
+
return error;
|
|
1102
|
+
}
|
|
1103
|
+
else {
|
|
1104
|
+
this.logger.debug(`404 Not found (${req.method})${req.url}`);
|
|
1105
|
+
const error = new HttpError(404);
|
|
1106
|
+
this.respond(error);
|
|
1107
|
+
return error;
|
|
1108
|
+
}
|
|
1109
|
+
});
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
async processHandlers(handlers) {
|
|
1113
|
+
const { store } = useHttpContext();
|
|
1114
|
+
for (const [i, handler] of handlers.entries()) {
|
|
1115
|
+
const isLastHandler = handlers.length === i + 1;
|
|
1116
|
+
try {
|
|
1117
|
+
const promise = handler();
|
|
1118
|
+
const result = await promise;
|
|
1119
|
+
this.respond(result);
|
|
1120
|
+
return result;
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
if (error instanceof HttpError) {} else this.logger.error(`Uncaught route handler exception: ${store("event").get("req")?.url || ""}`, error);
|
|
1123
|
+
if (isLastHandler) {
|
|
1124
|
+
this.respond(error);
|
|
1125
|
+
return error;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
997
1131
|
function createHttpApp(opts, wooks) {
|
|
998
|
-
|
|
1132
|
+
return new WooksHttp(opts, wooks);
|
|
999
1133
|
}
|
|
1000
1134
|
|
|
1001
|
-
|
|
1135
|
+
//#endregion
|
|
1136
|
+
export { BaseHttpResponse, BaseHttpResponseRenderer, DEFAULT_LIMITS, EHttpStatusCode, HttpError, HttpErrorRenderer, WooksHttp, WooksURLSearchParams, createHttpApp, createHttpContext, createWooksResponder, httpStatusCodes, renderCacheControl, useAccept, useAuthorization, useCookies, useEventLogger, useHeaders, useHttpContext, useRequest, useResponse, useRouteParams, useSearchParams, useSetCacheControl, useSetCookie, useSetCookies, useSetHeader, useSetHeaders, useStatus };
|