@withwiz/toolkit 0.9.3 → 0.10.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 (95) hide show
  1. package/dist/{chunk-KMUYO6YD.js → chunk-465MEI5K.js} +1 -1
  2. package/dist/{chunk-OXKVQGRH.js → chunk-5Z5CZAZP.js} +5 -5
  3. package/dist/chunk-BTNM5YSU.js +29 -0
  4. package/dist/chunk-CWS5RPRX.js +0 -0
  5. package/dist/{chunk-CNXK3SLK.js → chunk-HZN44RWL.js} +4 -4
  6. package/dist/{chunk-4Y5MRUMX.js → chunk-KHXS4DGA.js} +4 -4
  7. package/dist/{chunk-6SDUWMC3.js → chunk-KZ4PDS5K.js} +1 -1
  8. package/dist/chunk-L2A6NGW7.js +21 -0
  9. package/dist/chunk-MXWSG6ER.js +0 -0
  10. package/dist/chunk-NUHSUAXG.js +35 -0
  11. package/dist/{chunk-ZVGEGDYF.js → chunk-OII5BXCZ.js} +1 -1
  12. package/dist/chunk-P4MGYRJM.js +162 -0
  13. package/dist/{chunk-ROMGYJFX.js → chunk-SROPI74N.js} +1 -1
  14. package/dist/chunk-TN5ZNYR2.js +0 -0
  15. package/dist/{chunk-NERL6VYQ.js → chunk-VHRBXD7U.js} +1 -1
  16. package/dist/{chunk-ISP4MDKW.js → chunk-W27FQNP6.js} +1 -1
  17. package/dist/chunk-XWHT53CZ.js +38 -0
  18. package/dist/chunk-Z4J452HD.js +24 -0
  19. package/dist/{chunk-VQ47YRFC.js → chunk-Z64GNAB7.js} +2 -2
  20. package/dist/chunk-ZZTBIA57.js +18 -0
  21. package/dist/core/api-key/api-key.service.d.ts +28 -0
  22. package/dist/core/api-key/api-key.service.js +9 -0
  23. package/dist/core/api-key/index.d.ts +6 -0
  24. package/dist/core/api-key/index.js +28 -0
  25. package/dist/core/api-key/ip-whitelist.d.ts +4 -0
  26. package/dist/core/api-key/ip-whitelist.js +9 -0
  27. package/dist/core/api-key/key-generator.d.ts +6 -0
  28. package/dist/core/api-key/key-generator.js +11 -0
  29. package/dist/core/api-key/ports.d.ts +104 -0
  30. package/dist/core/api-key/ports.js +1 -0
  31. package/dist/core/api-key/types.d.ts +88 -0
  32. package/dist/core/api-key/types.js +1 -0
  33. package/dist/core/api-key/validate.d.ts +9 -0
  34. package/dist/core/api-key/validate.js +7 -0
  35. package/dist/core/auth/adapters/sql/email-token-repository.js +2 -2
  36. package/dist/core/auth/adapters/sql/index.js +8 -8
  37. package/dist/core/auth/adapters/sql/oauth-account-repository.js +2 -2
  38. package/dist/core/auth/adapters/sql/user-repository.js +2 -2
  39. package/dist/core/auth/index.js +4 -4
  40. package/dist/core/auth/jwt/cookie.js +2 -2
  41. package/dist/core/auth/jwt/index.js +2 -2
  42. package/dist/core/auth/oauth/index.js +4 -4
  43. package/dist/core/auth/oauth/providers/index.js +3 -3
  44. package/dist/core/auth/services/index.js +2 -2
  45. package/dist/core/auth/services/login.service.js +2 -2
  46. package/dist/core/auth/services/oauth-callback.service.js +2 -2
  47. package/dist/core/auth/services/token-refresh.service.js +2 -2
  48. package/dist/core/auth/token-delivery.js +3 -3
  49. package/dist/core/cache/cache-factory.js +1 -1
  50. package/dist/core/cache/cache-invalidation.js +1 -1
  51. package/dist/core/cache/cache-redis.js +1 -1
  52. package/dist/core/cache/cache-wrapper.js +1 -1
  53. package/dist/core/cache/cache.js +1 -1
  54. package/dist/core/cache/hybrid-cache-manager.js +1 -1
  55. package/dist/core/cache/index.js +1 -1
  56. package/dist/core/cache/redis-cache-manager.js +1 -1
  57. package/dist/core/geolocation/index.js +7 -7
  58. package/dist/core/geolocation/providers/index.js +7 -7
  59. package/dist/core/system/environment.js +1 -1
  60. package/dist/core/system/health-check.js +1 -1
  61. package/dist/core/system/index.js +8 -8
  62. package/dist/initialize.js +9 -9
  63. package/dist/next/auth-handlers/index.js +11 -11
  64. package/dist/next/auth-handlers/login.handler.js +4 -4
  65. package/dist/next/auth-handlers/logout.handler.js +3 -3
  66. package/dist/next/auth-handlers/me.handler.js +4 -4
  67. package/dist/next/auth-handlers/oauth-authorize.handler.js +3 -3
  68. package/dist/next/auth-handlers/oauth-callback.handler.js +5 -5
  69. package/dist/next/auth-handlers/refresh.handler.js +4 -4
  70. package/dist/next/auth-types/handler-types.js +3 -3
  71. package/dist/next/auth-types/index.js +3 -3
  72. package/dist/next/error/error-handler.js +2 -2
  73. package/dist/next/error/index.js +2 -2
  74. package/dist/next/middleware/auth.js +6 -6
  75. package/dist/next/middleware/error-handler.js +3 -3
  76. package/dist/next/middleware/index.js +15 -15
  77. package/dist/next/middleware/wrappers.js +11 -11
  78. package/dist/next/oapi/api-key-auth.d.ts +27 -0
  79. package/dist/next/oapi/api-key-auth.js +14 -0
  80. package/dist/next/oapi/helpers.d.ts +19 -0
  81. package/dist/next/oapi/helpers.js +13 -0
  82. package/dist/next/oapi/index.d.ts +3 -0
  83. package/dist/next/oapi/index.js +28 -0
  84. package/dist/next/oapi/openapi-spec.d.ts +18 -0
  85. package/dist/next/oapi/openapi-spec.js +7 -0
  86. package/dist/next/utils/index.js +1 -1
  87. package/package.json +12 -1
  88. package/dist/{chunk-BTYH4MHU.js → chunk-43XXILCX.js} +3 -3
  89. package/dist/{chunk-VQJY52YF.js → chunk-5VDT3ZB4.js} +3 -3
  90. package/dist/{chunk-BOABYFJ7.js → chunk-6NEGFM32.js} +3 -3
  91. package/dist/{chunk-V3GEYUBG.js → chunk-ER6LSA4M.js} +3 -3
  92. package/dist/{chunk-6A5JHOBB.js → chunk-GSRAIDD7.js} +3 -3
  93. package/dist/{chunk-AYCXN6QJ.js → chunk-R7EFDSPZ.js} +3 -3
  94. package/dist/{chunk-WU3V2AKE.js → chunk-UIWR5MXM.js} +0 -0
  95. package/dist/{chunk-Q5RPNLET.js → chunk-VDRLJU6C.js} +6 -6
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  clearTokenCookies
3
- } from "./chunk-BOABYFJ7.js";
3
+ } from "./chunk-6NEGFM32.js";
4
4
 
5
5
  // src/next/auth-handlers/logout.handler.ts
6
6
  import { NextResponse } from "next/server";
@@ -1,6 +1,9 @@
1
+ import {
2
+ corsMiddleware
3
+ } from "./chunk-37VGD4VX.js";
1
4
  import {
2
5
  errorHandlerMiddleware
3
- } from "./chunk-4Y5MRUMX.js";
6
+ } from "./chunk-KHXS4DGA.js";
4
7
  import {
5
8
  initRequestMiddleware
6
9
  } from "./chunk-VC2E6KYQ.js";
@@ -20,10 +23,7 @@ import {
20
23
  adminMiddleware,
21
24
  authMiddleware,
22
25
  optionalAuthMiddleware
23
- } from "./chunk-CNXK3SLK.js";
24
- import {
25
- corsMiddleware
26
- } from "./chunk-37VGD4VX.js";
26
+ } from "./chunk-HZN44RWL.js";
27
27
 
28
28
  // src/next/middleware/wrappers.ts
29
29
  function withPublicApi(handler) {
@@ -0,0 +1,29 @@
1
+ // src/core/api-key/validate.ts
2
+ function validateApiKeyRecord(record, opts) {
3
+ var _a, _b;
4
+ if (!record) return { valid: false, error: "INVALID_API_KEY", message: "Invalid API key" };
5
+ if (!record.isActive) return { valid: false, error: "INACTIVE_API_KEY", message: "API key is inactive" };
6
+ if (record.expiresAt && record.expiresAt < /* @__PURE__ */ new Date())
7
+ return { valid: false, error: "EXPIRED_API_KEY", message: "API key has expired" };
8
+ if (!record.user.isActive) return { valid: false, error: "INACTIVE_USER", message: "User account is inactive" };
9
+ if (((_a = opts.freemiumPlans) != null ? _a : []).includes(record.user.plan))
10
+ return { valid: false, error: "PLAN_RESTRICTED", message: "API access is not available for this plan. Please upgrade." };
11
+ return {
12
+ valid: true,
13
+ apiKey: {
14
+ id: record.id,
15
+ userId: record.user.id,
16
+ permissions: record.permissions,
17
+ rateLimit: record.rateLimit,
18
+ endpointLimits: (_b = record.endpointLimits) != null ? _b : void 0,
19
+ ipWhitelist: record.ipWhitelist,
20
+ environment: record.environment,
21
+ expiresAt: record.expiresAt
22
+ },
23
+ user: { id: record.user.id, email: record.user.email, plan: record.user.plan }
24
+ };
25
+ }
26
+
27
+ export {
28
+ validateApiKeyRecord
29
+ };
File without changes
@@ -4,15 +4,15 @@ import {
4
4
  import {
5
5
  ERROR_CODES
6
6
  } from "./chunk-XQIAXMRY.js";
7
- import {
8
- logger
9
- } from "./chunk-QAIN3WNN.js";
10
7
  import {
11
8
  JWTManager
12
9
  } from "./chunk-LWHLB2Y6.js";
13
10
  import {
14
11
  getTokenDeliveryStrategy
15
- } from "./chunk-NERL6VYQ.js";
12
+ } from "./chunk-VHRBXD7U.js";
13
+ import {
14
+ logger
15
+ } from "./chunk-QAIN3WNN.js";
16
16
  import {
17
17
  getAuthConfig
18
18
  } from "./chunk-N3TCQ5BF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AUTH_ERROR_CODE_MAP
3
- } from "./chunk-AYCXN6QJ.js";
3
+ } from "./chunk-R7EFDSPZ.js";
4
4
  import {
5
5
  AppError
6
6
  } from "./chunk-ATAQRXTH.js";
@@ -11,12 +11,12 @@ import {
11
11
  ERROR_CODES,
12
12
  classifyError
13
13
  } from "./chunk-XQIAXMRY.js";
14
- import {
15
- logger
16
- } from "./chunk-QAIN3WNN.js";
17
14
  import {
18
15
  AuthError
19
16
  } from "./chunk-5GWGARXI.js";
17
+ import {
18
+ logger
19
+ } from "./chunk-QAIN3WNN.js";
20
20
  import {
21
21
  __spreadValues
22
22
  } from "./chunk-N3ETBM74.js";
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-5GWGARXI.js";
7
7
  import {
8
8
  getTokenDeliveryStrategy
9
- } from "./chunk-NERL6VYQ.js";
9
+ } from "./chunk-VHRBXD7U.js";
10
10
 
11
11
  // src/next/auth-handlers/refresh.handler.ts
12
12
  import { NextResponse } from "next/server";
@@ -0,0 +1,21 @@
1
+ // src/next/oapi/openapi-spec.ts
2
+ function buildOpenApiSpec(input) {
3
+ var _a, _b;
4
+ return {
5
+ openapi: "3.0.3",
6
+ info: input.info,
7
+ servers: (_a = input.servers) != null ? _a : [],
8
+ paths: input.paths,
9
+ components: {
10
+ securitySchemes: {
11
+ ApiKeyAuth: { type: "apiKey", in: "header", name: "X-API-Key" }
12
+ },
13
+ schemas: (_b = input.schemas) != null ? _b : {}
14
+ },
15
+ security: [{ ApiKeyAuth: [] }]
16
+ };
17
+ }
18
+
19
+ export {
20
+ buildOpenApiSpec
21
+ };
File without changes
@@ -0,0 +1,35 @@
1
+ // src/core/api-key/ip-whitelist.ts
2
+ function isIpInCidr(ip, cidr) {
3
+ try {
4
+ const [range, bits] = cidr.split("/");
5
+ const mask = parseInt(bits, 10);
6
+ if (Number.isNaN(mask) || mask < 0 || mask > 32) return false;
7
+ const ipParts = ip.split(".").map(Number);
8
+ const rangeParts = range.split(".").map(Number);
9
+ if (ipParts.length !== 4 || rangeParts.length !== 4) return false;
10
+ if (![...ipParts, ...rangeParts].every((o) => Number.isInteger(o) && o >= 0 && o <= 255)) return false;
11
+ const ipNum = ipParts[0] << 24 | ipParts[1] << 16 | ipParts[2] << 8 | ipParts[3];
12
+ const rangeNum = rangeParts[0] << 24 | rangeParts[1] << 16 | rangeParts[2] << 8 | rangeParts[3];
13
+ const maskNum = mask === 0 ? 0 : ~0 << 32 - mask >>> 0;
14
+ return (ipNum & maskNum) === (rangeNum & maskNum);
15
+ } catch (e) {
16
+ return false;
17
+ }
18
+ }
19
+ function isIpAllowed(clientIp, whitelist) {
20
+ if (!whitelist || whitelist.length === 0) return true;
21
+ const normalizedIp = clientIp.replace(/^::ffff:/, "");
22
+ for (const allowed of whitelist) {
23
+ if (allowed.includes("/")) {
24
+ if (isIpInCidr(normalizedIp, allowed)) return true;
25
+ } else if (normalizedIp === allowed.replace(/^::ffff:/, "")) {
26
+ return true;
27
+ }
28
+ }
29
+ return false;
30
+ }
31
+
32
+ export {
33
+ isIpInCidr,
34
+ isIpAllowed
35
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  OAuthManager
3
- } from "./chunk-V3GEYUBG.js";
3
+ } from "./chunk-ER6LSA4M.js";
4
4
  import {
5
5
  generateOAuthState,
6
6
  setOAuthStateCookie
@@ -0,0 +1,162 @@
1
+ import {
2
+ generateRawKey,
3
+ hashKey,
4
+ keyPreview
5
+ } from "./chunk-ZZTBIA57.js";
6
+ import {
7
+ validateApiKeyRecord
8
+ } from "./chunk-BTNM5YSU.js";
9
+ import {
10
+ __spreadProps,
11
+ __spreadValues
12
+ } from "./chunk-N3ETBM74.js";
13
+
14
+ // src/core/api-key/api-key.service.ts
15
+ var ApiKeyService = class {
16
+ constructor(deps) {
17
+ this.deps = deps;
18
+ }
19
+ prefix(env) {
20
+ return env === "production" ? this.deps.env.prefixProd : this.deps.env.prefixDev;
21
+ }
22
+ toInfo(r) {
23
+ var _a, _b, _c, _d, _e;
24
+ return {
25
+ id: r.id,
26
+ name: r.name,
27
+ description: (_a = r.description) != null ? _a : void 0,
28
+ keyPreview: keyPreview(r.key),
29
+ permissions: r.permissions,
30
+ environment: r.environment,
31
+ rateLimit: r.rateLimit,
32
+ endpointLimits: (_b = r.endpointLimits) != null ? _b : void 0,
33
+ ipWhitelist: r.ipWhitelist,
34
+ lastUsedAt: (_c = r.lastUsedAt) != null ? _c : void 0,
35
+ lastUsedIp: (_d = r.lastUsedIp) != null ? _d : void 0,
36
+ usageCount: r.usageCount,
37
+ isActive: r.isActive,
38
+ expiresAt: (_e = r.expiresAt) != null ? _e : void 0,
39
+ createdAt: r.createdAt,
40
+ updatedAt: r.updatedAt
41
+ };
42
+ }
43
+ async requireOwned(id, userId, isAdmin) {
44
+ 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");
47
+ return rec;
48
+ }
49
+ async generateApiKey(userId, options, plan) {
50
+ var _a, _b, _c, _d, _e, _f, _g;
51
+ 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
+ }
55
+ const maxKeys = await planConfig.getApiKeyLimit(plan);
56
+ const active = await repo.countActive(userId);
57
+ if (active >= maxKeys) throw new Error(`API key limit reached. Max ${maxKeys} keys.`);
58
+ const rawKey = generateRawKey(this.prefix(options.environment));
59
+ const planRate = await planConfig.getRateLimit(plan);
60
+ const rateLimit = options.customRateLimit ? Math.min(options.customRateLimit, planRate) : planRate;
61
+ const expiresAt = (_a = options.expiresAt) != null ? _a : new Date(Date.now() + env.defaultExpiryDays * 864e5);
62
+ const created = await repo.create({
63
+ userId,
64
+ key: hashKey(rawKey),
65
+ name: options.name,
66
+ description: (_b = options.description) != null ? _b : null,
67
+ permissions: options.permissions,
68
+ rateLimit,
69
+ endpointLimits: (_c = options.endpointLimits) != null ? _c : null,
70
+ environment: options.environment,
71
+ ipWhitelist: (_d = options.ipWhitelist) != null ? _d : [],
72
+ expiresAt
73
+ });
74
+ return {
75
+ id: created.id,
76
+ key: rawKey,
77
+ name: created.name,
78
+ description: (_e = created.description) != null ? _e : void 0,
79
+ permissions: created.permissions,
80
+ environment: created.environment,
81
+ rateLimit: created.rateLimit,
82
+ endpointLimits: (_f = created.endpointLimits) != null ? _f : void 0,
83
+ expiresAt: (_g = created.expiresAt) != null ? _g : void 0,
84
+ createdAt: created.createdAt
85
+ };
86
+ }
87
+ async validateApiKey(rawKey) {
88
+ var _a;
89
+ const { repo, cache, env } = this.deps;
90
+ const keyHash = hashKey(rawKey);
91
+ const cached = await cache.getValidation(keyHash);
92
+ if (cached) {
93
+ const exp = (_a = cached.apiKey) == null ? void 0 : _a.expiresAt;
94
+ if (!(exp && new Date(exp) < /* @__PURE__ */ new Date())) return cached;
95
+ await cache.invalidate(keyHash);
96
+ }
97
+ const record = await repo.findByHash(keyHash);
98
+ const result = validateApiKeyRecord(record, { freemiumPlans: env.restrictedPlans });
99
+ if (result.valid) await cache.setValidation(keyHash, result);
100
+ return result;
101
+ }
102
+ async getApiKey(id, userId, isAdmin = false) {
103
+ const rec = await this.requireOwned(id, userId, isAdmin);
104
+ return this.toInfo(rec);
105
+ }
106
+ async getApiKeys(filters, requesterId, isAdmin = false) {
107
+ var _a, _b;
108
+ const scoped = isAdmin ? filters : __spreadProps(__spreadValues({}, filters), { userId: requesterId });
109
+ const page = (_a = scoped.page) != null ? _a : 1, pageSize = (_b = scoped.pageSize) != null ? _b : 10;
110
+ const { items, total } = await this.deps.repo.findMany(__spreadProps(__spreadValues({}, scoped), { page, pageSize }));
111
+ return { keys: items.map((r) => this.toInfo(r)), total, page, pageSize, hasMore: total > page * pageSize };
112
+ }
113
+ async updateApiKey(id, userId, data, isAdmin = false) {
114
+ const rec = await this.requireOwned(id, userId, isAdmin);
115
+ const updated = await this.deps.repo.update(id, {
116
+ name: data.name,
117
+ description: data.description,
118
+ isActive: data.isActive,
119
+ permissions: data.permissions,
120
+ ipWhitelist: data.ipWhitelist,
121
+ rateLimit: data.customRateLimit,
122
+ endpointLimits: data.endpointLimits
123
+ });
124
+ await this.deps.cache.invalidate(rec.key);
125
+ return this.toInfo(updated);
126
+ }
127
+ async deleteApiKey(id, userId, isAdmin = false) {
128
+ const rec = await this.requireOwned(id, userId, isAdmin);
129
+ await this.deps.repo.delete(id);
130
+ await this.deps.cache.invalidate(rec.key);
131
+ }
132
+ async trackUsage(apiKeyId, ip) {
133
+ try {
134
+ await this.deps.repo.incrementUsage(apiKeyId, ip);
135
+ } catch (e) {
136
+ }
137
+ }
138
+ async regenerateApiKey(userId, apiKeyId, plan, options = {}) {
139
+ var _a, _b, _c, _d, _e;
140
+ const old = await this.requireOwned(apiKeyId, userId, false);
141
+ if (!options.keepOldKeyActive) {
142
+ 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.`);
144
+ await this.deps.repo.deactivate(apiKeyId);
145
+ await this.deps.cache.invalidate(old.key);
146
+ }
147
+ return this.generateApiKey(userId, {
148
+ name: (_a = options.name) != null ? _a : old.name,
149
+ description: (_c = (_b = options.description) != null ? _b : old.description) != null ? _c : void 0,
150
+ permissions: old.permissions,
151
+ environment: old.environment,
152
+ customRateLimit: old.rateLimit,
153
+ ipWhitelist: old.ipWhitelist,
154
+ endpointLimits: (_d = old.endpointLimits) != null ? _d : void 0,
155
+ expiresAt: (_e = old.expiresAt) != null ? _e : void 0
156
+ }, plan);
157
+ }
158
+ };
159
+
160
+ export {
161
+ ApiKeyService
162
+ };
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-LWHLB2Y6.js";
4
4
  import {
5
5
  getTokenDeliveryStrategy
6
- } from "./chunk-NERL6VYQ.js";
6
+ } from "./chunk-VHRBXD7U.js";
7
7
  import {
8
8
  JWT_DEFAULTS
9
9
  } from "./chunk-7YWUKMZD.js";
File without changes
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  setTokenCookies
3
- } from "./chunk-BOABYFJ7.js";
3
+ } from "./chunk-6NEGFM32.js";
4
4
  import {
5
5
  getAuthConfig
6
6
  } from "./chunk-N3TCQ5BF.js";
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-5GWGARXI.js";
7
7
  import {
8
8
  getTokenDeliveryStrategy
9
- } from "./chunk-NERL6VYQ.js";
9
+ } from "./chunk-VHRBXD7U.js";
10
10
  import {
11
11
  JWT_DEFAULTS,
12
12
  ROLE_DEFAULTS
@@ -0,0 +1,38 @@
1
+ import {
2
+ isIpAllowed
3
+ } from "./chunk-NUHSUAXG.js";
4
+
5
+ // src/next/oapi/api-key-auth.ts
6
+ import { NextResponse } from "next/server";
7
+ var err = (code, status, message) => ({ response: NextResponse.json({ success: false, error: { code, message } }, { status }) });
8
+ function createApiKeyAuth(options) {
9
+ return async (req) => {
10
+ var _a;
11
+ try {
12
+ const apiKey = req.headers.get("x-api-key");
13
+ if (!apiKey) return err(40101, 401, "X-API-Key header is required");
14
+ const v = await options.service.validateApiKey(apiKey);
15
+ if (!v.valid || !v.apiKey || !v.user) return err(40101, 401, v.message || "Invalid API key");
16
+ const ip = options.extractClientIp(req.headers);
17
+ if (!isIpAllowed(ip, (_a = v.apiKey.ipWhitelist) != null ? _a : null)) return err(40301, 403, "Access denied: IP not in whitelist");
18
+ try {
19
+ const usage = await options.usage.canMakeApiCall(v.user.id, v.user.plan);
20
+ if (!usage.allowed) {
21
+ const t = usage.reason === "DAILY_LIMIT" ? "daily" : "monthly";
22
+ return err(40301, 403, `API ${t} usage limit exceeded. Please upgrade your plan or wait until reset.`);
23
+ }
24
+ } catch (e) {
25
+ }
26
+ options.service.trackUsage(v.apiKey.id, ip).catch(() => {
27
+ });
28
+ const role = await options.resolveRole(v.user.id);
29
+ return { user: { id: v.user.id, email: v.user.email, role, plan: v.user.plan, apiKeyId: v.apiKey.id } };
30
+ } catch (e) {
31
+ return err(50001, 500, "Internal authentication error");
32
+ }
33
+ };
34
+ }
35
+
36
+ export {
37
+ createApiKeyAuth
38
+ };
@@ -0,0 +1,24 @@
1
+ // src/next/oapi/helpers.ts
2
+ import { NextResponse } from "next/server";
3
+ function parsePaginationParams(sp) {
4
+ const page = Math.max(1, parseInt(sp.get("page") || "1", 10) || 1);
5
+ const pageSize = Math.min(100, Math.max(1, parseInt(sp.get("pageSize") || "10", 10) || 10));
6
+ return { page, pageSize };
7
+ }
8
+ function createPaginationMeta(total, page, pageSize) {
9
+ return { total, page, pageSize, hasMore: total > page * pageSize };
10
+ }
11
+ function parseSearchParams(sp) {
12
+ return { search: sp.get("search") || void 0 };
13
+ }
14
+ function requireParam(value, label) {
15
+ if (!value) return NextResponse.json({ success: false, error: { code: 40001, message: `${label} is required` } }, { status: 400 });
16
+ return null;
17
+ }
18
+
19
+ export {
20
+ parsePaginationParams,
21
+ createPaginationMeta,
22
+ parseSearchParams,
23
+ requireParam
24
+ };
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-MTZXWVW3.js";
4
4
  import {
5
5
  OAuthManager
6
- } from "./chunk-V3GEYUBG.js";
6
+ } from "./chunk-ER6LSA4M.js";
7
7
  import {
8
8
  OAUTH_STATE_COOKIE,
9
9
  clearOAuthStateCookie,
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-5GWGARXI.js";
15
15
  import {
16
16
  setTokenCookies
17
- } from "./chunk-BOABYFJ7.js";
17
+ } from "./chunk-6NEGFM32.js";
18
18
 
19
19
  // src/next/auth-handlers/oauth-callback.handler.ts
20
20
  import { NextResponse } from "next/server";
@@ -0,0 +1,18 @@
1
+ // src/core/api-key/key-generator.ts
2
+ import crypto from "crypto";
3
+ function generateRawKey(prefix) {
4
+ return `${prefix}${crypto.randomBytes(32).toString("hex")}`;
5
+ }
6
+ function hashKey(rawKey) {
7
+ return crypto.createHash("sha256").update(rawKey).digest("hex");
8
+ }
9
+ function keyPreview(keyHash) {
10
+ if (keyHash.length < 14) return keyHash;
11
+ return `${keyHash.substring(0, 10)}...${keyHash.substring(keyHash.length - 4)}`;
12
+ }
13
+
14
+ export {
15
+ generateRawKey,
16
+ hashKey,
17
+ keyPreview
18
+ };
@@ -0,0 +1,28 @@
1
+ import type { IApiKeyRepository, IApiKeyCacheStore, IPlanConfigProvider, IUsageTracker, ApiKeyServiceEnv } from '@withwiz/toolkit/core/api-key/ports';
2
+ import type { CreateApiKeyOptions, ApiKeyResult, ApiKeyValidationResult, ApiKeyInfo, ApiKeyFilters, ApiKeyListResponse, UpdateApiKeyData } from '@withwiz/toolkit/core/api-key/types';
3
+ export interface ApiKeyServiceDeps {
4
+ repo: IApiKeyRepository;
5
+ cache: IApiKeyCacheStore;
6
+ planConfig: IPlanConfigProvider;
7
+ usage: IUsageTracker;
8
+ env: ApiKeyServiceEnv;
9
+ }
10
+ export declare class ApiKeyService {
11
+ private readonly deps;
12
+ constructor(deps: ApiKeyServiceDeps);
13
+ private prefix;
14
+ private toInfo;
15
+ private requireOwned;
16
+ generateApiKey(userId: string, options: CreateApiKeyOptions, plan: string): Promise<ApiKeyResult>;
17
+ validateApiKey(rawKey: string): Promise<ApiKeyValidationResult>;
18
+ getApiKey(id: string, userId: string, isAdmin?: boolean): Promise<ApiKeyInfo>;
19
+ getApiKeys(filters: ApiKeyFilters, requesterId: string, isAdmin?: boolean): Promise<ApiKeyListResponse>;
20
+ updateApiKey(id: string, userId: string, data: UpdateApiKeyData, isAdmin?: boolean): Promise<ApiKeyInfo>;
21
+ deleteApiKey(id: string, userId: string, isAdmin?: boolean): Promise<void>;
22
+ trackUsage(apiKeyId: string, ip?: string): Promise<void>;
23
+ regenerateApiKey(userId: string, apiKeyId: string, plan: string, options?: {
24
+ name?: string;
25
+ description?: string;
26
+ keepOldKeyActive?: boolean;
27
+ }): Promise<ApiKeyResult>;
28
+ }
@@ -0,0 +1,9 @@
1
+ import {
2
+ ApiKeyService
3
+ } from "../../chunk-P4MGYRJM.js";
4
+ import "../../chunk-ZZTBIA57.js";
5
+ import "../../chunk-BTNM5YSU.js";
6
+ import "../../chunk-N3ETBM74.js";
7
+ export {
8
+ ApiKeyService
9
+ };
@@ -0,0 +1,6 @@
1
+ export * from '@withwiz/toolkit/core/api-key/types';
2
+ export * from '@withwiz/toolkit/core/api-key/ports';
3
+ export * from '@withwiz/toolkit/core/api-key/key-generator';
4
+ export * from '@withwiz/toolkit/core/api-key/ip-whitelist';
5
+ export * from '@withwiz/toolkit/core/api-key/validate';
6
+ export { ApiKeyService, type ApiKeyServiceDeps } from '@withwiz/toolkit/core/api-key/api-key.service';
@@ -0,0 +1,28 @@
1
+ import "../../chunk-MXWSG6ER.js";
2
+ import {
3
+ ApiKeyService
4
+ } from "../../chunk-P4MGYRJM.js";
5
+ import {
6
+ isIpAllowed,
7
+ isIpInCidr
8
+ } from "../../chunk-NUHSUAXG.js";
9
+ import {
10
+ generateRawKey,
11
+ hashKey,
12
+ keyPreview
13
+ } from "../../chunk-ZZTBIA57.js";
14
+ import "../../chunk-CWS5RPRX.js";
15
+ import "../../chunk-TN5ZNYR2.js";
16
+ import {
17
+ validateApiKeyRecord
18
+ } from "../../chunk-BTNM5YSU.js";
19
+ import "../../chunk-N3ETBM74.js";
20
+ export {
21
+ ApiKeyService,
22
+ generateRawKey,
23
+ hashKey,
24
+ isIpAllowed,
25
+ isIpInCidr,
26
+ keyPreview,
27
+ validateApiKeyRecord
28
+ };
@@ -0,0 +1,4 @@
1
+ /** IPv4 CIDR 범위 포함 여부. 잘못된 입력은 false(throw 안 함). */
2
+ export declare function isIpInCidr(ip: string, cidr: string): boolean;
3
+ /** 클라이언트 IP가 화이트리스트(단일 IP 또는 CIDR)에 포함되는지. 빈/null이면 모두 허용. */
4
+ export declare function isIpAllowed(clientIp: string, whitelist: string[] | null): boolean;
@@ -0,0 +1,9 @@
1
+ import {
2
+ isIpAllowed,
3
+ isIpInCidr
4
+ } from "../../chunk-NUHSUAXG.js";
5
+ import "../../chunk-N3ETBM74.js";
6
+ export {
7
+ isIpAllowed,
8
+ isIpInCidr
9
+ };
@@ -0,0 +1,6 @@
1
+ /** prefix + 32바이트 랜덤 hex. */
2
+ export declare function generateRawKey(prefix: string): string;
3
+ /** raw key의 sha256 hex (DB 저장용). */
4
+ export declare function hashKey(rawKey: string): string;
5
+ /** 키 해시 미리보기: 처음 10 + ... + 마지막 4. 14자 미만이면 원본. */
6
+ export declare function keyPreview(keyHash: string): string;
@@ -0,0 +1,11 @@
1
+ import {
2
+ generateRawKey,
3
+ hashKey,
4
+ keyPreview
5
+ } from "../../chunk-ZZTBIA57.js";
6
+ import "../../chunk-N3ETBM74.js";
7
+ export {
8
+ generateRawKey,
9
+ hashKey,
10
+ keyPreview
11
+ };