@withwiz/toolkit 0.11.0 → 0.13.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.
Files changed (84) hide show
  1. package/README.md +6 -0
  2. package/dist/chunk-4JZIIMAF.js +33 -0
  3. package/dist/{chunk-XQIAXMRY.js → chunk-5VZIAXO2.js} +2 -1
  4. package/dist/{chunk-MJOXTFIC.js → chunk-7Q6SMNMN.js} +2 -2
  5. package/dist/{chunk-4Y5MRUMX.js → chunk-A6NIKJX5.js} +3 -3
  6. package/dist/{chunk-DISEIUYD.js → chunk-AQQ7JSS5.js} +1 -1
  7. package/dist/{chunk-BRFW2LL2.js → chunk-D4QADM6T.js} +2 -2
  8. package/dist/{chunk-RWENSBNW.js → chunk-G4IGD3AZ.js} +30 -10
  9. package/dist/{chunk-4TGPAUJV.js → chunk-K7OZWWIS.js} +2 -2
  10. package/dist/{chunk-23LQJYZN.js → chunk-KAS5ILUM.js} +1 -1
  11. package/dist/{chunk-YBVZ5UVC.js → chunk-L4WQRYMR.js} +3 -3
  12. package/dist/{chunk-QBXNL6QU.js → chunk-LYO2HV5F.js} +3 -3
  13. package/dist/{chunk-TRGFXIEF.js → chunk-M4ZVQFOH.js} +2 -2
  14. package/dist/{chunk-ATAQRXTH.js → chunk-MCPPJI3T.js} +1 -1
  15. package/dist/{chunk-AYCXN6QJ.js → chunk-NHFIOK2D.js} +2 -2
  16. package/dist/{chunk-ZEHNCHIV.js → chunk-NKZPMRVF.js} +1 -1
  17. package/dist/{chunk-Y6CPPBJI.js → chunk-QVPGBTCL.js} +1 -1
  18. package/dist/{chunk-2QO7YXTF.js → chunk-QVU4BHMC.js} +1 -1
  19. package/dist/{chunk-XF3WUF3F.js → chunk-ROJJJXRL.js} +2 -2
  20. package/dist/{chunk-NAFMJT62.js → chunk-TDRB5BIM.js} +7 -7
  21. package/dist/{chunk-WYA763JL.js → chunk-TGEKWTFZ.js} +1 -1
  22. package/dist/{chunk-HV6A6Z5R.js → chunk-UGLEAXTY.js} +3 -3
  23. package/dist/{chunk-5S7M2AJL.js → chunk-W2FBLCOR.js} +1 -1
  24. package/dist/{chunk-7IOAGJMK.js → chunk-YOIZUVRD.js} +3 -3
  25. package/dist/{chunk-2GK4LDPV.js → chunk-Z3OLZKTN.js} +2 -2
  26. package/dist/{chunk-JRORMRVN.js → chunk-ZVGEGDYF.js} +1 -1
  27. package/dist/core/api-key/api-key.service.d.ts +1 -0
  28. package/dist/core/api-key/api-key.service.js +2 -1
  29. package/dist/core/api-key/errors.d.ts +21 -0
  30. package/dist/core/api-key/errors.js +11 -0
  31. package/dist/core/api-key/index.d.ts +1 -0
  32. package/dist/core/api-key/index.js +11 -3
  33. package/dist/core/auth/index.js +29 -29
  34. package/dist/core/auth/oauth/index.js +7 -7
  35. package/dist/core/auth/oauth/providers/index.js +6 -6
  36. package/dist/core/auth/services/index.js +7 -7
  37. package/dist/core/cache/cache-config.js +4 -4
  38. package/dist/core/cache/cache-env.js +3 -3
  39. package/dist/core/cache/cache-factory.js +9 -9
  40. package/dist/core/cache/cache-invalidation.js +10 -10
  41. package/dist/core/cache/cache-redis.js +4 -4
  42. package/dist/core/cache/cache-wrapper.js +10 -10
  43. package/dist/core/cache/cache.js +13 -13
  44. package/dist/core/cache/config.js +2 -2
  45. package/dist/core/cache/hybrid-cache-manager.js +5 -5
  46. package/dist/core/cache/index.js +13 -13
  47. package/dist/core/cache/noop-cache-manager.js +5 -5
  48. package/dist/core/cache/redis-cache-manager.js +5 -5
  49. package/dist/core/constants/error-codes.js +1 -1
  50. package/dist/core/constants/index.js +1 -1
  51. package/dist/core/error/app-error.js +2 -2
  52. package/dist/core/error/friendly-messages-v2.js +2 -2
  53. package/dist/core/error/friendly-messages.js +1 -1
  54. package/dist/core/error/index.js +3 -3
  55. package/dist/core/geolocation/index.js +7 -7
  56. package/dist/core/geolocation/providers/index.js +7 -7
  57. package/dist/core/storage/r2-storage.js +2 -2
  58. package/dist/core/system/environment.js +3 -3
  59. package/dist/core/system/health-check.js +3 -3
  60. package/dist/core/system/index.js +7 -7
  61. package/dist/core/utils/optimistic-lock.js +2 -2
  62. package/dist/core/utils/startup-banner.d.ts +56 -0
  63. package/dist/core/utils/startup-banner.js +78 -0
  64. package/dist/initialize.js +10 -10
  65. package/dist/next/auth-handlers/index.js +18 -18
  66. package/dist/next/auth-handlers/oauth-authorize.handler.js +4 -4
  67. package/dist/next/auth-handlers/oauth-callback.handler.js +5 -5
  68. package/dist/next/error/error-handler.js +3 -3
  69. package/dist/next/error/index.js +4 -4
  70. package/dist/next/middleware/auth.js +3 -3
  71. package/dist/next/middleware/error-handler.js +4 -4
  72. package/dist/next/middleware/index.js +7 -7
  73. package/dist/next/middleware/rate-limit.js +3 -3
  74. package/dist/next/middleware/wrappers.js +7 -7
  75. package/dist/next/oapi/api-key-auth.js +4 -3
  76. package/dist/next/oapi/index.js +4 -3
  77. package/dist/next/utils/api-helpers.js +2 -2
  78. package/dist/next/utils/error-processor.js +3 -3
  79. package/dist/next/utils/index.js +17 -17
  80. package/package.json +3 -1
  81. package/dist/{chunk-MXWSG6ER.js → chunk-KYUJ6D65.js} +0 -0
  82. package/dist/{chunk-VDRLJU6C.js → chunk-Q5RPNLET.js} +6 -6
  83. package/dist/{chunk-7KIM5MHV.js → chunk-RHYETIUR.js} +3 -3
  84. package/dist/{chunk-UQ3Z3ZAF.js → chunk-V3GEYUBG.js} +6 -6
package/README.md CHANGED
@@ -8,6 +8,7 @@ Shared utility library for [withwiz](https://github.com/greeun) projects — a c
8
8
 
9
9
  - **Composition root** — assemble every tier's configuration at once with a single `initialize()`
10
10
  - **Framework tiers** — dependencies split across three tiers: `core` / `next` / `prisma` (0.8+)
11
+ - **API key** — framework/DB-agnostic API key core (generation with sha256-hashed storage, validation FSM, IP whitelist, plan limits, typed errors) over injectable ports, plus an x-api-key auth middleware and OpenAPI spec builder for Next.js (`next/oapi`)
11
12
  - **Auth** — JWT, password hashing, OAuth helpers (Google / GitHub / Kakao / Microsoft / Meta), state-cookie CSRF binding, Prisma adapter
12
13
  - **Cache** — Redis / in-memory / hybrid / noop backends, factory, invalidation, defaults
13
14
  - **Constants** — Error codes, messages, pagination, security constants
@@ -141,6 +142,10 @@ and the 0.7.0 / 0.8.0 entries in [`CHANGELOG.md`](CHANGELOG.md).
141
142
 
142
143
  | Subpath | Description |
143
144
  |---|---|
145
+ | `/core/api-key` | API key core barrel (service + generator + validate + ip-whitelist + errors) |
146
+ | `/core/api-key/api-key.service` | `ApiKeyService` — generate / validate / CRUD / regenerate over injected ports |
147
+ | `/core/api-key/errors` | `ApiKeyError`, `API_KEY_ERROR_CODES`, `isApiKeyError` structural guard |
148
+ | `/core/api-key/{types,ports,key-generator,ip-whitelist,validate}` | Pure types, DI ports, and helpers |
144
149
  | `/core/auth` | Full auth (JWT + password + OAuth + services + email + types) |
145
150
  | `/core/auth/jwt` | JWT sign / verify |
146
151
  | `/core/auth/password` | bcrypt helpers |
@@ -172,6 +177,7 @@ and the 0.7.0 / 0.8.0 entries in [`CHANGELOG.md`](CHANGELOG.md).
172
177
  | `/next/auth-handlers` | Route handlers (login / refresh / oauth callback / me) |
173
178
  | `/next/auth-types` | Handler types (`NextRequest` signatures) |
174
179
  | `/next/error` | `error-handler` (NextResponse), `LocaleDetector`, `ErrorBoundary` |
180
+ | `/next/oapi` | `createApiKeyAuth` (x-api-key auth middleware), OpenAPI 3.0.3 spec builder, pagination helpers |
175
181
  | `/next/utils` | `api-helpers`, `cors`, `csv-export`, `error-processor` |
176
182
 
177
183
  ### `react` — moved to `@withwiz/ui` (0.8)
@@ -0,0 +1,33 @@
1
+ // src/core/api-key/errors.ts
2
+ var API_KEY_ERROR_CODES = {
3
+ /** 대상 API 키 미존재 */
4
+ NOT_FOUND: "API_KEY_NOT_FOUND",
5
+ /** 비소유자 접근 (admin 우회 제외) */
6
+ OWNERSHIP: "API_KEY_OWNERSHIP",
7
+ /** 제한 플랜(restrictedPlans)의 발급 시도 */
8
+ PLAN_RESTRICTED: "API_KEY_PLAN_RESTRICTED",
9
+ /** 플랜별 활성 키 한도 초과 */
10
+ LIMIT_REACHED: "API_KEY_LIMIT_REACHED"
11
+ };
12
+ var ApiKeyError = class _ApiKeyError extends Error {
13
+ constructor(message, code) {
14
+ super(message);
15
+ this.code = code;
16
+ this.name = "ApiKeyError";
17
+ if (Error.captureStackTrace) {
18
+ Error.captureStackTrace(this, _ApiKeyError);
19
+ }
20
+ }
21
+ };
22
+ function isApiKeyError(error, code) {
23
+ if (!(error instanceof Error) || error.name !== "ApiKeyError" || typeof error.code !== "string") {
24
+ return false;
25
+ }
26
+ return code === void 0 || error.code === code;
27
+ }
28
+
29
+ export {
30
+ API_KEY_ERROR_CODES,
31
+ ApiKeyError,
32
+ isApiKeyError
33
+ };
@@ -94,7 +94,8 @@ var ERROR_CODES = {
94
94
  },
95
95
  // ============================================
96
96
  // Permissions Related (403xx - 01~09)
97
- // Reserved: 40301~40303 (미사용, 향후 세분화 확장용)
97
+ // 40301: next/oapi api-key-auth wire 계약에서 사용 중 (IP 차단·사용량 초과) — 재배정 금지
98
+ // Reserved: 40302~40303 (미사용, 향후 세분화 확장용)
98
99
  // ============================================
99
100
  FORBIDDEN: {
100
101
  code: 40304,
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  AppError
3
- } from "./chunk-ATAQRXTH.js";
3
+ } from "./chunk-MCPPJI3T.js";
4
4
  import {
5
5
  ERROR_CODES
6
- } from "./chunk-XQIAXMRY.js";
6
+ } from "./chunk-5VZIAXO2.js";
7
7
  import {
8
8
  logger
9
9
  } from "./chunk-QAIN3WNN.js";
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  AUTH_ERROR_CODE_MAP
3
- } from "./chunk-AYCXN6QJ.js";
3
+ } from "./chunk-NHFIOK2D.js";
4
4
  import {
5
5
  AppError
6
- } from "./chunk-ATAQRXTH.js";
6
+ } from "./chunk-MCPPJI3T.js";
7
7
  import {
8
8
  getErrorMessage
9
9
  } from "./chunk-7WG7XPXC.js";
10
10
  import {
11
11
  ERROR_CODES,
12
12
  classifyError
13
- } from "./chunk-XQIAXMRY.js";
13
+ } from "./chunk-5VZIAXO2.js";
14
14
  import {
15
15
  logger
16
16
  } from "./chunk-QAIN3WNN.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-MTZXWVW3.js";
4
4
  import {
5
5
  OAuthManager
6
- } from "./chunk-UQ3Z3ZAF.js";
6
+ } from "./chunk-V3GEYUBG.js";
7
7
  import {
8
8
  OAUTH_STATE_COOKIE,
9
9
  clearOAuthStateCookie,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  AppError
3
- } from "./chunk-ATAQRXTH.js";
3
+ } from "./chunk-MCPPJI3T.js";
4
4
  import {
5
5
  ERROR_CODES,
6
6
  formatErrorMessage
7
- } from "./chunk-XQIAXMRY.js";
7
+ } from "./chunk-5VZIAXO2.js";
8
8
  import {
9
9
  logApiRequest,
10
10
  logApiResponse,
@@ -1,6 +1,10 @@
1
1
  import {
2
2
  validateApiKeyRecord
3
3
  } from "./chunk-BTNM5YSU.js";
4
+ import {
5
+ API_KEY_ERROR_CODES,
6
+ ApiKeyError
7
+ } from "./chunk-4JZIIMAF.js";
4
8
  import {
5
9
  generateRawKey,
6
10
  hashKey,
@@ -42,19 +46,28 @@ var ApiKeyService = class {
42
46
  }
43
47
  async requireOwned(id, userId, isAdmin) {
44
48
  const rec = await this.deps.repo.findById(id);
45
- if (!rec) throw new Error("API key not found");
46
- if (!isAdmin && rec.userId !== userId) throw new Error("Unauthorized");
49
+ if (!rec) throw new ApiKeyError("API key not found", API_KEY_ERROR_CODES.NOT_FOUND);
50
+ if (!isAdmin && rec.userId !== userId) throw new ApiKeyError("Unauthorized", API_KEY_ERROR_CODES.OWNERSHIP);
47
51
  return rec;
48
52
  }
53
+ // FREEMIUM 등 제한 플랜은 한도(0) 의존이 아닌 명시 차단 — generate/validate 단일원천
54
+ assertPlanNotRestricted(plan) {
55
+ if (this.deps.env.restrictedPlans.includes(plan)) {
56
+ throw new ApiKeyError(
57
+ `API key is not available for the ${plan} plan. Please upgrade.`,
58
+ API_KEY_ERROR_CODES.PLAN_RESTRICTED
59
+ );
60
+ }
61
+ }
49
62
  async generateApiKey(userId, options, plan) {
50
63
  var _a, _b, _c, _d, _e, _f, _g;
51
64
  const { repo, planConfig, env } = this.deps;
52
- if (env.restrictedPlans.includes(plan)) {
53
- throw new Error(`API key is not available for the ${plan} plan. Please upgrade.`);
54
- }
65
+ this.assertPlanNotRestricted(plan);
55
66
  const maxKeys = await planConfig.getApiKeyLimit(plan);
56
67
  const active = await repo.countActive(userId);
57
- if (active >= maxKeys) throw new Error(`API key limit reached. Max ${maxKeys} keys.`);
68
+ if (active >= maxKeys) {
69
+ throw new ApiKeyError(`API key limit reached. Max ${maxKeys} keys.`, API_KEY_ERROR_CODES.LIMIT_REACHED);
70
+ }
58
71
  const rawKey = generateRawKey(this.prefix(options.environment));
59
72
  const planRate = await planConfig.getRateLimit(plan);
60
73
  const rateLimit = options.customRateLimit ? Math.min(options.customRateLimit, planRate) : planRate;
@@ -88,15 +101,17 @@ var ApiKeyService = class {
88
101
  var _a;
89
102
  const { repo, cache, env } = this.deps;
90
103
  const keyHash = hashKey(rawKey);
91
- const cached = await cache.getValidation(keyHash);
104
+ const cached = await cache.getValidation(keyHash).catch(() => null);
92
105
  if (cached) {
93
106
  const exp = (_a = cached.apiKey) == null ? void 0 : _a.expiresAt;
94
107
  if (!(exp && new Date(exp) < /* @__PURE__ */ new Date())) return cached;
95
- await cache.invalidate(keyHash);
108
+ await cache.invalidate(keyHash).catch(() => {
109
+ });
96
110
  }
97
111
  const record = await repo.findByHash(keyHash);
98
112
  const result = validateApiKeyRecord(record, { freemiumPlans: env.restrictedPlans });
99
- if (result.valid) await cache.setValidation(keyHash, result);
113
+ if (result.valid) await cache.setValidation(keyHash, result).catch(() => {
114
+ });
100
115
  return result;
101
116
  }
102
117
  async getApiKey(id, userId, isAdmin = false) {
@@ -138,9 +153,14 @@ var ApiKeyService = class {
138
153
  async regenerateApiKey(userId, apiKeyId, plan, options = {}) {
139
154
  var _a, _b, _c, _d, _e;
140
155
  const old = await this.requireOwned(apiKeyId, userId, false);
156
+ this.assertPlanNotRestricted(plan);
141
157
  if (!options.keepOldKeyActive) {
142
158
  const max = await this.deps.planConfig.getApiKeyLimit(plan);
143
- if (await this.deps.repo.countActive(userId) >= max) throw new Error(`API key limit reached. Max ${max} keys.`);
159
+ const active = await this.deps.repo.countActive(userId);
160
+ const effective = old.isActive ? active - 1 : active;
161
+ if (effective >= max) {
162
+ throw new ApiKeyError(`API key limit reached. Max ${max} keys.`, API_KEY_ERROR_CODES.LIMIT_REACHED);
163
+ }
144
164
  await this.deps.repo.deactivate(apiKeyId);
145
165
  await this.deps.cache.invalidate(old.key);
146
166
  }
@@ -3,14 +3,14 @@ import {
3
3
  isRedisGloballyDisabled,
4
4
  notifyRedisError,
5
5
  resetRedisGlobalState
6
- } from "./chunk-ZEHNCHIV.js";
6
+ } from "./chunk-NKZPMRVF.js";
7
7
  import {
8
8
  logger
9
9
  } from "./chunk-QAIN3WNN.js";
10
10
  import {
11
11
  getENV,
12
12
  isCacheEnabled
13
- } from "./chunk-HV6A6Z5R.js";
13
+ } from "./chunk-UGLEAXTY.js";
14
14
  import {
15
15
  __spreadValues
16
16
  } from "./chunk-N3ETBM74.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ERROR_CODES,
3
3
  formatErrorMessage
4
- } from "./chunk-XQIAXMRY.js";
4
+ } from "./chunk-5VZIAXO2.js";
5
5
  import {
6
6
  ROLE_DEFAULTS
7
7
  } from "./chunk-7YWUKMZD.js";
@@ -7,12 +7,12 @@ import {
7
7
  import {
8
8
  getAuthConfig
9
9
  } from "./chunk-TQMQ5XXG.js";
10
+ import {
11
+ getResolvedCacheConfig
12
+ } from "./chunk-RHYETIUR.js";
10
13
  import {
11
14
  getCommonConfig
12
15
  } from "./chunk-PX535BHW.js";
13
- import {
14
- getResolvedCacheConfig
15
- } from "./chunk-7KIM5MHV.js";
16
16
 
17
17
  // src/core/system/environment.ts
18
18
  import os from "os";
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  getCacheManager,
3
3
  getEffectiveCacheBackend
4
- } from "./chunk-NAFMJT62.js";
4
+ } from "./chunk-TDRB5BIM.js";
5
5
  import {
6
6
  logger
7
7
  } from "./chunk-QAIN3WNN.js";
8
8
  import {
9
9
  getCacheConfig,
10
10
  getCacheTTL
11
- } from "./chunk-Y6CPPBJI.js";
11
+ } from "./chunk-QVPGBTCL.js";
12
12
  import {
13
13
  isCacheEnabled
14
- } from "./chunk-HV6A6Z5R.js";
14
+ } from "./chunk-UGLEAXTY.js";
15
15
 
16
16
  // src/core/cache/cache-wrapper.ts
17
17
  function getCacheBackendLabel() {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  AppError
3
- } from "./chunk-ATAQRXTH.js";
3
+ } from "./chunk-MCPPJI3T.js";
4
4
  import {
5
5
  ERROR_CODES
6
- } from "./chunk-XQIAXMRY.js";
6
+ } from "./chunk-5VZIAXO2.js";
7
7
  import {
8
8
  logger
9
9
  } from "./chunk-QAIN3WNN.js";
@@ -4,7 +4,7 @@ import {
4
4
  formatErrorMessage,
5
5
  getErrorCategory,
6
6
  getHttpStatus
7
- } from "./chunk-XQIAXMRY.js";
7
+ } from "./chunk-5VZIAXO2.js";
8
8
 
9
9
  // src/core/error/app-error.ts
10
10
  var AppError = class _AppError extends Error {
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  AppError
3
- } from "./chunk-ATAQRXTH.js";
3
+ } from "./chunk-MCPPJI3T.js";
4
4
  import {
5
5
  ERROR_CODES,
6
6
  classifyError,
7
7
  formatErrorMessage,
8
8
  getHttpStatus
9
- } from "./chunk-XQIAXMRY.js";
9
+ } from "./chunk-5VZIAXO2.js";
10
10
  import {
11
11
  logger
12
12
  } from "./chunk-QAIN3WNN.js";
@@ -7,7 +7,7 @@ import {
7
7
  getEnv,
8
8
  isCacheEnabled,
9
9
  validateRedisEnvironment
10
- } from "./chunk-HV6A6Z5R.js";
10
+ } from "./chunk-UGLEAXTY.js";
11
11
 
12
12
  // src/core/cache/cache-redis.ts
13
13
  import { Redis } from "@upstash/redis";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getENV,
3
3
  isCacheEnabled
4
- } from "./chunk-HV6A6Z5R.js";
4
+ } from "./chunk-UGLEAXTY.js";
5
5
 
6
6
  // src/core/cache/cache-config.ts
7
7
  var getCacheConfig = {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  cache,
3
3
  geoCache
4
- } from "./chunk-NAFMJT62.js";
4
+ } from "./chunk-TDRB5BIM.js";
5
5
 
6
6
  // src/core/cache/cache-invalidation.ts
7
7
  var invalidateCache = {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  getCacheConfig
3
- } from "./chunk-Y6CPPBJI.js";
3
+ } from "./chunk-QVPGBTCL.js";
4
4
  import {
5
5
  getENV
6
- } from "./chunk-HV6A6Z5R.js";
6
+ } from "./chunk-UGLEAXTY.js";
7
7
 
8
8
  // src/core/cache/noop-cache-manager.ts
9
9
  var NoopCacheManager = class {
@@ -1,32 +1,32 @@
1
1
  import {
2
2
  HybridCacheManager
3
- } from "./chunk-2GK4LDPV.js";
3
+ } from "./chunk-Z3OLZKTN.js";
4
4
  import {
5
5
  InMemoryCacheManager
6
6
  } from "./chunk-YYTA6ERS.js";
7
7
  import {
8
8
  NoopCacheManager
9
- } from "./chunk-XF3WUF3F.js";
9
+ } from "./chunk-ROJJJXRL.js";
10
10
  import {
11
11
  RedisCacheManager
12
- } from "./chunk-4TGPAUJV.js";
12
+ } from "./chunk-K7OZWWIS.js";
13
13
  import {
14
14
  isRedisAvailableNow,
15
15
  isRedisGloballyDisabled
16
- } from "./chunk-ZEHNCHIV.js";
16
+ } from "./chunk-NKZPMRVF.js";
17
17
  import {
18
18
  logger
19
19
  } from "./chunk-QAIN3WNN.js";
20
20
  import {
21
21
  getCacheConfig
22
- } from "./chunk-Y6CPPBJI.js";
22
+ } from "./chunk-QVPGBTCL.js";
23
23
  import {
24
24
  getENV,
25
25
  isCacheEnabled
26
- } from "./chunk-HV6A6Z5R.js";
26
+ } from "./chunk-UGLEAXTY.js";
27
27
  import {
28
28
  isCacheConfigInitialized
29
- } from "./chunk-7KIM5MHV.js";
29
+ } from "./chunk-RHYETIUR.js";
30
30
  import {
31
31
  configWarn
32
32
  } from "./chunk-6J2EJVND.js";
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-QAIN3WNN.js";
11
11
  import {
12
12
  getResolvedCacheConfig
13
- } from "./chunk-7KIM5MHV.js";
13
+ } from "./chunk-RHYETIUR.js";
14
14
 
15
15
  // src/core/system/health-check.ts
16
16
  async function checkServiceHealth(prismaClient) {
@@ -1,9 +1,9 @@
1
+ import {
2
+ getResolvedCacheConfig
3
+ } from "./chunk-RHYETIUR.js";
1
4
  import {
2
5
  getCommonConfig
3
6
  } from "./chunk-PX535BHW.js";
4
- import {
5
- getResolvedCacheConfig
6
- } from "./chunk-7KIM5MHV.js";
7
7
 
8
8
  // src/core/cache/cache-env.ts
9
9
  function _getNodeEnv() {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-7WG7XPXC.js";
4
4
  import {
5
5
  getErrorCategory
6
- } from "./chunk-XQIAXMRY.js";
6
+ } from "./chunk-5VZIAXO2.js";
7
7
 
8
8
  // src/core/error/friendly-messages-v2.ts
9
9
  var categoryIcons = {
@@ -8,13 +8,13 @@ import {
8
8
  adminMiddleware,
9
9
  authMiddleware,
10
10
  optionalAuthMiddleware
11
- } from "./chunk-MJOXTFIC.js";
11
+ } from "./chunk-7Q6SMNMN.js";
12
12
  import {
13
13
  corsMiddleware
14
14
  } from "./chunk-37VGD4VX.js";
15
15
  import {
16
16
  errorHandlerMiddleware
17
- } from "./chunk-4Y5MRUMX.js";
17
+ } from "./chunk-A6NIKJX5.js";
18
18
  import {
19
19
  initRequestMiddleware
20
20
  } from "./chunk-VC2E6KYQ.js";
@@ -23,7 +23,7 @@ import {
23
23
  } from "./chunk-WXOWI7BJ.js";
24
24
  import {
25
25
  rateLimitMiddleware
26
- } from "./chunk-TRGFXIEF.js";
26
+ } from "./chunk-M4ZVQFOH.js";
27
27
 
28
28
  // src/next/middleware/wrappers.ts
29
29
  function withPublicApi(handler) {
@@ -4,13 +4,13 @@ import {
4
4
  import {
5
5
  isRedisGloballyDisabled,
6
6
  notifyRedisError
7
- } from "./chunk-ZEHNCHIV.js";
7
+ } from "./chunk-NKZPMRVF.js";
8
8
  import {
9
9
  logger
10
10
  } from "./chunk-QAIN3WNN.js";
11
11
  import {
12
12
  getCacheFallbackConfig
13
- } from "./chunk-HV6A6Z5R.js";
13
+ } from "./chunk-UGLEAXTY.js";
14
14
  import {
15
15
  __spreadValues
16
16
  } from "./chunk-N3ETBM74.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  OAuthManager
3
- } from "./chunk-UQ3Z3ZAF.js";
3
+ } from "./chunk-V3GEYUBG.js";
4
4
  import {
5
5
  generateOAuthState,
6
6
  setOAuthStateCookie
@@ -13,6 +13,7 @@ export declare class ApiKeyService {
13
13
  private prefix;
14
14
  private toInfo;
15
15
  private requireOwned;
16
+ private assertPlanNotRestricted;
16
17
  generateApiKey(userId: string, options: CreateApiKeyOptions, plan: string): Promise<ApiKeyResult>;
17
18
  validateApiKey(rawKey: string): Promise<ApiKeyValidationResult>;
18
19
  getApiKey(id: string, userId: string, isAdmin?: boolean): Promise<ApiKeyInfo>;
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  ApiKeyService
3
- } from "../../chunk-RWENSBNW.js";
3
+ } from "../../chunk-G4IGD3AZ.js";
4
4
  import "../../chunk-BTNM5YSU.js";
5
+ import "../../chunk-4JZIIMAF.js";
5
6
  import "../../chunk-ZZTBIA57.js";
6
7
  import "../../chunk-N3ETBM74.js";
7
8
  export {
@@ -0,0 +1,21 @@
1
+ export declare const API_KEY_ERROR_CODES: {
2
+ /** 대상 API 키 미존재 */
3
+ readonly NOT_FOUND: "API_KEY_NOT_FOUND";
4
+ /** 비소유자 접근 (admin 우회 제외) */
5
+ readonly OWNERSHIP: "API_KEY_OWNERSHIP";
6
+ /** 제한 플랜(restrictedPlans)의 발급 시도 */
7
+ readonly PLAN_RESTRICTED: "API_KEY_PLAN_RESTRICTED";
8
+ /** 플랜별 활성 키 한도 초과 */
9
+ readonly LIMIT_REACHED: "API_KEY_LIMIT_REACHED";
10
+ };
11
+ export type ApiKeyErrorCode = (typeof API_KEY_ERROR_CODES)[keyof typeof API_KEY_ERROR_CODES];
12
+ export declare class ApiKeyError extends Error {
13
+ readonly code: ApiKeyErrorCode;
14
+ constructor(message: string, code: ApiKeyErrorCode);
15
+ }
16
+ /**
17
+ * ApiKeyError 판별 가드. instanceof 대신 name+code 구조 검사를 사용해
18
+ * 패키지 중복 설치(모듈 인스턴스 분리) 환경에서도 판별이 깨지지 않는다.
19
+ * code를 지정하면 해당 코드까지 일치해야 true.
20
+ */
21
+ export declare function isApiKeyError(error: unknown, code?: ApiKeyErrorCode): error is ApiKeyError;
@@ -0,0 +1,11 @@
1
+ import {
2
+ API_KEY_ERROR_CODES,
3
+ ApiKeyError,
4
+ isApiKeyError
5
+ } from "../../chunk-4JZIIMAF.js";
6
+ import "../../chunk-N3ETBM74.js";
7
+ export {
8
+ API_KEY_ERROR_CODES,
9
+ ApiKeyError,
10
+ isApiKeyError
11
+ };
@@ -1,4 +1,5 @@
1
1
  export * from '@withwiz/toolkit/core/api-key/types';
2
+ export * from '@withwiz/toolkit/core/api-key/errors';
2
3
  export * from '@withwiz/toolkit/core/api-key/ports';
3
4
  export * from '@withwiz/toolkit/core/api-key/key-generator';
4
5
  export * from '@withwiz/toolkit/core/api-key/ip-whitelist';
@@ -1,10 +1,16 @@
1
- import "../../chunk-MXWSG6ER.js";
1
+ import "../../chunk-KYUJ6D65.js";
2
+ import "../../chunk-TN5ZNYR2.js";
2
3
  import {
3
4
  ApiKeyService
4
- } from "../../chunk-RWENSBNW.js";
5
+ } from "../../chunk-G4IGD3AZ.js";
5
6
  import {
6
7
  validateApiKeyRecord
7
8
  } from "../../chunk-BTNM5YSU.js";
9
+ import {
10
+ API_KEY_ERROR_CODES,
11
+ ApiKeyError,
12
+ isApiKeyError
13
+ } from "../../chunk-4JZIIMAF.js";
8
14
  import {
9
15
  isIpAllowed,
10
16
  isIpInCidr
@@ -16,11 +22,13 @@ import {
16
22
  } from "../../chunk-ZZTBIA57.js";
17
23
  import "../../chunk-N3ETBM74.js";
18
24
  import "../../chunk-CWS5RPRX.js";
19
- import "../../chunk-TN5ZNYR2.js";
20
25
  export {
26
+ API_KEY_ERROR_CODES,
27
+ ApiKeyError,
21
28
  ApiKeyService,
22
29
  generateRawKey,
23
30
  hashKey,
31
+ isApiKeyError,
24
32
  isIpAllowed,
25
33
  isIpInCidr,
26
34
  keyPreview,