express-file-cluster 0.2.1 → 0.2.3
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.
- package/dist/auth/index.cjs +2 -2
- package/dist/auth/index.d.cts +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.js +1 -1
- package/dist/{chunk-DQGWFWBV.js → chunk-BHMFPULA.js} +1 -1
- package/dist/chunk-BHMFPULA.js.map +1 -0
- package/dist/{chunk-Z5YNIVQG.js → chunk-LPZEKFVN.js} +2 -4
- package/dist/{chunk-Z5YNIVQG.js.map → chunk-LPZEKFVN.js.map} +1 -1
- package/dist/{chunk-QB3X6LKZ.cjs → chunk-UUF2OYRW.cjs} +1 -1
- package/dist/{chunk-QB3X6LKZ.cjs.map → chunk-UUF2OYRW.cjs.map} +1 -1
- package/dist/{chunk-UDE6S53C.cjs → chunk-XH7O25BL.cjs} +2 -4
- package/dist/chunk-XH7O25BL.cjs.map +1 -0
- package/dist/cli/index.cjs +66 -5
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +89 -28
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +615 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +608 -10
- package/dist/index.js.map +1 -1
- package/dist/tasks/index.cjs +2 -2
- package/dist/tasks/index.d.cts +1 -1
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/{types-Dj9-sLOK.d.cts → types-BZehD43d.d.cts} +16 -3
- package/dist/{types-Dj9-sLOK.d.ts → types-BZehD43d.d.ts} +16 -3
- package/package.json +8 -8
- package/dist/chunk-DQGWFWBV.js.map +0 -1
- package/dist/chunk-UDE6S53C.cjs.map +0 -1
package/dist/auth/index.cjs
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
7
|
+
var _chunkUUF2OYRWcjs = require('../chunk-UUF2OYRW.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
exports.configureAuth =
|
|
14
|
+
exports.configureAuth = _chunkUUF2OYRWcjs.configureAuth; exports.issueToken = _chunkUUF2OYRWcjs.issueToken; exports.requireAuth = _chunkUUF2OYRWcjs.requireAuth; exports.revokeToken = _chunkUUF2OYRWcjs.revokeToken; exports.signToken = _chunkUUF2OYRWcjs.signToken;
|
|
15
15
|
//# sourceMappingURL=index.cjs.map
|
package/dist/auth/index.d.cts
CHANGED
package/dist/auth/index.d.ts
CHANGED
package/dist/auth/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth/index.ts"],"sourcesContent":["import type { 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\nexport const requireAuth: RequestHandler = async (req, res, next) => {\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 (req as typeof req & { user: unknown }).user = payload;\n next();\n } catch {\n res.status(401).json({ error: 'Unauthorized' });\n }\n};\n"],"mappings":";AACA,SAAS,SAAS,iBAAiB;AAUnC,IAAI,UAA6B;AAE1B,SAAS,cAAc,QAA0B;AACtD,YAAU;AACZ;AAEA,SAAS,YAAwB;AAC/B,MAAI,CAAC,QAAS,OAAM,IAAI,MAAM,6DAAwD;AACtF,SAAO;AACT;AAEA,eAAsB,WAAW,KAAe,SAAiD;AAC/F,QAAM,EAAE,QAAQ,WAAW,aAAa,IAAI,UAAU;AACtD,QAAM,gBAAgB,IAAI,YAAY,EAAE,OAAO,MAAM;AACrD,QAAM,QAAQ,MAAM,IAAI,QAAQ,OAAO,EACpC,mBAAmB,EAAE,KAAK,QAAQ,CAAC,EACnC,kBAAkB,SAAS,EAC3B,KAAK,aAAa;AAErB,MAAI,OAAO,aAAa,OAAO;AAAA,IAC7B,UAAU;AAAA,IACV,QAAQ,QAAQ,IAAI,UAAU,MAAM;AAAA,IACpC,UAAU;AAAA,IACV,GAAI,iBAAiB,UAAa,EAAE,QAAQ,aAAa;AAAA,EAC3D,CAAC;AACH;AAEO,SAAS,YAAY,KAAqB;AAC/C,MAAI,YAAY,WAAW;AAC7B;AAEA,eAAsB,UAAU,SAAmD;AACjF,QAAM,EAAE,QAAQ,UAAU,IAAI,UAAU;AACxC,QAAM,gBAAgB,IAAI,YAAY,EAAE,OAAO,MAAM;AACrD,SAAO,MAAM,IAAI,QAAQ,OAAO,EAC7B,mBAAmB,EAAE,KAAK,QAAQ,CAAC,EACnC,kBAAkB,SAAS,EAC3B,KAAK,aAAa;AACvB;AAEO,IAAM,cAA8B,OAAO,KAAK,KAAK,SAAS;AACnE,QAAM,EAAE,QAAQ,SAAS,IAAI,UAAU;AAEvC,MAAI;AACF,QAAI;AAEJ,QAAI,aAAa,aAAa;AAC5B,YAAM,UAAW,IAAyD;AAC1E,cAAQ,UAAU,WAAW;AAAA,IAC/B,OAAO;AACL,YAAM,OAAO,IAAI,QAAQ,eAAe;AACxC,UAAI,OAAO,SAAS,YAAY,KAAK,WAAW,SAAS,GAAG;AAC1D,gBAAQ,KAAK,MAAM,CAAC;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,CAAC,OAAO;AACV,UAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,eAAe,CAAC;AAC9C;AAAA,IACF;AAEA,UAAM,gBAAgB,IAAI,YAAY,EAAE,OAAO,MAAM;AACrD,UAAM,EAAE,QAAQ,IAAI,MAAM,UAAU,OAAO,aAAa;AACxD,IAAC,IAAuC,OAAO;AAC/C,SAAK;AAAA,EACP,QAAQ;AACN,QAAI,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,eAAe,CAAC;AAAA,EAChD;AACF;","names":[]}
|
|
@@ -22,9 +22,7 @@ function setEnqueueImpl(impl) {
|
|
|
22
22
|
}
|
|
23
23
|
async function enqueue(name, payload) {
|
|
24
24
|
if (!_impl) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
`[EFC] Task queue not initialised. Set tasks.backend in ignite() config.`
|
|
27
|
-
);
|
|
25
|
+
throw new Error(`[EFC] Task queue not initialised. Set tasks.backend in ignite() config.`);
|
|
28
26
|
}
|
|
29
27
|
return _impl(name, payload);
|
|
30
28
|
}
|
|
@@ -39,4 +37,4 @@ export {
|
|
|
39
37
|
enqueue,
|
|
40
38
|
registerTask
|
|
41
39
|
};
|
|
42
|
-
//# sourceMappingURL=chunk-
|
|
40
|
+
//# sourceMappingURL=chunk-LPZEKFVN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tasks/index.ts"],"sourcesContent":["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(
|
|
1
|
+
{"version":3,"sources":["../src/tasks/index.ts"],"sourcesContent":["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"],"mappings":";AAEO,IAAM,eAAe,oBAAI,IAA4B;AAQrD,IAAM,aAAiC,CAC5C,kBACA,iBACsB;AACtB,MAAI,UAAuB,CAAC;AAC5B,MAAI;AAEJ,MAAI,OAAO,qBAAqB,YAAY;AAC1C,cAAU;AAAA,EACZ,OAAO;AACL,cAAU;AACV,QAAI,CAAC,aAAc,OAAM,IAAI,MAAM,gDAAgD;AACnF,cAAU;AAAA,EACZ;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM;AAAA,EACR;AACF;AAGA,IAAI,QAA4B;AAEzB,SAAS,eAAe,MAAyB;AACtD,UAAQ;AACV;AAEA,eAAsB,QAAW,MAAc,SAA2B;AACxE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,yEAAyE;AAAA,EAC3F;AACA,SAAO,MAAM,MAAM,OAAkB;AACvC;AAEO,SAAS,aAAa,MAAc,KAA2B;AACpE,eAAa,IAAI,MAAM,EAAE,GAAG,KAAK,KAAK,CAAC;AACzC;","names":[]}
|
|
@@ -60,4 +60,4 @@ var requireAuth = async (req, res, next) => {
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
exports.configureAuth = configureAuth; exports.issueToken = issueToken; exports.revokeToken = revokeToken; exports.signToken = signToken; exports.requireAuth = requireAuth;
|
|
63
|
-
//# sourceMappingURL=chunk-
|
|
63
|
+
//# sourceMappingURL=chunk-UUF2OYRW.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-UUF2OYRW.cjs","../src/auth/index.ts"],"names":[],"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;AAEO,IAAM,YAAA,EAA8B,MAAA,CAAO,GAAA,EAAK,GAAA,EAAK,IAAA,EAAA,GAAS;AACnE,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;AACxD,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,CAAA;ADzBA;AACA;AACE;AACA;AACA;AACA;AACA;AACF,4KAAC","file":"/home/runner/work/efc.js/efc.js/packages/core/dist/chunk-UUF2OYRW.cjs","sourcesContent":[null,"import type { 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\nexport const requireAuth: RequestHandler = async (req, res, next) => {\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 (req as typeof req & { user: unknown }).user = payload;\n next();\n } catch {\n res.status(401).json({ error: 'Unauthorized' });\n }\n};\n"]}
|
|
@@ -22,9 +22,7 @@ function setEnqueueImpl(impl) {
|
|
|
22
22
|
}
|
|
23
23
|
async function enqueue(name, payload) {
|
|
24
24
|
if (!_impl) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
`[EFC] Task queue not initialised. Set tasks.backend in ignite() config.`
|
|
27
|
-
);
|
|
25
|
+
throw new Error(`[EFC] Task queue not initialised. Set tasks.backend in ignite() config.`);
|
|
28
26
|
}
|
|
29
27
|
return _impl(name, payload);
|
|
30
28
|
}
|
|
@@ -39,4 +37,4 @@ function registerTask(name, def) {
|
|
|
39
37
|
|
|
40
38
|
|
|
41
39
|
exports.taskRegistry = taskRegistry; exports.defineTask = defineTask; exports.setEnqueueImpl = setEnqueueImpl; exports.enqueue = enqueue; exports.registerTask = registerTask;
|
|
42
|
-
//# sourceMappingURL=chunk-
|
|
40
|
+
//# sourceMappingURL=chunk-XH7O25BL.cjs.map
|
|
@@ -0,0 +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"]}
|
package/dist/cli/index.cjs
CHANGED
|
@@ -50,9 +50,18 @@ function startDev() {
|
|
|
50
50
|
console.log(_picocolors2.default.cyan("[EFC] Starting development server\u2026"));
|
|
51
51
|
console.log(_picocolors2.default.dim(` Entry: ${entry}`));
|
|
52
52
|
const cwd = process.cwd();
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
function findTsx() {
|
|
54
|
+
let dir = cwd;
|
|
55
|
+
while (true) {
|
|
56
|
+
const candidate = _path2.default.join(dir, "node_modules", ".bin", "tsx");
|
|
57
|
+
if (_fs2.default.existsSync(candidate)) return candidate;
|
|
58
|
+
const parent = _path2.default.dirname(dir);
|
|
59
|
+
if (parent === dir) return "tsx";
|
|
60
|
+
dir = parent;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const tsx = findTsx();
|
|
64
|
+
const env = { NODE_ENV: "development", ...parseDotenv(cwd), ...process.env };
|
|
56
65
|
const child = _child_process.spawn.call(void 0, tsx, ["watch", "--include", "src", entry], { stdio: "inherit", env });
|
|
57
66
|
child.on("exit", (code) => process.exit(_nullishCoalesce(code, () => ( 0))));
|
|
58
67
|
}
|
|
@@ -85,6 +94,8 @@ function resolveEntry() {
|
|
|
85
94
|
|
|
86
95
|
|
|
87
96
|
|
|
97
|
+
|
|
98
|
+
|
|
88
99
|
function buildCommand() {
|
|
89
100
|
const cmd = new (0, _commander.Command)("build");
|
|
90
101
|
cmd.argument("<mode>", "prod").description("Build the application for production").action((mode) => {
|
|
@@ -96,15 +107,65 @@ function buildCommand() {
|
|
|
96
107
|
});
|
|
97
108
|
return cmd;
|
|
98
109
|
}
|
|
110
|
+
function findBin(name) {
|
|
111
|
+
let dir = process.cwd();
|
|
112
|
+
while (true) {
|
|
113
|
+
const candidate = _path2.default.join(dir, "node_modules", ".bin", name);
|
|
114
|
+
if (_fs2.default.existsSync(candidate)) return candidate;
|
|
115
|
+
const parent = _path2.default.dirname(dir);
|
|
116
|
+
if (parent === dir) return name;
|
|
117
|
+
dir = parent;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function resolveEntry2() {
|
|
121
|
+
const cwd = process.cwd();
|
|
122
|
+
const candidates = [
|
|
123
|
+
_path2.default.join(cwd, "src", "index.ts"),
|
|
124
|
+
_path2.default.join(cwd, "index.ts"),
|
|
125
|
+
_path2.default.join(cwd, "src", "index.js"),
|
|
126
|
+
_path2.default.join(cwd, "index.js")
|
|
127
|
+
];
|
|
128
|
+
return _nullishCoalesce(candidates.find((f) => _fs2.default.existsSync(f)), () => ( null));
|
|
129
|
+
}
|
|
130
|
+
function hasTsupConfig() {
|
|
131
|
+
const cwd = process.cwd();
|
|
132
|
+
return ["tsup.config.ts", "tsup.config.js", "tsup.config.mjs", "tsup.config.cjs"].some(
|
|
133
|
+
(f) => _fs2.default.existsSync(_path2.default.join(cwd, f))
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
function findTsConfig() {
|
|
137
|
+
const cwd = process.cwd();
|
|
138
|
+
const tsconfig = _path2.default.join(cwd, "tsconfig.json");
|
|
139
|
+
return _fs2.default.existsSync(tsconfig) ? tsconfig : null;
|
|
140
|
+
}
|
|
99
141
|
function buildProd() {
|
|
100
142
|
console.log(_picocolors2.default.cyan("[EFC] Building for production\u2026"));
|
|
101
|
-
const
|
|
143
|
+
const tsconfig = findTsConfig();
|
|
144
|
+
if (!tsconfig) {
|
|
145
|
+
console.error(_picocolors2.default.red("[EFC] No tsconfig.json found in the current directory."));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
const tsc = _child_process.spawn.call(void 0, findBin("tsc"), ["--noEmit", "--project", tsconfig], { stdio: "inherit" });
|
|
102
149
|
tsc.on("exit", (code) => {
|
|
103
150
|
if (code !== 0) {
|
|
104
151
|
console.error(_picocolors2.default.red("[EFC] TypeScript errors found. Fix them before building."));
|
|
105
152
|
process.exit(1);
|
|
106
153
|
}
|
|
107
|
-
|
|
154
|
+
let tsupArgs;
|
|
155
|
+
if (hasTsupConfig()) {
|
|
156
|
+
tsupArgs = [];
|
|
157
|
+
} else {
|
|
158
|
+
const entry = resolveEntry2();
|
|
159
|
+
if (!entry) {
|
|
160
|
+
console.error(
|
|
161
|
+
_picocolors2.default.red("[EFC] Could not find entry point. Expected src/index.ts or index.ts")
|
|
162
|
+
);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
tsupArgs = [entry, "--format", "cjs,esm", "--clean", "--target", "node18"];
|
|
167
|
+
}
|
|
168
|
+
const tsup = _child_process.spawn.call(void 0, findBin("tsup"), tsupArgs, { stdio: "inherit" });
|
|
108
169
|
tsup.on("exit", (tsupCode) => {
|
|
109
170
|
if (tsupCode === 0) {
|
|
110
171
|
console.log(_picocolors2.default.green("[EFC] Build complete \u2192 dist/"));
|
package/dist/cli/index.cjs.map
CHANGED
|
@@ -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')\n .description('Express File Cluster CLI')\n .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 const localTsx = path.join(cwd, 'node_modules', '.bin', 'tsx');\n const tsx = fs.existsSync(localTsx) ? localTsx : 'tsx';\n\n // .env values are base; existing process.env takes precedence (same as dotenv default)\n const env: NodeJS.ProcessEnv = { ...parseDotenv(cwd), ...process.env, NODE_ENV: 'development' };\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 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 buildProd(): void {\n console.log(pc.cyan('[EFC] Building for production…'));\n\n // Type-check first\n const tsc = spawn('npx', ['tsc', '--noEmit'], { 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 const tsup = spawn('npx', ['tsup'], { 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\n const content = `import type { Request, Response } from 'express';\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')\n .description('Print the resolved route table')\n .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')\n .description('List registered background tasks')\n .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/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":"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;AAEhB,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWW,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;ALkLuC;AACA;AM7Qf;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;ANmQuC;AACA;ACnXJ;AAEF;AACA;AACF;AACK;AAEE;AACd,EAAA;AACxB;AAE0B","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\n const content = `import type { Request, Response } from 'express';\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
|
@@ -50,9 +50,18 @@ function startDev() {
|
|
|
50
50
|
console.log(pc.cyan("[EFC] Starting development server\u2026"));
|
|
51
51
|
console.log(pc.dim(` Entry: ${entry}`));
|
|
52
52
|
const cwd = process.cwd();
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
function findTsx() {
|
|
54
|
+
let dir = cwd;
|
|
55
|
+
while (true) {
|
|
56
|
+
const candidate = path.join(dir, "node_modules", ".bin", "tsx");
|
|
57
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
58
|
+
const parent = path.dirname(dir);
|
|
59
|
+
if (parent === dir) return "tsx";
|
|
60
|
+
dir = parent;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const tsx = findTsx();
|
|
64
|
+
const env = { NODE_ENV: "development", ...parseDotenv(cwd), ...process.env };
|
|
56
65
|
const child = spawn(tsx, ["watch", "--include", "src", entry], { stdio: "inherit", env });
|
|
57
66
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
58
67
|
}
|
|
@@ -84,6 +93,8 @@ function resolveEntry() {
|
|
|
84
93
|
// src/cli/commands/build.ts
|
|
85
94
|
import { Command as Command2 } from "commander";
|
|
86
95
|
import { spawn as spawn2 } from "child_process";
|
|
96
|
+
import path2 from "path";
|
|
97
|
+
import fs2 from "fs";
|
|
87
98
|
import pc2 from "picocolors";
|
|
88
99
|
function buildCommand() {
|
|
89
100
|
const cmd = new Command2("build");
|
|
@@ -96,15 +107,65 @@ function buildCommand() {
|
|
|
96
107
|
});
|
|
97
108
|
return cmd;
|
|
98
109
|
}
|
|
110
|
+
function findBin(name) {
|
|
111
|
+
let dir = process.cwd();
|
|
112
|
+
while (true) {
|
|
113
|
+
const candidate = path2.join(dir, "node_modules", ".bin", name);
|
|
114
|
+
if (fs2.existsSync(candidate)) return candidate;
|
|
115
|
+
const parent = path2.dirname(dir);
|
|
116
|
+
if (parent === dir) return name;
|
|
117
|
+
dir = parent;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function resolveEntry2() {
|
|
121
|
+
const cwd = process.cwd();
|
|
122
|
+
const candidates = [
|
|
123
|
+
path2.join(cwd, "src", "index.ts"),
|
|
124
|
+
path2.join(cwd, "index.ts"),
|
|
125
|
+
path2.join(cwd, "src", "index.js"),
|
|
126
|
+
path2.join(cwd, "index.js")
|
|
127
|
+
];
|
|
128
|
+
return candidates.find((f) => fs2.existsSync(f)) ?? null;
|
|
129
|
+
}
|
|
130
|
+
function hasTsupConfig() {
|
|
131
|
+
const cwd = process.cwd();
|
|
132
|
+
return ["tsup.config.ts", "tsup.config.js", "tsup.config.mjs", "tsup.config.cjs"].some(
|
|
133
|
+
(f) => fs2.existsSync(path2.join(cwd, f))
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
function findTsConfig() {
|
|
137
|
+
const cwd = process.cwd();
|
|
138
|
+
const tsconfig = path2.join(cwd, "tsconfig.json");
|
|
139
|
+
return fs2.existsSync(tsconfig) ? tsconfig : null;
|
|
140
|
+
}
|
|
99
141
|
function buildProd() {
|
|
100
142
|
console.log(pc2.cyan("[EFC] Building for production\u2026"));
|
|
101
|
-
const
|
|
143
|
+
const tsconfig = findTsConfig();
|
|
144
|
+
if (!tsconfig) {
|
|
145
|
+
console.error(pc2.red("[EFC] No tsconfig.json found in the current directory."));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
const tsc = spawn2(findBin("tsc"), ["--noEmit", "--project", tsconfig], { stdio: "inherit" });
|
|
102
149
|
tsc.on("exit", (code) => {
|
|
103
150
|
if (code !== 0) {
|
|
104
151
|
console.error(pc2.red("[EFC] TypeScript errors found. Fix them before building."));
|
|
105
152
|
process.exit(1);
|
|
106
153
|
}
|
|
107
|
-
|
|
154
|
+
let tsupArgs;
|
|
155
|
+
if (hasTsupConfig()) {
|
|
156
|
+
tsupArgs = [];
|
|
157
|
+
} else {
|
|
158
|
+
const entry = resolveEntry2();
|
|
159
|
+
if (!entry) {
|
|
160
|
+
console.error(
|
|
161
|
+
pc2.red("[EFC] Could not find entry point. Expected src/index.ts or index.ts")
|
|
162
|
+
);
|
|
163
|
+
process.exit(1);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
tsupArgs = [entry, "--format", "cjs,esm", "--clean", "--target", "node18"];
|
|
167
|
+
}
|
|
168
|
+
const tsup = spawn2(findBin("tsup"), tsupArgs, { stdio: "inherit" });
|
|
108
169
|
tsup.on("exit", (tsupCode) => {
|
|
109
170
|
if (tsupCode === 0) {
|
|
110
171
|
console.log(pc2.green("[EFC] Build complete \u2192 dist/"));
|
|
@@ -139,8 +200,8 @@ function runTests(extraArgs) {
|
|
|
139
200
|
|
|
140
201
|
// src/cli/commands/generate.ts
|
|
141
202
|
import { Command as Command4 } from "commander";
|
|
142
|
-
import
|
|
143
|
-
import
|
|
203
|
+
import fs3 from "fs";
|
|
204
|
+
import path3 from "path";
|
|
144
205
|
import pc4 from "picocolors";
|
|
145
206
|
function generateCommand() {
|
|
146
207
|
const cmd = new Command4("generate").alias("g").description("Scaffold EFC modules");
|
|
@@ -150,18 +211,18 @@ function generateCommand() {
|
|
|
150
211
|
return cmd;
|
|
151
212
|
}
|
|
152
213
|
function writeFile(filePath, content) {
|
|
153
|
-
const dir =
|
|
154
|
-
|
|
155
|
-
if (
|
|
214
|
+
const dir = path3.dirname(filePath);
|
|
215
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
216
|
+
if (fs3.existsSync(filePath)) {
|
|
156
217
|
console.error(pc4.red(`File already exists: ${filePath}`));
|
|
157
218
|
process.exit(1);
|
|
158
219
|
}
|
|
159
|
-
|
|
160
|
-
console.log(pc4.green(` created ${
|
|
220
|
+
fs3.writeFileSync(filePath, content, "utf8");
|
|
221
|
+
console.log(pc4.green(` created ${path3.relative(process.cwd(), filePath)}`));
|
|
161
222
|
}
|
|
162
223
|
function generateRoute(routePath) {
|
|
163
224
|
const cwd = process.cwd();
|
|
164
|
-
const filePath =
|
|
225
|
+
const filePath = path3.join(cwd, "src", "api", `${routePath}.ts`);
|
|
165
226
|
const content = `import type { Request, Response } from 'express';
|
|
166
227
|
|
|
167
228
|
export const GET = async (req: Request, res: Response) => {
|
|
@@ -177,7 +238,7 @@ export const POST = async (req: Request, res: Response) => {
|
|
|
177
238
|
}
|
|
178
239
|
function generateTask(name) {
|
|
179
240
|
const cwd = process.cwd();
|
|
180
|
-
const filePath =
|
|
241
|
+
const filePath = path3.join(cwd, "src", "tasks", `${name}.ts`);
|
|
181
242
|
const content = `import { defineTask } from 'express-file-cluster/tasks';
|
|
182
243
|
|
|
183
244
|
interface ${name}Payload {
|
|
@@ -194,7 +255,7 @@ export default defineTask<${name}Payload>(async (payload) => {
|
|
|
194
255
|
}
|
|
195
256
|
function generateMiddleware(name) {
|
|
196
257
|
const cwd = process.cwd();
|
|
197
|
-
const filePath =
|
|
258
|
+
const filePath = path3.join(cwd, "src", "middlewares", `${name}.ts`);
|
|
198
259
|
const content = `import type { Request, Response, NextFunction } from 'express';
|
|
199
260
|
|
|
200
261
|
export function ${name}(req: Request, res: Response, next: NextFunction): void {
|
|
@@ -208,8 +269,8 @@ export function ${name}(req: Request, res: Response, next: NextFunction): void {
|
|
|
208
269
|
|
|
209
270
|
// src/cli/commands/diagnostics.ts
|
|
210
271
|
import { Command as Command5 } from "commander";
|
|
211
|
-
import
|
|
212
|
-
import
|
|
272
|
+
import path4 from "path";
|
|
273
|
+
import fs4 from "fs";
|
|
213
274
|
import pc5 from "picocolors";
|
|
214
275
|
function diagnosticsCommands() {
|
|
215
276
|
return [routesCommand(), tasksCommand(), doctorCommand()];
|
|
@@ -229,7 +290,7 @@ function routesCommand() {
|
|
|
229
290
|
console.log(pc5.bold("\n Route Table\n"));
|
|
230
291
|
console.log(pc5.dim(" " + "\u2500".repeat(60)));
|
|
231
292
|
for (const route of routes) {
|
|
232
|
-
const rel =
|
|
293
|
+
const rel = path4.relative(process.cwd(), route.filePath);
|
|
233
294
|
console.log(` ${pc5.cyan(route.urlPath.padEnd(35))} ${pc5.dim(rel)}`);
|
|
234
295
|
}
|
|
235
296
|
console.log(pc5.dim(" " + "\u2500".repeat(60)));
|
|
@@ -241,18 +302,18 @@ function routesCommand() {
|
|
|
241
302
|
function tasksCommand() {
|
|
242
303
|
return new Command5("tasks").description("List registered background tasks").action(() => {
|
|
243
304
|
const tasksDir = resolveTasksDir();
|
|
244
|
-
if (!tasksDir || !
|
|
305
|
+
if (!tasksDir || !fs4.existsSync(tasksDir)) {
|
|
245
306
|
console.log(pc5.yellow("No tasks directory found."));
|
|
246
307
|
return;
|
|
247
308
|
}
|
|
248
|
-
const files =
|
|
309
|
+
const files = fs4.readdirSync(tasksDir).filter((f) => /\.(ts|js)$/.test(f));
|
|
249
310
|
if (files.length === 0) {
|
|
250
311
|
console.log(pc5.yellow("No tasks found."));
|
|
251
312
|
return;
|
|
252
313
|
}
|
|
253
314
|
console.log(pc5.bold("\n Background Tasks\n"));
|
|
254
315
|
for (const file of files) {
|
|
255
|
-
console.log(` ${pc5.cyan(
|
|
316
|
+
console.log(` ${pc5.cyan(path4.basename(file, path4.extname(file)))}`);
|
|
256
317
|
}
|
|
257
318
|
console.log();
|
|
258
319
|
});
|
|
@@ -263,16 +324,16 @@ function doctorCommand() {
|
|
|
263
324
|
const checks = [
|
|
264
325
|
{
|
|
265
326
|
label: "package.json exists",
|
|
266
|
-
ok:
|
|
327
|
+
ok: fs4.existsSync(path4.join(cwd, "package.json"))
|
|
267
328
|
},
|
|
268
329
|
{
|
|
269
330
|
label: "tsconfig.json exists",
|
|
270
|
-
ok:
|
|
331
|
+
ok: fs4.existsSync(path4.join(cwd, "tsconfig.json")),
|
|
271
332
|
hint: "Run `tsc --init` to create one"
|
|
272
333
|
},
|
|
273
334
|
{
|
|
274
335
|
label: "src/api directory exists",
|
|
275
|
-
ok:
|
|
336
|
+
ok: fs4.existsSync(path4.join(cwd, "src", "api")),
|
|
276
337
|
hint: "Create src/api/ and add route files"
|
|
277
338
|
},
|
|
278
339
|
{
|
|
@@ -307,13 +368,13 @@ function doctorCommand() {
|
|
|
307
368
|
}
|
|
308
369
|
function resolveApiDir() {
|
|
309
370
|
const cwd = process.cwd();
|
|
310
|
-
const candidates = [
|
|
311
|
-
return candidates.find((d) =>
|
|
371
|
+
const candidates = [path4.join(cwd, "src", "api"), path4.join(cwd, "api")];
|
|
372
|
+
return candidates.find((d) => fs4.existsSync(d)) ?? null;
|
|
312
373
|
}
|
|
313
374
|
function resolveTasksDir() {
|
|
314
375
|
const cwd = process.cwd();
|
|
315
|
-
const candidates = [
|
|
316
|
-
return candidates.find((d) =>
|
|
376
|
+
const candidates = [path4.join(cwd, "src", "tasks"), path4.join(cwd, "tasks")];
|
|
377
|
+
return candidates.find((d) => fs4.existsSync(d)) ?? null;
|
|
317
378
|
}
|
|
318
379
|
|
|
319
380
|
// src/cli/index.ts
|