@withwiz/toolkit 0.2.1 → 0.2.3

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.
Files changed (84) hide show
  1. package/dist/auth/index.js +18 -18
  2. package/dist/{chunk-6JZQE7ZQ.js → chunk-GSUQE3SZ.js} +8 -8
  3. package/dist/{chunk-FH6E36YZ.js → chunk-SLG26KHZ.js} +1 -1
  4. package/dist/components/ui/DataTable.js +6 -6
  5. package/dist/components/ui/data-table/DataTable.js +6 -6
  6. package/dist/components/ui/data-table/DataTableFilters.js +2 -2
  7. package/dist/components/ui/data-table/DataTableSearch.js +2 -2
  8. package/dist/constants/index.js +13 -13
  9. package/dist/error/index.d.ts +0 -4
  10. package/dist/error/index.js +12 -80
  11. package/dist/geolocation/index.js +4 -4
  12. package/dist/geolocation/providers/index.js +4 -4
  13. package/dist/middleware/error-handler.js +2 -2
  14. package/dist/middleware/index.js +3 -3
  15. package/dist/middleware/wrappers.js +3 -3
  16. package/dist/utils/format-number.js +30 -4
  17. package/dist/utils/input-validation.js +4 -4
  18. package/dist/utils/short-code-generator.js +36 -4
  19. package/dist/utils/url-normalizer.js +194 -10
  20. package/package.json +1 -2
  21. package/dist/chunk-5ATB5D6S.js +0 -40
  22. package/dist/chunk-6C7HQIX4.js +0 -13
  23. package/dist/chunk-6UAYU5NU.js +0 -102
  24. package/dist/chunk-7VJNLGAS.js +0 -110
  25. package/dist/chunk-7XFHGAJP.js +0 -0
  26. package/dist/chunk-A6EAAWMK.js +0 -50
  27. package/dist/chunk-COK4ZXNG.js +0 -0
  28. package/dist/chunk-EQYTE7WD.js +0 -139
  29. package/dist/chunk-FW3IEJ7H.js +0 -71
  30. package/dist/chunk-HGC4CCKB.js +0 -29
  31. package/dist/chunk-JS5VI3OW.js +0 -143
  32. package/dist/chunk-MYLGYX4K.js +0 -57
  33. package/dist/chunk-TDZJ6SAI.js +0 -34
  34. package/dist/chunk-TEIYA7U4.js +0 -72
  35. package/dist/chunk-ULF5RDDX.js +0 -0
  36. package/dist/chunk-VWODEQ5C.js +0 -204
  37. package/dist/chunk-Y2TUZFCP.js +0 -0
  38. package/dist/chunk-YJ3TLEW3.js +0 -100
  39. package/dist/chunk-ZHVUK5OY.js +0 -314
  40. package/dist/chunk-ZZIKRBJU.js +0 -96
  41. package/dist/error/components/EmptyState.d.ts +0 -50
  42. package/dist/error/components/ErrorAlert.d.ts +0 -50
  43. package/dist/error/components/ErrorPage.d.ts +0 -39
  44. package/dist/error/components/LoadingState.d.ts +0 -37
  45. package/dist/error/components/index.d.ts +0 -13
  46. package/dist/error/components/index.js +0 -18
  47. package/dist/error/hooks/index.d.ts +0 -7
  48. package/dist/error/hooks/index.js +0 -14
  49. package/dist/error/hooks/useErrorHandler.d.ts +0 -67
  50. package/dist/error/hooks/useErrorHandler.js +0 -14
  51. package/dist/error/logging/error-logger.d.ts +0 -77
  52. package/dist/error/logging/error-logger.js +0 -10
  53. package/dist/error/logging/index.d.ts +0 -9
  54. package/dist/error/logging/index.js +0 -35
  55. package/dist/error/logging/transports/base.d.ts +0 -30
  56. package/dist/error/logging/transports/base.js +0 -7
  57. package/dist/error/logging/transports/console.d.ts +0 -40
  58. package/dist/error/logging/transports/console.js +0 -9
  59. package/dist/error/logging/transports/file.d.ts +0 -49
  60. package/dist/error/logging/transports/file.js +0 -8
  61. package/dist/error/logging/transports/index.d.ts +0 -12
  62. package/dist/error/logging/transports/index.js +0 -25
  63. package/dist/error/logging/transports/sentry.d.ts +0 -44
  64. package/dist/error/logging/transports/sentry.js +0 -9
  65. package/dist/error/logging/transports/slack.d.ts +0 -51
  66. package/dist/error/logging/transports/slack.js +0 -9
  67. package/dist/error/logging/types.d.ts +0 -83
  68. package/dist/error/logging/types.js +0 -7
  69. package/dist/error/recovery/circuit-breaker.d.ts +0 -85
  70. package/dist/error/recovery/circuit-breaker.js +0 -9
  71. package/dist/error/recovery/degradation.d.ts +0 -56
  72. package/dist/error/recovery/degradation.js +0 -7
  73. package/dist/error/recovery/fallback.d.ts +0 -55
  74. package/dist/error/recovery/fallback.js +0 -11
  75. package/dist/error/recovery/index.d.ts +0 -12
  76. package/dist/error/recovery/index.js +0 -26
  77. package/dist/error/recovery/retry.d.ts +0 -44
  78. package/dist/error/recovery/retry.js +0 -7
  79. package/dist/utils/shared-utils.d.ts +0 -25
  80. package/dist/utils/shared-utils.js +0 -43
  81. package/dist/{chunk-SEZJN4TC.js → chunk-LJEGM4OO.js} +3 -3
  82. package/dist/{chunk-S73334QY.js → chunk-QF6FH4GZ.js} +3 -3
  83. package/dist/{chunk-KHYY4KCV.js → chunk-TH45RVP7.js} +3 -3
  84. package/dist/{chunk-5OWZKYWQ.js → chunk-TMVS4F7E.js} +3 -3
@@ -1,14 +1,198 @@
1
- import {
2
- SUPPORTED_SCHEMES,
3
- extractScheme,
4
- getUrlType,
5
- hasValidScheme,
6
- isAppScheme,
7
- isWebUrl,
8
- normalizeUrl,
9
- validateUrl
10
- } from "../chunk-VWODEQ5C.js";
11
1
  import "../chunk-ORMEWXMH.js";
2
+
3
+ // src/utils/url-normalizer.ts
4
+ var SUPPORTED_SCHEMES = [
5
+ "http:",
6
+ "https:",
7
+ "mailto:",
8
+ "tel:",
9
+ "sms:",
10
+ "ftp:",
11
+ "ftps:",
12
+ // 'file:' - 보안상 제거 (로컬 파일 접근 방지)
13
+ // 'data:' - XSS 공격 벡터로 제거 (CVSS 7.5)
14
+ // Mobile app schemes
15
+ "intent:",
16
+ "market:",
17
+ "itms:",
18
+ "itms-apps:",
19
+ // Social media apps
20
+ "fb:",
21
+ "instagram:",
22
+ "twitter:",
23
+ "youtube:",
24
+ "linkedin:",
25
+ "tiktok:",
26
+ // Messaging apps
27
+ "whatsapp:",
28
+ "telegram:",
29
+ "line:",
30
+ "kakaotalk:",
31
+ "viber:",
32
+ "wechat:",
33
+ "slack:",
34
+ "discord:",
35
+ // Other apps
36
+ "spotify:",
37
+ "zoom:",
38
+ "skype:",
39
+ "maps:",
40
+ "geo:"
41
+ ];
42
+ var CUSTOM_SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
43
+ function hasValidScheme(url) {
44
+ try {
45
+ const urlObj = new URL(url);
46
+ const protocol = urlObj.protocol;
47
+ if (SUPPORTED_SCHEMES.includes(protocol)) {
48
+ return true;
49
+ }
50
+ if (CUSTOM_SCHEME_PATTERN.test(url)) {
51
+ return true;
52
+ }
53
+ return false;
54
+ } catch (e) {
55
+ return false;
56
+ }
57
+ }
58
+ function extractScheme(url) {
59
+ const match = url.match(/^([a-zA-Z][a-zA-Z0-9+.-]*):\/?\/?/);
60
+ return match ? match[1] : null;
61
+ }
62
+ function normalizeUrl(url) {
63
+ if (!url) {
64
+ return "";
65
+ }
66
+ let normalized = url.trim();
67
+ if (!normalized) {
68
+ return "";
69
+ }
70
+ const scheme = extractScheme(normalized);
71
+ if (scheme) {
72
+ return normalized;
73
+ }
74
+ if (normalized.startsWith("//")) {
75
+ return `https:${normalized}`;
76
+ }
77
+ return `https://${normalized}`;
78
+ }
79
+ function validateUrl(url, options) {
80
+ if (!url || !url.trim()) {
81
+ return {
82
+ isValid: false,
83
+ message: "URL\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694",
84
+ messageKey: "urlRequired"
85
+ };
86
+ }
87
+ const normalized = (options == null ? void 0 : options.skipNormalization) ? url.trim() : normalizeUrl(url);
88
+ try {
89
+ const urlObj = new URL(normalized);
90
+ const protocol = urlObj.protocol;
91
+ const isSupported = SUPPORTED_SCHEMES.includes(protocol);
92
+ const isCustom = CUSTOM_SCHEME_PATTERN.test(normalized);
93
+ if (!isSupported && !isCustom) {
94
+ return {
95
+ isValid: false,
96
+ message: `\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD504\uB85C\uD1A0\uCF5C\uC785\uB2C8\uB2E4: ${protocol}`,
97
+ messageKey: "unsupportedProtocol",
98
+ messageParams: { protocol }
99
+ };
100
+ }
101
+ if (protocol === "http:" || protocol === "https:") {
102
+ if (!urlObj.hostname || urlObj.hostname.length < 1) {
103
+ return {
104
+ isValid: false,
105
+ message: "\uC720\uD6A8\uD55C \uB3C4\uBA54\uC778\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694",
106
+ messageKey: "invalidDomain"
107
+ };
108
+ }
109
+ if (!urlObj.hostname.includes(".") && urlObj.hostname !== "localhost") {
110
+ return {
111
+ isValid: false,
112
+ message: "\uC720\uD6A8\uD55C \uB3C4\uBA54\uC778 \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4",
113
+ messageKey: "invalidDomainFormat"
114
+ };
115
+ }
116
+ }
117
+ if (protocol === "mailto:") {
118
+ const email = urlObj.pathname;
119
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
120
+ if (!emailRegex.test(email)) {
121
+ return {
122
+ isValid: false,
123
+ message: "\uC720\uD6A8\uD55C \uC774\uBA54\uC77C \uC8FC\uC18C\uAC00 \uC544\uB2D9\uB2C8\uB2E4",
124
+ messageKey: "invalidEmail"
125
+ };
126
+ }
127
+ }
128
+ if (protocol === "tel:") {
129
+ const phone = urlObj.pathname;
130
+ if (!/\d/.test(phone)) {
131
+ return {
132
+ isValid: false,
133
+ message: "\uC720\uD6A8\uD55C \uC804\uD654\uBC88\uD638\uAC00 \uC544\uB2D9\uB2C8\uB2E4",
134
+ messageKey: "invalidPhone"
135
+ };
136
+ }
137
+ }
138
+ if (normalized.length > 2048) {
139
+ return {
140
+ isValid: false,
141
+ message: "URL\uC774 \uB108\uBB34 \uAE41\uB2C8\uB2E4 (\uCD5C\uB300 2048\uC790)",
142
+ messageKey: "urlTooLong"
143
+ };
144
+ }
145
+ return {
146
+ isValid: true,
147
+ message: "\uC720\uD6A8\uD55C URL\uC785\uB2C8\uB2E4",
148
+ messageKey: "validUrl",
149
+ normalizedUrl: normalized
150
+ };
151
+ } catch (error) {
152
+ return {
153
+ isValid: false,
154
+ message: "\uC720\uD6A8\uD55C URL \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4",
155
+ messageKey: "invalidUrlFormat"
156
+ };
157
+ }
158
+ }
159
+ function isWebUrl(url) {
160
+ try {
161
+ const urlObj = new URL(url);
162
+ return urlObj.protocol === "http:" || urlObj.protocol === "https:";
163
+ } catch (e) {
164
+ return false;
165
+ }
166
+ }
167
+ function isAppScheme(url) {
168
+ try {
169
+ const urlObj = new URL(url);
170
+ return !["http:", "https:", "ftp:", "ftps:", "file:"].includes(urlObj.protocol);
171
+ } catch (e) {
172
+ return false;
173
+ }
174
+ }
175
+ function getUrlType(url) {
176
+ try {
177
+ const urlObj = new URL(url);
178
+ const protocol = urlObj.protocol;
179
+ if (protocol === "http:" || protocol === "https:") {
180
+ return "web";
181
+ }
182
+ if (protocol === "mailto:") {
183
+ return "email";
184
+ }
185
+ if (protocol === "tel:" || protocol === "sms:") {
186
+ return "tel";
187
+ }
188
+ if (isAppScheme(url)) {
189
+ return "app";
190
+ }
191
+ return "other";
192
+ } catch (e) {
193
+ return "other";
194
+ }
195
+ }
12
196
  export {
13
197
  SUPPORTED_SCHEMES,
14
198
  extractScheme,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withwiz/toolkit",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Shared utility library for withwiz projects",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -82,7 +82,6 @@
82
82
  "./utils/ip-utils": "./dist/utils/ip-utils.js",
83
83
  "./utils/optimistic-lock": "./dist/utils/optimistic-lock.js",
84
84
  "./utils/sanitizer": "./dist/utils/sanitizer.js",
85
- "./utils/shared-utils": "./dist/utils/shared-utils.js",
86
85
  "./utils/short-code-generator": "./dist/utils/short-code-generator.js",
87
86
  "./utils/timezone": "./dist/utils/timezone.js",
88
87
  "./utils/type-guards": "./dist/utils/type-guards.js",
@@ -1,40 +0,0 @@
1
- // src/utils/short-code-generator.ts
2
- function generateShortCode(length = 8) {
3
- if (!Number.isInteger(length) || length <= 0) {
4
- throw new Error("length must be a positive integer");
5
- }
6
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
7
- let result = "";
8
- for (let i = 0; i < length; i++) {
9
- result += chars.charAt(Math.floor(Math.random() * chars.length));
10
- }
11
- return result;
12
- }
13
- async function generateUniqueShortCode(options = {}) {
14
- const {
15
- length = 8,
16
- maxAttempts = 100,
17
- checkDuplicate
18
- } = options;
19
- let shortCode;
20
- let attempts = 0;
21
- do {
22
- shortCode = generateShortCode(length);
23
- attempts++;
24
- if (checkDuplicate) {
25
- const isDuplicate = await checkDuplicate(shortCode);
26
- if (!isDuplicate) break;
27
- } else {
28
- break;
29
- }
30
- if (attempts >= maxAttempts) {
31
- throw new Error("Failed to generate unique shortCode after multiple attempts");
32
- }
33
- } while (true);
34
- return shortCode;
35
- }
36
-
37
- export {
38
- generateShortCode,
39
- generateUniqueShortCode
40
- };
@@ -1,13 +0,0 @@
1
- // src/error/logging/types.ts
2
- var ELogLevel = /* @__PURE__ */ ((ELogLevel2) => {
3
- ELogLevel2["DEBUG"] = "debug";
4
- ELogLevel2["INFO"] = "info";
5
- ELogLevel2["WARN"] = "warn";
6
- ELogLevel2["ERROR"] = "error";
7
- ELogLevel2["CRITICAL"] = "critical";
8
- return ELogLevel2;
9
- })(ELogLevel || {});
10
-
11
- export {
12
- ELogLevel
13
- };
@@ -1,102 +0,0 @@
1
- import {
2
- AppError
3
- } from "./chunk-MLGO3HLS.js";
4
- import {
5
- getErrorDisplayInfo
6
- } from "./chunk-POKGHK3L.js";
7
- import {
8
- ERROR_CODES
9
- } from "./chunk-Y3OTJH2S.js";
10
-
11
- // src/error/hooks/useErrorHandler.ts
12
- import { useState, useCallback } from "react";
13
- function useErrorHandler(locale = "ko") {
14
- const [errorState, setErrorState] = useState({
15
- hasError: false
16
- });
17
- const handleError = useCallback(
18
- (error) => {
19
- console.error("[useErrorHandler] Error occurred:", error);
20
- if (error instanceof AppError) {
21
- const displayInfo2 = getErrorDisplayInfo(error.code, locale);
22
- setErrorState({
23
- hasError: true,
24
- code: error.code,
25
- message: error.message,
26
- displayInfo: displayInfo2,
27
- timestamp: Date.now()
28
- });
29
- return;
30
- }
31
- if (error && typeof error === "object" && "error" in error && typeof error.error === "object") {
32
- const apiError = error.error;
33
- const code = apiError.code || ERROR_CODES.INTERNAL_SERVER_ERROR.code;
34
- const displayInfo2 = getErrorDisplayInfo(code, locale);
35
- setErrorState({
36
- hasError: true,
37
- code,
38
- message: apiError.message || "Unknown error",
39
- displayInfo: displayInfo2,
40
- timestamp: Date.now()
41
- });
42
- return;
43
- }
44
- if (error instanceof Error) {
45
- const displayInfo2 = getErrorDisplayInfo(
46
- ERROR_CODES.INTERNAL_SERVER_ERROR.code,
47
- locale
48
- );
49
- setErrorState({
50
- hasError: true,
51
- code: ERROR_CODES.INTERNAL_SERVER_ERROR.code,
52
- message: error.message,
53
- displayInfo: displayInfo2,
54
- timestamp: Date.now()
55
- });
56
- return;
57
- }
58
- const displayInfo = getErrorDisplayInfo(
59
- ERROR_CODES.INTERNAL_SERVER_ERROR.code,
60
- locale
61
- );
62
- setErrorState({
63
- hasError: true,
64
- code: ERROR_CODES.INTERNAL_SERVER_ERROR.code,
65
- message: String(error),
66
- displayInfo,
67
- timestamp: Date.now()
68
- });
69
- },
70
- [locale]
71
- );
72
- const clearError = useCallback(() => {
73
- setErrorState({
74
- hasError: false
75
- });
76
- }, []);
77
- const handleAuthError = useCallback(
78
- (error, redirectUrl = "/login") => {
79
- handleError(error);
80
- if (error instanceof AppError) {
81
- const httpStatus = Math.floor(error.code / 100);
82
- if (httpStatus === 401 || httpStatus === 403) {
83
- setTimeout(() => {
84
- window.location.href = redirectUrl;
85
- }, 1e3);
86
- }
87
- }
88
- },
89
- [handleError]
90
- );
91
- return {
92
- errorState,
93
- handleError,
94
- clearError,
95
- handleAuthError,
96
- hasError: errorState.hasError
97
- };
98
- }
99
-
100
- export {
101
- useErrorHandler
102
- };
@@ -1,110 +0,0 @@
1
- // src/error/recovery/circuit-breaker.ts
2
- var ECircuitState = /* @__PURE__ */ ((ECircuitState2) => {
3
- ECircuitState2["CLOSED"] = "closed";
4
- ECircuitState2["OPEN"] = "open";
5
- ECircuitState2["HALF_OPEN"] = "half-open";
6
- return ECircuitState2;
7
- })(ECircuitState || {});
8
- var CircuitBreaker = class {
9
- constructor(options = {}) {
10
- this.state = "closed" /* CLOSED */;
11
- this.failureCount = 0;
12
- this.successCount = 0;
13
- this.nextAttemptTime = 0;
14
- this.options = {
15
- failureThreshold: options.failureThreshold || 5,
16
- successThreshold: options.successThreshold || 2,
17
- timeout: options.timeout || 6e4,
18
- onStateChange: options.onStateChange || (() => {
19
- }),
20
- onError: options.onError || (() => {
21
- })
22
- };
23
- }
24
- /**
25
- * 함수 실행
26
- */
27
- async execute(fn) {
28
- if (this.state === "open" /* OPEN */) {
29
- if (Date.now() < this.nextAttemptTime) {
30
- throw new Error("Circuit breaker is OPEN");
31
- }
32
- this.setState("half-open" /* HALF_OPEN */);
33
- }
34
- try {
35
- const result = await fn();
36
- this.onSuccess();
37
- return result;
38
- } catch (error) {
39
- this.onFailure();
40
- this.options.onError(error);
41
- throw error;
42
- }
43
- }
44
- /**
45
- * 성공 처리
46
- */
47
- onSuccess() {
48
- this.failureCount = 0;
49
- if (this.state === "half-open" /* HALF_OPEN */) {
50
- this.successCount++;
51
- if (this.successCount >= this.options.successThreshold) {
52
- this.setState("closed" /* CLOSED */);
53
- this.successCount = 0;
54
- }
55
- }
56
- }
57
- /**
58
- * 실패 처리
59
- */
60
- onFailure() {
61
- this.failureCount++;
62
- this.successCount = 0;
63
- if (this.failureCount >= this.options.failureThreshold) {
64
- this.setState("open" /* OPEN */);
65
- this.nextAttemptTime = Date.now() + this.options.timeout;
66
- }
67
- }
68
- /**
69
- * 상태 변경
70
- */
71
- setState(newState) {
72
- const oldState = this.state;
73
- if (oldState !== newState) {
74
- this.state = newState;
75
- this.options.onStateChange(oldState, newState);
76
- console.log(`[CircuitBreaker] State changed: ${oldState} -> ${newState}`);
77
- }
78
- }
79
- /**
80
- * 현재 상태 조회
81
- */
82
- getState() {
83
- return this.state;
84
- }
85
- /**
86
- * 상태 초기화
87
- */
88
- reset() {
89
- this.setState("closed" /* CLOSED */);
90
- this.failureCount = 0;
91
- this.successCount = 0;
92
- this.nextAttemptTime = 0;
93
- }
94
- /**
95
- * 메트릭 조회
96
- */
97
- getMetrics() {
98
- return {
99
- state: this.state,
100
- failureCount: this.failureCount,
101
- successCount: this.successCount,
102
- nextAttemptTime: this.nextAttemptTime
103
- };
104
- }
105
- };
106
-
107
- export {
108
- ECircuitState,
109
- CircuitBreaker
110
- };
File without changes
@@ -1,50 +0,0 @@
1
- // src/error/recovery/retry.ts
2
- function defaultShouldRetry(error) {
3
- if (error instanceof Error) {
4
- const message = error.message.toLowerCase();
5
- return message.includes("network") || message.includes("timeout") || message.includes("econnrefused") || message.includes("enotfound") || message.includes("503") || message.includes("504");
6
- }
7
- return false;
8
- }
9
- async function withRetry(fn, options = {}) {
10
- const {
11
- maxAttempts = 3,
12
- delay = 1e3,
13
- exponentialBackoff = true,
14
- backoffMultiplier = 2,
15
- maxDelay = 3e4,
16
- shouldRetry = defaultShouldRetry,
17
- onRetry
18
- } = options;
19
- let lastError;
20
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
21
- try {
22
- return await fn();
23
- } catch (error) {
24
- lastError = error;
25
- if (attempt === maxAttempts) {
26
- throw error;
27
- }
28
- if (!shouldRetry(error, attempt)) {
29
- throw error;
30
- }
31
- onRetry == null ? void 0 : onRetry(error, attempt);
32
- let currentDelay = delay;
33
- if (exponentialBackoff) {
34
- currentDelay = Math.min(
35
- delay * Math.pow(backoffMultiplier, attempt - 1),
36
- maxDelay
37
- );
38
- }
39
- await sleep(currentDelay);
40
- }
41
- }
42
- throw lastError;
43
- }
44
- function sleep(ms) {
45
- return new Promise((resolve) => setTimeout(resolve, ms));
46
- }
47
-
48
- export {
49
- withRetry
50
- };
File without changes
@@ -1,139 +0,0 @@
1
- import {
2
- BaseTransport
3
- } from "./chunk-HGC4CCKB.js";
4
-
5
- // src/error/logging/transports/slack.ts
6
- var LEVEL_COLORS = {
7
- ["debug" /* DEBUG */]: "#36a64f",
8
- // Green
9
- ["info" /* INFO */]: "#2196F3",
10
- // Blue
11
- ["warn" /* WARN */]: "#FFC107",
12
- // Amber
13
- ["error" /* ERROR */]: "#F44336",
14
- // Red
15
- ["critical" /* CRITICAL */]: "#9C27B0"
16
- // Purple
17
- };
18
- var SlackTransport = class extends BaseTransport {
19
- constructor(options = {}) {
20
- const webhookUrl = options.webhookUrl || process.env.SLACK_WEBHOOK_URL;
21
- super("slack", Boolean(webhookUrl) && options.enabled !== false);
22
- this.webhookUrl = webhookUrl;
23
- this.minLevel = options.minLevel || "critical" /* CRITICAL */;
24
- this.channel = options.channel;
25
- this.username = options.username || "Error Logger";
26
- this.iconEmoji = options.iconEmoji || ":rotating_light:";
27
- }
28
- async log(entry) {
29
- if (!this.webhookUrl) {
30
- return;
31
- }
32
- if (!this.shouldLog(entry.level)) {
33
- return;
34
- }
35
- try {
36
- const payload = this.buildPayload(entry);
37
- const response = await fetch(this.webhookUrl, {
38
- method: "POST",
39
- headers: {
40
- "Content-Type": "application/json"
41
- },
42
- body: JSON.stringify(payload)
43
- });
44
- if (!response.ok) {
45
- throw new Error(`Slack webhook failed: ${response.statusText}`);
46
- }
47
- } catch (error) {
48
- console.error("[SlackTransport] Failed to send to Slack:", error);
49
- }
50
- }
51
- /**
52
- * Slack 메시지 페이로드 생성
53
- */
54
- buildPayload(entry) {
55
- const payload = {
56
- username: this.username,
57
- icon_emoji: this.iconEmoji
58
- };
59
- if (this.channel) {
60
- payload.channel = this.channel;
61
- }
62
- const attachment = {
63
- color: LEVEL_COLORS[entry.level],
64
- title: `${entry.level.toUpperCase()}: ${entry.message}`,
65
- timestamp: Math.floor(entry.timestamp.getTime() / 1e3),
66
- fields: []
67
- };
68
- if (entry.context.requestId) {
69
- attachment.fields.push({
70
- title: "Request ID",
71
- value: entry.context.requestId,
72
- short: true
73
- });
74
- }
75
- if (entry.context.errorCode) {
76
- attachment.fields.push({
77
- title: "Error Code",
78
- value: entry.context.errorCode,
79
- short: true
80
- });
81
- }
82
- if (entry.context.userId) {
83
- attachment.fields.push({
84
- title: "User ID",
85
- value: entry.context.userId,
86
- short: true
87
- });
88
- }
89
- if (entry.context.environment) {
90
- attachment.fields.push({
91
- title: "Environment",
92
- value: entry.context.environment,
93
- short: true
94
- });
95
- }
96
- if (entry.context.path) {
97
- attachment.fields.push({
98
- title: "Path",
99
- value: entry.context.path,
100
- short: false
101
- });
102
- }
103
- if (entry.error && entry.error.stack) {
104
- attachment.fields.push({
105
- title: "Stack Trace",
106
- value: `\`\`\`${this.truncate(entry.error.stack, 1e3)}\`\`\``,
107
- short: false
108
- });
109
- }
110
- payload.attachments = [attachment];
111
- return payload;
112
- }
113
- /**
114
- * 문자열 자르기
115
- */
116
- truncate(str, maxLength) {
117
- if (str.length <= maxLength) {
118
- return str;
119
- }
120
- return str.substring(0, maxLength) + "...";
121
- }
122
- /**
123
- * 로그 레벨 체크
124
- */
125
- shouldLog(level) {
126
- const LOG_LEVEL_PRIORITY = {
127
- ["debug" /* DEBUG */]: 0,
128
- ["info" /* INFO */]: 1,
129
- ["warn" /* WARN */]: 2,
130
- ["error" /* ERROR */]: 3,
131
- ["critical" /* CRITICAL */]: 4
132
- };
133
- return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[this.minLevel];
134
- }
135
- };
136
-
137
- export {
138
- SlackTransport
139
- };