@mojojs/core 1.26.18 → 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.
- package/README.md +1 -1
- package/lib/app.d.ts +31 -16
- package/lib/app.js +181 -126
- package/lib/body/params.js +0 -1
- package/lib/body.d.ts +13 -5
- package/lib/body.js +47 -17
- package/lib/cache.d.ts +1 -2
- package/lib/cache.js +12 -21
- package/lib/cgi.d.ts +3 -3
- package/lib/cgi.js +16 -8
- package/lib/cli/cgi.d.ts +1 -1
- package/lib/cli/cgi.js +1 -2
- package/lib/cli/create-full-app.d.ts +1 -1
- package/lib/cli/create-full-app.js +27 -27
- package/lib/cli/create-lite-app.d.ts +1 -1
- package/lib/cli/create-lite-app.js +2 -3
- package/lib/cli/create-plugin.d.ts +1 -1
- package/lib/cli/create-plugin.js +25 -23
- package/lib/cli/eval.d.ts +1 -1
- package/lib/cli/eval.js +12 -5
- package/lib/cli/get.d.ts +1 -1
- package/lib/cli/get.js +30 -26
- package/lib/cli/repl.d.ts +1 -1
- package/lib/cli/repl.js +0 -1
- package/lib/cli/routes.d.ts +1 -1
- package/lib/cli/routes.js +10 -7
- package/lib/cli/server.d.ts +1 -1
- package/lib/cli/server.js +41 -24
- package/lib/cli/version.js +1 -2
- package/lib/cli.d.ts +1 -1
- package/lib/cli.js +25 -19
- package/lib/context.d.ts +33 -10
- package/lib/context.js +137 -32
- package/lib/core.d.ts +14 -13
- package/lib/core.js +12 -12
- package/lib/headers.js +5 -4
- package/lib/hooks.d.ts +1 -1
- package/lib/hooks.js +1 -5
- package/lib/logger.d.ts +2 -2
- package/lib/logger.js +28 -16
- package/lib/mime.js +10 -13
- package/lib/plugins/default-conditions.d.ts +1 -1
- package/lib/plugins/default-conditions.js +0 -1
- package/lib/plugins/default-helpers.d.ts +1 -1
- package/lib/plugins/default-helpers.js +28 -11
- package/lib/plugins/json-config.d.ts +1 -1
- package/lib/plugins/json-config.js +0 -1
- package/lib/plugins/mount.d.ts +1 -1
- package/lib/plugins/mount.js +0 -1
- package/lib/plugins/tmpl-engine.d.ts +1 -1
- package/lib/plugins/tmpl-engine.js +2 -5
- package/lib/plugins/yaml-config.d.ts +1 -1
- package/lib/plugins/yaml-config.js +1 -2
- package/lib/renderer.d.ts +1 -1
- package/lib/renderer.js +27 -30
- package/lib/router/pattern.d.ts +1 -1
- package/lib/router/pattern.js +25 -14
- package/lib/router/plan.d.ts +1 -1
- package/lib/router/plan.js +12 -15
- package/lib/router/route.d.ts +10 -3
- package/lib/router/route.js +44 -38
- package/lib/router.d.ts +4 -4
- package/lib/router.js +25 -26
- package/lib/server/cookie.d.ts +1 -1
- package/lib/server/cookie.js +3 -2
- package/lib/server/request.d.ts +3 -3
- package/lib/server/request.js +44 -17
- package/lib/server/response.d.ts +3 -3
- package/lib/server/response.js +20 -20
- package/lib/server.d.ts +7 -2
- package/lib/server.js +70 -20
- package/lib/session.d.ts +8 -3
- package/lib/session.js +47 -29
- package/lib/sse.d.ts +10 -0
- package/lib/sse.js +62 -0
- package/lib/static.d.ts +1 -1
- package/lib/static.js +27 -22
- package/lib/types.d.ts +13 -5
- package/lib/types.js +0 -1
- package/lib/user-agent/cookie-jar.d.ts +2 -2
- package/lib/user-agent/cookie-jar.js +6 -9
- package/lib/user-agent/mock.d.ts +4 -4
- package/lib/user-agent/mock.js +6 -7
- package/lib/user-agent/response.d.ts +12 -1
- package/lib/user-agent/response.js +36 -2
- package/lib/user-agent/test.d.ts +75 -5
- package/lib/user-agent/test.js +147 -13
- package/lib/user-agent/transport/http.d.ts +2 -2
- package/lib/user-agent/transport/http.js +7 -10
- package/lib/user-agent/transport/https.d.ts +2 -2
- package/lib/user-agent/transport/https.js +2 -6
- package/lib/user-agent/transport/ws.d.ts +2 -2
- package/lib/user-agent/transport/ws.js +2 -3
- package/lib/user-agent.d.ts +21 -18
- package/lib/user-agent.js +70 -49
- package/lib/util.d.ts +13 -0
- package/lib/util.js +35 -11
- package/lib/validator/result.d.ts +1 -1
- package/lib/validator/result.js +8 -1
- package/lib/validator.d.ts +2 -2
- package/lib/validator.js +3 -6
- package/lib/websocket.d.ts +2 -2
- package/lib/websocket.js +9 -1
- package/package.json +22 -29
- package/lib/app.js.map +0 -1
- package/lib/body/params.js.map +0 -1
- package/lib/body.js.map +0 -1
- package/lib/cache.js.map +0 -1
- package/lib/cgi.js.map +0 -1
- package/lib/cli/cgi.js.map +0 -1
- package/lib/cli/create-full-app.js.map +0 -1
- package/lib/cli/create-lite-app.js.map +0 -1
- package/lib/cli/create-plugin.js.map +0 -1
- package/lib/cli/eval.js.map +0 -1
- package/lib/cli/get.js.map +0 -1
- package/lib/cli/repl.js.map +0 -1
- package/lib/cli/routes.js.map +0 -1
- package/lib/cli/server.js.map +0 -1
- package/lib/cli/version.js.map +0 -1
- package/lib/cli.js.map +0 -1
- package/lib/context.js.map +0 -1
- package/lib/core.js.map +0 -1
- package/lib/headers.js.map +0 -1
- package/lib/hooks.js.map +0 -1
- package/lib/logger.js.map +0 -1
- package/lib/mime.js.map +0 -1
- package/lib/plugins/default-conditions.js.map +0 -1
- package/lib/plugins/default-helpers.js.map +0 -1
- package/lib/plugins/json-config.js.map +0 -1
- package/lib/plugins/mount.js.map +0 -1
- package/lib/plugins/tmpl-engine.js.map +0 -1
- package/lib/plugins/yaml-config.js.map +0 -1
- package/lib/renderer.js.map +0 -1
- package/lib/router/pattern.js.map +0 -1
- package/lib/router/plan.js.map +0 -1
- package/lib/router/route.js.map +0 -1
- package/lib/router.js.map +0 -1
- package/lib/server/cookie.js.map +0 -1
- package/lib/server/request.js.map +0 -1
- package/lib/server/response.js.map +0 -1
- package/lib/server.js.map +0 -1
- package/lib/session.js.map +0 -1
- package/lib/static.js.map +0 -1
- package/lib/types.js.map +0 -1
- package/lib/user-agent/cookie-jar.js.map +0 -1
- package/lib/user-agent/mock.js.map +0 -1
- package/lib/user-agent/response.js.map +0 -1
- package/lib/user-agent/test.js.map +0 -1
- package/lib/user-agent/transport/http.js.map +0 -1
- package/lib/user-agent/transport/https.js.map +0 -1
- package/lib/user-agent/transport/ws.js.map +0 -1
- package/lib/user-agent.js.map +0 -1
- package/lib/util.js.map +0 -1
- package/lib/validator/result.js.map +0 -1
- package/lib/validator.js.map +0 -1
- package/lib/websocket.js.map +0 -1
package/README.md
CHANGED
package/lib/app.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import type { Route } from './router/route.
|
|
2
|
-
import type { AnyArguments, AppOptions, BackendInfo, UserAgentOptions, MojoAction, MojoContext, MojoModels, NestedHelpers, RouteArguments, ServerOptions, TestUserAgentOptions } from './types.
|
|
3
|
-
import { CLI } from './cli.
|
|
4
|
-
import { Hooks } from './hooks.
|
|
5
|
-
import { Logger } from './logger.
|
|
6
|
-
import { Mime } from './mime.
|
|
7
|
-
import { Renderer } from './renderer.
|
|
8
|
-
import { Router } from './router.
|
|
9
|
-
import { ServerRequest } from './server/request.
|
|
10
|
-
import { ServerResponse } from './server/response.
|
|
11
|
-
import { Session } from './session.
|
|
12
|
-
import { Static } from './static.
|
|
13
|
-
import { MockUserAgent } from './user-agent/mock.
|
|
14
|
-
import { TestUserAgent } from './user-agent/test.
|
|
15
|
-
import { UserAgent } from './user-agent.
|
|
16
|
-
import { Validator } from './validator.
|
|
1
|
+
import type { Route } from './router/route.ts';
|
|
2
|
+
import type { AnyArguments, AppOptions, BackendInfo, UserAgentOptions, MojoAction, MojoContext, MojoModels, NestedHelpers, RouteArguments, ServerOptions, TestUserAgentOptions } from './types.ts';
|
|
3
|
+
import { CLI } from './cli.ts';
|
|
4
|
+
import { Hooks } from './hooks.ts';
|
|
5
|
+
import { Logger } from './logger.ts';
|
|
6
|
+
import { Mime } from './mime.ts';
|
|
7
|
+
import { Renderer } from './renderer.ts';
|
|
8
|
+
import { Router } from './router.ts';
|
|
9
|
+
import { ServerRequest } from './server/request.ts';
|
|
10
|
+
import { ServerResponse } from './server/response.ts';
|
|
11
|
+
import { Session } from './session.ts';
|
|
12
|
+
import { Static } from './static.ts';
|
|
13
|
+
import { MockUserAgent } from './user-agent/mock.ts';
|
|
14
|
+
import { TestUserAgent } from './user-agent/test.ts';
|
|
15
|
+
import { UserAgent } from './user-agent.ts';
|
|
16
|
+
import { Validator } from './validator.ts';
|
|
17
17
|
import Path from '@mojojs/path';
|
|
18
18
|
type AppHook = (app: App, ...args: any[]) => any;
|
|
19
19
|
type ContextHook = (app: MojoContext, ...args: any[]) => any;
|
|
@@ -85,6 +85,14 @@ export declare class App {
|
|
|
85
85
|
* app.log.debug('It works');
|
|
86
86
|
*/
|
|
87
87
|
log: Logger;
|
|
88
|
+
/**
|
|
89
|
+
* Maximum request body size in bytes, defaults to `16777216` (16 MiB). Requests exceeding the limit are answered
|
|
90
|
+
* with `413` when the body is read. Can also be changed for individual requests with `ctx.req.maxMessageSize`.
|
|
91
|
+
* @example
|
|
92
|
+
* // Allow larger uploads for the whole application
|
|
93
|
+
* app.maxRequestSize = 1024 * 1024 * 1024;
|
|
94
|
+
*/
|
|
95
|
+
maxRequestSize: number;
|
|
88
96
|
/**
|
|
89
97
|
* MIME types.
|
|
90
98
|
* @example
|
|
@@ -333,6 +341,13 @@ export declare class App {
|
|
|
333
341
|
* app.put('/user').to('User#replace');
|
|
334
342
|
*/
|
|
335
343
|
put(...args: RouteArguments): Route;
|
|
344
|
+
/**
|
|
345
|
+
* Generate route matching only `QUERY` requests.
|
|
346
|
+
* @example
|
|
347
|
+
* // Route with destination
|
|
348
|
+
* app.query('/search').to('Search#index');
|
|
349
|
+
*/
|
|
350
|
+
query(...args: RouteArguments): Route;
|
|
336
351
|
/**
|
|
337
352
|
* Start the command line interface.
|
|
338
353
|
* @example
|
package/lib/app.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
|
-
import { CLI } from
|
|
3
|
-
import { Context } from
|
|
4
|
-
import { Hooks } from
|
|
5
|
-
import { Logger } from
|
|
6
|
-
import { Mime } from
|
|
7
|
-
import defaultConditionsPlugin from
|
|
8
|
-
import defaultHelpersPlugin from
|
|
9
|
-
import tmplEnginePlugin from
|
|
10
|
-
import { Renderer } from
|
|
11
|
-
import { Router } from
|
|
12
|
-
import { ServerRequest } from
|
|
13
|
-
import { ServerResponse } from
|
|
14
|
-
import { Session } from
|
|
15
|
-
import { Static } from
|
|
16
|
-
import { MockUserAgent } from
|
|
17
|
-
import { TestUserAgent } from
|
|
18
|
-
import { UserAgent } from
|
|
19
|
-
import { Validator } from
|
|
2
|
+
import { CLI } from "./cli.js";
|
|
3
|
+
import { Context } from "./context.js";
|
|
4
|
+
import { Hooks } from "./hooks.js";
|
|
5
|
+
import { Logger } from "./logger.js";
|
|
6
|
+
import { Mime } from "./mime.js";
|
|
7
|
+
import defaultConditionsPlugin from "./plugins/default-conditions.js";
|
|
8
|
+
import defaultHelpersPlugin from "./plugins/default-helpers.js";
|
|
9
|
+
import tmplEnginePlugin from "./plugins/tmpl-engine.js";
|
|
10
|
+
import { Renderer } from "./renderer.js";
|
|
11
|
+
import { Router } from "./router.js";
|
|
12
|
+
import { ServerRequest } from "./server/request.js";
|
|
13
|
+
import { ServerResponse } from "./server/response.js";
|
|
14
|
+
import { Session } from "./session.js";
|
|
15
|
+
import { Static } from "./static.js";
|
|
16
|
+
import { MockUserAgent } from "./user-agent/mock.js";
|
|
17
|
+
import { TestUserAgent } from "./user-agent/test.js";
|
|
18
|
+
import { UserAgent } from "./user-agent.js";
|
|
19
|
+
import { Validator } from "./validator.js";
|
|
20
20
|
import Path from '@mojojs/path';
|
|
21
21
|
const ContextWrapper = class extends Context {
|
|
22
22
|
};
|
|
@@ -24,111 +24,159 @@ const ContextWrapper = class extends Context {
|
|
|
24
24
|
* Application class.
|
|
25
25
|
*/
|
|
26
26
|
export class App {
|
|
27
|
+
/**
|
|
28
|
+
* Command line interface.
|
|
29
|
+
* @example
|
|
30
|
+
* // Add another path to load commands from
|
|
31
|
+
* app.cli.commandPaths.push(app.home.child('cli').toString());
|
|
32
|
+
*/
|
|
33
|
+
cli = new CLI(this);
|
|
34
|
+
/**
|
|
35
|
+
* Application config.
|
|
36
|
+
* @example
|
|
37
|
+
* // Remove value
|
|
38
|
+
* delete app.config.foo;
|
|
39
|
+
*
|
|
40
|
+
* // Assign multiple values at once
|
|
41
|
+
* Object.assign(app.config, {foo: 'test', bar: 23});
|
|
42
|
+
*/
|
|
43
|
+
config;
|
|
44
|
+
/**
|
|
45
|
+
* Default stash values.
|
|
46
|
+
* @example
|
|
47
|
+
* // Remove value
|
|
48
|
+
* delete app.defaults.foo;
|
|
49
|
+
*
|
|
50
|
+
* // Assign multiple values at once
|
|
51
|
+
* Object.assign(app.defaults, {foo: 'test', bar: 23});
|
|
52
|
+
*/
|
|
53
|
+
defaults = {};
|
|
54
|
+
/**
|
|
55
|
+
* Detect if the application has been imported and disable the command line interface if it has.
|
|
56
|
+
*/
|
|
57
|
+
detectImport;
|
|
58
|
+
/**
|
|
59
|
+
* Format for HTTP exceptions ("html", "json", or "txt").
|
|
60
|
+
* @example
|
|
61
|
+
* // Change default exception format for whole application
|
|
62
|
+
* app.exceptionFormat = 'json';
|
|
63
|
+
*/
|
|
64
|
+
exceptionFormat;
|
|
65
|
+
/**
|
|
66
|
+
* Application hooks.
|
|
67
|
+
* @example
|
|
68
|
+
* // Run a custom hook
|
|
69
|
+
* await app.hooks.runHook('my:hook', foo, bar);
|
|
70
|
+
*/
|
|
71
|
+
hooks = new Hooks();
|
|
72
|
+
/**
|
|
73
|
+
* Application home directory.
|
|
74
|
+
* @example
|
|
75
|
+
* // Portably generate path relative to home directory
|
|
76
|
+
* const path = app.home.child('data', 'important.txt');
|
|
77
|
+
*/
|
|
78
|
+
home = new Path();
|
|
79
|
+
/**
|
|
80
|
+
* Application logger.
|
|
81
|
+
* @example
|
|
82
|
+
* // Log debug message
|
|
83
|
+
* app.log.debug('It works');
|
|
84
|
+
*/
|
|
85
|
+
log;
|
|
86
|
+
/**
|
|
87
|
+
* Maximum request body size in bytes, defaults to `16777216` (16 MiB). Requests exceeding the limit are answered
|
|
88
|
+
* with `413` when the body is read. Can also be changed for individual requests with `ctx.req.maxMessageSize`.
|
|
89
|
+
* @example
|
|
90
|
+
* // Allow larger uploads for the whole application
|
|
91
|
+
* app.maxRequestSize = 1024 * 1024 * 1024;
|
|
92
|
+
*/
|
|
93
|
+
maxRequestSize = 16 * 1024 * 1024;
|
|
94
|
+
/**
|
|
95
|
+
* MIME types.
|
|
96
|
+
* @example
|
|
97
|
+
* // Get MIME type for extension
|
|
98
|
+
* const type = app.mime.extType('txt');
|
|
99
|
+
*/
|
|
100
|
+
mime = new Mime();
|
|
101
|
+
/**
|
|
102
|
+
* Operating mode for application. Defaults to the value of the `NODE_ENV` environment variable or `development`.
|
|
103
|
+
*/
|
|
104
|
+
mode;
|
|
105
|
+
// Apps augment MojoModels with required keys they fill in later
|
|
106
|
+
/**
|
|
107
|
+
* Storage for user defined models.
|
|
108
|
+
* @example
|
|
109
|
+
* // Store database connection
|
|
110
|
+
* app.models.pg = new Pg('postgres://127.0.0.1:5432/db');
|
|
111
|
+
*/
|
|
112
|
+
models = {};
|
|
113
|
+
/**
|
|
114
|
+
* Application renderer.
|
|
115
|
+
* @example
|
|
116
|
+
* // Disable compression
|
|
117
|
+
* app.renderer.autoCompress = false;
|
|
118
|
+
*
|
|
119
|
+
* // Add another "views" directory
|
|
120
|
+
* app.renderer.viewPaths.push(app.home.child('views').toString());
|
|
121
|
+
*/
|
|
122
|
+
renderer = new Renderer();
|
|
123
|
+
/**
|
|
124
|
+
* Application router.
|
|
125
|
+
* @example
|
|
126
|
+
* // Add routes
|
|
127
|
+
* const r = app.router;
|
|
128
|
+
* r.get('/foo/bar').to('test#foo', {title: 'Hello Mojo!'});
|
|
129
|
+
* r.post('/baz').to('test#baz');
|
|
130
|
+
*
|
|
131
|
+
* // Add another path to load controllers from
|
|
132
|
+
* app.router.controllerPaths.push(app.home.child('more-controllers').toString());
|
|
133
|
+
*/
|
|
134
|
+
router = new Router();
|
|
135
|
+
/**
|
|
136
|
+
* Rotating secret passphrases used for signed cookies and the like.
|
|
137
|
+
* @example
|
|
138
|
+
* // Rotate passphrases
|
|
139
|
+
* app.secrets = ['new_passw0rd', 'old_passw0rd', 'very_old_passw0rd'];
|
|
140
|
+
*/
|
|
141
|
+
secrets;
|
|
142
|
+
/**
|
|
143
|
+
* Encrypted cookie based session manager.
|
|
144
|
+
* @example
|
|
145
|
+
* // Change name of cookie used for all sessions
|
|
146
|
+
* app.sessions.cookieName = 'mysession';
|
|
147
|
+
*
|
|
148
|
+
* // Disable SameSite feature
|
|
149
|
+
* app.sessions.sameSite = 'none';
|
|
150
|
+
*/
|
|
151
|
+
session = new Session(this);
|
|
152
|
+
/**
|
|
153
|
+
* Static file server.
|
|
154
|
+
* @example
|
|
155
|
+
* // Add another "public" directory
|
|
156
|
+
* app.static.publicPaths.push('/home/sri/public');
|
|
157
|
+
*
|
|
158
|
+
* // Add another "public" directory with higher precedence
|
|
159
|
+
* app.static.publicPaths.unshift('/home/sri/themes/blue/public');
|
|
160
|
+
*/
|
|
161
|
+
static = new Static();
|
|
162
|
+
/**
|
|
163
|
+
* HTTP/WebSocket user-agent.
|
|
164
|
+
* @example
|
|
165
|
+
* # Perform HTTP request
|
|
166
|
+
* const res = await app.ua.get('http://example.com');
|
|
167
|
+
*/
|
|
168
|
+
ua = new UserAgent();
|
|
169
|
+
/**
|
|
170
|
+
* JSON schema validator.
|
|
171
|
+
* @example
|
|
172
|
+
* // Add a named schema for later use
|
|
173
|
+
* app.validator.addSchema({type: 'object', properties: {test: {type: 'number'}}}, 'testForm');
|
|
174
|
+
*/
|
|
175
|
+
validator = new Validator();
|
|
176
|
+
_contextClass = class extends ContextWrapper {
|
|
177
|
+
};
|
|
178
|
+
_nestedHelpers = {};
|
|
27
179
|
constructor(options = {}) {
|
|
28
|
-
/**
|
|
29
|
-
* Command line interface.
|
|
30
|
-
* @example
|
|
31
|
-
* // Add another path to load commands from
|
|
32
|
-
* app.cli.commandPaths.push(app.home.child('cli').toString());
|
|
33
|
-
*/
|
|
34
|
-
this.cli = new CLI(this);
|
|
35
|
-
/**
|
|
36
|
-
* Default stash values.
|
|
37
|
-
* @example
|
|
38
|
-
* // Remove value
|
|
39
|
-
* delete app.defaults.foo;
|
|
40
|
-
*
|
|
41
|
-
* // Assign multiple values at once
|
|
42
|
-
* Object.assign(app.defaults, {foo: 'test', bar: 23});
|
|
43
|
-
*/
|
|
44
|
-
this.defaults = {};
|
|
45
|
-
/**
|
|
46
|
-
* Application hooks.
|
|
47
|
-
* @example
|
|
48
|
-
* // Run a custom hook
|
|
49
|
-
* await app.hooks.runHook('my:hook', foo, bar);
|
|
50
|
-
*/
|
|
51
|
-
this.hooks = new Hooks();
|
|
52
|
-
/**
|
|
53
|
-
* Application home directory.
|
|
54
|
-
* @example
|
|
55
|
-
* // Portably generate path relative to home directory
|
|
56
|
-
* const path = app.home.child('data', 'important.txt');
|
|
57
|
-
*/
|
|
58
|
-
this.home = new Path();
|
|
59
|
-
/**
|
|
60
|
-
* MIME types.
|
|
61
|
-
* @example
|
|
62
|
-
* // Get MIME type for extension
|
|
63
|
-
* const type = app.mime.extType('txt');
|
|
64
|
-
*/
|
|
65
|
-
this.mime = new Mime();
|
|
66
|
-
/**
|
|
67
|
-
* Storage for user defined models.
|
|
68
|
-
* @example
|
|
69
|
-
* // Store database connection
|
|
70
|
-
* app.models.pg = new Pg('postgres://127.0.0.1:5432/db');
|
|
71
|
-
*/
|
|
72
|
-
this.models = {};
|
|
73
|
-
/**
|
|
74
|
-
* Application renderer.
|
|
75
|
-
* @example
|
|
76
|
-
* // Disable compression
|
|
77
|
-
* app.renderer.autoCompress = false;
|
|
78
|
-
*
|
|
79
|
-
* // Add another "views" directory
|
|
80
|
-
* app.renderer.viewPaths.push(app.home.child('views').toString());
|
|
81
|
-
*/
|
|
82
|
-
this.renderer = new Renderer();
|
|
83
|
-
/**
|
|
84
|
-
* Application router.
|
|
85
|
-
* @example
|
|
86
|
-
* // Add routes
|
|
87
|
-
* const r = app.router;
|
|
88
|
-
* r.get('/foo/bar').to('test#foo', {title: 'Hello Mojo!'});
|
|
89
|
-
* r.post('/baz').to('test#baz');
|
|
90
|
-
*
|
|
91
|
-
* // Add another path to load controllers from
|
|
92
|
-
* app.router.controllerPaths.push(app.home.child('more-controllers').toString());
|
|
93
|
-
*/
|
|
94
|
-
this.router = new Router();
|
|
95
|
-
/**
|
|
96
|
-
* Encrypted cookie based session manager.
|
|
97
|
-
* @example
|
|
98
|
-
* // Change name of cookie used for all sessions
|
|
99
|
-
* app.sessions.cookieName = 'mysession';
|
|
100
|
-
*
|
|
101
|
-
* // Disable SameSite feature
|
|
102
|
-
* app.sessions.sameSite = 'none';
|
|
103
|
-
*/
|
|
104
|
-
this.session = new Session(this);
|
|
105
|
-
/**
|
|
106
|
-
* Static file server.
|
|
107
|
-
* @example
|
|
108
|
-
* // Add another "public" directory
|
|
109
|
-
* app.static.publicPaths.push('/home/sri/public');
|
|
110
|
-
*
|
|
111
|
-
* // Add another "public" directory with higher precedence
|
|
112
|
-
* app.static.publicPaths.unshift('/home/sri/themes/blue/public');
|
|
113
|
-
*/
|
|
114
|
-
this.static = new Static();
|
|
115
|
-
/**
|
|
116
|
-
* HTTP/WebSocket user-agent.
|
|
117
|
-
* @example
|
|
118
|
-
* # Perform HTTP request
|
|
119
|
-
* const res = await app.ua.get('http://example.com');
|
|
120
|
-
*/
|
|
121
|
-
this.ua = new UserAgent();
|
|
122
|
-
/**
|
|
123
|
-
* JSON schema validator.
|
|
124
|
-
* @example
|
|
125
|
-
* // Add a named schema for later use
|
|
126
|
-
* app.validator.addSchema({type: 'object', properties: {test: {type: 'number'}}}, 'testForm');
|
|
127
|
-
*/
|
|
128
|
-
this.validator = new Validator();
|
|
129
|
-
this._contextClass = class extends ContextWrapper {
|
|
130
|
-
};
|
|
131
|
-
this._nestedHelpers = {};
|
|
132
180
|
this.config = options.config ?? {};
|
|
133
181
|
this.detectImport = options.detectImport ?? true;
|
|
134
182
|
this.exceptionFormat = options.exceptionFormat ?? 'html';
|
|
@@ -194,10 +242,9 @@ export class App {
|
|
|
194
242
|
this._nestedHelpers[getterName] = {};
|
|
195
243
|
this.decorateContext(getterName, {
|
|
196
244
|
get: function () {
|
|
197
|
-
|
|
198
|
-
return ((_a = this._nestedHelpersCache)[getterName] ?? (_a[getterName] = Object.create(this.app._nestedHelpers[getterName], {
|
|
245
|
+
return (this._nestedHelpersCache[getterName] ??= Object.create(this.app._nestedHelpers[getterName], {
|
|
199
246
|
_ctx: { value: this }
|
|
200
|
-
}))
|
|
247
|
+
}));
|
|
201
248
|
}
|
|
202
249
|
});
|
|
203
250
|
}
|
|
@@ -399,6 +446,15 @@ export class App {
|
|
|
399
446
|
put(...args) {
|
|
400
447
|
return this.router.put(...args);
|
|
401
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Generate route matching only `QUERY` requests.
|
|
451
|
+
* @example
|
|
452
|
+
* // Route with destination
|
|
453
|
+
* app.query('/search').to('Search#index');
|
|
454
|
+
*/
|
|
455
|
+
query(...args) {
|
|
456
|
+
return this.router.query(...args);
|
|
457
|
+
}
|
|
402
458
|
/**
|
|
403
459
|
* Start the command line interface.
|
|
404
460
|
* @example
|
|
@@ -445,4 +501,3 @@ export class App {
|
|
|
445
501
|
return this.router.websocket(...args);
|
|
446
502
|
}
|
|
447
503
|
}
|
|
448
|
-
//# sourceMappingURL=app.js.map
|
package/lib/body/params.js
CHANGED
package/lib/body.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { JSONValue, UploadOptions } from './types.
|
|
2
|
-
import type
|
|
3
|
-
import { Params } from './body/params.
|
|
4
|
-
import { Headers } from './headers.
|
|
1
|
+
import type { JSONValue, UploadOptions } from './types.ts';
|
|
2
|
+
import { type Readable, type Writable } from 'node:stream';
|
|
3
|
+
import { Params } from './body/params.ts';
|
|
4
|
+
import { Headers } from './headers.ts';
|
|
5
5
|
import DOM from '@mojojs/dom';
|
|
6
6
|
interface FileUpload {
|
|
7
7
|
fieldname: string;
|
|
@@ -10,7 +10,11 @@ interface FileUpload {
|
|
|
10
10
|
encoding: string;
|
|
11
11
|
mimetype: string;
|
|
12
12
|
}
|
|
13
|
-
type FormIterator = AsyncIterableIterator<[string, Readable,
|
|
13
|
+
type FormIterator = AsyncIterableIterator<[string, Readable, {
|
|
14
|
+
filename: string;
|
|
15
|
+
encoding: string;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
}]>;
|
|
14
18
|
/**
|
|
15
19
|
* HTTP message body base class.
|
|
16
20
|
*/
|
|
@@ -23,6 +27,10 @@ export declare class Body {
|
|
|
23
27
|
* HTTP headers.
|
|
24
28
|
*/
|
|
25
29
|
headers: Headers;
|
|
30
|
+
/**
|
|
31
|
+
* Maximum message body size in bytes, after decompression, unlimited by default.
|
|
32
|
+
*/
|
|
33
|
+
maxMessageSize: number | undefined;
|
|
26
34
|
_form: Params | undefined;
|
|
27
35
|
_stream: Readable;
|
|
28
36
|
constructor(headers: string[], stream: Readable);
|
package/lib/body.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { on } from 'node:events';
|
|
2
|
+
import { Transform } from 'node:stream';
|
|
2
3
|
import zlib from 'node:zlib';
|
|
3
|
-
import { Params } from
|
|
4
|
-
import { Headers } from
|
|
4
|
+
import { Params } from "./body/params.js";
|
|
5
|
+
import { Headers } from "./headers.js";
|
|
6
|
+
import { HTTPError } from "./util.js";
|
|
5
7
|
import DOM from '@mojojs/dom';
|
|
6
8
|
import busboy from 'busboy';
|
|
7
9
|
import * as yaml from 'js-yaml';
|
|
@@ -9,12 +11,21 @@ import * as yaml from 'js-yaml';
|
|
|
9
11
|
* HTTP message body base class.
|
|
10
12
|
*/
|
|
11
13
|
export class Body {
|
|
14
|
+
/**
|
|
15
|
+
* Automatically decompress message body if necessary.
|
|
16
|
+
*/
|
|
17
|
+
autoDecompress = true;
|
|
18
|
+
/**
|
|
19
|
+
* HTTP headers.
|
|
20
|
+
*/
|
|
21
|
+
headers;
|
|
22
|
+
/**
|
|
23
|
+
* Maximum message body size in bytes, after decompression, unlimited by default.
|
|
24
|
+
*/
|
|
25
|
+
maxMessageSize = undefined;
|
|
26
|
+
_form = undefined;
|
|
27
|
+
_stream;
|
|
12
28
|
constructor(headers, stream) {
|
|
13
|
-
/**
|
|
14
|
-
* Automatically decompress message body if necessary.
|
|
15
|
-
*/
|
|
16
|
-
this.autoDecompress = true;
|
|
17
|
-
this._form = undefined;
|
|
18
29
|
this._stream = stream;
|
|
19
30
|
this.headers = new Headers(headers);
|
|
20
31
|
}
|
|
@@ -34,11 +45,27 @@ export class Body {
|
|
|
34
45
|
const stream = this._stream;
|
|
35
46
|
if (stream.readableEnded === true)
|
|
36
47
|
throw new Error('Request body has already been consumed');
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
stream
|
|
41
|
-
|
|
48
|
+
const max = this.maxMessageSize;
|
|
49
|
+
if (max !== undefined && parseInt(this.get('Content-Length') ?? '0') > max)
|
|
50
|
+
throw messageTooLarge();
|
|
51
|
+
let body = stream;
|
|
52
|
+
if (this.autoDecompress === true && this.get('content-encoding') === 'gzip') {
|
|
53
|
+
const gunzip = zlib.createGunzip();
|
|
54
|
+
stream.on('error', error => gunzip.destroy(error));
|
|
55
|
+
body = stream.pipe(gunzip);
|
|
56
|
+
}
|
|
57
|
+
if (max === undefined)
|
|
58
|
+
return body;
|
|
59
|
+
// Count after decompression, so small gzip bodies cannot unpack to huge ones
|
|
60
|
+
let size = 0;
|
|
61
|
+
const limit = new Transform({
|
|
62
|
+
transform(chunk, encoding, cb) {
|
|
63
|
+
size += chunk.length;
|
|
64
|
+
cb(size > max ? messageTooLarge() : null, chunk);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
body.on('error', error => limit.destroy(error));
|
|
68
|
+
return body.pipe(limit);
|
|
42
69
|
}
|
|
43
70
|
/**
|
|
44
71
|
* Get async iterator for uploaded files from message body.
|
|
@@ -57,9 +84,8 @@ export class Body {
|
|
|
57
84
|
if (this._isForm() === false)
|
|
58
85
|
return;
|
|
59
86
|
try {
|
|
60
|
-
for await (const [fieldname, file,
|
|
61
|
-
|
|
62
|
-
yield { fieldname, file, filename, encoding, mimetype };
|
|
87
|
+
for await (const [fieldname, file, { filename, encoding, mimeType }] of this._formIterator(options)) {
|
|
88
|
+
yield { fieldname, file, filename, encoding, mimetype: mimeType };
|
|
63
89
|
}
|
|
64
90
|
}
|
|
65
91
|
catch (error) {
|
|
@@ -155,7 +181,9 @@ export class Body {
|
|
|
155
181
|
bb.on('field', (fieldname, val) => params.append(fieldname, val));
|
|
156
182
|
bb.on('end', () => ac.abort()).on('close', () => ac.abort());
|
|
157
183
|
const files = on(bb, 'file', { signal: ac.signal });
|
|
158
|
-
this.
|
|
184
|
+
this.createReadStream()
|
|
185
|
+
.on('error', error => bb.destroy(error))
|
|
186
|
+
.pipe(bb);
|
|
159
187
|
return files;
|
|
160
188
|
}
|
|
161
189
|
_isForm() {
|
|
@@ -170,4 +198,6 @@ export class Body {
|
|
|
170
198
|
return this._form;
|
|
171
199
|
}
|
|
172
200
|
}
|
|
173
|
-
|
|
201
|
+
function messageTooLarge() {
|
|
202
|
+
return new HTTPError(413, 'Maximum message size exceeded');
|
|
203
|
+
}
|
package/lib/cache.d.ts
CHANGED
package/lib/cache.js
CHANGED
|
@@ -2,19 +2,17 @@
|
|
|
2
2
|
* Cache class.
|
|
3
3
|
*/
|
|
4
4
|
export class Cache {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
this._queue = [];
|
|
12
|
-
}
|
|
5
|
+
/**
|
|
6
|
+
* Maximum number of values in cache, defaults to `100`.
|
|
7
|
+
*/
|
|
8
|
+
max = 100;
|
|
9
|
+
// Maps keep insertion order, so the first key is always the oldest
|
|
10
|
+
_cache = new Map();
|
|
13
11
|
/**
|
|
14
12
|
* Get cached value.
|
|
15
13
|
*/
|
|
16
14
|
get(key) {
|
|
17
|
-
return this._cache
|
|
15
|
+
return this._cache.get(key);
|
|
18
16
|
}
|
|
19
17
|
/**
|
|
20
18
|
* Add value to the cache.
|
|
@@ -24,22 +22,15 @@ export class Cache {
|
|
|
24
22
|
if (max <= 0)
|
|
25
23
|
return;
|
|
26
24
|
const cache = this._cache;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
delete cache[key];
|
|
32
|
-
}
|
|
33
|
-
if (cache[key] === undefined) {
|
|
34
|
-
queue.push(key);
|
|
35
|
-
cache[key] = value;
|
|
36
|
-
}
|
|
25
|
+
while (cache.size >= max)
|
|
26
|
+
cache.delete(cache.keys().next().value);
|
|
27
|
+
if (cache.has(key) === false)
|
|
28
|
+
cache.set(key, value);
|
|
37
29
|
}
|
|
38
30
|
/**
|
|
39
31
|
* Current size of the cache.
|
|
40
32
|
*/
|
|
41
33
|
get size() {
|
|
42
|
-
return this.
|
|
34
|
+
return this._cache.size;
|
|
43
35
|
}
|
|
44
36
|
}
|
|
45
|
-
//# sourceMappingURL=cache.js.map
|
package/lib/cgi.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { MojoApp, ServerResponseBody } from './types.
|
|
1
|
+
import type { MojoApp, ServerResponseBody } from './types.ts';
|
|
2
2
|
import { type Readable } from 'node:stream';
|
|
3
|
-
import { ServerRequest } from './server/request.
|
|
4
|
-
import { ServerResponse } from './server/response.
|
|
3
|
+
import { ServerRequest } from './server/request.ts';
|
|
4
|
+
import { ServerResponse } from './server/response.ts';
|
|
5
5
|
/**
|
|
6
6
|
* CGI class. Is this a joke? Yes. Could you use it in production anyway? Probably.
|
|
7
7
|
*/
|
package/lib/cgi.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Stream } from 'node:stream';
|
|
2
|
-
import { ServerRequest } from
|
|
3
|
-
import { ServerResponse } from
|
|
4
|
-
import { httpStatusMessages } from
|
|
2
|
+
import { ServerRequest } from "./server/request.js";
|
|
3
|
+
import { ServerResponse } from "./server/response.js";
|
|
4
|
+
import { httpStatusMessages } from "./util.js";
|
|
5
|
+
import { decodeURIComponentSafe } from '@mojojs/util';
|
|
5
6
|
/**
|
|
6
7
|
* CGI class. Is this a joke? Yes. Could you use it in production anyway? Probably.
|
|
7
8
|
*/
|
|
8
9
|
export class CGI {
|
|
10
|
+
app;
|
|
9
11
|
constructor(app) {
|
|
10
12
|
this.app = app;
|
|
11
13
|
}
|
|
@@ -17,9 +19,15 @@ export class CGI {
|
|
|
17
19
|
const method = env.REQUEST_METHOD ?? 'GET';
|
|
18
20
|
// URL
|
|
19
21
|
let url = env.PATH_INFO ?? '/';
|
|
20
|
-
const name = env.SCRIPT_NAME;
|
|
21
|
-
if (
|
|
22
|
-
|
|
22
|
+
const name = (env.SCRIPT_NAME ?? '').replace(/^\/|\/$/g, '');
|
|
23
|
+
// Remove SCRIPT_NAME prefix if necessary (unless the server already did it)
|
|
24
|
+
const uri = decodeURIComponentSafe((env.REQUEST_URI ?? '').replace(/\?.*$/, '')) ?? '';
|
|
25
|
+
if (name !== '' && uri.startsWith(`/${name}${url}`) === false) {
|
|
26
|
+
if (url === `/${name}`)
|
|
27
|
+
url = '/';
|
|
28
|
+
else if (url.startsWith(`/${name}/`) === true)
|
|
29
|
+
url = url.slice(name.length + 1);
|
|
30
|
+
}
|
|
23
31
|
const query = env.QUERY_STRING;
|
|
24
32
|
if (query !== undefined && query !== '')
|
|
25
33
|
url += `?${query}`;
|
|
@@ -72,8 +80,8 @@ export class CGI {
|
|
|
72
80
|
}
|
|
73
81
|
else if (body instanceof Stream) {
|
|
74
82
|
stdout.write(res.headers.toString());
|
|
75
|
-
|
|
83
|
+
// Not pipeline, because stdout must stay open, and the response is just cut short on errors
|
|
84
|
+
body.on('error', () => { }).pipe(stdout);
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
|
-
//# sourceMappingURL=cgi.js.map
|