@vasperacapital/vaspera-shared 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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/errors/codes.ts","../../src/errors/factory.ts"],"sourcesContent":["export interface ErrorDefinition {\n code: string;\n message: string;\n httpStatus: number;\n}\n\nexport const ErrorCodes = {\n // Authentication Errors (VPM-AUTH-XXX)\n AUTH: {\n REQUIRED: {\n code: 'VPM-AUTH-001',\n message: 'Authentication required',\n httpStatus: 401,\n },\n INVALID_TOKEN: {\n code: 'VPM-AUTH-002',\n message: 'Invalid or expired authentication token',\n httpStatus: 401,\n },\n INSUFFICIENT_PERMISSIONS: {\n code: 'VPM-AUTH-003',\n message: 'Insufficient permissions for this action',\n httpStatus: 403,\n },\n SESSION_EXPIRED: {\n code: 'VPM-AUTH-004',\n message: 'Session has expired, please login again',\n httpStatus: 401,\n },\n MFA_REQUIRED: {\n code: 'VPM-AUTH-005',\n message: 'Multi-factor authentication required',\n httpStatus: 403,\n },\n },\n\n // API Key Errors (VPM-API-KEY-XXX)\n API_KEY: {\n REQUIRED: {\n code: 'VPM-API-KEY-001',\n message: 'API key is required',\n httpStatus: 401,\n },\n INVALID: {\n code: 'VPM-API-KEY-002',\n message: 'Invalid API key',\n httpStatus: 401,\n },\n REVOKED: {\n code: 'VPM-API-KEY-003',\n message: 'API key has been revoked',\n httpStatus: 401,\n },\n EXPIRED: {\n code: 'VPM-API-KEY-004',\n message: 'API key has expired',\n httpStatus: 401,\n },\n RATE_LIMITED: {\n code: 'VPM-API-KEY-005',\n message: 'API key rate limit exceeded',\n httpStatus: 429,\n },\n QUOTA_EXCEEDED: {\n code: 'VPM-API-KEY-006',\n message: 'Monthly usage quota exceeded',\n httpStatus: 429,\n },\n },\n\n // MCP Tool Errors (VPM-MCP-XXX)\n MCP: {\n TOOL_NOT_FOUND: {\n code: 'VPM-MCP-001',\n message: 'Requested tool not found',\n httpStatus: 404,\n },\n INVALID_ARGUMENTS: {\n code: 'VPM-MCP-002',\n message: 'Invalid tool arguments provided',\n httpStatus: 400,\n },\n EXECUTION_FAILED: {\n code: 'VPM-MCP-003',\n message: 'Tool execution failed',\n httpStatus: 500,\n },\n TIMEOUT: {\n code: 'VPM-MCP-004',\n message: 'Tool execution timed out',\n httpStatus: 504,\n },\n LLM_ERROR: {\n code: 'VPM-MCP-005',\n message: 'AI model returned an error',\n httpStatus: 502,\n },\n CONTEXT_TOO_LARGE: {\n code: 'VPM-MCP-006',\n message: 'Input context exceeds maximum size',\n httpStatus: 413,\n },\n },\n\n // Billing Errors (VPM-BILLING-XXX)\n BILLING: {\n NO_SUBSCRIPTION: {\n code: 'VPM-BILLING-001',\n message: 'No active subscription found',\n httpStatus: 402,\n },\n SUBSCRIPTION_EXPIRED: {\n code: 'VPM-BILLING-002',\n message: 'Subscription has expired',\n httpStatus: 402,\n },\n PAYMENT_FAILED: {\n code: 'VPM-BILLING-003',\n message: 'Payment processing failed',\n httpStatus: 402,\n },\n FEATURE_NOT_INCLUDED: {\n code: 'VPM-BILLING-004',\n message: 'Feature not included in current plan',\n httpStatus: 403,\n },\n UPGRADE_REQUIRED: {\n code: 'VPM-BILLING-005',\n message: 'Plan upgrade required for this action',\n httpStatus: 403,\n },\n },\n\n // Integration Errors (VPM-INT-XXX)\n INTEGRATION: {\n NOT_CONNECTED: {\n code: 'VPM-INT-001',\n message: 'Integration not connected',\n httpStatus: 400,\n },\n TOKEN_EXPIRED: {\n code: 'VPM-INT-002',\n message: 'Integration token expired, reconnection required',\n httpStatus: 401,\n },\n REFRESH_FAILED: {\n code: 'VPM-INT-003',\n message: 'Failed to refresh integration token',\n httpStatus: 502,\n },\n API_ERROR: {\n code: 'VPM-INT-004',\n message: 'External integration API error',\n httpStatus: 502,\n },\n RATE_LIMITED: {\n code: 'VPM-INT-005',\n message: 'Integration rate limit exceeded',\n httpStatus: 429,\n },\n },\n\n // Validation Errors (VPM-VAL-XXX)\n VALIDATION: {\n REQUIRED_FIELD: {\n code: 'VPM-VAL-001',\n message: 'Required field missing',\n httpStatus: 400,\n },\n INVALID_FORMAT: {\n code: 'VPM-VAL-002',\n message: 'Invalid field format',\n httpStatus: 400,\n },\n OUT_OF_RANGE: {\n code: 'VPM-VAL-003',\n message: 'Value out of allowed range',\n httpStatus: 400,\n },\n INVALID_JSON: {\n code: 'VPM-VAL-004',\n message: 'Invalid JSON in request body',\n httpStatus: 400,\n },\n },\n\n // System Errors (VPM-SYS-XXX)\n SYSTEM: {\n INTERNAL_ERROR: {\n code: 'VPM-SYS-001',\n message: 'Internal server error',\n httpStatus: 500,\n },\n DATABASE_ERROR: {\n code: 'VPM-SYS-002',\n message: 'Database operation failed',\n httpStatus: 500,\n },\n SERVICE_UNAVAILABLE: {\n code: 'VPM-SYS-003',\n message: 'Service temporarily unavailable',\n httpStatus: 503,\n },\n MAINTENANCE_MODE: {\n code: 'VPM-SYS-004',\n message: 'System is under maintenance',\n httpStatus: 503,\n },\n },\n} as const;\n\nexport type ErrorCodeType =\n (typeof ErrorCodes)[keyof typeof ErrorCodes][keyof (typeof ErrorCodes)[keyof typeof ErrorCodes]];\n","import type { ErrorDefinition } from './codes.js';\nimport { ErrorCodes } from './codes.js';\n\nexport interface VasperaError {\n code: string;\n message: string;\n details?: Record<string, unknown>;\n timestamp: string;\n requestId: string;\n docUrl?: string;\n}\n\nexport interface ErrorResponse {\n success: false;\n error: VasperaError;\n}\n\nfunction generateRequestId(): string {\n return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;\n}\n\nexport function createError(\n errorDef: ErrorDefinition,\n details?: Record<string, unknown>,\n requestId?: string\n): VasperaError {\n return {\n code: errorDef.code,\n message: errorDef.message,\n details,\n timestamp: new Date().toISOString(),\n requestId: requestId || generateRequestId(),\n docUrl: `https://docs.vaspera.pm/errors/${errorDef.code}`,\n };\n}\n\nexport function createErrorResponse(\n errorDef: ErrorDefinition,\n details?: Record<string, unknown>,\n requestId?: string\n): { response: ErrorResponse; status: number } {\n return {\n response: {\n success: false,\n error: createError(errorDef, details, requestId),\n },\n status: errorDef.httpStatus,\n };\n}\n\nfunction getNextResetDate(): string {\n const now = new Date();\n const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);\n return nextMonth.toISOString();\n}\n\n// Pre-built error creators for common cases\nexport const Errors = {\n authRequired: (requestId?: string) =>\n createErrorResponse(ErrorCodes.AUTH.REQUIRED, undefined, requestId),\n\n invalidApiKey: (requestId?: string) =>\n createErrorResponse(ErrorCodes.API_KEY.INVALID, undefined, requestId),\n\n apiKeyRevoked: (requestId?: string) =>\n createErrorResponse(ErrorCodes.API_KEY.REVOKED, undefined, requestId),\n\n apiKeyExpired: (requestId?: string) =>\n createErrorResponse(ErrorCodes.API_KEY.EXPIRED, undefined, requestId),\n\n rateLimited: (retryAfter: number, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.API_KEY.RATE_LIMITED,\n { retryAfterSeconds: retryAfter },\n requestId\n ),\n\n quotaExceeded: (currentUsage: number, limit: number, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.API_KEY.QUOTA_EXCEEDED,\n { currentUsage, limit, resetDate: getNextResetDate() },\n requestId\n ),\n\n toolNotFound: (toolName: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.MCP.TOOL_NOT_FOUND,\n { tool: toolName },\n requestId\n ),\n\n toolExecutionFailed: (toolName: string, reason: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.MCP.EXECUTION_FAILED,\n { tool: toolName, reason },\n requestId\n ),\n\n toolTimeout: (toolName: string, timeoutMs: number, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.MCP.TIMEOUT,\n { tool: toolName, timeoutMs },\n requestId\n ),\n\n validationFailed: (field: string, reason: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.VALIDATION.REQUIRED_FIELD,\n { field, reason },\n requestId\n ),\n\n invalidFormat: (field: string, expected: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.VALIDATION.INVALID_FORMAT,\n { field, expected },\n requestId\n ),\n\n internalError: (message?: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.SYSTEM.INTERNAL_ERROR,\n message ? { message } : undefined,\n requestId\n ),\n\n databaseError: (operation: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.SYSTEM.DATABASE_ERROR,\n { operation },\n requestId\n ),\n\n integrationNotConnected: (provider: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.INTEGRATION.NOT_CONNECTED,\n { provider },\n requestId\n ),\n\n subscriptionRequired: (feature: string, requiredTier: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.BILLING.FEATURE_NOT_INCLUDED,\n { feature, requiredTier },\n requestId\n ),\n};\n\n// Custom error class for throwing in API routes\nexport class VasperaApiError extends Error {\n public readonly errorDef: ErrorDefinition;\n public readonly details?: Record<string, unknown>;\n\n constructor(errorDef: ErrorDefinition, details?: Record<string, unknown>) {\n super(errorDef.message);\n this.name = 'VasperaApiError';\n this.errorDef = errorDef;\n this.details = details;\n }\n\n toResponse(requestId?: string): { response: ErrorResponse; status: number } {\n return createErrorResponse(this.errorDef, this.details, requestId);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,57 @@
1
+ export { ApiErrorResponse, ApiKey, ApiKeyWithSecret, ApiResponse, ApiSuccessResponse, IntegrationProvider, IntegrationStatus, IntegrationToken, McpToolName, McpToolResult, QUOTA_LIMITS, RATE_LIMITS, SubscriptionStatus, SubscriptionTier, UsageEvent, UsageSummary, UserProfile } from './types/index.mjs';
2
+ export { ErrorCodeType, ErrorCodes, ErrorDefinition, ErrorResponse, Errors, VasperaApiError, VasperaError, createError, createErrorResponse } from './errors/index.mjs';
3
+
4
+ interface GeneratedApiKey {
5
+ key: string;
6
+ keyPrefix: string;
7
+ keyHash: string;
8
+ }
9
+ /**
10
+ * Generate a new API key
11
+ * @param environment - 'live' or 'test'
12
+ * @returns Generated key with prefix and hash
13
+ */
14
+ declare function generateApiKey(environment?: 'live' | 'test'): GeneratedApiKey;
15
+ /**
16
+ * Hash an API key for storage
17
+ * Using SHA-256 since we need to look up by hash
18
+ */
19
+ declare function hashApiKey(key: string): string;
20
+ /**
21
+ * Validate API key format
22
+ */
23
+ declare function isValidApiKeyFormat(key: string): boolean;
24
+ /**
25
+ * Extract prefix from API key
26
+ */
27
+ declare function extractKeyPrefix(key: string): string;
28
+ /**
29
+ * Check if key is a test key
30
+ */
31
+ declare function isTestKey(key: string): boolean;
32
+ /**
33
+ * Mask an API key for display (show first 16 and last 4 chars)
34
+ */
35
+ declare function maskApiKey(key: string): string;
36
+
37
+ /**
38
+ * Encrypt text using AES-256-GCM
39
+ * @param text - Plain text to encrypt
40
+ * @param secret - Encryption secret
41
+ * @returns Encrypted string in format: salt:iv:tag:ciphertext (all base64)
42
+ */
43
+ declare function encrypt(text: string, secret: string): Promise<string>;
44
+ /**
45
+ * Decrypt text that was encrypted with encrypt()
46
+ * @param encryptedText - Encrypted string in format: salt:iv:tag:ciphertext
47
+ * @param secret - Encryption secret (must match encryption)
48
+ * @returns Decrypted plain text
49
+ */
50
+ declare function decrypt(encryptedText: string, secret: string): Promise<string>;
51
+ /**
52
+ * Generate a random encryption secret
53
+ * @returns 32-byte hex string suitable for use as encryption secret
54
+ */
55
+ declare function generateEncryptionSecret(): string;
56
+
57
+ export { type GeneratedApiKey, decrypt, encrypt, extractKeyPrefix, generateApiKey, generateEncryptionSecret, hashApiKey, isTestKey, isValidApiKeyFormat, maskApiKey };
@@ -0,0 +1,57 @@
1
+ export { ApiErrorResponse, ApiKey, ApiKeyWithSecret, ApiResponse, ApiSuccessResponse, IntegrationProvider, IntegrationStatus, IntegrationToken, McpToolName, McpToolResult, QUOTA_LIMITS, RATE_LIMITS, SubscriptionStatus, SubscriptionTier, UsageEvent, UsageSummary, UserProfile } from './types/index.js';
2
+ export { ErrorCodeType, ErrorCodes, ErrorDefinition, ErrorResponse, Errors, VasperaApiError, VasperaError, createError, createErrorResponse } from './errors/index.js';
3
+
4
+ interface GeneratedApiKey {
5
+ key: string;
6
+ keyPrefix: string;
7
+ keyHash: string;
8
+ }
9
+ /**
10
+ * Generate a new API key
11
+ * @param environment - 'live' or 'test'
12
+ * @returns Generated key with prefix and hash
13
+ */
14
+ declare function generateApiKey(environment?: 'live' | 'test'): GeneratedApiKey;
15
+ /**
16
+ * Hash an API key for storage
17
+ * Using SHA-256 since we need to look up by hash
18
+ */
19
+ declare function hashApiKey(key: string): string;
20
+ /**
21
+ * Validate API key format
22
+ */
23
+ declare function isValidApiKeyFormat(key: string): boolean;
24
+ /**
25
+ * Extract prefix from API key
26
+ */
27
+ declare function extractKeyPrefix(key: string): string;
28
+ /**
29
+ * Check if key is a test key
30
+ */
31
+ declare function isTestKey(key: string): boolean;
32
+ /**
33
+ * Mask an API key for display (show first 16 and last 4 chars)
34
+ */
35
+ declare function maskApiKey(key: string): string;
36
+
37
+ /**
38
+ * Encrypt text using AES-256-GCM
39
+ * @param text - Plain text to encrypt
40
+ * @param secret - Encryption secret
41
+ * @returns Encrypted string in format: salt:iv:tag:ciphertext (all base64)
42
+ */
43
+ declare function encrypt(text: string, secret: string): Promise<string>;
44
+ /**
45
+ * Decrypt text that was encrypted with encrypt()
46
+ * @param encryptedText - Encrypted string in format: salt:iv:tag:ciphertext
47
+ * @param secret - Encryption secret (must match encryption)
48
+ * @returns Decrypted plain text
49
+ */
50
+ declare function decrypt(encryptedText: string, secret: string): Promise<string>;
51
+ /**
52
+ * Generate a random encryption secret
53
+ * @returns 32-byte hex string suitable for use as encryption secret
54
+ */
55
+ declare function generateEncryptionSecret(): string;
56
+
57
+ export { type GeneratedApiKey, decrypt, encrypt, extractKeyPrefix, generateApiKey, generateEncryptionSecret, hashApiKey, isTestKey, isValidApiKeyFormat, maskApiKey };
package/dist/index.js ADDED
@@ -0,0 +1,458 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ErrorCodes: () => ErrorCodes,
24
+ Errors: () => Errors,
25
+ QUOTA_LIMITS: () => QUOTA_LIMITS,
26
+ RATE_LIMITS: () => RATE_LIMITS,
27
+ VasperaApiError: () => VasperaApiError,
28
+ createError: () => createError,
29
+ createErrorResponse: () => createErrorResponse,
30
+ decrypt: () => decrypt,
31
+ encrypt: () => encrypt,
32
+ extractKeyPrefix: () => extractKeyPrefix,
33
+ generateApiKey: () => generateApiKey,
34
+ generateEncryptionSecret: () => generateEncryptionSecret,
35
+ hashApiKey: () => hashApiKey,
36
+ isTestKey: () => isTestKey,
37
+ isValidApiKeyFormat: () => isValidApiKeyFormat,
38
+ maskApiKey: () => maskApiKey
39
+ });
40
+ module.exports = __toCommonJS(index_exports);
41
+
42
+ // src/types/index.ts
43
+ var QUOTA_LIMITS = {
44
+ free: 5,
45
+ starter: 100,
46
+ pro: 500,
47
+ enterprise: 999999
48
+ // Effectively unlimited
49
+ };
50
+ var RATE_LIMITS = {
51
+ free: { perMinute: 10, perDay: 100 },
52
+ starter: { perMinute: 30, perDay: 1e3 },
53
+ pro: { perMinute: 60, perDay: 5e3 },
54
+ enterprise: { perMinute: 120, perDay: 999999 }
55
+ };
56
+
57
+ // src/errors/codes.ts
58
+ var ErrorCodes = {
59
+ // Authentication Errors (VPM-AUTH-XXX)
60
+ AUTH: {
61
+ REQUIRED: {
62
+ code: "VPM-AUTH-001",
63
+ message: "Authentication required",
64
+ httpStatus: 401
65
+ },
66
+ INVALID_TOKEN: {
67
+ code: "VPM-AUTH-002",
68
+ message: "Invalid or expired authentication token",
69
+ httpStatus: 401
70
+ },
71
+ INSUFFICIENT_PERMISSIONS: {
72
+ code: "VPM-AUTH-003",
73
+ message: "Insufficient permissions for this action",
74
+ httpStatus: 403
75
+ },
76
+ SESSION_EXPIRED: {
77
+ code: "VPM-AUTH-004",
78
+ message: "Session has expired, please login again",
79
+ httpStatus: 401
80
+ },
81
+ MFA_REQUIRED: {
82
+ code: "VPM-AUTH-005",
83
+ message: "Multi-factor authentication required",
84
+ httpStatus: 403
85
+ }
86
+ },
87
+ // API Key Errors (VPM-API-KEY-XXX)
88
+ API_KEY: {
89
+ REQUIRED: {
90
+ code: "VPM-API-KEY-001",
91
+ message: "API key is required",
92
+ httpStatus: 401
93
+ },
94
+ INVALID: {
95
+ code: "VPM-API-KEY-002",
96
+ message: "Invalid API key",
97
+ httpStatus: 401
98
+ },
99
+ REVOKED: {
100
+ code: "VPM-API-KEY-003",
101
+ message: "API key has been revoked",
102
+ httpStatus: 401
103
+ },
104
+ EXPIRED: {
105
+ code: "VPM-API-KEY-004",
106
+ message: "API key has expired",
107
+ httpStatus: 401
108
+ },
109
+ RATE_LIMITED: {
110
+ code: "VPM-API-KEY-005",
111
+ message: "API key rate limit exceeded",
112
+ httpStatus: 429
113
+ },
114
+ QUOTA_EXCEEDED: {
115
+ code: "VPM-API-KEY-006",
116
+ message: "Monthly usage quota exceeded",
117
+ httpStatus: 429
118
+ }
119
+ },
120
+ // MCP Tool Errors (VPM-MCP-XXX)
121
+ MCP: {
122
+ TOOL_NOT_FOUND: {
123
+ code: "VPM-MCP-001",
124
+ message: "Requested tool not found",
125
+ httpStatus: 404
126
+ },
127
+ INVALID_ARGUMENTS: {
128
+ code: "VPM-MCP-002",
129
+ message: "Invalid tool arguments provided",
130
+ httpStatus: 400
131
+ },
132
+ EXECUTION_FAILED: {
133
+ code: "VPM-MCP-003",
134
+ message: "Tool execution failed",
135
+ httpStatus: 500
136
+ },
137
+ TIMEOUT: {
138
+ code: "VPM-MCP-004",
139
+ message: "Tool execution timed out",
140
+ httpStatus: 504
141
+ },
142
+ LLM_ERROR: {
143
+ code: "VPM-MCP-005",
144
+ message: "AI model returned an error",
145
+ httpStatus: 502
146
+ },
147
+ CONTEXT_TOO_LARGE: {
148
+ code: "VPM-MCP-006",
149
+ message: "Input context exceeds maximum size",
150
+ httpStatus: 413
151
+ }
152
+ },
153
+ // Billing Errors (VPM-BILLING-XXX)
154
+ BILLING: {
155
+ NO_SUBSCRIPTION: {
156
+ code: "VPM-BILLING-001",
157
+ message: "No active subscription found",
158
+ httpStatus: 402
159
+ },
160
+ SUBSCRIPTION_EXPIRED: {
161
+ code: "VPM-BILLING-002",
162
+ message: "Subscription has expired",
163
+ httpStatus: 402
164
+ },
165
+ PAYMENT_FAILED: {
166
+ code: "VPM-BILLING-003",
167
+ message: "Payment processing failed",
168
+ httpStatus: 402
169
+ },
170
+ FEATURE_NOT_INCLUDED: {
171
+ code: "VPM-BILLING-004",
172
+ message: "Feature not included in current plan",
173
+ httpStatus: 403
174
+ },
175
+ UPGRADE_REQUIRED: {
176
+ code: "VPM-BILLING-005",
177
+ message: "Plan upgrade required for this action",
178
+ httpStatus: 403
179
+ }
180
+ },
181
+ // Integration Errors (VPM-INT-XXX)
182
+ INTEGRATION: {
183
+ NOT_CONNECTED: {
184
+ code: "VPM-INT-001",
185
+ message: "Integration not connected",
186
+ httpStatus: 400
187
+ },
188
+ TOKEN_EXPIRED: {
189
+ code: "VPM-INT-002",
190
+ message: "Integration token expired, reconnection required",
191
+ httpStatus: 401
192
+ },
193
+ REFRESH_FAILED: {
194
+ code: "VPM-INT-003",
195
+ message: "Failed to refresh integration token",
196
+ httpStatus: 502
197
+ },
198
+ API_ERROR: {
199
+ code: "VPM-INT-004",
200
+ message: "External integration API error",
201
+ httpStatus: 502
202
+ },
203
+ RATE_LIMITED: {
204
+ code: "VPM-INT-005",
205
+ message: "Integration rate limit exceeded",
206
+ httpStatus: 429
207
+ }
208
+ },
209
+ // Validation Errors (VPM-VAL-XXX)
210
+ VALIDATION: {
211
+ REQUIRED_FIELD: {
212
+ code: "VPM-VAL-001",
213
+ message: "Required field missing",
214
+ httpStatus: 400
215
+ },
216
+ INVALID_FORMAT: {
217
+ code: "VPM-VAL-002",
218
+ message: "Invalid field format",
219
+ httpStatus: 400
220
+ },
221
+ OUT_OF_RANGE: {
222
+ code: "VPM-VAL-003",
223
+ message: "Value out of allowed range",
224
+ httpStatus: 400
225
+ },
226
+ INVALID_JSON: {
227
+ code: "VPM-VAL-004",
228
+ message: "Invalid JSON in request body",
229
+ httpStatus: 400
230
+ }
231
+ },
232
+ // System Errors (VPM-SYS-XXX)
233
+ SYSTEM: {
234
+ INTERNAL_ERROR: {
235
+ code: "VPM-SYS-001",
236
+ message: "Internal server error",
237
+ httpStatus: 500
238
+ },
239
+ DATABASE_ERROR: {
240
+ code: "VPM-SYS-002",
241
+ message: "Database operation failed",
242
+ httpStatus: 500
243
+ },
244
+ SERVICE_UNAVAILABLE: {
245
+ code: "VPM-SYS-003",
246
+ message: "Service temporarily unavailable",
247
+ httpStatus: 503
248
+ },
249
+ MAINTENANCE_MODE: {
250
+ code: "VPM-SYS-004",
251
+ message: "System is under maintenance",
252
+ httpStatus: 503
253
+ }
254
+ }
255
+ };
256
+
257
+ // src/errors/factory.ts
258
+ function generateRequestId() {
259
+ return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
260
+ }
261
+ function createError(errorDef, details, requestId) {
262
+ return {
263
+ code: errorDef.code,
264
+ message: errorDef.message,
265
+ details,
266
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
267
+ requestId: requestId || generateRequestId(),
268
+ docUrl: `https://docs.vaspera.pm/errors/${errorDef.code}`
269
+ };
270
+ }
271
+ function createErrorResponse(errorDef, details, requestId) {
272
+ return {
273
+ response: {
274
+ success: false,
275
+ error: createError(errorDef, details, requestId)
276
+ },
277
+ status: errorDef.httpStatus
278
+ };
279
+ }
280
+ function getNextResetDate() {
281
+ const now = /* @__PURE__ */ new Date();
282
+ const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
283
+ return nextMonth.toISOString();
284
+ }
285
+ var Errors = {
286
+ authRequired: (requestId) => createErrorResponse(ErrorCodes.AUTH.REQUIRED, void 0, requestId),
287
+ invalidApiKey: (requestId) => createErrorResponse(ErrorCodes.API_KEY.INVALID, void 0, requestId),
288
+ apiKeyRevoked: (requestId) => createErrorResponse(ErrorCodes.API_KEY.REVOKED, void 0, requestId),
289
+ apiKeyExpired: (requestId) => createErrorResponse(ErrorCodes.API_KEY.EXPIRED, void 0, requestId),
290
+ rateLimited: (retryAfter, requestId) => createErrorResponse(
291
+ ErrorCodes.API_KEY.RATE_LIMITED,
292
+ { retryAfterSeconds: retryAfter },
293
+ requestId
294
+ ),
295
+ quotaExceeded: (currentUsage, limit, requestId) => createErrorResponse(
296
+ ErrorCodes.API_KEY.QUOTA_EXCEEDED,
297
+ { currentUsage, limit, resetDate: getNextResetDate() },
298
+ requestId
299
+ ),
300
+ toolNotFound: (toolName, requestId) => createErrorResponse(
301
+ ErrorCodes.MCP.TOOL_NOT_FOUND,
302
+ { tool: toolName },
303
+ requestId
304
+ ),
305
+ toolExecutionFailed: (toolName, reason, requestId) => createErrorResponse(
306
+ ErrorCodes.MCP.EXECUTION_FAILED,
307
+ { tool: toolName, reason },
308
+ requestId
309
+ ),
310
+ toolTimeout: (toolName, timeoutMs, requestId) => createErrorResponse(
311
+ ErrorCodes.MCP.TIMEOUT,
312
+ { tool: toolName, timeoutMs },
313
+ requestId
314
+ ),
315
+ validationFailed: (field, reason, requestId) => createErrorResponse(
316
+ ErrorCodes.VALIDATION.REQUIRED_FIELD,
317
+ { field, reason },
318
+ requestId
319
+ ),
320
+ invalidFormat: (field, expected, requestId) => createErrorResponse(
321
+ ErrorCodes.VALIDATION.INVALID_FORMAT,
322
+ { field, expected },
323
+ requestId
324
+ ),
325
+ internalError: (message, requestId) => createErrorResponse(
326
+ ErrorCodes.SYSTEM.INTERNAL_ERROR,
327
+ message ? { message } : void 0,
328
+ requestId
329
+ ),
330
+ databaseError: (operation, requestId) => createErrorResponse(
331
+ ErrorCodes.SYSTEM.DATABASE_ERROR,
332
+ { operation },
333
+ requestId
334
+ ),
335
+ integrationNotConnected: (provider, requestId) => createErrorResponse(
336
+ ErrorCodes.INTEGRATION.NOT_CONNECTED,
337
+ { provider },
338
+ requestId
339
+ ),
340
+ subscriptionRequired: (feature, requiredTier, requestId) => createErrorResponse(
341
+ ErrorCodes.BILLING.FEATURE_NOT_INCLUDED,
342
+ { feature, requiredTier },
343
+ requestId
344
+ )
345
+ };
346
+ var VasperaApiError = class extends Error {
347
+ errorDef;
348
+ details;
349
+ constructor(errorDef, details) {
350
+ super(errorDef.message);
351
+ this.name = "VasperaApiError";
352
+ this.errorDef = errorDef;
353
+ this.details = details;
354
+ }
355
+ toResponse(requestId) {
356
+ return createErrorResponse(this.errorDef, this.details, requestId);
357
+ }
358
+ };
359
+
360
+ // src/utils/api-key.ts
361
+ var import_crypto = require("crypto");
362
+ var API_KEY_PREFIX_LIVE = "vpm_live_";
363
+ var API_KEY_PREFIX_TEST = "vpm_test_";
364
+ var API_KEY_RANDOM_BYTES = 24;
365
+ function generateApiKey(environment = "live") {
366
+ const prefix = environment === "live" ? API_KEY_PREFIX_LIVE : API_KEY_PREFIX_TEST;
367
+ const randomPart = (0, import_crypto.randomBytes)(API_KEY_RANDOM_BYTES).toString("base64url").slice(0, 32);
368
+ const key = `${prefix}${randomPart}`;
369
+ const keyPrefix = key.slice(0, 16);
370
+ const keyHash = hashApiKey(key);
371
+ return {
372
+ key,
373
+ keyPrefix,
374
+ keyHash
375
+ };
376
+ }
377
+ function hashApiKey(key) {
378
+ return (0, import_crypto.createHash)("sha256").update(key).digest("hex");
379
+ }
380
+ function isValidApiKeyFormat(key) {
381
+ const livePattern = /^vpm_live_[a-zA-Z0-9_-]{32}$/;
382
+ const testPattern = /^vpm_test_[a-zA-Z0-9_-]{32}$/;
383
+ return livePattern.test(key) || testPattern.test(key);
384
+ }
385
+ function extractKeyPrefix(key) {
386
+ return key.slice(0, 16);
387
+ }
388
+ function isTestKey(key) {
389
+ return key.startsWith(API_KEY_PREFIX_TEST);
390
+ }
391
+ function maskApiKey(key) {
392
+ if (key.length < 24) return key;
393
+ return `${key.slice(0, 16)}...${key.slice(-4)}`;
394
+ }
395
+
396
+ // src/utils/encryption.ts
397
+ var import_crypto2 = require("crypto");
398
+ var import_util = require("util");
399
+ var scryptAsync = (0, import_util.promisify)(import_crypto2.scrypt);
400
+ var ALGORITHM = "aes-256-gcm";
401
+ var IV_LENGTH = 16;
402
+ var SALT_LENGTH = 32;
403
+ var KEY_LENGTH = 32;
404
+ async function encrypt(text, secret) {
405
+ const salt = (0, import_crypto2.randomBytes)(SALT_LENGTH);
406
+ const iv = (0, import_crypto2.randomBytes)(IV_LENGTH);
407
+ const key = await scryptAsync(secret, salt, KEY_LENGTH);
408
+ const cipher = (0, import_crypto2.createCipheriv)(ALGORITHM, key, iv);
409
+ const encrypted = Buffer.concat([
410
+ cipher.update(text, "utf8"),
411
+ cipher.final()
412
+ ]);
413
+ const tag = cipher.getAuthTag();
414
+ return [
415
+ salt.toString("base64"),
416
+ iv.toString("base64"),
417
+ tag.toString("base64"),
418
+ encrypted.toString("base64")
419
+ ].join(":");
420
+ }
421
+ async function decrypt(encryptedText, secret) {
422
+ const parts = encryptedText.split(":");
423
+ if (parts.length !== 4) {
424
+ throw new Error("Invalid encrypted text format");
425
+ }
426
+ const [saltB64, ivB64, tagB64, encryptedB64] = parts;
427
+ const salt = Buffer.from(saltB64, "base64");
428
+ const iv = Buffer.from(ivB64, "base64");
429
+ const tag = Buffer.from(tagB64, "base64");
430
+ const encrypted = Buffer.from(encryptedB64, "base64");
431
+ const key = await scryptAsync(secret, salt, KEY_LENGTH);
432
+ const decipher = (0, import_crypto2.createDecipheriv)(ALGORITHM, key, iv);
433
+ decipher.setAuthTag(tag);
434
+ return decipher.update(encrypted) + decipher.final("utf8");
435
+ }
436
+ function generateEncryptionSecret() {
437
+ return (0, import_crypto2.randomBytes)(32).toString("hex");
438
+ }
439
+ // Annotate the CommonJS export names for ESM import in node:
440
+ 0 && (module.exports = {
441
+ ErrorCodes,
442
+ Errors,
443
+ QUOTA_LIMITS,
444
+ RATE_LIMITS,
445
+ VasperaApiError,
446
+ createError,
447
+ createErrorResponse,
448
+ decrypt,
449
+ encrypt,
450
+ extractKeyPrefix,
451
+ generateApiKey,
452
+ generateEncryptionSecret,
453
+ hashApiKey,
454
+ isTestKey,
455
+ isValidApiKeyFormat,
456
+ maskApiKey
457
+ });
458
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types/index.ts","../src/errors/codes.ts","../src/errors/factory.ts","../src/utils/api-key.ts","../src/utils/encryption.ts"],"sourcesContent":["// Types\nexport * from './types/index.js';\n\n// Errors\nexport * from './errors/index.js';\n\n// Utilities\nexport * from './utils/index.js';\n","// Subscription Types\nexport type SubscriptionTier = 'free' | 'starter' | 'pro' | 'enterprise';\nexport type SubscriptionStatus = 'active' | 'canceled' | 'past_due' | 'trialing' | 'incomplete';\n\n// User Profile\nexport interface UserProfile {\n id: string;\n email: string;\n fullName: string | null;\n avatarUrl: string | null;\n subscriptionTier: SubscriptionTier;\n subscriptionStatus: SubscriptionStatus;\n stripeCustomerId: string | null;\n stripeSubscriptionId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n// API Key\nexport interface ApiKey {\n id: string;\n userId: string;\n name: string;\n keyPrefix: string;\n lastUsedAt: string | null;\n expiresAt: string | null;\n revokedAt: string | null;\n createdAt: string;\n}\n\nexport interface ApiKeyWithSecret extends Omit<ApiKey, 'revokedAt'> {\n key: string; // Full key (only shown once)\n}\n\n// Usage\nexport interface UsageEvent {\n id: string;\n userId: string;\n apiKeyId: string | null;\n toolName: string;\n tokensUsed: number;\n latencyMs: number | null;\n success: boolean;\n errorCode: string | null;\n requestId: string | null;\n metadata: Record<string, unknown>;\n createdAt: string;\n}\n\nexport interface UsageSummary {\n period: {\n start: string;\n end: string;\n };\n summary: {\n totalToolCalls: number;\n totalTokensUsed: number;\n quotaUsed: number;\n quotaLimit: number;\n quotaPercentage: number;\n };\n byTool: Array<{\n tool: string;\n calls: number;\n tokensUsed: number;\n avgLatencyMs: number;\n }>;\n}\n\n// Quota Limits by Tier\nexport const QUOTA_LIMITS: Record<SubscriptionTier, number> = {\n free: 5,\n starter: 100,\n pro: 500,\n enterprise: 999999, // Effectively unlimited\n};\n\nexport const RATE_LIMITS: Record<SubscriptionTier, { perMinute: number; perDay: number }> = {\n free: { perMinute: 10, perDay: 100 },\n starter: { perMinute: 30, perDay: 1000 },\n pro: { perMinute: 60, perDay: 5000 },\n enterprise: { perMinute: 120, perDay: 999999 },\n};\n\n// Integration Types\nexport type IntegrationProvider = 'jira' | 'linear' | 'github' | 'gitlab' | 'asana';\n\nexport interface IntegrationToken {\n id: string;\n userId: string;\n provider: IntegrationProvider;\n tokenType: string;\n expiresAt: string | null;\n scopes: string[] | null;\n providerUserId: string | null;\n providerEmail: string | null;\n metadata: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface IntegrationStatus {\n provider: IntegrationProvider;\n connected: boolean;\n connectedAt?: string;\n providerEmail?: string;\n scopes?: string[];\n metadata?: Record<string, unknown>;\n}\n\n// MCP Tool Types\nexport type McpToolName =\n | 'synthesize_requirements'\n | 'review_prd'\n | 'explode_backlog'\n | 'generate_architecture'\n | 'sync_to_tracker'\n | 'infer_prd_from_code'\n | 'reverse_engineer_user_flows'\n | 'generate_test_specs'\n | 'explain_codebase'\n | 'validate_implementation'\n | 'suggest_refactors'\n | 'generate_api_docs'\n | 'dependency_audit'\n | 'estimate_migration';\n\nexport interface McpToolResult<T = unknown> {\n content: Array<{\n type: 'text' | 'image' | 'resource';\n text?: string;\n data?: string;\n mimeType?: string;\n }>;\n data?: T;\n tokensUsed?: number;\n isError?: boolean;\n}\n\n// API Response Types\nexport interface ApiSuccessResponse<T> {\n success: true;\n data: T;\n meta?: {\n requestId: string;\n timestamp: string;\n };\n}\n\nexport interface ApiErrorResponse {\n success: false;\n error: {\n code: string;\n message: string;\n details?: Record<string, unknown>;\n docUrl?: string;\n };\n meta?: {\n requestId: string;\n timestamp: string;\n };\n}\n\nexport type ApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;\n","export interface ErrorDefinition {\n code: string;\n message: string;\n httpStatus: number;\n}\n\nexport const ErrorCodes = {\n // Authentication Errors (VPM-AUTH-XXX)\n AUTH: {\n REQUIRED: {\n code: 'VPM-AUTH-001',\n message: 'Authentication required',\n httpStatus: 401,\n },\n INVALID_TOKEN: {\n code: 'VPM-AUTH-002',\n message: 'Invalid or expired authentication token',\n httpStatus: 401,\n },\n INSUFFICIENT_PERMISSIONS: {\n code: 'VPM-AUTH-003',\n message: 'Insufficient permissions for this action',\n httpStatus: 403,\n },\n SESSION_EXPIRED: {\n code: 'VPM-AUTH-004',\n message: 'Session has expired, please login again',\n httpStatus: 401,\n },\n MFA_REQUIRED: {\n code: 'VPM-AUTH-005',\n message: 'Multi-factor authentication required',\n httpStatus: 403,\n },\n },\n\n // API Key Errors (VPM-API-KEY-XXX)\n API_KEY: {\n REQUIRED: {\n code: 'VPM-API-KEY-001',\n message: 'API key is required',\n httpStatus: 401,\n },\n INVALID: {\n code: 'VPM-API-KEY-002',\n message: 'Invalid API key',\n httpStatus: 401,\n },\n REVOKED: {\n code: 'VPM-API-KEY-003',\n message: 'API key has been revoked',\n httpStatus: 401,\n },\n EXPIRED: {\n code: 'VPM-API-KEY-004',\n message: 'API key has expired',\n httpStatus: 401,\n },\n RATE_LIMITED: {\n code: 'VPM-API-KEY-005',\n message: 'API key rate limit exceeded',\n httpStatus: 429,\n },\n QUOTA_EXCEEDED: {\n code: 'VPM-API-KEY-006',\n message: 'Monthly usage quota exceeded',\n httpStatus: 429,\n },\n },\n\n // MCP Tool Errors (VPM-MCP-XXX)\n MCP: {\n TOOL_NOT_FOUND: {\n code: 'VPM-MCP-001',\n message: 'Requested tool not found',\n httpStatus: 404,\n },\n INVALID_ARGUMENTS: {\n code: 'VPM-MCP-002',\n message: 'Invalid tool arguments provided',\n httpStatus: 400,\n },\n EXECUTION_FAILED: {\n code: 'VPM-MCP-003',\n message: 'Tool execution failed',\n httpStatus: 500,\n },\n TIMEOUT: {\n code: 'VPM-MCP-004',\n message: 'Tool execution timed out',\n httpStatus: 504,\n },\n LLM_ERROR: {\n code: 'VPM-MCP-005',\n message: 'AI model returned an error',\n httpStatus: 502,\n },\n CONTEXT_TOO_LARGE: {\n code: 'VPM-MCP-006',\n message: 'Input context exceeds maximum size',\n httpStatus: 413,\n },\n },\n\n // Billing Errors (VPM-BILLING-XXX)\n BILLING: {\n NO_SUBSCRIPTION: {\n code: 'VPM-BILLING-001',\n message: 'No active subscription found',\n httpStatus: 402,\n },\n SUBSCRIPTION_EXPIRED: {\n code: 'VPM-BILLING-002',\n message: 'Subscription has expired',\n httpStatus: 402,\n },\n PAYMENT_FAILED: {\n code: 'VPM-BILLING-003',\n message: 'Payment processing failed',\n httpStatus: 402,\n },\n FEATURE_NOT_INCLUDED: {\n code: 'VPM-BILLING-004',\n message: 'Feature not included in current plan',\n httpStatus: 403,\n },\n UPGRADE_REQUIRED: {\n code: 'VPM-BILLING-005',\n message: 'Plan upgrade required for this action',\n httpStatus: 403,\n },\n },\n\n // Integration Errors (VPM-INT-XXX)\n INTEGRATION: {\n NOT_CONNECTED: {\n code: 'VPM-INT-001',\n message: 'Integration not connected',\n httpStatus: 400,\n },\n TOKEN_EXPIRED: {\n code: 'VPM-INT-002',\n message: 'Integration token expired, reconnection required',\n httpStatus: 401,\n },\n REFRESH_FAILED: {\n code: 'VPM-INT-003',\n message: 'Failed to refresh integration token',\n httpStatus: 502,\n },\n API_ERROR: {\n code: 'VPM-INT-004',\n message: 'External integration API error',\n httpStatus: 502,\n },\n RATE_LIMITED: {\n code: 'VPM-INT-005',\n message: 'Integration rate limit exceeded',\n httpStatus: 429,\n },\n },\n\n // Validation Errors (VPM-VAL-XXX)\n VALIDATION: {\n REQUIRED_FIELD: {\n code: 'VPM-VAL-001',\n message: 'Required field missing',\n httpStatus: 400,\n },\n INVALID_FORMAT: {\n code: 'VPM-VAL-002',\n message: 'Invalid field format',\n httpStatus: 400,\n },\n OUT_OF_RANGE: {\n code: 'VPM-VAL-003',\n message: 'Value out of allowed range',\n httpStatus: 400,\n },\n INVALID_JSON: {\n code: 'VPM-VAL-004',\n message: 'Invalid JSON in request body',\n httpStatus: 400,\n },\n },\n\n // System Errors (VPM-SYS-XXX)\n SYSTEM: {\n INTERNAL_ERROR: {\n code: 'VPM-SYS-001',\n message: 'Internal server error',\n httpStatus: 500,\n },\n DATABASE_ERROR: {\n code: 'VPM-SYS-002',\n message: 'Database operation failed',\n httpStatus: 500,\n },\n SERVICE_UNAVAILABLE: {\n code: 'VPM-SYS-003',\n message: 'Service temporarily unavailable',\n httpStatus: 503,\n },\n MAINTENANCE_MODE: {\n code: 'VPM-SYS-004',\n message: 'System is under maintenance',\n httpStatus: 503,\n },\n },\n} as const;\n\nexport type ErrorCodeType =\n (typeof ErrorCodes)[keyof typeof ErrorCodes][keyof (typeof ErrorCodes)[keyof typeof ErrorCodes]];\n","import type { ErrorDefinition } from './codes.js';\nimport { ErrorCodes } from './codes.js';\n\nexport interface VasperaError {\n code: string;\n message: string;\n details?: Record<string, unknown>;\n timestamp: string;\n requestId: string;\n docUrl?: string;\n}\n\nexport interface ErrorResponse {\n success: false;\n error: VasperaError;\n}\n\nfunction generateRequestId(): string {\n return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;\n}\n\nexport function createError(\n errorDef: ErrorDefinition,\n details?: Record<string, unknown>,\n requestId?: string\n): VasperaError {\n return {\n code: errorDef.code,\n message: errorDef.message,\n details,\n timestamp: new Date().toISOString(),\n requestId: requestId || generateRequestId(),\n docUrl: `https://docs.vaspera.pm/errors/${errorDef.code}`,\n };\n}\n\nexport function createErrorResponse(\n errorDef: ErrorDefinition,\n details?: Record<string, unknown>,\n requestId?: string\n): { response: ErrorResponse; status: number } {\n return {\n response: {\n success: false,\n error: createError(errorDef, details, requestId),\n },\n status: errorDef.httpStatus,\n };\n}\n\nfunction getNextResetDate(): string {\n const now = new Date();\n const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);\n return nextMonth.toISOString();\n}\n\n// Pre-built error creators for common cases\nexport const Errors = {\n authRequired: (requestId?: string) =>\n createErrorResponse(ErrorCodes.AUTH.REQUIRED, undefined, requestId),\n\n invalidApiKey: (requestId?: string) =>\n createErrorResponse(ErrorCodes.API_KEY.INVALID, undefined, requestId),\n\n apiKeyRevoked: (requestId?: string) =>\n createErrorResponse(ErrorCodes.API_KEY.REVOKED, undefined, requestId),\n\n apiKeyExpired: (requestId?: string) =>\n createErrorResponse(ErrorCodes.API_KEY.EXPIRED, undefined, requestId),\n\n rateLimited: (retryAfter: number, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.API_KEY.RATE_LIMITED,\n { retryAfterSeconds: retryAfter },\n requestId\n ),\n\n quotaExceeded: (currentUsage: number, limit: number, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.API_KEY.QUOTA_EXCEEDED,\n { currentUsage, limit, resetDate: getNextResetDate() },\n requestId\n ),\n\n toolNotFound: (toolName: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.MCP.TOOL_NOT_FOUND,\n { tool: toolName },\n requestId\n ),\n\n toolExecutionFailed: (toolName: string, reason: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.MCP.EXECUTION_FAILED,\n { tool: toolName, reason },\n requestId\n ),\n\n toolTimeout: (toolName: string, timeoutMs: number, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.MCP.TIMEOUT,\n { tool: toolName, timeoutMs },\n requestId\n ),\n\n validationFailed: (field: string, reason: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.VALIDATION.REQUIRED_FIELD,\n { field, reason },\n requestId\n ),\n\n invalidFormat: (field: string, expected: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.VALIDATION.INVALID_FORMAT,\n { field, expected },\n requestId\n ),\n\n internalError: (message?: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.SYSTEM.INTERNAL_ERROR,\n message ? { message } : undefined,\n requestId\n ),\n\n databaseError: (operation: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.SYSTEM.DATABASE_ERROR,\n { operation },\n requestId\n ),\n\n integrationNotConnected: (provider: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.INTEGRATION.NOT_CONNECTED,\n { provider },\n requestId\n ),\n\n subscriptionRequired: (feature: string, requiredTier: string, requestId?: string) =>\n createErrorResponse(\n ErrorCodes.BILLING.FEATURE_NOT_INCLUDED,\n { feature, requiredTier },\n requestId\n ),\n};\n\n// Custom error class for throwing in API routes\nexport class VasperaApiError extends Error {\n public readonly errorDef: ErrorDefinition;\n public readonly details?: Record<string, unknown>;\n\n constructor(errorDef: ErrorDefinition, details?: Record<string, unknown>) {\n super(errorDef.message);\n this.name = 'VasperaApiError';\n this.errorDef = errorDef;\n this.details = details;\n }\n\n toResponse(requestId?: string): { response: ErrorResponse; status: number } {\n return createErrorResponse(this.errorDef, this.details, requestId);\n }\n}\n","import { randomBytes, createHash } from 'crypto';\n\nconst API_KEY_PREFIX_LIVE = 'vpm_live_';\nconst API_KEY_PREFIX_TEST = 'vpm_test_';\nconst API_KEY_RANDOM_BYTES = 24; // 32 chars in base64url\n\nexport interface GeneratedApiKey {\n key: string; // Full key to show user once\n keyPrefix: string; // First 16 chars for identification\n keyHash: string; // Hash for storage and validation\n}\n\n/**\n * Generate a new API key\n * @param environment - 'live' or 'test'\n * @returns Generated key with prefix and hash\n */\nexport function generateApiKey(environment: 'live' | 'test' = 'live'): GeneratedApiKey {\n const prefix = environment === 'live' ? API_KEY_PREFIX_LIVE : API_KEY_PREFIX_TEST;\n const randomPart = randomBytes(API_KEY_RANDOM_BYTES)\n .toString('base64url')\n .slice(0, 32);\n\n const key = `${prefix}${randomPart}`;\n const keyPrefix = key.slice(0, 16);\n const keyHash = hashApiKey(key);\n\n return {\n key,\n keyPrefix,\n keyHash,\n };\n}\n\n/**\n * Hash an API key for storage\n * Using SHA-256 since we need to look up by hash\n */\nexport function hashApiKey(key: string): string {\n return createHash('sha256').update(key).digest('hex');\n}\n\n/**\n * Validate API key format\n */\nexport function isValidApiKeyFormat(key: string): boolean {\n const livePattern = /^vpm_live_[a-zA-Z0-9_-]{32}$/;\n const testPattern = /^vpm_test_[a-zA-Z0-9_-]{32}$/;\n return livePattern.test(key) || testPattern.test(key);\n}\n\n/**\n * Extract prefix from API key\n */\nexport function extractKeyPrefix(key: string): string {\n return key.slice(0, 16);\n}\n\n/**\n * Check if key is a test key\n */\nexport function isTestKey(key: string): boolean {\n return key.startsWith(API_KEY_PREFIX_TEST);\n}\n\n/**\n * Mask an API key for display (show first 16 and last 4 chars)\n */\nexport function maskApiKey(key: string): string {\n if (key.length < 24) return key;\n return `${key.slice(0, 16)}...${key.slice(-4)}`;\n}\n","import {\n createCipheriv,\n createDecipheriv,\n randomBytes,\n scrypt,\n} from 'crypto';\nimport { promisify } from 'util';\n\nconst scryptAsync = promisify(scrypt);\nconst ALGORITHM = 'aes-256-gcm';\nconst IV_LENGTH = 16;\nconst SALT_LENGTH = 32;\nconst TAG_LENGTH = 16;\nconst KEY_LENGTH = 32;\n\n/**\n * Encrypt text using AES-256-GCM\n * @param text - Plain text to encrypt\n * @param secret - Encryption secret\n * @returns Encrypted string in format: salt:iv:tag:ciphertext (all base64)\n */\nexport async function encrypt(text: string, secret: string): Promise<string> {\n const salt = randomBytes(SALT_LENGTH);\n const iv = randomBytes(IV_LENGTH);\n const key = (await scryptAsync(secret, salt, KEY_LENGTH)) as Buffer;\n\n const cipher = createCipheriv(ALGORITHM, key, iv);\n const encrypted = Buffer.concat([\n cipher.update(text, 'utf8'),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n\n // Format: salt:iv:tag:encrypted (all base64)\n return [\n salt.toString('base64'),\n iv.toString('base64'),\n tag.toString('base64'),\n encrypted.toString('base64'),\n ].join(':');\n}\n\n/**\n * Decrypt text that was encrypted with encrypt()\n * @param encryptedText - Encrypted string in format: salt:iv:tag:ciphertext\n * @param secret - Encryption secret (must match encryption)\n * @returns Decrypted plain text\n */\nexport async function decrypt(\n encryptedText: string,\n secret: string\n): Promise<string> {\n const parts = encryptedText.split(':');\n if (parts.length !== 4) {\n throw new Error('Invalid encrypted text format');\n }\n\n const [saltB64, ivB64, tagB64, encryptedB64] = parts;\n\n const salt = Buffer.from(saltB64!, 'base64');\n const iv = Buffer.from(ivB64!, 'base64');\n const tag = Buffer.from(tagB64!, 'base64');\n const encrypted = Buffer.from(encryptedB64!, 'base64');\n\n const key = (await scryptAsync(secret, salt, KEY_LENGTH)) as Buffer;\n\n const decipher = createDecipheriv(ALGORITHM, key, iv);\n decipher.setAuthTag(tag);\n\n return decipher.update(encrypted) + decipher.final('utf8');\n}\n\n/**\n * Generate a random encryption secret\n * @returns 32-byte hex string suitable for use as encryption secret\n */\nexport function generateEncryptionSecret(): string {\n return randomBytes(32).toString('hex');\n}\n"],"mappings":"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","names":["import_crypto"]}