@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.
@@ -0,0 +1,281 @@
1
+ // packages/plugins/src/ids.ts
2
+ function assertLocalId(value) {
3
+ if (typeof value !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value)) {
4
+ throw new Error("\u63D2\u4EF6\u6807\u8BC6\u5FC5\u987B\u4E3A 1 \u81F3 128 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u6A2A\u7EBF\u6216\u4E0B\u5212\u7EBF");
5
+ }
6
+ }
7
+
8
+ // packages/plugins/src/version.ts
9
+ function parseVersion(value) {
10
+ const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(
11
+ value
12
+ );
13
+ if (!match) throw new Error(`\u7248\u672C\u53F7\u65E0\u6548\uFF1A${value}`);
14
+ const pre = match[4]?.split(".") ?? [];
15
+ if (pre.some((part) => /^\d+$/.test(part) && part.length > 1 && part.startsWith("0")))
16
+ throw new Error(`\u7248\u672C\u53F7\u65E0\u6548\uFF1A${value}`);
17
+ return { core: match.slice(1, 4), pre };
18
+ }
19
+ function comparePluginVersions(left, right) {
20
+ const a = parseVersion(left);
21
+ const b = parseVersion(right);
22
+ const numeric = (x, y) => BigInt(x) === BigInt(y) ? 0 : BigInt(x) > BigInt(y) ? 1 : -1;
23
+ for (let index = 0; index < 3; index++) {
24
+ const result = numeric(a.core[index], b.core[index]);
25
+ if (result) return result;
26
+ }
27
+ if (!a.pre.length || !b.pre.length)
28
+ return a.pre.length === b.pre.length ? 0 : a.pre.length ? -1 : 1;
29
+ for (let index = 0; index < Math.max(a.pre.length, b.pre.length); index++) {
30
+ const x = a.pre[index], y = b.pre[index];
31
+ if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
32
+ if (x === y) continue;
33
+ const nx = /^\d+$/.test(x), ny = /^\d+$/.test(y);
34
+ return nx && ny ? numeric(x, y) : nx !== ny ? nx ? -1 : 1 : x > y ? 1 : -1;
35
+ }
36
+ return 0;
37
+ }
38
+
39
+ // packages/plugins/src/categories.ts
40
+ var PLUGIN_CATEGORIES = [
41
+ { id: "sync", label: "\u540C\u6B65" },
42
+ { id: "upload", label: "\u8D44\u6E90\u4E0A\u4F20" },
43
+ { id: "editor", label: "\u7F16\u8F91\u5668" },
44
+ { id: "whiteboard", label: "\u767D\u677F" },
45
+ { id: "blog-template", label: "\u535A\u5BA2\u6A21\u677F" },
46
+ { id: "blog-publish", label: "\u535A\u5BA2\u53D1\u5E03" },
47
+ { id: "ai", label: "AI" },
48
+ { id: "voice", label: "\u8BED\u97F3" },
49
+ { id: "video", label: "\u5728\u7EBF\u89C6\u9891" },
50
+ { id: "page", label: "\u9875\u9762" }
51
+ ];
52
+ var PLUGIN_KEYWORD_LIMIT = 5;
53
+ var PLUGIN_KEYWORD_MAX_LENGTH = 20;
54
+ var categoryIds = new Set(PLUGIN_CATEGORIES.map((item) => item.id));
55
+ var isPluginCategory = (value) => typeof value === "string" && categoryIds.has(value);
56
+ function readCatalogFields(item, strict) {
57
+ const fail = (message) => {
58
+ if (strict) throw new Error(message);
59
+ };
60
+ const list = (value, name) => {
61
+ if (value === void 0) return [];
62
+ if (Array.isArray(value)) return value;
63
+ fail(`${name} \u5FC5\u987B\u662F\u6570\u7EC4`);
64
+ return [];
65
+ };
66
+ const categories = [];
67
+ for (const value of list(item.categories, "categories")) {
68
+ if (!isPluginCategory(value)) fail(`\u672A\u77E5\u63D2\u4EF6\u5206\u7C7B\uFF1A${String(value)}`);
69
+ else if (!categories.includes(value)) categories.push(value);
70
+ }
71
+ const keywords = [];
72
+ for (const value of list(item.keywords, "keywords")) {
73
+ const keyword = typeof value === "string" ? value.trim() : "";
74
+ if (!keyword || keyword.length > PLUGIN_KEYWORD_MAX_LENGTH)
75
+ fail(`\u5173\u952E\u8BCD\u5FC5\u987B\u4E3A 1 \u81F3 ${PLUGIN_KEYWORD_MAX_LENGTH} \u5B57`);
76
+ else if (!keywords.includes(keyword)) keywords.push(keyword);
77
+ }
78
+ if (keywords.length > PLUGIN_KEYWORD_LIMIT) {
79
+ fail(`\u5173\u952E\u8BCD\u6700\u591A ${PLUGIN_KEYWORD_LIMIT} \u4E2A`);
80
+ keywords.length = PLUGIN_KEYWORD_LIMIT;
81
+ }
82
+ return {
83
+ ...categories.length ? { categories: Object.freeze(categories) } : {},
84
+ ...keywords.length ? { keywords: Object.freeze(keywords) } : {}
85
+ };
86
+ }
87
+
88
+ // packages/plugins/src/permissions.ts
89
+ var PLUGIN_PERMISSIONS = [
90
+ "cards:read",
91
+ "cards:write",
92
+ "cards:delete",
93
+ "articles:read",
94
+ "articles:write",
95
+ "articles:delete",
96
+ "documents:read",
97
+ "documents:write",
98
+ "todos:read",
99
+ "todos:write",
100
+ "todos:delete",
101
+ "calendar:read",
102
+ "calendar:write",
103
+ "calendar:delete"
104
+ ];
105
+ var permissionIds = new Set(PLUGIN_PERMISSIONS);
106
+ var isPluginPermission = (value) => typeof value === "string" && permissionIds.has(value);
107
+ function readPermissionsField(item, strict) {
108
+ const fail = (message) => {
109
+ if (strict) throw new Error(message);
110
+ };
111
+ if (item.permissions === void 0) return {};
112
+ if (!Array.isArray(item.permissions)) {
113
+ fail("permissions \u5FC5\u987B\u662F\u6570\u7EC4");
114
+ return {};
115
+ }
116
+ const permissions = [];
117
+ for (const value of item.permissions) {
118
+ if (!isPluginPermission(value)) fail(`\u672A\u77E5\u63D2\u4EF6\u6743\u9650\uFF1A${String(value)}`);
119
+ else if (!permissions.includes(value)) permissions.push(value);
120
+ }
121
+ return permissions.length ? { permissions: Object.freeze(permissions) } : {};
122
+ }
123
+
124
+ // packages/plugins/src/backend-manifest.ts
125
+ var PLUGIN_SYSTEM_ACCESS = ["filesystem", "network", "process"];
126
+ function validateBackendManifest(value) {
127
+ if (!value || typeof value !== "object" || Array.isArray(value))
128
+ throw new Error("\u540E\u53F0\u58F0\u660E\u5FC5\u987B\u662F\u5BF9\u8C61");
129
+ const item = value;
130
+ const keys = [
131
+ "entry",
132
+ "runtime",
133
+ "apiVersion",
134
+ "scope",
135
+ "activation",
136
+ "lifetime",
137
+ "reason",
138
+ "systemAccess",
139
+ "tools"
140
+ ];
141
+ if (Object.keys(item).some((key) => !keys.includes(key))) throw new Error("\u540E\u53F0\u58F0\u660E\u5305\u542B\u672A\u77E5\u5B57\u6BB5");
142
+ if (typeof item.entry !== "string" || !/^[\w./-]+\.js$/.test(item.entry) || item.entry.split("/").some((part) => !part || part === "." || part === ".."))
143
+ throw new Error("\u540E\u53F0\u5165\u53E3\u5FC5\u987B\u662F\u5305\u5185 JS \u6587\u4EF6");
144
+ if (item.runtime !== "node" || item.apiVersion !== 1)
145
+ throw new Error("\u540E\u53F0\u8FD0\u884C\u65F6\u6216\u534F\u8BAE\u7248\u672C\u4E0D\u517C\u5BB9");
146
+ if (item.scope !== "application" && item.scope !== "workspace") throw new Error("\u540E\u53F0\u4F5C\u7528\u57DF\u65E0\u6548");
147
+ if (item.activation !== "on-demand" && item.activation !== "app-ready" && item.activation !== "workspace-ready")
148
+ throw new Error("\u540E\u53F0\u6FC0\u6D3B\u65F6\u673A\u65E0\u6548");
149
+ if (item.activation !== "on-demand" && item.activation !== (item.scope === "application" ? "app-ready" : "workspace-ready"))
150
+ throw new Error("\u540E\u53F0\u6FC0\u6D3B\u65F6\u673A\u4E0E\u4F5C\u7528\u57DF\u4E0D\u5339\u914D");
151
+ if (item.lifetime !== "idle" && item.lifetime !== "persistent")
152
+ throw new Error("\u540E\u53F0\u751F\u547D\u5468\u671F\u65E0\u6548");
153
+ if (typeof item.reason !== "string" || !item.reason.trim() || item.reason.length > 500)
154
+ throw new Error("\u540E\u53F0\u7528\u9014\u5FC5\u987B\u4E3A 1 \u81F3 500 \u5B57");
155
+ if (!Array.isArray(item.systemAccess) || new Set(item.systemAccess).size !== item.systemAccess.length || item.systemAccess.some((value2) => !PLUGIN_SYSTEM_ACCESS.includes(value2)))
156
+ throw new Error("\u540E\u53F0\u7CFB\u7EDF\u7528\u9014\u5206\u7C7B\u65E0\u6548");
157
+ let tools;
158
+ if (item.tools !== void 0) {
159
+ if (!Array.isArray(item.tools) || item.tools.length > 32 || !item.systemAccess.includes("process"))
160
+ throw new Error("\u5916\u90E8\u5DE5\u5177\u987B\u58F0\u660E process \u7528\u9014\uFF0C\u6700\u591A 32 \u9879");
161
+ const ids = /* @__PURE__ */ new Set();
162
+ tools = Object.freeze(
163
+ item.tools.map((tool) => {
164
+ if (!tool || typeof tool !== "object" || Array.isArray(tool))
165
+ throw new Error("\u5916\u90E8\u5DE5\u5177\u58F0\u660E\u65E0\u6548");
166
+ const value2 = tool;
167
+ if (Object.keys(value2).some((key) => !["id", "command", "args"].includes(key)) || typeof value2.id !== "string" || !/^[a-z][\w.-]{0,63}$/.test(value2.id) || ids.has(value2.id) || typeof value2.command !== "string" || !value2.command.trim() || value2.command.length > 1024 || /[\0\r\n]/.test(value2.command))
168
+ throw new Error("\u5916\u90E8\u5DE5\u5177\u8EAB\u4EFD\u6216\u547D\u4EE4\u65E0\u6548");
169
+ ids.add(value2.id);
170
+ if (value2.args !== void 0 && (!Array.isArray(value2.args) || value2.args.length > 64 || value2.args.some(
171
+ (arg) => typeof arg !== "string" || arg.length > 4096 || arg.includes("\0")
172
+ )))
173
+ throw new Error("\u5916\u90E8\u5DE5\u5177\u53C2\u6570\u65E0\u6548");
174
+ return Object.freeze({
175
+ id: value2.id,
176
+ command: value2.command,
177
+ ...value2.args ? { args: Object.freeze([...value2.args]) } : {}
178
+ });
179
+ })
180
+ );
181
+ }
182
+ return Object.freeze({
183
+ ...tools ? { tools } : {},
184
+ entry: item.entry,
185
+ runtime: "node",
186
+ apiVersion: 1,
187
+ scope: item.scope,
188
+ activation: item.activation,
189
+ lifetime: item.lifetime,
190
+ reason: item.reason.trim(),
191
+ systemAccess: Object.freeze([...item.systemAccess])
192
+ });
193
+ }
194
+
195
+ // packages/plugins/src/package.ts
196
+ var PLUGIN_SHARED_MODULES = [
197
+ "@tau/plugins",
198
+ "@tau/plugins/whiteboard",
199
+ "@tau/plugins/sync",
200
+ "@tau/ui",
201
+ "react",
202
+ "react-dom",
203
+ "react-dom/client",
204
+ "react/jsx-runtime",
205
+ "react/jsx-dev-runtime"
206
+ ];
207
+ function validatePluginManifest(value, options = {}) {
208
+ if (!value || typeof value !== "object" || Array.isArray(value))
209
+ throw new Error("\u63D2\u4EF6\u6E05\u5355\u5FC5\u987B\u662F\u5BF9\u8C61");
210
+ const item = value;
211
+ if (item.formatVersion !== 1 && item.formatVersion !== 2 || item.apiVersion !== 1 || item.platform !== "desktop" || item.format !== "cjs")
212
+ throw new Error("\u63D2\u4EF6\u5305\u683C\u5F0F\u3001API \u7248\u672C\u6216\u5E73\u53F0\u4E0D\u517C\u5BB9");
213
+ if (typeof item.id !== "string") throw new Error("\u63D2\u4EF6 ID \u65E0\u6548");
214
+ assertLocalId(item.id);
215
+ if (typeof item.name !== "string" || !item.name.trim() || typeof item.version !== "string" || !/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(item.version))
216
+ throw new Error("\u63D2\u4EF6\u540D\u79F0\u6216\u7248\u672C\u65E0\u6548");
217
+ const file = (input, extension) => {
218
+ if (typeof input !== "string" || !/^[\w./-]+$/.test(input) || input.split("/").some((part) => !part || part === "." || part === "..") || !input.endsWith(extension))
219
+ throw new Error("\u63D2\u4EF6\u5165\u53E3\u6216\u6837\u5F0F\u8DEF\u5F84\u65E0\u6548");
220
+ return input;
221
+ };
222
+ const main = file(item.main, ".js");
223
+ const backend = item.backend === void 0 ? void 0 : validateBackendManifest(item.backend);
224
+ if (item.formatVersion === 2 !== Boolean(backend))
225
+ throw new Error("\u540E\u53F0\u58F0\u660E\u5FC5\u987B\u4F7F\u7528\u5305\u683C\u5F0F 2\uFF0C\u666E\u901A\u63D2\u4EF6\u4F7F\u7528\u683C\u5F0F 1");
226
+ if (backend?.entry === main) throw new Error("\u540E\u53F0\u5165\u53E3\u4E0D\u80FD\u4E0E\u6E32\u67D3\u5165\u53E3\u76F8\u540C");
227
+ if (backend && typeof item.minAppVersion !== "string")
228
+ throw new Error("\u540E\u53F0\u63D2\u4EF6\u5FC5\u987B\u58F0\u660E\u6700\u4F4E\u5BA2\u6237\u7AEF\u7248\u672C");
229
+ if (item.minAppVersion !== void 0) {
230
+ if (typeof item.minAppVersion !== "string") throw new Error("\u6700\u4F4E\u5BA2\u6237\u7AEF\u7248\u672C\u65E0\u6548");
231
+ comparePluginVersions(item.minAppVersion, item.minAppVersion);
232
+ }
233
+ const styles = item.styles === void 0 ? void 0 : file(item.styles, ".css");
234
+ if (item.editor !== void 0 && item.editor !== true) throw new Error("editor \u53EA\u80FD\u58F0\u660E\u4E3A true");
235
+ if (item.whiteboard !== void 0 && item.whiteboard !== true)
236
+ throw new Error("whiteboard \u53EA\u80FD\u58F0\u660E\u4E3A true");
237
+ const catalog = readCatalogFields(item, options.strict === true);
238
+ const permissions = readPermissionsField(item, options.strict === true);
239
+ const integrity = {};
240
+ for (const name of [main, ...styles ? [styles] : [], ...backend ? [backend.entry] : []]) {
241
+ const hash = item.integrity && typeof item.integrity === "object" ? item.integrity[name] : void 0;
242
+ if (typeof hash !== "string" || !/^[a-f0-9]{64}$/.test(hash))
243
+ throw new Error("\u63D2\u4EF6\u4EA7\u7269\u7F3A\u5C11\u6709\u6548\u7684\u5B8C\u6574\u6027\u6458\u8981");
244
+ integrity[name] = hash;
245
+ }
246
+ return Object.freeze({
247
+ formatVersion: item.formatVersion,
248
+ id: item.id,
249
+ name: item.name,
250
+ version: item.version,
251
+ ...typeof item.minAppVersion === "string" ? { minAppVersion: item.minAppVersion } : {},
252
+ apiVersion: 1,
253
+ platform: "desktop",
254
+ format: "cjs",
255
+ main,
256
+ ...backend ? { backend } : {},
257
+ ...item.editor === true ? { editor: true } : {},
258
+ ...item.whiteboard === true ? { whiteboard: true } : {},
259
+ ...catalog,
260
+ ...permissions,
261
+ integrity: Object.freeze(integrity),
262
+ ...styles === void 0 ? {} : { styles }
263
+ });
264
+ }
265
+ var isContentPlugin = (manifest) => manifest.editor === true || manifest.whiteboard === true;
266
+
267
+ export {
268
+ assertLocalId,
269
+ comparePluginVersions,
270
+ PLUGIN_CATEGORIES,
271
+ PLUGIN_KEYWORD_LIMIT,
272
+ PLUGIN_KEYWORD_MAX_LENGTH,
273
+ isPluginCategory,
274
+ PLUGIN_PERMISSIONS,
275
+ isPluginPermission,
276
+ PLUGIN_SYSTEM_ACCESS,
277
+ validateBackendManifest,
278
+ PLUGIN_SHARED_MODULES,
279
+ validatePluginManifest,
280
+ isContentPlugin
281
+ };
package/package.js ADDED
@@ -0,0 +1,30 @@
1
+ import {
2
+ PLUGIN_CATEGORIES,
3
+ PLUGIN_KEYWORD_LIMIT,
4
+ PLUGIN_KEYWORD_MAX_LENGTH,
5
+ PLUGIN_PERMISSIONS,
6
+ PLUGIN_SHARED_MODULES,
7
+ PLUGIN_SYSTEM_ACCESS,
8
+ assertLocalId,
9
+ comparePluginVersions,
10
+ isContentPlugin,
11
+ isPluginCategory,
12
+ isPluginPermission,
13
+ validateBackendManifest,
14
+ validatePluginManifest
15
+ } from "./client/chunk-GQO6J7O3.js";
16
+ export {
17
+ PLUGIN_CATEGORIES,
18
+ PLUGIN_KEYWORD_LIMIT,
19
+ PLUGIN_KEYWORD_MAX_LENGTH,
20
+ PLUGIN_PERMISSIONS,
21
+ PLUGIN_SHARED_MODULES,
22
+ PLUGIN_SYSTEM_ACCESS,
23
+ assertLocalId,
24
+ comparePluginVersions,
25
+ isContentPlugin,
26
+ isPluginCategory,
27
+ isPluginPermission,
28
+ validateBackendManifest,
29
+ validatePluginManifest
30
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiongtao.xt/tau-plugins",
3
- "version": "0.23.1",
3
+ "version": "0.25.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,6 +18,14 @@
18
18
  "default": "./runtime.js"
19
19
  },
20
20
  "./tailwind.css": "./tailwind.css",
21
+ "./package": {
22
+ "types": "./types/packages/plugins/src/package.d.ts",
23
+ "default": "./package.js"
24
+ },
25
+ "./backend": {
26
+ "types": "./types/packages/plugins/src/backend.d.ts",
27
+ "default": "./runtime.js"
28
+ },
21
29
  "./sync": {
22
30
  "types": "./types/packages/plugins/src/sync.d.ts",
23
31
  "default": "./runtime.js"
@@ -1,152 +1,7 @@
1
- // packages/plugins/src/ids.ts
2
- function assertLocalId(value) {
3
- if (typeof value !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value)) {
4
- throw new Error("\u63D2\u4EF6\u6807\u8BC6\u5FC5\u987B\u4E3A 1 \u81F3 128 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u6A2A\u7EBF\u6216\u4E0B\u5212\u7EBF");
5
- }
6
- }
7
-
8
- // packages/plugins/src/version.ts
9
- function parseVersion(value) {
10
- const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(
11
- value
12
- );
13
- if (!match) throw new Error(`\u7248\u672C\u53F7\u65E0\u6548\uFF1A${value}`);
14
- const pre = match[4]?.split(".") ?? [];
15
- if (pre.some((part) => /^\d+$/.test(part) && part.length > 1 && part.startsWith("0")))
16
- throw new Error(`\u7248\u672C\u53F7\u65E0\u6548\uFF1A${value}`);
17
- return { core: match.slice(1, 4), pre };
18
- }
19
- function comparePluginVersions(left, right) {
20
- const a = parseVersion(left);
21
- const b = parseVersion(right);
22
- const numeric = (x, y) => BigInt(x) === BigInt(y) ? 0 : BigInt(x) > BigInt(y) ? 1 : -1;
23
- for (let index = 0; index < 3; index++) {
24
- const result = numeric(a.core[index], b.core[index]);
25
- if (result) return result;
26
- }
27
- if (!a.pre.length || !b.pre.length)
28
- return a.pre.length === b.pre.length ? 0 : a.pre.length ? -1 : 1;
29
- for (let index = 0; index < Math.max(a.pre.length, b.pre.length); index++) {
30
- const x = a.pre[index], y = b.pre[index];
31
- if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
32
- if (x === y) continue;
33
- const nx = /^\d+$/.test(x), ny = /^\d+$/.test(y);
34
- return nx && ny ? numeric(x, y) : nx !== ny ? nx ? -1 : 1 : x > y ? 1 : -1;
35
- }
36
- return 0;
37
- }
38
-
39
- // packages/plugins/src/categories.ts
40
- var PLUGIN_CATEGORIES = [
41
- { id: "sync", label: "\u540C\u6B65" },
42
- { id: "upload", label: "\u8D44\u6E90\u4E0A\u4F20" },
43
- { id: "editor", label: "\u7F16\u8F91\u5668" },
44
- { id: "whiteboard", label: "\u767D\u677F" },
45
- { id: "blog-template", label: "\u535A\u5BA2\u6A21\u677F" },
46
- { id: "blog-publish", label: "\u535A\u5BA2\u53D1\u5E03" },
47
- { id: "ai", label: "AI" },
48
- { id: "voice", label: "\u8BED\u97F3" },
49
- { id: "video", label: "\u5728\u7EBF\u89C6\u9891" },
50
- { id: "page", label: "\u9875\u9762" }
51
- ];
52
- var PLUGIN_KEYWORD_LIMIT = 5;
53
- var PLUGIN_KEYWORD_MAX_LENGTH = 20;
54
- var categoryIds = new Set(PLUGIN_CATEGORIES.map((item) => item.id));
55
- var isPluginCategory = (value) => typeof value === "string" && categoryIds.has(value);
56
- function readCatalogFields(item, strict) {
57
- const fail = (message) => {
58
- if (strict) throw new Error(message);
59
- };
60
- const list = (value, name) => {
61
- if (value === void 0) return [];
62
- if (Array.isArray(value)) return value;
63
- fail(`${name} \u5FC5\u987B\u662F\u6570\u7EC4`);
64
- return [];
65
- };
66
- const categories = [];
67
- for (const value of list(item.categories, "categories")) {
68
- if (!isPluginCategory(value)) fail(`\u672A\u77E5\u63D2\u4EF6\u5206\u7C7B\uFF1A${String(value)}`);
69
- else if (!categories.includes(value)) categories.push(value);
70
- }
71
- const keywords = [];
72
- for (const value of list(item.keywords, "keywords")) {
73
- const keyword = typeof value === "string" ? value.trim() : "";
74
- if (!keyword || keyword.length > PLUGIN_KEYWORD_MAX_LENGTH)
75
- fail(`\u5173\u952E\u8BCD\u5FC5\u987B\u4E3A 1 \u81F3 ${PLUGIN_KEYWORD_MAX_LENGTH} \u5B57`);
76
- else if (!keywords.includes(keyword)) keywords.push(keyword);
77
- }
78
- if (keywords.length > PLUGIN_KEYWORD_LIMIT) {
79
- fail(`\u5173\u952E\u8BCD\u6700\u591A ${PLUGIN_KEYWORD_LIMIT} \u4E2A`);
80
- keywords.length = PLUGIN_KEYWORD_LIMIT;
81
- }
82
- return {
83
- ...categories.length ? { categories: Object.freeze(categories) } : {},
84
- ...keywords.length ? { keywords: Object.freeze(keywords) } : {}
85
- };
86
- }
87
-
88
- // packages/plugins/src/package.ts
89
- var PLUGIN_SHARED_MODULES = [
90
- "@tau/plugins",
91
- "@tau/plugins/whiteboard",
92
- "@tau/plugins/sync",
93
- "@tau/ui",
94
- "react",
95
- "react-dom",
96
- "react-dom/client",
97
- "react/jsx-runtime",
98
- "react/jsx-dev-runtime"
99
- ];
100
- function validatePluginManifest(value, options = {}) {
101
- if (!value || typeof value !== "object" || Array.isArray(value))
102
- throw new Error("\u63D2\u4EF6\u6E05\u5355\u5FC5\u987B\u662F\u5BF9\u8C61");
103
- const item = value;
104
- if (item.formatVersion !== 1 || item.apiVersion !== 1 || item.platform !== "desktop" || item.format !== "cjs")
105
- throw new Error("\u63D2\u4EF6\u5305\u683C\u5F0F\u3001API \u7248\u672C\u6216\u5E73\u53F0\u4E0D\u517C\u5BB9");
106
- if (typeof item.id !== "string") throw new Error("\u63D2\u4EF6 ID \u65E0\u6548");
107
- assertLocalId(item.id);
108
- if (typeof item.name !== "string" || !item.name.trim() || typeof item.version !== "string" || !/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(item.version))
109
- throw new Error("\u63D2\u4EF6\u540D\u79F0\u6216\u7248\u672C\u65E0\u6548");
110
- const file = (input, extension) => {
111
- if (typeof input !== "string" || !/^[\w./-]+$/.test(input) || input.split("/").some((part) => !part || part === "." || part === "..") || !input.endsWith(extension))
112
- throw new Error("\u63D2\u4EF6\u5165\u53E3\u6216\u6837\u5F0F\u8DEF\u5F84\u65E0\u6548");
113
- return input;
114
- };
115
- const main = file(item.main, ".js");
116
- if (item.sync !== void 0) throw new Error("Node\u540C\u6B65\u5165\u53E3\u5DF2\u505C\u7528\uFF0C\u8BF7\u66F4\u65B0\u63D2\u4EF6");
117
- if (item.minAppVersion !== void 0) {
118
- if (typeof item.minAppVersion !== "string") throw new Error("\u6700\u4F4E\u5BA2\u6237\u7AEF\u7248\u672C\u65E0\u6548");
119
- comparePluginVersions(item.minAppVersion, item.minAppVersion);
120
- }
121
- const styles = item.styles === void 0 ? void 0 : file(item.styles, ".css");
122
- if (item.editor !== void 0 && item.editor !== true) throw new Error("editor \u53EA\u80FD\u58F0\u660E\u4E3A true");
123
- if (item.whiteboard !== void 0 && item.whiteboard !== true)
124
- throw new Error("whiteboard \u53EA\u80FD\u58F0\u660E\u4E3A true");
125
- const catalog = readCatalogFields(item, options.strict === true);
126
- const integrity = {};
127
- for (const name of [main, ...styles ? [styles] : []]) {
128
- const hash = item.integrity && typeof item.integrity === "object" ? item.integrity[name] : void 0;
129
- if (typeof hash !== "string" || !/^[a-f0-9]{64}$/.test(hash))
130
- throw new Error("\u63D2\u4EF6\u4EA7\u7269\u7F3A\u5C11\u6709\u6548\u7684\u5B8C\u6574\u6027\u6458\u8981");
131
- integrity[name] = hash;
132
- }
133
- return Object.freeze({
134
- formatVersion: 1,
135
- id: item.id,
136
- name: item.name,
137
- version: item.version,
138
- ...typeof item.minAppVersion === "string" ? { minAppVersion: item.minAppVersion } : {},
139
- apiVersion: 1,
140
- platform: "desktop",
141
- format: "cjs",
142
- main,
143
- ...item.editor === true ? { editor: true } : {},
144
- ...item.whiteboard === true ? { whiteboard: true } : {},
145
- ...catalog,
146
- integrity: Object.freeze(integrity),
147
- ...styles === void 0 ? {} : { styles }
148
- });
149
- }
1
+ import {
2
+ PLUGIN_SHARED_MODULES,
3
+ validatePluginManifest
4
+ } from "./client/chunk-GQO6J7O3.js";
150
5
 
151
6
  // packages/plugins/src/rendering.ts
152
7
  var PLUGIN_RENDER_VERSION = 1;
@@ -0,0 +1,55 @@
1
+ import type { PluginContentRef } from "./data";
2
+ /**
3
+ * 关联与打开已有内容:插件页面(如自建画布)引用用户的卡片、日记、待办等,并在点击时打开。
4
+ * 引用可以序列化后存入插件自己的数据;id 与 context.data 中同类实体的 id 一致。
5
+ */
6
+ export type PluginEntityKind = "card" | "article" | "document" | "diary" | "whiteboard" | "todo" | "event";
7
+ export declare const PLUGIN_ENTITY_KINDS: readonly PluginEntityKind[];
8
+ export interface PluginEntityRef {
9
+ kind: PluginEntityKind;
10
+ id: string;
11
+ }
12
+ /** 用户选中的一项:标题是选择时的快照,之后的改名需要读取权限才能取到 */
13
+ export interface PluginPickedEntity {
14
+ ref: PluginEntityRef;
15
+ title: string;
16
+ }
17
+ export interface PluginPickOptions {
18
+ /** 可选类型,顺序即弹窗中的分组顺序 */
19
+ kinds: readonly PluginEntityKind[];
20
+ /** 默认 false:点选一项即确认 */
21
+ multiple?: boolean;
22
+ /** 弹窗标题,默认「选择要关联的内容」 */
23
+ title?: string;
24
+ }
25
+ export type PluginExportFormat = "markdown" | "image" | "pdf" | "epub";
26
+ export declare const PLUGIN_EXPORT_FORMATS: readonly PluginExportFormat[];
27
+ /** 宿主动作:界面与确认都由 Tau 提供,插件拿不到正文;目前支持卡片、文章与项目文档的正文 */
28
+ export interface PluginAppActions {
29
+ /** Markdown 直接保存文件;图片、PDF、EPUB 打开导出窗口 */
30
+ "content.export": {
31
+ ref: PluginContentRef;
32
+ format: PluginExportFormat;
33
+ };
34
+ /** 全屏演示 */
35
+ "content.present": {
36
+ ref: PluginContentRef;
37
+ };
38
+ /** 打开「内容协作」窗口,由用户确认发起共享或管理成员 */
39
+ "content.share": {
40
+ ref: PluginContentRef;
41
+ };
42
+ }
43
+ export type PluginAppAction = keyof PluginAppActions;
44
+ export declare const PLUGIN_APP_ACTIONS: readonly PluginAppAction[];
45
+ export interface PluginApp {
46
+ /**
47
+ * 打开 Tau 的搜索选择弹窗,返回用户选中的内容;用户取消时返回空数组。
48
+ * 用户亲手挑选即视为同意插件引用这些内容,不需要读取权限。只能在用户操作(点击、按键)后调用。
49
+ */
50
+ pick(options: PluginPickOptions): Promise<PluginPickedEntity[]>;
51
+ /** 打开对应的页面:卡片详情、日记当天、待办详情、日程详情等。只能在用户操作后调用;内容已删除时抛错。 */
52
+ open(ref: PluginEntityRef): Promise<void>;
53
+ /** 执行宿主动作,对应界面打开后返回。只能在用户操作后调用;不需要数据权限;内容已删除时抛错。 */
54
+ run<A extends PluginAppAction>(action: A, options: PluginAppActions[A]): Promise<void>;
55
+ }
@@ -0,0 +1,19 @@
1
+ export declare const PLUGIN_SYSTEM_ACCESS: readonly ["filesystem", "network", "process"];
2
+ export type PluginSystemAccess = (typeof PLUGIN_SYSTEM_ACCESS)[number];
3
+ export interface PluginBackendManifest {
4
+ tools?: readonly {
5
+ id: string;
6
+ command: string;
7
+ args?: readonly string[];
8
+ }[];
9
+ entry: string;
10
+ runtime: "node";
11
+ apiVersion: 1;
12
+ scope: "application" | "workspace";
13
+ activation: "on-demand" | "app-ready" | "workspace-ready";
14
+ lifetime: "idle" | "persistent";
15
+ reason: string;
16
+ /** 系统用途披露,不表示操作系统级权限限制。 */
17
+ systemAccess: readonly PluginSystemAccess[];
18
+ }
19
+ export declare function validateBackendManifest(value: unknown): PluginBackendManifest;
@@ -0,0 +1,65 @@
1
+ import type { JsonValue } from "./json";
2
+ export type { JsonValue } from "./json";
3
+ export type { PluginBackendManifest } from "./backend-manifest";
4
+ export type BackendState = "stopped" | "starting" | "running" | "draining" | "failed" | "blocked";
5
+ export interface BackendStatus {
6
+ state: BackendState;
7
+ generation?: string;
8
+ pid?: number;
9
+ error?: string;
10
+ diagnostics?: {
11
+ startedAt: number;
12
+ startupMs?: number;
13
+ failures: number;
14
+ timeouts: number;
15
+ };
16
+ resources?: {
17
+ cpuPercent: number;
18
+ memoryKiB: number;
19
+ };
20
+ }
21
+ export interface BackendDisposable {
22
+ dispose(): void | Promise<void>;
23
+ }
24
+ export interface BackendSchema<T extends JsonValue = JsonValue> {
25
+ parse(value: unknown): T;
26
+ }
27
+ export interface PluginBackendClient {
28
+ call(method: string, input: JsonValue, options?: {
29
+ signal?: AbortSignal;
30
+ }): Promise<JsonValue>;
31
+ subscribe(event: string, listener: (value: JsonValue) => void): BackendDisposable;
32
+ getState(): Promise<BackendStatus>;
33
+ }
34
+ export interface BackendContext {
35
+ readonly process: {
36
+ run(toolId: string, args?: readonly string[], options?: {
37
+ signal?: AbortSignal;
38
+ }): Promise<BackendProcessResult>;
39
+ };
40
+ readonly pluginId: string;
41
+ readonly workspaceId: string | null;
42
+ readonly signal: AbortSignal;
43
+ register(resource: BackendDisposable): BackendDisposable;
44
+ readonly rpc: {
45
+ register<I extends JsonValue, O extends JsonValue>(method: string, schemas: {
46
+ input: BackendSchema<I>;
47
+ output: BackendSchema<O>;
48
+ }, handler: (input: I, request: {
49
+ signal: AbortSignal;
50
+ }) => O | Promise<O>): BackendDisposable;
51
+ emit(event: string, value: JsonValue): void;
52
+ };
53
+ }
54
+ export interface BackendProcessResult {
55
+ exitCode: number;
56
+ stdout: string;
57
+ stderr: string;
58
+ }
59
+ export interface BackendDefinition {
60
+ create(): {
61
+ activate(context: BackendContext): void | Promise<void>;
62
+ deactivate?(): void | Promise<void>;
63
+ };
64
+ }
65
+ export declare function defineBackend(definition: BackendDefinition): BackendDefinition;
@@ -0,0 +1,30 @@
1
+ import type { ReactElement } from "react";
2
+ import type { PluginContentRef } from "./data";
3
+ /**
4
+ * 与卡片详情相同的正文编辑器:协作、内置与已安装的编辑器扩展、文档待办都由宿主提供。
5
+ * 可编辑需要所属实体的写入权限,只读需要读取权限;未授权时显示「允许访问」,由用户点击后询问。
6
+ * 只能在插件页面内使用。
7
+ */
8
+ export interface ContentEditorProps {
9
+ contentRef: PluginContentRef;
10
+ /** 默认 false */
11
+ readonly?: boolean;
12
+ /** 正文为空时的提示文字 */
13
+ placeholder?: string;
14
+ /** 打开后滚动并闪烁到的位置:从 Tau 打开插件内容时页面参数 params.at 原样传入 */
15
+ at?: string;
16
+ }
17
+ /** 正文开头几块的只读渲染,用于列表与卡面;需要所属实体的读取权限。 */
18
+ export interface ContentPreviewProps {
19
+ contentRef: PluginContentRef;
20
+ /** 显示的块数,默认 3 */
21
+ maxBlocks?: number;
22
+ }
23
+ /** 宿主注入的实现;SDK 根入口只引用 React 类型,不加载 React 运行时。 */
24
+ export interface ContentComponentsRuntime {
25
+ ContentEditor(props: ContentEditorProps): ReactElement | null;
26
+ ContentPreview(props: ContentPreviewProps): ReactElement | null;
27
+ }
28
+ export declare function configureContentComponents(value: ContentComponentsRuntime): void;
29
+ export declare const ContentEditor: (props: ContentEditorProps) => ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | null;
30
+ export declare const ContentPreview: (props: ContentPreviewProps) => ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | null;