@forgedevstack/harbor 1.0.0 → 1.5.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 (123) hide show
  1. package/CHANGELOG.md +82 -101
  2. package/README.md +210 -794
  3. package/dist/auth/apiKey.d.ts +6 -0
  4. package/dist/auth/apiKey.d.ts.map +1 -0
  5. package/dist/auth/index.d.ts +7 -0
  6. package/dist/auth/index.d.ts.map +1 -0
  7. package/dist/auth/index.js +2 -0
  8. package/dist/auth/index.js.map +1 -0
  9. package/dist/auth/jwt.d.ts +21 -0
  10. package/dist/auth/jwt.d.ts.map +1 -0
  11. package/dist/auth/password.d.ts +6 -0
  12. package/dist/auth/password.d.ts.map +1 -0
  13. package/dist/auth/rbac.d.ts +6 -0
  14. package/dist/auth/rbac.d.ts.map +1 -0
  15. package/dist/auth/signing.d.ts +5 -0
  16. package/dist/auth/signing.d.ts.map +1 -0
  17. package/dist/auth/types/apiKey.types.d.ts +9 -0
  18. package/dist/auth/types/apiKey.types.d.ts.map +1 -0
  19. package/dist/auth/types/index.d.ts +5 -0
  20. package/dist/auth/types/index.d.ts.map +1 -0
  21. package/dist/auth/types/jwt.types.d.ts +17 -0
  22. package/dist/auth/types/jwt.types.d.ts.map +1 -0
  23. package/dist/auth/types/rbac.types.d.ts +8 -0
  24. package/dist/auth/types/rbac.types.d.ts.map +1 -0
  25. package/dist/auth/types/signing.types.d.ts +8 -0
  26. package/dist/auth/types/signing.types.d.ts.map +1 -0
  27. package/dist/cache/index.d.ts +4 -0
  28. package/dist/cache/index.d.ts.map +1 -0
  29. package/dist/cache/index.js +2 -0
  30. package/dist/cache/index.js.map +1 -0
  31. package/dist/cache/manager.d.ts +24 -0
  32. package/dist/cache/manager.d.ts.map +1 -0
  33. package/dist/cache/stores.d.ts +28 -0
  34. package/dist/cache/stores.d.ts.map +1 -0
  35. package/dist/cache/types.d.ts +23 -0
  36. package/dist/cache/types.d.ts.map +1 -0
  37. package/dist/cli/index.js +21 -22
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/core/config.d.ts.map +1 -1
  40. package/dist/core/router.d.ts +40 -2
  41. package/dist/core/router.d.ts.map +1 -1
  42. package/dist/core/server.d.ts.map +1 -1
  43. package/dist/database/connection.d.ts +1 -2
  44. package/dist/database/connection.d.ts.map +1 -1
  45. package/dist/database/index.js +2 -0
  46. package/dist/database/index.js.map +1 -0
  47. package/dist/database/model.d.ts +1 -4
  48. package/dist/database/model.d.ts.map +1 -1
  49. package/dist/docker/index.js +1 -1
  50. package/dist/http.const-BKHG1Lsj.mjs +62 -0
  51. package/dist/http.const-BKHG1Lsj.mjs.map +1 -0
  52. package/dist/http.const-Ckcy7OFp.js +2 -0
  53. package/dist/http.const-Ckcy7OFp.js.map +1 -0
  54. package/dist/index-Ca4WpLvw.js +2 -0
  55. package/dist/index-Ca4WpLvw.js.map +1 -0
  56. package/dist/index-DIVHd6rO.mjs +1054 -0
  57. package/dist/index-DIVHd6rO.mjs.map +1 -0
  58. package/dist/index.cjs.js +16 -16
  59. package/dist/index.cjs.js.map +1 -1
  60. package/dist/index.d.ts +11 -2
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.es.js +676 -1691
  63. package/dist/index.es.js.map +1 -1
  64. package/dist/logger-CZn7QxCl.mjs +102 -0
  65. package/dist/{logger-D7aJSi62.mjs.map → logger-CZn7QxCl.mjs.map} +1 -1
  66. package/dist/logger-D-lfaRWQ.js +3 -0
  67. package/dist/{logger-DEnWXtpk.js.map → logger-D-lfaRWQ.js.map} +1 -1
  68. package/dist/manager-CjcKb4P9.mjs +149 -0
  69. package/dist/{manager-B6vqJgEn.mjs.map → manager-CjcKb4P9.mjs.map} +1 -1
  70. package/dist/manager-DrF1vbJg.js +4 -0
  71. package/dist/{manager-B1UKMjXW.js.map → manager-DrF1vbJg.js.map} +1 -1
  72. package/dist/middleware/health.d.ts +65 -0
  73. package/dist/middleware/health.d.ts.map +1 -0
  74. package/dist/middleware/index.d.ts +5 -0
  75. package/dist/middleware/index.d.ts.map +1 -0
  76. package/dist/middleware/index.js +2 -0
  77. package/dist/middleware/index.js.map +1 -0
  78. package/dist/middleware/metrics.d.ts +68 -0
  79. package/dist/middleware/metrics.d.ts.map +1 -0
  80. package/dist/middleware/rateLimit.d.ts +52 -0
  81. package/dist/middleware/rateLimit.d.ts.map +1 -0
  82. package/dist/middleware/upload.d.ts +59 -0
  83. package/dist/middleware/upload.d.ts.map +1 -0
  84. package/dist/password-BXBkKbv3.js +2 -0
  85. package/dist/password-BXBkKbv3.js.map +1 -0
  86. package/dist/password-y4m307oa.mjs +223 -0
  87. package/dist/password-y4m307oa.mjs.map +1 -0
  88. package/dist/scheduler/index.d.ts +3 -0
  89. package/dist/scheduler/index.d.ts.map +1 -0
  90. package/dist/scheduler/index.js +2 -0
  91. package/dist/scheduler/index.js.map +1 -0
  92. package/dist/scheduler/scheduler.d.ts +30 -0
  93. package/dist/scheduler/scheduler.d.ts.map +1 -0
  94. package/dist/scheduler/types.d.ts +25 -0
  95. package/dist/scheduler/types.d.ts.map +1 -0
  96. package/dist/types/server.types.d.ts +7 -0
  97. package/dist/types/server.types.d.ts.map +1 -1
  98. package/dist/upload-9lCNnKK_.js +5 -0
  99. package/dist/upload-9lCNnKK_.js.map +1 -0
  100. package/dist/upload-DUjQiuq7.mjs +619 -0
  101. package/dist/upload-DUjQiuq7.mjs.map +1 -0
  102. package/dist/validation/index.js +1 -1
  103. package/dist/validation/index.js.map +1 -1
  104. package/dist/websocket/index.d.ts +3 -0
  105. package/dist/websocket/index.d.ts.map +1 -0
  106. package/dist/websocket/index.js +2 -0
  107. package/dist/websocket/index.js.map +1 -0
  108. package/dist/websocket/manager.d.ts +30 -0
  109. package/dist/websocket/manager.d.ts.map +1 -0
  110. package/dist/websocket/types.d.ts +27 -0
  111. package/dist/websocket/types.d.ts.map +1 -0
  112. package/package.json +58 -18
  113. package/templates/default/controllers/user.controller.ts +44 -64
  114. package/templates/default/package.json +9 -33
  115. package/templates/default/routes/index.ts +2 -12
  116. package/templates/default/routes/user.routes.ts +26 -19
  117. package/templates/default/server.ts +16 -35
  118. package/dist/logger-D7aJSi62.mjs +0 -102
  119. package/dist/logger-DEnWXtpk.js +0 -3
  120. package/dist/manager-B1UKMjXW.js +0 -4
  121. package/dist/manager-B6vqJgEn.mjs +0 -152
  122. package/dist/portal.d.ts +0 -13
  123. package/dist/portal.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-DUjQiuq7.mjs","sources":["../src/middleware/rateLimit.ts","../src/middleware/health.ts","../src/middleware/metrics.ts","../src/middleware/upload.ts"],"sourcesContent":["// Rate Limiting Middleware for Harbor\nimport { RequestHandler } from 'express';\nimport { createLogger } from '../utils/logger';\nimport { HTTP_STATUS } from '../constants';\n\nconst logger = createLogger('rate-limit');\n\nexport interface RateLimitOptions {\n windowMs?: number;\n max?: number;\n message?: string;\n statusCode?: number;\n keyGenerator?: (req: any) => string;\n skip?: (req: any) => boolean;\n onLimitReached?: (req: any, res: any) => void;\n headers?: boolean;\n store?: RateLimitStore;\n}\n\nexport interface RateLimitStore {\n increment(key: string): Promise<RateLimitInfo>;\n decrement(key: string): Promise<void>;\n resetKey(key: string): Promise<void>;\n get(key: string): Promise<RateLimitInfo | null>;\n}\n\nexport interface RateLimitInfo {\n count: number;\n resetTime: number;\n}\n\n// In-memory store (default)\nclass MemoryStore implements RateLimitStore {\n private hits: Map<string, RateLimitInfo> = new Map();\n private windowMs: number;\n\n constructor(windowMs: number) {\n this.windowMs = windowMs;\n \n // Clean up expired entries periodically\n setInterval(() => this.cleanup(), windowMs);\n }\n\n async increment(key: string): Promise<RateLimitInfo> {\n const now = Date.now();\n const existing = this.hits.get(key);\n\n if (existing && existing.resetTime > now) {\n existing.count++;\n return existing;\n }\n\n const info: RateLimitInfo = {\n count: 1,\n resetTime: now + this.windowMs,\n };\n this.hits.set(key, info);\n return info;\n }\n\n async decrement(key: string): Promise<void> {\n const existing = this.hits.get(key);\n if (existing && existing.count > 0) {\n existing.count--;\n }\n }\n\n async resetKey(key: string): Promise<void> {\n this.hits.delete(key);\n }\n\n async get(key: string): Promise<RateLimitInfo | null> {\n return this.hits.get(key) || null;\n }\n\n private cleanup(): void {\n const now = Date.now();\n for (const [key, info] of this.hits.entries()) {\n if (info.resetTime <= now) {\n this.hits.delete(key);\n }\n }\n }\n}\n\n// Redis store for distributed rate limiting\nexport class RedisStore implements RateLimitStore {\n private client: any;\n private windowMs: number;\n private prefix: string;\n\n constructor(client: any, windowMs: number, prefix = 'rl:') {\n this.client = client;\n this.windowMs = windowMs;\n this.prefix = prefix;\n }\n\n async increment(key: string): Promise<RateLimitInfo> {\n const redisKey = this.prefix + key;\n const multi = this.client.multi();\n \n multi.incr(redisKey);\n multi.pttl(redisKey);\n \n const results = await multi.exec();\n const count = results[0][1];\n let ttl = results[1][1];\n\n if (ttl === -1) {\n await this.client.pexpire(redisKey, this.windowMs);\n ttl = this.windowMs;\n }\n\n return {\n count,\n resetTime: Date.now() + ttl,\n };\n }\n\n async decrement(key: string): Promise<void> {\n await this.client.decr(this.prefix + key);\n }\n\n async resetKey(key: string): Promise<void> {\n await this.client.del(this.prefix + key);\n }\n\n async get(key: string): Promise<RateLimitInfo | null> {\n const redisKey = this.prefix + key;\n const [count, ttl] = await Promise.all([\n this.client.get(redisKey),\n this.client.pttl(redisKey),\n ]);\n\n if (count === null) return null;\n\n return {\n count: parseInt(count, 10),\n resetTime: Date.now() + Math.max(ttl, 0),\n };\n }\n}\n\n/**\n * Create a rate limiting middleware\n * \n * @example\n * // Basic usage - 100 requests per 15 minutes\n * app.use(rateLimit({ max: 100 }));\n * \n * // Per-route rate limiting\n * app.post('/api/login', rateLimit({ max: 5, windowMs: 60000 }), loginHandler);\n * \n * // With Redis for distributed systems\n * app.use(rateLimit({ store: new RedisStore(redisClient, 900000) }));\n */\nexport function rateLimit(options: RateLimitOptions = {}): RequestHandler {\n const {\n windowMs = 15 * 60 * 1000, // 15 minutes\n max = 100,\n message = 'Too many requests, please try again later.',\n statusCode = HTTP_STATUS.TOO_MANY_REQUESTS,\n keyGenerator = (req) => req.ip || req.connection?.remoteAddress || 'unknown',\n skip = () => false,\n onLimitReached,\n headers = true,\n store = new MemoryStore(windowMs),\n } = options;\n\n return async (req, res, next) => {\n if (skip(req)) {\n return next();\n }\n\n const key = keyGenerator(req);\n\n try {\n const info = await store.increment(key);\n const remaining = Math.max(0, max - info.count);\n\n if (headers) {\n res.setHeader('X-RateLimit-Limit', max);\n res.setHeader('X-RateLimit-Remaining', remaining);\n res.setHeader('X-RateLimit-Reset', Math.ceil(info.resetTime / 1000));\n }\n\n if (info.count > max) {\n logger.warn(`Rate limit exceeded for ${key}`);\n onLimitReached?.(req, res);\n\n if (headers) {\n res.setHeader('Retry-After', Math.ceil((info.resetTime - Date.now()) / 1000));\n }\n\n return res.status(statusCode).json({\n success: false,\n error: {\n message,\n retryAfter: Math.ceil((info.resetTime - Date.now()) / 1000),\n },\n });\n }\n\n next();\n } catch (err) {\n const error = err as Error;\n logger.error(`Rate limit error: ${error.message}`);\n next(error);\n }\n };\n}\n\n/**\n * Sliding window rate limiter for more accurate limiting\n */\nexport function slidingWindowRateLimit(options: RateLimitOptions = {}): RequestHandler {\n const {\n windowMs = 15 * 60 * 1000,\n max = 100,\n message = 'Too many requests, please try again later.',\n statusCode = HTTP_STATUS.TOO_MANY_REQUESTS,\n keyGenerator = (req) => req.ip || 'unknown',\n skip = () => false,\n headers = true,\n } = options;\n\n const requests: Map<string, number[]> = new Map();\n\n return (req, res, next) => {\n if (skip(req)) {\n return next();\n }\n\n const key = keyGenerator(req);\n const now = Date.now();\n const windowStart = now - windowMs;\n\n // Get or create request timestamps array\n let timestamps = requests.get(key) || [];\n \n // Filter out old requests\n timestamps = timestamps.filter((t) => t > windowStart);\n \n // Add current request\n timestamps.push(now);\n requests.set(key, timestamps);\n\n const remaining = Math.max(0, max - timestamps.length);\n\n if (headers) {\n res.setHeader('X-RateLimit-Limit', max);\n res.setHeader('X-RateLimit-Remaining', remaining);\n res.setHeader('X-RateLimit-Reset', Math.ceil((now + windowMs) / 1000));\n }\n\n if (timestamps.length > max) {\n logger.warn(`Sliding window rate limit exceeded for ${key}`);\n \n return res.status(statusCode).json({\n success: false,\n error: {\n message,\n retryAfter: Math.ceil(windowMs / 1000),\n },\n });\n }\n\n next();\n };\n}\n\n","// Health Check Middleware for Harbor\nimport { RequestHandler } from 'express';\n// Health Check Middleware\n\nexport interface HealthCheckResult {\n name: string;\n status: 'healthy' | 'unhealthy' | 'degraded';\n latency?: number;\n message?: string;\n details?: Record<string, unknown>;\n}\n\nexport interface HealthCheck {\n name: string;\n check: () => Promise<HealthCheckResult>;\n critical?: boolean;\n timeout?: number;\n}\n\nexport interface HealthOptions {\n path?: string;\n checks?: HealthCheck[];\n timeout?: number;\n onHealthCheck?: (results: HealthCheckResult[]) => void;\n}\n\nexport interface HealthStatus {\n status: 'healthy' | 'unhealthy' | 'degraded';\n timestamp: string;\n uptime: number;\n version?: string;\n checks: HealthCheckResult[];\n}\n\nconst startTime = Date.now();\n\n/**\n * Create health check endpoint\n * \n * @example\n * app.use(healthCheck({\n * checks: [\n * mongoHealthCheck(connection),\n * redisHealthCheck(redisClient),\n * customHealthCheck('api', async () => { ... }),\n * ],\n * }));\n */\nexport function healthCheck(options: HealthOptions = {}): RequestHandler {\n const {\n checks = [],\n timeout = 5000,\n onHealthCheck,\n } = options;\n\n return async (_req, res) => {\n const results: HealthCheckResult[] = [];\n let overallStatus: 'healthy' | 'unhealthy' | 'degraded' = 'healthy';\n\n // Run all health checks in parallel with timeout\n const checkPromises = checks.map(async (check) => {\n const startTime = Date.now();\n \n try {\n const result = await Promise.race([\n check.check(),\n new Promise<HealthCheckResult>((_, reject) =>\n setTimeout(() => reject(new Error('Timeout')), check.timeout || timeout)\n ),\n ]);\n \n result.latency = Date.now() - startTime;\n return result;\n } catch (error) {\n return {\n name: check.name,\n status: 'unhealthy' as const,\n latency: Date.now() - startTime,\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n });\n\n const checkResults = await Promise.all(checkPromises);\n results.push(...checkResults);\n\n // Determine overall status\n for (const result of results) {\n if (result.status === 'unhealthy') {\n const check = checks.find((c) => c.name === result.name);\n if (check?.critical !== false) {\n overallStatus = 'unhealthy';\n break;\n } else {\n overallStatus = 'degraded';\n }\n } else if (result.status === 'degraded' && overallStatus === 'healthy') {\n overallStatus = 'degraded';\n }\n }\n\n const healthStatus: HealthStatus = {\n status: overallStatus,\n timestamp: new Date().toISOString(),\n uptime: Math.floor((Date.now() - startTime) / 1000),\n checks: results,\n };\n\n onHealthCheck?.(results);\n\n const statusCode = overallStatus === 'healthy' ? 200 : overallStatus === 'degraded' ? 200 : 503;\n res.status(statusCode).json(healthStatus);\n };\n}\n\n// Pre-built health checks\n\n/**\n * MongoDB health check\n */\nexport function mongoHealthCheck(connection: any, name = 'mongodb'): HealthCheck {\n return {\n name,\n critical: true,\n check: async () => {\n try {\n if (connection.readyState === 1) {\n await connection.db?.admin().ping();\n return { name, status: 'healthy', message: 'Connected' };\n }\n return { name, status: 'unhealthy', message: 'Not connected' };\n } catch (error) {\n return {\n name,\n status: 'unhealthy',\n message: error instanceof Error ? error.message : 'Connection failed',\n };\n }\n },\n };\n}\n\n/**\n * Redis health check\n */\nexport function redisHealthCheck(client: any, name = 'redis'): HealthCheck {\n return {\n name,\n critical: false,\n check: async () => {\n try {\n const pong = await client.ping();\n if (pong === 'PONG') {\n return { name, status: 'healthy', message: 'Connected' };\n }\n return { name, status: 'unhealthy', message: 'Invalid response' };\n } catch (error) {\n return {\n name,\n status: 'unhealthy',\n message: error instanceof Error ? error.message : 'Connection failed',\n };\n }\n },\n };\n}\n\n/**\n * Memory health check\n */\nexport function memoryHealthCheck(\n maxHeapMB = 512,\n name = 'memory'\n): HealthCheck {\n return {\n name,\n critical: false,\n check: async () => {\n const usage = process.memoryUsage();\n const heapUsedMB = Math.round(usage.heapUsed / 1024 / 1024);\n const heapTotalMB = Math.round(usage.heapTotal / 1024 / 1024);\n const rssMB = Math.round(usage.rss / 1024 / 1024);\n\n const status = heapUsedMB > maxHeapMB ? 'degraded' : 'healthy';\n\n return {\n name,\n status,\n message: `Heap: ${heapUsedMB}MB / ${heapTotalMB}MB`,\n details: {\n heapUsed: heapUsedMB,\n heapTotal: heapTotalMB,\n rss: rssMB,\n external: Math.round(usage.external / 1024 / 1024),\n },\n };\n },\n };\n}\n\n/**\n * Disk health check (requires 'check-disk-space' package)\n */\nexport function diskHealthCheck(\n _path = '/',\n _minFreeGB = 1,\n name = 'disk'\n): HealthCheck {\n return {\n name,\n critical: false,\n check: async () => {\n // Disk space check requires 'check-disk-space' package\n return {\n name,\n status: 'healthy',\n message: 'Disk check requires check-disk-space package',\n };\n },\n };\n}\n\n/**\n * Custom health check\n */\nexport function customHealthCheck(\n name: string,\n checkFn: () => Promise<boolean | { healthy: boolean; message?: string }>,\n critical = false\n): HealthCheck {\n return {\n name,\n critical,\n check: async () => {\n try {\n const result = await checkFn();\n if (typeof result === 'boolean') {\n return {\n name,\n status: result ? 'healthy' : 'unhealthy',\n };\n }\n return {\n name,\n status: result.healthy ? 'healthy' : 'unhealthy',\n message: result.message,\n };\n } catch (error) {\n return {\n name,\n status: 'unhealthy',\n message: error instanceof Error ? error.message : 'Check failed',\n };\n }\n },\n };\n}\n\n","// Prometheus-compatible Metrics for Harbor\nimport { RequestHandler } from 'express';\n// Prometheus-compatible Metrics for Harbor\n\nexport interface MetricsOptions {\n path?: string;\n prefix?: string;\n defaultLabels?: Record<string, string>;\n collectDefaultMetrics?: boolean;\n requestDurationBuckets?: number[];\n requestSizeBuckets?: number[];\n responseSizeBuckets?: number[];\n}\n\ninterface Metric {\n name: string;\n help: string;\n type: 'counter' | 'gauge' | 'histogram' | 'summary';\n values: Map<string, number | number[]>;\n buckets?: number[];\n}\n\nexport class MetricsRegistry {\n private metrics: Map<string, Metric> = new Map();\n private prefix: string;\n private defaultLabels: Record<string, string>;\n\n constructor(prefix = 'harbor_', defaultLabels: Record<string, string> = {}) {\n this.prefix = prefix;\n this.defaultLabels = defaultLabels;\n }\n\n // Counter - only goes up\n counter(name: string, help: string): Counter {\n const fullName = this.prefix + name;\n if (!this.metrics.has(fullName)) {\n this.metrics.set(fullName, {\n name: fullName,\n help,\n type: 'counter',\n values: new Map(),\n });\n }\n return new Counter(this.metrics.get(fullName)!, this.defaultLabels);\n }\n\n // Gauge - can go up and down\n gauge(name: string, help: string): Gauge {\n const fullName = this.prefix + name;\n if (!this.metrics.has(fullName)) {\n this.metrics.set(fullName, {\n name: fullName,\n help,\n type: 'gauge',\n values: new Map(),\n });\n }\n return new Gauge(this.metrics.get(fullName)!, this.defaultLabels);\n }\n\n // Histogram - observations in buckets\n histogram(name: string, help: string, buckets: number[] = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]): Histogram {\n const fullName = this.prefix + name;\n if (!this.metrics.has(fullName)) {\n this.metrics.set(fullName, {\n name: fullName,\n help,\n type: 'histogram',\n values: new Map(),\n buckets,\n });\n }\n return new Histogram(this.metrics.get(fullName)!, this.defaultLabels);\n }\n\n // Get all metrics in Prometheus format\n getMetrics(): string {\n const lines: string[] = [];\n\n for (const metric of this.metrics.values()) {\n lines.push(`# HELP ${metric.name} ${metric.help}`);\n lines.push(`# TYPE ${metric.name} ${metric.type}`);\n\n if (metric.type === 'histogram') {\n // Group by labels and output histogram format\n const labelGroups = new Map<string, { sum: number; count: number; buckets: Map<number, number> }>();\n \n for (const [key, value] of metric.values.entries()) {\n const [labelsStr, bucket] = key.split('|');\n if (!labelGroups.has(labelsStr)) {\n labelGroups.set(labelsStr, { sum: 0, count: 0, buckets: new Map() });\n }\n const group = labelGroups.get(labelsStr)!;\n \n if (bucket === 'sum') {\n group.sum = value as number;\n } else if (bucket === 'count') {\n group.count = value as number;\n } else {\n group.buckets.set(parseFloat(bucket), value as number);\n }\n }\n\n for (const [labelsStr, group] of labelGroups.entries()) {\n const labels = labelsStr ? `{${labelsStr}}` : '';\n let cumulative = 0;\n \n for (const bucket of metric.buckets || []) {\n cumulative += group.buckets.get(bucket) || 0;\n const bucketLabels = labelsStr ? `{${labelsStr},le=\"${bucket}\"}` : `{le=\"${bucket}\"}`;\n lines.push(`${metric.name}_bucket${bucketLabels} ${cumulative}`);\n }\n \n const infLabels = labelsStr ? `{${labelsStr},le=\"+Inf\"}` : `{le=\"+Inf\"}`;\n lines.push(`${metric.name}_bucket${infLabels} ${group.count}`);\n lines.push(`${metric.name}_sum${labels} ${group.sum}`);\n lines.push(`${metric.name}_count${labels} ${group.count}`);\n }\n } else {\n for (const [labels, value] of metric.values.entries()) {\n const labelsStr = labels ? `{${labels}}` : '';\n lines.push(`${metric.name}${labelsStr} ${value}`);\n }\n }\n }\n\n return lines.join('\\n');\n }\n\n reset(): void {\n for (const metric of this.metrics.values()) {\n metric.values.clear();\n }\n }\n}\n\nclass Counter {\n private metric: Metric;\n private defaultLabels: Record<string, string>;\n\n constructor(metric: Metric, defaultLabels: Record<string, string>) {\n this.metric = metric;\n this.defaultLabels = defaultLabels;\n }\n\n inc(labels: Record<string, string> = {}, value = 1): void {\n const key = this.labelsToString({ ...this.defaultLabels, ...labels });\n const current = (this.metric.values.get(key) as number) || 0;\n this.metric.values.set(key, current + value);\n }\n\n private labelsToString(labels: Record<string, string>): string {\n return Object.entries(labels)\n .map(([k, v]) => `${k}=\"${v}\"`)\n .join(',');\n }\n}\n\nclass Gauge {\n private metric: Metric;\n private defaultLabels: Record<string, string>;\n\n constructor(metric: Metric, defaultLabels: Record<string, string>) {\n this.metric = metric;\n this.defaultLabels = defaultLabels;\n }\n\n set(value: number, labels: Record<string, string> = {}): void {\n const key = this.labelsToString({ ...this.defaultLabels, ...labels });\n this.metric.values.set(key, value);\n }\n\n inc(labels: Record<string, string> = {}, value = 1): void {\n const key = this.labelsToString({ ...this.defaultLabels, ...labels });\n const current = (this.metric.values.get(key) as number) || 0;\n this.metric.values.set(key, current + value);\n }\n\n dec(labels: Record<string, string> = {}, value = 1): void {\n const key = this.labelsToString({ ...this.defaultLabels, ...labels });\n const current = (this.metric.values.get(key) as number) || 0;\n this.metric.values.set(key, current - value);\n }\n\n private labelsToString(labels: Record<string, string>): string {\n return Object.entries(labels)\n .map(([k, v]) => `${k}=\"${v}\"`)\n .join(',');\n }\n}\n\nclass Histogram {\n private metric: Metric;\n private defaultLabels: Record<string, string>;\n\n constructor(metric: Metric, defaultLabels: Record<string, string>) {\n this.metric = metric;\n this.defaultLabels = defaultLabels;\n }\n\n observe(value: number, labels: Record<string, string> = {}): void {\n const labelsStr = this.labelsToString({ ...this.defaultLabels, ...labels });\n \n // Update sum\n const sumKey = `${labelsStr}|sum`;\n const currentSum = (this.metric.values.get(sumKey) as number) || 0;\n this.metric.values.set(sumKey, currentSum + value);\n\n // Update count\n const countKey = `${labelsStr}|count`;\n const currentCount = (this.metric.values.get(countKey) as number) || 0;\n this.metric.values.set(countKey, currentCount + 1);\n\n // Update buckets\n for (const bucket of this.metric.buckets || []) {\n if (value <= bucket) {\n const bucketKey = `${labelsStr}|${bucket}`;\n const current = (this.metric.values.get(bucketKey) as number) || 0;\n this.metric.values.set(bucketKey, current + 1);\n }\n }\n }\n\n startTimer(labels: Record<string, string> = {}): () => void {\n const start = process.hrtime.bigint();\n return () => {\n const end = process.hrtime.bigint();\n const duration = Number(end - start) / 1e9; // Convert to seconds\n this.observe(duration, labels);\n };\n }\n\n private labelsToString(labels: Record<string, string>): string {\n return Object.entries(labels)\n .map(([k, v]) => `${k}=\"${v}\"`)\n .join(',');\n }\n}\n\n// Global registry instance\nexport const defaultRegistry = new MetricsRegistry();\n\n// Pre-built metrics\nexport const httpRequestsTotal = defaultRegistry.counter(\n 'http_requests_total',\n 'Total number of HTTP requests'\n);\n\nexport const httpRequestDuration = defaultRegistry.histogram(\n 'http_request_duration_seconds',\n 'HTTP request duration in seconds'\n);\n\nexport const httpRequestSize = defaultRegistry.histogram(\n 'http_request_size_bytes',\n 'HTTP request size in bytes',\n [100, 1000, 10000, 100000, 1000000]\n);\n\nexport const httpResponseSize = defaultRegistry.histogram(\n 'http_response_size_bytes',\n 'HTTP response size in bytes',\n [100, 1000, 10000, 100000, 1000000]\n);\n\n/**\n * Metrics collection middleware\n */\nexport function metricsMiddleware(): RequestHandler {\n return (req, res, next) => {\n const timer = httpRequestDuration.startTimer({\n method: req.method,\n path: req.route?.path || req.path,\n });\n\n const requestSize = parseInt(req.get('content-length') || '0', 10);\n if (requestSize > 0) {\n httpRequestSize.observe(requestSize, { method: req.method });\n }\n\n res.on('finish', () => {\n timer();\n \n httpRequestsTotal.inc({\n method: req.method,\n path: req.route?.path || req.path,\n status: res.statusCode.toString(),\n });\n\n const responseSize = parseInt(res.get('content-length') || '0', 10);\n if (responseSize > 0) {\n httpResponseSize.observe(responseSize, {\n method: req.method,\n status: res.statusCode.toString(),\n });\n }\n });\n\n next();\n };\n}\n\n/**\n * Metrics endpoint handler\n */\nexport function metricsEndpoint(registry = defaultRegistry): RequestHandler {\n return (_req, res) => {\n res.set('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\n res.send(registry.getMetrics());\n };\n}\n\nexport { Counter, Gauge, Histogram };\n\n","// File Upload Middleware for Harbor\nimport { RequestHandler } from 'express';\nimport { createWriteStream, existsSync, mkdirSync } from 'fs';\nimport { join, extname } from 'path';\nimport { createLogger } from '../utils/logger';\nimport { HTTP_STATUS } from '../constants';\n\nconst logger = createLogger('upload');\n\nexport interface UploadOptions {\n dest?: string;\n limits?: {\n fileSize?: number;\n files?: number;\n fields?: number;\n fieldSize?: number;\n };\n allowedMimeTypes?: string[];\n allowedExtensions?: string[];\n filename?: (originalName: string, mimeType: string) => string;\n storage?: 'disk' | 'memory';\n onFileBegin?: (fieldName: string, file: UploadedFile) => void;\n onFileEnd?: (fieldName: string, file: UploadedFile) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface UploadedFile {\n fieldName: string;\n originalName: string;\n mimeType: string;\n size: number;\n path?: string;\n buffer?: Buffer;\n encoding: string;\n}\n\ninterface MultipartPart {\n fieldName: string;\n filename?: string;\n mimeType: string;\n encoding: string;\n data: Buffer[];\n}\n\n/**\n * Parse multipart boundary from content-type header\n */\nfunction getBoundary(contentType: string): string | null {\n const match = contentType.match(/boundary=(?:\"([^\"]+)\"|([^;]+))/i);\n return match ? match[1] || match[2] : null;\n}\n\n/**\n * Parse multipart form data\n */\nfunction parseMultipart(buffer: Buffer, boundary: string): MultipartPart[] {\n const parts: MultipartPart[] = [];\n const boundaryBuffer = Buffer.from(`--${boundary}`);\n const endBoundary = Buffer.from(`--${boundary}--`);\n \n let start = buffer.indexOf(boundaryBuffer) + boundaryBuffer.length + 2; // Skip CRLF\n \n while (start < buffer.length) {\n const end = buffer.indexOf(boundaryBuffer, start);\n if (end === -1) break;\n \n const partData = buffer.slice(start, end - 2); // Remove trailing CRLF\n const headerEnd = partData.indexOf('\\r\\n\\r\\n');\n \n if (headerEnd !== -1) {\n const headers = partData.slice(0, headerEnd).toString();\n const body = partData.slice(headerEnd + 4);\n \n const contentDisposition = headers.match(/Content-Disposition:\\s*form-data;\\s*name=\"([^\"]+)\"(?:;\\s*filename=\"([^\"]+)\")?/i);\n const contentType = headers.match(/Content-Type:\\s*([^\\r\\n]+)/i);\n const encoding = headers.match(/Content-Transfer-Encoding:\\s*([^\\r\\n]+)/i);\n \n if (contentDisposition) {\n parts.push({\n fieldName: contentDisposition[1],\n filename: contentDisposition[2],\n mimeType: contentType ? contentType[1] : 'application/octet-stream',\n encoding: encoding ? encoding[1] : '7bit',\n data: [body],\n });\n }\n }\n \n start = end + boundaryBuffer.length + 2;\n \n // Check for end boundary\n if (buffer.slice(end, end + endBoundary.length).equals(endBoundary)) {\n break;\n }\n }\n \n return parts;\n}\n\n/**\n * Generate unique filename\n */\nfunction generateFilename(originalName: string): string {\n const ext = extname(originalName);\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 8);\n return `${timestamp}-${random}${ext}`;\n}\n\n/**\n * File upload middleware\n * \n * @example\n * // Single file upload\n * app.post('/upload', upload({ dest: './uploads' }), (req, res) => {\n * console.log(req.file);\n * res.json({ uploaded: true });\n * });\n * \n * // Multiple files\n * app.post('/uploads', upload({ dest: './uploads', limits: { files: 10 } }), (req, res) => {\n * console.log(req.files);\n * res.json({ count: req.files.length });\n * });\n * \n * // Memory storage\n * app.post('/buffer', upload({ storage: 'memory' }), (req, res) => {\n * const buffer = req.file.buffer;\n * // Process buffer...\n * });\n */\nexport function upload(options: UploadOptions = {}): RequestHandler {\n const {\n dest = './uploads',\n limits = {},\n allowedMimeTypes,\n allowedExtensions,\n filename = generateFilename,\n storage = 'disk',\n onFileBegin,\n onFileEnd,\n onError,\n } = options;\n\n const {\n fileSize = 10 * 1024 * 1024, // 10MB default\n files = 10,\n fields = 100,\n fieldSize = 1024 * 1024, // 1MB default\n } = limits;\n\n // Ensure upload directory exists\n if (storage === 'disk' && !existsSync(dest)) {\n mkdirSync(dest, { recursive: true });\n }\n\n return async (req, res, next) => {\n const contentType = req.get('content-type') || '';\n \n if (!contentType.includes('multipart/form-data')) {\n return next();\n }\n\n const boundary = getBoundary(contentType);\n if (!boundary) {\n return res.status(HTTP_STATUS.BAD_REQUEST).json({\n success: false,\n error: { message: 'Missing boundary in content-type' },\n });\n }\n\n const chunks: Buffer[] = [];\n let totalSize = 0;\n\n req.on('data', (chunk: Buffer) => {\n totalSize += chunk.length;\n if (totalSize > fileSize * files) {\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n\n req.on('end', async () => {\n try {\n const buffer = Buffer.concat(chunks);\n const parts = parseMultipart(buffer, boundary);\n\n const uploadedFiles: UploadedFile[] = [];\n const formFields: Record<string, string> = {};\n let fileCount = 0;\n let fieldCount = 0;\n\n for (const part of parts) {\n if (part.filename) {\n // File upload\n if (fileCount >= files) {\n throw new Error(`Too many files. Maximum: ${files}`);\n }\n\n const fileBuffer = Buffer.concat(part.data);\n \n if (fileBuffer.length > fileSize) {\n throw new Error(`File too large: ${part.filename}. Maximum: ${fileSize} bytes`);\n }\n\n // Check mime type\n if (allowedMimeTypes && !allowedMimeTypes.includes(part.mimeType)) {\n throw new Error(`Invalid file type: ${part.mimeType}`);\n }\n\n // Check extension\n if (allowedExtensions) {\n const ext = extname(part.filename).toLowerCase().slice(1);\n if (!allowedExtensions.includes(ext)) {\n throw new Error(`Invalid file extension: ${ext}`);\n }\n }\n\n const file: UploadedFile = {\n fieldName: part.fieldName,\n originalName: part.filename,\n mimeType: part.mimeType,\n size: fileBuffer.length,\n encoding: part.encoding,\n };\n\n onFileBegin?.(part.fieldName, file);\n\n if (storage === 'disk') {\n const newFilename = filename(part.filename, part.mimeType);\n const filePath = join(dest, newFilename);\n \n await new Promise<void>((resolve, reject) => {\n const writeStream = createWriteStream(filePath);\n writeStream.write(fileBuffer);\n writeStream.end();\n writeStream.on('finish', resolve);\n writeStream.on('error', reject);\n });\n\n file.path = filePath;\n } else {\n file.buffer = fileBuffer;\n }\n\n onFileEnd?.(part.fieldName, file);\n uploadedFiles.push(file);\n fileCount++;\n } else {\n // Form field\n if (fieldCount >= fields) {\n throw new Error(`Too many fields. Maximum: ${fields}`);\n }\n\n const value = Buffer.concat(part.data).toString();\n if (value.length > fieldSize) {\n throw new Error(`Field too large: ${part.fieldName}`);\n }\n\n formFields[part.fieldName] = value;\n fieldCount++;\n }\n }\n\n // Attach to request\n (req as any).files = uploadedFiles;\n (req as any).file = uploadedFiles[0];\n (req as any).body = { ...(req as any).body, ...formFields };\n\n logger.debug(`Uploaded ${uploadedFiles.length} files`);\n next();\n } catch (err) {\n const error = err as Error;\n logger.error(`Upload error: ${error.message}`);\n onError?.(error);\n res.status(HTTP_STATUS.BAD_REQUEST).json({\n success: false,\n error: { message: error.message },\n });\n }\n });\n\n req.on('error', (err) => {\n logger.error('Request error:', err);\n onError?.(err as Error);\n next(err as Error);\n });\n };\n}\n\n/**\n * Validate file type helper\n */\nexport function validateFileType(\n file: UploadedFile,\n allowedTypes: string[]\n): boolean {\n return allowedTypes.includes(file.mimeType);\n}\n\n/**\n * Get file extension from mime type\n */\nexport function mimeToExtension(mimeType: string): string {\n const mimeMap: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/gif': 'gif',\n 'image/webp': 'webp',\n 'image/svg+xml': 'svg',\n 'application/pdf': 'pdf',\n 'application/json': 'json',\n 'text/plain': 'txt',\n 'text/csv': 'csv',\n 'application/zip': 'zip',\n 'application/x-rar-compressed': 'rar',\n };\n\n return mimeMap[mimeType] || 'bin';\n}\n\n"],"names":["logger","createLogger","MemoryStore","windowMs","key","now","existing","info","RedisStore","client","prefix","redisKey","multi","results","count","ttl","rateLimit","options","max","message","statusCode","HTTP_STATUS","keyGenerator","req","skip","onLimitReached","headers","store","res","next","remaining","err","error","slidingWindowRateLimit","requests","windowStart","timestamps","t","startTime","healthCheck","checks","timeout","onHealthCheck","_req","overallStatus","checkPromises","check","result","_","reject","checkResults","c","healthStatus","mongoHealthCheck","connection","name","redisHealthCheck","memoryHealthCheck","maxHeapMB","usage","heapUsedMB","heapTotalMB","rssMB","status","diskHealthCheck","_path","_minFreeGB","customHealthCheck","checkFn","critical","MetricsRegistry","defaultLabels","help","fullName","Counter","Gauge","buckets","Histogram","lines","metric","labelGroups","value","labelsStr","bucket","group","labels","cumulative","bucketLabels","infLabels","current","k","v","sumKey","currentSum","countKey","currentCount","bucketKey","start","end","duration","defaultRegistry","httpRequestsTotal","httpRequestDuration","httpRequestSize","httpResponseSize","metricsMiddleware","timer","requestSize","responseSize","metricsEndpoint","registry","getBoundary","contentType","match","parseMultipart","buffer","boundary","parts","boundaryBuffer","endBoundary","partData","headerEnd","body","contentDisposition","encoding","generateFilename","originalName","ext","extname","timestamp","random","upload","dest","limits","allowedMimeTypes","allowedExtensions","filename","storage","onFileBegin","onFileEnd","onError","fileSize","files","fields","fieldSize","existsSync","mkdirSync","chunks","totalSize","chunk","uploadedFiles","formFields","fileCount","fieldCount","part","fileBuffer","file","newFilename","filePath","join","resolve","writeStream","createWriteStream","validateFileType","allowedTypes","mimeToExtension","mimeType"],"mappings":";;;;AAKA,MAAMA,IAASC,EAAa,YAAY;AA2BxC,MAAMC,EAAsC;AAAA,EAClC,2BAAuC,IAAA;AAAA,EACvC;AAAA,EAER,YAAYC,GAAkB;AAC5B,SAAK,WAAWA,GAGhB,YAAY,MAAM,KAAK,QAAA,GAAWA,CAAQ;AAAA,EAC5C;AAAA,EAEA,MAAM,UAAUC,GAAqC;AACnD,UAAMC,IAAM,KAAK,IAAA,GACXC,IAAW,KAAK,KAAK,IAAIF,CAAG;AAElC,QAAIE,KAAYA,EAAS,YAAYD;AACnC,aAAAC,EAAS,SACFA;AAGT,UAAMC,IAAsB;AAAA,MAC1B,OAAO;AAAA,MACP,WAAWF,IAAM,KAAK;AAAA,IAAA;AAExB,gBAAK,KAAK,IAAID,GAAKG,CAAI,GAChBA;AAAA,EACT;AAAA,EAEA,MAAM,UAAUH,GAA4B;AAC1C,UAAME,IAAW,KAAK,KAAK,IAAIF,CAAG;AAClC,IAAIE,KAAYA,EAAS,QAAQ,KAC/BA,EAAS;AAAA,EAEb;AAAA,EAEA,MAAM,SAASF,GAA4B;AACzC,SAAK,KAAK,OAAOA,CAAG;AAAA,EACtB;AAAA,EAEA,MAAM,IAAIA,GAA4C;AACpD,WAAO,KAAK,KAAK,IAAIA,CAAG,KAAK;AAAA,EAC/B;AAAA,EAEQ,UAAgB;AACtB,UAAMC,IAAM,KAAK,IAAA;AACjB,eAAW,CAACD,GAAKG,CAAI,KAAK,KAAK,KAAK;AAClC,MAAIA,EAAK,aAAaF,KACpB,KAAK,KAAK,OAAOD,CAAG;AAAA,EAG1B;AACF;AAGO,MAAMI,GAAqC;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAYC,GAAaN,GAAkBO,IAAS,OAAO;AACzD,SAAK,SAASD,GACd,KAAK,WAAWN,GAChB,KAAK,SAASO;AAAA,EAChB;AAAA,EAEA,MAAM,UAAUN,GAAqC;AACnD,UAAMO,IAAW,KAAK,SAASP,GACzBQ,IAAQ,KAAK,OAAO,MAAA;AAE1B,IAAAA,EAAM,KAAKD,CAAQ,GACnBC,EAAM,KAAKD,CAAQ;AAEnB,UAAME,IAAU,MAAMD,EAAM,KAAA,GACtBE,IAAQD,EAAQ,CAAC,EAAE,CAAC;AAC1B,QAAIE,IAAMF,EAAQ,CAAC,EAAE,CAAC;AAEtB,WAAIE,MAAQ,OACV,MAAM,KAAK,OAAO,QAAQJ,GAAU,KAAK,QAAQ,GACjDI,IAAM,KAAK,WAGN;AAAA,MACL,OAAAD;AAAA,MACA,WAAW,KAAK,QAAQC;AAAA,IAAA;AAAA,EAE5B;AAAA,EAEA,MAAM,UAAUX,GAA4B;AAC1C,UAAM,KAAK,OAAO,KAAK,KAAK,SAASA,CAAG;AAAA,EAC1C;AAAA,EAEA,MAAM,SAASA,GAA4B;AACzC,UAAM,KAAK,OAAO,IAAI,KAAK,SAASA,CAAG;AAAA,EACzC;AAAA,EAEA,MAAM,IAAIA,GAA4C;AACpD,UAAMO,IAAW,KAAK,SAASP,GACzB,CAACU,GAAOC,CAAG,IAAI,MAAM,QAAQ,IAAI;AAAA,MACrC,KAAK,OAAO,IAAIJ,CAAQ;AAAA,MACxB,KAAK,OAAO,KAAKA,CAAQ;AAAA,IAAA,CAC1B;AAED,WAAIG,MAAU,OAAa,OAEpB;AAAA,MACL,OAAO,SAASA,GAAO,EAAE;AAAA,MACzB,WAAW,KAAK,IAAA,IAAQ,KAAK,IAAIC,GAAK,CAAC;AAAA,IAAA;AAAA,EAE3C;AACF;AAeO,SAASC,GAAUC,IAA4B,IAAoB;AACxE,QAAM;AAAA,IACJ,UAAAd,IAAW,KAAK,KAAK;AAAA;AAAA,IACrB,KAAAe,IAAM;AAAA,IACN,SAAAC,IAAU;AAAA,IACV,YAAAC,IAAaC,EAAY;AAAA,IACzB,cAAAC,IAAe,CAACC,MAAQA,EAAI,MAAMA,EAAI,YAAY,iBAAiB;AAAA,IACnE,MAAAC,IAAO,MAAM;AAAA,IACb,gBAAAC;AAAA,IACA,SAAAC,IAAU;AAAA,IACV,OAAAC,IAAQ,IAAIzB,EAAYC,CAAQ;AAAA,EAAA,IAC9Bc;AAEJ,SAAO,OAAOM,GAAKK,GAAKC,MAAS;AAC/B,QAAIL,EAAKD,CAAG;AACV,aAAOM,EAAA;AAGT,UAAMzB,IAAMkB,EAAaC,CAAG;AAE5B,QAAI;AACF,YAAMhB,IAAO,MAAMoB,EAAM,UAAUvB,CAAG,GAChC0B,IAAY,KAAK,IAAI,GAAGZ,IAAMX,EAAK,KAAK;AAQ9C,UANImB,MACFE,EAAI,UAAU,qBAAqBV,CAAG,GACtCU,EAAI,UAAU,yBAAyBE,CAAS,GAChDF,EAAI,UAAU,qBAAqB,KAAK,KAAKrB,EAAK,YAAY,GAAI,CAAC,IAGjEA,EAAK,QAAQW;AACflB,eAAAA,EAAO,KAAK,2BAA2BI,CAAG,EAAE,GAC5CqB,IAAiBF,GAAKK,CAAG,GAErBF,KACFE,EAAI,UAAU,eAAe,KAAK,MAAMrB,EAAK,YAAY,KAAK,IAAA,KAAS,GAAI,CAAC,GAGvEqB,EAAI,OAAOR,CAAU,EAAE,KAAK;AAAA,UACjC,SAAS;AAAA,UACT,OAAO;AAAA,YACL,SAAAD;AAAA,YACA,YAAY,KAAK,MAAMZ,EAAK,YAAY,KAAK,IAAA,KAAS,GAAI;AAAA,UAAA;AAAA,QAC5D,CACD;AAGH,MAAAsB,EAAA;AAAA,IACF,SAASE,GAAK;AACZ,YAAMC,IAAQD;AACd/B,MAAAA,EAAO,MAAM,qBAAqBgC,EAAM,OAAO,EAAE,GACjDH,EAAKG,CAAK;AAAA,IACZ;AAAA,EACF;AACF;AAKO,SAASC,GAAuBhB,IAA4B,IAAoB;AACrF,QAAM;AAAA,IACJ,UAAAd,IAAW,KAAK,KAAK;AAAA,IACrB,KAAAe,IAAM;AAAA,IACN,SAAAC,IAAU;AAAA,IACV,YAAAC,IAAaC,EAAY;AAAA,IACzB,cAAAC,IAAe,CAACC,MAAQA,EAAI,MAAM;AAAA,IAClC,MAAAC,IAAO,MAAM;AAAA,IACb,SAAAE,IAAU;AAAA,EAAA,IACRT,GAEEiB,wBAAsC,IAAA;AAE5C,SAAO,CAACX,GAAKK,GAAKC,MAAS;AACzB,QAAIL,EAAKD,CAAG;AACV,aAAOM,EAAA;AAGT,UAAMzB,IAAMkB,EAAaC,CAAG,GACtBlB,IAAM,KAAK,IAAA,GACX8B,IAAc9B,IAAMF;AAG1B,QAAIiC,IAAaF,EAAS,IAAI9B,CAAG,KAAK,CAAA;AAGtC,IAAAgC,IAAaA,EAAW,OAAO,CAACC,MAAMA,IAAIF,CAAW,GAGrDC,EAAW,KAAK/B,CAAG,GACnB6B,EAAS,IAAI9B,GAAKgC,CAAU;AAE5B,UAAMN,IAAY,KAAK,IAAI,GAAGZ,IAAMkB,EAAW,MAAM;AAQrD,QANIV,MACFE,EAAI,UAAU,qBAAqBV,CAAG,GACtCU,EAAI,UAAU,yBAAyBE,CAAS,GAChDF,EAAI,UAAU,qBAAqB,KAAK,MAAMvB,IAAMF,KAAY,GAAI,CAAC,IAGnEiC,EAAW,SAASlB;AACtBlB,aAAAA,EAAO,KAAK,0CAA0CI,CAAG,EAAE,GAEpDwB,EAAI,OAAOR,CAAU,EAAE,KAAK;AAAA,QACjC,SAAS;AAAA,QACT,OAAO;AAAA,UACL,SAAAD;AAAA,UACA,YAAY,KAAK,KAAKhB,IAAW,GAAI;AAAA,QAAA;AAAA,MACvC,CACD;AAGH,IAAA0B,EAAA;AAAA,EACF;AACF;AC3OA,MAAMS,IAAY,KAAK,IAAA;AAchB,SAASC,GAAYtB,IAAyB,IAAoB;AACvE,QAAM;AAAA,IACJ,QAAAuB,IAAS,CAAA;AAAA,IACT,SAAAC,IAAU;AAAA,IACV,eAAAC;AAAA,EAAA,IACEzB;AAEJ,SAAO,OAAO0B,GAAMf,MAAQ;AAC1B,UAAMf,IAA+B,CAAA;AACrC,QAAI+B,IAAsD;AAG1D,UAAMC,IAAgBL,EAAO,IAAI,OAAOM,MAAU;AAChD,YAAMR,IAAY,KAAK,IAAA;AAEvB,UAAI;AACF,cAAMS,IAAS,MAAM,QAAQ,KAAK;AAAA,UAChCD,EAAM,MAAA;AAAA,UACN,IAAI;AAAA,YAA2B,CAACE,GAAGC,MACjC,WAAW,MAAMA,EAAO,IAAI,MAAM,SAAS,CAAC,GAAGH,EAAM,WAAWL,CAAO;AAAA,UAAA;AAAA,QACzE,CACD;AAED,eAAAM,EAAO,UAAU,KAAK,IAAA,IAAQT,GACvBS;AAAA,MACT,SAASf,GAAO;AACd,eAAO;AAAA,UACL,MAAMc,EAAM;AAAA,UACZ,QAAQ;AAAA,UACR,SAAS,KAAK,IAAA,IAAQR;AAAAA,UACtB,SAASN,aAAiB,QAAQA,EAAM,UAAU;AAAA,QAAA;AAAA,MAEtD;AAAA,IACF,CAAC,GAEKkB,IAAe,MAAM,QAAQ,IAAIL,CAAa;AACpD,IAAAhC,EAAQ,KAAK,GAAGqC,CAAY;AAG5B,eAAWH,KAAUlC;AACnB,UAAIkC,EAAO,WAAW;AAEpB,YADcP,EAAO,KAAK,CAACW,MAAMA,EAAE,SAASJ,EAAO,IAAI,GAC5C,aAAa,IAAO;AAC7B,UAAAH,IAAgB;AAChB;AAAA,QACF;AACE,UAAAA,IAAgB;AAAA,UAEpB,CAAWG,EAAO,WAAW,cAAcH,MAAkB,cAC3DA,IAAgB;AAIpB,UAAMQ,IAA6B;AAAA,MACjC,QAAQR;AAAA,MACR,YAAW,oBAAI,KAAA,GAAO,YAAA;AAAA,MACtB,QAAQ,KAAK,OAAO,KAAK,IAAA,IAAQN,KAAa,GAAI;AAAA,MAClD,QAAQzB;AAAA,IAAA;AAGV,IAAA6B,IAAgB7B,CAAO;AAEvB,UAAMO,IAAawB,MAAkB,aAAkBA,MAAkB,aAAxB,MAA2C;AAC5F,IAAAhB,EAAI,OAAOR,CAAU,EAAE,KAAKgC,CAAY;AAAA,EAC1C;AACF;AAOO,SAASC,GAAiBC,GAAiBC,IAAO,WAAwB;AAC/E,SAAO;AAAA,IACL,MAAAA;AAAA,IACA,UAAU;AAAA,IACV,OAAO,YAAY;AACjB,UAAI;AACF,eAAID,EAAW,eAAe,KAC5B,MAAMA,EAAW,IAAI,MAAA,EAAQ,KAAA,GACtB,EAAE,MAAAC,GAAM,QAAQ,WAAW,SAAS,YAAA,KAEtC,EAAE,MAAAA,GAAM,QAAQ,aAAa,SAAS,gBAAA;AAAA,MAC/C,SAASvB,GAAO;AACd,eAAO;AAAA,UACL,MAAAuB;AAAA,UACA,QAAQ;AAAA,UACR,SAASvB,aAAiB,QAAQA,EAAM,UAAU;AAAA,QAAA;AAAA,MAEtD;AAAA,IACF;AAAA,EAAA;AAEJ;AAKO,SAASwB,GAAiB/C,GAAa8C,IAAO,SAAsB;AACzE,SAAO;AAAA,IACL,MAAAA;AAAA,IACA,UAAU;AAAA,IACV,OAAO,YAAY;AACjB,UAAI;AAEF,eADa,MAAM9C,EAAO,KAAA,MACb,SACJ,EAAE,MAAA8C,GAAM,QAAQ,WAAW,SAAS,YAAA,IAEtC,EAAE,MAAAA,GAAM,QAAQ,aAAa,SAAS,mBAAA;AAAA,MAC/C,SAASvB,GAAO;AACd,eAAO;AAAA,UACL,MAAAuB;AAAA,UACA,QAAQ;AAAA,UACR,SAASvB,aAAiB,QAAQA,EAAM,UAAU;AAAA,QAAA;AAAA,MAEtD;AAAA,IACF;AAAA,EAAA;AAEJ;AAKO,SAASyB,GACdC,IAAY,KACZH,IAAO,UACM;AACb,SAAO;AAAA,IACL,MAAAA;AAAA,IACA,UAAU;AAAA,IACV,OAAO,YAAY;AACjB,YAAMI,IAAQ,QAAQ,YAAA,GAChBC,IAAa,KAAK,MAAMD,EAAM,WAAW,OAAO,IAAI,GACpDE,IAAc,KAAK,MAAMF,EAAM,YAAY,OAAO,IAAI,GACtDG,IAAQ,KAAK,MAAMH,EAAM,MAAM,OAAO,IAAI,GAE1CI,IAASH,IAAaF,IAAY,aAAa;AAErD,aAAO;AAAA,QACL,MAAAH;AAAA,QACA,QAAAQ;AAAA,QACA,SAAS,SAASH,CAAU,QAAQC,CAAW;AAAA,QAC/C,SAAS;AAAA,UACP,UAAUD;AAAA,UACV,WAAWC;AAAA,UACX,KAAKC;AAAA,UACL,UAAU,KAAK,MAAMH,EAAM,WAAW,OAAO,IAAI;AAAA,QAAA;AAAA,MACnD;AAAA,IAEJ;AAAA,EAAA;AAEJ;AAKO,SAASK,GACdC,IAAQ,KACRC,IAAa,GACbX,IAAO,QACM;AACb,SAAO;AAAA,IACL,MAAAA;AAAA,IACA,UAAU;AAAA,IACV,OAAO,aAEE;AAAA,MACL,MAAAA;AAAA,MACA,QAAQ;AAAA,MACR,SAAS;AAAA,IAAA;AAAA,EAEb;AAEJ;AAKO,SAASY,GACdZ,GACAa,GACAC,IAAW,IACE;AACb,SAAO;AAAA,IACL,MAAAd;AAAA,IACA,UAAAc;AAAA,IACA,OAAO,YAAY;AACjB,UAAI;AACF,cAAMtB,IAAS,MAAMqB,EAAA;AACrB,eAAI,OAAOrB,KAAW,YACb;AAAA,UACL,MAAAQ;AAAA,UACA,QAAQR,IAAS,YAAY;AAAA,QAAA,IAG1B;AAAA,UACL,MAAAQ;AAAA,UACA,QAAQR,EAAO,UAAU,YAAY;AAAA,UACrC,SAASA,EAAO;AAAA,QAAA;AAAA,MAEpB,SAASf,GAAO;AACd,eAAO;AAAA,UACL,MAAAuB;AAAA,UACA,QAAQ;AAAA,UACR,SAASvB,aAAiB,QAAQA,EAAM,UAAU;AAAA,QAAA;AAAA,MAEtD;AAAA,IACF;AAAA,EAAA;AAEJ;AC1OO,MAAMsC,EAAgB;AAAA,EACnB,8BAAmC,IAAA;AAAA,EACnC;AAAA,EACA;AAAA,EAER,YAAY5D,IAAS,WAAW6D,IAAwC,CAAA,GAAI;AAC1E,SAAK,SAAS7D,GACd,KAAK,gBAAgB6D;AAAA,EACvB;AAAA;AAAA,EAGA,QAAQhB,GAAciB,GAAuB;AAC3C,UAAMC,IAAW,KAAK,SAASlB;AAC/B,WAAK,KAAK,QAAQ,IAAIkB,CAAQ,KAC5B,KAAK,QAAQ,IAAIA,GAAU;AAAA,MACzB,MAAMA;AAAA,MACN,MAAAD;AAAA,MACA,MAAM;AAAA,MACN,4BAAY,IAAA;AAAA,IAAI,CACjB,GAEI,IAAIE,EAAQ,KAAK,QAAQ,IAAID,CAAQ,GAAI,KAAK,aAAa;AAAA,EACpE;AAAA;AAAA,EAGA,MAAMlB,GAAciB,GAAqB;AACvC,UAAMC,IAAW,KAAK,SAASlB;AAC/B,WAAK,KAAK,QAAQ,IAAIkB,CAAQ,KAC5B,KAAK,QAAQ,IAAIA,GAAU;AAAA,MACzB,MAAMA;AAAA,MACN,MAAAD;AAAA,MACA,MAAM;AAAA,MACN,4BAAY,IAAA;AAAA,IAAI,CACjB,GAEI,IAAIG,EAAM,KAAK,QAAQ,IAAIF,CAAQ,GAAI,KAAK,aAAa;AAAA,EAClE;AAAA;AAAA,EAGA,UAAUlB,GAAciB,GAAcI,IAAoB,CAAC,MAAO,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,GAAG,KAAK,GAAG,EAAE,GAAc;AAC9H,UAAMH,IAAW,KAAK,SAASlB;AAC/B,WAAK,KAAK,QAAQ,IAAIkB,CAAQ,KAC5B,KAAK,QAAQ,IAAIA,GAAU;AAAA,MACzB,MAAMA;AAAA,MACN,MAAAD;AAAA,MACA,MAAM;AAAA,MACN,4BAAY,IAAA;AAAA,MACZ,SAAAI;AAAA,IAAA,CACD,GAEI,IAAIC,EAAU,KAAK,QAAQ,IAAIJ,CAAQ,GAAI,KAAK,aAAa;AAAA,EACtE;AAAA;AAAA,EAGA,aAAqB;AACnB,UAAMK,IAAkB,CAAA;AAExB,eAAWC,KAAU,KAAK,QAAQ,OAAA;AAIhC,UAHAD,EAAM,KAAK,UAAUC,EAAO,IAAI,IAAIA,EAAO,IAAI,EAAE,GACjDD,EAAM,KAAK,UAAUC,EAAO,IAAI,IAAIA,EAAO,IAAI,EAAE,GAE7CA,EAAO,SAAS,aAAa;AAE/B,cAAMC,wBAAkB,IAAA;AAExB,mBAAW,CAAC5E,GAAK6E,CAAK,KAAKF,EAAO,OAAO,WAAW;AAClD,gBAAM,CAACG,GAAWC,CAAM,IAAI/E,EAAI,MAAM,GAAG;AACzC,UAAK4E,EAAY,IAAIE,CAAS,KAC5BF,EAAY,IAAIE,GAAW,EAAE,KAAK,GAAG,OAAO,GAAG,SAAS,oBAAI,IAAA,EAAI,CAAG;AAErE,gBAAME,IAAQJ,EAAY,IAAIE,CAAS;AAEvC,UAAIC,MAAW,QACbC,EAAM,MAAMH,IACHE,MAAW,UACpBC,EAAM,QAAQH,IAEdG,EAAM,QAAQ,IAAI,WAAWD,CAAM,GAAGF,CAAe;AAAA,QAEzD;AAEA,mBAAW,CAACC,GAAWE,CAAK,KAAKJ,EAAY,WAAW;AACtD,gBAAMK,IAASH,IAAY,IAAIA,CAAS,MAAM;AAC9C,cAAII,IAAa;AAEjB,qBAAWH,KAAUJ,EAAO,WAAW,CAAA,GAAI;AACzC,YAAAO,KAAcF,EAAM,QAAQ,IAAID,CAAM,KAAK;AAC3C,kBAAMI,IAAeL,IAAY,IAAIA,CAAS,QAAQC,CAAM,OAAO,QAAQA,CAAM;AACjF,YAAAL,EAAM,KAAK,GAAGC,EAAO,IAAI,UAAUQ,CAAY,IAAID,CAAU,EAAE;AAAA,UACjE;AAEA,gBAAME,IAAYN,IAAY,IAAIA,CAAS,gBAAgB;AAC3D,UAAAJ,EAAM,KAAK,GAAGC,EAAO,IAAI,UAAUS,CAAS,IAAIJ,EAAM,KAAK,EAAE,GAC7DN,EAAM,KAAK,GAAGC,EAAO,IAAI,OAAOM,CAAM,IAAID,EAAM,GAAG,EAAE,GACrDN,EAAM,KAAK,GAAGC,EAAO,IAAI,SAASM,CAAM,IAAID,EAAM,KAAK,EAAE;AAAA,QAC3D;AAAA,MACF;AACE,mBAAW,CAACC,GAAQJ,CAAK,KAAKF,EAAO,OAAO,WAAW;AACrD,gBAAMG,IAAYG,IAAS,IAAIA,CAAM,MAAM;AAC3C,UAAAP,EAAM,KAAK,GAAGC,EAAO,IAAI,GAAGG,CAAS,IAAID,CAAK,EAAE;AAAA,QAClD;AAIJ,WAAOH,EAAM,KAAK;AAAA,CAAI;AAAA,EACxB;AAAA,EAEA,QAAc;AACZ,eAAWC,KAAU,KAAK,QAAQ,OAAA;AAChC,MAAAA,EAAO,OAAO,MAAA;AAAA,EAElB;AACF;AAEA,MAAML,EAAQ;AAAA,EACJ;AAAA,EACA;AAAA,EAER,YAAYK,GAAgBR,GAAuC;AACjE,SAAK,SAASQ,GACd,KAAK,gBAAgBR;AAAA,EACvB;AAAA,EAEA,IAAIc,IAAiC,IAAIJ,IAAQ,GAAS;AACxD,UAAM7E,IAAM,KAAK,eAAe,EAAE,GAAG,KAAK,eAAe,GAAGiF,GAAQ,GAC9DI,IAAW,KAAK,OAAO,OAAO,IAAIrF,CAAG,KAAgB;AAC3D,SAAK,OAAO,OAAO,IAAIA,GAAKqF,IAAUR,CAAK;AAAA,EAC7C;AAAA,EAEQ,eAAeI,GAAwC;AAC7D,WAAO,OAAO,QAAQA,CAAM,EACzB,IAAI,CAAC,CAACK,GAAGC,CAAC,MAAM,GAAGD,CAAC,KAAKC,CAAC,GAAG,EAC7B,KAAK,GAAG;AAAA,EACb;AACF;AAEA,MAAMhB,EAAM;AAAA,EACF;AAAA,EACA;AAAA,EAER,YAAYI,GAAgBR,GAAuC;AACjE,SAAK,SAASQ,GACd,KAAK,gBAAgBR;AAAA,EACvB;AAAA,EAEA,IAAIU,GAAeI,IAAiC,IAAU;AAC5D,UAAMjF,IAAM,KAAK,eAAe,EAAE,GAAG,KAAK,eAAe,GAAGiF,GAAQ;AACpE,SAAK,OAAO,OAAO,IAAIjF,GAAK6E,CAAK;AAAA,EACnC;AAAA,EAEA,IAAII,IAAiC,IAAIJ,IAAQ,GAAS;AACxD,UAAM7E,IAAM,KAAK,eAAe,EAAE,GAAG,KAAK,eAAe,GAAGiF,GAAQ,GAC9DI,IAAW,KAAK,OAAO,OAAO,IAAIrF,CAAG,KAAgB;AAC3D,SAAK,OAAO,OAAO,IAAIA,GAAKqF,IAAUR,CAAK;AAAA,EAC7C;AAAA,EAEA,IAAII,IAAiC,IAAIJ,IAAQ,GAAS;AACxD,UAAM7E,IAAM,KAAK,eAAe,EAAE,GAAG,KAAK,eAAe,GAAGiF,GAAQ,GAC9DI,IAAW,KAAK,OAAO,OAAO,IAAIrF,CAAG,KAAgB;AAC3D,SAAK,OAAO,OAAO,IAAIA,GAAKqF,IAAUR,CAAK;AAAA,EAC7C;AAAA,EAEQ,eAAeI,GAAwC;AAC7D,WAAO,OAAO,QAAQA,CAAM,EACzB,IAAI,CAAC,CAACK,GAAGC,CAAC,MAAM,GAAGD,CAAC,KAAKC,CAAC,GAAG,EAC7B,KAAK,GAAG;AAAA,EACb;AACF;AAEA,MAAMd,EAAU;AAAA,EACN;AAAA,EACA;AAAA,EAER,YAAYE,GAAgBR,GAAuC;AACjE,SAAK,SAASQ,GACd,KAAK,gBAAgBR;AAAA,EACvB;AAAA,EAEA,QAAQU,GAAeI,IAAiC,IAAU;AAChE,UAAMH,IAAY,KAAK,eAAe,EAAE,GAAG,KAAK,eAAe,GAAGG,GAAQ,GAGpEO,IAAS,GAAGV,CAAS,QACrBW,IAAc,KAAK,OAAO,OAAO,IAAID,CAAM,KAAgB;AACjE,SAAK,OAAO,OAAO,IAAIA,GAAQC,IAAaZ,CAAK;AAGjD,UAAMa,IAAW,GAAGZ,CAAS,UACvBa,IAAgB,KAAK,OAAO,OAAO,IAAID,CAAQ,KAAgB;AACrE,SAAK,OAAO,OAAO,IAAIA,GAAUC,IAAe,CAAC;AAGjD,eAAWZ,KAAU,KAAK,OAAO,WAAW,CAAA;AAC1C,UAAIF,KAASE,GAAQ;AACnB,cAAMa,IAAY,GAAGd,CAAS,IAAIC,CAAM,IAClCM,IAAW,KAAK,OAAO,OAAO,IAAIO,CAAS,KAAgB;AACjE,aAAK,OAAO,OAAO,IAAIA,GAAWP,IAAU,CAAC;AAAA,MAC/C;AAAA,EAEJ;AAAA,EAEA,WAAWJ,IAAiC,IAAgB;AAC1D,UAAMY,IAAQ,QAAQ,OAAO,OAAA;AAC7B,WAAO,MAAM;AACX,YAAMC,IAAM,QAAQ,OAAO,OAAA,GACrBC,IAAW,OAAOD,IAAMD,CAAK,IAAI;AACvC,WAAK,QAAQE,GAAUd,CAAM;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,eAAeA,GAAwC;AAC7D,WAAO,OAAO,QAAQA,CAAM,EACzB,IAAI,CAAC,CAACK,GAAGC,CAAC,MAAM,GAAGD,CAAC,KAAKC,CAAC,GAAG,EAC7B,KAAK,GAAG;AAAA,EACb;AACF;AAGO,MAAMS,IAAkB,IAAI9B,EAAA,GAGtB+B,IAAoBD,EAAgB;AAAA,EAC/C;AAAA,EACA;AACF,GAEaE,IAAsBF,EAAgB;AAAA,EACjD;AAAA,EACA;AACF,GAEaG,IAAkBH,EAAgB;AAAA,EAC7C;AAAA,EACA;AAAA,EACA,CAAC,KAAK,KAAM,KAAO,KAAQ,GAAO;AACpC,GAEaI,KAAmBJ,EAAgB;AAAA,EAC9C;AAAA,EACA;AAAA,EACA,CAAC,KAAK,KAAM,KAAO,KAAQ,GAAO;AACpC;AAKO,SAASK,KAAoC;AAClD,SAAO,CAAClF,GAAKK,GAAKC,MAAS;AACzB,UAAM6E,IAAQJ,EAAoB,WAAW;AAAA,MAC3C,QAAQ/E,EAAI;AAAA,MACZ,MAAMA,EAAI,OAAO,QAAQA,EAAI;AAAA,IAAA,CAC9B,GAEKoF,IAAc,SAASpF,EAAI,IAAI,gBAAgB,KAAK,KAAK,EAAE;AACjE,IAAIoF,IAAc,KAChBJ,EAAgB,QAAQI,GAAa,EAAE,QAAQpF,EAAI,QAAQ,GAG7DK,EAAI,GAAG,UAAU,MAAM;AACrB,MAAA8E,EAAA,GAEAL,EAAkB,IAAI;AAAA,QACpB,QAAQ9E,EAAI;AAAA,QACZ,MAAMA,EAAI,OAAO,QAAQA,EAAI;AAAA,QAC7B,QAAQK,EAAI,WAAW,SAAA;AAAA,MAAS,CACjC;AAED,YAAMgF,IAAe,SAAShF,EAAI,IAAI,gBAAgB,KAAK,KAAK,EAAE;AAClE,MAAIgF,IAAe,KACjBJ,GAAiB,QAAQI,GAAc;AAAA,QACrC,QAAQrF,EAAI;AAAA,QACZ,QAAQK,EAAI,WAAW,SAAA;AAAA,MAAS,CACjC;AAAA,IAEL,CAAC,GAEDC,EAAA;AAAA,EACF;AACF;AAKO,SAASgF,GAAgBC,IAAWV,GAAiC;AAC1E,SAAO,CAACzD,GAAMf,MAAQ;AACpB,IAAAA,EAAI,IAAI,gBAAgB,0CAA0C,GAClEA,EAAI,KAAKkF,EAAS,YAAY;AAAA,EAChC;AACF;AC/SA,MAAM9G,IAASC,EAAa,QAAQ;AAwCpC,SAAS8G,GAAYC,GAAoC;AACvD,QAAMC,IAAQD,EAAY,MAAM,iCAAiC;AACjE,SAAOC,IAAQA,EAAM,CAAC,KAAKA,EAAM,CAAC,IAAI;AACxC;AAKA,SAASC,GAAeC,GAAgBC,GAAmC;AACzE,QAAMC,IAAyB,CAAA,GACzBC,IAAiB,OAAO,KAAK,KAAKF,CAAQ,EAAE,GAC5CG,IAAc,OAAO,KAAK,KAAKH,CAAQ,IAAI;AAEjD,MAAInB,IAAQkB,EAAO,QAAQG,CAAc,IAAIA,EAAe,SAAS;AAErE,SAAOrB,IAAQkB,EAAO,UAAQ;AAC5B,UAAMjB,IAAMiB,EAAO,QAAQG,GAAgBrB,CAAK;AAChD,QAAIC,MAAQ,GAAI;AAEhB,UAAMsB,IAAWL,EAAO,MAAMlB,GAAOC,IAAM,CAAC,GACtCuB,IAAYD,EAAS,QAAQ;AAAA;AAAA,CAAU;AAE7C,QAAIC,MAAc,IAAI;AACpB,YAAM/F,IAAU8F,EAAS,MAAM,GAAGC,CAAS,EAAE,SAAA,GACvCC,IAAOF,EAAS,MAAMC,IAAY,CAAC,GAEnCE,IAAqBjG,EAAQ,MAAM,gFAAgF,GACnHsF,IAActF,EAAQ,MAAM,6BAA6B,GACzDkG,IAAWlG,EAAQ,MAAM,0CAA0C;AAEzE,MAAIiG,KACFN,EAAM,KAAK;AAAA,QACT,WAAWM,EAAmB,CAAC;AAAA,QAC/B,UAAUA,EAAmB,CAAC;AAAA,QAC9B,UAAUX,IAAcA,EAAY,CAAC,IAAI;AAAA,QACzC,UAAUY,IAAWA,EAAS,CAAC,IAAI;AAAA,QACnC,MAAM,CAACF,CAAI;AAAA,MAAA,CACZ;AAAA,IAEL;AAKA,QAHAzB,IAAQC,IAAMoB,EAAe,SAAS,GAGlCH,EAAO,MAAMjB,GAAKA,IAAMqB,EAAY,MAAM,EAAE,OAAOA,CAAW;AAChE;AAAA,EAEJ;AAEA,SAAOF;AACT;AAKA,SAASQ,GAAiBC,GAA8B;AACtD,QAAMC,IAAMC,EAAQF,CAAY,GAC1BG,IAAY,KAAK,IAAA,GACjBC,IAAS,KAAK,SAAS,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC;AACxD,SAAO,GAAGD,CAAS,IAAIC,CAAM,GAAGH,CAAG;AACrC;AAwBO,SAASI,GAAOlH,IAAyB,IAAoB;AAClE,QAAM;AAAA,IACJ,MAAAmH,IAAO;AAAA,IACP,QAAAC,IAAS,CAAA;AAAA,IACT,kBAAAC;AAAA,IACA,mBAAAC;AAAA,IACA,UAAAC,IAAWX;AAAA,IACX,SAAAY,IAAU;AAAA,IACV,aAAAC;AAAA,IACA,WAAAC;AAAA,IACA,SAAAC;AAAA,EAAA,IACE3H,GAEE;AAAA,IACJ,UAAA4H,IAAW,KAAK,OAAO;AAAA;AAAA,IACvB,OAAAC,IAAQ;AAAA,IACR,QAAAC,IAAS;AAAA,IACT,WAAAC,IAAY,OAAO;AAAA;AAAA,EAAA,IACjBX;AAGJ,SAAII,MAAY,UAAU,CAACQ,EAAWb,CAAI,KACxCc,EAAUd,GAAM,EAAE,WAAW,GAAA,CAAM,GAG9B,OAAO7G,GAAKK,GAAKC,MAAS;AAC/B,UAAMmF,IAAczF,EAAI,IAAI,cAAc,KAAK;AAE/C,QAAI,CAACyF,EAAY,SAAS,qBAAqB;AAC7C,aAAOnF,EAAA;AAGT,UAAMuF,IAAWL,GAAYC,CAAW;AACxC,QAAI,CAACI;AACH,aAAOxF,EAAI,OAAOP,EAAY,WAAW,EAAE,KAAK;AAAA,QAC9C,SAAS;AAAA,QACT,OAAO,EAAE,SAAS,mCAAA;AAAA,MAAmC,CACtD;AAGH,UAAM8H,IAAmB,CAAA;AACzB,QAAIC,IAAY;AAEhB,IAAA7H,EAAI,GAAG,QAAQ,CAAC8H,MAAkB;AAEhC,UADAD,KAAaC,EAAM,QACfD,IAAYP,IAAWC,GAAO;AAChC,QAAAvH,EAAI,QAAA;AACJ;AAAA,MACF;AACA,MAAA4H,EAAO,KAAKE,CAAK;AAAA,IACnB,CAAC,GAED9H,EAAI,GAAG,OAAO,YAAY;AACxB,UAAI;AACF,cAAM4F,IAAS,OAAO,OAAOgC,CAAM,GAC7B9B,IAAQH,GAAeC,GAAQC,CAAQ,GAEvCkC,IAAgC,CAAA,GAChCC,IAAqC,CAAA;AAC3C,YAAIC,IAAY,GACZC,IAAa;AAEjB,mBAAWC,KAAQrC;AACjB,cAAIqC,EAAK,UAAU;AAEjB,gBAAIF,KAAaV;AACf,oBAAM,IAAI,MAAM,4BAA4BA,CAAK,EAAE;AAGrD,kBAAMa,IAAa,OAAO,OAAOD,EAAK,IAAI;AAE1C,gBAAIC,EAAW,SAASd;AACtB,oBAAM,IAAI,MAAM,mBAAmBa,EAAK,QAAQ,cAAcb,CAAQ,QAAQ;AAIhF,gBAAIP,KAAoB,CAACA,EAAiB,SAASoB,EAAK,QAAQ;AAC9D,oBAAM,IAAI,MAAM,sBAAsBA,EAAK,QAAQ,EAAE;AAIvD,gBAAInB,GAAmB;AACrB,oBAAMR,IAAMC,EAAQ0B,EAAK,QAAQ,EAAE,YAAA,EAAc,MAAM,CAAC;AACxD,kBAAI,CAACnB,EAAkB,SAASR,CAAG;AACjC,sBAAM,IAAI,MAAM,2BAA2BA,CAAG,EAAE;AAAA,YAEpD;AAEA,kBAAM6B,IAAqB;AAAA,cACzB,WAAWF,EAAK;AAAA,cAChB,cAAcA,EAAK;AAAA,cACnB,UAAUA,EAAK;AAAA,cACf,MAAMC,EAAW;AAAA,cACjB,UAAUD,EAAK;AAAA,YAAA;AAKjB,gBAFAhB,IAAcgB,EAAK,WAAWE,CAAI,GAE9BnB,MAAY,QAAQ;AACtB,oBAAMoB,IAAcrB,EAASkB,EAAK,UAAUA,EAAK,QAAQ,GACnDI,IAAWC,EAAK3B,GAAMyB,CAAW;AAEvC,oBAAM,IAAI,QAAc,CAACG,GAAS/G,MAAW;AAC3C,sBAAMgH,IAAcC,EAAkBJ,CAAQ;AAC9C,gBAAAG,EAAY,MAAMN,CAAU,GAC5BM,EAAY,IAAA,GACZA,EAAY,GAAG,UAAUD,CAAO,GAChCC,EAAY,GAAG,SAAShH,CAAM;AAAA,cAChC,CAAC,GAED2G,EAAK,OAAOE;AAAA,YACd;AACE,cAAAF,EAAK,SAASD;AAGhB,YAAAhB,IAAYe,EAAK,WAAWE,CAAI,GAChCN,EAAc,KAAKM,CAAI,GACvBJ;AAAA,UACF,OAAO;AAEL,gBAAIC,KAAcV;AAChB,oBAAM,IAAI,MAAM,6BAA6BA,CAAM,EAAE;AAGvD,kBAAM9D,IAAQ,OAAO,OAAOyE,EAAK,IAAI,EAAE,SAAA;AACvC,gBAAIzE,EAAM,SAAS+D;AACjB,oBAAM,IAAI,MAAM,oBAAoBU,EAAK,SAAS,EAAE;AAGtD,YAAAH,EAAWG,EAAK,SAAS,IAAIzE,GAC7BwE;AAAA,UACF;AAID,QAAAlI,EAAY,QAAQ+H,GACpB/H,EAAY,OAAO+H,EAAc,CAAC,GAClC/H,EAAY,OAAO,EAAE,GAAIA,EAAY,MAAM,GAAGgI,EAAA,GAE/CvJ,EAAO,MAAM,YAAYsJ,EAAc,MAAM,QAAQ,GACrDzH,EAAA;AAAA,MACF,SAASE,GAAK;AACZ,cAAMC,IAAQD;AACd,QAAA/B,EAAO,MAAM,iBAAiBgC,EAAM,OAAO,EAAE,GAC7C4G,IAAU5G,CAAK,GACfJ,EAAI,OAAOP,EAAY,WAAW,EAAE,KAAK;AAAA,UACvC,SAAS;AAAA,UACT,OAAO,EAAE,SAASW,EAAM,QAAA;AAAA,QAAQ,CACjC;AAAA,MACH;AAAA,IACF,CAAC,GAEDT,EAAI,GAAG,SAAS,CAACQ,MAAQ;AACvB,MAAA/B,EAAO,MAAM,kBAAkB+B,CAAG,GAClC6G,IAAU7G,CAAY,GACtBF,EAAKE,CAAY;AAAA,IACnB,CAAC;AAAA,EACH;AACF;AAKO,SAASoI,GACdP,GACAQ,GACS;AACT,SAAOA,EAAa,SAASR,EAAK,QAAQ;AAC5C;AAKO,SAASS,GAAgBC,GAA0B;AAexD,SAdwC;AAAA,IACtC,cAAc;AAAA,IACd,aAAa;AAAA,IACb,aAAa;AAAA,IACb,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,gCAAgC;AAAA,EAAA,EAGnBA,CAAQ,KAAK;AAC9B;"}
@@ -1,2 +1,2 @@
1
- "use strict";var b=Object.defineProperty;var v=(e,t,r)=>t in e?b(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var l=(e,t,r)=>v(e,typeof t!="symbol"?t+"":t,r);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u={REQUIRED:"{field} is required",TYPE_MISMATCH:"{field} must be of type {type}",MIN_VALUE:"{field} must be at least {min}",MAX_VALUE:"{field} must be at most {max}",MIN_LENGTH:"{field} must be at least {min} characters",MAX_LENGTH:"{field} must be at most {max} characters",PATTERN:"{field} does not match the required pattern",ENUM:"{field} must be one of: {values}",INVALID_OBJECT_ID:"{field} is not a valid ObjectId",INVALID_EMAIL:"{field} is not a valid email address"},f={EMAIL:/^[^\s@]+@[^\s@]+\.[^\s@]+$/,URL:/^https?:\/\/[^\s/$.?#].[^\s]*$/i,OBJECT_ID:/^[0-9a-fA-F]{24}$/,UUID:/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i};async function I(e,t,r){const a=[],n={},i=t??{};for(const[d,m]of Object.entries(e)){const p=i[d],c=await g(d,p,m,r);c.valid?n[d]=c.value:a.push(...c.errors??[])}return a.length>0?{valid:!1,errors:a}:{valid:!0,data:n}}async function g(e,t,r,a){const n=[];if(t==null||t==="")return r.required?(n.push({field:e,message:o(u.REQUIRED,{field:e}),code:"REQUIRED"}),{valid:!1,errors:n}):r.default!==void 0?{valid:!0,value:r.default}:{valid:!0,value:void 0};let i=t;return r.transform&&(i=r.transform(i)),a.sanitize&&(i=E(i,r.type)),A(i,r.type)?(r.type==="string"&&typeof i=="string"&&(r.min!==void 0&&i.length<r.min&&n.push({field:e,message:o(u.MIN_LENGTH,{field:e,min:r.min}),code:"MIN_LENGTH"}),r.max!==void 0&&i.length>r.max&&n.push({field:e,message:o(u.MAX_LENGTH,{field:e,max:r.max}),code:"MAX_LENGTH"}),r.pattern&&(new RegExp(r.pattern).test(i)||n.push({field:e,message:o(u.PATTERN,{field:e}),code:"PATTERN"}))),r.type==="number"&&typeof i=="number"&&(r.min!==void 0&&i<r.min&&n.push({field:e,message:o(u.MIN_VALUE,{field:e,min:r.min}),code:"MIN_VALUE"}),r.max!==void 0&&i>r.max&&n.push({field:e,message:o(u.MAX_VALUE,{field:e,max:r.max}),code:"MAX_VALUE"})),r.type==="email"&&typeof i=="string"&&(f.EMAIL.test(i)||n.push({field:e,message:o(u.INVALID_EMAIL,{field:e}),code:"INVALID_EMAIL"})),r.type==="objectId"&&typeof i=="string"&&(f.OBJECT_ID.test(i)||n.push({field:e,message:o(u.INVALID_OBJECT_ID,{field:e}),code:"INVALID_OBJECT_ID"})),r.enum&&!r.enum.includes(i)&&n.push({field:e,message:o(u.ENUM,{field:e,values:r.enum.join(", ")}),code:"ENUM"}),n.length>0?{valid:!1,errors:n}:{valid:!0,value:i}):(n.push({field:e,message:o(u.TYPE_MISMATCH,{field:e,type:r.type}),code:"TYPE_MISMATCH"}),{valid:!1,errors:n})}function A(e,t){switch(t){case"string":case"email":case"objectId":return typeof e=="string";case"number":return typeof e=="number"&&!isNaN(e);case"boolean":return typeof e=="boolean";case"array":return Array.isArray(e);case"object":return typeof e=="object"&&e!==null&&!Array.isArray(e);case"date":return e instanceof Date||typeof e=="string"&&!isNaN(Date.parse(e));default:return!0}}function E(e,t){if(t==="string"&&typeof e=="string")return e.trim();if(t==="number"&&typeof e=="string"){const r=parseFloat(e);return isNaN(r)?e:r}if(t==="boolean"){if(e==="true")return!0;if(e==="false")return!1}return e}function o(e,t){let r=e;for(const[a,n]of Object.entries(t))r=r.replace(`{${a}}`,String(n));return r}class y{constructor(t,r){l(this,"schema");l(this,"customAdapter");this.schema=t,this.customAdapter=r}async validate(t){if(this.customAdapter&&typeof this.customAdapter.validate=="function")return this.customAdapter.validate(this.schema,t);const r=[],a={},n=t??{};for(const[i,d]of Object.entries(this.schema)){const m=n[i],p=this.validateField(i,m,d);p.valid?a[i]=p.value:r.push(...p.errors??[])}return r.length>0?{valid:!1,errors:r}:{valid:!0,data:a}}validateField(t,r,a){const n=[];if(r==null)return a.required?(n.push({field:t,message:`${t} is required`,code:"REQUIRED"}),{valid:!1,errors:n}):a.default!==void 0?{valid:!0,value:a.default}:{valid:!0,value:void 0};let i=r;return a.transform&&(i=a.transform(i)),this.validateType(i,a.type)?(a.type==="String"&&typeof i=="string"&&(a.minLength!==void 0&&i.length<a.minLength&&n.push({field:t,message:`${t} must be at least ${a.minLength} characters`,code:"MIN_LENGTH"}),a.maxLength!==void 0&&i.length>a.maxLength&&n.push({field:t,message:`${t} must be at most ${a.maxLength} characters`,code:"MAX_LENGTH"}),a.match&&!a.match.test(i)&&n.push({field:t,message:`${t} does not match the required pattern`,code:"PATTERN"})),a.type==="Number"&&typeof i=="number"&&(a.min!==void 0&&i<a.min&&n.push({field:t,message:`${t} must be at least ${a.min}`,code:"MIN_VALUE"}),a.max!==void 0&&i>a.max&&n.push({field:t,message:`${t} must be at most ${a.max}`,code:"MAX_VALUE"})),a.type==="ObjectId"&&typeof i=="string"&&(f.OBJECT_ID.test(i)||n.push({field:t,message:`${t} is not a valid ObjectId`,code:"INVALID_OBJECT_ID"})),a.enum&&!a.enum.includes(i)&&n.push({field:t,message:`${t} must be one of: ${a.enum.join(", ")}`,code:"ENUM"}),a.validate&&a.validate.validator(i)===!1&&n.push({field:t,message:a.validate.message??`${t} failed custom validation`,code:"CUSTOM_VALIDATION"}),n.length>0?{valid:!1,errors:n}:{valid:!0,value:i}):(n.push({field:t,message:`${t} must be of type ${a.type}`,code:"TYPE_MISMATCH"}),{valid:!1,errors:n})}validateType(t,r){switch(r){case"String":return typeof t=="string";case"Number":return typeof t=="number"&&!isNaN(t);case"Boolean":return typeof t=="boolean";case"Date":return t instanceof Date||typeof t=="string"&&!isNaN(Date.parse(t));case"ObjectId":return typeof t=="string"&&f.OBJECT_ID.test(t);case"Array":return Array.isArray(t);case"Object":case"Mixed":return typeof t=="object"&&t!==null;case"Buffer":return Buffer.isBuffer(t);default:return!0}}getSchema(){return this.schema}}function N(e){return new y(e)}class s{constructor(t){l(this,"isOptional",!1);l(this,"defaultValue");l(this,"transformFn");l(this,"validateFn");this.validateFn=t}validate(t){if(t==null||t==="")return this.defaultValue!==void 0?{valid:!0,value:this.defaultValue}:this.isOptional?{valid:!0,value:void 0}:{valid:!1,error:"Value is required"};let r=t;return this.transformFn&&(r=this.transformFn(r)),this.validateFn(r)}optional(){return this.isOptional=!0,this}default(t){return this.defaultValue=t,this}transform(t){return this.transformFn=t,this}}const V={string(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:{valid:!0,value:e})},number(){return new s(e=>{const t=typeof e=="string"?parseFloat(e):e;return typeof t!="number"||isNaN(t)?{valid:!1,error:"Value must be a number"}:{valid:!0,value:t}})},integer(){return new s(e=>{const t=typeof e=="string"?parseInt(e,10):e;return typeof t!="number"||isNaN(t)||!Number.isInteger(t)?{valid:!1,error:"Value must be an integer"}:{valid:!0,value:t}})},boolean(){return new s(e=>typeof e=="boolean"?{valid:!0,value:e}:e==="true"?{valid:!0,value:!0}:e==="false"?{valid:!0,value:!1}:{valid:!1,error:"Value must be a boolean"})},email(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:f.EMAIL.test(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be a valid email"})},objectId(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:f.OBJECT_ID.test(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be a valid ObjectId"})},uuid(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:f.UUID.test(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be a valid UUID"})},url(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:f.URL.test(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be a valid URL"})},date(){return new s(e=>{const t=e instanceof Date?e:new Date(e);return isNaN(t.getTime())?{valid:!1,error:"Value must be a valid date"}:{valid:!0,value:t}})},array(){return new s(e=>Array.isArray(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be an array"})},enum(e){return new s(t=>e.includes(t)?{valid:!0,value:t}:{valid:!1,error:`Value must be one of: ${e.join(", ")}`})},custom(e,t){return new s(r=>e(r)?{valid:!0,value:r}:{valid:!1,error:t??"Custom validation failed"})}};function M(e){return new s(e)}exports.MongoValidator=y;exports.createMongoSchema=N;exports.createParamValidator=M;exports.validateField=g;exports.validateRequest=I;exports.validators=V;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u={REQUIRED:"{field} is required",TYPE_MISMATCH:"{field} must be of type {type}",MIN_VALUE:"{field} must be at least {min}",MAX_VALUE:"{field} must be at most {max}",MIN_LENGTH:"{field} must be at least {min} characters",MAX_LENGTH:"{field} must be at most {max} characters",PATTERN:"{field} does not match the required pattern",ENUM:"{field} must be one of: {values}",INVALID_OBJECT_ID:"{field} is not a valid ObjectId",INVALID_EMAIL:"{field} is not a valid email address"},f={EMAIL:/^[^\s@]+@[^\s@]+\.[^\s@]+$/,URL:/^https?:\/\/[^\s/$.?#].[^\s]*$/i,OBJECT_ID:/^[0-9a-fA-F]{24}$/,UUID:/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i};async function y(e,t,r){const a=[],n={},i=t??{};for(const[d,p]of Object.entries(e)){const l=i[d],m=await c(d,l,p,r);m.valid?n[d]=m.value:a.push(...m.errors??[])}return a.length>0?{valid:!1,errors:a}:{valid:!0,data:n}}async function c(e,t,r,a){const n=[];if(t==null||t==="")return r.required?(n.push({field:e,message:o(u.REQUIRED,{field:e}),code:"REQUIRED"}),{valid:!1,errors:n}):r.default!==void 0?{valid:!0,value:r.default}:{valid:!0,value:void 0};let i=t;return r.transform&&(i=r.transform(i)),a.sanitize&&(i=v(i,r.type)),b(i,r.type)?(r.type==="string"&&typeof i=="string"&&(r.min!==void 0&&i.length<r.min&&n.push({field:e,message:o(u.MIN_LENGTH,{field:e,min:r.min}),code:"MIN_LENGTH"}),r.max!==void 0&&i.length>r.max&&n.push({field:e,message:o(u.MAX_LENGTH,{field:e,max:r.max}),code:"MAX_LENGTH"}),r.pattern&&(new RegExp(r.pattern).test(i)||n.push({field:e,message:o(u.PATTERN,{field:e}),code:"PATTERN"}))),r.type==="number"&&typeof i=="number"&&(r.min!==void 0&&i<r.min&&n.push({field:e,message:o(u.MIN_VALUE,{field:e,min:r.min}),code:"MIN_VALUE"}),r.max!==void 0&&i>r.max&&n.push({field:e,message:o(u.MAX_VALUE,{field:e,max:r.max}),code:"MAX_VALUE"})),r.type==="email"&&typeof i=="string"&&(f.EMAIL.test(i)||n.push({field:e,message:o(u.INVALID_EMAIL,{field:e}),code:"INVALID_EMAIL"})),r.type==="objectId"&&typeof i=="string"&&(f.OBJECT_ID.test(i)||n.push({field:e,message:o(u.INVALID_OBJECT_ID,{field:e}),code:"INVALID_OBJECT_ID"})),r.enum&&!r.enum.includes(i)&&n.push({field:e,message:o(u.ENUM,{field:e,values:r.enum.join(", ")}),code:"ENUM"}),n.length>0?{valid:!1,errors:n}:{valid:!0,value:i}):(n.push({field:e,message:o(u.TYPE_MISMATCH,{field:e,type:r.type}),code:"TYPE_MISMATCH"}),{valid:!1,errors:n})}function b(e,t){switch(t){case"string":case"email":case"objectId":return typeof e=="string";case"number":return typeof e=="number"&&!isNaN(e);case"boolean":return typeof e=="boolean";case"array":return Array.isArray(e);case"object":return typeof e=="object"&&e!==null&&!Array.isArray(e);case"date":return e instanceof Date||typeof e=="string"&&!isNaN(Date.parse(e));default:return!0}}function v(e,t){if(t==="string"&&typeof e=="string")return e.trim();if(t==="number"&&typeof e=="string"){const r=parseFloat(e);return isNaN(r)?e:r}if(t==="boolean"){if(e==="true")return!0;if(e==="false")return!1}return e}function o(e,t){let r=e;for(const[a,n]of Object.entries(t))r=r.replace(`{${a}}`,String(n));return r}class g{schema;customAdapter;constructor(t,r){this.schema=t,this.customAdapter=r}async validate(t){if(this.customAdapter&&typeof this.customAdapter.validate=="function")return this.customAdapter.validate(this.schema,t);const r=[],a={},n=t??{};for(const[i,d]of Object.entries(this.schema)){const p=n[i],l=this.validateField(i,p,d);l.valid?a[i]=l.value:r.push(...l.errors??[])}return r.length>0?{valid:!1,errors:r}:{valid:!0,data:a}}validateField(t,r,a){const n=[];if(r==null)return a.required?(n.push({field:t,message:`${t} is required`,code:"REQUIRED"}),{valid:!1,errors:n}):a.default!==void 0?{valid:!0,value:a.default}:{valid:!0,value:void 0};let i=r;return a.transform&&(i=a.transform(i)),this.validateType(i,a.type)?(a.type==="String"&&typeof i=="string"&&(a.minLength!==void 0&&i.length<a.minLength&&n.push({field:t,message:`${t} must be at least ${a.minLength} characters`,code:"MIN_LENGTH"}),a.maxLength!==void 0&&i.length>a.maxLength&&n.push({field:t,message:`${t} must be at most ${a.maxLength} characters`,code:"MAX_LENGTH"}),a.match&&!a.match.test(i)&&n.push({field:t,message:`${t} does not match the required pattern`,code:"PATTERN"})),a.type==="Number"&&typeof i=="number"&&(a.min!==void 0&&i<a.min&&n.push({field:t,message:`${t} must be at least ${a.min}`,code:"MIN_VALUE"}),a.max!==void 0&&i>a.max&&n.push({field:t,message:`${t} must be at most ${a.max}`,code:"MAX_VALUE"})),a.type==="ObjectId"&&typeof i=="string"&&(f.OBJECT_ID.test(i)||n.push({field:t,message:`${t} is not a valid ObjectId`,code:"INVALID_OBJECT_ID"})),a.enum&&!a.enum.includes(i)&&n.push({field:t,message:`${t} must be one of: ${a.enum.join(", ")}`,code:"ENUM"}),a.validate&&a.validate.validator(i)===!1&&n.push({field:t,message:a.validate.message??`${t} failed custom validation`,code:"CUSTOM_VALIDATION"}),n.length>0?{valid:!1,errors:n}:{valid:!0,value:i}):(n.push({field:t,message:`${t} must be of type ${a.type}`,code:"TYPE_MISMATCH"}),{valid:!1,errors:n})}validateType(t,r){switch(r){case"String":return typeof t=="string";case"Number":return typeof t=="number"&&!isNaN(t);case"Boolean":return typeof t=="boolean";case"Date":return t instanceof Date||typeof t=="string"&&!isNaN(Date.parse(t));case"ObjectId":return typeof t=="string"&&f.OBJECT_ID.test(t);case"Array":return Array.isArray(t);case"Object":case"Mixed":return typeof t=="object"&&t!==null;case"Buffer":return Buffer.isBuffer(t);default:return!0}}getSchema(){return this.schema}}function I(e){return new g(e)}class s{isOptional=!1;defaultValue;transformFn;validateFn;constructor(t){this.validateFn=t}validate(t){if(t==null||t==="")return this.defaultValue!==void 0?{valid:!0,value:this.defaultValue}:this.isOptional?{valid:!0,value:void 0}:{valid:!1,error:"Value is required"};let r=t;return this.transformFn&&(r=this.transformFn(r)),this.validateFn(r)}optional(){return this.isOptional=!0,this}default(t){return this.defaultValue=t,this}transform(t){return this.transformFn=t,this}}const A={string(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:{valid:!0,value:e})},number(){return new s(e=>{const t=typeof e=="string"?parseFloat(e):e;return typeof t!="number"||isNaN(t)?{valid:!1,error:"Value must be a number"}:{valid:!0,value:t}})},integer(){return new s(e=>{const t=typeof e=="string"?parseInt(e,10):e;return typeof t!="number"||isNaN(t)||!Number.isInteger(t)?{valid:!1,error:"Value must be an integer"}:{valid:!0,value:t}})},boolean(){return new s(e=>typeof e=="boolean"?{valid:!0,value:e}:e==="true"?{valid:!0,value:!0}:e==="false"?{valid:!0,value:!1}:{valid:!1,error:"Value must be a boolean"})},email(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:f.EMAIL.test(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be a valid email"})},objectId(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:f.OBJECT_ID.test(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be a valid ObjectId"})},uuid(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:f.UUID.test(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be a valid UUID"})},url(){return new s(e=>typeof e!="string"?{valid:!1,error:"Value must be a string"}:f.URL.test(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be a valid URL"})},date(){return new s(e=>{const t=e instanceof Date?e:new Date(e);return isNaN(t.getTime())?{valid:!1,error:"Value must be a valid date"}:{valid:!0,value:t}})},array(){return new s(e=>Array.isArray(e)?{valid:!0,value:e}:{valid:!1,error:"Value must be an array"})},enum(e){return new s(t=>e.includes(t)?{valid:!0,value:t}:{valid:!1,error:`Value must be one of: ${e.join(", ")}`})},custom(e,t){return new s(r=>e(r)?{valid:!0,value:r}:{valid:!1,error:t??"Custom validation failed"})}};function E(e){return new s(e)}exports.MongoValidator=g;exports.createMongoSchema=I;exports.createParamValidator=E;exports.validateField=c;exports.validateRequest=y;exports.validators=A;
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/constants/validation.const.ts","../../src/validation/validators.ts","../../src/validation/mongo.ts","../../src/validation/paramValidators.ts"],"sourcesContent":["export const MONGO_FIELD_TYPES = {\n STRING: 'String',\n NUMBER: 'Number',\n BOOLEAN: 'Boolean',\n DATE: 'Date',\n OBJECT_ID: 'ObjectId',\n ARRAY: 'Array',\n OBJECT: 'Object',\n BUFFER: 'Buffer',\n MIXED: 'Mixed',\n} as const;\n\nexport const VALIDATION_MESSAGES = {\n REQUIRED: '{field} is required',\n TYPE_MISMATCH: '{field} must be of type {type}',\n MIN_VALUE: '{field} must be at least {min}',\n MAX_VALUE: '{field} must be at most {max}',\n MIN_LENGTH: '{field} must be at least {min} characters',\n MAX_LENGTH: '{field} must be at most {max} characters',\n PATTERN: '{field} does not match the required pattern',\n ENUM: '{field} must be one of: {values}',\n INVALID_OBJECT_ID: '{field} is not a valid ObjectId',\n INVALID_EMAIL: '{field} is not a valid email address',\n INVALID_URL: '{field} is not a valid URL',\n INVALID_DATE: '{field} is not a valid date',\n} as const;\n\nexport const REGEX_PATTERNS = {\n EMAIL: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/,\n URL: /^https?:\\/\\/[^\\s/$.?#].[^\\s]*$/i,\n OBJECT_ID: /^[0-9a-fA-F]{24}$/,\n UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n PHONE: /^\\+?[\\d\\s-()]+$/,\n ALPHANUMERIC: /^[a-zA-Z0-9]+$/,\n SLUG: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,\n} as const;\n\n","import type {\n ValidationSchema,\n FieldValidation,\n ValidationResult,\n ValidationError,\n ValidationConfig,\n} from '../types';\nimport { VALIDATION_MESSAGES, REGEX_PATTERNS } from '../constants';\n\nexport async function validateRequest<T = Record<string, unknown>>(\n schema: ValidationSchema,\n data: unknown,\n config: ValidationConfig\n): Promise<ValidationResult<T>> {\n const errors: ValidationError[] = [];\n const validated: Record<string, unknown> = {};\n const inputData = (data ?? {}) as Record<string, unknown>;\n\n for (const [field, fieldSchema] of Object.entries(schema)) {\n const value = inputData[field];\n const result = await validateField(field, value, fieldSchema, config);\n\n if (!result.valid) {\n errors.push(...(result.errors ?? []));\n } else {\n validated[field] = result.value;\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, data: validated as T };\n}\n\nexport async function validateField(\n field: string,\n value: unknown,\n schema: FieldValidation,\n config: ValidationConfig\n): Promise<{ valid: boolean; value?: unknown; errors?: ValidationError[] }> {\n const errors: ValidationError[] = [];\n\n if (value === undefined || value === null || value === '') {\n if (schema.required) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.REQUIRED, { field }),\n code: 'REQUIRED',\n });\n return { valid: false, errors };\n }\n\n if (schema.default !== undefined) {\n return { valid: true, value: schema.default };\n }\n\n return { valid: true, value: undefined };\n }\n\n let processedValue: unknown = value;\n\n if (schema.transform) {\n processedValue = schema.transform(processedValue);\n }\n\n if (config.sanitize) {\n processedValue = sanitizeValue(processedValue, schema.type);\n }\n\n const typeValid = validateType(processedValue, schema.type);\n if (!typeValid) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.TYPE_MISMATCH, { field, type: schema.type }),\n code: 'TYPE_MISMATCH',\n });\n return { valid: false, errors };\n }\n\n if (schema.type === 'string' && typeof processedValue === 'string') {\n if (schema.min !== undefined && processedValue.length < schema.min) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.MIN_LENGTH, { field, min: schema.min }),\n code: 'MIN_LENGTH',\n });\n }\n\n if (schema.max !== undefined && processedValue.length > schema.max) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.MAX_LENGTH, { field, max: schema.max }),\n code: 'MAX_LENGTH',\n });\n }\n\n if (schema.pattern) {\n const regex = new RegExp(schema.pattern);\n if (!regex.test(processedValue)) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.PATTERN, { field }),\n code: 'PATTERN',\n });\n }\n }\n }\n\n if (schema.type === 'number' && typeof processedValue === 'number') {\n if (schema.min !== undefined && processedValue < schema.min) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.MIN_VALUE, { field, min: schema.min }),\n code: 'MIN_VALUE',\n });\n }\n\n if (schema.max !== undefined && processedValue > schema.max) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.MAX_VALUE, { field, max: schema.max }),\n code: 'MAX_VALUE',\n });\n }\n }\n\n if (schema.type === 'email' && typeof processedValue === 'string') {\n if (!REGEX_PATTERNS.EMAIL.test(processedValue)) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.INVALID_EMAIL, { field }),\n code: 'INVALID_EMAIL',\n });\n }\n }\n\n if (schema.type === 'objectId' && typeof processedValue === 'string') {\n if (!REGEX_PATTERNS.OBJECT_ID.test(processedValue)) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.INVALID_OBJECT_ID, { field }),\n code: 'INVALID_OBJECT_ID',\n });\n }\n }\n\n if (schema.enum && !schema.enum.includes(processedValue)) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.ENUM, { field, values: schema.enum.join(', ') }),\n code: 'ENUM',\n });\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, value: processedValue };\n}\n\nfunction validateType(value: unknown, type: FieldValidation['type']): boolean {\n switch (type) {\n case 'string':\n case 'email':\n case 'objectId':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && !isNaN(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'array':\n return Array.isArray(value);\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n case 'date':\n return value instanceof Date || (typeof value === 'string' && !isNaN(Date.parse(value)));\n default:\n return true;\n }\n}\n\nfunction sanitizeValue(value: unknown, type: FieldValidation['type']): unknown {\n if (type === 'string' && typeof value === 'string') {\n return value.trim();\n }\n\n if (type === 'number' && typeof value === 'string') {\n const parsed = parseFloat(value);\n return isNaN(parsed) ? value : parsed;\n }\n\n if (type === 'boolean') {\n if (value === 'true') return true;\n if (value === 'false') return false;\n }\n\n return value;\n}\n\nfunction formatMessage(template: string, params: Record<string, unknown>): string {\n let message = template;\n for (const [key, value] of Object.entries(params)) {\n message = message.replace(`{${key}}`, String(value));\n }\n return message;\n}\n\n","import type {\n MongoValidationSchema,\n MongoFieldSchema,\n ValidationResult,\n ValidationError,\n} from '../types';\nimport { REGEX_PATTERNS } from '../constants';\n\nexport class MongoValidator {\n private schema: MongoValidationSchema;\n private customAdapter: unknown;\n\n constructor(schema: MongoValidationSchema, customAdapter?: unknown) {\n this.schema = schema;\n this.customAdapter = customAdapter;\n }\n\n async validate<T = Record<string, unknown>>(\n data: unknown\n ): Promise<ValidationResult<T>> {\n if (this.customAdapter && typeof (this.customAdapter as any).validate === 'function') {\n return (this.customAdapter as any).validate(this.schema, data);\n }\n\n const errors: ValidationError[] = [];\n const validated: Record<string, unknown> = {};\n const inputData = (data ?? {}) as Record<string, unknown>;\n\n for (const [field, fieldSchema] of Object.entries(this.schema)) {\n const value = inputData[field];\n const result = this.validateField(field, value, fieldSchema);\n\n if (!result.valid) {\n errors.push(...(result.errors ?? []));\n } else {\n validated[field] = result.value;\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, data: validated as T };\n }\n\n private validateField(\n field: string,\n value: unknown,\n schema: MongoFieldSchema\n ): { valid: boolean; value?: unknown; errors?: ValidationError[] } {\n const errors: ValidationError[] = [];\n\n if (value === undefined || value === null) {\n if (schema.required) {\n errors.push({\n field,\n message: `${field} is required`,\n code: 'REQUIRED',\n });\n return { valid: false, errors };\n }\n\n if (schema.default !== undefined) {\n return { valid: true, value: schema.default };\n }\n\n return { valid: true, value: undefined };\n }\n\n let processedValue: unknown = value;\n\n if (schema.transform) {\n processedValue = schema.transform(processedValue);\n }\n\n if (!this.validateType(processedValue, schema.type)) {\n errors.push({\n field,\n message: `${field} must be of type ${schema.type}`,\n code: 'TYPE_MISMATCH',\n });\n return { valid: false, errors };\n }\n\n if (schema.type === 'String' && typeof processedValue === 'string') {\n if (schema.minLength !== undefined && processedValue.length < schema.minLength) {\n errors.push({\n field,\n message: `${field} must be at least ${schema.minLength} characters`,\n code: 'MIN_LENGTH',\n });\n }\n\n if (schema.maxLength !== undefined && processedValue.length > schema.maxLength) {\n errors.push({\n field,\n message: `${field} must be at most ${schema.maxLength} characters`,\n code: 'MAX_LENGTH',\n });\n }\n\n if (schema.match && !schema.match.test(processedValue)) {\n errors.push({\n field,\n message: `${field} does not match the required pattern`,\n code: 'PATTERN',\n });\n }\n }\n\n if (schema.type === 'Number' && typeof processedValue === 'number') {\n if (schema.min !== undefined && processedValue < schema.min) {\n errors.push({\n field,\n message: `${field} must be at least ${schema.min}`,\n code: 'MIN_VALUE',\n });\n }\n\n if (schema.max !== undefined && processedValue > schema.max) {\n errors.push({\n field,\n message: `${field} must be at most ${schema.max}`,\n code: 'MAX_VALUE',\n });\n }\n }\n\n if (schema.type === 'ObjectId' && typeof processedValue === 'string') {\n if (!REGEX_PATTERNS.OBJECT_ID.test(processedValue)) {\n errors.push({\n field,\n message: `${field} is not a valid ObjectId`,\n code: 'INVALID_OBJECT_ID',\n });\n }\n }\n\n if (schema.enum && !schema.enum.includes(processedValue)) {\n errors.push({\n field,\n message: `${field} must be one of: ${schema.enum.join(', ')}`,\n code: 'ENUM',\n });\n }\n\n if (schema.validate) {\n const customResult = schema.validate.validator(processedValue);\n if (customResult === false) {\n errors.push({\n field,\n message: schema.validate.message ?? `${field} failed custom validation`,\n code: 'CUSTOM_VALIDATION',\n });\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, value: processedValue };\n }\n\n private validateType(value: unknown, type: MongoFieldSchema['type']): boolean {\n switch (type) {\n case 'String':\n return typeof value === 'string';\n case 'Number':\n return typeof value === 'number' && !isNaN(value);\n case 'Boolean':\n return typeof value === 'boolean';\n case 'Date':\n return value instanceof Date || (typeof value === 'string' && !isNaN(Date.parse(value)));\n case 'ObjectId':\n return typeof value === 'string' && REGEX_PATTERNS.OBJECT_ID.test(value);\n case 'Array':\n return Array.isArray(value);\n case 'Object':\n case 'Mixed':\n return typeof value === 'object' && value !== null;\n case 'Buffer':\n return Buffer.isBuffer(value);\n default:\n return true;\n }\n }\n\n getSchema(): MongoValidationSchema {\n return this.schema;\n }\n}\n\nexport function createMongoSchema(schema: MongoValidationSchema): MongoValidator {\n return new MongoValidator(schema);\n}\n\n","import type { ParamValidator, ValidationParamResult, TransformFunction } from '../types';\nimport { REGEX_PATTERNS } from '../constants';\n\nclass BaseParamValidator<T> implements ParamValidator<T> {\n protected isOptional = false;\n protected defaultValue?: T;\n protected transformFn?: TransformFunction;\n protected validateFn: (value: unknown) => ValidationParamResult<T>;\n\n constructor(validateFn: (value: unknown) => ValidationParamResult<T>) {\n this.validateFn = validateFn;\n }\n\n validate(value: unknown): ValidationParamResult<T> {\n if (value === undefined || value === null || value === '') {\n if (this.defaultValue !== undefined) {\n return { valid: true, value: this.defaultValue };\n }\n if (this.isOptional) {\n return { valid: true, value: undefined as unknown as T };\n }\n return { valid: false, error: 'Value is required' };\n }\n\n let processedValue: unknown = value;\n if (this.transformFn) {\n processedValue = this.transformFn(processedValue);\n }\n\n return this.validateFn(processedValue);\n }\n\n optional(): ParamValidator<T | undefined> {\n this.isOptional = true;\n return this as unknown as ParamValidator<T | undefined>;\n }\n\n default(defaultValue: T): ParamValidator<T> {\n this.defaultValue = defaultValue;\n return this;\n }\n\n transform(fn: TransformFunction): ParamValidator<T> {\n this.transformFn = fn;\n return this;\n }\n}\n\nexport const validators = {\n string(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n return { valid: true, value };\n });\n },\n\n number(): ParamValidator<number> {\n return new BaseParamValidator((value) => {\n const num = typeof value === 'string' ? parseFloat(value) : value;\n if (typeof num !== 'number' || isNaN(num)) {\n return { valid: false, error: 'Value must be a number' };\n }\n return { valid: true, value: num };\n });\n },\n\n integer(): ParamValidator<number> {\n return new BaseParamValidator((value) => {\n const num = typeof value === 'string' ? parseInt(value, 10) : value;\n if (typeof num !== 'number' || isNaN(num) || !Number.isInteger(num)) {\n return { valid: false, error: 'Value must be an integer' };\n }\n return { valid: true, value: num };\n });\n },\n\n boolean(): ParamValidator<boolean> {\n return new BaseParamValidator((value) => {\n if (typeof value === 'boolean') {\n return { valid: true, value };\n }\n if (value === 'true') return { valid: true, value: true };\n if (value === 'false') return { valid: true, value: false };\n return { valid: false, error: 'Value must be a boolean' };\n });\n },\n\n email(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n if (!REGEX_PATTERNS.EMAIL.test(value)) {\n return { valid: false, error: 'Value must be a valid email' };\n }\n return { valid: true, value };\n });\n },\n\n objectId(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n if (!REGEX_PATTERNS.OBJECT_ID.test(value)) {\n return { valid: false, error: 'Value must be a valid ObjectId' };\n }\n return { valid: true, value };\n });\n },\n\n uuid(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n if (!REGEX_PATTERNS.UUID.test(value)) {\n return { valid: false, error: 'Value must be a valid UUID' };\n }\n return { valid: true, value };\n });\n },\n\n url(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n if (!REGEX_PATTERNS.URL.test(value)) {\n return { valid: false, error: 'Value must be a valid URL' };\n }\n return { valid: true, value };\n });\n },\n\n date(): ParamValidator<Date> {\n return new BaseParamValidator((value) => {\n const date = value instanceof Date ? value : new Date(value as string);\n if (isNaN(date.getTime())) {\n return { valid: false, error: 'Value must be a valid date' };\n }\n return { valid: true, value: date };\n });\n },\n\n array<T>(): ParamValidator<T[]> {\n return new BaseParamValidator((value) => {\n if (!Array.isArray(value)) {\n return { valid: false, error: 'Value must be an array' };\n }\n return { valid: true, value: value as T[] };\n });\n },\n\n enum<T extends string>(values: readonly T[]): ParamValidator<T> {\n return new BaseParamValidator((value) => {\n if (!values.includes(value as T)) {\n return { valid: false, error: `Value must be one of: ${values.join(', ')}` };\n }\n return { valid: true, value: value as T };\n });\n },\n\n custom<T>(validateFn: (value: unknown) => boolean, errorMessage?: string): ParamValidator<T> {\n return new BaseParamValidator((value) => {\n if (!validateFn(value)) {\n return { valid: false, error: errorMessage ?? 'Custom validation failed' };\n }\n return { valid: true, value: value as T };\n });\n },\n};\n\nexport function createParamValidator<T>(\n validateFn: (value: unknown) => ValidationParamResult<T>\n): ParamValidator<T> {\n return new BaseParamValidator(validateFn);\n}\n\n"],"names":["VALIDATION_MESSAGES","REGEX_PATTERNS","validateRequest","schema","data","config","errors","validated","inputData","field","fieldSchema","value","result","validateField","formatMessage","processedValue","sanitizeValue","validateType","type","parsed","template","params","message","key","MongoValidator","customAdapter","__publicField","createMongoSchema","BaseParamValidator","validateFn","defaultValue","fn","validators","num","date","values","errorMessage","createParamValidator"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/constants/validation.const.ts","../../src/validation/validators.ts","../../src/validation/mongo.ts","../../src/validation/paramValidators.ts"],"sourcesContent":["export const MONGO_FIELD_TYPES = {\n STRING: 'String',\n NUMBER: 'Number',\n BOOLEAN: 'Boolean',\n DATE: 'Date',\n OBJECT_ID: 'ObjectId',\n ARRAY: 'Array',\n OBJECT: 'Object',\n BUFFER: 'Buffer',\n MIXED: 'Mixed',\n} as const;\n\nexport const VALIDATION_MESSAGES = {\n REQUIRED: '{field} is required',\n TYPE_MISMATCH: '{field} must be of type {type}',\n MIN_VALUE: '{field} must be at least {min}',\n MAX_VALUE: '{field} must be at most {max}',\n MIN_LENGTH: '{field} must be at least {min} characters',\n MAX_LENGTH: '{field} must be at most {max} characters',\n PATTERN: '{field} does not match the required pattern',\n ENUM: '{field} must be one of: {values}',\n INVALID_OBJECT_ID: '{field} is not a valid ObjectId',\n INVALID_EMAIL: '{field} is not a valid email address',\n INVALID_URL: '{field} is not a valid URL',\n INVALID_DATE: '{field} is not a valid date',\n} as const;\n\nexport const REGEX_PATTERNS = {\n EMAIL: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/,\n URL: /^https?:\\/\\/[^\\s/$.?#].[^\\s]*$/i,\n OBJECT_ID: /^[0-9a-fA-F]{24}$/,\n UUID: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,\n PHONE: /^\\+?[\\d\\s-()]+$/,\n ALPHANUMERIC: /^[a-zA-Z0-9]+$/,\n SLUG: /^[a-z0-9]+(?:-[a-z0-9]+)*$/,\n} as const;\n\n","import type {\n ValidationSchema,\n FieldValidation,\n ValidationResult,\n ValidationError,\n ValidationConfig,\n} from '../types';\nimport { VALIDATION_MESSAGES, REGEX_PATTERNS } from '../constants';\n\nexport async function validateRequest<T = Record<string, unknown>>(\n schema: ValidationSchema,\n data: unknown,\n config: ValidationConfig\n): Promise<ValidationResult<T>> {\n const errors: ValidationError[] = [];\n const validated: Record<string, unknown> = {};\n const inputData = (data ?? {}) as Record<string, unknown>;\n\n for (const [field, fieldSchema] of Object.entries(schema)) {\n const value = inputData[field];\n const result = await validateField(field, value, fieldSchema, config);\n\n if (!result.valid) {\n errors.push(...(result.errors ?? []));\n } else {\n validated[field] = result.value;\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, data: validated as T };\n}\n\nexport async function validateField(\n field: string,\n value: unknown,\n schema: FieldValidation,\n config: ValidationConfig\n): Promise<{ valid: boolean; value?: unknown; errors?: ValidationError[] }> {\n const errors: ValidationError[] = [];\n\n if (value === undefined || value === null || value === '') {\n if (schema.required) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.REQUIRED, { field }),\n code: 'REQUIRED',\n });\n return { valid: false, errors };\n }\n\n if (schema.default !== undefined) {\n return { valid: true, value: schema.default };\n }\n\n return { valid: true, value: undefined };\n }\n\n let processedValue = value;\n\n if (schema.transform) {\n processedValue = schema.transform(processedValue) as typeof processedValue;\n }\n\n if (config.sanitize) {\n processedValue = sanitizeValue(processedValue, schema.type) as typeof processedValue;\n }\n\n const typeValid = validateType(processedValue, schema.type);\n if (!typeValid) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.TYPE_MISMATCH, { field, type: schema.type }),\n code: 'TYPE_MISMATCH',\n });\n return { valid: false, errors };\n }\n\n if (schema.type === 'string' && typeof processedValue === 'string') {\n if (schema.min !== undefined && processedValue.length < schema.min) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.MIN_LENGTH, { field, min: schema.min }),\n code: 'MIN_LENGTH',\n });\n }\n\n if (schema.max !== undefined && processedValue.length > schema.max) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.MAX_LENGTH, { field, max: schema.max }),\n code: 'MAX_LENGTH',\n });\n }\n\n if (schema.pattern) {\n const regex = new RegExp(schema.pattern);\n if (!regex.test(processedValue)) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.PATTERN, { field }),\n code: 'PATTERN',\n });\n }\n }\n }\n\n if (schema.type === 'number' && typeof processedValue === 'number') {\n if (schema.min !== undefined && processedValue < schema.min) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.MIN_VALUE, { field, min: schema.min }),\n code: 'MIN_VALUE',\n });\n }\n\n if (schema.max !== undefined && processedValue > schema.max) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.MAX_VALUE, { field, max: schema.max }),\n code: 'MAX_VALUE',\n });\n }\n }\n\n if (schema.type === 'email' && typeof processedValue === 'string') {\n if (!REGEX_PATTERNS.EMAIL.test(processedValue)) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.INVALID_EMAIL, { field }),\n code: 'INVALID_EMAIL',\n });\n }\n }\n\n if (schema.type === 'objectId' && typeof processedValue === 'string') {\n if (!REGEX_PATTERNS.OBJECT_ID.test(processedValue)) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.INVALID_OBJECT_ID, { field }),\n code: 'INVALID_OBJECT_ID',\n });\n }\n }\n\n if (schema.enum && !schema.enum.includes(processedValue)) {\n errors.push({\n field,\n message: formatMessage(VALIDATION_MESSAGES.ENUM, { field, values: schema.enum.join(', ') }),\n code: 'ENUM',\n });\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, value: processedValue };\n}\n\nfunction validateType(value: unknown, type: FieldValidation['type']): boolean {\n switch (type) {\n case 'string':\n case 'email':\n case 'objectId':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && !isNaN(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'array':\n return Array.isArray(value);\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n case 'date':\n return value instanceof Date || (typeof value === 'string' && !isNaN(Date.parse(value)));\n default:\n return true;\n }\n}\n\nfunction sanitizeValue(value: unknown, type: FieldValidation['type']): unknown {\n if (type === 'string' && typeof value === 'string') {\n return value.trim();\n }\n\n if (type === 'number' && typeof value === 'string') {\n const parsed = parseFloat(value);\n return isNaN(parsed) ? value : parsed;\n }\n\n if (type === 'boolean') {\n if (value === 'true') return true;\n if (value === 'false') return false;\n }\n\n return value;\n}\n\nfunction formatMessage(template: string, params: Record<string, unknown>): string {\n let message = template;\n for (const [key, value] of Object.entries(params)) {\n message = message.replace(`{${key}}`, String(value));\n }\n return message;\n}\n\n","import type {\n MongoValidationSchema,\n MongoFieldSchema,\n ValidationResult,\n ValidationError,\n} from '../types';\nimport { REGEX_PATTERNS } from '../constants';\n\nexport class MongoValidator {\n private schema: MongoValidationSchema;\n private customAdapter: unknown;\n\n constructor(schema: MongoValidationSchema, customAdapter?: unknown) {\n this.schema = schema;\n this.customAdapter = customAdapter;\n }\n\n async validate<T = Record<string, unknown>>(\n data: unknown\n ): Promise<ValidationResult<T>> {\n if (this.customAdapter && typeof (this.customAdapter as any).validate === 'function') {\n return (this.customAdapter as any).validate(this.schema, data);\n }\n\n const errors: ValidationError[] = [];\n const validated: Record<string, unknown> = {};\n const inputData = (data ?? {}) as Record<string, unknown>;\n\n for (const [field, fieldSchema] of Object.entries(this.schema)) {\n const value = inputData[field];\n const result = this.validateField(field, value, fieldSchema);\n\n if (!result.valid) {\n errors.push(...(result.errors ?? []));\n } else {\n validated[field] = result.value;\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, data: validated as T };\n }\n\n private validateField(\n field: string,\n value: unknown,\n schema: MongoFieldSchema\n ): { valid: boolean; value?: unknown; errors?: ValidationError[] } {\n const errors: ValidationError[] = [];\n\n if (value === undefined || value === null) {\n if (schema.required) {\n errors.push({\n field,\n message: `${field} is required`,\n code: 'REQUIRED',\n });\n return { valid: false, errors };\n }\n\n if (schema.default !== undefined) {\n return { valid: true, value: schema.default };\n }\n\n return { valid: true, value: undefined };\n }\n\n let processedValue = value;\n\n if (schema.transform) {\n processedValue = schema.transform(processedValue) as typeof processedValue;\n }\n\n if (!this.validateType(processedValue, schema.type)) {\n errors.push({\n field,\n message: `${field} must be of type ${schema.type}`,\n code: 'TYPE_MISMATCH',\n });\n return { valid: false, errors };\n }\n\n if (schema.type === 'String' && typeof processedValue === 'string') {\n if (schema.minLength !== undefined && processedValue.length < schema.minLength) {\n errors.push({\n field,\n message: `${field} must be at least ${schema.minLength} characters`,\n code: 'MIN_LENGTH',\n });\n }\n\n if (schema.maxLength !== undefined && processedValue.length > schema.maxLength) {\n errors.push({\n field,\n message: `${field} must be at most ${schema.maxLength} characters`,\n code: 'MAX_LENGTH',\n });\n }\n\n if (schema.match && !schema.match.test(processedValue)) {\n errors.push({\n field,\n message: `${field} does not match the required pattern`,\n code: 'PATTERN',\n });\n }\n }\n\n if (schema.type === 'Number' && typeof processedValue === 'number') {\n if (schema.min !== undefined && processedValue < schema.min) {\n errors.push({\n field,\n message: `${field} must be at least ${schema.min}`,\n code: 'MIN_VALUE',\n });\n }\n\n if (schema.max !== undefined && processedValue > schema.max) {\n errors.push({\n field,\n message: `${field} must be at most ${schema.max}`,\n code: 'MAX_VALUE',\n });\n }\n }\n\n if (schema.type === 'ObjectId' && typeof processedValue === 'string') {\n if (!REGEX_PATTERNS.OBJECT_ID.test(processedValue)) {\n errors.push({\n field,\n message: `${field} is not a valid ObjectId`,\n code: 'INVALID_OBJECT_ID',\n });\n }\n }\n\n if (schema.enum && !schema.enum.includes(processedValue)) {\n errors.push({\n field,\n message: `${field} must be one of: ${schema.enum.join(', ')}`,\n code: 'ENUM',\n });\n }\n\n if (schema.validate) {\n const customResult = schema.validate.validator(processedValue);\n if (customResult === false) {\n errors.push({\n field,\n message: schema.validate.message ?? `${field} failed custom validation`,\n code: 'CUSTOM_VALIDATION',\n });\n }\n }\n\n if (errors.length > 0) {\n return { valid: false, errors };\n }\n\n return { valid: true, value: processedValue };\n }\n\n private validateType(value: unknown, type: MongoFieldSchema['type']): boolean {\n switch (type) {\n case 'String':\n return typeof value === 'string';\n case 'Number':\n return typeof value === 'number' && !isNaN(value);\n case 'Boolean':\n return typeof value === 'boolean';\n case 'Date':\n return value instanceof Date || (typeof value === 'string' && !isNaN(Date.parse(value)));\n case 'ObjectId':\n return typeof value === 'string' && REGEX_PATTERNS.OBJECT_ID.test(value);\n case 'Array':\n return Array.isArray(value);\n case 'Object':\n case 'Mixed':\n return typeof value === 'object' && value !== null;\n case 'Buffer':\n return Buffer.isBuffer(value);\n default:\n return true;\n }\n }\n\n getSchema(): MongoValidationSchema {\n return this.schema;\n }\n}\n\nexport function createMongoSchema(schema: MongoValidationSchema): MongoValidator {\n return new MongoValidator(schema);\n}\n\n","import type { ParamValidator, ValidationParamResult, TransformFunction } from '../types';\nimport { REGEX_PATTERNS } from '../constants';\n\nclass BaseParamValidator<T> implements ParamValidator<T> {\n protected isOptional = false;\n protected defaultValue?: T;\n protected transformFn?: TransformFunction;\n protected validateFn: (value: unknown) => ValidationParamResult<T>;\n\n constructor(validateFn: (value: unknown) => ValidationParamResult<T>) {\n this.validateFn = validateFn;\n }\n\n validate(value: unknown): ValidationParamResult<T> {\n if (value === undefined || value === null || value === '') {\n if (this.defaultValue !== undefined) {\n return { valid: true, value: this.defaultValue };\n }\n if (this.isOptional) {\n return { valid: true, value: undefined as unknown as T };\n }\n return { valid: false, error: 'Value is required' };\n }\n\n let processedValue = value;\n if (this.transformFn) {\n processedValue = this.transformFn(processedValue) as typeof processedValue;\n }\n\n return this.validateFn(processedValue);\n }\n\n optional(): ParamValidator<T | undefined> {\n this.isOptional = true;\n return this as unknown as ParamValidator<T | undefined>;\n }\n\n default(defaultValue: T): ParamValidator<T> {\n this.defaultValue = defaultValue;\n return this;\n }\n\n transform(fn: TransformFunction): ParamValidator<T> {\n this.transformFn = fn;\n return this;\n }\n}\n\nexport const validators = {\n string(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n return { valid: true, value };\n });\n },\n\n number(): ParamValidator<number> {\n return new BaseParamValidator((value) => {\n const num = typeof value === 'string' ? parseFloat(value) : value;\n if (typeof num !== 'number' || isNaN(num)) {\n return { valid: false, error: 'Value must be a number' };\n }\n return { valid: true, value: num };\n });\n },\n\n integer(): ParamValidator<number> {\n return new BaseParamValidator((value) => {\n const num = typeof value === 'string' ? parseInt(value, 10) : value;\n if (typeof num !== 'number' || isNaN(num) || !Number.isInteger(num)) {\n return { valid: false, error: 'Value must be an integer' };\n }\n return { valid: true, value: num };\n });\n },\n\n boolean(): ParamValidator<boolean> {\n return new BaseParamValidator((value) => {\n if (typeof value === 'boolean') {\n return { valid: true, value };\n }\n if (value === 'true') return { valid: true, value: true };\n if (value === 'false') return { valid: true, value: false };\n return { valid: false, error: 'Value must be a boolean' };\n });\n },\n\n email(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n if (!REGEX_PATTERNS.EMAIL.test(value)) {\n return { valid: false, error: 'Value must be a valid email' };\n }\n return { valid: true, value };\n });\n },\n\n objectId(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n if (!REGEX_PATTERNS.OBJECT_ID.test(value)) {\n return { valid: false, error: 'Value must be a valid ObjectId' };\n }\n return { valid: true, value };\n });\n },\n\n uuid(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n if (!REGEX_PATTERNS.UUID.test(value)) {\n return { valid: false, error: 'Value must be a valid UUID' };\n }\n return { valid: true, value };\n });\n },\n\n url(): ParamValidator<string> {\n return new BaseParamValidator((value) => {\n if (typeof value !== 'string') {\n return { valid: false, error: 'Value must be a string' };\n }\n if (!REGEX_PATTERNS.URL.test(value)) {\n return { valid: false, error: 'Value must be a valid URL' };\n }\n return { valid: true, value };\n });\n },\n\n date(): ParamValidator<Date> {\n return new BaseParamValidator((value) => {\n const date = value instanceof Date ? value : new Date(value as string);\n if (isNaN(date.getTime())) {\n return { valid: false, error: 'Value must be a valid date' };\n }\n return { valid: true, value: date };\n });\n },\n\n array<T>(): ParamValidator<T[]> {\n return new BaseParamValidator((value) => {\n if (!Array.isArray(value)) {\n return { valid: false, error: 'Value must be an array' };\n }\n return { valid: true, value: value as T[] };\n });\n },\n\n enum<T extends string>(values: readonly T[]): ParamValidator<T> {\n return new BaseParamValidator((value) => {\n if (!values.includes(value as T)) {\n return { valid: false, error: `Value must be one of: ${values.join(', ')}` };\n }\n return { valid: true, value: value as T };\n });\n },\n\n custom<T>(validateFn: (value: unknown) => boolean, errorMessage?: string): ParamValidator<T> {\n return new BaseParamValidator((value) => {\n if (!validateFn(value)) {\n return { valid: false, error: errorMessage ?? 'Custom validation failed' };\n }\n return { valid: true, value: value as T };\n });\n },\n};\n\nexport function createParamValidator<T>(\n validateFn: (value: unknown) => ValidationParamResult<T>\n): ParamValidator<T> {\n return new BaseParamValidator(validateFn);\n}\n\n"],"names":["VALIDATION_MESSAGES","REGEX_PATTERNS","validateRequest","schema","data","config","errors","validated","inputData","field","fieldSchema","value","result","validateField","formatMessage","processedValue","sanitizeValue","validateType","type","parsed","template","params","message","key","MongoValidator","customAdapter","createMongoSchema","BaseParamValidator","validateFn","defaultValue","fn","validators","num","date","values","errorMessage","createParamValidator"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { WebSocketManager, createWebSocketServer } from './manager';
2
+ export type { WebSocketOptions, HarborWebSocket, Room } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/websocket/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ "use strict";var d=Object.create;var h=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,b=Object.prototype.hasOwnProperty;var u=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of p(e))!b.call(o,s)&&s!==t&&h(o,s,{get:()=>e[s],enumerable:!(r=f(e,s))||r.enumerable});return o};var m=(o,e,t)=>(t=o!=null?d(S(o)):{},u(e||!o||!o.__esModule?h(t,"default",{value:o,enumerable:!0}):t,o));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const v=require("../logger-D-lfaRWQ.js"),n=v.createLogger("websocket");class l{wss=null;clients=new Map;rooms=new Map;heartbeatTimer=null;options;constructor(e={}){this.options={path:"/ws",maxPayload:1024*1024,perMessageDeflate:!1,clientTracking:!0,heartbeatInterval:3e4,...e}}async attach(e){try{const t=await import("ws"),r=t.WebSocketServer||t.default?.WebSocketServer;return this.wss=new r({server:e,path:this.options.path,maxPayload:this.options.maxPayload,perMessageDeflate:this.options.perMessageDeflate,clientTracking:this.options.clientTracking}),this.wss.on("connection",(s,c)=>{const i=this.enhanceClient(s);this.clients.set(i.id,i),n.info(`WebSocket client connected: ${i.id}`),this.options.onConnection?.(i,c),s.on("message",a=>{this.handleMessage(i,a)}),s.on("close",(a,g)=>{this.handleDisconnect(i,a,g.toString())}),s.on("error",a=>{n.error(`WebSocket error for ${i.id}:`,a),this.options.onError?.(i,a)}),s.on("pong",()=>{i.isAlive=!0})}),this.startHeartbeat(),n.info(`WebSocket server started on path ${this.options.path}`),this.wss}catch(t){throw n.warn("WebSocket not available. Install ws package: npm i ws"),t}}handleMessage(e,t){try{const r=JSON.parse(t.toString());this.options.onMessage?.(e,r)}catch{this.options.onMessage?.(e,t.toString())}}enhanceClient(e){const t=e;return t.id=this.generateId(),t.isAlive=!0,t.data={},t.rooms=new Set,t}generateId(){return`ws_${Date.now()}_${Math.random().toString(36).substring(2,9)}`}handleDisconnect(e,t,r){e.rooms.forEach(s=>{this.leave(e,s)}),this.clients.delete(e.id),n.info(`WebSocket client disconnected: ${e.id} (${t})`),this.options.onClose?.(e,t,r)}startHeartbeat(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.heartbeatTimer=setInterval(()=>{this.clients.forEach(e=>{if(!e.isAlive){e.terminate();return}e.isAlive=!1,e.ping()})},this.options.heartbeatInterval)}join(e,t){this.rooms.has(t)||this.rooms.set(t,{name:t,clients:new Set}),this.rooms.get(t).clients.add(e),e.rooms.add(t),n.debug(`Client ${e.id} joined room ${t}`)}leave(e,t){const r=this.rooms.get(t);r&&(r.clients.delete(e),e.rooms.delete(t),r.clients.size===0&&this.rooms.delete(t),n.debug(`Client ${e.id} left room ${t}`))}broadcast(e,t){const r=typeof e=="string"?e:JSON.stringify(e);this.clients.forEach(s=>{s!==t&&s.readyState===1&&s.send(r)})}broadcastToRoom(e,t,r){const s=this.rooms.get(e);if(!s)return;const c=typeof t=="string"?t:JSON.stringify(t);s.clients.forEach(i=>{i!==r&&i.readyState===1&&i.send(c)})}send(e,t){const r=this.clients.get(e);if(r&&r.readyState===1){const s=typeof t=="string"?t:JSON.stringify(t);return r.send(s),!0}return!1}getClient(e){return this.clients.get(e)}getClients(){return Array.from(this.clients.values())}getRoom(e){return this.rooms.get(e)}getRooms(){return Array.from(this.rooms.keys())}getClientCount(){return this.clients.size}close(){this.heartbeatTimer&&clearInterval(this.heartbeatTimer),this.wss?.close?.(),this.clients.clear(),this.rooms.clear(),n.info("WebSocket server closed")}}function y(o){return new l(o)}exports.WebSocketManager=l;exports.createWebSocketServer=y;
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/websocket/manager.ts"],"sourcesContent":["import { Server as HttpServer } from 'http';\nimport { createLogger } from '../utils/logger';\nimport type { WebSocketOptions, HarborWebSocket, Room } from './types';\n\nconst logger = createLogger('websocket');\n\nexport class WebSocketManager {\n private wss: unknown = null;\n private clients: Map<string, HarborWebSocket> = new Map();\n private rooms: Map<string, Room> = new Map();\n private heartbeatTimer: NodeJS.Timeout | null = null;\n private options: WebSocketOptions;\n\n constructor(options: WebSocketOptions = {}) {\n this.options = {\n path: '/ws',\n maxPayload: 1024 * 1024,\n perMessageDeflate: false,\n clientTracking: true,\n heartbeatInterval: 30000,\n ...options,\n };\n }\n\n async attach(server: HttpServer): Promise<unknown> {\n try {\n const ws = await import('ws');\n const WebSocketServer = ws.WebSocketServer || ws.default?.WebSocketServer;\n \n this.wss = new WebSocketServer({\n server,\n path: this.options.path,\n maxPayload: this.options.maxPayload,\n perMessageDeflate: this.options.perMessageDeflate,\n clientTracking: this.options.clientTracking,\n });\n\n (this.wss as any).on('connection', (wsClient: any, request: unknown) => {\n const client = this.enhanceClient(wsClient);\n this.clients.set(client.id, client);\n\n logger.info(`WebSocket client connected: ${client.id}`);\n this.options.onConnection?.(client, request);\n\n wsClient.on('message', (data: Buffer) => {\n this.handleMessage(client, data);\n });\n\n wsClient.on('close', (code: number, reason: Buffer) => {\n this.handleDisconnect(client, code, reason.toString());\n });\n\n wsClient.on('error', (error: Error) => {\n logger.error(`WebSocket error for ${client.id}:`, error);\n this.options.onError?.(client, error);\n });\n\n wsClient.on('pong', () => {\n client.isAlive = true;\n });\n });\n\n this.startHeartbeat();\n logger.info(`WebSocket server started on path ${this.options.path}`);\n\n return this.wss;\n } catch (error) {\n logger.warn('WebSocket not available. Install ws package: npm i ws');\n throw error;\n }\n }\n\n private handleMessage(client: HarborWebSocket, data: Buffer): void {\n try {\n const parsed = JSON.parse(data.toString());\n this.options.onMessage?.(client, parsed);\n } catch {\n this.options.onMessage?.(client, data.toString());\n }\n }\n\n private enhanceClient(ws: unknown): HarborWebSocket {\n const client = ws as HarborWebSocket;\n client.id = this.generateId();\n client.isAlive = true;\n client.data = {};\n client.rooms = new Set();\n return client;\n }\n\n private generateId(): string {\n return `ws_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n\n private handleDisconnect(client: HarborWebSocket, code: number, reason: string): void {\n client.rooms.forEach((roomName) => {\n this.leave(client, roomName);\n });\n this.clients.delete(client.id);\n logger.info(`WebSocket client disconnected: ${client.id} (${code})`);\n this.options.onClose?.(client, code, reason);\n }\n\n private startHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n }\n\n this.heartbeatTimer = setInterval(() => {\n this.clients.forEach((client) => {\n if (!client.isAlive) {\n client.terminate();\n return;\n }\n client.isAlive = false;\n client.ping();\n });\n }, this.options.heartbeatInterval);\n }\n\n join(client: HarborWebSocket, roomName: string): void {\n if (!this.rooms.has(roomName)) {\n this.rooms.set(roomName, { name: roomName, clients: new Set() });\n }\n const room = this.rooms.get(roomName)!;\n room.clients.add(client);\n client.rooms.add(roomName);\n logger.debug(`Client ${client.id} joined room ${roomName}`);\n }\n\n leave(client: HarborWebSocket, roomName: string): void {\n const room = this.rooms.get(roomName);\n if (room) {\n room.clients.delete(client);\n client.rooms.delete(roomName);\n if (room.clients.size === 0) {\n this.rooms.delete(roomName);\n }\n logger.debug(`Client ${client.id} left room ${roomName}`);\n }\n }\n\n broadcast(data: unknown, exclude?: HarborWebSocket): void {\n const message = typeof data === 'string' ? data : JSON.stringify(data);\n this.clients.forEach((client) => {\n if (client !== exclude && client.readyState === 1) {\n client.send(message);\n }\n });\n }\n\n broadcastToRoom(roomName: string, data: unknown, exclude?: HarborWebSocket): void {\n const room = this.rooms.get(roomName);\n if (!room) return;\n\n const message = typeof data === 'string' ? data : JSON.stringify(data);\n room.clients.forEach((client) => {\n if (client !== exclude && client.readyState === 1) {\n client.send(message);\n }\n });\n }\n\n send(clientId: string, data: unknown): boolean {\n const client = this.clients.get(clientId);\n if (client && client.readyState === 1) {\n const message = typeof data === 'string' ? data : JSON.stringify(data);\n client.send(message);\n return true;\n }\n return false;\n }\n\n getClient(id: string): HarborWebSocket | undefined {\n return this.clients.get(id);\n }\n\n getClients(): HarborWebSocket[] {\n return Array.from(this.clients.values());\n }\n\n getRoom(name: string): Room | undefined {\n return this.rooms.get(name);\n }\n\n getRooms(): string[] {\n return Array.from(this.rooms.keys());\n }\n\n getClientCount(): number {\n return this.clients.size;\n }\n\n close(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n }\n (this.wss as any)?.close?.();\n this.clients.clear();\n this.rooms.clear();\n logger.info('WebSocket server closed');\n }\n}\n\nexport function createWebSocketServer(options?: WebSocketOptions): WebSocketManager {\n return new WebSocketManager(options);\n}\n\n"],"names":["logger","createLogger","WebSocketManager","options","server","ws","WebSocketServer","wsClient","request","client","data","code","reason","error","parsed","roomName","room","exclude","message","clientId","id","name","createWebSocketServer"],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { Server as HttpServer } from 'http';
2
+ import { WebSocketOptions, HarborWebSocket, Room } from './types';
3
+
4
+ export declare class WebSocketManager {
5
+ private wss;
6
+ private clients;
7
+ private rooms;
8
+ private heartbeatTimer;
9
+ private options;
10
+ constructor(options?: WebSocketOptions);
11
+ attach(server: HttpServer): Promise<unknown>;
12
+ private handleMessage;
13
+ private enhanceClient;
14
+ private generateId;
15
+ private handleDisconnect;
16
+ private startHeartbeat;
17
+ join(client: HarborWebSocket, roomName: string): void;
18
+ leave(client: HarborWebSocket, roomName: string): void;
19
+ broadcast(data: unknown, exclude?: HarborWebSocket): void;
20
+ broadcastToRoom(roomName: string, data: unknown, exclude?: HarborWebSocket): void;
21
+ send(clientId: string, data: unknown): boolean;
22
+ getClient(id: string): HarborWebSocket | undefined;
23
+ getClients(): HarborWebSocket[];
24
+ getRoom(name: string): Room | undefined;
25
+ getRooms(): string[];
26
+ getClientCount(): number;
27
+ close(): void;
28
+ }
29
+ export declare function createWebSocketServer(options?: WebSocketOptions): WebSocketManager;
30
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/websocket/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AAE5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAIvE,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,OAAO,CAA2C;IAC1D,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,OAAO,CAAmB;gBAEtB,OAAO,GAAE,gBAAqB;IAWpC,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAgDlD,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,cAAc;IAiBtB,IAAI,CAAC,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAUrD,KAAK,CAAC,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYtD,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI;IASzD,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI;IAYjF,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO;IAU9C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIlD,UAAU,IAAI,eAAe,EAAE;IAI/B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIvC,QAAQ,IAAI,MAAM,EAAE;IAIpB,cAAc,IAAI,MAAM;IAIxB,KAAK,IAAI,IAAI;CASd;AAED,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,CAElF"}
@@ -0,0 +1,27 @@
1
+ export interface WebSocketOptions {
2
+ path?: string;
3
+ maxPayload?: number;
4
+ perMessageDeflate?: boolean;
5
+ clientTracking?: boolean;
6
+ heartbeatInterval?: number;
7
+ onConnection?: (client: HarborWebSocket, request: unknown) => void;
8
+ onMessage?: (client: HarborWebSocket, data: unknown) => void;
9
+ onClose?: (client: HarborWebSocket, code: number, reason: string) => void;
10
+ onError?: (client: HarborWebSocket, error: Error) => void;
11
+ }
12
+ export interface HarborWebSocket {
13
+ id: string;
14
+ isAlive: boolean;
15
+ data: Record<string, unknown>;
16
+ rooms: Set<string>;
17
+ readyState: number;
18
+ send: (data: string) => void;
19
+ ping: () => void;
20
+ terminate: () => void;
21
+ on: (event: string, handler: (...args: unknown[]) => void) => void;
22
+ }
23
+ export interface Room {
24
+ name: string;
25
+ clients: Set<HarborWebSocket>;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/websocket/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACnE,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7D,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,IAAI,CAAC;CACpE;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,GAAG,CAAC,eAAe,CAAC,CAAC;CAC/B"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@forgedevstack/harbor",
3
- "version": "1.0.0",
4
- "description": "The pipeline for Node.js backends - Fast server creation, MongoDB ODM (Mongoose replacement), route management, validation, and Docker orchestration",
3
+ "version": "1.5.0",
4
+ "description": "ForgeStack Harbor - Complete Node.js backend framework with MongoDB ODM, WebSocket, scheduling, caching, auth, and more",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
7
7
  "types": "dist/index.d.ts",
@@ -21,10 +21,30 @@
21
21
  "require": "./dist/validation/index.js",
22
22
  "types": "./dist/validation/index.d.ts"
23
23
  },
24
- "./validations": {
25
- "import": "./dist/validation/index.js",
26
- "require": "./dist/validation/index.js",
27
- "types": "./dist/validation/index.d.ts"
24
+ "./middleware": {
25
+ "import": "./dist/middleware/index.js",
26
+ "require": "./dist/middleware/index.js",
27
+ "types": "./dist/middleware/index.d.ts"
28
+ },
29
+ "./websocket": {
30
+ "import": "./dist/websocket/index.js",
31
+ "require": "./dist/websocket/index.js",
32
+ "types": "./dist/websocket/index.d.ts"
33
+ },
34
+ "./scheduler": {
35
+ "import": "./dist/scheduler/index.js",
36
+ "require": "./dist/scheduler/index.js",
37
+ "types": "./dist/scheduler/index.d.ts"
38
+ },
39
+ "./cache": {
40
+ "import": "./dist/cache/index.js",
41
+ "require": "./dist/cache/index.js",
42
+ "types": "./dist/cache/index.d.ts"
43
+ },
44
+ "./auth": {
45
+ "import": "./dist/auth/index.js",
46
+ "require": "./dist/auth/index.js",
47
+ "types": "./dist/auth/index.d.ts"
28
48
  },
29
49
  "./docker": {
30
50
  "import": "./dist/docker/index.js",
@@ -53,29 +73,42 @@
53
73
  "build:watch": "vite build --watch",
54
74
  "lint": "eslint src --ext .ts",
55
75
  "test": "vitest",
56
- "portal:dev": "cd portal && npm run dev",
57
- "portal:build": "cd portal && npm run build",
58
- "prepublishOnly": "npm run build"
76
+ "prepublishOnly": "npm run build",
77
+ "release": "npm run build && npm publish --access public",
78
+ "release:patch": "npm version patch && npm run release",
79
+ "release:minor": "npm version minor && npm run release",
80
+ "release:major": "npm version major && npm run release"
59
81
  },
60
82
  "keywords": [
83
+ "forgestack",
84
+ "harbor",
61
85
  "nodejs",
62
86
  "server",
63
87
  "express",
64
88
  "mongodb",
65
- "validation",
66
- "routing",
67
- "docker",
89
+ "mongoose-alternative",
90
+ "websocket",
91
+ "scheduler",
92
+ "cron",
93
+ "rate-limit",
94
+ "cache",
95
+ "jwt",
96
+ "authentication",
97
+ "metrics",
98
+ "prometheus",
99
+ "health-check",
100
+ "file-upload",
68
101
  "backend",
69
102
  "api",
70
103
  "framework"
71
104
  ],
72
- "author": "ForgeDevStack",
105
+ "author": "John Yaghobieh",
73
106
  "license": "MIT",
74
- "homepage": "https://forgedevstack.com",
75
107
  "repository": {
76
108
  "type": "git",
77
- "url": "https://github.com/yaghobieh/Harbor"
109
+ "url": "https://github.com/yaghobieh/Harbork"
78
110
  },
111
+ "homepage": "https://forgestack.com",
79
112
  "bugs": {
80
113
  "url": "https://github.com/yaghobieh/Harbor/issues"
81
114
  },
@@ -87,21 +120,28 @@
87
120
  },
88
121
  "peerDependencies": {
89
122
  "express": ">=4.18.0",
90
- "mongodb": ">=6.0.0"
123
+ "mongodb": ">=6.0.0",
124
+ "ws": ">=8.0.0",
125
+ "ioredis": ">=5.0.0"
91
126
  },
92
127
  "peerDependenciesMeta": {
93
128
  "mongodb": {
94
129
  "optional": true
130
+ },
131
+ "ws": {
132
+ "optional": true
133
+ },
134
+ "ioredis": {
135
+ "optional": true
95
136
  }
96
137
  },
97
138
  "devDependencies": {
98
139
  "@types/express": "^4.17.21",
99
140
  "@types/node": "^20.10.0",
100
- "mongodb": "^6.0.0",
141
+ "@types/ws": "^8.5.10",
101
142
  "typescript": "^5.3.0",
102
143
  "vite": "^5.0.0",
103
144
  "vite-plugin-dts": "^3.6.0",
104
145
  "vitest": "^1.0.0"
105
146
  }
106
147
  }
107
-