NoteGenNOTEGEN.

接口与类型参考

查询 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 会在编译后消失。使用 PluginErrorisPluginErrorPLUGIN_API_VERSIONdefinePluginManifest 等运行时值时,构建器必须把包代码打入最终的单文件入口。

这个包没有运行时依赖,也不要求 TypeScript 项目启用 DOM 类型。

运行时值导出

导出类型或作用
PLUGIN_API_VERSION当前包描述的具体宿主 API 版本,当前为 "0.1.0"
PLUGIN_ERROR_CODES全部稳定 PluginErrorCode 的只读列表
PluginErrorcodemessage 和可选 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 与贡献类型

分类导出
主 manifestPluginManifestV1PluginAuthorPluginPlatformPluginActivationEvent
权限PluginPermissionNamePluginPermissionScopePluginPermissionDeclarationPluginPermissionDeclarations
命令PluginCommandContribution
设置PluginSettingContributionPluginSettingOptionPluginSettingValue
状态栏PluginStatusBarContributionPluginStatusBarUpdate
菜单PluginMenuLocationPluginMenuContribution
汇总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 参考

成员主要方法权限或声明要求
pluginidversionapiVersion只读当前实例信息
signalthrowIfAborted()、abort 监听无;用于停止异步工作
commandshandle(commandId, handler)命令必须在 manifest 声明
workspacegetCurrent()onDidChange无;只返回不透明 ID 和名称
calendarresolveDay(options)无;使用 IANA 时区和 HH:mm 日界线
notes读取、列举、搜索、创建、写入、移动、删除和变更事件对应的 notes.* 权限
attachmentsreadcreate独立的 attachments.readattachments.create 权限
editor活动编辑器、选区、Markdown 快照、修改和事件editor.read;修改另需 editor.write
loginfowarningerror本地诊断消息,不自动捕获 console
storage.devicegetsetdelete插件私有本机 KV
storage.workspacegetsetdelete按工作区 ID 分区的本机 KV
ui通知、状态栏、声明式视图和对话框状态栏和视图 ID 必须在 manifest 声明
networkfetch(request)network.fetch,只访问用户授权的 HTTPS origin
i18nt(key, values?)使用 manifest 声明的 locale 文件
settingsgetonDidChangekey 必须由 contributes.settings 声明

每个方法的参数、返回值、权限、额度和失败行为见功能调用与权限

宿主数据类型

能力参数、结果与事件类型
工作区WorkspaceInfoWorkspaceChangeEvent
日期ResolveDayOptionsResolvedDay
笔记NoteSnapshotNoteEntry、读写与移动参数、NoteChangeEvent
编辑器身份ActiveEditorContext
选区与正文EditorSelectionGetEditorTextSnapshotOptionsEditorTextSnapshot
编辑器修改与事件ApplyEditorEditOptionsApplyEditorEditResultEditorActiveChangeEventEditorContentChangeEvent
网络PluginNetworkRequestPluginNetworkResponse
声明式界面PluginUiDocumentPluginUiBlockPluginDialogOptionsPluginFormBlockPluginFormFieldPluginFormValuePluginViewState
搜索SearchNotesOptionsSearchNotesResult
范围编辑EditorRangeEditApplyEditorEditsOptionsSetEditorSelectionOptions
附件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、非有限数字、循环引用和带自定义原型的类实例会被拒绝;DateMapSet 和错误对象应先转换为普通 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;开发分支中的未发布快照仍需通过提交版本区分。