@mojojs/core 1.27.0 → 2.0.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.
Files changed (157) hide show
  1. package/README.md +1 -1
  2. package/lib/app.d.ts +24 -16
  3. package/lib/app.js +172 -126
  4. package/lib/body/params.js +0 -1
  5. package/lib/body.d.ts +13 -5
  6. package/lib/body.js +47 -17
  7. package/lib/cache.d.ts +1 -2
  8. package/lib/cache.js +12 -21
  9. package/lib/cgi.d.ts +3 -3
  10. package/lib/cgi.js +6 -5
  11. package/lib/cli/cgi.d.ts +1 -1
  12. package/lib/cli/cgi.js +1 -2
  13. package/lib/cli/create-full-app.d.ts +1 -1
  14. package/lib/cli/create-full-app.js +27 -27
  15. package/lib/cli/create-lite-app.d.ts +1 -1
  16. package/lib/cli/create-lite-app.js +2 -3
  17. package/lib/cli/create-plugin.d.ts +1 -1
  18. package/lib/cli/create-plugin.js +25 -23
  19. package/lib/cli/eval.d.ts +1 -1
  20. package/lib/cli/eval.js +12 -5
  21. package/lib/cli/get.d.ts +1 -1
  22. package/lib/cli/get.js +30 -26
  23. package/lib/cli/repl.d.ts +1 -1
  24. package/lib/cli/repl.js +0 -1
  25. package/lib/cli/routes.d.ts +1 -1
  26. package/lib/cli/routes.js +10 -7
  27. package/lib/cli/server.d.ts +1 -1
  28. package/lib/cli/server.js +41 -24
  29. package/lib/cli/version.js +1 -2
  30. package/lib/cli.d.ts +1 -1
  31. package/lib/cli.js +25 -19
  32. package/lib/context.d.ts +10 -10
  33. package/lib/context.js +94 -34
  34. package/lib/core.d.ts +14 -14
  35. package/lib/core.js +12 -13
  36. package/lib/headers.js +5 -4
  37. package/lib/hooks.d.ts +1 -1
  38. package/lib/hooks.js +1 -5
  39. package/lib/logger.d.ts +2 -2
  40. package/lib/logger.js +28 -16
  41. package/lib/mime.js +10 -13
  42. package/lib/plugins/default-conditions.d.ts +1 -1
  43. package/lib/plugins/default-conditions.js +0 -1
  44. package/lib/plugins/default-helpers.d.ts +1 -1
  45. package/lib/plugins/default-helpers.js +28 -11
  46. package/lib/plugins/json-config.d.ts +1 -1
  47. package/lib/plugins/json-config.js +0 -1
  48. package/lib/plugins/mount.d.ts +1 -1
  49. package/lib/plugins/mount.js +0 -1
  50. package/lib/plugins/tmpl-engine.d.ts +1 -1
  51. package/lib/plugins/tmpl-engine.js +2 -5
  52. package/lib/plugins/yaml-config.d.ts +1 -1
  53. package/lib/plugins/yaml-config.js +1 -2
  54. package/lib/renderer.d.ts +1 -1
  55. package/lib/renderer.js +27 -30
  56. package/lib/router/pattern.d.ts +1 -1
  57. package/lib/router/pattern.js +25 -14
  58. package/lib/router/plan.d.ts +1 -1
  59. package/lib/router/plan.js +12 -15
  60. package/lib/router/route.d.ts +3 -3
  61. package/lib/router/route.js +35 -38
  62. package/lib/router.d.ts +4 -4
  63. package/lib/router.js +25 -26
  64. package/lib/server/cookie.d.ts +1 -1
  65. package/lib/server/cookie.js +1 -2
  66. package/lib/server/request.d.ts +3 -3
  67. package/lib/server/request.js +44 -17
  68. package/lib/server/response.d.ts +3 -3
  69. package/lib/server/response.js +20 -20
  70. package/lib/server.d.ts +7 -2
  71. package/lib/server.js +69 -19
  72. package/lib/session.d.ts +3 -3
  73. package/lib/session.js +46 -34
  74. package/lib/sse.d.ts +1 -1
  75. package/lib/sse.js +0 -1
  76. package/lib/static.d.ts +1 -1
  77. package/lib/static.js +27 -22
  78. package/lib/types.d.ts +6 -5
  79. package/lib/types.js +0 -1
  80. package/lib/user-agent/cookie-jar.d.ts +2 -2
  81. package/lib/user-agent/cookie-jar.js +6 -9
  82. package/lib/user-agent/mock.d.ts +4 -4
  83. package/lib/user-agent/mock.js +6 -7
  84. package/lib/user-agent/response.d.ts +2 -2
  85. package/lib/user-agent/response.js +14 -3
  86. package/lib/user-agent/test.d.ts +5 -5
  87. package/lib/user-agent/test.js +14 -15
  88. package/lib/user-agent/transport/http.d.ts +2 -2
  89. package/lib/user-agent/transport/http.js +7 -10
  90. package/lib/user-agent/transport/https.d.ts +2 -2
  91. package/lib/user-agent/transport/https.js +2 -6
  92. package/lib/user-agent/transport/ws.d.ts +2 -2
  93. package/lib/user-agent/transport/ws.js +2 -3
  94. package/lib/user-agent.d.ts +18 -19
  95. package/lib/user-agent.js +64 -49
  96. package/lib/util.d.ts +13 -0
  97. package/lib/util.js +35 -11
  98. package/lib/validator/result.d.ts +1 -1
  99. package/lib/validator/result.js +8 -1
  100. package/lib/validator.d.ts +2 -2
  101. package/lib/validator.js +3 -6
  102. package/lib/websocket.d.ts +2 -2
  103. package/lib/websocket.js +9 -1
  104. package/package.json +22 -29
  105. package/lib/app.js.map +0 -1
  106. package/lib/body/params.js.map +0 -1
  107. package/lib/body.js.map +0 -1
  108. package/lib/cache.js.map +0 -1
  109. package/lib/cgi.js.map +0 -1
  110. package/lib/cli/cgi.js.map +0 -1
  111. package/lib/cli/create-full-app.js.map +0 -1
  112. package/lib/cli/create-lite-app.js.map +0 -1
  113. package/lib/cli/create-plugin.js.map +0 -1
  114. package/lib/cli/eval.js.map +0 -1
  115. package/lib/cli/get.js.map +0 -1
  116. package/lib/cli/repl.js.map +0 -1
  117. package/lib/cli/routes.js.map +0 -1
  118. package/lib/cli/server.js.map +0 -1
  119. package/lib/cli/version.js.map +0 -1
  120. package/lib/cli.js.map +0 -1
  121. package/lib/context.js.map +0 -1
  122. package/lib/core.js.map +0 -1
  123. package/lib/headers.js.map +0 -1
  124. package/lib/hooks.js.map +0 -1
  125. package/lib/logger.js.map +0 -1
  126. package/lib/mime.js.map +0 -1
  127. package/lib/plugins/default-conditions.js.map +0 -1
  128. package/lib/plugins/default-helpers.js.map +0 -1
  129. package/lib/plugins/json-config.js.map +0 -1
  130. package/lib/plugins/mount.js.map +0 -1
  131. package/lib/plugins/tmpl-engine.js.map +0 -1
  132. package/lib/plugins/yaml-config.js.map +0 -1
  133. package/lib/renderer.js.map +0 -1
  134. package/lib/router/pattern.js.map +0 -1
  135. package/lib/router/plan.js.map +0 -1
  136. package/lib/router/route.js.map +0 -1
  137. package/lib/router.js.map +0 -1
  138. package/lib/server/cookie.js.map +0 -1
  139. package/lib/server/request.js.map +0 -1
  140. package/lib/server/response.js.map +0 -1
  141. package/lib/server.js.map +0 -1
  142. package/lib/session.js.map +0 -1
  143. package/lib/sse.js.map +0 -1
  144. package/lib/static.js.map +0 -1
  145. package/lib/types.js.map +0 -1
  146. package/lib/user-agent/cookie-jar.js.map +0 -1
  147. package/lib/user-agent/mock.js.map +0 -1
  148. package/lib/user-agent/response.js.map +0 -1
  149. package/lib/user-agent/test.js.map +0 -1
  150. package/lib/user-agent/transport/http.js.map +0 -1
  151. package/lib/user-agent/transport/https.js.map +0 -1
  152. package/lib/user-agent/transport/ws.js.map +0 -1
  153. package/lib/user-agent.js.map +0 -1
  154. package/lib/util.js.map +0 -1
  155. package/lib/validator/result.js.map +0 -1
  156. package/lib/validator.js.map +0 -1
  157. package/lib/websocket.js.map +0 -1
package/lib/server.js CHANGED
@@ -2,11 +2,11 @@ import cluster from 'node:cluster';
2
2
  import http from 'node:http';
3
3
  import https from 'node:https';
4
4
  import os from 'node:os';
5
- import { Stream } from 'node:stream';
5
+ import { pipeline, Stream } from 'node:stream';
6
6
  import { URL } from 'node:url';
7
- import { ServerRequest } from './server/request.js';
8
- import { ServerResponse } from './server/response.js';
9
- import { WebSocket } from './websocket.js';
7
+ import { ServerRequest } from "./server/request.js";
8
+ import { ServerResponse } from "./server/response.js";
9
+ import { WebSocket } from "./websocket.js";
10
10
  import Path from '@mojojs/path';
11
11
  import { termEscape } from '@mojojs/util';
12
12
  import { WebSocketServer } from 'ws';
@@ -22,16 +22,52 @@ const devKey = certs.child('development.key').toString();
22
22
  * HTTP and WebSocket server class.
23
23
  */
24
24
  export class Server {
25
+ /**
26
+ * Application this server handles.
27
+ */
28
+ app;
29
+ /**
30
+ * Limit the amount of time the parser will wait to receive the complete HTTP headers, defaults to `60000`
31
+ * (60 seconds).
32
+ */
33
+ headersTimeout;
34
+ /**
35
+ * Limit the amount of time of inactivity a server needs to wait for additional incoming data, after it has finished
36
+ * writing the last response, before a socket will be destroyed, defaults to `5000` (5 seconds).
37
+ */
38
+ keepAliveTimeout;
39
+ /**
40
+ * Maximum number of requests socket can handle before closing keep alive connection, defaults to `0`.
41
+ */
42
+ maxRequestsPerSocket;
43
+ /**
44
+ * Maximum WebSocket message size in bytes, defaults to `262144` (256 KiB). Connections exceeding the limit are closed
45
+ * with status `1009`.
46
+ */
47
+ maxWebSocketSize;
48
+ /**
49
+ * Limit the amount of time for receiving the entire request from the client, defaults to `300000` (300 seconds).
50
+ */
51
+ requestTimeout;
52
+ /**
53
+ * Reverse proxy mode.
54
+ */
55
+ reverseProxy;
56
+ /**
57
+ * Server URLs.
58
+ */
59
+ urls = [];
60
+ _cluster;
61
+ _listen;
62
+ _servers = [];
63
+ _quiet;
64
+ _workers;
25
65
  constructor(app, options = {}) {
26
- /**
27
- * Server URLs.
28
- */
29
- this.urls = [];
30
- this._servers = [];
31
66
  this.app = app;
32
67
  this.headersTimeout = options.headersTimeout;
33
68
  this.keepAliveTimeout = options.keepAliveTimeout;
34
69
  this.maxRequestsPerSocket = options.maxRequestsPerSocket;
70
+ this.maxWebSocketSize = options.maxWebSocketSize ?? 256 * 1024;
35
71
  this.requestTimeout = options.requestTimeout;
36
72
  this.reverseProxy = options.reverseProxy ?? false;
37
73
  this._cluster = options.cluster ?? false;
@@ -72,6 +108,7 @@ export class Server {
72
108
  cluster.fork();
73
109
  }
74
110
  else {
111
+ await app.warmup();
75
112
  for (const location of this._listen) {
76
113
  await this._createServer(location);
77
114
  }
@@ -100,8 +137,7 @@ export class Server {
100
137
  options.key = await new Path(searchParams.get('key') ?? devKey).readFile();
101
138
  isHttps = true;
102
139
  }
103
- await this.app.warmup();
104
- const wss = new WebSocketServer({ noServer: true });
140
+ const wss = new WebSocketServer({ maxPayload: this.maxWebSocketSize, noServer: true });
105
141
  const server = (isHttps ? https : http).createServer(options, this._handleRequest.bind(this));
106
142
  this._servers.push(server);
107
143
  if (this.maxRequestsPerSocket !== undefined)
@@ -118,9 +154,9 @@ export class Server {
118
154
  const stderr = process.stderr;
119
155
  socket.on('data', (chunk) => stderr.write(termEscape(`-- Server <<< Client\n${chunk}`)));
120
156
  const write = socket.write;
121
- socket.write = (chunk, cb) => {
157
+ socket.write = (chunk, ...args) => {
122
158
  stderr.write(termEscape(`-- Server >>> Client\n${chunk}`));
123
- return write.apply(socket, [chunk, cb]);
159
+ return write.apply(socket, [chunk, ...args]);
124
160
  };
125
161
  });
126
162
  }
@@ -202,11 +238,18 @@ function sendHeaders(res, raw) {
202
238
  const statusCode = res.statusCode;
203
239
  const statusMessage = res.statusMessage;
204
240
  const headers = res.headers.toArray();
205
- if (statusMessage === null) {
206
- raw.writeHead(statusCode, headers);
241
+ try {
242
+ if (statusMessage === null) {
243
+ raw.writeHead(statusCode, headers);
244
+ }
245
+ else {
246
+ raw.writeHead(statusCode, statusMessage, headers);
247
+ }
207
248
  }
208
- else {
209
- raw.writeHead(statusCode, statusMessage, headers);
249
+ catch (error) {
250
+ // The response counts as sent already, so close the connection instead of letting the client wait forever
251
+ raw.destroy();
252
+ throw error;
210
253
  }
211
254
  }
212
255
  function sendResponse(res, body, raw) {
@@ -217,7 +260,15 @@ function sendResponse(res, body, raw) {
217
260
  }
218
261
  else if (body instanceof Stream) {
219
262
  sendHeaders(res, raw);
220
- body.pipe(raw);
263
+ // Both streams need to be cleaned up, and only aborted connections are expected
264
+ pipeline(body, raw, error => {
265
+ if (error === undefined ||
266
+ error === null ||
267
+ error.code === 'ERR_STREAM_PREMATURE_CLOSE') {
268
+ return;
269
+ }
270
+ res._ctx?.deref()?.log.error(`Response stream failed: ${error.stack}`);
271
+ });
221
272
  }
222
273
  else {
223
274
  sendHeaders(res, raw);
@@ -227,4 +278,3 @@ function sendResponse(res, body, raw) {
227
278
  function urlToSocketPath(url) {
228
279
  return url.host + url.pathname;
229
280
  }
230
- //# sourceMappingURL=server.js.map
package/lib/session.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { App } from './app.js';
2
- import type { Context } from './context.js';
3
- import type { SessionData } from './types.js';
1
+ import type { App } from './app.ts';
2
+ import type { Context } from './context.ts';
3
+ import type { SessionData } from './types.ts';
4
4
  /**
5
5
  * Session manager class.
6
6
  */
package/lib/session.js CHANGED
@@ -2,42 +2,55 @@ import crypto from 'node:crypto';
2
2
  import { promisify } from 'node:util';
3
3
  const scrypt = promisify(crypto.scrypt);
4
4
  const randomBytes = promisify(crypto.randomBytes);
5
+ // Deriving keys with scrypt is slow on purpose, so it is only done once per secret
6
+ const keys = new Map();
7
+ function deriveKey(secret) {
8
+ let key = keys.get(secret);
9
+ if (key === undefined) {
10
+ key = scrypt(secret, 'salt', 32);
11
+ keys.set(secret, key);
12
+ // Do not cache failures
13
+ key.catch(() => keys.delete(secret));
14
+ }
15
+ return key;
16
+ }
5
17
  /**
6
18
  * Session manager class.
7
19
  */
8
20
  export class Session {
21
+ /**
22
+ * Name for session cookies, defaults to `mojo`.
23
+ */
24
+ cookieName = 'mojo';
25
+ /**
26
+ * Path for session cookies, defaults to `/`.
27
+ */
28
+ cookiePath = '/';
29
+ /**
30
+ * Default time for sessions to expire in seconds from now, defaults to `3600`. The expiration timeout gets refreshed
31
+ * for every request. Setting the value to `0` will allow sessions to persist until the browser window is closed,
32
+ * this can have security implications though.
33
+ */
34
+ expiration = 3600;
35
+ /**
36
+ * Set the `HttpOnly` value on all session cookies.
37
+ */
38
+ httpOnly = true;
39
+ /**
40
+ * Set the `Partitioned` value on all session cookies, to be used in accordance with the CHIPS amendment to RFC 6265.
41
+ * Note that this property is EXPERIMENTAL and might change without warning!
42
+ */
43
+ partitioned = false;
44
+ /**
45
+ * Set the `SameSite` value on all session cookies, defaults to `lax`.
46
+ */
47
+ sameSite = 'lax';
48
+ /**
49
+ * Set the secure flag on all session cookies, so that browsers send them only over HTTPS connections.
50
+ */
51
+ secure = false;
52
+ _app;
9
53
  constructor(app) {
10
- /**
11
- * Name for session cookies, defaults to `mojo`.
12
- */
13
- this.cookieName = 'mojo';
14
- /**
15
- * Path for session cookies, defaults to `/`.
16
- */
17
- this.cookiePath = '/';
18
- /**
19
- * Default time for sessions to expire in seconds from now, defaults to `3600`. The expiration timeout gets refreshed
20
- * for every request. Setting the value to `0` will allow sessions to persist until the browser window is closed,
21
- * this can have security implications though.
22
- */
23
- this.expiration = 3600;
24
- /**
25
- * Set the `HttpOnly` value on all session cookies.
26
- */
27
- this.httpOnly = true;
28
- /**
29
- * Set the `Partitioned` value on all session cookies, to be used in accordance with the CHIPS amendment to RFC 6265.
30
- * Note that this property is EXPERIMENTAL and might change without warning!
31
- */
32
- this.partitioned = false;
33
- /**
34
- * Set the `SameSite` value on all session cookies, defaults to `lax`.
35
- */
36
- this.sameSite = 'lax';
37
- /**
38
- * Set the secure flag on all session cookies, so that browsers send them only over HTTPS connections.
39
- */
40
- this.secure = false;
41
54
  this._app = new WeakRef(app);
42
55
  }
43
56
  /**
@@ -52,7 +65,7 @@ export class Session {
52
65
  const authTag = Buffer.from(match[3], 'base64');
53
66
  for (const secret of secrets) {
54
67
  try {
55
- const key = await scrypt(secret, 'salt', 32);
68
+ const key = await deriveKey(secret);
56
69
  const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv, { authTagLength: 16 });
57
70
  decipher.setAuthTag(authTag);
58
71
  const decrypted = decipher.update(value, 'base64', 'utf8');
@@ -68,7 +81,7 @@ export class Session {
68
81
  * Encrypt cookie.
69
82
  */
70
83
  static async encrypt(secret, value) {
71
- const key = await scrypt(secret, 'salt', 32);
84
+ const key = await deriveKey(secret);
72
85
  const iv = await randomBytes(12);
73
86
  const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
74
87
  const encrypted = cipher.update(value, 'utf8', 'base64') + cipher.final('base64');
@@ -123,4 +136,3 @@ export class Session {
123
136
  });
124
137
  }
125
138
  }
126
- //# sourceMappingURL=session.js.map
package/lib/sse.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { SSEEvent } from './types.js';
1
+ import type { SSEEvent } from './types.ts';
2
2
  /**
3
3
  * Build Server-Sent Event. Note that this function is EXPERIMENTAL and might change without warning!
4
4
  */
package/lib/sse.js CHANGED
@@ -60,4 +60,3 @@ function splitLines(value) {
60
60
  lines.pop();
61
61
  return lines;
62
62
  }
63
- //# sourceMappingURL=sse.js.map
package/lib/static.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MojoContext } from './types.js';
1
+ import type { MojoContext } from './types.ts';
2
2
  import Path from '@mojojs/path';
3
3
  type AssetIndex = Record<string, string>;
4
4
  /**
package/lib/static.js CHANGED
@@ -1,23 +1,21 @@
1
- import crypto from 'node:crypto';
2
1
  import Path from '@mojojs/path';
3
2
  /**
4
3
  * Static file server class.
5
4
  */
6
5
  export class Static {
7
- constructor() {
8
- /**
9
- * Subdirectory used for all static assets.
10
- */
11
- this.assetDir = 'assets';
12
- /**
13
- * Prefix to use for all static files.
14
- */
15
- this.prefix = '/static';
16
- /**
17
- * Directories to serve static files from, first one has the highest precedence.
18
- */
19
- this.publicPaths = [Path.currentFile().sibling('..', 'vendor', 'public').toString()];
20
- }
6
+ /**
7
+ * Subdirectory used for all static assets.
8
+ */
9
+ assetDir = 'assets';
10
+ /**
11
+ * Prefix to use for all static files.
12
+ */
13
+ prefix = '/static';
14
+ /**
15
+ * Directories to serve static files from, first one has the highest precedence.
16
+ */
17
+ publicPaths = [Path.currentFile().sibling('..', 'vendor', 'public').toString()];
18
+ _assets;
21
19
  /**
22
20
  * Get static asset path.
23
21
  */
@@ -79,9 +77,10 @@ export class Static {
79
77
  // If-None-Match
80
78
  const ifNoneMatch = req.get('If-None-Match');
81
79
  if (etag !== undefined && ifNoneMatch !== null) {
82
- const etags = ifNoneMatch.split(/,\s+/).map(value => value.replaceAll('"', ''));
80
+ // Weak comparison, because proxies like nginx turn ETags into weak ones when compressing responses
81
+ const etags = ifNoneMatch.split(/\s*,\s*/).map(value => value.replace(/^W\//, '').replaceAll('"', ''));
83
82
  for (const match of etags) {
84
- if (match === etag)
83
+ if (match === etag || match === '*')
85
84
  return true;
86
85
  }
87
86
  }
@@ -91,7 +90,8 @@ export class Static {
91
90
  const epoch = Date.parse(ifModifiedSince);
92
91
  if (isNaN(epoch))
93
92
  return false;
94
- if (epoch > options.lastModified.getTime())
93
+ // HTTP dates have no milliseconds
94
+ if (epoch >= Math.floor(options.lastModified.getTime() / 1000) * 1000)
95
95
  return true;
96
96
  }
97
97
  return false;
@@ -113,7 +113,8 @@ export class Static {
113
113
  const { res } = ctx;
114
114
  res.set('Accept-Ranges', 'bytes');
115
115
  const lastModified = stat.mtime;
116
- const etag = crypto.createHash('md5').update(lastModified.getTime().toString()).digest('hex');
116
+ // Size too, because reproducible builds often give all files the same modification time
117
+ const etag = `${lastModified.getTime()}-${length}`;
117
118
  if (this.isFresh(ctx, { etag, lastModified })) {
118
119
  await res.status(304).send();
119
120
  return;
@@ -131,10 +132,15 @@ export class Static {
131
132
  if (bytes === null)
132
133
  return await this._rangeNotSatisfiable(ctx);
133
134
  let start = parseInt(bytes[1]);
135
+ let end = parseInt(bytes[2]);
136
+ // Suffix range for the last bytes of the file
137
+ if (isNaN(start) && isNaN(end) === false) {
138
+ start = Math.max(length - end, 0);
139
+ end = length - 1;
140
+ }
134
141
  if (isNaN(start))
135
142
  start = 0;
136
- let end = parseInt(bytes[2]);
137
- if (isNaN(end))
143
+ if (isNaN(end) || end >= length)
138
144
  end = length - 1;
139
145
  if (start > end)
140
146
  return await this._rangeNotSatisfiable(ctx);
@@ -175,4 +181,3 @@ export class Static {
175
181
  await ctx.res.status(416).send();
176
182
  }
177
183
  }
178
- //# sourceMappingURL=static.js.map
package/lib/types.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { App } from './app.js';
2
- import type { Context } from './context.js';
3
- import type { Route } from './router/route.js';
4
- import type { SafeString } from './util.js';
5
- import type { ValidatorResult } from './validator/result.js';
1
+ import type { App } from './app.ts';
2
+ import type { Context } from './context.ts';
3
+ import type { Route } from './router/route.ts';
4
+ import type { SafeString } from './util.ts';
5
+ import type { ValidatorResult } from './validator/result.ts';
6
6
  import type { Agent } from 'node:http';
7
7
  import type { Readable, Stream } from 'node:stream';
8
8
  import type { URL } from 'node:url';
@@ -156,6 +156,7 @@ export interface ServerOptions {
156
156
  keepAliveTimeout?: number;
157
157
  listen?: string[];
158
158
  maxRequestsPerSocket?: number;
159
+ maxWebSocketSize?: number;
159
160
  quiet?: boolean;
160
161
  requestTimeout?: number;
161
162
  reverseProxy?: boolean;
package/lib/types.js CHANGED
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
@@ -1,5 +1,5 @@
1
1
  import { type URL } from 'node:url';
2
- import tough from 'tough-cookie';
2
+ import { CookieJar as ToughCookieJar } from 'tough-cookie';
3
3
  /**
4
4
  * Cookie jar class.
5
5
  */
@@ -7,7 +7,7 @@ export declare class CookieJar {
7
7
  /**
8
8
  * Cookie storage.
9
9
  */
10
- storage: tough.CookieJar;
10
+ storage: ToughCookieJar;
11
11
  /**
12
12
  * Load cookies from storage.
13
13
  */
@@ -1,15 +1,13 @@
1
1
  import { format } from 'node:url';
2
- import tough from 'tough-cookie';
2
+ import { Cookie, CookieJar as ToughCookieJar } from 'tough-cookie';
3
3
  /**
4
4
  * Cookie jar class.
5
5
  */
6
6
  export class CookieJar {
7
- constructor() {
8
- /**
9
- * Cookie storage.
10
- */
11
- this.storage = new tough.CookieJar();
12
- }
7
+ /**
8
+ * Cookie storage.
9
+ */
10
+ storage = new ToughCookieJar();
13
11
  /**
14
12
  * Load cookies from storage.
15
13
  */
@@ -24,7 +22,7 @@ export class CookieJar {
24
22
  */
25
23
  async storeCookies(url, headers) {
26
24
  const cookieURL = this._cookieURL(url);
27
- for (const cookie of headers.map(value => tough.Cookie.parse(value))) {
25
+ for (const cookie of headers.map(value => Cookie.parse(value))) {
28
26
  if (cookie !== undefined)
29
27
  await this.storage.setCookie(cookie, cookieURL);
30
28
  }
@@ -33,4 +31,3 @@ export class CookieJar {
33
31
  return format(currentURL, { auth: false, fragment: false, search: false });
34
32
  }
35
33
  }
36
- //# sourceMappingURL=cookie-jar.js.map
@@ -1,7 +1,7 @@
1
- import type { App } from '../app.js';
2
- import type { ServerOptions, UserAgentOptions } from '../types.js';
3
- import { Server } from '../server.js';
4
- import { UserAgent } from '../user-agent.js';
1
+ import type { App } from '../app.ts';
2
+ import type { ServerOptions, UserAgentOptions } from '../types.ts';
3
+ import { Server } from '../server.ts';
4
+ import { UserAgent } from '../user-agent.ts';
5
5
  /**
6
6
  * Mock user-agent class.
7
7
  */
@@ -1,15 +1,15 @@
1
- import { Server } from '../server.js';
2
- import { UserAgent } from '../user-agent.js';
1
+ import { Server } from "../server.js";
2
+ import { UserAgent } from "../user-agent.js";
3
3
  /**
4
4
  * Mock user-agent class.
5
5
  */
6
6
  export class MockUserAgent extends UserAgent {
7
+ /**
8
+ * Server to use for mock requests.
9
+ */
10
+ server = undefined;
7
11
  constructor(options) {
8
12
  super(options);
9
- /**
10
- * Server to use for mock requests.
11
- */
12
- this.server = undefined;
13
13
  this.server = undefined;
14
14
  }
15
15
  async [Symbol.asyncDispose]() {
@@ -41,4 +41,3 @@ export class MockUserAgent extends UserAgent {
41
41
  return await this.server.stop();
42
42
  }
43
43
  }
44
- //# sourceMappingURL=mock.js.map
@@ -1,6 +1,6 @@
1
- import type { SSEEvent } from '../types.js';
1
+ import type { SSEEvent } from '../types.ts';
2
2
  import type { Readable } from 'node:stream';
3
- import { Body } from '../body.js';
3
+ import { Body } from '../body.ts';
4
4
  interface UserAgentResponseOptions {
5
5
  body: Readable;
6
6
  headers: string[];
@@ -1,9 +1,21 @@
1
- import { Body } from '../body.js';
2
- import { parseEvent } from '../sse.js';
1
+ import { Body } from "../body.js";
2
+ import { parseEvent } from "../sse.js";
3
3
  /**
4
4
  * User-agent response class.
5
5
  */
6
6
  export class UserAgentResponse extends Body {
7
+ /**
8
+ * HTTP version.
9
+ */
10
+ httpVersion;
11
+ /**
12
+ * Response status code.
13
+ */
14
+ statusCode;
15
+ /**
16
+ * Response status message.
17
+ */
18
+ statusMessage;
7
19
  constructor(options) {
8
20
  super(options.headers, options.body);
9
21
  this.httpVersion = options.httpVersion;
@@ -73,4 +85,3 @@ export class UserAgentResponse extends Body {
73
85
  return this.get('Content-Type');
74
86
  }
75
87
  }
76
- //# sourceMappingURL=response.js.map
@@ -1,10 +1,10 @@
1
- import type { UserAgentResponse } from './response.js';
2
- import type { App } from '../app.js';
3
- import type { JSONValue, SSEEvent, ServerOptions, TestContext, TestUserAgentOptions, UserAgentRequestOptions, UserAgentWebSocketOptions } from '../types.js';
4
- import type { WebSocket } from '../websocket.js';
1
+ import type { UserAgentResponse } from './response.ts';
2
+ import type { App } from '../app.ts';
3
+ import type { JSONValue, SSEEvent, ServerOptions, TestContext, TestUserAgentOptions, UserAgentRequestOptions, UserAgentWebSocketOptions } from '../types.ts';
4
+ import type { WebSocket } from '../websocket.ts';
5
5
  import type { URL } from 'node:url';
6
6
  import assert from 'node:assert/strict';
7
- import { MockUserAgent } from './mock.js';
7
+ import { MockUserAgent } from './mock.ts';
8
8
  import DOM from '@mojojs/dom';
9
9
  import StackUtils from 'stack-utils';
10
10
  type SkipFunction = (...args: any[]) => any;
@@ -1,6 +1,6 @@
1
1
  import assert from 'node:assert/strict';
2
2
  import { on } from 'node:events';
3
- import { MockUserAgent } from './mock.js';
3
+ import { MockUserAgent } from "./mock.js";
4
4
  import DOM from '@mojojs/dom';
5
5
  import { jsonPointer } from '@mojojs/util';
6
6
  import * as yaml from 'js-yaml';
@@ -18,21 +18,21 @@ function addNodeAssertMethods(tapInstance) {
18
18
  * Test user-agent class.
19
19
  */
20
20
  export class TestUserAgent extends MockUserAgent {
21
+ /**
22
+ * Current HTTP response content.
23
+ */
24
+ body = Buffer.from('');
25
+ _assert = undefined;
26
+ _dom = undefined;
27
+ _finished = undefined;
28
+ _messages = undefined;
29
+ _res = undefined;
30
+ _sse = undefined;
31
+ _sseEvents = undefined;
32
+ _stack = new StackUtils();
33
+ _ws = undefined;
21
34
  constructor(options = {}) {
22
35
  super(options);
23
- /**
24
- * Current HTTP response content.
25
- */
26
- this.body = Buffer.from('');
27
- this._assert = undefined;
28
- this._dom = undefined;
29
- this._finished = undefined;
30
- this._messages = undefined;
31
- this._res = undefined;
32
- this._sse = undefined;
33
- this._sseEvents = undefined;
34
- this._stack = new StackUtils();
35
- this._ws = undefined;
36
36
  if (options.tap !== undefined)
37
37
  this._prepareTap(options.tap);
38
38
  }
@@ -472,4 +472,3 @@ export class TestUserAgent extends MockUserAgent {
472
472
  });
473
473
  }
474
474
  }
475
- //# sourceMappingURL=test.js.map
@@ -1,7 +1,7 @@
1
- import type { UserAgentRequestOptions } from '../../types.js';
1
+ import type { UserAgentRequestOptions } from '../../types.ts';
2
2
  import type { URL } from 'node:url';
3
3
  import http from 'node:http';
4
- import { UserAgentResponse } from '../response.js';
4
+ import { UserAgentResponse } from '../response.ts';
5
5
  /**
6
6
  * HTTP transport class.
7
7
  */
@@ -1,17 +1,15 @@
1
1
  import http from 'node:http';
2
2
  import Stream from 'node:stream';
3
- import { UserAgentResponse } from '../response.js';
3
+ import { UserAgentResponse } from "../response.js";
4
4
  import { termEscape } from '@mojojs/util';
5
5
  /**
6
6
  * HTTP transport class.
7
7
  */
8
8
  export class HTTPTransport {
9
- constructor() {
10
- /**
11
- * HTTP agent.
12
- */
13
- this.agent = new http.Agent();
14
- }
9
+ /**
10
+ * HTTP agent.
11
+ */
12
+ agent = new http.Agent();
15
13
  /**
16
14
  * Destroy active keep-alive connections.
17
15
  */
@@ -40,9 +38,9 @@ export class HTTPTransport {
40
38
  const stderr = process.stderr;
41
39
  socket.on('data', (chunk) => stderr.write(termEscape(`-- Client <<< Server\n${chunk}`)));
42
40
  const write = socket.write;
43
- socket.write = (chunk, cb) => {
41
+ socket.write = (chunk, ...args) => {
44
42
  stderr.write(termEscape(`-- Client >>> Server\n${chunk}`));
45
- return write.apply(socket, [chunk, cb]);
43
+ return write.apply(socket, [chunk, ...args]);
46
44
  };
47
45
  });
48
46
  }
@@ -75,4 +73,3 @@ export class HTTPTransport {
75
73
  return http.request(url, options, cb);
76
74
  }
77
75
  }
78
- //# sourceMappingURL=http.js.map
@@ -1,8 +1,8 @@
1
- import type { UserAgentRequestOptions } from '../../types.js';
1
+ import type { UserAgentRequestOptions } from '../../types.ts';
2
2
  import type http from 'node:http';
3
3
  import type { URL } from 'node:url';
4
4
  import https from 'node:https';
5
- import { HTTPTransport } from './http.js';
5
+ import { HTTPTransport } from './http.ts';
6
6
  /**
7
7
  * HTTPS transport class.
8
8
  */