接口与类型参考
查询 NoteGen 插件 manifest、生命周期、PluginContext、数据对象和稳定错误的 TypeScript 契约。
@notegen/plugin-api 是插件代码与 NoteGen 宿主共同遵守的公开 TypeScript 契约。它提供类型、API 版本常量和少量作者辅助函数,不连接服务,也不会让插件绕过 PluginContext 取得额外能力。
更新日期:2026-09-10。四个 SDK 包已发布 npm,官方插件签名市场已上线;社区投稿尚未开放。接口说明以当前开发分支为准,未发布的新增能力需使用对应源码版本。远程安装还要求 NoteGen 支持插件系统并内置正式根公钥。
安装与导入
将已发布的 npm 包安装为开发依赖:
pnpm add -D @notegen/plugin-api插件入口通常只导入类型:
import type { PluginActivate } from "@notegen/plugin-api";
export const activate: PluginActivate = async (ctx) => {
ctx.commands.handle("com.example.hello.open", async () => {
await ctx.ui.showNotice("Hello from NoteGen");
});
};import type 会在编译后消失。使用 PluginError、isPluginError、PLUGIN_API_VERSION 或 definePluginManifest 等运行时值时,构建器必须把包代码打入最终的单文件入口。
这个包没有运行时依赖,也不要求 TypeScript 项目启用 DOM 类型。
运行时值导出
| 导出 | 类型或作用 |
|---|---|
PLUGIN_API_VERSION | 当前包描述的具体宿主 API 版本,当前为 "0.1.0" |
PLUGIN_ERROR_CODES | 全部稳定 PluginErrorCode 的只读列表 |
PluginError | 带 code、message 和可选 details 的错误类 |
isPluginError(value) | 跨 Worker/realm 按结构识别已知插件错误 |
definePluginManifest(manifest) | 保留 manifest 字面量类型并在编译期检查 v1 形状 |
definePluginManifest 是恒等辅助函数,不读取或生成 plugin.json,也不会替代 CLI 和 NoteGen 的运行时校验。
Manifest JSON Schema
包内同时发布面向编辑器的 JSON Schema,深层入口是:
@notegen/plugin-api/plugin-manifest-v1.schema.json例如在 VS Code 工作区的 .vscode/settings.json 中,把它关联到各插件的 plugin.json:
{
"json.schemas": [
{
"fileMatch": ["**/plugin.json"],
"url": "./node_modules/@notegen/plugin-api/schema/plugin-manifest-v1.schema.json"
}
]
}Schema 用于编辑时补全字段、提示类型和发现结构错误。它不替代 notegen-plugin validate:命名空间归属、locale 文件、API/应用版本兼容性和打包文件检查仍以 CLI 与 NoteGen 宿主为准。不要在 plugin.json 中添加 $schema 字段;严格 manifest 校验会拒绝未声明字段。
Manifest 与贡献类型
| 分类 | 导出 |
|---|---|
| 主 manifest | PluginManifestV1、PluginAuthor、PluginPlatform、PluginActivationEvent |
| 权限 | PluginPermissionName、PluginPermissionScope、PluginPermissionDeclaration、PluginPermissionDeclarations |
| 命令 | PluginCommandContribution |
| 设置 | PluginSettingContribution、PluginSettingOption、PluginSettingValue |
| 状态栏 | PluginStatusBarContribution、PluginStatusBarUpdate |
| 菜单 | PluginMenuLocation、PluginMenuContribution |
| 汇总 | PluginContributions |
这些类型描述作者可以声明的最大能力,但 TypeScript 校验不是安全边界。导入和安装时,宿主仍会严格拒绝重复字段、未知字段、显式 null、不兼容版本、错误权限范围和无效贡献引用。完整 JSON 规则见插件配置。
生命周期类型
interface PluginModule {
activate: (context: PluginContext) => void | Promise<void>;
deactivate?: () => void | Promise<void>;
}
type PluginActivate = PluginModule["activate"];
type PluginDeactivate = NonNullable<PluginModule["deactivate"]>;
interface PluginDisposable {
readonly dispose: () => void;
}入口必须具名导出 activate,可以导出 deactivate。事件订阅和命令处理器会返回 PluginDisposable;插件应在不再需要时调用 dispose()。宿主停止插件时也会清理当前运行实例注册的资源。
PluginAbortSignal 是市场和开发运行时都实现的取消契约:
interface PluginAbortSignal {
readonly aborted: boolean;
readonly reason: unknown;
readonly throwIfAborted: () => void;
readonly addEventListener: (
type: "abort",
listener: PluginAbortListener,
options?: { once?: boolean },
) => void;
readonly removeEventListener: (
type: "abort",
listener: PluginAbortListener,
) => void;
}它不是浏览器原生 AbortSignal,不要做 instanceof AbortSignal 判断,也不要依赖未声明的 DOM 方法。生命周期细节见插件运行机制。
PluginContext 参考
| 成员 | 主要方法 | 权限或声明要求 |
|---|---|---|
plugin | id、version、apiVersion | 只读当前实例信息 |
signal | throwIfAborted()、abort 监听 | 无;用于停止异步工作 |
commands | handle(commandId, handler) | 命令必须在 manifest 声明 |
workspace | getCurrent()、onDidChange | 无;只返回不透明 ID 和名称 |
calendar | resolveDay(options) | 无;使用 IANA 时区和 HH:mm 日界线 |
notes | 读取、列举、搜索、创建、写入、移动、删除和变更事件 | 对应的 notes.* 权限 |
attachments | read、create | 独立的 attachments.read、attachments.create 权限 |
editor | 活动编辑器、选区、Markdown 快照、修改和事件 | editor.read;修改另需 editor.write |
log | info、warning、error | 本地诊断消息,不自动捕获 console |
storage.device | get、set、delete | 插件私有本机 KV |
storage.workspace | get、set、delete | 按工作区 ID 分区的本机 KV |
ui | 通知、状态栏、声明式视图和对话框 | 状态栏和视图 ID 必须在 manifest 声明 |
network | fetch(request) | network.fetch,只访问用户授权的 HTTPS origin |
i18n | t(key, values?) | 使用 manifest 声明的 locale 文件 |
settings | get、onDidChange | key 必须由 contributes.settings 声明 |
每个方法的参数、返回值、权限、额度和失败行为见功能调用与权限。
宿主数据类型
| 能力 | 参数、结果与事件类型 |
|---|---|
| 工作区 | WorkspaceInfo、WorkspaceChangeEvent |
| 日期 | ResolveDayOptions、ResolvedDay |
| 笔记 | NoteSnapshot、NoteEntry、读写与移动参数、NoteChangeEvent |
| 编辑器身份 | ActiveEditorContext |
| 选区与正文 | EditorSelection、GetEditorTextSnapshotOptions、EditorTextSnapshot |
| 编辑器修改与事件 | ApplyEditorEditOptions、ApplyEditorEditResult、EditorActiveChangeEvent、EditorContentChangeEvent |
| 网络 | PluginNetworkRequest、PluginNetworkResponse |
| 声明式界面 | PluginUiDocument、PluginUiBlock、PluginDialogOptions、PluginFormBlock、PluginFormField、PluginFormValue、PluginViewState |
| 搜索 | SearchNotesOptions、SearchNotesResult |
| 范围编辑 | EditorRangeEdit、ApplyEditorEditsOptions、SetEditorSelectionOptions |
| 附件 | PluginAttachment |
| 存储 | PluginStorageArea |
这些对象是调用时快照。ID 不透明,路径始终相对工作区;不要从 ID 猜测绝对路径。编辑器数据带 revision,异步读取时必须正确处理 StaleRevision。
JSON 数据边界
命令参数、命令返回值、插件存储值和声明式 UI action 参数使用同一组公开类型:
type PluginJsonValue =
| null
| boolean
| number
| string
| readonly PluginJsonValue[]
| { readonly [key: string]: PluginJsonValue };
type PluginCommandArgument = PluginJsonValue | undefined;
type PluginCommandResult = PluginJsonValue | void;PluginJsonValue 只包含可无损往返的 JSON 值:null、布尔值、有限数字、字符串,以及递归的数组和普通对象。对象属性和数组元素不能是 undefined;需要表达空值时使用 null,不需要的对象属性则直接省略。函数、Symbol、BigInt、非有限数字、循环引用和带自定义原型的类实例会被拒绝;Date、Map、Set 和错误对象应先转换为普通 JSON 数据。
undefined 只在命令最外层有两种含义:省略 executeCommand 的参数,或处理器没有返回值。它不能嵌套在 PluginJsonValue 内。存储的 get() 返回 undefined 只表示 key 不存在,set() 仍只接受 PluginJsonValue。
API 版本值
manifest 中的 apiVersion 是插件接受的 SemVer 范围:
{
"apiVersion": "^0.1.0"
}PLUGIN_API_VERSION 与运行中的 ctx.plugin.apiVersion 是具体版本:
import { PLUGIN_API_VERSION } from "@notegen/plugin-api";
import type { PluginActivate } from "@notegen/plugin-api";
export const activate: PluginActivate = async (ctx) => {
// PLUGIN_API_VERSION === "0.1.0"
// ctx.plugin.apiVersion === "0.1.0"(当前宿主)
};ctx.plugin.apiVersion 的公开类型是 string,因为用户可能在兼容范围内使用比开发时 SDK 更新的宿主。它适合诊断,不应替代 manifest 兼容范围。
处理 API 错误
所有稳定错误码组成 PluginErrorCode。跨 Worker 边界不要只依赖 instanceof PluginError;使用 isPluginError:
import { isPluginError } from "@notegen/plugin-api";
import type { PluginActivate } from "@notegen/plugin-api";
export const activate: PluginActivate = async (ctx) => {
try {
await ctx.notes.read({ path: "Templates/example.md" });
} catch (error) {
if (isPluginError(error) && error.code === "PermissionDenied") {
await ctx.ui.showNotice("The selected file is not authorized.");
return;
}
throw error;
}
};isPluginError 是值导入,必须被打包进入口。插件逻辑应优先判断稳定 code,不要匹配完整英文消息。全部错误码见功能调用与权限。
单文件加载边界
插件运行时只加载 manifest 指定的一个自包含 ESM 入口,不解析入口中的相对模块、npm 包、Node.js 内置模块或远程模块。
- 只使用类型时优先
import type; - 使用本包运行时值或其他依赖时,通过
notegen-plugin build打包; - 不使用打包器时,最终入口只能依赖 NoteGen 传入的
ctx; - 构建结果中不能残留静态或动态 import。
本包不公开市场目录、安装记录、签名校验器、宿主存储状态、Worker/RPC 消息或其他宿主内部对象。
继续阅读
SDK 已完成 npm 首发。修改已发布包的内容需要提升对应包版本;协议兼容性变化需同步更新宿主与 SDK。插件的 apiVersion 应声明实际支持的协议范围,例如 ^0.1.0;开发分支中的未发布快照仍需通过提交版本区分。