Appearance
运行时
ctx
所有 handler 的第一个参数。
| 字段 | 内容 |
|---|---|
locale | BCP 47,如 zh-CN |
userId | 可选,用于限流或权益校验,不用于界面展示 |
settings | 包级 settings 的当前值,由字段 default 与用户在包详情页填写的值合并而成。所有 handler 均从此处读取包级设置,不应从 input.params 中查找。用法见 开发者指南 · 设置 |
http.get / http.post | 网络 |
html.load | 唯一 DOM API,返回 cheerio 句柄 |
storage.get / set / remove | 包私有 KV |
运行时不提供全局宿主对象、其他 DOM API 或跨包共享的 KV 存储。
console
console.log / info / warn / error 由宿主记录,并显示在调试页中。参数会转换为字符串;对象应使用 JSON.stringify 序列化。每次 handler 调用的日志独立记录,不与结果缓存关联。
http
ts
ctx.http.get(url, options?)
ctx.http.post(url, body, options?)返回 { status, headers, data }。对于非 2xx 响应,运行时不会自动抛出异常。
| 选项 | 规则 |
|---|---|
headers | 请求头 |
query | 由 runtime 编码 |
timeoutMs | 可以缩短,但不能超过 App 设置的上限 |
followRedirects | 默认 true |
cacheTtlSeconds | 按 method + URL + query 缓存 HTTP 响应 |
decompress | 可选 |
请求 origin 必须包含在包的 permissions.network 中,否则请求不会发送。
storage
存储作用域为包 id。同一包内的多个扩展共享存储,不同包之间相互隔离。
ts
ctx.storage.get(key)
ctx.storage.set(key, value, { ttlSeconds? })
ctx.storage.remove(key)值必须能 JSON 序列化。
错误
| 情况 | 做法 |
|---|---|
| 请求成功但无数据 | 返回空数组,或由 detail 返回 null |
| 失败 | throw ExtensionError |
ExtensionError:code、message(给用户)、retryable。
code | retryable | 典型原因 |
|---|---|---|
invalid_params | false | 缺少关键词、枚举值无效 |
not_found | false | 详情不存在 |
rate_limited | true | 超出配额 |
unavailable | true | 上游超时或 5xx |
internal | false | 脚本逻辑错误 |
普通 Error 会被统一转换为 internal 错误。
缓存
声明写在扩展上。键:(packageId, type, extensionId, method, input)。
| type / 方法 | 默认 ttlSeconds |
|---|---|
widget.load / search.search | 3600 |
widget.placeholder | 0(安装时单独写入磁盘,不进入结果缓存) |
detail.load | 60 |
playback.sources | 0 |
subtitle.match / search | 3600 |
subtitle.file | 0 |
danmu.match / search / episodes | 3600 |
danmu.comments | 0 |
用户清理包缓存时,App 会同时清除该包的结果缓存、storage 和 HTTP 缓存。
权限
ts
permissions: {
network: string[];
}未声明 network 或列表为空时,禁止发起 HTTP 请求。storage 默认可用。新增能力必须显式声明权限,未声明时默认拒绝。
扩展目录
订阅 URL 应返回以下 JSON。Content-Type 不受限制,但响应正文必须是有效 JSON。目录信息从 definePackage 字面量中静态提取,提取过程不会执行 handler。format 仅支持 1;其他值会导致整份目录被忽略。
json
{
"format": 1,
"title": "示例源",
"description": "可选",
"updated": "2026-09-24T08:00:00Z",
"packages": [
{
"id": "conflux.bangumi",
"title": "动漫数据",
"description": "每日播出与详情",
"author": "可选",
"icon": "https://example.com/icon.png",
"version": "1.2.0",
"engine": 1,
"changelog": "修复时区",
"types": ["widget", "detail", "playback"],
"url": "https://example.com/packages/bangumi.js"
}
]
}| 字段 | 必填 | 含义 |
|---|---|---|
format | 是 | 清单格式,仅支持整数 1 |
title | 是 | 订阅源的展示名称 |
description | 否 | 源说明 |
updated | 否 | 清单生成时间,ISO 8601 |
packages | 是 | 包列表,可为空数组 |
packages[].id | 是 | 与 definePackage.id 相同,更新时用于匹配已安装的包 |
packages[].title | 是 | 展示名 |
packages[].description | 否 | 说明 |
packages[].author / icon | 否 | 展示 |
packages[].version | 是 | semver 字符串,必须取自包的 version |
packages[].engine | 是 | 仅支持整数 1;其他值对应的条目会被忽略 |
packages[].changelog | 否 | 当前版本的更新说明,使用 Markdown 纯文本 |
packages[].types | 是 | 包内扩展 type 的去重列表 |
packages[].url | 是 | 该包 .js 的 http(s) 地址 |
App 使用 types 筛选“可添加到 Dashboard”或“可作为弹幕服务”的扩展包。version 和 updated 必须为字符串,不能使用数字。