@chatu-ai/edge-plugin
v0.21.0
Published
ChatU 企业网关(chatu-edge)插件契约:definePlugin / ctx 类型 / manifest schema / 能力描述 / 线格式 / caps REST,以及本地测试用 createTestCtx
Maintainers
Readme
@chatu-ai/edge-plugin
ChatU 企业网关(chatu-edge)插件契约。写插件只需要它:definePlugin 给出类型推断与 manifest 提取锚点,ctx 是插件在网关里唯一能触达外界的方式。
import { definePlugin, z } from '@chatu-ai/edge-plugin';
export default definePlugin({
name: 'crm-customer',
version: '1.0.0',
datasources: { crm: { kind: 'sql', dialect: 'mysql' } }, // 声明即权限
egress: ['api.example.com'], // 不声明 = 完全不能出网
secrets: ['crmApiToken'],
tools: {
searchCustomer: {
title: '查询客户', description: '按姓名模糊查询,分页返回',
readonly: true, idempotent: true,
input: z.object({ keyword: z.string().min(1), page: z.number().int().min(0).default(0) }),
output: z.object({ items: z.array(z.object({ id: z.string(), name: z.string() })) }),
async handler(input, ctx) {
const sql = ctx.sql('crm');
const kw = `%${sql.like(input.keyword)}%`; // like 必须转义
const items = await sql`select id, name from customer where name like ${kw} limit 20 offset ${input.page * 20}`;
return { items };
},
},
},
});几条写插件时必须知道的
- SQL 只能写标签模板:
${}里的值永远变成绑定参数,拼接写不出来;数组自动展开(in (${ids})),空数组会报错。 throw ctx.fail(...):fail声明返回never且内部即抛出,但 TypeScript 对上下文推断出来的ctx不做 never 收窄——只写ctx.fail(...)会出现「'row' is possibly null」这类假报错,加throw即可。ctx.user可能为null(public 应用),attrs可能为空;它只是只读身份信息,不是鉴权点——行级策略由网关强制,插件里写if (role === 'admin')不改变实际可见的数据。outputSchema是字段白名单:网关用它校验并剥掉未声明字段,select *带出来的敏感列出不了网关。ctx.http不是 fetch:没有流,目标必须在egress声明且经企业管理员批准,重定向到白名单外同样会被拦。- 明确没有:shell、原始 socket、任意文件读写、读环境变量、自开子进程——不是暂时没做,是设计上不会有。
本地测试
import { createTestCtx } from '@chatu-ai/edge-plugin/testing';
const ctx = createTestCtx({
user: { id: 'u1', roles: [], identity: 'channel', attrs: { deptId: 'd9' }, resolved: true },
sql: { crm: ({ text, params }) => [{ id: '1', name: '张三' }] },
http: async () => ({ status: 200, body: '{}' }),
secrets: { crmApiToken: 'test' },
});
const out = await plugin.tools.searchCustomer.handler({ keyword: '张', page: 0 }, ctx);
ctx.sqlCalls[0].text; // 'select id, name from customer where name like ? limit 20 offset ?'未声明的数据源、密文、出网目标在测试里同样被拒——契约就是同一份。
包含的契约
| 模块 | 内容 |
| --- | --- |
| manifest | 插件 manifest 的 zod schema(编写期 / 发布期两种) |
| ctx | Ctx 接口:sql / http / secrets / state / log / user / env / traceId / signal / fail |
| define | definePlugin / defineTool |
| capability | 能力目录描述、授权(中控与 app-sdk 共用) |
| wire | 网关 ↔ 平台线格式:密码套件 id、公钥、多重签名信封、握手、期望状态、capability token |
| caps | 应用侧 /data/v1/caps/* REST 契约 |
| errors | 错误码(可加:消费方必须能处理未知码) |
