Compare commits
12 Commits
123d02f452
...
e7dca513f3
| Author | SHA1 | Date | |
|---|---|---|---|
| e7dca513f3 | |||
| 0f8986b491 | |||
| 911f03b4bd | |||
| 8a1aff4c50 | |||
| 3284a06ad5 | |||
| 7dcf53fb4f | |||
| 61add1aad1 | |||
| 2363617404 | |||
| f4372ae55f | |||
|
|
9b11ea5138 | ||
| 999397611c | |||
| 730f4c6eb9 |
5
.cnb.yml
5
.cnb.yml
@@ -17,10 +17,7 @@ $:
|
||||
- vscode
|
||||
- docker
|
||||
imports: !reference [.common_env, imports]
|
||||
# 开发环境启动后会执行的任务
|
||||
# stages:
|
||||
# - name: pnpm install
|
||||
# script: pnpm install
|
||||
stages: !reference [.dev_tempalte, stages]
|
||||
|
||||
.common_sync_to_gitea: &common_sync_to_gitea
|
||||
- <<: *common_env
|
||||
|
||||
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 };
|
||||
25
AGENTS.md
Normal file
25
AGENTS.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# @kevisual/router
|
||||
|
||||
## 是什么
|
||||
|
||||
`@kevisual/router` 是一个基于自定义的的轻量级路由框架,支持 TypeScript,适用于构建 API 服务。
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
npm install @kevisual/router
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
```ts
|
||||
import { App } from '@kevisual/router';
|
||||
const app = new App();
|
||||
app.listen(4002);
|
||||
|
||||
app.route({path:'demo', key: '01'})
|
||||
.define(async (ctx) => {
|
||||
ctx.body = '01';
|
||||
})
|
||||
.addTo(app);
|
||||
```
|
||||
15
STATIC.md
Normal file
15
STATIC.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## 兼容服务器静态资源代理
|
||||
|
||||
```ts
|
||||
import { App } from '@kevisual/router';
|
||||
|
||||
const app = new App();
|
||||
app.listen(4002);
|
||||
import { proxyRoute, initProxy } from '@kevisual/local-proxy/proxy.ts';
|
||||
initProxy({
|
||||
pagesDir: './demo',
|
||||
watch: true,
|
||||
});
|
||||
|
||||
app.onServerRequest(proxyRoute);
|
||||
```
|
||||
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.use(
|
||||
// 'demo',
|
||||
// async (ctx) => {
|
||||
// ctx.body = '01';
|
||||
// return ctx;
|
||||
// },
|
||||
// { key: '01' },
|
||||
// );
|
||||
|
||||
const route02 = new Route('demo', '02');
|
||||
route02.run = async (ctx) => {
|
||||
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);
|
||||
|
||||
```
|
||||
31
package.json
31
package.json
@@ -1,43 +1,51 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package",
|
||||
"name": "@kevisual/router",
|
||||
"version": "0.0.54",
|
||||
"version": "0.0.62",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"main": "./dist/router.js",
|
||||
"types": "./dist/router.d.ts",
|
||||
"scripts": {
|
||||
"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",
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src",
|
||||
"agent",
|
||||
"auto.ts",
|
||||
"mod.ts"
|
||||
],
|
||||
"keywords": [],
|
||||
"author": "abearxiong",
|
||||
"license": "MIT",
|
||||
"packageManager": "pnpm@10.28.0",
|
||||
"packageManager": "pnpm@10.28.1",
|
||||
"devDependencies": {
|
||||
"@kevisual/context": "^0.0.4",
|
||||
"@kevisual/js-filter": "^0.0.5",
|
||||
"@kevisual/local-proxy": "^0.0.8",
|
||||
"@kevisual/query": "^0.0.35",
|
||||
"@kevisual/use-config": "^1.0.28",
|
||||
"@opencode-ai/plugin": "^1.1.27",
|
||||
"@rollup/plugin-alias": "^6.0.0",
|
||||
"@rollup/plugin-commonjs": "29.0.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||
"@rollup/plugin-typescript": "^12.3.0",
|
||||
"@types/bun": "^1.3.6",
|
||||
"@types/node": "^25.0.8",
|
||||
"@types/node": "^25.0.9",
|
||||
"@types/send": "^1.2.1",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@types/xml2js": "^0.4.14",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"eventemitter3": "^5.0.4",
|
||||
"fast-glob": "^3.3.3",
|
||||
"nanoid": "^5.1.6",
|
||||
"rollup": "^4.55.1",
|
||||
"path-to-regexp": "^8.3.0",
|
||||
"rollup": "^4.55.2",
|
||||
"rollup-plugin-dts": "^6.3.0",
|
||||
"send": "^1.2.1",
|
||||
"ts-loader": "^9.5.4",
|
||||
"ts-node": "^10.9.2",
|
||||
"tslib": "^2.8.1",
|
||||
@@ -45,16 +53,15 @@
|
||||
"typescript": "^5.9.3",
|
||||
"ws": "npm:@kevisual/ws",
|
||||
"xml2js": "^0.6.2",
|
||||
"zod": "^4.3.5",
|
||||
"@kevisual/js-filter": "^0.0.4",
|
||||
"path-to-regexp": "^8.3.0",
|
||||
"send": "^1.2.1"
|
||||
"zod": "^4.3.5"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/abearxiong/kevisual-router.git"
|
||||
},
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"hono": "^4.11.4"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
@@ -74,6 +81,8 @@
|
||||
"require": "./dist/router-simple.js",
|
||||
"types": "./dist/router-simple.d.ts"
|
||||
},
|
||||
"./opencode": "./dist/opencode.js",
|
||||
"./skill": "./dist/app.js",
|
||||
"./define": {
|
||||
"import": "./dist/router-define.js",
|
||||
"require": "./dist/router-define.js",
|
||||
|
||||
457
pnpm-lock.yaml
generated
457
pnpm-lock.yaml
generated
@@ -7,34 +7,47 @@ settings:
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
hono:
|
||||
specifier: ^4.11.4
|
||||
version: 4.11.4
|
||||
devDependencies:
|
||||
'@kevisual/js-filter':
|
||||
'@kevisual/context':
|
||||
specifier: ^0.0.4
|
||||
version: 0.0.4
|
||||
'@kevisual/js-filter':
|
||||
specifier: ^0.0.5
|
||||
version: 0.0.5
|
||||
'@kevisual/local-proxy':
|
||||
specifier: ^0.0.8
|
||||
version: 0.0.8
|
||||
'@kevisual/query':
|
||||
specifier: ^0.0.35
|
||||
version: 0.0.35
|
||||
'@kevisual/use-config':
|
||||
specifier: ^1.0.28
|
||||
version: 1.0.28(dotenv@17.2.3)
|
||||
'@opencode-ai/plugin':
|
||||
specifier: ^1.1.27
|
||||
version: 1.1.27
|
||||
'@rollup/plugin-alias':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(rollup@4.55.1)
|
||||
version: 6.0.0(rollup@4.55.2)
|
||||
'@rollup/plugin-commonjs':
|
||||
specifier: 29.0.0
|
||||
version: 29.0.0(rollup@4.55.1)
|
||||
version: 29.0.0(rollup@4.55.2)
|
||||
'@rollup/plugin-node-resolve':
|
||||
specifier: ^16.0.3
|
||||
version: 16.0.3(rollup@4.55.1)
|
||||
version: 16.0.3(rollup@4.55.2)
|
||||
'@rollup/plugin-typescript':
|
||||
specifier: ^12.3.0
|
||||
version: 12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.9.3)
|
||||
version: 12.3.0(rollup@4.55.2)(tslib@2.8.1)(typescript@5.9.3)
|
||||
'@types/bun':
|
||||
specifier: ^1.3.6
|
||||
version: 1.3.6
|
||||
'@types/node':
|
||||
specifier: ^25.0.8
|
||||
version: 25.0.8
|
||||
specifier: ^25.0.9
|
||||
version: 25.0.9
|
||||
'@types/send':
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
@@ -45,8 +58,11 @@ importers:
|
||||
specifier: ^0.4.14
|
||||
version: 0.4.14
|
||||
eventemitter3:
|
||||
specifier: ^5.0.1
|
||||
version: 5.0.1
|
||||
specifier: ^5.0.4
|
||||
version: 5.0.4
|
||||
fast-glob:
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
nanoid:
|
||||
specifier: ^5.1.6
|
||||
version: 5.1.6
|
||||
@@ -54,11 +70,11 @@ importers:
|
||||
specifier: ^8.3.0
|
||||
version: 8.3.0
|
||||
rollup:
|
||||
specifier: ^4.55.1
|
||||
version: 4.55.1
|
||||
specifier: ^4.55.2
|
||||
version: 4.55.2
|
||||
rollup-plugin-dts:
|
||||
specifier: ^6.3.0
|
||||
version: 6.3.0(rollup@4.55.1)(typescript@5.9.3)
|
||||
version: 6.3.0(rollup@4.55.2)(typescript@5.9.3)
|
||||
send:
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
@@ -67,7 +83,7 @@ importers:
|
||||
version: 9.5.4(typescript@5.9.3)(webpack@5.104.1)
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@25.0.8)(typescript@5.9.3)
|
||||
version: 10.9.2(@types/node@25.0.9)(typescript@5.9.3)
|
||||
tslib:
|
||||
specifier: ^2.8.1
|
||||
version: 2.8.1
|
||||
@@ -98,7 +114,7 @@ importers:
|
||||
version: 1.1.1
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@25.0.8)(typescript@5.9.3)
|
||||
version: 10.9.2(@types/node@25.0.9)(typescript@5.9.3)
|
||||
typescript:
|
||||
specifier: ^5.5.4
|
||||
version: 5.9.3
|
||||
@@ -292,8 +308,14 @@ packages:
|
||||
'@jridgewell/trace-mapping@0.3.9':
|
||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||
|
||||
'@kevisual/js-filter@0.0.4':
|
||||
resolution: {integrity: sha512-ncwQmJWqpmK4q2KWSnYQJDxv20gTOb2BZ2rusvBf6H173nddhz/G2geDzgK40THragPOpvZywgVQbFNEjKjOzA==}
|
||||
'@kevisual/context@0.0.4':
|
||||
resolution: {integrity: sha512-HJeLeZQLU+7tCluSfOyvkgKLs0HjCZrdJlZgEgKRSa8XTwZfMAUt6J7qZTbrZAHBlPtX68EPu/PI8JMCeu3WAQ==}
|
||||
|
||||
'@kevisual/js-filter@0.0.5':
|
||||
resolution: {integrity: sha512-+S+Sf3K/aP6XtZI2s7TgKOr35UuvUvtpJ9YDW30a+mY0/N8gRuzyKhieBzQN7Ykayzz70uoMavBXut2rUlLgzw==}
|
||||
|
||||
'@kevisual/load@0.0.6':
|
||||
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
|
||||
|
||||
'@kevisual/local-proxy@0.0.8':
|
||||
resolution: {integrity: sha512-VX/P+6/Cc8ruqp34ag6gVX073BchUmf5VNZcTV/6MJtjrNE76G8V6TLpBE8bywLnrqyRtFLIspk4QlH8up9B5Q==}
|
||||
@@ -301,10 +323,33 @@ packages:
|
||||
'@kevisual/query@0.0.35':
|
||||
resolution: {integrity: sha512-80dyy2LMCmEC72g+X4QWUKlZErhawQPgnGSBNR4yhrBcFgHIJQ14LR1Z+bS5S1I7db+1PDNpaxBTjIaoYoXunw==}
|
||||
|
||||
'@kevisual/use-config@1.0.28':
|
||||
resolution: {integrity: sha512-ngF+LDbjxpXWrZNmnShIKF/jPpAa+ezV+DcgoZIIzHlRnIjE+rr9sLkN/B7WJbiH9C/j1tQXOILY8ujBqILrow==}
|
||||
peerDependencies:
|
||||
dotenv: ^17
|
||||
|
||||
'@kevisual/ws@8.0.0':
|
||||
resolution: {integrity: sha512-jlFxSlXUEz93cFW+UYT5BXv/rFVgiMQnIfqRYZ0gj1hSP8PMGRqMqUoHSLfKvfRRS4jseLSvTTeEKSQpZJtURg==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@nodelib/fs.stat@2.0.5':
|
||||
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':
|
||||
resolution: {integrity: sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
@@ -354,128 +399,128 @@ packages:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.55.1':
|
||||
resolution: {integrity: sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==}
|
||||
'@rollup/rollup-android-arm-eabi@4.55.2':
|
||||
resolution: {integrity: sha512-21J6xzayjy3O6NdnlO6aXi/urvSRjm6nCI6+nF6ra2YofKruGixN9kfT+dt55HVNwfDmpDHJcaS3JuP/boNnlA==}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-android-arm64@4.55.1':
|
||||
resolution: {integrity: sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==}
|
||||
'@rollup/rollup-android-arm64@4.55.2':
|
||||
resolution: {integrity: sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.55.1':
|
||||
resolution: {integrity: sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==}
|
||||
'@rollup/rollup-darwin-arm64@4.55.2':
|
||||
resolution: {integrity: sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.55.1':
|
||||
resolution: {integrity: sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==}
|
||||
'@rollup/rollup-darwin-x64@4.55.2':
|
||||
resolution: {integrity: sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.55.1':
|
||||
resolution: {integrity: sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==}
|
||||
'@rollup/rollup-freebsd-arm64@4.55.2':
|
||||
resolution: {integrity: sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.55.1':
|
||||
resolution: {integrity: sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==}
|
||||
'@rollup/rollup-freebsd-x64@4.55.2':
|
||||
resolution: {integrity: sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.55.1':
|
||||
resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==}
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.55.2':
|
||||
resolution: {integrity: sha512-AEXMESUDWWGqD6LwO/HkqCZgUE1VCJ1OhbvYGsfqX2Y6w5quSXuyoy/Fg3nRqiwro+cJYFxiw5v4kB2ZDLhxrw==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.55.1':
|
||||
resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==}
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.55.2':
|
||||
resolution: {integrity: sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==}
|
||||
'@rollup/rollup-linux-arm64-gnu@4.55.2':
|
||||
resolution: {integrity: sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==}
|
||||
'@rollup/rollup-linux-arm64-musl@4.55.2':
|
||||
resolution: {integrity: sha512-s3KoWVNnye9mm/2WpOZ3JeUiediUVw6AvY/H7jNA6qgKA2V2aM25lMkVarTDfiicn/DLq3O0a81jncXszoyCFA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==}
|
||||
'@rollup/rollup-linux-loong64-gnu@4.55.2':
|
||||
resolution: {integrity: sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==}
|
||||
'@rollup/rollup-linux-loong64-musl@4.55.2':
|
||||
resolution: {integrity: sha512-qSlWiXnVaS/ceqXNfnoFZh4IiCA0EwvCivivTGbEu1qv2o+WTHpn1zNmCTAoOG5QaVr2/yhCoLScQtc/7RxshA==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==}
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.55.2':
|
||||
resolution: {integrity: sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==}
|
||||
'@rollup/rollup-linux-ppc64-musl@4.55.2':
|
||||
resolution: {integrity: sha512-g+0ZLMook31iWV4PvqKU0i9E78gaZgYpSrYPed/4Bu+nGTgfOPtfs1h11tSSRPXSjC5EzLTjV/1A7L2Vr8pJoQ==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==}
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.55.2':
|
||||
resolution: {integrity: sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==}
|
||||
'@rollup/rollup-linux-riscv64-musl@4.55.2':
|
||||
resolution: {integrity: sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==}
|
||||
'@rollup/rollup-linux-s390x-gnu@4.55.2':
|
||||
resolution: {integrity: sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==}
|
||||
'@rollup/rollup-linux-x64-gnu@4.55.2':
|
||||
resolution: {integrity: sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==}
|
||||
'@rollup/rollup-linux-x64-musl@4.55.2':
|
||||
resolution: {integrity: sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.55.1':
|
||||
resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==}
|
||||
'@rollup/rollup-openbsd-x64@4.55.2':
|
||||
resolution: {integrity: sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.55.1':
|
||||
resolution: {integrity: sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==}
|
||||
'@rollup/rollup-openharmony-arm64@4.55.2':
|
||||
resolution: {integrity: sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.55.1':
|
||||
resolution: {integrity: sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==}
|
||||
'@rollup/rollup-win32-arm64-msvc@4.55.2':
|
||||
resolution: {integrity: sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.55.1':
|
||||
resolution: {integrity: sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==}
|
||||
'@rollup/rollup-win32-ia32-msvc@4.55.2':
|
||||
resolution: {integrity: sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==}
|
||||
'@rollup/rollup-win32-x64-gnu@4.55.2':
|
||||
resolution: {integrity: sha512-KvXsBvp13oZz9JGe5NYS7FNizLe99Ny+W8ETsuCyjXiKdiGrcz2/J/N8qxZ/RSwivqjQguug07NLHqrIHrqfYw==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.55.1':
|
||||
resolution: {integrity: sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==}
|
||||
'@rollup/rollup-win32-x64-msvc@4.55.2':
|
||||
resolution: {integrity: sha512-xNO+fksQhsAckRtDSPWaMeT1uIM+JrDRXlerpnWNXhn1TdB3YZ6uKBMBTKP0eX9XtYEP978hHk1f8332i2AW8Q==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
@@ -506,8 +551,8 @@ packages:
|
||||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
'@types/node@25.0.8':
|
||||
resolution: {integrity: sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==}
|
||||
'@types/node@25.0.9':
|
||||
resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==}
|
||||
|
||||
'@types/resolve@1.20.2':
|
||||
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
|
||||
@@ -681,6 +726,10 @@ packages:
|
||||
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
|
||||
dotenv@17.2.3:
|
||||
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
@@ -733,8 +782,8 @@ packages:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
eventemitter3@5.0.1:
|
||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||
eventemitter3@5.0.4:
|
||||
resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
|
||||
|
||||
events@3.3.0:
|
||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||
@@ -743,9 +792,16 @@ packages:
|
||||
fast-deep-equal@3.1.3:
|
||||
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:
|
||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||
|
||||
fastq@1.20.1:
|
||||
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
|
||||
|
||||
fdir@6.5.0:
|
||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -774,6 +830,10 @@ packages:
|
||||
get-tsconfig@4.13.0:
|
||||
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:
|
||||
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
|
||||
|
||||
@@ -788,6 +848,10 @@ packages:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
hono@4.11.4:
|
||||
resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==}
|
||||
engines: {node: '>=16.9.0'}
|
||||
|
||||
http-errors@2.0.1:
|
||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@@ -799,6 +863,14 @@ packages:
|
||||
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||
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:
|
||||
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
||||
|
||||
@@ -835,6 +907,10 @@ packages:
|
||||
merge-stream@2.0.0:
|
||||
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:
|
||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||
engines: {node: '>=8.6'}
|
||||
@@ -890,6 +966,9 @@ packages:
|
||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
randombytes@2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
|
||||
@@ -909,6 +988,10 @@ packages:
|
||||
engines: {node: '>= 0.4'}
|
||||
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:
|
||||
resolution: {integrity: sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA==}
|
||||
engines: {node: '>=16'}
|
||||
@@ -916,11 +999,14 @@ packages:
|
||||
rollup: ^3.29.4 || ^4
|
||||
typescript: ^4.5 || ^5.0
|
||||
|
||||
rollup@4.55.1:
|
||||
resolution: {integrity: sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==}
|
||||
rollup@4.55.2:
|
||||
resolution: {integrity: sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
|
||||
run-parallel@1.2.0:
|
||||
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
|
||||
|
||||
safe-buffer@5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
|
||||
@@ -1082,6 +1168,9 @@ packages:
|
||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
zod@4.1.8:
|
||||
resolution: {integrity: sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ==}
|
||||
|
||||
zod@4.3.5:
|
||||
resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==}
|
||||
|
||||
@@ -1203,7 +1292,13 @@ snapshots:
|
||||
'@jridgewell/resolve-uri': 3.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
'@kevisual/js-filter@0.0.4': {}
|
||||
'@kevisual/context@0.0.4': {}
|
||||
|
||||
'@kevisual/js-filter@0.0.5': {}
|
||||
|
||||
'@kevisual/load@0.0.6':
|
||||
dependencies:
|
||||
eventemitter3: 5.0.4
|
||||
|
||||
'@kevisual/local-proxy@0.0.8': {}
|
||||
|
||||
@@ -1211,15 +1306,39 @@ snapshots:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@kevisual/use-config@1.0.28(dotenv@17.2.3)':
|
||||
dependencies:
|
||||
'@kevisual/load': 0.0.6
|
||||
dotenv: 17.2.3
|
||||
|
||||
'@kevisual/ws@8.0.0': {}
|
||||
|
||||
'@rollup/plugin-alias@6.0.0(rollup@4.55.1)':
|
||||
optionalDependencies:
|
||||
rollup: 4.55.1
|
||||
|
||||
'@rollup/plugin-commonjs@29.0.0(rollup@4.55.1)':
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.55.1)
|
||||
'@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
|
||||
|
||||
'@opencode-ai/sdk@1.1.27': {}
|
||||
|
||||
'@rollup/plugin-alias@6.0.0(rollup@4.55.2)':
|
||||
optionalDependencies:
|
||||
rollup: 4.55.2
|
||||
|
||||
'@rollup/plugin-commonjs@29.0.0(rollup@4.55.2)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.55.2)
|
||||
commondir: 1.0.1
|
||||
estree-walker: 2.0.2
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -1227,108 +1346,108 @@ snapshots:
|
||||
magic-string: 0.30.21
|
||||
picomatch: 4.0.3
|
||||
optionalDependencies:
|
||||
rollup: 4.55.1
|
||||
rollup: 4.55.2
|
||||
|
||||
'@rollup/plugin-node-resolve@16.0.3(rollup@4.55.1)':
|
||||
'@rollup/plugin-node-resolve@16.0.3(rollup@4.55.2)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.55.1)
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.55.2)
|
||||
'@types/resolve': 1.20.2
|
||||
deepmerge: 4.3.1
|
||||
is-module: 1.0.0
|
||||
resolve: 1.22.11
|
||||
optionalDependencies:
|
||||
rollup: 4.55.1
|
||||
rollup: 4.55.2
|
||||
|
||||
'@rollup/plugin-typescript@12.3.0(rollup@4.55.1)(tslib@2.8.1)(typescript@5.9.3)':
|
||||
'@rollup/plugin-typescript@12.3.0(rollup@4.55.2)(tslib@2.8.1)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.55.1)
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.55.2)
|
||||
resolve: 1.22.11
|
||||
typescript: 5.9.3
|
||||
optionalDependencies:
|
||||
rollup: 4.55.1
|
||||
rollup: 4.55.2
|
||||
tslib: 2.8.1
|
||||
|
||||
'@rollup/pluginutils@5.3.0(rollup@4.55.1)':
|
||||
'@rollup/pluginutils@5.3.0(rollup@4.55.2)':
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
estree-walker: 2.0.2
|
||||
picomatch: 4.0.3
|
||||
optionalDependencies:
|
||||
rollup: 4.55.1
|
||||
rollup: 4.55.2
|
||||
|
||||
'@rollup/rollup-android-arm-eabi@4.55.1':
|
||||
'@rollup/rollup-android-arm-eabi@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-android-arm64@4.55.1':
|
||||
'@rollup/rollup-android-arm64@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-arm64@4.55.1':
|
||||
'@rollup/rollup-darwin-arm64@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-darwin-x64@4.55.1':
|
||||
'@rollup/rollup-darwin-x64@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-arm64@4.55.1':
|
||||
'@rollup/rollup-freebsd-arm64@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-freebsd-x64@4.55.1':
|
||||
'@rollup/rollup-freebsd-x64@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.55.1':
|
||||
'@rollup/rollup-linux-arm-gnueabihf@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.55.1':
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.55.1':
|
||||
'@rollup/rollup-linux-arm64-gnu@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.55.1':
|
||||
'@rollup/rollup-linux-arm64-musl@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.55.1':
|
||||
'@rollup/rollup-linux-loong64-gnu@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.55.1':
|
||||
'@rollup/rollup-linux-loong64-musl@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.55.1':
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.55.1':
|
||||
'@rollup/rollup-linux-ppc64-musl@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.55.1':
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.55.1':
|
||||
'@rollup/rollup-linux-riscv64-musl@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.55.1':
|
||||
'@rollup/rollup-linux-s390x-gnu@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.55.1':
|
||||
'@rollup/rollup-linux-x64-gnu@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.55.1':
|
||||
'@rollup/rollup-linux-x64-musl@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.55.1':
|
||||
'@rollup/rollup-openbsd-x64@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-openharmony-arm64@4.55.1':
|
||||
'@rollup/rollup-openharmony-arm64@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-arm64-msvc@4.55.1':
|
||||
'@rollup/rollup-win32-arm64-msvc@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-ia32-msvc@4.55.1':
|
||||
'@rollup/rollup-win32-ia32-msvc@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-gnu@4.55.1':
|
||||
'@rollup/rollup-win32-x64-gnu@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@rollup/rollup-win32-x64-msvc@4.55.1':
|
||||
'@rollup/rollup-win32-x64-msvc@4.55.2':
|
||||
optional: true
|
||||
|
||||
'@tsconfig/node10@1.0.12': {}
|
||||
@@ -1357,7 +1476,7 @@ snapshots:
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/node@25.0.8':
|
||||
'@types/node@25.0.9':
|
||||
dependencies:
|
||||
undici-types: 7.16.0
|
||||
|
||||
@@ -1365,15 +1484,15 @@ snapshots:
|
||||
|
||||
'@types/send@1.2.1':
|
||||
dependencies:
|
||||
'@types/node': 25.0.8
|
||||
'@types/node': 25.0.9
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
dependencies:
|
||||
'@types/node': 25.0.8
|
||||
'@types/node': 25.0.9
|
||||
|
||||
'@types/xml2js@0.4.14':
|
||||
dependencies:
|
||||
'@types/node': 25.0.8
|
||||
'@types/node': 25.0.9
|
||||
|
||||
'@webassemblyjs/ast@1.14.1':
|
||||
dependencies:
|
||||
@@ -1505,7 +1624,7 @@ snapshots:
|
||||
|
||||
bun-types@1.3.6:
|
||||
dependencies:
|
||||
'@types/node': 25.0.8
|
||||
'@types/node': 25.0.9
|
||||
|
||||
caniuse-lite@1.0.30001761: {}
|
||||
|
||||
@@ -1540,6 +1659,8 @@ snapshots:
|
||||
|
||||
diff@4.0.2: {}
|
||||
|
||||
dotenv@17.2.3: {}
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
electron-to-chromium@1.5.267: {}
|
||||
@@ -1603,14 +1724,26 @@ snapshots:
|
||||
|
||||
etag@1.8.1: {}
|
||||
|
||||
eventemitter3@5.0.1: {}
|
||||
eventemitter3@5.0.4: {}
|
||||
|
||||
events@3.3.0: {}
|
||||
|
||||
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: {}
|
||||
|
||||
fastq@1.20.1:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
|
||||
fdir@6.5.0(picomatch@4.0.3):
|
||||
optionalDependencies:
|
||||
picomatch: 4.0.3
|
||||
@@ -1630,6 +1763,10 @@ snapshots:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
|
||||
glob-parent@5.1.2:
|
||||
dependencies:
|
||||
is-glob: 4.0.3
|
||||
|
||||
glob-to-regexp@0.4.1: {}
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
@@ -1640,6 +1777,8 @@ snapshots:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
hono@4.11.4: {}
|
||||
|
||||
http-errors@2.0.1:
|
||||
dependencies:
|
||||
depd: 2.0.0
|
||||
@@ -1654,6 +1793,12 @@ snapshots:
|
||||
dependencies:
|
||||
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-number@7.0.0: {}
|
||||
@@ -1664,7 +1809,7 @@ snapshots:
|
||||
|
||||
jest-worker@27.5.1:
|
||||
dependencies:
|
||||
'@types/node': 25.0.8
|
||||
'@types/node': 25.0.9
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
|
||||
@@ -1685,6 +1830,8 @@ snapshots:
|
||||
|
||||
merge-stream@2.0.0: {}
|
||||
|
||||
merge2@1.4.1: {}
|
||||
|
||||
micromatch@4.0.8:
|
||||
dependencies:
|
||||
braces: 3.0.3
|
||||
@@ -1724,6 +1871,8 @@ snapshots:
|
||||
|
||||
picomatch@4.0.3: {}
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
randombytes@2.1.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
@@ -1740,45 +1889,51 @@ snapshots:
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
|
||||
rollup-plugin-dts@6.3.0(rollup@4.55.1)(typescript@5.9.3):
|
||||
reusify@1.1.0: {}
|
||||
|
||||
rollup-plugin-dts@6.3.0(rollup@4.55.2)(typescript@5.9.3):
|
||||
dependencies:
|
||||
magic-string: 0.30.21
|
||||
rollup: 4.55.1
|
||||
rollup: 4.55.2
|
||||
typescript: 5.9.3
|
||||
optionalDependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
|
||||
rollup@4.55.1:
|
||||
rollup@4.55.2:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
optionalDependencies:
|
||||
'@rollup/rollup-android-arm-eabi': 4.55.1
|
||||
'@rollup/rollup-android-arm64': 4.55.1
|
||||
'@rollup/rollup-darwin-arm64': 4.55.1
|
||||
'@rollup/rollup-darwin-x64': 4.55.1
|
||||
'@rollup/rollup-freebsd-arm64': 4.55.1
|
||||
'@rollup/rollup-freebsd-x64': 4.55.1
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.55.1
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.55.1
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-arm64-musl': 4.55.1
|
||||
'@rollup/rollup-linux-loong64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-loong64-musl': 4.55.1
|
||||
'@rollup/rollup-linux-ppc64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-ppc64-musl': 4.55.1
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-riscv64-musl': 4.55.1
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-x64-gnu': 4.55.1
|
||||
'@rollup/rollup-linux-x64-musl': 4.55.1
|
||||
'@rollup/rollup-openbsd-x64': 4.55.1
|
||||
'@rollup/rollup-openharmony-arm64': 4.55.1
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.55.1
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.55.1
|
||||
'@rollup/rollup-win32-x64-gnu': 4.55.1
|
||||
'@rollup/rollup-win32-x64-msvc': 4.55.1
|
||||
'@rollup/rollup-android-arm-eabi': 4.55.2
|
||||
'@rollup/rollup-android-arm64': 4.55.2
|
||||
'@rollup/rollup-darwin-arm64': 4.55.2
|
||||
'@rollup/rollup-darwin-x64': 4.55.2
|
||||
'@rollup/rollup-freebsd-arm64': 4.55.2
|
||||
'@rollup/rollup-freebsd-x64': 4.55.2
|
||||
'@rollup/rollup-linux-arm-gnueabihf': 4.55.2
|
||||
'@rollup/rollup-linux-arm-musleabihf': 4.55.2
|
||||
'@rollup/rollup-linux-arm64-gnu': 4.55.2
|
||||
'@rollup/rollup-linux-arm64-musl': 4.55.2
|
||||
'@rollup/rollup-linux-loong64-gnu': 4.55.2
|
||||
'@rollup/rollup-linux-loong64-musl': 4.55.2
|
||||
'@rollup/rollup-linux-ppc64-gnu': 4.55.2
|
||||
'@rollup/rollup-linux-ppc64-musl': 4.55.2
|
||||
'@rollup/rollup-linux-riscv64-gnu': 4.55.2
|
||||
'@rollup/rollup-linux-riscv64-musl': 4.55.2
|
||||
'@rollup/rollup-linux-s390x-gnu': 4.55.2
|
||||
'@rollup/rollup-linux-x64-gnu': 4.55.2
|
||||
'@rollup/rollup-linux-x64-musl': 4.55.2
|
||||
'@rollup/rollup-openbsd-x64': 4.55.2
|
||||
'@rollup/rollup-openharmony-arm64': 4.55.2
|
||||
'@rollup/rollup-win32-arm64-msvc': 4.55.2
|
||||
'@rollup/rollup-win32-ia32-msvc': 4.55.2
|
||||
'@rollup/rollup-win32-x64-gnu': 4.55.2
|
||||
'@rollup/rollup-win32-x64-msvc': 4.55.2
|
||||
fsevents: 2.3.3
|
||||
|
||||
run-parallel@1.2.0:
|
||||
dependencies:
|
||||
queue-microtask: 1.2.3
|
||||
|
||||
safe-buffer@5.2.1: {}
|
||||
|
||||
sax@1.4.3: {}
|
||||
@@ -1869,14 +2024,14 @@ snapshots:
|
||||
typescript: 5.9.3
|
||||
webpack: 5.104.1
|
||||
|
||||
ts-node@10.9.2(@types/node@25.0.8)(typescript@5.9.3):
|
||||
ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@tsconfig/node10': 1.0.12
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/node': 25.0.8
|
||||
'@types/node': 25.0.9
|
||||
acorn: 8.15.0
|
||||
acorn-walk: 8.3.4
|
||||
arg: 4.1.3
|
||||
@@ -1956,4 +2111,6 @@ snapshots:
|
||||
|
||||
yn@3.1.1: {}
|
||||
|
||||
zod@4.1.8: {}
|
||||
|
||||
zod@4.3.5: {}
|
||||
|
||||
174
readme.md
174
readme.md
@@ -1,5 +1,9 @@
|
||||
# router
|
||||
|
||||
一个轻量级的路由框架,支持链式调用、中间件、嵌套路由等功能。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```ts
|
||||
import { App } from '@kevisual/router';
|
||||
|
||||
@@ -7,30 +11,178 @@ const app = new App();
|
||||
app.listen(4002);
|
||||
|
||||
app
|
||||
.route({path:'demo', key: '02})
|
||||
.route({ path: 'demo', key: '02' })
|
||||
.define(async (ctx) => {
|
||||
ctx.body = '02';
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route('demo', '03')
|
||||
.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);
|
||||
import { proxyRoute, initProxy } from '@kevisual/local-proxy/proxy.ts';
|
||||
initProxy({
|
||||
pagesDir: './demo',
|
||||
watch: true,
|
||||
});
|
||||
|
||||
app.onServerRequest(proxyRoute);
|
||||
```
|
||||
// 基本路由
|
||||
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**,错误信息中会包含找不到的中间件列表。
|
||||
|
||||
@@ -126,4 +126,26 @@ export default [
|
||||
},
|
||||
plugins: [dts()],
|
||||
},
|
||||
{
|
||||
input: 'src/opencode.ts',
|
||||
output: {
|
||||
file: 'dist/opencode.js',
|
||||
format: 'es',
|
||||
},
|
||||
plugins: [
|
||||
resolve({
|
||||
browser: true,
|
||||
}),
|
||||
commonjs(),
|
||||
typescript(),
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/opencode.ts',
|
||||
output: {
|
||||
file: 'dist/opencode.d.ts',
|
||||
format: 'es',
|
||||
},
|
||||
plugins: [dts()],
|
||||
},
|
||||
];
|
||||
|
||||
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 { HandleCtx } from './server/server-base.ts';
|
||||
import { ServerType } from './server/server-type.ts';
|
||||
import { CustomError } from './result/error.ts';
|
||||
import { handleServer } from './server/handle-server.ts';
|
||||
import { IncomingMessage, ServerResponse } from 'http';
|
||||
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 的处理
|
||||
* U - Route Context的扩展类型
|
||||
*/
|
||||
export class App<U = {}> {
|
||||
appId: string;
|
||||
export class App<U = {}> extends QueryRouter {
|
||||
declare appId: string;
|
||||
router: QueryRouter;
|
||||
server: ServerType;
|
||||
constructor(opts?: AppOptions<U>) {
|
||||
const router = opts?.router || new QueryRouter();
|
||||
super();
|
||||
const router = this;
|
||||
let server = opts?.server;
|
||||
if (!server) {
|
||||
const serverOptions = opts?.serverOptions || {};
|
||||
@@ -64,15 +64,9 @@ export class App<U = {}> {
|
||||
// @ts-ignore
|
||||
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) {
|
||||
this.router.add(route);
|
||||
super.add(route);
|
||||
}
|
||||
add = this.addRoute;
|
||||
|
||||
Route = Route;
|
||||
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 }) {
|
||||
const router = this.router;
|
||||
return await router.call(message, ctx);
|
||||
return await super.call(message, ctx);
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
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);
|
||||
async run(msg: { id?: string, path?: string; key?: string; payload?: any }, ctx?: Partial<AppRouteContext<U>> & { [key: string]: any }) {
|
||||
return await super.run(msg, ctx);
|
||||
}
|
||||
static handleRequest(req: IncomingMessage, res: ServerResponse) {
|
||||
return handleServer(req, res);
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
export { Route, QueryRouter, QueryRouterServer, Mini } from './route.ts';
|
||||
|
||||
export type { Rule, Schema } from './validator/index.ts';
|
||||
export type { Rule, Schema, } from './validator/index.ts';
|
||||
|
||||
export { createSchema } from './validator/index.ts';
|
||||
|
||||
export type { RouteContext, RouteOpts } from './route.ts';
|
||||
export type { RouteContext, RouteOpts, RouteMiddleware } from './route.ts';
|
||||
|
||||
export type { Run, Skill } from './route.ts';
|
||||
|
||||
export { createSkill } from './route.ts';
|
||||
export { createSkill, tool } from './route.ts';
|
||||
|
||||
export { CustomError } from './result/error.ts';
|
||||
|
||||
export * from './router-define.ts';
|
||||
|
||||
export { MockProcess } from './utils/listen-process.ts'
|
||||
// --- 以上同步更新至 browser.ts ---
|
||||
@@ -8,12 +8,15 @@ export type { RouteContext, RouteOpts, RouteMiddleware } from './route.ts';
|
||||
|
||||
export type { Run, Skill } from './route.ts';
|
||||
|
||||
export { createSkill } from './route.ts';
|
||||
export { createSkill, tool } from './route.ts';
|
||||
|
||||
export { CustomError } from './result/error.ts';
|
||||
|
||||
export * from './router-define.ts';
|
||||
|
||||
export { MockProcess } from './utils/listen-process.ts'
|
||||
// --- 以上同步更新至 browser.ts ---
|
||||
|
||||
export { ServerNode, handleServer } from './server/index.ts';
|
||||
|
||||
export { App } from './app.ts';
|
||||
|
||||
108
src/opencode.ts
Normal file
108
src/opencode.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { useContextKey } from '@kevisual/context'
|
||||
import { createSkill, type QueryRouterServer, tool, type QueryRouter, type Skill } from './route.ts'
|
||||
import { type App } from './app.ts'
|
||||
import { type Plugin } from "@opencode-ai/plugin"
|
||||
|
||||
import { filter } from '@kevisual/js-filter';
|
||||
export const addCallFn = (app: App) => {
|
||||
app.route({
|
||||
path: 'call',
|
||||
key: '',
|
||||
description: '调用',
|
||||
middleware: ['auth'],
|
||||
metadata: {
|
||||
tags: ['opencode'],
|
||||
...createSkill({
|
||||
skill: 'call-app',
|
||||
title: '调用app应用',
|
||||
summary: '调用router的应用, 参数path, key, payload',
|
||||
args: {
|
||||
path: tool.schema.string().describe('应用路径,例如 cnb'),
|
||||
key: tool.schema.string().optional().describe('应用key,例如 list-repos'),
|
||||
payload: tool.schema.object({}).optional().describe('调用参数'),
|
||||
}
|
||||
})
|
||||
},
|
||||
}).define(async (ctx) => {
|
||||
const { path, key = '' } = ctx.query;
|
||||
if (!path) {
|
||||
ctx.throw('路径path不能为空');
|
||||
}
|
||||
const res = await ctx.run({ path, key, payload: ctx.query.payload || {} }, {
|
||||
...ctx
|
||||
});
|
||||
ctx.forward(res);
|
||||
}).addTo(app)
|
||||
}
|
||||
export const createRouterAgentPluginFn = (opts?: {
|
||||
router?: App | QueryRouterServer,
|
||||
//** 过滤比如,WHERE metadata.tags includes 'opencode' */
|
||||
query?: string
|
||||
}) => {
|
||||
let router = opts?.router
|
||||
if (!router) {
|
||||
const app = useContextKey<App>('app')
|
||||
router = app
|
||||
}
|
||||
if (!router) {
|
||||
throw new Error('Router 参数缺失')
|
||||
}
|
||||
if (!router.hasRoute('call', '')) {
|
||||
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 = _routes.filter(r => {
|
||||
const metadata = r.metadata as Skill
|
||||
if (metadata && metadata.tags && metadata.tags.includes('opencode')) {
|
||||
return !!metadata.skill
|
||||
}
|
||||
return false
|
||||
})
|
||||
// opencode run "查看系统信息"
|
||||
const AgentPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
|
||||
return {
|
||||
'tool': {
|
||||
...routes.reduce((acc, route) => {
|
||||
const metadata = route.metadata as Skill
|
||||
acc[metadata.skill!] = {
|
||||
name: metadata.title || metadata.skill,
|
||||
description: metadata.summary || '',
|
||||
args: metadata.args || {},
|
||||
async execute(args: Record<string, any>) {
|
||||
const res = await router.run({
|
||||
path: route.path,
|
||||
key: route.key,
|
||||
payload: args
|
||||
},
|
||||
{ appId: router.appId! });
|
||||
if (res.code === 200) {
|
||||
if (res.data?.content) {
|
||||
return res.data.content;
|
||||
}
|
||||
if (res.data?.final) {
|
||||
return '调用程序成功';
|
||||
}
|
||||
const str = JSON.stringify(res.data || res, null, 2);
|
||||
if (str.length > 10000) {
|
||||
return str.slice(0, 10000) + '... (truncated)';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
console.error('调用出错', res);
|
||||
return `Error: ${res?.message || '无法获取结果'}`;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, any>)
|
||||
},
|
||||
'tool.execute.before': async (opts) => {
|
||||
// console.log('CnbPlugin: tool.execute.before', opts.tool);
|
||||
// delete toolSkills['cnb-login-verify']
|
||||
}
|
||||
}
|
||||
}
|
||||
return AgentPlugin
|
||||
}
|
||||
@@ -9,10 +9,10 @@ export class CustomError extends Error {
|
||||
this.name = 'CustomError';
|
||||
if (typeof code === 'number') {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.message = message!;
|
||||
} else {
|
||||
this.code = 500;
|
||||
this.message = code;
|
||||
this.message = code!;
|
||||
}
|
||||
this.tips = tips;
|
||||
// 这一步可不写,默认会保存堆栈追踪信息到自定义错误构造函数之前,
|
||||
|
||||
19
src/route.ts
19
src/route.ts
@@ -60,7 +60,7 @@ export type RouteContext<T = { code?: number }, S = any> = {
|
||||
needSerialize?: boolean;
|
||||
} & T;
|
||||
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 RouteMiddleware =
|
||||
@@ -102,6 +102,9 @@ export type Skill<T = SimpleObject> = {
|
||||
[key: string]: any
|
||||
};
|
||||
} & T
|
||||
export const tool = {
|
||||
schema: z
|
||||
}
|
||||
/** */
|
||||
export const createSkill = <T = SimpleObject>(skill: Skill<T>): Skill<T> => {
|
||||
return {
|
||||
@@ -352,7 +355,7 @@ export class QueryRouter {
|
||||
const middleware = routeMiddleware[i];
|
||||
if (middleware) {
|
||||
try {
|
||||
await middleware.run(ctx);
|
||||
await middleware.run(ctx as Required<RouteContext>);
|
||||
} catch (e) {
|
||||
if (route?.isDebug) {
|
||||
console.error('=====debug====:middlerware error');
|
||||
@@ -382,7 +385,7 @@ export class QueryRouter {
|
||||
if (route) {
|
||||
if (route.run) {
|
||||
try {
|
||||
await route.run(ctx);
|
||||
await route.run(ctx as Required<RouteContext>);
|
||||
} catch (e) {
|
||||
if (route?.isDebug) {
|
||||
console.error('=====debug====:', 'router run error:', e.message);
|
||||
@@ -611,7 +614,7 @@ export class QueryRouter {
|
||||
}
|
||||
/**
|
||||
* 等待程序运行, 获取到message的数据,就执行
|
||||
*
|
||||
* params 是预设参数
|
||||
* emitter = process
|
||||
* -- .exit
|
||||
* -- .on
|
||||
@@ -628,7 +631,7 @@ export class QueryRouter {
|
||||
if (getList) {
|
||||
this.createRouteList(opts?.force ?? false, opts?.filter);
|
||||
}
|
||||
return listenProcess({ app: this, params, ...opts });
|
||||
return listenProcess({ app: this as any, params, ...opts });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,15 +664,9 @@ export class QueryRouterServer extends QueryRouter {
|
||||
setHandle(wrapperFn?: HandleFn, ctx?: RouteContext) {
|
||||
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) {
|
||||
this.add(route);
|
||||
}
|
||||
|
||||
Route = Route;
|
||||
route(opts: RouteOpts): Route<Required<RouteContext>>;
|
||||
route(path: string, key?: string): Route<Required<RouteContext>>;
|
||||
|
||||
@@ -2,6 +2,8 @@ import { pathToRegexp, Key } from 'path-to-regexp';
|
||||
import type { IncomingMessage, ServerResponse, Server } from 'node:http';
|
||||
import { parseBody, parseSearch, parseSearchValue } from './server/parse-body.ts';
|
||||
import { ListenOptions } from 'node:net';
|
||||
// import { Hono } from 'hono'
|
||||
// const app = new Hono()
|
||||
|
||||
type Req = IncomingMessage & { params?: Record<string, string> };
|
||||
type SimpleObject = {
|
||||
|
||||
16
src/test/mini.ts
Normal file
16
src/test/mini.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Mini } from "../route.ts";
|
||||
|
||||
const app = new Mini();
|
||||
|
||||
app.route({
|
||||
path: 'main',
|
||||
id: 'abc',
|
||||
description: '这是一个测试的 main 路由'
|
||||
}).define(async (ctx) => {
|
||||
ctx.body = {
|
||||
a: '123'
|
||||
}
|
||||
}).addTo(app)
|
||||
|
||||
|
||||
app.wait()
|
||||
59
src/test/run-mini.ts
Normal file
59
src/test/run-mini.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { fork } from 'child_process'
|
||||
|
||||
export type RunCodeParams = {
|
||||
path?: string;
|
||||
key?: string;
|
||||
payload?: string;
|
||||
[key: string]: any
|
||||
}
|
||||
type RunCode = {
|
||||
// 调用进程的功能
|
||||
success?: boolean
|
||||
data?: {
|
||||
// 调用router的结果
|
||||
code?: number
|
||||
data?: any
|
||||
message?: string
|
||||
[key: string]: any
|
||||
};
|
||||
error?: any
|
||||
timestamp?: string
|
||||
[key: string]: any
|
||||
}
|
||||
export const runCode = async (tsPath: string, params: RunCodeParams = {}): Promise<RunCode> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 使用 Bun 的 fork 模式启动子进程
|
||||
const child = fork(tsPath)
|
||||
|
||||
// 监听来自子进程的消息
|
||||
child.on('message', (msg: RunCode) => {
|
||||
resolve(msg)
|
||||
})
|
||||
|
||||
// child.on('exit', (code, signal) => {
|
||||
// console.log('子进程已退出,退出码:', code, '信号:', signal)
|
||||
// })
|
||||
|
||||
// child.on('close', (code, signal) => {
|
||||
// console.log('子进程已关闭,退出码:', code, '信号:', signal)
|
||||
// })
|
||||
|
||||
child.on('error', (error) => {
|
||||
resolve({
|
||||
success: false, error: error?.message
|
||||
})
|
||||
})
|
||||
|
||||
// 向子进程发送消息
|
||||
child.send(params)
|
||||
});
|
||||
}
|
||||
import path from 'node:path'
|
||||
const res = await runCode(path.join(process.cwd(), './src/test/mini.ts'), {
|
||||
// path: 'main'
|
||||
// id: 'abc'
|
||||
path: 'router',
|
||||
key: 'list'
|
||||
})
|
||||
|
||||
console.log('res', res.data.data.list)
|
||||
@@ -1,23 +1,63 @@
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import { QueryRouterServer } from "../route.ts"
|
||||
export class MockProcess {
|
||||
emitter?: EventEmitter
|
||||
process?: NodeJS.Process;
|
||||
constructor(opts?: { emitter?: EventEmitter, isNode?: boolean }) {
|
||||
this.emitter = opts?.emitter || new EventEmitter();
|
||||
const isNode = opts?.isNode ?? true;
|
||||
if (isNode) {
|
||||
this.process = globalThis?.process;
|
||||
}
|
||||
}
|
||||
send(data?: any, callback?: (err?: Error) => void) {
|
||||
if (this.process) {
|
||||
this.process?.send?.(data, (err?: Error) => {
|
||||
callback(err)
|
||||
})
|
||||
}
|
||||
this.emitter.emit('send', data)
|
||||
}
|
||||
exit(flag: number = 0) {
|
||||
if (this.process) {
|
||||
this.process?.exit?.(flag)
|
||||
}
|
||||
this.emitter.emit('exit', flag)
|
||||
}
|
||||
on(fn: (msg?: any) => any) {
|
||||
if (this.process) {
|
||||
this.process.on('message', fn)
|
||||
}
|
||||
this.emitter.on('message', fn)
|
||||
}
|
||||
desctroy() {
|
||||
if (this.emitter) {
|
||||
this.emitter = undefined;
|
||||
}
|
||||
this.process = undefined;
|
||||
}
|
||||
}
|
||||
export type ListenProcessOptions = {
|
||||
app?: any; // 传入的应用实例
|
||||
emitter?: any; // 可选的事件发射器
|
||||
app?: QueryRouterServer; // 传入的应用实例
|
||||
mockProcess?: MockProcess; // 可选的事件发射器
|
||||
params?: any; // 可选的参数
|
||||
timeout?: number; // 可选的超时时间 (单位: 毫秒)
|
||||
timeout?: number; // 可选的超时时间 (单位: 毫秒) 默认 10 分钟
|
||||
};
|
||||
export const listenProcess = async ({ app, emitter, params, timeout = 10 * 60 * 60 * 1000 }: ListenProcessOptions) => {
|
||||
const process = emitter || globalThis.process;
|
||||
export const listenProcess = async ({ app, mockProcess, params, timeout = 10 * 60 * 60 * 1000 }: ListenProcessOptions) => {
|
||||
const process = mockProcess || new MockProcess();
|
||||
let isEnd = false;
|
||||
const timer = setTimeout(() => {
|
||||
if (isEnd) return;
|
||||
isEnd = true;
|
||||
process.send?.({ success: false, error: 'Timeout' });
|
||||
process.exit?.(1);
|
||||
process.send?.({ success: false, error: 'Timeout' }, () => {
|
||||
process.exit?.(1);
|
||||
});
|
||||
}, timeout);
|
||||
|
||||
// 监听来自主进程的消息
|
||||
const getParams = async (): Promise<any> => {
|
||||
return new Promise((resolve) => {
|
||||
process.on('message', (msg) => {
|
||||
process.on((msg) => {
|
||||
if (isEnd) return;
|
||||
isEnd = true;
|
||||
clearTimeout(timer);
|
||||
@@ -27,9 +67,23 @@ export const listenProcess = async ({ app, emitter, params, timeout = 10 * 60 *
|
||||
}
|
||||
|
||||
try {
|
||||
const { path = 'main', ...rest } = await getParams()
|
||||
/**
|
||||
* 如果不提供path,默认是main
|
||||
*/
|
||||
const {
|
||||
payload = {},
|
||||
...rest
|
||||
} = await getParams()
|
||||
const msg = { ...params, ...rest, payload: { ...params?.payload, ...payload } }
|
||||
/**
|
||||
* 如果没有提供path和id,默认取第一个路由, 而且路由path不是router的
|
||||
*/
|
||||
if (!msg.path && !msg.id) {
|
||||
const route = app.routes.find(r => r.path !== 'router')
|
||||
msg.id = route?.id
|
||||
}
|
||||
// 执行主要逻辑
|
||||
const result = await app.queryRoute({ path, ...rest, ...params })
|
||||
const result = await app.run(msg)
|
||||
// 发送结果回主进程
|
||||
const response = {
|
||||
success: true,
|
||||
@@ -37,14 +91,15 @@ export const listenProcess = async ({ app, emitter, params, timeout = 10 * 60 *
|
||||
timestamp: new Date().toISOString()
|
||||
}
|
||||
|
||||
process.send?.(response, (error) => {
|
||||
process.send?.(response, () => {
|
||||
process.exit?.(0)
|
||||
})
|
||||
} catch (error) {
|
||||
process.send?.({
|
||||
success: false,
|
||||
error: error.message
|
||||
}, () => {
|
||||
process.exit?.(1)
|
||||
})
|
||||
process.exit?.(1)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user