@xiongtao.xt/tau-plugins 0.23.1 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,6 +17,12 @@ import type { PluginSidebar } from "./sidebar";
17
17
  import type { PluginExcerpts, PluginMaterials } from "./excerpts";
18
18
  import type { PluginMCP } from "./mcp";
19
19
  import type { PluginChat } from "./chat";
20
+ import type { PluginBackendClient } from "./backend";
21
+ import type { PluginPermissions } from "./permissions";
22
+ import type { PluginContent, PluginData } from "./data";
23
+ import type { PluginEvents } from "./events";
24
+ import type { PluginApp } from "./app";
25
+ import type { PluginOwnEntities } from "./entities";
20
26
  import type { JsonValue } from "./json";
21
27
  export type { JsonValue } from "./json";
22
28
  export interface Disposable {
@@ -34,6 +40,7 @@ export interface PluginCommand {
34
40
  run(input: JsonValue): JsonValue | Promise<JsonValue>;
35
41
  }
36
42
  export interface PluginContext {
43
+ readonly backend: PluginBackendClient;
37
44
  readonly pluginId: string;
38
45
  readonly workspaceId: string;
39
46
  readonly signal: AbortSignal;
@@ -58,6 +65,18 @@ export interface PluginContext {
58
65
  readonly ai: PluginAI;
59
66
  readonly mcp: PluginMCP;
60
67
  readonly chat: PluginChat;
68
+ /** 业务数据权限的查询与申请;数据接口首次调用时也会自动申请 */
69
+ readonly permissions: PluginPermissions;
70
+ /** 卡片、文章、项目文档、待办与日程的只读访问 */
71
+ readonly data: PluginData;
72
+ /** 按 ContentRef 读取正文 */
73
+ readonly content: PluginContent;
74
+ /** 业务数据变更事件,如卡片更新 */
75
+ readonly events: PluginEvents;
76
+ /** 选择与打开已有内容 */
77
+ readonly app: PluginApp;
78
+ /** 插件自建、各带一份正文的内容;读写自己的内容不需要业务数据权限 */
79
+ readonly entities: PluginOwnEntities;
61
80
  /** 将订阅等资源交给宿主,在停用或激活失败时逆序回收。 */
62
81
  register(resource: Disposable): Disposable;
63
82
  }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * 业务数据接口。ID 与 ContentRef 都是不透明字符串:只用于传回宿主,不要解析其格式。
3
+ * 每次调用前宿主按 manifest.permissions 与用户授权校验,未获准抛出 PluginPermissionError。
4
+ * 修改与删除要传读到的 revision,数据已被别处修改时抛出 PluginConflictError。
5
+ */
6
+ /** 一份正文的句柄,从实体上取得,传给 context.content 读取 */
7
+ export type PluginContentRef = string;
8
+ export interface PluginPage<T> {
9
+ items: T[];
10
+ /** 还有下一页时给出,原样传回 query 的 cursor */
11
+ cursor?: string;
12
+ }
13
+ export interface PluginEntityQuery {
14
+ /** 毫秒时间戳,含起点、不含终点 */
15
+ createdAfter?: number;
16
+ createdBefore?: number;
17
+ updatedAfter?: number;
18
+ updatedBefore?: number;
19
+ /** 层级标签按前缀命中:「读书」也命中「读书/小说」 */
20
+ tag?: string;
21
+ /** 默认按更新时间倒序 */
22
+ sort?: "created" | "updated";
23
+ /** 1–200,默认 50 */
24
+ limit?: number;
25
+ cursor?: string;
26
+ }
27
+ interface PluginEntityBase {
28
+ id: string;
29
+ /** 元数据版本,修改与删除时作为 expectedRevision 传回;正文修改不改变它 */
30
+ revision: string;
31
+ title: string;
32
+ tags: string[];
33
+ wordCount: number;
34
+ createdAt: number;
35
+ /** 元数据与正文中较晚的修改时间 */
36
+ updatedAt: number;
37
+ }
38
+ export interface PluginCard extends PluginEntityBase {
39
+ /** 卡片没有标题字段,这里是 AI 标题或正文开头 */
40
+ title: string;
41
+ pinned: boolean;
42
+ contentRef: PluginContentRef;
43
+ }
44
+ export interface PluginArticle extends PluginEntityBase {
45
+ pinned: boolean;
46
+ contentRef: PluginContentRef;
47
+ }
48
+ export interface PluginDocument extends PluginEntityBase {
49
+ /** document(富文本)、white-board 等;非富文本类型没有正文 */
50
+ kind: string;
51
+ contentRef: PluginContentRef | null;
52
+ projectIds: string[];
53
+ }
54
+ export interface PluginEntityReader<T> {
55
+ get(id: string): Promise<T | null>;
56
+ query(query?: PluginEntityQuery): Promise<PluginPage<T>>;
57
+ }
58
+ export interface PluginWriteOptions {
59
+ /** 读取时得到的 revision */
60
+ expectedRevision: string;
61
+ }
62
+ export interface PluginCardInput {
63
+ /** 正文,Markdown;省略时为空卡片 */
64
+ markdown?: string;
65
+ tags?: string[];
66
+ pinned?: boolean;
67
+ }
68
+ export interface PluginCardPatch {
69
+ tags?: string[];
70
+ pinned?: boolean;
71
+ }
72
+ export interface PluginArticleInput {
73
+ title: string;
74
+ markdown?: string;
75
+ tags?: string[];
76
+ }
77
+ export interface PluginArticlePatch {
78
+ title?: string;
79
+ tags?: string[];
80
+ pinned?: boolean;
81
+ }
82
+ export interface PluginDocumentPatch {
83
+ title?: string;
84
+ tags?: string[];
85
+ }
86
+ /** 新建与修改需要 `*:write`,删除需要 `*:delete`;删除可由用户在插件详情页 7 天内恢复 */
87
+ export interface PluginEntityWriter<T, Input, Patch> extends PluginEntityReader<T> {
88
+ create(input: Input): Promise<T>;
89
+ update(id: string, patch: Patch, options: PluginWriteOptions): Promise<T>;
90
+ delete(id: string, options: PluginWriteOptions): Promise<void>;
91
+ }
92
+ export interface PluginTodoQuery {
93
+ /** 缺省为全部:独立待办与正文里的勾选项 */
94
+ source?: "all" | "todo" | "document";
95
+ completed?: boolean;
96
+ keyword?: string;
97
+ /** YYYY-MM-DD,按截止日期筛选 */
98
+ start?: string;
99
+ end?: string;
100
+ /** 1–100,默认 50 */
101
+ limit?: number;
102
+ cursor?: string;
103
+ }
104
+ export interface PluginTodo {
105
+ id: string;
106
+ revision: string;
107
+ title: string;
108
+ completed: boolean;
109
+ archived: boolean;
110
+ /** YYYY-MM-DD 或 ISO 时间 */
111
+ dueAt: string | null;
112
+ /** 正文里的勾选项所在的文档 */
113
+ source?: {
114
+ kind: "card" | "article" | "document" | "diary";
115
+ id: string;
116
+ title?: string;
117
+ };
118
+ }
119
+ export interface PluginCalendarQuery {
120
+ /** YYYY-MM-DD 或带时区的 ISO 时间,必填 */
121
+ start: string;
122
+ end: string;
123
+ /** 1–100,默认 50 */
124
+ limit?: number;
125
+ cursor?: string;
126
+ }
127
+ export interface PluginCalendarEvent {
128
+ id: string;
129
+ revision: string;
130
+ title: string;
131
+ start: string;
132
+ end: string;
133
+ allDay: boolean;
134
+ calendarId: string;
135
+ /** 由待办安排出的日程 */
136
+ todoId?: string;
137
+ }
138
+ export interface PluginTodoInput {
139
+ title: string;
140
+ /** YYYY-MM-DD 或带时区的 ISO 时间 */
141
+ dueAt?: string | null;
142
+ }
143
+ export interface PluginTodoPatch {
144
+ title?: string;
145
+ dueAt?: string | null;
146
+ }
147
+ export interface PluginCalendarInput {
148
+ title: string;
149
+ /** 全天日程用 YYYY-MM-DD,结束日期不含当天(当天全天的 end 为次日);定时日程用带时区的 ISO 时间 */
150
+ start: string;
151
+ end: string;
152
+ allDay: boolean;
153
+ /** 缺省为默认日历 */
154
+ calendarId?: string;
155
+ }
156
+ export type PluginCalendarPatch = Partial<PluginCalendarInput>;
157
+ export interface PluginData {
158
+ readonly cards: PluginEntityWriter<PluginCard, PluginCardInput, PluginCardPatch>;
159
+ readonly articles: PluginEntityWriter<PluginArticle, PluginArticleInput, PluginArticlePatch>;
160
+ /** 项目文档只能修改标题与标签;新建、移动与删除涉及文档树,暂不开放 */
161
+ readonly documents: PluginEntityReader<PluginDocument> & {
162
+ update(id: string, patch: PluginDocumentPatch, options: PluginWriteOptions): Promise<PluginDocument>;
163
+ };
164
+ readonly todos: {
165
+ query(query?: PluginTodoQuery): Promise<PluginPage<PluginTodo>>;
166
+ create(input: PluginTodoInput): Promise<PluginTodo>;
167
+ update(id: string, patch: PluginTodoPatch, options: PluginWriteOptions): Promise<PluginTodo>;
168
+ setCompleted(id: string, completed: boolean, options: PluginWriteOptions): Promise<PluginTodo>;
169
+ /** 有子待办时拒绝删除 */
170
+ delete(id: string, options: PluginWriteOptions): Promise<void>;
171
+ };
172
+ readonly calendar: {
173
+ query(query: PluginCalendarQuery): Promise<PluginPage<PluginCalendarEvent>>;
174
+ create(input: PluginCalendarInput): Promise<PluginCalendarEvent>;
175
+ update(id: string, patch: PluginCalendarPatch, options: PluginWriteOptions): Promise<PluginCalendarEvent>;
176
+ delete(id: string, options: PluginWriteOptions): Promise<void>;
177
+ };
178
+ }
179
+ export interface PluginContentSnapshot {
180
+ ref: PluginContentRef;
181
+ /** 正文版本,edit 时作为 expectedRevision 传回 */
182
+ revision: string;
183
+ /** format 为 markdown(默认)时给出 */
184
+ markdown?: string;
185
+ /** format 为 nodes 时给出编辑器节点 JSON;结构随编辑器演进,优先使用 markdown */
186
+ nodes?: unknown[];
187
+ wordCount: number;
188
+ updatedAt: number;
189
+ }
190
+ /**
191
+ * 正文修改。append / prepend 只追加新内容,原有内容保持不变;replaceText 与 replaceAll 会把整篇
192
+ * 经 Markdown 重建,Markdown 无法表达的格式可能简化。
193
+ */
194
+ export type PluginContentEdit = {
195
+ op: "append";
196
+ markdown: string;
197
+ } | {
198
+ op: "prepend";
199
+ markdown: string;
200
+ }
201
+ /** find 必须在当前 Markdown 中恰好出现一次 */
202
+ | {
203
+ op: "replaceText";
204
+ find: string;
205
+ markdown: string;
206
+ } | {
207
+ op: "replaceAll";
208
+ markdown: string;
209
+ };
210
+ export interface PluginContent {
211
+ /** 需要拥有该正文所属实体的读取权限;正文不存在时返回 null */
212
+ read(ref: PluginContentRef, options?: {
213
+ format?: "markdown" | "nodes";
214
+ }): Promise<PluginContentSnapshot | null>;
215
+ /**
216
+ * 修改正文,需要所属实体的写入权限。经协作会话写入:打开中的编辑器与协作者实时看到;
217
+ * 修改不进入编辑器的撤销记录。返回新的 revision。
218
+ */
219
+ edit(ref: PluginContentRef, edit: PluginContentEdit, options: PluginWriteOptions): Promise<{
220
+ revision: string;
221
+ }>;
222
+ }
223
+ export {};
@@ -0,0 +1,98 @@
1
+ /**
2
+ * 插件实体:插件自己创建、各带一份正文的内容(如周记、看板卡片)。正文与卡片正文一样实时保存、
3
+ * 随云同步;读写自己的实体与正文不需要业务数据权限。
4
+ */
5
+ import type { Disposable } from "./contract";
6
+ import type { PluginContentRef, PluginPage, PluginWriteOptions } from "./data";
7
+ import type { JsonValue } from "./json";
8
+ import type { PluginPageParams } from "./pages";
9
+ import type { PluginEntityRef } from "./app";
10
+ import type { PluginIcon } from "./icons";
11
+ export type PluginOwnEntityMeta = Record<string, JsonValue>;
12
+ export interface PluginOwnEntity {
13
+ id: string;
14
+ /** registerKind 声明的类型 */
15
+ kind: string;
16
+ /** 插件给定、同一类型内唯一的键,如周记用「2026-W43」 */
17
+ key: string;
18
+ title: string;
19
+ /** 交给 context.content 或 ContentEditor 读写正文 */
20
+ contentRef: PluginContentRef;
21
+ meta: PluginOwnEntityMeta;
22
+ createdAt: number;
23
+ /** 标题、meta 与正文中较新的修改时间 */
24
+ updatedAt: number;
25
+ /** 标题与 meta 的版本,update 时作为 expectedRevision */
26
+ revision: string;
27
+ }
28
+ export interface PluginOwnEntityKind {
29
+ /** 插件内唯一的类型 ID */
30
+ kind: string;
31
+ /** 在 Tau 中显示的类型名,如「周记」 */
32
+ label: string;
33
+ /**
34
+ * 类型图标,与侧边栏图标同一协议。宿主声明时渲染一次并随笔记库保存:插件停用、卸载宽限期内,
35
+ * 搜索结果、正文中的引用、脉络等处仍按声明的类型名与图标显示。缺省为通用的插件图标。
36
+ */
37
+ icon?: PluginIcon;
38
+ /** 用户在 Tau 中打开这项内容时进入的插件页面;params 只能读取实体字段,不访问其他状态 */
39
+ open: {
40
+ page: string;
41
+ params?: (entity: PluginOwnEntity) => PluginPageParams;
42
+ };
43
+ /** 是否可在正文中用 @ 引用,默认 false */
44
+ mentionable?: boolean;
45
+ }
46
+ export interface PluginOwnEntityInput {
47
+ kind: string;
48
+ key: string;
49
+ title?: string;
50
+ meta?: PluginOwnEntityMeta;
51
+ }
52
+ export interface PluginOwnEntityPatch {
53
+ title?: string;
54
+ meta?: PluginOwnEntityMeta;
55
+ }
56
+ export interface PluginOwnEntityQuery {
57
+ kind?: string;
58
+ cursor?: string;
59
+ /** 默认 50,最多 200 */
60
+ limit?: number;
61
+ }
62
+ /** 正文里引用了这项内容的一处来源 */
63
+ export interface PluginOwnEntityBacklink {
64
+ /** 可交给 context.app.open 打开 */
65
+ ref: PluginEntityRef;
66
+ title: string;
67
+ /** 引用处的上下文:前文、链接文字、后文 */
68
+ snippets: {
69
+ before: string;
70
+ label: string;
71
+ after: string;
72
+ }[];
73
+ }
74
+ export interface PluginOwnEntities {
75
+ /** 声明一种内容类型;create 只接受已声明的类型 */
76
+ registerKind(definition: PluginOwnEntityKind): Disposable;
77
+ /** 新建一项,正文为空。同一类型下 key 已存在时抛出 PluginConflictError */
78
+ create(input: PluginOwnEntityInput): Promise<PluginOwnEntity>;
79
+ get(id: string): Promise<PluginOwnEntity | null>;
80
+ find(kind: string, key: string): Promise<PluginOwnEntity | null>;
81
+ /** 按创建时间倒序分页 */
82
+ query(query?: PluginOwnEntityQuery): Promise<PluginPage<PluginOwnEntity>>;
83
+ /** 修改标题或 meta;revision 不是最新时抛出 PluginConflictError */
84
+ update(id: string, patch: PluginOwnEntityPatch, options: PluginWriteOptions): Promise<PluginOwnEntity>;
85
+ /**
86
+ * 删除一项及其正文;revision 不是最新时抛出 PluginConflictError。用户可在插件详情页
87
+ * 「最近删除」中 7 天内恢复,恢复后 ID、key 与正文不变,指向它的引用重新生效。
88
+ */
89
+ delete(id: string, options: PluginWriteOptions): Promise<void>;
90
+ /**
91
+ * 哪些卡片、文章、项目文档在正文里引用了这项内容。只返回插件已获准读取的类型,不询问权限;
92
+ * 其余来源(未获准的类型、日记、其他插件的内容)只计入 omitted。
93
+ */
94
+ backlinks(id: string): Promise<{
95
+ items: PluginOwnEntityBacklink[];
96
+ omitted: number;
97
+ }>;
98
+ }
@@ -0,0 +1,5 @@
1
+ /** 写入时数据已被别处修改(expectedRevision 不是最新):重新读取后再决定是否重试 */
2
+ export declare class PluginConflictError extends Error {
3
+ readonly name = "PluginConflictError";
4
+ constructor(message?: string);
5
+ }
@@ -0,0 +1,30 @@
1
+ import type { Disposable } from "./contract";
2
+ import type { PluginPermission } from "./permissions";
3
+ /**
4
+ * 业务数据变更事件。事件只说明「哪一项变了」,不携带数据:需要时用 context.data 重新读取。
5
+ * 正文修改计入所属卡片、文章或项目文档的 updated;待办与日程只给出集合级变化。
6
+ */
7
+ export declare const PLUGIN_EVENT_TYPES: readonly ["card.created", "card.updated", "card.deleted", "article.created", "article.updated", "article.deleted", "document.created", "document.updated", "document.deleted", "todos.changed", "calendar.changed", "workspace.reset"];
8
+ export type PluginEventType = (typeof PLUGIN_EVENT_TYPES)[number];
9
+ /** 变化来自哪里:插件经 context.data / context.content 写入时为 plugin,其余(用户、同步、AI 等)为 app */
10
+ export type PluginEventOrigin = {
11
+ kind: "plugin";
12
+ pluginId: string;
13
+ } | {
14
+ kind: "app";
15
+ };
16
+ export interface PluginDomainEvent {
17
+ type: PluginEventType;
18
+ /** 实体事件给出与 context.data 相同的 ID;集合级事件没有 */
19
+ id?: string;
20
+ /** 宿主发出事件的时间(毫秒) */
21
+ at: number;
22
+ /** 用来忽略自己写入引起的事件;待办与日程的集合级事件恒为 app */
23
+ origin: PluginEventOrigin;
24
+ }
25
+ /** 接收事件需要对应数据的读取权限;未获准时事件不送达,也不会弹窗询问 */
26
+ export declare const PLUGIN_EVENT_PERMISSIONS: Record<PluginEventType, PluginPermission | null>;
27
+ export declare const isPluginEventType: (value: unknown) => value is PluginEventType;
28
+ export interface PluginEvents {
29
+ on(types: PluginEventType | readonly PluginEventType[], listener: (event: PluginDomainEvent) => void): Disposable;
30
+ }
@@ -0,0 +1,9 @@
1
+ import type { ComponentType, SVGProps } from "react";
2
+ /**
3
+ * 插件提供的图标:线性单色 SVG 组件(如 lucide-react 图标或自绘组件),用 currentColor 跟随主题。
4
+ * 侧边栏条目与内容类型共用这一协议;宿主统一传入 size、strokeWidth、className 与 aria-hidden。
5
+ */
6
+ export type PluginIconProps = SVGProps<SVGSVGElement> & {
7
+ size?: number | string;
8
+ };
9
+ export type PluginIcon = ComponentType<PluginIconProps>;
@@ -1,4 +1,5 @@
1
1
  import type { PluginDefinition } from "./contract";
2
+ export type { PluginBackendClient, BackendStatus, BackendState } from "./backend";
2
3
  export type * from "./upload";
3
4
  export type * from "./tts";
4
5
  export type * from "./images";
@@ -10,8 +11,20 @@ export * from "./editor";
10
11
  export { SourceBlockEditor, useSourceBlock, useReportPreviewError, insertSourceBlock, sourceBlockParagraphBehavior, } from "./source-editor";
11
12
  export type { SourceBlockEditorProps, PluginRuntimeStyleCompiler } from "./source-editor";
12
13
  export { useInlineSource, insertInlineSource, InlineSourceBoundary } from "./inline-source";
14
+ export { ContentEditor, ContentPreview } from "./components";
15
+ export type { ContentEditorProps, ContentPreviewProps } from "./components";
13
16
  export * from "./sidebar";
17
+ export type * from "./icons";
14
18
  export type * from "./excerpts";
19
+ export type * from "./data";
20
+ export type * from "./entities";
21
+ export { PluginConflictError } from "./errors";
22
+ export { PLUGIN_ENTITY_KINDS, PLUGIN_APP_ACTIONS, PLUGIN_EXPORT_FORMATS } from "./app";
23
+ export type { PluginApp, PluginAppAction, PluginAppActions, PluginExportFormat, PluginEntityKind, PluginEntityRef, PluginPickOptions, PluginPickedEntity, } from "./app";
24
+ export { PLUGIN_EVENT_TYPES } from "./events";
25
+ export type { PluginDomainEvent, PluginEventOrigin, PluginEventType, PluginEvents } from "./events";
26
+ export { PLUGIN_PERMISSIONS, PluginPermissionError, isPluginPermission } from "./permissions";
27
+ export type { PluginPermission, PluginPermissions, PluginPermissionState, PluginPermissionDenial, } from "./permissions";
15
28
  export type * from "./services";
16
29
  export { usePluginServices } from "./service-access";
17
30
  export type { PluginSkill } from "./skills";
@@ -1,10 +1,14 @@
1
1
  export { assertLocalId } from "./ids";
2
2
  import { type PluginCategory } from "./categories";
3
+ import { type PluginPermission } from "./permissions";
4
+ import { type PluginBackendManifest } from "./backend-manifest";
5
+ export { validateBackendManifest, PLUGIN_SYSTEM_ACCESS, type PluginBackendManifest, type PluginSystemAccess, } from "./backend-manifest";
3
6
  export { comparePluginVersions } from "./version";
4
7
  export { PLUGIN_CATEGORIES, PLUGIN_KEYWORD_LIMIT, PLUGIN_KEYWORD_MAX_LENGTH, isPluginCategory, type PluginCategory, } from "./categories";
8
+ export { PLUGIN_PERMISSIONS, isPluginPermission, type PluginPermission } from "./permissions";
5
9
  export declare const PLUGIN_SHARED_MODULES: readonly ["@tau/plugins", "@tau/plugins/whiteboard", "@tau/plugins/sync", "@tau/ui", "react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime"];
6
10
  export interface PluginManifest {
7
- formatVersion: 1;
11
+ formatVersion: 1 | 2;
8
12
  id: string;
9
13
  name: string;
10
14
  version: string;
@@ -13,7 +17,7 @@ export interface PluginManifest {
13
17
  platform: "desktop";
14
18
  format: "cjs";
15
19
  main: string;
16
- /** 无界面的同步存储入口,Node产物与UI入口分别校验。 */
20
+ backend?: PluginBackendManifest;
17
21
  styles?: string;
18
22
  /** 静态编辑器贡献在窗口启动时装配,启停需重启。 */
19
23
  editor?: true;
@@ -22,6 +26,8 @@ export interface PluginManifest {
22
26
  categories?: readonly PluginCategory[];
23
27
  /** 仅参与搜索匹配。 */
24
28
  keywords?: readonly string[];
29
+ /** 可申请的业务数据权限上限;实际授权由用户在调用时决定。 */
30
+ permissions?: readonly PluginPermission[];
25
31
  integrity: Record<string, string>;
26
32
  }
27
33
  /** 宿主内部传输的已读取产物,不属于作者运行时 API。 */
@@ -30,7 +36,7 @@ export interface DevelopmentPluginPackage {
30
36
  code: string;
31
37
  css?: string;
32
38
  }
33
- /** strict 供门户上传使用:分类或关键词不合规时报错,客户端默认静默丢弃。 */
39
+ /** strict 供门户上传使用:分类、关键词或权限不合规时报错,客户端默认静默丢弃。 */
34
40
  export declare function validatePluginManifest(value: unknown, options?: {
35
41
  strict?: boolean;
36
42
  }): PluginManifest;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 业务数据权限:manifest 的 permissions 声明插件可申请的上限,首次调用对应接口时由宿主
3
+ * 弹窗询问用户。read 读取,write 新建与修改(含正文),delete 删除(可在插件详情页恢复)。
4
+ * 插件与应用运行在同一环境,权限约束的是 SDK 接口,不是安全隔离。
5
+ */
6
+ export declare const PLUGIN_PERMISSIONS: readonly ["cards:read", "cards:write", "cards:delete", "articles:read", "articles:write", "articles:delete", "documents:read", "documents:write", "todos:read", "todos:write", "todos:delete", "calendar:read", "calendar:write", "calendar:delete"];
7
+ export type PluginPermission = (typeof PLUGIN_PERMISSIONS)[number];
8
+ export declare const isPluginPermission: (value: unknown) => value is PluginPermission;
9
+ /** granted:可直接调用;prompt:调用时会询问用户;denied:本次运行已拒绝或已被阻止 */
10
+ export type PluginPermissionState = "granted" | "prompt" | "denied";
11
+ /**
12
+ * undeclared:manifest 未声明;denied:用户拒绝;blocked:用户已阻止,需到插件详情页解除;
13
+ * unavailable:应用不在前台无法询问,请求已记入插件详情页等待用户处理。
14
+ */
15
+ export type PluginPermissionDenial = "undeclared" | "denied" | "blocked" | "unavailable";
16
+ export declare class PluginPermissionError extends Error {
17
+ readonly name = "PluginPermissionError";
18
+ readonly permission: PluginPermission;
19
+ readonly reason: PluginPermissionDenial;
20
+ constructor(permission: PluginPermission, reason: PluginPermissionDenial);
21
+ }
22
+ export interface PluginPermissions {
23
+ query(permission: PluginPermission): Promise<PluginPermissionState>;
24
+ /** 一次询问多项;全部获准时返回 true。已获准的不再询问。 */
25
+ request(permissions: readonly PluginPermission[]): Promise<boolean>;
26
+ }
27
+ /** 读取 manifest.permissions;strict 用于门户上传,客户端静默丢弃未知权限。 */
28
+ export declare function readPermissionsField(item: Record<string, unknown>, strict: boolean): {
29
+ permissions?: readonly PluginPermission[];
30
+ };
@@ -56,16 +56,6 @@ export interface PluginServices {
56
56
  css: string;
57
57
  }>;
58
58
  };
59
- typst: {
60
- compile(input: {
61
- source: string;
62
- format?: "html";
63
- inputs?: Record<string, string>;
64
- files?: ServiceFile[];
65
- }, options?: ServiceOptions): Promise<{
66
- html: string;
67
- }>;
68
- };
69
59
  markdown: {
70
60
  deserialize(source: string, options?: MarkdownServiceOptions): Promise<{
71
61
  nodes: Descendant[];
@@ -1,10 +1,10 @@
1
1
  import type { Disposable } from "./contract";
2
2
  import type { PluginPageHandle, PluginPageParams } from "./pages";
3
- import type { ComponentType, SVGProps } from "react";
4
- export type PluginSidebarIconProps = SVGProps<SVGSVGElement> & {
5
- size?: number | string;
6
- };
7
- export type PluginSidebarIcon = ComponentType<PluginSidebarIconProps>;
3
+ import type { PluginIcon, PluginIconProps } from "./icons";
4
+ /** 与 PluginIconProps 相同 */
5
+ export type PluginSidebarIconProps = PluginIconProps;
6
+ /** 与 PluginIcon 相同 */
7
+ export type PluginSidebarIcon = PluginIcon;
8
8
  export declare const SIDEBAR_GROUPS: Readonly<{
9
9
  readonly daily: "daily";
10
10
  readonly knowledge: "knowledge";
@@ -1,11 +1,11 @@
1
1
  /**
2
- * 统一实体地址:跨模块指向「一份正文的某个身份」(卡片、文章、项目文档、日记)。
2
+ * 统一实体地址:跨模块指向「一份正文的某个身份」(卡片、文章、项目文档、日记、插件内容)。
3
3
  *
4
4
  * 纯 TypeScript,桌面端与移动端共用。存量各处的类型写法(question_link 的 project_item、
5
5
  * content-link / 索引的 project-item)经 normalizeEntityRefKind 收口;
6
6
  * 日记正文身份为 diary-moment + 片段 id,存量日级引用在开库时转换。
7
7
  */
8
- export declare const ENTITY_REF_KINDS: readonly ["card", "article", "project-item", "diary-moment"];
8
+ export declare const ENTITY_REF_KINDS: readonly ["card", "article", "project-item", "diary-moment", "plugin-entity"];
9
9
  export type EntityRefKind = (typeof ENTITY_REF_KINDS)[number];
10
10
  export interface EntityRef {
11
11
  kind: EntityRefKind;
@@ -15,5 +15,5 @@ export interface EntityRef {
15
15
  export declare function normalizeEntityRefKind(raw: unknown): EntityRefKind | null;
16
16
  export declare const entityRefKey: (ref: EntityRef) => string;
17
17
  export declare const isSameEntityRef: (a: EntityRef, b: EntityRef) => boolean;
18
- /** 同一份正文被多个实体共用时,选哪个身份作代表:卡片 > 文章 > 项目文档 > 日记 */
18
+ /** 同一份正文被多个实体共用时,选哪个身份作代表:卡片 > 文章 > 项目文档 > 日记 > 插件内容 */
19
19
  export declare const ENTITY_REF_PRIORITY: Record<EntityRefKind, number>;