@pori15/logixlysia 6.0.10 → 6.0.11
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 +79 -79
- package/package.json +1 -1
- package/src/{error → Error}/errors.ts +156 -156
- package/src/{error → Error}/type.ts +10 -10
- package/src/extensions/banner.ts +26 -26
- package/src/extensions/index.ts +28 -28
- package/src/helpers/status.ts +58 -58
- package/src/index.ts +151 -151
- package/src/interfaces.ts +207 -207
- package/src/logger/create-logger.ts +238 -238
- package/src/logger/handle-http-error.ts +134 -134
- package/src/logger/index.ts +89 -89
- package/src/output/file.ts +40 -40
- package/src/output/fs.ts +5 -5
- package/src/output/index.ts +42 -42
- package/src/output/rotation-manager.ts +121 -121
- package/src/utils/format.ts +2 -2
- package/src/utils/get-error-code.ts +23 -23
- package/src/utils/handle-error.ts +149 -149
- package/src/utils/rotation.ts +91 -91
- package/dist/index.d.ts +0 -244
- package/dist/index.js +0 -8
package/README.md
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
<h1><code>🦊</code> Logixlysia</h1>
|
|
3
|
-
<strong>Logixlysia is a logging library for ElysiaJS</strong>
|
|
4
|
-
<img src="https://github.com/PunGrumpy/logixlysia/blob/main/apps/docs/app/opengraph-image.png?raw=true" alt="Logixlysia" width="100%" height="auto" />
|
|
5
|
-
</div>
|
|
6
|
-
|
|
7
|
-
## `📩` Installation
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
bun add @pori15/logixlysia
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## `📝` Usage
|
|
14
|
-
|
|
15
|
-
### Basic
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
import { Elysia } from 'elysia'
|
|
19
|
-
import logixlysia from 'logixlysia'
|
|
20
|
-
|
|
21
|
-
const app = new Elysia()
|
|
22
|
-
.use(logixlysia())
|
|
23
|
-
.get('/', () => 'Hello World')
|
|
24
|
-
.listen(3000)
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### With Configuration
|
|
28
|
-
|
|
29
|
-
```ts
|
|
30
|
-
app.use(logixlysia({
|
|
31
|
-
startup: {
|
|
32
|
-
show: true,
|
|
33
|
-
format: 'simple',
|
|
34
|
-
},
|
|
35
|
-
format: {
|
|
36
|
-
timestamp: 'yyyy-mm-dd HH:MM:ss.SSS',
|
|
37
|
-
showIp: true,
|
|
38
|
-
template: '🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}',
|
|
39
|
-
},
|
|
40
|
-
file: {
|
|
41
|
-
path: './logs/example.log',
|
|
42
|
-
rotation: {
|
|
43
|
-
maxSize: '10m',
|
|
44
|
-
maxFiles: 7,
|
|
45
|
-
compress: true,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
logLevel: ['ERROR', 'WARNING'],
|
|
49
|
-
}))
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## `⚙️` Options
|
|
53
|
-
|
|
54
|
-
| Option | Type | Default | Description |
|
|
55
|
-
|--------|------|---------|-------------|
|
|
56
|
-
| `startup.show` | `boolean` | `true` | Show startup message |
|
|
57
|
-
| `startup.format` | `"simple" \| "banner"` | `"banner"` | Startup message style |
|
|
58
|
-
| `format.colors` | `boolean` | `true` (TTY) | Enable colored output |
|
|
59
|
-
| `format.timestamp` | `string` | — | Timestamp format pattern (e.g. `'yyyy-mm-dd HH:MM:ss.SSS'`) |
|
|
60
|
-
| `format.template` | `string` | — | Custom log format template |
|
|
61
|
-
| `format.showIp` | `boolean` | `false` | Show IP address in logs |
|
|
62
|
-
| `logLevel` | `LogLevel \| LogLevel[]` | — | Filter logs by level(s) |
|
|
63
|
-
| `file` | `false \| { path, rotation? }` | — | File logging config (`false` to disable) |
|
|
64
|
-
| `file.path` | `string` | — | Log file path (required when file logging enabled) |
|
|
65
|
-
| `file.rotation` | `LogRotationConfig` | — | Log file rotation settings |
|
|
66
|
-
| `transports` | `Transport[] \| { targets, only? }` | — | Custom transports |
|
|
67
|
-
| `pino` | `PinoLoggerOptions` | — | Pino logger options |
|
|
68
|
-
| `error.typeBaseUrl` | `string` | — | Base URL for error types (RFC 9457) |
|
|
69
|
-
| `error.errorMap` | `Record<string, ErrorMapping>` | — | Error code to HTTP status mapping |
|
|
70
|
-
| `error.resolve` | `ErrorResolver` | — | Custom error resolver function |
|
|
71
|
-
| `error.verbose` | `boolean` | `false` | Show full error details in console |
|
|
72
|
-
|
|
73
|
-
## `📚` Documentation
|
|
74
|
-
|
|
75
|
-
Check out the [website](https://logixlysia.vercel.app) for more detailed documentation and examples.
|
|
76
|
-
|
|
77
|
-
## `📄` License
|
|
78
|
-
|
|
79
|
-
Licensed under the [MIT License](LICENSE).
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1><code>🦊</code> Logixlysia</h1>
|
|
3
|
+
<strong>Logixlysia is a logging library for ElysiaJS</strong>
|
|
4
|
+
<img src="https://github.com/PunGrumpy/logixlysia/blob/main/apps/docs/app/opengraph-image.png?raw=true" alt="Logixlysia" width="100%" height="auto" />
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
## `📩` Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add @pori15/logixlysia
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## `📝` Usage
|
|
14
|
+
|
|
15
|
+
### Basic
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { Elysia } from 'elysia'
|
|
19
|
+
import logixlysia from 'logixlysia'
|
|
20
|
+
|
|
21
|
+
const app = new Elysia()
|
|
22
|
+
.use(logixlysia())
|
|
23
|
+
.get('/', () => 'Hello World')
|
|
24
|
+
.listen(3000)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### With Configuration
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
app.use(logixlysia({
|
|
31
|
+
startup: {
|
|
32
|
+
show: true,
|
|
33
|
+
format: 'simple',
|
|
34
|
+
},
|
|
35
|
+
format: {
|
|
36
|
+
timestamp: 'yyyy-mm-dd HH:MM:ss.SSS',
|
|
37
|
+
showIp: true,
|
|
38
|
+
template: '🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}',
|
|
39
|
+
},
|
|
40
|
+
file: {
|
|
41
|
+
path: './logs/example.log',
|
|
42
|
+
rotation: {
|
|
43
|
+
maxSize: '10m',
|
|
44
|
+
maxFiles: 7,
|
|
45
|
+
compress: true,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
logLevel: ['ERROR', 'WARNING'],
|
|
49
|
+
}))
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## `⚙️` Options
|
|
53
|
+
|
|
54
|
+
| Option | Type | Default | Description |
|
|
55
|
+
|--------|------|---------|-------------|
|
|
56
|
+
| `startup.show` | `boolean` | `true` | Show startup message |
|
|
57
|
+
| `startup.format` | `"simple" \| "banner"` | `"banner"` | Startup message style |
|
|
58
|
+
| `format.colors` | `boolean` | `true` (TTY) | Enable colored output |
|
|
59
|
+
| `format.timestamp` | `string` | — | Timestamp format pattern (e.g. `'yyyy-mm-dd HH:MM:ss.SSS'`) |
|
|
60
|
+
| `format.template` | `string` | — | Custom log format template |
|
|
61
|
+
| `format.showIp` | `boolean` | `false` | Show IP address in logs |
|
|
62
|
+
| `logLevel` | `LogLevel \| LogLevel[]` | — | Filter logs by level(s) |
|
|
63
|
+
| `file` | `false \| { path, rotation? }` | — | File logging config (`false` to disable) |
|
|
64
|
+
| `file.path` | `string` | — | Log file path (required when file logging enabled) |
|
|
65
|
+
| `file.rotation` | `LogRotationConfig` | — | Log file rotation settings |
|
|
66
|
+
| `transports` | `Transport[] \| { targets, only? }` | — | Custom transports |
|
|
67
|
+
| `pino` | `PinoLoggerOptions` | — | Pino logger options |
|
|
68
|
+
| `error.typeBaseUrl` | `string` | — | Base URL for error types (RFC 9457) |
|
|
69
|
+
| `error.errorMap` | `Record<string, ErrorMapping>` | — | Error code to HTTP status mapping |
|
|
70
|
+
| `error.resolve` | `ErrorResolver` | — | Custom error resolver function |
|
|
71
|
+
| `error.verbose` | `boolean` | `false` | Show full error details in console |
|
|
72
|
+
|
|
73
|
+
## `📚` Documentation
|
|
74
|
+
|
|
75
|
+
Check out the [website](https://logixlysia.vercel.app) for more detailed documentation and examples.
|
|
76
|
+
|
|
77
|
+
## `📄` License
|
|
78
|
+
|
|
79
|
+
Licensed under the [MIT License](LICENSE).
|
package/package.json
CHANGED
|
@@ -1,156 +1,156 @@
|
|
|
1
|
-
// RFC 9457 Problem Details - https://www.rfc-editor.org/rfc/rfc9457.html
|
|
2
|
-
|
|
3
|
-
export interface ProblemDocument {
|
|
4
|
-
detail?: string;
|
|
5
|
-
instance?: string;
|
|
6
|
-
status?: number;
|
|
7
|
-
title: string;
|
|
8
|
-
type: string;
|
|
9
|
-
[key: string]: unknown;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* RFC 9457 Problem Details Error
|
|
14
|
-
*
|
|
15
|
-
* Core members:
|
|
16
|
-
* - type: URI reference identifying the problem type (default "about:blank")
|
|
17
|
-
* - title: Short human-readable summary
|
|
18
|
-
* - status: HTTP status code
|
|
19
|
-
* - detail: Human-readable explanation for this occurrence
|
|
20
|
-
* - instance: URI reference identifying this specific occurrence
|
|
21
|
-
* - extensions: Additional properties serialized as-is
|
|
22
|
-
*/
|
|
23
|
-
export class ProblemError extends Error {
|
|
24
|
-
public readonly status: number;
|
|
25
|
-
public readonly title: string;
|
|
26
|
-
public readonly type: string;
|
|
27
|
-
public readonly detail?: string;
|
|
28
|
-
public readonly instance?: string;
|
|
29
|
-
public readonly extensions?: Record<string, unknown>;
|
|
30
|
-
|
|
31
|
-
constructor(
|
|
32
|
-
type = "about:blank",
|
|
33
|
-
title: string,
|
|
34
|
-
status: number,
|
|
35
|
-
detail?: string,
|
|
36
|
-
instance?: string,
|
|
37
|
-
extensions?: Record<string, unknown>
|
|
38
|
-
) {
|
|
39
|
-
super(detail || title);
|
|
40
|
-
Object.setPrototypeOf(this, ProblemError.prototype);
|
|
41
|
-
|
|
42
|
-
this.status = status;
|
|
43
|
-
this.title = title;
|
|
44
|
-
this.type = type;
|
|
45
|
-
this.detail = detail;
|
|
46
|
-
this.instance = instance;
|
|
47
|
-
this.extensions = extensions;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
toJSON(): ProblemDocument {
|
|
51
|
-
return {
|
|
52
|
-
type: this.type,
|
|
53
|
-
title: this.title,
|
|
54
|
-
status: this.status,
|
|
55
|
-
...(this.detail ? { detail: this.detail } : {}),
|
|
56
|
-
...(this.instance ? { instance: this.instance } : {}),
|
|
57
|
-
...this.extensions,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ==========================================
|
|
63
|
-
// Factory Function
|
|
64
|
-
// ==========================================
|
|
65
|
-
|
|
66
|
-
const DEFAULT_TITLES: Record<number, string> = {
|
|
67
|
-
400: "Bad Request",
|
|
68
|
-
401: "Unauthorized",
|
|
69
|
-
402: "Payment Required",
|
|
70
|
-
403: "Forbidden",
|
|
71
|
-
404: "Not Found",
|
|
72
|
-
405: "Method Not Allowed",
|
|
73
|
-
406: "Not Acceptable",
|
|
74
|
-
409: "Conflict",
|
|
75
|
-
500: "Internal Server Error",
|
|
76
|
-
501: "Not Implemented",
|
|
77
|
-
502: "Bad Gateway",
|
|
78
|
-
503: "Service Unavailable",
|
|
79
|
-
504: "Gateway Timeout",
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export interface ProblemConfig {
|
|
83
|
-
detail?: string;
|
|
84
|
-
extensions?: Record<string, unknown>;
|
|
85
|
-
instance?: string;
|
|
86
|
-
title?: string;
|
|
87
|
-
type?: string;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 工厂函数:根据 HTTP 状态码快速创建 ProblemError
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* throw createProblem(400, { detail: 'Invalid email' })
|
|
95
|
-
* throw createProblem(409, { title: 'Duplicate', detail: 'Email already exists' })
|
|
96
|
-
*/
|
|
97
|
-
export const createProblem = (
|
|
98
|
-
status: number,
|
|
99
|
-
overrides?: ProblemConfig
|
|
100
|
-
): ProblemError => {
|
|
101
|
-
const title = overrides?.title ?? DEFAULT_TITLES[status] ?? "Unknown Error";
|
|
102
|
-
return new ProblemError(
|
|
103
|
-
overrides?.type ?? `https://httpstatuses.com/${status}`,
|
|
104
|
-
title,
|
|
105
|
-
status,
|
|
106
|
-
overrides?.detail,
|
|
107
|
-
overrides?.instance,
|
|
108
|
-
overrides?.extensions
|
|
109
|
-
);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// ==========================================
|
|
113
|
-
// HttpError Namespace (convenience wrappers via createProblem)
|
|
114
|
-
// ==========================================
|
|
115
|
-
|
|
116
|
-
type HttpErrorFactory = (
|
|
117
|
-
detail?: string,
|
|
118
|
-
extensions?: Record<string, unknown>
|
|
119
|
-
) => ProblemError;
|
|
120
|
-
|
|
121
|
-
const factory =
|
|
122
|
-
(status: number): HttpErrorFactory =>
|
|
123
|
-
(detail, extensions) =>
|
|
124
|
-
createProblem(status, { detail, extensions });
|
|
125
|
-
|
|
126
|
-
export interface HttpErrorConstructor {
|
|
127
|
-
BadGateway: HttpErrorFactory;
|
|
128
|
-
BadRequest: HttpErrorFactory;
|
|
129
|
-
Conflict: HttpErrorFactory;
|
|
130
|
-
Forbidden: HttpErrorFactory;
|
|
131
|
-
GatewayTimeout: HttpErrorFactory;
|
|
132
|
-
InternalServerError: HttpErrorFactory;
|
|
133
|
-
MethodNotAllowed: HttpErrorFactory;
|
|
134
|
-
NotAcceptable: HttpErrorFactory;
|
|
135
|
-
NotFound: HttpErrorFactory;
|
|
136
|
-
NotImplemented: HttpErrorFactory;
|
|
137
|
-
PaymentRequired: HttpErrorFactory;
|
|
138
|
-
ServiceUnavailable: HttpErrorFactory;
|
|
139
|
-
Unauthorized: HttpErrorFactory;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export const HttpError: HttpErrorConstructor = {
|
|
143
|
-
BadRequest: factory(400),
|
|
144
|
-
Unauthorized: factory(401),
|
|
145
|
-
PaymentRequired: factory(402),
|
|
146
|
-
Forbidden: factory(403),
|
|
147
|
-
NotFound: factory(404),
|
|
148
|
-
MethodNotAllowed: factory(405),
|
|
149
|
-
NotAcceptable: factory(406),
|
|
150
|
-
Conflict: factory(409),
|
|
151
|
-
InternalServerError: factory(500),
|
|
152
|
-
NotImplemented: factory(501),
|
|
153
|
-
BadGateway: factory(502),
|
|
154
|
-
ServiceUnavailable: factory(503),
|
|
155
|
-
GatewayTimeout: factory(504),
|
|
156
|
-
};
|
|
1
|
+
// RFC 9457 Problem Details - https://www.rfc-editor.org/rfc/rfc9457.html
|
|
2
|
+
|
|
3
|
+
export interface ProblemDocument {
|
|
4
|
+
detail?: string;
|
|
5
|
+
instance?: string;
|
|
6
|
+
status?: number;
|
|
7
|
+
title: string;
|
|
8
|
+
type: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* RFC 9457 Problem Details Error
|
|
14
|
+
*
|
|
15
|
+
* Core members:
|
|
16
|
+
* - type: URI reference identifying the problem type (default "about:blank")
|
|
17
|
+
* - title: Short human-readable summary
|
|
18
|
+
* - status: HTTP status code
|
|
19
|
+
* - detail: Human-readable explanation for this occurrence
|
|
20
|
+
* - instance: URI reference identifying this specific occurrence
|
|
21
|
+
* - extensions: Additional properties serialized as-is
|
|
22
|
+
*/
|
|
23
|
+
export class ProblemError extends Error {
|
|
24
|
+
public readonly status: number;
|
|
25
|
+
public readonly title: string;
|
|
26
|
+
public readonly type: string;
|
|
27
|
+
public readonly detail?: string;
|
|
28
|
+
public readonly instance?: string;
|
|
29
|
+
public readonly extensions?: Record<string, unknown>;
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
type = "about:blank",
|
|
33
|
+
title: string,
|
|
34
|
+
status: number,
|
|
35
|
+
detail?: string,
|
|
36
|
+
instance?: string,
|
|
37
|
+
extensions?: Record<string, unknown>
|
|
38
|
+
) {
|
|
39
|
+
super(detail || title);
|
|
40
|
+
Object.setPrototypeOf(this, ProblemError.prototype);
|
|
41
|
+
|
|
42
|
+
this.status = status;
|
|
43
|
+
this.title = title;
|
|
44
|
+
this.type = type;
|
|
45
|
+
this.detail = detail;
|
|
46
|
+
this.instance = instance;
|
|
47
|
+
this.extensions = extensions;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
toJSON(): ProblemDocument {
|
|
51
|
+
return {
|
|
52
|
+
type: this.type,
|
|
53
|
+
title: this.title,
|
|
54
|
+
status: this.status,
|
|
55
|
+
...(this.detail ? { detail: this.detail } : {}),
|
|
56
|
+
...(this.instance ? { instance: this.instance } : {}),
|
|
57
|
+
...this.extensions,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ==========================================
|
|
63
|
+
// Factory Function
|
|
64
|
+
// ==========================================
|
|
65
|
+
|
|
66
|
+
const DEFAULT_TITLES: Record<number, string> = {
|
|
67
|
+
400: "Bad Request",
|
|
68
|
+
401: "Unauthorized",
|
|
69
|
+
402: "Payment Required",
|
|
70
|
+
403: "Forbidden",
|
|
71
|
+
404: "Not Found",
|
|
72
|
+
405: "Method Not Allowed",
|
|
73
|
+
406: "Not Acceptable",
|
|
74
|
+
409: "Conflict",
|
|
75
|
+
500: "Internal Server Error",
|
|
76
|
+
501: "Not Implemented",
|
|
77
|
+
502: "Bad Gateway",
|
|
78
|
+
503: "Service Unavailable",
|
|
79
|
+
504: "Gateway Timeout",
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export interface ProblemConfig {
|
|
83
|
+
detail?: string;
|
|
84
|
+
extensions?: Record<string, unknown>;
|
|
85
|
+
instance?: string;
|
|
86
|
+
title?: string;
|
|
87
|
+
type?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 工厂函数:根据 HTTP 状态码快速创建 ProblemError
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* throw createProblem(400, { detail: 'Invalid email' })
|
|
95
|
+
* throw createProblem(409, { title: 'Duplicate', detail: 'Email already exists' })
|
|
96
|
+
*/
|
|
97
|
+
export const createProblem = (
|
|
98
|
+
status: number,
|
|
99
|
+
overrides?: ProblemConfig
|
|
100
|
+
): ProblemError => {
|
|
101
|
+
const title = overrides?.title ?? DEFAULT_TITLES[status] ?? "Unknown Error";
|
|
102
|
+
return new ProblemError(
|
|
103
|
+
overrides?.type ?? `https://httpstatuses.com/${status}`,
|
|
104
|
+
title,
|
|
105
|
+
status,
|
|
106
|
+
overrides?.detail,
|
|
107
|
+
overrides?.instance,
|
|
108
|
+
overrides?.extensions
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// ==========================================
|
|
113
|
+
// HttpError Namespace (convenience wrappers via createProblem)
|
|
114
|
+
// ==========================================
|
|
115
|
+
|
|
116
|
+
type HttpErrorFactory = (
|
|
117
|
+
detail?: string,
|
|
118
|
+
extensions?: Record<string, unknown>
|
|
119
|
+
) => ProblemError;
|
|
120
|
+
|
|
121
|
+
const factory =
|
|
122
|
+
(status: number): HttpErrorFactory =>
|
|
123
|
+
(detail, extensions) =>
|
|
124
|
+
createProblem(status, { detail, extensions });
|
|
125
|
+
|
|
126
|
+
export interface HttpErrorConstructor {
|
|
127
|
+
BadGateway: HttpErrorFactory;
|
|
128
|
+
BadRequest: HttpErrorFactory;
|
|
129
|
+
Conflict: HttpErrorFactory;
|
|
130
|
+
Forbidden: HttpErrorFactory;
|
|
131
|
+
GatewayTimeout: HttpErrorFactory;
|
|
132
|
+
InternalServerError: HttpErrorFactory;
|
|
133
|
+
MethodNotAllowed: HttpErrorFactory;
|
|
134
|
+
NotAcceptable: HttpErrorFactory;
|
|
135
|
+
NotFound: HttpErrorFactory;
|
|
136
|
+
NotImplemented: HttpErrorFactory;
|
|
137
|
+
PaymentRequired: HttpErrorFactory;
|
|
138
|
+
ServiceUnavailable: HttpErrorFactory;
|
|
139
|
+
Unauthorized: HttpErrorFactory;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const HttpError: HttpErrorConstructor = {
|
|
143
|
+
BadRequest: factory(400),
|
|
144
|
+
Unauthorized: factory(401),
|
|
145
|
+
PaymentRequired: factory(402),
|
|
146
|
+
Forbidden: factory(403),
|
|
147
|
+
NotFound: factory(404),
|
|
148
|
+
MethodNotAllowed: factory(405),
|
|
149
|
+
NotAcceptable: factory(406),
|
|
150
|
+
Conflict: factory(409),
|
|
151
|
+
InternalServerError: factory(500),
|
|
152
|
+
NotImplemented: factory(501),
|
|
153
|
+
BadGateway: factory(502),
|
|
154
|
+
ServiceUnavailable: factory(503),
|
|
155
|
+
GatewayTimeout: factory(504),
|
|
156
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export type Code =
|
|
2
|
-
| number
|
|
3
|
-
| "PROBLEM_ERROR"
|
|
4
|
-
| "UNKNOWN"
|
|
5
|
-
| "VALIDATION"
|
|
6
|
-
| "NOT_FOUND"
|
|
7
|
-
| "PARSE"
|
|
8
|
-
| "INTERNAL_SERVER_ERROR"
|
|
9
|
-
| "INVALID_COOKIE_SIGNATURE"
|
|
10
|
-
| "INVALID_FILE_TYPE";
|
|
1
|
+
export type Code =
|
|
2
|
+
| number
|
|
3
|
+
| "PROBLEM_ERROR"
|
|
4
|
+
| "UNKNOWN"
|
|
5
|
+
| "VALIDATION"
|
|
6
|
+
| "NOT_FOUND"
|
|
7
|
+
| "PARSE"
|
|
8
|
+
| "INTERNAL_SERVER_ERROR"
|
|
9
|
+
| "INVALID_COOKIE_SIGNATURE"
|
|
10
|
+
| "INVALID_FILE_TYPE";
|
package/src/extensions/banner.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import elysiaPkg from "elysia/package.json";
|
|
2
|
-
|
|
3
|
-
const centerText = (text: string, width: number): string => {
|
|
4
|
-
if (text.length >= width) {
|
|
5
|
-
return text.slice(0, width);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const left = Math.floor((width - text.length) / 2);
|
|
9
|
-
const right = width - text.length - left;
|
|
10
|
-
return `${" ".repeat(left)}${text}${" ".repeat(right)}`;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const renderBanner = (message: string): string => {
|
|
14
|
-
const versionLine = `Elysia v${elysiaPkg.version}`;
|
|
15
|
-
const contentWidth = Math.max(message.length, versionLine.length);
|
|
16
|
-
const innerWidth = contentWidth + 4; // 2 spaces padding on both sides
|
|
17
|
-
|
|
18
|
-
const top = `┌${"─".repeat(innerWidth)}┐`;
|
|
19
|
-
const bot = `└${"─".repeat(innerWidth)}┘`;
|
|
20
|
-
const empty = `│${" ".repeat(innerWidth)}│`;
|
|
21
|
-
|
|
22
|
-
const versionRow = `│${centerText(versionLine, innerWidth)}│`;
|
|
23
|
-
const messageRow = `│ ${message}${" ".repeat(Math.max(0, innerWidth - message.length - 4))} │`;
|
|
24
|
-
|
|
25
|
-
return [top, empty, versionRow, empty, messageRow, empty, bot].join("\n");
|
|
26
|
-
};
|
|
1
|
+
import elysiaPkg from "elysia/package.json";
|
|
2
|
+
|
|
3
|
+
const centerText = (text: string, width: number): string => {
|
|
4
|
+
if (text.length >= width) {
|
|
5
|
+
return text.slice(0, width);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const left = Math.floor((width - text.length) / 2);
|
|
9
|
+
const right = width - text.length - left;
|
|
10
|
+
return `${" ".repeat(left)}${text}${" ".repeat(right)}`;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const renderBanner = (message: string): string => {
|
|
14
|
+
const versionLine = `Elysia v${elysiaPkg.version}`;
|
|
15
|
+
const contentWidth = Math.max(message.length, versionLine.length);
|
|
16
|
+
const innerWidth = contentWidth + 4; // 2 spaces padding on both sides
|
|
17
|
+
|
|
18
|
+
const top = `┌${"─".repeat(innerWidth)}┐`;
|
|
19
|
+
const bot = `└${"─".repeat(innerWidth)}┘`;
|
|
20
|
+
const empty = `│${" ".repeat(innerWidth)}│`;
|
|
21
|
+
|
|
22
|
+
const versionRow = `│${centerText(versionLine, innerWidth)}│`;
|
|
23
|
+
const messageRow = `│ ${message}${" ".repeat(Math.max(0, innerWidth - message.length - 4))} │`;
|
|
24
|
+
|
|
25
|
+
return [top, empty, versionRow, empty, messageRow, empty, bot].join("\n");
|
|
26
|
+
};
|
package/src/extensions/index.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import type { Options } from "../interfaces";
|
|
2
|
-
import { renderBanner } from "./banner";
|
|
3
|
-
|
|
4
|
-
export const startServer = (
|
|
5
|
-
server: { port?: number; hostname?: string; protocol?: string | null },
|
|
6
|
-
options: Options
|
|
7
|
-
): void => {
|
|
8
|
-
const showStartupMessage = options.startup?.show ?? true;
|
|
9
|
-
if (!showStartupMessage) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const { port, hostname, protocol } = server;
|
|
14
|
-
if (port === undefined || !hostname || !protocol) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const url = `${protocol}://${hostname}:${port}`;
|
|
19
|
-
const message = `🦊 Elysia is running at ${url}`;
|
|
20
|
-
|
|
21
|
-
const format = options.startup?.format ?? "banner";
|
|
22
|
-
if (format === "simple") {
|
|
23
|
-
console.log(message);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
console.log(renderBanner(message));
|
|
28
|
-
};
|
|
1
|
+
import type { Options } from "../interfaces";
|
|
2
|
+
import { renderBanner } from "./banner";
|
|
3
|
+
|
|
4
|
+
export const startServer = (
|
|
5
|
+
server: { port?: number; hostname?: string; protocol?: string | null },
|
|
6
|
+
options: Options
|
|
7
|
+
): void => {
|
|
8
|
+
const showStartupMessage = options.startup?.show ?? true;
|
|
9
|
+
if (!showStartupMessage) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { port, hostname, protocol } = server;
|
|
14
|
+
if (port === undefined || !hostname || !protocol) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const url = `${protocol}://${hostname}:${port}`;
|
|
19
|
+
const message = `🦊 Elysia is running at ${url}`;
|
|
20
|
+
|
|
21
|
+
const format = options.startup?.format ?? "banner";
|
|
22
|
+
if (format === "simple") {
|
|
23
|
+
console.log(message);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(renderBanner(message));
|
|
28
|
+
};
|