@pori15/logixlysia 6.0.11 → 6.0.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pori15/logixlysia",
3
- "version": "6.0.11",
3
+ "version": "6.0.12",
4
4
  "description": "🦊 Logixlysia is a logger for Elysia",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -51,7 +51,7 @@
51
51
  "peerDependencies": {
52
52
  "elysia": "^1.4.28",
53
53
  "pino-pretty": ">=13.0.0",
54
- "typescript": "^5.9.3"
54
+ "typescript": "^6.0.2"
55
55
  },
56
56
  "peerDependenciesMeta": {
57
57
  "pino-pretty": {
@@ -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
+ };
package/src/Error/type.ts CHANGED
@@ -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";
@@ -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
+ };
@@ -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
+ };
@@ -1,58 +1,58 @@
1
- import { StatusMap } from "elysia";
2
-
3
- const DIGITS_ONLY = /^\d+$/;
4
- const DELIMITERS = /[_-]+/g;
5
- const CAMEL_BOUNDARY_1 = /([a-z0-9])([A-Z])/g;
6
- const CAMEL_BOUNDARY_2 = /([A-Z])([A-Z][a-z])/g;
7
- const APOSTROPHES = /['’]/g;
8
- const NON_ALPHANUMERIC = /[^a-z0-9\s]+/g;
9
- const WHITESPACE = /\s+/g;
10
-
11
- const normalizeStatusName = (value: string): string => {
12
- // Handles common variants:
13
- // - case differences: "not found" vs "Not Found"
14
- // - spacing/punctuation: "Not-Found", "not_found"
15
- // - camelCase/PascalCase: "InternalServerError"
16
- const trimmed = value.trim();
17
- if (!trimmed) {
18
- return "";
19
- }
20
-
21
- return trimmed
22
- .replace(DELIMITERS, " ")
23
- .replace(CAMEL_BOUNDARY_1, "$1 $2")
24
- .replace(CAMEL_BOUNDARY_2, "$1 $2")
25
- .replace(APOSTROPHES, "")
26
- .toLowerCase()
27
- .replace(NON_ALPHANUMERIC, " ")
28
- .replace(WHITESPACE, " ")
29
- .trim();
30
- };
31
-
32
- const STATUS_BY_NORMALIZED_NAME = (() => {
33
- const map = new Map<string, number>();
34
-
35
- for (const [name, code] of Object.entries(StatusMap)) {
36
- map.set(normalizeStatusName(name), code);
37
- }
38
-
39
- return map;
40
- })();
41
-
42
- export const getStatusCode = (value: unknown): number => {
43
- if (typeof value === "number" && Number.isFinite(value)) {
44
- return value;
45
- }
46
-
47
- if (typeof value === "string") {
48
- const trimmed = value.trim();
49
- if (DIGITS_ONLY.test(trimmed)) {
50
- return Number(trimmed);
51
- }
52
-
53
- const known = STATUS_BY_NORMALIZED_NAME.get(normalizeStatusName(trimmed));
54
- return known ?? 500;
55
- }
56
-
57
- return 500;
58
- };
1
+ import { StatusMap } from "elysia";
2
+
3
+ const DIGITS_ONLY = /^\d+$/;
4
+ const DELIMITERS = /[_-]+/g;
5
+ const CAMEL_BOUNDARY_1 = /([a-z0-9])([A-Z])/g;
6
+ const CAMEL_BOUNDARY_2 = /([A-Z])([A-Z][a-z])/g;
7
+ const APOSTROPHES = /['’]/g;
8
+ const NON_ALPHANUMERIC = /[^a-z0-9\s]+/g;
9
+ const WHITESPACE = /\s+/g;
10
+
11
+ const normalizeStatusName = (value: string): string => {
12
+ // Handles common variants:
13
+ // - case differences: "not found" vs "Not Found"
14
+ // - spacing/punctuation: "Not-Found", "not_found"
15
+ // - camelCase/PascalCase: "InternalServerError"
16
+ const trimmed = value.trim();
17
+ if (!trimmed) {
18
+ return "";
19
+ }
20
+
21
+ return trimmed
22
+ .replace(DELIMITERS, " ")
23
+ .replace(CAMEL_BOUNDARY_1, "$1 $2")
24
+ .replace(CAMEL_BOUNDARY_2, "$1 $2")
25
+ .replace(APOSTROPHES, "")
26
+ .toLowerCase()
27
+ .replace(NON_ALPHANUMERIC, " ")
28
+ .replace(WHITESPACE, " ")
29
+ .trim();
30
+ };
31
+
32
+ const STATUS_BY_NORMALIZED_NAME = (() => {
33
+ const map = new Map<string, number>();
34
+
35
+ for (const [name, code] of Object.entries(StatusMap)) {
36
+ map.set(normalizeStatusName(name), code);
37
+ }
38
+
39
+ return map;
40
+ })();
41
+
42
+ export const getStatusCode = (value: unknown): number => {
43
+ if (typeof value === "number" && Number.isFinite(value)) {
44
+ return value;
45
+ }
46
+
47
+ if (typeof value === "string") {
48
+ const trimmed = value.trim();
49
+ if (DIGITS_ONLY.test(trimmed)) {
50
+ return Number(trimmed);
51
+ }
52
+
53
+ const known = STATUS_BY_NORMALIZED_NAME.get(normalizeStatusName(trimmed));
54
+ return known ?? 500;
55
+ }
56
+
57
+ return 500;
58
+ };