dsh-plugin-manager-companion 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/LICENSE +21 -0
- package/README.en.md +144 -0
- package/README.md +142 -0
- package/cordis.patch.yml +9 -0
- package/dist/about.d.ts +77 -0
- package/dist/about.js +179 -0
- package/dist/cli.d.ts +226 -0
- package/dist/cli.js +856 -0
- package/dist/client/AboutPage.d.ts +75 -0
- package/dist/client/ConsolePage.d.ts +79 -0
- package/dist/client/KindsPage.d.ts +21 -0
- package/dist/client/MarketplacePage.d.ts +36 -0
- package/dist/client/OfficialSlots.d.ts +35 -0
- package/dist/client/UpgradeRow.d.ts +108 -0
- package/dist/client/index.d.ts +26 -0
- package/dist/client/locales.d.ts +475 -0
- package/dist/client/pmSelect.d.ts +38 -0
- package/dist/client/shared.d.ts +928 -0
- package/dist/client/upgradeView.d.ts +278 -0
- package/dist/client/wire.d.ts +401 -0
- package/dist/client.js +9194 -0
- package/dist/diagnostics.d.ts +332 -0
- package/dist/diagnostics.js +2631 -0
- package/dist/envManager.d.ts +1047 -0
- package/dist/envManager.js +3214 -0
- package/dist/fix.d.ts +60 -0
- package/dist/fix.js +168 -0
- package/dist/guard.d.ts +133 -0
- package/dist/guard.js +232 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +1150 -0
- package/dist/installSession.d.ts +111 -0
- package/dist/installSession.js +150 -0
- package/dist/kinds.d.ts +464 -0
- package/dist/kinds.js +1029 -0
- package/dist/marketView.d.ts +261 -0
- package/dist/marketView.js +406 -0
- package/dist/marketplace.d.ts +248 -0
- package/dist/marketplace.js +500 -0
- package/dist/match.d.ts +67 -0
- package/dist/match.js +203 -0
- package/dist/net.d.ts +108 -0
- package/dist/net.js +163 -0
- package/dist/official.d.ts +145 -0
- package/dist/official.js +205 -0
- package/dist/paths.d.ts +108 -0
- package/dist/paths.js +236 -0
- package/dist/presets.d.ts +299 -0
- package/dist/presets.js +578 -0
- package/dist/qualityGate.d.ts +66 -0
- package/dist/qualityGate.js +247 -0
- package/dist/rank.d.ts +88 -0
- package/dist/rank.js +164 -0
- package/dist/registry.d.ts +295 -0
- package/dist/registry.js +686 -0
- package/dist/rest.d.ts +122 -0
- package/dist/rest.js +219 -0
- package/dist/scan.d.ts +134 -0
- package/dist/scan.js +396 -0
- package/dist/settings.d.ts +447 -0
- package/dist/settings.js +263 -0
- package/dist/tags.d.ts +119 -0
- package/dist/tags.js +166 -0
- package/dist/tools.d.ts +131 -0
- package/dist/tools.js +377 -0
- package/dist/types.d.ts +651 -0
- package/dist/types.js +13 -0
- package/dist/upgrade.d.ts +428 -0
- package/dist/upgrade.js +1100 -0
- package/dist/upgradeView.d.ts +313 -0
- package/dist/upgradeView.js +273 -0
- package/docs/images/readme/01-console-health.png +0 -0
- package/docs/images/readme/02-console-envs.png +0 -0
- package/docs/images/readme/03-marketplace.png +0 -0
- package/docs/images/readme/04-official-plugin-page.png +0 -0
- package/package.json +104 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 安装会话状态机(awaiting-input)。
|
|
3
|
+
*
|
|
4
|
+
* 归属:A 类·重写(有状态、管生命周期;旧 src/installSession.ts 仅作意图参考,未复制代码)。
|
|
5
|
+
* 旧实现参考:dsh-web-plugin-manager/src/installSession.ts(81 行:spec 为键、15 分钟 TTL、
|
|
6
|
+
* 惰性清理、answers 按扫描白名单校验、__ 前缀内部键拒绝、spec 归一化防重扫)。
|
|
7
|
+
* 官方复用:无(官方没有"安装暂停等输入"的概念)。
|
|
8
|
+
* 前提检查:仍然成立——git 源插件需要凭据类变量时,安装必须暂停并把变量名交给
|
|
9
|
+
* 用户,而不是静默失败或全量透传宿主 env。旧实现的会话只活在进程内,这一点
|
|
10
|
+
* 必须保留并写清:CLI 每次调用是新进程,会话不跨进程,所以 CLI 提交 --env 时
|
|
11
|
+
* 用**本次扫描**的白名单直接校验(显式提供即同意),不依赖会话存在。
|
|
12
|
+
*
|
|
13
|
+
* 会话里只存"允许注入哪些键"这一件事:值不存在会话里(用户提交时不落内存),
|
|
14
|
+
* 因此即使会话泄漏也不会泄漏凭据。
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* 一条安装会话。
|
|
18
|
+
*
|
|
19
|
+
* 键是归一化后的 spec(见 sessionKey):同一 spec 同时只允许一个进行中的暂停安装。
|
|
20
|
+
*/
|
|
21
|
+
export interface InstallSession {
|
|
22
|
+
/** 原始安装源 spec(npm 名 / git URL / 本地路径)。 */
|
|
23
|
+
readonly spec: string;
|
|
24
|
+
/** 已就绪的仓库目录(克隆缓存或本地路径)。 */
|
|
25
|
+
readonly repoDir: string;
|
|
26
|
+
/** 扫描白名单:只允许这些键被注入。 */
|
|
27
|
+
readonly scanned: readonly string[];
|
|
28
|
+
/** 创建时刻(epoch 毫秒)。 */
|
|
29
|
+
readonly createdAt: number;
|
|
30
|
+
}
|
|
31
|
+
/** 会话存活时长:超过后视为放弃;仓库缓存保留,可复用。 */
|
|
32
|
+
export declare const SESSION_TTL_MS: number;
|
|
33
|
+
/**
|
|
34
|
+
* 归一化 spec 作为会话键。
|
|
35
|
+
*
|
|
36
|
+
* 尾部斜杠与大小写都不能把一个安装拆成两个会话(旧仓库审计点:换个斜杠重提交
|
|
37
|
+
* 会重建会话并重新扫描一遍)。
|
|
38
|
+
*
|
|
39
|
+
* @param spec - 原始安装源。
|
|
40
|
+
* @returns 归一化后的键。
|
|
41
|
+
*/
|
|
42
|
+
export declare function sessionKey(spec: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* 创建一个会话(同 spec 已存在则覆盖),返回会话键。
|
|
45
|
+
*
|
|
46
|
+
* @param spec - 安装源。
|
|
47
|
+
* @param repoDir - 已就绪的仓库目录。
|
|
48
|
+
* @param scanned - 扫描得到的变量名白名单。
|
|
49
|
+
* @returns 会话键(后续 get/drop 用同一归一化规则)。
|
|
50
|
+
*/
|
|
51
|
+
export declare function createInstallSession(spec: string, repoDir: string, scanned: readonly string[]): string;
|
|
52
|
+
/**
|
|
53
|
+
* 读一个会话。
|
|
54
|
+
* @param spec - 安装源。
|
|
55
|
+
* @returns 会话;不存在或已过期时为 undefined。
|
|
56
|
+
*/
|
|
57
|
+
export declare function getInstallSession(spec: string): InstallSession | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* 丢弃一个会话(用户取消 / 安装继续后不再需要)。
|
|
60
|
+
* @param spec - 安装源。
|
|
61
|
+
* @returns 是否真的存在并被删除。
|
|
62
|
+
*/
|
|
63
|
+
export declare function dropInstallSession(spec: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* 校验并过滤 answers。
|
|
66
|
+
*
|
|
67
|
+
* 三条规则,两条拒绝一条跳过:
|
|
68
|
+
* - 键必须 ∈ 白名单(这是防 PATH/HOME/NODE_OPTIONS/__proto__ 注入的全部依据);
|
|
69
|
+
* - 键不得以双下划线开头(内部保留前缀,纯防御);
|
|
70
|
+
* - 值为空字符串表示"我看到了但没提供",跳过而不是注入空值。
|
|
71
|
+
* 返回新对象,不修改传入的 answers。
|
|
72
|
+
*
|
|
73
|
+
* @param allowlist - 允许注入的键(本次扫描结果或会话白名单,两者等价)。
|
|
74
|
+
* @param answers - 用户提交的键值对。
|
|
75
|
+
* @returns 通过校验的子集。
|
|
76
|
+
*/
|
|
77
|
+
export declare function filterAnswers(allowlist: readonly string[], answers: Readonly<Record<string, string>> | undefined): Record<string, string>;
|
|
78
|
+
/**
|
|
79
|
+
* 惰性清理过期会话(每次访问顺带执行,不挂定时器)。
|
|
80
|
+
*
|
|
81
|
+
* 定时器会让插件在宿主里留下一个永不退出的句柄,而惰性清理的代价只是每次读
|
|
82
|
+
* 多走一遍 Map——会话数量上限是"同时在途的暂停安装",实践中为个位数。
|
|
83
|
+
*
|
|
84
|
+
* @returns 本次清掉的会话数。
|
|
85
|
+
*/
|
|
86
|
+
export declare function pruneExpiredSessions(): number;
|
|
87
|
+
/** 当前会话数(诊断与测试用)。 */
|
|
88
|
+
export declare function sessionCount(): number;
|
|
89
|
+
/**
|
|
90
|
+
* 替换时钟(仅测试用)。
|
|
91
|
+
*
|
|
92
|
+
* 会话的 TTL 是 15 分钟,真等一遍不可能;用一个可注入的时钟把"过期"变成
|
|
93
|
+
* 确定性事件。生产路径不调用它。
|
|
94
|
+
*
|
|
95
|
+
* @param clock - 返回 epoch 毫秒的函数。
|
|
96
|
+
* @returns 把时钟恢复为 Date.now 的还原函数。
|
|
97
|
+
*/
|
|
98
|
+
export declare function __setClockForTests(clock: () => number): () => void;
|
|
99
|
+
/** 清空全部会话(测试用;返回被清掉的数量)。 */
|
|
100
|
+
export declare function __resetSessionsForTests(): number;
|
|
101
|
+
/**
|
|
102
|
+
* 把一次"需要用户输入"的安装挂到全局变更队列上。
|
|
103
|
+
*
|
|
104
|
+
* 存在的意义:会话创建与随后的安装是两步,中间可能有并发的第二个安装。
|
|
105
|
+
* 走 paths.ts 的 enqueueMutation 让"读会话 → 解析 answers → 触发安装"整体串行,
|
|
106
|
+
* 与环境的其他变更共享同一把进程内锁。
|
|
107
|
+
*
|
|
108
|
+
* @param task - 要在串行区里执行的工作。
|
|
109
|
+
* @returns 任务结果。
|
|
110
|
+
*/
|
|
111
|
+
export declare function withInstallSession<T>(task: () => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 安装会话状态机(awaiting-input)。
|
|
3
|
+
*
|
|
4
|
+
* 归属:A 类·重写(有状态、管生命周期;旧 src/installSession.ts 仅作意图参考,未复制代码)。
|
|
5
|
+
* 旧实现参考:dsh-web-plugin-manager/src/installSession.ts(81 行:spec 为键、15 分钟 TTL、
|
|
6
|
+
* 惰性清理、answers 按扫描白名单校验、__ 前缀内部键拒绝、spec 归一化防重扫)。
|
|
7
|
+
* 官方复用:无(官方没有"安装暂停等输入"的概念)。
|
|
8
|
+
* 前提检查:仍然成立——git 源插件需要凭据类变量时,安装必须暂停并把变量名交给
|
|
9
|
+
* 用户,而不是静默失败或全量透传宿主 env。旧实现的会话只活在进程内,这一点
|
|
10
|
+
* 必须保留并写清:CLI 每次调用是新进程,会话不跨进程,所以 CLI 提交 --env 时
|
|
11
|
+
* 用**本次扫描**的白名单直接校验(显式提供即同意),不依赖会话存在。
|
|
12
|
+
*
|
|
13
|
+
* 会话里只存"允许注入哪些键"这一件事:值不存在会话里(用户提交时不落内存),
|
|
14
|
+
* 因此即使会话泄漏也不会泄漏凭据。
|
|
15
|
+
*/
|
|
16
|
+
import { enqueueMutation } from "./paths.js";
|
|
17
|
+
/** 会话存活时长:超过后视为放弃;仓库缓存保留,可复用。 */
|
|
18
|
+
export const SESSION_TTL_MS = 15 * 60 * 1000;
|
|
19
|
+
/** 进程内会话表。键为归一化 spec。 */
|
|
20
|
+
const sessions = new Map();
|
|
21
|
+
/** 可注入的时钟(测试用它把 TTL 推到过去,而不必真的等待 15 分钟)。 */
|
|
22
|
+
let now = () => Date.now();
|
|
23
|
+
/**
|
|
24
|
+
* 归一化 spec 作为会话键。
|
|
25
|
+
*
|
|
26
|
+
* 尾部斜杠与大小写都不能把一个安装拆成两个会话(旧仓库审计点:换个斜杠重提交
|
|
27
|
+
* 会重建会话并重新扫描一遍)。
|
|
28
|
+
*
|
|
29
|
+
* @param spec - 原始安装源。
|
|
30
|
+
* @returns 归一化后的键。
|
|
31
|
+
*/
|
|
32
|
+
export function sessionKey(spec) {
|
|
33
|
+
return spec.trim().replace(/\/+$/, '').toLowerCase();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 创建一个会话(同 spec 已存在则覆盖),返回会话键。
|
|
37
|
+
*
|
|
38
|
+
* @param spec - 安装源。
|
|
39
|
+
* @param repoDir - 已就绪的仓库目录。
|
|
40
|
+
* @param scanned - 扫描得到的变量名白名单。
|
|
41
|
+
* @returns 会话键(后续 get/drop 用同一归一化规则)。
|
|
42
|
+
*/
|
|
43
|
+
export function createInstallSession(spec, repoDir, scanned) {
|
|
44
|
+
pruneExpiredSessions();
|
|
45
|
+
const key = sessionKey(spec);
|
|
46
|
+
sessions.set(key, { spec, repoDir, scanned: [...new Set(scanned)], createdAt: now() });
|
|
47
|
+
return key;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 读一个会话。
|
|
51
|
+
* @param spec - 安装源。
|
|
52
|
+
* @returns 会话;不存在或已过期时为 undefined。
|
|
53
|
+
*/
|
|
54
|
+
export function getInstallSession(spec) {
|
|
55
|
+
pruneExpiredSessions();
|
|
56
|
+
return sessions.get(sessionKey(spec));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 丢弃一个会话(用户取消 / 安装继续后不再需要)。
|
|
60
|
+
* @param spec - 安装源。
|
|
61
|
+
* @returns 是否真的存在并被删除。
|
|
62
|
+
*/
|
|
63
|
+
export function dropInstallSession(spec) {
|
|
64
|
+
return sessions.delete(sessionKey(spec));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 校验并过滤 answers。
|
|
68
|
+
*
|
|
69
|
+
* 三条规则,两条拒绝一条跳过:
|
|
70
|
+
* - 键必须 ∈ 白名单(这是防 PATH/HOME/NODE_OPTIONS/__proto__ 注入的全部依据);
|
|
71
|
+
* - 键不得以双下划线开头(内部保留前缀,纯防御);
|
|
72
|
+
* - 值为空字符串表示"我看到了但没提供",跳过而不是注入空值。
|
|
73
|
+
* 返回新对象,不修改传入的 answers。
|
|
74
|
+
*
|
|
75
|
+
* @param allowlist - 允许注入的键(本次扫描结果或会话白名单,两者等价)。
|
|
76
|
+
* @param answers - 用户提交的键值对。
|
|
77
|
+
* @returns 通过校验的子集。
|
|
78
|
+
*/
|
|
79
|
+
export function filterAnswers(allowlist, answers) {
|
|
80
|
+
const out = {};
|
|
81
|
+
if (answers === undefined)
|
|
82
|
+
return out;
|
|
83
|
+
const allowed = new Set(allowlist);
|
|
84
|
+
for (const [key, value] of Object.entries(answers)) {
|
|
85
|
+
if (key.startsWith('__'))
|
|
86
|
+
continue;
|
|
87
|
+
if (!allowed.has(key))
|
|
88
|
+
continue;
|
|
89
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
90
|
+
continue;
|
|
91
|
+
out[key] = value;
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 惰性清理过期会话(每次访问顺带执行,不挂定时器)。
|
|
97
|
+
*
|
|
98
|
+
* 定时器会让插件在宿主里留下一个永不退出的句柄,而惰性清理的代价只是每次读
|
|
99
|
+
* 多走一遍 Map——会话数量上限是"同时在途的暂停安装",实践中为个位数。
|
|
100
|
+
*
|
|
101
|
+
* @returns 本次清掉的会话数。
|
|
102
|
+
*/
|
|
103
|
+
export function pruneExpiredSessions() {
|
|
104
|
+
const cutoff = now() - SESSION_TTL_MS;
|
|
105
|
+
let removed = 0;
|
|
106
|
+
for (const [key, session] of sessions) {
|
|
107
|
+
if (session.createdAt > cutoff)
|
|
108
|
+
continue;
|
|
109
|
+
sessions.delete(key);
|
|
110
|
+
removed += 1;
|
|
111
|
+
}
|
|
112
|
+
return removed;
|
|
113
|
+
}
|
|
114
|
+
/** 当前会话数(诊断与测试用)。 */
|
|
115
|
+
export function sessionCount() {
|
|
116
|
+
return sessions.size;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 替换时钟(仅测试用)。
|
|
120
|
+
*
|
|
121
|
+
* 会话的 TTL 是 15 分钟,真等一遍不可能;用一个可注入的时钟把"过期"变成
|
|
122
|
+
* 确定性事件。生产路径不调用它。
|
|
123
|
+
*
|
|
124
|
+
* @param clock - 返回 epoch 毫秒的函数。
|
|
125
|
+
* @returns 把时钟恢复为 Date.now 的还原函数。
|
|
126
|
+
*/
|
|
127
|
+
export function __setClockForTests(clock) {
|
|
128
|
+
const previous = now;
|
|
129
|
+
now = clock;
|
|
130
|
+
return () => { now = previous; };
|
|
131
|
+
}
|
|
132
|
+
/** 清空全部会话(测试用;返回被清掉的数量)。 */
|
|
133
|
+
export function __resetSessionsForTests() {
|
|
134
|
+
const size = sessions.size;
|
|
135
|
+
sessions.clear();
|
|
136
|
+
return size;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* 把一次"需要用户输入"的安装挂到全局变更队列上。
|
|
140
|
+
*
|
|
141
|
+
* 存在的意义:会话创建与随后的安装是两步,中间可能有并发的第二个安装。
|
|
142
|
+
* 走 paths.ts 的 enqueueMutation 让"读会话 → 解析 answers → 触发安装"整体串行,
|
|
143
|
+
* 与环境的其他变更共享同一把进程内锁。
|
|
144
|
+
*
|
|
145
|
+
* @param task - 要在串行区里执行的工作。
|
|
146
|
+
* @returns 任务结果。
|
|
147
|
+
*/
|
|
148
|
+
export function withInstallSession(task) {
|
|
149
|
+
return enqueueMutation(task);
|
|
150
|
+
}
|