dsh-multi-router 0.5.5 → 0.5.6

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.
@@ -2,8 +2,11 @@ import {
2
2
  Checkins,
3
3
  jsonCredential,
4
4
  qoderPluginDataDir,
5
- supportsCheckin
6
- } from "./chunk-EGLF4CWD.js";
5
+ readLimitedText,
6
+ refreshWorkBuddyCheckinCredential,
7
+ supportsCheckin,
8
+ workbuddyToken
9
+ } from "./chunk-U2MU2M5C.js";
7
10
  import {
8
11
  discoverLocalAccounts,
9
12
  importAccount,
@@ -33,16 +36,16 @@ import {
33
36
  } from "./chunk-TEZ2FMEO.js";
34
37
 
35
38
  // src/manager.mjs
36
- import { createHash, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
39
+ import { createHash, randomBytes as randomBytes3, timingSafeEqual } from "node:crypto";
37
40
 
38
41
  // package.json
39
- var version = "0.5.5";
42
+ var version = "0.5.6";
40
43
 
41
44
  // src/manager.mjs
42
- import { readFile as readFile2, mkdir as mkdir2, mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
45
+ import { readFile as readFile3, mkdir as mkdir2, mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
43
46
  import { watch } from "node:fs";
44
47
  import { dirname as dirname3, join as join4, relative as relative2, resolve } from "node:path";
45
- import { withFileLock as withFileLock2 } from "@deepseek-ai/dsh-atomic-write";
48
+ import { withFileLock as withFileLock3 } from "@deepseek-ai/dsh-atomic-write";
46
49
 
47
50
  // upstream/qoder/src/status-paths.ts
48
51
  var QODER_STATUS_PATH = "/plugins/dsh-qoder-connect/status";
@@ -680,6 +683,141 @@ var PluginUpdates = class {
680
683
  }
681
684
  };
682
685
 
686
+ // src/workbuddy-login.mjs
687
+ import { randomBytes as randomBytes2 } from "node:crypto";
688
+ import { readFile as readFile2 } from "node:fs/promises";
689
+ import { withFileLock as withFileLock2 } from "@deepseek-ai/dsh-atomic-write";
690
+ var WorkBuddyLogin = class {
691
+ constructor(file, { fetchImpl = (...args) => fetch(...args), now = Date.now } = {}) {
692
+ this.file = file;
693
+ this.fetchImpl = fetchImpl;
694
+ this.now = now;
695
+ this.abort = new AbortController();
696
+ this.abort.signal.addEventListener("abort", () => this.finish(), { once: true });
697
+ }
698
+ async reserve(field, ms) {
699
+ await withFileLock2(this.file, async () => {
700
+ let state = {};
701
+ try {
702
+ state = JSON.parse(await readFile2(this.file, "utf8"));
703
+ } catch (e) {
704
+ if (e.code !== "ENOENT") throw Error("\u767B\u5F55\u51B7\u5374\u8BB0\u5F55\u4E0D\u53EF\u8BFB\uFF0C\u8BF7\u68C0\u67E5\u672C\u673A\u6587\u4EF6");
705
+ }
706
+ if (state.pausedUntil > this.now() || state[field] > this.now()) throw Error("\u8BF7\u6C42\u51B7\u5374\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\uFF1B\u5E73\u53F0\u9650\u5236\u8BF7\u5728\u5B98\u65B9\u5BA2\u6237\u7AEF\u5904\u7406");
707
+ state[field] = this.now() + ms;
708
+ await writePrivateJson(this.file, state);
709
+ });
710
+ }
711
+ async pause() {
712
+ this.pending = void 0;
713
+ await withFileLock2(this.file, async () => {
714
+ const state = JSON.parse(await readFile2(this.file, "utf8"));
715
+ state.pausedUntil = this.now() + 15 * 6e4;
716
+ await writePrivateJson(this.file, state);
717
+ });
718
+ }
719
+ async post(path, body) {
720
+ let response;
721
+ try {
722
+ response = await this.fetchImpl(`https://www.workbuddy.cn/v2/plugin/login/${path}`, {
723
+ method: "POST",
724
+ headers: { "Content-Type": "application/json", Accept: "application/json", Origin: "https://www.workbuddy.cn", Referer: "https://www.workbuddy.cn/" },
725
+ body: JSON.stringify(body),
726
+ signal: AbortSignal.any([this.abort.signal, AbortSignal.timeout(3e4)]),
727
+ redirect: "error"
728
+ });
729
+ } catch {
730
+ throw Error("\u767B\u5F55\u8BF7\u6C42\u672A\u5B8C\u6210\uFF0C\u8BF7\u7A0D\u540E\u624B\u52A8\u91CD\u8BD5\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u91CD\u53D1\u77ED\u4FE1");
731
+ }
732
+ if ([403, 429].includes(response.status)) {
733
+ await this.pause();
734
+ throw Error("\u5E73\u53F0\u9650\u5236\u6216\u9700\u8981\u9A8C\u8BC1\uFF0C\u5DF2\u6682\u505C\u767B\u5F55\u8BF7\u6C42\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF");
735
+ }
736
+ if (!response.ok) throw Error("\u5B98\u65B9\u767B\u5F55\u670D\u52A1\u6682\u4E0D\u53EF\u7528\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
737
+ let result;
738
+ try {
739
+ result = JSON.parse(await readLimitedText(response, 256 * 1024, "Login"));
740
+ } catch {
741
+ throw Error("\u767B\u5F55\u54CD\u5E94\u65E0\u6CD5\u8BC6\u522B\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF");
742
+ }
743
+ if (result?.code !== 0) {
744
+ if ([403, 429].includes(result?.code) || /频繁|图形验证码|滑块|安全验证|captcha|risk|too many|frequent|验证失败次数/i.test(result?.msg || "")) {
745
+ await this.pause();
746
+ throw Error("\u5E73\u53F0\u9650\u5236\u6216\u9700\u8981\u9A8C\u8BC1\uFF0C\u5DF2\u6682\u505C\u767B\u5F55\u8BF7\u6C42\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF");
747
+ }
748
+ throw Error(path === "token" ? "\u767B\u5F55\u672A\u6210\u529F\uFF0C\u8BF7\u68C0\u67E5\u9A8C\u8BC1\u7801\u662F\u5426\u6B63\u786E\u3001\u8FC7\u671F\uFF1B\u4EC5\u652F\u6301\u5DF2\u6709\u8D26\u53F7" : "\u77ED\u4FE1\u672A\u53D1\u9001\u6210\u529F\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u6709\u8D26\u53F7\u53CA\u624B\u673A\u53F7\uFF0C\u6216\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF");
749
+ }
750
+ return result.data ?? {};
751
+ }
752
+ async send(phone) {
753
+ if (typeof phone !== "string" || !/^1[3-9]\d{9}$/.test(phone)) throw Error("\u8BF7\u8F93\u5165 11 \u4F4D\u4E2D\u56FD\u5927\u9646\u624B\u673A\u53F7");
754
+ if (this.flight) throw Error("\u767B\u5F55\u8BF7\u6C42\u6B63\u5728\u5904\u7406\u4E2D");
755
+ this.flight = (async () => {
756
+ await this.reserve("smsAt", 6e4);
757
+ this.pending = void 0;
758
+ const data = await this.post("send-sms", { phone });
759
+ const expires = Math.min(300, Math.max(1, Number(data.expires_in) || 300)) * 1e3;
760
+ this.pending = { phone, challenge: randomBytes2(24).toString("hex"), expiresAt: this.now() + expires, attempts: 0 };
761
+ clearTimeout(this.expiryTimer);
762
+ this.expiryTimer = setTimeout(() => this.finish(), expires);
763
+ this.expiryTimer.unref();
764
+ return { challenge: this.pending.challenge, expiresAt: this.pending.expiresAt, resendAt: this.now() + 6e4 };
765
+ })();
766
+ try {
767
+ return await this.flight;
768
+ } finally {
769
+ this.flight = void 0;
770
+ }
771
+ }
772
+ async complete(challenge, code, verify = true) {
773
+ if (typeof challenge !== "string" || !this.pending || challenge !== this.pending.challenge || this.pending.expiresAt <= this.now()) throw Error("\u672C\u6B21\u767B\u5F55\u5DF2\u8FC7\u671F\u6216\u63D2\u4EF6\u5DF2\u91CD\u542F\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u9A8C\u8BC1\u7801");
774
+ if (this.flight) throw Error("\u767B\u5F55\u8BF7\u6C42\u6B63\u5728\u5904\u7406\u4E2D");
775
+ if (this.pending.document) return this.pending;
776
+ if (typeof code !== "string" || !/^\d{4,8}$/.test(code) || typeof verify !== "boolean") throw Error("\u8BF7\u8F93\u5165\u6536\u5230\u7684\u77ED\u4FE1\u9A8C\u8BC1\u7801");
777
+ if (this.pending.attempts >= 5) throw Error("\u672C\u6B21\u9A8C\u8BC1\u7801\u5C1D\u8BD5\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650\uFF0C\u8BF7\u7A0D\u540E\u91CD\u65B0\u83B7\u53D6");
778
+ this.flight = (async () => {
779
+ await this.reserve("loginAt", 5e3);
780
+ const pending = this.pending;
781
+ pending.attempts++;
782
+ const data = await this.post("token", { login_method: "phone", phone: pending.phone, sms_code: code });
783
+ const accessToken = data.accessToken || data.access_token, refreshToken = data.refreshToken || data.refresh_token;
784
+ let token;
785
+ try {
786
+ token = workbuddyToken(accessToken);
787
+ } catch {
788
+ throw Error("\u767B\u5F55\u8FD4\u56DE\u7684\u4EE4\u724C\u4E0D\u5C5E\u4E8E WorkBuddy \u4E2D\u56FD\u7248\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF");
789
+ }
790
+ if (typeof refreshToken !== "string" || !refreshToken || !Number.isFinite(token.exp) || token.exp * 1e3 <= this.now()) throw Error("\u767B\u5F55\u54CD\u5E94\u7F3A\u5C11\u6709\u6548\u51ED\u8BC1\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55");
791
+ let credential = { accessToken, refreshToken, uid: token.sub, expiresAtMs: token.exp * 1e3, domain: "www.workbuddy.cn", source: "dsh" };
792
+ if (verify) {
793
+ try {
794
+ const rotated = await refreshWorkBuddyCheckinCredential(credential, { fetchImpl: this.fetchImpl, signal: AbortSignal.any([this.abort.signal, AbortSignal.timeout(3e4)]) });
795
+ credential = {
796
+ ...credential,
797
+ accessToken: rotated.accessToken,
798
+ refreshToken: rotated.refreshToken || credential.refreshToken,
799
+ expiresAtMs: Date.now() + rotated.expiresInSec * 1e3
800
+ };
801
+ } catch {
802
+ pending.warning = "\u767B\u5F55\u51ED\u8BC1\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u5237\u65B0\u4EE4\u724C\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF1B\u8BF7\u7A0D\u540E\u5728\u8D26\u53F7\u8BE6\u60C5\u68C0\u67E5\u767B\u5F55\u6709\u6548\u671F\u3002";
803
+ }
804
+ }
805
+ delete pending.phone;
806
+ pending.document = { version: 1, credential };
807
+ return pending;
808
+ })();
809
+ try {
810
+ return await this.flight;
811
+ } finally {
812
+ this.flight = void 0;
813
+ }
814
+ }
815
+ finish() {
816
+ clearTimeout(this.expiryTimer);
817
+ this.pending = void 0;
818
+ }
819
+ };
820
+
683
821
  // src/manager.mjs
684
822
  var MANAGEMENT_PATH = "/.well-known/dsh-multi-router";
685
823
  var revisionOf = (raw) => createHash("sha256").update(JSON.stringify(raw)).digest("hex");
@@ -733,6 +871,7 @@ var Manager = class {
733
871
  this.telemetry = new Telemetry(join4(dirname3(file), "usage.json"));
734
872
  this.plugins = new PluginUpdates({ ...pluginAccess, stateFile: join4(dirname3(file), "plugin-updates.json") });
735
873
  this.checkins = new Checkins(join4(dirname3(file), "checkins.json"), this);
874
+ this.workbuddyLogin = new WorkBuddyLogin(join4(dirname3(file), "workbuddy-login.json"), { fetchImpl: pluginAccess.fetchImpl });
736
875
  this.setupFile = join4(dirname3(file), "initial-setup.json");
737
876
  router.telemetry = this.telemetry;
738
877
  router.monitor = (a) => this.monitorAccount(a);
@@ -740,9 +879,9 @@ var Manager = class {
740
879
  router.freeModels = (account) => this.freeModels(account);
741
880
  }
742
881
  async load() {
743
- this.raw = JSON.parse(await readFile2(this.file, "utf8"));
882
+ this.raw = JSON.parse(await readFile3(this.file, "utf8"));
744
883
  try {
745
- this.setup = JSON.parse(await readFile2(this.setupFile, "utf8"));
884
+ this.setup = JSON.parse(await readFile3(this.setupFile, "utf8"));
746
885
  } catch {
747
886
  this.setup = void 0;
748
887
  }
@@ -753,7 +892,7 @@ var Manager = class {
753
892
  this.plugins.rows = [];
754
893
  });
755
894
  try {
756
- const saved = JSON.parse(await readFile2(this.catalogFile, "utf8"));
895
+ const saved = JSON.parse(await readFile3(this.catalogFile, "utf8"));
757
896
  for (const account of this.config.accounts) {
758
897
  const item = saved[account.id];
759
898
  if (item?.credentialFile === account.credentialFile && Array.isArray(item.models)) {
@@ -793,9 +932,9 @@ var Manager = class {
793
932
  ...discovered.status.map((s) => ({ ...s, checkedAt: Date.now() }))
794
933
  ];
795
934
  if (this.closed || !discovered.accounts.length) return;
796
- await withFileLock2(this.file, async () => {
935
+ await withFileLock3(this.file, async () => {
797
936
  if (this.closed) return;
798
- let raw = JSON.parse(await readFile2(this.file, "utf8"));
937
+ let raw = JSON.parse(await readFile3(this.file, "utf8"));
799
938
  let changed = false;
800
939
  const saved = /* @__PURE__ */ new Map();
801
940
  for (const item of discovered.accounts) {
@@ -879,9 +1018,9 @@ var Manager = class {
879
1018
  }
880
1019
  async finishInitialSetup() {
881
1020
  if (this.setup?.completedAt) return;
882
- await withFileLock2(this.setupFile, async () => {
1021
+ await withFileLock3(this.setupFile, async () => {
883
1022
  try {
884
- this.setup = JSON.parse(await readFile2(this.setupFile, "utf8"));
1023
+ this.setup = JSON.parse(await readFile3(this.setupFile, "utf8"));
885
1024
  } catch {
886
1025
  }
887
1026
  if (this.setup?.completedAt) return;
@@ -1063,7 +1202,7 @@ var Manager = class {
1063
1202
  if (this.closed || !this.config.accounts.some((a) => a.id === account.id && a.credentialFile === account.credentialFile)) return;
1064
1203
  this.catalogs.set(account.id, { credentialFile: account.credentialFile, fetchedAt: Date.now(), pricingVersion: 1, models });
1065
1204
  this.catalogErrors.delete(account.id);
1066
- await withFileLock2(this.catalogFile, () => writePrivateJson(this.catalogFile, Object.fromEntries(this.catalogs)));
1205
+ await withFileLock3(this.catalogFile, () => writePrivateJson(this.catalogFile, Object.fromEntries(this.catalogs)));
1067
1206
  } catch (error) {
1068
1207
  if (this.closed || !this.config.accounts.some((a) => a.id === account.id)) return;
1069
1208
  this.catalogErrors.set(account.id, { status: Number(error.status ?? error.failure?.status) || 502, code: "catalog_fetch_failed", at: Date.now() });
@@ -1116,6 +1255,63 @@ var Manager = class {
1116
1255
  }
1117
1256
  async action(input) {
1118
1257
  if (!input || typeof input !== "object" || Array.isArray(input)) bad("\u8BF7\u6C42\u683C\u5F0F\u65E0\u6548");
1258
+ if (input.action === "workbuddy.sms") {
1259
+ try {
1260
+ const workbuddyLogin = await this.workbuddyLogin.send(input.phone);
1261
+ return { ...this.state(), workbuddyLogin };
1262
+ } catch (e) {
1263
+ bad(e.message);
1264
+ }
1265
+ }
1266
+ if (input.action === "workbuddy.login") {
1267
+ 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\u91CD\u65B0\u63D0\u4EA4\u767B\u5F55");
1268
+ let login;
1269
+ try {
1270
+ login = await this.workbuddyLogin.complete(input.challenge, input.code, input.verify ?? true);
1271
+ } catch (e) {
1272
+ bad(e.message);
1273
+ }
1274
+ let existing;
1275
+ for (const a of this.config.accounts.filter((a2) => a2.provider === "workbuddy")) {
1276
+ try {
1277
+ if ((await jsonCredential(a.credentialFile)).credential.uid === login.document.credential.uid) {
1278
+ existing = a;
1279
+ break;
1280
+ }
1281
+ } catch {
1282
+ }
1283
+ }
1284
+ if (input.id && input.id !== existing?.id) bad("\u767B\u5F55\u8EAB\u4EFD\u4E0E\u6B63\u5728\u7F16\u8F91\u7684\u8D26\u53F7\u4E0D\u540C\uFF0C\u8BF7\u4ECE\u6DFB\u52A0\u8D26\u53F7\u5165\u53E3\u4FDD\u5B58");
1285
+ const state = await this.action({
1286
+ action: existing ? "account.credentials" : "account.add",
1287
+ revision: input.revision,
1288
+ id: existing?.id ?? `workbuddy_${randomBytes3(8).toString("hex")}`,
1289
+ provider: "workbuddy",
1290
+ name: input.name,
1291
+ document: login.document
1292
+ });
1293
+ this.workbuddyLogin.finish();
1294
+ return { ...state, loginResult: { warning: login.warning, saved: true } };
1295
+ }
1296
+ if (input.action === "checkins.verify") {
1297
+ const account = this.config.accounts.find((a) => a.id === input.id && a.provider === "workbuddy");
1298
+ if (!account) bad("\u8BF7\u9009\u62E9 WorkBuddy \u4E2D\u56FD\u7248\u8D26\u53F7");
1299
+ if (this.checkins.flight || this.checkins.failed) bad("\u8BF7\u7B49\u5F85\u7B7E\u5230\u5B8C\u6210\uFF0C\u6216\u5148\u4FEE\u590D\u7B7E\u5230\u8BB0\u5F55");
1300
+ try {
1301
+ await this.workbuddyLogin.reserve("verifyAt", 3e4);
1302
+ } catch (e) {
1303
+ bad(e.message);
1304
+ }
1305
+ try {
1306
+ const client = await this.router.client(account);
1307
+ await client.checkin.validate(AbortSignal.timeout(3e4));
1308
+ await this.checkins.credentialsUpdated(account.id);
1309
+ await this.readLogin(account);
1310
+ } catch {
1311
+ bad("\u767B\u5F55\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF1A\u8BF7\u5728\u8D26\u53F7\u4E0E\u767B\u5F55\u4E2D\u66F4\u65B0\u51ED\u8BC1\uFF1B\u4E0D\u4F1A\u81EA\u52A8\u91CD\u8BD5\u6216\u9886\u53D6");
1312
+ }
1313
+ return this.state();
1314
+ }
1119
1315
  if (input.action === "checkins.run") {
1120
1316
  try {
1121
1317
  this.checkins.start(input.ids);
@@ -1141,14 +1337,14 @@ var Manager = class {
1141
1337
  return this.state();
1142
1338
  }
1143
1339
  if (input.action === "setup.dismiss") {
1144
- await withFileLock2(this.setupFile, async () => {
1340
+ await withFileLock3(this.setupFile, async () => {
1145
1341
  this.setup = { ...this.setup, completedAt: this.setup?.completedAt ?? Date.now(), dismissed: true };
1146
1342
  await writePrivateJson(this.setupFile, this.setup);
1147
1343
  });
1148
1344
  return this.state();
1149
1345
  }
1150
1346
  if (input.action === "account.export") {
1151
- 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");
1347
+ 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");
1152
1348
  const account = this.config.accounts.find((a) => a.id === input.id);
1153
1349
  if (!account) bad("\u8D26\u53F7\u4E0D\u5B58\u5728");
1154
1350
  let credential;
@@ -1170,7 +1366,7 @@ var Manager = class {
1170
1366
  } };
1171
1367
  }
1172
1368
  if (input.action === "config.export") {
1173
- 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");
1369
+ 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");
1174
1370
  try {
1175
1371
  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) } };
1176
1372
  } catch (e) {
@@ -1206,7 +1402,7 @@ var Manager = class {
1206
1402
  }
1207
1403
  if (input.action === "account.capture") {
1208
1404
  if (!PROVIDERS.includes(input.provider)) bad("\u672A\u77E5\u4F9B\u5E94\u5546");
1209
- input = { ...input, action: "account.add", id: `${input.provider.replace("-", "_")}_${randomBytes2(4).toString("hex")}`, capture: true };
1405
+ input = { ...input, action: "account.add", id: `${input.provider.replace("-", "_")}_${randomBytes3(4).toString("hex")}`, capture: true };
1210
1406
  }
1211
1407
  if (input.action === "refresh") {
1212
1408
  if (input.provider && !PROVIDERS.includes(input.provider)) bad("\u672A\u77E5\u4F9B\u5E94\u5546");
@@ -1217,8 +1413,8 @@ var Manager = class {
1217
1413
  await this.checkFreeModels(true);
1218
1414
  return this.state();
1219
1415
  }
1220
- return withFileLock2(this.file, async () => {
1221
- let raw = JSON.parse(await readFile2(this.file, "utf8"));
1416
+ return withFileLock3(this.file, async () => {
1417
+ let raw = JSON.parse(await readFile3(this.file, "utf8"));
1222
1418
  if (input.revision !== revisionOf(raw)) throw new ManagementError(409, "\u914D\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u5237\u65B0\u540E\u518D\u4FDD\u5B58");
1223
1419
  raw.routes ??= structuredClone(this.config.routes);
1224
1420
  let staging;
@@ -1228,7 +1424,7 @@ var Manager = class {
1228
1424
  try {
1229
1425
  const prepared = await prepareMigration(this, raw, await decodeConfiguration(input), input.mode);
1230
1426
  staging = prepared.staging;
1231
- await writePrivateJson(`${this.file}.before-import-${Date.now()}-${randomBytes2(3).toString("hex")}.bak`, raw);
1427
+ await writePrivateJson(`${this.file}.before-import-${Date.now()}-${randomBytes3(3).toString("hex")}.bak`, raw);
1232
1428
  raw = prepared.raw;
1233
1429
  } catch (e) {
1234
1430
  bad(e.message);
@@ -1367,7 +1563,7 @@ var Manager = class {
1367
1563
  } };
1368
1564
  } else if (input.action === "route.save") {
1369
1565
  if (input.id === void 0 || input.id === "") {
1370
- input.id = input.previousId || `route_${randomBytes2(8).toString("hex")}`;
1566
+ input.id = input.previousId || `route_${randomBytes3(8).toString("hex")}`;
1371
1567
  }
1372
1568
  if (!/^[a-zA-Z0-9_.-]{1,128}$/.test(input.id ?? "")) bad("\u8DEF\u7531 ID \u4EC5\u652F\u6301\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u548C\u77ED\u6A2A\u7EBF");
1373
1569
  if (input.previousId && !Object.hasOwn(raw.routes, input.previousId)) bad("\u539F\u8DEF\u7531\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5237\u65B0\u9875\u9762");
@@ -1444,8 +1640,8 @@ var Manager = class {
1444
1640
  if (filename && String(filename) !== this.file.split(/[\\/]/).pop()) return;
1445
1641
  clearTimeout(timer);
1446
1642
  timer = setTimeout(() => {
1447
- void withFileLock2(this.file, async () => {
1448
- const raw = JSON.parse(await readFile2(this.file, "utf8"));
1643
+ void withFileLock3(this.file, async () => {
1644
+ const raw = JSON.parse(await readFile3(this.file, "utf8"));
1449
1645
  if (this.closed || revisionOf(raw) === this.revision) return;
1450
1646
  const config = validateConfig(raw, this.file);
1451
1647
  this.raw = raw;
@@ -1463,7 +1659,7 @@ var Manager = class {
1463
1659
  }
1464
1660
  };
1465
1661
  function managementHandler(manager) {
1466
- const key = randomBytes2(32).toString("base64url");
1662
+ const key = randomBytes3(32).toString("base64url");
1467
1663
  const json = (res, status, value) => {
1468
1664
  res.writeHead(status, { "Content-Type": "application/json", "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff" });
1469
1665
  res.end(JSON.stringify(value));
@@ -1512,4 +1708,4 @@ export {
1512
1708
  Manager,
1513
1709
  managementHandler
1514
1710
  };
1515
- //# sourceMappingURL=chunk-PQETKUGT.js.map
1711
+ //# sourceMappingURL=chunk-XKDXPB5T.js.map