@noob-stupid/dsh-plugin-console 0.5.48 → 0.5.49
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/lib/server/infra/paths.js +52 -10
- package/package.json +1 -1
|
@@ -66,20 +66,45 @@ function baseDirOf(baseUrl) {
|
|
|
66
66
|
* 成功后从解析结果**向上找最近的 package.json** 作为该包的清单。
|
|
67
67
|
* ⇒ 负控不变:真不存在的子路径,三条路都失败 ⇒ 仍然返回 null(**绝不放松成"一律放行"**)。
|
|
68
68
|
*/
|
|
69
|
-
|
|
69
|
+
/** 从解析结果向上找清单。**优先认包名匹配的那份**(★ 0.5.49 改错,见下)。
|
|
70
|
+
*
|
|
71
|
+
* ★ 2026-10-14(0.5.49)改错:不能只取"最近的 package.json"。
|
|
72
|
+
* 真机现场:`@linxin666/dsh-web-all/plugin-manager` 的 exports 目标是 `./lib/shells/shell.js`,
|
|
73
|
+
* 而 `lib/shells/` 下还有一个**构建产物用的私有子清单**
|
|
74
|
+
* (`{"name":"@linxin666/dsh-web-all-shells","private":true}` —— **没有 version 字段**)。
|
|
75
|
+
* 只认"最近" ⇒ 拿到那份子清单 ⇒ 版本/仓库全空(和"解不出来"一样是坏结果,只是换了个坏法)。
|
|
76
|
+
* 所以向上找时:命中"name 与引用包名相同"的清单立即返回;一路都没匹配才退回最近的那份
|
|
77
|
+
* (不返回 null —— 包确实存在,只是清单不规范,此时宁可给出最近的那份也不谎报"没有这个包")。
|
|
78
|
+
*/
|
|
79
|
+
function nearestPackageJson(fromPath, expectedName = null) {
|
|
70
80
|
try {
|
|
71
81
|
let dir = dirname(fromPath)
|
|
82
|
+
let fallback = null
|
|
72
83
|
for (let depth = 0; depth < 40; depth += 1) {
|
|
73
84
|
const candidate = join(dir, 'package.json')
|
|
74
|
-
if (existsSync(candidate))
|
|
85
|
+
if (existsSync(candidate)) {
|
|
86
|
+
if (fallback === null) fallback = candidate
|
|
87
|
+
if (typeof expectedName === 'string' && expectedName !== '' && manifestNameOf(candidate) === expectedName) return candidate
|
|
88
|
+
}
|
|
75
89
|
const parent = dirname(dir)
|
|
76
90
|
if (parent === dir) break
|
|
77
91
|
dir = parent
|
|
78
92
|
}
|
|
93
|
+
return fallback
|
|
79
94
|
} catch {}
|
|
80
95
|
return null
|
|
81
96
|
}
|
|
82
97
|
|
|
98
|
+
/** 读一份清单的 `name`(读不到/不是 JSON 就返回 null)。 */
|
|
99
|
+
function manifestNameOf(file) {
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(readFileSync(file, 'utf8'))
|
|
102
|
+
return typeof parsed?.name === 'string' ? parsed.name : null
|
|
103
|
+
} catch {
|
|
104
|
+
return null
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
83
108
|
/** 该引用是不是"包 + 子路径"形态(`pkg/sub`、`@scope/pkg/sub`)。
|
|
84
109
|
* 判据与 packageNameOf 同源:剥掉包名后还剩东西 ⇒ 是子路径引用。 */
|
|
85
110
|
function isSubpathRef(refName) {
|
|
@@ -87,12 +112,15 @@ function isSubpathRef(refName) {
|
|
|
87
112
|
return refName !== packageNameOf(refName)
|
|
88
113
|
}
|
|
89
114
|
|
|
90
|
-
/**
|
|
115
|
+
/** 用真实解析语义解析「包/子路径」引用的清单路径:先解析引用本身,再向上找**该包**的清单。
|
|
116
|
+
* 向上找时把包名传下去(`nearestPackageJson(refName, expectedName)`)—— 真机上就有子目录里放
|
|
117
|
+
* 私有子清单的包(`@linxin666/dsh-web-all/lib/shells/package.json`,name 是 `…-shells` 且无 version),
|
|
118
|
+
* 只取"最近"会拿到那份、版本照样是空的。详见 nearestPackageJson 的注释。 */
|
|
91
119
|
function resolveViaRealSemantics(refName, base) {
|
|
92
120
|
if (typeof base !== 'string' || base === '') return null
|
|
93
121
|
try {
|
|
94
122
|
const entry = createRequire(join(base, 'package.json')).resolve(refName)
|
|
95
|
-
return nearestPackageJson(entry)
|
|
123
|
+
return nearestPackageJson(entry, packageNameOf(refName))
|
|
96
124
|
} catch {
|
|
97
125
|
return null
|
|
98
126
|
}
|
|
@@ -103,13 +131,27 @@ function resolvePackageJson(pkgName, baseDir, fallbackBase) {
|
|
|
103
131
|
// ① 真实解析语义(认 exports 子路径)—— 优先,且**不**拼 `/package.json`
|
|
104
132
|
const real = resolveViaRealSemantics(pkgName, baseDir)
|
|
105
133
|
if (real !== null) return real
|
|
106
|
-
// ★
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
//
|
|
134
|
+
// ★ 子路径引用(`包/子路径`)单独一条路:只认「真实解析语义」,但**两个基准都认**。
|
|
135
|
+
//
|
|
136
|
+
// 为什么要挡住后两条:那两条是按**包名**(packageNameOf 剥掉子路径后的 name)找
|
|
137
|
+
// `node_modules/<包名>/package.json`,对不存在的子路径也会命中**包根**那份清单
|
|
138
|
+
// ⇒ 把一个坏引用判成好的 —— 正是"校验被放松成一律放行",任务红线明令不许。
|
|
110
139
|
// (本机实测:`@scope/tool/nope` 在 @scope/tool 存在时会从 fallback 拿到包根清单。)
|
|
111
|
-
//
|
|
112
|
-
|
|
140
|
+
//
|
|
141
|
+
// ★ 2026-10-14(0.5.49)改错:这道闸原先写成**在 fallbackBase 那次真实解析之前**就 `return null`,
|
|
142
|
+
// 于是把 profile 回退这条**合法**路径也一起掐了 —— 0.5.48 上 `@linxin666/dsh-web-all/plugin-manager`
|
|
143
|
+
// (框架树里没有、只在 profile 里)从"解得出"退回 null,面板里那批第三方子路径行的
|
|
144
|
+
// 版本/安装日期/仓库全变空(实测 /plugin-console/state 确认),而官方子路径行走的是框架基准、
|
|
145
|
+
// 不受影响 ⇒ 现场不显眼。判据本身没错,错在**位置**:要挡的是"按包名找清单"那两条兜底,
|
|
146
|
+
// 不是"解析这个引用本身"。所以现在:baseDir 真实解析 → fallbackBase 真实解析 → 再 return null。
|
|
147
|
+
// ⇒ 负控不变(`@scope/tool/nope` 两条真实解析都失败 ⇒ 仍是 null,绝不放松成一律放行)。
|
|
148
|
+
if (isSubpathRef(pkgName)) {
|
|
149
|
+
if (typeof fallbackBase === 'string' && fallbackBase !== '' && fallbackBase !== baseDir) {
|
|
150
|
+
const realFallback = resolveViaRealSemantics(pkgName, fallbackBase)
|
|
151
|
+
if (realFallback !== null) return realFallback
|
|
152
|
+
}
|
|
153
|
+
return null
|
|
154
|
+
}
|
|
113
155
|
// ② 既有两条(顺序与行为不变):`<name>/package.json` 解析 → node_modules 物理路径
|
|
114
156
|
try {
|
|
115
157
|
return createRequire(join(baseDir, 'package.json')).resolve(`${name}/package.json`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noob-stupid/dsh-plugin-console",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.49",
|
|
4
4
|
"description": "DSH 框架升级安全与插件升级门控:一键升级、失败自动回滚、升级后回滚上版、旧插件不适配自动禁用;内置多源插件市场为发现层,插件源全部可自定义,可指向公司内网私有源 / 私有索引 / 本地 Git 仓库,纯内网离线可用 | Framework upgrade safety & plugin version gating for DSH, with a customizable multi-source plugin market: point every source at internal mirrors or a local file:// repo for intranet-only, offline installs.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|