express-file-cluster 0.3.0 → 0.3.1

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":["/home/runner/work/efc.js/efc.js/packages/core/dist/auth/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACF,sQAAC","file":"/home/runner/work/efc.js/efc.js/packages/core/dist/auth/index.cjs"}
1
+ {"version":3,"sources":["/home/prashant/Projects/temp-nodejs/packages/core/dist/auth/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACF,sQAAC","file":"/home/prashant/Projects/temp-nodejs/packages/core/dist/auth/index.cjs"}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-MQNVNOH5.cjs","../src/router/scan.ts"],"names":[],"mappings":"AAAA;ACAA,gEAAe;AACf,wEAAiB;AAGjB,IAAM,cAAA,EAAgB,4BAAA;AACtB,IAAM,mBAAA,EAAqB,eAAA;AAE3B,SAAS,iBAAA,CAAkB,YAAA,EAA8B;AACvD,EAAA,IAAI,EAAA,EAAI,YAAA,CAAa,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAE9C,EAAA,EAAA,EAAI,CAAA,CAAE,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAE5B,EAAA,EAAA,EAAI,CAAA,CAAE,OAAA,CAAQ,kBAAA,EAAoB,KAAK,CAAA;AACvC,EAAA,OAAO,EAAA,IAAM,GAAA,EAAK,IAAA,EAAM,CAAA,CAAE,UAAA,CAAW,GAAG,EAAA,EAAI,EAAA,EAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA;AACvD;AAEuD;AAC3B,EAAA;AACtB,EAAA;AACgD,EAAA;AACH,EAAA;AACb,IAAA;AACpC,EAAA;AACO,EAAA;AACT;AAEuE;AACpC,EAAA;AAEF,EAAA;AACoB,EAAA;AAEzB,EAAA;AACiB,IAAA;AACjB,IAAA;AACiB,MAAA;AACC,IAAA;AACG,MAAA;AAC9B,MAAA;AACwB,QAAA;AACzB,QAAA;AACoB,QAAA;AAC/B,MAAA;AACH,IAAA;AACF,EAAA;AAG8B,EAAA;AACmB,IAAA;AACA,IAAA;AACP,IAAA;AACzC,EAAA;AACH;ADTwD;AACA;AACA;AACA","file":"/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-MQNVNOH5.cjs","sourcesContent":[null,"import fs from 'node:fs';\nimport path from 'node:path';\nimport type { RouteEntry } from '../types.js';\n\nconst ROUTE_FILE_RE = /\\.(ts|js|mts|mjs|cts|cjs)$/;\nconst DYNAMIC_SEGMENT_RE = /\\[([^\\]]+)\\]/g;\n\nfunction filePathToUrlPath(relativePath: string): string {\n let p = relativePath.replace(ROUTE_FILE_RE, '');\n // index files map to parent path\n p = p.replace(/\\/index$/, '');\n // [param] → :param\n p = p.replace(DYNAMIC_SEGMENT_RE, ':$1');\n return p === '' ? '/' : p.startsWith('/') ? p : `/${p}`;\n}\n\nfunction extractParams(relativePath: string): string[] {\n const params: string[] = [];\n let match: RegExpExecArray | null;\n const re = new RegExp(DYNAMIC_SEGMENT_RE.source, 'g');\n while ((match = re.exec(relativePath)) !== null) {\n if (match[1]) params.push(match[1]);\n }\n return params;\n}\n\nexport function scanDir(dir: string, base: string = dir): RouteEntry[] {\n if (!fs.existsSync(dir)) return [];\n\n const entries: RouteEntry[] = [];\n const items = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const item of items) {\n const fullPath = path.join(dir, item.name);\n if (item.isDirectory()) {\n entries.push(...scanDir(fullPath, base));\n } else if (ROUTE_FILE_RE.test(item.name)) {\n const relative = '/' + path.relative(base, fullPath).replace(/\\\\/g, '/');\n entries.push({\n urlPath: filePathToUrlPath(relative),\n filePath: fullPath,\n params: extractParams(relative),\n });\n }\n }\n\n // Sort: static routes before dynamic ones at each segment level\n return entries.sort((a, b) => {\n const aDynamic = a.urlPath.includes(':') ? 1 : 0;\n const bDynamic = b.urlPath.includes(':') ? 1 : 0;\n return aDynamic - bDynamic || a.urlPath.localeCompare(b.urlPath);\n });\n}\n\nexport { filePathToUrlPath };\n"]}
1
+ {"version":3,"sources":["/home/prashant/Projects/temp-nodejs/packages/core/dist/chunk-MQNVNOH5.cjs","../src/router/scan.ts"],"names":[],"mappings":"AAAA;ACAA,gEAAe;AACf,wEAAiB;AAGjB,IAAM,cAAA,EAAgB,4BAAA;AACtB,IAAM,mBAAA,EAAqB,eAAA;AAE3B,SAAS,iBAAA,CAAkB,YAAA,EAA8B;AACvD,EAAA,IAAI,EAAA,EAAI,YAAA,CAAa,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAE9C,EAAA,EAAA,EAAI,CAAA,CAAE,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AAE5B,EAAA,EAAA,EAAI,CAAA,CAAE,OAAA,CAAQ,kBAAA,EAAoB,KAAK,CAAA;AACvC,EAAA,OAAO,EAAA,IAAM,GAAA,EAAK,IAAA,EAAM,CAAA,CAAE,UAAA,CAAW,GAAG,EAAA,EAAI,EAAA,EAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA;AACvD;AAEuD;AAC3B,EAAA;AACtB,EAAA;AACgD,EAAA;AACH,EAAA;AACb,IAAA;AACpC,EAAA;AACO,EAAA;AACT;AAEuE;AACpC,EAAA;AAEF,EAAA;AACoB,EAAA;AAEzB,EAAA;AACiB,IAAA;AACjB,IAAA;AACiB,MAAA;AACC,IAAA;AACG,MAAA;AAC9B,MAAA;AACwB,QAAA;AACzB,QAAA;AACoB,QAAA;AAC/B,MAAA;AACH,IAAA;AACF,EAAA;AAG8B,EAAA;AACmB,IAAA;AACA,IAAA;AACP,IAAA;AACzC,EAAA;AACH;ADTwD;AACA;AACA;AACA","file":"/home/prashant/Projects/temp-nodejs/packages/core/dist/chunk-MQNVNOH5.cjs","sourcesContent":[null,"import fs from 'node:fs';\nimport path from 'node:path';\nimport type { RouteEntry } from '../types.js';\n\nconst ROUTE_FILE_RE = /\\.(ts|js|mts|mjs|cts|cjs)$/;\nconst DYNAMIC_SEGMENT_RE = /\\[([^\\]]+)\\]/g;\n\nfunction filePathToUrlPath(relativePath: string): string {\n let p = relativePath.replace(ROUTE_FILE_RE, '');\n // index files map to parent path\n p = p.replace(/\\/index$/, '');\n // [param] → :param\n p = p.replace(DYNAMIC_SEGMENT_RE, ':$1');\n return p === '' ? '/' : p.startsWith('/') ? p : `/${p}`;\n}\n\nfunction extractParams(relativePath: string): string[] {\n const params: string[] = [];\n let match: RegExpExecArray | null;\n const re = new RegExp(DYNAMIC_SEGMENT_RE.source, 'g');\n while ((match = re.exec(relativePath)) !== null) {\n if (match[1]) params.push(match[1]);\n }\n return params;\n}\n\nexport function scanDir(dir: string, base: string = dir): RouteEntry[] {\n if (!fs.existsSync(dir)) return [];\n\n const entries: RouteEntry[] = [];\n const items = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const item of items) {\n const fullPath = path.join(dir, item.name);\n if (item.isDirectory()) {\n entries.push(...scanDir(fullPath, base));\n } else if (ROUTE_FILE_RE.test(item.name)) {\n const relative = '/' + path.relative(base, fullPath).replace(/\\\\/g, '/');\n entries.push({\n urlPath: filePathToUrlPath(relative),\n filePath: fullPath,\n params: extractParams(relative),\n });\n }\n }\n\n // Sort: static routes before dynamic ones at each segment level\n return entries.sort((a, b) => {\n const aDynamic = a.urlPath.includes(':') ? 1 : 0;\n const bDynamic = b.urlPath.includes(':') ? 1 : 0;\n return aDynamic - bDynamic || a.urlPath.localeCompare(b.urlPath);\n });\n}\n\nexport { filePathToUrlPath };\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-QOKLEPTX.cjs","../src/auth/index.ts"],"names":["req","res","next"],"mappings":"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","file":"/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-QOKLEPTX.cjs","sourcesContent":[null,"import type { NextFunction, Request, RequestHandler, Response } from 'express';\nimport { SignJWT, jwtVerify } from 'jose';\nimport type { AuthStrategy } from '../types.js';\n\ninterface AuthConfig {\n secret: string;\n strategy: AuthStrategy;\n expiresIn: string;\n cookieDomain?: string | undefined;\n}\n\nlet _config: AuthConfig | null = null;\n\nexport function configureAuth(config: AuthConfig): void {\n _config = config;\n}\n\nfunction getConfig(): AuthConfig {\n if (!_config) throw new Error('[EFC] Auth not configured — pass jwtSecret to ignite()');\n return _config;\n}\n\nexport async function issueToken(res: Response, payload: Record<string, unknown>): Promise<void> {\n const { secret, expiresIn, cookieDomain } = getConfig();\n const encodedSecret = new TextEncoder().encode(secret);\n const token = await new SignJWT(payload)\n .setProtectedHeader({ alg: 'HS256' })\n .setExpirationTime(expiresIn)\n .sign(encodedSecret);\n\n res.cookie('efc_token', token, {\n httpOnly: true,\n secure: process.env['NODE_ENV'] === 'production',\n sameSite: 'strict',\n ...(cookieDomain !== undefined && { domain: cookieDomain }),\n });\n}\n\nexport function revokeToken(res: Response): void {\n res.clearCookie('efc_token');\n}\n\nexport async function signToken(payload: Record<string, unknown>): Promise<string> {\n const { secret, expiresIn } = getConfig();\n const encodedSecret = new TextEncoder().encode(secret);\n return await new SignJWT(payload)\n .setProtectedHeader({ alg: 'HS256' })\n .setExpirationTime(expiresIn)\n .sign(encodedSecret);\n}\n\nasync function authenticate(\n req: Request,\n res: Response,\n next: NextFunction,\n roles: string[],\n): Promise<void> {\n const { secret, strategy } = getConfig();\n\n try {\n let token: string | undefined;\n\n if (strategy === 'http-only') {\n const cookies = (req as typeof req & { cookies: Record<string, string> }).cookies;\n token = cookies?.['efc_token'];\n } else {\n const auth = req.headers['authorization'];\n if (typeof auth === 'string' && auth.startsWith('Bearer ')) {\n token = auth.slice(7);\n }\n }\n\n if (!token) {\n res.status(401).json({ error: 'Unauthorized' });\n return;\n }\n\n const encodedSecret = new TextEncoder().encode(secret);\n const { payload } = await jwtVerify(token, encodedSecret);\n\n if (roles.length > 0) {\n const role = (payload as Record<string, unknown>)['role'];\n if (typeof role !== 'string' || !roles.includes(role)) {\n res.status(403).json({ error: 'Forbidden' });\n return;\n }\n }\n\n (req as typeof req & { user: unknown }).user = payload;\n next();\n } catch {\n res.status(401).json({ error: 'Unauthorized' });\n }\n}\n\n/**\n * Used bare (`middlewares = [requireAuth]`) it just verifies the JWT.\n * Called with role names (`middlewares = [requireAuth('admin')]`) it\n * returns a middleware that also enforces `payload.role` is one of them.\n */\nexport interface RequireAuth {\n (req: Request, res: Response, next: NextFunction): void;\n (...roles: string[]): RequestHandler;\n}\n\nexport const requireAuth: RequireAuth = ((...args: unknown[]) => {\n if (args.length > 0 && typeof args[0] === 'string') {\n const roles = args as string[];\n return (req: Request, res: Response, next: NextFunction) => {\n void authenticate(req, res, next, roles);\n };\n }\n const [req, res, next] = args as [Request, Response, NextFunction];\n void authenticate(req, res, next, []);\n}) as RequireAuth;\n"]}
1
+ {"version":3,"sources":["/home/prashant/Projects/temp-nodejs/packages/core/dist/chunk-QOKLEPTX.cjs","../src/auth/index.ts"],"names":["req","res","next"],"mappings":"AAAA;ACCA,4BAAmC;AAUnC,IAAI,QAAA,EAA6B,IAAA;AAE1B,SAAS,aAAA,CAAc,MAAA,EAA0B;AACtD,EAAA,QAAA,EAAU,MAAA;AACZ;AAEA,SAAS,SAAA,CAAA,EAAwB;AAC/B,EAAA,GAAA,CAAI,CAAC,OAAA,EAAS,MAAM,IAAI,KAAA,CAAM,6DAAwD,CAAA;AACtF,EAAA,OAAO,OAAA;AACT;AAEA,MAAA,SAAsB,UAAA,CAAW,GAAA,EAAe,OAAA,EAAiD;AAC/F,EAAA,MAAM,EAAE,MAAA,EAAQ,SAAA,EAAW,aAAa,EAAA,EAAI,SAAA,CAAU,CAAA;AACtD,EAAA,MAAM,cAAA,EAAgB,IAAI,WAAA,CAAY,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA;AACrD,EAAA,MAAM,MAAA,EAAQ,MAAM,IAAI,kBAAA,CAAQ,OAAO,CAAA,CACpC,kBAAA,CAAmB,EAAE,GAAA,EAAK,QAAQ,CAAC,CAAA,CACnC,iBAAA,CAAkB,SAAS,CAAA,CAC3B,IAAA,CAAK,aAAa,CAAA;AAErB,EAAA,GAAA,CAAI,MAAA,CAAO,WAAA,EAAa,KAAA,EAAO;AAAA,IAC7B,QAAA,EAAU,IAAA;AAAA,IACV,MAAA,EAAQ,OAAA,CAAQ,GAAA,CAAI,UAAU,EAAA,IAAM,YAAA;AAAA,IACpC,QAAA,EAAU,QAAA;AAAA,IACV,GAAI,aAAA,IAAiB,KAAA,EAAA,GAAa,EAAE,MAAA,EAAQ,aAAa;AAAA,EAC3D,CAAC,CAAA;AACH;AAEO,SAAS,WAAA,CAAY,GAAA,EAAqB;AAC/C,EAAA,GAAA,CAAI,WAAA,CAAY,WAAW,CAAA;AAC7B;AAEA,MAAA,SAAsB,SAAA,CAAU,OAAA,EAAmD;AACjF,EAAA,MAAM,EAAE,MAAA,EAAQ,UAAU,EAAA,EAAI,SAAA,CAAU,CAAA;AACxC,EAAA,MAAM,cAAA,EAAgB,IAAI,WAAA,CAAY,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA;AACrD,EAAA,OAAO,MAAM,IAAI,kBAAA,CAAQ,OAAO,CAAA,CAC7B,kBAAA,CAAmB,EAAE,GAAA,EAAK,QAAQ,CAAC,CAAA,CACnC,iBAAA,CAAkB,SAAS,CAAA,CAC3B,IAAA,CAAK,aAAa,CAAA;AACvB;AAEA,MAAA,SAAe,YAAA,CACb,GAAA,EACA,GAAA,EACA,IAAA,EACA,KAAA,EACe;AACf,EAAA,MAAM,EAAE,MAAA,EAAQ,SAAS,EAAA,EAAI,SAAA,CAAU,CAAA;AAEvC,EAAA,IAAI;AACF,IAAA,IAAI,KAAA;AAEJ,IAAA,GAAA,CAAI,SAAA,IAAa,WAAA,EAAa;AAC5B,MAAA,MAAM,QAAA,EAAW,GAAA,CAAyD,OAAA;AAC1E,MAAA,MAAA,kBAAQ,OAAA,0BAAA,CAAU,WAAW,GAAA;AAAA,IAC/B,EAAA,KAAO;AACL,MAAA,MAAM,KAAA,EAAO,GAAA,CAAI,OAAA,CAAQ,eAAe,CAAA;AACxC,MAAA,GAAA,CAAI,OAAO,KAAA,IAAS,SAAA,GAAY,IAAA,CAAK,UAAA,CAAW,SAAS,CAAA,EAAG;AAC1D,QAAA,MAAA,EAAQ,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AAAA,MACtB;AAAA,IACF;AAEA,IAAA,GAAA,CAAI,CAAC,KAAA,EAAO;AACV,MAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,eAAe,CAAC,CAAA;AAC9C,MAAA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,cAAA,EAAgB,IAAI,WAAA,CAAY,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA;AACrD,IAAA,MAAM,EAAE,QAAQ,EAAA,EAAI,MAAM,6BAAA,KAAU,EAAO,aAAa,CAAA;AAExD,IAAA,GAAA,CAAI,KAAA,CAAM,OAAA,EAAS,CAAA,EAAG;AACpB,MAAA,MAAM,KAAA,EAAQ,OAAA,CAAoC,MAAM,CAAA;AACxD,MAAA,GAAA,CAAI,OAAO,KAAA,IAAS,SAAA,GAAY,CAAC,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA,EAAG;AACrD,QAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,YAAY,CAAC,CAAA;AAC3C,QAAA,MAAA;AAAA,MACF;AAAA,IACF;AAEA,IAAC,GAAA,CAAuC,KAAA,EAAO,OAAA;AAC/C,IAAA,IAAA,CAAK,CAAA;AAAA,EACP,EAAA,UAAQ;AACN,IAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,KAAA,EAAO,eAAe,CAAC,CAAA;AAAA,EAChD;AACF;AAYO,IAAM,YAAA,EAAA,CAA4B,CAAA,GAAI,IAAA,EAAA,GAAoB;AAC/D,EAAA,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,EAAA,GAAK,OAAO,IAAA,CAAK,CAAC,EAAA,IAAM,QAAA,EAAU;AAClD,IAAA,MAAM,MAAA,EAAQ,IAAA;AACd,IAAA,OAAO,CAACA,IAAAA,EAAcC,IAAAA,EAAeC,KAAAA,EAAAA,GAAuB;AAC1D,MAAA,KAAK,YAAA,CAAaF,IAAAA,EAAKC,IAAAA,EAAKC,KAAAA,EAAM,KAAK,CAAA;AAAA,IACzC,CAAA;AAAA,EACF;AACA,EAAA,MAAM,CAAC,GAAA,EAAK,GAAA,EAAK,IAAI,EAAA,EAAI,IAAA;AACzB,EAAA,KAAK,YAAA,CAAa,GAAA,EAAK,GAAA,EAAK,IAAA,EAAM,CAAC,CAAC,CAAA;AACtC,CAAA,CAAA;AD3CA;AACA;AACE;AACA;AACA;AACA;AACA;AACF,4KAAC","file":"/home/prashant/Projects/temp-nodejs/packages/core/dist/chunk-QOKLEPTX.cjs","sourcesContent":[null,"import type { NextFunction, Request, RequestHandler, Response } from 'express';\nimport { SignJWT, jwtVerify } from 'jose';\nimport type { AuthStrategy } from '../types.js';\n\ninterface AuthConfig {\n secret: string;\n strategy: AuthStrategy;\n expiresIn: string;\n cookieDomain?: string | undefined;\n}\n\nlet _config: AuthConfig | null = null;\n\nexport function configureAuth(config: AuthConfig): void {\n _config = config;\n}\n\nfunction getConfig(): AuthConfig {\n if (!_config) throw new Error('[EFC] Auth not configured — pass jwtSecret to ignite()');\n return _config;\n}\n\nexport async function issueToken(res: Response, payload: Record<string, unknown>): Promise<void> {\n const { secret, expiresIn, cookieDomain } = getConfig();\n const encodedSecret = new TextEncoder().encode(secret);\n const token = await new SignJWT(payload)\n .setProtectedHeader({ alg: 'HS256' })\n .setExpirationTime(expiresIn)\n .sign(encodedSecret);\n\n res.cookie('efc_token', token, {\n httpOnly: true,\n secure: process.env['NODE_ENV'] === 'production',\n sameSite: 'strict',\n ...(cookieDomain !== undefined && { domain: cookieDomain }),\n });\n}\n\nexport function revokeToken(res: Response): void {\n res.clearCookie('efc_token');\n}\n\nexport async function signToken(payload: Record<string, unknown>): Promise<string> {\n const { secret, expiresIn } = getConfig();\n const encodedSecret = new TextEncoder().encode(secret);\n return await new SignJWT(payload)\n .setProtectedHeader({ alg: 'HS256' })\n .setExpirationTime(expiresIn)\n .sign(encodedSecret);\n}\n\nasync function authenticate(\n req: Request,\n res: Response,\n next: NextFunction,\n roles: string[],\n): Promise<void> {\n const { secret, strategy } = getConfig();\n\n try {\n let token: string | undefined;\n\n if (strategy === 'http-only') {\n const cookies = (req as typeof req & { cookies: Record<string, string> }).cookies;\n token = cookies?.['efc_token'];\n } else {\n const auth = req.headers['authorization'];\n if (typeof auth === 'string' && auth.startsWith('Bearer ')) {\n token = auth.slice(7);\n }\n }\n\n if (!token) {\n res.status(401).json({ error: 'Unauthorized' });\n return;\n }\n\n const encodedSecret = new TextEncoder().encode(secret);\n const { payload } = await jwtVerify(token, encodedSecret);\n\n if (roles.length > 0) {\n const role = (payload as Record<string, unknown>)['role'];\n if (typeof role !== 'string' || !roles.includes(role)) {\n res.status(403).json({ error: 'Forbidden' });\n return;\n }\n }\n\n (req as typeof req & { user: unknown }).user = payload;\n next();\n } catch {\n res.status(401).json({ error: 'Unauthorized' });\n }\n}\n\n/**\n * Used bare (`middlewares = [requireAuth]`) it just verifies the JWT.\n * Called with role names (`middlewares = [requireAuth('admin')]`) it\n * returns a middleware that also enforces `payload.role` is one of them.\n */\nexport interface RequireAuth {\n (req: Request, res: Response, next: NextFunction): void;\n (...roles: string[]): RequestHandler;\n}\n\nexport const requireAuth: RequireAuth = ((...args: unknown[]) => {\n if (args.length > 0 && typeof args[0] === 'string') {\n const roles = args as string[];\n return (req: Request, res: Response, next: NextFunction) => {\n void authenticate(req, res, next, roles);\n };\n }\n const [req, res, next] = args as [Request, Response, NextFunction];\n void authenticate(req, res, next, []);\n}) as RequireAuth;\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-XH7O25BL.cjs","../src/tasks/index.ts"],"names":[],"mappings":"AAAA;ACEO,IAAM,aAAA,kBAAe,IAAI,GAAA,CAA4B,CAAA;AAQrD,IAAM,WAAA,EAAiC,CAC5C,gBAAA,EACA,YAAA,EAAA,GACsB;AACtB,EAAA,IAAI,QAAA,EAAuB,CAAC,CAAA;AAC5B,EAAA,IAAI,OAAA;AAEJ,EAAA,GAAA,CAAI,OAAO,iBAAA,IAAqB,UAAA,EAAY;AAC1C,IAAA,QAAA,EAAU,gBAAA;AAAA,EACZ,EAAA,KAAO;AACL,IAAA,QAAA,EAAU,gBAAA;AACV,IAAA,GAAA,CAAI,CAAC,YAAA,EAAc,MAAM,IAAI,KAAA,CAAM,gDAAgD,CAAA;AACnF,IAAA,QAAA,EAAU,YAAA;AAAA,EACZ;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA;AAAA,IACA,IAAA,EAAM;AAAA,EACR,CAAA;AACF,CAAA;AAGA,IAAI,MAAA,EAA4B,IAAA;AAEzB,SAAS,cAAA,CAAe,IAAA,EAAyB;AACtD,EAAA,MAAA,EAAQ,IAAA;AACV;AAEA,MAAA,SAAsB,OAAA,CAAW,IAAA,EAAc,OAAA,EAA2B;AACxE,EAAA,GAAA,CAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uEAAA,CAAyE,CAAA;AAAA,EAC3F;AACA,EAAA,OAAO,KAAA,CAAM,IAAA,EAAM,OAAkB,CAAA;AACvC;AAEO,SAAS,YAAA,CAAa,IAAA,EAAc,GAAA,EAA2B;AACpE,EAAA,YAAA,CAAa,GAAA,CAAI,IAAA,EAAM,EAAE,GAAG,GAAA,EAAK,KAAK,CAAC,CAAA;AACzC;ADjBA;AACA;AACE;AACA;AACA;AACA;AACA;AACF,8KAAC","file":"/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-XH7O25BL.cjs","sourcesContent":[null,"import type { TaskDefinition, TaskOptions } from '../types.js';\n\nexport const taskRegistry = new Map<string, TaskDefinition>();\n\ntype HandlerFn<T> = (payload: T) => Promise<void>;\ntype DefineTaskOverload = {\n <T>(handler: HandlerFn<T>): TaskDefinition<T>;\n <T>(options: TaskOptions, handler: HandlerFn<T>): TaskDefinition<T>;\n};\n\nexport const defineTask: DefineTaskOverload = <T>(\n handlerOrOptions: HandlerFn<T> | TaskOptions,\n maybeHandler?: HandlerFn<T>,\n): TaskDefinition<T> => {\n let options: TaskOptions = {};\n let handler: HandlerFn<T>;\n\n if (typeof handlerOrOptions === 'function') {\n handler = handlerOrOptions;\n } else {\n options = handlerOrOptions;\n if (!maybeHandler) throw new Error('[EFC] defineTask: handler function is required');\n handler = maybeHandler;\n }\n\n return {\n handler: handler as (payload: unknown) => Promise<void>,\n options,\n name: '',\n };\n};\n\ntype EnqueueImpl = (name: string, payload: unknown) => Promise<void>;\nlet _impl: EnqueueImpl | null = null;\n\nexport function setEnqueueImpl(impl: EnqueueImpl): void {\n _impl = impl;\n}\n\nexport async function enqueue<T>(name: string, payload: T): Promise<void> {\n if (!_impl) {\n throw new Error(`[EFC] Task queue not initialised. Set tasks.backend in ignite() config.`);\n }\n return _impl(name, payload as unknown);\n}\n\nexport function registerTask(name: string, def: TaskDefinition): void {\n taskRegistry.set(name, { ...def, name });\n}\n"]}
1
+ {"version":3,"sources":["/home/prashant/Projects/temp-nodejs/packages/core/dist/chunk-XH7O25BL.cjs","../src/tasks/index.ts"],"names":[],"mappings":"AAAA;ACEO,IAAM,aAAA,kBAAe,IAAI,GAAA,CAA4B,CAAA;AAQrD,IAAM,WAAA,EAAiC,CAC5C,gBAAA,EACA,YAAA,EAAA,GACsB;AACtB,EAAA,IAAI,QAAA,EAAuB,CAAC,CAAA;AAC5B,EAAA,IAAI,OAAA;AAEJ,EAAA,GAAA,CAAI,OAAO,iBAAA,IAAqB,UAAA,EAAY;AAC1C,IAAA,QAAA,EAAU,gBAAA;AAAA,EACZ,EAAA,KAAO;AACL,IAAA,QAAA,EAAU,gBAAA;AACV,IAAA,GAAA,CAAI,CAAC,YAAA,EAAc,MAAM,IAAI,KAAA,CAAM,gDAAgD,CAAA;AACnF,IAAA,QAAA,EAAU,YAAA;AAAA,EACZ;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA;AAAA,IACA,IAAA,EAAM;AAAA,EACR,CAAA;AACF,CAAA;AAGA,IAAI,MAAA,EAA4B,IAAA;AAEzB,SAAS,cAAA,CAAe,IAAA,EAAyB;AACtD,EAAA,MAAA,EAAQ,IAAA;AACV;AAEA,MAAA,SAAsB,OAAA,CAAW,IAAA,EAAc,OAAA,EAA2B;AACxE,EAAA,GAAA,CAAI,CAAC,KAAA,EAAO;AACV,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uEAAA,CAAyE,CAAA;AAAA,EAC3F;AACA,EAAA,OAAO,KAAA,CAAM,IAAA,EAAM,OAAkB,CAAA;AACvC;AAEO,SAAS,YAAA,CAAa,IAAA,EAAc,GAAA,EAA2B;AACpE,EAAA,YAAA,CAAa,GAAA,CAAI,IAAA,EAAM,EAAE,GAAG,GAAA,EAAK,KAAK,CAAC,CAAA;AACzC;ADjBA;AACA;AACE;AACA;AACA;AACA;AACA;AACF,8KAAC","file":"/home/prashant/Projects/temp-nodejs/packages/core/dist/chunk-XH7O25BL.cjs","sourcesContent":[null,"import type { TaskDefinition, TaskOptions } from '../types.js';\n\nexport const taskRegistry = new Map<string, TaskDefinition>();\n\ntype HandlerFn<T> = (payload: T) => Promise<void>;\ntype DefineTaskOverload = {\n <T>(handler: HandlerFn<T>): TaskDefinition<T>;\n <T>(options: TaskOptions, handler: HandlerFn<T>): TaskDefinition<T>;\n};\n\nexport const defineTask: DefineTaskOverload = <T>(\n handlerOrOptions: HandlerFn<T> | TaskOptions,\n maybeHandler?: HandlerFn<T>,\n): TaskDefinition<T> => {\n let options: TaskOptions = {};\n let handler: HandlerFn<T>;\n\n if (typeof handlerOrOptions === 'function') {\n handler = handlerOrOptions;\n } else {\n options = handlerOrOptions;\n if (!maybeHandler) throw new Error('[EFC] defineTask: handler function is required');\n handler = maybeHandler;\n }\n\n return {\n handler: handler as (payload: unknown) => Promise<void>,\n options,\n name: '',\n };\n};\n\ntype EnqueueImpl = (name: string, payload: unknown) => Promise<void>;\nlet _impl: EnqueueImpl | null = null;\n\nexport function setEnqueueImpl(impl: EnqueueImpl): void {\n _impl = impl;\n}\n\nexport async function enqueue<T>(name: string, payload: T): Promise<void> {\n if (!_impl) {\n throw new Error(`[EFC] Task queue not initialised. Set tasks.backend in ignite() config.`);\n }\n return _impl(name, payload as unknown);\n}\n\nexport function registerTask(name: string, def: TaskDefinition): void {\n taskRegistry.set(name, { ...def, name });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/efc.js/efc.js/packages/core/dist/cli/index.cjs","../../src/cli/index.ts","../../src/cli/commands/start.ts","../../src/cli/commands/build.ts","../../src/cli/commands/run.ts","../../src/cli/commands/generate.ts","../../src/cli/commands/diagnostics.ts"],"names":["path","pc"],"mappings":"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","file":"/home/runner/work/efc.js/efc.js/packages/core/dist/cli/index.cjs","sourcesContent":[null,"#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { startCommand } from './commands/start.js';\nimport { buildCommand } from './commands/build.js';\nimport { runCommand } from './commands/run.js';\nimport { generateCommand } from './commands/generate.js';\nimport { diagnosticsCommands } from './commands/diagnostics.js';\n\nconst program = new Command('efc').description('Express File Cluster CLI').version('0.1.0');\n\nprogram.addCommand(startCommand());\nprogram.addCommand(buildCommand());\nprogram.addCommand(runCommand());\nprogram.addCommand(generateCommand());\n\nfor (const cmd of diagnosticsCommands()) {\n program.addCommand(cmd);\n}\n\nprogram.parse(process.argv);\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport pc from 'picocolors';\n\nexport function startCommand(): Command {\n const cmd = new Command('start');\n\n cmd\n .argument('<mode>', 'dev | prod')\n .description('Start the EFC server')\n .action((mode: string) => {\n if (mode === 'dev') {\n startDev();\n } else if (mode === 'prod') {\n startProd();\n } else {\n console.error(pc.red(`Unknown mode: ${mode}. Use 'dev' or 'prod'.`));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nfunction parseDotenv(cwd: string): Record<string, string> {\n const envFile = path.join(cwd, '.env');\n if (!fs.existsSync(envFile)) return {};\n const vars: Record<string, string> = {};\n for (const line of fs.readFileSync(envFile, 'utf8').split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eq = trimmed.indexOf('=');\n if (eq === -1) continue;\n const key = trimmed.slice(0, eq).trim();\n const raw = trimmed.slice(eq + 1).trim();\n vars[key] = raw.replace(/^(['\"])(.*)\\1$/, '$2');\n }\n return vars;\n}\n\nfunction startDev(): void {\n const entry = resolveEntry();\n if (!entry) {\n console.error(pc.red('[EFC] Could not find entry point. Expected src/index.ts or index.ts'));\n process.exit(1);\n }\n\n console.log(pc.cyan('[EFC] Starting development server…'));\n console.log(pc.dim(` Entry: ${entry}`));\n\n const cwd = process.cwd();\n // Walk up from cwd looking for tsx in node_modules/.bin (handles workspace hoisting)\n function findTsx(): string {\n let dir = cwd;\n while (true) {\n const candidate = path.join(dir, 'node_modules', '.bin', 'tsx');\n if (fs.existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) return 'tsx'; // reached filesystem root, fall back to PATH\n dir = parent;\n }\n }\n const tsx = findTsx();\n\n // .env values are base; existing process.env takes precedence (same as dotenv default)\n const env: NodeJS.ProcessEnv = { NODE_ENV: 'development', ...parseDotenv(cwd), ...process.env };\n\n const child = spawn(tsx, ['watch', '--include', 'src', entry], { stdio: 'inherit', env });\n child.on('exit', (code) => process.exit(code ?? 0));\n}\n\nfunction startProd(): void {\n const cwd = process.cwd();\n const distEntry = path.join(cwd, 'dist', 'index.js');\n\n if (!fs.existsSync(distEntry)) {\n console.error(pc.red('[EFC] dist/index.js not found. Run `efc build prod` first.'));\n process.exit(1);\n }\n\n console.log(pc.cyan('[EFC] Starting production server…'));\n\n // Production env comes exclusively from process.env — no .env file loading.\n // Platforms (Docker, Kubernetes, Railway, Heroku, etc.) inject vars directly.\n const child = spawn('node', [distEntry], {\n stdio: 'inherit',\n env: { ...process.env, NODE_ENV: 'production' },\n });\n child.on('exit', (code) => process.exit(code ?? 0));\n}\n\nfunction resolveEntry(): string | null {\n const cwd = process.cwd();\n const candidates = [\n path.join(cwd, 'src', 'index.ts'),\n path.join(cwd, 'index.ts'),\n path.join(cwd, 'src', 'index.js'),\n path.join(cwd, 'index.js'),\n ];\n return candidates.find((f) => fs.existsSync(f)) ?? null;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport pc from 'picocolors';\n\nexport function buildCommand(): Command {\n const cmd = new Command('build');\n\n cmd\n .argument('<mode>', 'prod')\n .description('Build the application for production')\n .action((mode: string) => {\n if (mode !== 'prod') {\n console.error(pc.red(`Unknown build mode: ${mode}. Use 'prod'.`));\n process.exit(1);\n }\n buildProd();\n });\n\n return cmd;\n}\n\nfunction findBin(name: string): string {\n let dir = process.cwd();\n while (true) {\n const candidate = path.join(dir, 'node_modules', '.bin', name);\n if (fs.existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) return name; // fell off root, hope it's on PATH\n dir = parent;\n }\n}\n\nfunction resolveEntry(): string | null {\n const cwd = process.cwd();\n const candidates = [\n path.join(cwd, 'src', 'index.ts'),\n path.join(cwd, 'index.ts'),\n path.join(cwd, 'src', 'index.js'),\n path.join(cwd, 'index.js'),\n ];\n return candidates.find((f) => fs.existsSync(f)) ?? null;\n}\n\nfunction hasTsupConfig(): boolean {\n const cwd = process.cwd();\n return ['tsup.config.ts', 'tsup.config.js', 'tsup.config.mjs', 'tsup.config.cjs'].some((f) =>\n fs.existsSync(path.join(cwd, f)),\n );\n}\n\nfunction findTsConfig(): string | null {\n const cwd = process.cwd();\n const tsconfig = path.join(cwd, 'tsconfig.json');\n return fs.existsSync(tsconfig) ? tsconfig : null;\n}\n\nfunction buildProd(): void {\n console.log(pc.cyan('[EFC] Building for production…'));\n\n const tsconfig = findTsConfig();\n if (!tsconfig) {\n console.error(pc.red('[EFC] No tsconfig.json found in the current directory.'));\n process.exit(1);\n }\n\n const tsc = spawn(findBin('tsc'), ['--noEmit', '--project', tsconfig], { stdio: 'inherit' });\n\n tsc.on('exit', (code) => {\n if (code !== 0) {\n console.error(pc.red('[EFC] TypeScript errors found. Fix them before building.'));\n process.exit(1);\n }\n\n let tsupArgs: string[];\n if (hasTsupConfig()) {\n tsupArgs = [];\n } else {\n const entry = resolveEntry();\n if (!entry) {\n console.error(\n pc.red('[EFC] Could not find entry point. Expected src/index.ts or index.ts'),\n );\n process.exit(1);\n return;\n }\n tsupArgs = [entry, '--format', 'cjs,esm', '--clean', '--target', 'node18'];\n }\n\n const tsup = spawn(findBin('tsup'), tsupArgs, { stdio: 'inherit' });\n tsup.on('exit', (tsupCode) => {\n if (tsupCode === 0) {\n console.log(pc.green('[EFC] Build complete → dist/'));\n } else {\n process.exit(tsupCode ?? 1);\n }\n });\n });\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport pc from 'picocolors';\n\nexport function runCommand(): Command {\n const cmd = new Command('run');\n\n cmd\n .argument('<runner>', 'tests')\n .description('Run EFC sub-commands (tests)')\n .allowUnknownOption()\n .action((runner: string) => {\n if (runner === 'tests') {\n runTests(cmd.args.slice(1));\n } else {\n console.error(pc.red(`Unknown runner: ${runner}. Use 'tests'.`));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nfunction runTests(extraArgs: string[]): void {\n console.log(pc.cyan('[EFC] Running tests via Vitest…'));\n const child = spawn('npx', ['vitest', 'run', ...extraArgs], { stdio: 'inherit' });\n child.on('exit', (code) => process.exit(code ?? 0));\n}\n","import { Command } from 'commander';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\n\nexport function generateCommand(): Command {\n const cmd = new Command('generate').alias('g').description('Scaffold EFC modules');\n\n cmd\n .command('route <routePath>')\n .description('Scaffold a route module, e.g. users/[id]')\n .action((routePath: string) => generateRoute(routePath));\n\n cmd\n .command('task <name>')\n .description('Scaffold a background task module')\n .action((name: string) => generateTask(name));\n\n cmd\n .command('middleware <name>')\n .description('Scaffold a middleware module')\n .action((name: string) => generateMiddleware(name));\n\n return cmd;\n}\n\nfunction writeFile(filePath: string, content: string): void {\n const dir = path.dirname(filePath);\n fs.mkdirSync(dir, { recursive: true });\n if (fs.existsSync(filePath)) {\n console.error(pc.red(`File already exists: ${filePath}`));\n process.exit(1);\n }\n fs.writeFileSync(filePath, content, 'utf8');\n console.log(pc.green(` created ${path.relative(process.cwd(), filePath)}`));\n}\n\nfunction generateRoute(routePath: string): void {\n const cwd = process.cwd();\n const filePath = path.join(cwd, 'src', 'api', `${routePath}.ts`);\n const content = `import type { Request, Response } from 'express';\nimport type { RouteMeta } from 'express-file-cluster';\n\nexport const meta: RouteMeta = {\n GET: {\n description: 'TODO: describe this endpoint.',\n request: {\n headers: {\n // 'Content-Type': 'application/json'\n },\n query: {\n // search: 'query'\n },\n },\n response: {\n status: 200,\n body: {\n message: 'OK'\n }\n }\n },\n POST: {\n description: 'TODO: describe this endpoint.',\n request: {\n body: {\n // name: 'string'\n }\n },\n response: {\n status: 201,\n body: {\n message: 'Created'\n }\n }\n }\n};\n\nexport const GET = async (req: Request, res: Response) => {\n res.json({ message: 'OK' });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n res.status(201).json({ message: 'Created' });\n};\n`;\n\n writeFile(filePath, content);\n console.log(pc.cyan(`[EFC] Route scaffolded`));\n}\n\nfunction generateTask(name: string): void {\n const cwd = process.cwd();\n const filePath = path.join(cwd, 'src', 'tasks', `${name}.ts`);\n\n const content = `import { defineTask } from 'express-file-cluster/tasks';\n\ninterface ${name}Payload {\n // TODO: define payload fields\n}\n\nexport default defineTask<${name}Payload>(async (payload) => {\n // TODO: implement task logic\n console.log('[Task:${name}]', payload);\n});\n`;\n\n writeFile(filePath, content);\n console.log(pc.cyan(`[EFC] Task scaffolded`));\n}\n\nfunction generateMiddleware(name: string): void {\n const cwd = process.cwd();\n const filePath = path.join(cwd, 'src', 'middlewares', `${name}.ts`);\n\n const content = `import type { Request, Response, NextFunction } from 'express';\n\nexport function ${name}(req: Request, res: Response, next: NextFunction): void {\n // TODO: implement middleware logic\n next();\n}\n`;\n\n writeFile(filePath, content);\n console.log(pc.cyan(`[EFC] Middleware scaffolded`));\n}\n","import { Command } from 'commander';\nimport { scanDir } from '../../router/scan.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport pc from 'picocolors';\n\nexport function diagnosticsCommands(): Command[] {\n return [routesCommand(), tasksCommand(), doctorCommand()];\n}\n\nfunction routesCommand(): Command {\n return new Command('routes').description('Print the resolved route table').action(() => {\n const apiDir = resolveApiDir();\n if (!apiDir) {\n console.error(pc.red('[EFC] Could not find apiDir (expected src/api)'));\n process.exit(1);\n }\n\n const routes = scanDir(apiDir);\n if (routes.length === 0) {\n console.log(pc.yellow('No routes found.'));\n return;\n }\n\n console.log(pc.bold('\\n Route Table\\n'));\n console.log(pc.dim(' ' + '─'.repeat(60)));\n for (const route of routes) {\n const rel = path.relative(process.cwd(), route.filePath);\n console.log(` ${pc.cyan(route.urlPath.padEnd(35))} ${pc.dim(rel)}`);\n }\n console.log(pc.dim(' ' + '─'.repeat(60)));\n console.log(pc.dim(`\\n ${routes.length} route(s) found\\n`));\n });\n}\n\nfunction tasksCommand(): Command {\n return new Command('tasks').description('List registered background tasks').action(() => {\n const tasksDir = resolveTasksDir();\n if (!tasksDir || !fs.existsSync(tasksDir)) {\n console.log(pc.yellow('No tasks directory found.'));\n return;\n }\n\n const files = fs.readdirSync(tasksDir).filter((f) => /\\.(ts|js)$/.test(f));\n if (files.length === 0) {\n console.log(pc.yellow('No tasks found.'));\n return;\n }\n\n console.log(pc.bold('\\n Background Tasks\\n'));\n for (const file of files) {\n console.log(` ${pc.cyan(path.basename(file, path.extname(file)))}`);\n }\n console.log();\n });\n}\n\nfunction doctorCommand(): Command {\n return new Command('doctor')\n .description('Validate config, env vars, and project setup')\n .action(() => {\n const cwd = process.cwd();\n const checks: { label: string; ok: boolean; hint?: string }[] = [\n {\n label: 'package.json exists',\n ok: fs.existsSync(path.join(cwd, 'package.json')),\n },\n {\n label: 'tsconfig.json exists',\n ok: fs.existsSync(path.join(cwd, 'tsconfig.json')),\n hint: 'Run `tsc --init` to create one',\n },\n {\n label: 'src/api directory exists',\n ok: fs.existsSync(path.join(cwd, 'src', 'api')),\n hint: 'Create src/api/ and add route files',\n },\n {\n label: 'DATABASE_URL set',\n ok: Boolean(process.env['DATABASE_URL']),\n hint: 'Add DATABASE_URL to .env',\n },\n {\n label: 'JWT_SECRET set',\n ok: Boolean(process.env['JWT_SECRET']),\n hint: 'Add JWT_SECRET to .env (generate: openssl rand -hex 64)',\n },\n ];\n\n console.log(pc.bold('\\n EFC Doctor\\n'));\n let allOk = true;\n for (const check of checks) {\n const icon = check.ok ? pc.green('✓') : pc.red('✗');\n console.log(` ${icon} ${check.label}`);\n if (!check.ok) {\n allOk = false;\n if (check.hint) console.log(pc.dim(` → ${check.hint}`));\n }\n }\n console.log();\n if (allOk) {\n console.log(pc.green(' All checks passed!\\n'));\n } else {\n console.log(pc.yellow(' Some checks failed. Fix the issues above.\\n'));\n process.exit(1);\n }\n });\n}\n\nfunction resolveApiDir(): string | null {\n const cwd = process.cwd();\n const candidates = [path.join(cwd, 'src', 'api'), path.join(cwd, 'api')];\n return candidates.find((d) => fs.existsSync(d)) ?? null;\n}\n\nfunction resolveTasksDir(): string | null {\n const cwd = process.cwd();\n const candidates = [path.join(cwd, 'src', 'tasks'), path.join(cwd, 'tasks')];\n return candidates.find((d) => fs.existsSync(d)) ?? null;\n}\n"]}
1
+ {"version":3,"sources":["/home/prashant/Projects/temp-nodejs/packages/core/dist/cli/index.cjs","../../src/cli/index.ts","../../src/cli/commands/start.ts","../../src/cli/commands/build.ts","../../src/cli/commands/run.ts","../../src/cli/commands/generate.ts","../../src/cli/commands/diagnostics.ts"],"names":["path","pc"],"mappings":"AAAA;AACA;AACE;AACF,yDAA8B;AAC9B;AACA;ACJA,sCAAwB;ADMxB;AACA;AERA;AACA,8CAAsB;AACtB,wEAAiB;AACjB,gEAAe;AACf,gGAAe;AAER,SAAS,YAAA,CAAA,EAAwB;AACtC,EAAA,MAAM,IAAA,EAAM,IAAI,uBAAA,CAAQ,OAAO,CAAA;AAE/B,EAAA,GAAA,CACG,QAAA,CAAS,QAAA,EAAU,YAAY,CAAA,CAC/B,WAAA,CAAY,sBAAsB,CAAA,CAClC,MAAA,CAAO,CAAC,IAAA,EAAA,GAAiB;AACxB,IAAA,GAAA,CAAI,KAAA,IAAS,KAAA,EAAO;AAClB,MAAA,QAAA,CAAS,CAAA;AAAA,IACX,EAAA,KAAA,GAAA,CAAW,KAAA,IAAS,MAAA,EAAQ;AAC1B,MAAA,SAAA,CAAU,CAAA;AAAA,IACZ,EAAA,KAAO;AACL,MAAA,OAAA,CAAQ,KAAA,CAAM,oBAAA,CAAG,GAAA,CAAI,CAAA,cAAA,EAAiB,IAAI,CAAA,sBAAA,CAAwB,CAAC,CAAA;AACnE,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA;AAAA,IAChB;AAAA,EACF,CAAC,CAAA;AAEH,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,WAAA,CAAY,GAAA,EAAqC;AACxD,EAAA,MAAM,QAAA,EAAU,cAAA,CAAK,IAAA,CAAK,GAAA,EAAK,MAAM,CAAA;AACrC,EAAA,GAAA,CAAI,CAAC,YAAA,CAAG,UAAA,CAAW,OAAO,CAAA,EAAG,OAAO,CAAC,CAAA;AACrC,EAAA,MAAM,KAAA,EAA+B,CAAC,CAAA;AACtC,EAAA,IAAA,CAAA,MAAW,KAAA,GAAQ,YAAA,CAAG,YAAA,CAAa,OAAA,EAAS,MAAM,CAAA,CAAE,KAAA,CAAM,IAAI,CAAA,EAAG;AAC/D,IAAA,MAAM,QAAA,EAAU,IAAA,CAAK,IAAA,CAAK,CAAA;AAC1B,IAAA,GAAA,CAAI,CAAC,QAAA,GAAW,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAG,QAAA;AACzC,IAAA,MAAM,GAAA,EAAK,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AAC9B,IAAA,GAAA,CAAI,GAAA,IAAO,CAAA,CAAA,EAAI,QAAA;AACf,IAAA,MAAM,IAAA,EAAM,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,CAAE,IAAA,CAAK,CAAA;AACtC,IAAA,MAAM,IAAA,EAAM,OAAA,CAAQ,KAAA,CAAM,GAAA,EAAK,CAAC,CAAA,CAAE,IAAA,CAAK,CAAA;AACvC,IAAA,IAAA,CAAK,GAAG,EAAA,EAAI,GAAA,CAAI,OAAA,CAAQ,gBAAA,EAAkB,IAAI,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,QAAA,CAAA,EAAiB;AACxB,EAAA,MAAM,MAAA,EAAQ,YAAA,CAAa,CAAA;AAC3B,EAAA,GAAA,CAAI,CAAC,KAAA,EAAO;AACV,IAAA,OAAA,CAAQ,KAAA,CAAM,oBAAA,CAAG,GAAA,CAAI,qEAAqE,CAAC,CAAA;AAC3F,IAAA,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA;AAAA,EAChB;AAEA,EAAA,OAAA,CAAQ,GAAA,CAAI,oBAAA,CAAG,IAAA,CAAK,yCAAoC,CAAC,CAAA;AACzD,EAAA,OAAA,CAAQ,GAAA,CAAI,oBAAA,CAAG,GAAA,CAAI,CAAA,SAAA,EAAY,KAAK,CAAA,CAAA;AAEZ,EAAA;AAEG,EAAA;AACf,IAAA;AACG,IAAA;AACsB,MAAA;AACH,MAAA;AACC,MAAA;AACJ,MAAA;AACrB,MAAA;AACR,IAAA;AACF,EAAA;AACoB,EAAA;AAGuB,EAAA;AAER,EAAA;AACA,EAAA;AACrC;AAE2B;AACD,EAAA;AACS,EAAA;AAEF,EAAA;AACR,IAAA;AACP,IAAA;AAChB,EAAA;AAEoB,EAAA;AAIS,EAAA;AACpB,IAAA;AAC0B,IAAA;AAClC,EAAA;AACkC,EAAA;AACrC;AAEuC;AACb,EAAA;AACL,EAAA;AACe,IAAA;AACP,IAAA;AACO,IAAA;AACP,IAAA;AAC3B,EAAA;AACiC,EAAA;AACnC;AFXuC;AACA;AG5Ff;AACF;AACL;AACF;AACA;AAEyB;AACP,EAAA;AAI5B,EAAA;AAEsB,IAAA;AACE,MAAA;AACP,MAAA;AAChB,IAAA;AACU,IAAA;AACX,EAAA;AAEI,EAAA;AACT;AAEuC;AACf,EAAA;AACT,EAAA;AACsB,IAAA;AACH,IAAA;AACC,IAAA;AACJ,IAAA;AACrB,IAAA;AACR,EAAA;AACF;AAEuC;AACb,EAAA;AACL,EAAA;AACe,IAAA;AACP,IAAA;AACO,IAAA;AACP,IAAA;AAC3B,EAAA;AACiC,EAAA;AACnC;AAEkC;AACR,EAAA;AACE,EAAA;AACA,IAAA;AAC1B,EAAA;AACF;AAEuC;AACb,EAAA;AACQ,EAAA;AACC,EAAA;AACnC;AAE2B;AACL,EAAA;AAEU,EAAA;AACf,EAAA;AACQ,IAAA;AACP,IAAA;AAChB,EAAA;AAEmC,EAAA;AAEV,EAAA;AACP,IAAA;AACO,MAAA;AACP,MAAA;AAChB,IAAA;AAEI,IAAA;AACiB,IAAA;AACP,MAAA;AACP,IAAA;AACsB,MAAA;AACf,MAAA;AACF,QAAA;AACC,UAAA;AACT,QAAA;AACc,QAAA;AACd,QAAA;AACF,MAAA;AAC+B,MAAA;AACjC,IAAA;AAEiC,IAAA;AACH,IAAA;AACR,MAAA;AACG,QAAA;AAChB,MAAA;AACqB,QAAA;AAC5B,MAAA;AACD,IAAA;AACF,EAAA;AACH;AH8EuC;AACA;AIlLf;AACF;AACP;AAEuB;AACP,EAAA;AAI1B,EAAA;AAGyB,IAAA;AACI,MAAA;AACrB,IAAA;AACgB,MAAA;AACP,MAAA;AAChB,IAAA;AACD,EAAA;AAEI,EAAA;AACT;AAE6C;AACvB,EAAA;AACQ,EAAA;AACO,EAAA;AACrC;AJ4KuC;AACA;AKxMf;AACT;AACE;AACF;AAE4B;AACL,EAAA;AAIjC,EAAA;AAKA,EAAA;AAKA,EAAA;AAGI,EAAA;AACT;AAE4D;AACzB,EAAA;AACG,EAAA;AACP,EAAA;AACN,IAAA;AACP,IAAA;AAChB,EAAA;AACoC,EAAA;AACDA,EAAAA;AACrC;AAEgD;AACtB,EAAA;AACQ,EAAA;AAChB,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8CW,EAAA;AACP,EAAA;AACtB;AAE0C;AAChB,EAAA;AACQ,EAAA;AAEhB,EAAA;AAAA;AAEF,UAAA;AAAA;AAAA;AAAA;AAIgB,0BAAA;AAAA;AAEL,qBAAA;AAAA;AAAA;AAIE,EAAA;AACP,EAAA;AACtB;AAEgD;AACtB,EAAA;AACQ,EAAA;AAEhB,EAAA;AAAA;AAEI,gBAAA;AAAA;AAAA;AAAA;AAAA;AAMO,EAAA;AACP,EAAA;AACtB;ALmLuC;AACA;AMhTf;AAEP;AACF;AACA;AAEkC;AACtB,EAAA;AAC3B;AAEkC;AACH,EAAA;AACE,IAAA;AAChB,IAAA;AACU,MAAA;AACP,MAAA;AAChB,IAAA;AAE6B,IAAA;AACJ,IAAA;AACD,MAAA;AACtB,MAAA;AACF,IAAA;AAEoB,IAAA;AACM,IAAA;AACE,IAAA;AACA,MAAA;AACK,MAAA;AACjC,IAAA;AAC0B,IAAA;AACP,IAAA;AAAoB,EAAA;AAAoB;AAC5D,EAAA;AACH;AAEiC;AACH,EAAA;AACO,IAAA;AACD,IAAA;AACR,MAAA;AACtB,MAAA;AACF,IAAA;AAE6B,IAAA;AACL,IAAA;AACA,MAAA;AACtB,MAAA;AACF,IAAA;AAEoB,IAAA;AACM,IAAA;AACM,MAAA;AAChC,IAAA;AACY,IAAA;AACb,EAAA;AACH;AAEkC;AAE7B,EAAA;AAEyB,IAAA;AACwC,IAAA;AAC9D,MAAA;AACS,QAAA;AACqB,QAAA;AAC9B,MAAA;AACA,MAAA;AACS,QAAA;AACqB,QAAA;AACtB,QAAA;AACR,MAAA;AACA,MAAA;AACS,QAAA;AACqB,QAAA;AACtB,QAAA;AACR,MAAA;AACA,MAAA;AACS,QAAA;AACiB,QAAA;AAClB,QAAA;AACR,MAAA;AACA,MAAA;AACS,QAAA;AACiB,QAAA;AAClB,QAAA;AACR,MAAA;AACF,IAAA;AAEoB,IAAA;AACR,IAAA;AACgB,IAAA;AACC,MAAA;AACK,MAAA;AACjB,MAAA;AACL,QAAA;AACoBC,QAAAA;AAC9B,MAAA;AACF,IAAA;AACY,IAAA;AACD,IAAA;AACY,MAAA;AAChB,IAAA;AACiB,MAAA;AACR,MAAA;AAChB,IAAA;AACD,EAAA;AACL;AAEwC;AACd,EAAA;AACW,EAAA;AACF,EAAA;AACnC;AAE0C;AAChB,EAAA;AACW,EAAA;AACF,EAAA;AACnC;ANsSuC;AACA;ACtZJ;AAEF;AACA;AACF;AACK;AAEE;AACd,EAAA;AACxB;AAE0B","file":"/home/prashant/Projects/temp-nodejs/packages/core/dist/cli/index.cjs","sourcesContent":[null,"#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { startCommand } from './commands/start.js';\nimport { buildCommand } from './commands/build.js';\nimport { runCommand } from './commands/run.js';\nimport { generateCommand } from './commands/generate.js';\nimport { diagnosticsCommands } from './commands/diagnostics.js';\n\nconst program = new Command('efc').description('Express File Cluster CLI').version('0.1.0');\n\nprogram.addCommand(startCommand());\nprogram.addCommand(buildCommand());\nprogram.addCommand(runCommand());\nprogram.addCommand(generateCommand());\n\nfor (const cmd of diagnosticsCommands()) {\n program.addCommand(cmd);\n}\n\nprogram.parse(process.argv);\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport pc from 'picocolors';\n\nexport function startCommand(): Command {\n const cmd = new Command('start');\n\n cmd\n .argument('<mode>', 'dev | prod')\n .description('Start the EFC server')\n .action((mode: string) => {\n if (mode === 'dev') {\n startDev();\n } else if (mode === 'prod') {\n startProd();\n } else {\n console.error(pc.red(`Unknown mode: ${mode}. Use 'dev' or 'prod'.`));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nfunction parseDotenv(cwd: string): Record<string, string> {\n const envFile = path.join(cwd, '.env');\n if (!fs.existsSync(envFile)) return {};\n const vars: Record<string, string> = {};\n for (const line of fs.readFileSync(envFile, 'utf8').split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eq = trimmed.indexOf('=');\n if (eq === -1) continue;\n const key = trimmed.slice(0, eq).trim();\n const raw = trimmed.slice(eq + 1).trim();\n vars[key] = raw.replace(/^(['\"])(.*)\\1$/, '$2');\n }\n return vars;\n}\n\nfunction startDev(): void {\n const entry = resolveEntry();\n if (!entry) {\n console.error(pc.red('[EFC] Could not find entry point. Expected src/index.ts or index.ts'));\n process.exit(1);\n }\n\n console.log(pc.cyan('[EFC] Starting development server…'));\n console.log(pc.dim(` Entry: ${entry}`));\n\n const cwd = process.cwd();\n // Walk up from cwd looking for tsx in node_modules/.bin (handles workspace hoisting)\n function findTsx(): string {\n let dir = cwd;\n while (true) {\n const candidate = path.join(dir, 'node_modules', '.bin', 'tsx');\n if (fs.existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) return 'tsx'; // reached filesystem root, fall back to PATH\n dir = parent;\n }\n }\n const tsx = findTsx();\n\n // .env values are base; existing process.env takes precedence (same as dotenv default)\n const env: NodeJS.ProcessEnv = { NODE_ENV: 'development', ...parseDotenv(cwd), ...process.env };\n\n const child = spawn(tsx, ['watch', '--include', 'src', entry], { stdio: 'inherit', env });\n child.on('exit', (code) => process.exit(code ?? 0));\n}\n\nfunction startProd(): void {\n const cwd = process.cwd();\n const distEntry = path.join(cwd, 'dist', 'index.js');\n\n if (!fs.existsSync(distEntry)) {\n console.error(pc.red('[EFC] dist/index.js not found. Run `efc build prod` first.'));\n process.exit(1);\n }\n\n console.log(pc.cyan('[EFC] Starting production server…'));\n\n // Production env comes exclusively from process.env — no .env file loading.\n // Platforms (Docker, Kubernetes, Railway, Heroku, etc.) inject vars directly.\n const child = spawn('node', [distEntry], {\n stdio: 'inherit',\n env: { ...process.env, NODE_ENV: 'production' },\n });\n child.on('exit', (code) => process.exit(code ?? 0));\n}\n\nfunction resolveEntry(): string | null {\n const cwd = process.cwd();\n const candidates = [\n path.join(cwd, 'src', 'index.ts'),\n path.join(cwd, 'index.ts'),\n path.join(cwd, 'src', 'index.js'),\n path.join(cwd, 'index.js'),\n ];\n return candidates.find((f) => fs.existsSync(f)) ?? null;\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport pc from 'picocolors';\n\nexport function buildCommand(): Command {\n const cmd = new Command('build');\n\n cmd\n .argument('<mode>', 'prod')\n .description('Build the application for production')\n .action((mode: string) => {\n if (mode !== 'prod') {\n console.error(pc.red(`Unknown build mode: ${mode}. Use 'prod'.`));\n process.exit(1);\n }\n buildProd();\n });\n\n return cmd;\n}\n\nfunction findBin(name: string): string {\n let dir = process.cwd();\n while (true) {\n const candidate = path.join(dir, 'node_modules', '.bin', name);\n if (fs.existsSync(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) return name; // fell off root, hope it's on PATH\n dir = parent;\n }\n}\n\nfunction resolveEntry(): string | null {\n const cwd = process.cwd();\n const candidates = [\n path.join(cwd, 'src', 'index.ts'),\n path.join(cwd, 'index.ts'),\n path.join(cwd, 'src', 'index.js'),\n path.join(cwd, 'index.js'),\n ];\n return candidates.find((f) => fs.existsSync(f)) ?? null;\n}\n\nfunction hasTsupConfig(): boolean {\n const cwd = process.cwd();\n return ['tsup.config.ts', 'tsup.config.js', 'tsup.config.mjs', 'tsup.config.cjs'].some((f) =>\n fs.existsSync(path.join(cwd, f)),\n );\n}\n\nfunction findTsConfig(): string | null {\n const cwd = process.cwd();\n const tsconfig = path.join(cwd, 'tsconfig.json');\n return fs.existsSync(tsconfig) ? tsconfig : null;\n}\n\nfunction buildProd(): void {\n console.log(pc.cyan('[EFC] Building for production…'));\n\n const tsconfig = findTsConfig();\n if (!tsconfig) {\n console.error(pc.red('[EFC] No tsconfig.json found in the current directory.'));\n process.exit(1);\n }\n\n const tsc = spawn(findBin('tsc'), ['--noEmit', '--project', tsconfig], { stdio: 'inherit' });\n\n tsc.on('exit', (code) => {\n if (code !== 0) {\n console.error(pc.red('[EFC] TypeScript errors found. Fix them before building.'));\n process.exit(1);\n }\n\n let tsupArgs: string[];\n if (hasTsupConfig()) {\n tsupArgs = [];\n } else {\n const entry = resolveEntry();\n if (!entry) {\n console.error(\n pc.red('[EFC] Could not find entry point. Expected src/index.ts or index.ts'),\n );\n process.exit(1);\n return;\n }\n tsupArgs = [entry, '--format', 'cjs,esm', '--clean', '--target', 'node18'];\n }\n\n const tsup = spawn(findBin('tsup'), tsupArgs, { stdio: 'inherit' });\n tsup.on('exit', (tsupCode) => {\n if (tsupCode === 0) {\n console.log(pc.green('[EFC] Build complete → dist/'));\n } else {\n process.exit(tsupCode ?? 1);\n }\n });\n });\n}\n","import { Command } from 'commander';\nimport { spawn } from 'node:child_process';\nimport pc from 'picocolors';\n\nexport function runCommand(): Command {\n const cmd = new Command('run');\n\n cmd\n .argument('<runner>', 'tests')\n .description('Run EFC sub-commands (tests)')\n .allowUnknownOption()\n .action((runner: string) => {\n if (runner === 'tests') {\n runTests(cmd.args.slice(1));\n } else {\n console.error(pc.red(`Unknown runner: ${runner}. Use 'tests'.`));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nfunction runTests(extraArgs: string[]): void {\n console.log(pc.cyan('[EFC] Running tests via Vitest…'));\n const child = spawn('npx', ['vitest', 'run', ...extraArgs], { stdio: 'inherit' });\n child.on('exit', (code) => process.exit(code ?? 0));\n}\n","import { Command } from 'commander';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport pc from 'picocolors';\n\nexport function generateCommand(): Command {\n const cmd = new Command('generate').alias('g').description('Scaffold EFC modules');\n\n cmd\n .command('route <routePath>')\n .description('Scaffold a route module, e.g. users/[id]')\n .action((routePath: string) => generateRoute(routePath));\n\n cmd\n .command('task <name>')\n .description('Scaffold a background task module')\n .action((name: string) => generateTask(name));\n\n cmd\n .command('middleware <name>')\n .description('Scaffold a middleware module')\n .action((name: string) => generateMiddleware(name));\n\n return cmd;\n}\n\nfunction writeFile(filePath: string, content: string): void {\n const dir = path.dirname(filePath);\n fs.mkdirSync(dir, { recursive: true });\n if (fs.existsSync(filePath)) {\n console.error(pc.red(`File already exists: ${filePath}`));\n process.exit(1);\n }\n fs.writeFileSync(filePath, content, 'utf8');\n console.log(pc.green(` created ${path.relative(process.cwd(), filePath)}`));\n}\n\nfunction generateRoute(routePath: string): void {\n const cwd = process.cwd();\n const filePath = path.join(cwd, 'src', 'api', `${routePath}.ts`);\n const content = `import type { Request, Response } from 'express';\nimport type { RouteMeta } from 'express-file-cluster';\n\nexport const meta: RouteMeta = {\n GET: {\n description: 'TODO: describe this endpoint.',\n request: {\n headers: {\n // 'Content-Type': 'application/json'\n },\n query: {\n // search: 'query'\n },\n },\n response: {\n status: 200,\n body: {\n message: 'OK'\n }\n }\n },\n POST: {\n description: 'TODO: describe this endpoint.',\n request: {\n body: {\n // name: 'string'\n }\n },\n response: {\n status: 201,\n body: {\n message: 'Created'\n }\n }\n }\n};\n\nexport const GET = async (req: Request, res: Response) => {\n res.json({ message: 'OK' });\n};\n\nexport const POST = async (req: Request, res: Response) => {\n res.status(201).json({ message: 'Created' });\n};\n`;\n\n writeFile(filePath, content);\n console.log(pc.cyan(`[EFC] Route scaffolded`));\n}\n\nfunction generateTask(name: string): void {\n const cwd = process.cwd();\n const filePath = path.join(cwd, 'src', 'tasks', `${name}.ts`);\n\n const content = `import { defineTask } from 'express-file-cluster/tasks';\n\ninterface ${name}Payload {\n // TODO: define payload fields\n}\n\nexport default defineTask<${name}Payload>(async (payload) => {\n // TODO: implement task logic\n console.log('[Task:${name}]', payload);\n});\n`;\n\n writeFile(filePath, content);\n console.log(pc.cyan(`[EFC] Task scaffolded`));\n}\n\nfunction generateMiddleware(name: string): void {\n const cwd = process.cwd();\n const filePath = path.join(cwd, 'src', 'middlewares', `${name}.ts`);\n\n const content = `import type { Request, Response, NextFunction } from 'express';\n\nexport function ${name}(req: Request, res: Response, next: NextFunction): void {\n // TODO: implement middleware logic\n next();\n}\n`;\n\n writeFile(filePath, content);\n console.log(pc.cyan(`[EFC] Middleware scaffolded`));\n}\n","import { Command } from 'commander';\nimport { scanDir } from '../../router/scan.js';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport pc from 'picocolors';\n\nexport function diagnosticsCommands(): Command[] {\n return [routesCommand(), tasksCommand(), doctorCommand()];\n}\n\nfunction routesCommand(): Command {\n return new Command('routes').description('Print the resolved route table').action(() => {\n const apiDir = resolveApiDir();\n if (!apiDir) {\n console.error(pc.red('[EFC] Could not find apiDir (expected src/api)'));\n process.exit(1);\n }\n\n const routes = scanDir(apiDir);\n if (routes.length === 0) {\n console.log(pc.yellow('No routes found.'));\n return;\n }\n\n console.log(pc.bold('\\n Route Table\\n'));\n console.log(pc.dim(' ' + '─'.repeat(60)));\n for (const route of routes) {\n const rel = path.relative(process.cwd(), route.filePath);\n console.log(` ${pc.cyan(route.urlPath.padEnd(35))} ${pc.dim(rel)}`);\n }\n console.log(pc.dim(' ' + '─'.repeat(60)));\n console.log(pc.dim(`\\n ${routes.length} route(s) found\\n`));\n });\n}\n\nfunction tasksCommand(): Command {\n return new Command('tasks').description('List registered background tasks').action(() => {\n const tasksDir = resolveTasksDir();\n if (!tasksDir || !fs.existsSync(tasksDir)) {\n console.log(pc.yellow('No tasks directory found.'));\n return;\n }\n\n const files = fs.readdirSync(tasksDir).filter((f) => /\\.(ts|js)$/.test(f));\n if (files.length === 0) {\n console.log(pc.yellow('No tasks found.'));\n return;\n }\n\n console.log(pc.bold('\\n Background Tasks\\n'));\n for (const file of files) {\n console.log(` ${pc.cyan(path.basename(file, path.extname(file)))}`);\n }\n console.log();\n });\n}\n\nfunction doctorCommand(): Command {\n return new Command('doctor')\n .description('Validate config, env vars, and project setup')\n .action(() => {\n const cwd = process.cwd();\n const checks: { label: string; ok: boolean; hint?: string }[] = [\n {\n label: 'package.json exists',\n ok: fs.existsSync(path.join(cwd, 'package.json')),\n },\n {\n label: 'tsconfig.json exists',\n ok: fs.existsSync(path.join(cwd, 'tsconfig.json')),\n hint: 'Run `tsc --init` to create one',\n },\n {\n label: 'src/api directory exists',\n ok: fs.existsSync(path.join(cwd, 'src', 'api')),\n hint: 'Create src/api/ and add route files',\n },\n {\n label: 'DATABASE_URL set',\n ok: Boolean(process.env['DATABASE_URL']),\n hint: 'Add DATABASE_URL to .env',\n },\n {\n label: 'JWT_SECRET set',\n ok: Boolean(process.env['JWT_SECRET']),\n hint: 'Add JWT_SECRET to .env (generate: openssl rand -hex 64)',\n },\n ];\n\n console.log(pc.bold('\\n EFC Doctor\\n'));\n let allOk = true;\n for (const check of checks) {\n const icon = check.ok ? pc.green('✓') : pc.red('✗');\n console.log(` ${icon} ${check.label}`);\n if (!check.ok) {\n allOk = false;\n if (check.hint) console.log(pc.dim(` → ${check.hint}`));\n }\n }\n console.log();\n if (allOk) {\n console.log(pc.green(' All checks passed!\\n'));\n } else {\n console.log(pc.yellow(' Some checks failed. Fix the issues above.\\n'));\n process.exit(1);\n }\n });\n}\n\nfunction resolveApiDir(): string | null {\n const cwd = process.cwd();\n const candidates = [path.join(cwd, 'src', 'api'), path.join(cwd, 'api')];\n return candidates.find((d) => fs.existsSync(d)) ?? null;\n}\n\nfunction resolveTasksDir(): string | null {\n const cwd = process.cwd();\n const candidates = [path.join(cwd, 'src', 'tasks'), path.join(cwd, 'tasks')];\n return candidates.find((d) => fs.existsSync(d)) ?? null;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/efc.js/efc.js/packages/core/dist/index.cjs","../src/index.ts","../src/router/mount.ts","../src/cluster/index.ts","../src/db/mongo.ts","../src/db/model.ts","../src/db/index.ts","../src/tasks/scanner.ts","../src/tasks/thread-runner.ts","../src/tasks/bullmq-backend.ts","../src/dashboard.ts","../src/errors.ts","../src/compose.ts"],"names":[],"mappings":"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","file":"/home/runner/work/efc.js/efc.js/packages/core/dist/index.cjs","sourcesContent":[null,"import http from 'node:http';\nimport fs from 'node:fs';\nimport express from 'express';\nimport cors from 'cors';\nimport cookieParser from 'cookie-parser';\nimport cluster from 'node:cluster';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { EFCConfig, MountedRoute } from './types.js';\nimport { scanDir } from './router/scan.js';\nimport { mountRoutes } from './router/mount.js';\nimport { runMaster, shutdownMaster } from './cluster/index.js';\nimport { configureAuth } from './auth/index.js';\nimport { HttpError } from './errors.js';\nimport { connectMongo } from './db/mongo.js';\nimport { setDbClient } from './db/index.js';\nimport { scanTasks } from './tasks/scanner.js';\nimport { initBullMQ } from './tasks/bullmq-backend.js';\nimport { generateDashboard } from './dashboard.js';\n\nfunction detectDatabase(url?: string): 'mongodb' | 'postgresql' | undefined {\n if (!url) return undefined;\n if (url.startsWith('mongodb')) return 'mongodb';\n if (url.startsWith('postgres')) return 'postgresql';\n return undefined;\n}\n\nexport async function ignite(config: EFCConfig): Promise<http.Server | undefined> {\n const {\n port: _port,\n workers,\n globalMiddlewares = [],\n onWorkerReady,\n onWorkerCrash,\n onError,\n } = config;\n\n // Resolve api/tasks dirs from convention. argv[1]-based resolution is unreliable in tsx watch\n // + cluster workers (argv[1] can point to the tsx binary instead of the user's script), so we\n // probe multiple candidates and use the first that exists on disk.\n function resolveConventionDir(name: string): string {\n const candidates: string[] = [\n ...(process.argv[1] ? [path.join(path.dirname(process.argv[1]), name)] : []),\n path.join(process.cwd(), 'src', name),\n path.join(process.cwd(), name),\n path.join(process.cwd(), 'dist', name),\n ];\n return candidates.find((c) => fs.existsSync(c)) ?? candidates[0]!;\n }\n const apiDir = resolveConventionDir('api');\n const tasksDir = resolveConventionDir('tasks');\n const basePath = config.basePath ?? '/v1/api';\n\n function readProjectMeta(): { name: string; version: string } {\n try {\n const raw = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8');\n const pkg = JSON.parse(raw) as { name?: string; version?: string };\n return { name: pkg.name ?? 'API', version: pkg.version ?? '' };\n } catch {\n return { name: 'API', version: '' };\n }\n }\n\n const envPort = process.env['PORT'] != null ? Number(process.env['PORT']) : NaN;\n const port =\n _port != null && !Number.isNaN(_port) ? _port : !Number.isNaN(envPort) ? envPort : 3000;\n const databaseUrl = config.databaseUrl ?? process.env['DATABASE_URL'];\n const database = config.database ?? detectDatabase(databaseUrl);\n const jwtSecret = config.jwtSecret ?? process.env['JWT_SECRET'];\n const authStrategy = config.authStrategy ?? 'http-only';\n const clusterEnabled = config.cluster ?? process.env['NODE_ENV'] === 'production';\n\n if (clusterEnabled && cluster.isPrimary) {\n runMaster({\n workers: workers ?? os.cpus().length,\n ...(onWorkerReady !== undefined && { onWorkerReady }),\n ...(onWorkerCrash !== undefined && { onWorkerCrash }),\n });\n return;\n }\n\n const app = express();\n\n const corsOption = config.cors ?? true;\n if (corsOption !== false) {\n const envOrigins = process.env['CORS_ORIGINS'];\n let origin: string | string[] | boolean;\n if (envOrigins) {\n const list = envOrigins\n .split(',')\n .map((o) => o.trim())\n .filter(Boolean);\n origin = list; // always array so cors validates against the request Origin\n } else if (typeof corsOption === 'object' && corsOption.origin !== undefined) {\n origin = corsOption.origin;\n } else {\n origin = true;\n }\n const corsOpts = typeof corsOption === 'object' ? { ...corsOption, origin } : { origin };\n app.use(cors(corsOpts));\n }\n\n app.use(express.json());\n app.use(express.urlencoded({ extended: true }));\n app.use(cookieParser());\n\n for (const mw of globalMiddlewares) {\n app.use(mw);\n }\n\n // Pre-Flight step 1: Connect database\n if (database === 'mongodb' && databaseUrl) {\n const conn = await connectMongo(databaseUrl);\n setDbClient(conn as unknown as Record<string, unknown>);\n }\n\n // Pre-Flight step 2: Configure auth\n if (jwtSecret) {\n const cookieDomain = process.env['COOKIE_DOMAIN'];\n configureAuth({\n secret: jwtSecret,\n strategy: authStrategy,\n expiresIn: process.env['JWT_EXPIRES_IN'] ?? '7d',\n ...(cookieDomain !== undefined && { cookieDomain }),\n });\n }\n\n // Pre-Flight step 3: Scan and register tasks\n if (tasksDir) {\n await scanTasks(tasksDir);\n }\n\n // Pre-Flight step 4: Start task queue backend\n if (config.tasks) {\n if (config.tasks.backend === 'bullmq') {\n await initBullMQ({\n redisUrl: config.tasks.redisUrl ?? 'redis://localhost:6379',\n concurrency: config.tasks.concurrency ?? 5,\n });\n }\n }\n\n // Pre-Flight step 5: Scan routes and mount\n const routes = scanDir(apiDir);\n const apiRouter = express.Router();\n const mounted: MountedRoute[] = await mountRoutes(apiRouter, routes);\n app.use(basePath, apiRouter);\n\n if (config.dashboard !== false && process.env['NODE_ENV'] === 'development') {\n app.get('/', (_req, res) => {\n const { name, version } = readProjectMeta();\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.send(generateDashboard(mounted, basePath, port, name, version));\n });\n }\n\n if (onError) {\n app.use(onError);\n } else {\n app.use(\n (err: unknown, _req: express.Request, res: express.Response, _next: express.NextFunction) => {\n const asHttp = err instanceof Error && 'statusCode' in err ? (err as HttpError) : null;\n if (asHttp) {\n res\n .status(asHttp.statusCode)\n .json({ error: asHttp.message, statusCode: asHttp.statusCode });\n } else {\n console.error('[EFC] Unhandled error:', err);\n res.status(500).json({ error: 'Internal Server Error', statusCode: 500 });\n }\n },\n );\n }\n\n return new Promise<http.Server>((resolve, reject) => {\n const server = app.listen(port);\n\n server.once('listening', () => {\n const wid = (cluster.worker as { id: number } | undefined)?.id ?? 'primary';\n const addr = server.address() as { port: number } | null;\n console.log(`[EFC] Worker ${wid} listening on :${addr?.port ?? port}`);\n resolve(server);\n });\n\n server.once('error', reject);\n });\n}\n\nexport function gracefulShutdown(server: http.Server | undefined, timeoutMs = 10_000): void {\n const shutdown = (signal: string) => {\n console.log(`[EFC] ${signal} received — closing server gracefully…`);\n if (server) {\n server.closeIdleConnections();\n server.close(() => {\n console.log('[EFC] Server closed');\n process.exit(0);\n });\n setTimeout(() => {\n console.error('[EFC] Forced exit after timeout');\n process.exit(1);\n }, timeoutMs).unref();\n } else {\n shutdownMaster();\n }\n };\n process.once('SIGTERM', () => shutdown('SIGTERM'));\n process.once('SIGINT', () => shutdown('SIGINT'));\n}\n\nexport { HttpError } from './errors.js';\nexport { compose } from './compose.js';\nexport { db, setDbClient, getDbClient, defineModel } from './db/index.js';\nexport { scanDir } from './router/scan.js';\nexport type {\n EFCConfig,\n CorsConfig,\n RouteEntry,\n RouteMeta,\n RouteMethodMeta,\n TaskOptions,\n TaskDefinition,\n DatabaseEngine,\n AuthStrategy,\n ModelSchema,\n ModelCRUD,\n} from './types.js';\n","import type { IRouter, RequestHandler } from 'express';\nimport type { MountedRoute, RouteMeta, RouteEntry } from '../types.js';\n\nconst HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const;\ntype HttpMethod = (typeof HTTP_METHODS)[number];\n\nfunction asyncWrap(handler: RequestHandler): RequestHandler {\n return (req, res, next) => {\n Promise.resolve(handler(req, res, next)).catch(next);\n };\n}\n\nexport async function mountRoutes(\n app: IRouter,\n routes: RouteEntry[],\n): Promise<MountedRoute[]> {\n const mounted: MountedRoute[] = [];\n\n for (const route of routes) {\n const mod = (await import(route.filePath)) as Record<string, unknown>;\n const routeMiddlewares: RequestHandler[] = Array.isArray(mod['middlewares'])\n ? (mod['middlewares'] as RequestHandler[])\n : [];\n\n const raw = mod['meta'];\n const meta: RouteMeta | undefined =\n raw != null && typeof raw === 'object' && !Array.isArray(raw)\n ? (raw as RouteMeta)\n : undefined;\n\n const implemented: HttpMethod[] = [];\n const unimplemented: HttpMethod[] = [];\n\n for (const method of HTTP_METHODS) {\n if (typeof mod[method] === 'function') {\n implemented.push(method);\n app[method.toLowerCase() as Lowercase<HttpMethod>](\n route.urlPath,\n ...routeMiddlewares,\n asyncWrap(mod[method] as RequestHandler),\n );\n } else {\n unimplemented.push(method);\n }\n }\n\n if (implemented.length > 0 && unimplemented.length > 0) {\n const allowHeader = implemented.join(', ');\n app.all(route.urlPath, (req, res, next) => {\n if ((unimplemented as string[]).includes(req.method)) {\n res.set('Allow', allowHeader).status(405).json({ error: 'Method Not Allowed' });\n } else {\n next();\n }\n });\n }\n\n mounted.push({ ...route, methods: implemented, ...(meta !== undefined && { meta }) });\n }\n\n return mounted;\n}\n\nexport { asyncWrap };\n","import cluster from 'node:cluster';\nimport os from 'node:os';\n\ninterface ClusterOptions {\n workers?: number;\n onWorkerReady?: ((id: number) => void) | undefined;\n onWorkerCrash?: ((id: number, code: number) => void) | undefined;\n}\n\nlet isShuttingDown = false;\n\nexport function shutdownMaster(): void {\n isShuttingDown = true;\n console.log('[EFC] Cluster master shutting down, waiting for workers…');\n}\n\nexport function runMaster(options: ClusterOptions = {}): void {\n const count = options.workers ?? os.cpus().length;\n\n console.log(`[EFC] Primary ${process.pid} starting ${count} workers`);\n\n for (let i = 0; i < count; i++) {\n cluster.fork();\n }\n\n cluster.on('online', (worker) => {\n options.onWorkerReady?.(worker.id);\n });\n\n cluster.on('exit', (worker, code, signal) => {\n const exitCode = code ?? (signal ? -1 : 0);\n if (isShuttingDown) {\n console.log(`[EFC] Worker ${worker.id} gracefully exited`);\n if (Object.keys(cluster.workers ?? {}).length === 0) {\n console.log('[EFC] All workers exited. Primary exiting.');\n process.exit(0);\n }\n return;\n }\n\n console.warn(`[EFC] Worker ${worker.id} exited (code=${exitCode}), respawning…`);\n options.onWorkerCrash?.(worker.id, exitCode);\n cluster.fork();\n });\n}\n\nexport { cluster };\n","// Wraps mongoose connection for Pre-Flight. Throws clearly if mongoose isn't installed.\n\nlet mongoose: typeof import('mongoose');\n\nasync function loadMongoose(): Promise<typeof import('mongoose')> {\n if (mongoose) return mongoose;\n try {\n mongoose = await import('mongoose');\n return mongoose;\n } catch {\n throw new Error('[EFC] mongoose is not installed. Run: npm install mongoose');\n }\n}\n\nexport async function connectMongo(url: string): Promise<import('mongoose').Connection> {\n const mg = await loadMongoose();\n await mg.connect(url);\n console.log('[EFC] MongoDB connected');\n return mg.connection;\n}\n","import type { ModelSchema, ModelCRUD } from '../types.js';\n\ntype AnyRecord = Record<string, unknown> & { id: string };\n\nfunction normalise(doc: Record<string, unknown>): AnyRecord {\n const id = doc['_id'] ? String(doc['_id']) : '';\n return { ...doc, id } as AnyRecord;\n}\n\nasync function getModel(\n name: string,\n schemaObj: Record<string, unknown>,\n): Promise<import('mongoose').Model<Record<string, unknown>>> {\n let mg: typeof import('mongoose');\n try {\n const mod = await import('mongoose');\n mg = (mod.default || mod) as typeof import('mongoose');\n } catch {\n throw new Error('[EFC] mongoose is not installed. Run: npm install mongoose');\n }\n\n if (mg.models[name]) return mg.models[name] as import('mongoose').Model<Record<string, unknown>>;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const schema = new mg.Schema(schemaObj as any, { timestamps: true });\n return mg.model<Record<string, unknown>>(name, schema);\n}\n\nfunction buildMongooseSchema(schema: ModelSchema): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, def] of Object.entries(schema)) {\n const entry: Record<string, unknown> = {};\n switch (def.type) {\n case 'string':\n entry['type'] = String;\n break;\n case 'number':\n entry['type'] = Number;\n break;\n case 'boolean':\n entry['type'] = Boolean;\n break;\n case 'date':\n entry['type'] = Date;\n break;\n case 'object':\n entry['type'] = Object;\n break;\n case 'array':\n entry['type'] = Array;\n break;\n }\n if (def.required !== undefined) entry['required'] = def.required;\n if (def.unique !== undefined) entry['unique'] = def.unique;\n if (def.default !== undefined) entry['default'] = def.default;\n out[key] = entry;\n }\n return out;\n}\n\nexport function defineModel<T extends Record<string, any>>(\n name: string,\n schema: ModelSchema,\n): ModelCRUD<T> {\n const mongooseSchema = buildMongooseSchema(schema);\n\n return {\n async find(filter = {}) {\n const M = await getModel(name, mongooseSchema);\n const docs = await M.find(filter as Record<string, unknown>).lean();\n return (docs as Record<string, unknown>[]).map(normalise) as (T & { id: string })[];\n },\n\n async findById(id) {\n const M = await getModel(name, mongooseSchema);\n const doc = await M.findById(id).lean();\n if (!doc) return null;\n return normalise(doc as Record<string, unknown>) as T & { id: string };\n },\n\n async findOne(filter) {\n const M = await getModel(name, mongooseSchema);\n const doc = await M.findOne(filter as Record<string, unknown>).lean();\n if (!doc) return null;\n return normalise(doc as Record<string, unknown>) as T & { id: string };\n },\n\n async create(data) {\n const M = await getModel(name, mongooseSchema);\n const doc = await M.create(data);\n return normalise(doc.toObject() as Record<string, unknown>) as T & { id: string };\n },\n\n async update(id, data) {\n const M = await getModel(name, mongooseSchema);\n const doc = await M.findByIdAndUpdate(id, data, { new: true }).lean();\n if (!doc) return null;\n return normalise(doc as Record<string, unknown>) as T & { id: string };\n },\n\n async delete(id) {\n const M = await getModel(name, mongooseSchema);\n await M.findByIdAndDelete(id);\n },\n\n async count(filter = {}) {\n const M = await getModel(name, mongooseSchema);\n return M.countDocuments(filter as Record<string, unknown>);\n },\n };\n}\n","// Thread-local DB client populated during Pre-Flight.\n// The Proxy ensures callers import `db` once and never null-check it —\n// it throws with a helpful message if accessed before Pre-Flight completes.\n\ntype AnyClient = Record<string, unknown>;\n\nlet _client: AnyClient | null = null;\n\nexport function setDbClient(client: AnyClient): void {\n _client = client;\n}\n\nexport function getDbClient(): AnyClient {\n if (!_client) {\n throw new Error('[EFC] db not ready — accessed before Pre-Flight completed');\n }\n return _client;\n}\n\nexport const db: AnyClient = new Proxy({} as AnyClient, {\n get(_target, prop: string) {\n return getDbClient()[prop];\n },\n set(_target, prop: string, value: unknown) {\n getDbClient()[prop] = value;\n return true;\n },\n});\n\nexport { connectMongo } from './mongo.js';\nexport { defineModel } from './model.js';\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { registerTask } from './index.js';\nimport type { TaskDefinition } from '../types.js';\n\nexport async function scanTasks(tasksDir: string): Promise<void> {\n if (!fs.existsSync(tasksDir)) return;\n\n const files = fs.readdirSync(tasksDir).filter((f) => /\\.(ts|js|mts|mjs)$/.test(f));\n\n for (const file of files) {\n const filePath = path.join(tasksDir, file);\n const taskName = path.basename(file, path.extname(file));\n\n try {\n const mod = (await import(filePath)) as Record<string, unknown>;\n const def = mod['default'] as TaskDefinition | undefined;\n\n if (!def || typeof def.handler !== 'function') {\n console.warn(`[EFC] Task file ${file} has no valid default export — skipping`);\n continue;\n }\n\n registerTask(taskName, { ...def, filePath });\n console.log(`[EFC] Registered task: ${taskName}`);\n } catch (err) {\n console.warn(`[EFC] Failed to load task ${file}:`, err);\n }\n }\n}\n","import { Worker, workerData, parentPort, isMainThread } from 'node:worker_threads';\nimport type { TaskDefinition } from '../types.js';\n\n// ── Worker-thread side ────────────────────────────────────────────────────────\nif (!isMainThread) {\n const { handlerPath, payload } = workerData as { handlerPath: string; payload: unknown };\n\n (async () => {\n try {\n const mod = (await import(handlerPath)) as Record<string, unknown>;\n const def = mod['default'] as TaskDefinition | undefined;\n if (!def || typeof def.handler !== 'function') {\n throw new Error(`[EFC] Thread runner: no valid task export in ${handlerPath}`);\n }\n await def.handler(payload);\n parentPort?.postMessage({ ok: true });\n } catch (err) {\n parentPort?.postMessage({ ok: false, error: String(err) });\n }\n })();\n}\n\n// ── Main-thread side ──────────────────────────────────────────────────────────\nexport function runInThread(handlerPath: string, payload: unknown): Promise<void> {\n return new Promise((resolve, reject) => {\n const worker = new Worker(new URL('./thread-runner.js', import.meta.url), {\n workerData: { handlerPath, payload },\n });\n\n worker.on('message', (msg: { ok: boolean; error?: string }) => {\n if (msg.ok) resolve();\n else reject(new Error(msg.error ?? 'Thread task failed'));\n });\n\n worker.on('error', reject);\n worker.on('exit', (code) => {\n if (code !== 0) reject(new Error(`Thread worker exited with code ${code}`));\n });\n });\n}\n","import type { Job } from 'bullmq';\nimport { taskRegistry, setEnqueueImpl } from './index.js';\nimport { runInThread } from './thread-runner.js';\n\ninterface BullMQOpts {\n redisUrl: string;\n concurrency: number;\n}\n\nexport async function initBullMQ(opts: BullMQOpts): Promise<void> {\n let bullmq: typeof import('bullmq');\n try {\n bullmq = await import('bullmq');\n } catch {\n throw new Error('[EFC] bullmq is not installed. Run: npm install bullmq');\n }\n\n const connection = parseRedisUrl(opts.redisUrl);\n const queue = new bullmq.Queue('efc', { connection });\n\n const worker = new bullmq.Worker(\n 'efc',\n async (job: Job) => {\n const def = taskRegistry.get(job.name);\n if (!def) {\n throw new Error(`[EFC] No task registered for name: ${job.name}`);\n }\n\n if (def.options.thread && def.filePath) {\n await runInThread(def.filePath, job.data);\n } else {\n await def.handler(job.data);\n }\n },\n { connection, concurrency: opts.concurrency },\n );\n\n worker.on('failed', (job: Job | undefined, err: Error) => {\n console.error(`[EFC] Task ${job?.name ?? 'unknown'} failed:`, err.message);\n });\n\n worker.on('completed', (job: Job) => {\n console.log(`[EFC] Task ${job.name} completed (id=${job.id})`);\n });\n\n setEnqueueImpl(async (name, payload) => {\n const def = taskRegistry.get(name);\n if (!def) {\n throw new Error(\n `[EFC] Cannot enqueue unknown task: \"${name}\". Is the task file in tasksDir?`,\n );\n }\n\n await queue.add(name, payload, {\n attempts: def.options.retries ?? 3,\n backoff: {\n type: def.options.backoff ?? 'exponential',\n delay: 1000,\n },\n });\n });\n\n console.log('[EFC] BullMQ backend initialised');\n}\n\nfunction parseRedisUrl(url: string): { host: string; port: number; password?: string } {\n try {\n const u = new URL(url);\n const result: { host: string; port: number; password?: string } = {\n host: u.hostname || 'localhost',\n port: parseInt(u.port || '6379', 10),\n };\n if (u.password) result.password = u.password;\n return result;\n } catch {\n return { host: 'localhost', port: 6379 };\n }\n}\n","import type { MountedRoute } from './types.js';\n\nconst HTTP_STATUS: Record<number, string> = {\n 200: 'OK',\n 201: 'Created',\n 202: 'Accepted',\n 204: 'No Content',\n 400: 'Bad Request',\n 401: 'Unauthorized',\n 403: 'Forbidden',\n 404: 'Not Found',\n 405: 'Method Not Allowed',\n 409: 'Conflict',\n 422: 'Unprocessable Entity',\n 500: 'Internal Server Error',\n 503: 'Service Unavailable',\n};\n\nexport function generateDashboard(\n routes: MountedRoute[],\n basePath: string,\n port: number,\n projectName: string,\n projectVersion: string,\n): string {\n const safeRoutes = JSON.stringify(\n routes.map((r) => ({\n urlPath: r.urlPath,\n methods: r.methods,\n params: r.params,\n meta: r.meta ?? null,\n })),\n ).replace(/<\\/script>/gi, '<\\\\/script>');\n const safeHttpStatus = JSON.stringify(HTTP_STATUS);\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${projectName} — API Reference</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap\" rel=\"stylesheet\" />\n <style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n :root {\n --bg: #080b0f;\n --bg-card: #0d1117;\n --bg-raised: #111820;\n --border: #1e2832;\n --border-lit: #263040;\n --text: #e2e8f0;\n --text-dim: #64748b;\n --text-muted: #334155;\n --accent: #F0A030;\n --accent-dim: rgba(240,160,48,.12);\n --accent-glow: rgba(240,160,48,.22);\n --purple: #a78bfa;\n --blue: #60a5fa;\n --orange: #fb923c;\n --green: #7AAE8E;\n --radius: 10px;\n --radius-lg: 16px;\n --font-mono: 'JetBrains Mono', monospace;\n --font-sans: 'Inter', sans-serif;\n }\n html { scroll-behavior: smooth; }\n body {\n background: var(--bg); color: var(--text);\n font-family: var(--font-sans); font-size: 16px;\n line-height: 1.6; -webkit-font-smoothing: antialiased;\n position: relative;\n }\n body::before {\n content: ''; position: fixed; inset: 0; z-index: 0;\n background-image:\n linear-gradient(var(--border) 1px, transparent 1px),\n linear-gradient(90deg, var(--border) 1px, transparent 1px);\n background-size: 60px 60px; opacity: .28; pointer-events: none;\n }\n section, footer, .page-hero, .docs-layout { position: relative; z-index: 1; }\n a { text-decoration: none; color: inherit; }\n em { font-style: italic; }\n code {\n font-family: var(--font-mono); font-size: .85em;\n background: var(--bg-raised); border: 1px solid var(--border);\n border-radius: 4px; padding: 1px 6px; color: var(--accent);\n }\n .container { max-width: 1140px; margin: 0 auto; padding: 0 24px; }\n ::-webkit-scrollbar { width: 6px; }\n ::-webkit-scrollbar-track { background: var(--bg); }\n ::-webkit-scrollbar-thumb { background: var(--border-lit); border-radius: 3px; }\n\n /* ── PAGE HERO ── */\n .page-hero {\n padding: 48px 0 56px; border-bottom: 1px solid var(--border);\n }\n .page-hero .hero-glow {\n position: absolute; top: -40px; left: 10%; width: 500px; height: 350px;\n background: radial-gradient(ellipse, rgba(240,160,48,.1) 0%, transparent 68%);\n pointer-events: none;\n }\n .page-title {\n font-size: clamp(2rem, 5vw, 3.4rem); font-weight: 800;\n line-height: 1.1; letter-spacing: -.02em; margin-bottom: 24px;\n display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap;\n }\n .project-version {\n font-family: var(--font-mono); font-size: clamp(.85rem, 2vw, 1.1rem);\n font-weight: 500; color: var(--accent);\n background: var(--accent-dim); border: 1px solid rgba(240,160,48,.3);\n border-radius: 6px; padding: 2px 10px; letter-spacing: .5px;\n }\n .hero-meta { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 40px; }\n .base-url-pill {\n display: flex; align-items: center; gap: 8px;\n background: var(--bg-card); border: 1px solid var(--border);\n border-radius: 7px; padding: 8px 14px;\n }\n .base-url-label { font-size: .72rem; font-family: var(--font-mono);\n color: var(--text-muted); text-transform: uppercase; letter-spacing: .5px; }\n .base-url-val { font-family: var(--font-mono); font-size: .8rem; color: var(--accent); }\n .count-pill {\n font-family: var(--font-mono); font-size: .72rem; color: var(--text-dim);\n background: var(--bg-card); border: 1px solid var(--border);\n border-radius: 7px; padding: 8px 14px;\n }\n\n /* ── TOOLBAR ── */\n .toolbar {\n display: flex; align-items: center; gap: 12px; flex-wrap: wrap;\n }\n .method-filters { display: flex; gap: 4px; flex-wrap: wrap; }\n .filter-btn {\n background: var(--bg-card); border: 1px solid var(--border);\n color: var(--text-dim); font-family: var(--font-mono);\n font-size: .72rem; font-weight: 600; letter-spacing: .5px;\n padding: 6px 12px; border-radius: 6px; cursor: pointer;\n transition: all .15s;\n }\n .filter-btn:hover { border-color: var(--border-lit); color: var(--text); }\n .filter-btn.active { background: var(--accent); color: #0d0d1a; border-color: var(--accent); }\n .filter-btn[data-method=\"GET\"].active { background: rgba(96,165,250,.18); color: #60a5fa; border-color: rgba(96,165,250,.4); }\n .filter-btn[data-method=\"POST\"].active { background: rgba(122,174,142,.18); color: #7AAE8E; border-color: rgba(122,174,142,.4); }\n .filter-btn[data-method=\"PUT\"].active { background: rgba(240,160,48,.18); color: #F0A030; border-color: rgba(240,160,48,.4); }\n .filter-btn[data-method=\"PATCH\"].active { background: rgba(251,191,36,.18); color: #fbbf24; border-color: rgba(251,191,36,.4); }\n .filter-btn[data-method=\"DELETE\"].active { background: rgba(248,113,113,.18); color: #f87171; border-color: rgba(248,113,113,.4); }\n .filter-btn[data-method=\"HEAD\"].active { background: rgba(167,139,250,.18); color: #a78bfa; border-color: rgba(167,139,250,.4); }\n .search-wrap { margin-left: auto; }\n .search-input {\n background: var(--bg-card); border: 1px solid var(--border);\n color: var(--text); font-family: var(--font-sans); font-size: .85rem;\n padding: 7px 14px; border-radius: 7px; width: 240px;\n outline: none; transition: border-color .2s;\n }\n .search-input::placeholder { color: var(--text-muted); }\n .search-input:focus { border-color: var(--border-lit); }\n\n /* ── DOCS LAYOUT ── */\n .docs-layout {\n display: grid; grid-template-columns: 260px 1fr;\n gap: 48px; padding: 52px 0 80px; max-width: 1140px;\n margin: 0 auto; padding-left: 24px; padding-right: 24px;\n align-items: start;\n }\n\n /* ── SIDEBAR ── */\n .docs-sidebar {\n position: sticky; top: 24px;\n max-height: calc(100vh - 48px);\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: none;\n padding-right: 4px;\n }\n .docs-sidebar::-webkit-scrollbar { display: none; }\n .sidebar-section { margin-bottom: 28px; }\n .sidebar-label {\n font-family: var(--font-mono); font-size: .68rem; font-weight: 600;\n color: var(--text-muted); letter-spacing: 1.2px; text-transform: uppercase;\n margin-bottom: 8px; padding: 0 4px;\n }\n .sidebar-link {\n display: flex; align-items: center; gap: 8px;\n padding: 7px 10px; border-radius: 6px;\n border-left: 2px solid transparent;\n font-size: .82rem; color: var(--text-dim); cursor: pointer;\n transition: background .15s, color .15s, border-color .15s;\n overflow: hidden; white-space: nowrap;\n }\n .sidebar-link:hover { background: var(--bg-raised); color: var(--text); }\n .sidebar-link.active { color: var(--accent); border-left-color: var(--accent); background: var(--accent-dim); }\n .sidebar-method-dot {\n width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;\n }\n .sidebar-path { font-family: var(--font-mono); font-size: .72rem; }\n\n /* ── ENDPOINT CARDS ── */\n .endpoint-card {\n background: var(--bg-card); border: 1px solid var(--border);\n border-radius: var(--radius-lg); margin-bottom: 20px;\n overflow: hidden; transition: border-color .2s;\n animation: fadeUp .45s ease both;\n }\n .endpoint-card:hover { border-color: var(--border-lit); }\n @keyframes fadeUp {\n from { opacity: 0; transform: translateY(16px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @media (prefers-reduced-motion: reduce) {\n .endpoint-card { animation: none; }\n }\n .endpoint-header {\n display: flex; align-items: center; gap: 14px;\n padding: 20px 24px 18px; border-bottom: 1px solid var(--border);\n flex-wrap: wrap;\n }\n .method-badges { display: flex; gap: 6px; flex-wrap: wrap; }\n .method-badge {\n font-family: var(--font-mono); font-size: .7rem; font-weight: 600;\n letter-spacing: .8px; padding: 4px 10px; border-radius: 5px;\n border: 1px solid; text-transform: uppercase;\n }\n .endpoint-path {\n font-family: var(--font-mono); font-size: .9rem; color: var(--text);\n background: none; border: none; padding: 0;\n word-break: break-all;\n }\n .endpoint-body { padding: 6px 24px 24px; }\n .endpoint-desc { font-size: .9rem; color: var(--text-dim); line-height: 1.7; margin-bottom: 20px; }\n\n /* ── PER-METHOD DOC BLOCKS ── */\n .method-block { padding-top: 20px; }\n .method-block + .method-block { margin-top: 4px; border-top: 1px solid var(--border); }\n .method-block-header { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }\n .method-block-header .method-badge { font-size: .68rem; }\n .method-block-empty { font-size: .82rem; color: var(--text-muted); }\n\n /* ── CODE BLOCKS ── */\n .example-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .code-block-wrap {\n background: var(--bg-raised); border: 1px solid var(--border);\n border-radius: var(--radius); overflow: hidden;\n }\n .code-bar {\n display: flex; align-items: center; gap: 6px;\n padding: 9px 14px; border-bottom: 1px solid var(--border);\n background: var(--bg-card);\n }\n .dot { width: 11px; height: 11px; border-radius: 50%; }\n .dot-r { background: #ff5f57; }\n .dot-y { background: #febc2e; }\n .dot-g { background: #28c840; }\n .code-label { font-family: var(--font-mono); font-size: .68rem; color: var(--text-dim); margin-left: 4px; }\n pre.code-pre {\n font-family: var(--font-mono); font-size: .78rem; line-height: 1.7;\n padding: 16px 18px; overflow-x: auto; tab-size: 2; white-space: pre;\n }\n .c-dim { color: var(--text-muted); }\n .c-green { color: #7AAE8E; }\n .c-blue { color: #60a5fa; }\n .c-orange { color: #fb923c; }\n .c-purple { color: #a78bfa; }\n .c-accent { color: var(--accent); }\n .status-2xx { color: #7AAE8E; }\n .status-4xx { color: #f87171; }\n .status-5xx { color: #fb923c; }\n\n /* ── EMPTY STATE ── */\n .empty-state {\n text-align: center; padding: 80px 24px;\n color: var(--text-muted); font-size: .9rem;\n }\n\n /* ── RESPONSIVE ── */\n @media (max-width: 900px) {\n .docs-layout { grid-template-columns: 1fr; }\n .docs-sidebar { position: static; max-height: none; overflow-y: visible; padding-right: 0; }\n .example-grid { grid-template-columns: 1fr; }\n .search-wrap { margin-left: 0; width: 100%; }\n .search-input { width: 100%; }\n }\n @media (max-width: 600px) {\n .page-hero { padding: 32px 0 32px; }\n .page-title { font-size: 2rem; }\n }\n </style>\n</head>\n<body>\n\n <div class=\"page-hero\">\n <div class=\"hero-glow\"></div>\n <div class=\"container\">\n <h1 class=\"page-title\">${projectName}${projectVersion ? `<span class=\"project-version\">v${projectVersion}</span>` : ''}</h1>\n <div class=\"hero-meta\">\n <div class=\"base-url-pill\">\n <span class=\"base-url-label\">Base</span>\n <span class=\"base-url-val\">http://localhost:${port}${basePath}</span>\n </div>\n <div class=\"count-pill\" id=\"countPill\"></div>\n </div>\n <div class=\"toolbar\">\n <div class=\"method-filters\" id=\"methodFilters\">\n <button class=\"filter-btn active\" data-method=\"ALL\">ALL</button>\n </div>\n <div class=\"search-wrap\">\n <input type=\"text\" id=\"searchInput\" class=\"search-input\" placeholder=\"Search endpoints…\" />\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"docs-layout\">\n <aside class=\"docs-sidebar\" id=\"sidebar\"></aside>\n <main id=\"endpoints\"></main>\n </div>\n\n <script>\n const ROUTES = ${safeRoutes};\n const BASE_PATH = ${JSON.stringify(basePath)};\n const HTTP_STATUS = ${safeHttpStatus};\n\n const METHOD_STYLE = {\n GET: { bg: 'rgba(96,165,250,.14)', color: '#60a5fa', border: 'rgba(96,165,250,.35)' },\n POST: { bg: 'rgba(122,174,142,.14)', color: '#7AAE8E', border: 'rgba(122,174,142,.35)' },\n PUT: { bg: 'rgba(240,160,48,.14)', color: '#F0A030', border: 'rgba(240,160,48,.35)' },\n PATCH: { bg: 'rgba(251,191,36,.14)', color: '#fbbf24', border: 'rgba(251,191,36,.35)' },\n DELETE: { bg: 'rgba(248,113,113,.14)', color: '#f87171', border: 'rgba(248,113,113,.35)' },\n HEAD: { bg: 'rgba(167,139,250,.14)', color: '#a78bfa', border: 'rgba(167,139,250,.35)' },\n OPTIONS: { bg: 'rgba(148,163,184,.14)', color: '#94a3b8', border: 'rgba(148,163,184,.35)' },\n };\n\n function esc(s) {\n return String(s)\n .replace(/&/g,'&amp;').replace(/</g,'&lt;')\n .replace(/>/g,'&gt;').replace(/\"/g,'&quot;');\n }\n\n function methodBadge(m) {\n const s = METHOD_STYLE[m] || METHOD_STYLE.GET;\n return '<span class=\"method-badge\" style=\"background:' + s.bg + ';color:' + s.color + ';border-color:' + s.border + '\">' + m + '</span>';\n }\n\n function joinPath(base, p) {\n return (base.replace(/\\\\/+$/, '') + p) || '/';\n }\n\n function sidebarDot(method) {\n const s = METHOD_STYLE[method] || METHOD_STYLE.GET;\n return '<span class=\"sidebar-method-dot\" style=\"background:' + s.color + '\"></span>';\n }\n\n function statusClass(code) {\n if (code >= 200 && code < 300) return 'status-2xx';\n if (code >= 400 && code < 500) return 'status-4xx';\n if (code >= 500) return 'status-5xx';\n return '';\n }\n\n function renderSchema(val, indent) {\n const pad = ' '.repeat(indent || 0);\n if (val === null) return '<span class=\"c-dim\">null</span>';\n if (typeof val === 'string') {\n const isDate = /^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}:\\\\d{2}/.test(val);\n return isDate ? '<span class=\"c-green\">Date</span>' : '<span class=\"c-purple\">String</span>';\n }\n if (typeof val === 'number') return '<span class=\"c-orange\">Number</span>';\n if (typeof val === 'boolean') return '<span class=\"c-purple\">Boolean</span>';\n if (Array.isArray(val)) {\n if (!val.length) return '[]';\n return '[\\\\n' + pad + ' ' + renderSchema(val[0], (indent || 0) + 1) + '\\\\n' + pad + ']';\n }\n if (typeof val === 'object') {\n const keys = Object.keys(val);\n if (!keys.length) return '{}';\n const inner = keys.map(function(k) {\n return pad + ' <span class=\"c-blue\">&quot;' + esc(k) + '&quot;</span>: ' + renderSchema(val[k], (indent || 0) + 1);\n }).join(',\\\\n');\n return '{\\\\n' + inner + '\\\\n' + pad + '}';\n }\n return esc(String(val));\n }\n\n function codeBlock(label, content) {\n return '<div class=\"code-block-wrap\">' +\n '<div class=\"code-bar\">' +\n '<span class=\"dot dot-r\"></span>' +\n '<span class=\"dot dot-y\"></span>' +\n '<span class=\"dot dot-g\"></span>' +\n '<span class=\"code-label\">' + esc(label) + '</span>' +\n '</div>' +\n '<pre class=\"code-pre\">' + content + '</pre>' +\n '</div>';\n }\n\n function buildRequestContent(route, method, example) {\n const req = example || {};\n let path = joinPath(BASE_PATH, route.urlPath);\n if (req.params) {\n for (const [k, v] of Object.entries(req.params)) {\n path = path.replace(':' + k, String(v));\n }\n }\n if (req.query && Object.keys(req.query).length) {\n path += '?' + new URLSearchParams(req.query).toString();\n }\n let lines = '<span class=\"c-accent\">' + esc(method) + '</span> <span class=\"c-blue\">' + esc(path) + '</span>';\n const headers = { ...(req.headers || {}) };\n if (req.body !== undefined && !headers['Content-Type']) {\n headers['Content-Type'] = 'application/json';\n }\n if (Object.keys(headers).length) {\n lines += '\\\\n' + Object.entries(headers)\n .map(([k, v]) => '<span class=\"c-dim\">' + esc(k) + ':</span> ' + esc(String(v)))\n .join('\\\\n');\n }\n if (req.body !== undefined) {\n lines += '\\\\n\\\\n' + renderSchema(req.body, 0);\n }\n return lines;\n }\n\n function buildResponseContent(example) {\n const resp = example || {};\n const code = resp.status || 200;\n const text = HTTP_STATUS[code] || 'OK';\n const cls = statusClass(code);\n let lines = 'HTTP/1.1 <span class=\"' + cls + '\">' + code + ' ' + esc(text) + '</span>';\n if (resp.body !== undefined) {\n lines += '\\\\n<span class=\"c-dim\">Content-Type:</span> application/json\\\\n\\\\n';\n lines += renderSchema(resp.body, 0);\n }\n return lines;\n }\n\n function renderMethodBlock(route, method) {\n const methodMeta = route.meta ? route.meta[method] : null;\n const header = '<div class=\"method-block-header\">' + methodBadge(method) + '</div>';\n\n if (!methodMeta) {\n return '<div class=\"method-block\" data-method=\"' + esc(method) + '\">' + header +\n '<p class=\"method-block-empty\">No documentation provided for this method.</p></div>';\n }\n\n const desc = methodMeta.description\n ? '<p class=\"endpoint-desc\">' + esc(methodMeta.description) + '</p>'\n : '';\n const reqHtml = methodMeta.request !== undefined\n ? codeBlock('request', buildRequestContent(route, method, methodMeta.request))\n : '';\n const respHtml = methodMeta.response !== undefined\n ? codeBlock('response', buildResponseContent(methodMeta.response))\n : '';\n const examples = reqHtml || respHtml\n ? '<div class=\"example-grid\">' + reqHtml + respHtml + '</div>'\n : '';\n\n return '<div class=\"method-block\" data-method=\"' + esc(method) + '\">' + header + desc + examples + '</div>';\n }\n\n function renderCard(route, index) {\n const id = 'ep-' + index;\n const fullPath = joinPath(BASE_PATH, route.urlPath);\n const badges = route.methods.map(methodBadge).join('');\n const body = route.methods.map(function(m) { return renderMethodBlock(route, m); }).join('');\n const delay = (index * 0.06).toFixed(2) + 's';\n return '<div class=\"endpoint-card\" id=\"' + id + '\" data-methods=\"' + route.methods.join(',') + '\" data-path=\"' + esc(fullPath) + '\" style=\"animation-delay:' + delay + '\">' +\n '<div class=\"endpoint-header\">' +\n '<div class=\"method-badges\">' + badges + '</div>' +\n '<code class=\"endpoint-path\">' + esc(fullPath) + '</code>' +\n '</div>' +\n '<div class=\"endpoint-body\">' + body + '</div>' +\n '</div>';\n }\n\n function buildMethodFilters() {\n const allMethods = [...new Set(ROUTES.flatMap(r => r.methods))].sort();\n const filtersEl = document.getElementById('methodFilters');\n allMethods.forEach(m => {\n const btn = document.createElement('button');\n btn.className = 'filter-btn';\n btn.dataset.method = m;\n btn.textContent = m;\n filtersEl.appendChild(btn);\n });\n }\n\n function buildSidebar(routes) {\n const sidebar = document.getElementById('sidebar');\n if (!routes.length) { sidebar.innerHTML = ''; return; }\n\n const label = document.createElement('div');\n label.className = 'sidebar-label';\n label.textContent = 'Endpoints';\n sidebar.appendChild(label);\n\n routes.forEach((route, i) => {\n const link = document.createElement('div');\n link.className = 'sidebar-link';\n link.dataset.target = 'ep-' + ROUTES.indexOf(route);\n link.innerHTML = sidebarDot(route.methods[0] || 'GET') +\n '<span class=\"sidebar-path\">' + esc(route.urlPath || '/') + '</span>';\n link.addEventListener('click', () => {\n const target = document.getElementById(link.dataset.target);\n if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });\n });\n sidebar.appendChild(link);\n });\n }\n\n let activeFilter = 'ALL';\n let searchQuery = '';\n\n function applyFilters() {\n const cards = document.querySelectorAll('.endpoint-card');\n let visible = 0;\n cards.forEach(card => {\n const methods = card.dataset.methods.split(',');\n const path = card.dataset.path || '';\n const matchMethod = activeFilter === 'ALL' || methods.includes(activeFilter);\n const matchSearch = !searchQuery || path.toLowerCase().includes(searchQuery);\n const show = matchMethod && matchSearch;\n card.style.display = show ? '' : 'none';\n if (show) visible++;\n });\n document.getElementById('empty-state').style.display = visible ? 'none' : 'block';\n\n // Sync sidebar visibility\n document.querySelectorAll('.sidebar-link').forEach(link => {\n const targetId = link.dataset.target;\n const targetCard = document.getElementById(targetId);\n link.style.display = targetCard && targetCard.style.display !== 'none' ? '' : 'none';\n });\n }\n\n function init() {\n const count = ROUTES.length;\n document.getElementById('countPill').textContent = count + ' endpoint' + (count !== 1 ? 's' : '');\n\n buildMethodFilters();\n\n const container = document.getElementById('endpoints');\n container.innerHTML = ROUTES.map((r, i) => renderCard(r, i)).join('');\n\n // Add empty state after cards\n const emptyEl = document.createElement('div');\n emptyEl.id = 'empty-state';\n emptyEl.className = 'empty-state';\n emptyEl.style.display = 'none';\n emptyEl.innerHTML = '<p>No endpoints match your filter.</p>';\n container.after(emptyEl);\n\n buildSidebar(ROUTES);\n\n // Method filter clicks\n document.getElementById('methodFilters').addEventListener('click', e => {\n const btn = e.target.closest('.filter-btn');\n if (!btn) return;\n document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));\n btn.classList.add('active');\n activeFilter = btn.dataset.method;\n applyFilters();\n });\n\n // Search\n document.getElementById('searchInput').addEventListener('input', e => {\n searchQuery = e.target.value.trim().toLowerCase();\n applyFilters();\n });\n\n // Scroll spy for sidebar\n const cardEls = document.querySelectorAll('.endpoint-card');\n const sidebarLinks = document.querySelectorAll('.sidebar-link');\n const observer = new IntersectionObserver(entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const id = entry.target.id;\n sidebarLinks.forEach(l => l.classList.toggle('active', l.dataset.target === id));\n const sidebar = document.getElementById('sidebar');\n const activeLink = sidebar && sidebar.querySelector('.sidebar-link.active');\n if (sidebar && activeLink) {\n const linkTop = activeLink.getBoundingClientRect().top - sidebar.getBoundingClientRect().top + sidebar.scrollTop;\n sidebar.scrollTo({ top: linkTop, behavior: 'smooth' });\n }\n }\n });\n }, { rootMargin: '-80px 0px -60% 0px' });\n cardEls.forEach(el => observer.observe(el));\n\n }\n\n try {\n init();\n } catch (e) {\n document.body.insertAdjacentHTML('afterbegin',\n '<div style=\"position:fixed;top:60px;left:0;right:0;z-index:9999;background:#7f1d1d;color:#fca5a5;padding:16px 24px;font-family:monospace;font-size:13px;border-bottom:1px solid #ef4444\">' +\n '<strong>Dashboard JS error:</strong> ' + (e && e.message ? e.message : String(e)) +\n (e && e.stack ? '<pre style=\"margin-top:8px;white-space:pre-wrap\">' + e.stack + '</pre>' : '') +\n '</div>'\n );\n }\n </script>\n</body>\n</html>`;\n}\n","export class HttpError extends Error {\n readonly statusCode: number;\n\n constructor(statusCode: number, message: string) {\n super(message);\n this.name = 'HttpError';\n this.statusCode = statusCode;\n Error.captureStackTrace(this, HttpError);\n }\n}\n","import type { RequestHandler } from 'express';\n\nexport function compose(...handlers: RequestHandler[]): RequestHandler {\n return (req, res, next) => {\n let index = 0;\n\n function dispatch(i: number): void {\n if (i >= handlers.length) {\n next();\n return;\n }\n const handler = handlers[i];\n if (!handler) {\n next();\n return;\n }\n try {\n Promise.resolve(handler(req, res, () => dispatch(i + 1))).catch(next);\n } catch (err) {\n next(err);\n }\n }\n\n dispatch(index);\n };\n}\n"]}
1
+ {"version":3,"sources":["/home/prashant/Projects/temp-nodejs/packages/core/dist/index.cjs","../src/index.ts","../src/router/mount.ts","../src/cluster/index.ts","../src/db/mongo.ts","../src/db/model.ts","../src/db/index.ts","../src/tasks/scanner.ts","../src/tasks/thread-runner.ts","../src/tasks/bullmq-backend.ts","../src/dashboard.ts","../src/errors.ts","../src/compose.ts"],"names":[],"mappings":"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","file":"/home/prashant/Projects/temp-nodejs/packages/core/dist/index.cjs","sourcesContent":[null,"import http from 'node:http';\nimport fs from 'node:fs';\nimport express from 'express';\nimport cors from 'cors';\nimport cookieParser from 'cookie-parser';\nimport cluster from 'node:cluster';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { EFCConfig, MountedRoute } from './types.js';\nimport { scanDir } from './router/scan.js';\nimport { mountRoutes } from './router/mount.js';\nimport { runMaster, shutdownMaster } from './cluster/index.js';\nimport { configureAuth } from './auth/index.js';\nimport { HttpError } from './errors.js';\nimport { connectMongo } from './db/mongo.js';\nimport { setDbClient } from './db/index.js';\nimport { scanTasks } from './tasks/scanner.js';\nimport { initBullMQ } from './tasks/bullmq-backend.js';\nimport { generateDashboard } from './dashboard.js';\n\nfunction detectDatabase(url?: string): 'mongodb' | 'postgresql' | undefined {\n if (!url) return undefined;\n if (url.startsWith('mongodb')) return 'mongodb';\n if (url.startsWith('postgres')) return 'postgresql';\n return undefined;\n}\n\nexport async function ignite(config: EFCConfig): Promise<http.Server | undefined> {\n const {\n port: _port,\n workers,\n globalMiddlewares = [],\n onWorkerReady,\n onWorkerCrash,\n onError,\n } = config;\n\n // Resolve api/tasks dirs from convention. argv[1]-based resolution is unreliable in tsx watch\n // + cluster workers (argv[1] can point to the tsx binary instead of the user's script), so we\n // probe multiple candidates and use the first that exists on disk.\n function resolveConventionDir(name: string): string {\n const candidates: string[] = [\n ...(process.argv[1] ? [path.join(path.dirname(process.argv[1]), name)] : []),\n path.join(process.cwd(), 'src', name),\n path.join(process.cwd(), name),\n path.join(process.cwd(), 'dist', name),\n ];\n return candidates.find((c) => fs.existsSync(c)) ?? candidates[0]!;\n }\n const apiDir = resolveConventionDir('api');\n const tasksDir = resolveConventionDir('tasks');\n const basePath = config.basePath ?? '/v1/api';\n\n function readProjectMeta(): { name: string; version: string } {\n try {\n const raw = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8');\n const pkg = JSON.parse(raw) as { name?: string; version?: string };\n return { name: pkg.name ?? 'API', version: pkg.version ?? '' };\n } catch {\n return { name: 'API', version: '' };\n }\n }\n\n const envPort = process.env['PORT'] != null ? Number(process.env['PORT']) : NaN;\n const port =\n _port != null && !Number.isNaN(_port) ? _port : !Number.isNaN(envPort) ? envPort : 3000;\n const databaseUrl = config.databaseUrl ?? process.env['DATABASE_URL'];\n const database = config.database ?? detectDatabase(databaseUrl);\n const jwtSecret = config.jwtSecret ?? process.env['JWT_SECRET'];\n const authStrategy = config.authStrategy ?? 'http-only';\n const clusterEnabled = config.cluster ?? process.env['NODE_ENV'] === 'production';\n\n if (clusterEnabled && cluster.isPrimary) {\n runMaster({\n workers: workers ?? os.cpus().length,\n ...(onWorkerReady !== undefined && { onWorkerReady }),\n ...(onWorkerCrash !== undefined && { onWorkerCrash }),\n });\n return;\n }\n\n const app = express();\n\n const corsOption = config.cors ?? true;\n if (corsOption !== false) {\n const envOrigins = process.env['CORS_ORIGINS'];\n let origin: string | string[] | boolean;\n if (envOrigins) {\n const list = envOrigins\n .split(',')\n .map((o) => o.trim())\n .filter(Boolean);\n origin = list; // always array so cors validates against the request Origin\n } else if (typeof corsOption === 'object' && corsOption.origin !== undefined) {\n origin = corsOption.origin;\n } else {\n origin = true;\n }\n const corsOpts = typeof corsOption === 'object' ? { ...corsOption, origin } : { origin };\n app.use(cors(corsOpts));\n }\n\n app.use(express.json());\n app.use(express.urlencoded({ extended: true }));\n app.use(cookieParser());\n\n for (const mw of globalMiddlewares) {\n app.use(mw);\n }\n\n // Pre-Flight step 1: Connect database\n if (database === 'mongodb' && databaseUrl) {\n const conn = await connectMongo(databaseUrl);\n setDbClient(conn as unknown as Record<string, unknown>);\n }\n\n // Pre-Flight step 2: Configure auth\n if (jwtSecret) {\n const cookieDomain = process.env['COOKIE_DOMAIN'];\n configureAuth({\n secret: jwtSecret,\n strategy: authStrategy,\n expiresIn: process.env['JWT_EXPIRES_IN'] ?? '7d',\n ...(cookieDomain !== undefined && { cookieDomain }),\n });\n }\n\n // Pre-Flight step 3: Scan and register tasks\n if (tasksDir) {\n await scanTasks(tasksDir);\n }\n\n // Pre-Flight step 4: Start task queue backend\n if (config.tasks) {\n if (config.tasks.backend === 'bullmq') {\n await initBullMQ({\n redisUrl: config.tasks.redisUrl ?? 'redis://localhost:6379',\n concurrency: config.tasks.concurrency ?? 5,\n });\n }\n }\n\n // Pre-Flight step 5: Scan routes and mount\n const routes = scanDir(apiDir);\n const apiRouter = express.Router();\n const mounted: MountedRoute[] = await mountRoutes(apiRouter, routes);\n app.use(basePath, apiRouter);\n\n if (config.dashboard !== false && process.env['NODE_ENV'] === 'development') {\n app.get('/', (_req, res) => {\n const { name, version } = readProjectMeta();\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.send(generateDashboard(mounted, basePath, port, name, version));\n });\n }\n\n if (onError) {\n app.use(onError);\n } else {\n app.use(\n (err: unknown, _req: express.Request, res: express.Response, _next: express.NextFunction) => {\n const asHttp = err instanceof Error && 'statusCode' in err ? (err as HttpError) : null;\n if (asHttp) {\n res\n .status(asHttp.statusCode)\n .json({ error: asHttp.message, statusCode: asHttp.statusCode });\n } else {\n console.error('[EFC] Unhandled error:', err);\n res.status(500).json({ error: 'Internal Server Error', statusCode: 500 });\n }\n },\n );\n }\n\n return new Promise<http.Server>((resolve, reject) => {\n const server = app.listen(port);\n\n server.once('listening', () => {\n const wid = (cluster.worker as { id: number } | undefined)?.id ?? 'primary';\n const addr = server.address() as { port: number } | null;\n console.log(`[EFC] Worker ${wid} listening on :${addr?.port ?? port}`);\n resolve(server);\n });\n\n server.once('error', reject);\n });\n}\n\nexport function gracefulShutdown(server: http.Server | undefined, timeoutMs = 10_000): void {\n const shutdown = (signal: string) => {\n console.log(`[EFC] ${signal} received — closing server gracefully…`);\n if (server) {\n server.closeIdleConnections();\n server.close(() => {\n console.log('[EFC] Server closed');\n process.exit(0);\n });\n setTimeout(() => {\n console.error('[EFC] Forced exit after timeout');\n process.exit(1);\n }, timeoutMs).unref();\n } else {\n shutdownMaster();\n }\n };\n process.once('SIGTERM', () => shutdown('SIGTERM'));\n process.once('SIGINT', () => shutdown('SIGINT'));\n}\n\nexport { HttpError } from './errors.js';\nexport { compose } from './compose.js';\nexport { db, setDbClient, getDbClient, defineModel } from './db/index.js';\nexport { scanDir } from './router/scan.js';\nexport type {\n EFCConfig,\n CorsConfig,\n RouteEntry,\n RouteMeta,\n RouteMethodMeta,\n TaskOptions,\n TaskDefinition,\n DatabaseEngine,\n AuthStrategy,\n ModelSchema,\n ModelCRUD,\n} from './types.js';\n","import type { IRouter, RequestHandler } from 'express';\nimport type { MountedRoute, RouteMeta, RouteEntry } from '../types.js';\n\nconst HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const;\ntype HttpMethod = (typeof HTTP_METHODS)[number];\n\nfunction asyncWrap(handler: RequestHandler): RequestHandler {\n return (req, res, next) => {\n Promise.resolve(handler(req, res, next)).catch(next);\n };\n}\n\nexport async function mountRoutes(\n app: IRouter,\n routes: RouteEntry[],\n): Promise<MountedRoute[]> {\n const mounted: MountedRoute[] = [];\n\n for (const route of routes) {\n const mod = (await import(route.filePath)) as Record<string, unknown>;\n const routeMiddlewares: RequestHandler[] = Array.isArray(mod['middlewares'])\n ? (mod['middlewares'] as RequestHandler[])\n : [];\n\n const raw = mod['meta'];\n const meta: RouteMeta | undefined =\n raw != null && typeof raw === 'object' && !Array.isArray(raw)\n ? (raw as RouteMeta)\n : undefined;\n\n const implemented: HttpMethod[] = [];\n const unimplemented: HttpMethod[] = [];\n\n for (const method of HTTP_METHODS) {\n if (typeof mod[method] === 'function') {\n implemented.push(method);\n app[method.toLowerCase() as Lowercase<HttpMethod>](\n route.urlPath,\n ...routeMiddlewares,\n asyncWrap(mod[method] as RequestHandler),\n );\n } else {\n unimplemented.push(method);\n }\n }\n\n if (implemented.length > 0 && unimplemented.length > 0) {\n const allowHeader = implemented.join(', ');\n app.all(route.urlPath, (req, res, next) => {\n if ((unimplemented as string[]).includes(req.method)) {\n res.set('Allow', allowHeader).status(405).json({ error: 'Method Not Allowed' });\n } else {\n next();\n }\n });\n }\n\n mounted.push({ ...route, methods: implemented, ...(meta !== undefined && { meta }) });\n }\n\n return mounted;\n}\n\nexport { asyncWrap };\n","import cluster from 'node:cluster';\nimport os from 'node:os';\n\ninterface ClusterOptions {\n workers?: number;\n onWorkerReady?: ((id: number) => void) | undefined;\n onWorkerCrash?: ((id: number, code: number) => void) | undefined;\n}\n\nlet isShuttingDown = false;\n\nexport function shutdownMaster(): void {\n isShuttingDown = true;\n console.log('[EFC] Cluster master shutting down, waiting for workers…');\n}\n\nexport function runMaster(options: ClusterOptions = {}): void {\n const count = options.workers ?? os.cpus().length;\n\n console.log(`[EFC] Primary ${process.pid} starting ${count} workers`);\n\n for (let i = 0; i < count; i++) {\n cluster.fork();\n }\n\n cluster.on('online', (worker) => {\n options.onWorkerReady?.(worker.id);\n });\n\n cluster.on('exit', (worker, code, signal) => {\n const exitCode = code ?? (signal ? -1 : 0);\n if (isShuttingDown) {\n console.log(`[EFC] Worker ${worker.id} gracefully exited`);\n if (Object.keys(cluster.workers ?? {}).length === 0) {\n console.log('[EFC] All workers exited. Primary exiting.');\n process.exit(0);\n }\n return;\n }\n\n console.warn(`[EFC] Worker ${worker.id} exited (code=${exitCode}), respawning…`);\n options.onWorkerCrash?.(worker.id, exitCode);\n cluster.fork();\n });\n}\n\nexport { cluster };\n","// Wraps mongoose connection for Pre-Flight. Throws clearly if mongoose isn't installed.\n\nlet mongoose: typeof import('mongoose');\n\nasync function loadMongoose(): Promise<typeof import('mongoose')> {\n if (mongoose) return mongoose;\n try {\n mongoose = await import('mongoose');\n return mongoose;\n } catch {\n throw new Error('[EFC] mongoose is not installed. Run: npm install mongoose');\n }\n}\n\nexport async function connectMongo(url: string): Promise<import('mongoose').Connection> {\n const mg = await loadMongoose();\n await mg.connect(url);\n console.log('[EFC] MongoDB connected');\n return mg.connection;\n}\n","import type { ModelSchema, ModelCRUD } from '../types.js';\n\ntype AnyRecord = Record<string, unknown> & { id: string };\n\nfunction normalise(doc: Record<string, unknown>): AnyRecord {\n const id = doc['_id'] ? String(doc['_id']) : '';\n return { ...doc, id } as AnyRecord;\n}\n\nasync function getModel(\n name: string,\n schemaObj: Record<string, unknown>,\n): Promise<import('mongoose').Model<Record<string, unknown>>> {\n let mg: typeof import('mongoose');\n try {\n const mod = await import('mongoose');\n mg = (mod.default || mod) as typeof import('mongoose');\n } catch {\n throw new Error('[EFC] mongoose is not installed. Run: npm install mongoose');\n }\n\n if (mg.models[name]) return mg.models[name] as import('mongoose').Model<Record<string, unknown>>;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const schema = new mg.Schema(schemaObj as any, { timestamps: true });\n return mg.model<Record<string, unknown>>(name, schema);\n}\n\nfunction buildMongooseSchema(schema: ModelSchema): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, def] of Object.entries(schema)) {\n const entry: Record<string, unknown> = {};\n switch (def.type) {\n case 'string':\n entry['type'] = String;\n break;\n case 'number':\n entry['type'] = Number;\n break;\n case 'boolean':\n entry['type'] = Boolean;\n break;\n case 'date':\n entry['type'] = Date;\n break;\n case 'object':\n entry['type'] = Object;\n break;\n case 'array':\n entry['type'] = Array;\n break;\n }\n if (def.required !== undefined) entry['required'] = def.required;\n if (def.unique !== undefined) entry['unique'] = def.unique;\n if (def.default !== undefined) entry['default'] = def.default;\n out[key] = entry;\n }\n return out;\n}\n\nexport function defineModel<T extends Record<string, any>>(\n name: string,\n schema: ModelSchema,\n): ModelCRUD<T> {\n const mongooseSchema = buildMongooseSchema(schema);\n\n return {\n async find(filter = {}) {\n const M = await getModel(name, mongooseSchema);\n const docs = await M.find(filter as Record<string, unknown>).lean();\n return (docs as Record<string, unknown>[]).map(normalise) as (T & { id: string })[];\n },\n\n async findById(id) {\n const M = await getModel(name, mongooseSchema);\n const doc = await M.findById(id).lean();\n if (!doc) return null;\n return normalise(doc as Record<string, unknown>) as T & { id: string };\n },\n\n async findOne(filter) {\n const M = await getModel(name, mongooseSchema);\n const doc = await M.findOne(filter as Record<string, unknown>).lean();\n if (!doc) return null;\n return normalise(doc as Record<string, unknown>) as T & { id: string };\n },\n\n async create(data) {\n const M = await getModel(name, mongooseSchema);\n const doc = await M.create(data);\n return normalise(doc.toObject() as Record<string, unknown>) as T & { id: string };\n },\n\n async update(id, data) {\n const M = await getModel(name, mongooseSchema);\n const doc = await M.findByIdAndUpdate(id, data, { new: true }).lean();\n if (!doc) return null;\n return normalise(doc as Record<string, unknown>) as T & { id: string };\n },\n\n async delete(id) {\n const M = await getModel(name, mongooseSchema);\n await M.findByIdAndDelete(id);\n },\n\n async count(filter = {}) {\n const M = await getModel(name, mongooseSchema);\n return M.countDocuments(filter as Record<string, unknown>);\n },\n };\n}\n","// Thread-local DB client populated during Pre-Flight.\n// The Proxy ensures callers import `db` once and never null-check it —\n// it throws with a helpful message if accessed before Pre-Flight completes.\n\ntype AnyClient = Record<string, unknown>;\n\nlet _client: AnyClient | null = null;\n\nexport function setDbClient(client: AnyClient): void {\n _client = client;\n}\n\nexport function getDbClient(): AnyClient {\n if (!_client) {\n throw new Error('[EFC] db not ready — accessed before Pre-Flight completed');\n }\n return _client;\n}\n\nexport const db: AnyClient = new Proxy({} as AnyClient, {\n get(_target, prop: string) {\n return getDbClient()[prop];\n },\n set(_target, prop: string, value: unknown) {\n getDbClient()[prop] = value;\n return true;\n },\n});\n\nexport { connectMongo } from './mongo.js';\nexport { defineModel } from './model.js';\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { registerTask } from './index.js';\nimport type { TaskDefinition } from '../types.js';\n\nexport async function scanTasks(tasksDir: string): Promise<void> {\n if (!fs.existsSync(tasksDir)) return;\n\n const files = fs.readdirSync(tasksDir).filter((f) => /\\.(ts|js|mts|mjs)$/.test(f));\n\n for (const file of files) {\n const filePath = path.join(tasksDir, file);\n const taskName = path.basename(file, path.extname(file));\n\n try {\n const mod = (await import(filePath)) as Record<string, unknown>;\n const def = mod['default'] as TaskDefinition | undefined;\n\n if (!def || typeof def.handler !== 'function') {\n console.warn(`[EFC] Task file ${file} has no valid default export — skipping`);\n continue;\n }\n\n registerTask(taskName, { ...def, filePath });\n console.log(`[EFC] Registered task: ${taskName}`);\n } catch (err) {\n console.warn(`[EFC] Failed to load task ${file}:`, err);\n }\n }\n}\n","import { Worker, workerData, parentPort, isMainThread } from 'node:worker_threads';\nimport type { TaskDefinition } from '../types.js';\n\n// ── Worker-thread side ────────────────────────────────────────────────────────\nif (!isMainThread) {\n const { handlerPath, payload } = workerData as { handlerPath: string; payload: unknown };\n\n (async () => {\n try {\n const mod = (await import(handlerPath)) as Record<string, unknown>;\n const def = mod['default'] as TaskDefinition | undefined;\n if (!def || typeof def.handler !== 'function') {\n throw new Error(`[EFC] Thread runner: no valid task export in ${handlerPath}`);\n }\n await def.handler(payload);\n parentPort?.postMessage({ ok: true });\n } catch (err) {\n parentPort?.postMessage({ ok: false, error: String(err) });\n }\n })();\n}\n\n// ── Main-thread side ──────────────────────────────────────────────────────────\nexport function runInThread(handlerPath: string, payload: unknown): Promise<void> {\n return new Promise((resolve, reject) => {\n const worker = new Worker(new URL('./thread-runner.js', import.meta.url), {\n workerData: { handlerPath, payload },\n });\n\n worker.on('message', (msg: { ok: boolean; error?: string }) => {\n if (msg.ok) resolve();\n else reject(new Error(msg.error ?? 'Thread task failed'));\n });\n\n worker.on('error', reject);\n worker.on('exit', (code) => {\n if (code !== 0) reject(new Error(`Thread worker exited with code ${code}`));\n });\n });\n}\n","import type { Job } from 'bullmq';\nimport { taskRegistry, setEnqueueImpl } from './index.js';\nimport { runInThread } from './thread-runner.js';\n\ninterface BullMQOpts {\n redisUrl: string;\n concurrency: number;\n}\n\nexport async function initBullMQ(opts: BullMQOpts): Promise<void> {\n let bullmq: typeof import('bullmq');\n try {\n bullmq = await import('bullmq');\n } catch {\n throw new Error('[EFC] bullmq is not installed. Run: npm install bullmq');\n }\n\n const connection = parseRedisUrl(opts.redisUrl);\n const queue = new bullmq.Queue('efc', { connection });\n\n const worker = new bullmq.Worker(\n 'efc',\n async (job: Job) => {\n const def = taskRegistry.get(job.name);\n if (!def) {\n throw new Error(`[EFC] No task registered for name: ${job.name}`);\n }\n\n if (def.options.thread && def.filePath) {\n await runInThread(def.filePath, job.data);\n } else {\n await def.handler(job.data);\n }\n },\n { connection, concurrency: opts.concurrency },\n );\n\n worker.on('failed', (job: Job | undefined, err: Error) => {\n console.error(`[EFC] Task ${job?.name ?? 'unknown'} failed:`, err.message);\n });\n\n worker.on('completed', (job: Job) => {\n console.log(`[EFC] Task ${job.name} completed (id=${job.id})`);\n });\n\n setEnqueueImpl(async (name, payload) => {\n const def = taskRegistry.get(name);\n if (!def) {\n throw new Error(\n `[EFC] Cannot enqueue unknown task: \"${name}\". Is the task file in tasksDir?`,\n );\n }\n\n await queue.add(name, payload, {\n attempts: def.options.retries ?? 3,\n backoff: {\n type: def.options.backoff ?? 'exponential',\n delay: 1000,\n },\n });\n });\n\n console.log('[EFC] BullMQ backend initialised');\n}\n\nfunction parseRedisUrl(url: string): { host: string; port: number; password?: string } {\n try {\n const u = new URL(url);\n const result: { host: string; port: number; password?: string } = {\n host: u.hostname || 'localhost',\n port: parseInt(u.port || '6379', 10),\n };\n if (u.password) result.password = u.password;\n return result;\n } catch {\n return { host: 'localhost', port: 6379 };\n }\n}\n","import type { MountedRoute } from './types.js';\n\nconst HTTP_STATUS: Record<number, string> = {\n 200: 'OK',\n 201: 'Created',\n 202: 'Accepted',\n 204: 'No Content',\n 400: 'Bad Request',\n 401: 'Unauthorized',\n 403: 'Forbidden',\n 404: 'Not Found',\n 405: 'Method Not Allowed',\n 409: 'Conflict',\n 422: 'Unprocessable Entity',\n 500: 'Internal Server Error',\n 503: 'Service Unavailable',\n};\n\nexport function generateDashboard(\n routes: MountedRoute[],\n basePath: string,\n port: number,\n projectName: string,\n projectVersion: string,\n): string {\n const safeRoutes = JSON.stringify(\n routes.map((r) => ({\n urlPath: r.urlPath,\n methods: r.methods,\n params: r.params,\n meta: r.meta ?? null,\n })),\n ).replace(/<\\/script>/gi, '<\\\\/script>');\n const safeHttpStatus = JSON.stringify(HTTP_STATUS);\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>${projectName} — API Reference</title>\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap\" rel=\"stylesheet\" />\n <style>\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n :root {\n --bg: #080b0f;\n --bg-card: #0d1117;\n --bg-raised: #111820;\n --border: #1e2832;\n --border-lit: #263040;\n --text: #e2e8f0;\n --text-dim: #64748b;\n --text-muted: #334155;\n --accent: #F0A030;\n --accent-dim: rgba(240,160,48,.12);\n --accent-glow: rgba(240,160,48,.22);\n --purple: #a78bfa;\n --blue: #60a5fa;\n --orange: #fb923c;\n --green: #7AAE8E;\n --radius: 10px;\n --radius-lg: 16px;\n --font-mono: 'JetBrains Mono', monospace;\n --font-sans: 'Inter', sans-serif;\n }\n html { scroll-behavior: smooth; }\n body {\n background: var(--bg); color: var(--text);\n font-family: var(--font-sans); font-size: 16px;\n line-height: 1.6; -webkit-font-smoothing: antialiased;\n position: relative;\n }\n body::before {\n content: ''; position: fixed; inset: 0; z-index: 0;\n background-image:\n linear-gradient(var(--border) 1px, transparent 1px),\n linear-gradient(90deg, var(--border) 1px, transparent 1px);\n background-size: 60px 60px; opacity: .28; pointer-events: none;\n }\n section, footer, .page-hero, .docs-layout { position: relative; z-index: 1; }\n a { text-decoration: none; color: inherit; }\n em { font-style: italic; }\n code {\n font-family: var(--font-mono); font-size: .85em;\n background: var(--bg-raised); border: 1px solid var(--border);\n border-radius: 4px; padding: 1px 6px; color: var(--accent);\n }\n .container { max-width: 1140px; margin: 0 auto; padding: 0 24px; }\n ::-webkit-scrollbar { width: 6px; }\n ::-webkit-scrollbar-track { background: var(--bg); }\n ::-webkit-scrollbar-thumb { background: var(--border-lit); border-radius: 3px; }\n\n /* ── PAGE HERO ── */\n .page-hero {\n padding: 48px 0 56px; border-bottom: 1px solid var(--border);\n }\n .page-hero .hero-glow {\n position: absolute; top: -40px; left: 10%; width: 500px; height: 350px;\n background: radial-gradient(ellipse, rgba(240,160,48,.1) 0%, transparent 68%);\n pointer-events: none;\n }\n .page-title {\n font-size: clamp(2rem, 5vw, 3.4rem); font-weight: 800;\n line-height: 1.1; letter-spacing: -.02em; margin-bottom: 24px;\n display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap;\n }\n .project-version {\n font-family: var(--font-mono); font-size: clamp(.85rem, 2vw, 1.1rem);\n font-weight: 500; color: var(--accent);\n background: var(--accent-dim); border: 1px solid rgba(240,160,48,.3);\n border-radius: 6px; padding: 2px 10px; letter-spacing: .5px;\n }\n .hero-meta { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 40px; }\n .base-url-pill {\n display: flex; align-items: center; gap: 8px;\n background: var(--bg-card); border: 1px solid var(--border);\n border-radius: 7px; padding: 8px 14px;\n }\n .base-url-label { font-size: .72rem; font-family: var(--font-mono);\n color: var(--text-muted); text-transform: uppercase; letter-spacing: .5px; }\n .base-url-val { font-family: var(--font-mono); font-size: .8rem; color: var(--accent); }\n .count-pill {\n font-family: var(--font-mono); font-size: .72rem; color: var(--text-dim);\n background: var(--bg-card); border: 1px solid var(--border);\n border-radius: 7px; padding: 8px 14px;\n }\n\n /* ── TOOLBAR ── */\n .toolbar {\n display: flex; align-items: center; gap: 12px; flex-wrap: wrap;\n }\n .method-filters { display: flex; gap: 4px; flex-wrap: wrap; }\n .filter-btn {\n background: var(--bg-card); border: 1px solid var(--border);\n color: var(--text-dim); font-family: var(--font-mono);\n font-size: .72rem; font-weight: 600; letter-spacing: .5px;\n padding: 6px 12px; border-radius: 6px; cursor: pointer;\n transition: all .15s;\n }\n .filter-btn:hover { border-color: var(--border-lit); color: var(--text); }\n .filter-btn.active { background: var(--accent); color: #0d0d1a; border-color: var(--accent); }\n .filter-btn[data-method=\"GET\"].active { background: rgba(96,165,250,.18); color: #60a5fa; border-color: rgba(96,165,250,.4); }\n .filter-btn[data-method=\"POST\"].active { background: rgba(122,174,142,.18); color: #7AAE8E; border-color: rgba(122,174,142,.4); }\n .filter-btn[data-method=\"PUT\"].active { background: rgba(240,160,48,.18); color: #F0A030; border-color: rgba(240,160,48,.4); }\n .filter-btn[data-method=\"PATCH\"].active { background: rgba(251,191,36,.18); color: #fbbf24; border-color: rgba(251,191,36,.4); }\n .filter-btn[data-method=\"DELETE\"].active { background: rgba(248,113,113,.18); color: #f87171; border-color: rgba(248,113,113,.4); }\n .filter-btn[data-method=\"HEAD\"].active { background: rgba(167,139,250,.18); color: #a78bfa; border-color: rgba(167,139,250,.4); }\n .search-wrap { margin-left: auto; }\n .search-input {\n background: var(--bg-card); border: 1px solid var(--border);\n color: var(--text); font-family: var(--font-sans); font-size: .85rem;\n padding: 7px 14px; border-radius: 7px; width: 240px;\n outline: none; transition: border-color .2s;\n }\n .search-input::placeholder { color: var(--text-muted); }\n .search-input:focus { border-color: var(--border-lit); }\n\n /* ── DOCS LAYOUT ── */\n .docs-layout {\n display: grid; grid-template-columns: 260px 1fr;\n gap: 48px; padding: 52px 0 80px; max-width: 1140px;\n margin: 0 auto; padding-left: 24px; padding-right: 24px;\n align-items: start;\n }\n\n /* ── SIDEBAR ── */\n .docs-sidebar {\n position: sticky; top: 24px;\n max-height: calc(100vh - 48px);\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: none;\n padding-right: 4px;\n }\n .docs-sidebar::-webkit-scrollbar { display: none; }\n .sidebar-section { margin-bottom: 28px; }\n .sidebar-label {\n font-family: var(--font-mono); font-size: .68rem; font-weight: 600;\n color: var(--text-muted); letter-spacing: 1.2px; text-transform: uppercase;\n margin-bottom: 8px; padding: 0 4px;\n }\n .sidebar-link {\n display: flex; align-items: center; gap: 8px;\n padding: 7px 10px; border-radius: 6px;\n border-left: 2px solid transparent;\n font-size: .82rem; color: var(--text-dim); cursor: pointer;\n transition: background .15s, color .15s, border-color .15s;\n overflow: hidden; white-space: nowrap;\n }\n .sidebar-link:hover { background: var(--bg-raised); color: var(--text); }\n .sidebar-link.active { color: var(--accent); border-left-color: var(--accent); background: var(--accent-dim); }\n .sidebar-method-dot {\n width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;\n }\n .sidebar-path { font-family: var(--font-mono); font-size: .72rem; }\n\n /* ── ENDPOINT CARDS ── */\n .endpoint-card {\n background: var(--bg-card); border: 1px solid var(--border);\n border-radius: var(--radius-lg); margin-bottom: 20px;\n overflow: hidden; transition: border-color .2s;\n animation: fadeUp .45s ease both;\n }\n .endpoint-card:hover { border-color: var(--border-lit); }\n @keyframes fadeUp {\n from { opacity: 0; transform: translateY(16px); }\n to { opacity: 1; transform: translateY(0); }\n }\n @media (prefers-reduced-motion: reduce) {\n .endpoint-card { animation: none; }\n }\n .endpoint-header {\n display: flex; align-items: center; gap: 14px;\n padding: 20px 24px 18px; border-bottom: 1px solid var(--border);\n flex-wrap: wrap;\n }\n .method-badges { display: flex; gap: 6px; flex-wrap: wrap; }\n .method-badge {\n font-family: var(--font-mono); font-size: .7rem; font-weight: 600;\n letter-spacing: .8px; padding: 4px 10px; border-radius: 5px;\n border: 1px solid; text-transform: uppercase;\n }\n .endpoint-path {\n font-family: var(--font-mono); font-size: .9rem; color: var(--text);\n background: none; border: none; padding: 0;\n word-break: break-all;\n }\n .endpoint-body { padding: 6px 24px 24px; }\n .endpoint-desc { font-size: .9rem; color: var(--text-dim); line-height: 1.7; margin-bottom: 20px; }\n\n /* ── PER-METHOD DOC BLOCKS ── */\n .method-block { padding-top: 20px; }\n .method-block + .method-block { margin-top: 4px; border-top: 1px solid var(--border); }\n .method-block-header { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }\n .method-block-header .method-badge { font-size: .68rem; }\n .method-block-empty { font-size: .82rem; color: var(--text-muted); }\n\n /* ── CODE BLOCKS ── */\n .example-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }\n .code-block-wrap {\n background: var(--bg-raised); border: 1px solid var(--border);\n border-radius: var(--radius); overflow: hidden;\n }\n .code-bar {\n display: flex; align-items: center; gap: 6px;\n padding: 9px 14px; border-bottom: 1px solid var(--border);\n background: var(--bg-card);\n }\n .dot { width: 11px; height: 11px; border-radius: 50%; }\n .dot-r { background: #ff5f57; }\n .dot-y { background: #febc2e; }\n .dot-g { background: #28c840; }\n .code-label { font-family: var(--font-mono); font-size: .68rem; color: var(--text-dim); margin-left: 4px; }\n pre.code-pre {\n font-family: var(--font-mono); font-size: .78rem; line-height: 1.7;\n padding: 16px 18px; overflow-x: auto; tab-size: 2; white-space: pre;\n }\n .c-dim { color: var(--text-muted); }\n .c-green { color: #7AAE8E; }\n .c-blue { color: #60a5fa; }\n .c-orange { color: #fb923c; }\n .c-purple { color: #a78bfa; }\n .c-accent { color: var(--accent); }\n .status-2xx { color: #7AAE8E; }\n .status-4xx { color: #f87171; }\n .status-5xx { color: #fb923c; }\n\n /* ── EMPTY STATE ── */\n .empty-state {\n text-align: center; padding: 80px 24px;\n color: var(--text-muted); font-size: .9rem;\n }\n\n /* ── RESPONSIVE ── */\n @media (max-width: 900px) {\n .docs-layout { grid-template-columns: 1fr; }\n .docs-sidebar { position: static; max-height: none; overflow-y: visible; padding-right: 0; }\n .example-grid { grid-template-columns: 1fr; }\n .search-wrap { margin-left: 0; width: 100%; }\n .search-input { width: 100%; }\n }\n @media (max-width: 600px) {\n .page-hero { padding: 32px 0 32px; }\n .page-title { font-size: 2rem; }\n }\n </style>\n</head>\n<body>\n\n <div class=\"page-hero\">\n <div class=\"hero-glow\"></div>\n <div class=\"container\">\n <h1 class=\"page-title\">${projectName}${projectVersion ? `<span class=\"project-version\">v${projectVersion}</span>` : ''}</h1>\n <div class=\"hero-meta\">\n <div class=\"base-url-pill\">\n <span class=\"base-url-label\">Base</span>\n <span class=\"base-url-val\">http://localhost:${port}${basePath}</span>\n </div>\n <div class=\"count-pill\" id=\"countPill\"></div>\n </div>\n <div class=\"toolbar\">\n <div class=\"method-filters\" id=\"methodFilters\">\n <button class=\"filter-btn active\" data-method=\"ALL\">ALL</button>\n </div>\n <div class=\"search-wrap\">\n <input type=\"text\" id=\"searchInput\" class=\"search-input\" placeholder=\"Search endpoints…\" />\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"docs-layout\">\n <aside class=\"docs-sidebar\" id=\"sidebar\"></aside>\n <main id=\"endpoints\"></main>\n </div>\n\n <script>\n const ROUTES = ${safeRoutes};\n const BASE_PATH = ${JSON.stringify(basePath)};\n const HTTP_STATUS = ${safeHttpStatus};\n\n const METHOD_STYLE = {\n GET: { bg: 'rgba(96,165,250,.14)', color: '#60a5fa', border: 'rgba(96,165,250,.35)' },\n POST: { bg: 'rgba(122,174,142,.14)', color: '#7AAE8E', border: 'rgba(122,174,142,.35)' },\n PUT: { bg: 'rgba(240,160,48,.14)', color: '#F0A030', border: 'rgba(240,160,48,.35)' },\n PATCH: { bg: 'rgba(251,191,36,.14)', color: '#fbbf24', border: 'rgba(251,191,36,.35)' },\n DELETE: { bg: 'rgba(248,113,113,.14)', color: '#f87171', border: 'rgba(248,113,113,.35)' },\n HEAD: { bg: 'rgba(167,139,250,.14)', color: '#a78bfa', border: 'rgba(167,139,250,.35)' },\n OPTIONS: { bg: 'rgba(148,163,184,.14)', color: '#94a3b8', border: 'rgba(148,163,184,.35)' },\n };\n\n function esc(s) {\n return String(s)\n .replace(/&/g,'&amp;').replace(/</g,'&lt;')\n .replace(/>/g,'&gt;').replace(/\"/g,'&quot;');\n }\n\n function methodBadge(m) {\n const s = METHOD_STYLE[m] || METHOD_STYLE.GET;\n return '<span class=\"method-badge\" style=\"background:' + s.bg + ';color:' + s.color + ';border-color:' + s.border + '\">' + m + '</span>';\n }\n\n function joinPath(base, p) {\n return (base.replace(/\\\\/+$/, '') + p) || '/';\n }\n\n function sidebarDot(method) {\n const s = METHOD_STYLE[method] || METHOD_STYLE.GET;\n return '<span class=\"sidebar-method-dot\" style=\"background:' + s.color + '\"></span>';\n }\n\n function statusClass(code) {\n if (code >= 200 && code < 300) return 'status-2xx';\n if (code >= 400 && code < 500) return 'status-4xx';\n if (code >= 500) return 'status-5xx';\n return '';\n }\n\n function renderSchema(val, indent) {\n const pad = ' '.repeat(indent || 0);\n if (val === null) return '<span class=\"c-dim\">null</span>';\n if (typeof val === 'string') {\n const isDate = /^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}:\\\\d{2}/.test(val);\n return isDate ? '<span class=\"c-green\">Date</span>' : '<span class=\"c-purple\">String</span>';\n }\n if (typeof val === 'number') return '<span class=\"c-orange\">Number</span>';\n if (typeof val === 'boolean') return '<span class=\"c-purple\">Boolean</span>';\n if (Array.isArray(val)) {\n if (!val.length) return '[]';\n return '[\\\\n' + pad + ' ' + renderSchema(val[0], (indent || 0) + 1) + '\\\\n' + pad + ']';\n }\n if (typeof val === 'object') {\n const keys = Object.keys(val);\n if (!keys.length) return '{}';\n const inner = keys.map(function(k) {\n return pad + ' <span class=\"c-blue\">&quot;' + esc(k) + '&quot;</span>: ' + renderSchema(val[k], (indent || 0) + 1);\n }).join(',\\\\n');\n return '{\\\\n' + inner + '\\\\n' + pad + '}';\n }\n return esc(String(val));\n }\n\n function codeBlock(label, content) {\n return '<div class=\"code-block-wrap\">' +\n '<div class=\"code-bar\">' +\n '<span class=\"dot dot-r\"></span>' +\n '<span class=\"dot dot-y\"></span>' +\n '<span class=\"dot dot-g\"></span>' +\n '<span class=\"code-label\">' + esc(label) + '</span>' +\n '</div>' +\n '<pre class=\"code-pre\">' + content + '</pre>' +\n '</div>';\n }\n\n function buildRequestContent(route, method, example) {\n const req = example || {};\n let path = joinPath(BASE_PATH, route.urlPath);\n if (req.params) {\n for (const [k, v] of Object.entries(req.params)) {\n path = path.replace(':' + k, String(v));\n }\n }\n if (req.query && Object.keys(req.query).length) {\n path += '?' + new URLSearchParams(req.query).toString();\n }\n let lines = '<span class=\"c-accent\">' + esc(method) + '</span> <span class=\"c-blue\">' + esc(path) + '</span>';\n const headers = { ...(req.headers || {}) };\n if (req.body !== undefined && !headers['Content-Type']) {\n headers['Content-Type'] = 'application/json';\n }\n if (Object.keys(headers).length) {\n lines += '\\\\n' + Object.entries(headers)\n .map(([k, v]) => '<span class=\"c-dim\">' + esc(k) + ':</span> ' + esc(String(v)))\n .join('\\\\n');\n }\n if (req.body !== undefined) {\n lines += '\\\\n\\\\n' + renderSchema(req.body, 0);\n }\n return lines;\n }\n\n function buildResponseContent(example) {\n const resp = example || {};\n const code = resp.status || 200;\n const text = HTTP_STATUS[code] || 'OK';\n const cls = statusClass(code);\n let lines = 'HTTP/1.1 <span class=\"' + cls + '\">' + code + ' ' + esc(text) + '</span>';\n if (resp.body !== undefined) {\n lines += '\\\\n<span class=\"c-dim\">Content-Type:</span> application/json\\\\n\\\\n';\n lines += renderSchema(resp.body, 0);\n }\n return lines;\n }\n\n function renderMethodBlock(route, method) {\n const methodMeta = route.meta ? route.meta[method] : null;\n const header = '<div class=\"method-block-header\">' + methodBadge(method) + '</div>';\n\n if (!methodMeta) {\n return '<div class=\"method-block\" data-method=\"' + esc(method) + '\">' + header +\n '<p class=\"method-block-empty\">No documentation provided for this method.</p></div>';\n }\n\n const desc = methodMeta.description\n ? '<p class=\"endpoint-desc\">' + esc(methodMeta.description) + '</p>'\n : '';\n const reqHtml = methodMeta.request !== undefined\n ? codeBlock('request', buildRequestContent(route, method, methodMeta.request))\n : '';\n const respHtml = methodMeta.response !== undefined\n ? codeBlock('response', buildResponseContent(methodMeta.response))\n : '';\n const examples = reqHtml || respHtml\n ? '<div class=\"example-grid\">' + reqHtml + respHtml + '</div>'\n : '';\n\n return '<div class=\"method-block\" data-method=\"' + esc(method) + '\">' + header + desc + examples + '</div>';\n }\n\n function renderCard(route, index) {\n const id = 'ep-' + index;\n const fullPath = joinPath(BASE_PATH, route.urlPath);\n const badges = route.methods.map(methodBadge).join('');\n const body = route.methods.map(function(m) { return renderMethodBlock(route, m); }).join('');\n const delay = (index * 0.06).toFixed(2) + 's';\n return '<div class=\"endpoint-card\" id=\"' + id + '\" data-methods=\"' + route.methods.join(',') + '\" data-path=\"' + esc(fullPath) + '\" style=\"animation-delay:' + delay + '\">' +\n '<div class=\"endpoint-header\">' +\n '<div class=\"method-badges\">' + badges + '</div>' +\n '<code class=\"endpoint-path\">' + esc(fullPath) + '</code>' +\n '</div>' +\n '<div class=\"endpoint-body\">' + body + '</div>' +\n '</div>';\n }\n\n function buildMethodFilters() {\n const allMethods = [...new Set(ROUTES.flatMap(r => r.methods))].sort();\n const filtersEl = document.getElementById('methodFilters');\n allMethods.forEach(m => {\n const btn = document.createElement('button');\n btn.className = 'filter-btn';\n btn.dataset.method = m;\n btn.textContent = m;\n filtersEl.appendChild(btn);\n });\n }\n\n function buildSidebar(routes) {\n const sidebar = document.getElementById('sidebar');\n if (!routes.length) { sidebar.innerHTML = ''; return; }\n\n const label = document.createElement('div');\n label.className = 'sidebar-label';\n label.textContent = 'Endpoints';\n sidebar.appendChild(label);\n\n routes.forEach((route, i) => {\n const link = document.createElement('div');\n link.className = 'sidebar-link';\n link.dataset.target = 'ep-' + ROUTES.indexOf(route);\n link.innerHTML = sidebarDot(route.methods[0] || 'GET') +\n '<span class=\"sidebar-path\">' + esc(route.urlPath || '/') + '</span>';\n link.addEventListener('click', () => {\n const target = document.getElementById(link.dataset.target);\n if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' });\n });\n sidebar.appendChild(link);\n });\n }\n\n let activeFilter = 'ALL';\n let searchQuery = '';\n\n function applyFilters() {\n const cards = document.querySelectorAll('.endpoint-card');\n let visible = 0;\n cards.forEach(card => {\n const methods = card.dataset.methods.split(',');\n const path = card.dataset.path || '';\n const matchMethod = activeFilter === 'ALL' || methods.includes(activeFilter);\n const matchSearch = !searchQuery || path.toLowerCase().includes(searchQuery);\n const show = matchMethod && matchSearch;\n card.style.display = show ? '' : 'none';\n if (show) visible++;\n });\n document.getElementById('empty-state').style.display = visible ? 'none' : 'block';\n\n // Sync sidebar visibility\n document.querySelectorAll('.sidebar-link').forEach(link => {\n const targetId = link.dataset.target;\n const targetCard = document.getElementById(targetId);\n link.style.display = targetCard && targetCard.style.display !== 'none' ? '' : 'none';\n });\n }\n\n function init() {\n const count = ROUTES.length;\n document.getElementById('countPill').textContent = count + ' endpoint' + (count !== 1 ? 's' : '');\n\n buildMethodFilters();\n\n const container = document.getElementById('endpoints');\n container.innerHTML = ROUTES.map((r, i) => renderCard(r, i)).join('');\n\n // Add empty state after cards\n const emptyEl = document.createElement('div');\n emptyEl.id = 'empty-state';\n emptyEl.className = 'empty-state';\n emptyEl.style.display = 'none';\n emptyEl.innerHTML = '<p>No endpoints match your filter.</p>';\n container.after(emptyEl);\n\n buildSidebar(ROUTES);\n\n // Method filter clicks\n document.getElementById('methodFilters').addEventListener('click', e => {\n const btn = e.target.closest('.filter-btn');\n if (!btn) return;\n document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));\n btn.classList.add('active');\n activeFilter = btn.dataset.method;\n applyFilters();\n });\n\n // Search\n document.getElementById('searchInput').addEventListener('input', e => {\n searchQuery = e.target.value.trim().toLowerCase();\n applyFilters();\n });\n\n // Scroll spy for sidebar\n const cardEls = document.querySelectorAll('.endpoint-card');\n const sidebarLinks = document.querySelectorAll('.sidebar-link');\n const observer = new IntersectionObserver(entries => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const id = entry.target.id;\n sidebarLinks.forEach(l => l.classList.toggle('active', l.dataset.target === id));\n const sidebar = document.getElementById('sidebar');\n const activeLink = sidebar && sidebar.querySelector('.sidebar-link.active');\n if (sidebar && activeLink) {\n const linkTop = activeLink.getBoundingClientRect().top - sidebar.getBoundingClientRect().top + sidebar.scrollTop;\n sidebar.scrollTo({ top: linkTop, behavior: 'smooth' });\n }\n }\n });\n }, { rootMargin: '-80px 0px -60% 0px' });\n cardEls.forEach(el => observer.observe(el));\n\n }\n\n try {\n init();\n } catch (e) {\n document.body.insertAdjacentHTML('afterbegin',\n '<div style=\"position:fixed;top:60px;left:0;right:0;z-index:9999;background:#7f1d1d;color:#fca5a5;padding:16px 24px;font-family:monospace;font-size:13px;border-bottom:1px solid #ef4444\">' +\n '<strong>Dashboard JS error:</strong> ' + (e && e.message ? e.message : String(e)) +\n (e && e.stack ? '<pre style=\"margin-top:8px;white-space:pre-wrap\">' + e.stack + '</pre>' : '') +\n '</div>'\n );\n }\n </script>\n</body>\n</html>`;\n}\n","export class HttpError extends Error {\n readonly statusCode: number;\n\n constructor(statusCode: number, message: string) {\n super(message);\n this.name = 'HttpError';\n this.statusCode = statusCode;\n Error.captureStackTrace(this, HttpError);\n }\n}\n","import type { RequestHandler } from 'express';\n\nexport function compose(...handlers: RequestHandler[]): RequestHandler {\n return (req, res, next) => {\n let index = 0;\n\n function dispatch(i: number): void {\n if (i >= handlers.length) {\n next();\n return;\n }\n const handler = handlers[i];\n if (!handler) {\n next();\n return;\n }\n try {\n Promise.resolve(handler(req, res, () => dispatch(i + 1))).catch(next);\n } catch (err) {\n next(err);\n }\n }\n\n dispatch(index);\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/efc.js/efc.js/packages/core/dist/tasks/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACF,wQAAC","file":"/home/runner/work/efc.js/efc.js/packages/core/dist/tasks/index.cjs"}
1
+ {"version":3,"sources":["/home/prashant/Projects/temp-nodejs/packages/core/dist/tasks/index.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACF,yDAA8B;AAC9B;AACE;AACA;AACA;AACA;AACA;AACF,wQAAC","file":"/home/prashant/Projects/temp-nodejs/packages/core/dist/tasks/index.cjs"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-file-cluster",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Enterprise-grade, zero-boilerplate backend framework with file-based routing and multi-core clustering",
5
5
  "license": "MIT",
6
6
  "type": "module",