@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.
- package/README.md +1 -1
- package/lib/app.d.ts +24 -16
- package/lib/app.js +172 -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 +6 -5
- 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 +10 -10
- package/lib/context.js +94 -34
- package/lib/core.d.ts +14 -14
- package/lib/core.js +12 -13
- 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 +3 -3
- package/lib/router/route.js +35 -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 +1 -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 +69 -19
- package/lib/session.d.ts +3 -3
- package/lib/session.js +46 -34
- package/lib/sse.d.ts +1 -1
- package/lib/sse.js +0 -1
- package/lib/static.d.ts +1 -1
- package/lib/static.js +27 -22
- package/lib/types.d.ts +6 -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 +2 -2
- package/lib/user-agent/response.js +14 -3
- package/lib/user-agent/test.d.ts +5 -5
- package/lib/user-agent/test.js +14 -15
- 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 +18 -19
- package/lib/user-agent.js +64 -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/sse.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/lib/context.js
CHANGED
|
@@ -1,49 +1,110 @@
|
|
|
1
1
|
import EventEmitter from 'node:events';
|
|
2
2
|
import querystring from 'node:querystring';
|
|
3
3
|
import { PassThrough } from 'node:stream';
|
|
4
|
-
import { Params } from
|
|
5
|
-
import { buildEvent } from
|
|
6
|
-
import { SafeString } from
|
|
4
|
+
import { Params } from "./body/params.js";
|
|
5
|
+
import { buildEvent } from "./sse.js";
|
|
6
|
+
import { SafeString } from "./util.js";
|
|
7
7
|
const ABSOLUTE = /^[a-zA-Z][a-zA-Z0-9]*:\/\//;
|
|
8
8
|
/**
|
|
9
9
|
* Context class.
|
|
10
10
|
*/
|
|
11
11
|
class Context extends EventEmitter {
|
|
12
|
+
/**
|
|
13
|
+
* Application this context belongs to.
|
|
14
|
+
*/
|
|
15
|
+
app;
|
|
16
|
+
/**
|
|
17
|
+
* Backend information for server that received the request.
|
|
18
|
+
* @example
|
|
19
|
+
* // Backend name (usually "server", "cgi", or "mock")
|
|
20
|
+
* const {name} = ctx.backend;
|
|
21
|
+
*
|
|
22
|
+
* // Use low level Node.js APIs with "server" backend
|
|
23
|
+
* const {res} = ctx.backend;
|
|
24
|
+
* res.writeHead(200);
|
|
25
|
+
* res.end('Hello World!');
|
|
26
|
+
*/
|
|
27
|
+
backend;
|
|
28
|
+
/**
|
|
29
|
+
* Partial content. Always returns at least an empty string, even for sections that have not been defined with
|
|
30
|
+
* `ctx.contentFor()`.
|
|
31
|
+
* @example
|
|
32
|
+
* // Get content for "head" section
|
|
33
|
+
* const head = ctx.content.head;
|
|
34
|
+
*/
|
|
35
|
+
content = new Proxy({}, {
|
|
36
|
+
get: function (target, name) {
|
|
37
|
+
return new SafeString(target[name] ?? '');
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Format for HTTP exceptions ("html", "json", or "txt").
|
|
42
|
+
*/
|
|
43
|
+
exceptionFormat;
|
|
44
|
+
/**
|
|
45
|
+
* WebSocket JSON mode.
|
|
46
|
+
*/
|
|
47
|
+
jsonMode = false;
|
|
48
|
+
/**
|
|
49
|
+
* Logger with request id.
|
|
50
|
+
* @example
|
|
51
|
+
* // Pass logger with context to model
|
|
52
|
+
* const log = ctx.log;
|
|
53
|
+
* ctx.model.users.create({name: 'kraih'}, log);
|
|
54
|
+
*/
|
|
55
|
+
log;
|
|
56
|
+
/**
|
|
57
|
+
* Router dispatch plan.
|
|
58
|
+
*/
|
|
59
|
+
plan = null;
|
|
60
|
+
/**
|
|
61
|
+
* HTTP request information.
|
|
62
|
+
* @example
|
|
63
|
+
* // Extract request information
|
|
64
|
+
* const id = ctx.req.requestId;
|
|
65
|
+
* const method = ctx.req.method;
|
|
66
|
+
* const baseURL = ctx.req.baseURL;
|
|
67
|
+
* const url = ctx.req.url;
|
|
68
|
+
* const query = ctx.req.query;
|
|
69
|
+
* const info = ctx.req.userinfo;
|
|
70
|
+
* const agent = ctx.req.get('User-Agent');
|
|
71
|
+
* const buffer = await ctx.req.buffer();
|
|
72
|
+
* const text = await ctx.req.text();
|
|
73
|
+
* const form = await ctx.req.form();
|
|
74
|
+
* const value = await ctx.req.json();
|
|
75
|
+
* const html = await ctx.req.html();
|
|
76
|
+
* const xml = await ctx.req.xml();
|
|
77
|
+
*/
|
|
78
|
+
req;
|
|
79
|
+
/**
|
|
80
|
+
* HTTP response information.
|
|
81
|
+
* @example
|
|
82
|
+
* // Force file download by setting a response header
|
|
83
|
+
* ctx.res.set('Content-Disposition', 'attachment; filename=foo.png;');
|
|
84
|
+
*
|
|
85
|
+
* // Make sure response is cached correctly
|
|
86
|
+
* ctx.res.set('Cache-Control', 'public, max-age=300');
|
|
87
|
+
* ctx.res.headers.append('Vary', 'Accept-Encoding');
|
|
88
|
+
*/
|
|
89
|
+
res;
|
|
90
|
+
/**
|
|
91
|
+
* Non-persistent data storage and exchange for the current request.
|
|
92
|
+
*/
|
|
93
|
+
stash = {};
|
|
94
|
+
_flash = undefined;
|
|
95
|
+
_nestedHelpersCache = {};
|
|
96
|
+
_params = undefined;
|
|
97
|
+
_session = undefined;
|
|
98
|
+
_sse = undefined;
|
|
99
|
+
_ws = null;
|
|
12
100
|
constructor(app, req, res, backend) {
|
|
13
101
|
super({ captureRejections: true });
|
|
14
|
-
/**
|
|
15
|
-
* Partial content. Always returns at least an empty string, even for sections that have not been defined with
|
|
16
|
-
* `ctx.contentFor()`.
|
|
17
|
-
* @example
|
|
18
|
-
* // Get content for "head" section
|
|
19
|
-
* const head = ctx.content.head;
|
|
20
|
-
*/
|
|
21
|
-
this.content = new Proxy({}, {
|
|
22
|
-
get: function (target, name) {
|
|
23
|
-
return new SafeString(target[name] ?? '');
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
/**
|
|
27
|
-
* WebSocket JSON mode.
|
|
28
|
-
*/
|
|
29
|
-
this.jsonMode = false;
|
|
30
|
-
/**
|
|
31
|
-
* Router dispatch plan.
|
|
32
|
-
*/
|
|
33
|
-
this.plan = null;
|
|
34
|
-
/**
|
|
35
|
-
* Non-persistent data storage and exchange for the current request.
|
|
36
|
-
*/
|
|
37
|
-
this.stash = {};
|
|
38
|
-
this._flash = undefined;
|
|
39
|
-
this._nestedHelpersCache = {};
|
|
40
|
-
this._params = undefined;
|
|
41
|
-
this._session = undefined;
|
|
42
|
-
this._sse = undefined;
|
|
43
|
-
this._ws = null;
|
|
44
102
|
this.app = app;
|
|
45
103
|
this.exceptionFormat = app.exceptionFormat;
|
|
46
104
|
this.req = req;
|
|
105
|
+
// Mounted applications share the request, and the limit of the outer one
|
|
106
|
+
if (req.maxMessageSize === undefined)
|
|
107
|
+
req.maxMessageSize = app.maxRequestSize;
|
|
47
108
|
this.res = res;
|
|
48
109
|
this.res.bindContext(this);
|
|
49
110
|
this.backend = backend;
|
|
@@ -421,4 +482,3 @@ class Context extends EventEmitter {
|
|
|
421
482
|
}
|
|
422
483
|
}
|
|
423
484
|
export { Context };
|
|
424
|
-
//# sourceMappingURL=context.js.map
|
package/lib/core.d.ts
CHANGED
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
* Copyright (C) 2021-2024 Sebastian Riedel
|
|
4
4
|
* MIT Licensed
|
|
5
5
|
*/
|
|
6
|
-
import type { AppOptions } from './types.
|
|
7
|
-
import { App } from './app.
|
|
6
|
+
import type { AppOptions } from './types.ts';
|
|
7
|
+
import { App } from './app.ts';
|
|
8
8
|
export declare const version: any;
|
|
9
9
|
/**
|
|
10
10
|
* Create a new mojo.js application.
|
|
11
11
|
*/
|
|
12
12
|
export default function mojo(options?: AppOptions): App;
|
|
13
|
-
export { default as jsonConfigPlugin } from './plugins/json-config.
|
|
14
|
-
export { default as yamlConfigPlugin } from './plugins/yaml-config.
|
|
15
|
-
export { default as mountPlugin } from './plugins/mount.
|
|
16
|
-
export { CGI } from './cgi.
|
|
17
|
-
export { Logger } from './logger.
|
|
18
|
-
export { Server } from './server.
|
|
19
|
-
export { Session } from './session.
|
|
20
|
-
export { buildEvent, parseEvent } from './sse.
|
|
21
|
-
export { TestUserAgent } from './user-agent/test.
|
|
22
|
-
export { UserAgent } from './user-agent.
|
|
23
|
-
export * as util from './util.
|
|
24
|
-
export { JSONValue, MojoAction, MojoApp, MojoContext, MojoModels, MojoRenderOptions, MojoRoute, MojoTags, MojoURLOptions, SSEEvent } from './types.
|
|
13
|
+
export { default as jsonConfigPlugin } from './plugins/json-config.ts';
|
|
14
|
+
export { default as yamlConfigPlugin } from './plugins/yaml-config.ts';
|
|
15
|
+
export { default as mountPlugin } from './plugins/mount.ts';
|
|
16
|
+
export { CGI } from './cgi.ts';
|
|
17
|
+
export { Logger } from './logger.ts';
|
|
18
|
+
export { Server } from './server.ts';
|
|
19
|
+
export { Session } from './session.ts';
|
|
20
|
+
export { buildEvent, parseEvent } from './sse.ts';
|
|
21
|
+
export { TestUserAgent } from './user-agent/test.ts';
|
|
22
|
+
export { UserAgent } from './user-agent.ts';
|
|
23
|
+
export * as util from './util.ts';
|
|
24
|
+
export type { JSONValue, MojoAction, MojoApp, MojoContext, MojoModels, MojoRenderOptions, MojoRoute, MojoTags, MojoURLOptions, SSEEvent } from './types.ts';
|
package/lib/core.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { App } from
|
|
1
|
+
import { App } from "./app.js";
|
|
2
2
|
import Path from '@mojojs/path';
|
|
3
3
|
export const version = JSON.parse(Path.currentFile().dirname().sibling('package.json').readFileSync().toString()).version;
|
|
4
4
|
/**
|
|
@@ -22,15 +22,14 @@ export default function mojo(options) {
|
|
|
22
22
|
return app;
|
|
23
23
|
}
|
|
24
24
|
// "Professor: These old Doomsday devices are dangerously unstable. I'll rest easier not knowing where they are."
|
|
25
|
-
export { default as jsonConfigPlugin } from
|
|
26
|
-
export { default as yamlConfigPlugin } from
|
|
27
|
-
export { default as mountPlugin } from
|
|
28
|
-
export { CGI } from
|
|
29
|
-
export { Logger } from
|
|
30
|
-
export { Server } from
|
|
31
|
-
export { Session } from
|
|
32
|
-
export { buildEvent, parseEvent } from
|
|
33
|
-
export { TestUserAgent } from
|
|
34
|
-
export { UserAgent } from
|
|
35
|
-
export * as util from
|
|
36
|
-
//# sourceMappingURL=core.js.map
|
|
25
|
+
export { default as jsonConfigPlugin } from "./plugins/json-config.js";
|
|
26
|
+
export { default as yamlConfigPlugin } from "./plugins/yaml-config.js";
|
|
27
|
+
export { default as mountPlugin } from "./plugins/mount.js";
|
|
28
|
+
export { CGI } from "./cgi.js";
|
|
29
|
+
export { Logger } from "./logger.js";
|
|
30
|
+
export { Server } from "./server.js";
|
|
31
|
+
export { Session } from "./session.js";
|
|
32
|
+
export { buildEvent, parseEvent } from "./sse.js";
|
|
33
|
+
export { TestUserAgent } from "./user-agent/test.js";
|
|
34
|
+
export { UserAgent } from "./user-agent.js";
|
|
35
|
+
export * as util from "./util.js";
|
package/lib/headers.js
CHANGED
|
@@ -13,6 +13,8 @@ const HOP_BY_HOP = [
|
|
|
13
13
|
* HTTP header class.
|
|
14
14
|
*/
|
|
15
15
|
export class Headers {
|
|
16
|
+
_headers;
|
|
17
|
+
_init;
|
|
16
18
|
constructor(init = []) {
|
|
17
19
|
this._init = init;
|
|
18
20
|
}
|
|
@@ -70,7 +72,6 @@ export class Headers {
|
|
|
70
72
|
* const {link, title} = headers.getLinks().next;
|
|
71
73
|
*/
|
|
72
74
|
getLinks() {
|
|
73
|
-
var _a;
|
|
74
75
|
const data = {};
|
|
75
76
|
let value = this.get('Link') ?? '';
|
|
76
77
|
while (value.length > 0) {
|
|
@@ -81,7 +82,7 @@ export class Headers {
|
|
|
81
82
|
const { params, remainder } = headerParams(linkMatch[2]);
|
|
82
83
|
value = remainder;
|
|
83
84
|
if (params.rel !== undefined)
|
|
84
|
-
data[
|
|
85
|
+
data[params.rel] ??= { ...params, link };
|
|
85
86
|
}
|
|
86
87
|
return data;
|
|
87
88
|
}
|
|
@@ -149,7 +150,8 @@ export class Headers {
|
|
|
149
150
|
}
|
|
150
151
|
_getHeaders() {
|
|
151
152
|
if (this._headers === undefined) {
|
|
152
|
-
|
|
153
|
+
// No prototype, so names like "constructor" are just regular headers
|
|
154
|
+
const headers = (this._headers = Object.create(null));
|
|
153
155
|
const init = this._init;
|
|
154
156
|
for (let i = 0; i < init.length; i += 2) {
|
|
155
157
|
const name = init[i];
|
|
@@ -166,4 +168,3 @@ export class Headers {
|
|
|
166
168
|
return this._headers;
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
|
-
//# sourceMappingURL=headers.js.map
|
package/lib/hooks.d.ts
CHANGED
package/lib/hooks.js
CHANGED
|
@@ -3,10 +3,7 @@ import { AsyncHooks } from '@mojojs/util';
|
|
|
3
3
|
* Hook class.
|
|
4
4
|
*/
|
|
5
5
|
export class Hooks extends AsyncHooks {
|
|
6
|
-
|
|
7
|
-
super(...arguments);
|
|
8
|
-
this._lifecycleHookScore = 0;
|
|
9
|
-
}
|
|
6
|
+
_lifecycleHookScore = 0;
|
|
10
7
|
/**
|
|
11
8
|
* Run `command:before` hook with dependencies. Note that this method is EXPERIMENTAL and might change without
|
|
12
9
|
* warning!
|
|
@@ -49,4 +46,3 @@ export class Hooks extends AsyncHooks {
|
|
|
49
46
|
await this.runHook('app:stop', app);
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
|
-
//# sourceMappingURL=hooks.js.map
|
package/lib/logger.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ interface LogEvent extends LogContext {
|
|
|
8
8
|
time: string;
|
|
9
9
|
msg: string;
|
|
10
10
|
}
|
|
11
|
-
type LogFormatter = (data: LogEvent) => string;
|
|
11
|
+
type LogFormatter = (data: LogEvent, destination: NodeJS.WritableStream) => string;
|
|
12
12
|
/**
|
|
13
13
|
* A simple logger class.
|
|
14
14
|
*/
|
|
@@ -45,7 +45,7 @@ export declare class Logger {
|
|
|
45
45
|
/**
|
|
46
46
|
* Log formatter with color highlighting.
|
|
47
47
|
*/
|
|
48
|
-
static colorFormatter(data: LogEvent): string;
|
|
48
|
+
static colorFormatter(data: LogEvent, destination?: NodeJS.WritableStream): string;
|
|
49
49
|
/**
|
|
50
50
|
* Log `debug` message.
|
|
51
51
|
*/
|
package/lib/logger.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert';
|
|
2
|
-
import
|
|
2
|
+
import { styleText } from 'node:util';
|
|
3
3
|
const LEVEL = {
|
|
4
4
|
fatal: 2,
|
|
5
5
|
error: 3,
|
|
@@ -12,13 +12,22 @@ const LEVEL = {
|
|
|
12
12
|
* A simple logger class.
|
|
13
13
|
*/
|
|
14
14
|
export class Logger {
|
|
15
|
+
/**
|
|
16
|
+
* Log destination stream.
|
|
17
|
+
*/
|
|
18
|
+
destination;
|
|
19
|
+
/**
|
|
20
|
+
* Log formatter.
|
|
21
|
+
*/
|
|
22
|
+
formatter;
|
|
23
|
+
/**
|
|
24
|
+
* The last few logged messages.
|
|
25
|
+
*/
|
|
26
|
+
history = [];
|
|
27
|
+
_capture = undefined;
|
|
28
|
+
_historySize;
|
|
29
|
+
_level = 7;
|
|
15
30
|
constructor(options = {}) {
|
|
16
|
-
/**
|
|
17
|
-
* The last few logged messages.
|
|
18
|
-
*/
|
|
19
|
-
this.history = [];
|
|
20
|
-
this._capture = undefined;
|
|
21
|
-
this._level = 7;
|
|
22
31
|
this.destination = options.destination ?? process.stderr;
|
|
23
32
|
this.formatter = options.formatter ?? Logger.colorFormatter;
|
|
24
33
|
this.level = process.env.MOJO_LOG_LEVEL ?? options.level ?? 'trace';
|
|
@@ -47,13 +56,14 @@ export class Logger {
|
|
|
47
56
|
/**
|
|
48
57
|
* Log formatter with color highlighting.
|
|
49
58
|
*/
|
|
50
|
-
static colorFormatter(data) {
|
|
59
|
+
static colorFormatter(data, destination = process.stderr) {
|
|
51
60
|
const formatted = Logger.stringFormatter(data);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
return
|
|
56
|
-
|
|
61
|
+
const { level } = data;
|
|
62
|
+
const color = level === 'error' || level === 'fatal' ? 'red' : level === 'warn' ? 'yellow' : null;
|
|
63
|
+
if (color === null)
|
|
64
|
+
return formatted;
|
|
65
|
+
// Keep the trailing newline outside of the color codes, and only use colors if the destination supports them
|
|
66
|
+
return styleText(color, formatted.slice(0, -1), { stream: destination }) + '\n';
|
|
57
67
|
}
|
|
58
68
|
/**
|
|
59
69
|
* Log `debug` message.
|
|
@@ -139,7 +149,7 @@ export class Logger {
|
|
|
139
149
|
if (historySize > maxHistorySize)
|
|
140
150
|
history.splice(0, historySize - maxHistorySize);
|
|
141
151
|
}
|
|
142
|
-
const formatted = this.formatter(data);
|
|
152
|
+
const formatted = this.formatter(data, this.destination);
|
|
143
153
|
if (this._capture === undefined) {
|
|
144
154
|
this.destination.write(formatted);
|
|
145
155
|
}
|
|
@@ -152,9 +162,10 @@ export class Logger {
|
|
|
152
162
|
* Captured log message class.
|
|
153
163
|
*/
|
|
154
164
|
class CapturedLogs extends Array {
|
|
165
|
+
_cb;
|
|
166
|
+
_stopped = false;
|
|
155
167
|
constructor(cb) {
|
|
156
168
|
super();
|
|
157
|
-
this._stopped = false;
|
|
158
169
|
this._cb = cb;
|
|
159
170
|
}
|
|
160
171
|
/**
|
|
@@ -177,6 +188,8 @@ class CapturedLogs extends Array {
|
|
|
177
188
|
* Child logger class.
|
|
178
189
|
*/
|
|
179
190
|
export class ChildLogger {
|
|
191
|
+
parent;
|
|
192
|
+
context;
|
|
180
193
|
constructor(parent, context) {
|
|
181
194
|
this.parent = parent;
|
|
182
195
|
this.context = context;
|
|
@@ -218,4 +231,3 @@ export class ChildLogger {
|
|
|
218
231
|
this.parent.warn(msg, this.context);
|
|
219
232
|
}
|
|
220
233
|
}
|
|
221
|
-
//# sourceMappingURL=logger.js.map
|
package/lib/mime.js
CHANGED
|
@@ -3,18 +3,16 @@ import mime from 'mime-types';
|
|
|
3
3
|
* MIME class.
|
|
4
4
|
*/
|
|
5
5
|
export class Mime {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
this._reverseCustom = undefined;
|
|
17
|
-
}
|
|
6
|
+
/**
|
|
7
|
+
* Custom MIME types.
|
|
8
|
+
*/
|
|
9
|
+
custom = {
|
|
10
|
+
html: 'text/html; charset=utf-8',
|
|
11
|
+
json: 'application/json; charset=utf-8',
|
|
12
|
+
txt: 'text/plain; charset=utf-8',
|
|
13
|
+
yaml: 'text/yaml; charset=utf-8'
|
|
14
|
+
};
|
|
15
|
+
_reverseCustom = undefined;
|
|
18
16
|
/**
|
|
19
17
|
* Detect file extensions from `Accept` header value.
|
|
20
18
|
*/
|
|
@@ -50,4 +48,3 @@ export class Mime {
|
|
|
50
48
|
return this.custom[ext] ?? mime.types[ext] ?? null;
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
|
-
//# sourceMappingURL=mime.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { inspect } from 'node:util';
|
|
2
|
-
import { Logger } from
|
|
3
|
-
import { exceptionContext, SafeString } from
|
|
2
|
+
import { Logger } from "../logger.js";
|
|
3
|
+
import { exceptionContext, HTTPError, httpStatusMessages, SafeString } from "../util.js";
|
|
4
4
|
import DOM from '@mojojs/dom';
|
|
5
5
|
/**
|
|
6
6
|
* Default helper plugin.
|
|
@@ -140,12 +140,13 @@ async function hiddenFieldTag(ctx, name, value, attrs = {}) {
|
|
|
140
140
|
async function htmlException(ctx, error) {
|
|
141
141
|
ctx.stash.exception = error;
|
|
142
142
|
const mode = ctx.app.mode;
|
|
143
|
-
|
|
143
|
+
const status = errorStatus(error);
|
|
144
|
+
if (await ctx.render({ view: `exception.${mode}`, maybe: true, status }))
|
|
144
145
|
return true;
|
|
145
|
-
if (await ctx.render({ view: 'exception', maybe: true, status
|
|
146
|
+
if (await ctx.render({ view: 'exception', maybe: true, status }))
|
|
146
147
|
return true;
|
|
147
148
|
const view = mode === 'development' ? 'mojo/debug' : 'mojo/exception';
|
|
148
|
-
return await ctx.render({ view, status
|
|
149
|
+
return await ctx.render({ view, status, stringFormatter: Logger.stringFormatter, exceptionContext });
|
|
149
150
|
}
|
|
150
151
|
async function htmlNotFound(ctx) {
|
|
151
152
|
ctx.stash.exception = null;
|
|
@@ -159,7 +160,15 @@ async function htmlNotFound(ctx) {
|
|
|
159
160
|
}
|
|
160
161
|
async function httpException(ctx, error) {
|
|
161
162
|
error = ensureError(error);
|
|
162
|
-
|
|
163
|
+
// Client errors are not worth a stack trace
|
|
164
|
+
const status = errorStatus(error);
|
|
165
|
+
if (status < 500)
|
|
166
|
+
ctx.log.debug(error.message);
|
|
167
|
+
else
|
|
168
|
+
ctx.log.error(error.stack);
|
|
169
|
+
// Do not wait for the rest of a request body that is too large
|
|
170
|
+
if (status === 413)
|
|
171
|
+
ctx.res.set('Connection', 'close');
|
|
163
172
|
const exceptionFormat = ctx.exceptionFormat;
|
|
164
173
|
if (exceptionFormat === 'txt')
|
|
165
174
|
return ctx.txtException(error);
|
|
@@ -195,6 +204,7 @@ async function include(ctx, options, stash) {
|
|
|
195
204
|
return str === null ? null : new SafeString(str);
|
|
196
205
|
}
|
|
197
206
|
async function jsonException(ctx, error) {
|
|
207
|
+
const status = errorStatus(error);
|
|
198
208
|
if (ctx.app.mode === 'development') {
|
|
199
209
|
return await ctx.render({
|
|
200
210
|
json: {
|
|
@@ -205,10 +215,10 @@ async function jsonException(ctx, error) {
|
|
|
205
215
|
}
|
|
206
216
|
},
|
|
207
217
|
pretty: true,
|
|
208
|
-
status
|
|
218
|
+
status
|
|
209
219
|
});
|
|
210
220
|
}
|
|
211
|
-
return await ctx.render({ json: { error: { message:
|
|
221
|
+
return await ctx.render({ json: { error: { message: httpStatusMessages[status] } }, pretty: true, status });
|
|
212
222
|
}
|
|
213
223
|
async function jsonNotFound(ctx) {
|
|
214
224
|
return await ctx.render({ json: { error: { message: 'Not Found' } }, pretty: true, status: 404 });
|
|
@@ -276,10 +286,11 @@ async function textAreaTag(ctx, name, attrs = {}, content) {
|
|
|
276
286
|
return ctx.tag('textarea', { ...attrs, name }, content);
|
|
277
287
|
}
|
|
278
288
|
async function txtException(ctx, error) {
|
|
289
|
+
const status = errorStatus(error);
|
|
279
290
|
if (ctx.app.mode === 'development') {
|
|
280
|
-
return await ctx.render({ text: error.stack, status
|
|
291
|
+
return await ctx.render({ text: error.stack, status });
|
|
281
292
|
}
|
|
282
|
-
return await ctx.render({ text:
|
|
293
|
+
return await ctx.render({ text: httpStatusMessages[status], status });
|
|
283
294
|
}
|
|
284
295
|
async function txtNotFound(ctx) {
|
|
285
296
|
return await ctx.render({ text: 'Not Found', status: 404 });
|
|
@@ -299,4 +310,10 @@ function urlTarget(target) {
|
|
|
299
310
|
function ensureError(error) {
|
|
300
311
|
return error instanceof Error ? error : new Error(error);
|
|
301
312
|
}
|
|
302
|
-
|
|
313
|
+
// Only our own errors, a "status" property from other libraries could hide real server errors
|
|
314
|
+
function errorStatus(error) {
|
|
315
|
+
if (!(error instanceof HTTPError))
|
|
316
|
+
return 500;
|
|
317
|
+
const { status } = error;
|
|
318
|
+
return Number.isInteger(status) && status >= 400 && status <= 599 ? status : 500;
|
|
319
|
+
}
|
package/lib/plugins/mount.d.ts
CHANGED
package/lib/plugins/mount.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { Cache } from
|
|
2
|
+
import { Cache } from "../cache.js";
|
|
3
3
|
import Path from '@mojojs/path';
|
|
4
4
|
import Template from '@mojojs/template';
|
|
5
5
|
/**
|
|
@@ -9,9 +9,7 @@ export default function tmplEnginePlugin(app) {
|
|
|
9
9
|
app.renderer.addEngine('tmpl', new TmplEngine());
|
|
10
10
|
}
|
|
11
11
|
class TmplEngine {
|
|
12
|
-
|
|
13
|
-
this.cache = new Cache();
|
|
14
|
-
}
|
|
12
|
+
cache = new Cache();
|
|
15
13
|
async render(ctx, options) {
|
|
16
14
|
let template;
|
|
17
15
|
if (options.inline !== undefined) {
|
|
@@ -35,4 +33,3 @@ class TmplEngine {
|
|
|
35
33
|
return Buffer.from(await template({ ...ctx.stash, stash: ctx.stash, ctx, view: options, tags: ctx.tags }));
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
|
-
//# sourceMappingURL=tmpl-engine.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loadConfig } from
|
|
1
|
+
import { loadConfig } from "./json-config.js";
|
|
2
2
|
import * as yaml from 'js-yaml';
|
|
3
3
|
/**
|
|
4
4
|
* YAML config plugin.
|
|
@@ -8,4 +8,3 @@ export default function yamlConfigPlugin(app, options) {
|
|
|
8
8
|
options.ext = 'yml';
|
|
9
9
|
loadConfig(app, options, yaml.load);
|
|
10
10
|
}
|
|
11
|
-
//# sourceMappingURL=yaml-config.js.map
|
package/lib/renderer.d.ts
CHANGED