diff --git a/docs/src/content/docs/en/configuration/routing.md b/docs/src/content/docs/en/configuration/routing.md index a99e0081..960427fd 100644 --- a/docs/src/content/docs/en/configuration/routing.md +++ b/docs/src/content/docs/en/configuration/routing.md @@ -96,7 +96,7 @@ Scripts run in rule-list order. A non-match continues to the next rule; a match 3. Select the script file, choose a timeout from 10 to 30000 milliseconds, and use **Validate** or **Test script** to check it. 4. Save the rule. CCR reads the file before every execution, so later file edits do not require saving the rule again. -The Desktop file picker stores an absolute path. A Web UI cannot obtain the real local path selected by the browser, so enter an absolute, relative, or `~/...` path on the machine running CCR. Relative paths resolve from the CCR process working directory. A script file may be at most 64 KiB. +The Desktop file picker stores an absolute path. A Web UI cannot obtain the real local path selected by the browser, so enter an absolute, relative, or `~/...` path on the machine running CCR. Relative paths resolve from the CCR process working directory. A script file may be at most 5 MiB. The script file is an **async function body**. Use the injected `input`, `api`, and `return` directly; do not write it as a CommonJS or ES module: @@ -397,7 +397,7 @@ The saved rule has the following shape. It is normally generated by the UI and d | Limit | Current value | | --- | --- | -| Script file | 64 KiB maximum | +| Script file | 5 MiB maximum | | Execution timeout | 10-30000 ms; 2000 ms by default | | Fetch request / response body | 256 KiB / 1 MiB | | Individual file read or write | 1 MiB | diff --git a/docs/src/content/docs/zh/configuration/routing.md b/docs/src/content/docs/zh/configuration/routing.md index 2c763a47..f98a6021 100644 --- a/docs/src/content/docs/zh/configuration/routing.md +++ b/docs/src/content/docs/zh/configuration/routing.md @@ -96,7 +96,7 @@ CCR 会自动为第三方或非 GPT 模型适配 Codex 的 `apply_patch` 文件 3. 选择脚本文件,设置 10–30000 毫秒的超时时间,然后使用 **验证** 或 **测试脚本** 检查结果。 4. 保存规则。CCR 会在每次执行前重新读取文件,因此后续修改脚本内容不需要重新保存规则。 -桌面版文件选择器保存绝对路径。Web UI 不能获得浏览器所选文件的真实路径,需要手动填写 CCR 服务所在机器上的绝对路径、相对路径或 `~/...` 路径;相对路径以 CCR 进程的工作目录为基准。单个脚本文件最大 64 KiB。 +桌面版文件选择器保存绝对路径。Web UI 不能获得浏览器所选文件的真实路径,需要手动填写 CCR 服务所在机器上的绝对路径、相对路径或 `~/...` 路径;相对路径以 CCR 进程的工作目录为基准。单个脚本文件最大 5 MiB。 脚本文件是一个 **异步函数体**。直接使用已注入的 `input`、`api` 和 `return`;不需要写 `module.exports`、`export default` 或 `import`: @@ -397,7 +397,7 @@ return { | 限制 | 当前值 | | --- | --- | -| 脚本文件 | 最大 64 KiB | +| 脚本文件 | 最大 5 MiB | | 执行超时 | 10–30000 毫秒,默认 2000 毫秒 | | Fetch 请求体 / 响应体 | 256 KiB / 1 MiB | | 单次文件读取或写入 | 1 MiB | diff --git a/packages/core/src/contracts/app.ts b/packages/core/src/contracts/app.ts index 4d316a3b..cfd06ed8 100644 --- a/packages/core/src/contracts/app.ts +++ b/packages/core/src/contracts/app.ts @@ -659,7 +659,7 @@ export type RouterRuleRewrite = { }; export const ROUTER_SCRIPT_API_VERSION = 1 as const; -export const ROUTER_SCRIPT_MAX_SOURCE_BYTES = 64 * 1024; +export const ROUTER_SCRIPT_MAX_SOURCE_BYTES = 5 * 1024 * 1024; export const ROUTER_SCRIPT_DEFAULT_TIMEOUT_MS = 2_000; export const ROUTER_SCRIPT_MAX_TIMEOUT_MS = 30_000; diff --git a/packages/core/test/unit/routing/route-script-runtime.test.mjs b/packages/core/test/unit/routing/route-script-runtime.test.mjs index 6b15c2df..7c883e55 100644 --- a/packages/core/test/unit/routing/route-script-runtime.test.mjs +++ b/packages/core/test/unit/routing/route-script-runtime.test.mjs @@ -4,6 +4,7 @@ import { createServer } from "node:http"; import os from "node:os"; import path from "node:path"; import test from "node:test"; +import { ROUTER_SCRIPT_MAX_SOURCE_BYTES } from "@ccr/core/contracts/app.ts"; import { gatewayService } from "@ccr/core/gateway/application/gateway-service.ts"; import { ClaudeCodeRouterPlugin } from "@ccr/core/gateway/claude-code-router-plugin.ts"; import { buildRouteScriptInput } from "@ccr/core/routing/route-script-context.ts"; @@ -249,13 +250,13 @@ test("route script validation rejects invalid metadata, paths, content, and limi const cases = [ [{ ...valid, apiVersion: 2 }, /unsupported route script api or language/i], [{ ...valid, language: "typescript" }, /unsupported route script api or language/i], - [{ ...valid, file: undefined, source: " " }, /between 1 and 65536 bytes/i], + [{ ...valid, file: undefined, source: " " }, new RegExp(`between 1 and ${ROUTER_SCRIPT_MAX_SOURCE_BYTES} bytes`, "i")], [{ ...valid, file: `${valid.file}.txt` }, /\.js, \.mjs, or \.cjs extension/i], [{ ...valid, timeoutMs: 9 }, /between 10 and 30000 ms/i], [{ ...valid, timeoutMs: 30001 }, /between 10 and 30000 ms/i], [{ ...valid, file: path.join(routeScriptDirectory, "missing.js") }, /unable to read route script file/i], [{ ...valid, file: directoryFile }, /is not a file/i], - [routeScript("x".repeat(64 * 1024 + 1)), /exceeds 65536 bytes/i] + [routeScript("x".repeat(ROUTER_SCRIPT_MAX_SOURCE_BYTES + 1)), new RegExp(`exceeds ${ROUTER_SCRIPT_MAX_SOURCE_BYTES} bytes`, "i")] ]; try { for (const [script, expectedMessage] of cases) {