dsh-multi-router 0.5.1 → 0.5.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。版本号从 `0.1` 起以功能迭代为主,接口在 `1.0` 前可能变化。
4
4
 
5
+ ## 0.5.3
6
+
7
+ - 签到面板的手机号打码兼容国际区号及以 0 开头的号码,账号名称和自动签到控件标签都隐藏中间数字。
8
+
9
+ ## 0.5.2
10
+
11
+ - Qoder 签到复用 PAT → Job Token 认证及桌面活动请求头,仅领取有效期内的 `CLAIM_BENEFIT / CLAIMABLE` 活动;宣传和锁定活动不领取,「无活动」不误报认证失败,奖励不使用猜测值。
12
+ - 北京时间 10:05 首次检查,20:05 只补查尚未提交领取的失败,最多补查一次;已完成、无活动、提交后结果不明的账号跳过。按账号身份持久化,支持重启、账号调整顺序和重复身份去重。
13
+ - 单独展示令牌失效、平台限制、查询失败与结果待核对;显式更新凭证仅清除认证失败记录,不清除领取意图或设备限制。TRAE 使用原客户端凭证续期,查询失败不再一律误报令牌失效。
14
+ - 签到面板增加最近一轮汇总和补查时间,全部跳过时不重复汇报,手机号打码。接入 WorkBuddy 国内版签到与 AT / RT 续期,查询已签或活动结束时跳过,面板显示连签天数、活动累计积分与本次奖励;只读状态查询可有限重试,领取结果不明不重复提交。
15
+
5
16
  ## 0.5.1
6
17
 
7
18
  - GitHub 插件更新检查只请求提交 SHA,不再下载完整提交差异,修复构建产物较大时「更新元数据过大」导致无法检查的问题。
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  一个插件内置 WorkBuddy、Trae、Qoder 的认证、模型发现和聊天传输,提供三家的多账号池及集中路由。运行不依赖原来三个 DSH 插件;三家代码随安装包一起打包。基于 MIT 上游,固定版本见 `upstream-lock.json`,许可见 `THIRD_PARTY_NOTICES.md`。
8
8
 
9
- 版本:0.5.1。适配 DSH Desktop / Web 0.2.0-rc.2,Node.js ^22.19.0 或 >=24。
9
+ 版本:0.5.3。适配 DSH Desktop / Web 0.2.0-rc.2,Node.js ^22.19.0 或 >=24。
10
10
 
11
11
  ## 在 DSH 里管理
12
12
 
@@ -95,13 +95,15 @@ Qoder 的 `dfmodel` 在真实目录里显示为 DeepSeek-Flash,未声明具体
95
95
 
96
96
  ## 每日积分签到
97
97
 
98
- 在配置面板打开 **积分签到**。当前接入 Trae CN 与 Qoder CN / Global 的已有签到能力:先查询平台是否开放活动、账号与设备是否已领取,再提交领取;活动是否开放和奖励额度以平台响应为准。WorkBuddy / WorkBuddy AI 与 Trae Global 暂无已核验的签到接口,面板会显示需到官方客户端查看,不猜测接口或奖励。
98
+ 在配置面板打开 **积分签到**。当前接入 WorkBuddy 国内版、Trae CN 与 Qoder CN / Global 的签到能力:先查询平台是否开放活动、账号与设备是否已领取,再提交领取;活动是否开放和奖励额度以平台响应为准。WorkBuddy AI 与 Trae Global 暂无已核验的签到接口,面板会显示需到官方客户端查看,不猜测接口或奖励。
99
99
 
100
- - 每个账号可选择「立即签到」,或「签到全部可用账号」。**每日自动签到默认关闭**,按账号单独开启;已停用账号不参与。每天北京时间 10:05 后、DSH 运行期间执行,错过时在下次启动补查;10:05 前不会发起签到请求。
101
- - 请求串行,账号间至少间隔 10 秒。先持久化当天尝试记录,再发请求;同一账号当天最多尝试一次,重复账号副本按平台身份去重。网络超时或结果不明确时不重复提交,请到官方客户端核对。
100
+ - 每个账号可选择「立即签到」,或「签到全部可用账号」。**每日自动签到默认关闭**,按账号单独开启;已停用账号不参与。每天北京时间 10:05 后首次检查,20:05 后仅补查确认未提交领取的查询失败或尚未开放窗口,每个账号最多补查一次。DSH 关闭期间不执行,下次启动按当前时间补查;10:05 前不会发起签到请求。
101
+ - Qoder 先用 PAT 交换临时 Job Token,活动请求使用 `Cosy-ClientType: 10`;仅领取有效期内 `CLAIM_BENEFIT` 且 `CLAIMABLE` 的活动。宣传、锁定或未开放给此账号的活动显示「无活动」,不会误报令牌失效;奖励仅显示领取响应实际返回的金额。TRAE 沿用客户端登录的 Refresh Token 和真实设备参数续期,不依赖短信登录,也不按账号数组位置保存状态。
102
+ - WorkBuddy 国内版沿用已保存的客户端 AT / RT,按 JWT 中的账号身份校验请求;续期后保存新 AT 和轮换的 RT。先查今日签到状态及活动结束时间,再提交一次领取,已签或活动结束时跳过;面板展示返回的连签天数、活动累计积分和本次奖励。网络或 5xx 仅对领取前的只读状态查询最多重试两次(2 秒、4 秒),领取请求不做快速重试。接口契约参考 [WorkBuddy-Daily](https://github.com/L0NE-6/WorkBuddy-Daily/blob/main/workbuddy_daily.py),未采用成长任务、抽奖或客户端活跃模拟。
103
+ - 请求串行,账号间至少间隔 10 秒。先持久化当天意图再发请求,重复账号副本按平台身份去重,调整账号顺序不影响记录。每天最多提交一次领取;提交后网络超时或结果不明确时不重复提交,请到官方客户端核对。成功、今日已领、无活动和结果不明的账号不会加入晚间重试队列。
102
104
  - 保留 Trae 原有设备身份;同一设备当天的领取已使用或结果不明确时,不切到同设备的其他账号继续领取。Qoder 优先复用官方 CLI 的设备身份,没有时使用连接器持久化的单一设备身份,所有账号一致,不随签到轮换。
103
- - 验证、授权拒绝或限流会暂停该平台签到;在官方客户端处理后,可以点击「恢复后续签到」。恢复不会清除今日尝试记录与设备限制,不提供更换设备身份、代理或绕过验证码的能力。平台风控行为不可预测,这些措施不能保证不触发风控。
104
- - 最近结果、可核验的奖励积分与自动签到开关直接展示(Qoder 不展示上游辅助函数猜测的奖励数额);成功后刷新该账号平台余额。记录保存在配置旁的 `checkins.json`,0600 权限,仅保存身份哈希、日期和结果,不保存 Token 或原始服务端错误。保留最近 30 天,记录损坏时停止签到,不自动清空后重试。
105
+ - 验证、403 拒绝或限流会暂停该平台签到;在官方客户端处理后,可以点击「恢复后续签到」。恢复不会清除今日尝试记录与设备限制。401 或明确过期且无法续期的凭证单独显示「令牌失效」,请在「账号与登录」更新凭证;替换凭证只解除认证失败记录,已提交或结果不明的领取记录仍保留。普通网络查询失败不会要求重交令牌。不提供更换设备身份、代理或绕过验证码的能力;不能保证不触发平台风控。
106
+ - 面板显示最近一轮汇总、账号结果、补查时间、可核验奖励与自动签到开关;全部已完成或没有待补查账号时不重复汇报。签到页的手机号打码,不输出令牌或上游原始错误;成功后刷新平台余额。记录保存在配置旁的 `checkins.json`,0600 权限,仅保存身份哈希、日期和结果。保留最近 30 天,记录损坏时停止签到,不自动清空后重试。
105
107
  - 自动签到设置可随配置导入导出,领取记录与平台暂停状态不迁移。多台设备的本地记录不会互相同步,建议只在一台设备开启自动签到;平台领取状态仍会在提交前查询。
106
108
 
107
109
  ## 所有已安装插件的更新与安装
@@ -135,7 +137,7 @@ dsh plugin --profile desktop add dsh-multi-router
135
137
  dsh plugin --profile web add dsh-multi-router
136
138
  ```
137
139
 
138
- 包地址:[dsh-multi-router · npm](https://www.npmjs.com/package/dsh-multi-router)。正式版本由 GitHub Release 自动测试、打包并发布到 npm `latest`,包中已包含编译产物,用户无需自行构建。需要固定版本时可安装 `dsh-multi-router@0.5.1`。
140
+ 包地址:[dsh-multi-router · npm](https://www.npmjs.com/package/dsh-multi-router)。正式版本由 GitHub Release 自动测试、打包并发布到 npm `latest`,包中已包含编译产物,用户无需自行构建。需要固定版本时可安装 `dsh-multi-router@0.5.3`。
139
141
 
140
142
  已使用 npm 来源的用户更新:
141
143
 
@@ -192,7 +194,7 @@ cd dsh-multi-router
192
194
  npm ci
193
195
  npm run check
194
196
  npm run pack:release
195
- dsh plugin --profile desktop add ./dsh-multi-router-0.5.1.tgz
197
+ dsh plugin --profile desktop add ./dsh-multi-router-0.5.3.tgz
196
198
  ```
197
199
 
198
200
  ### 配置账号
package/lib/accounts.js CHANGED
@@ -3,10 +3,10 @@ import {
3
3
  importAccount,
4
4
  localAccountKey,
5
5
  readPortableCredential
6
- } from "./chunk-OMG4FZWV.js";
6
+ } from "./chunk-4H6ZXK75.js";
7
7
  import "./chunk-FTM7RHQV.js";
8
8
  import "./chunk-S5KMFAQM.js";
9
- import "./chunk-GAQ77CH4.js";
9
+ import "./chunk-U7J4ABAM.js";
10
10
  import "./chunk-TEZ2FMEO.js";
11
11
  export {
12
12
  discoverLocalAccounts,
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  PROVIDERS,
14
14
  writePrivateJson
15
- } from "./chunk-GAQ77CH4.js";
15
+ } from "./chunk-U7J4ABAM.js";
16
16
 
17
17
  // src/accounts.mjs
18
18
  import { readFile } from "node:fs/promises";
@@ -161,4 +161,4 @@ export {
161
161
  readPortableCredential,
162
162
  importAccount
163
163
  };
164
- //# sourceMappingURL=chunk-OMG4FZWV.js.map
164
+ //# sourceMappingURL=chunk-4H6ZXK75.js.map
@@ -1,20 +1,22 @@
1
1
  import {
2
+ Checkins,
2
3
  jsonCredential,
3
- qoderPluginDataDir
4
- } from "./chunk-YUP77Q3A.js";
4
+ qoderPluginDataDir,
5
+ supportsCheckin
6
+ } from "./chunk-RPW6DI6O.js";
5
7
  import {
6
8
  discoverLocalAccounts,
7
9
  importAccount,
8
10
  localAccountKey,
9
11
  readPortableCredential
10
- } from "./chunk-OMG4FZWV.js";
12
+ } from "./chunk-4H6ZXK75.js";
11
13
  import {
12
14
  hostIsLoopback
13
15
  } from "./chunk-DNQPZMPF.js";
14
16
  import {
15
17
  Telemetry,
16
18
  matchModel
17
- } from "./chunk-XV7O2LRF.js";
19
+ } from "./chunk-XA3V2DGT.js";
18
20
  import {
19
21
  PROVIDERS,
20
22
  PROVIDER_NAMES,
@@ -25,22 +27,22 @@ import {
25
27
  routeReasoning,
26
28
  validateConfig,
27
29
  writePrivateJson
28
- } from "./chunk-GAQ77CH4.js";
30
+ } from "./chunk-U7J4ABAM.js";
29
31
  import {
30
32
  modelWithCurrentPromotion
31
33
  } from "./chunk-TEZ2FMEO.js";
32
34
 
33
35
  // src/manager.mjs
34
- import { createHash as createHash2, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
36
+ import { createHash, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
35
37
 
36
38
  // package.json
37
- var version = "0.5.1";
39
+ var version = "0.5.3";
38
40
 
39
41
  // src/manager.mjs
40
- import { readFile as readFile3, mkdir as mkdir2, mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
42
+ import { readFile as readFile2, mkdir as mkdir2, mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
41
43
  import { watch } from "node:fs";
42
44
  import { dirname as dirname3, join as join4, relative as relative2, resolve } from "node:path";
43
- import { withFileLock as withFileLock3 } from "@deepseek-ai/dsh-atomic-write";
45
+ import { withFileLock as withFileLock2 } from "@deepseek-ai/dsh-atomic-write";
44
46
 
45
47
  // upstream/qoder/src/status-paths.ts
46
48
  var QODER_STATUS_PATH = "/plugins/dsh-qoder-connect/status";
@@ -629,172 +631,9 @@ var PluginUpdates = class {
629
631
  }
630
632
  };
631
633
 
632
- // src/checkins.mjs
633
- import { createHash } from "node:crypto";
634
- import { readFile as readFile2 } from "node:fs/promises";
635
- import { setTimeout as delay } from "node:timers/promises";
636
- import { withFileLock as withFileLock2 } from "@deepseek-ai/dsh-atomic-write";
637
- var supportsCheckin = (provider) => ["trae", "qoder", "qoder-global"].includes(provider);
638
- var hash = (value) => createHash("sha256").update(value).digest("hex");
639
- var nextDay = (now) => Date.parse(`${beijingDay(now)}T00:00:00+08:00`) + 864e5;
640
- var checkinMessages = {
641
- claimed: "\u7B7E\u5230\u6210\u529F",
642
- "already-claimed": "\u4ECA\u65E5\u5DF2\u9886\u53D6",
643
- "device-used": "\u6B64\u8BBE\u5907\u4ECA\u65E5\u5DF2\u53C2\u4E0E\u7B7E\u5230\uFF0C\u4E0D\u518D\u5207\u6362\u5176\u4ED6\u8D26\u53F7\u9886\u53D6",
644
- "no-campaign": "\u5E73\u53F0\u672A\u5F00\u653E\u53EF\u9886\u53D6\u6D3B\u52A8",
645
- "before-window": "\u7B7E\u5230\u7A97\u53E3\u5C1A\u672A\u5F00\u542F",
646
- paused: "\u5E73\u53F0\u9650\u5236\u6216\u9700\u8981\u9A8C\u8BC1\uFF0C\u5DF2\u6682\u505C\u6B64\u5E73\u53F0\u7B7E\u5230\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u5904\u7406",
647
- uncertain: "\u8BF7\u6C42\u7ED3\u679C\u5F85\u786E\u8BA4\uFF0C\u4ECA\u65E5\u4E0D\u518D\u81EA\u52A8\u63D0\u4EA4\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u6838\u5BF9",
648
- error: "\u7B7E\u5230\u672A\u5B8C\u6210\uFF0C\u4ECA\u65E5\u4E0D\u518D\u91CD\u590D\u5C1D\u8BD5\uFF0C\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u67E5\u770B",
649
- unsupported: "\u6682\u672A\u63A5\u5165\u53EF\u6838\u9A8C\u7684\u7B7E\u5230\u63A5\u53E3\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF"
650
- };
651
- var Checkins = class {
652
- constructor(file, manager, { now = Date.now, spacingMs = 1e4 } = {}) {
653
- this.file = file;
654
- this.manager = manager;
655
- this.now = now;
656
- this.spacingMs = spacingMs;
657
- this.data = { records: {}, devices: {}, pauses: {} };
658
- this.abort = new AbortController();
659
- }
660
- async read() {
661
- try {
662
- const raw = JSON.parse(await readFile2(this.file, "utf8"));
663
- const object = (value) => value && typeof value === "object" && !Array.isArray(value);
664
- if (!object(raw) || !["records", "devices", "pauses"].every((k) => object(raw[k])) || Object.values(raw.records).some((r) => !object(r) || !Array.isArray(r.ids) || !Number.isFinite(r.at) || typeof r.day !== "string")) throw Error("Invalid check-in journal");
665
- this.data = raw;
666
- } catch (e) {
667
- if (e.code !== "ENOENT") throw e;
668
- }
669
- }
670
- async load() {
671
- try {
672
- await this.read();
673
- } catch {
674
- this.failed = true;
675
- }
676
- }
677
- state() {
678
- return {
679
- running: !!this.flight,
680
- current: this.current,
681
- error: this.failed ? "\u7B7E\u5230\u8BB0\u5F55\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u5DF2\u505C\u6B62\u7B7E\u5230\uFF1B\u8BF7\u4FEE\u590D\u8BB0\u5F55\u6587\u4EF6\u540E\u91CD\u542F\u63D2\u4EF6\u3002" : void 0,
682
- schedule: "\u5317\u4EAC\u65F6\u95F4\u6BCF\u5929 10:05 \u540E\uFF0CDSH \u8FD0\u884C\u65F6\u6267\u884C\uFF1B\u9519\u8FC7\u540E\u4E0B\u6B21\u542F\u52A8\u8865\u67E5",
683
- accounts: this.manager.config.accounts.map((a) => {
684
- const rows = Object.values(this.data.records).filter((r) => r.ids?.includes(a.id));
685
- const last = rows.sort((a2, b) => b.at - a2.at)[0];
686
- const pause = this.data.pauses[a.provider];
687
- return {
688
- id: a.id,
689
- supported: supportsCheckin(a.provider),
690
- auto: a.autoCheckin === true,
691
- paused: !!pause,
692
- last: last ? {
693
- day: last.day,
694
- at: last.at,
695
- status: last.status,
696
- amount: last.amount,
697
- message: checkinMessages[last.status] || checkinMessages.error
698
- } : void 0
699
- };
700
- })
701
- };
702
- }
703
- start(ids, automatic = false) {
704
- if (this.failed || this.abort.signal.aborted || this.flight) return;
705
- if (!automatic && (!Array.isArray(ids) || !ids.length || ids.length > 200 || ids.some((id) => !this.manager.config.accounts.some((a) => a.id === id)))) throw Error("\u8BF7\u9009\u62E9\u6709\u6548\u7684\u7B7E\u5230\u8D26\u53F7");
706
- const selected = this.manager.config.accounts.filter((a) => supportsCheckin(a.provider) && a.enabled !== false && (automatic ? a.autoCheckin === true : ids.includes(a.id))).map((a) => a.id);
707
- if (!selected.length) return;
708
- this.flight = (async () => {
709
- let requested = false;
710
- for (const id of selected) {
711
- if (this.abort.signal.aborted) break;
712
- const account = this.manager.config.accounts.find((a) => a.id === id && a.enabled !== false && (!automatic || a.autoCheckin === true));
713
- if (!account) continue;
714
- if (requested) {
715
- await delay(this.spacingMs, void 0, { signal: this.abort.signal });
716
- requested = false;
717
- }
718
- this.current = id;
719
- requested = await this.run(account, automatic);
720
- }
721
- })().catch(() => {
722
- if (!this.abort.signal.aborted) this.failed = true;
723
- }).finally(() => {
724
- this.flight = void 0;
725
- this.current = void 0;
726
- });
727
- }
728
- async resume(provider) {
729
- if (!supportsCheckin(provider) || this.failed || this.flight) throw Error("\u8BF7\u7B49\u5F85\u7B7E\u5230\u5B8C\u6210\uFF0C\u6216\u5148\u4FEE\u590D\u7B7E\u5230\u8BB0\u5F55");
730
- await withFileLock2(this.file, async () => {
731
- await this.read();
732
- delete this.data.pauses[provider];
733
- await writePrivateJson(this.file, this.data);
734
- });
735
- }
736
- async run(account, automatic = false) {
737
- const now = this.now(), day = beijingDay(now);
738
- if (now < Date.parse(`${day}T10:05:00+08:00`)) return false;
739
- return withFileLock2(this.file, async () => {
740
- await this.read();
741
- if (this.abort.signal.aborted || this.data.pauses[account.provider]) return false;
742
- if (Object.values(this.data.records).some((r) => r.day === day && r.ids?.includes(account.id))) return false;
743
- if (this.data.lastRequestAt && now - this.data.lastRequestAt < this.spacingMs) return false;
744
- this.data.lastRequestAt = now;
745
- await writePrivateJson(this.file, this.data);
746
- const client = await this.manager.router.client(account);
747
- if (!client.checkin) return false;
748
- let identity;
749
- try {
750
- identity = await client.checkin.identity(AbortSignal.any([this.abort.signal, AbortSignal.timeout(3e4)]));
751
- } catch {
752
- this.data.pauses[account.provider] = { at: now };
753
- await writePrivateJson(this.file, this.data);
754
- return true;
755
- }
756
- if (!identity?.account || account.provider === "trae" && !identity.device) throw Error("Missing check-in identity");
757
- if (this.abort.signal.aborted || !this.manager.config.accounts.some((a) => a.id === account.id && a.enabled !== false && a.credentialFile === account.credentialFile && (!automatic || a.autoCheckin === true))) return true;
758
- const key = hash(`${account.provider}:${identity.account}`), device = identity.device ? hash(`${account.provider}:${identity.device}`) : void 0;
759
- const old = this.data.records[key];
760
- if (old?.day === day) {
761
- if (!old.ids.includes(account.id)) {
762
- old.ids.push(account.id);
763
- await writePrivateJson(this.file, this.data);
764
- }
765
- return true;
766
- }
767
- const record = { day, at: now, status: "uncertain", ids: [account.id] };
768
- this.data.records[key] = record;
769
- for (const [k, row] of Object.entries(this.data.records)) if (row.at < now - 30 * 864e5) delete this.data.records[k];
770
- for (const [k, row] of Object.entries(this.data.devices)) if (row.until <= now) delete this.data.devices[k];
771
- if (device && this.data.devices[device]?.until > now) {
772
- record.status = "device-used";
773
- await writePrivateJson(this.file, this.data);
774
- return true;
775
- }
776
- if (device) this.data.devices[device] = { until: nextDay(now) };
777
- await writePrivateJson(this.file, this.data);
778
- let result;
779
- try {
780
- result = await client.checkin.claim(AbortSignal.any([this.abort.signal, AbortSignal.timeout(3e4)]));
781
- } catch {
782
- result = { status: "uncertain" };
783
- }
784
- record.status = Object.hasOwn(checkinMessages, result?.status) ? result.status : "uncertain";
785
- if (device && ["already-claimed", "no-campaign"].includes(record.status)) delete this.data.devices[device];
786
- if (["claimed", "already-claimed"].includes(record.status) && Number.isFinite(result.amount) && result.amount >= 0) record.amount = result.amount;
787
- if (record.status === "paused") this.data.pauses[account.provider] = { at: now };
788
- await writePrivateJson(this.file, this.data);
789
- if (record.status === "claimed") await this.manager.monitorAccount(account);
790
- return true;
791
- }, { waitMs: 1e3 });
792
- }
793
- };
794
-
795
634
  // src/manager.mjs
796
635
  var MANAGEMENT_PATH = "/.well-known/dsh-multi-router";
797
- var revisionOf = (raw) => createHash2("sha256").update(JSON.stringify(raw)).digest("hex");
636
+ var revisionOf = (raw) => createHash("sha256").update(JSON.stringify(raw)).digest("hex");
798
637
  var ManagementError = class extends Error {
799
638
  constructor(status, message) {
800
639
  super(message);
@@ -852,16 +691,16 @@ var Manager = class {
852
691
  router.freeModels = (account) => this.freeModels(account);
853
692
  }
854
693
  async load() {
855
- this.raw = JSON.parse(await readFile3(this.file, "utf8"));
694
+ this.raw = JSON.parse(await readFile2(this.file, "utf8"));
856
695
  try {
857
- this.setup = JSON.parse(await readFile3(this.setupFile, "utf8"));
696
+ this.setup = JSON.parse(await readFile2(this.setupFile, "utf8"));
858
697
  } catch {
859
698
  this.setup = void 0;
860
699
  }
861
700
  this.config = validateConfig(this.raw, this.file);
862
701
  await this.checkins.load();
863
702
  try {
864
- const saved = JSON.parse(await readFile3(this.catalogFile, "utf8"));
703
+ const saved = JSON.parse(await readFile2(this.catalogFile, "utf8"));
865
704
  for (const account of this.config.accounts) {
866
705
  const item = saved[account.id];
867
706
  if (item?.credentialFile === account.credentialFile && Array.isArray(item.models)) {
@@ -901,9 +740,9 @@ var Manager = class {
901
740
  ...discovered.status.map((s) => ({ ...s, checkedAt: Date.now() }))
902
741
  ];
903
742
  if (this.closed || !discovered.accounts.length) return;
904
- await withFileLock3(this.file, async () => {
743
+ await withFileLock2(this.file, async () => {
905
744
  if (this.closed) return;
906
- let raw = JSON.parse(await readFile3(this.file, "utf8"));
745
+ let raw = JSON.parse(await readFile2(this.file, "utf8"));
907
746
  let changed = false;
908
747
  const saved = /* @__PURE__ */ new Map();
909
748
  for (const item of discovered.accounts) {
@@ -922,7 +761,7 @@ var Manager = class {
922
761
  } catch {
923
762
  }
924
763
  }
925
- const id = existing?.id ?? `local_${createHash2("sha256").update(key).digest("hex").slice(0, 20)}`;
764
+ const id = existing?.id ?? `local_${createHash("sha256").update(key).digest("hex").slice(0, 20)}`;
926
765
  const recordSaved = () => {
927
766
  if (!saved.has(item.provider)) saved.set(item.provider, /* @__PURE__ */ new Set());
928
767
  saved.get(item.provider).add(id);
@@ -987,9 +826,9 @@ var Manager = class {
987
826
  }
988
827
  async finishInitialSetup() {
989
828
  if (this.setup?.completedAt) return;
990
- await withFileLock3(this.setupFile, async () => {
829
+ await withFileLock2(this.setupFile, async () => {
991
830
  try {
992
- this.setup = JSON.parse(await readFile3(this.setupFile, "utf8"));
831
+ this.setup = JSON.parse(await readFile2(this.setupFile, "utf8"));
993
832
  } catch {
994
833
  }
995
834
  if (this.setup?.completedAt) return;
@@ -1056,7 +895,7 @@ var Manager = class {
1056
895
  for (const account of this.config.accounts.filter((a) => a.enabled !== false)) {
1057
896
  for (const model of this.freeModels(account)) {
1058
897
  if (!row.targets.some((t) => t.provider === account.provider && (!t.account || t.account === account.id) && (!t.model || t.model === model.id) && (!t.models || t.models.includes(model.id)))) continue;
1059
- const id = `free_${createHash2("sha256").update(JSON.stringify([parentId, account.provider, model.id])).digest("hex").slice(0, 24)}`;
898
+ const id = `free_${createHash("sha256").update(JSON.stringify([parentId, account.provider, model.id])).digest("hex").slice(0, 24)}`;
1060
899
  if (!groups.has(id)) groups.set(id, { id, models: [], targets: [], accountNames: [], modelName: model.name, provider: account.provider, modelId: model.id });
1061
900
  const group = groups.get(id);
1062
901
  group.models.push({ model, provider: account.provider });
@@ -1171,7 +1010,7 @@ var Manager = class {
1171
1010
  if (this.closed || !this.config.accounts.some((a) => a.id === account.id && a.credentialFile === account.credentialFile)) return;
1172
1011
  this.catalogs.set(account.id, { credentialFile: account.credentialFile, fetchedAt: Date.now(), pricingVersion: 1, models });
1173
1012
  this.catalogErrors.delete(account.id);
1174
- await withFileLock3(this.catalogFile, () => writePrivateJson(this.catalogFile, Object.fromEntries(this.catalogs)));
1013
+ await withFileLock2(this.catalogFile, () => writePrivateJson(this.catalogFile, Object.fromEntries(this.catalogs)));
1175
1014
  } catch (error) {
1176
1015
  if (this.closed || !this.config.accounts.some((a) => a.id === account.id)) return;
1177
1016
  this.catalogErrors.set(account.id, { status: Number(error.status ?? error.failure?.status) || 502, code: "catalog_fetch_failed", at: Date.now() });
@@ -1249,14 +1088,14 @@ var Manager = class {
1249
1088
  return this.state();
1250
1089
  }
1251
1090
  if (input.action === "setup.dismiss") {
1252
- await withFileLock3(this.setupFile, async () => {
1091
+ await withFileLock2(this.setupFile, async () => {
1253
1092
  this.setup = { ...this.setup, completedAt: this.setup?.completedAt ?? Date.now(), dismissed: true };
1254
1093
  await writePrivateJson(this.setupFile, this.setup);
1255
1094
  });
1256
1095
  return this.state();
1257
1096
  }
1258
1097
  if (input.action === "account.export") {
1259
- if (input.revision !== revisionOf(JSON.parse(await readFile3(this.file, "utf8")))) throw new ManagementError(409, "\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u63D0\u53D6\u51ED\u8BC1");
1098
+ if (input.revision !== revisionOf(JSON.parse(await readFile2(this.file, "utf8")))) throw new ManagementError(409, "\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u63D0\u53D6\u51ED\u8BC1");
1260
1099
  const account = this.config.accounts.find((a) => a.id === input.id);
1261
1100
  if (!account) bad("\u8D26\u53F7\u4E0D\u5B58\u5728");
1262
1101
  let credential;
@@ -1278,7 +1117,7 @@ var Manager = class {
1278
1117
  } };
1279
1118
  }
1280
1119
  if (input.action === "config.export") {
1281
- if (input.revision !== revisionOf(JSON.parse(await readFile3(this.file, "utf8")))) throw new ManagementError(409, "\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u5BFC\u51FA");
1120
+ if (input.revision !== revisionOf(JSON.parse(await readFile2(this.file, "utf8")))) throw new ManagementError(409, "\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u5BFC\u51FA");
1282
1121
  try {
1283
1122
  return { ...this.state(), exported: { filename: `dsh-multi-router-${input.includeCredentials ? "encrypted" : "settings"}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`, document: await exportConfiguration(this, input) } };
1284
1123
  } catch (e) {
@@ -1325,8 +1164,8 @@ var Manager = class {
1325
1164
  await this.checkFreeModels(true);
1326
1165
  return this.state();
1327
1166
  }
1328
- return withFileLock3(this.file, async () => {
1329
- let raw = JSON.parse(await readFile3(this.file, "utf8"));
1167
+ return withFileLock2(this.file, async () => {
1168
+ let raw = JSON.parse(await readFile2(this.file, "utf8"));
1330
1169
  if (input.revision !== revisionOf(raw)) throw new ManagementError(409, "\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u518D\u4FDD\u5B58");
1331
1170
  raw.routes ??= structuredClone(this.config.routes);
1332
1171
  let staging;
@@ -1530,6 +1369,7 @@ var Manager = class {
1530
1369
  }
1531
1370
  if (input.action === "account.add" || input.action === "account.credentials") {
1532
1371
  const account = this.config.accounts.find((a) => a.id === input.id);
1372
+ if (input.action === "account.credentials" && !this.checkins.failed) await this.checkins.credentialsUpdated(input.id);
1533
1373
  if (account) {
1534
1374
  await Promise.all([this.refreshAccount(account, true), this.monitorAccount(account)]);
1535
1375
  return this.state();
@@ -1544,8 +1384,8 @@ var Manager = class {
1544
1384
  if (filename && String(filename) !== this.file.split(/[\\/]/).pop()) return;
1545
1385
  clearTimeout(timer);
1546
1386
  timer = setTimeout(() => {
1547
- void withFileLock3(this.file, async () => {
1548
- const raw = JSON.parse(await readFile3(this.file, "utf8"));
1387
+ void withFileLock2(this.file, async () => {
1388
+ const raw = JSON.parse(await readFile2(this.file, "utf8"));
1549
1389
  if (this.closed || revisionOf(raw) === this.revision) return;
1550
1390
  const config = validateConfig(raw, this.file);
1551
1391
  this.raw = raw;
@@ -1612,4 +1452,4 @@ export {
1612
1452
  Manager,
1613
1453
  managementHandler
1614
1454
  };
1615
- //# sourceMappingURL=chunk-C6JBDATB.js.map
1455
+ //# sourceMappingURL=chunk-EJWYFWIT.js.map