dsh-vscode-mode 0.1.42 → 0.1.44
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/client.js +107 -66
- package/lib/client.js.map +1 -1
- package/lib/index.js +252 -26
- package/lib/index.js.map +1 -1
- package/package.json +1 -5
- package/src/client/monaco/lsp/providers.ts +129 -62
- package/src/client/styles/editor.css +0 -6
- package/src/client/ui/McpSettings.ts +5 -1
- package/src/compat.ts +46 -5
- package/src/dshVersion.ts +121 -0
- package/src/fileOpenSettings.ts +143 -24
- package/src/host-deps.d.ts +5 -5
- package/src/index.ts +2 -1
- package/src/lsp/settings.ts +12 -6
- package/src/shared/compat.ts +9 -3
package/lib/index.js
CHANGED
|
@@ -128,18 +128,9 @@ const FILE_OPEN_SETTINGS_NS = "dsh-vscode-mode";
|
|
|
128
128
|
const FILE_OPEN_DEFAULT = "auto";
|
|
129
129
|
let depsPromise;
|
|
130
130
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* @returns keybindings 字段形状
|
|
135
|
-
*/
|
|
136
|
-
function keybindingsShape(z) {
|
|
137
|
-
const shape = {};
|
|
138
|
-
for (const [id, chord] of Object.entries(KEYBINDING_DEFAULTS)) shape[id] = z.string().default(chord);
|
|
139
|
-
return shape;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* 动态加载设置依赖(模块级缓存;任一缺失返回 null 而非抛错)。
|
|
131
|
+
* 动态加载设置依赖(模块级缓存;任一缺失/失败返回 null 而非抛错)。
|
|
132
|
+
* installSettingsSection 仅在 rc 线 dsh-settings 中存在时提供(alpha 起移除,
|
|
133
|
+
* 属性探测得到 undefined,不抛错)。
|
|
143
134
|
* @author ddj 2026年08月24号
|
|
144
135
|
* @returns 设置依赖或 null
|
|
145
136
|
*/
|
|
@@ -150,6 +141,101 @@ function loadSettingsDeps() {
|
|
|
150
141
|
})).catch(() => null);
|
|
151
142
|
return depsPromise;
|
|
152
143
|
}
|
|
144
|
+
const INSTALL_UNMOUNTED = "设置 section 尚未装配";
|
|
145
|
+
const INSTALL_LEGACY = "rc 线:dsh-settings.installSettingsSection";
|
|
146
|
+
const INSTALL_SERVICE = "0.1.2-alpha 线:settings 服务 installSection";
|
|
147
|
+
const INSTALL_NONE = "两路均不可用:设置持久化降级为配置值";
|
|
148
|
+
let observedInstall = {
|
|
149
|
+
strategy: "unknown",
|
|
150
|
+
note: INSTALL_UNMOUNTED
|
|
151
|
+
};
|
|
152
|
+
/** 记录最近一次安装策略(供兼容报告展示;失败路径也记录,便于诊断)。 */
|
|
153
|
+
function recordInstall(strategy, note) {
|
|
154
|
+
observedInstall = {
|
|
155
|
+
strategy,
|
|
156
|
+
note
|
|
157
|
+
};
|
|
158
|
+
return strategy;
|
|
159
|
+
}
|
|
160
|
+
/** 读取观测到的安装策略(供报告;测试可用 reset 复位)。 */
|
|
161
|
+
function settingsInstallStrategy() {
|
|
162
|
+
return observedInstall.strategy;
|
|
163
|
+
}
|
|
164
|
+
/** 读取观测到的安装策略说明文案。 */
|
|
165
|
+
function settingsInstallNote() {
|
|
166
|
+
return observedInstall.note;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* 设置 section 版本自适应安装(核心策略分派)。
|
|
170
|
+
* legacy:dsh-settings 仍导出 installSettingsSection(rc 线)→ 原样调用,行为与旧版一致。
|
|
171
|
+
* service:该导出已移除(0.1.2-alpha 起)→ 经 ctx.inject(['settings']) 走服务方法
|
|
172
|
+
* provider.installSection(owner, ns, schema, entry, hooks)(等义封装,含
|
|
173
|
+
* base 层与 fiber 卸载回退)。回调内方法缺失再降级记录 none。
|
|
174
|
+
* none:两条路由都不存在 → 仅记录并告警,调用方按配置值运行。
|
|
175
|
+
* 全程不抛错、不产生未捕获 rejection。
|
|
176
|
+
* @author ddj 2026年09月02号
|
|
177
|
+
* @param ctx DSH host 上下文(inject 可选探测)
|
|
178
|
+
* @param ns 设置命名空间
|
|
179
|
+
* @param schema schemastery schema
|
|
180
|
+
* @param entry 初始设置值(作为 base 层)
|
|
181
|
+
* @param hooks 设置源绑定与变更回调
|
|
182
|
+
* @param loader 依赖装载器(测试注入)
|
|
183
|
+
* @returns 采用/观测到的策略
|
|
184
|
+
*/
|
|
185
|
+
async function runSettingsInstall(ctx, ns, schema, entry, hooks, loader = loadSettingsDeps) {
|
|
186
|
+
let deps = null;
|
|
187
|
+
try {
|
|
188
|
+
deps = await loader();
|
|
189
|
+
} catch {}
|
|
190
|
+
if (!deps) {
|
|
191
|
+
console.warn("[dsh-vscode-mode] 设置依赖不可用,section " + ns + " 未安装(配置回退)");
|
|
192
|
+
return recordInstall("none", INSTALL_NONE);
|
|
193
|
+
}
|
|
194
|
+
const legacy = deps.installSettingsSection;
|
|
195
|
+
if (typeof legacy === "function") try {
|
|
196
|
+
legacy(ctx, ns, schema, entry, hooks);
|
|
197
|
+
return recordInstall("legacy", INSTALL_LEGACY);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
console.warn("[dsh-vscode-mode] legacy 设置安装失败,尝试服务路由:" + String(error));
|
|
200
|
+
}
|
|
201
|
+
const ctxInject = ctx.inject;
|
|
202
|
+
if (typeof ctxInject !== "function") return recordInstall("none", INSTALL_NONE);
|
|
203
|
+
try {
|
|
204
|
+
ctxInject(["settings"], (sctx) => {
|
|
205
|
+
const sc = sctx;
|
|
206
|
+
const provider = typeof sc.get === "function" ? sc.get("settings") : sc.settings;
|
|
207
|
+
const install = provider?.installSection;
|
|
208
|
+
if (typeof install !== "function") {
|
|
209
|
+
console.warn("[dsh-vscode-mode] settings 服务无 installSection(DSH 版本 API 变化),section " + ns + " 降级为配置值");
|
|
210
|
+
recordInstall("none", INSTALL_NONE);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
install.call(provider, ctx, ns, schema, entry, hooks);
|
|
215
|
+
recordInstall("service", INSTALL_SERVICE);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.warn("[dsh-vscode-mode] settings.installSection 安装失败(" + String(error) + "),section " + ns + " 降级为配置值");
|
|
218
|
+
recordInstall("none", INSTALL_NONE);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.warn("[dsh-vscode-mode] settings 服务路由不可用(" + String(error) + ")");
|
|
223
|
+
return recordInstall("none", INSTALL_NONE);
|
|
224
|
+
}
|
|
225
|
+
if (observedInstall.strategy !== "unknown") return observedInstall.strategy;
|
|
226
|
+
return recordInstall("service", "已调度 settings 服务 installSection(等待 settings 就绪)");
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* 按命令目录构建 keybindings 显式键形状(每键独立默认值)。
|
|
230
|
+
* @author ddj 2026年08月26号
|
|
231
|
+
* @param z schemastery 命名空间
|
|
232
|
+
* @returns keybindings 字段形状
|
|
233
|
+
*/
|
|
234
|
+
function keybindingsShape(z) {
|
|
235
|
+
const shape = {};
|
|
236
|
+
for (const [id, chord] of Object.entries(KEYBINDING_DEFAULTS)) shape[id] = z.string().default(chord);
|
|
237
|
+
return shape;
|
|
238
|
+
}
|
|
153
239
|
function normalizeValue(value) {
|
|
154
240
|
if (typeof value !== "string" || value.trim() === "") return FILE_OPEN_DEFAULT;
|
|
155
241
|
return value.trim();
|
|
@@ -158,8 +244,8 @@ function configValue(config) {
|
|
|
158
244
|
return normalizeValue(config?.fileOpenTool);
|
|
159
245
|
}
|
|
160
246
|
/**
|
|
161
|
-
* 安装设置 section
|
|
162
|
-
* @author ddj 2026年08月24号
|
|
247
|
+
* 安装设置 section(版本自适应;任一策略不可用返回 false 不抛错)。
|
|
248
|
+
* @author ddj 2026年08月24号 / 2026年09月02号
|
|
163
249
|
* @param ctx DSH host 上下文
|
|
164
250
|
* @param ns 设置命名空间
|
|
165
251
|
* @param entry 初始设置值
|
|
@@ -168,14 +254,19 @@ function configValue(config) {
|
|
|
168
254
|
* @returns 是否成功安装
|
|
169
255
|
*/
|
|
170
256
|
async function installOpenSettingsSection(ctx, ns, entry, hooks, loader = loadSettingsDeps) {
|
|
171
|
-
|
|
257
|
+
let deps = null;
|
|
258
|
+
try {
|
|
259
|
+
deps = await loader();
|
|
260
|
+
} catch {}
|
|
172
261
|
if (!deps) return false;
|
|
173
|
-
const
|
|
262
|
+
const strategy = await runSettingsInstall(ctx, ns, deps.z.object({
|
|
174
263
|
fileOpenTool: deps.z.string().default(FILE_OPEN_DEFAULT),
|
|
175
264
|
keybindings: deps.z.object(keybindingsShape(deps.z)).default({ ...KEYBINDING_DEFAULTS })
|
|
176
|
-
})
|
|
177
|
-
|
|
178
|
-
|
|
265
|
+
}), entry, {
|
|
266
|
+
setSource: (source) => hooks.setSource(source),
|
|
267
|
+
onChange: hooks.onChange
|
|
268
|
+
}, loader);
|
|
269
|
+
return strategy === "legacy" || strategy === "service";
|
|
179
270
|
}
|
|
180
271
|
/**
|
|
181
272
|
* 注册设置命名空间,并提供 host 侧的读取与更新状态。
|
|
@@ -370,6 +461,101 @@ async function runPnpmInstall(ctx, profileDir) {
|
|
|
370
461
|
}
|
|
371
462
|
}
|
|
372
463
|
//#endregion
|
|
464
|
+
//#region src/dshVersion.ts
|
|
465
|
+
/**
|
|
466
|
+
* dsh-vscode-mode host — DSH 核心版本探测与区间匹配(版本适配机制的地基)。
|
|
467
|
+
* 约定:以运行时可解析的 @deepseek-ai/dsh-settings 包版本代表 DSH 核心版本——
|
|
468
|
+
* 核心包发布锁步同版(rc.2 / alpha.2 全树同版实证),且该包是插件动态依赖面、
|
|
469
|
+
* exports 已放行 ./package.json。解析失败按候选降级(dsh-web-app / dsh-base / dsh),
|
|
470
|
+
* 全部失败返回空串(报告显示"未探测",功能按能力探测运行)。
|
|
471
|
+
* 纯函数(parse / compare / inRange / familyLabel)可在 node 环境单测。
|
|
472
|
+
* 作者 ddj 2026-09-02
|
|
473
|
+
*/
|
|
474
|
+
const VERSION_RE = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
475
|
+
/** 解析版本串;非法返回 null(不抛错)。 */
|
|
476
|
+
function parseDshVersion(input) {
|
|
477
|
+
const match = VERSION_RE.exec(input.trim());
|
|
478
|
+
if (!match) return null;
|
|
479
|
+
return {
|
|
480
|
+
major: Number(match[1]),
|
|
481
|
+
minor: Number(match[2]),
|
|
482
|
+
patch: Number(match[3]),
|
|
483
|
+
pre: match[4] ? match[4].split(".") : []
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
/** 预发布标识比较:纯数字按值;数字段 < 字母段;字母按字典序(semver 规则)。 */
|
|
487
|
+
function comparePreId(a, b) {
|
|
488
|
+
const numericA = /^\d+$/.test(a);
|
|
489
|
+
const numericB = /^\d+$/.test(b);
|
|
490
|
+
if (numericA && numericB) return Number(a) - Number(b);
|
|
491
|
+
if (numericA !== numericB) return numericA ? -1 : 1;
|
|
492
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
493
|
+
}
|
|
494
|
+
/** 比较两个已解析版本:a<b → -1;相等 → 0;a>b → 1。 */
|
|
495
|
+
function compareDshVersions(a, b) {
|
|
496
|
+
for (const key of [
|
|
497
|
+
"major",
|
|
498
|
+
"minor",
|
|
499
|
+
"patch"
|
|
500
|
+
]) if (a[key] !== b[key]) return a[key] < b[key] ? -1 : 1;
|
|
501
|
+
if (a.pre.length === b.pre.length && a.pre.every((part, index) => part === b.pre[index])) return 0;
|
|
502
|
+
if (a.pre.length === 0) return 1;
|
|
503
|
+
if (b.pre.length === 0) return -1;
|
|
504
|
+
const length = Math.max(a.pre.length, b.pre.length);
|
|
505
|
+
for (let i = 0; i < length; i++) {
|
|
506
|
+
const left = a.pre[i];
|
|
507
|
+
const right = b.pre[i];
|
|
508
|
+
if (left === void 0) return -1;
|
|
509
|
+
if (right === void 0) return 1;
|
|
510
|
+
const cmp = comparePreId(left, right);
|
|
511
|
+
if (cmp !== 0) return cmp;
|
|
512
|
+
}
|
|
513
|
+
return 0;
|
|
514
|
+
}
|
|
515
|
+
/** 版本是否落在区间内(入参解析失败一律不命中)。 */
|
|
516
|
+
function inDshRange(version, range) {
|
|
517
|
+
if (!version) return false;
|
|
518
|
+
if (range.from) {
|
|
519
|
+
const lower = parseDshVersion(range.from);
|
|
520
|
+
if (!lower || compareDshVersions(version, lower) < 0) return false;
|
|
521
|
+
}
|
|
522
|
+
if (range.to) {
|
|
523
|
+
const upper = parseDshVersion(range.to);
|
|
524
|
+
if (!upper || compareDshVersions(version, upper) > 0) return false;
|
|
525
|
+
}
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
/** 版本线标签:报告与文档展示版本归属;不可解析返回 '未知'。 */
|
|
529
|
+
function familyLabel(input) {
|
|
530
|
+
const version = parseDshVersion(input);
|
|
531
|
+
if (!version) return "未知";
|
|
532
|
+
if (inDshRange(version, { from: "0.1.2-alpha.1" })) return "0.1.2-alpha 及更新(设置 API=settings.installSection)";
|
|
533
|
+
return "0.1.0/0.1.1 rc 线(设置 API=installSettingsSection)";
|
|
534
|
+
}
|
|
535
|
+
/** 探测候选:按与插件运行环境相关性排序,逐个尝试解析 package.json。 */
|
|
536
|
+
const VERSION_CANDIDATES = [
|
|
537
|
+
"@deepseek-ai/dsh-settings/package.json",
|
|
538
|
+
"@deepseek-ai/dsh-web-app/package.json",
|
|
539
|
+
"@deepseek-ai/dsh-base/package.json",
|
|
540
|
+
"@deepseek-ai/dsh/package.json"
|
|
541
|
+
];
|
|
542
|
+
let detectedVersion;
|
|
543
|
+
/** 探测运行中 DSH 核心版本(模块级缓存;失败空串,不抛错)。 */
|
|
544
|
+
function detectDshVersion() {
|
|
545
|
+
if (detectedVersion !== void 0) return detectedVersion;
|
|
546
|
+
detectedVersion = "";
|
|
547
|
+
const require = createRequire(import.meta.url);
|
|
548
|
+
for (const specifier of VERSION_CANDIDATES) try {
|
|
549
|
+
const file = require.resolve(specifier);
|
|
550
|
+
const pkg = JSON.parse(readFileSync(file, "utf8"));
|
|
551
|
+
if (typeof pkg.version === "string" && parseDshVersion(pkg.version) !== null) {
|
|
552
|
+
detectedVersion = pkg.version;
|
|
553
|
+
break;
|
|
554
|
+
}
|
|
555
|
+
} catch {}
|
|
556
|
+
return detectedVersion;
|
|
557
|
+
}
|
|
558
|
+
//#endregion
|
|
373
559
|
//#region src/shared/rpc.ts
|
|
374
560
|
/** webServer 精确路由。 */
|
|
375
561
|
const RPC_PATH = "/edrv/rpc";
|
|
@@ -745,26 +931,63 @@ function detectGuards(ctx) {
|
|
|
745
931
|
note: duplicates[0] ?? "唯一装配"
|
|
746
932
|
}];
|
|
747
933
|
}
|
|
934
|
+
/** 已实测覆盖的最高 DSH 版本(适配矩阵上界,超过则提示,见 buildReport)。 */
|
|
935
|
+
const TESTED_DSH_MAX = "0.1.2-alpha.4";
|
|
936
|
+
/** 版本适配机制状态行:DSH 版本探测 + 设置 section 安装策略。 */
|
|
937
|
+
function versionAdapters(dshVersion) {
|
|
938
|
+
const adapters = [];
|
|
939
|
+
const parsed = parseDshVersion(dshVersion);
|
|
940
|
+
if (dshVersion === "") adapters.push({
|
|
941
|
+
name: "DSH 版本",
|
|
942
|
+
active: false,
|
|
943
|
+
note: "未探测到版本号(能力探测模式运行)"
|
|
944
|
+
});
|
|
945
|
+
else if (!parsed) adapters.push({
|
|
946
|
+
name: "DSH 版本",
|
|
947
|
+
active: false,
|
|
948
|
+
note: "无法解析版本号 " + dshVersion + "(能力探测模式运行)"
|
|
949
|
+
});
|
|
950
|
+
else adapters.push({
|
|
951
|
+
name: "DSH 版本",
|
|
952
|
+
active: true,
|
|
953
|
+
note: dshVersion + " · " + familyLabel(dshVersion)
|
|
954
|
+
});
|
|
955
|
+
const strategy = settingsInstallStrategy();
|
|
956
|
+
adapters.push({
|
|
957
|
+
name: "设置 section 安装(版本适配)",
|
|
958
|
+
active: strategy === "legacy" || strategy === "service",
|
|
959
|
+
note: settingsInstallNote()
|
|
960
|
+
});
|
|
961
|
+
return adapters;
|
|
962
|
+
}
|
|
748
963
|
/**
|
|
749
964
|
* 构建完整兼容性报告(RPC 与启动日志共用)。
|
|
750
|
-
* @author ddj 2026年08月24号
|
|
965
|
+
* @author ddj 2026年08月24号 / 2026年09月02号
|
|
751
966
|
* @param ctx DSH host 上下文
|
|
752
|
-
* @param options 测试注入:depsAvailable 跳过动态导入、version
|
|
967
|
+
* @param options 测试注入:depsAvailable 跳过动态导入、version 固定插件版本、dshVersion 固定 DSH 版本
|
|
753
968
|
* @returns 兼容性报告
|
|
754
969
|
*/
|
|
755
970
|
async function buildReport(ctx, options) {
|
|
756
971
|
const deps = options?.depsAvailable ?? await loadSettingsDeps() !== null;
|
|
972
|
+
const dshVersion = options?.dshVersion ?? detectDshVersion();
|
|
757
973
|
const external = detectExternal(ctx, deps);
|
|
758
974
|
const guards = detectGuards(ctx);
|
|
975
|
+
const adapters = versionAdapters(dshVersion);
|
|
759
976
|
const warnings = [];
|
|
760
977
|
if (!deps) warnings.push("未安装 @deepseek-ai/dsh-settings:文件打开工具设置持久化不可用(降级为配置值)");
|
|
978
|
+
if (settingsInstallStrategy() === "none") warnings.push("设置 section 安装不可用:" + settingsInstallNote());
|
|
979
|
+
const parsed = parseDshVersion(dshVersion);
|
|
980
|
+
const testedMax = parseDshVersion(TESTED_DSH_MAX);
|
|
981
|
+
if (parsed && testedMax && compareDshVersions(parsed, testedMax) > 0) warnings.push("DSH " + dshVersion + " 高于已实测版本(0.1.2-alpha.4):设置 API 按能力探测运行,异常时请回报适配矩阵");
|
|
761
982
|
for (const guard of guards) if (!guard.active && guard.note) warnings.push(guard.note);
|
|
762
983
|
return {
|
|
763
984
|
pluginVersion: options?.version ?? pluginVersionOf(),
|
|
764
985
|
external,
|
|
765
986
|
guards,
|
|
987
|
+
adapters,
|
|
766
988
|
warnings,
|
|
767
|
-
devForm: readDevForm()
|
|
989
|
+
devForm: readDevForm(),
|
|
990
|
+
dshVersion
|
|
768
991
|
};
|
|
769
992
|
}
|
|
770
993
|
//#endregion
|
|
@@ -7498,7 +7721,10 @@ function createLspRpc(deps) {
|
|
|
7498
7721
|
* @returns 是否成功安装
|
|
7499
7722
|
*/
|
|
7500
7723
|
async function installLspSettingsSection(ctx, entry) {
|
|
7501
|
-
|
|
7724
|
+
let deps = null;
|
|
7725
|
+
try {
|
|
7726
|
+
deps = await loadSettingsDeps();
|
|
7727
|
+
} catch {}
|
|
7502
7728
|
if (!deps) return false;
|
|
7503
7729
|
try {
|
|
7504
7730
|
const z = deps.z;
|
|
@@ -7509,11 +7735,11 @@ async function installLspSettingsSection(ctx, entry) {
|
|
|
7509
7735
|
path: z.string()
|
|
7510
7736
|
}).default({});
|
|
7511
7737
|
const schema = z.object(langShape).default({});
|
|
7512
|
-
|
|
7738
|
+
const strategy = await runSettingsInstall(ctx, LSP_SETTINGS_NS, schema, entry, {
|
|
7513
7739
|
setSource: () => {},
|
|
7514
7740
|
onChange: () => {}
|
|
7515
7741
|
});
|
|
7516
|
-
return
|
|
7742
|
+
return strategy === "legacy" || strategy === "service";
|
|
7517
7743
|
} catch (error) {
|
|
7518
7744
|
console.error("[dsh-vscode-mode] LSP 设置 section 安装失败:" + String(error));
|
|
7519
7745
|
return false;
|
|
@@ -7599,7 +7825,7 @@ async function logCompatSummary(ctx, warnings) {
|
|
|
7599
7825
|
for (const warning of warnings) report.warnings.push(warning);
|
|
7600
7826
|
const logger = ctx.logger;
|
|
7601
7827
|
if (!logger?.info) return;
|
|
7602
|
-
const head = "[dsh-vscode-mode] 兼容性:" + report.external.length + " 项外部适配 / " + report.guards.length + " 项护栏";
|
|
7828
|
+
const head = "[dsh-vscode-mode] 兼容性:" + (report.dshVersion ? "DSH " + report.dshVersion : "DSH 未探测") + " · " + report.external.length + " 项外部适配 / " + report.guards.length + " 项护栏 / " + (report.adapters?.length ?? 0) + " 项版本适配";
|
|
7603
7829
|
if (report.warnings.length) logger.warn?.(head + ",警告 " + report.warnings.length + " 条:" + report.warnings.join(";"));
|
|
7604
7830
|
else logger.info?.(head + ",无警告");
|
|
7605
7831
|
} catch (error) {
|