@wooksjs/event-http 0.4.25 → 0.4.27

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
@@ -2,9 +2,9 @@
2
2
 
3
3
  var eventCore = require('@wooksjs/event-core');
4
4
  var url = require('url');
5
- var stream = require('stream');
6
- var wooks = require('wooks');
7
5
  var http = require('http');
6
+ var wooks = require('wooks');
7
+ var stream = require('stream');
8
8
 
9
9
  function createHttpContext(data, options) {
10
10
  return eventCore.createEventContext({
@@ -19,58 +19,106 @@ function useHttpContext() {
19
19
  return eventCore.useEventContext('HTTP');
20
20
  }
21
21
 
22
+ function escapeRegex(s) {
23
+ return s.replace(/[$()*+./?[\\\]^{|}-]/g, '\\$&');
24
+ }
25
+ function safeDecode(f, v) {
26
+ try {
27
+ return f(v);
28
+ }
29
+ catch (error) {
30
+ return v;
31
+ }
32
+ }
33
+ function safeDecodeURIComponent(uri) {
34
+ if (!uri.includes('%')) {
35
+ return uri;
36
+ }
37
+ return safeDecode(decodeURIComponent, uri);
38
+ }
39
+
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];
51
+ }
52
+ 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,
61
+ };
62
+
63
+ 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}`;
76
+ }
77
+ 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'}` : '',
85
+ };
86
+
22
87
  const xForwardedFor = 'x-forwarded-for';
23
88
  function useRequest() {
24
89
  const { store } = useHttpContext();
25
90
  const { init } = store('request');
26
91
  const event = store('event');
27
- const { req } = event.value;
28
- const rawBody = () => init('rawBody', () => {
29
- return new Promise((resolve, reject) => {
30
- let body = Buffer.from('');
31
- req.on('data', function (chunk) {
32
- body = Buffer.concat([body, chunk]);
33
- });
34
- req.on('error', function (err) {
35
- reject(err);
36
- });
37
- req.on('end', function () {
38
- resolve(body);
39
- });
92
+ const req = event.get('req');
93
+ const rawBody = async () => init('rawBody', async () => new Promise((resolve, reject) => {
94
+ let body = Buffer.from('');
95
+ req.on('data', chunk => {
96
+ body = Buffer.concat([body, chunk]);
40
97
  });
41
- });
98
+ req.on('error', err => {
99
+ reject(err);
100
+ });
101
+ req.on('end', () => {
102
+ resolve(body);
103
+ });
104
+ }));
42
105
  const reqId = eventCore.useEventId().getId;
43
106
  const forwardedIp = () => init('forwardedIp', () => {
44
- if (typeof req.headers[xForwardedFor] === 'string' &&
45
- req.headers[xForwardedFor]) {
46
- return req.headers[xForwardedFor]
47
- .split(',')
48
- .shift()
49
- ?.trim();
107
+ if (typeof req.headers[xForwardedFor] === 'string' && req.headers[xForwardedFor]) {
108
+ return req.headers[xForwardedFor].split(',').shift()?.trim();
50
109
  }
51
110
  else {
52
111
  return '';
53
112
  }
54
113
  });
55
- const remoteIp = () => init('remoteIp', () => req.socket?.remoteAddress || req.connection?.remoteAddress || '');
114
+ const remoteIp = () => init('remoteIp', () => req.socket.remoteAddress || req.connection.remoteAddress || '');
56
115
  function getIp(options) {
57
- if (options?.trustProxy) {
58
- return forwardedIp() || getIp();
59
- }
60
- else {
61
- return remoteIp();
62
- }
116
+ return options?.trustProxy ? forwardedIp() || getIp() : remoteIp();
63
117
  }
64
- const getIpList = () => init('ipList', () => {
65
- return {
66
- remoteIp: req.socket?.remoteAddress ||
67
- req.connection?.remoteAddress ||
68
- '',
69
- forwarded: (req.headers[xForwardedFor] || '')
70
- .split(',')
71
- .map((s) => s.trim()),
72
- };
73
- });
118
+ const getIpList = () => init('ipList', () => ({
119
+ remoteIp: req.socket.remoteAddress || req.connection.remoteAddress || '',
120
+ forwarded: (req.headers[xForwardedFor] || '').split(',').map(s => s.trim()),
121
+ }));
74
122
  return {
75
123
  rawRequest: req,
76
124
  url: req.url,
@@ -113,13 +161,73 @@ function useSetHeader(name) {
113
161
  return hook(name);
114
162
  }
115
163
 
164
+ function useCookies() {
165
+ const { store } = useHttpContext();
166
+ const { cookie } = useHeaders();
167
+ const { init } = store('cookies');
168
+ const getCookie = (name) => init(name, () => {
169
+ if (cookie) {
170
+ const result = new RegExp(`(?:^|; )${escapeRegex(name)}=(.*?)(?:;?$|; )`, 'i').exec(cookie);
171
+ return result?.[1] ? safeDecodeURIComponent(result[1]) : null;
172
+ }
173
+ else {
174
+ return null;
175
+ }
176
+ });
177
+ return {
178
+ rawCookies: cookie,
179
+ getCookie,
180
+ };
181
+ }
182
+ function useSetCookies() {
183
+ const { store } = useHttpContext();
184
+ const cookiesStore = store('setCookies');
185
+ function setCookie(name, value, attrs) {
186
+ cookiesStore.set(name, {
187
+ value,
188
+ attrs: attrs || {},
189
+ });
190
+ }
191
+ function cookies() {
192
+ return cookiesStore
193
+ .entries()
194
+ .filter(a => Boolean(a[1]))
195
+ .map(([key, value]) => renderCookie(key, value));
196
+ }
197
+ return {
198
+ setCookie,
199
+ getCookie: cookiesStore.get,
200
+ removeCookie: cookiesStore.del,
201
+ clearCookies: cookiesStore.clear,
202
+ cookies,
203
+ };
204
+ }
205
+ function useSetCookie(name) {
206
+ const { setCookie, getCookie } = useSetCookies();
207
+ const valueHook = eventCore.attachHook({
208
+ name,
209
+ type: 'cookie',
210
+ }, {
211
+ get: () => getCookie(name).value,
212
+ set: (value) => {
213
+ setCookie(name, value, getCookie(name).attrs);
214
+ },
215
+ });
216
+ return eventCore.attachHook(valueHook, {
217
+ get: () => getCookie(name).attrs,
218
+ set: (attrs) => {
219
+ setCookie(name, getCookie(name).value || '', attrs);
220
+ },
221
+ }, 'attrs');
222
+ }
223
+
116
224
  function useAccept() {
117
225
  const { store } = useHttpContext();
118
226
  const { accept } = useHeaders();
119
227
  const accepts = (mime) => {
120
228
  const { set, get, has } = store('accept');
121
229
  if (!has(mime)) {
122
- return set(mime, !!(accept && (accept === '*/*' || accept.indexOf(mime) >= 0)));
230
+ return set(mime, Boolean(accept && (accept === '*/*' || accept.includes(mime))));
123
231
  }
124
232
  return get(mime);
125
233
  };
@@ -171,62 +279,39 @@ function useAuthorization() {
171
279
  };
172
280
  }
173
281
 
174
- function convertTime(time, unit = 'ms') {
175
- if (typeof time === 'number')
176
- return time / units[unit];
177
- const rg = /(\d+)(\w+)/g;
178
- let t = 0;
179
- let r;
180
- while ((r = rg.exec(time))) {
181
- t += Number(r[1]) * (units[r[2]] || 0);
182
- }
183
- return t / units[unit];
184
- }
185
- const units = {
186
- ms: 1,
187
- s: 1000,
188
- m: 1000 * 60,
189
- h: 1000 * 60 * 60,
190
- d: 1000 * 60 * 60 * 24,
191
- w: 1000 * 60 * 60 * 24 * 7,
192
- M: 1000 * 60 * 60 * 24 * 30,
193
- Y: 1000 * 60 * 60 * 24 * 365,
194
- };
195
-
196
282
  function renderCacheControl(data) {
197
283
  let attrs = '';
198
284
  for (const [a, v] of Object.entries(data)) {
199
- if (typeof v === 'undefined')
285
+ if (v === undefined) {
200
286
  continue;
287
+ }
201
288
  const func = cacheControlFunc[a];
202
289
  if (typeof func === 'function') {
203
290
  const val = func(v);
204
291
  if (val) {
205
- attrs += attrs ? ', ' + val : val;
292
+ attrs += attrs ? `, ${val}` : val;
206
293
  }
207
294
  }
208
295
  else {
209
- throw new Error('Unknown Cache-Control attribute ' + a);
296
+ throw new TypeError(`Unknown Cache-Control attribute ${a}`);
210
297
  }
211
298
  }
212
299
  return attrs;
213
300
  }
214
301
  const cacheControlFunc = {
215
- mustRevalidate: (v) => v ? 'must-revalidate' : '',
302
+ mustRevalidate: (v) => (v ? 'must-revalidate' : ''),
216
303
  noCache: (v) => v ? (typeof v === 'string' ? `no-cache="${v}"` : 'no-cache') : '',
217
304
  noStore: (v) => (v ? 'no-store' : ''),
218
305
  noTransform: (v) => (v ? 'no-transform' : ''),
219
306
  public: (v) => (v ? 'public' : ''),
220
307
  private: (v) => v ? (typeof v === 'string' ? `private="${v}"` : 'private') : '',
221
- proxyRevalidate: (v) => v ? 'proxy-revalidate' : '',
222
- maxAge: (v) => 'max-age=' + convertTime(v, 's').toString(),
223
- sMaxage: (v) => 's-maxage=' + convertTime(v, 's').toString(),
308
+ proxyRevalidate: (v) => (v ? 'proxy-revalidate' : ''),
309
+ maxAge: (v) => `max-age=${convertTime(v, 's').toString()}`,
310
+ sMaxage: (v) => `s-maxage=${convertTime(v, 's').toString()}`,
224
311
  };
225
312
 
226
313
  const renderAge = (v) => convertTime(v, 's').toString();
227
- const renderExpires = (v) => typeof v === 'string' || typeof v === 'number'
228
- ? new Date(v).toUTCString()
229
- : v.toUTCString();
314
+ const renderExpires = (v) => typeof v === 'string' || typeof v === 'number' ? new Date(v).toUTCString() : v.toUTCString();
230
315
  const renderPragmaNoCache = (v) => (v ? 'no-cache' : '');
231
316
  function useSetCacheControl() {
232
317
  const { setHeader } = useSetHeaders();
@@ -253,15 +338,16 @@ function useSetCacheControl() {
253
338
  function useResponse() {
254
339
  const { store } = useHttpContext();
255
340
  const event = store('event');
256
- const { res } = event.value;
341
+ const res = event.get('res');
257
342
  const responded = store('response').hook('responded');
258
343
  const statusCode = store('status').hook('code');
259
344
  function status(code) {
260
- return (statusCode.value = code ? code : statusCode.value);
345
+ return (statusCode.value = code || statusCode.value);
261
346
  }
262
347
  const rawResponse = (options) => {
263
- if (!options || !options.passthrough)
348
+ if (!options || !options.passthrough) {
264
349
  responded.value = true;
350
+ }
265
351
  return res;
266
352
  };
267
353
  return {
@@ -278,108 +364,6 @@ function useStatus() {
278
364
  return store('status').hook('code');
279
365
  }
280
366
 
281
- function renderCookie(key, data) {
282
- let attrs = '';
283
- for (const [a, v] of Object.entries(data.attrs)) {
284
- const func = cookieAttrFunc[a];
285
- if (typeof func === 'function') {
286
- const val = func(v);
287
- attrs += val ? '; ' + val : '';
288
- }
289
- else {
290
- throw new Error('Unknown Set-Cookie attribute ' + a);
291
- }
292
- }
293
- return `${key}=${encodeURIComponent(data.value)}${attrs}`;
294
- }
295
- const cookieAttrFunc = {
296
- expires: (v) => 'Expires=' +
297
- (typeof v === 'string' || typeof v === 'number'
298
- ? new Date(v).toUTCString()
299
- : v.toUTCString()),
300
- maxAge: (v) => 'Max-Age=' + convertTime(v, 's').toString(),
301
- domain: (v) => 'Domain=' + v,
302
- path: (v) => 'Path=' + v,
303
- secure: (v) => (v ? 'Secure' : ''),
304
- httpOnly: (v) => (v ? 'HttpOnly' : ''),
305
- sameSite: (v) => v ? 'SameSite=' + (typeof v === 'string' ? v : 'Strict') : '',
306
- };
307
-
308
- function escapeRegex(s) {
309
- return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
310
- }
311
- function safeDecode(f, v) {
312
- try {
313
- return f(v);
314
- }
315
- catch (e) {
316
- return v;
317
- }
318
- }
319
- function safeDecodeURIComponent(uri) {
320
- if (uri.indexOf('%') < 0)
321
- return uri;
322
- return safeDecode(decodeURIComponent, uri);
323
- }
324
-
325
- function useCookies() {
326
- const { store } = useHttpContext();
327
- const { cookie } = useHeaders();
328
- const { init } = store('cookies');
329
- const getCookie = (name) => init(name, () => {
330
- if (cookie) {
331
- const result = new RegExp(`(?:^|; )${escapeRegex(name)}=(.*?)(?:;?$|; )`, 'i').exec(cookie);
332
- return result && result[1]
333
- ? safeDecodeURIComponent(result[1])
334
- : null;
335
- }
336
- else {
337
- return null;
338
- }
339
- });
340
- return {
341
- rawCookies: cookie,
342
- getCookie,
343
- };
344
- }
345
- function useSetCookies() {
346
- const { store } = useHttpContext();
347
- const cookiesStore = store('setCookies');
348
- function setCookie(name, value, attrs) {
349
- cookiesStore.set(name, {
350
- value,
351
- attrs: attrs || {},
352
- });
353
- }
354
- function cookies() {
355
- return cookiesStore
356
- .entries()
357
- .filter((a) => !!a[1])
358
- .map(([key, value]) => renderCookie(key, value));
359
- }
360
- return {
361
- setCookie,
362
- getCookie: cookiesStore.get,
363
- removeCookie: cookiesStore.del,
364
- clearCookies: cookiesStore.clear,
365
- cookies,
366
- };
367
- }
368
- function useSetCookie(name) {
369
- const { setCookie, getCookie } = useSetCookies();
370
- const valueHook = eventCore.attachHook({
371
- name,
372
- type: 'cookie',
373
- }, {
374
- get: () => getCookie(name)?.value,
375
- set: (value) => setCookie(name, value, getCookie(name)?.attrs),
376
- });
377
- return eventCore.attachHook(valueHook, {
378
- get: () => getCookie(name)?.attrs,
379
- set: (attrs) => setCookie(name, getCookie(name)?.value || '', attrs),
380
- }, 'attrs');
381
- }
382
-
383
367
  class WooksURLSearchParams extends url.URLSearchParams {
384
368
  toJson() {
385
369
  const json = {};
@@ -420,89 +404,91 @@ class BaseHttpResponseRenderer {
420
404
  if (typeof response.body === 'string' ||
421
405
  typeof response.body === 'boolean' ||
422
406
  typeof response.body === 'number') {
423
- if (!response.getContentType())
407
+ if (!response.getContentType()) {
424
408
  response.setContentType('text/plain');
409
+ }
425
410
  return response.body.toString();
426
411
  }
427
- if (typeof response.body === 'undefined') {
412
+ if (response.body === undefined) {
428
413
  return '';
429
414
  }
430
415
  if (response.body instanceof Uint8Array) {
431
416
  return response.body;
432
417
  }
433
418
  if (typeof response.body === 'object') {
434
- if (!response.getContentType())
419
+ if (!response.getContentType()) {
435
420
  response.setContentType('application/json');
421
+ }
436
422
  return JSON.stringify(response.body);
437
423
  }
438
- throw new Error('Unsupported body format "' + typeof response.body + '"');
424
+ throw new Error(`Unsupported body format "${typeof response.body}"`);
439
425
  }
440
426
  }
441
427
 
442
428
  const httpStatusCodes = {
443
- [100]: 'Continue',
444
- [101]: 'Switching protocols',
445
- [102]: 'Processing',
446
- [103]: 'Early Hints',
447
- [200]: 'OK',
448
- [201]: 'Created',
449
- [202]: 'Accepted',
450
- [203]: 'Non-Authoritative Information',
451
- [204]: 'No Content',
452
- [205]: 'Reset Content',
453
- [206]: 'Partial Content',
454
- [207]: 'Multi-Status',
455
- [208]: 'Already Reported',
456
- [226]: 'IM Used',
457
- [300]: 'Multiple Choices',
458
- [301]: 'Moved Permanently',
459
- [302]: 'Found (Previously "Moved Temporarily")',
460
- [303]: 'See Other',
461
- [304]: 'Not Modified',
462
- [305]: 'Use Proxy',
463
- [306]: 'Switch Proxy',
464
- [307]: 'Temporary Redirect',
465
- [308]: 'Permanent Redirect',
466
- [400]: 'Bad Request',
467
- [401]: 'Unauthorized',
468
- [402]: 'Payment Required',
469
- [403]: 'Forbidden',
470
- [404]: 'Not Found',
471
- [405]: 'Method Not Allowed',
472
- [406]: 'Not Acceptable',
473
- [407]: 'Proxy Authentication Required',
474
- [408]: 'Request Timeout',
475
- [409]: 'Conflict',
476
- [410]: 'Gone',
477
- [411]: 'Length Required',
478
- [412]: 'Precondition Failed',
479
- [413]: 'Payload Too Large',
480
- [414]: 'URI Too Long',
481
- [415]: 'Unsupported Media Type',
482
- [416]: 'Range Not Satisfiable',
483
- [417]: 'Expectation Failed',
484
- [418]: 'I\'m a Teapot',
485
- [421]: 'Misdirected Request',
486
- [422]: 'Unprocessable Entity',
487
- [423]: 'Locked',
488
- [424]: 'Failed Dependency',
489
- [425]: 'Too Early',
490
- [426]: 'Upgrade Required',
491
- [428]: 'Precondition Required',
492
- [429]: 'Too Many Requests',
493
- [431]: 'Request Header Fields Too Large',
494
- [451]: 'Unavailable For Legal Reasons',
495
- [500]: 'Internal Server Error',
496
- [501]: 'Not Implemented',
497
- [502]: 'Bad Gateway',
498
- [503]: 'Service Unavailable',
499
- [504]: 'Gateway Timeout',
500
- [505]: 'HTTP Version Not Supported',
501
- [506]: 'Variant Also Negotiates',
502
- [507]: 'Insufficient Storage',
503
- [508]: 'Loop Detected',
504
- [510]: 'Not Extended',
505
- [511]: 'Network Authentication Required',
429
+ 100: 'Continue',
430
+ 101: 'Switching protocols',
431
+ 102: 'Processing',
432
+ 103: 'Early Hints',
433
+ 200: 'OK',
434
+ 201: 'Created',
435
+ 202: 'Accepted',
436
+ 203: 'Non-Authoritative Information',
437
+ 204: 'No Content',
438
+ 205: 'Reset Content',
439
+ 206: 'Partial Content',
440
+ 207: 'Multi-Status',
441
+ 208: 'Already Reported',
442
+ 226: 'IM Used',
443
+ 300: 'Multiple Choices',
444
+ 301: 'Moved Permanently',
445
+ 302: 'Found (Previously "Moved Temporarily")',
446
+ 303: 'See Other',
447
+ 304: 'Not Modified',
448
+ 305: 'Use Proxy',
449
+ 306: 'Switch Proxy',
450
+ 307: 'Temporary Redirect',
451
+ 308: 'Permanent Redirect',
452
+ 400: 'Bad Request',
453
+ 401: 'Unauthorized',
454
+ 402: 'Payment Required',
455
+ 403: 'Forbidden',
456
+ 404: 'Not Found',
457
+ 405: 'Method Not Allowed',
458
+ 406: 'Not Acceptable',
459
+ 407: 'Proxy Authentication Required',
460
+ 408: 'Request Timeout',
461
+ 409: 'Conflict',
462
+ 410: 'Gone',
463
+ 411: 'Length Required',
464
+ 412: 'Precondition Failed',
465
+ 413: 'Payload Too Large',
466
+ 414: 'URI Too Long',
467
+ 415: 'Unsupported Media Type',
468
+ 416: 'Range Not Satisfiable',
469
+ 417: 'Expectation Failed',
470
+ 418: "I'm a Teapot",
471
+ 421: 'Misdirected Request',
472
+ 422: 'Unprocessable Entity',
473
+ 423: 'Locked',
474
+ 424: 'Failed Dependency',
475
+ 425: 'Too Early',
476
+ 426: 'Upgrade Required',
477
+ 428: 'Precondition Required',
478
+ 429: 'Too Many Requests',
479
+ 431: 'Request Header Fields Too Large',
480
+ 451: 'Unavailable For Legal Reasons',
481
+ 500: 'Internal Server Error',
482
+ 501: 'Not Implemented',
483
+ 502: 'Bad Gateway',
484
+ 503: 'Service Unavailable',
485
+ 504: 'Gateway Timeout',
486
+ 505: 'HTTP Version Not Supported',
487
+ 506: 'Variant Also Negotiates',
488
+ 507: 'Insufficient Storage',
489
+ 508: 'Loop Detected',
490
+ 510: 'Not Extended',
491
+ 511: 'Network Authentication Required',
506
492
  };
507
493
  exports.EHttpStatusCode = void 0;
508
494
  (function (EHttpStatusCode) {
@@ -571,6 +557,110 @@ exports.EHttpStatusCode = void 0;
571
557
  EHttpStatusCode[EHttpStatusCode["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
572
558
  })(exports.EHttpStatusCode || (exports.EHttpStatusCode = {}));
573
559
 
560
+ const preStyles = 'font-family: monospace;' +
561
+ 'width: 100%;' +
562
+ 'max-width: 900px;' +
563
+ 'padding: 10px;' +
564
+ 'margin: 20px auto;' +
565
+ 'border-radius: 8px;' +
566
+ 'background-color: #494949;' +
567
+ 'box-shadow: 0px 0px 3px 2px rgb(255 255 255 / 20%);';
568
+ class HttpErrorRenderer extends BaseHttpResponseRenderer {
569
+ renderHtml(response) {
570
+ const data = response.body || {};
571
+ response.setContentType('text/html');
572
+ const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
573
+ return ('<html style="background-color: #333; color: #bbb;">' +
574
+ `<head><title>${data.statusCode} ${httpStatusCodes[data.statusCode]}</title></head>` +
575
+ `<body><center><h1>${data.statusCode} ${httpStatusCodes[data.statusCode]}</h1></center>` +
576
+ `<center><h4>${data.message}</h1></center><hr color="#666">` +
577
+ `<center style="color: #666;"> Wooks v${"0.4.27"} </center>` +
578
+ `${keys.length > 0
579
+ ? `<pre style="${preStyles}">${JSON.stringify({
580
+ ...data,
581
+ statusCode: undefined,
582
+ message: undefined,
583
+ error: undefined,
584
+ }, null, ' ')}</pre>`
585
+ : ''}` +
586
+ '</body></html>');
587
+ }
588
+ renderText(response) {
589
+ const data = response.body || {};
590
+ response.setContentType('text/plain');
591
+ const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
592
+ return (`${data.statusCode} ${httpStatusCodes[data.statusCode]}\n${data.message}` +
593
+ `\n\n${keys.length > 0
594
+ ? `${JSON.stringify({
595
+ ...data,
596
+ statusCode: undefined,
597
+ message: undefined,
598
+ error: undefined,
599
+ }, null, ' ')}`
600
+ : ''}`);
601
+ }
602
+ renderJson(response) {
603
+ const data = response.body || {};
604
+ response.setContentType('application/json');
605
+ const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
606
+ return (`{"statusCode":${escapeQuotes(data.statusCode)},` +
607
+ `"error":"${escapeQuotes(data.error)}",` +
608
+ `"message":"${escapeQuotes(data.message)}"` +
609
+ `${keys.length > 0
610
+ ?
611
+ `,${keys.map(k => `"${escapeQuotes(k)}":${JSON.stringify(data[k])}`).join(',')}`
612
+ : ''}}`);
613
+ }
614
+ render(response) {
615
+ const { acceptsJson, acceptsText, acceptsHtml } = useAccept();
616
+ response.status = response.body?.statusCode || 500;
617
+ if (acceptsJson()) {
618
+ return this.renderJson(response);
619
+ }
620
+ else if (acceptsHtml()) {
621
+ return this.renderHtml(response);
622
+ }
623
+ else if (acceptsText()) {
624
+ return this.renderText(response);
625
+ }
626
+ else {
627
+ return this.renderJson(response);
628
+ }
629
+ }
630
+ }
631
+ function escapeQuotes(s) {
632
+ return (typeof s === 'number' ? s : s || '').toString().replace(/"/g, '\\"');
633
+ }
634
+
635
+ class HttpError extends Error {
636
+ constructor(code = 500, _body = '') {
637
+ super(typeof _body === 'string' ? _body : _body.message);
638
+ this.code = code;
639
+ this._body = _body;
640
+ this.name = 'HttpError';
641
+ }
642
+ get body() {
643
+ return typeof this._body === 'string'
644
+ ? {
645
+ statusCode: this.code,
646
+ message: this.message,
647
+ error: httpStatusCodes[this.code],
648
+ }
649
+ : {
650
+ ...this._body,
651
+ statusCode: this.code,
652
+ message: this.message,
653
+ error: httpStatusCodes[this.code],
654
+ };
655
+ }
656
+ attachRenderer(renderer) {
657
+ this.renderer = renderer;
658
+ }
659
+ getRenderer() {
660
+ return this.renderer;
661
+ }
662
+ }
663
+
574
664
  const defaultStatus = {
575
665
  GET: exports.EHttpStatusCode.OK,
576
666
  POST: exports.EHttpStatusCode.Created,
@@ -651,7 +741,7 @@ class BaseHttpResponse {
651
741
  ...this._headers,
652
742
  };
653
743
  const setCookie = [...newCookies, ...cookies()];
654
- if (setCookie && setCookie.length) {
744
+ if (setCookie.length > 0) {
655
745
  this._headers['set-cookie'] = setCookie;
656
746
  }
657
747
  return this;
@@ -698,7 +788,7 @@ class BaseHttpResponse {
698
788
  }
699
789
  else {
700
790
  return new Promise((resolve, reject) => {
701
- stream.on('error', (e) => {
791
+ stream.on('error', e => {
702
792
  stream.destroy();
703
793
  res.end();
704
794
  reject(e);
@@ -711,8 +801,7 @@ class BaseHttpResponse {
711
801
  });
712
802
  }
713
803
  }
714
- else if (globalThis.Response &&
715
- this.body instanceof Response) {
804
+ else if (globalThis.Response && this.body instanceof Response) {
716
805
  this.mergeFetchStatus(this.body.status);
717
806
  if (method === 'HEAD') {
718
807
  res.end();
@@ -735,10 +824,12 @@ class BaseHttpResponse {
735
824
  else {
736
825
  const renderedBody = this.renderer.render(this);
737
826
  this.mergeStatus(renderedBody);
738
- res.writeHead(this.status, {
827
+ res
828
+ .writeHead(this.status, {
739
829
  'content-length': Buffer.byteLength(renderedBody),
740
830
  ...this._headers,
741
- }).end(method !== 'HEAD' ? renderedBody : '');
831
+ })
832
+ .end(method === 'HEAD' ? '' : renderedBody);
742
833
  }
743
834
  }
744
835
  }
@@ -749,133 +840,21 @@ async function respondWithFetch(fetchBody, res) {
749
840
  res.write(chunk);
750
841
  }
751
842
  }
752
- catch (e) {
843
+ catch (error) {
753
844
  }
754
845
  }
755
846
  res.end();
756
847
  }
757
848
 
758
- const preStyles = 'font-family: monospace;' +
759
- 'width: 100%;' +
760
- 'max-width: 900px;' +
761
- 'padding: 10px;' +
762
- 'margin: 20px auto;' +
763
- 'border-radius: 8px;' +
764
- 'background-color: #494949;' +
765
- 'box-shadow: 0px 0px 3px 2px rgb(255 255 255 / 20%);';
766
- class HttpErrorRenderer extends BaseHttpResponseRenderer {
767
- renderHtml(response) {
768
- const data = response.body || {};
769
- response.setContentType('text/html');
770
- const keys = Object.keys(data).filter((key) => !['statusCode', 'error', 'message'].includes(key));
771
- return ('<html style="background-color: #333; color: #bbb;">' +
772
- `<head><title>${data.statusCode} ${httpStatusCodes[data.statusCode]}</title></head>` +
773
- `<body><center><h1>${data.statusCode} ${httpStatusCodes[data.statusCode]}</h1></center>` +
774
- `<center><h4>${data.message}</h1></center><hr color="#666">` +
775
- `<center style="color: #666;"> Wooks v${"0.4.25"} </center>` +
776
- `${keys.length
777
- ? `<pre style="${preStyles}">${JSON.stringify({
778
- ...data,
779
- statusCode: undefined,
780
- message: undefined,
781
- error: undefined,
782
- }, null, ' ')}</pre>`
783
- : ''}` +
784
- '</body></html>');
785
- }
786
- renderText(response) {
787
- const data = response.body || {};
788
- response.setContentType('text/plain');
789
- const keys = Object.keys(data).filter((key) => !['statusCode', 'error', 'message'].includes(key));
790
- return (`${data.statusCode} ${httpStatusCodes[data.statusCode]}\n${data.message}` +
791
- `\n\n${keys.length
792
- ? `${JSON.stringify({
793
- ...data,
794
- statusCode: undefined,
795
- message: undefined,
796
- error: undefined,
797
- }, null, ' ')}`
798
- : ''}`);
799
- }
800
- renderJson(response) {
801
- const data = response.body || {};
802
- response.setContentType('application/json');
803
- const keys = Object.keys(data).filter((key) => !['statusCode', 'error', 'message'].includes(key));
804
- return (`{"statusCode":${escapeQuotes(data.statusCode)},` +
805
- `"error":"${escapeQuotes(data.error)}",` +
806
- `"message":"${escapeQuotes(data.message)}"` +
807
- `${keys.length
808
- ? ',' +
809
- keys
810
- .map((k) => `"${escapeQuotes(k)}":${JSON.stringify(data[k])}`)
811
- .join(',')
812
- : ''}}`);
813
- }
814
- render(response) {
815
- const { acceptsJson, acceptsText, acceptsHtml } = useAccept();
816
- response.status = response.body?.statusCode || 500;
817
- if (acceptsJson()) {
818
- return this.renderJson(response);
819
- }
820
- else if (acceptsHtml()) {
821
- return this.renderHtml(response);
822
- }
823
- else if (acceptsText()) {
824
- return this.renderText(response);
825
- }
826
- else {
827
- return this.renderJson(response);
828
- }
829
- }
830
- }
831
- function escapeQuotes(s) {
832
- return (typeof s === 'number' ? s : s || '')
833
- .toString()
834
- .replace(/[\""]/g, '\\"');
835
- }
836
-
837
- class HttpError extends Error {
838
- constructor(code = 500, _body = '') {
839
- super(typeof _body === 'string' ? _body : _body.message);
840
- this.code = code;
841
- this._body = _body;
842
- }
843
- get body() {
844
- return typeof this._body === 'string'
845
- ? {
846
- statusCode: this.code,
847
- message: this.message,
848
- error: httpStatusCodes[this.code],
849
- }
850
- : {
851
- ...this._body,
852
- statusCode: this.code,
853
- message: this.message,
854
- error: httpStatusCodes[this.code],
855
- };
856
- }
857
- attachRenderer(renderer) {
858
- this.renderer = renderer;
859
- }
860
- getRenderer() {
861
- return this.renderer;
862
- }
863
- }
864
-
865
849
  function createWooksResponder(renderer = new BaseHttpResponseRenderer(), errorRenderer = new HttpErrorRenderer()) {
866
850
  function createResponse(data) {
867
851
  const { hasResponded } = useResponse();
868
- if (hasResponded())
852
+ if (hasResponded()) {
869
853
  return null;
854
+ }
870
855
  if (data instanceof Error) {
871
856
  const r = new BaseHttpResponse(errorRenderer);
872
- let httpError;
873
- if (data instanceof HttpError) {
874
- httpError = data;
875
- }
876
- else {
877
- httpError = new HttpError(500, data.message);
878
- }
857
+ const httpError = data instanceof HttpError ? data : new HttpError(500, data.message);
879
858
  r.setBody(httpError.body);
880
859
  return r;
881
860
  }
@@ -888,7 +867,7 @@ function createWooksResponder(renderer = new BaseHttpResponseRenderer(), errorRe
888
867
  }
889
868
  return {
890
869
  createResponse,
891
- respond: (data) => createResponse(data)?.respond(),
870
+ respond: async (data) => createResponse(data)?.respond(),
892
871
  };
893
872
  }
894
873
 
@@ -931,12 +910,14 @@ class WooksHttp extends wooks.WooksAdapterBase {
931
910
  server.listen(...args);
932
911
  });
933
912
  }
934
- close(server) {
913
+ async close(server) {
935
914
  const srv = server || this.server;
936
915
  return new Promise((resolve, reject) => {
937
- srv?.close((err) => {
938
- if (err)
939
- return reject(err);
916
+ srv?.close(err => {
917
+ if (err) {
918
+ reject(err);
919
+ return;
920
+ }
940
921
  resolve(srv);
941
922
  });
942
923
  });
@@ -948,8 +929,8 @@ class WooksHttp extends wooks.WooksAdapterBase {
948
929
  this.server = server;
949
930
  }
950
931
  respond(data) {
951
- void this.responder.respond(data)?.catch((e) => {
952
- this.logger.error('Uncought response exception', e);
932
+ void this.responder.respond(data).catch(error => {
933
+ this.logger.error('Uncought response exception', error);
953
934
  });
954
935
  }
955
936
  getServerCb() {
@@ -960,10 +941,10 @@ class WooksHttp extends wooks.WooksAdapterBase {
960
941
  try {
961
942
  await this.processHandlers(handlers || [this.opts?.onNotFound]);
962
943
  }
963
- catch (e) {
964
- this.logger.error('Internal error, please report', e);
944
+ catch (error) {
945
+ this.logger.error('Internal error, please report', error);
965
946
  restoreCtx();
966
- this.respond(e);
947
+ this.respond(error);
967
948
  clearCtx();
968
949
  }
969
950
  }
@@ -988,11 +969,11 @@ class WooksHttp extends wooks.WooksAdapterBase {
988
969
  clearCtx();
989
970
  break;
990
971
  }
991
- catch (e) {
992
- this.logger.error(`Uncought route handler exception: ${store('event').get('req').url || ''}`, e);
972
+ catch (error) {
973
+ this.logger.error(`Uncought route handler exception: ${store('event').get('req').url || ''}`, error);
993
974
  if (isLastHandler) {
994
975
  restoreCtx();
995
- this.respond(e);
976
+ this.respond(error);
996
977
  clearCtx();
997
978
  }
998
979
  }