@linkdesk/plugin-sdk 0.1.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.
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # @linkdesk/plugin-sdk
2
+
3
+ LinkDesk 插件作者 SDK——对标 `@types/vscode`:装一个包,拿到 **`window.linkdesk.*` 类型提示 + 一键构建 `.linkdesk-plugin` + plugin.json 验证**。零壳源码依赖。
4
+
5
+ > 类型真相源 = `@linkdesk/contracts`(本包依赖转发,不复制生成物——契约漂移 → 你的 tsc 立即红)。
6
+ > 插件作者写代码一律走 `window.linkdesk.*`(preload 注入),**禁止 `import @src/core`**。
7
+
8
+ ## 安装
9
+
10
+ ```bash
11
+ npm install -D @linkdesk/plugin-sdk
12
+ ```
13
+
14
+ ## 使用
15
+
16
+ ### 1. tsconfig——让 `window.linkdesk.` 有类型
17
+
18
+ ```jsonc
19
+ {
20
+ "compilerOptions": {
21
+ "types": ["@linkdesk/plugin-sdk"], // 全局 window.linkdesk 声明随契约注入
22
+ "jsx": "react-jsx"
23
+ }
24
+ }
25
+ ```
26
+
27
+ 不建任何 global.d.ts。`.ts/.tsx` 里 `window.linkdesk.tabs.create({...})` 直接有参数类型与返回类型检查。
28
+
29
+ ### 2. plugin.json——声明插件(必填 `name`+`version`,可注释/尾逗号)
30
+
31
+ ```jsonc
32
+ {
33
+ "name": "My Plugin", // 显示名
34
+ "version": "1.0.0",
35
+ "entry": "src/index.tsx", // view/card/protocol 型插件必需
36
+ "contributes": { "i18n": { "en": "i18n/en.json" } }
37
+ }
38
+ ```
39
+
40
+ ### 3. 构建——产出 `.linkdesk-plugin` 分发文件
41
+
42
+ ```bash
43
+ npm run build # 包自带 bin,等价 linkdesk-plugin-sdk build
44
+ ```
45
+
46
+ 构建自动完成:**validate plugin.json → Vite 打包 `src/index.tsx` 为 `index.bundle.js` → 收拢 manifest/图标/i18n/README 进 `dist/<id>.linkdesk-plugin/` → zip 成项目根 `<id>.linkdesk-plugin`**。
47
+
48
+ - `react` / `react-dom` / `react-i18next` / `i18next` 由壳提供,**不打包**——其他依赖全部 inline,插件自包含。
49
+ - 插件 id = `plugin.json` 的 `pluginId` 字段;不声明则以**项目目录名**兜底(对齐壳加载契约)。
50
+ - 想自定义入口/输出目录/额外 external:
51
+ ```js
52
+ // vite.config.ts
53
+ import { defineLinkdeskPluginConfig } from "@linkdesk/plugin-sdk";
54
+ export default defineLinkdeskPluginConfig({ entry: "src/index.tsx", outDir: "dist" });
55
+ ```
56
+
57
+ ### 单独校验
58
+
59
+ ```bash
60
+ npm run validate # 或 linkdesk-plugin-sdk validate ./plugin.json
61
+ ```
62
+
63
+ ### index.bundle.js 约定
64
+
65
+ 打包产物 `export default` 一个 React 组件——壳以 `{ isActive }` 渲染它:
66
+
67
+ ```tsx
68
+ export default function MyView({ isActive }: { isActive: boolean }) {
69
+ return <div>Hello LinkDesk</div>;
70
+ }
71
+ ```
72
+
73
+ ## 限制
74
+
75
+ - **dev 预览**(壳内源码 glob 加载)对 plugin.json 走严格 JSON 解析;本 SDK validate 容忍注释/尾逗号是发布向能力——若插件要在 dev 预览跑,plugin.json 请保持无注释。
76
+ - plugin.json 若带注释直接放进壳 `plugins/` dev 目录,预览加载会崩(壳侧 jsonc 支持是后续轮)。
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `linkdesk-plugin-sdk` CLI——E6#1 拍板(bin 形态:与脚手架 01-create-linkdesk-plugin脚手架 / 发布
4
+ * 流水线 03 文档钉死的作者模板 `build: "linkdesk-plugin-sdk build"` 一致,作者零额外配置)。
5
+ *
6
+ * 子命令 build / validate。bin 只是**编排壳**——validate 与 zip 归属仍在库内(validatePluginJson /
7
+ * defineLinkdeskPluginConfig 内嵌 packager),无双路径分歧:
8
+ * - build:工程根有 vite.config.* → 交 Vite 自身加载(作者可自定义);无 → 直接零配置默认路径
9
+ * - validate:跑 validatePluginJson 逐行打错,exit 1/0
10
+ */
11
+ import { existsSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { build } from "vite";
14
+ import { validatePluginJson } from "./validate.js";
15
+ import { defineLinkdeskPluginConfig } from "./vite-config.js";
16
+ const VITE_CONFIG_FILES = [
17
+ "vite.config.ts",
18
+ "vite.config.mts",
19
+ "vite.config.cts",
20
+ "vite.config.js",
21
+ "vite.config.mjs",
22
+ "vite.config.cjs",
23
+ ];
24
+ const USAGE = `linkdesk-plugin-sdk <command>
25
+
26
+ 命令:
27
+ build 在插件工程根构建 .linkdesk-plugin(读 plugin.json → Vite build → zip)
28
+ validate 校验 plugin.json(参数 = 路径,默认 ./plugin.json)
29
+ `;
30
+ async function cmdBuild() {
31
+ const root = process.cwd();
32
+ const hasConfig = VITE_CONFIG_FILES.some((f) => existsSync(join(root, f)));
33
+ if (hasConfig) {
34
+ await build(); // 作者自定义 vite.config.*(通常就是 defineLinkdeskPluginConfig())
35
+ }
36
+ else {
37
+ await build(defineLinkdeskPluginConfig()); // 零配置默认路径
38
+ }
39
+ return 0;
40
+ }
41
+ function cmdValidate(target) {
42
+ const res = validatePluginJson(target);
43
+ if (!res.valid) {
44
+ console.error("❌ plugin.json 验证失败:");
45
+ for (const e of res.errors)
46
+ console.error(` ${e}`);
47
+ return 1;
48
+ }
49
+ console.log("✅ plugin.json 验证通过");
50
+ return 0;
51
+ }
52
+ async function main() {
53
+ const [, , command, arg] = process.argv;
54
+ let code;
55
+ switch (command) {
56
+ case "build":
57
+ code = await cmdBuild();
58
+ break;
59
+ case "validate":
60
+ code = cmdValidate(arg ?? "plugin.json");
61
+ break;
62
+ default:
63
+ console.error(USAGE);
64
+ code = command ? 1 : 0;
65
+ break;
66
+ }
67
+ process.exit(code);
68
+ }
69
+ main().catch((err) => {
70
+ console.error(`[linkdesk-plugin-sdk] ❌ ${err instanceof Error ? err.message : String(err)}`);
71
+ process.exit(1);
72
+ });
73
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE9D,MAAM,iBAAiB,GAAG;IACxB,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;IACjB,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;CAClB,CAAC;AAEF,MAAM,KAAK,GAAG;;;;;CAKb,CAAC;AAEF,KAAK,UAAU,QAAQ;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,KAAK,EAAE,CAAC,CAAC,yDAAyD;IAC1E,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,CAAC,0BAA0B,EAAE,CAAC,CAAC,CAAC,UAAU;IACvD,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM;YAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,EAAE,AAAD,EAAG,OAAO,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IACxC,IAAI,IAAY,CAAC;IACjB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,OAAO;YACV,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;YACxB,MAAM;QACR,KAAK,UAAU;YACb,IAAI,GAAG,WAAW,CAAC,GAAG,IAAI,aAAa,CAAC,CAAC;YACzC,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACrB,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACvB,MAAM;IACV,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @linkdesk/plugin-sdk 公共出口(barrel)。
3
+ *
4
+ * 运行面只有两个函数:`defineLinkdeskPluginConfig()`(构建)+ `validatePluginJson()`(验证);
5
+ * 类型面经 types.js 全量转发 @linkdesk/contracts(window.linkdesk.* 全局声明随契约进 program,E6#2b)。
6
+ * validate 的内部 helper(collectI18nDecls/derivePluginId/SAFE_PLUGIN_ID 等)供 vite-config/packager
7
+ * 跨模块复用,但**不进 barrel**——公共 API 面保持最小(对标 @types/vscode 只给类型+工具)。
8
+ */
9
+ export { defineLinkdeskPluginConfig } from "./vite-config.js";
10
+ export type { LinkdeskPluginOptions } from "./vite-config.js";
11
+ export { validatePluginJson } from "./validate.js";
12
+ export type { ValidationResult } from "./validate.js";
13
+ export type * from "./types.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,mBAAmB,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @linkdesk/plugin-sdk 公共出口(barrel)。
3
+ *
4
+ * 运行面只有两个函数:`defineLinkdeskPluginConfig()`(构建)+ `validatePluginJson()`(验证);
5
+ * 类型面经 types.js 全量转发 @linkdesk/contracts(window.linkdesk.* 全局声明随契约进 program,E6#2b)。
6
+ * validate 的内部 helper(collectI18nDecls/derivePluginId/SAFE_PLUGIN_ID 等)供 vite-config/packager
7
+ * 跨模块复用,但**不进 barrel**——公共 API 面保持最小(对标 @types/vscode 只给类型+工具)。
8
+ */
9
+ export { defineLinkdeskPluginConfig } from "./vite-config.js";
10
+ export { validatePluginJson } from "./validate.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * window.linkdesk.* 类型出口——E6#2。
3
+ *
4
+ * **从 E5.8 生成契约派生,不手写第二份真相源**:直接转发 `@linkdesk/contracts`(判据⑧归一性)。
5
+ * 契约 `linkdesk.d.ts` 自带 `export {} + declare global { Window.linkdesk: LinkDeskAPI }`;
6
+ * 本文件经 `export type *` 把契约拉进消费方 program → 全局 `window.linkdesk.` 自动有类型(E6#2b),
7
+ * 作者无需手写 global.d.ts。契约漂移 → 消费方 tsc 立即红,不存在两份真相源失步。
8
+ *
9
+ * 2026-08-20 E5.8#22.6 提示:@linkdesk/contracts 已建好且 types 直指生成契约——plugin-sdk 直接
10
+ * dependencies 转发即可,不必复制生成物。dev 过渡态 = file: 本地引用;#2.5 真发布后改 ^0.1.0(registry)。
11
+ */
12
+ export type * from "@linkdesk/contracts";
13
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,mBAAmB,qBAAqB,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * plugin.json 验证工具(E6#5)——jsonc 解析 + JSON Schema(ajv-2020)+ i18n 文件存在性。
3
+ * 纯逻辑、无 vite import——`validatePluginJson` 与 bin / defineLinkdeskPluginConfig 三方共用。
4
+ *
5
+ * 设计裁决:
6
+ * - **解析走 jsonc-parser**(对齐壳 E6#55)——作者 plugin.json 可写注释/尾逗号(对标 VS Code
7
+ * package.json),注释不参与校验。语法错误报 plugin.json:行:列(ESLint 风格)。
8
+ * - **必填/contributes 以 plugin.schema.json 为唯一真源**(判据⑧归一性)——读包内 schema 副本做
9
+ * ajv-2020 全量校验,不手写第二份字段清单。schema 改 → 校验自动跟上。副本漂移由
10
+ * scripts/check-plugin-schema-sync.mjs 整文件守卫。
11
+ * - **i18n 文件存在性**是 schema 管不了的第二类检查(schema 只验声明形状,不验文件存在)。
12
+ * - **entry 语义洞(H2,E6#5a 注记)**:schema 的 entry 条件块只认**废弃 `type`**(const view/card/
13
+ * protocol,allOf/if/then);E5.8 后插件走 pluginRole/factoryRole 无 type → schema 拦不住「现代
14
+ * view 插件缺 entry」,由 vite build 兜底(无 input 报错)。不在此手写第二条 entry 规则(违归一);
15
+ * schema 上游补丁留 schema 轮。
16
+ * - 友好错误:schema 违规没有 plugin.json 行号(JSON Pointer 语义),格式定为
17
+ * `plugin.json:<instancePath 美化>: <中文消息>`;语法错才有 :行:列。
18
+ */
19
+ /**
20
+ * pluginId 形状约束——复制自壳 src/pluginLoader/manifest.ts:64(独立 npm 包不能 import @src 壳源码;
21
+ * 加载契约 = 安装目录名 → validateInstallManifest 兜底,E6#7 钉死)。防路径穿越字符直通文件系统。
22
+ */
23
+ export declare const SAFE_PLUGIN_ID: RegExp;
24
+ export interface ValidationResult {
25
+ valid: boolean;
26
+ errors: string[];
27
+ }
28
+ /** i18n 声明(相对插件根路径 + 声明来源)——validate 存在性检查与 packager 拷贝清单共用 */
29
+ export interface I18nDecl {
30
+ rel: string;
31
+ origin: "contributes.i18n" | "i18n";
32
+ }
33
+ /**
34
+ * 收集插件 i18n 声明——顶层**废弃** `manifest.i18n` + `contributes.i18n` 两层(schema 243/623 行:
35
+ * 顶层 i18n @deprecated,contributes 为现役)。shape = { 语言代码: 相对路径 }。
36
+ */
37
+ export declare function collectI18nDecls(manifest: unknown): I18nDecl[];
38
+ /**
39
+ * pluginId 裁决 = manifest.pluginId ?? 源目录名(对齐壳 validateInstallManifest manifest.ts:78-104,
40
+ * 支持目录名 ≠ pluginId 的正确安装)。manifest.pluginId 非字符串 / 任一不合 SAFE_PLUGIN_ID → 抛错。
41
+ * 文件名 `<id>.linkdesk-plugin` 与壳解压目录 {userData}/plugins/<id>/ 都据此契约(E6#7)。
42
+ */
43
+ export declare function derivePluginId(manifest: unknown, sourceDirName: string): string;
44
+ /** jsonc 读插件 manifest——注释/尾逗号容忍,语法错抛清晰错误。validate 与 packager 共用同一读取路径 */
45
+ export declare function readPluginManifest(path: string): unknown;
46
+ /** 相对插件根的 rel 是否逃逸根目录(反斜杠/绝对/.. 统一拒)——拷贝与存在性检查共用 */
47
+ export declare function isWithinRoot(root: string, target: string): boolean;
48
+ /**
49
+ * 校验 plugin.json——返回 { valid, errors },**不抛**(集成方拿非 valid 拼文案 throw)。
50
+ * 顺序:读文件 → jsonc 语法 → schema 全量 → i18n 文件存在性(schema 干净才查第二类,防噪音)。
51
+ */
52
+ export declare function validatePluginJson(path: string): ValidationResult;
53
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAYH;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAiC,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,+DAA+D;AAC/D,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,EAAE,CAc9D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAkB/E;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAWxD;AAiED,oDAAoD;AACpD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGlE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAiCjE"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * plugin.json 验证工具(E6#5)——jsonc 解析 + JSON Schema(ajv-2020)+ i18n 文件存在性。
3
+ * 纯逻辑、无 vite import——`validatePluginJson` 与 bin / defineLinkdeskPluginConfig 三方共用。
4
+ *
5
+ * 设计裁决:
6
+ * - **解析走 jsonc-parser**(对齐壳 E6#55)——作者 plugin.json 可写注释/尾逗号(对标 VS Code
7
+ * package.json),注释不参与校验。语法错误报 plugin.json:行:列(ESLint 风格)。
8
+ * - **必填/contributes 以 plugin.schema.json 为唯一真源**(判据⑧归一性)——读包内 schema 副本做
9
+ * ajv-2020 全量校验,不手写第二份字段清单。schema 改 → 校验自动跟上。副本漂移由
10
+ * scripts/check-plugin-schema-sync.mjs 整文件守卫。
11
+ * - **i18n 文件存在性**是 schema 管不了的第二类检查(schema 只验声明形状,不验文件存在)。
12
+ * - **entry 语义洞(H2,E6#5a 注记)**:schema 的 entry 条件块只认**废弃 `type`**(const view/card/
13
+ * protocol,allOf/if/then);E5.8 后插件走 pluginRole/factoryRole 无 type → schema 拦不住「现代
14
+ * view 插件缺 entry」,由 vite build 兜底(无 input 报错)。不在此手写第二条 entry 规则(违归一);
15
+ * schema 上游补丁留 schema 轮。
16
+ * - 友好错误:schema 违规没有 plugin.json 行号(JSON Pointer 语义),格式定为
17
+ * `plugin.json:<instancePath 美化>: <中文消息>`;语法错才有 :行:列。
18
+ */
19
+ import { existsSync, readFileSync } from "node:fs";
20
+ import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
21
+ import { fileURLToPath } from "node:url";
22
+ import * as jsonc from "jsonc-parser";
23
+ import Ajv2020 from "ajv/dist/2020.js"; // ajv 无 exports 映射——Node ESM 需显式 .js(bundler 态才可去后缀)
24
+ /** 包内 schema 副本定位——dist/validate.js → ../schemas = 包根/schemas;src 直跑同样上溯一级命中 */
25
+ const SCHEMA_URL = new URL("../schemas/plugin.schema.json", import.meta.url);
26
+ /**
27
+ * pluginId 形状约束——复制自壳 src/pluginLoader/manifest.ts:64(独立 npm 包不能 import @src 壳源码;
28
+ * 加载契约 = 安装目录名 → validateInstallManifest 兜底,E6#7 钉死)。防路径穿越字符直通文件系统。
29
+ */
30
+ export const SAFE_PLUGIN_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
31
+ /**
32
+ * 收集插件 i18n 声明——顶层**废弃** `manifest.i18n` + `contributes.i18n` 两层(schema 243/623 行:
33
+ * 顶层 i18n @deprecated,contributes 为现役)。shape = { 语言代码: 相对路径 }。
34
+ */
35
+ export function collectI18nDecls(manifest) {
36
+ if (!manifest || typeof manifest !== "object")
37
+ return [];
38
+ const m = manifest;
39
+ const out = [];
40
+ const push = (o, origin) => {
41
+ if (!o || typeof o !== "object" || Array.isArray(o))
42
+ return;
43
+ for (const v of Object.values(o)) {
44
+ if (typeof v === "string" && v.trim() !== "")
45
+ out.push({ rel: v, origin });
46
+ }
47
+ };
48
+ push(m.i18n, "i18n");
49
+ const c = m.contributes;
50
+ push(c?.i18n, "contributes.i18n");
51
+ return out;
52
+ }
53
+ /**
54
+ * pluginId 裁决 = manifest.pluginId ?? 源目录名(对齐壳 validateInstallManifest manifest.ts:78-104,
55
+ * 支持目录名 ≠ pluginId 的正确安装)。manifest.pluginId 非字符串 / 任一不合 SAFE_PLUGIN_ID → 抛错。
56
+ * 文件名 `<id>.linkdesk-plugin` 与壳解压目录 {userData}/plugins/<id>/ 都据此契约(E6#7)。
57
+ */
58
+ export function derivePluginId(manifest, sourceDirName) {
59
+ const m = manifest;
60
+ let pluginId;
61
+ const rawId = m?.pluginId;
62
+ if (rawId === undefined || rawId === null) {
63
+ pluginId = sourceDirName;
64
+ }
65
+ else if (typeof rawId !== "string") {
66
+ throw new Error(`plugin.json 的 pluginId 必须是字符串`);
67
+ }
68
+ else {
69
+ pluginId = rawId;
70
+ }
71
+ if (!SAFE_PLUGIN_ID.test(pluginId)) {
72
+ throw new Error(`pluginId "${pluginId}" 不合法(只允许字母/数字/._-,开头须为字母或数字)` +
73
+ `——plugin.json 未声明 pluginId 时以项目目录名兜底,请改名目录或在 plugin.json 声明 pluginId`);
74
+ }
75
+ return pluginId;
76
+ }
77
+ /** jsonc 读插件 manifest——注释/尾逗号容忍,语法错抛清晰错误。validate 与 packager 共用同一读取路径 */
78
+ export function readPluginManifest(path) {
79
+ const text = readFileSync(path, "utf8");
80
+ const parseErrors = [];
81
+ const value = jsonc.parse(text, parseErrors, { allowTrailingComma: true, disallowComments: false });
82
+ if (parseErrors.length > 0) {
83
+ const { line, col } = offsetToLineCol(text, parseErrors[0].offset);
84
+ throw new Error(`${basename(path)}:${line}:${col}: ${jsonc.printParseErrorCode(parseErrors[0].error)}——plugin.json 语法错误`);
85
+ }
86
+ return value;
87
+ }
88
+ /** jsonc 语法错 offset → {line,col}(1 起)。CRLF 的 \r 算一列,可读性足够,不做精确归一 */
89
+ function offsetToLineCol(text, offset) {
90
+ let line = 1;
91
+ let col = 1;
92
+ const end = Math.min(offset, text.length);
93
+ for (let i = 0; i < end; i++) {
94
+ if (text[i] === "\n") {
95
+ line++;
96
+ col = 1;
97
+ }
98
+ else {
99
+ col++;
100
+ }
101
+ }
102
+ return { line, col };
103
+ }
104
+ let cachedValidate = null;
105
+ let cachedAjvErrors = [];
106
+ /** ajv-2020 单例——schema 读一次 compile 一次(同一 schema 全进程复用) */
107
+ function getValidator() {
108
+ if (cachedValidate)
109
+ return cachedValidate;
110
+ const raw = readFileSync(fileURLToPath(SCHEMA_URL), "utf8");
111
+ const schema = JSON.parse(raw);
112
+ // eslint-disable-next-line new-cap
113
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
114
+ const validate = ajv.compile(schema);
115
+ cachedValidate = (data) => {
116
+ const ok = validate(data);
117
+ // 先 validate 再取 errors——validate.errors 是上次调用的状态,顺序反了会拿到旧/空 errors
118
+ cachedAjvErrors = validate.errors ?? [];
119
+ return ok;
120
+ };
121
+ return cachedValidate;
122
+ }
123
+ /** instancePath → 可读路径:/contributes/commands/0 → contributes.commands[0];空 = 顶部 */
124
+ function prettyInstancePath(instancePath) {
125
+ if (!instancePath)
126
+ return "顶部";
127
+ return instancePath
128
+ .replace(/^\//, "")
129
+ .replace(/\/(\d+)\//g, "[$1].")
130
+ .replace(/\/(\d+)$/g, "[$1]")
131
+ .replace(/\//g, ".");
132
+ }
133
+ /** schema 违规 → 中文友好消息。required/type 白名单,其余 keyword+params 降级(不追求全覆盖) */
134
+ function formatSchemaError(err) {
135
+ const at = prettyInstancePath(err.instancePath);
136
+ if (err.keyword === "required") {
137
+ const missing = err.params.missingProperty;
138
+ return `${at}: 缺少必填字段 "${missing}"`;
139
+ }
140
+ if (err.keyword === "type") {
141
+ const type = err.params.type;
142
+ return `${at}: 字段类型应为 ${type}`;
143
+ }
144
+ if (err.keyword === "const") {
145
+ return `${at}: 值必须为 ${JSON.stringify(err.params.allowedValue)}`;
146
+ }
147
+ return `${at}: 不符合 schema 约束 ${err.keyword}`;
148
+ }
149
+ /** 相对插件根的 rel 是否逃逸根目录(反斜杠/绝对/.. 统一拒)——拷贝与存在性检查共用 */
150
+ export function isWithinRoot(root, target) {
151
+ const rel = relative(root, target);
152
+ return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel) && rel !== "..");
153
+ }
154
+ /**
155
+ * 校验 plugin.json——返回 { valid, errors },**不抛**(集成方拿非 valid 拼文案 throw)。
156
+ * 顺序:读文件 → jsonc 语法 → schema 全量 → i18n 文件存在性(schema 干净才查第二类,防噪音)。
157
+ */
158
+ export function validatePluginJson(path) {
159
+ const errors = [];
160
+ const base = basename(path);
161
+ let manifest;
162
+ try {
163
+ manifest = readPluginManifest(path);
164
+ }
165
+ catch (err) {
166
+ return { valid: false, errors: [`${err instanceof Error ? err.message : String(err)}`] };
167
+ }
168
+ // 1) JSON Schema(唯一真源)
169
+ const validate = getValidator();
170
+ const ok = validate(manifest);
171
+ if (!ok) {
172
+ for (const e of cachedAjvErrors)
173
+ errors.push(`${base}:${formatSchemaError(e)}`);
174
+ return { valid: false, errors };
175
+ }
176
+ // 2) i18n 文件存在性(schema 管不到:声明形状合法但文件可以缺)
177
+ const rootDir = dirname(resolve(path));
178
+ for (const decl of collectI18nDecls(manifest)) {
179
+ const target = resolve(rootDir, decl.rel);
180
+ if (!isWithinRoot(rootDir, target)) {
181
+ errors.push(`${decl.rel}: 在 ${decl.origin} 中声明的路径越出了插件根目录`);
182
+ continue;
183
+ }
184
+ if (!existsSync(target)) {
185
+ errors.push(`${decl.rel}: 在 ${decl.origin} 中声明但文件不存在`);
186
+ }
187
+ }
188
+ return { valid: errors.length === 0, errors };
189
+ }
190
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 插件 Vite 构建配置(E6#4)——`defineLinkdeskPluginConfig()` 一键产出 `.linkdesk-plugin` zip。
3
+ *
4
+ * 作者用法:工程根放 plugin.json + src/index.tsx,vite.config.ts 写
5
+ * `export default defineLinkdeskPluginConfig()`,`npm run build`(= linkdesk-plugin-sdk build)即得
6
+ * `<id>.linkdesk-plugin`。产物两份(对齐脚手架/流水线文档 01/03):
7
+ * - 项目根 `./<id>.linkdesk-plugin`(zip 单文件,分发态)
8
+ * - `dist/<id>.linkdesk-plugin/`(解包目录,#4a 目录产物,调试/壳加载调试面)
9
+ *
10
+ * 构建裁决:
11
+ * - React/react-dom/react-i18next/**i18next** external(壳提供——插件自打 i18next 实例 → 翻译全空,
12
+ * B3 教训);其他依赖 inline 完全自包含。
13
+ * - 打包 = 内嵌私有插件 `linkdesk-plugin-packager` 的 Vite hook 序列(closeBundle 时机 zip,归属唯一,
14
+ * bin 只编排不重复 zip):
15
+ * configResolved → buildStart 跑 validatePluginJson(build 前校验,失败即 abort,#5b)
16
+ * → buildEnd 记 failed → closeBundle(failed 或 bundle 缺失则跳过)拷静态清单 + jszip。
17
+ * - 静态清单从**源码 pluginRoot** 拷贝(非 outDir——outDir 每次 emptyOutDir 清空),含 plugin.json/
18
+ * icon/README.md/CHANGELOG.md(K2 缝隙)/ i18n 声明文件;build 产物 index.bundle.js + assets/ 从
19
+ * outDir 深拷贝进 pkgDir。
20
+ * - zip 条目相对 pkgDir、正斜杠、无外层目录(loader 解压期待 plugin.json 在顶,E6#7 契约)。
21
+ * - dev/serve 不触发 build 系 hook → packager 天然只在 build 跑。
22
+ */
23
+ import type { UserConfig } from "vite";
24
+ export interface LinkdeskPluginOptions {
25
+ /** 入口文件,默认 plugin.json 的 entry,再缺省 "src/index.tsx" */
26
+ entry?: string;
27
+ /** 输出目录,默认 "dist" */
28
+ outDir?: string;
29
+ /** 额外 external 依赖(壳还可能提供别的共享件) */
30
+ external?: string[];
31
+ }
32
+ export declare function defineLinkdeskPluginConfig(options?: LinkdeskPluginOptions): UserConfig;
33
+ //# sourceMappingURL=vite-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-config.d.ts","sourceRoot":"","sources":["../src/vite-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAU,UAAU,EAAE,MAAM,MAAM,CAAC;AAc/C,MAAM,WAAW,qBAAqB;IACpC,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAqCD,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,qBAA0B,GAAG,UAAU,CAwG1F"}