koa-ts-core 0.3.7 → 0.3.9
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,10 +1,13 @@
|
|
|
1
1
|
interface ExceptionOptions {
|
|
2
2
|
message: string;
|
|
3
|
-
code
|
|
3
|
+
code?: number;
|
|
4
4
|
data?: Record<string, any>;
|
|
5
|
+
statusCode?: number;
|
|
5
6
|
}
|
|
6
7
|
/**
|
|
7
8
|
* @class BaseException 定义异常基类
|
|
9
|
+
* 已实现子类型
|
|
10
|
+
* 1. 权限异常 ForbiddenException 403
|
|
8
11
|
*/
|
|
9
12
|
declare abstract class BaseException extends Error {
|
|
10
13
|
code: number;
|
package/dist/index.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";require("reflect-metadata");var e=require("async_hooks"),t=require("fs"),s=require("path"),r=require("@koa/router"),o=require("koa"),a=require("portfinder"),n=require("dotenv"),c=require("log4js"),i=require("koa-bodyparser"),d=require("koa2-cors"),p=require("crypto"),l=require("koa2-swagger-ui");const u=["get","post","put","delete","patch","options"],h=0,g="index",f="get_",m=[g,f,...u],y=Symbol("route_metadata");function w(e){const t=e.trim();if(!t)return"";return`/${t.replace(/^\/+/,"")}`}function x(e,t,s=!1){return(r,o,a)=>{if("function"!=typeof a.value)throw new Error(`@Router/@AuthRouter 只能用于方法:${o}`);let n=Reflect.getMetadata(y,r.constructor);n||(n=new Map,Reflect.defineMetadata(y,n,r.constructor));const c=function(e,t){return e||(t===f?"get":u.includes(t)?t:"get")}(e,o),i=function(e,t){return null!=e?w(e):m.includes(t)?"":w(t)}(t,o),d={handler:a.value,path:i,method:c,functionName:o,authRequired:s,middlewares:[],className:r.constructor.name,apiPrePath:""};return n.set(o,d),a}}const v=new e.AsyncLocalStorage,P=()=>{const e=v.getStore();if(!e)throw new Error("context is not exist");return e},k=e=>{const{success:t=!0,errorCode:s=-1,message:r="success",errorMessage:o="error request",data:a=null,statusCode:n=200}=e??{},c=P(),i={code:t?h:s,message:t?r:o,...null!=a?{data:a}:{}};c.trackId&&(i.trackId=c.trackId),c.body=i,c.status=n},b=(e,t)=>{k({success:!1,errorMessage:t?.message,errorCode:t?.code,data:t?.data,statusCode:e})};class q extends Error{constructor(e){super(e?.message||"An unexpected error occurred"),this.name=this.constructor.name,this.code=e?.code??-1,this.statusCode=500,"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.stack=this.stack??new Error(this.message).stack}get toRspOptions(){return{code:this.code,message:this.message,data:this.stack}}}const M=()=>{const e=process.cwd();if(t.existsSync(s.resolve(e,"controller")))return e;const r=s.resolve(e,"src");if(t.existsSync(r))return r;const o=s.resolve(e,"dist");if(t.existsSync(o))return o;const a=s.resolve(e,"build");return t.existsSync(a)?a:r},E=()=>{const e=M();return{controllerModule:s.resolve(e,"controller"),validateModule:s.resolve(e,"validate"),viewModule:s.resolve(e,"view"),docModule:s.resolve(e,"doc")}},S=e=>{if(t.existsSync(e))try{const t=require(e);return t.default||t}catch(t){throw console.error(`[koa-ts-core] Failed to load module: ${e}`,t),t}};function R(e,r){t.existsSync(e)&&t.readdirSync(e,{withFileTypes:!0}).forEach(t=>{const o=s.resolve(e,t.name);t.isFile()?r({path:e,name:t.name,wholePath:o},t):t.isDirectory()&&R(o,r)})}const A=e=>e.split(s.sep).join("/"),I=e=>{const t=A(e).replace(/^\/+/,"");return t?`/${t}`:""},N=(e,t)=>{const s=A(e.path).split("/"),r=s.lastIndexOf(t);if(-1===r){const s=e.path.indexOf(t);if(-1===s)throw new Error(`'${t}' not found in path: ${e.path}`);const r=e.path.substring(s+t.length),o=I(r),a=e.name?.split(".")?.[0];return{pathPrefix:o,moduleName:a,name:e.name}}const o=s.slice(r+1).join("/"),a=I(o),n=e.name?.split(".")?.[0];return{pathPrefix:a,moduleName:n,name:e.name}};function O(e){try{return t.statSync(e).isDirectory()}catch{return!1}}var C;exports.MiddlewarePhase=void 0,(C=exports.MiddlewarePhase||(exports.MiddlewarePhase={})).AsyncContext="AsyncContext",C.ErrorHandling="ErrorHandling",C.Logging="Logging",C.Security="Security",C.BodyParsing="BodyParsing",C.Auth="Auth",C.Routing="Routing";const $=new r,_=async e=>{if(!process.env.APP_PORT)try{const e=await a.getPortPromise({port:8e3,stopPort:9999});process.env.APP_PORT=String(e)}catch(e){console.warn("[koa-ts-core] Failed to find available port automatically.")}const t=e.listen;e.listen=function(...e){if(0===e.length&&process.env.APP_PORT){const t=Number(process.env.APP_PORT);isNaN(t)||e.push(t)}const s=t.apply(this,e);return s.on("listening",()=>(e=>{const t=e.address();if(t)if("string"==typeof t)console.log(`Server listening on ${t}`);else{const{port:e}=t;console.log(`Server running at http://localhost:${e}`)}})(s)),s}},j=Symbol("validate_metadata"),D=Symbol("swagger_tags"),T=Symbol("swagger_operation"),L=Symbol("swagger_parameters"),B=Symbol("swagger_body"),U=Symbol("swagger_responses"),H={DOCUMENTATION_DIR:s.join(process.cwd(),"doc")},F=()=>{const e=[];return O(H.DOCUMENTATION_DIR)?(R(H.DOCUMENTATION_DIR,t=>{if(!t.name.endsWith(".ts")&&!t.name.endsWith(".js"))return;const{pathPrefix:s}=N(t,"doc"),r=((e,t)=>{const s=S(e.wholePath);if(!s)return{configs:[],desc:"",name:"",pathPrefix:t,apiPrePath:""};const r=s.prototype,o=Object.getOwnPropertyNames(r).filter(e=>"function"==typeof r[e]&&"constructor"!==e),a=e.path.indexOf("doc"),n=a>=0?I(e.path.substring(a+3)):"";let c=n;if(e.name&&!e.name.startsWith("index.")){const t=e.name.split(".")[0];c=`${n}/${t}`}const i=o.map(e=>{const t=r[e];if("function"==typeof t){const e=t();return e.path=`${c}${e.path}`,e}return null}).filter(e=>!!e);let d="";if(i[0]?.path){const e=i[0].path.lastIndexOf("/");e>-1&&(d=i[0].path.substring(0,e))}return{configs:i,desc:s.desc,name:s.name,pathPrefix:t,apiPrePath:d}})(t,s);r.configs.length>0&&e.push(r)}),e):[]};class V{constructor(){this.paths={}}static getInstance(){return this.instance||(this.instance=new V),this.instance}addRoute(e,t,s,r){const o=r.replace(/:([a-zA-Z0-9_]+)/g,"{$1}");this.paths[o]||(this.paths[o]={});const a=e.prototype,n=Reflect.getMetadata(T,a,t)||{},c=n.summary,i=n.description,d=Reflect.getMetadata(D,e)||[e.name],p=Reflect.getMetadata(L,a,t)||[],l=Reflect.getMetadata(B,a,t);let u;l&&(u={description:l.description,required:l.required,content:{"application/json":{schema:l.schema||{type:"object"}}}});const h=Reflect.getMetadata(U,a,t)||[],g={};h.forEach(e=>{g[e.status]={description:e.description||"",content:e.schema?{"application/json":{schema:e.schema}}:void 0}}),0===Object.keys(g).length&&(g[200]={description:"Success"}),this.paths[o][s.toLowerCase()]={tags:d,summary:c,description:i,parameters:p,requestBody:u,responses:g}}loadDocMetadata(){F().forEach(e=>{const t=e.desc||e.name;e.configs.forEach(e=>{const s=("/"+e.path).replace(/\/+/g,"/"),r=s.replace(/:([a-zA-Z0-9_]+)/g,"{$1}"),o=e.method.toLowerCase();this.paths[r]||(this.paths[r]={}),this.paths[r][o]||(this.paths[r][o]={});const a=this.paths[r][o];a.summary||(a.summary=e.description),a.tags&&0!==a.tags.length||(a.tags=[t]);const n=s.match(/:([a-zA-Z0-9_]+)/g);if(n&&(a.parameters||(a.parameters=[]),n.forEach(e=>{const t=e.substring(1);a.parameters.find(e=>e.name===t&&"path"===e.in)||a.parameters.push({name:t,in:"path",required:!0,schema:{type:"string"},description:t})})),e.request?.query&&(a.parameters||(a.parameters=[]),Object.keys(e.request.query).forEach(t=>{if(!a.parameters.find(e=>e.name===t&&"query"===e.in)){const s=e.request?.query?.[t];s&&"object"==typeof s&&a.parameters.push({name:t,in:"query",description:s.description,required:!1!==s.required,schema:s.schema??{type:s.type??"string"},example:s.example})}})),e.request?.header&&(a.parameters||(a.parameters=[]),Object.keys(e.request.header).forEach(t=>{if("content-type"===t.toLowerCase())return;if(!a.parameters.find(e=>e.name===t&&"header"===e.in)){const s=e.request?.header?.[t];s&&"object"==typeof s&&a.parameters.push({name:t,in:"header",description:s.description,required:!1!==s.required,schema:s.schema??{type:s.type??"string"},example:s.example})}})),e.request?.body&&Object.keys(e.request.body).length>0&&!a.requestBody){const t=e.request.body;a.requestBody={description:t.description,required:t.required,content:{"application/json":{schema:{type:"object",properties:t.schema},example:t.example}}}}e.response?.body&&(a.responses||(a.responses={}),a.responses[200]||(a.responses[200]={description:"Success",content:{"application/json":{schema:{type:"object",example:e.response.body}}}}))})})}tagSpecByPrefix(e,t={}){const{level:s=2,onlyIfEmpty:r=!0}=t,o=new Set(["get","post","put","delete","patch","head","options","trace"]),a=new Set((e.tags||[]).map(e=>e.name)),n=e.paths||{};for(const[e,t]of Object.entries(n)){if(!t)continue;const n="/"+e.split("/").filter(Boolean).slice(0,s).join("/");for(const[e,s]of Object.entries(t)){if(!o.has(e))continue;if(!s||"object"!=typeof s)continue;const t=s,c=Array.isArray(t.tags)&&t.tags.length>0;r&&c||(t.tags=[n]),a.add(n)}}return e.tags=Array.from(a).map(e=>({name:e})),e}generateSpec(){return{openapi:"3.0.0",info:{title:"API Documentation",version:"1.0.0",description:"Auto generated by koa-ts-core"},paths:this.paths,components:{schemas:{}}}}}const z=(e,t,s,r,o)=>{if(!r||0===r.size)return;const{pathPrefix:a,moduleName:n,name:c}=N(t,"controller"),i=`${a}/${n}`,d=S(`${e}${a}/${c}`),p=e=>async(t,s)=>{const r=e(t);r instanceof Promise&&await r,await s()};r.forEach(e=>{const{method:t,path:r,handler:n,functionName:c,authRequired:l,middlewares:u}=e,h=[...u],g=Reflect.getMetadata(j,s.prototype,c);g?h.push(p(g)):d&&"function"==typeof d[c]&&h.push(p(d[c].bind(d))),h.push(((e,t)=>async(s,r)=>{let a=o(e,s);return a instanceof Promise&&(a=await a),a?t(s,r):s.throw(403,"无权限")})(l,n));const f=W(r,i,c,h,t);V.getInstance().addRoute(s,c,t,f),e.path=f,e.apiPrePath=a})},W=(e,t,s,r,o)=>{const a=`${t}${e}`;if(s===g){const e=`${t}/index`;$[o](e,...r)}return $[o](a,...r),a};let Z=null;const K=()=>(Z||(Z=c.configure({appenders:{console:{type:"console"},file:{type:"dateFile",filename:"logs/app.log",pattern:".yyyy-MM-dd",compress:!0,numBackups:7,alwaysIncludePattern:!0}},categories:{default:{appenders:["console","file"],level:"info"}}})),Z),Q=(e,t)=>v.run(e,()=>t()),X=e=>{const{generator:t,exposeHeader:s=!0,headerName:r="x-request-id"}=e;return!1===t?async(e,t)=>{await t()}:async(e,o)=>{const a=await t(e);a&&(e.trackId=a,s&&e.set(r,a)),await o()}},Y=async(e,t)=>{const s=Date.now(),r=K().getLogger(),o=e.runtimeLog;o&&r.info("[REQUEST] %s %s %s - ip: %s - ua: %s",e.trackId,e.method,e.url,e.ip,e.get("user-agent")||"-");try{e.hook?.(e,"request"),await t(),e.hook?.(e,"response")}catch(t){const a=Date.now()-s;throw o&&r.error("[ERROR] %s %s %s - status: %s - cost: %dms - message: %s - stack: %s",e.trackId,e.method,e.url,t.status||500,a,t.message||"unknown error",t.stack||""),t}const a=Date.now()-s;o&&r.info("[RESPONSE] %s %s %s - status: %d - cost: %dms - length: %s",e.trackId,e.method,e.url,e.status,a,e.length||e.response.length||"-")},G=async(e,t)=>{e.extra={get:e.query,post:e.request.body??{}},await t()};(()=>{const e=process.env.NODE_ENV||"production";let t;const r=process.env.ENV_DIR;if(r){if(t=s.isAbsolute(r)?r:s.resolve(process.cwd(),r),!O(t))throw new Error(`[koa-ts-core] ENV_DIR is set but directory not found: ${t}`)}else{const e=M();let r=s.resolve(e,"env");if(O(r)||(r=s.resolve(e,"..","env")),!O(r))return void console.warn(`[koa-ts-core] env directory not found: tried ${s.resolve(e,"env")} and ${s.resolve(e,"..","env")}`);t=r}console.log("[koa-ts-core] load env path:",t),n.config({path:s.resolve(t,".env.local")});const o={development:".development.env",test:".test.env",production:".production.env"}[e];o&&n.config({path:s.resolve(t,`${o}.local`)}),o&&n.config({path:s.resolve(t,o)}),n.config({path:s.resolve(t,".common.env")})})(),global.isDev="development"===process.env.NODE_ENV;const J=e=>{const{koaInstance:t,auth:s,error:r,log:a,hooks:n,phaseMiddlewares:c,koa2Cors:i,trackId:d,swagger:l,bodyParser:u}=e;return{app:t??new o,auth:{handler:s?.handler},error:{handler:r?.handler,exposeStack:r?.exposeStack??"production"!==process.env.NODE_ENV},log:{log4:a?.log4??!1,runtimeLog:a?.runtimeLog??!0},hooks:{register:n?.register},phaseMiddlewares:c??new Map,koa2Cors:i,trackId:{generator:!1!==d?.generator&&(async e=>{const t=d?.headerName??"x-request-id",s=e.get(t);return s||p.randomUUID()}),exposeHeader:d?.exposeHeader??!0,headerName:d?.headerName??"x-request-id"},swagger:l,bodyParser:u}},ee=(e,t)=>{const{log:s,hooks:r}=t;e.context.log4=(e=>{if(!1!==e)return"boolean"==typeof e&&!0===e?K():e(c)})(s.log4),e.context.runtimeLog=s.runtimeLog,e.context.hook=r.register,e.context.validated={params:{},get:{},post:{}}},te=e=>{(e=>{const{controllerModule:t,validateModule:s}=E();console.log("load controller path:",t),R(t,t=>{if(!t.name.endsWith(".ts")&&!t.name.endsWith(".js"))return;const r=S(t.wholePath);if(!r)return;const o=Reflect.getMetadata(y,r);o instanceof Map&&0!==o.size&&z(s,t,r,o,(s,r)=>{if(!s)return!0;if(!e)throw new Error(`Route requires auth but no authCheckCallback provided. File: ${t.wholePath}`);return e({filePath:t,ctx:r})})})})(e),$.get("/",async e=>{e.body={code:200,message:"hello koa-ts-cli https://www.npmjs.com/package/koa-ts-core"}})};exports.AuthRouter=function(e,t){return x(e,t,!0)},exports.BaseException=q,exports.INDEX_ROUTE=g,exports.ROUTE_METADATA_KEY=y,exports.Router=function(e,t){return x(e,t,!1)},exports.contextStore=v,exports.createKoaApp=async e=>{const t=J(e),{app:s}=t;if(ee(s,t),te(t.auth.handler),t.swagger?.enabled){V.getInstance().loadDocMetadata();const e=V.getInstance().generateSpec();t.swagger.title&&(e.info.title=t.swagger.title),t.swagger.description&&(e.info.description=t.swagger.description),t.swagger.version&&(e.info.version=t.swagger.version);const r=t.swagger.path||"/swagger-ui";s.use(l.koaSwagger({routePrefix:r,swaggerOptions:{spec:V.getInstance().tagSpecByPrefix(e,{level:2,onlyIfEmpty:!1})}})),console.log(`[koa-ts-core] Swagger UI available at ${r}`)}return((e,t,s)=>{const{errorConfig:r,koa2Cors:o,trackConfig:a,bodyParser:n}=s,c={[exports.MiddlewarePhase.AsyncContext]:[Q],[exports.MiddlewarePhase.ErrorHandling]:[(p=r?.handler,async(e,t)=>{try{await t()}catch(t){if(e.hook?.(e,"error"),p)p(t,e);else{const e=t.statusCode||t.status||500,s=t.code??-1;b(e,{message:t.message,code:s,data:"production"!==process.env.NODE_ENV?t.stack:void 0})}}})],[exports.MiddlewarePhase.Logging]:[X(a),Y],[exports.MiddlewarePhase.Security]:[...o?[o(d)]:[]],[exports.MiddlewarePhase.BodyParsing]:[i(n),G],[exports.MiddlewarePhase.Auth]:[],[exports.MiddlewarePhase.Routing]:[$.routes()]};var p;const l=[exports.MiddlewarePhase.AsyncContext,exports.MiddlewarePhase.ErrorHandling,exports.MiddlewarePhase.Logging,exports.MiddlewarePhase.Security,exports.MiddlewarePhase.BodyParsing,exports.MiddlewarePhase.Auth,exports.MiddlewarePhase.Routing];for(const s of l){const r=t.get(s),o=c[s]??[];if(r?.before)for(const t of r.before)e.use(t);for(const t of o)e.use(t);if(r?.use)for(const t of r.use)e.use(t);if(r?.after)for(const t of r.after)e.use(t)}})(s,t.phaseMiddlewares,{errorConfig:t.error,koa2Cors:t.koa2Cors,trackConfig:t.trackId,bodyParser:t.bodyParser}),await _(s),[s,$]},exports.errorRsp=b,exports.getCurrentContext=P,exports.getSrcModulePaths=E,exports.successRsp=e=>{const t=Array.isArray(e?.data);k({success:!0,message:e?.message,data:t?{list:e?.data}:e?.data})},exports.unSuccessRsp=e=>{k({success:!1,errorCode:e?.code,errorMessage:e?.message,data:e?.data})};
|
|
1
|
+
"use strict";require("reflect-metadata");var e=require("async_hooks"),t=require("fs"),s=require("path"),r=require("@koa/router"),o=require("koa"),a=require("portfinder"),n=require("dotenv"),c=require("log4js"),i=require("koa-bodyparser"),d=require("koa2-cors"),p=require("crypto"),u=require("koa2-swagger-ui");const l=["get","post","put","delete","patch","options"],h=0,g="index",f="get_",m=[g,f,...l],y=Symbol("route_metadata");function w(e){const t=e.trim();if(!t)return"";return`/${t.replace(/^\/+/,"")}`}function x(e,t,s=!1){return(r,o,a)=>{if("function"!=typeof a.value)throw new Error(`@Router/@AuthRouter 只能用于方法:${o}`);let n=Reflect.getMetadata(y,r.constructor);n||(n=new Map,Reflect.defineMetadata(y,n,r.constructor));const c=function(e,t){return e||(t===f?"get":l.includes(t)?t:"get")}(e,o),i=function(e,t){return null!=e?w(e):m.includes(t)?"":w(t)}(t,o),d={handler:a.value,path:i,method:c,functionName:o,authRequired:s,middlewares:[],className:r.constructor.name,apiPrePath:""};return n.set(o,d),a}}const v=new e.AsyncLocalStorage,P=()=>{const e=v.getStore();if(!e)throw new Error("context is not exist");return e},k=e=>{const{success:t=!0,errorCode:s=-1,message:r="success",errorMessage:o="error request",data:a=null,statusCode:n=200}=e??{},c=P(),i={code:t?h:s,message:t?r:o,...null!=a?{data:a}:{}};c.trackId&&(i.trackId=c.trackId),c.body=i,c.status=n},b=(e,t)=>{k({success:!1,errorMessage:t?.message,errorCode:t?.code,data:t?.data,statusCode:e})};class q extends Error{constructor(e){super(e?.message||"An unexpected error occurred"),this.name=this.constructor.name,this.code=e?.code??-1,this.statusCode=e?.statusCode??500,"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.stack=this.stack??new Error(this.message).stack}get toRspOptions(){return{code:this.code,message:this.message,data:this.stack}}}class E extends q{constructor(e){super({statusCode:403,message:e})}}const M=()=>{const e=process.cwd();if(t.existsSync(s.resolve(e,"controller")))return e;const r=s.resolve(e,"src");if(t.existsSync(r))return r;const o=s.resolve(e,"dist");if(t.existsSync(o))return o;const a=s.resolve(e,"build");return t.existsSync(a)?a:r},S=()=>{const e=M();return{controllerModule:s.resolve(e,"controller"),validateModule:s.resolve(e,"validate"),viewModule:s.resolve(e,"view"),docModule:s.resolve(e,"doc")}},R=e=>{if(t.existsSync(e))try{const t=require(e);return t.default||t}catch(t){throw console.error(`[koa-ts-core] Failed to load module: ${e}`,t),t}};function A(e,r){t.existsSync(e)&&t.readdirSync(e,{withFileTypes:!0}).forEach(t=>{const o=s.resolve(e,t.name);t.isFile()?r({path:e,name:t.name,wholePath:o},t):t.isDirectory()&&A(o,r)})}const N=e=>e.split(s.sep).join("/"),I=e=>{const t=N(e).replace(/^\/+/,"");return t?`/${t}`:""},O=(e,t)=>{const s=N(e.path).split("/"),r=s.lastIndexOf(t);if(-1===r){const s=e.path.indexOf(t);if(-1===s)throw new Error(`'${t}' not found in path: ${e.path}`);const r=e.path.substring(s+t.length),o=I(r),a=e.name?.split(".")?.[0];return{pathPrefix:o,moduleName:a,name:e.name}}const o=s.slice(r+1).join("/"),a=I(o),n=e.name?.split(".")?.[0];return{pathPrefix:a,moduleName:n,name:e.name}};function C(e){try{return t.statSync(e).isDirectory()}catch{return!1}}var $;exports.MiddlewarePhase=void 0,($=exports.MiddlewarePhase||(exports.MiddlewarePhase={})).AsyncContext="AsyncContext",$.ErrorHandling="ErrorHandling",$.Logging="Logging",$.Security="Security",$.BodyParsing="BodyParsing",$.Auth="Auth",$.Routing="Routing";const _=new r,j=async e=>{if(!process.env.APP_PORT)try{const e=await a.getPortPromise({port:8e3,stopPort:9999});process.env.APP_PORT=String(e)}catch(e){console.warn("[koa-ts-core] Failed to find available port automatically.")}const t=e.listen;e.listen=function(...e){if(0===e.length&&process.env.APP_PORT){const t=Number(process.env.APP_PORT);isNaN(t)||e.push(t)}const s=t.apply(this,e);return s.on("listening",()=>(e=>{const t=e.address();if(t)if("string"==typeof t)console.log(`Server listening on ${t}`);else{const{port:e}=t;console.log(`Server running at http://localhost:${e}`)}})(s)),s}},D=Symbol("validate_metadata"),T=Symbol("swagger_tags"),L=Symbol("swagger_operation"),B=Symbol("swagger_parameters"),U=Symbol("swagger_body"),H=Symbol("swagger_responses"),V={DOCUMENTATION_DIR:s.join(process.cwd(),"doc")},F=()=>{const e=[];return C(V.DOCUMENTATION_DIR)?(A(V.DOCUMENTATION_DIR,t=>{if(!t.name.endsWith(".ts")&&!t.name.endsWith(".js"))return;const{pathPrefix:s}=O(t,"doc"),r=((e,t)=>{const s=R(e.wholePath);if(!s)return{configs:[],desc:"",name:"",pathPrefix:t,apiPrePath:""};const r=s.prototype,o=Object.getOwnPropertyNames(r).filter(e=>"function"==typeof r[e]&&"constructor"!==e),a=e.path.indexOf("doc"),n=a>=0?I(e.path.substring(a+3)):"";let c=n;if(e.name&&!e.name.startsWith("index.")){const t=e.name.split(".")[0];c=`${n}/${t}`}const i=o.map(e=>{const t=r[e];if("function"==typeof t){const e=t();return e.path=`${c}${e.path}`,e}return null}).filter(e=>!!e);let d="";if(i[0]?.path){const e=i[0].path.lastIndexOf("/");e>-1&&(d=i[0].path.substring(0,e))}return{configs:i,desc:s.desc,name:s.name,pathPrefix:t,apiPrePath:d}})(t,s);r.configs.length>0&&e.push(r)}),e):[]};class z{constructor(){this.paths={}}static getInstance(){return this.instance||(this.instance=new z),this.instance}addRoute(e,t,s,r){const o=r.replace(/:([a-zA-Z0-9_]+)/g,"{$1}");this.paths[o]||(this.paths[o]={});const a=e.prototype,n=Reflect.getMetadata(L,a,t)||{},c=n.summary,i=n.description,d=Reflect.getMetadata(T,e)||[e.name],p=Reflect.getMetadata(B,a,t)||[],u=Reflect.getMetadata(U,a,t);let l;u&&(l={description:u.description,required:u.required,content:{"application/json":{schema:u.schema||{type:"object"}}}});const h=Reflect.getMetadata(H,a,t)||[],g={};h.forEach(e=>{g[e.status]={description:e.description||"",content:e.schema?{"application/json":{schema:e.schema}}:void 0}}),0===Object.keys(g).length&&(g[200]={description:"Success"}),this.paths[o][s.toLowerCase()]={tags:d,summary:c,description:i,parameters:p,requestBody:l,responses:g}}loadDocMetadata(){F().forEach(e=>{const t=e.desc||e.name;e.configs.forEach(e=>{const s=("/"+e.path).replace(/\/+/g,"/"),r=s.replace(/:([a-zA-Z0-9_]+)/g,"{$1}"),o=e.method.toLowerCase();this.paths[r]||(this.paths[r]={}),this.paths[r][o]||(this.paths[r][o]={});const a=this.paths[r][o];a.summary||(a.summary=e.description),a.tags&&0!==a.tags.length||(a.tags=[t]);const n=s.match(/:([a-zA-Z0-9_]+)/g);if(n&&(a.parameters||(a.parameters=[]),n.forEach(e=>{const t=e.substring(1);a.parameters.find(e=>e.name===t&&"path"===e.in)||a.parameters.push({name:t,in:"path",required:!0,schema:{type:"string"},description:t})})),e.request?.query&&(a.parameters||(a.parameters=[]),Object.keys(e.request.query).forEach(t=>{if(!a.parameters.find(e=>e.name===t&&"query"===e.in)){const s=e.request?.query?.[t];s&&"object"==typeof s&&a.parameters.push({name:t,in:"query",description:s.description,required:!1!==s.required,schema:s.schema??{type:s.type??"string"},example:s.example})}})),e.request?.header&&(a.parameters||(a.parameters=[]),Object.keys(e.request.header).forEach(t=>{if("content-type"===t.toLowerCase())return;if(!a.parameters.find(e=>e.name===t&&"header"===e.in)){const s=e.request?.header?.[t];s&&"object"==typeof s&&a.parameters.push({name:t,in:"header",description:s.description,required:!1!==s.required,schema:s.schema??{type:s.type??"string"},example:s.example})}})),e.request?.body&&Object.keys(e.request.body).length>0&&!a.requestBody){const t=e.request.body;a.requestBody={description:t.description,required:t.required,content:{"application/json":{schema:{type:"object",properties:t.schema},example:t.example}}}}e.response?.body&&(a.responses||(a.responses={}),a.responses[200]||(a.responses[200]={description:"Success",content:{"application/json":{schema:{type:"object",example:e.response.body}}}}))})})}tagSpecByPrefix(e,t={}){const{level:s=2,onlyIfEmpty:r=!0}=t,o=new Set(["get","post","put","delete","patch","head","options","trace"]),a=new Set((e.tags||[]).map(e=>e.name)),n=e.paths||{};for(const[e,t]of Object.entries(n)){if(!t)continue;const n="/"+e.split("/").filter(Boolean).slice(0,s).join("/");for(const[e,s]of Object.entries(t)){if(!o.has(e))continue;if(!s||"object"!=typeof s)continue;const t=s,c=Array.isArray(t.tags)&&t.tags.length>0;r&&c||(t.tags=[n]),a.add(n)}}return e.tags=Array.from(a).map(e=>({name:e})),e}generateSpec(){return{openapi:"3.0.0",info:{title:"API Documentation",version:"1.0.0",description:"Auto generated by koa-ts-core"},paths:this.paths,components:{schemas:{}}}}}const W=(e,t,s,r,o)=>{if(!r||0===r.size)return;const{pathPrefix:a,moduleName:n,name:c}=O(t,"controller"),i=`${a}/${n}`,d=R(`${e}${a}/${c}`),p=e=>async(t,s)=>{const r=e(t);r instanceof Promise&&await r,await s()};r.forEach(e=>{const{method:t,path:r,handler:n,functionName:c,authRequired:u,middlewares:l}=e,h=[...l],g=Reflect.getMetadata(D,s.prototype,c);g?h.push(p(g)):d&&"function"==typeof d[c]&&h.push(p(d[c].bind(d))),h.push(((e,t)=>async(s,r)=>{let a=o(e,s);if(a instanceof Promise&&(a=await a),!a)throw new E("Access denied");return t(s,r)})(u,n));const f=Z(r,i,c,h,t);z.getInstance().addRoute(s,c,t,f),e.path=f,e.apiPrePath=a})},Z=(e,t,s,r,o)=>{const a=`${t}${e}`;if(s===g){const e=`${t}/index`;_[o](e,...r)}return _[o](a,...r),a};let K=null;const Q=()=>(K||(K=c.configure({appenders:{console:{type:"console"},file:{type:"dateFile",filename:"logs/app.log",pattern:".yyyy-MM-dd",compress:!0,numBackups:7,alwaysIncludePattern:!0}},categories:{default:{appenders:["console","file"],level:"info"}}})),K),X=(e,t)=>v.run(e,()=>t()),Y=e=>{const{generator:t,exposeHeader:s=!0,headerName:r="x-request-id"}=e;return!1===t?async(e,t)=>{await t()}:async(e,o)=>{const a=await t(e);a&&(e.trackId=a,s&&e.set(r,a)),await o()}},G=async(e,t)=>{const s=Date.now(),r=Q().getLogger(),o=e.runtimeLog;o&&r.info("[REQUEST] %s %s %s - ip: %s - ua: %s",e.trackId,e.method,e.url,e.ip,e.get("user-agent")||"-");try{e.hook?.(e,"request"),await t(),e.hook?.(e,"response")}catch(t){const a=Date.now()-s;throw o&&r.error("[ERROR] %s %s %s - status: %s - cost: %dms - message: %s - stack: %s",e.trackId,e.method,e.url,t.status||500,a,t.message||"unknown error",t.stack||""),t}const a=Date.now()-s;o&&r.info("[RESPONSE] %s %s %s - status: %d - cost: %dms - length: %s",e.trackId,e.method,e.url,e.status,a,e.length||e.response.length||"-")},J=async(e,t)=>{e.extra={get:e.query,post:e.request.body??{}},await t()};(()=>{const e=process.env.NODE_ENV||"production";let t;const r=process.env.ENV_DIR;if(r){if(t=s.isAbsolute(r)?r:s.resolve(process.cwd(),r),!C(t))throw new Error(`[koa-ts-core] ENV_DIR is set but directory not found: ${t}`)}else{const e=M();let r=s.resolve(e,"env");if(C(r)||(r=s.resolve(e,"..","env")),!C(r))return void console.warn(`[koa-ts-core] env directory not found: tried ${s.resolve(e,"env")} and ${s.resolve(e,"..","env")}`);t=r}console.log("[koa-ts-core] load env path:",t),n.config({path:s.resolve(t,".env.local")});const o={development:".development.env",test:".test.env",production:".production.env"}[e];o&&n.config({path:s.resolve(t,`${o}.local`)}),o&&n.config({path:s.resolve(t,o)}),n.config({path:s.resolve(t,".common.env")})})(),global.isDev="development"===process.env.NODE_ENV;const ee=e=>{const{koaInstance:t,auth:s,error:r,log:a,hooks:n,phaseMiddlewares:c,koa2Cors:i,trackId:d,swagger:u,bodyParser:l}=e;return{app:t??new o,auth:{handler:s?.handler},error:{handler:r?.handler,exposeStack:r?.exposeStack??"production"!==process.env.NODE_ENV},log:{log4:a?.log4??!1,runtimeLog:a?.runtimeLog??!0},hooks:{register:n?.register},phaseMiddlewares:c??new Map,koa2Cors:i,trackId:{generator:!1!==d?.generator&&(async e=>{const t=d?.headerName??"x-request-id",s=e.get(t);return s||p.randomUUID()}),exposeHeader:d?.exposeHeader??!0,headerName:d?.headerName??"x-request-id"},swagger:u,bodyParser:l}},te=(e,t)=>{const{log:s,hooks:r}=t;e.context.log4=(e=>{if(!1!==e)return"boolean"==typeof e&&!0===e?Q():e(c)})(s.log4),e.context.runtimeLog=s.runtimeLog,e.context.hook=r.register,e.context.validated={params:{},get:{},post:{}}},se=e=>{(e=>{const{controllerModule:t,validateModule:s}=S();console.log("load controller path:",t),A(t,t=>{if(!t.name.endsWith(".ts")&&!t.name.endsWith(".js"))return;const r=R(t.wholePath);if(!r)return;const o=Reflect.getMetadata(y,r);o instanceof Map&&0!==o.size&&W(s,t,r,o,(s,r)=>{if(!s)return!0;if(!e)throw new Error(`Route requires auth but no authCheckCallback provided. File: ${t.wholePath}`);return e({filePath:t,ctx:r})})})})(e),_.get("/",async e=>{e.body={code:200,message:"hello koa-ts-cli https://www.npmjs.com/package/koa-ts-core"}})};exports.AuthRouter=function(e,t){return x(e,t,!0)},exports.BaseException=q,exports.INDEX_ROUTE=g,exports.ParamException=E,exports.ROUTE_METADATA_KEY=y,exports.Router=function(e,t){return x(e,t,!1)},exports.contextStore=v,exports.createKoaApp=async e=>{const t=ee(e),{app:s}=t;if(te(s,t),se(t.auth.handler),t.swagger?.enabled){z.getInstance().loadDocMetadata();const e=z.getInstance().generateSpec();t.swagger.title&&(e.info.title=t.swagger.title),t.swagger.description&&(e.info.description=t.swagger.description),t.swagger.version&&(e.info.version=t.swagger.version);const r=t.swagger.path||"/swagger-ui";s.use(u.koaSwagger({routePrefix:r,swaggerOptions:{spec:z.getInstance().tagSpecByPrefix(e,{level:2,onlyIfEmpty:!1})}})),console.log(`[koa-ts-core] Swagger UI available at ${r}`)}return((e,t,s)=>{const{errorConfig:r,koa2Cors:o,trackConfig:a,bodyParser:n}=s,c={[exports.MiddlewarePhase.AsyncContext]:[X],[exports.MiddlewarePhase.ErrorHandling]:[(p=r?.handler,async(e,t)=>{try{await t()}catch(t){if(e.hook?.(e,"error"),p)p(t,e);else{const e=t.statusCode||t.status||500,s=t.code??-1;b(e,{message:t.message,code:s,data:"production"!==process.env.NODE_ENV?t.stack:void 0})}}})],[exports.MiddlewarePhase.Logging]:[Y(a),G],[exports.MiddlewarePhase.Security]:[...o?[o(d)]:[]],[exports.MiddlewarePhase.BodyParsing]:[i(n),J],[exports.MiddlewarePhase.Auth]:[],[exports.MiddlewarePhase.Routing]:[_.routes()]};var p;const u=[exports.MiddlewarePhase.AsyncContext,exports.MiddlewarePhase.ErrorHandling,exports.MiddlewarePhase.Logging,exports.MiddlewarePhase.Security,exports.MiddlewarePhase.BodyParsing,exports.MiddlewarePhase.Auth,exports.MiddlewarePhase.Routing];for(const s of u){const r=t.get(s),o=c[s]??[];if(r?.before)for(const t of r.before)e.use(t);for(const t of o)e.use(t);if(r?.use)for(const t of r.use)e.use(t);if(r?.after)for(const t of r.after)e.use(t)}})(s,t.phaseMiddlewares,{errorConfig:t.error,koa2Cors:t.koa2Cors,trackConfig:t.trackId,bodyParser:t.bodyParser}),await j(s),"production"===process.env.NODE_ENV&&console.log(`[koa-ts-core] version: ${require("../package.json").version}`),[s,_]},exports.errorRsp=b,exports.getCurrentContext=P,exports.getSrcModulePaths=S,exports.successRsp=e=>{const t=Array.isArray(e?.data);k({success:!0,message:e?.message,data:t?{list:e?.data}:e?.data})},exports.unSuccessRsp=e=>{k({success:!1,errorCode:e?.code,errorMessage:e?.message,data:e?.data})};
|
package/dist/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"reflect-metadata";import{AsyncLocalStorage as e}from"async_hooks";import{statSync as t,existsSync as o,readdirSync as r}from"fs";import{resolve as s,sep as a,join as n,isAbsolute as c}from"path";import i from"@koa/router";import p from"koa";import d from"portfinder";import u from"dotenv";import l from"log4js";import h from"koa-bodyparser";import g from"koa2-cors";import{randomUUID as m}from"crypto";import{koaSwagger as f}from"koa2-swagger-ui";const y=["get","post","put","delete","patch","options"],w=0,k="index",b="get_",P=[k,b,...y],v=Symbol("route_metadata");function x(e){const t=e.trim();if(!t)return"";return`/${t.replace(/^\/+/,"")}`}function E(e,t,o=!1){return(r,s,a)=>{if("function"!=typeof a.value)throw new Error(`@Router/@AuthRouter 只能用于方法:${s}`);let n=Reflect.getMetadata(v,r.constructor);n||(n=new Map,Reflect.defineMetadata(v,n,r.constructor));const c=function(e,t){return e||(t===b?"get":y.includes(t)?t:"get")}(e,s),i=function(e,t){return null!=e?x(e):P.includes(t)?"":x(t)}(t,s),p={handler:a.value,path:i,method:c,functionName:s,authRequired:o,middlewares:[],className:r.constructor.name,apiPrePath:""};return n.set(s,p),a}}function q(e,t){return E(e,t,!1)}function R(e,t){return E(e,t,!0)}const I=new e,M=()=>{const e=I.getStore();if(!e)throw new Error("context is not exist");return e},N=e=>{const{success:t=!0,errorCode:o=-1,message:r="success",errorMessage:s="error request",data:a=null,statusCode:n=200}=e??{},c=M(),i={code:t?w:o,message:t?r:s,...null!=a?{data:a}:{}};c.trackId&&(i.trackId=c.trackId),c.body=i,c.status=n},S=e=>{const t=Array.isArray(e?.data);N({success:!0,message:e?.message,data:t?{list:e?.data}:e?.data})},O=e=>{N({success:!1,errorCode:e?.code,errorMessage:e?.message,data:e?.data})},C=(e,t)=>{N({success:!1,errorMessage:t?.message,errorCode:t?.code,data:t?.data,statusCode:e})};class $ extends Error{constructor(e){super(e?.message||"An unexpected error occurred"),this.name=this.constructor.name,this.code=e?.code??-1,this.statusCode=500,"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.stack=this.stack??new Error(this.message).stack}get toRspOptions(){return{code:this.code,message:this.message,data:this.stack}}}const A=()=>{const e=process.cwd();if(o(s(e,"controller")))return e;const t=s(e,"src");if(o(t))return t;const r=s(e,"dist");if(o(r))return r;const a=s(e,"build");return o(a)?a:t},_=()=>{const e=A();return{controllerModule:s(e,"controller"),validateModule:s(e,"validate"),viewModule:s(e,"view"),docModule:s(e,"doc")}},j=e=>{if(o(e))try{const t=require(e);return t.default||t}catch(t){throw console.error(`[koa-ts-core] Failed to load module: ${e}`,t),t}};function D(e,t){o(e)&&r(e,{withFileTypes:!0}).forEach(o=>{const r=s(e,o.name);o.isFile()?t({path:e,name:o.name,wholePath:r},o):o.isDirectory()&&D(r,t)})}const T=e=>e.split(a).join("/"),L=e=>{const t=T(e).replace(/^\/+/,"");return t?`/${t}`:""},B=(e,t)=>{const o=T(e.path).split("/"),r=o.lastIndexOf(t);if(-1===r){const o=e.path.indexOf(t);if(-1===o)throw new Error(`'${t}' not found in path: ${e.path}`);const r=e.path.substring(o+t.length),s=L(r),a=e.name?.split(".")?.[0];return{pathPrefix:s,moduleName:a,name:e.name}}const s=o.slice(r+1).join("/"),a=L(s),n=e.name?.split(".")?.[0];return{pathPrefix:a,moduleName:n,name:e.name}};function H(e){try{return t(e).isDirectory()}catch{return!1}}var F;!function(e){e.AsyncContext="AsyncContext",e.ErrorHandling="ErrorHandling",e.Logging="Logging",e.Security="Security",e.BodyParsing="BodyParsing",e.Auth="Auth",e.Routing="Routing"}(F||(F={}));const V=new i,z=async e=>{if(!process.env.APP_PORT)try{const e=await d.getPortPromise({port:8e3,stopPort:9999});process.env.APP_PORT=String(e)}catch(e){console.warn("[koa-ts-core] Failed to find available port automatically.")}const t=e.listen;e.listen=function(...e){if(0===e.length&&process.env.APP_PORT){const t=Number(process.env.APP_PORT);isNaN(t)||e.push(t)}const o=t.apply(this,e);return o.on("listening",()=>(e=>{const t=e.address();if(t)if("string"==typeof t)console.log(`Server listening on ${t}`);else{const{port:e}=t;console.log(`Server running at http://localhost:${e}`)}})(o)),o}},U=Symbol("validate_metadata"),W=Symbol("swagger_tags"),Z=Symbol("swagger_operation"),Q=Symbol("swagger_parameters"),G=Symbol("swagger_body"),J=Symbol("swagger_responses"),K={DOCUMENTATION_DIR:n(process.cwd(),"doc")},X=()=>{const e=[];return H(K.DOCUMENTATION_DIR)?(D(K.DOCUMENTATION_DIR,t=>{if(!t.name.endsWith(".ts")&&!t.name.endsWith(".js"))return;const{pathPrefix:o}=B(t,"doc"),r=((e,t)=>{const o=j(e.wholePath);if(!o)return{configs:[],desc:"",name:"",pathPrefix:t,apiPrePath:""};const r=o.prototype,s=Object.getOwnPropertyNames(r).filter(e=>"function"==typeof r[e]&&"constructor"!==e),a=e.path.indexOf("doc"),n=a>=0?L(e.path.substring(a+3)):"";let c=n;if(e.name&&!e.name.startsWith("index.")){const t=e.name.split(".")[0];c=`${n}/${t}`}const i=s.map(e=>{const t=r[e];if("function"==typeof t){const e=t();return e.path=`${c}${e.path}`,e}return null}).filter(e=>!!e);let p="";if(i[0]?.path){const e=i[0].path.lastIndexOf("/");e>-1&&(p=i[0].path.substring(0,e))}return{configs:i,desc:o.desc,name:o.name,pathPrefix:t,apiPrePath:p}})(t,o);r.configs.length>0&&e.push(r)}),e):[]};class Y{constructor(){this.paths={}}static getInstance(){return this.instance||(this.instance=new Y),this.instance}addRoute(e,t,o,r){const s=r.replace(/:([a-zA-Z0-9_]+)/g,"{$1}");this.paths[s]||(this.paths[s]={});const a=e.prototype,n=Reflect.getMetadata(Z,a,t)||{},c=n.summary,i=n.description,p=Reflect.getMetadata(W,e)||[e.name],d=Reflect.getMetadata(Q,a,t)||[],u=Reflect.getMetadata(G,a,t);let l;u&&(l={description:u.description,required:u.required,content:{"application/json":{schema:u.schema||{type:"object"}}}});const h=Reflect.getMetadata(J,a,t)||[],g={};h.forEach(e=>{g[e.status]={description:e.description||"",content:e.schema?{"application/json":{schema:e.schema}}:void 0}}),0===Object.keys(g).length&&(g[200]={description:"Success"}),this.paths[s][o.toLowerCase()]={tags:p,summary:c,description:i,parameters:d,requestBody:l,responses:g}}loadDocMetadata(){X().forEach(e=>{const t=e.desc||e.name;e.configs.forEach(e=>{const o=("/"+e.path).replace(/\/+/g,"/"),r=o.replace(/:([a-zA-Z0-9_]+)/g,"{$1}"),s=e.method.toLowerCase();this.paths[r]||(this.paths[r]={}),this.paths[r][s]||(this.paths[r][s]={});const a=this.paths[r][s];a.summary||(a.summary=e.description),a.tags&&0!==a.tags.length||(a.tags=[t]);const n=o.match(/:([a-zA-Z0-9_]+)/g);if(n&&(a.parameters||(a.parameters=[]),n.forEach(e=>{const t=e.substring(1);a.parameters.find(e=>e.name===t&&"path"===e.in)||a.parameters.push({name:t,in:"path",required:!0,schema:{type:"string"},description:t})})),e.request?.query&&(a.parameters||(a.parameters=[]),Object.keys(e.request.query).forEach(t=>{if(!a.parameters.find(e=>e.name===t&&"query"===e.in)){const o=e.request?.query?.[t];o&&"object"==typeof o&&a.parameters.push({name:t,in:"query",description:o.description,required:!1!==o.required,schema:o.schema??{type:o.type??"string"},example:o.example})}})),e.request?.header&&(a.parameters||(a.parameters=[]),Object.keys(e.request.header).forEach(t=>{if("content-type"===t.toLowerCase())return;if(!a.parameters.find(e=>e.name===t&&"header"===e.in)){const o=e.request?.header?.[t];o&&"object"==typeof o&&a.parameters.push({name:t,in:"header",description:o.description,required:!1!==o.required,schema:o.schema??{type:o.type??"string"},example:o.example})}})),e.request?.body&&Object.keys(e.request.body).length>0&&!a.requestBody){const t=e.request.body;a.requestBody={description:t.description,required:t.required,content:{"application/json":{schema:{type:"object",properties:t.schema},example:t.example}}}}e.response?.body&&(a.responses||(a.responses={}),a.responses[200]||(a.responses[200]={description:"Success",content:{"application/json":{schema:{type:"object",example:e.response.body}}}}))})})}tagSpecByPrefix(e,t={}){const{level:o=2,onlyIfEmpty:r=!0}=t,s=new Set(["get","post","put","delete","patch","head","options","trace"]),a=new Set((e.tags||[]).map(e=>e.name)),n=e.paths||{};for(const[e,t]of Object.entries(n)){if(!t)continue;const n="/"+e.split("/").filter(Boolean).slice(0,o).join("/");for(const[e,o]of Object.entries(t)){if(!s.has(e))continue;if(!o||"object"!=typeof o)continue;const t=o,c=Array.isArray(t.tags)&&t.tags.length>0;r&&c||(t.tags=[n]),a.add(n)}}return e.tags=Array.from(a).map(e=>({name:e})),e}generateSpec(){return{openapi:"3.0.0",info:{title:"API Documentation",version:"1.0.0",description:"Auto generated by koa-ts-core"},paths:this.paths,components:{schemas:{}}}}}const ee=(e,t,o,r,s)=>{if(!r||0===r.size)return;const{pathPrefix:a,moduleName:n,name:c}=B(t,"controller"),i=`${a}/${n}`,p=j(`${e}${a}/${c}`),d=e=>async(t,o)=>{const r=e(t);r instanceof Promise&&await r,await o()};r.forEach(e=>{const{method:t,path:r,handler:n,functionName:c,authRequired:u,middlewares:l}=e,h=[...l],g=Reflect.getMetadata(U,o.prototype,c);g?h.push(d(g)):p&&"function"==typeof p[c]&&h.push(d(p[c].bind(p))),h.push(((e,t)=>async(o,r)=>{let a=s(e,o);return a instanceof Promise&&(a=await a),a?t(o,r):o.throw(403,"无权限")})(u,n));const m=te(r,i,c,h,t);Y.getInstance().addRoute(o,c,t,m),e.path=m,e.apiPrePath=a})},te=(e,t,o,r,s)=>{const a=`${t}${e}`;if(o===k){const e=`${t}/index`;V[s](e,...r)}return V[s](a,...r),a};let oe=null;const re=()=>(oe||(oe=l.configure({appenders:{console:{type:"console"},file:{type:"dateFile",filename:"logs/app.log",pattern:".yyyy-MM-dd",compress:!0,numBackups:7,alwaysIncludePattern:!0}},categories:{default:{appenders:["console","file"],level:"info"}}})),oe),se=(e,t)=>I.run(e,()=>t()),ae=e=>{const{generator:t,exposeHeader:o=!0,headerName:r="x-request-id"}=e;return!1===t?async(e,t)=>{await t()}:async(e,s)=>{const a=await t(e);a&&(e.trackId=a,o&&e.set(r,a)),await s()}},ne=async(e,t)=>{const o=Date.now(),r=re().getLogger(),s=e.runtimeLog;s&&r.info("[REQUEST] %s %s %s - ip: %s - ua: %s",e.trackId,e.method,e.url,e.ip,e.get("user-agent")||"-");try{e.hook?.(e,"request"),await t(),e.hook?.(e,"response")}catch(t){const a=Date.now()-o;throw s&&r.error("[ERROR] %s %s %s - status: %s - cost: %dms - message: %s - stack: %s",e.trackId,e.method,e.url,t.status||500,a,t.message||"unknown error",t.stack||""),t}const a=Date.now()-o;s&&r.info("[RESPONSE] %s %s %s - status: %d - cost: %dms - length: %s",e.trackId,e.method,e.url,e.status,a,e.length||e.response.length||"-")},ce=async(e,t)=>{e.extra={get:e.query,post:e.request.body??{}},await t()};(()=>{const e=process.env.NODE_ENV||"production";let t;const o=process.env.ENV_DIR;if(o){if(t=c(o)?o:s(process.cwd(),o),!H(t))throw new Error(`[koa-ts-core] ENV_DIR is set but directory not found: ${t}`)}else{const e=A();let o=s(e,"env");if(H(o)||(o=s(e,"..","env")),!H(o))return void console.warn(`[koa-ts-core] env directory not found: tried ${s(e,"env")} and ${s(e,"..","env")}`);t=o}console.log("[koa-ts-core] load env path:",t),u.config({path:s(t,".env.local")});const r={development:".development.env",test:".test.env",production:".production.env"}[e];r&&u.config({path:s(t,`${r}.local`)}),r&&u.config({path:s(t,r)}),u.config({path:s(t,".common.env")})})(),global.isDev="development"===process.env.NODE_ENV;const ie=e=>{const{koaInstance:t,auth:o,error:r,log:s,hooks:a,phaseMiddlewares:n,koa2Cors:c,trackId:i,swagger:d,bodyParser:u}=e;return{app:t??new p,auth:{handler:o?.handler},error:{handler:r?.handler,exposeStack:r?.exposeStack??"production"!==process.env.NODE_ENV},log:{log4:s?.log4??!1,runtimeLog:s?.runtimeLog??!0},hooks:{register:a?.register},phaseMiddlewares:n??new Map,koa2Cors:c,trackId:{generator:!1!==i?.generator&&(async e=>{const t=i?.headerName??"x-request-id",o=e.get(t);return o||m()}),exposeHeader:i?.exposeHeader??!0,headerName:i?.headerName??"x-request-id"},swagger:d,bodyParser:u}},pe=(e,t)=>{const{log:o,hooks:r}=t;e.context.log4=(e=>{if(!1!==e)return"boolean"==typeof e&&!0===e?re():e(l)})(o.log4),e.context.runtimeLog=o.runtimeLog,e.context.hook=r.register,e.context.validated={params:{},get:{},post:{}}},de=e=>{(e=>{const{controllerModule:t,validateModule:o}=_();console.log("load controller path:",t),D(t,t=>{if(!t.name.endsWith(".ts")&&!t.name.endsWith(".js"))return;const r=j(t.wholePath);if(!r)return;const s=Reflect.getMetadata(v,r);s instanceof Map&&0!==s.size&&ee(o,t,r,s,(o,r)=>{if(!o)return!0;if(!e)throw new Error(`Route requires auth but no authCheckCallback provided. File: ${t.wholePath}`);return e({filePath:t,ctx:r})})})})(e),V.get("/",async e=>{e.body={code:200,message:"hello koa-ts-cli https://www.npmjs.com/package/koa-ts-core"}})},ue=async e=>{const t=ie(e),{app:o}=t;if(pe(o,t),de(t.auth.handler),t.swagger?.enabled){Y.getInstance().loadDocMetadata();const e=Y.getInstance().generateSpec();t.swagger.title&&(e.info.title=t.swagger.title),t.swagger.description&&(e.info.description=t.swagger.description),t.swagger.version&&(e.info.version=t.swagger.version);const r=t.swagger.path||"/swagger-ui";o.use(f({routePrefix:r,swaggerOptions:{spec:Y.getInstance().tagSpecByPrefix(e,{level:2,onlyIfEmpty:!1})}})),console.log(`[koa-ts-core] Swagger UI available at ${r}`)}return((e,t,o)=>{const{errorConfig:r,koa2Cors:s,trackConfig:a,bodyParser:n}=o,c={[F.AsyncContext]:[se],[F.ErrorHandling]:[(i=r?.handler,async(e,t)=>{try{await t()}catch(t){if(e.hook?.(e,"error"),i)i(t,e);else{const e=t.statusCode||t.status||500,o=t.code??-1;C(e,{message:t.message,code:o,data:"production"!==process.env.NODE_ENV?t.stack:void 0})}}})],[F.Logging]:[ae(a),ne],[F.Security]:[...s?[s(g)]:[]],[F.BodyParsing]:[h(n),ce],[F.Auth]:[],[F.Routing]:[V.routes()]};var i;const p=[F.AsyncContext,F.ErrorHandling,F.Logging,F.Security,F.BodyParsing,F.Auth,F.Routing];for(const o of p){const r=t.get(o),s=c[o]??[];if(r?.before)for(const t of r.before)e.use(t);for(const t of s)e.use(t);if(r?.use)for(const t of r.use)e.use(t);if(r?.after)for(const t of r.after)e.use(t)}})(o,t.phaseMiddlewares,{errorConfig:t.error,koa2Cors:t.koa2Cors,trackConfig:t.trackId,bodyParser:t.bodyParser}),await z(o),[o,V]};export{R as AuthRouter,$ as BaseException,k as INDEX_ROUTE,F as MiddlewarePhase,v as ROUTE_METADATA_KEY,q as Router,I as contextStore,ue as createKoaApp,C as errorRsp,M as getCurrentContext,_ as getSrcModulePaths,S as successRsp,O as unSuccessRsp};
|
|
1
|
+
import"reflect-metadata";import{AsyncLocalStorage as e}from"async_hooks";import{statSync as t,existsSync as o,readdirSync as s}from"fs";import{resolve as r,sep as a,join as n,isAbsolute as c}from"path";import i from"@koa/router";import p from"koa";import d from"portfinder";import u from"dotenv";import l from"log4js";import h from"koa-bodyparser";import g from"koa2-cors";import{randomUUID as m}from"crypto";import{koaSwagger as f}from"koa2-swagger-ui";const y=["get","post","put","delete","patch","options"],w=0,k="index",v="get_",b=[k,v,...y],P=Symbol("route_metadata");function x(e){const t=e.trim();if(!t)return"";return`/${t.replace(/^\/+/,"")}`}function E(e,t,o=!1){return(s,r,a)=>{if("function"!=typeof a.value)throw new Error(`@Router/@AuthRouter 只能用于方法:${r}`);let n=Reflect.getMetadata(P,s.constructor);n||(n=new Map,Reflect.defineMetadata(P,n,s.constructor));const c=function(e,t){return e||(t===v?"get":y.includes(t)?t:"get")}(e,r),i=function(e,t){return null!=e?x(e):b.includes(t)?"":x(t)}(t,r),p={handler:a.value,path:i,method:c,functionName:r,authRequired:o,middlewares:[],className:s.constructor.name,apiPrePath:""};return n.set(r,p),a}}function q(e,t){return E(e,t,!1)}function R(e,t){return E(e,t,!0)}const N=new e,I=()=>{const e=N.getStore();if(!e)throw new Error("context is not exist");return e},M=e=>{const{success:t=!0,errorCode:o=-1,message:s="success",errorMessage:r="error request",data:a=null,statusCode:n=200}=e??{},c=I(),i={code:t?w:o,message:t?s:r,...null!=a?{data:a}:{}};c.trackId&&(i.trackId=c.trackId),c.body=i,c.status=n},O=e=>{const t=Array.isArray(e?.data);M({success:!0,message:e?.message,data:t?{list:e?.data}:e?.data})},S=e=>{M({success:!1,errorCode:e?.code,errorMessage:e?.message,data:e?.data})},C=(e,t)=>{M({success:!1,errorMessage:t?.message,errorCode:t?.code,data:t?.data,statusCode:e})};class $ extends Error{constructor(e){super(e?.message||"An unexpected error occurred"),this.name=this.constructor.name,this.code=e?.code??-1,this.statusCode=e?.statusCode??500,"function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),this.stack=this.stack??new Error(this.message).stack}get toRspOptions(){return{code:this.code,message:this.message,data:this.stack}}}class A extends ${constructor(e){super({statusCode:403,message:e})}}const _=()=>{const e=process.cwd();if(o(r(e,"controller")))return e;const t=r(e,"src");if(o(t))return t;const s=r(e,"dist");if(o(s))return s;const a=r(e,"build");return o(a)?a:t},j=()=>{const e=_();return{controllerModule:r(e,"controller"),validateModule:r(e,"validate"),viewModule:r(e,"view"),docModule:r(e,"doc")}},D=e=>{if(o(e))try{const t=require(e);return t.default||t}catch(t){throw console.error(`[koa-ts-core] Failed to load module: ${e}`,t),t}};function T(e,t){o(e)&&s(e,{withFileTypes:!0}).forEach(o=>{const s=r(e,o.name);o.isFile()?t({path:e,name:o.name,wholePath:s},o):o.isDirectory()&&T(s,t)})}const L=e=>e.split(a).join("/"),B=e=>{const t=L(e).replace(/^\/+/,"");return t?`/${t}`:""},H=(e,t)=>{const o=L(e.path).split("/"),s=o.lastIndexOf(t);if(-1===s){const o=e.path.indexOf(t);if(-1===o)throw new Error(`'${t}' not found in path: ${e.path}`);const s=e.path.substring(o+t.length),r=B(s),a=e.name?.split(".")?.[0];return{pathPrefix:r,moduleName:a,name:e.name}}const r=o.slice(s+1).join("/"),a=B(r),n=e.name?.split(".")?.[0];return{pathPrefix:a,moduleName:n,name:e.name}};function V(e){try{return t(e).isDirectory()}catch{return!1}}var F;!function(e){e.AsyncContext="AsyncContext",e.ErrorHandling="ErrorHandling",e.Logging="Logging",e.Security="Security",e.BodyParsing="BodyParsing",e.Auth="Auth",e.Routing="Routing"}(F||(F={}));const z=new i,U=async e=>{if(!process.env.APP_PORT)try{const e=await d.getPortPromise({port:8e3,stopPort:9999});process.env.APP_PORT=String(e)}catch(e){console.warn("[koa-ts-core] Failed to find available port automatically.")}const t=e.listen;e.listen=function(...e){if(0===e.length&&process.env.APP_PORT){const t=Number(process.env.APP_PORT);isNaN(t)||e.push(t)}const o=t.apply(this,e);return o.on("listening",()=>(e=>{const t=e.address();if(t)if("string"==typeof t)console.log(`Server listening on ${t}`);else{const{port:e}=t;console.log(`Server running at http://localhost:${e}`)}})(o)),o}},W=Symbol("validate_metadata"),Z=Symbol("swagger_tags"),Q=Symbol("swagger_operation"),G=Symbol("swagger_parameters"),J=Symbol("swagger_body"),K=Symbol("swagger_responses"),X={DOCUMENTATION_DIR:n(process.cwd(),"doc")},Y=()=>{const e=[];return V(X.DOCUMENTATION_DIR)?(T(X.DOCUMENTATION_DIR,t=>{if(!t.name.endsWith(".ts")&&!t.name.endsWith(".js"))return;const{pathPrefix:o}=H(t,"doc"),s=((e,t)=>{const o=D(e.wholePath);if(!o)return{configs:[],desc:"",name:"",pathPrefix:t,apiPrePath:""};const s=o.prototype,r=Object.getOwnPropertyNames(s).filter(e=>"function"==typeof s[e]&&"constructor"!==e),a=e.path.indexOf("doc"),n=a>=0?B(e.path.substring(a+3)):"";let c=n;if(e.name&&!e.name.startsWith("index.")){const t=e.name.split(".")[0];c=`${n}/${t}`}const i=r.map(e=>{const t=s[e];if("function"==typeof t){const e=t();return e.path=`${c}${e.path}`,e}return null}).filter(e=>!!e);let p="";if(i[0]?.path){const e=i[0].path.lastIndexOf("/");e>-1&&(p=i[0].path.substring(0,e))}return{configs:i,desc:o.desc,name:o.name,pathPrefix:t,apiPrePath:p}})(t,o);s.configs.length>0&&e.push(s)}),e):[]};class ee{constructor(){this.paths={}}static getInstance(){return this.instance||(this.instance=new ee),this.instance}addRoute(e,t,o,s){const r=s.replace(/:([a-zA-Z0-9_]+)/g,"{$1}");this.paths[r]||(this.paths[r]={});const a=e.prototype,n=Reflect.getMetadata(Q,a,t)||{},c=n.summary,i=n.description,p=Reflect.getMetadata(Z,e)||[e.name],d=Reflect.getMetadata(G,a,t)||[],u=Reflect.getMetadata(J,a,t);let l;u&&(l={description:u.description,required:u.required,content:{"application/json":{schema:u.schema||{type:"object"}}}});const h=Reflect.getMetadata(K,a,t)||[],g={};h.forEach(e=>{g[e.status]={description:e.description||"",content:e.schema?{"application/json":{schema:e.schema}}:void 0}}),0===Object.keys(g).length&&(g[200]={description:"Success"}),this.paths[r][o.toLowerCase()]={tags:p,summary:c,description:i,parameters:d,requestBody:l,responses:g}}loadDocMetadata(){Y().forEach(e=>{const t=e.desc||e.name;e.configs.forEach(e=>{const o=("/"+e.path).replace(/\/+/g,"/"),s=o.replace(/:([a-zA-Z0-9_]+)/g,"{$1}"),r=e.method.toLowerCase();this.paths[s]||(this.paths[s]={}),this.paths[s][r]||(this.paths[s][r]={});const a=this.paths[s][r];a.summary||(a.summary=e.description),a.tags&&0!==a.tags.length||(a.tags=[t]);const n=o.match(/:([a-zA-Z0-9_]+)/g);if(n&&(a.parameters||(a.parameters=[]),n.forEach(e=>{const t=e.substring(1);a.parameters.find(e=>e.name===t&&"path"===e.in)||a.parameters.push({name:t,in:"path",required:!0,schema:{type:"string"},description:t})})),e.request?.query&&(a.parameters||(a.parameters=[]),Object.keys(e.request.query).forEach(t=>{if(!a.parameters.find(e=>e.name===t&&"query"===e.in)){const o=e.request?.query?.[t];o&&"object"==typeof o&&a.parameters.push({name:t,in:"query",description:o.description,required:!1!==o.required,schema:o.schema??{type:o.type??"string"},example:o.example})}})),e.request?.header&&(a.parameters||(a.parameters=[]),Object.keys(e.request.header).forEach(t=>{if("content-type"===t.toLowerCase())return;if(!a.parameters.find(e=>e.name===t&&"header"===e.in)){const o=e.request?.header?.[t];o&&"object"==typeof o&&a.parameters.push({name:t,in:"header",description:o.description,required:!1!==o.required,schema:o.schema??{type:o.type??"string"},example:o.example})}})),e.request?.body&&Object.keys(e.request.body).length>0&&!a.requestBody){const t=e.request.body;a.requestBody={description:t.description,required:t.required,content:{"application/json":{schema:{type:"object",properties:t.schema},example:t.example}}}}e.response?.body&&(a.responses||(a.responses={}),a.responses[200]||(a.responses[200]={description:"Success",content:{"application/json":{schema:{type:"object",example:e.response.body}}}}))})})}tagSpecByPrefix(e,t={}){const{level:o=2,onlyIfEmpty:s=!0}=t,r=new Set(["get","post","put","delete","patch","head","options","trace"]),a=new Set((e.tags||[]).map(e=>e.name)),n=e.paths||{};for(const[e,t]of Object.entries(n)){if(!t)continue;const n="/"+e.split("/").filter(Boolean).slice(0,o).join("/");for(const[e,o]of Object.entries(t)){if(!r.has(e))continue;if(!o||"object"!=typeof o)continue;const t=o,c=Array.isArray(t.tags)&&t.tags.length>0;s&&c||(t.tags=[n]),a.add(n)}}return e.tags=Array.from(a).map(e=>({name:e})),e}generateSpec(){return{openapi:"3.0.0",info:{title:"API Documentation",version:"1.0.0",description:"Auto generated by koa-ts-core"},paths:this.paths,components:{schemas:{}}}}}const te=(e,t,o,s,r)=>{if(!s||0===s.size)return;const{pathPrefix:a,moduleName:n,name:c}=H(t,"controller"),i=`${a}/${n}`,p=D(`${e}${a}/${c}`),d=e=>async(t,o)=>{const s=e(t);s instanceof Promise&&await s,await o()};s.forEach(e=>{const{method:t,path:s,handler:n,functionName:c,authRequired:u,middlewares:l}=e,h=[...l],g=Reflect.getMetadata(W,o.prototype,c);g?h.push(d(g)):p&&"function"==typeof p[c]&&h.push(d(p[c].bind(p))),h.push(((e,t)=>async(o,s)=>{let a=r(e,o);if(a instanceof Promise&&(a=await a),!a)throw new A("Access denied");return t(o,s)})(u,n));const m=oe(s,i,c,h,t);ee.getInstance().addRoute(o,c,t,m),e.path=m,e.apiPrePath=a})},oe=(e,t,o,s,r)=>{const a=`${t}${e}`;if(o===k){const e=`${t}/index`;z[r](e,...s)}return z[r](a,...s),a};let se=null;const re=()=>(se||(se=l.configure({appenders:{console:{type:"console"},file:{type:"dateFile",filename:"logs/app.log",pattern:".yyyy-MM-dd",compress:!0,numBackups:7,alwaysIncludePattern:!0}},categories:{default:{appenders:["console","file"],level:"info"}}})),se),ae=(e,t)=>N.run(e,()=>t()),ne=e=>{const{generator:t,exposeHeader:o=!0,headerName:s="x-request-id"}=e;return!1===t?async(e,t)=>{await t()}:async(e,r)=>{const a=await t(e);a&&(e.trackId=a,o&&e.set(s,a)),await r()}},ce=async(e,t)=>{const o=Date.now(),s=re().getLogger(),r=e.runtimeLog;r&&s.info("[REQUEST] %s %s %s - ip: %s - ua: %s",e.trackId,e.method,e.url,e.ip,e.get("user-agent")||"-");try{e.hook?.(e,"request"),await t(),e.hook?.(e,"response")}catch(t){const a=Date.now()-o;throw r&&s.error("[ERROR] %s %s %s - status: %s - cost: %dms - message: %s - stack: %s",e.trackId,e.method,e.url,t.status||500,a,t.message||"unknown error",t.stack||""),t}const a=Date.now()-o;r&&s.info("[RESPONSE] %s %s %s - status: %d - cost: %dms - length: %s",e.trackId,e.method,e.url,e.status,a,e.length||e.response.length||"-")},ie=async(e,t)=>{e.extra={get:e.query,post:e.request.body??{}},await t()};(()=>{const e=process.env.NODE_ENV||"production";let t;const o=process.env.ENV_DIR;if(o){if(t=c(o)?o:r(process.cwd(),o),!V(t))throw new Error(`[koa-ts-core] ENV_DIR is set but directory not found: ${t}`)}else{const e=_();let o=r(e,"env");if(V(o)||(o=r(e,"..","env")),!V(o))return void console.warn(`[koa-ts-core] env directory not found: tried ${r(e,"env")} and ${r(e,"..","env")}`);t=o}console.log("[koa-ts-core] load env path:",t),u.config({path:r(t,".env.local")});const s={development:".development.env",test:".test.env",production:".production.env"}[e];s&&u.config({path:r(t,`${s}.local`)}),s&&u.config({path:r(t,s)}),u.config({path:r(t,".common.env")})})(),global.isDev="development"===process.env.NODE_ENV;const pe=e=>{const{koaInstance:t,auth:o,error:s,log:r,hooks:a,phaseMiddlewares:n,koa2Cors:c,trackId:i,swagger:d,bodyParser:u}=e;return{app:t??new p,auth:{handler:o?.handler},error:{handler:s?.handler,exposeStack:s?.exposeStack??"production"!==process.env.NODE_ENV},log:{log4:r?.log4??!1,runtimeLog:r?.runtimeLog??!0},hooks:{register:a?.register},phaseMiddlewares:n??new Map,koa2Cors:c,trackId:{generator:!1!==i?.generator&&(async e=>{const t=i?.headerName??"x-request-id",o=e.get(t);return o||m()}),exposeHeader:i?.exposeHeader??!0,headerName:i?.headerName??"x-request-id"},swagger:d,bodyParser:u}},de=(e,t)=>{const{log:o,hooks:s}=t;e.context.log4=(e=>{if(!1!==e)return"boolean"==typeof e&&!0===e?re():e(l)})(o.log4),e.context.runtimeLog=o.runtimeLog,e.context.hook=s.register,e.context.validated={params:{},get:{},post:{}}},ue=e=>{(e=>{const{controllerModule:t,validateModule:o}=j();console.log("load controller path:",t),T(t,t=>{if(!t.name.endsWith(".ts")&&!t.name.endsWith(".js"))return;const s=D(t.wholePath);if(!s)return;const r=Reflect.getMetadata(P,s);r instanceof Map&&0!==r.size&&te(o,t,s,r,(o,s)=>{if(!o)return!0;if(!e)throw new Error(`Route requires auth but no authCheckCallback provided. File: ${t.wholePath}`);return e({filePath:t,ctx:s})})})})(e),z.get("/",async e=>{e.body={code:200,message:"hello koa-ts-cli https://www.npmjs.com/package/koa-ts-core"}})},le=async e=>{const t=pe(e),{app:o}=t;if(de(o,t),ue(t.auth.handler),t.swagger?.enabled){ee.getInstance().loadDocMetadata();const e=ee.getInstance().generateSpec();t.swagger.title&&(e.info.title=t.swagger.title),t.swagger.description&&(e.info.description=t.swagger.description),t.swagger.version&&(e.info.version=t.swagger.version);const s=t.swagger.path||"/swagger-ui";o.use(f({routePrefix:s,swaggerOptions:{spec:ee.getInstance().tagSpecByPrefix(e,{level:2,onlyIfEmpty:!1})}})),console.log(`[koa-ts-core] Swagger UI available at ${s}`)}return((e,t,o)=>{const{errorConfig:s,koa2Cors:r,trackConfig:a,bodyParser:n}=o,c={[F.AsyncContext]:[ae],[F.ErrorHandling]:[(i=s?.handler,async(e,t)=>{try{await t()}catch(t){if(e.hook?.(e,"error"),i)i(t,e);else{const e=t.statusCode||t.status||500,o=t.code??-1;C(e,{message:t.message,code:o,data:"production"!==process.env.NODE_ENV?t.stack:void 0})}}})],[F.Logging]:[ne(a),ce],[F.Security]:[...r?[r(g)]:[]],[F.BodyParsing]:[h(n),ie],[F.Auth]:[],[F.Routing]:[z.routes()]};var i;const p=[F.AsyncContext,F.ErrorHandling,F.Logging,F.Security,F.BodyParsing,F.Auth,F.Routing];for(const o of p){const s=t.get(o),r=c[o]??[];if(s?.before)for(const t of s.before)e.use(t);for(const t of r)e.use(t);if(s?.use)for(const t of s.use)e.use(t);if(s?.after)for(const t of s.after)e.use(t)}})(o,t.phaseMiddlewares,{errorConfig:t.error,koa2Cors:t.koa2Cors,trackConfig:t.trackId,bodyParser:t.bodyParser}),await U(o),"production"===process.env.NODE_ENV&&console.log(`[koa-ts-core] version: ${require("../package.json").version}`),[o,z]};export{R as AuthRouter,$ as BaseException,k as INDEX_ROUTE,F as MiddlewarePhase,A as ParamException,P as ROUTE_METADATA_KEY,q as Router,N as contextStore,le as createKoaApp,C as errorRsp,I as getCurrentContext,j as getSrcModulePaths,O as successRsp,S as unSuccessRsp};
|