@parsrun/server 0.1.28 → 0.1.29

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/context.ts","../../src/middleware/error-handler.ts","../../src/middleware/auth.ts","../../src/middleware/cors.ts","../../src/middleware/csrf.ts","../../src/middleware/rate-limit.ts","../../src/middleware/request-logger.ts","../../src/middleware/tracing.ts","../../src/middleware/usage-tracking.ts","../../src/middleware/quota-enforcement.ts"],"sourcesContent":["/**\n * @parsrun/server - Server Context\n * Type definitions for server context and configuration\n */\n\nimport type { Logger } from \"@parsrun/core\";\n\n/**\n * Database adapter interface\n * Implement this for your database (Drizzle, Prisma, etc.)\n */\nexport interface DatabaseAdapter {\n /** Execute raw SQL query */\n execute(sql: string): Promise<unknown>;\n /** Check connection */\n ping?(): Promise<boolean>;\n}\n\n/**\n * Module manifest for registering modules\n */\nexport interface ModuleManifest {\n /** Unique module name */\n name: string;\n /** Module version */\n version: string;\n /** Module description */\n description: string;\n /** Required permissions for this module */\n permissions: Record<string, string[]>;\n /** Module dependencies (other module names) */\n dependencies?: string[];\n /** Register routes for this module */\n registerRoutes: (app: HonoApp) => void;\n /** Called when module is enabled */\n onEnable?: () => Promise<void>;\n /** Called when module is disabled */\n onDisable?: () => Promise<void>;\n}\n\n/**\n * Server configuration\n */\nexport interface ServerConfig {\n /** Database adapter */\n database: DatabaseAdapter;\n /** CORS configuration */\n cors?: CorsConfig;\n /** Base path for API */\n basePath?: string;\n /** Cookie prefix for all cookies */\n cookiePrefix?: string;\n /** Logger instance */\n logger?: Logger;\n /** Custom context data */\n custom?: Record<string, unknown>;\n}\n\n/**\n * CORS configuration\n */\nexport interface CorsConfig {\n /** Allowed origins */\n origin: string | string[] | ((origin: string) => boolean);\n /** Allow credentials */\n credentials?: boolean;\n /** Allowed methods */\n methods?: string[];\n /** Allowed headers */\n allowedHeaders?: string[];\n /** Exposed headers */\n exposedHeaders?: string[];\n /** Max age in seconds */\n maxAge?: number;\n}\n\n/**\n * User information in context\n */\nexport interface ContextUser {\n id: string;\n email: string | undefined;\n tenantId: string | undefined;\n role: string | undefined;\n permissions: string[];\n}\n\n/**\n * Tenant information in context\n */\nexport interface ContextTenant {\n id: string;\n slug: string | undefined;\n name: string | undefined;\n status: string;\n}\n\n/**\n * Server context variables\n * Available in Hono context via c.get()\n */\nexport interface ServerContextVariables {\n /** Database adapter */\n db: DatabaseAdapter;\n /** Server configuration */\n config: ServerConfig;\n /** Enabled modules set */\n enabledModules: Set<string>;\n /** Current user (if authenticated) */\n user: ContextUser | undefined;\n /** Current tenant (if resolved) */\n tenant: ContextTenant | undefined;\n /** Request logger */\n logger: Logger;\n /** Request ID */\n requestId: string;\n /** Cookie prefix */\n cookiePrefix: string | undefined;\n /** Custom context data */\n custom: Record<string, unknown>;\n}\n\n/**\n * Hono app type with server context\n */\nexport type HonoApp = import(\"hono\").Hono<{ Variables: ServerContextVariables }>;\n\n/**\n * Hono context type with server context\n */\nexport type HonoContext = import(\"hono\").Context<{ Variables: ServerContextVariables }>;\n\n/**\n * Middleware next function\n */\nexport type HonoNext = () => Promise<void>;\n\n/**\n * Middleware function type\n */\nexport type Middleware = (c: HonoContext, next: HonoNext) => Promise<Response | void>;\n\n/**\n * Route handler function type\n */\nexport type RouteHandler = (c: HonoContext) => Promise<Response> | Response;\n\n/**\n * Permission check input\n */\nexport interface PermissionCheck {\n /** Resource name (e.g., \"users\", \"items\") */\n resource: string;\n /** Action name (e.g., \"read\", \"create\", \"update\", \"delete\") */\n action: string;\n /** Permission scope */\n scope?: \"tenant\" | \"global\" | \"own\";\n}\n\n/**\n * Permission definition\n */\nexport interface PermissionDefinition {\n /** Permission name (e.g., \"users:read\") */\n name: string;\n /** Resource part */\n resource: string;\n /** Action part */\n action: string;\n /** Description */\n description?: string;\n /** Scope */\n scope?: \"tenant\" | \"global\" | \"own\";\n}\n\n/**\n * Role definition\n */\nexport interface RoleDefinition {\n /** Role name */\n name: string;\n /** Display name */\n displayName?: string;\n /** Description */\n description?: string;\n /** Permissions assigned to this role */\n permissions: string[];\n /** Is this a system role */\n isSystem?: boolean;\n}\n\n/**\n * Standard API response structure\n */\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: {\n code: string;\n message: string;\n details?: Record<string, unknown> | undefined;\n };\n meta?: {\n page?: number | undefined;\n limit?: number | undefined;\n total?: number | undefined;\n requestId?: string | undefined;\n } | undefined;\n}\n\n/**\n * Create a success response\n */\nexport function success<T>(data: T, meta?: ApiResponse[\"meta\"]): ApiResponse<T> {\n return {\n success: true,\n data,\n meta: meta ?? undefined,\n };\n}\n\n/**\n * Create an error response\n */\nexport function error(\n code: string,\n message: string,\n details?: Record<string, unknown>\n): ApiResponse<never> {\n return {\n success: false,\n error: { code, message, details: details ?? undefined },\n };\n}\n\n/**\n * Generate a request ID\n */\nexport function generateRequestId(): string {\n return crypto.randomUUID();\n}\n","/**\n * @parsrun/server - Error Handler Middleware\n * Global error handling and response formatting\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\nimport { error as errorResponse } from \"../context.js\";\nimport type { ErrorTransport, ErrorContext } from \"@parsrun/core/transports\";\n\n/**\n * Base API error class\n */\nexport class ApiError extends Error {\n constructor(\n public readonly statusCode: number,\n public readonly code: string,\n message: string,\n public readonly details?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n\n toResponse() {\n return errorResponse(this.code, this.message, this.details);\n }\n}\n\n/**\n * 400 Bad Request\n */\nexport class BadRequestError extends ApiError {\n constructor(message = \"Bad request\", details?: Record<string, unknown>) {\n super(400, \"BAD_REQUEST\", message, details);\n this.name = \"BadRequestError\";\n }\n}\n\n/**\n * 401 Unauthorized\n */\nexport class UnauthorizedError extends ApiError {\n constructor(message = \"Unauthorized\", details?: Record<string, unknown>) {\n super(401, \"UNAUTHORIZED\", message, details);\n this.name = \"UnauthorizedError\";\n }\n}\n\n/**\n * 403 Forbidden\n */\nexport class ForbiddenError extends ApiError {\n constructor(message = \"Forbidden\", details?: Record<string, unknown>) {\n super(403, \"FORBIDDEN\", message, details);\n this.name = \"ForbiddenError\";\n }\n}\n\n/**\n * 404 Not Found\n */\nexport class NotFoundError extends ApiError {\n constructor(message = \"Not found\", details?: Record<string, unknown>) {\n super(404, \"NOT_FOUND\", message, details);\n this.name = \"NotFoundError\";\n }\n}\n\n/**\n * 409 Conflict\n */\nexport class ConflictError extends ApiError {\n constructor(message = \"Conflict\", details?: Record<string, unknown>) {\n super(409, \"CONFLICT\", message, details);\n this.name = \"ConflictError\";\n }\n}\n\n/**\n * 422 Unprocessable Entity (Validation Error)\n */\nexport class ValidationError extends ApiError {\n constructor(message = \"Validation failed\", details?: Record<string, unknown>) {\n super(422, \"VALIDATION_ERROR\", message, details);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * 429 Too Many Requests\n */\nexport class RateLimitError extends ApiError {\n constructor(\n message = \"Too many requests\",\n public readonly retryAfter?: number\n ) {\n super(429, \"RATE_LIMIT_EXCEEDED\", message, { retryAfter });\n this.name = \"RateLimitError\";\n }\n}\n\n/**\n * 500 Internal Server Error\n */\nexport class InternalError extends ApiError {\n constructor(message = \"Internal server error\", details?: Record<string, unknown>) {\n super(500, \"INTERNAL_ERROR\", message, details);\n this.name = \"InternalError\";\n }\n}\n\n/**\n * 503 Service Unavailable\n */\nexport class ServiceUnavailableError extends ApiError {\n constructor(message = \"Service unavailable\", details?: Record<string, unknown>) {\n super(503, \"SERVICE_UNAVAILABLE\", message, details);\n this.name = \"ServiceUnavailableError\";\n }\n}\n\n/**\n * Error handler options\n */\nexport interface ErrorHandlerOptions {\n /** Include stack trace in development */\n includeStack?: boolean;\n /** Custom error logger */\n onError?: (error: Error, c: HonoContext) => void;\n /**\n * Error transport for external error tracking (e.g., Sentry)\n * Automatically captures exceptions with request context\n */\n errorTransport?: ErrorTransport;\n /**\n * Capture all errors including 4xx client errors\n * By default, only 5xx server errors are captured\n * @default false\n */\n captureAllErrors?: boolean;\n /**\n * Custom function to determine if an error should be captured\n * Overrides the default captureAllErrors behavior\n */\n shouldCapture?: (error: Error, statusCode: number) => boolean;\n}\n\n/**\n * Global error handler middleware\n *\n * @example Basic usage\n * ```typescript\n * app.use('*', errorHandler({\n * includeStack: process.env.NODE_ENV === 'development',\n * onError: (error, c) => {\n * console.error(`[${c.get('requestId')}]`, error);\n * },\n * }));\n * ```\n *\n * @example With Sentry error tracking\n * ```typescript\n * import { SentryTransport } from '@parsrun/core/transports';\n *\n * const sentry = new SentryTransport({\n * dsn: process.env.SENTRY_DSN!,\n * environment: process.env.NODE_ENV,\n * });\n *\n * app.use('*', errorHandler({\n * errorTransport: sentry,\n * captureAllErrors: false, // Only capture 5xx errors\n * }));\n * ```\n */\nexport function errorHandler(options: ErrorHandlerOptions = {}) {\n const {\n includeStack = false,\n onError,\n errorTransport,\n captureAllErrors = false,\n shouldCapture,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n try {\n await next();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n // Determine status code\n const statusCode = error instanceof ApiError ? error.statusCode : 500;\n\n // Log error\n if (onError) {\n onError(error, c);\n } else {\n const logger = c.get(\"logger\");\n if (logger) {\n logger.error(\"Request error\", {\n requestId: c.get(\"requestId\"),\n error: error.message,\n stack: error.stack,\n });\n }\n }\n\n // Capture to error transport if configured\n if (errorTransport) {\n const shouldCaptureError = shouldCapture\n ? shouldCapture(error, statusCode)\n : captureAllErrors || statusCode >= 500;\n\n if (shouldCaptureError) {\n const user = c.get(\"user\");\n const tenant = c.get(\"tenant\");\n\n // Build error context with only defined values\n const errorContext: ErrorContext = {\n requestId: c.get(\"requestId\"),\n tags: {\n path: c.req.path,\n method: c.req.method,\n statusCode: String(statusCode),\n },\n };\n\n if (user?.id) {\n errorContext.userId = user.id;\n }\n if (tenant?.id) {\n errorContext.tenantId = tenant.id;\n }\n\n // Add extra context\n const extra: Record<string, unknown> = {\n query: c.req.query(),\n };\n if (error instanceof ApiError) {\n extra[\"errorCode\"] = error.code;\n }\n errorContext.extra = extra;\n\n // Capture asynchronously to not block response\n Promise.resolve(\n errorTransport.captureException(error, errorContext)\n ).catch(() => {\n // Silent fail - don't let transport errors affect response\n });\n }\n }\n\n // Handle known API errors\n if (error instanceof ApiError) {\n return c.json(error.toResponse(), error.statusCode as 400);\n }\n\n // Handle unknown errors\n const details: Record<string, unknown> = {};\n\n if (includeStack && error.stack) {\n details[\"stack\"] = error.stack;\n }\n\n return c.json(\n errorResponse(\"INTERNAL_ERROR\", \"An unexpected error occurred\", details),\n 500\n );\n }\n };\n}\n\n/**\n * Not found handler\n *\n * @example\n * ```typescript\n * app.notFound(notFoundHandler);\n * ```\n */\nexport function notFoundHandler(c: HonoContext) {\n return c.json(\n errorResponse(\"NOT_FOUND\", `Route ${c.req.method} ${c.req.path} not found`),\n 404\n );\n}\n","/**\n * @parsrun/server - Auth Middleware\n * JWT authentication middleware\n */\n\nimport type { HonoContext, HonoNext, ContextUser } from \"../context.js\";\nimport { UnauthorizedError } from \"./error-handler.js\";\n\n/**\n * JWT payload structure\n */\nexport interface JwtPayload {\n sub: string; // User ID\n email?: string;\n tenantId?: string;\n role?: string;\n permissions?: string[];\n iat?: number;\n exp?: number;\n jti?: string;\n}\n\n/**\n * JWT verification function type\n */\nexport type JwtVerifier = (token: string) => Promise<JwtPayload | null>;\n\n/**\n * Auth middleware options\n */\nexport interface AuthMiddlewareOptions {\n /** JWT verification function */\n verify: JwtVerifier;\n /** Header name for token (default: Authorization) */\n header?: string;\n /** Token prefix (default: Bearer) */\n prefix?: string;\n /** Cookie name for token (alternative to header) */\n cookie?: string;\n /** Skip auth for certain requests */\n skip?: (c: HonoContext) => boolean;\n /** Custom error message */\n message?: string;\n}\n\n/**\n * Extract token from request\n */\nfunction extractToken(\n c: HonoContext,\n header: string,\n prefix: string,\n cookie?: string\n): string | null {\n // Try header first\n const authHeader = c.req.header(header);\n if (authHeader) {\n if (prefix && authHeader.startsWith(`${prefix} `)) {\n return authHeader.slice(prefix.length + 1);\n }\n return authHeader;\n }\n\n // Try cookie\n if (cookie) {\n const cookieHeader = c.req.header(\"cookie\");\n if (cookieHeader) {\n const cookies = cookieHeader.split(\";\").map((c) => c.trim());\n for (const c of cookies) {\n const [key, ...valueParts] = c.split(\"=\");\n if (key === cookie) {\n return valueParts.join(\"=\");\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Auth middleware - requires valid JWT\n *\n * @example\n * ```typescript\n * import { verifyJwt } from '@parsrun/auth';\n *\n * const authMiddleware = auth({\n * verify: (token) => verifyJwt(token, secret),\n * cookie: 'auth_token',\n * });\n *\n * app.use('/api/*', authMiddleware);\n *\n * // Access user in handlers\n * app.get('/api/me', (c) => {\n * const user = c.get('user');\n * return c.json({ user });\n * });\n * ```\n */\nexport function auth(options: AuthMiddlewareOptions) {\n const {\n verify,\n header = \"authorization\",\n prefix = \"Bearer\",\n cookie,\n skip,\n message = \"Authentication required\",\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n // Extract token\n const token = extractToken(c, header, prefix, cookie);\n\n if (!token) {\n throw new UnauthorizedError(message);\n }\n\n // Verify token\n const payload = await verify(token);\n\n if (!payload) {\n throw new UnauthorizedError(\"Invalid or expired token\");\n }\n\n // Set user in context\n const user: ContextUser = {\n id: payload.sub,\n email: payload.email,\n tenantId: payload.tenantId,\n role: payload.role,\n permissions: payload.permissions ?? [],\n };\n\n c.set(\"user\", user);\n\n await next();\n };\n}\n\n/**\n * Optional auth middleware - sets user if token present, but doesn't require it\n *\n * @example\n * ```typescript\n * app.use('/api/public/*', optionalAuth({\n * verify: (token) => verifyJwt(token, secret),\n * }));\n *\n * // User may or may not be present\n * app.get('/api/public/items', (c) => {\n * const user = c.get('user'); // may be undefined\n * // Return different data based on auth status\n * });\n * ```\n */\nexport function optionalAuth(options: Omit<AuthMiddlewareOptions, \"message\">) {\n const { verify, header = \"authorization\", prefix = \"Bearer\", cookie, skip } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n // Extract token\n const token = extractToken(c, header, prefix, cookie);\n\n if (token) {\n try {\n const payload = await verify(token);\n\n if (payload) {\n // Set user in context\n const user: ContextUser = {\n id: payload.sub,\n email: payload.email,\n tenantId: payload.tenantId,\n role: payload.role,\n permissions: payload.permissions ?? [],\n };\n\n c.set(\"user\", user);\n }\n } catch {\n // Ignore verification errors for optional auth\n }\n }\n\n await next();\n };\n}\n\n/**\n * Create auth middleware from verifier function\n *\n * @example\n * ```typescript\n * const { auth, optionalAuth } = createAuthMiddleware({\n * verify: async (token) => {\n * return verifyJwt(token, process.env.JWT_SECRET);\n * },\n * cookie: 'session',\n * });\n *\n * app.use('/api/*', auth);\n * app.use('/public/*', optionalAuth);\n * ```\n */\nexport function createAuthMiddleware(\n baseOptions: Omit<AuthMiddlewareOptions, \"skip\" | \"message\">\n) {\n return {\n auth: (options?: Partial<AuthMiddlewareOptions>) =>\n auth({ ...baseOptions, ...options }),\n optionalAuth: (options?: Partial<Omit<AuthMiddlewareOptions, \"message\">>) =>\n optionalAuth({ ...baseOptions, ...options }),\n };\n}\n","/**\n * @parsrun/server - CORS Middleware\n * Cross-Origin Resource Sharing configuration\n */\n\nimport type { HonoContext, HonoNext, CorsConfig } from \"../context.js\";\n\n/**\n * Default CORS configuration\n */\nconst defaultCorsConfig: CorsConfig = {\n origin: \"*\",\n credentials: false,\n methods: [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\"],\n allowedHeaders: [\"Content-Type\", \"Authorization\", \"X-Request-ID\", \"X-CSRF-Token\"],\n exposedHeaders: [\"X-Request-ID\", \"X-Total-Count\"],\n maxAge: 86400, // 24 hours\n};\n\n/**\n * Check if origin is allowed\n */\nfunction isOriginAllowed(origin: string, config: CorsConfig): boolean {\n if (config.origin === \"*\") return true;\n\n if (typeof config.origin === \"string\") {\n return origin === config.origin;\n }\n\n if (Array.isArray(config.origin)) {\n return config.origin.includes(origin);\n }\n\n if (typeof config.origin === \"function\") {\n return config.origin(origin);\n }\n\n return false;\n}\n\n/**\n * CORS middleware\n *\n * @example\n * ```typescript\n * app.use('*', cors({\n * origin: ['https://example.com', 'https://app.example.com'],\n * credentials: true,\n * }));\n * ```\n */\nexport function cors(config?: Partial<CorsConfig>): (c: HonoContext, next: HonoNext) => Promise<Response | void> {\n const corsConfig = { ...defaultCorsConfig, ...config };\n\n return async (c: HonoContext, next: HonoNext): Promise<Response | void> => {\n const origin = c.req.header(\"origin\") ?? \"\";\n\n // Handle preflight requests\n if (c.req.method === \"OPTIONS\") {\n const response = new Response(null, { status: 204 });\n\n if (isOriginAllowed(origin, corsConfig)) {\n response.headers.set(\"Access-Control-Allow-Origin\", origin || \"*\");\n }\n\n if (corsConfig.credentials) {\n response.headers.set(\"Access-Control-Allow-Credentials\", \"true\");\n }\n\n if (corsConfig.methods) {\n response.headers.set(\n \"Access-Control-Allow-Methods\",\n corsConfig.methods.join(\", \")\n );\n }\n\n if (corsConfig.allowedHeaders) {\n response.headers.set(\n \"Access-Control-Allow-Headers\",\n corsConfig.allowedHeaders.join(\", \")\n );\n }\n\n if (corsConfig.maxAge) {\n response.headers.set(\"Access-Control-Max-Age\", String(corsConfig.maxAge));\n }\n\n return response;\n }\n\n // Handle actual requests\n await next();\n\n // Add CORS headers to response\n if (isOriginAllowed(origin, corsConfig)) {\n c.header(\"Access-Control-Allow-Origin\", origin || \"*\");\n }\n\n if (corsConfig.credentials) {\n c.header(\"Access-Control-Allow-Credentials\", \"true\");\n }\n\n if (corsConfig.exposedHeaders) {\n c.header(\"Access-Control-Expose-Headers\", corsConfig.exposedHeaders.join(\", \"));\n }\n };\n}\n","/**\n * @parsrun/server - CSRF Middleware\n * Cross-Site Request Forgery protection\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\nimport { ForbiddenError } from \"./error-handler.js\";\n\n/**\n * CSRF options\n */\nexport interface CsrfOptions {\n /** Cookie name for CSRF token */\n cookieName?: string;\n /** Header name for CSRF token */\n headerName?: string;\n /** Methods that require CSRF validation */\n methods?: string[];\n /** Paths to exclude from CSRF protection */\n excludePaths?: string[];\n /** Skip CSRF for certain requests */\n skip?: (c: HonoContext) => boolean;\n /** Token generator */\n generateToken?: () => string;\n /** Cookie options */\n cookie?: {\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n path?: string;\n maxAge?: number;\n };\n}\n\n/**\n * Generate random token\n */\nfunction generateRandomToken(): string {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Get cookie value\n */\nfunction getCookie(c: HonoContext, name: string): string | undefined {\n const cookieHeader = c.req.header(\"cookie\");\n if (!cookieHeader) return undefined;\n\n const cookies = cookieHeader.split(\";\").map((c) => c.trim());\n for (const cookie of cookies) {\n const [key, ...valueParts] = cookie.split(\"=\");\n if (key === name) {\n return valueParts.join(\"=\");\n }\n }\n return undefined;\n}\n\n/**\n * CSRF protection middleware\n *\n * @example\n * ```typescript\n * app.use('*', csrf({\n * cookieName: '_csrf',\n * headerName: 'X-CSRF-Token',\n * methods: ['POST', 'PUT', 'PATCH', 'DELETE'],\n * cookie: {\n * secure: true,\n * sameSite: 'strict',\n * },\n * }));\n *\n * // Get token in handler\n * app.get('/csrf-token', (c) => {\n * return c.json({ token: c.get('csrfToken') });\n * });\n * ```\n */\nexport function csrf(options: CsrfOptions = {}) {\n const {\n cookieName = \"_csrf\",\n headerName = \"x-csrf-token\",\n methods = [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n excludePaths = [],\n skip,\n generateToken = generateRandomToken,\n cookie = {},\n } = options;\n\n const cookieOptions = {\n secure: cookie.secure ?? true,\n httpOnly: cookie.httpOnly ?? true,\n sameSite: cookie.sameSite ?? (\"lax\" as const),\n path: cookie.path ?? \"/\",\n maxAge: cookie.maxAge ?? 86400, // 24 hours\n };\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n // Skip excluded paths\n const path = c.req.path;\n if (excludePaths.some((p) => path.startsWith(p))) {\n return next();\n }\n\n // Get or create token\n let token = getCookie(c, cookieName);\n\n if (!token) {\n // Generate new token\n token = generateToken();\n\n // Set cookie\n const cookieValue = [\n `${cookieName}=${token}`,\n `Path=${cookieOptions.path}`,\n `Max-Age=${cookieOptions.maxAge}`,\n cookieOptions.sameSite && `SameSite=${cookieOptions.sameSite}`,\n cookieOptions.secure && \"Secure\",\n cookieOptions.httpOnly && \"HttpOnly\",\n ]\n .filter(Boolean)\n .join(\"; \");\n\n c.header(\"Set-Cookie\", cookieValue);\n }\n\n // Store token in context for handlers\n (c as HonoContext & { csrfToken: string }).set(\"csrfToken\" as never, token as never);\n\n // Validate token for protected methods\n if (methods.includes(c.req.method)) {\n const headerToken = c.req.header(headerName);\n const bodyToken = await getBodyToken(c);\n\n const providedToken = headerToken ?? bodyToken;\n\n if (!providedToken || providedToken !== token) {\n throw new ForbiddenError(\"Invalid CSRF token\");\n }\n }\n\n await next();\n };\n}\n\n/**\n * Try to get CSRF token from request body\n */\nasync function getBodyToken(c: HonoContext): Promise<string | undefined> {\n try {\n const contentType = c.req.header(\"content-type\") ?? \"\";\n\n if (contentType.includes(\"application/json\")) {\n const body = (await c.req.json()) as Record<string, unknown>;\n return (body[\"_csrf\"] ?? body[\"csrfToken\"] ?? body[\"csrf_token\"]) as string | undefined;\n }\n\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const body = await c.req.parseBody();\n return body[\"_csrf\"] as string | undefined;\n }\n } catch {\n // Ignore parsing errors\n }\n return undefined;\n}\n\n/**\n * Double Submit Cookie pattern\n * Generates a token and validates it matches between cookie and header\n */\nexport function doubleSubmitCookie(options: CsrfOptions = {}) {\n return csrf({\n ...options,\n cookie: {\n ...options.cookie,\n httpOnly: false, // Allow JS to read the cookie\n },\n });\n}\n","/**\n * @parsrun/server - Rate Limit Middleware\n * Request throttling with multiple storage backends\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\nimport { RateLimitError } from \"./error-handler.js\";\n\n/**\n * Rate limit storage interface\n */\nexport interface RateLimitStorage {\n /** Get current count for key */\n get(key: string): Promise<number>;\n /** Increment count and set expiry */\n increment(key: string, windowMs: number): Promise<number>;\n /** Reset count for key */\n reset(key: string): Promise<void>;\n}\n\n/**\n * In-memory rate limit storage\n * For single-instance deployments or development\n */\nexport class MemoryRateLimitStorage implements RateLimitStorage {\n private store = new Map<string, { count: number; expires: number }>();\n\n async get(key: string): Promise<number> {\n const entry = this.store.get(key);\n if (!entry || entry.expires < Date.now()) {\n return 0;\n }\n return entry.count;\n }\n\n async increment(key: string, windowMs: number): Promise<number> {\n const now = Date.now();\n const entry = this.store.get(key);\n\n if (!entry || entry.expires < now) {\n // Start new window\n this.store.set(key, { count: 1, expires: now + windowMs });\n return 1;\n }\n\n // Increment existing\n entry.count++;\n return entry.count;\n }\n\n async reset(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n /** Clean up expired entries */\n cleanup(): void {\n const now = Date.now();\n for (const [key, entry] of this.store) {\n if (entry.expires < now) {\n this.store.delete(key);\n }\n }\n }\n}\n\n/**\n * Rate limit options\n */\nexport interface RateLimitOptions {\n /** Time window in milliseconds */\n windowMs?: number;\n /** Maximum requests per window */\n max?: number;\n /** Generate key from request (default: IP address) */\n keyGenerator?: (c: HonoContext) => string;\n /** Skip rate limiting for certain requests */\n skip?: (c: HonoContext) => boolean;\n /** Custom storage backend */\n storage?: RateLimitStorage;\n /** Error message */\n message?: string;\n /** Include rate limit headers */\n headers?: boolean;\n /** Handler when limit is exceeded */\n onLimitReached?: (c: HonoContext, key: string) => void;\n}\n\n// Global default storage\nlet defaultStorage: RateLimitStorage | null = null;\n\n/**\n * Get or create default memory storage\n */\nfunction getDefaultStorage(): RateLimitStorage {\n if (!defaultStorage) {\n defaultStorage = new MemoryRateLimitStorage();\n }\n return defaultStorage;\n}\n\n/**\n * Rate limit middleware\n *\n * @example\n * ```typescript\n * // Basic usage - 100 requests per minute\n * app.use('/api/*', rateLimit({\n * windowMs: 60 * 1000,\n * max: 100,\n * }));\n *\n * // Per-user rate limiting\n * app.use('/api/*', rateLimit({\n * keyGenerator: (c) => c.get('user')?.id ?? getIP(c),\n * max: 1000,\n * }));\n *\n * // Strict limit for auth endpoints\n * app.use('/api/auth/*', rateLimit({\n * windowMs: 15 * 60 * 1000, // 15 minutes\n * max: 5,\n * message: 'Too many login attempts',\n * }));\n * ```\n */\nexport function rateLimit(options: RateLimitOptions = {}) {\n const {\n windowMs = 60 * 1000, // 1 minute\n max = 100,\n keyGenerator = defaultKeyGenerator,\n skip,\n storage = getDefaultStorage(),\n message = \"Too many requests, please try again later\",\n headers = true,\n onLimitReached,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n const key = `ratelimit:${keyGenerator(c)}`;\n const current = await storage.increment(key, windowMs);\n\n // Set rate limit headers\n if (headers) {\n c.header(\"X-RateLimit-Limit\", String(max));\n c.header(\"X-RateLimit-Remaining\", String(Math.max(0, max - current)));\n c.header(\"X-RateLimit-Reset\", String(Math.ceil((Date.now() + windowMs) / 1000)));\n }\n\n // Check if limit exceeded\n if (current > max) {\n if (onLimitReached) {\n onLimitReached(c, key);\n }\n\n const retryAfter = Math.ceil(windowMs / 1000);\n c.header(\"Retry-After\", String(retryAfter));\n\n throw new RateLimitError(message, retryAfter);\n }\n\n await next();\n };\n}\n\n/**\n * Default key generator - uses IP address\n */\nfunction defaultKeyGenerator(c: HonoContext): string {\n return (\n c.req.header(\"x-forwarded-for\")?.split(\",\")[0]?.trim() ??\n c.req.header(\"x-real-ip\") ??\n c.req.header(\"cf-connecting-ip\") ??\n \"unknown\"\n );\n}\n\n/**\n * Create rate limiter for specific routes\n *\n * @example\n * ```typescript\n * const apiLimiter = createRateLimiter({\n * windowMs: 60000,\n * max: 100,\n * });\n *\n * app.use('/api/*', apiLimiter.middleware);\n *\n * // Reset limit for a user after successful auth\n * await apiLimiter.reset('user:123');\n * ```\n */\nexport function createRateLimiter(options: RateLimitOptions = {}) {\n const storage = options.storage ?? getDefaultStorage();\n\n return {\n middleware: rateLimit({ ...options, storage }),\n storage,\n reset: (key: string) => storage.reset(`ratelimit:${key}`),\n get: (key: string) => storage.get(`ratelimit:${key}`),\n };\n}\n","/**\n * @parsrun/server - Request Logger Middleware\n * HTTP request/response logging\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\n\n/**\n * Request logger options\n */\nexport interface RequestLoggerOptions {\n /** Skip logging for certain paths */\n skip?: (c: HonoContext) => boolean;\n /** Custom log format */\n format?: \"json\" | \"combined\" | \"short\";\n /** Include request body in logs */\n includeBody?: boolean;\n /** Include response body in logs (be careful with large responses) */\n includeResponseBody?: boolean;\n /** Maximum body length to log */\n maxBodyLength?: number;\n}\n\n/**\n * Format bytes to human readable\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\n/**\n * Request logger middleware\n *\n * @example\n * ```typescript\n * app.use('*', requestLogger({\n * skip: (c) => c.req.path === '/health',\n * format: 'json',\n * }));\n * ```\n */\nexport function requestLogger(options: RequestLoggerOptions = {}) {\n const {\n skip,\n format = \"json\",\n includeBody = false,\n maxBodyLength = 1000,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n const start = Date.now();\n const logger = c.get(\"logger\");\n const requestId = c.get(\"requestId\");\n\n // Request info\n const method = c.req.method;\n const path = c.req.path;\n const query = c.req.query();\n const userAgent = c.req.header(\"user-agent\");\n const ip = c.req.header(\"x-forwarded-for\") ?? c.req.header(\"x-real-ip\") ?? \"unknown\";\n\n // Log request start\n if (format === \"json\") {\n logger?.debug(\"Request started\", {\n requestId,\n method,\n path,\n query: Object.keys(query).length > 0 ? query : undefined,\n ip,\n userAgent,\n });\n }\n\n // Get body if needed\n let requestBody: string | undefined;\n if (includeBody && [\"POST\", \"PUT\", \"PATCH\"].includes(method)) {\n try {\n const contentType = c.req.header(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n const body = await c.req.text();\n requestBody = body.length > maxBodyLength\n ? body.substring(0, maxBodyLength) + \"...\"\n : body;\n }\n } catch {\n // Ignore body parsing errors\n }\n }\n\n // Process request\n await next();\n\n // Calculate duration\n const duration = Date.now() - start;\n const status = c.res.status;\n\n // Get response size\n const contentLength = c.res.headers.get(\"content-length\");\n const size = contentLength ? parseInt(contentLength, 10) : 0;\n\n // Log based on format\n if (format === \"json\") {\n const logData: Record<string, unknown> = {\n requestId,\n method,\n path,\n status,\n duration: `${duration}ms`,\n size: formatBytes(size),\n };\n\n if (requestBody) {\n logData[\"requestBody\"] = requestBody;\n }\n\n // Use appropriate log level\n if (status >= 500) {\n logger?.error(\"Request completed\", logData);\n } else if (status >= 400) {\n logger?.warn(\"Request completed\", logData);\n } else {\n logger?.info(\"Request completed\", logData);\n }\n } else if (format === \"combined\") {\n // Apache combined log format\n const log = `${ip} - - [${new Date().toISOString()}] \"${method} ${path}\" ${status} ${size} \"-\" \"${userAgent}\" ${duration}ms`;\n console.log(log);\n } else {\n // Short format\n const log = `${method} ${path} ${status} ${duration}ms`;\n console.log(log);\n }\n };\n}\n","/**\n * @parsrun/server - Tracing Middleware\n * Request correlation and distributed tracing support\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\nimport { generateRequestId } from \"../context.js\";\n\n/**\n * Tracing options\n */\nexport interface TracingOptions {\n /**\n * Header name for request ID\n * @default \"x-request-id\"\n */\n headerName?: string;\n\n /**\n * Custom request ID generator\n * @default crypto.randomUUID()\n */\n generateId?: () => string;\n\n /**\n * Enable W3C Trace Context propagation\n * When enabled, parses and propagates traceparent/tracestate headers\n * @default false\n */\n propagate?: boolean;\n\n /**\n * Emit request ID in response headers\n * @default true\n */\n emitHeader?: boolean;\n\n /**\n * Trust incoming request ID from header\n * Set to false in production to always generate new IDs\n * @default true\n */\n trustIncoming?: boolean;\n}\n\n/**\n * W3C Trace Context - Parsed traceparent header\n * Format: {version}-{trace-id}-{parent-id}-{trace-flags}\n */\nexport interface TraceContext {\n /** Trace version (currently \"00\") */\n version: string;\n /** 32 hex character trace ID */\n traceId: string;\n /** 16 hex character parent span ID */\n parentId: string;\n /** Trace flags (sampled, etc.) */\n traceFlags: number;\n}\n\n/**\n * Parse W3C traceparent header\n * Format: 00-{trace-id}-{parent-id}-{trace-flags}\n *\n * @see https://www.w3.org/TR/trace-context/\n */\nexport function parseTraceparent(header: string): TraceContext | null {\n // Version 00 format: 00-<trace-id>-<parent-id>-<trace-flags>\n const match = header.match(\n /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/i\n );\n\n if (!match) return null;\n\n const [, version, traceId, parentId, flags] = match;\n\n // Validate trace-id and parent-id are not all zeros\n if (traceId === \"00000000000000000000000000000000\") return null;\n if (parentId === \"0000000000000000\") return null;\n\n return {\n version: version!,\n traceId: traceId!,\n parentId: parentId!,\n traceFlags: parseInt(flags!, 16),\n };\n}\n\n/**\n * Generate a new trace ID (32 hex characters)\n */\nexport function generateTraceId(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Generate a new span ID (16 hex characters)\n */\nexport function generateSpanId(): string {\n const bytes = new Uint8Array(8);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Create a traceparent header value\n */\nexport function createTraceparent(\n traceId: string,\n spanId: string,\n sampled: boolean = true\n): string {\n const flags = sampled ? \"01\" : \"00\";\n return `00-${traceId}-${spanId}-${flags}`;\n}\n\n/**\n * Extended context for tracing\n * These values are set on the context for downstream middleware/handlers\n */\ndeclare module \"../context.js\" {\n interface ServerContextVariables {\n /** W3C trace context (if propagation is enabled) */\n traceContext?: TraceContext;\n /** Current span ID for this request */\n spanId?: string;\n /** Tracestate header value (for forwarding) */\n traceState?: string;\n }\n}\n\n/**\n * Tracing middleware\n *\n * Handles request ID generation and W3C Trace Context propagation.\n *\n * @example Basic usage\n * ```typescript\n * app.use('*', tracing());\n *\n * // Access in handlers\n * app.get('/api/test', (c) => {\n * const requestId = c.get('requestId');\n * return c.json({ requestId });\n * });\n * ```\n *\n * @example With distributed tracing\n * ```typescript\n * app.use('*', tracing({\n * propagate: true,\n * trustIncoming: true,\n * }));\n *\n * // Access trace context\n * app.get('/api/test', (c) => {\n * const trace = c.get('traceContext');\n * const spanId = c.get('spanId');\n * return c.json({ traceId: trace?.traceId, spanId });\n * });\n * ```\n *\n * @example Outgoing requests (forwarding trace context)\n * ```typescript\n * app.get('/api/proxy', async (c) => {\n * const trace = c.get('traceContext');\n * const spanId = c.get('spanId');\n * const traceState = c.get('traceState');\n *\n * const headers: Record<string, string> = {};\n *\n * if (trace) {\n * // Create new traceparent with our spanId as parent\n * headers['traceparent'] = createTraceparent(trace.traceId, spanId!, true);\n * if (traceState) {\n * headers['tracestate'] = traceState;\n * }\n * }\n *\n * const response = await fetch('https://downstream-service.com/api', { headers });\n * return c.json(await response.json());\n * });\n * ```\n */\nexport function tracing(options: TracingOptions = {}) {\n const {\n headerName = \"x-request-id\",\n generateId = generateRequestId,\n propagate = false,\n emitHeader = true,\n trustIncoming = true,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n let requestId: string;\n\n // Get or generate request ID\n if (trustIncoming) {\n requestId = c.req.header(headerName) ?? generateId();\n } else {\n requestId = generateId();\n }\n\n // Set request ID in context\n c.set(\"requestId\", requestId);\n\n // Handle W3C Trace Context propagation\n if (propagate) {\n const traceparent = c.req.header(\"traceparent\");\n const tracestate = c.req.header(\"tracestate\");\n\n // Generate a new span ID for this request\n const spanId = generateSpanId();\n c.set(\"spanId\", spanId);\n\n if (traceparent) {\n const traceContext = parseTraceparent(traceparent);\n\n if (traceContext) {\n c.set(\"traceContext\", traceContext);\n\n if (tracestate) {\n c.set(\"traceState\", tracestate);\n }\n }\n } else {\n // No incoming trace context - start a new trace\n const traceId = generateTraceId();\n c.set(\"traceContext\", {\n version: \"00\",\n traceId,\n parentId: spanId,\n traceFlags: 1, // Sampled\n });\n }\n }\n\n // Emit request ID in response header\n if (emitHeader) {\n c.header(headerName, requestId);\n }\n\n // Process request\n await next();\n };\n}\n\n/**\n * Create tracing middleware (alias)\n */\nexport const tracingMiddleware = tracing;\n","/**\n * @parsrun/server - Usage Tracking Middleware\n * Automatically track API usage per request\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\n\n/**\n * Usage service interface (from @parsrun/payments)\n * Defined here to avoid circular dependency\n */\nexport interface UsageServiceLike {\n trackUsage(options: {\n tenantId: string;\n customerId: string;\n subscriptionId?: string;\n featureKey: string;\n quantity?: number;\n metadata?: Record<string, unknown>;\n idempotencyKey?: string;\n }): Promise<unknown>;\n}\n\n/**\n * Usage tracking middleware options\n */\nexport interface UsageTrackingOptions {\n /**\n * Usage service instance\n */\n usageService: UsageServiceLike;\n\n /**\n * Feature key to track\n * Can be a static string or a function that extracts it from context\n * @default \"api_calls\"\n */\n featureKey?: string | ((c: HonoContext) => string);\n\n /**\n * Quantity to track\n * Can be a static number or a function that calculates it from context\n * @default 1\n */\n quantity?: number | ((c: HonoContext) => number);\n\n /**\n * Skip tracking for certain requests\n */\n skip?: (c: HonoContext) => boolean;\n\n /**\n * When to track: before or after the request\n * @default \"response\"\n */\n trackOn?: \"request\" | \"response\";\n\n /**\n * Only track successful responses (2xx)\n * @default true\n */\n successOnly?: boolean;\n\n /**\n * Custom customer ID extractor\n * @default Uses c.get(\"user\")?.id\n */\n getCustomerId?: (c: HonoContext) => string | undefined;\n\n /**\n * Custom tenant ID extractor\n * @default Uses c.get(\"tenant\")?.id or c.get(\"user\")?.tenantId\n */\n getTenantId?: (c: HonoContext) => string | undefined;\n\n /**\n * Custom subscription ID extractor\n */\n getSubscriptionId?: (c: HonoContext) => string | undefined;\n\n /**\n * Include request metadata\n * @default true\n */\n includeMetadata?: boolean;\n\n /**\n * Generate idempotency key to prevent duplicates\n */\n getIdempotencyKey?: (c: HonoContext) => string | undefined;\n}\n\n/**\n * Usage tracking middleware\n *\n * Automatically tracks API usage for authenticated requests.\n *\n * @example\n * ```typescript\n * import { usageTracking } from \"@parsrun/server\";\n * import { createUsageService, createMemoryUsageStorage } from \"@parsrun/payments\";\n *\n * const usageService = createUsageService({\n * storage: createMemoryUsageStorage(),\n * });\n *\n * // Track all API calls\n * app.use(\"/api/*\", usageTracking({\n * usageService,\n * featureKey: \"api_calls\",\n * }));\n *\n * // Track with custom feature key based on route\n * app.use(\"/api/ai/*\", usageTracking({\n * usageService,\n * featureKey: \"ai_requests\",\n * quantity: (c) => {\n * // Track tokens used from response\n * return c.get(\"tokensUsed\") ?? 1;\n * },\n * }));\n *\n * // Skip certain routes\n * app.use(\"/api/*\", usageTracking({\n * usageService,\n * skip: (c) => c.req.path.startsWith(\"/api/health\"),\n * }));\n * ```\n */\nexport function usageTracking(options: UsageTrackingOptions) {\n const {\n usageService,\n featureKey = \"api_calls\",\n quantity = 1,\n skip,\n trackOn = \"response\",\n successOnly = true,\n getCustomerId = (c) => c.get(\"user\")?.id,\n getTenantId = (c) => c.get(\"tenant\")?.id ?? c.get(\"user\")?.tenantId,\n getSubscriptionId,\n includeMetadata = true,\n getIdempotencyKey,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Track on request (before processing)\n if (trackOn === \"request\") {\n await trackUsage(c);\n return next();\n }\n\n // Track on response (after processing)\n await next();\n\n // Skip if configured\n if (skip?.(c)) return;\n\n // Skip failed responses if configured\n if (successOnly && c.res.status >= 400) return;\n\n await trackUsage(c);\n };\n\n async function trackUsage(c: HonoContext) {\n const customerId = getCustomerId(c);\n const tenantId = getTenantId(c);\n\n // Skip if no user or tenant\n if (!customerId || !tenantId) return;\n\n const resolvedFeatureKey =\n typeof featureKey === \"function\" ? featureKey(c) : featureKey;\n\n const resolvedQuantity =\n typeof quantity === \"function\" ? quantity(c) : quantity;\n\n const metadata = includeMetadata\n ? {\n path: c.req.path,\n method: c.req.method,\n statusCode: c.res.status,\n userAgent: c.req.header(\"user-agent\"),\n }\n : undefined;\n\n try {\n // Build track options with only defined optional properties\n const trackOptions: {\n tenantId: string;\n customerId: string;\n featureKey: string;\n quantity?: number;\n subscriptionId?: string;\n metadata?: Record<string, unknown>;\n idempotencyKey?: string;\n } = {\n tenantId,\n customerId,\n featureKey: resolvedFeatureKey,\n quantity: resolvedQuantity,\n };\n\n const subscriptionId = getSubscriptionId?.(c);\n if (subscriptionId !== undefined) {\n trackOptions.subscriptionId = subscriptionId;\n }\n\n if (metadata !== undefined) {\n trackOptions.metadata = metadata;\n }\n\n const idempotencyKey = getIdempotencyKey?.(c);\n if (idempotencyKey !== undefined) {\n trackOptions.idempotencyKey = idempotencyKey;\n }\n\n await usageService.trackUsage(trackOptions);\n } catch (error) {\n // Log but don't fail the request\n const logger = c.get(\"logger\");\n if (logger) {\n logger.error(\"Usage tracking failed\", {\n error: error instanceof Error ? error.message : String(error),\n customerId,\n featureKey: resolvedFeatureKey,\n });\n }\n }\n }\n}\n\n/**\n * Create usage tracking middleware with pre-configured options\n */\nexport function createUsageTracking(baseOptions: UsageTrackingOptions) {\n return (overrides?: Partial<UsageTrackingOptions>) => {\n return usageTracking({ ...baseOptions, ...overrides });\n };\n}\n","/**\n * @parsrun/server - Quota Enforcement Middleware\n * Enforce usage quotas before processing requests\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\n\n/**\n * Quota check result interface (from @parsrun/payments)\n */\nexport interface QuotaCheckResult {\n allowed: boolean;\n currentUsage: number;\n limit: number | null;\n remaining: number | null;\n wouldExceed: boolean;\n percentAfter: number | null;\n}\n\n/**\n * Quota manager interface (from @parsrun/payments)\n * Defined here to avoid circular dependency\n */\nexport interface QuotaManagerLike {\n checkQuota(\n customerId: string,\n featureKey: string,\n quantity?: number\n ): Promise<QuotaCheckResult>;\n\n enforceQuota(\n customerId: string,\n featureKey: string,\n quantity?: number\n ): Promise<void>;\n}\n\n/**\n * Quota exceeded error class\n */\nexport class QuotaExceededError extends Error {\n public readonly statusCode = 429;\n public readonly code = \"QUOTA_EXCEEDED\";\n\n constructor(\n public readonly featureKey: string,\n public readonly limit: number | null,\n public readonly currentUsage: number,\n public readonly requestedQuantity: number = 1\n ) {\n super(\n `Quota exceeded for \"${featureKey}\": ${currentUsage}/${limit ?? \"unlimited\"} used`\n );\n this.name = \"QuotaExceededError\";\n }\n}\n\n/**\n * Quota enforcement middleware options\n */\nexport interface QuotaEnforcementOptions {\n /**\n * Quota manager instance\n */\n quotaManager: QuotaManagerLike;\n\n /**\n * Feature key to check\n * Can be a static string or a function that extracts it from context\n */\n featureKey: string | ((c: HonoContext) => string);\n\n /**\n * Quantity to check (default: 1)\n */\n quantity?: number | ((c: HonoContext) => number);\n\n /**\n * Skip quota check for certain requests\n */\n skip?: (c: HonoContext) => boolean;\n\n /**\n * Custom customer ID extractor\n * @default Uses c.get(\"user\")?.id\n */\n getCustomerId?: (c: HonoContext) => string | undefined;\n\n /**\n * Include quota headers in response\n * @default true\n */\n includeHeaders?: boolean;\n\n /**\n * Custom error handler\n */\n onQuotaExceeded?: (\n c: HonoContext,\n result: QuotaCheckResult,\n featureKey: string\n ) => Response | void;\n\n /**\n * Soft limit mode - warn but don't block\n * @default false\n */\n softLimit?: boolean;\n\n /**\n * Callback when quota is close to limit (>80%)\n */\n onQuotaWarning?: (\n c: HonoContext,\n result: QuotaCheckResult,\n featureKey: string\n ) => void;\n}\n\n/**\n * Quota enforcement middleware\n *\n * Checks and enforces usage quotas before processing requests.\n *\n * @example\n * ```typescript\n * import { quotaEnforcement } from \"@parsrun/server\";\n * import { createQuotaManager, createMemoryUsageStorage } from \"@parsrun/payments\";\n *\n * const quotaManager = createQuotaManager({\n * storage: createMemoryUsageStorage(),\n * });\n *\n * // Enforce API call quota\n * app.use(\"/api/*\", quotaEnforcement({\n * quotaManager,\n * featureKey: \"api_calls\",\n * }));\n *\n * // Enforce with dynamic feature key\n * app.use(\"/api/*\", quotaEnforcement({\n * quotaManager,\n * featureKey: (c) => {\n * if (c.req.path.startsWith(\"/api/ai\")) return \"ai_requests\";\n * return \"api_calls\";\n * },\n * }));\n *\n * // Soft limit mode (warn but allow)\n * app.use(\"/api/*\", quotaEnforcement({\n * quotaManager,\n * featureKey: \"api_calls\",\n * softLimit: true,\n * onQuotaWarning: (c, result) => {\n * console.warn(\"Quota warning:\", result);\n * },\n * }));\n * ```\n */\nexport function quotaEnforcement(options: QuotaEnforcementOptions) {\n const {\n quotaManager,\n featureKey,\n quantity = 1,\n skip,\n getCustomerId = (c) => c.get(\"user\")?.id,\n includeHeaders = true,\n onQuotaExceeded,\n softLimit = false,\n onQuotaWarning,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n const customerId = getCustomerId(c);\n\n // Skip if no user (unauthenticated requests)\n if (!customerId) {\n return next();\n }\n\n const resolvedFeatureKey =\n typeof featureKey === \"function\" ? featureKey(c) : featureKey;\n\n const resolvedQuantity =\n typeof quantity === \"function\" ? quantity(c) : quantity;\n\n try {\n const result = await quotaManager.checkQuota(\n customerId,\n resolvedFeatureKey,\n resolvedQuantity\n );\n\n // Set quota headers\n if (includeHeaders) {\n c.header(\"X-Quota-Limit\", String(result.limit ?? \"unlimited\"));\n c.header(\"X-Quota-Remaining\", String(result.remaining ?? \"unlimited\"));\n c.header(\"X-Quota-Used\", String(result.currentUsage));\n\n if (result.percentAfter !== null) {\n c.header(\"X-Quota-Percent\", String(result.percentAfter));\n }\n }\n\n // Check for warning threshold (>80%)\n if (\n result.percentAfter !== null &&\n result.percentAfter >= 80 &&\n onQuotaWarning\n ) {\n onQuotaWarning(c, result, resolvedFeatureKey);\n }\n\n // Check if quota exceeded\n if (!result.allowed && !softLimit) {\n // Custom error handler\n if (onQuotaExceeded) {\n const response = onQuotaExceeded(c, result, resolvedFeatureKey);\n if (response) return response;\n }\n\n // Default error response\n throw new QuotaExceededError(\n resolvedFeatureKey,\n result.limit,\n result.currentUsage,\n resolvedQuantity\n );\n }\n\n // Continue to next middleware\n await next();\n } catch (error) {\n // Re-throw quota errors\n if (error instanceof QuotaExceededError) {\n throw error;\n }\n\n // Log other errors but continue\n const logger = c.get(\"logger\");\n if (logger) {\n logger.error(\"Quota check failed\", {\n error: error instanceof Error ? error.message : String(error),\n customerId,\n featureKey: resolvedFeatureKey,\n });\n }\n\n // Continue on error (fail open)\n await next();\n }\n };\n}\n\n/**\n * Create quota enforcement middleware with pre-configured options\n */\nexport function createQuotaEnforcement(\n baseOptions: Omit<QuotaEnforcementOptions, \"featureKey\">\n) {\n return (featureKey: string | ((c: HonoContext) => string)) => {\n return quotaEnforcement({ ...baseOptions, featureKey });\n };\n}\n\n/**\n * Multiple quota enforcement\n * Check multiple features at once\n */\nexport function multiQuotaEnforcement(\n options: Omit<QuotaEnforcementOptions, \"featureKey\"> & {\n features: Array<{\n featureKey: string;\n quantity?: number | ((c: HonoContext) => number);\n }>;\n }\n) {\n const { features } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n const customerId = (options.getCustomerId ?? ((ctx) => ctx.get(\"user\")?.id))(c);\n\n if (!customerId || options.skip?.(c)) {\n return next();\n }\n\n // Check all quotas\n for (const feature of features) {\n const resolvedQuantity =\n typeof feature.quantity === \"function\"\n ? feature.quantity(c)\n : feature.quantity ?? 1;\n\n const result = await options.quotaManager.checkQuota(\n customerId,\n feature.featureKey,\n resolvedQuantity\n );\n\n if (!result.allowed && !options.softLimit) {\n if (options.onQuotaExceeded) {\n const response = options.onQuotaExceeded(c, result, feature.featureKey);\n if (response) return response;\n }\n\n throw new QuotaExceededError(\n feature.featureKey,\n result.limit,\n result.currentUsage,\n resolvedQuantity\n );\n }\n }\n\n await next();\n };\n}\n"],"mappings":"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","names":["error","c","c","error","error"]}
1
+ {"version":3,"sources":["../../src/context.ts","../../src/middleware/error-handler.ts","../../src/middleware/auth.ts","../../src/middleware/cors.ts","../../src/middleware/csrf.ts","../../src/middleware/rate-limit.ts","../../src/middleware/request-logger.ts","../../src/middleware/tracing.ts","../../src/middleware/usage-tracking.ts","../../src/middleware/quota-enforcement.ts"],"sourcesContent":["/**\n * @parsrun/server - Server Context\n * Type definitions for server context and configuration\n */\n\nimport type { Logger } from \"@parsrun/core\";\n\n/**\n * Database adapter interface\n * Implement this for your database (Drizzle, Prisma, etc.)\n */\nexport interface DatabaseAdapter {\n /** Execute raw SQL query */\n execute(sql: string): Promise<unknown>;\n /** Check connection */\n ping?(): Promise<boolean>;\n}\n\n/**\n * Module manifest for registering modules\n */\nexport interface ModuleManifest {\n /** Unique module name */\n name: string;\n /** Module version */\n version: string;\n /** Module description */\n description: string;\n /** Required permissions for this module */\n permissions: Record<string, string[]>;\n /** Module dependencies (other module names) */\n dependencies?: string[];\n /** Register routes for this module */\n registerRoutes: (app: HonoApp) => void;\n /** Called when module is enabled */\n onEnable?: () => Promise<void>;\n /** Called when module is disabled */\n onDisable?: () => Promise<void>;\n}\n\n/**\n * Server configuration\n */\nexport interface ServerConfig {\n /** Database adapter */\n database: DatabaseAdapter;\n /** CORS configuration */\n cors?: CorsConfig;\n /** Base path for API */\n basePath?: string;\n /** Cookie prefix for all cookies */\n cookiePrefix?: string;\n /** Logger instance */\n logger?: Logger;\n /** Custom context data */\n custom?: Record<string, unknown>;\n}\n\n/**\n * CORS configuration\n */\nexport interface CorsConfig {\n /** Allowed origins */\n origin: string | string[] | ((origin: string) => boolean);\n /** Allow credentials */\n credentials?: boolean;\n /** Allowed methods */\n methods?: string[];\n /** Allowed headers */\n allowedHeaders?: string[];\n /** Exposed headers */\n exposedHeaders?: string[];\n /** Max age in seconds */\n maxAge?: number;\n}\n\n/**\n * User information in context\n */\nexport interface ContextUser {\n id: string;\n email: string | undefined;\n tenantId: string | undefined;\n role: string | undefined;\n permissions: string[];\n}\n\n/**\n * Tenant information in context\n */\nexport interface ContextTenant {\n id: string;\n slug: string | undefined;\n name: string | undefined;\n status: string;\n}\n\n/**\n * Server context variables\n * Available in Hono context via c.get()\n */\n/**\n * W3C Trace Context - Parsed traceparent header\n * Format: {version}-{trace-id}-{parent-id}-{trace-flags}\n */\nexport interface TraceContext {\n /** Trace version (currently \"00\") */\n version: string;\n /** 32 hex character trace ID */\n traceId: string;\n /** 16 hex character parent span ID */\n parentId: string;\n /** Trace flags (sampled, etc.) */\n traceFlags: number;\n}\n\nexport interface ServerContextVariables {\n /** Database adapter */\n db: DatabaseAdapter;\n /** Server configuration */\n config: ServerConfig;\n /** Enabled modules set */\n enabledModules: Set<string>;\n /** Current user (if authenticated) */\n user: ContextUser | undefined;\n /** Current tenant (if resolved) */\n tenant: ContextTenant | undefined;\n /** Request logger */\n logger: Logger;\n /** Request ID */\n requestId: string;\n /** Cookie prefix */\n cookiePrefix: string | undefined;\n /** Custom context data */\n custom: Record<string, unknown>;\n /** W3C trace context (if propagation is enabled) */\n traceContext?: TraceContext;\n /** Current span ID for this request */\n spanId?: string;\n /** Tracestate header value (for forwarding) */\n traceState?: string;\n}\n\n/**\n * Hono app type with server context\n */\nexport type HonoApp = import(\"hono\").Hono<{ Variables: ServerContextVariables }>;\n\n/**\n * Hono context type with server context\n */\nexport type HonoContext = import(\"hono\").Context<{ Variables: ServerContextVariables }>;\n\n/**\n * Middleware next function\n */\nexport type HonoNext = () => Promise<void>;\n\n/**\n * Middleware function type\n */\nexport type Middleware = (c: HonoContext, next: HonoNext) => Promise<Response | void>;\n\n/**\n * Route handler function type\n */\nexport type RouteHandler = (c: HonoContext) => Promise<Response> | Response;\n\n/**\n * Permission check input\n */\nexport interface PermissionCheck {\n /** Resource name (e.g., \"users\", \"items\") */\n resource: string;\n /** Action name (e.g., \"read\", \"create\", \"update\", \"delete\") */\n action: string;\n /** Permission scope */\n scope?: \"tenant\" | \"global\" | \"own\";\n}\n\n/**\n * Permission definition\n */\nexport interface PermissionDefinition {\n /** Permission name (e.g., \"users:read\") */\n name: string;\n /** Resource part */\n resource: string;\n /** Action part */\n action: string;\n /** Description */\n description?: string;\n /** Scope */\n scope?: \"tenant\" | \"global\" | \"own\";\n}\n\n/**\n * Role definition\n */\nexport interface RoleDefinition {\n /** Role name */\n name: string;\n /** Display name */\n displayName?: string;\n /** Description */\n description?: string;\n /** Permissions assigned to this role */\n permissions: string[];\n /** Is this a system role */\n isSystem?: boolean;\n}\n\n/**\n * Standard API response structure\n */\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: {\n code: string;\n message: string;\n details?: Record<string, unknown> | undefined;\n };\n meta?: {\n page?: number | undefined;\n limit?: number | undefined;\n total?: number | undefined;\n requestId?: string | undefined;\n } | undefined;\n}\n\n/**\n * Create a success response\n */\nexport function success<T>(data: T, meta?: ApiResponse[\"meta\"]): ApiResponse<T> {\n return {\n success: true,\n data,\n meta: meta ?? undefined,\n };\n}\n\n/**\n * Create an error response\n */\nexport function error(\n code: string,\n message: string,\n details?: Record<string, unknown>\n): ApiResponse<never> {\n return {\n success: false,\n error: { code, message, details: details ?? undefined },\n };\n}\n\n/**\n * Generate a request ID\n */\nexport function generateRequestId(): string {\n return crypto.randomUUID();\n}\n","/**\n * @parsrun/server - Error Handler Middleware\n * Global error handling and response formatting\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\nimport { error as errorResponse } from \"../context.js\";\nimport type { ErrorTransport, ErrorContext } from \"@parsrun/core/transports\";\n\n/**\n * Base API error class\n */\nexport class ApiError extends Error {\n constructor(\n public readonly statusCode: number,\n public readonly code: string,\n message: string,\n public readonly details?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"ApiError\";\n }\n\n toResponse() {\n return errorResponse(this.code, this.message, this.details);\n }\n}\n\n/**\n * 400 Bad Request\n */\nexport class BadRequestError extends ApiError {\n constructor(message = \"Bad request\", details?: Record<string, unknown>) {\n super(400, \"BAD_REQUEST\", message, details);\n this.name = \"BadRequestError\";\n }\n}\n\n/**\n * 401 Unauthorized\n */\nexport class UnauthorizedError extends ApiError {\n constructor(message = \"Unauthorized\", details?: Record<string, unknown>) {\n super(401, \"UNAUTHORIZED\", message, details);\n this.name = \"UnauthorizedError\";\n }\n}\n\n/**\n * 403 Forbidden\n */\nexport class ForbiddenError extends ApiError {\n constructor(message = \"Forbidden\", details?: Record<string, unknown>) {\n super(403, \"FORBIDDEN\", message, details);\n this.name = \"ForbiddenError\";\n }\n}\n\n/**\n * 404 Not Found\n */\nexport class NotFoundError extends ApiError {\n constructor(message = \"Not found\", details?: Record<string, unknown>) {\n super(404, \"NOT_FOUND\", message, details);\n this.name = \"NotFoundError\";\n }\n}\n\n/**\n * 409 Conflict\n */\nexport class ConflictError extends ApiError {\n constructor(message = \"Conflict\", details?: Record<string, unknown>) {\n super(409, \"CONFLICT\", message, details);\n this.name = \"ConflictError\";\n }\n}\n\n/**\n * 422 Unprocessable Entity (Validation Error)\n */\nexport class ValidationError extends ApiError {\n constructor(message = \"Validation failed\", details?: Record<string, unknown>) {\n super(422, \"VALIDATION_ERROR\", message, details);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * 429 Too Many Requests\n */\nexport class RateLimitError extends ApiError {\n constructor(\n message = \"Too many requests\",\n public readonly retryAfter?: number\n ) {\n super(429, \"RATE_LIMIT_EXCEEDED\", message, { retryAfter });\n this.name = \"RateLimitError\";\n }\n}\n\n/**\n * 500 Internal Server Error\n */\nexport class InternalError extends ApiError {\n constructor(message = \"Internal server error\", details?: Record<string, unknown>) {\n super(500, \"INTERNAL_ERROR\", message, details);\n this.name = \"InternalError\";\n }\n}\n\n/**\n * 503 Service Unavailable\n */\nexport class ServiceUnavailableError extends ApiError {\n constructor(message = \"Service unavailable\", details?: Record<string, unknown>) {\n super(503, \"SERVICE_UNAVAILABLE\", message, details);\n this.name = \"ServiceUnavailableError\";\n }\n}\n\n/**\n * Error handler options\n */\nexport interface ErrorHandlerOptions {\n /** Include stack trace in development */\n includeStack?: boolean;\n /** Custom error logger */\n onError?: (error: Error, c: HonoContext) => void;\n /**\n * Error transport for external error tracking (e.g., Sentry)\n * Automatically captures exceptions with request context\n */\n errorTransport?: ErrorTransport;\n /**\n * Capture all errors including 4xx client errors\n * By default, only 5xx server errors are captured\n * @default false\n */\n captureAllErrors?: boolean;\n /**\n * Custom function to determine if an error should be captured\n * Overrides the default captureAllErrors behavior\n */\n shouldCapture?: (error: Error, statusCode: number) => boolean;\n}\n\n/**\n * Global error handler middleware\n *\n * @example Basic usage\n * ```typescript\n * app.use('*', errorHandler({\n * includeStack: process.env.NODE_ENV === 'development',\n * onError: (error, c) => {\n * console.error(`[${c.get('requestId')}]`, error);\n * },\n * }));\n * ```\n *\n * @example With Sentry error tracking\n * ```typescript\n * import { SentryTransport } from '@parsrun/core/transports';\n *\n * const sentry = new SentryTransport({\n * dsn: process.env.SENTRY_DSN!,\n * environment: process.env.NODE_ENV,\n * });\n *\n * app.use('*', errorHandler({\n * errorTransport: sentry,\n * captureAllErrors: false, // Only capture 5xx errors\n * }));\n * ```\n */\nexport function errorHandler(options: ErrorHandlerOptions = {}) {\n const {\n includeStack = false,\n onError,\n errorTransport,\n captureAllErrors = false,\n shouldCapture,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n try {\n await next();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n // Determine status code\n const statusCode = error instanceof ApiError ? error.statusCode : 500;\n\n // Log error\n if (onError) {\n onError(error, c);\n } else {\n const logger = c.get(\"logger\");\n if (logger) {\n logger.error(\"Request error\", {\n requestId: c.get(\"requestId\"),\n error: error.message,\n stack: error.stack,\n });\n }\n }\n\n // Capture to error transport if configured\n if (errorTransport) {\n const shouldCaptureError = shouldCapture\n ? shouldCapture(error, statusCode)\n : captureAllErrors || statusCode >= 500;\n\n if (shouldCaptureError) {\n const user = c.get(\"user\");\n const tenant = c.get(\"tenant\");\n\n // Build error context with only defined values\n const errorContext: ErrorContext = {\n requestId: c.get(\"requestId\"),\n tags: {\n path: c.req.path,\n method: c.req.method,\n statusCode: String(statusCode),\n },\n };\n\n if (user?.id) {\n errorContext.userId = user.id;\n }\n if (tenant?.id) {\n errorContext.tenantId = tenant.id;\n }\n\n // Add extra context\n const extra: Record<string, unknown> = {\n query: c.req.query(),\n };\n if (error instanceof ApiError) {\n extra[\"errorCode\"] = error.code;\n }\n errorContext.extra = extra;\n\n // Capture asynchronously to not block response\n Promise.resolve(\n errorTransport.captureException(error, errorContext)\n ).catch(() => {\n // Silent fail - don't let transport errors affect response\n });\n }\n }\n\n // Handle known API errors\n if (error instanceof ApiError) {\n return c.json(error.toResponse(), error.statusCode as 400);\n }\n\n // Handle unknown errors\n const details: Record<string, unknown> = {};\n\n if (includeStack && error.stack) {\n details[\"stack\"] = error.stack;\n }\n\n return c.json(\n errorResponse(\"INTERNAL_ERROR\", \"An unexpected error occurred\", details),\n 500\n );\n }\n };\n}\n\n/**\n * Not found handler\n *\n * @example\n * ```typescript\n * app.notFound(notFoundHandler);\n * ```\n */\nexport function notFoundHandler(c: HonoContext) {\n return c.json(\n errorResponse(\"NOT_FOUND\", `Route ${c.req.method} ${c.req.path} not found`),\n 404\n );\n}\n","/**\n * @parsrun/server - Auth Middleware\n * JWT authentication middleware\n */\n\nimport type { HonoContext, HonoNext, ContextUser } from \"../context.js\";\nimport { UnauthorizedError } from \"./error-handler.js\";\n\n/**\n * JWT payload structure\n */\nexport interface JwtPayload {\n sub: string; // User ID\n email?: string;\n tenantId?: string;\n role?: string;\n permissions?: string[];\n iat?: number;\n exp?: number;\n jti?: string;\n}\n\n/**\n * JWT verification function type\n */\nexport type JwtVerifier = (token: string) => Promise<JwtPayload | null>;\n\n/**\n * Auth middleware options\n */\nexport interface AuthMiddlewareOptions {\n /** JWT verification function */\n verify: JwtVerifier;\n /** Header name for token (default: Authorization) */\n header?: string;\n /** Token prefix (default: Bearer) */\n prefix?: string;\n /** Cookie name for token (alternative to header) */\n cookie?: string;\n /** Skip auth for certain requests */\n skip?: (c: HonoContext) => boolean;\n /** Custom error message */\n message?: string;\n}\n\n/**\n * Extract token from request\n */\nfunction extractToken(\n c: HonoContext,\n header: string,\n prefix: string,\n cookie?: string\n): string | null {\n // Try header first\n const authHeader = c.req.header(header);\n if (authHeader) {\n if (prefix && authHeader.startsWith(`${prefix} `)) {\n return authHeader.slice(prefix.length + 1);\n }\n return authHeader;\n }\n\n // Try cookie\n if (cookie) {\n const cookieHeader = c.req.header(\"cookie\");\n if (cookieHeader) {\n const cookies = cookieHeader.split(\";\").map((c) => c.trim());\n for (const c of cookies) {\n const [key, ...valueParts] = c.split(\"=\");\n if (key === cookie) {\n return valueParts.join(\"=\");\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Auth middleware - requires valid JWT\n *\n * @example\n * ```typescript\n * import { verifyJwt } from '@parsrun/auth';\n *\n * const authMiddleware = auth({\n * verify: (token) => verifyJwt(token, secret),\n * cookie: 'auth_token',\n * });\n *\n * app.use('/api/*', authMiddleware);\n *\n * // Access user in handlers\n * app.get('/api/me', (c) => {\n * const user = c.get('user');\n * return c.json({ user });\n * });\n * ```\n */\nexport function auth(options: AuthMiddlewareOptions) {\n const {\n verify,\n header = \"authorization\",\n prefix = \"Bearer\",\n cookie,\n skip,\n message = \"Authentication required\",\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n // Extract token\n const token = extractToken(c, header, prefix, cookie);\n\n if (!token) {\n throw new UnauthorizedError(message);\n }\n\n // Verify token\n const payload = await verify(token);\n\n if (!payload) {\n throw new UnauthorizedError(\"Invalid or expired token\");\n }\n\n // Set user in context\n const user: ContextUser = {\n id: payload.sub,\n email: payload.email,\n tenantId: payload.tenantId,\n role: payload.role,\n permissions: payload.permissions ?? [],\n };\n\n c.set(\"user\", user);\n\n await next();\n };\n}\n\n/**\n * Optional auth middleware - sets user if token present, but doesn't require it\n *\n * @example\n * ```typescript\n * app.use('/api/public/*', optionalAuth({\n * verify: (token) => verifyJwt(token, secret),\n * }));\n *\n * // User may or may not be present\n * app.get('/api/public/items', (c) => {\n * const user = c.get('user'); // may be undefined\n * // Return different data based on auth status\n * });\n * ```\n */\nexport function optionalAuth(options: Omit<AuthMiddlewareOptions, \"message\">) {\n const { verify, header = \"authorization\", prefix = \"Bearer\", cookie, skip } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n // Extract token\n const token = extractToken(c, header, prefix, cookie);\n\n if (token) {\n try {\n const payload = await verify(token);\n\n if (payload) {\n // Set user in context\n const user: ContextUser = {\n id: payload.sub,\n email: payload.email,\n tenantId: payload.tenantId,\n role: payload.role,\n permissions: payload.permissions ?? [],\n };\n\n c.set(\"user\", user);\n }\n } catch {\n // Ignore verification errors for optional auth\n }\n }\n\n await next();\n };\n}\n\n/**\n * Create auth middleware from verifier function\n *\n * @example\n * ```typescript\n * const { auth, optionalAuth } = createAuthMiddleware({\n * verify: async (token) => {\n * return verifyJwt(token, process.env.JWT_SECRET);\n * },\n * cookie: 'session',\n * });\n *\n * app.use('/api/*', auth);\n * app.use('/public/*', optionalAuth);\n * ```\n */\nexport function createAuthMiddleware(\n baseOptions: Omit<AuthMiddlewareOptions, \"skip\" | \"message\">\n) {\n return {\n auth: (options?: Partial<AuthMiddlewareOptions>) =>\n auth({ ...baseOptions, ...options }),\n optionalAuth: (options?: Partial<Omit<AuthMiddlewareOptions, \"message\">>) =>\n optionalAuth({ ...baseOptions, ...options }),\n };\n}\n","/**\n * @parsrun/server - CORS Middleware\n * Cross-Origin Resource Sharing configuration\n */\n\nimport type { HonoContext, HonoNext, CorsConfig } from \"../context.js\";\n\n/**\n * Default CORS configuration\n */\nconst defaultCorsConfig: CorsConfig = {\n origin: \"*\",\n credentials: false,\n methods: [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\"],\n allowedHeaders: [\"Content-Type\", \"Authorization\", \"X-Request-ID\", \"X-CSRF-Token\"],\n exposedHeaders: [\"X-Request-ID\", \"X-Total-Count\"],\n maxAge: 86400, // 24 hours\n};\n\n/**\n * Check if origin is allowed\n */\nfunction isOriginAllowed(origin: string, config: CorsConfig): boolean {\n if (config.origin === \"*\") return true;\n\n if (typeof config.origin === \"string\") {\n return origin === config.origin;\n }\n\n if (Array.isArray(config.origin)) {\n return config.origin.includes(origin);\n }\n\n if (typeof config.origin === \"function\") {\n return config.origin(origin);\n }\n\n return false;\n}\n\n/**\n * CORS middleware\n *\n * @example\n * ```typescript\n * app.use('*', cors({\n * origin: ['https://example.com', 'https://app.example.com'],\n * credentials: true,\n * }));\n * ```\n */\nexport function cors(config?: Partial<CorsConfig>): (c: HonoContext, next: HonoNext) => Promise<Response | void> {\n const corsConfig = { ...defaultCorsConfig, ...config };\n\n return async (c: HonoContext, next: HonoNext): Promise<Response | void> => {\n const origin = c.req.header(\"origin\") ?? \"\";\n\n // Handle preflight requests\n if (c.req.method === \"OPTIONS\") {\n const response = new Response(null, { status: 204 });\n\n if (isOriginAllowed(origin, corsConfig)) {\n response.headers.set(\"Access-Control-Allow-Origin\", origin || \"*\");\n }\n\n if (corsConfig.credentials) {\n response.headers.set(\"Access-Control-Allow-Credentials\", \"true\");\n }\n\n if (corsConfig.methods) {\n response.headers.set(\n \"Access-Control-Allow-Methods\",\n corsConfig.methods.join(\", \")\n );\n }\n\n if (corsConfig.allowedHeaders) {\n response.headers.set(\n \"Access-Control-Allow-Headers\",\n corsConfig.allowedHeaders.join(\", \")\n );\n }\n\n if (corsConfig.maxAge) {\n response.headers.set(\"Access-Control-Max-Age\", String(corsConfig.maxAge));\n }\n\n return response;\n }\n\n // Handle actual requests\n await next();\n\n // Add CORS headers to response\n if (isOriginAllowed(origin, corsConfig)) {\n c.header(\"Access-Control-Allow-Origin\", origin || \"*\");\n }\n\n if (corsConfig.credentials) {\n c.header(\"Access-Control-Allow-Credentials\", \"true\");\n }\n\n if (corsConfig.exposedHeaders) {\n c.header(\"Access-Control-Expose-Headers\", corsConfig.exposedHeaders.join(\", \"));\n }\n };\n}\n","/**\n * @parsrun/server - CSRF Middleware\n * Cross-Site Request Forgery protection\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\nimport { ForbiddenError } from \"./error-handler.js\";\n\n/**\n * CSRF options\n */\nexport interface CsrfOptions {\n /** Cookie name for CSRF token */\n cookieName?: string;\n /** Header name for CSRF token */\n headerName?: string;\n /** Methods that require CSRF validation */\n methods?: string[];\n /** Paths to exclude from CSRF protection */\n excludePaths?: string[];\n /** Skip CSRF for certain requests */\n skip?: (c: HonoContext) => boolean;\n /** Token generator */\n generateToken?: () => string;\n /** Cookie options */\n cookie?: {\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: \"strict\" | \"lax\" | \"none\";\n path?: string;\n maxAge?: number;\n };\n}\n\n/**\n * Generate random token\n */\nfunction generateRandomToken(): string {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Get cookie value\n */\nfunction getCookie(c: HonoContext, name: string): string | undefined {\n const cookieHeader = c.req.header(\"cookie\");\n if (!cookieHeader) return undefined;\n\n const cookies = cookieHeader.split(\";\").map((c) => c.trim());\n for (const cookie of cookies) {\n const [key, ...valueParts] = cookie.split(\"=\");\n if (key === name) {\n return valueParts.join(\"=\");\n }\n }\n return undefined;\n}\n\n/**\n * CSRF protection middleware\n *\n * @example\n * ```typescript\n * app.use('*', csrf({\n * cookieName: '_csrf',\n * headerName: 'X-CSRF-Token',\n * methods: ['POST', 'PUT', 'PATCH', 'DELETE'],\n * cookie: {\n * secure: true,\n * sameSite: 'strict',\n * },\n * }));\n *\n * // Get token in handler\n * app.get('/csrf-token', (c) => {\n * return c.json({ token: c.get('csrfToken') });\n * });\n * ```\n */\nexport function csrf(options: CsrfOptions = {}) {\n const {\n cookieName = \"_csrf\",\n headerName = \"x-csrf-token\",\n methods = [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"],\n excludePaths = [],\n skip,\n generateToken = generateRandomToken,\n cookie = {},\n } = options;\n\n const cookieOptions = {\n secure: cookie.secure ?? true,\n httpOnly: cookie.httpOnly ?? true,\n sameSite: cookie.sameSite ?? (\"lax\" as const),\n path: cookie.path ?? \"/\",\n maxAge: cookie.maxAge ?? 86400, // 24 hours\n };\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n // Skip excluded paths\n const path = c.req.path;\n if (excludePaths.some((p) => path.startsWith(p))) {\n return next();\n }\n\n // Get or create token\n let token = getCookie(c, cookieName);\n\n if (!token) {\n // Generate new token\n token = generateToken();\n\n // Set cookie\n const cookieValue = [\n `${cookieName}=${token}`,\n `Path=${cookieOptions.path}`,\n `Max-Age=${cookieOptions.maxAge}`,\n cookieOptions.sameSite && `SameSite=${cookieOptions.sameSite}`,\n cookieOptions.secure && \"Secure\",\n cookieOptions.httpOnly && \"HttpOnly\",\n ]\n .filter(Boolean)\n .join(\"; \");\n\n c.header(\"Set-Cookie\", cookieValue);\n }\n\n // Store token in context for handlers\n (c as HonoContext & { csrfToken: string }).set(\"csrfToken\" as never, token as never);\n\n // Validate token for protected methods\n if (methods.includes(c.req.method)) {\n const headerToken = c.req.header(headerName);\n const bodyToken = await getBodyToken(c);\n\n const providedToken = headerToken ?? bodyToken;\n\n if (!providedToken || providedToken !== token) {\n throw new ForbiddenError(\"Invalid CSRF token\");\n }\n }\n\n await next();\n };\n}\n\n/**\n * Try to get CSRF token from request body\n */\nasync function getBodyToken(c: HonoContext): Promise<string | undefined> {\n try {\n const contentType = c.req.header(\"content-type\") ?? \"\";\n\n if (contentType.includes(\"application/json\")) {\n const body = (await c.req.json()) as Record<string, unknown>;\n return (body[\"_csrf\"] ?? body[\"csrfToken\"] ?? body[\"csrf_token\"]) as string | undefined;\n }\n\n if (contentType.includes(\"application/x-www-form-urlencoded\")) {\n const body = await c.req.parseBody();\n return body[\"_csrf\"] as string | undefined;\n }\n } catch {\n // Ignore parsing errors\n }\n return undefined;\n}\n\n/**\n * Double Submit Cookie pattern\n * Generates a token and validates it matches between cookie and header\n */\nexport function doubleSubmitCookie(options: CsrfOptions = {}) {\n return csrf({\n ...options,\n cookie: {\n ...options.cookie,\n httpOnly: false, // Allow JS to read the cookie\n },\n });\n}\n","/**\n * @parsrun/server - Rate Limit Middleware\n * Request throttling with multiple storage backends\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\nimport { RateLimitError } from \"./error-handler.js\";\n\n/**\n * Rate limit storage interface\n */\nexport interface RateLimitStorage {\n /** Get current count for key */\n get(key: string): Promise<number>;\n /** Increment count and set expiry */\n increment(key: string, windowMs: number): Promise<number>;\n /** Reset count for key */\n reset(key: string): Promise<void>;\n}\n\n/**\n * In-memory rate limit storage\n * For single-instance deployments or development\n */\nexport class MemoryRateLimitStorage implements RateLimitStorage {\n private store = new Map<string, { count: number; expires: number }>();\n\n async get(key: string): Promise<number> {\n const entry = this.store.get(key);\n if (!entry || entry.expires < Date.now()) {\n return 0;\n }\n return entry.count;\n }\n\n async increment(key: string, windowMs: number): Promise<number> {\n const now = Date.now();\n const entry = this.store.get(key);\n\n if (!entry || entry.expires < now) {\n // Start new window\n this.store.set(key, { count: 1, expires: now + windowMs });\n return 1;\n }\n\n // Increment existing\n entry.count++;\n return entry.count;\n }\n\n async reset(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n /** Clean up expired entries */\n cleanup(): void {\n const now = Date.now();\n for (const [key, entry] of this.store) {\n if (entry.expires < now) {\n this.store.delete(key);\n }\n }\n }\n}\n\n/**\n * Rate limit options\n */\nexport interface RateLimitOptions {\n /** Time window in milliseconds */\n windowMs?: number;\n /** Maximum requests per window */\n max?: number;\n /** Generate key from request (default: IP address) */\n keyGenerator?: (c: HonoContext) => string;\n /** Skip rate limiting for certain requests */\n skip?: (c: HonoContext) => boolean;\n /** Custom storage backend */\n storage?: RateLimitStorage;\n /** Error message */\n message?: string;\n /** Include rate limit headers */\n headers?: boolean;\n /** Handler when limit is exceeded */\n onLimitReached?: (c: HonoContext, key: string) => void;\n}\n\n// Global default storage\nlet defaultStorage: RateLimitStorage | null = null;\n\n/**\n * Get or create default memory storage\n */\nfunction getDefaultStorage(): RateLimitStorage {\n if (!defaultStorage) {\n defaultStorage = new MemoryRateLimitStorage();\n }\n return defaultStorage;\n}\n\n/**\n * Rate limit middleware\n *\n * @example\n * ```typescript\n * // Basic usage - 100 requests per minute\n * app.use('/api/*', rateLimit({\n * windowMs: 60 * 1000,\n * max: 100,\n * }));\n *\n * // Per-user rate limiting\n * app.use('/api/*', rateLimit({\n * keyGenerator: (c) => c.get('user')?.id ?? getIP(c),\n * max: 1000,\n * }));\n *\n * // Strict limit for auth endpoints\n * app.use('/api/auth/*', rateLimit({\n * windowMs: 15 * 60 * 1000, // 15 minutes\n * max: 5,\n * message: 'Too many login attempts',\n * }));\n * ```\n */\nexport function rateLimit(options: RateLimitOptions = {}) {\n const {\n windowMs = 60 * 1000, // 1 minute\n max = 100,\n keyGenerator = defaultKeyGenerator,\n skip,\n storage = getDefaultStorage(),\n message = \"Too many requests, please try again later\",\n headers = true,\n onLimitReached,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n const key = `ratelimit:${keyGenerator(c)}`;\n const current = await storage.increment(key, windowMs);\n\n // Set rate limit headers\n if (headers) {\n c.header(\"X-RateLimit-Limit\", String(max));\n c.header(\"X-RateLimit-Remaining\", String(Math.max(0, max - current)));\n c.header(\"X-RateLimit-Reset\", String(Math.ceil((Date.now() + windowMs) / 1000)));\n }\n\n // Check if limit exceeded\n if (current > max) {\n if (onLimitReached) {\n onLimitReached(c, key);\n }\n\n const retryAfter = Math.ceil(windowMs / 1000);\n c.header(\"Retry-After\", String(retryAfter));\n\n throw new RateLimitError(message, retryAfter);\n }\n\n await next();\n };\n}\n\n/**\n * Default key generator - uses IP address\n */\nfunction defaultKeyGenerator(c: HonoContext): string {\n return (\n c.req.header(\"x-forwarded-for\")?.split(\",\")[0]?.trim() ??\n c.req.header(\"x-real-ip\") ??\n c.req.header(\"cf-connecting-ip\") ??\n \"unknown\"\n );\n}\n\n/**\n * Create rate limiter for specific routes\n *\n * @example\n * ```typescript\n * const apiLimiter = createRateLimiter({\n * windowMs: 60000,\n * max: 100,\n * });\n *\n * app.use('/api/*', apiLimiter.middleware);\n *\n * // Reset limit for a user after successful auth\n * await apiLimiter.reset('user:123');\n * ```\n */\nexport function createRateLimiter(options: RateLimitOptions = {}) {\n const storage = options.storage ?? getDefaultStorage();\n\n return {\n middleware: rateLimit({ ...options, storage }),\n storage,\n reset: (key: string) => storage.reset(`ratelimit:${key}`),\n get: (key: string) => storage.get(`ratelimit:${key}`),\n };\n}\n","/**\n * @parsrun/server - Request Logger Middleware\n * HTTP request/response logging\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\n\n/**\n * Request logger options\n */\nexport interface RequestLoggerOptions {\n /** Skip logging for certain paths */\n skip?: (c: HonoContext) => boolean;\n /** Custom log format */\n format?: \"json\" | \"combined\" | \"short\";\n /** Include request body in logs */\n includeBody?: boolean;\n /** Include response body in logs (be careful with large responses) */\n includeResponseBody?: boolean;\n /** Maximum body length to log */\n maxBodyLength?: number;\n}\n\n/**\n * Format bytes to human readable\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\n/**\n * Request logger middleware\n *\n * @example\n * ```typescript\n * app.use('*', requestLogger({\n * skip: (c) => c.req.path === '/health',\n * format: 'json',\n * }));\n * ```\n */\nexport function requestLogger(options: RequestLoggerOptions = {}) {\n const {\n skip,\n format = \"json\",\n includeBody = false,\n maxBodyLength = 1000,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n const start = Date.now();\n const logger = c.get(\"logger\");\n const requestId = c.get(\"requestId\");\n\n // Request info\n const method = c.req.method;\n const path = c.req.path;\n const query = c.req.query();\n const userAgent = c.req.header(\"user-agent\");\n const ip = c.req.header(\"x-forwarded-for\") ?? c.req.header(\"x-real-ip\") ?? \"unknown\";\n\n // Log request start\n if (format === \"json\") {\n logger?.debug(\"Request started\", {\n requestId,\n method,\n path,\n query: Object.keys(query).length > 0 ? query : undefined,\n ip,\n userAgent,\n });\n }\n\n // Get body if needed\n let requestBody: string | undefined;\n if (includeBody && [\"POST\", \"PUT\", \"PATCH\"].includes(method)) {\n try {\n const contentType = c.req.header(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n const body = await c.req.text();\n requestBody = body.length > maxBodyLength\n ? body.substring(0, maxBodyLength) + \"...\"\n : body;\n }\n } catch {\n // Ignore body parsing errors\n }\n }\n\n // Process request\n await next();\n\n // Calculate duration\n const duration = Date.now() - start;\n const status = c.res.status;\n\n // Get response size\n const contentLength = c.res.headers.get(\"content-length\");\n const size = contentLength ? parseInt(contentLength, 10) : 0;\n\n // Log based on format\n if (format === \"json\") {\n const logData: Record<string, unknown> = {\n requestId,\n method,\n path,\n status,\n duration: `${duration}ms`,\n size: formatBytes(size),\n };\n\n if (requestBody) {\n logData[\"requestBody\"] = requestBody;\n }\n\n // Use appropriate log level\n if (status >= 500) {\n logger?.error(\"Request completed\", logData);\n } else if (status >= 400) {\n logger?.warn(\"Request completed\", logData);\n } else {\n logger?.info(\"Request completed\", logData);\n }\n } else if (format === \"combined\") {\n // Apache combined log format\n const log = `${ip} - - [${new Date().toISOString()}] \"${method} ${path}\" ${status} ${size} \"-\" \"${userAgent}\" ${duration}ms`;\n console.log(log);\n } else {\n // Short format\n const log = `${method} ${path} ${status} ${duration}ms`;\n console.log(log);\n }\n };\n}\n","/**\n * @parsrun/server - Tracing Middleware\n * Request correlation and distributed tracing support\n */\n\nimport type { HonoContext, HonoNext, TraceContext } from \"../context.js\";\nimport { generateRequestId } from \"../context.js\";\n\n/**\n * Tracing options\n */\nexport interface TracingOptions {\n /**\n * Header name for request ID\n * @default \"x-request-id\"\n */\n headerName?: string;\n\n /**\n * Custom request ID generator\n * @default crypto.randomUUID()\n */\n generateId?: () => string;\n\n /**\n * Enable W3C Trace Context propagation\n * When enabled, parses and propagates traceparent/tracestate headers\n * @default false\n */\n propagate?: boolean;\n\n /**\n * Emit request ID in response headers\n * @default true\n */\n emitHeader?: boolean;\n\n /**\n * Trust incoming request ID from header\n * Set to false in production to always generate new IDs\n * @default true\n */\n trustIncoming?: boolean;\n}\n\n// TraceContext is imported from context.js\nexport type { TraceContext } from \"../context.js\";\n\n/**\n * Parse W3C traceparent header\n * Format: 00-{trace-id}-{parent-id}-{trace-flags}\n *\n * @see https://www.w3.org/TR/trace-context/\n */\nexport function parseTraceparent(header: string): TraceContext | null {\n // Version 00 format: 00-<trace-id>-<parent-id>-<trace-flags>\n const match = header.match(\n /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/i\n );\n\n if (!match) return null;\n\n const [, version, traceId, parentId, flags] = match;\n\n // Validate trace-id and parent-id are not all zeros\n if (traceId === \"00000000000000000000000000000000\") return null;\n if (parentId === \"0000000000000000\") return null;\n\n return {\n version: version!,\n traceId: traceId!,\n parentId: parentId!,\n traceFlags: parseInt(flags!, 16),\n };\n}\n\n/**\n * Generate a new trace ID (32 hex characters)\n */\nexport function generateTraceId(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Generate a new span ID (16 hex characters)\n */\nexport function generateSpanId(): string {\n const bytes = new Uint8Array(8);\n crypto.getRandomValues(bytes);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Create a traceparent header value\n */\nexport function createTraceparent(\n traceId: string,\n spanId: string,\n sampled: boolean = true\n): string {\n const flags = sampled ? \"01\" : \"00\";\n return `00-${traceId}-${spanId}-${flags}`;\n}\n\n/**\n * Tracing middleware\n *\n * Handles request ID generation and W3C Trace Context propagation.\n *\n * @example Basic usage\n * ```typescript\n * app.use('*', tracing());\n *\n * // Access in handlers\n * app.get('/api/test', (c) => {\n * const requestId = c.get('requestId');\n * return c.json({ requestId });\n * });\n * ```\n *\n * @example With distributed tracing\n * ```typescript\n * app.use('*', tracing({\n * propagate: true,\n * trustIncoming: true,\n * }));\n *\n * // Access trace context\n * app.get('/api/test', (c) => {\n * const trace = c.get('traceContext');\n * const spanId = c.get('spanId');\n * return c.json({ traceId: trace?.traceId, spanId });\n * });\n * ```\n *\n * @example Outgoing requests (forwarding trace context)\n * ```typescript\n * app.get('/api/proxy', async (c) => {\n * const trace = c.get('traceContext');\n * const spanId = c.get('spanId');\n * const traceState = c.get('traceState');\n *\n * const headers: Record<string, string> = {};\n *\n * if (trace) {\n * // Create new traceparent with our spanId as parent\n * headers['traceparent'] = createTraceparent(trace.traceId, spanId!, true);\n * if (traceState) {\n * headers['tracestate'] = traceState;\n * }\n * }\n *\n * const response = await fetch('https://downstream-service.com/api', { headers });\n * return c.json(await response.json());\n * });\n * ```\n */\nexport function tracing(options: TracingOptions = {}) {\n const {\n headerName = \"x-request-id\",\n generateId = generateRequestId,\n propagate = false,\n emitHeader = true,\n trustIncoming = true,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n let requestId: string;\n\n // Get or generate request ID\n if (trustIncoming) {\n requestId = c.req.header(headerName) ?? generateId();\n } else {\n requestId = generateId();\n }\n\n // Set request ID in context\n c.set(\"requestId\", requestId);\n\n // Handle W3C Trace Context propagation\n if (propagate) {\n const traceparent = c.req.header(\"traceparent\");\n const tracestate = c.req.header(\"tracestate\");\n\n // Generate a new span ID for this request\n const spanId = generateSpanId();\n c.set(\"spanId\", spanId);\n\n if (traceparent) {\n const traceContext = parseTraceparent(traceparent);\n\n if (traceContext) {\n c.set(\"traceContext\", traceContext);\n\n if (tracestate) {\n c.set(\"traceState\", tracestate);\n }\n }\n } else {\n // No incoming trace context - start a new trace\n const traceId = generateTraceId();\n c.set(\"traceContext\", {\n version: \"00\",\n traceId,\n parentId: spanId,\n traceFlags: 1, // Sampled\n });\n }\n }\n\n // Emit request ID in response header\n if (emitHeader) {\n c.header(headerName, requestId);\n }\n\n // Process request\n await next();\n };\n}\n\n/**\n * Create tracing middleware (alias)\n */\nexport const tracingMiddleware = tracing;\n","/**\n * @parsrun/server - Usage Tracking Middleware\n * Automatically track API usage per request\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\n\n/**\n * Usage service interface (from @parsrun/payments)\n * Defined here to avoid circular dependency\n */\nexport interface UsageServiceLike {\n trackUsage(options: {\n tenantId: string;\n customerId: string;\n subscriptionId?: string;\n featureKey: string;\n quantity?: number;\n metadata?: Record<string, unknown>;\n idempotencyKey?: string;\n }): Promise<unknown>;\n}\n\n/**\n * Usage tracking middleware options\n */\nexport interface UsageTrackingOptions {\n /**\n * Usage service instance\n */\n usageService: UsageServiceLike;\n\n /**\n * Feature key to track\n * Can be a static string or a function that extracts it from context\n * @default \"api_calls\"\n */\n featureKey?: string | ((c: HonoContext) => string);\n\n /**\n * Quantity to track\n * Can be a static number or a function that calculates it from context\n * @default 1\n */\n quantity?: number | ((c: HonoContext) => number);\n\n /**\n * Skip tracking for certain requests\n */\n skip?: (c: HonoContext) => boolean;\n\n /**\n * When to track: before or after the request\n * @default \"response\"\n */\n trackOn?: \"request\" | \"response\";\n\n /**\n * Only track successful responses (2xx)\n * @default true\n */\n successOnly?: boolean;\n\n /**\n * Custom customer ID extractor\n * @default Uses c.get(\"user\")?.id\n */\n getCustomerId?: (c: HonoContext) => string | undefined;\n\n /**\n * Custom tenant ID extractor\n * @default Uses c.get(\"tenant\")?.id or c.get(\"user\")?.tenantId\n */\n getTenantId?: (c: HonoContext) => string | undefined;\n\n /**\n * Custom subscription ID extractor\n */\n getSubscriptionId?: (c: HonoContext) => string | undefined;\n\n /**\n * Include request metadata\n * @default true\n */\n includeMetadata?: boolean;\n\n /**\n * Generate idempotency key to prevent duplicates\n */\n getIdempotencyKey?: (c: HonoContext) => string | undefined;\n}\n\n/**\n * Usage tracking middleware\n *\n * Automatically tracks API usage for authenticated requests.\n *\n * @example\n * ```typescript\n * import { usageTracking } from \"@parsrun/server\";\n * import { createUsageService, createMemoryUsageStorage } from \"@parsrun/payments\";\n *\n * const usageService = createUsageService({\n * storage: createMemoryUsageStorage(),\n * });\n *\n * // Track all API calls\n * app.use(\"/api/*\", usageTracking({\n * usageService,\n * featureKey: \"api_calls\",\n * }));\n *\n * // Track with custom feature key based on route\n * app.use(\"/api/ai/*\", usageTracking({\n * usageService,\n * featureKey: \"ai_requests\",\n * quantity: (c) => {\n * // Track tokens used from response\n * return c.get(\"tokensUsed\") ?? 1;\n * },\n * }));\n *\n * // Skip certain routes\n * app.use(\"/api/*\", usageTracking({\n * usageService,\n * skip: (c) => c.req.path.startsWith(\"/api/health\"),\n * }));\n * ```\n */\nexport function usageTracking(options: UsageTrackingOptions) {\n const {\n usageService,\n featureKey = \"api_calls\",\n quantity = 1,\n skip,\n trackOn = \"response\",\n successOnly = true,\n getCustomerId = (c) => c.get(\"user\")?.id,\n getTenantId = (c) => c.get(\"tenant\")?.id ?? c.get(\"user\")?.tenantId,\n getSubscriptionId,\n includeMetadata = true,\n getIdempotencyKey,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Track on request (before processing)\n if (trackOn === \"request\") {\n await trackUsage(c);\n return next();\n }\n\n // Track on response (after processing)\n await next();\n\n // Skip if configured\n if (skip?.(c)) return;\n\n // Skip failed responses if configured\n if (successOnly && c.res.status >= 400) return;\n\n await trackUsage(c);\n };\n\n async function trackUsage(c: HonoContext) {\n const customerId = getCustomerId(c);\n const tenantId = getTenantId(c);\n\n // Skip if no user or tenant\n if (!customerId || !tenantId) return;\n\n const resolvedFeatureKey =\n typeof featureKey === \"function\" ? featureKey(c) : featureKey;\n\n const resolvedQuantity =\n typeof quantity === \"function\" ? quantity(c) : quantity;\n\n const metadata = includeMetadata\n ? {\n path: c.req.path,\n method: c.req.method,\n statusCode: c.res.status,\n userAgent: c.req.header(\"user-agent\"),\n }\n : undefined;\n\n try {\n // Build track options with only defined optional properties\n const trackOptions: {\n tenantId: string;\n customerId: string;\n featureKey: string;\n quantity?: number;\n subscriptionId?: string;\n metadata?: Record<string, unknown>;\n idempotencyKey?: string;\n } = {\n tenantId,\n customerId,\n featureKey: resolvedFeatureKey,\n quantity: resolvedQuantity,\n };\n\n const subscriptionId = getSubscriptionId?.(c);\n if (subscriptionId !== undefined) {\n trackOptions.subscriptionId = subscriptionId;\n }\n\n if (metadata !== undefined) {\n trackOptions.metadata = metadata;\n }\n\n const idempotencyKey = getIdempotencyKey?.(c);\n if (idempotencyKey !== undefined) {\n trackOptions.idempotencyKey = idempotencyKey;\n }\n\n await usageService.trackUsage(trackOptions);\n } catch (error) {\n // Log but don't fail the request\n const logger = c.get(\"logger\");\n if (logger) {\n logger.error(\"Usage tracking failed\", {\n error: error instanceof Error ? error.message : String(error),\n customerId,\n featureKey: resolvedFeatureKey,\n });\n }\n }\n }\n}\n\n/**\n * Create usage tracking middleware with pre-configured options\n */\nexport function createUsageTracking(baseOptions: UsageTrackingOptions) {\n return (overrides?: Partial<UsageTrackingOptions>) => {\n return usageTracking({ ...baseOptions, ...overrides });\n };\n}\n","/**\n * @parsrun/server - Quota Enforcement Middleware\n * Enforce usage quotas before processing requests\n */\n\nimport type { HonoContext, HonoNext } from \"../context.js\";\n\n/**\n * Quota check result interface (from @parsrun/payments)\n */\nexport interface QuotaCheckResult {\n allowed: boolean;\n currentUsage: number;\n limit: number | null;\n remaining: number | null;\n wouldExceed: boolean;\n percentAfter: number | null;\n}\n\n/**\n * Quota manager interface (from @parsrun/payments)\n * Defined here to avoid circular dependency\n */\nexport interface QuotaManagerLike {\n checkQuota(\n customerId: string,\n featureKey: string,\n quantity?: number\n ): Promise<QuotaCheckResult>;\n\n enforceQuota(\n customerId: string,\n featureKey: string,\n quantity?: number\n ): Promise<void>;\n}\n\n/**\n * Quota exceeded error class\n */\nexport class QuotaExceededError extends Error {\n public readonly statusCode = 429;\n public readonly code = \"QUOTA_EXCEEDED\";\n\n constructor(\n public readonly featureKey: string,\n public readonly limit: number | null,\n public readonly currentUsage: number,\n public readonly requestedQuantity: number = 1\n ) {\n super(\n `Quota exceeded for \"${featureKey}\": ${currentUsage}/${limit ?? \"unlimited\"} used`\n );\n this.name = \"QuotaExceededError\";\n }\n}\n\n/**\n * Quota enforcement middleware options\n */\nexport interface QuotaEnforcementOptions {\n /**\n * Quota manager instance\n */\n quotaManager: QuotaManagerLike;\n\n /**\n * Feature key to check\n * Can be a static string or a function that extracts it from context\n */\n featureKey: string | ((c: HonoContext) => string);\n\n /**\n * Quantity to check (default: 1)\n */\n quantity?: number | ((c: HonoContext) => number);\n\n /**\n * Skip quota check for certain requests\n */\n skip?: (c: HonoContext) => boolean;\n\n /**\n * Custom customer ID extractor\n * @default Uses c.get(\"user\")?.id\n */\n getCustomerId?: (c: HonoContext) => string | undefined;\n\n /**\n * Include quota headers in response\n * @default true\n */\n includeHeaders?: boolean;\n\n /**\n * Custom error handler\n */\n onQuotaExceeded?: (\n c: HonoContext,\n result: QuotaCheckResult,\n featureKey: string\n ) => Response | void;\n\n /**\n * Soft limit mode - warn but don't block\n * @default false\n */\n softLimit?: boolean;\n\n /**\n * Callback when quota is close to limit (>80%)\n */\n onQuotaWarning?: (\n c: HonoContext,\n result: QuotaCheckResult,\n featureKey: string\n ) => void;\n}\n\n/**\n * Quota enforcement middleware\n *\n * Checks and enforces usage quotas before processing requests.\n *\n * @example\n * ```typescript\n * import { quotaEnforcement } from \"@parsrun/server\";\n * import { createQuotaManager, createMemoryUsageStorage } from \"@parsrun/payments\";\n *\n * const quotaManager = createQuotaManager({\n * storage: createMemoryUsageStorage(),\n * });\n *\n * // Enforce API call quota\n * app.use(\"/api/*\", quotaEnforcement({\n * quotaManager,\n * featureKey: \"api_calls\",\n * }));\n *\n * // Enforce with dynamic feature key\n * app.use(\"/api/*\", quotaEnforcement({\n * quotaManager,\n * featureKey: (c) => {\n * if (c.req.path.startsWith(\"/api/ai\")) return \"ai_requests\";\n * return \"api_calls\";\n * },\n * }));\n *\n * // Soft limit mode (warn but allow)\n * app.use(\"/api/*\", quotaEnforcement({\n * quotaManager,\n * featureKey: \"api_calls\",\n * softLimit: true,\n * onQuotaWarning: (c, result) => {\n * console.warn(\"Quota warning:\", result);\n * },\n * }));\n * ```\n */\nexport function quotaEnforcement(options: QuotaEnforcementOptions) {\n const {\n quotaManager,\n featureKey,\n quantity = 1,\n skip,\n getCustomerId = (c) => c.get(\"user\")?.id,\n includeHeaders = true,\n onQuotaExceeded,\n softLimit = false,\n onQuotaWarning,\n } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n // Skip if configured\n if (skip?.(c)) {\n return next();\n }\n\n const customerId = getCustomerId(c);\n\n // Skip if no user (unauthenticated requests)\n if (!customerId) {\n return next();\n }\n\n const resolvedFeatureKey =\n typeof featureKey === \"function\" ? featureKey(c) : featureKey;\n\n const resolvedQuantity =\n typeof quantity === \"function\" ? quantity(c) : quantity;\n\n try {\n const result = await quotaManager.checkQuota(\n customerId,\n resolvedFeatureKey,\n resolvedQuantity\n );\n\n // Set quota headers\n if (includeHeaders) {\n c.header(\"X-Quota-Limit\", String(result.limit ?? \"unlimited\"));\n c.header(\"X-Quota-Remaining\", String(result.remaining ?? \"unlimited\"));\n c.header(\"X-Quota-Used\", String(result.currentUsage));\n\n if (result.percentAfter !== null) {\n c.header(\"X-Quota-Percent\", String(result.percentAfter));\n }\n }\n\n // Check for warning threshold (>80%)\n if (\n result.percentAfter !== null &&\n result.percentAfter >= 80 &&\n onQuotaWarning\n ) {\n onQuotaWarning(c, result, resolvedFeatureKey);\n }\n\n // Check if quota exceeded\n if (!result.allowed && !softLimit) {\n // Custom error handler\n if (onQuotaExceeded) {\n const response = onQuotaExceeded(c, result, resolvedFeatureKey);\n if (response) return response;\n }\n\n // Default error response\n throw new QuotaExceededError(\n resolvedFeatureKey,\n result.limit,\n result.currentUsage,\n resolvedQuantity\n );\n }\n\n // Continue to next middleware\n await next();\n } catch (error) {\n // Re-throw quota errors\n if (error instanceof QuotaExceededError) {\n throw error;\n }\n\n // Log other errors but continue\n const logger = c.get(\"logger\");\n if (logger) {\n logger.error(\"Quota check failed\", {\n error: error instanceof Error ? error.message : String(error),\n customerId,\n featureKey: resolvedFeatureKey,\n });\n }\n\n // Continue on error (fail open)\n await next();\n }\n };\n}\n\n/**\n * Create quota enforcement middleware with pre-configured options\n */\nexport function createQuotaEnforcement(\n baseOptions: Omit<QuotaEnforcementOptions, \"featureKey\">\n) {\n return (featureKey: string | ((c: HonoContext) => string)) => {\n return quotaEnforcement({ ...baseOptions, featureKey });\n };\n}\n\n/**\n * Multiple quota enforcement\n * Check multiple features at once\n */\nexport function multiQuotaEnforcement(\n options: Omit<QuotaEnforcementOptions, \"featureKey\"> & {\n features: Array<{\n featureKey: string;\n quantity?: number | ((c: HonoContext) => number);\n }>;\n }\n) {\n const { features } = options;\n\n return async (c: HonoContext, next: HonoNext) => {\n const customerId = (options.getCustomerId ?? ((ctx) => ctx.get(\"user\")?.id))(c);\n\n if (!customerId || options.skip?.(c)) {\n return next();\n }\n\n // Check all quotas\n for (const feature of features) {\n const resolvedQuantity =\n typeof feature.quantity === \"function\"\n ? feature.quantity(c)\n : feature.quantity ?? 1;\n\n const result = await options.quotaManager.checkQuota(\n customerId,\n feature.featureKey,\n resolvedQuantity\n );\n\n if (!result.allowed && !options.softLimit) {\n if (options.onQuotaExceeded) {\n const response = options.onQuotaExceeded(c, result, feature.featureKey);\n if (response) return response;\n }\n\n throw new QuotaExceededError(\n feature.featureKey,\n result.limit,\n result.currentUsage,\n resolvedQuantity\n );\n }\n }\n\n await next();\n };\n}\n"],"mappings":";AAqPO,SAAS,MACd,MACA,SACA,SACoB;AACpB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO,EAAE,MAAM,SAAS,SAAS,WAAW,OAAU;AAAA,EACxD;AACF;AAKO,SAAS,oBAA4B;AAC1C,SAAO,OAAO,WAAW;AAC3B;;;ACzPO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC,YACkB,YACA,MAChB,SACgB,SAChB;AACA,UAAM,OAAO;AALG;AACA;AAEA;AAGhB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,aAAa;AACX,WAAO,MAAc,KAAK,MAAM,KAAK,SAAS,KAAK,OAAO;AAAA,EAC5D;AACF;AAKO,IAAM,kBAAN,cAA8B,SAAS;AAAA,EAC5C,YAAY,UAAU,eAAe,SAAmC;AACtE,UAAM,KAAK,eAAe,SAAS,OAAO;AAC1C,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,oBAAN,cAAgC,SAAS;AAAA,EAC9C,YAAY,UAAU,gBAAgB,SAAmC;AACvE,UAAM,KAAK,gBAAgB,SAAS,OAAO;AAC3C,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAC3C,YAAY,UAAU,aAAa,SAAmC;AACpE,UAAM,KAAK,aAAa,SAAS,OAAO;AACxC,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,gBAAN,cAA4B,SAAS;AAAA,EAC1C,YAAY,UAAU,aAAa,SAAmC;AACpE,UAAM,KAAK,aAAa,SAAS,OAAO;AACxC,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,gBAAN,cAA4B,SAAS;AAAA,EAC1C,YAAY,UAAU,YAAY,SAAmC;AACnE,UAAM,KAAK,YAAY,SAAS,OAAO;AACvC,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,kBAAN,cAA8B,SAAS;AAAA,EAC5C,YAAY,UAAU,qBAAqB,SAAmC;AAC5E,UAAM,KAAK,oBAAoB,SAAS,OAAO;AAC/C,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAC3C,YACE,UAAU,qBACM,YAChB;AACA,UAAM,KAAK,uBAAuB,SAAS,EAAE,WAAW,CAAC;AAFzC;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,gBAAN,cAA4B,SAAS;AAAA,EAC1C,YAAY,UAAU,yBAAyB,SAAmC;AAChF,UAAM,KAAK,kBAAkB,SAAS,OAAO;AAC7C,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,0BAAN,cAAsC,SAAS;AAAA,EACpD,YAAY,UAAU,uBAAuB,SAAmC;AAC9E,UAAM,KAAK,uBAAuB,SAAS,OAAO;AAClD,SAAK,OAAO;AAAA,EACd;AACF;AAwDO,SAAS,aAAa,UAA+B,CAAC,GAAG;AAC9D,QAAM;AAAA,IACJ,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,IACnB;AAAA,EACF,IAAI;AAEJ,SAAO,OAAO,GAAgB,SAAmB;AAC/C,QAAI;AACF,YAAM,KAAK;AAAA,IACb,SAAS,KAAK;AACZ,YAAMA,SAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAGhE,YAAM,aAAaA,kBAAiB,WAAWA,OAAM,aAAa;AAGlE,UAAI,SAAS;AACX,gBAAQA,QAAO,CAAC;AAAA,MAClB,OAAO;AACL,cAAM,SAAS,EAAE,IAAI,QAAQ;AAC7B,YAAI,QAAQ;AACV,iBAAO,MAAM,iBAAiB;AAAA,YAC5B,WAAW,EAAE,IAAI,WAAW;AAAA,YAC5B,OAAOA,OAAM;AAAA,YACb,OAAOA,OAAM;AAAA,UACf,CAAC;AAAA,QACH;AAAA,MACF;AAGA,UAAI,gBAAgB;AAClB,cAAM,qBAAqB,gBACvB,cAAcA,QAAO,UAAU,IAC/B,oBAAoB,cAAc;AAEtC,YAAI,oBAAoB;AACtB,gBAAM,OAAO,EAAE,IAAI,MAAM;AACzB,gBAAM,SAAS,EAAE,IAAI,QAAQ;AAG7B,gBAAM,eAA6B;AAAA,YACjC,WAAW,EAAE,IAAI,WAAW;AAAA,YAC5B,MAAM;AAAA,cACJ,MAAM,EAAE,IAAI;AAAA,cACZ,QAAQ,EAAE,IAAI;AAAA,cACd,YAAY,OAAO,UAAU;AAAA,YAC/B;AAAA,UACF;AAEA,cAAI,MAAM,IAAI;AACZ,yBAAa,SAAS,KAAK;AAAA,UAC7B;AACA,cAAI,QAAQ,IAAI;AACd,yBAAa,WAAW,OAAO;AAAA,UACjC;AAGA,gBAAM,QAAiC;AAAA,YACrC,OAAO,EAAE,IAAI,MAAM;AAAA,UACrB;AACA,cAAIA,kBAAiB,UAAU;AAC7B,kBAAM,WAAW,IAAIA,OAAM;AAAA,UAC7B;AACA,uBAAa,QAAQ;AAGrB,kBAAQ;AAAA,YACN,eAAe,iBAAiBA,QAAO,YAAY;AAAA,UACrD,EAAE,MAAM,MAAM;AAAA,UAEd,CAAC;AAAA,QACH;AAAA,MACF;AAGA,UAAIA,kBAAiB,UAAU;AAC7B,eAAO,EAAE,KAAKA,OAAM,WAAW,GAAGA,OAAM,UAAiB;AAAA,MAC3D;AAGA,YAAM,UAAmC,CAAC;AAE1C,UAAI,gBAAgBA,OAAM,OAAO;AAC/B,gBAAQ,OAAO,IAAIA,OAAM;AAAA,MAC3B;AAEA,aAAO,EAAE;AAAA,QACP,MAAc,kBAAkB,gCAAgC,OAAO;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAUO,SAAS,gBAAgB,GAAgB;AAC9C,SAAO,EAAE;AAAA,IACP,MAAc,aAAa,SAAS,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,IAAI,YAAY;AAAA,IAC1E;AAAA,EACF;AACF;;;AC7OA,SAAS,aACP,GACA,QACA,QACA,QACe;AAEf,QAAM,aAAa,EAAE,IAAI,OAAO,MAAM;AACtC,MAAI,YAAY;AACd,QAAI,UAAU,WAAW,WAAW,GAAG,MAAM,GAAG,GAAG;AACjD,aAAO,WAAW,MAAM,OAAO,SAAS,CAAC;AAAA,IAC3C;AACA,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ;AACV,UAAM,eAAe,EAAE,IAAI,OAAO,QAAQ;AAC1C,QAAI,cAAc;AAChB,YAAM,UAAU,aAAa,MAAM,GAAG,EAAE,IAAI,CAACC,OAAMA,GAAE,KAAK,CAAC;AAC3D,iBAAWA,MAAK,SAAS;AACvB,cAAM,CAAC,KAAK,GAAG,UAAU,IAAIA,GAAE,MAAM,GAAG;AACxC,YAAI,QAAQ,QAAQ;AAClB,iBAAO,WAAW,KAAK,GAAG;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAuBO,SAAS,KAAK,SAAgC;AACnD,QAAM;AAAA,IACJ;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA,UAAU;AAAA,EACZ,IAAI;AAEJ,SAAO,OAAO,GAAgB,SAAmB;AAE/C,QAAI,OAAO,CAAC,GAAG;AACb,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,QAAQ,aAAa,GAAG,QAAQ,QAAQ,MAAM;AAEpD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,kBAAkB,OAAO;AAAA,IACrC;AAGA,UAAM,UAAU,MAAM,OAAO,KAAK;AAElC,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,kBAAkB,0BAA0B;AAAA,IACxD;AAGA,UAAM,OAAoB;AAAA,MACxB,IAAI,QAAQ;AAAA,MACZ,OAAO,QAAQ;AAAA,MACf,UAAU,QAAQ;AAAA,MAClB,MAAM,QAAQ;AAAA,MACd,aAAa,QAAQ,eAAe,CAAC;AAAA,IACvC;AAEA,MAAE,IAAI,QAAQ,IAAI;AAElB,UAAM,KAAK;AAAA,EACb;AACF;AAkBO,SAAS,aAAa,SAAiD;AAC5E,QAAM,EAAE,QAAQ,SAAS,iBAAiB,SAAS,UAAU,QAAQ,KAAK,IAAI;AAE9E,SAAO,OAAO,GAAgB,SAAmB;AAE/C,QAAI,OAAO,CAAC,GAAG;AACb,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,QAAQ,aAAa,GAAG,QAAQ,QAAQ,MAAM;AAEpD,QAAI,OAAO;AACT,UAAI;AACF,cAAM,UAAU,MAAM,OAAO,KAAK;AAElC,YAAI,SAAS;AAEX,gBAAM,OAAoB;AAAA,YACxB,IAAI,QAAQ;AAAA,YACZ,OAAO,QAAQ;AAAA,YACf,UAAU,QAAQ;AAAA,YAClB,MAAM,QAAQ;AAAA,YACd,aAAa,QAAQ,eAAe,CAAC;AAAA,UACvC;AAEA,YAAE,IAAI,QAAQ,IAAI;AAAA,QACpB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,KAAK;AAAA,EACb;AACF;AAkBO,SAAS,qBACd,aACA;AACA,SAAO;AAAA,IACL,MAAM,CAAC,YACL,KAAK,EAAE,GAAG,aAAa,GAAG,QAAQ,CAAC;AAAA,IACrC,cAAc,CAAC,YACb,aAAa,EAAE,GAAG,aAAa,GAAG,QAAQ,CAAC;AAAA,EAC/C;AACF;;;ACtNA,IAAM,oBAAgC;AAAA,EACpC,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,SAAS,CAAC,OAAO,QAAQ,OAAO,SAAS,UAAU,SAAS;AAAA,EAC5D,gBAAgB,CAAC,gBAAgB,iBAAiB,gBAAgB,cAAc;AAAA,EAChF,gBAAgB,CAAC,gBAAgB,eAAe;AAAA,EAChD,QAAQ;AAAA;AACV;AAKA,SAAS,gBAAgB,QAAgB,QAA6B;AACpE,MAAI,OAAO,WAAW,IAAK,QAAO;AAElC,MAAI,OAAO,OAAO,WAAW,UAAU;AACrC,WAAO,WAAW,OAAO;AAAA,EAC3B;AAEA,MAAI,MAAM,QAAQ,OAAO,MAAM,GAAG;AAChC,WAAO,OAAO,OAAO,SAAS,MAAM;AAAA,EACtC;AAEA,MAAI,OAAO,OAAO,WAAW,YAAY;AACvC,WAAO,OAAO,OAAO,MAAM;AAAA,EAC7B;AAEA,SAAO;AACT;AAaO,SAAS,KAAK,QAA4F;AAC/G,QAAM,aAAa,EAAE,GAAG,mBAAmB,GAAG,OAAO;AAErD,SAAO,OAAO,GAAgB,SAA6C;AACzE,UAAM,SAAS,EAAE,IAAI,OAAO,QAAQ,KAAK;AAGzC,QAAI,EAAE,IAAI,WAAW,WAAW;AAC9B,YAAM,WAAW,IAAI,SAAS,MAAM,EAAE,QAAQ,IAAI,CAAC;AAEnD,UAAI,gBAAgB,QAAQ,UAAU,GAAG;AACvC,iBAAS,QAAQ,IAAI,+BAA+B,UAAU,GAAG;AAAA,MACnE;AAEA,UAAI,WAAW,aAAa;AAC1B,iBAAS,QAAQ,IAAI,oCAAoC,MAAM;AAAA,MACjE;AAEA,UAAI,WAAW,SAAS;AACtB,iBAAS,QAAQ;AAAA,UACf;AAAA,UACA,WAAW,QAAQ,KAAK,IAAI;AAAA,QAC9B;AAAA,MACF;AAEA,UAAI,WAAW,gBAAgB;AAC7B,iBAAS,QAAQ;AAAA,UACf;AAAA,UACA,WAAW,eAAe,KAAK,IAAI;AAAA,QACrC;AAAA,MACF;AAEA,UAAI,WAAW,QAAQ;AACrB,iBAAS,QAAQ,IAAI,0BAA0B,OAAO,WAAW,MAAM,CAAC;AAAA,MAC1E;AAEA,aAAO;AAAA,IACT;AAGA,UAAM,KAAK;AAGX,QAAI,gBAAgB,QAAQ,UAAU,GAAG;AACvC,QAAE,OAAO,+BAA+B,UAAU,GAAG;AAAA,IACvD;AAEA,QAAI,WAAW,aAAa;AAC1B,QAAE,OAAO,oCAAoC,MAAM;AAAA,IACrD;AAEA,QAAI,WAAW,gBAAgB;AAC7B,QAAE,OAAO,iCAAiC,WAAW,eAAe,KAAK,IAAI,CAAC;AAAA,IAChF;AAAA,EACF;AACF;;;ACrEA,SAAS,sBAA8B;AACrC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,SAAO,MAAM,KAAK,KAAK,EACpB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACZ;AAKA,SAAS,UAAU,GAAgB,MAAkC;AACnE,QAAM,eAAe,EAAE,IAAI,OAAO,QAAQ;AAC1C,MAAI,CAAC,aAAc,QAAO;AAE1B,QAAM,UAAU,aAAa,MAAM,GAAG,EAAE,IAAI,CAACC,OAAMA,GAAE,KAAK,CAAC;AAC3D,aAAW,UAAU,SAAS;AAC5B,UAAM,CAAC,KAAK,GAAG,UAAU,IAAI,OAAO,MAAM,GAAG;AAC7C,QAAI,QAAQ,MAAM;AAChB,aAAO,WAAW,KAAK,GAAG;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;AAuBO,SAAS,KAAK,UAAuB,CAAC,GAAG;AAC9C,QAAM;AAAA,IACJ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,UAAU,CAAC,QAAQ,OAAO,SAAS,QAAQ;AAAA,IAC3C,eAAe,CAAC;AAAA,IAChB;AAAA,IACA,gBAAgB;AAAA,IAChB,SAAS,CAAC;AAAA,EACZ,IAAI;AAEJ,QAAM,gBAAgB;AAAA,IACpB,QAAQ,OAAO,UAAU;AAAA,IACzB,UAAU,OAAO,YAAY;AAAA,IAC7B,UAAU,OAAO,YAAa;AAAA,IAC9B,MAAM,OAAO,QAAQ;AAAA,IACrB,QAAQ,OAAO,UAAU;AAAA;AAAA,EAC3B;AAEA,SAAO,OAAO,GAAgB,SAAmB;AAE/C,QAAI,OAAO,CAAC,GAAG;AACb,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,OAAO,EAAE,IAAI;AACnB,QAAI,aAAa,KAAK,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,GAAG;AAChD,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,QAAQ,UAAU,GAAG,UAAU;AAEnC,QAAI,CAAC,OAAO;AAEV,cAAQ,cAAc;AAGtB,YAAM,cAAc;AAAA,QAClB,GAAG,UAAU,IAAI,KAAK;AAAA,QACtB,QAAQ,cAAc,IAAI;AAAA,QAC1B,WAAW,cAAc,MAAM;AAAA,QAC/B,cAAc,YAAY,YAAY,cAAc,QAAQ;AAAA,QAC5D,cAAc,UAAU;AAAA,QACxB,cAAc,YAAY;AAAA,MAC5B,EACG,OAAO,OAAO,EACd,KAAK,IAAI;AAEZ,QAAE,OAAO,cAAc,WAAW;AAAA,IACpC;AAGA,IAAC,EAA0C,IAAI,aAAsB,KAAc;AAGnF,QAAI,QAAQ,SAAS,EAAE,IAAI,MAAM,GAAG;AAClC,YAAM,cAAc,EAAE,IAAI,OAAO,UAAU;AAC3C,YAAM,YAAY,MAAM,aAAa,CAAC;AAEtC,YAAM,gBAAgB,eAAe;AAErC,UAAI,CAAC,iBAAiB,kBAAkB,OAAO;AAC7C,cAAM,IAAI,eAAe,oBAAoB;AAAA,MAC/C;AAAA,IACF;AAEA,UAAM,KAAK;AAAA,EACb;AACF;AAKA,eAAe,aAAa,GAA6C;AACvE,MAAI;AACF,UAAM,cAAc,EAAE,IAAI,OAAO,cAAc,KAAK;AAEpD,QAAI,YAAY,SAAS,kBAAkB,GAAG;AAC5C,YAAM,OAAQ,MAAM,EAAE,IAAI,KAAK;AAC/B,aAAQ,KAAK,OAAO,KAAK,KAAK,WAAW,KAAK,KAAK,YAAY;AAAA,IACjE;AAEA,QAAI,YAAY,SAAS,mCAAmC,GAAG;AAC7D,YAAM,OAAO,MAAM,EAAE,IAAI,UAAU;AACnC,aAAO,KAAK,OAAO;AAAA,IACrB;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAMO,SAAS,mBAAmB,UAAuB,CAAC,GAAG;AAC5D,SAAO,KAAK;AAAA,IACV,GAAG;AAAA,IACH,QAAQ;AAAA,MACN,GAAG,QAAQ;AAAA,MACX,UAAU;AAAA;AAAA,IACZ;AAAA,EACF,CAAC;AACH;;;ACrKO,IAAM,yBAAN,MAAyD;AAAA,EACtD,QAAQ,oBAAI,IAAgD;AAAA,EAEpE,MAAM,IAAI,KAA8B;AACtC,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,QAAI,CAAC,SAAS,MAAM,UAAU,KAAK,IAAI,GAAG;AACxC,aAAO;AAAA,IACT;AACA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,MAAM,UAAU,KAAa,UAAmC;AAC9D,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAEhC,QAAI,CAAC,SAAS,MAAM,UAAU,KAAK;AAEjC,WAAK,MAAM,IAAI,KAAK,EAAE,OAAO,GAAG,SAAS,MAAM,SAAS,CAAC;AACzD,aAAO;AAAA,IACT;AAGA,UAAM;AACN,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,MAAM,MAAM,KAA4B;AACtC,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA;AAAA,EAGA,UAAgB;AACd,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,OAAO;AACrC,UAAI,MAAM,UAAU,KAAK;AACvB,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;AAyBA,IAAI,iBAA0C;AAK9C,SAAS,oBAAsC;AAC7C,MAAI,CAAC,gBAAgB;AACnB,qBAAiB,IAAI,uBAAuB;AAAA,EAC9C;AACA,SAAO;AACT;AA2BO,SAAS,UAAU,UAA4B,CAAC,GAAG;AACxD,QAAM;AAAA,IACJ,WAAW,KAAK;AAAA;AAAA,IAChB,MAAM;AAAA,IACN,eAAe;AAAA,IACf;AAAA,IACA,UAAU,kBAAkB;AAAA,IAC5B,UAAU;AAAA,IACV,UAAU;AAAA,IACV;AAAA,EACF,IAAI;AAEJ,SAAO,OAAO,GAAgB,SAAmB;AAE/C,QAAI,OAAO,CAAC,GAAG;AACb,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,MAAM,aAAa,aAAa,CAAC,CAAC;AACxC,UAAM,UAAU,MAAM,QAAQ,UAAU,KAAK,QAAQ;AAGrD,QAAI,SAAS;AACX,QAAE,OAAO,qBAAqB,OAAO,GAAG,CAAC;AACzC,QAAE,OAAO,yBAAyB,OAAO,KAAK,IAAI,GAAG,MAAM,OAAO,CAAC,CAAC;AACpE,QAAE,OAAO,qBAAqB,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,YAAY,GAAI,CAAC,CAAC;AAAA,IACjF;AAGA,QAAI,UAAU,KAAK;AACjB,UAAI,gBAAgB;AAClB,uBAAe,GAAG,GAAG;AAAA,MACvB;AAEA,YAAM,aAAa,KAAK,KAAK,WAAW,GAAI;AAC5C,QAAE,OAAO,eAAe,OAAO,UAAU,CAAC;AAE1C,YAAM,IAAI,eAAe,SAAS,UAAU;AAAA,IAC9C;AAEA,UAAM,KAAK;AAAA,EACb;AACF;AAKA,SAAS,oBAAoB,GAAwB;AACnD,SACE,EAAE,IAAI,OAAO,iBAAiB,GAAG,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,KACrD,EAAE,IAAI,OAAO,WAAW,KACxB,EAAE,IAAI,OAAO,kBAAkB,KAC/B;AAEJ;AAkBO,SAAS,kBAAkB,UAA4B,CAAC,GAAG;AAChE,QAAM,UAAU,QAAQ,WAAW,kBAAkB;AAErD,SAAO;AAAA,IACL,YAAY,UAAU,EAAE,GAAG,SAAS,QAAQ,CAAC;AAAA,IAC7C;AAAA,IACA,OAAO,CAAC,QAAgB,QAAQ,MAAM,aAAa,GAAG,EAAE;AAAA,IACxD,KAAK,CAAC,QAAgB,QAAQ,IAAI,aAAa,GAAG,EAAE;AAAA,EACtD;AACF;;;ACpLA,SAAS,YAAY,OAAuB;AAC1C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC5D,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC9C;AAaO,SAAS,cAAc,UAAgC,CAAC,GAAG;AAChE,QAAM;AAAA,IACJ;AAAA,IACA,SAAS;AAAA,IACT,cAAc;AAAA,IACd,gBAAgB;AAAA,EAClB,IAAI;AAEJ,SAAO,OAAO,GAAgB,SAAmB;AAE/C,QAAI,OAAO,CAAC,GAAG;AACb,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,SAAS,EAAE,IAAI,QAAQ;AAC7B,UAAM,YAAY,EAAE,IAAI,WAAW;AAGnC,UAAM,SAAS,EAAE,IAAI;AACrB,UAAM,OAAO,EAAE,IAAI;AACnB,UAAM,QAAQ,EAAE,IAAI,MAAM;AAC1B,UAAM,YAAY,EAAE,IAAI,OAAO,YAAY;AAC3C,UAAM,KAAK,EAAE,IAAI,OAAO,iBAAiB,KAAK,EAAE,IAAI,OAAO,WAAW,KAAK;AAG3E,QAAI,WAAW,QAAQ;AACrB,cAAQ,MAAM,mBAAmB;AAAA,QAC/B;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AAAA,QAC/C;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAGA,QAAI;AACJ,QAAI,eAAe,CAAC,QAAQ,OAAO,OAAO,EAAE,SAAS,MAAM,GAAG;AAC5D,UAAI;AACF,cAAM,cAAc,EAAE,IAAI,OAAO,cAAc,KAAK;AACpD,YAAI,YAAY,SAAS,kBAAkB,GAAG;AAC5C,gBAAM,OAAO,MAAM,EAAE,IAAI,KAAK;AAC9B,wBAAc,KAAK,SAAS,gBACxB,KAAK,UAAU,GAAG,aAAa,IAAI,QACnC;AAAA,QACN;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,UAAM,KAAK;AAGX,UAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,UAAM,SAAS,EAAE,IAAI;AAGrB,UAAM,gBAAgB,EAAE,IAAI,QAAQ,IAAI,gBAAgB;AACxD,UAAM,OAAO,gBAAgB,SAAS,eAAe,EAAE,IAAI;AAG3D,QAAI,WAAW,QAAQ;AACrB,YAAM,UAAmC;AAAA,QACvC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,GAAG,QAAQ;AAAA,QACrB,MAAM,YAAY,IAAI;AAAA,MACxB;AAEA,UAAI,aAAa;AACf,gBAAQ,aAAa,IAAI;AAAA,MAC3B;AAGA,UAAI,UAAU,KAAK;AACjB,gBAAQ,MAAM,qBAAqB,OAAO;AAAA,MAC5C,WAAW,UAAU,KAAK;AACxB,gBAAQ,KAAK,qBAAqB,OAAO;AAAA,MAC3C,OAAO;AACL,gBAAQ,KAAK,qBAAqB,OAAO;AAAA,MAC3C;AAAA,IACF,WAAW,WAAW,YAAY;AAEhC,YAAM,MAAM,GAAG,EAAE,UAAS,oBAAI,KAAK,GAAE,YAAY,CAAC,MAAM,MAAM,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,SAAS,SAAS,KAAK,QAAQ;AACxH,cAAQ,IAAI,GAAG;AAAA,IACjB,OAAO;AAEL,YAAM,MAAM,GAAG,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,QAAQ;AACnD,cAAQ,IAAI,GAAG;AAAA,IACjB;AAAA,EACF;AACF;;;ACtFO,SAAS,iBAAiB,QAAqC;AAEpE,QAAM,QAAQ,OAAO;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,CAAC,EAAE,SAAS,SAAS,UAAU,KAAK,IAAI;AAG9C,MAAI,YAAY,mCAAoC,QAAO;AAC3D,MAAI,aAAa,mBAAoB,QAAO;AAE5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,SAAS,OAAQ,EAAE;AAAA,EACjC;AACF;AAKO,SAAS,kBAA0B;AACxC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,SAAO,gBAAgB,KAAK;AAC5B,SAAO,MAAM,KAAK,KAAK,EACpB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACZ;AAKO,SAAS,iBAAyB;AACvC,QAAM,QAAQ,IAAI,WAAW,CAAC;AAC9B,SAAO,gBAAgB,KAAK;AAC5B,SAAO,MAAM,KAAK,KAAK,EACpB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACZ;AAKO,SAAS,kBACd,SACA,QACA,UAAmB,MACX;AACR,QAAM,QAAQ,UAAU,OAAO;AAC/B,SAAO,MAAM,OAAO,IAAI,MAAM,IAAI,KAAK;AACzC;AAuDO,SAAS,QAAQ,UAA0B,CAAC,GAAG;AACpD,QAAM;AAAA,IACJ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB,IAAI;AAEJ,SAAO,OAAO,GAAgB,SAAmB;AAC/C,QAAI;AAGJ,QAAI,eAAe;AACjB,kBAAY,EAAE,IAAI,OAAO,UAAU,KAAK,WAAW;AAAA,IACrD,OAAO;AACL,kBAAY,WAAW;AAAA,IACzB;AAGA,MAAE,IAAI,aAAa,SAAS;AAG5B,QAAI,WAAW;AACb,YAAM,cAAc,EAAE,IAAI,OAAO,aAAa;AAC9C,YAAM,aAAa,EAAE,IAAI,OAAO,YAAY;AAG5C,YAAM,SAAS,eAAe;AAC9B,QAAE,IAAI,UAAU,MAAM;AAEtB,UAAI,aAAa;AACf,cAAM,eAAe,iBAAiB,WAAW;AAEjD,YAAI,cAAc;AAChB,YAAE,IAAI,gBAAgB,YAAY;AAElC,cAAI,YAAY;AACd,cAAE,IAAI,cAAc,UAAU;AAAA,UAChC;AAAA,QACF;AAAA,MACF,OAAO;AAEL,cAAM,UAAU,gBAAgB;AAChC,UAAE,IAAI,gBAAgB;AAAA,UACpB,SAAS;AAAA,UACT;AAAA,UACA,UAAU;AAAA,UACV,YAAY;AAAA;AAAA,QACd,CAAC;AAAA,MACH;AAAA,IACF;AAGA,QAAI,YAAY;AACd,QAAE,OAAO,YAAY,SAAS;AAAA,IAChC;AAGA,UAAM,KAAK;AAAA,EACb;AACF;AAKO,IAAM,oBAAoB;;;ACpG1B,SAAS,cAAc,SAA+B;AAC3D,QAAM;AAAA,IACJ;AAAA,IACA,aAAa;AAAA,IACb,WAAW;AAAA,IACX;AAAA,IACA,UAAU;AAAA,IACV,cAAc;AAAA,IACd,gBAAgB,CAAC,MAAM,EAAE,IAAI,MAAM,GAAG;AAAA,IACtC,cAAc,CAAC,MAAM,EAAE,IAAI,QAAQ,GAAG,MAAM,EAAE,IAAI,MAAM,GAAG;AAAA,IAC3D;AAAA,IACA,kBAAkB;AAAA,IAClB;AAAA,EACF,IAAI;AAEJ,SAAO,OAAO,GAAgB,SAAmB;AAE/C,QAAI,YAAY,WAAW;AACzB,YAAM,WAAW,CAAC;AAClB,aAAO,KAAK;AAAA,IACd;AAGA,UAAM,KAAK;AAGX,QAAI,OAAO,CAAC,EAAG;AAGf,QAAI,eAAe,EAAE,IAAI,UAAU,IAAK;AAExC,UAAM,WAAW,CAAC;AAAA,EACpB;AAEA,iBAAe,WAAW,GAAgB;AACxC,UAAM,aAAa,cAAc,CAAC;AAClC,UAAM,WAAW,YAAY,CAAC;AAG9B,QAAI,CAAC,cAAc,CAAC,SAAU;AAE9B,UAAM,qBACJ,OAAO,eAAe,aAAa,WAAW,CAAC,IAAI;AAErD,UAAM,mBACJ,OAAO,aAAa,aAAa,SAAS,CAAC,IAAI;AAEjD,UAAM,WAAW,kBACb;AAAA,MACE,MAAM,EAAE,IAAI;AAAA,MACZ,QAAQ,EAAE,IAAI;AAAA,MACd,YAAY,EAAE,IAAI;AAAA,MAClB,WAAW,EAAE,IAAI,OAAO,YAAY;AAAA,IACtC,IACA;AAEJ,QAAI;AAEF,YAAM,eAQF;AAAA,QACF;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ,UAAU;AAAA,MACZ;AAEA,YAAM,iBAAiB,oBAAoB,CAAC;AAC5C,UAAI,mBAAmB,QAAW;AAChC,qBAAa,iBAAiB;AAAA,MAChC;AAEA,UAAI,aAAa,QAAW;AAC1B,qBAAa,WAAW;AAAA,MAC1B;AAEA,YAAM,iBAAiB,oBAAoB,CAAC;AAC5C,UAAI,mBAAmB,QAAW;AAChC,qBAAa,iBAAiB;AAAA,MAChC;AAEA,YAAM,aAAa,WAAW,YAAY;AAAA,IAC5C,SAASC,QAAO;AAEd,YAAM,SAAS,EAAE,IAAI,QAAQ;AAC7B,UAAI,QAAQ;AACV,eAAO,MAAM,yBAAyB;AAAA,UACpC,OAAOA,kBAAiB,QAAQA,OAAM,UAAU,OAAOA,MAAK;AAAA,UAC5D;AAAA,UACA,YAAY;AAAA,QACd,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,oBAAoB,aAAmC;AACrE,SAAO,CAAC,cAA8C;AACpD,WAAO,cAAc,EAAE,GAAG,aAAa,GAAG,UAAU,CAAC;AAAA,EACvD;AACF;;;ACtMO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAI5C,YACkB,YACA,OACA,cACA,oBAA4B,GAC5C;AACA;AAAA,MACE,uBAAuB,UAAU,MAAM,YAAY,IAAI,SAAS,WAAW;AAAA,IAC7E;AAPgB;AACA;AACA;AACA;AAKhB,SAAK,OAAO;AAAA,EACd;AAAA,EAbgB,aAAa;AAAA,EACb,OAAO;AAazB;AAwGO,SAAS,iBAAiB,SAAkC;AACjE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,gBAAgB,CAAC,MAAM,EAAE,IAAI,MAAM,GAAG;AAAA,IACtC,iBAAiB;AAAA,IACjB;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,EACF,IAAI;AAEJ,SAAO,OAAO,GAAgB,SAAmB;AAE/C,QAAI,OAAO,CAAC,GAAG;AACb,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,aAAa,cAAc,CAAC;AAGlC,QAAI,CAAC,YAAY;AACf,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,qBACJ,OAAO,eAAe,aAAa,WAAW,CAAC,IAAI;AAErD,UAAM,mBACJ,OAAO,aAAa,aAAa,SAAS,CAAC,IAAI;AAEjD,QAAI;AACF,YAAM,SAAS,MAAM,aAAa;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAGA,UAAI,gBAAgB;AAClB,UAAE,OAAO,iBAAiB,OAAO,OAAO,SAAS,WAAW,CAAC;AAC7D,UAAE,OAAO,qBAAqB,OAAO,OAAO,aAAa,WAAW,CAAC;AACrE,UAAE,OAAO,gBAAgB,OAAO,OAAO,YAAY,CAAC;AAEpD,YAAI,OAAO,iBAAiB,MAAM;AAChC,YAAE,OAAO,mBAAmB,OAAO,OAAO,YAAY,CAAC;AAAA,QACzD;AAAA,MACF;AAGA,UACE,OAAO,iBAAiB,QACxB,OAAO,gBAAgB,MACvB,gBACA;AACA,uBAAe,GAAG,QAAQ,kBAAkB;AAAA,MAC9C;AAGA,UAAI,CAAC,OAAO,WAAW,CAAC,WAAW;AAEjC,YAAI,iBAAiB;AACnB,gBAAM,WAAW,gBAAgB,GAAG,QAAQ,kBAAkB;AAC9D,cAAI,SAAU,QAAO;AAAA,QACvB;AAGA,cAAM,IAAI;AAAA,UACR;AAAA,UACA,OAAO;AAAA,UACP,OAAO;AAAA,UACP;AAAA,QACF;AAAA,MACF;AAGA,YAAM,KAAK;AAAA,IACb,SAASC,QAAO;AAEd,UAAIA,kBAAiB,oBAAoB;AACvC,cAAMA;AAAA,MACR;AAGA,YAAM,SAAS,EAAE,IAAI,QAAQ;AAC7B,UAAI,QAAQ;AACV,eAAO,MAAM,sBAAsB;AAAA,UACjC,OAAOA,kBAAiB,QAAQA,OAAM,UAAU,OAAOA,MAAK;AAAA,UAC5D;AAAA,UACA,YAAY;AAAA,QACd,CAAC;AAAA,MACH;AAGA,YAAM,KAAK;AAAA,IACb;AAAA,EACF;AACF;AAKO,SAAS,uBACd,aACA;AACA,SAAO,CAAC,eAAsD;AAC5D,WAAO,iBAAiB,EAAE,GAAG,aAAa,WAAW,CAAC;AAAA,EACxD;AACF;AAMO,SAAS,sBACd,SAMA;AACA,QAAM,EAAE,SAAS,IAAI;AAErB,SAAO,OAAO,GAAgB,SAAmB;AAC/C,UAAM,cAAc,QAAQ,kBAAkB,CAAC,QAAQ,IAAI,IAAI,MAAM,GAAG,KAAK,CAAC;AAE9E,QAAI,CAAC,cAAc,QAAQ,OAAO,CAAC,GAAG;AACpC,aAAO,KAAK;AAAA,IACd;AAGA,eAAW,WAAW,UAAU;AAC9B,YAAM,mBACJ,OAAO,QAAQ,aAAa,aACxB,QAAQ,SAAS,CAAC,IAClB,QAAQ,YAAY;AAE1B,YAAM,SAAS,MAAM,QAAQ,aAAa;AAAA,QACxC;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,MACF;AAEA,UAAI,CAAC,OAAO,WAAW,CAAC,QAAQ,WAAW;AACzC,YAAI,QAAQ,iBAAiB;AAC3B,gBAAM,WAAW,QAAQ,gBAAgB,GAAG,QAAQ,QAAQ,UAAU;AACtE,cAAI,SAAU,QAAO;AAAA,QACvB;AAEA,cAAM,IAAI;AAAA,UACR,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,OAAO;AAAA,UACP;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,KAAK;AAAA,EACb;AACF;","names":["error","c","c","error","error"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/module-loader.ts","../src/context.ts"],"sourcesContent":["/**\n * @parsrun/server - Module Loader\n * Dynamic module loading system for Pars server\n */\n\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { createLogger, type Logger } from \"@parsrun/core\";\nimport type {\n CorsConfig,\n DatabaseAdapter,\n HonoApp,\n ModuleManifest,\n ServerConfig,\n ServerContextVariables,\n} from \"./context.js\";\nimport { generateRequestId } from \"./context.js\";\n\n/**\n * Module Loader options\n */\nexport interface ModuleLoaderOptions {\n /** Server configuration */\n config: ServerConfig;\n /** Cookie prefix */\n cookiePrefix?: string;\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * Module Loader\n * Manages dynamic module registration and lifecycle\n *\n * @example\n * ```typescript\n * const loader = new ModuleLoader({\n * config: {\n * database: drizzleDb,\n * cors: { origin: '*' },\n * },\n * });\n *\n * await loader.initialize();\n *\n * // Register modules\n * loader.registerModule(itemsModule);\n * loader.registerModule(usersModule);\n *\n * // Enable modules\n * await loader.enableModule('items');\n * await loader.enableModule('users');\n *\n * // Get Hono app\n * export default loader.getApp();\n * ```\n */\nexport class ModuleLoader {\n private app: HonoApp;\n private db: DatabaseAdapter;\n private enabledModules: Set<string> = new Set();\n private moduleRegistry: Map<string, ModuleManifest> = new Map();\n private logger: Logger;\n private config: ServerConfig;\n private cookiePrefix: string | undefined;\n private initialized = false;\n\n constructor(options: ModuleLoaderOptions) {\n this.config = options.config;\n this.db = options.config.database;\n this.cookiePrefix = options.cookiePrefix;\n this.logger = options.logger ?? createLogger({ name: \"ModuleLoader\" });\n\n // Create Hono app with typed context\n this.app = new Hono<{ Variables: ServerContextVariables }>();\n\n this.setupMiddleware();\n this.setupCoreRoutes();\n }\n\n /**\n * Initialize the module loader\n * Checks database connection\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n this.logger.warn(\"ModuleLoader already initialized\");\n return;\n }\n\n this.logger.info(\"Initializing ModuleLoader...\");\n\n // Check database connection\n try {\n if (this.db.ping) {\n const ok = await this.db.ping();\n if (!ok) throw new Error(\"Database ping returned false\");\n } else {\n await this.db.execute(\"SELECT 1\");\n }\n this.logger.info(\"Database connection: OK\");\n } catch (error) {\n this.logger.error(\"Database connection failed\", error);\n throw new Error(\"Database connection failed\");\n }\n\n this.initialized = true;\n this.logger.info(\"ModuleLoader initialized successfully\");\n }\n\n /**\n * Setup core middleware\n */\n private setupMiddleware(): void {\n // Request ID and logging\n this.app.use(\"*\", async (c, next) => {\n const requestId = generateRequestId();\n const requestLogger = this.logger.child({ requestId });\n\n // Set context variables\n c.set(\"db\", this.db);\n c.set(\"config\", this.config);\n c.set(\"enabledModules\", this.enabledModules);\n c.set(\"logger\", requestLogger);\n c.set(\"requestId\", requestId);\n c.set(\"cookiePrefix\", this.cookiePrefix);\n c.set(\"custom\", this.config.custom ?? {});\n c.set(\"user\", undefined);\n c.set(\"tenant\", undefined);\n\n const start = Date.now();\n\n await next();\n\n const duration = Date.now() - start;\n requestLogger.debug(\"Request completed\", {\n method: c.req.method,\n path: c.req.path,\n status: c.res.status,\n durationMs: duration,\n });\n });\n\n // CORS\n if (this.config.cors) {\n this.app.use(\"*\", cors(this.normalizeCorsConfig(this.config.cors)));\n }\n }\n\n /**\n * Normalize CORS config for Hono\n */\n private normalizeCorsConfig(config: CorsConfig): Parameters<typeof cors>[0] {\n const result: Parameters<typeof cors>[0] = {\n origin: typeof config.origin === \"function\"\n ? (origin) => (config.origin as (origin: string) => boolean)(origin) ? origin : null\n : config.origin,\n };\n\n if (config.credentials !== undefined) {\n result.credentials = config.credentials;\n }\n if (config.methods !== undefined) {\n result.allowMethods = config.methods;\n }\n if (config.allowedHeaders !== undefined) {\n result.allowHeaders = config.allowedHeaders;\n }\n if (config.exposedHeaders !== undefined) {\n result.exposeHeaders = config.exposedHeaders;\n }\n if (config.maxAge !== undefined) {\n result.maxAge = config.maxAge;\n }\n\n return result;\n }\n\n /**\n * Setup core routes\n */\n private setupCoreRoutes(): void {\n const basePath = this.config.basePath ?? \"/api/v1\";\n\n // Health check\n this.app.get(\"/health\", (c) => {\n return c.json({\n status: \"ok\",\n timestamp: new Date().toISOString(),\n });\n });\n\n // Health check with details\n this.app.get(\"/health/details\", async (c) => {\n let dbStatus = \"unknown\";\n try {\n if (this.db.ping) {\n dbStatus = (await this.db.ping()) ? \"ok\" : \"error\";\n } else {\n await this.db.execute(\"SELECT 1\");\n dbStatus = \"ok\";\n }\n } catch {\n dbStatus = \"error\";\n }\n\n return c.json({\n status: dbStatus === \"ok\" ? \"ok\" : \"degraded\",\n timestamp: new Date().toISOString(),\n services: {\n database: dbStatus,\n },\n modules: {\n enabled: Array.from(this.enabledModules),\n registered: Array.from(this.moduleRegistry.keys()),\n },\n });\n });\n\n // API info\n this.app.get(basePath, (c) => {\n const endpoints: Record<string, string> = {\n health: \"/health\",\n features: `${basePath}/features`,\n };\n\n // Add module endpoints\n for (const moduleName of this.enabledModules) {\n endpoints[moduleName] = `${basePath}/${moduleName}`;\n }\n\n return c.json({\n name: \"Pars API\",\n version: \"1.0.0\",\n endpoints,\n });\n });\n\n // Feature discovery\n this.app.get(`${basePath}/features`, (c) => {\n const features = Array.from(this.enabledModules).map((name) => {\n const module = this.moduleRegistry.get(name);\n return {\n name,\n version: module?.version ?? \"1.0.0\",\n description: module?.description ?? \"\",\n permissions: module?.permissions ?? {},\n };\n });\n\n return c.json({\n enabled: Array.from(this.enabledModules),\n features,\n });\n });\n }\n\n /**\n * Register a module\n */\n registerModule(manifest: ModuleManifest): void {\n if (this.moduleRegistry.has(manifest.name)) {\n this.logger.warn(`Module already registered: ${manifest.name}`);\n return;\n }\n\n this.moduleRegistry.set(manifest.name, manifest);\n this.logger.info(`Registered module: ${manifest.name}`);\n }\n\n /**\n * Enable a registered module\n */\n async enableModule(moduleName: string): Promise<boolean> {\n const module = this.moduleRegistry.get(moduleName);\n\n if (!module) {\n this.logger.error(`Module not found: ${moduleName}`);\n return false;\n }\n\n if (this.enabledModules.has(moduleName)) {\n this.logger.warn(`Module already enabled: ${moduleName}`);\n return true;\n }\n\n // Check dependencies\n if (module.dependencies) {\n for (const dep of module.dependencies) {\n if (!this.enabledModules.has(dep)) {\n this.logger.error(\n `Module ${moduleName} requires ${dep} to be enabled first`\n );\n return false;\n }\n }\n }\n\n try {\n this.logger.info(`Enabling module: ${moduleName}`);\n\n // Run onEnable hook\n if (module.onEnable) {\n await module.onEnable();\n }\n\n // Register routes\n module.registerRoutes(this.app);\n\n // Mark as enabled\n this.enabledModules.add(moduleName);\n\n this.logger.info(`Enabled module: ${moduleName}`);\n return true;\n } catch (error) {\n this.logger.error(`Failed to enable module ${moduleName}`, error);\n return false;\n }\n }\n\n /**\n * Disable an enabled module\n */\n async disableModule(moduleName: string): Promise<boolean> {\n if (!this.enabledModules.has(moduleName)) {\n this.logger.warn(`Module not enabled: ${moduleName}`);\n return true;\n }\n\n const module = this.moduleRegistry.get(moduleName);\n if (!module) {\n this.logger.error(`Module not found: ${moduleName}`);\n return false;\n }\n\n // Check if other modules depend on this one\n for (const [name, m] of this.moduleRegistry) {\n if (this.enabledModules.has(name) && m.dependencies?.includes(moduleName)) {\n this.logger.error(\n `Cannot disable ${moduleName}: ${name} depends on it`\n );\n return false;\n }\n }\n\n try {\n // Run onDisable hook\n if (module.onDisable) {\n await module.onDisable();\n }\n\n // Note: Routes cannot be easily unregistered in Hono\n // The module will remain registered but marked as disabled\n this.enabledModules.delete(moduleName);\n\n this.logger.info(`Disabled module: ${moduleName}`);\n return true;\n } catch (error) {\n this.logger.error(`Failed to disable module ${moduleName}`, error);\n return false;\n }\n }\n\n /**\n * Get the Hono app instance\n */\n getApp(): HonoApp {\n return this.app;\n }\n\n /**\n * Get enabled modules\n */\n getEnabledModules(): string[] {\n return Array.from(this.enabledModules);\n }\n\n /**\n * Get registered modules\n */\n getRegisteredModules(): string[] {\n return Array.from(this.moduleRegistry.keys());\n }\n\n /**\n * Check if module is enabled\n */\n isModuleEnabled(moduleName: string): boolean {\n return this.enabledModules.has(moduleName);\n }\n\n /**\n * Check if module is registered\n */\n isModuleRegistered(moduleName: string): boolean {\n return this.moduleRegistry.has(moduleName);\n }\n\n /**\n * Get database adapter\n */\n getDatabase(): DatabaseAdapter {\n return this.db;\n }\n\n /**\n * Get logger\n */\n getLogger(): Logger {\n return this.logger;\n }\n}\n\n/**\n * Create a module loader\n */\nexport function createModuleLoader(options: ModuleLoaderOptions): ModuleLoader {\n return new ModuleLoader(options);\n}\n\n/**\n * Create a module manifest helper\n */\nexport function defineModule(manifest: ModuleManifest): ModuleManifest {\n return manifest;\n}\n","/**\n * @parsrun/server - Server Context\n * Type definitions for server context and configuration\n */\n\nimport type { Logger } from \"@parsrun/core\";\n\n/**\n * Database adapter interface\n * Implement this for your database (Drizzle, Prisma, etc.)\n */\nexport interface DatabaseAdapter {\n /** Execute raw SQL query */\n execute(sql: string): Promise<unknown>;\n /** Check connection */\n ping?(): Promise<boolean>;\n}\n\n/**\n * Module manifest for registering modules\n */\nexport interface ModuleManifest {\n /** Unique module name */\n name: string;\n /** Module version */\n version: string;\n /** Module description */\n description: string;\n /** Required permissions for this module */\n permissions: Record<string, string[]>;\n /** Module dependencies (other module names) */\n dependencies?: string[];\n /** Register routes for this module */\n registerRoutes: (app: HonoApp) => void;\n /** Called when module is enabled */\n onEnable?: () => Promise<void>;\n /** Called when module is disabled */\n onDisable?: () => Promise<void>;\n}\n\n/**\n * Server configuration\n */\nexport interface ServerConfig {\n /** Database adapter */\n database: DatabaseAdapter;\n /** CORS configuration */\n cors?: CorsConfig;\n /** Base path for API */\n basePath?: string;\n /** Cookie prefix for all cookies */\n cookiePrefix?: string;\n /** Logger instance */\n logger?: Logger;\n /** Custom context data */\n custom?: Record<string, unknown>;\n}\n\n/**\n * CORS configuration\n */\nexport interface CorsConfig {\n /** Allowed origins */\n origin: string | string[] | ((origin: string) => boolean);\n /** Allow credentials */\n credentials?: boolean;\n /** Allowed methods */\n methods?: string[];\n /** Allowed headers */\n allowedHeaders?: string[];\n /** Exposed headers */\n exposedHeaders?: string[];\n /** Max age in seconds */\n maxAge?: number;\n}\n\n/**\n * User information in context\n */\nexport interface ContextUser {\n id: string;\n email: string | undefined;\n tenantId: string | undefined;\n role: string | undefined;\n permissions: string[];\n}\n\n/**\n * Tenant information in context\n */\nexport interface ContextTenant {\n id: string;\n slug: string | undefined;\n name: string | undefined;\n status: string;\n}\n\n/**\n * Server context variables\n * Available in Hono context via c.get()\n */\nexport interface ServerContextVariables {\n /** Database adapter */\n db: DatabaseAdapter;\n /** Server configuration */\n config: ServerConfig;\n /** Enabled modules set */\n enabledModules: Set<string>;\n /** Current user (if authenticated) */\n user: ContextUser | undefined;\n /** Current tenant (if resolved) */\n tenant: ContextTenant | undefined;\n /** Request logger */\n logger: Logger;\n /** Request ID */\n requestId: string;\n /** Cookie prefix */\n cookiePrefix: string | undefined;\n /** Custom context data */\n custom: Record<string, unknown>;\n}\n\n/**\n * Hono app type with server context\n */\nexport type HonoApp = import(\"hono\").Hono<{ Variables: ServerContextVariables }>;\n\n/**\n * Hono context type with server context\n */\nexport type HonoContext = import(\"hono\").Context<{ Variables: ServerContextVariables }>;\n\n/**\n * Middleware next function\n */\nexport type HonoNext = () => Promise<void>;\n\n/**\n * Middleware function type\n */\nexport type Middleware = (c: HonoContext, next: HonoNext) => Promise<Response | void>;\n\n/**\n * Route handler function type\n */\nexport type RouteHandler = (c: HonoContext) => Promise<Response> | Response;\n\n/**\n * Permission check input\n */\nexport interface PermissionCheck {\n /** Resource name (e.g., \"users\", \"items\") */\n resource: string;\n /** Action name (e.g., \"read\", \"create\", \"update\", \"delete\") */\n action: string;\n /** Permission scope */\n scope?: \"tenant\" | \"global\" | \"own\";\n}\n\n/**\n * Permission definition\n */\nexport interface PermissionDefinition {\n /** Permission name (e.g., \"users:read\") */\n name: string;\n /** Resource part */\n resource: string;\n /** Action part */\n action: string;\n /** Description */\n description?: string;\n /** Scope */\n scope?: \"tenant\" | \"global\" | \"own\";\n}\n\n/**\n * Role definition\n */\nexport interface RoleDefinition {\n /** Role name */\n name: string;\n /** Display name */\n displayName?: string;\n /** Description */\n description?: string;\n /** Permissions assigned to this role */\n permissions: string[];\n /** Is this a system role */\n isSystem?: boolean;\n}\n\n/**\n * Standard API response structure\n */\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: {\n code: string;\n message: string;\n details?: Record<string, unknown> | undefined;\n };\n meta?: {\n page?: number | undefined;\n limit?: number | undefined;\n total?: number | undefined;\n requestId?: string | undefined;\n } | undefined;\n}\n\n/**\n * Create a success response\n */\nexport function success<T>(data: T, meta?: ApiResponse[\"meta\"]): ApiResponse<T> {\n return {\n success: true,\n data,\n meta: meta ?? undefined,\n };\n}\n\n/**\n * Create an error response\n */\nexport function error(\n code: string,\n message: string,\n details?: Record<string, unknown>\n): ApiResponse<never> {\n return {\n success: false,\n error: { code, message, details: details ?? undefined },\n };\n}\n\n/**\n * Generate a request ID\n */\nexport function generateRequestId(): string {\n return crypto.randomUUID();\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/module-loader.ts","../src/context.ts"],"sourcesContent":["/**\n * @parsrun/server - Module Loader\n * Dynamic module loading system for Pars server\n */\n\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { createLogger, type Logger } from \"@parsrun/core\";\nimport type {\n CorsConfig,\n DatabaseAdapter,\n HonoApp,\n ModuleManifest,\n ServerConfig,\n ServerContextVariables,\n} from \"./context.js\";\nimport { generateRequestId } from \"./context.js\";\n\n/**\n * Module Loader options\n */\nexport interface ModuleLoaderOptions {\n /** Server configuration */\n config: ServerConfig;\n /** Cookie prefix */\n cookiePrefix?: string;\n /** Logger instance */\n logger?: Logger;\n}\n\n/**\n * Module Loader\n * Manages dynamic module registration and lifecycle\n *\n * @example\n * ```typescript\n * const loader = new ModuleLoader({\n * config: {\n * database: drizzleDb,\n * cors: { origin: '*' },\n * },\n * });\n *\n * await loader.initialize();\n *\n * // Register modules\n * loader.registerModule(itemsModule);\n * loader.registerModule(usersModule);\n *\n * // Enable modules\n * await loader.enableModule('items');\n * await loader.enableModule('users');\n *\n * // Get Hono app\n * export default loader.getApp();\n * ```\n */\nexport class ModuleLoader {\n private app: HonoApp;\n private db: DatabaseAdapter;\n private enabledModules: Set<string> = new Set();\n private moduleRegistry: Map<string, ModuleManifest> = new Map();\n private logger: Logger;\n private config: ServerConfig;\n private cookiePrefix: string | undefined;\n private initialized = false;\n\n constructor(options: ModuleLoaderOptions) {\n this.config = options.config;\n this.db = options.config.database;\n this.cookiePrefix = options.cookiePrefix;\n this.logger = options.logger ?? createLogger({ name: \"ModuleLoader\" });\n\n // Create Hono app with typed context\n this.app = new Hono<{ Variables: ServerContextVariables }>();\n\n this.setupMiddleware();\n this.setupCoreRoutes();\n }\n\n /**\n * Initialize the module loader\n * Checks database connection\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n this.logger.warn(\"ModuleLoader already initialized\");\n return;\n }\n\n this.logger.info(\"Initializing ModuleLoader...\");\n\n // Check database connection\n try {\n if (this.db.ping) {\n const ok = await this.db.ping();\n if (!ok) throw new Error(\"Database ping returned false\");\n } else {\n await this.db.execute(\"SELECT 1\");\n }\n this.logger.info(\"Database connection: OK\");\n } catch (error) {\n this.logger.error(\"Database connection failed\", error);\n throw new Error(\"Database connection failed\");\n }\n\n this.initialized = true;\n this.logger.info(\"ModuleLoader initialized successfully\");\n }\n\n /**\n * Setup core middleware\n */\n private setupMiddleware(): void {\n // Request ID and logging\n this.app.use(\"*\", async (c, next) => {\n const requestId = generateRequestId();\n const requestLogger = this.logger.child({ requestId });\n\n // Set context variables\n c.set(\"db\", this.db);\n c.set(\"config\", this.config);\n c.set(\"enabledModules\", this.enabledModules);\n c.set(\"logger\", requestLogger);\n c.set(\"requestId\", requestId);\n c.set(\"cookiePrefix\", this.cookiePrefix);\n c.set(\"custom\", this.config.custom ?? {});\n c.set(\"user\", undefined);\n c.set(\"tenant\", undefined);\n\n const start = Date.now();\n\n await next();\n\n const duration = Date.now() - start;\n requestLogger.debug(\"Request completed\", {\n method: c.req.method,\n path: c.req.path,\n status: c.res.status,\n durationMs: duration,\n });\n });\n\n // CORS\n if (this.config.cors) {\n this.app.use(\"*\", cors(this.normalizeCorsConfig(this.config.cors)));\n }\n }\n\n /**\n * Normalize CORS config for Hono\n */\n private normalizeCorsConfig(config: CorsConfig): Parameters<typeof cors>[0] {\n const result: Parameters<typeof cors>[0] = {\n origin: typeof config.origin === \"function\"\n ? (origin) => (config.origin as (origin: string) => boolean)(origin) ? origin : null\n : config.origin,\n };\n\n if (config.credentials !== undefined) {\n result.credentials = config.credentials;\n }\n if (config.methods !== undefined) {\n result.allowMethods = config.methods;\n }\n if (config.allowedHeaders !== undefined) {\n result.allowHeaders = config.allowedHeaders;\n }\n if (config.exposedHeaders !== undefined) {\n result.exposeHeaders = config.exposedHeaders;\n }\n if (config.maxAge !== undefined) {\n result.maxAge = config.maxAge;\n }\n\n return result;\n }\n\n /**\n * Setup core routes\n */\n private setupCoreRoutes(): void {\n const basePath = this.config.basePath ?? \"/api/v1\";\n\n // Health check\n this.app.get(\"/health\", (c) => {\n return c.json({\n status: \"ok\",\n timestamp: new Date().toISOString(),\n });\n });\n\n // Health check with details\n this.app.get(\"/health/details\", async (c) => {\n let dbStatus = \"unknown\";\n try {\n if (this.db.ping) {\n dbStatus = (await this.db.ping()) ? \"ok\" : \"error\";\n } else {\n await this.db.execute(\"SELECT 1\");\n dbStatus = \"ok\";\n }\n } catch {\n dbStatus = \"error\";\n }\n\n return c.json({\n status: dbStatus === \"ok\" ? \"ok\" : \"degraded\",\n timestamp: new Date().toISOString(),\n services: {\n database: dbStatus,\n },\n modules: {\n enabled: Array.from(this.enabledModules),\n registered: Array.from(this.moduleRegistry.keys()),\n },\n });\n });\n\n // API info\n this.app.get(basePath, (c) => {\n const endpoints: Record<string, string> = {\n health: \"/health\",\n features: `${basePath}/features`,\n };\n\n // Add module endpoints\n for (const moduleName of this.enabledModules) {\n endpoints[moduleName] = `${basePath}/${moduleName}`;\n }\n\n return c.json({\n name: \"Pars API\",\n version: \"1.0.0\",\n endpoints,\n });\n });\n\n // Feature discovery\n this.app.get(`${basePath}/features`, (c) => {\n const features = Array.from(this.enabledModules).map((name) => {\n const module = this.moduleRegistry.get(name);\n return {\n name,\n version: module?.version ?? \"1.0.0\",\n description: module?.description ?? \"\",\n permissions: module?.permissions ?? {},\n };\n });\n\n return c.json({\n enabled: Array.from(this.enabledModules),\n features,\n });\n });\n }\n\n /**\n * Register a module\n */\n registerModule(manifest: ModuleManifest): void {\n if (this.moduleRegistry.has(manifest.name)) {\n this.logger.warn(`Module already registered: ${manifest.name}`);\n return;\n }\n\n this.moduleRegistry.set(manifest.name, manifest);\n this.logger.info(`Registered module: ${manifest.name}`);\n }\n\n /**\n * Enable a registered module\n */\n async enableModule(moduleName: string): Promise<boolean> {\n const module = this.moduleRegistry.get(moduleName);\n\n if (!module) {\n this.logger.error(`Module not found: ${moduleName}`);\n return false;\n }\n\n if (this.enabledModules.has(moduleName)) {\n this.logger.warn(`Module already enabled: ${moduleName}`);\n return true;\n }\n\n // Check dependencies\n if (module.dependencies) {\n for (const dep of module.dependencies) {\n if (!this.enabledModules.has(dep)) {\n this.logger.error(\n `Module ${moduleName} requires ${dep} to be enabled first`\n );\n return false;\n }\n }\n }\n\n try {\n this.logger.info(`Enabling module: ${moduleName}`);\n\n // Run onEnable hook\n if (module.onEnable) {\n await module.onEnable();\n }\n\n // Register routes\n module.registerRoutes(this.app);\n\n // Mark as enabled\n this.enabledModules.add(moduleName);\n\n this.logger.info(`Enabled module: ${moduleName}`);\n return true;\n } catch (error) {\n this.logger.error(`Failed to enable module ${moduleName}`, error);\n return false;\n }\n }\n\n /**\n * Disable an enabled module\n */\n async disableModule(moduleName: string): Promise<boolean> {\n if (!this.enabledModules.has(moduleName)) {\n this.logger.warn(`Module not enabled: ${moduleName}`);\n return true;\n }\n\n const module = this.moduleRegistry.get(moduleName);\n if (!module) {\n this.logger.error(`Module not found: ${moduleName}`);\n return false;\n }\n\n // Check if other modules depend on this one\n for (const [name, m] of this.moduleRegistry) {\n if (this.enabledModules.has(name) && m.dependencies?.includes(moduleName)) {\n this.logger.error(\n `Cannot disable ${moduleName}: ${name} depends on it`\n );\n return false;\n }\n }\n\n try {\n // Run onDisable hook\n if (module.onDisable) {\n await module.onDisable();\n }\n\n // Note: Routes cannot be easily unregistered in Hono\n // The module will remain registered but marked as disabled\n this.enabledModules.delete(moduleName);\n\n this.logger.info(`Disabled module: ${moduleName}`);\n return true;\n } catch (error) {\n this.logger.error(`Failed to disable module ${moduleName}`, error);\n return false;\n }\n }\n\n /**\n * Get the Hono app instance\n */\n getApp(): HonoApp {\n return this.app;\n }\n\n /**\n * Get enabled modules\n */\n getEnabledModules(): string[] {\n return Array.from(this.enabledModules);\n }\n\n /**\n * Get registered modules\n */\n getRegisteredModules(): string[] {\n return Array.from(this.moduleRegistry.keys());\n }\n\n /**\n * Check if module is enabled\n */\n isModuleEnabled(moduleName: string): boolean {\n return this.enabledModules.has(moduleName);\n }\n\n /**\n * Check if module is registered\n */\n isModuleRegistered(moduleName: string): boolean {\n return this.moduleRegistry.has(moduleName);\n }\n\n /**\n * Get database adapter\n */\n getDatabase(): DatabaseAdapter {\n return this.db;\n }\n\n /**\n * Get logger\n */\n getLogger(): Logger {\n return this.logger;\n }\n}\n\n/**\n * Create a module loader\n */\nexport function createModuleLoader(options: ModuleLoaderOptions): ModuleLoader {\n return new ModuleLoader(options);\n}\n\n/**\n * Create a module manifest helper\n */\nexport function defineModule(manifest: ModuleManifest): ModuleManifest {\n return manifest;\n}\n","/**\n * @parsrun/server - Server Context\n * Type definitions for server context and configuration\n */\n\nimport type { Logger } from \"@parsrun/core\";\n\n/**\n * Database adapter interface\n * Implement this for your database (Drizzle, Prisma, etc.)\n */\nexport interface DatabaseAdapter {\n /** Execute raw SQL query */\n execute(sql: string): Promise<unknown>;\n /** Check connection */\n ping?(): Promise<boolean>;\n}\n\n/**\n * Module manifest for registering modules\n */\nexport interface ModuleManifest {\n /** Unique module name */\n name: string;\n /** Module version */\n version: string;\n /** Module description */\n description: string;\n /** Required permissions for this module */\n permissions: Record<string, string[]>;\n /** Module dependencies (other module names) */\n dependencies?: string[];\n /** Register routes for this module */\n registerRoutes: (app: HonoApp) => void;\n /** Called when module is enabled */\n onEnable?: () => Promise<void>;\n /** Called when module is disabled */\n onDisable?: () => Promise<void>;\n}\n\n/**\n * Server configuration\n */\nexport interface ServerConfig {\n /** Database adapter */\n database: DatabaseAdapter;\n /** CORS configuration */\n cors?: CorsConfig;\n /** Base path for API */\n basePath?: string;\n /** Cookie prefix for all cookies */\n cookiePrefix?: string;\n /** Logger instance */\n logger?: Logger;\n /** Custom context data */\n custom?: Record<string, unknown>;\n}\n\n/**\n * CORS configuration\n */\nexport interface CorsConfig {\n /** Allowed origins */\n origin: string | string[] | ((origin: string) => boolean);\n /** Allow credentials */\n credentials?: boolean;\n /** Allowed methods */\n methods?: string[];\n /** Allowed headers */\n allowedHeaders?: string[];\n /** Exposed headers */\n exposedHeaders?: string[];\n /** Max age in seconds */\n maxAge?: number;\n}\n\n/**\n * User information in context\n */\nexport interface ContextUser {\n id: string;\n email: string | undefined;\n tenantId: string | undefined;\n role: string | undefined;\n permissions: string[];\n}\n\n/**\n * Tenant information in context\n */\nexport interface ContextTenant {\n id: string;\n slug: string | undefined;\n name: string | undefined;\n status: string;\n}\n\n/**\n * Server context variables\n * Available in Hono context via c.get()\n */\n/**\n * W3C Trace Context - Parsed traceparent header\n * Format: {version}-{trace-id}-{parent-id}-{trace-flags}\n */\nexport interface TraceContext {\n /** Trace version (currently \"00\") */\n version: string;\n /** 32 hex character trace ID */\n traceId: string;\n /** 16 hex character parent span ID */\n parentId: string;\n /** Trace flags (sampled, etc.) */\n traceFlags: number;\n}\n\nexport interface ServerContextVariables {\n /** Database adapter */\n db: DatabaseAdapter;\n /** Server configuration */\n config: ServerConfig;\n /** Enabled modules set */\n enabledModules: Set<string>;\n /** Current user (if authenticated) */\n user: ContextUser | undefined;\n /** Current tenant (if resolved) */\n tenant: ContextTenant | undefined;\n /** Request logger */\n logger: Logger;\n /** Request ID */\n requestId: string;\n /** Cookie prefix */\n cookiePrefix: string | undefined;\n /** Custom context data */\n custom: Record<string, unknown>;\n /** W3C trace context (if propagation is enabled) */\n traceContext?: TraceContext;\n /** Current span ID for this request */\n spanId?: string;\n /** Tracestate header value (for forwarding) */\n traceState?: string;\n}\n\n/**\n * Hono app type with server context\n */\nexport type HonoApp = import(\"hono\").Hono<{ Variables: ServerContextVariables }>;\n\n/**\n * Hono context type with server context\n */\nexport type HonoContext = import(\"hono\").Context<{ Variables: ServerContextVariables }>;\n\n/**\n * Middleware next function\n */\nexport type HonoNext = () => Promise<void>;\n\n/**\n * Middleware function type\n */\nexport type Middleware = (c: HonoContext, next: HonoNext) => Promise<Response | void>;\n\n/**\n * Route handler function type\n */\nexport type RouteHandler = (c: HonoContext) => Promise<Response> | Response;\n\n/**\n * Permission check input\n */\nexport interface PermissionCheck {\n /** Resource name (e.g., \"users\", \"items\") */\n resource: string;\n /** Action name (e.g., \"read\", \"create\", \"update\", \"delete\") */\n action: string;\n /** Permission scope */\n scope?: \"tenant\" | \"global\" | \"own\";\n}\n\n/**\n * Permission definition\n */\nexport interface PermissionDefinition {\n /** Permission name (e.g., \"users:read\") */\n name: string;\n /** Resource part */\n resource: string;\n /** Action part */\n action: string;\n /** Description */\n description?: string;\n /** Scope */\n scope?: \"tenant\" | \"global\" | \"own\";\n}\n\n/**\n * Role definition\n */\nexport interface RoleDefinition {\n /** Role name */\n name: string;\n /** Display name */\n displayName?: string;\n /** Description */\n description?: string;\n /** Permissions assigned to this role */\n permissions: string[];\n /** Is this a system role */\n isSystem?: boolean;\n}\n\n/**\n * Standard API response structure\n */\nexport interface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: {\n code: string;\n message: string;\n details?: Record<string, unknown> | undefined;\n };\n meta?: {\n page?: number | undefined;\n limit?: number | undefined;\n total?: number | undefined;\n requestId?: string | undefined;\n } | undefined;\n}\n\n/**\n * Create a success response\n */\nexport function success<T>(data: T, meta?: ApiResponse[\"meta\"]): ApiResponse<T> {\n return {\n success: true,\n data,\n meta: meta ?? undefined,\n };\n}\n\n/**\n * Create an error response\n */\nexport function error(\n code: string,\n message: string,\n details?: Record<string, unknown>\n): ApiResponse<never> {\n return {\n success: false,\n error: { code, message, details: details ?? undefined },\n };\n}\n\n/**\n * Generate a request ID\n */\nexport function generateRequestId(): string {\n return crypto.randomUUID();\n}\n"],"mappings":"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","names":[]}