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