express-file-cluster 0.2.11 → 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,5 +1,5 @@
1
1
  import { Request, Response, NextFunction, RequestHandler } from 'express';
2
- import { A as AuthStrategy } from '../types-BZehD43d.cjs';
2
+ import { A as AuthStrategy } from '../types-CFU2IhRW.cjs';
3
3
 
4
4
  interface AuthConfig {
5
5
  secret: string;
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, NextFunction, RequestHandler } from 'express';
2
- import { A as AuthStrategy } from '../types-BZehD43d.js';
2
+ import { A as AuthStrategy } from '../types-CFU2IhRW.js';
3
3
 
4
4
  interface AuthConfig {
5
5
  secret: string;
@@ -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":"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","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"]}
@@ -227,22 +227,35 @@ function generateRoute(routePath) {
227
227
  import type { RouteMeta } from 'express-file-cluster';
228
228
 
229
229
  export const meta: RouteMeta = {
230
- description: 'TODO: describe this endpoint.',
231
- request: {
232
- headers: {
233
- // 'Content-Type': 'application/json'
234
- },
235
- query: {
236
- // search: 'query'
230
+ GET: {
231
+ description: 'TODO: describe this endpoint.',
232
+ request: {
233
+ headers: {
234
+ // 'Content-Type': 'application/json'
235
+ },
236
+ query: {
237
+ // search: 'query'
238
+ },
237
239
  },
238
- body: {
239
- // name: 'string'
240
+ response: {
241
+ status: 200,
242
+ body: {
243
+ message: 'OK'
244
+ }
240
245
  }
241
246
  },
242
- response: {
243
- status: 200,
244
- body: {
245
- message: 'OK'
247
+ POST: {
248
+ description: 'TODO: describe this endpoint.',
249
+ request: {
250
+ body: {
251
+ // name: 'string'
252
+ }
253
+ },
254
+ response: {
255
+ status: 201,
256
+ body: {
257
+ message: 'Created'
258
+ }
246
259
  }
247
260
  }
248
261
  };
@@ -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 description: 'TODO: describe this endpoint.',\n request: {\n headers: {\n // 'Content-Type': 'application/json'\n },\n query: {\n // search: 'query'\n },\n body: {\n // name: 'string'\n }\n },\n response: {\n status: 200,\n body: {\n message: 'OK'\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"]}
package/dist/cli/index.js CHANGED
@@ -227,22 +227,35 @@ function generateRoute(routePath) {
227
227
  import type { RouteMeta } from 'express-file-cluster';
228
228
 
229
229
  export const meta: RouteMeta = {
230
- description: 'TODO: describe this endpoint.',
231
- request: {
232
- headers: {
233
- // 'Content-Type': 'application/json'
234
- },
235
- query: {
236
- // search: 'query'
230
+ GET: {
231
+ description: 'TODO: describe this endpoint.',
232
+ request: {
233
+ headers: {
234
+ // 'Content-Type': 'application/json'
235
+ },
236
+ query: {
237
+ // search: 'query'
238
+ },
237
239
  },
238
- body: {
239
- // name: 'string'
240
+ response: {
241
+ status: 200,
242
+ body: {
243
+ message: 'OK'
244
+ }
240
245
  }
241
246
  },
242
- response: {
243
- status: 200,
244
- body: {
245
- message: 'OK'
247
+ POST: {
248
+ description: 'TODO: describe this endpoint.',
249
+ request: {
250
+ body: {
251
+ // name: 'string'
252
+ }
253
+ },
254
+ response: {
255
+ status: 201,
256
+ body: {
257
+ message: 'Created'
258
+ }
246
259
  }
247
260
  }
248
261
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../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"],"sourcesContent":["#!/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 description: 'TODO: describe this endpoint.',\n request: {\n headers: {\n // 'Content-Type': 'application/json'\n },\n query: {\n // search: 'query'\n },\n body: {\n // name: 'string'\n }\n },\n response: {\n status: 200,\n body: {\n message: 'OK'\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"],"mappings":"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","names":["Command","Command","spawn","path","fs","pc","resolveEntry","Command","spawn","pc","Command","fs","path","pc","Command","path","fs","pc","Command","Command"]}
1
+ {"version":3,"sources":["../../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"],"sourcesContent":["#!/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"],"mappings":"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","names":["Command","Command","spawn","path","fs","pc","resolveEntry","Command","spawn","pc","Command","fs","path","pc","Command","path","fs","pc","Command","Command"]}
package/dist/index.cjs CHANGED
@@ -564,9 +564,16 @@ function generateDashboard(routes, basePath, port, projectName, projectVersion)
564
564
  background: none; border: none; padding: 0;
565
565
  word-break: break-all;
566
566
  }
567
- .endpoint-body { padding: 18px 24px 24px; }
567
+ .endpoint-body { padding: 6px 24px 24px; }
568
568
  .endpoint-desc { font-size: .9rem; color: var(--text-dim); line-height: 1.7; margin-bottom: 20px; }
569
569
 
570
+ /* \u2500\u2500 PER-METHOD DOC BLOCKS \u2500\u2500 */
571
+ .method-block { padding-top: 20px; }
572
+ .method-block + .method-block { margin-top: 4px; border-top: 1px solid var(--border); }
573
+ .method-block-header { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
574
+ .method-block-header .method-badge { font-size: .68rem; }
575
+ .method-block-empty { font-size: .82rem; color: var(--text-muted); }
576
+
570
577
  /* \u2500\u2500 CODE BLOCKS \u2500\u2500 */
571
578
  .example-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
572
579
  .code-block-wrap {
@@ -724,9 +731,8 @@ function generateDashboard(routes, basePath, port, projectName, projectVersion)
724
731
  '</div>';
725
732
  }
726
733
 
727
- function buildRequestContent(route, example) {
734
+ function buildRequestContent(route, method, example) {
728
735
  const req = example || {};
729
- const method = route.methods[0] || 'GET';
730
736
  let path = joinPath(BASE_PATH, route.urlPath);
731
737
  if (req.params) {
732
738
  for (const [k, v] of Object.entries(req.params)) {
@@ -765,33 +771,43 @@ function generateDashboard(routes, basePath, port, projectName, projectVersion)
765
771
  return lines;
766
772
  }
767
773
 
774
+ function renderMethodBlock(route, method) {
775
+ const methodMeta = route.meta ? route.meta[method] : null;
776
+ const header = '<div class="method-block-header">' + methodBadge(method) + '</div>';
777
+
778
+ if (!methodMeta) {
779
+ return '<div class="method-block" data-method="' + esc(method) + '">' + header +
780
+ '<p class="method-block-empty">No documentation provided for this method.</p></div>';
781
+ }
782
+
783
+ const desc = methodMeta.description
784
+ ? '<p class="endpoint-desc">' + esc(methodMeta.description) + '</p>'
785
+ : '';
786
+ const reqHtml = methodMeta.request !== undefined
787
+ ? codeBlock('request', buildRequestContent(route, method, methodMeta.request))
788
+ : '';
789
+ const respHtml = methodMeta.response !== undefined
790
+ ? codeBlock('response', buildResponseContent(methodMeta.response))
791
+ : '';
792
+ const examples = reqHtml || respHtml
793
+ ? '<div class="example-grid">' + reqHtml + respHtml + '</div>'
794
+ : '';
795
+
796
+ return '<div class="method-block" data-method="' + esc(method) + '">' + header + desc + examples + '</div>';
797
+ }
798
+
768
799
  function renderCard(route, index) {
769
800
  const id = 'ep-' + index;
770
801
  const fullPath = joinPath(BASE_PATH, route.urlPath);
771
802
  const badges = route.methods.map(methodBadge).join('');
772
- const meta = route.meta;
773
- const desc = meta && meta.description
774
- ? '<p class="endpoint-desc">' + esc(meta.description) + '</p>'
775
- : '';
776
- let examples = '';
777
- if (meta) {
778
- const reqHtml = meta.request !== undefined
779
- ? codeBlock('request', buildRequestContent(route, meta.request))
780
- : '';
781
- const respHtml = meta.response !== undefined
782
- ? codeBlock('response', buildResponseContent(meta.response))
783
- : '';
784
- if (reqHtml || respHtml) {
785
- examples = '<div class="example-grid">' + reqHtml + respHtml + '</div>';
786
- }
787
- }
803
+ const body = route.methods.map(function(m) { return renderMethodBlock(route, m); }).join('');
788
804
  const delay = (index * 0.06).toFixed(2) + 's';
789
805
  return '<div class="endpoint-card" id="' + id + '" data-methods="' + route.methods.join(',') + '" data-path="' + esc(fullPath) + '" style="animation-delay:' + delay + '">' +
790
806
  '<div class="endpoint-header">' +
791
807
  '<div class="method-badges">' + badges + '</div>' +
792
808
  '<code class="endpoint-path">' + esc(fullPath) + '</code>' +
793
809
  '</div>' +
794
- '<div class="endpoint-body">' + desc + examples + '</div>' +
810
+ '<div class="endpoint-body">' + body + '</div>' +
795
811
  '</div>';
796
812
  }
797
813