@withwiz/toolkit 0.1.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 +162 -0
- package/dist/auth/adapters/prisma/index.d.ts +43 -0
- package/dist/auth/adapters/prisma/index.js +284 -0
- package/dist/auth/core/email/token-generator.d.ts +43 -0
- package/dist/auth/core/email/token-generator.js +7 -0
- package/dist/auth/core/jwt/client.d.ts +87 -0
- package/dist/auth/core/jwt/client.js +36 -0
- package/dist/auth/core/jwt/index.d.ts +110 -0
- package/dist/auth/core/jwt/index.js +10 -0
- package/dist/auth/core/jwt/types.d.ts +6 -0
- package/dist/auth/core/jwt/types.js +13 -0
- package/dist/auth/core/oauth/index.d.ts +51 -0
- package/dist/auth/core/oauth/index.js +12 -0
- package/dist/auth/core/password/client-helper.d.ts +44 -0
- package/dist/auth/core/password/client-helper.js +28 -0
- package/dist/auth/core/password/index.d.ts +71 -0
- package/dist/auth/core/password/index.js +14 -0
- package/dist/auth/errors/index.d.ts +49 -0
- package/dist/auth/errors/index.js +17 -0
- package/dist/auth/index.d.ts +21 -0
- package/dist/auth/index.js +97 -0
- package/dist/auth/types/index.d.ts +213 -0
- package/dist/auth/types/index.js +13 -0
- package/dist/cache/cache-config.d.ts +73 -0
- package/dist/cache/cache-config.js +12 -0
- package/dist/cache/cache-defaults.d.ts +141 -0
- package/dist/cache/cache-defaults.js +33 -0
- package/dist/cache/cache-env.d.ts +75 -0
- package/dist/cache/cache-env.js +25 -0
- package/dist/cache/cache-factory.d.ts +34 -0
- package/dist/cache/cache-factory.js +28 -0
- package/dist/cache/cache-invalidation.d.ts +90 -0
- package/dist/cache/cache-invalidation.js +24 -0
- package/dist/cache/cache-keys-legacy.d.ts +35 -0
- package/dist/cache/cache-keys-legacy.js +7 -0
- package/dist/cache/cache-redis.d.ts +74 -0
- package/dist/cache/cache-redis.js +24 -0
- package/dist/cache/cache-types.d.ts +151 -0
- package/dist/cache/cache-types.js +9 -0
- package/dist/cache/cache-wrapper.d.ts +27 -0
- package/dist/cache/cache-wrapper.js +22 -0
- package/dist/cache/cache.d.ts +14 -0
- package/dist/cache/cache.js +112 -0
- package/dist/cache/hybrid-cache-manager.d.ts +148 -0
- package/dist/cache/hybrid-cache-manager.js +13 -0
- package/dist/cache/index.d.ts +21 -0
- package/dist/cache/index.js +112 -0
- package/dist/cache/inmemory-cache-manager.d.ts +163 -0
- package/dist/cache/inmemory-cache-manager.js +9 -0
- package/dist/cache/noop-cache-manager.d.ts +36 -0
- package/dist/cache/noop-cache-manager.js +11 -0
- package/dist/cache/redis-cache-manager.d.ts +34 -0
- package/dist/cache/redis-cache-manager.js +11 -0
- package/dist/chunk-26Y7VEYG.js +93 -0
- package/dist/chunk-2DVWSDST.js +119 -0
- package/dist/chunk-2KAPUVIS.js +155 -0
- package/dist/chunk-2TO7WUKK.js +93 -0
- package/dist/chunk-34WAGUT5.js +117 -0
- package/dist/chunk-3DZA6AGS.js +120 -0
- package/dist/chunk-4DPSCTX4.js +212 -0
- package/dist/chunk-4KJXENRM.js +64 -0
- package/dist/chunk-4NWJ3WCZ.js +28 -0
- package/dist/chunk-4ODT3Q4A.js +86 -0
- package/dist/chunk-5ATB5D6S.js +40 -0
- package/dist/chunk-62FLBG6B.js +34 -0
- package/dist/chunk-62Q7DN5G.js +25 -0
- package/dist/chunk-65LHDFU3.js +242 -0
- package/dist/chunk-6C7HQIX4.js +13 -0
- package/dist/chunk-6D3HHYER.js +32 -0
- package/dist/chunk-6LTZCXNC.js +326 -0
- package/dist/chunk-7VJNLGAS.js +110 -0
- package/dist/chunk-7XFHGAJP.js +0 -0
- package/dist/chunk-A6EAAWMK.js +50 -0
- package/dist/chunk-AHDPGRXS.js +51 -0
- package/dist/chunk-AIH3F7JV.js +76 -0
- package/dist/chunk-AIHQBQ3E.js +109 -0
- package/dist/chunk-BKGVSC6S.js +152 -0
- package/dist/chunk-COK4ZXNG.js +0 -0
- package/dist/chunk-DEEJBDJE.js +47 -0
- package/dist/chunk-DH2ZHGW2.js +53 -0
- package/dist/chunk-EBUEBEJX.js +0 -0
- package/dist/chunk-EEUBKZV4.js +54 -0
- package/dist/chunk-EQYTE7WD.js +139 -0
- package/dist/chunk-EUQATJLI.js +180 -0
- package/dist/chunk-EZC6ETFW.js +80 -0
- package/dist/chunk-EZR55KV2.js +249 -0
- package/dist/chunk-F6LCSFSU.js +31 -0
- package/dist/chunk-FOKAATUQ.js +62 -0
- package/dist/chunk-FW3IEJ7H.js +71 -0
- package/dist/chunk-G26T2PRQ.js +53 -0
- package/dist/chunk-G4NI37NN.js +257 -0
- package/dist/chunk-GCZOXUDV.js +132 -0
- package/dist/chunk-GDWEDUHO.js +55 -0
- package/dist/chunk-GL2NANFH.js +434 -0
- package/dist/chunk-GPBOMJSZ.js +136 -0
- package/dist/chunk-H5I5GWAA.js +94 -0
- package/dist/chunk-HGC4CCKB.js +29 -0
- package/dist/chunk-HV3DGSSH.js +447 -0
- package/dist/chunk-I47QEDTX.js +193 -0
- package/dist/chunk-IAJNC34M.js +102 -0
- package/dist/chunk-IHXRF3BH.js +215 -0
- package/dist/chunk-IJEZ7G7S.js +26 -0
- package/dist/chunk-IQQKKUAV.js +151 -0
- package/dist/chunk-JBCDEAMW.js +35 -0
- package/dist/chunk-JLLMTTQ4.js +75 -0
- package/dist/chunk-JS5VI3OW.js +143 -0
- package/dist/chunk-KAWVMIRJ.js +44 -0
- package/dist/chunk-KMCJIL57.js +214 -0
- package/dist/chunk-KWTBD4CM.js +145 -0
- package/dist/chunk-KXAWBFJN.js +310 -0
- package/dist/chunk-L25BNU3E.js +56 -0
- package/dist/chunk-L76O3X3D.js +197 -0
- package/dist/chunk-LNV2E4I6.js +63 -0
- package/dist/chunk-MLGO3HLS.js +329 -0
- package/dist/chunk-MRJE6OX5.js +22 -0
- package/dist/chunk-MYLGYX4K.js +57 -0
- package/dist/chunk-N4YGR5WH.js +310 -0
- package/dist/chunk-OIVXOT2X.js +80 -0
- package/dist/chunk-ORMEWXMH.js +37 -0
- package/dist/chunk-POKGHK3L.js +57 -0
- package/dist/chunk-Q7IP4JMW.js +69 -0
- package/dist/chunk-RJUVBBZG.js +27 -0
- package/dist/chunk-S73334QY.js +89 -0
- package/dist/chunk-SLG26KHZ.js +101 -0
- package/dist/chunk-SR65BF6X.js +82 -0
- package/dist/chunk-SS56XFLI.js +19 -0
- package/dist/chunk-T3LJYAMO.js +277 -0
- package/dist/chunk-TDZJ6SAI.js +34 -0
- package/dist/chunk-TEIYA7U4.js +72 -0
- package/dist/chunk-TMVS4F7E.js +88 -0
- package/dist/chunk-TRBKJ7JT.js +137 -0
- package/dist/chunk-TXGNSECL.js +84 -0
- package/dist/chunk-TZAP5T4N.js +188 -0
- package/dist/chunk-UCYQNHST.js +24 -0
- package/dist/chunk-ULF5RDDX.js +0 -0
- package/dist/chunk-UXQRU3EM.js +167 -0
- package/dist/chunk-V5K5FYU7.js +200 -0
- package/dist/chunk-VDXB5DCY.js +68 -0
- package/dist/chunk-VSGKVZB4.js +47 -0
- package/dist/chunk-VWODEQ5C.js +204 -0
- package/dist/chunk-WDUFQFDP.js +193 -0
- package/dist/chunk-WHR7HPWF.js +126 -0
- package/dist/chunk-WSQMXMTL.js +122 -0
- package/dist/chunk-XHZ5L4FO.js +103 -0
- package/dist/chunk-XPASCCUA.js +404 -0
- package/dist/chunk-XRRPEBKB.js +231 -0
- package/dist/chunk-Y2TUZFCP.js +0 -0
- package/dist/chunk-Y3OTJH2S.js +473 -0
- package/dist/chunk-YBSHN67U.js +161 -0
- package/dist/chunk-YJ3TLEW3.js +100 -0
- package/dist/chunk-YJWLWUFK.js +105 -0
- package/dist/chunk-Z4D4CMDA.js +488 -0
- package/dist/chunk-ZHVUK5OY.js +314 -0
- package/dist/chunk-ZTN4X5FN.js +29 -0
- package/dist/chunk-ZZIKRBJU.js +96 -0
- package/dist/components/ui/Alert.d.ts +12 -0
- package/dist/components/ui/Alert.js +10 -0
- package/dist/components/ui/Badge.d.ts +7 -0
- package/dist/components/ui/Badge.js +8 -0
- package/dist/components/ui/Button.d.ts +7 -0
- package/dist/components/ui/Button.js +8 -0
- package/dist/components/ui/DataTable.d.ts +103 -0
- package/dist/components/ui/DataTable.js +606 -0
- package/dist/components/ui/DomainDisplay.d.ts +12 -0
- package/dist/components/ui/DomainDisplay.js +31 -0
- package/dist/components/ui/Input.d.ts +5 -0
- package/dist/components/ui/Input.js +8 -0
- package/dist/components/ui/Label.d.ts +5 -0
- package/dist/components/ui/Label.js +8 -0
- package/dist/components/ui/Pagination.d.ts +42 -0
- package/dist/components/ui/Pagination.js +20 -0
- package/dist/components/ui/Select.d.ts +15 -0
- package/dist/components/ui/Select.js +27 -0
- package/dist/components/ui/Skeleton.d.ts +6 -0
- package/dist/components/ui/Skeleton.js +8 -0
- package/dist/components/ui/TimezoneDisplay.d.ts +22 -0
- package/dist/components/ui/TimezoneDisplay.js +83 -0
- package/dist/components/ui/Tooltip.d.ts +21 -0
- package/dist/components/ui/Tooltip.js +94 -0
- package/dist/components/ui/WorldMapChart.d.ts +17 -0
- package/dist/components/ui/WorldMapChart.js +250 -0
- package/dist/components/ui/loading-bar.d.ts +20 -0
- package/dist/components/ui/loading-bar.js +15 -0
- package/dist/constants/error-codes.d.ts +389 -0
- package/dist/constants/error-codes.js +27 -0
- package/dist/constants/index.d.ts +11 -0
- package/dist/constants/index.js +85 -0
- package/dist/constants/messages.d.ts +83 -0
- package/dist/constants/messages.js +13 -0
- package/dist/constants/pagination.d.ts +43 -0
- package/dist/constants/pagination.js +15 -0
- package/dist/constants/security.d.ts +66 -0
- package/dist/constants/security.js +23 -0
- package/dist/constants/validation.d.ts +60 -0
- package/dist/constants/validation.js +19 -0
- package/dist/error/ErrorBoundary.d.ts +47 -0
- package/dist/error/app-error.d.ts +144 -0
- package/dist/error/app-error.js +10 -0
- package/dist/error/components/EmptyState.d.ts +50 -0
- package/dist/error/components/ErrorAlert.d.ts +50 -0
- package/dist/error/components/ErrorPage.d.ts +39 -0
- package/dist/error/components/LoadingState.d.ts +37 -0
- package/dist/error/components/index.d.ts +13 -0
- package/dist/error/components/index.js +18 -0
- package/dist/error/core/locale-detector.d.ts +44 -0
- package/dist/error/core/locale-detector.js +9 -0
- package/dist/error/error-display.d.ts +55 -0
- package/dist/error/error-display.js +24 -0
- package/dist/error/error-handler.d.ts +118 -0
- package/dist/error/error-handler.js +18 -0
- package/dist/error/friendly-messages-v2.d.ts +46 -0
- package/dist/error/friendly-messages-v2.js +15 -0
- package/dist/error/friendly-messages.d.ts +22 -0
- package/dist/error/friendly-messages.js +12 -0
- package/dist/error/hooks/index.d.ts +7 -0
- package/dist/error/hooks/index.js +14 -0
- package/dist/error/hooks/useErrorHandler.d.ts +67 -0
- package/dist/error/hooks/useErrorHandler.js +14 -0
- package/dist/error/index.d.ts +26 -0
- package/dist/error/index.js +289 -0
- package/dist/error/logging/error-logger.d.ts +77 -0
- package/dist/error/logging/error-logger.js +10 -0
- package/dist/error/logging/index.d.ts +9 -0
- package/dist/error/logging/index.js +35 -0
- package/dist/error/logging/transports/base.d.ts +30 -0
- package/dist/error/logging/transports/base.js +7 -0
- package/dist/error/logging/transports/console.d.ts +40 -0
- package/dist/error/logging/transports/console.js +9 -0
- package/dist/error/logging/transports/file.d.ts +49 -0
- package/dist/error/logging/transports/file.js +8 -0
- package/dist/error/logging/transports/index.d.ts +12 -0
- package/dist/error/logging/transports/index.js +25 -0
- package/dist/error/logging/transports/sentry.d.ts +44 -0
- package/dist/error/logging/transports/sentry.js +9 -0
- package/dist/error/logging/transports/slack.d.ts +51 -0
- package/dist/error/logging/transports/slack.js +9 -0
- package/dist/error/logging/types.d.ts +83 -0
- package/dist/error/logging/types.js +7 -0
- package/dist/error/messages/en.d.ts +5 -0
- package/dist/error/messages/en.js +7 -0
- package/dist/error/messages/index.d.ts +40 -0
- package/dist/error/messages/index.js +17 -0
- package/dist/error/messages/ko.d.ts +5 -0
- package/dist/error/messages/ko.js +7 -0
- package/dist/error/messages/types.d.ts +30 -0
- package/dist/error/messages/types.js +0 -0
- package/dist/error/recovery/circuit-breaker.d.ts +85 -0
- package/dist/error/recovery/circuit-breaker.js +9 -0
- package/dist/error/recovery/degradation.d.ts +56 -0
- package/dist/error/recovery/degradation.js +7 -0
- package/dist/error/recovery/fallback.d.ts +55 -0
- package/dist/error/recovery/fallback.js +11 -0
- package/dist/error/recovery/index.d.ts +12 -0
- package/dist/error/recovery/index.js +26 -0
- package/dist/error/recovery/retry.d.ts +44 -0
- package/dist/error/recovery/retry.js +7 -0
- package/dist/geolocation/batch-processor.d.ts +33 -0
- package/dist/geolocation/batch-processor.js +10 -0
- package/dist/geolocation/index.d.ts +14 -0
- package/dist/geolocation/index.js +36 -0
- package/dist/geolocation/providers/base-provider.d.ts +33 -0
- package/dist/geolocation/providers/base-provider.js +9 -0
- package/dist/geolocation/providers/index.d.ts +54 -0
- package/dist/geolocation/providers/index.js +29 -0
- package/dist/geolocation/providers/ip-api-provider.d.ts +17 -0
- package/dist/geolocation/providers/ip-api-provider.js +8 -0
- package/dist/geolocation/providers/ipapi-co-provider.d.ts +17 -0
- package/dist/geolocation/providers/ipapi-co-provider.js +8 -0
- package/dist/geolocation/providers/ipgeolocation-provider.d.ts +18 -0
- package/dist/geolocation/providers/ipgeolocation-provider.js +8 -0
- package/dist/geolocation/providers/maxmind-provider.d.ts +18 -0
- package/dist/geolocation/providers/maxmind-provider.js +8 -0
- package/dist/hooks/useDataTable.d.ts +51 -0
- package/dist/hooks/useDataTable.js +149 -0
- package/dist/hooks/useDebounce.d.ts +7 -0
- package/dist/hooks/useDebounce.js +7 -0
- package/dist/hooks/useExitIntent.d.ts +35 -0
- package/dist/hooks/useExitIntent.js +72 -0
- package/dist/hooks/useTimezone.d.ts +19 -0
- package/dist/hooks/useTimezone.js +11 -0
- package/dist/logger/logger.d.ts +11 -0
- package/dist/logger/logger.js +17 -0
- package/dist/middleware/auth.d.ts +87 -0
- package/dist/middleware/auth.js +20 -0
- package/dist/middleware/cors.d.ts +30 -0
- package/dist/middleware/cors.js +10 -0
- package/dist/middleware/error-handler.d.ts +23 -0
- package/dist/middleware/error-handler.js +13 -0
- package/dist/middleware/index.d.ts +16 -0
- package/dist/middleware/index.js +72 -0
- package/dist/middleware/init-request.d.ts +18 -0
- package/dist/middleware/init-request.js +8 -0
- package/dist/middleware/middleware-chain.d.ts +53 -0
- package/dist/middleware/middleware-chain.js +8 -0
- package/dist/middleware/rate-limit.d.ts +82 -0
- package/dist/middleware/rate-limit.js +14 -0
- package/dist/middleware/response-logger.d.ts +22 -0
- package/dist/middleware/response-logger.js +8 -0
- package/dist/middleware/security.d.ts +31 -0
- package/dist/middleware/security.js +9 -0
- package/dist/middleware/types.d.ts +45 -0
- package/dist/middleware/types.js +0 -0
- package/dist/middleware/wrappers.d.ts +91 -0
- package/dist/middleware/wrappers.js +32 -0
- package/dist/storage/r2-storage.d.ts +38 -0
- package/dist/storage/r2-storage.js +105 -0
- package/dist/system/cpu.d.ts +2 -0
- package/dist/system/cpu.js +9 -0
- package/dist/system/disk.d.ts +2 -0
- package/dist/system/disk.js +9 -0
- package/dist/system/environment.d.ts +8 -0
- package/dist/system/environment.js +9 -0
- package/dist/system/health-check.d.ts +26 -0
- package/dist/system/health-check.js +10 -0
- package/dist/system/index.d.ts +51 -0
- package/dist/system/index.js +194 -0
- package/dist/system/memory.d.ts +2 -0
- package/dist/system/memory.js +9 -0
- package/dist/system/network.d.ts +2 -0
- package/dist/system/network.js +9 -0
- package/dist/system/types.d.ts +93 -0
- package/dist/system/types.js +0 -0
- package/dist/system/utils.d.ts +12 -0
- package/dist/system/utils.js +26 -0
- package/dist/types/api.d.ts +80 -0
- package/dist/types/api.js +0 -0
- package/dist/types/database.d.ts +38 -0
- package/dist/types/database.js +0 -0
- package/dist/types/env.d.ts +105 -0
- package/dist/types/env.js +0 -0
- package/dist/types/geoip.d.ts +152 -0
- package/dist/types/geoip.js +0 -0
- package/dist/types/i18n.d.ts +11 -0
- package/dist/types/i18n.js +0 -0
- package/dist/types/qr-code.d.ts +139 -0
- package/dist/types/qr-code.js +75 -0
- package/dist/types/user.d.ts +54 -0
- package/dist/types/user.js +0 -0
- package/dist/utils/api-helpers.d.ts +147 -0
- package/dist/utils/api-helpers.js +30 -0
- package/dist/utils/client/client-utils.d.ts +3 -0
- package/dist/utils/client/client-utils.js +9 -0
- package/dist/utils/client/qr-code.d.ts +16 -0
- package/dist/utils/client/qr-code.js +215 -0
- package/dist/utils/cors.d.ts +40 -0
- package/dist/utils/cors.js +21 -0
- package/dist/utils/csv-export.d.ts +97 -0
- package/dist/utils/csv-export.js +20 -0
- package/dist/utils/error-message-formatter.d.ts +17 -0
- package/dist/utils/error-message-formatter.js +11 -0
- package/dist/utils/error-processor.d.ts +70 -0
- package/dist/utils/error-processor.js +34 -0
- package/dist/utils/format-number.d.ts +17 -0
- package/dist/utils/format-number.js +9 -0
- package/dist/utils/index.d.ts +13 -0
- package/dist/utils/index.js +160 -0
- package/dist/utils/input-validation.d.ts +88 -0
- package/dist/utils/input-validation.js +223 -0
- package/dist/utils/ip-utils.d.ts +15 -0
- package/dist/utils/ip-utils.js +91 -0
- package/dist/utils/optimistic-lock.d.ts +27 -0
- package/dist/utils/optimistic-lock.js +16 -0
- package/dist/utils/sanitizer.d.ts +72 -0
- package/dist/utils/sanitizer.js +19 -0
- package/dist/utils/shared-utils.d.ts +25 -0
- package/dist/utils/shared-utils.js +43 -0
- package/dist/utils/short-code-generator.d.ts +24 -0
- package/dist/utils/short-code-generator.js +9 -0
- package/dist/utils/timezone.d.ts +56 -0
- package/dist/utils/timezone.js +29 -0
- package/dist/utils/type-guards.d.ts +164 -0
- package/dist/utils/type-guards.js +59 -0
- package/dist/utils/url-normalizer.d.ts +53 -0
- package/dist/utils/url-normalizer.js +21 -0
- package/dist/validators/index.d.ts +7 -0
- package/dist/validators/index.js +13 -0
- package/dist/validators/password-validator.d.ts +86 -0
- package/dist/validators/password-validator.js +13 -0
- package/dist/world_countries-C2WUL2CQ.js +279 -0
- package/package.json +129 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MiddlewareChain
|
|
3
|
+
} from "./chunk-4ODT3Q4A.js";
|
|
4
|
+
import {
|
|
5
|
+
rateLimitMiddleware
|
|
6
|
+
} from "./chunk-H5I5GWAA.js";
|
|
7
|
+
import {
|
|
8
|
+
responseLoggerMiddleware
|
|
9
|
+
} from "./chunk-KAWVMIRJ.js";
|
|
10
|
+
import {
|
|
11
|
+
securityMiddleware
|
|
12
|
+
} from "./chunk-WSQMXMTL.js";
|
|
13
|
+
import {
|
|
14
|
+
adminMiddleware,
|
|
15
|
+
authMiddleware,
|
|
16
|
+
optionalAuthMiddleware
|
|
17
|
+
} from "./chunk-UXQRU3EM.js";
|
|
18
|
+
import {
|
|
19
|
+
corsMiddleware
|
|
20
|
+
} from "./chunk-FOKAATUQ.js";
|
|
21
|
+
import {
|
|
22
|
+
errorHandlerMiddleware
|
|
23
|
+
} from "./chunk-TMVS4F7E.js";
|
|
24
|
+
import {
|
|
25
|
+
initRequestMiddleware
|
|
26
|
+
} from "./chunk-62Q7DN5G.js";
|
|
27
|
+
|
|
28
|
+
// src/middleware/wrappers.ts
|
|
29
|
+
function withPublicApi(handler) {
|
|
30
|
+
const chain = new MiddlewareChain().use(errorHandlerMiddleware).use(securityMiddleware).use(corsMiddleware).use(initRequestMiddleware).use(rateLimitMiddleware.api).use(responseLoggerMiddleware);
|
|
31
|
+
return async (request, props) => {
|
|
32
|
+
const context = {
|
|
33
|
+
request,
|
|
34
|
+
locale: "ko",
|
|
35
|
+
requestId: "",
|
|
36
|
+
startTime: Date.now(),
|
|
37
|
+
metadata: {}
|
|
38
|
+
};
|
|
39
|
+
return await chain.execute(context, handler, props);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function withAuthApi(handler) {
|
|
43
|
+
const chain = new MiddlewareChain().use(errorHandlerMiddleware).use(securityMiddleware).use(corsMiddleware).use(initRequestMiddleware).use(authMiddleware).use(rateLimitMiddleware.api).use(responseLoggerMiddleware);
|
|
44
|
+
return async (request, props) => {
|
|
45
|
+
const context = {
|
|
46
|
+
request,
|
|
47
|
+
locale: "ko",
|
|
48
|
+
requestId: "",
|
|
49
|
+
startTime: Date.now(),
|
|
50
|
+
metadata: {}
|
|
51
|
+
};
|
|
52
|
+
return await chain.execute(context, handler, props);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function withAdminApi(handler) {
|
|
56
|
+
const chain = new MiddlewareChain().use(errorHandlerMiddleware).use(securityMiddleware).use(corsMiddleware).use(initRequestMiddleware).use(authMiddleware).use(adminMiddleware).use(rateLimitMiddleware.admin).use(responseLoggerMiddleware);
|
|
57
|
+
return async (request, props) => {
|
|
58
|
+
const context = {
|
|
59
|
+
request,
|
|
60
|
+
locale: "ko",
|
|
61
|
+
requestId: "",
|
|
62
|
+
startTime: Date.now(),
|
|
63
|
+
metadata: {}
|
|
64
|
+
};
|
|
65
|
+
return await chain.execute(context, handler, props);
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function withOptionalAuthApi(handler) {
|
|
69
|
+
const chain = new MiddlewareChain().use(errorHandlerMiddleware).use(securityMiddleware).use(corsMiddleware).use(initRequestMiddleware).use(optionalAuthMiddleware).use(rateLimitMiddleware.api).use(responseLoggerMiddleware);
|
|
70
|
+
return async (request, props) => {
|
|
71
|
+
const context = {
|
|
72
|
+
request,
|
|
73
|
+
locale: "ko",
|
|
74
|
+
requestId: "",
|
|
75
|
+
startTime: Date.now(),
|
|
76
|
+
metadata: {}
|
|
77
|
+
};
|
|
78
|
+
return await chain.execute(context, handler, props);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function withCustomApi(handler, configureChain) {
|
|
82
|
+
const chain = configureChain(new MiddlewareChain());
|
|
83
|
+
return async (request, props) => {
|
|
84
|
+
const context = {
|
|
85
|
+
request,
|
|
86
|
+
locale: "ko",
|
|
87
|
+
requestId: "",
|
|
88
|
+
startTime: Date.now(),
|
|
89
|
+
metadata: {}
|
|
90
|
+
};
|
|
91
|
+
return await chain.execute(context, handler, props);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
withPublicApi,
|
|
97
|
+
withAuthApi,
|
|
98
|
+
withAdminApi,
|
|
99
|
+
withOptionalAuthApi,
|
|
100
|
+
withCustomApi
|
|
101
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__spreadValues
|
|
3
|
+
} from "./chunk-ORMEWXMH.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/sanitizer.ts
|
|
6
|
+
function sanitizeHtml(input) {
|
|
7
|
+
if (!input || typeof input !== "string") {
|
|
8
|
+
return "";
|
|
9
|
+
}
|
|
10
|
+
return input.replace(/<[^>]*>/g, "").replace(/</gi, "<").replace(/>/gi, ">").replace(/<[^>]*>/g, "").replace(/&/gi, "&").replace(/"/gi, '"').replace(/'/gi, "'").replace(///gi, "/").trim();
|
|
11
|
+
}
|
|
12
|
+
function removeEventHandlers(input) {
|
|
13
|
+
if (!input || typeof input !== "string") {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
return input.replace(/\bon\w+\s*=\s*["'][^"']*["']/gi, "");
|
|
17
|
+
}
|
|
18
|
+
function sanitizeUrl(url) {
|
|
19
|
+
if (!url || typeof url !== "string") {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
const trimmedUrl = url.trim().toLowerCase();
|
|
23
|
+
const dangerousProtocols = [
|
|
24
|
+
"javascript:",
|
|
25
|
+
"vbscript:",
|
|
26
|
+
"data:text/html",
|
|
27
|
+
"data:application"
|
|
28
|
+
];
|
|
29
|
+
for (const protocol of dangerousProtocols) {
|
|
30
|
+
if (trimmedUrl.startsWith(protocol)) {
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return url.trim();
|
|
35
|
+
}
|
|
36
|
+
function sanitizeInput(input) {
|
|
37
|
+
if (!input || typeof input !== "string") {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
let result = input;
|
|
41
|
+
result = sanitizeHtml(result);
|
|
42
|
+
result = removeEventHandlers(result);
|
|
43
|
+
result = result.replace(/\s+/g, " ");
|
|
44
|
+
result = result.trim();
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
function sanitizeArray(arr) {
|
|
48
|
+
if (!Array.isArray(arr)) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
return arr.filter((item) => typeof item === "string").map((item) => sanitizeInput(item)).filter((item) => item.length > 0);
|
|
52
|
+
}
|
|
53
|
+
function sanitizeObjectFields(obj, fields) {
|
|
54
|
+
const result = __spreadValues({}, obj);
|
|
55
|
+
for (const field of fields) {
|
|
56
|
+
const value = result[field];
|
|
57
|
+
if (typeof value === "string") {
|
|
58
|
+
result[field] = sanitizeInput(value);
|
|
59
|
+
} else if (Array.isArray(value)) {
|
|
60
|
+
result[field] = sanitizeArray(value);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
var sanitizer_default = {
|
|
66
|
+
sanitizeHtml,
|
|
67
|
+
sanitizeUrl,
|
|
68
|
+
sanitizeInput,
|
|
69
|
+
sanitizeArray,
|
|
70
|
+
sanitizeObjectFields,
|
|
71
|
+
removeEventHandlers
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
sanitizeHtml,
|
|
76
|
+
removeEventHandlers,
|
|
77
|
+
sanitizeUrl,
|
|
78
|
+
sanitizeInput,
|
|
79
|
+
sanitizeArray,
|
|
80
|
+
sanitizeObjectFields,
|
|
81
|
+
sanitizer_default
|
|
82
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/cache/cache-types.ts
|
|
2
|
+
var DEFAULT_INMEMORY_CONFIG = {
|
|
3
|
+
maxSize: 1e5,
|
|
4
|
+
maxMemoryMB: 200,
|
|
5
|
+
evictionPolicy: "lru",
|
|
6
|
+
cleanupInterval: 6e4,
|
|
7
|
+
defaultTTL: 3600
|
|
8
|
+
};
|
|
9
|
+
var DEFAULT_HYBRID_CONFIG = {
|
|
10
|
+
backend: "hybrid",
|
|
11
|
+
fallbackOnRedisError: true,
|
|
12
|
+
writeToMemoryOnRedisError: true,
|
|
13
|
+
inmemory: DEFAULT_INMEMORY_CONFIG
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
DEFAULT_INMEMORY_CONFIG,
|
|
18
|
+
DEFAULT_HYBRID_CONFIG
|
|
19
|
+
};
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JWTError
|
|
3
|
+
} from "./chunk-AIH3F7JV.js";
|
|
4
|
+
|
|
5
|
+
// src/auth/core/jwt/index.ts
|
|
6
|
+
import { SignJWT, jwtVerify } from "jose";
|
|
7
|
+
var JWTManager = class {
|
|
8
|
+
constructor(config, logger) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.logger = logger;
|
|
11
|
+
this.secretKey = new TextEncoder().encode(config.secret);
|
|
12
|
+
if (config.secret.length < 32) {
|
|
13
|
+
throw new Error("JWT secret must be at least 32 characters long");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Access JWT 토큰 생성
|
|
18
|
+
*/
|
|
19
|
+
async createAccessToken(payload) {
|
|
20
|
+
try {
|
|
21
|
+
const jwt = await new SignJWT(payload).setProtectedHeader({ alg: this.config.algorithm }).setIssuedAt().setExpirationTime(this.config.accessTokenExpiry).sign(this.secretKey);
|
|
22
|
+
this.logger.debug("Access token created successfully", {
|
|
23
|
+
userId: payload.userId,
|
|
24
|
+
expiresIn: this.config.accessTokenExpiry
|
|
25
|
+
});
|
|
26
|
+
return jwt;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
this.logger.error("Failed to create access token", { error, payload });
|
|
29
|
+
throw new JWTError(
|
|
30
|
+
"Access token creation failed",
|
|
31
|
+
"TOKEN_CREATION_FAILED"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Refresh 토큰 생성
|
|
37
|
+
*/
|
|
38
|
+
async createRefreshToken(userId) {
|
|
39
|
+
try {
|
|
40
|
+
const payload = {
|
|
41
|
+
userId,
|
|
42
|
+
tokenType: "refresh"
|
|
43
|
+
};
|
|
44
|
+
const jwt = await new SignJWT(payload).setProtectedHeader({ alg: this.config.algorithm }).setIssuedAt().setExpirationTime(this.config.refreshTokenExpiry).sign(this.secretKey);
|
|
45
|
+
this.logger.debug("Refresh token created successfully", {
|
|
46
|
+
userId,
|
|
47
|
+
expiresIn: this.config.refreshTokenExpiry
|
|
48
|
+
});
|
|
49
|
+
return jwt;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
this.logger.error("Failed to create refresh token", { error, userId });
|
|
52
|
+
throw new JWTError(
|
|
53
|
+
"Refresh token creation failed",
|
|
54
|
+
"TOKEN_CREATION_FAILED"
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 토큰 쌍 생성 (Access + Refresh)
|
|
60
|
+
*/
|
|
61
|
+
async createTokenPair(user) {
|
|
62
|
+
try {
|
|
63
|
+
const [accessToken, refreshToken] = await Promise.all([
|
|
64
|
+
this.createAccessToken({
|
|
65
|
+
id: user.id,
|
|
66
|
+
userId: user.id,
|
|
67
|
+
email: user.email,
|
|
68
|
+
role: user.role,
|
|
69
|
+
emailVerified: user.emailVerified
|
|
70
|
+
}),
|
|
71
|
+
this.createRefreshToken(user.id)
|
|
72
|
+
]);
|
|
73
|
+
this.logger.debug("Token pair created successfully", { userId: user.id });
|
|
74
|
+
return { accessToken, refreshToken };
|
|
75
|
+
} catch (error) {
|
|
76
|
+
this.logger.error("Failed to create token pair", {
|
|
77
|
+
error,
|
|
78
|
+
userId: user.id
|
|
79
|
+
});
|
|
80
|
+
throw new JWTError("Token pair creation failed", "TOKEN_CREATION_FAILED");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Access JWT 토큰 검증
|
|
85
|
+
*/
|
|
86
|
+
async verifyAccessToken(token) {
|
|
87
|
+
try {
|
|
88
|
+
const { payload } = await jwtVerify(token, this.secretKey, {
|
|
89
|
+
algorithms: [this.config.algorithm]
|
|
90
|
+
});
|
|
91
|
+
const userId = payload.userId || payload.sub || payload.id;
|
|
92
|
+
if (!userId || !payload.email || !payload.role) {
|
|
93
|
+
throw new JWTError("Invalid JWT payload structure", "INVALID_PAYLOAD");
|
|
94
|
+
}
|
|
95
|
+
this.logger.debug("Access token verified successfully", {
|
|
96
|
+
userId
|
|
97
|
+
});
|
|
98
|
+
return {
|
|
99
|
+
id: userId,
|
|
100
|
+
userId,
|
|
101
|
+
email: payload.email,
|
|
102
|
+
role: payload.role,
|
|
103
|
+
emailVerified: payload.emailVerified,
|
|
104
|
+
tokenType: payload.tokenType,
|
|
105
|
+
iat: payload.iat,
|
|
106
|
+
exp: payload.exp
|
|
107
|
+
};
|
|
108
|
+
} catch (error) {
|
|
109
|
+
this.logger.error("Failed to verify access token", {
|
|
110
|
+
error: error.message,
|
|
111
|
+
token: token.substring(0, 20) + "..."
|
|
112
|
+
});
|
|
113
|
+
if (error.code === "ERR_JWT_EXPIRED") {
|
|
114
|
+
throw new JWTError("Token has expired", "TOKEN_EXPIRED");
|
|
115
|
+
}
|
|
116
|
+
throw new JWTError(
|
|
117
|
+
"Token verification failed",
|
|
118
|
+
"TOKEN_VERIFICATION_FAILED"
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Refresh 토큰 검증
|
|
124
|
+
*/
|
|
125
|
+
async verifyRefreshToken(token) {
|
|
126
|
+
try {
|
|
127
|
+
const { payload } = await jwtVerify(token, this.secretKey, {
|
|
128
|
+
algorithms: [this.config.algorithm]
|
|
129
|
+
});
|
|
130
|
+
const userId = payload.userId || payload.sub || payload.id;
|
|
131
|
+
if (!userId || payload.tokenType !== "refresh") {
|
|
132
|
+
throw new JWTError(
|
|
133
|
+
"Invalid refresh token payload structure",
|
|
134
|
+
"INVALID_PAYLOAD"
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
this.logger.debug("Refresh token verified successfully", {
|
|
138
|
+
userId
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
userId,
|
|
142
|
+
tokenType: payload.tokenType
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
this.logger.error("Failed to verify refresh token", {
|
|
146
|
+
error: error.message,
|
|
147
|
+
token: token.substring(0, 20) + "..."
|
|
148
|
+
});
|
|
149
|
+
if (error.code === "ERR_JWT_EXPIRED") {
|
|
150
|
+
throw new JWTError(
|
|
151
|
+
"Refresh token has expired",
|
|
152
|
+
"REFRESH_TOKEN_EXPIRED"
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
throw new JWTError(
|
|
156
|
+
"Refresh token verification failed",
|
|
157
|
+
"TOKEN_VERIFICATION_FAILED"
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Authorization 헤더에서 토큰 추출
|
|
163
|
+
*/
|
|
164
|
+
extractTokenFromHeader(authHeader) {
|
|
165
|
+
if (!authHeader) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const parts = authHeader.split(" ");
|
|
169
|
+
if (parts.length !== 2 || parts[0] !== "Bearer") {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
return parts[1];
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 토큰 만료 여부 확인
|
|
176
|
+
*/
|
|
177
|
+
isTokenExpired(payload) {
|
|
178
|
+
if (!payload.exp) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
const currentTime = Math.floor(Date.now() / 1e3);
|
|
182
|
+
return payload.exp < currentTime;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* 토큰 남은 시간 (초)
|
|
186
|
+
*/
|
|
187
|
+
getTokenRemainingTime(payload) {
|
|
188
|
+
if (!payload.exp) {
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
const currentTime = Math.floor(Date.now() / 1e3);
|
|
192
|
+
const remainingTime = payload.exp - currentTime;
|
|
193
|
+
return Math.max(0, remainingTime);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* 토큰에서 사용자 정보 추출
|
|
197
|
+
*/
|
|
198
|
+
extractUserFromPayload(payload) {
|
|
199
|
+
return {
|
|
200
|
+
id: payload.userId,
|
|
201
|
+
email: payload.email,
|
|
202
|
+
role: payload.role
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
var JWTService = class {
|
|
207
|
+
constructor(config) {
|
|
208
|
+
const logger = {
|
|
209
|
+
debug: () => {
|
|
210
|
+
},
|
|
211
|
+
// 테스트에서는 로그 출력 안 함
|
|
212
|
+
info: () => {
|
|
213
|
+
},
|
|
214
|
+
warn: () => {
|
|
215
|
+
},
|
|
216
|
+
error: (message, meta) => {
|
|
217
|
+
if (process.env.NODE_ENV === "test") {
|
|
218
|
+
console.error("[JWTService Error]", message, meta);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
this.manager = new JWTManager(config, logger);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Access 토큰 생성 (sign으로 alias)
|
|
226
|
+
*/
|
|
227
|
+
async sign(payload) {
|
|
228
|
+
return this.manager.createAccessToken(payload);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* 토큰 검증
|
|
232
|
+
*/
|
|
233
|
+
async verify(token) {
|
|
234
|
+
return this.manager.verifyAccessToken(token);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Refresh 토큰 생성
|
|
238
|
+
*/
|
|
239
|
+
async createRefreshToken(userId) {
|
|
240
|
+
return this.manager.createRefreshToken(userId);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Refresh 토큰 검증
|
|
244
|
+
*/
|
|
245
|
+
async verifyRefreshToken(token) {
|
|
246
|
+
return this.manager.verifyRefreshToken(token);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 토큰 쌍 생성
|
|
250
|
+
*/
|
|
251
|
+
async createTokenPair(user) {
|
|
252
|
+
return this.manager.createTokenPair(user);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Access 토큰 생성
|
|
256
|
+
*/
|
|
257
|
+
async createAccessToken(payload) {
|
|
258
|
+
return this.manager.createAccessToken(payload);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Access 토큰 검증
|
|
262
|
+
*/
|
|
263
|
+
async verifyAccessToken(token) {
|
|
264
|
+
return this.manager.verifyAccessToken(token);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Authorization 헤더에서 토큰 추출
|
|
268
|
+
*/
|
|
269
|
+
extractTokenFromHeader(authHeader) {
|
|
270
|
+
return this.manager.extractTokenFromHeader(authHeader != null ? authHeader : null);
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
export {
|
|
275
|
+
JWTManager,
|
|
276
|
+
JWTService
|
|
277
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// src/utils/format-number.ts
|
|
2
|
+
function formatNumber(num) {
|
|
3
|
+
if (num === null || num === void 0) {
|
|
4
|
+
return "-";
|
|
5
|
+
}
|
|
6
|
+
const numericValue = typeof num === "string" ? parseFloat(num) : num;
|
|
7
|
+
if (isNaN(numericValue)) {
|
|
8
|
+
return "NaN";
|
|
9
|
+
}
|
|
10
|
+
if (!isFinite(numericValue)) {
|
|
11
|
+
return numericValue > 0 ? "Infinity" : "-Infinity";
|
|
12
|
+
}
|
|
13
|
+
const isNegative = numericValue < 0;
|
|
14
|
+
const absNum = Math.abs(numericValue);
|
|
15
|
+
if (absNum < 1e3) {
|
|
16
|
+
return numericValue.toString();
|
|
17
|
+
}
|
|
18
|
+
if (absNum < 1e6) {
|
|
19
|
+
return numericValue.toLocaleString();
|
|
20
|
+
}
|
|
21
|
+
if (absNum < 1e7) {
|
|
22
|
+
return numericValue.toLocaleString();
|
|
23
|
+
}
|
|
24
|
+
const formatted = (absNum / 1e6).toFixed(1) + "M";
|
|
25
|
+
return isNegative ? "-" + formatted : formatted;
|
|
26
|
+
}
|
|
27
|
+
function formatChartNumber(num) {
|
|
28
|
+
return formatNumber(num);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
formatNumber,
|
|
33
|
+
formatChartNumber
|
|
34
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__spreadValues
|
|
3
|
+
} from "./chunk-ORMEWXMH.js";
|
|
4
|
+
|
|
5
|
+
// src/error/recovery/degradation.ts
|
|
6
|
+
var FeatureDegradation = class {
|
|
7
|
+
/**
|
|
8
|
+
* 기능 실행 (실패해도 앱은 계속)
|
|
9
|
+
*/
|
|
10
|
+
static async execute(featureName, fn, fallbackValue) {
|
|
11
|
+
try {
|
|
12
|
+
const data = await fn();
|
|
13
|
+
return {
|
|
14
|
+
success: true,
|
|
15
|
+
data
|
|
16
|
+
};
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.warn(`[FeatureDegradation] Feature "${featureName}" failed:`, error);
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
data: fallbackValue,
|
|
22
|
+
error
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 여러 기능을 병렬로 실행 (일부 실패해도 계속)
|
|
28
|
+
*/
|
|
29
|
+
static async executeAll(features) {
|
|
30
|
+
const promises = features.map(
|
|
31
|
+
(feature) => this.execute(feature.name, feature.fn, feature.fallbackValue).then(
|
|
32
|
+
(result) => __spreadValues({
|
|
33
|
+
name: feature.name
|
|
34
|
+
}, result)
|
|
35
|
+
)
|
|
36
|
+
);
|
|
37
|
+
return await Promise.all(promises);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 타임아웃 포함 실행
|
|
41
|
+
*/
|
|
42
|
+
static async executeWithTimeout(featureName, fn, timeoutMs, fallbackValue) {
|
|
43
|
+
try {
|
|
44
|
+
const data = await Promise.race([
|
|
45
|
+
fn(),
|
|
46
|
+
new Promise(
|
|
47
|
+
(_, reject) => setTimeout(() => reject(new Error("Timeout")), timeoutMs)
|
|
48
|
+
)
|
|
49
|
+
]);
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
data
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
const timedOut = error instanceof Error && error.message === "Timeout";
|
|
56
|
+
console.warn(
|
|
57
|
+
`[FeatureDegradation] Feature "${featureName}" ${timedOut ? "timed out" : "failed"}:`,
|
|
58
|
+
error
|
|
59
|
+
);
|
|
60
|
+
return {
|
|
61
|
+
success: false,
|
|
62
|
+
data: fallbackValue,
|
|
63
|
+
error,
|
|
64
|
+
timedOut
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
FeatureDegradation
|
|
72
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getErrorMessage
|
|
3
|
+
} from "./chunk-EEUBKZV4.js";
|
|
4
|
+
import {
|
|
5
|
+
AppError
|
|
6
|
+
} from "./chunk-MLGO3HLS.js";
|
|
7
|
+
import {
|
|
8
|
+
ERROR_CODES
|
|
9
|
+
} from "./chunk-Y3OTJH2S.js";
|
|
10
|
+
import {
|
|
11
|
+
logger
|
|
12
|
+
} from "./chunk-EZR55KV2.js";
|
|
13
|
+
import {
|
|
14
|
+
__spreadValues
|
|
15
|
+
} from "./chunk-ORMEWXMH.js";
|
|
16
|
+
|
|
17
|
+
// src/middleware/error-handler.ts
|
|
18
|
+
import { NextResponse } from "next/server";
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
var errorHandlerMiddleware = async (context, next) => {
|
|
21
|
+
var _a, _b;
|
|
22
|
+
try {
|
|
23
|
+
return await next();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (error instanceof AppError) {
|
|
26
|
+
return createErrorResponse(
|
|
27
|
+
error.code,
|
|
28
|
+
error.message,
|
|
29
|
+
context.locale,
|
|
30
|
+
context.requestId,
|
|
31
|
+
error.details
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (error instanceof z.ZodError) {
|
|
35
|
+
const issues = error.errors.map((e) => ({
|
|
36
|
+
path: e.path.join("."),
|
|
37
|
+
message: e.message,
|
|
38
|
+
code: e.code
|
|
39
|
+
}));
|
|
40
|
+
const firstMessage = ((_a = issues[0]) == null ? void 0 : _a.message) || "Validation failed";
|
|
41
|
+
return createErrorResponse(
|
|
42
|
+
ERROR_CODES.VALIDATION_ERROR.code,
|
|
43
|
+
firstMessage,
|
|
44
|
+
context.locale,
|
|
45
|
+
context.requestId,
|
|
46
|
+
{ issues }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
logger.error("[ErrorHandler] Unexpected error:", error);
|
|
50
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
51
|
+
const safeMessage = isProduction ? "Internal server error" : error instanceof Error ? error.message : "Unknown error";
|
|
52
|
+
return createErrorResponse(
|
|
53
|
+
ERROR_CODES.INTERNAL_SERVER_ERROR.code,
|
|
54
|
+
safeMessage,
|
|
55
|
+
context.locale,
|
|
56
|
+
context.requestId,
|
|
57
|
+
// 개발 환경에서만 스택 트레이스 포함
|
|
58
|
+
!isProduction && error instanceof Error ? { stack: (_b = error.stack) == null ? void 0 : _b.split("\n").slice(0, 5) } : void 0
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function createErrorResponse(code, message, locale, requestId, metadata) {
|
|
63
|
+
const userMessage = getErrorMessage(code, locale);
|
|
64
|
+
const httpStatus = Math.floor(code / 100);
|
|
65
|
+
const errorResponse = {
|
|
66
|
+
success: false,
|
|
67
|
+
error: __spreadValues({
|
|
68
|
+
code,
|
|
69
|
+
message,
|
|
70
|
+
userMessage: {
|
|
71
|
+
title: userMessage.title,
|
|
72
|
+
description: userMessage.description,
|
|
73
|
+
action: userMessage.action
|
|
74
|
+
},
|
|
75
|
+
requestId
|
|
76
|
+
}, metadata && { metadata })
|
|
77
|
+
};
|
|
78
|
+
return NextResponse.json(errorResponse, {
|
|
79
|
+
status: httpStatus,
|
|
80
|
+
headers: {
|
|
81
|
+
"Content-Type": "application/json"
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
errorHandlerMiddleware
|
|
88
|
+
};
|