@_tc/template-core 0.0.1-bate.56 → 0.0.1-bate.58
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/AGENT_README.md +27 -9
- package/README.md +61 -0
- package/cjs/app/controller/project.js +1 -1
- package/cjs/app/middleware/error-handle.js +1 -1
- package/cjs/app/middleware/request-parameter-parsing.js +1 -0
- package/cjs/app/middleware.js +1 -1
- package/esm/app/controller/project.js +7 -2
- package/esm/app/middleware/error-handle.js +1 -1
- package/esm/app/middleware/request-parameter-parsing.js +18 -0
- package/esm/app/middleware.js +1 -1
- package/package.json +7 -2
- package/types/app/middleware/request-parameter-parsing.d.ts +7 -0
- package/types/app/type.d.ts +30 -2
- package/types/app/typings.d.ts +1 -0
- package/types/index.d.ts +1 -1
package/AGENT_README.md
CHANGED
|
@@ -102,6 +102,24 @@ config/config.{env}.(js|ts) -> app.config
|
|
|
102
102
|
model/**/*.(js|ts) -> 内置 project service 读取的项目模型配置
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
常用后端类型:
|
|
106
|
+
|
|
107
|
+
| 类型 | 使用场景 |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `Ctx` | Controller、middleware、router handler 的请求上下文,包含 `ctx.params` 和可选 `ctx.reqData`。 |
|
|
110
|
+
| `ControllerFN` | 约束 `app/controller/*.ts` 默认导出的 controller 工厂。 |
|
|
111
|
+
| `ServiceFN` | 约束 `app/service/*.ts` 默认导出的 service 工厂。 |
|
|
112
|
+
| `MiddlewareFN` | 约束 `app/middleware/*.ts` 默认导出的 middleware 工厂。 |
|
|
113
|
+
| `RouterFN` | 约束 `app/router/*.ts` 默认导出的路由注册函数。 |
|
|
114
|
+
|
|
115
|
+
`ctx.reqData` 是 API 请求的统一参数入口:
|
|
116
|
+
|
|
117
|
+
- `ctx.reqData.query` 来自 `ctx.query`。
|
|
118
|
+
- `ctx.reqData.body` 来自 `ctx.request.body`。
|
|
119
|
+
- `ctx.reqData.headers` 来自 `ctx.headers`。
|
|
120
|
+
- `ctx.reqData.data` 按 `query -> body` 合并;字段冲突时 body 覆盖 query。
|
|
121
|
+
- router params 不在 `reqData` 里,继续用 `ctx.params`。
|
|
122
|
+
|
|
105
123
|
Controller 示例:
|
|
106
124
|
|
|
107
125
|
```ts
|
|
@@ -118,15 +136,15 @@ const getProductController = ((app) => {
|
|
|
118
136
|
list = async (ctx: Ctx) => {
|
|
119
137
|
this.success(ctx, {
|
|
120
138
|
data: products,
|
|
121
|
-
page: Number(ctx.
|
|
122
|
-
pageSize: Number(ctx.
|
|
139
|
+
page: Number(ctx.reqData?.data.page || 1),
|
|
140
|
+
pageSize: Number(ctx.reqData?.data.pageSize || 10),
|
|
123
141
|
total: products.length,
|
|
124
142
|
})
|
|
125
143
|
}
|
|
126
144
|
|
|
127
145
|
detail = async (ctx: Ctx) => {
|
|
128
146
|
const item = products.find((product) => {
|
|
129
|
-
return product.product_id === ctx.
|
|
147
|
+
return product.product_id === ctx.reqData?.data.product_id
|
|
130
148
|
})
|
|
131
149
|
|
|
132
150
|
this.success(ctx, item ?? null)
|
|
@@ -140,12 +158,12 @@ export default getProductController
|
|
|
140
158
|
Router 示例:
|
|
141
159
|
|
|
142
160
|
```ts
|
|
143
|
-
import type {
|
|
161
|
+
import type { RouterFN } from '@_tc/template-core'
|
|
144
162
|
|
|
145
|
-
export default (app
|
|
163
|
+
export default ((app, router) => {
|
|
146
164
|
router.get('/api/product/list', app.controller.product.list)
|
|
147
165
|
router.get('/api/product', app.controller.product.detail)
|
|
148
|
-
}
|
|
166
|
+
}) satisfies RouterFN
|
|
149
167
|
```
|
|
150
168
|
|
|
151
169
|
路由挂载顺序:
|
|
@@ -156,12 +174,12 @@ export default (app: KoaApp, router: Router) => {
|
|
|
156
174
|
- 通配、兜底、重定向类路由建议设置较大的 `level`,避免抢先匹配业务 API。
|
|
157
175
|
|
|
158
176
|
```ts
|
|
159
|
-
import type {
|
|
177
|
+
import type { RouterFN } from '@_tc/template-core'
|
|
160
178
|
|
|
161
|
-
export default (app
|
|
179
|
+
export default ((app, router) => {
|
|
162
180
|
router.level = 10
|
|
163
181
|
router.get('/api/fallback/:id', app.controller.fallback.detail)
|
|
164
|
-
}
|
|
182
|
+
}) satisfies RouterFN
|
|
165
183
|
```
|
|
166
184
|
|
|
167
185
|
内置响应约定:`BaseController.success(ctx, data)` 返回 `{ data, code: 0, message: 'ok' }`。
|
package/README.md
CHANGED
|
@@ -165,6 +165,49 @@ http://localhost:9000/dash?projk=demo
|
|
|
165
165
|
| `@_tc/template-core/fe/tailwind_ui.css` | 前端全局样式入口,源码对应 `frontend/src/main.css` |
|
|
166
166
|
| `@_tc/template-core/model` | model 配置类型 |
|
|
167
167
|
|
|
168
|
+
### 后端类型
|
|
169
|
+
|
|
170
|
+
`@_tc/template-core` 会导出常用 Node 侧类型,业务项目写 `app/*` 文件时建议优先复用这些类型。
|
|
171
|
+
|
|
172
|
+
| 类型 | 使用场景 |
|
|
173
|
+
| --- | --- |
|
|
174
|
+
| `Ctx` | Controller、middleware、router handler 的 Koa 请求上下文类型,包含框架补充的 `ctx.params` 和可选 `ctx.reqData`。 |
|
|
175
|
+
| `ControllerFN` | `app/controller/*.ts` 默认导出工厂函数的约束类型,适合配合 `satisfies ControllerFN` 保留 controller 实例方法类型。 |
|
|
176
|
+
| `ServiceFN` | `app/service/*.ts` 默认导出工厂函数的约束类型,适合配合 `satisfies ServiceFN` 约束 service class 工厂。 |
|
|
177
|
+
| `MiddlewareFN` | `app/middleware/*.ts` 默认导出工厂函数的约束类型,返回标准 Koa middleware。 |
|
|
178
|
+
| `RouterFN` | `app/router/*.ts` 默认导出函数的约束类型,用于接收 `app` 和 `router` 并注册路由。 |
|
|
179
|
+
|
|
180
|
+
示例:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { baseFn, type ControllerFN, type Ctx, type MiddlewareFN, type RouterFN, type ServiceFN } from '@_tc/template-core'
|
|
184
|
+
|
|
185
|
+
export const getDemoController = ((app) => {
|
|
186
|
+
const BaseController = baseFn.baseControllerFn(app)
|
|
187
|
+
|
|
188
|
+
return class DemoController extends BaseController {
|
|
189
|
+
list = async (ctx: Ctx) => {
|
|
190
|
+
this.success(ctx, ctx.reqData?.data ?? {})
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}) satisfies ControllerFN
|
|
194
|
+
|
|
195
|
+
export const getDemoService = ((app) => {
|
|
196
|
+
return class DemoService {
|
|
197
|
+
readonly app = app
|
|
198
|
+
}
|
|
199
|
+
}) satisfies ServiceFN
|
|
200
|
+
|
|
201
|
+
export const demoMiddleware = ((app) => async (ctx, next) => {
|
|
202
|
+
app.extends.logger?.info(ctx.path)
|
|
203
|
+
await next()
|
|
204
|
+
}) satisfies MiddlewareFN
|
|
205
|
+
|
|
206
|
+
export const demoRouter = ((app, router) => {
|
|
207
|
+
router.get(`${app.options.apiPrefix}/demo/list`, app.controller.demo.list)
|
|
208
|
+
}) satisfies RouterFN
|
|
209
|
+
```
|
|
210
|
+
|
|
168
211
|
## 样式与 Tailwind V4
|
|
169
212
|
|
|
170
213
|
使用内置前端或 UI 组件时,需要引入包内样式。默认 `@_tc/template-core/fe` 的 `initApp` 会经过源码入口 `frontend/src/main.tsx` 引入 `frontend/src/main.css`;如果项目侧自定义入口、只使用 `fe/rc` 组件,或希望样式入口更明确,建议显式引入:
|
|
@@ -662,6 +705,24 @@ model/**/*.(js|ts) -> 项目模型配置
|
|
|
662
705
|
- `app.extends.crypto`:Node 侧加密辅助方法,支持 base64url 编解码、HMAC 签名、签名 payload 和常量时间比较。
|
|
663
706
|
- `app.extends.db`:默认 SQLite 框架数据库,提供 `getDBData/setDBData` 等通用数据方法。
|
|
664
707
|
|
|
708
|
+
API controller 可以通过 `ctx.reqData` 读取统一请求参数:
|
|
709
|
+
|
|
710
|
+
```ts
|
|
711
|
+
const { query, body, headers, data } = ctx.reqData ?? {
|
|
712
|
+
query: {},
|
|
713
|
+
body: undefined,
|
|
714
|
+
headers: {},
|
|
715
|
+
data: {},
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
- `query` 来自 `ctx.query`。
|
|
720
|
+
- `body` 来自 `ctx.request.body`。
|
|
721
|
+
- `headers` 来自 `ctx.headers`。
|
|
722
|
+
- `data` 是便捷合并层,当前按 `query -> body` 顺序合并;字段冲突时 body 覆盖 query。
|
|
723
|
+
|
|
724
|
+
`ctx.reqData` 只在 API 请求中由内置中间件注入,类型上是可选字段。router params 不在 `reqData` 里,仍然从 `ctx.params` 获取。
|
|
725
|
+
|
|
665
726
|
### 数据库扩展
|
|
666
727
|
|
|
667
728
|
默认 `app.extends.db` 使用 SQLite 保存数据,数据库文件位于项目根目录 `.template-core/template-core.sqlite`。可以在配置中调整路径:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./base.js`);var t=(t=>{let n=e(t);return class extends n{getModelList=async e=>{let t=(await this.service.project.getModelList()).reduce((e,t)=>{let{model:n,project:r}=t,{key:i,name:a,desc:o}=n,s={key:i,name:a,desc:o},c=Object.keys(r).reduce((e,t)=>{let{key:n,name:i,desc:a,homePage:o}=r[t];return e[t]={key:n,name:i,desc:a,homePage:o},e},{});return e.push({model:s,project:c}),e},[]);this.success(e,t)};getProjectList=async e=>{let
|
|
1
|
+
const e=require(`./base.js`);var t=(t=>{let n=e(t);return class extends n{getModelList=async e=>{let t=(await this.service.project.getModelList()).reduce((e,t)=>{let{model:n,project:r}=t,{key:i,name:a,desc:o}=n,s={key:i,name:a,desc:o},c=Object.keys(r).reduce((e,t)=>{let{key:n,name:i,desc:a,homePage:o}=r[t];return e[t]={key:n,name:i,desc:a,homePage:o},e},{});return e.push({model:s,project:c}),e},[]);this.success(e,t)};getProjectList=async e=>{let t=e.reqData?.data.projk,n=(await this.service.project.getList(t))?.map(e=>{let{modelKey:t,key:n,name:r,desc:i,homePage:a}=e;return{modelKey:t,key:n,name:r,desc:i,homePage:a}});this.success(e,n)};getProject=async e=>{let{key:t}=e.params;if(!t){this.fail(e,10001,`获取项目异常`);return}let n=this.service.project.getProject(t);if(!n){this.fail(e,10001,`获取项目异常`);return}this.success(e,n)}}});module.exports=t;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e={},t=t=>async(n,r)=>{try{await r()}catch(r){let{status:i=200,message:a,detail:o,code:s=5e4,returnError:c}=r;if(t.extends.logger?.info(`error info -> ${JSON.stringify(r)}`),t.extends.logger?.error(`-- [excption] --`,r),t.extends.logger?.error(`-- [excption] info --`,i,a,o),a?.includes(`template not found`)){let r=n.req.url;if(e[r]===void 0?e[r]=0:e[r]+=1,e[r]<t.config.notFoundRedirectCount){n.status=302,n.redirect(t.options?.homePage??`/`);return}else e[r]=0}c?(n.status=i,n.body={code:s,message:a}):(n.status=200,n.body={code:5e4,message:`网络错误`})}};module.exports=t;
|
|
1
|
+
var e={},t=t=>async(n,r)=>{try{await r()}catch(r){let{status:i=200,message:a,detail:o,code:s=5e4,returnError:c}=r;if(t.extends.logger?.info(`error info -> ${JSON.stringify(r)}`),t.extends.logger?.error(`-- [excption] --`,r),t.extends.logger?.error(`-- [excption] info --`,i,a,o),a?.includes(`template not found`)){let r=n.path??n.req.url??n.url;if(e[r]===void 0?e[r]=0:e[r]+=1,e[r]<t.config.notFoundRedirectCount){n.status=302,n.redirect(t.options?.homePage??`/`);return}else e[r]=0}c?(n.status=i,n.body={code:s,message:a}):(n.status=200,n.body={code:5e4,message:`网络错误`})}};module.exports=t;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=e=>typeof e==`object`&&!!e&&!Array.isArray(e),t=(t=>async(n,r)=>{if(n.path.includes(`${t.options.apiPrefix}/`)){let{query:t,headers:r}=n,i=n.request.body;n.reqData={query:t,body:i,headers:r,data:{...t,...e(i)?i:{}}}}await r()});module.exports=t;
|
package/cjs/app/middleware.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/core/paths.js`);let n=require(`koa-compress`);n=e.__toESM(n);let r=require(`path`),i=require(`koa-bodyparser`);i=e.__toESM(i);let a=require(`koa-static`);a=e.__toESM(a);var o=(0,i.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),s=e=>{let i=e.envs.isLocal()?{maxage:0,setHeaders(e){e.setHeader(`Cache-Control`,`no-store, no-cache, must-revalidate, proxy-revalidate`),e.setHeader(`Pragma`,`no-cache`),e.setHeader(`Expires`,`0`)}}:{maxage:365*24*60*60*1e3};e.use(e.middlewares.errorHandle),e.use((0,n.default)({threshold:2048}));let s=(0,r.resolve)(t.getAppPath(e,`business`),`./public`),c=(0,r.resolve)(t.getAppPath(e,`frame`),`./public`),l=e.options.additionalPublicPaths??[];l=Array.isArray(l)?l:[l],e.use((0,a.default)(c,i)),e.use((0,a.default)(s,i)),l.forEach(t=>e.use((0,a.default)(t,i))),e.use(o),e.use(e.middlewares.projectHandler),!e.envs.isLocal()&&e.use(e.middlewares.apiSignVerify),e.use(e.middlewares.apiParamsVerify)};module.exports=s;
|
|
1
|
+
const e=require(`../_virtual/_rolldown/runtime.js`),t=require(`../packages/core/paths.js`);let n=require(`koa-compress`);n=e.__toESM(n);let r=require(`path`),i=require(`koa-bodyparser`);i=e.__toESM(i);let a=require(`koa-static`);a=e.__toESM(a);var o=(0,i.default)({formLimit:`1000mb`,enableTypes:[`form`,`json`,`text`]}),s=e=>{let i=e.envs.isLocal()?{maxage:0,setHeaders(e){e.setHeader(`Cache-Control`,`no-store, no-cache, must-revalidate, proxy-revalidate`),e.setHeader(`Pragma`,`no-cache`),e.setHeader(`Expires`,`0`)}}:{maxage:365*24*60*60*1e3};e.use(e.middlewares.errorHandle),e.use((0,n.default)({threshold:2048}));let s=(0,r.resolve)(t.getAppPath(e,`business`),`./public`),c=(0,r.resolve)(t.getAppPath(e,`frame`),`./public`),l=e.options.additionalPublicPaths??[];l=Array.isArray(l)?l:[l],e.use((0,a.default)(c,i)),e.use((0,a.default)(s,i)),l.forEach(t=>e.use((0,a.default)(t,i))),e.use(o),e.use(e.middlewares.requestParameterParsing),e.use(e.middlewares.projectHandler),!e.envs.isLocal()&&e.use(e.middlewares.apiSignVerify),e.use(e.middlewares.apiParamsVerify)};module.exports=s;
|
|
@@ -26,7 +26,7 @@ var t = ((t) => {
|
|
|
26
26
|
this.success(e, t);
|
|
27
27
|
};
|
|
28
28
|
getProjectList = async (e) => {
|
|
29
|
-
let
|
|
29
|
+
let t = e.reqData?.data.projk, n = (await this.service.project.getList(t))?.map((e) => {
|
|
30
30
|
let { modelKey: t, key: n, name: r, desc: i, homePage: a } = e;
|
|
31
31
|
return {
|
|
32
32
|
modelKey: t,
|
|
@@ -39,7 +39,12 @@ var t = ((t) => {
|
|
|
39
39
|
this.success(e, n);
|
|
40
40
|
};
|
|
41
41
|
getProject = async (e) => {
|
|
42
|
-
let { key: t } = e.params
|
|
42
|
+
let { key: t } = e.params;
|
|
43
|
+
if (!t) {
|
|
44
|
+
this.fail(e, 10001, "获取项目异常");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let n = this.service.project.getProject(t);
|
|
43
48
|
if (!n) {
|
|
44
49
|
this.fail(e, 10001, "获取项目异常");
|
|
45
50
|
return;
|
|
@@ -5,7 +5,7 @@ var e = {}, t = (t) => async (n, r) => {
|
|
|
5
5
|
} catch (r) {
|
|
6
6
|
let { status: i = 200, message: a, detail: o, code: s = 5e4, returnError: c } = r;
|
|
7
7
|
if (t.extends.logger?.info(`error info -> ${JSON.stringify(r)}`), t.extends.logger?.error("-- [excption] --", r), t.extends.logger?.error("-- [excption] info --", i, a, o), a?.includes("template not found")) {
|
|
8
|
-
let r = n.req.url;
|
|
8
|
+
let r = n.path ?? n.req.url ?? n.url;
|
|
9
9
|
if (e[r] === void 0 ? e[r] = 0 : e[r] += 1, e[r] < t.config.notFoundRedirectCount) {
|
|
10
10
|
n.status = 302, n.redirect(t.options?.homePage ?? "/");
|
|
11
11
|
return;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region app/middleware/request-parameter-parsing.ts
|
|
2
|
+
var e = (e) => typeof e == "object" && !!e && !Array.isArray(e), t = ((t) => async (n, r) => {
|
|
3
|
+
if (n.path.includes(`${t.options.apiPrefix}/`)) {
|
|
4
|
+
let { query: t, headers: r } = n, i = n.request.body;
|
|
5
|
+
n.reqData = {
|
|
6
|
+
query: t,
|
|
7
|
+
body: i,
|
|
8
|
+
headers: r,
|
|
9
|
+
data: {
|
|
10
|
+
...t,
|
|
11
|
+
...e(i) ? i : {}
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
await r();
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { t as default };
|
package/esm/app/middleware.js
CHANGED
|
@@ -20,7 +20,7 @@ var a = r({
|
|
|
20
20
|
} : { maxage: 365 * 24 * 60 * 60 * 1e3 };
|
|
21
21
|
r.use(r.middlewares.errorHandle), r.use(t({ threshold: 2048 }));
|
|
22
22
|
let s = n(e(r, "business"), "./public"), c = n(e(r, "frame"), "./public"), l = r.options.additionalPublicPaths ?? [];
|
|
23
|
-
l = Array.isArray(l) ? l : [l], r.use(i(c, o)), r.use(i(s, o)), l.forEach((e) => r.use(i(e, o))), r.use(a), r.use(r.middlewares.projectHandler), !r.envs.isLocal() && r.use(r.middlewares.apiSignVerify), r.use(r.middlewares.apiParamsVerify);
|
|
23
|
+
l = Array.isArray(l) ? l : [l], r.use(i(c, o)), r.use(i(s, o)), l.forEach((e) => r.use(i(e, o))), r.use(a), r.use(r.middlewares.requestParameterParsing), r.use(r.middlewares.projectHandler), !r.envs.isLocal() && r.use(r.middlewares.apiSignVerify), r.use(r.middlewares.apiParamsVerify);
|
|
24
24
|
};
|
|
25
25
|
//#endregion
|
|
26
26
|
export { o as default };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@_tc/template-core",
|
|
3
|
-
"version": "0.0.1-bate.
|
|
3
|
+
"version": "0.0.1-bate.58",
|
|
4
4
|
"description": "A full-stack TypeScript admin framework powered by Koa, React, and Vite - monorepo root",
|
|
5
5
|
"types": "./types/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -64,7 +64,12 @@
|
|
|
64
64
|
"tailwindcss": "4.2.4"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@types/
|
|
67
|
+
"@types/json-schema": "7.0.15",
|
|
68
|
+
"@types/md5": "2.3.6",
|
|
69
|
+
"@types/node": "20.19.39",
|
|
70
|
+
"@types/nunjucks": "3.2.6",
|
|
71
|
+
"@types/koa-router": "7.4.9",
|
|
72
|
+
"@types/koa": "2.15.0",
|
|
68
73
|
"@vitejs/plugin-react": "6.0.1",
|
|
69
74
|
"clsx": "^2.1.0",
|
|
70
75
|
"date-fns": "^3.6.0",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* - 统一处理请求参数获取
|
|
3
|
+
* - 除了params 因为params 必须经过router才会有
|
|
4
|
+
* - 而当前中间件是在 router之前追加,router params 仍然从 ctx.params 获取
|
|
5
|
+
*/
|
|
6
|
+
declare const requestParameterParsing: (app: import("../../packages/core/index").KoaApp) => (ctx: import("app/type").Ctx, next: import("koa").Next) => Promise<void>;
|
|
7
|
+
export default requestParameterParsing;
|
package/types/app/type.d.ts
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
|
+
import type Koa from "koa";
|
|
2
|
+
import type Router from "koa-router";
|
|
3
|
+
import type { IncomingHttpHeaders } from "http";
|
|
4
|
+
import type { ParsedUrlQuery } from "querystring";
|
|
1
5
|
export type KoaApp = import('./typings').KoaApp;
|
|
2
6
|
export type KoaRouter = import('./typings').KoaRouter;
|
|
3
|
-
export type
|
|
7
|
+
export type CtxParams = Router.IRouterParamContext['params'];
|
|
8
|
+
export interface CtxReqData {
|
|
9
|
+
/**
|
|
10
|
+
* URL query 参数。
|
|
11
|
+
*/
|
|
12
|
+
query: ParsedUrlQuery;
|
|
13
|
+
/**
|
|
14
|
+
* bodyparser 解析后的请求 body。
|
|
15
|
+
*/
|
|
16
|
+
body: unknown;
|
|
17
|
+
/**
|
|
18
|
+
* 原始请求 headers。
|
|
19
|
+
*/
|
|
20
|
+
headers: IncomingHttpHeaders;
|
|
21
|
+
/**
|
|
22
|
+
* 便捷合并层:当前中间件会按 query -> body 的顺序合并。
|
|
23
|
+
* 字段有冲突时,后面的来源会覆盖前面的来源;需要精确来源时请使用 query/body/headers。
|
|
24
|
+
*/
|
|
25
|
+
data: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
export type Ctx = Router.RouterContext<Koa.DefaultState, Koa.DefaultContext> & {
|
|
28
|
+
params: CtxParams;
|
|
29
|
+
reqData?: CtxReqData;
|
|
30
|
+
};
|
|
31
|
+
export type MiddlewareFN = (app: KoaApp) => (ctx: Ctx, next: Koa.Next) => Promise<void>;
|
|
32
|
+
export type RouterFN = (app: KoaApp, router: KoaRouter) => void;
|
|
4
33
|
export type ControllerFN<T extends object = object> = (app: KoaApp) => new () => T;
|
|
5
34
|
export type ServiceFN<T extends object = object> = (app: KoaApp) => new () => T;
|
|
6
|
-
export type RouterFN = (app: KoaApp, router: KoaRouter) => void;
|
package/types/app/typings.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ declare module '../packages/core/index' {
|
|
|
35
35
|
errorHandle: import('koa').Middleware;
|
|
36
36
|
apiSignVerify: import('koa').Middleware;
|
|
37
37
|
apiParamsVerify: import('koa').Middleware;
|
|
38
|
+
requestParameterParsing: import('koa').Middleware;
|
|
38
39
|
projectHandler: import('koa').Middleware;
|
|
39
40
|
}
|
|
40
41
|
interface AppConfigAugmented extends Partial<DefaultAppConfig> {
|
package/types/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { MOmit } from "./typings/type";
|
|
|
5
5
|
export type { FrameworkAugment, KoaApp } from "./packages/core/index";
|
|
6
6
|
export type { CryptoExtend, CryptoHashAlgorithm, HmacSignOptions, SignedPayloadOptions, VerifySignedPayloadOptions, } from "./app/extend/crypto";
|
|
7
7
|
export type { DB, DBDataOptions, DBDataRecord, DBFactory, DBRunResult, FrameworkDB, ListDBDataOptions, SQLiteParams, SQLiteValue, } from "./app/extend/db";
|
|
8
|
-
export type { ControllerFN, Ctx, RouterFN, ServiceFN } from "./app/type";
|
|
8
|
+
export type { ControllerFN, Ctx, MiddlewareFN, RouterFN, ServiceFN } from "./app/type";
|
|
9
9
|
export type { Router };
|
|
10
10
|
export declare const serverStart: (options?: MOmit<StartOptions, "frameBaseDir">) => Promise<import("./packages/core/index").KoaApp>;
|
|
11
11
|
export declare const baseFn: {
|