@pori15/logixlysia 6.0.1 → 6.0.2

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.
@@ -1,258 +1,258 @@
1
- // src/libs/elysia-http-problem-json/errors.ts
2
-
3
- export interface ProblemDocument {
4
- type: string;
5
- title: string;
6
- status?: number;
7
- detail?: string;
8
- instance?: string;
9
- [key: string]: unknown;
10
- }
11
-
12
- /**
13
- * RFC 9457 Problem Details Error Base Class
14
- *
15
- * Core members as per RFC 9457:
16
- * - type: A URI reference [RFC3986] that identifies the problem type.
17
- * Defaults to "about:blank" when omitted.
18
- * - title: A short, human-readable summary of the problem type.
19
- * - status: The HTTP status code ([RFC7231], Section 6).
20
- * - detail: A human-readable explanation specific to this occurrence of the problem.
21
- * - instance: A URI reference that identifies the specific occurrence of the problem.
22
- *
23
- * Extension members: Additional properties can be added to provide more context.
24
- * These are serialized as-is in the JSON response.
25
- */
26
- /**
27
- * RFC 9457 Error Base Class
28
- * * 修改思路:直接使用 public readonly 属性,拒绝嵌套,拒绝 Getter。
29
- */
30
- export class ProblemError extends Error {
31
- // 1. 直接声明公开属性
32
- public readonly status: number;
33
- public readonly title: string;
34
- public readonly type: string;
35
- public readonly detail?: string;
36
- public readonly instance?: string;
37
- public readonly extensions?: Record<string, unknown>;
38
-
39
- constructor(
40
- type = "about:blank",
41
- title: string,
42
- status: number,
43
- detail?: string,
44
- instance?: string,
45
- extensions: Record<string, unknown> = {}
46
- ) {
47
- super(detail || title);
48
- Object.setPrototypeOf(this, ProblemError.prototype);
49
-
50
- // 2. 直接赋值给 this
51
- this.status = status;
52
- this.title = title;
53
- this.type = type;
54
- this.detail = detail;
55
- this.instance = instance;
56
- this.extensions = extensions;
57
- }
58
-
59
- // 3. toJSON 的时候动态组装一下即可
60
- toJSON(): ProblemDocument {
61
- return {
62
- type: this.type,
63
- title: this.title,
64
- status: this.status,
65
- ...(this.detail ? { detail: this.detail } : {}),
66
- ...(this.instance ? { instance: this.instance } : {}),
67
- // 把扩展字段展开 (extensions)
68
- ...this.extensions,
69
- };
70
- }
71
- }
72
-
73
- // --- 40X Errors ---
74
- class BadRequest extends ProblemError {
75
- constructor(detail?: string, extensions?: Record<string, any>) {
76
- super(
77
- "https://httpstatuses.com/400",
78
- "Bad Request",
79
- 400,
80
- detail,
81
- undefined,
82
- extensions
83
- );
84
- }
85
- }
86
-
87
- class Unauthorized extends ProblemError {
88
- constructor(detail?: string, extensions?: Record<string, any>) {
89
- super(
90
- "https://httpstatuses.com/401",
91
- "Unauthorized",
92
- 401,
93
- detail,
94
- undefined,
95
- extensions
96
- );
97
- }
98
- }
99
-
100
- class Forbidden extends ProblemError {
101
- constructor(detail?: string, extensions?: Record<string, any>) {
102
- super(
103
- "https://httpstatuses.com/403",
104
- "Forbidden",
105
- 403,
106
- detail,
107
- undefined,
108
- extensions
109
- );
110
- }
111
- }
112
-
113
- class NotFound extends ProblemError {
114
- constructor(detail?: string, extensions?: Record<string, any>) {
115
- super(
116
- "https://httpstatuses.com/404",
117
- "Not Found",
118
- 404,
119
- detail,
120
- undefined,
121
- extensions
122
- );
123
- }
124
- }
125
-
126
- class Conflict extends ProblemError {
127
- constructor(detail?: string, extensions?: Record<string, any>) {
128
- super(
129
- "https://httpstatuses.com/409",
130
- "Conflict",
131
- 409,
132
- detail,
133
- undefined,
134
- extensions
135
- );
136
- }
137
- }
138
-
139
- class PaymentRequired extends ProblemError {
140
- constructor(detail?: string, extensions?: Record<string, any>) {
141
- super(
142
- "https://httpstatuses.com/402",
143
- "Payment Required",
144
- 402,
145
- detail,
146
- undefined,
147
- extensions
148
- );
149
- }
150
- }
151
-
152
- class MethodNotAllowed extends ProblemError {
153
- constructor(detail?: string, extensions?: Record<string, any>) {
154
- super(
155
- "https://httpstatuses.com/405",
156
- "Method Not Allowed",
157
- 405,
158
- detail,
159
- undefined,
160
- extensions
161
- );
162
- }
163
- }
164
-
165
- class NotAcceptable extends ProblemError {
166
- constructor(detail?: string, extensions?: Record<string, any>) {
167
- super(
168
- "https://httpstatuses.com/406",
169
- "Not Acceptable",
170
- 406,
171
- detail,
172
- undefined,
173
- extensions
174
- );
175
- }
176
- }
177
-
178
- // 50X Errors
179
- class InternalServerError extends ProblemError {
180
- constructor(detail?: string, extensions?: Record<string, any>) {
181
- super(
182
- "https://httpstatuses.com/500",
183
- "Internal Server Error",
184
- 500,
185
- detail,
186
- undefined,
187
- extensions
188
- );
189
- }
190
- }
191
-
192
- class NotImplemented extends ProblemError {
193
- constructor(detail?: string, extensions?: Record<string, any>) {
194
- super(
195
- "https://httpstatuses.com/501",
196
- "Not Implemented",
197
- 501,
198
- detail,
199
- undefined,
200
- extensions
201
- );
202
- }
203
- }
204
-
205
- class BadGateway extends ProblemError {
206
- constructor(detail?: string, extensions?: Record<string, any>) {
207
- super(
208
- "https://httpstatuses.com/502",
209
- "Bad Gateway",
210
- 502,
211
- detail,
212
- undefined,
213
- extensions
214
- );
215
- }
216
- }
217
-
218
- class ServiceUnavailable extends ProblemError {
219
- constructor(detail?: string, extensions?: Record<string, any>) {
220
- super(
221
- "https://httpstatuses.com/503",
222
- "Service Unavailable",
223
- 503,
224
- detail,
225
- undefined,
226
- extensions
227
- );
228
- }
229
- }
230
-
231
- class GatewayTimeout extends ProblemError {
232
- constructor(detail?: string, extensions?: Record<string, any>) {
233
- super(
234
- "https://httpstatuses.com/504",
235
- "Gateway Timeout",
236
- 504,
237
- detail,
238
- undefined,
239
- extensions
240
- );
241
- }
242
- }
243
-
244
- export const HttpError = {
245
- BadRequest,
246
- Unauthorized,
247
- PaymentRequired,
248
- Forbidden,
249
- NotFound,
250
- MethodNotAllowed,
251
- NotAcceptable,
252
- Conflict,
253
- InternalServerError,
254
- NotImplemented,
255
- BadGateway,
256
- ServiceUnavailable,
257
- GatewayTimeout,
258
- } as const;
1
+ // src/libs/elysia-http-problem-json/errors.ts
2
+
3
+ export interface ProblemDocument {
4
+ type: string
5
+ title: string
6
+ status?: number
7
+ detail?: string
8
+ instance?: string
9
+ [key: string]: unknown
10
+ }
11
+
12
+ /**
13
+ * RFC 9457 Problem Details Error Base Class
14
+ *
15
+ * Core members as per RFC 9457:
16
+ * - type: A URI reference [RFC3986] that identifies the problem type.
17
+ * Defaults to "about:blank" when omitted.
18
+ * - title: A short, human-readable summary of the problem type.
19
+ * - status: The HTTP status code ([RFC7231], Section 6).
20
+ * - detail: A human-readable explanation specific to this occurrence of the problem.
21
+ * - instance: A URI reference that identifies the specific occurrence of the problem.
22
+ *
23
+ * Extension members: Additional properties can be added to provide more context.
24
+ * These are serialized as-is in the JSON response.
25
+ */
26
+ /**
27
+ * RFC 9457 Error Base Class
28
+ * * 修改思路:直接使用 public readonly 属性,拒绝嵌套,拒绝 Getter。
29
+ */
30
+ export class ProblemError extends Error {
31
+ // 1. 直接声明公开属性
32
+ public readonly status: number
33
+ public readonly title: string
34
+ public readonly type: string
35
+ public readonly detail?: string
36
+ public readonly instance?: string
37
+ public readonly extensions?: Record<string, unknown>
38
+
39
+ constructor(
40
+ type = 'about:blank',
41
+ title: string,
42
+ status: number,
43
+ detail?: string,
44
+ instance?: string,
45
+ extensions: Record<string, unknown> = {}
46
+ ) {
47
+ super(detail || title)
48
+ Object.setPrototypeOf(this, ProblemError.prototype)
49
+
50
+ // 2. 直接赋值给 this
51
+ this.status = status
52
+ this.title = title
53
+ this.type = type
54
+ this.detail = detail
55
+ this.instance = instance
56
+ this.extensions = extensions
57
+ }
58
+
59
+ // 3. toJSON 的时候动态组装一下即可
60
+ toJSON(): ProblemDocument {
61
+ return {
62
+ type: this.type,
63
+ title: this.title,
64
+ status: this.status,
65
+ ...(this.detail ? { detail: this.detail } : {}),
66
+ ...(this.instance ? { instance: this.instance } : {}),
67
+ // 把扩展字段展开 (extensions)
68
+ ...this.extensions
69
+ }
70
+ }
71
+ }
72
+
73
+ // --- 40X Errors ---
74
+ class BadRequest extends ProblemError {
75
+ constructor(detail?: string, extensions?: Record<string, any>) {
76
+ super(
77
+ 'https://httpstatuses.com/400',
78
+ 'Bad Request',
79
+ 400,
80
+ detail,
81
+ undefined,
82
+ extensions
83
+ )
84
+ }
85
+ }
86
+
87
+ class Unauthorized extends ProblemError {
88
+ constructor(detail?: string, extensions?: Record<string, any>) {
89
+ super(
90
+ 'https://httpstatuses.com/401',
91
+ 'Unauthorized',
92
+ 401,
93
+ detail,
94
+ undefined,
95
+ extensions
96
+ )
97
+ }
98
+ }
99
+
100
+ class Forbidden extends ProblemError {
101
+ constructor(detail?: string, extensions?: Record<string, any>) {
102
+ super(
103
+ 'https://httpstatuses.com/403',
104
+ 'Forbidden',
105
+ 403,
106
+ detail,
107
+ undefined,
108
+ extensions
109
+ )
110
+ }
111
+ }
112
+
113
+ class NotFound extends ProblemError {
114
+ constructor(detail?: string, extensions?: Record<string, any>) {
115
+ super(
116
+ 'https://httpstatuses.com/404',
117
+ 'Not Found',
118
+ 404,
119
+ detail,
120
+ undefined,
121
+ extensions
122
+ )
123
+ }
124
+ }
125
+
126
+ class Conflict extends ProblemError {
127
+ constructor(detail?: string, extensions?: Record<string, any>) {
128
+ super(
129
+ 'https://httpstatuses.com/409',
130
+ 'Conflict',
131
+ 409,
132
+ detail,
133
+ undefined,
134
+ extensions
135
+ )
136
+ }
137
+ }
138
+
139
+ class PaymentRequired extends ProblemError {
140
+ constructor(detail?: string, extensions?: Record<string, any>) {
141
+ super(
142
+ 'https://httpstatuses.com/402',
143
+ 'Payment Required',
144
+ 402,
145
+ detail,
146
+ undefined,
147
+ extensions
148
+ )
149
+ }
150
+ }
151
+
152
+ class MethodNotAllowed extends ProblemError {
153
+ constructor(detail?: string, extensions?: Record<string, any>) {
154
+ super(
155
+ 'https://httpstatuses.com/405',
156
+ 'Method Not Allowed',
157
+ 405,
158
+ detail,
159
+ undefined,
160
+ extensions
161
+ )
162
+ }
163
+ }
164
+
165
+ class NotAcceptable extends ProblemError {
166
+ constructor(detail?: string, extensions?: Record<string, any>) {
167
+ super(
168
+ 'https://httpstatuses.com/406',
169
+ 'Not Acceptable',
170
+ 406,
171
+ detail,
172
+ undefined,
173
+ extensions
174
+ )
175
+ }
176
+ }
177
+
178
+ // 50X Errors
179
+ class InternalServerError extends ProblemError {
180
+ constructor(detail?: string, extensions?: Record<string, any>) {
181
+ super(
182
+ 'https://httpstatuses.com/500',
183
+ 'Internal Server Error',
184
+ 500,
185
+ detail,
186
+ undefined,
187
+ extensions
188
+ )
189
+ }
190
+ }
191
+
192
+ class NotImplemented extends ProblemError {
193
+ constructor(detail?: string, extensions?: Record<string, any>) {
194
+ super(
195
+ 'https://httpstatuses.com/501',
196
+ 'Not Implemented',
197
+ 501,
198
+ detail,
199
+ undefined,
200
+ extensions
201
+ )
202
+ }
203
+ }
204
+
205
+ class BadGateway extends ProblemError {
206
+ constructor(detail?: string, extensions?: Record<string, any>) {
207
+ super(
208
+ 'https://httpstatuses.com/502',
209
+ 'Bad Gateway',
210
+ 502,
211
+ detail,
212
+ undefined,
213
+ extensions
214
+ )
215
+ }
216
+ }
217
+
218
+ class ServiceUnavailable extends ProblemError {
219
+ constructor(detail?: string, extensions?: Record<string, any>) {
220
+ super(
221
+ 'https://httpstatuses.com/503',
222
+ 'Service Unavailable',
223
+ 503,
224
+ detail,
225
+ undefined,
226
+ extensions
227
+ )
228
+ }
229
+ }
230
+
231
+ class GatewayTimeout extends ProblemError {
232
+ constructor(detail?: string, extensions?: Record<string, any>) {
233
+ super(
234
+ 'https://httpstatuses.com/504',
235
+ 'Gateway Timeout',
236
+ 504,
237
+ detail,
238
+ undefined,
239
+ extensions
240
+ )
241
+ }
242
+ }
243
+
244
+ export const HttpError = {
245
+ BadRequest,
246
+ Unauthorized,
247
+ PaymentRequired,
248
+ Forbidden,
249
+ NotFound,
250
+ MethodNotAllowed,
251
+ NotAcceptable,
252
+ Conflict,
253
+ InternalServerError,
254
+ NotImplemented,
255
+ BadGateway,
256
+ ServiceUnavailable,
257
+ GatewayTimeout
258
+ } as const
package/src/Error/type.ts CHANGED
@@ -1,51 +1,51 @@
1
- // src/libs/elysia-http-problem-json/types.ts
2
-
3
- import { HttpError, ProblemError } from "./errors";
4
-
5
- export type Code =
6
- | number
7
- | "PROBLEM_ERROR"
8
- | "UNKNOWN"
9
- | "VALIDATION"
10
- | "NOT_FOUND"
11
- | "PARSE"
12
- | "INTERNAL_SERVER_ERROR"
13
- | "INVALID_COOKIE_SIGNATURE"
14
- | "INVALID_FILE_TYPE";
15
-
16
- // 获取 HttpError 对象的所有 Key (例如 "BadRequest" | "NotFound")
17
- export type HttpErrorType = keyof typeof HttpError;
18
-
19
- export interface ErrorContext {
20
- request: Request;
21
- path: string;
22
- code: string | number;
23
- error: unknown;
24
- }
25
-
26
- export interface HttpProblemJsonOptions {
27
- /**
28
- * 自定义错误类型的 Base URL
29
- * @example "https://api.mysite.com/errors"
30
- */
31
- typeBaseUrl?: string;
32
-
33
- /**
34
- * 🪝 Transform Hook
35
- * 将未知错误转换为 HttpError。
36
- * 返回 undefined/null 表示不处理(走默认逻辑)。
37
- */
38
- transform?: (
39
- error: unknown,
40
- context: ErrorContext
41
- ) => ProblemError | undefined | null; // 这里直接返回 ProblemError 实例更好,或者用 HttpErrorType 也可以,看你喜好
42
-
43
- /**
44
- * 📢 Listen Hook
45
- * 在响应发送前触发(用于日志)。
46
- */
47
- onBeforeRespond?: (
48
- problem: ProblemError,
49
- context: ErrorContext
50
- ) => void | Promise<void>;
51
- }
1
+ // src/libs/elysia-http-problem-json/types.ts
2
+
3
+ import type { HttpError, ProblemError } from './errors'
4
+
5
+ export type Code =
6
+ | number
7
+ | 'PROBLEM_ERROR'
8
+ | 'UNKNOWN'
9
+ | 'VALIDATION'
10
+ | 'NOT_FOUND'
11
+ | 'PARSE'
12
+ | 'INTERNAL_SERVER_ERROR'
13
+ | 'INVALID_COOKIE_SIGNATURE'
14
+ | 'INVALID_FILE_TYPE'
15
+
16
+ // 获取 HttpError 对象的所有 Key (例如 "BadRequest" | "NotFound")
17
+ export type HttpErrorType = keyof typeof HttpError
18
+
19
+ export interface ErrorContext {
20
+ request: Request
21
+ path: string
22
+ code: string | number
23
+ error: unknown
24
+ }
25
+
26
+ export interface HttpProblemJsonOptions {
27
+ /**
28
+ * 自定义错误类型的 Base URL
29
+ * @example "https://api.mysite.com/errors"
30
+ */
31
+ typeBaseUrl?: string
32
+
33
+ /**
34
+ * 🪝 Transform Hook
35
+ * 将未知错误转换为 HttpError。
36
+ * 返回 undefined/null 表示不处理(走默认逻辑)。
37
+ */
38
+ transform?: (
39
+ error: unknown,
40
+ context: ErrorContext
41
+ ) => ProblemError | undefined | null // 这里直接返回 ProblemError 实例更好,或者用 HttpErrorType 也可以,看你喜好
42
+
43
+ /**
44
+ * 📢 Listen Hook
45
+ * 在响应发送前触发(用于日志)。
46
+ */
47
+ onBeforeRespond?: (
48
+ problem: ProblemError,
49
+ context: ErrorContext
50
+ ) => void | Promise<void>
51
+ }
@@ -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
+ }