feat: 更新静态资源代理文档,优化路由和插件集成,提升代码可读性和功能性
This commit is contained in:
3
.opencode/plugin/agent.ts
Normal file
3
.opencode/plugin/agent.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { routerAgentPlugin } from "../../agent/main.ts";
|
||||||
|
|
||||||
|
export { routerAgentPlugin };
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
## 兼容服务器
|
## 兼容服务器静态资源代理
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { App } from '@kevisual/router';
|
import { App } from '@kevisual/router';
|
||||||
|
|
||||||
|
|||||||
5
agent/app.ts
Normal file
5
agent/app.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { App } from '../src/app.ts';
|
||||||
|
import { useContextKey } from '@kevisual/context';
|
||||||
|
export const app = useContextKey<App>('app', () => new App());
|
||||||
|
|
||||||
|
export { createSkill, type Skill, tool } from '../src/app.ts';
|
||||||
42
agent/gen.ts
Normal file
42
agent/gen.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import glob from 'fast-glob';
|
||||||
|
|
||||||
|
async function inlineMarkdownFiles() {
|
||||||
|
const files: { path: string; name: string }[] = [];
|
||||||
|
|
||||||
|
// 添加 readme.md
|
||||||
|
const readmePath = path.join(import.meta.dir, '..', 'readme.md');
|
||||||
|
files.push({ path: readmePath, name: 'readme' });
|
||||||
|
|
||||||
|
// 使用 fast-glob 动态获取 docs 目录下的 md 文件
|
||||||
|
const rootDir = path.join(import.meta.dir, '..', 'docs');
|
||||||
|
const mdFiles = await glob('**.md', { cwd: rootDir });
|
||||||
|
for (const filename of mdFiles) {
|
||||||
|
// 将路径转为变量名,如 examples/base -> examples_base
|
||||||
|
const name = filename.replace(/\.md$/, '').replace(/[^a-zA-Z0-9]/g, '_');
|
||||||
|
files.push({ path: path.join(rootDir, filename), name });
|
||||||
|
}
|
||||||
|
|
||||||
|
let generatedCode = '// Generated by build script\n';
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
const content = await Bun.file(file.path).text();
|
||||||
|
// 转义模板字符串中的特殊字符
|
||||||
|
const escapedContent = content
|
||||||
|
.replace(/\\/g, '\\\\')
|
||||||
|
.replace(/`/g, '\\`')
|
||||||
|
.replace(/\${/g, '\\${');
|
||||||
|
|
||||||
|
generatedCode += `export const ${file.name} = \`${escapedContent}\`;\n`;
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`Failed to read ${file.path}:`, error);
|
||||||
|
generatedCode += `export const ${file.name} = '';\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入生成的文件
|
||||||
|
await Bun.write(path.join(import.meta.dir, 'gen', 'index.ts'), generatedCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
await inlineMarkdownFiles();
|
||||||
205
agent/gen/index.ts
Normal file
205
agent/gen/index.ts
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
// Generated by build script
|
||||||
|
export const readme = `# router
|
||||||
|
|
||||||
|
一个轻量级的路由框架,支持链式调用、中间件、嵌套路由等功能。
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
\`\`\`ts
|
||||||
|
import { App } from '@kevisual/router';
|
||||||
|
|
||||||
|
const app = new App();
|
||||||
|
app.listen(4002);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({ path: 'demo', key: '02' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
ctx.body = '02';
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({ path: 'demo', key: '03' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
ctx.body = '03';
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## 核心概念
|
||||||
|
|
||||||
|
### RouteContext 属性说明
|
||||||
|
|
||||||
|
在 route handler 中,你可以通过 \`ctx\` 访问以下属性:
|
||||||
|
|
||||||
|
| 属性 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| \`query\` | \`object\` | 请求参数,会自动合并 payload |
|
||||||
|
| \`body\` | \`number \\| string \\| Object\` | 响应内容 |
|
||||||
|
| \`code\` | \`number\` | 响应状态码,默认为 200 |
|
||||||
|
| \`message\` | \`string\` | 响应消息 |
|
||||||
|
| \`state\` | \`any\` | 状态数据,可在路由间传递 |
|
||||||
|
| \`appId\` | \`string\` | 应用标识 |
|
||||||
|
| \`currentPath\` | \`string\` | 当前路由路径 |
|
||||||
|
| \`currentKey\` | \`string\` | 当前路由 key |
|
||||||
|
| \`currentRoute\` | \`Route\` | 当前 Route 实例 |
|
||||||
|
| \`progress\` | \`[string, string][]\` | 路由执行路径记录 |
|
||||||
|
| \`nextQuery\` | \`object\` | 传递给下一个路由的参数 |
|
||||||
|
| \`end\` | \`boolean\` | 是否提前结束路由执行 |
|
||||||
|
| \`app\` | \`QueryRouter\` | 路由实例引用 |
|
||||||
|
| \`error\` | \`any\` | 错误信息 |
|
||||||
|
| \`index\` | \`number\` | 当前路由执行深度 |
|
||||||
|
| \`needSerialize\` | \`boolean\` | 是否需要序列化响应数据 |
|
||||||
|
|
||||||
|
### 上下文方法
|
||||||
|
|
||||||
|
| 方法 | 参数 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| \`ctx.call(msg, ctx?)\` | \`{ path, key?, payload?, ... } \\| { id }\` | 调用其他路由,返回完整 context |
|
||||||
|
| \`ctx.run(msg, ctx?)\` | \`{ path, key?, payload? }\` | 调用其他路由,返回 \`{ code, data, message }\` |
|
||||||
|
| \`ctx.forward(res)\` | \`{ code, data?, message? }\` | 设置响应结果 |
|
||||||
|
| \`ctx.throw(code?, message?, tips?)\` | - | 抛出自定义错误 |
|
||||||
|
|
||||||
|
## 完整示例
|
||||||
|
|
||||||
|
\`\`\`ts
|
||||||
|
import { App } from '@kevisual/router';
|
||||||
|
|
||||||
|
const app = new App();
|
||||||
|
app.listen(4002);
|
||||||
|
|
||||||
|
// 基本路由
|
||||||
|
app
|
||||||
|
.route({ path: 'user', key: 'info' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
// ctx.query 包含请求参数
|
||||||
|
const { id } = ctx.query;
|
||||||
|
ctx.body = { id, name: '张三' };
|
||||||
|
ctx.code = 200;
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
// 使用 state 在路由间传递数据
|
||||||
|
app
|
||||||
|
.route({ path: 'order', key: 'create' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
ctx.state = { orderId: '12345' };
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({ path: 'order', key: 'pay' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
// 可以获取前一个路由设置的 state
|
||||||
|
const { orderId } = ctx.state;
|
||||||
|
ctx.body = { orderId, status: 'paid' };
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
// 链式调用
|
||||||
|
app
|
||||||
|
.route({ path: 'product', key: 'list' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
ctx.body = [{ id: 1, name: '商品A' }];
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
// 调用其他路由
|
||||||
|
app
|
||||||
|
.route({ path: 'dashboard', key: 'stats' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
// 调用 user/info 路由
|
||||||
|
const userRes = await ctx.run({ path: 'user', key: 'info', payload: { id: 1 } });
|
||||||
|
// 调用 product/list 路由
|
||||||
|
const productRes = await ctx.run({ path: 'product', key: 'list' });
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
user: userRes.data,
|
||||||
|
products: productRes.data
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
// 使用 throw 抛出错误
|
||||||
|
app
|
||||||
|
.route({ path: 'admin', key: 'delete' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
const { id } = ctx.query;
|
||||||
|
if (!id) {
|
||||||
|
ctx.throw(400, '缺少参数', 'id is required');
|
||||||
|
}
|
||||||
|
ctx.body = { success: true };
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## 中间件
|
||||||
|
|
||||||
|
\`\`\`ts
|
||||||
|
import { App, Route } from '@kevisual/router';
|
||||||
|
|
||||||
|
const app = new App();
|
||||||
|
|
||||||
|
// 定义中间件
|
||||||
|
app.route({
|
||||||
|
id: 'auth-example',
|
||||||
|
description: '权限校验中间件'
|
||||||
|
}).define(async(ctx) => {
|
||||||
|
const token = ctx.query.token;
|
||||||
|
if (!token) {
|
||||||
|
ctx.throw(401, '未登录', '需要 token');
|
||||||
|
}
|
||||||
|
// 验证通过,设置用户信息到 state
|
||||||
|
ctx.state.tokenUser = { id: 1, name: '用户A' };
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 使用中间件(通过 id 引用)
|
||||||
|
app
|
||||||
|
.route({ path: 'admin', key: 'panel', middleware: ['auth-example'] })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
// 可以访问中间件设置的 state
|
||||||
|
const { tokenUser } = ctx.state;
|
||||||
|
ctx.body = { tokenUser };
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **path 和 key 的组合是路由的唯一标识**,同一个 path+key 只能添加一个路由,后添加的会覆盖之前的。
|
||||||
|
|
||||||
|
2. **ctx.call vs ctx.run**:
|
||||||
|
- \`call\` 返回完整 context,包含所有属性
|
||||||
|
- \`run\` 返回 \`{ code, data, message }\` 格式,data 即 body
|
||||||
|
|
||||||
|
3. **ctx.throw 会自动结束执行**,抛出自定义错误。
|
||||||
|
|
||||||
|
4. **state 不会自动继承**,每个路由的 state 是独立的,除非显式传递或使用 nextRoute。
|
||||||
|
|
||||||
|
5. **payload 会自动合并到 query**,调用 \`ctx.run({ path, key, payload })\` 时,payload 会合并到 query。
|
||||||
|
|
||||||
|
6. **nextQuery 用于传递给 nextRoute**,在当前路由中设置 \`ctx.nextQuery\`,会在执行 nextRoute 时合并到 query。
|
||||||
|
|
||||||
|
7. **避免 nextRoute 循环调用**,默认最大深度为 40 次,超过会返回 500 错误。
|
||||||
|
|
||||||
|
8. **needSerialize 默认为 true**,会自动对 body 进行 JSON 序列化和反序列化。
|
||||||
|
|
||||||
|
9. **progress 记录执行路径**,可用于调试和追踪路由调用链。
|
||||||
|
|
||||||
|
10. **中间件找不到会返回 404**,错误信息中会包含找不到的中间件列表。
|
||||||
|
`;
|
||||||
|
export const examples_base = `# 最基本的用法
|
||||||
|
|
||||||
|
\`\`\`ts
|
||||||
|
import { App } from '@kevisual/router';
|
||||||
|
const app = new App();
|
||||||
|
app.listen(4002);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({ path: 'demo', key: '02' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
ctx.body = '02';
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
\`\`\``;
|
||||||
6
agent/main.ts
Normal file
6
agent/main.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { app } from './app.ts'
|
||||||
|
import { createRouterAgentPluginFn } from '../src/opencode.ts'
|
||||||
|
import './routes/index.ts'
|
||||||
|
|
||||||
|
// 工具列表
|
||||||
|
export const routerAgentPlugin = createRouterAgentPluginFn({ router: app });
|
||||||
14
agent/routes/index.ts
Normal file
14
agent/routes/index.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { app } from '../app.ts'
|
||||||
|
import './route-create.ts'
|
||||||
|
|
||||||
|
if (!app.hasRoute('auth', '')) {
|
||||||
|
app.route({
|
||||||
|
path: 'auth',
|
||||||
|
key: '',
|
||||||
|
id: 'auth',
|
||||||
|
description: '身份验证路由',
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
//
|
||||||
|
}).addTo(app);
|
||||||
|
}
|
||||||
|
|
||||||
45
agent/routes/route-create.ts
Normal file
45
agent/routes/route-create.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { app, createSkill, tool } from '../app.ts';
|
||||||
|
import * as docs from '../gen/index.ts'
|
||||||
|
import * as pkgs from '../../package.json' assert { type: 'json' };
|
||||||
|
app.route({
|
||||||
|
path: 'router-skill',
|
||||||
|
key: 'create-route',
|
||||||
|
description: '创建路由技能',
|
||||||
|
middleware: ['auth'],
|
||||||
|
metadata: {
|
||||||
|
tags: ['opencode'],
|
||||||
|
...createSkill({
|
||||||
|
skill: 'create-router-skill',
|
||||||
|
title: '创建路由技能',
|
||||||
|
summary: '创建一个新的路由技能,参数包括路径、键、描述、参数等',
|
||||||
|
args: {
|
||||||
|
question: tool.schema.string().describe('要实现的功能'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const { question } = ctx.query || {};
|
||||||
|
if (!question) {
|
||||||
|
ctx.throw('参数 question 不能为空');
|
||||||
|
}
|
||||||
|
let base = ''
|
||||||
|
base += `根据用户需要实现的功能生成一个route的代码:${question}\n\n`;
|
||||||
|
base += `资料库:\n`
|
||||||
|
base += docs.readme + '\n\n';
|
||||||
|
|
||||||
|
ctx.body = {
|
||||||
|
body: base
|
||||||
|
}
|
||||||
|
}).addTo(app);
|
||||||
|
|
||||||
|
// 调用router应用 path router-skill key version
|
||||||
|
app.route({
|
||||||
|
path: 'router-skill',
|
||||||
|
key: 'version',
|
||||||
|
description: '获取路由技能版本',
|
||||||
|
middleware: ['auth'],
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
ctx.body = {
|
||||||
|
content: pkgs.version || 'unknown'
|
||||||
|
}
|
||||||
|
}).addTo(app);
|
||||||
24
bun.config.ts
Normal file
24
bun.config.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import path from 'node:path';
|
||||||
|
import pkg from './package.json';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import { execSync } from 'node:child_process';
|
||||||
|
const w = (p: string) => path.resolve(import.meta.dir, p);
|
||||||
|
|
||||||
|
const external: string[] = ["bun"];
|
||||||
|
await Bun.build({
|
||||||
|
target: 'node',
|
||||||
|
format: 'esm',
|
||||||
|
entrypoints: [w('./agent/main.ts')],
|
||||||
|
outdir: w('./dist'),
|
||||||
|
naming: {
|
||||||
|
entry: 'app.js',
|
||||||
|
},
|
||||||
|
define: {},
|
||||||
|
external
|
||||||
|
});
|
||||||
|
|
||||||
|
const cmd = 'dts -i ./agent/main.ts -o /app.d.ts';
|
||||||
|
|
||||||
|
execSync(cmd, { stdio: 'inherit' });
|
||||||
|
|
||||||
|
// Copy package.json to dist
|
||||||
@@ -10,15 +10,6 @@ route01.run = async (ctx) => {
|
|||||||
};
|
};
|
||||||
app.addRoute(route01);
|
app.addRoute(route01);
|
||||||
|
|
||||||
// app.use(
|
|
||||||
// 'demo',
|
|
||||||
// async (ctx) => {
|
|
||||||
// ctx.body = '01';
|
|
||||||
// return ctx;
|
|
||||||
// },
|
|
||||||
// { key: '01' },
|
|
||||||
// );
|
|
||||||
|
|
||||||
const route02 = new Route('demo', '02');
|
const route02 = new Route('demo', '02');
|
||||||
route02.run = async (ctx) => {
|
route02.run = async (ctx) => {
|
||||||
ctx.body = '02';
|
ctx.body = '02';
|
||||||
|
|||||||
15
docs/examples/base.md
Normal file
15
docs/examples/base.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# 最基本的用法
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { App } from '@kevisual/router';
|
||||||
|
const app = new App();
|
||||||
|
app.listen(4002);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({ path: 'demo', key: '02' })
|
||||||
|
.define(async (ctx) => {
|
||||||
|
ctx.body = '02';
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
|
```
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.58",
|
"version": "0.0.60",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/router.js",
|
"main": "./dist/router.js",
|
||||||
"types": "./dist/router.d.ts",
|
"types": "./dist/router.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run clean && rollup -c",
|
"build": "npm run clean && rollup -c",
|
||||||
"build:app": "npm run build && rsync dist/*browser* ../deploy/dist",
|
"postbuild": "bun run bun.config.ts",
|
||||||
"watch": "rollup -c -w",
|
"watch": "rollup -c -w",
|
||||||
"clean": "rm -rf dist"
|
"clean": "rm -rf dist"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
"src",
|
"src",
|
||||||
|
"agent",
|
||||||
"auto.ts",
|
"auto.ts",
|
||||||
"mod.ts"
|
"mod.ts"
|
||||||
],
|
],
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
"@kevisual/local-proxy": "^0.0.8",
|
"@kevisual/local-proxy": "^0.0.8",
|
||||||
"@kevisual/query": "^0.0.35",
|
"@kevisual/query": "^0.0.35",
|
||||||
"@kevisual/use-config": "^1.0.28",
|
"@kevisual/use-config": "^1.0.28",
|
||||||
"@opencode-ai/plugin": "^1.1.26",
|
"@opencode-ai/plugin": "^1.1.27",
|
||||||
"@rollup/plugin-alias": "^6.0.0",
|
"@rollup/plugin-alias": "^6.0.0",
|
||||||
"@rollup/plugin-commonjs": "29.0.0",
|
"@rollup/plugin-commonjs": "29.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"@types/xml2js": "^0.4.14",
|
"@types/xml2js": "^0.4.14",
|
||||||
"eventemitter3": "^5.0.4",
|
"eventemitter3": "^5.0.4",
|
||||||
|
"fast-glob": "^3.3.3",
|
||||||
"nanoid": "^5.1.6",
|
"nanoid": "^5.1.6",
|
||||||
"path-to-regexp": "^8.3.0",
|
"path-to-regexp": "^8.3.0",
|
||||||
"rollup": "^4.55.2",
|
"rollup": "^4.55.2",
|
||||||
@@ -80,6 +82,7 @@
|
|||||||
"types": "./dist/router-simple.d.ts"
|
"types": "./dist/router-simple.d.ts"
|
||||||
},
|
},
|
||||||
"./opencode": "./dist/opencode.js",
|
"./opencode": "./dist/opencode.js",
|
||||||
|
"./skill": "./dist/app.js",
|
||||||
"./define": {
|
"./define": {
|
||||||
"import": "./dist/router-define.js",
|
"import": "./dist/router-define.js",
|
||||||
"require": "./dist/router-define.js",
|
"require": "./dist/router-define.js",
|
||||||
|
|||||||
110
pnpm-lock.yaml
generated
110
pnpm-lock.yaml
generated
@@ -28,8 +28,8 @@ importers:
|
|||||||
specifier: ^1.0.28
|
specifier: ^1.0.28
|
||||||
version: 1.0.28(dotenv@17.2.3)
|
version: 1.0.28(dotenv@17.2.3)
|
||||||
'@opencode-ai/plugin':
|
'@opencode-ai/plugin':
|
||||||
specifier: ^1.1.26
|
specifier: ^1.1.27
|
||||||
version: 1.1.26
|
version: 1.1.27
|
||||||
'@rollup/plugin-alias':
|
'@rollup/plugin-alias':
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.0.0(rollup@4.55.2)
|
version: 6.0.0(rollup@4.55.2)
|
||||||
@@ -60,6 +60,9 @@ importers:
|
|||||||
eventemitter3:
|
eventemitter3:
|
||||||
specifier: ^5.0.4
|
specifier: ^5.0.4
|
||||||
version: 5.0.4
|
version: 5.0.4
|
||||||
|
fast-glob:
|
||||||
|
specifier: ^3.3.3
|
||||||
|
version: 3.3.3
|
||||||
nanoid:
|
nanoid:
|
||||||
specifier: ^5.1.6
|
specifier: ^5.1.6
|
||||||
version: 5.1.6
|
version: 5.1.6
|
||||||
@@ -329,11 +332,23 @@ packages:
|
|||||||
resolution: {integrity: sha512-jlFxSlXUEz93cFW+UYT5BXv/rFVgiMQnIfqRYZ0gj1hSP8PMGRqMqUoHSLfKvfRRS4jseLSvTTeEKSQpZJtURg==}
|
resolution: {integrity: sha512-jlFxSlXUEz93cFW+UYT5BXv/rFVgiMQnIfqRYZ0gj1hSP8PMGRqMqUoHSLfKvfRRS4jseLSvTTeEKSQpZJtURg==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
'@opencode-ai/plugin@1.1.26':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-GnhLZuw9NHDJwY5msUZnFIWiLc0SnoBXWZNfnWF5+hu0fcVLgul8gqB2VK4kUv+KOQlzCVMILYikSSQkMYp7RQ==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.1.26':
|
'@nodelib/fs.stat@2.0.5':
|
||||||
resolution: {integrity: sha512-5s+yxNJy7DpWwDq0L//F2sqKERz4640DmDLyrRlFXmckx5prnzFl3liEOOTySOL2WaxgVwjYw8OBiT15v2mAgA==}
|
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
'@nodelib/fs.walk@1.2.8':
|
||||||
|
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
'@opencode-ai/plugin@1.1.27':
|
||||||
|
resolution: {integrity: sha512-EevLVaEhQ1jTLNRbQJj18tFZaVNJcZZcVqvZEbDSe17CfmVRv3FQNKRAjD/QHwb+Kym7sn+LAZxD7aYIPPelvQ==}
|
||||||
|
|
||||||
|
'@opencode-ai/sdk@1.1.27':
|
||||||
|
resolution: {integrity: sha512-ssRZpET3zUNdk1GuF6HwFkNHhCXSTG0lhuPmw9HjifTwv1EVrn8gz7jAuME2OCvUSBvRTesH6Lb0Xt78Qbhzww==}
|
||||||
|
|
||||||
'@rollup/plugin-alias@6.0.0':
|
'@rollup/plugin-alias@6.0.0':
|
||||||
resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==}
|
resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==}
|
||||||
@@ -777,9 +792,16 @@ packages:
|
|||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
|
fast-glob@3.3.3:
|
||||||
|
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
|
||||||
|
engines: {node: '>=8.6.0'}
|
||||||
|
|
||||||
fast-uri@3.1.0:
|
fast-uri@3.1.0:
|
||||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||||
|
|
||||||
|
fastq@1.20.1:
|
||||||
|
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
|
||||||
|
|
||||||
fdir@6.5.0:
|
fdir@6.5.0:
|
||||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
@@ -808,6 +830,10 @@ packages:
|
|||||||
get-tsconfig@4.13.0:
|
get-tsconfig@4.13.0:
|
||||||
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
|
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
|
||||||
|
|
||||||
|
glob-parent@5.1.2:
|
||||||
|
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
glob-to-regexp@0.4.1:
|
glob-to-regexp@0.4.1:
|
||||||
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
|
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
|
||||||
|
|
||||||
@@ -837,6 +863,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
is-extglob@2.1.1:
|
||||||
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
is-glob@4.0.3:
|
||||||
|
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
is-module@1.0.0:
|
is-module@1.0.0:
|
||||||
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
||||||
|
|
||||||
@@ -873,6 +907,10 @@ packages:
|
|||||||
merge-stream@2.0.0:
|
merge-stream@2.0.0:
|
||||||
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
|
||||||
|
|
||||||
|
merge2@1.4.1:
|
||||||
|
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
micromatch@4.0.8:
|
micromatch@4.0.8:
|
||||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||||
engines: {node: '>=8.6'}
|
engines: {node: '>=8.6'}
|
||||||
@@ -928,6 +966,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
queue-microtask@1.2.3:
|
||||||
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
|
|
||||||
randombytes@2.1.0:
|
randombytes@2.1.0:
|
||||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||||
|
|
||||||
@@ -947,6 +988,10 @@ packages:
|
|||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
reusify@1.1.0:
|
||||||
|
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
|
||||||
|
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
|
||||||
|
|
||||||
rollup-plugin-dts@6.3.0:
|
rollup-plugin-dts@6.3.0:
|
||||||
resolution: {integrity: sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA==}
|
resolution: {integrity: sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
@@ -959,6 +1004,9 @@ packages:
|
|||||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
run-parallel@1.2.0:
|
||||||
|
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||||
|
|
||||||
safe-buffer@5.2.1:
|
safe-buffer@5.2.1:
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
@@ -1265,12 +1313,24 @@ snapshots:
|
|||||||
|
|
||||||
'@kevisual/ws@8.0.0': {}
|
'@kevisual/ws@8.0.0': {}
|
||||||
|
|
||||||
'@opencode-ai/plugin@1.1.26':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@opencode-ai/sdk': 1.1.26
|
'@nodelib/fs.stat': 2.0.5
|
||||||
|
run-parallel: 1.2.0
|
||||||
|
|
||||||
|
'@nodelib/fs.stat@2.0.5': {}
|
||||||
|
|
||||||
|
'@nodelib/fs.walk@1.2.8':
|
||||||
|
dependencies:
|
||||||
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
|
fastq: 1.20.1
|
||||||
|
|
||||||
|
'@opencode-ai/plugin@1.1.27':
|
||||||
|
dependencies:
|
||||||
|
'@opencode-ai/sdk': 1.1.27
|
||||||
zod: 4.1.8
|
zod: 4.1.8
|
||||||
|
|
||||||
'@opencode-ai/sdk@1.1.26': {}
|
'@opencode-ai/sdk@1.1.27': {}
|
||||||
|
|
||||||
'@rollup/plugin-alias@6.0.0(rollup@4.55.2)':
|
'@rollup/plugin-alias@6.0.0(rollup@4.55.2)':
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
@@ -1670,8 +1730,20 @@ snapshots:
|
|||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
|
fast-glob@3.3.3:
|
||||||
|
dependencies:
|
||||||
|
'@nodelib/fs.stat': 2.0.5
|
||||||
|
'@nodelib/fs.walk': 1.2.8
|
||||||
|
glob-parent: 5.1.2
|
||||||
|
merge2: 1.4.1
|
||||||
|
micromatch: 4.0.8
|
||||||
|
|
||||||
fast-uri@3.1.0: {}
|
fast-uri@3.1.0: {}
|
||||||
|
|
||||||
|
fastq@1.20.1:
|
||||||
|
dependencies:
|
||||||
|
reusify: 1.1.0
|
||||||
|
|
||||||
fdir@6.5.0(picomatch@4.0.3):
|
fdir@6.5.0(picomatch@4.0.3):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
@@ -1691,6 +1763,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
resolve-pkg-maps: 1.0.0
|
resolve-pkg-maps: 1.0.0
|
||||||
|
|
||||||
|
glob-parent@5.1.2:
|
||||||
|
dependencies:
|
||||||
|
is-glob: 4.0.3
|
||||||
|
|
||||||
glob-to-regexp@0.4.1: {}
|
glob-to-regexp@0.4.1: {}
|
||||||
|
|
||||||
graceful-fs@4.2.11: {}
|
graceful-fs@4.2.11: {}
|
||||||
@@ -1717,6 +1793,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
hasown: 2.0.2
|
hasown: 2.0.2
|
||||||
|
|
||||||
|
is-extglob@2.1.1: {}
|
||||||
|
|
||||||
|
is-glob@4.0.3:
|
||||||
|
dependencies:
|
||||||
|
is-extglob: 2.1.1
|
||||||
|
|
||||||
is-module@1.0.0: {}
|
is-module@1.0.0: {}
|
||||||
|
|
||||||
is-number@7.0.0: {}
|
is-number@7.0.0: {}
|
||||||
@@ -1748,6 +1830,8 @@ snapshots:
|
|||||||
|
|
||||||
merge-stream@2.0.0: {}
|
merge-stream@2.0.0: {}
|
||||||
|
|
||||||
|
merge2@1.4.1: {}
|
||||||
|
|
||||||
micromatch@4.0.8:
|
micromatch@4.0.8:
|
||||||
dependencies:
|
dependencies:
|
||||||
braces: 3.0.3
|
braces: 3.0.3
|
||||||
@@ -1787,6 +1871,8 @@ snapshots:
|
|||||||
|
|
||||||
picomatch@4.0.3: {}
|
picomatch@4.0.3: {}
|
||||||
|
|
||||||
|
queue-microtask@1.2.3: {}
|
||||||
|
|
||||||
randombytes@2.1.0:
|
randombytes@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
@@ -1803,6 +1889,8 @@ snapshots:
|
|||||||
path-parse: 1.0.7
|
path-parse: 1.0.7
|
||||||
supports-preserve-symlinks-flag: 1.0.0
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
|
|
||||||
|
reusify@1.1.0: {}
|
||||||
|
|
||||||
rollup-plugin-dts@6.3.0(rollup@4.55.2)(typescript@5.9.3):
|
rollup-plugin-dts@6.3.0(rollup@4.55.2)(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
@@ -1842,6 +1930,10 @@ snapshots:
|
|||||||
'@rollup/rollup-win32-x64-msvc': 4.55.2
|
'@rollup/rollup-win32-x64-msvc': 4.55.2
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
run-parallel@1.2.0:
|
||||||
|
dependencies:
|
||||||
|
queue-microtask: 1.2.3
|
||||||
|
|
||||||
safe-buffer@5.2.1: {}
|
safe-buffer@5.2.1: {}
|
||||||
|
|
||||||
sax@1.4.3: {}
|
sax@1.4.3: {}
|
||||||
|
|||||||
42
src/app.ts
42
src/app.ts
@@ -2,7 +2,6 @@ import { QueryRouter, Route, RouteContext, RouteOpts } from './route.ts';
|
|||||||
import { ServerNode, ServerNodeOpts } from './server/server.ts';
|
import { ServerNode, ServerNodeOpts } from './server/server.ts';
|
||||||
import { HandleCtx } from './server/server-base.ts';
|
import { HandleCtx } from './server/server-base.ts';
|
||||||
import { ServerType } from './server/server-type.ts';
|
import { ServerType } from './server/server-type.ts';
|
||||||
import { CustomError } from './result/error.ts';
|
|
||||||
import { handleServer } from './server/handle-server.ts';
|
import { handleServer } from './server/handle-server.ts';
|
||||||
import { IncomingMessage, ServerResponse } from 'http';
|
import { IncomingMessage, ServerResponse } from 'http';
|
||||||
import { isBun } from './utils/is-engine.ts';
|
import { isBun } from './utils/is-engine.ts';
|
||||||
@@ -26,12 +25,13 @@ export type AppRouteContext<T = {}> = HandleCtx & RouteContext<T> & { app: App<T
|
|||||||
* 封装了 Router 和 Server 的 App 模块,处理http的请求和响应,内置了 Cookie 和 Token 和 res 的处理
|
* 封装了 Router 和 Server 的 App 模块,处理http的请求和响应,内置了 Cookie 和 Token 和 res 的处理
|
||||||
* U - Route Context的扩展类型
|
* U - Route Context的扩展类型
|
||||||
*/
|
*/
|
||||||
export class App<U = {}> {
|
export class App<U = {}> extends QueryRouter {
|
||||||
appId: string;
|
declare appId: string;
|
||||||
router: QueryRouter;
|
router: QueryRouter;
|
||||||
server: ServerType;
|
server: ServerType;
|
||||||
constructor(opts?: AppOptions<U>) {
|
constructor(opts?: AppOptions<U>) {
|
||||||
const router = opts?.router || new QueryRouter();
|
super();
|
||||||
|
const router = this;
|
||||||
let server = opts?.server;
|
let server = opts?.server;
|
||||||
if (!server) {
|
if (!server) {
|
||||||
const serverOptions = opts?.serverOptions || {};
|
const serverOptions = opts?.serverOptions || {};
|
||||||
@@ -64,15 +64,9 @@ export class App<U = {}> {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.server.listen(...args);
|
this.server.listen(...args);
|
||||||
}
|
}
|
||||||
use(path: string, fn: (ctx: any) => any, opts?: RouteOpts) {
|
|
||||||
const route = new Route(path, '', opts);
|
|
||||||
route.run = fn;
|
|
||||||
this.router.add(route);
|
|
||||||
}
|
|
||||||
addRoute(route: Route) {
|
addRoute(route: Route) {
|
||||||
this.router.add(route);
|
super.add(route);
|
||||||
}
|
}
|
||||||
add = this.addRoute;
|
|
||||||
|
|
||||||
Route = Route;
|
Route = Route;
|
||||||
route(opts: RouteOpts<AppRouteContext<U>>): Route<AppRouteContext<U>>;
|
route(opts: RouteOpts<AppRouteContext<U>>): Route<AppRouteContext<U>>;
|
||||||
@@ -109,30 +103,10 @@ export class App<U = {}> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async call(message: { id?: string, path?: string; key?: string; payload?: any }, ctx?: AppRouteContext<U> & { [key: string]: any }) {
|
async call(message: { id?: string, path?: string; key?: string; payload?: any }, ctx?: AppRouteContext<U> & { [key: string]: any }) {
|
||||||
const router = this.router;
|
return await super.call(message, ctx);
|
||||||
return await router.call(message, ctx);
|
|
||||||
}
|
}
|
||||||
/**
|
async run(msg: { id?: string, path?: string; key?: string; payload?: any }, ctx?: Partial<AppRouteContext<U>> & { [key: string]: any }) {
|
||||||
* @deprecated
|
return await super.run(msg, ctx);
|
||||||
*/
|
|
||||||
async queryRoute(path: string, key?: string, payload?: any, ctx?: AppRouteContext<U> & { [key: string]: any }) {
|
|
||||||
return await this.router.queryRoute({ path, key, payload }, ctx);
|
|
||||||
}
|
|
||||||
async run(msg: { id?: string, path?: string; key?: string; payload?: any }, ctx?: AppRouteContext<U> & { [key: string]: any }) {
|
|
||||||
return await this.router.run(msg, ctx);
|
|
||||||
}
|
|
||||||
exportRoutes() {
|
|
||||||
return this.router.exportRoutes();
|
|
||||||
}
|
|
||||||
importRoutes(routes: any[]) {
|
|
||||||
this.router.importRoutes(routes);
|
|
||||||
}
|
|
||||||
importApp(app: App) {
|
|
||||||
this.importRoutes(app.exportRoutes());
|
|
||||||
}
|
|
||||||
throw(code?: number | string, message?: string, tips?: string): void;
|
|
||||||
throw(...args: any[]) {
|
|
||||||
throw new CustomError(...args);
|
|
||||||
}
|
}
|
||||||
static handleRequest(req: IncomingMessage, res: ServerResponse) {
|
static handleRequest(req: IncomingMessage, res: ServerResponse) {
|
||||||
return handleServer(req, res);
|
return handleServer(req, res);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { type App } from './app.ts'
|
|||||||
import { type Plugin } from "@opencode-ai/plugin"
|
import { type Plugin } from "@opencode-ai/plugin"
|
||||||
|
|
||||||
import { filter } from '@kevisual/js-filter';
|
import { filter } from '@kevisual/js-filter';
|
||||||
export const addCallFn = (app: QueryRouterServer) => {
|
export const addCallFn = (app: App) => {
|
||||||
app.route({
|
app.route({
|
||||||
path: 'call',
|
path: 'call',
|
||||||
key: '',
|
key: '',
|
||||||
@@ -35,20 +35,23 @@ export const addCallFn = (app: QueryRouterServer) => {
|
|||||||
}).addTo(app)
|
}).addTo(app)
|
||||||
}
|
}
|
||||||
export const createRouterAgentPluginFn = (opts?: {
|
export const createRouterAgentPluginFn = (opts?: {
|
||||||
router?: QueryRouter,
|
router?: App | QueryRouterServer,
|
||||||
//** 过滤比如,WHERE metadata.tags includes 'opencode' */
|
//** 过滤比如,WHERE metadata.tags includes 'opencode' */
|
||||||
query?: string
|
query?: string
|
||||||
}) => {
|
}) => {
|
||||||
let router = opts?.router
|
let router = opts?.router
|
||||||
if (!router) {
|
if (!router) {
|
||||||
const app = useContextKey<App>('app')
|
const app = useContextKey<App>('app')
|
||||||
router = app.router
|
router = app
|
||||||
}
|
}
|
||||||
if (!router) {
|
if (!router) {
|
||||||
throw new Error('Router 参数缺失')
|
throw new Error('Router 参数缺失')
|
||||||
}
|
}
|
||||||
if (!router.hasRoute('call', '')) {
|
if (!router.hasRoute('call', '')) {
|
||||||
addCallFn(router as QueryRouterServer)
|
addCallFn(router as App)
|
||||||
|
}
|
||||||
|
if (!router.hasRoute('auth', '')) {
|
||||||
|
router.route({ path: 'auth', key: '', id: 'auth', description: '认证' }).define(async (ctx) => { }).addTo(router as App)
|
||||||
}
|
}
|
||||||
const _routes = filter(router.routes, opts?.query || '')
|
const _routes = filter(router.routes, opts?.query || '')
|
||||||
const routes = _routes.filter(r => {
|
const routes = _routes.filter(r => {
|
||||||
@@ -88,6 +91,7 @@ export const createRouterAgentPluginFn = (opts?: {
|
|||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
console.error('调用出错', res);
|
||||||
return `Error: ${res?.message || '无法获取结果'}`;
|
return `Error: ${res?.message || '无法获取结果'}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/route.ts
12
src/route.ts
@@ -60,7 +60,7 @@ export type RouteContext<T = { code?: number }, S = any> = {
|
|||||||
needSerialize?: boolean;
|
needSerialize?: boolean;
|
||||||
} & T;
|
} & T;
|
||||||
export type SimpleObject = Record<string, any>;
|
export type SimpleObject = Record<string, any>;
|
||||||
export type Run<T extends SimpleObject = {}> = (ctx: RouteContext<T>) => Promise<typeof ctx | null | void>;
|
export type Run<T extends SimpleObject = {}> = (ctx: Required<RouteContext<T>>) => Promise<typeof ctx | null | void>;
|
||||||
|
|
||||||
export type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
|
export type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
|
||||||
export type RouteMiddleware =
|
export type RouteMiddleware =
|
||||||
@@ -355,7 +355,7 @@ export class QueryRouter {
|
|||||||
const middleware = routeMiddleware[i];
|
const middleware = routeMiddleware[i];
|
||||||
if (middleware) {
|
if (middleware) {
|
||||||
try {
|
try {
|
||||||
await middleware.run(ctx);
|
await middleware.run(ctx as Required<RouteContext>);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (route?.isDebug) {
|
if (route?.isDebug) {
|
||||||
console.error('=====debug====:middlerware error');
|
console.error('=====debug====:middlerware error');
|
||||||
@@ -385,7 +385,7 @@ export class QueryRouter {
|
|||||||
if (route) {
|
if (route) {
|
||||||
if (route.run) {
|
if (route.run) {
|
||||||
try {
|
try {
|
||||||
await route.run(ctx);
|
await route.run(ctx as Required<RouteContext>);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (route?.isDebug) {
|
if (route?.isDebug) {
|
||||||
console.error('=====debug====:', 'router run error:', e.message);
|
console.error('=====debug====:', 'router run error:', e.message);
|
||||||
@@ -664,15 +664,9 @@ export class QueryRouterServer extends QueryRouter {
|
|||||||
setHandle(wrapperFn?: HandleFn, ctx?: RouteContext) {
|
setHandle(wrapperFn?: HandleFn, ctx?: RouteContext) {
|
||||||
this.handle = this.getHandle(this, wrapperFn, ctx);
|
this.handle = this.getHandle(this, wrapperFn, ctx);
|
||||||
}
|
}
|
||||||
use(path: string, fn: (ctx: any) => any, opts?: RouteOpts) {
|
|
||||||
const route = new Route(path, '', opts);
|
|
||||||
route.run = fn;
|
|
||||||
this.add(route);
|
|
||||||
}
|
|
||||||
addRoute(route: Route) {
|
addRoute(route: Route) {
|
||||||
this.add(route);
|
this.add(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
Route = Route;
|
Route = Route;
|
||||||
route(opts: RouteOpts): Route<Required<RouteContext>>;
|
route(opts: RouteOpts): Route<Required<RouteContext>>;
|
||||||
route(path: string, key?: string): Route<Required<RouteContext>>;
|
route(path: string, key?: string): Route<Required<RouteContext>>;
|
||||||
|
|||||||
Reference in New Issue
Block a user