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 +11 -0
- package/README.md +10 -8
- package/lib/accounts.js +2 -2
- package/lib/{chunk-OMG4FZWV.js → chunk-4H6ZXK75.js} +2 -2
- package/lib/{chunk-C6JBDATB.js → chunk-EJWYFWIT.js} +31 -191
- package/lib/{chunk-C6JBDATB.js.map → chunk-EJWYFWIT.js.map} +4 -4
- package/lib/{chunk-U2YTBWLW.js → chunk-JYVJJ7OX.js} +3 -3
- package/lib/{chunk-YUP77Q3A.js → chunk-RPW6DI6O.js} +410 -56
- package/lib/chunk-RPW6DI6O.js.map +7 -0
- package/lib/{chunk-GAQ77CH4.js → chunk-U7J4ABAM.js} +2 -2
- package/lib/chunk-U7J4ABAM.js.map +7 -0
- package/lib/{chunk-XV7O2LRF.js → chunk-XA3V2DGT.js} +2 -2
- package/lib/cli.js +4 -4
- package/lib/client.js +23 -10
- package/lib/client.js.map +2 -2
- package/lib/clients.js +11 -5
- package/lib/host.js +6 -6
- package/lib/index.js +6 -6
- package/lib/manager.js +5 -5
- package/lib/router.js +2 -2
- package/lib/shim.js +3 -3
- package/package.json +1 -1
- package/lib/chunk-GAQ77CH4.js.map +0 -7
- package/lib/chunk-YUP77Q3A.js.map +0 -7
- /package/lib/{chunk-OMG4FZWV.js.map → chunk-4H6ZXK75.js.map} +0 -0
- /package/lib/{chunk-U2YTBWLW.js.map → chunk-JYVJJ7OX.js.map} +0 -0
- /package/lib/{chunk-XV7O2LRF.js.map → chunk-XA3V2DGT.js.map} +0 -0
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-DNQPZMPF.js";
|
|
5
5
|
import {
|
|
6
6
|
RouteError
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XA3V2DGT.js";
|
|
8
8
|
import {
|
|
9
9
|
REASONING_EFFORTS
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-U7J4ABAM.js";
|
|
11
11
|
|
|
12
12
|
// src/shim.mjs
|
|
13
13
|
import { createServer } from "node:http";
|
|
@@ -113,4 +113,4 @@ function createShim(router, { modelPrefix = "" } = {}) {
|
|
|
113
113
|
export {
|
|
114
114
|
createShim
|
|
115
115
|
};
|
|
116
|
-
//# sourceMappingURL=chunk-
|
|
116
|
+
//# sourceMappingURL=chunk-JYVJJ7OX.js.map
|
|
@@ -12,7 +12,11 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
RouteError,
|
|
14
14
|
abortable
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-XA3V2DGT.js";
|
|
16
|
+
import {
|
|
17
|
+
beijingDay,
|
|
18
|
+
writePrivateJson
|
|
19
|
+
} from "./chunk-U7J4ABAM.js";
|
|
16
20
|
import {
|
|
17
21
|
WorkBuddyUpstreamClient,
|
|
18
22
|
modelWithCurrentPromotion,
|
|
@@ -20,7 +24,8 @@ import {
|
|
|
20
24
|
} from "./chunk-TEZ2FMEO.js";
|
|
21
25
|
|
|
22
26
|
// src/clients.mjs
|
|
23
|
-
import { readFile } from "node:fs/promises";
|
|
27
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
28
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
24
29
|
|
|
25
30
|
// upstream/trae/src/usage.ts
|
|
26
31
|
function asNumber(value) {
|
|
@@ -2425,26 +2430,26 @@ async function validateAndTranslateMessages(messages, systemPrompt, attachments,
|
|
|
2425
2430
|
|
|
2426
2431
|
// upstream/qoder/src/qoder/transport/wire/serialize.ts
|
|
2427
2432
|
function stableHash(prefix, ...inputs) {
|
|
2428
|
-
const
|
|
2429
|
-
|
|
2433
|
+
const hash2 = crypto3.createHash("sha256");
|
|
2434
|
+
hash2.update(prefix);
|
|
2430
2435
|
for (const input of inputs) {
|
|
2431
|
-
|
|
2432
|
-
|
|
2436
|
+
hash2.update("\0");
|
|
2437
|
+
hash2.update(input);
|
|
2433
2438
|
}
|
|
2434
|
-
return
|
|
2439
|
+
return hash2.digest("hex").slice(0, 16);
|
|
2435
2440
|
}
|
|
2436
2441
|
function stableChatRecordId(model, messages, tools, maxTokens) {
|
|
2437
|
-
const
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
return
|
|
2442
|
+
const hash2 = crypto3.createHash("sha256");
|
|
2443
|
+
hash2.update("qoder-record");
|
|
2444
|
+
hash2.update("\0");
|
|
2445
|
+
hash2.update(model);
|
|
2446
|
+
hash2.update("\0");
|
|
2447
|
+
hash2.update(JSON.stringify(messages));
|
|
2448
|
+
hash2.update("\0");
|
|
2449
|
+
hash2.update(JSON.stringify(tools));
|
|
2450
|
+
hash2.update("\0");
|
|
2451
|
+
hash2.update(`mt=${maxTokens}`);
|
|
2452
|
+
return hash2.digest("hex").slice(0, 16);
|
|
2448
2453
|
}
|
|
2449
2454
|
function validateQoderRequestShape(options, model) {
|
|
2450
2455
|
if (options.reasoningEffort !== void 0) {
|
|
@@ -2691,20 +2696,20 @@ var QoderImageUploader = class {
|
|
|
2691
2696
|
* are included because a center object is never shared across either.
|
|
2692
2697
|
*/
|
|
2693
2698
|
cacheKey(image, credentials) {
|
|
2694
|
-
const
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2699
|
+
const hash2 = crypto4.createHash("sha256");
|
|
2700
|
+
hash2.update(getQoderImageUploadUrl(this.region));
|
|
2701
|
+
hash2.update("\0");
|
|
2702
|
+
hash2.update(credentials.userID);
|
|
2703
|
+
hash2.update("\0");
|
|
2704
|
+
hash2.update(image.mediaType);
|
|
2705
|
+
hash2.update("\0");
|
|
2701
2706
|
const variantId = typeof image.variantId === "string" ? image.variantId : "";
|
|
2702
2707
|
if (variantId.length > 0) {
|
|
2703
|
-
|
|
2708
|
+
hash2.update(variantId);
|
|
2704
2709
|
} else {
|
|
2705
|
-
|
|
2710
|
+
hash2.update(crypto4.createHash("sha256").update(Buffer.from(image.data)).digest("hex"));
|
|
2706
2711
|
}
|
|
2707
|
-
return
|
|
2712
|
+
return hash2.digest("hex");
|
|
2708
2713
|
}
|
|
2709
2714
|
remember(key, url) {
|
|
2710
2715
|
this.cache.delete(key);
|
|
@@ -4787,6 +4792,224 @@ function modelInfoOf(model) {
|
|
|
4787
4792
|
var DEFAULT_MAX_TOKENS = 32768;
|
|
4788
4793
|
var DEFAULT_CONTEXT_WINDOW = 18e4;
|
|
4789
4794
|
|
|
4795
|
+
// src/checkins.mjs
|
|
4796
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
4797
|
+
import { readFile } from "node:fs/promises";
|
|
4798
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
4799
|
+
import { withFileLock } from "@deepseek-ai/dsh-atomic-write";
|
|
4800
|
+
var supportsCheckin = (provider) => ["workbuddy", "trae", "qoder", "qoder-global"].includes(provider);
|
|
4801
|
+
var hash = (value) => createHash2("sha256").update(value).digest("hex");
|
|
4802
|
+
var nextDay = (now) => Date.parse(`${beijingDay(now)}T00:00:00+08:00`) + 864e5;
|
|
4803
|
+
var evening = (now) => Date.parse(`${beijingDay(now)}T20:05:00+08:00`);
|
|
4804
|
+
function checkinFailure(error, submitted = false) {
|
|
4805
|
+
const status = error?.status ?? error?.failure?.status ?? Number(/\bhttp\s+(401|403|429)\b/i.exec(error?.message || "")?.[1]);
|
|
4806
|
+
if (status === 401) return { status: "auth-invalid" };
|
|
4807
|
+
if ([403, 429].includes(status)) return { status: "paused" };
|
|
4808
|
+
if (/no valid refresh token is available|no refresh token is stored/.test(error?.message || "")) return { status: "auth-invalid" };
|
|
4809
|
+
return { status: submitted ? "uncertain" : "retryable" };
|
|
4810
|
+
}
|
|
4811
|
+
var canRetry = (record2, now) => ["retryable", "before-window"].includes(record2.status) && record2.retryAt <= now && (record2.attempts || 1) < 2;
|
|
4812
|
+
var checkinMessages = {
|
|
4813
|
+
claimed: "\u7B7E\u5230\u6210\u529F",
|
|
4814
|
+
"already-claimed": "\u4ECA\u65E5\u5DF2\u9886\u53D6",
|
|
4815
|
+
"device-used": "\u6B64\u8BBE\u5907\u4ECA\u65E5\u5DF2\u53C2\u4E0E\u7B7E\u5230\uFF0C\u4E0D\u518D\u5207\u6362\u5176\u4ED6\u8D26\u53F7\u9886\u53D6",
|
|
4816
|
+
"no-campaign": "\u5E73\u53F0\u672A\u5F00\u653E\u53EF\u9886\u53D6\u6D3B\u52A8",
|
|
4817
|
+
"before-window": "\u7B7E\u5230\u7A97\u53E3\u5C1A\u672A\u5F00\u542F",
|
|
4818
|
+
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",
|
|
4819
|
+
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",
|
|
4820
|
+
"auth-invalid": "\u4EE4\u724C\u5931\u6548\uFF0C\u8BF7\u5230\u8D26\u53F7\u4E0E\u767B\u5F55\u66F4\u65B0\u51ED\u8BC1",
|
|
4821
|
+
retryable: "\u67E5\u8BE2\u5931\u8D25\uFF0C\u9886\u53D6\u5C1A\u672A\u63D0\u4EA4",
|
|
4822
|
+
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",
|
|
4823
|
+
unsupported: "\u6682\u672A\u63A5\u5165\u53EF\u6838\u9A8C\u7684\u7B7E\u5230\u63A5\u53E3\uFF0C\u8BF7\u4F7F\u7528\u5B98\u65B9\u5BA2\u6237\u7AEF"
|
|
4824
|
+
};
|
|
4825
|
+
var Checkins = class {
|
|
4826
|
+
constructor(file, manager, { now = Date.now, spacingMs = 1e4 } = {}) {
|
|
4827
|
+
this.file = file;
|
|
4828
|
+
this.manager = manager;
|
|
4829
|
+
this.now = now;
|
|
4830
|
+
this.spacingMs = spacingMs;
|
|
4831
|
+
this.data = { records: {}, devices: {}, pauses: {} };
|
|
4832
|
+
this.abort = new AbortController();
|
|
4833
|
+
}
|
|
4834
|
+
async read() {
|
|
4835
|
+
try {
|
|
4836
|
+
const raw = JSON.parse(await readFile(this.file, "utf8"));
|
|
4837
|
+
const object = (value) => value && typeof value === "object" && !Array.isArray(value);
|
|
4838
|
+
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");
|
|
4839
|
+
this.data = raw;
|
|
4840
|
+
} catch (e) {
|
|
4841
|
+
if (e.code !== "ENOENT") throw e;
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4844
|
+
async load() {
|
|
4845
|
+
try {
|
|
4846
|
+
await this.read();
|
|
4847
|
+
} catch {
|
|
4848
|
+
this.failed = true;
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4851
|
+
state() {
|
|
4852
|
+
return {
|
|
4853
|
+
running: !!this.flight,
|
|
4854
|
+
current: this.current,
|
|
4855
|
+
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,
|
|
4856
|
+
schedule: "\u5317\u4EAC\u65F6\u95F4 10:05 \u9996\u6B21\u7B7E\u5230\uFF0C20:05 \u4EC5\u8865\u67E5\u53EF\u91CD\u8BD5\u7684\u5931\u8D25\uFF1BDSH \u8FD0\u884C\u65F6\u6267\u884C\uFF0C\u542F\u52A8\u65F6\u8865\u67E5",
|
|
4857
|
+
report: this.data.report,
|
|
4858
|
+
accounts: this.manager.config.accounts.map((a) => {
|
|
4859
|
+
const rows = Object.values(this.data.records).filter((r) => r.ids?.includes(a.id));
|
|
4860
|
+
const last = rows.sort((a2, b) => b.at - a2.at)[0];
|
|
4861
|
+
const pause = this.data.pauses[a.provider];
|
|
4862
|
+
return {
|
|
4863
|
+
id: a.id,
|
|
4864
|
+
supported: supportsCheckin(a.provider),
|
|
4865
|
+
auto: a.autoCheckin === true,
|
|
4866
|
+
paused: !!pause,
|
|
4867
|
+
last: last ? {
|
|
4868
|
+
day: last.day,
|
|
4869
|
+
at: last.at,
|
|
4870
|
+
status: last.status,
|
|
4871
|
+
amount: last.amount,
|
|
4872
|
+
activity: last.activity,
|
|
4873
|
+
retryAt: last.retryAt,
|
|
4874
|
+
retryReady: canRetry(last, this.now()),
|
|
4875
|
+
message: checkinMessages[last.status] || checkinMessages.error
|
|
4876
|
+
} : void 0
|
|
4877
|
+
};
|
|
4878
|
+
})
|
|
4879
|
+
};
|
|
4880
|
+
}
|
|
4881
|
+
start(ids, automatic = false) {
|
|
4882
|
+
if (this.failed || this.abort.signal.aborted || this.flight) return;
|
|
4883
|
+
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");
|
|
4884
|
+
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);
|
|
4885
|
+
if (!selected.length) return;
|
|
4886
|
+
this.flight = (async () => {
|
|
4887
|
+
let requested = false;
|
|
4888
|
+
const counts = {};
|
|
4889
|
+
for (const id of selected) {
|
|
4890
|
+
if (this.abort.signal.aborted) break;
|
|
4891
|
+
const account = this.manager.config.accounts.find((a) => a.id === id && a.enabled !== false && (!automatic || a.autoCheckin === true));
|
|
4892
|
+
if (!account) continue;
|
|
4893
|
+
if (requested) {
|
|
4894
|
+
await delay(this.spacingMs, void 0, { signal: this.abort.signal });
|
|
4895
|
+
requested = false;
|
|
4896
|
+
}
|
|
4897
|
+
this.current = id;
|
|
4898
|
+
requested = await this.run(account, automatic);
|
|
4899
|
+
if (requested) {
|
|
4900
|
+
const last = this.state().accounts.find((a) => a.id === id)?.last;
|
|
4901
|
+
if (last) counts[last.status] = (counts[last.status] || 0) + 1;
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
if (Object.keys(counts).length) await withFileLock(this.file, async () => {
|
|
4905
|
+
await this.read();
|
|
4906
|
+
this.data.report = { at: this.now(), counts };
|
|
4907
|
+
await writePrivateJson(this.file, this.data);
|
|
4908
|
+
});
|
|
4909
|
+
})().catch(() => {
|
|
4910
|
+
if (!this.abort.signal.aborted) this.failed = true;
|
|
4911
|
+
}).finally(() => {
|
|
4912
|
+
this.flight = void 0;
|
|
4913
|
+
this.current = void 0;
|
|
4914
|
+
});
|
|
4915
|
+
}
|
|
4916
|
+
async resume(provider) {
|
|
4917
|
+
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");
|
|
4918
|
+
await withFileLock(this.file, async () => {
|
|
4919
|
+
await this.read();
|
|
4920
|
+
delete this.data.pauses[provider];
|
|
4921
|
+
await writePrivateJson(this.file, this.data);
|
|
4922
|
+
});
|
|
4923
|
+
}
|
|
4924
|
+
async credentialsUpdated(id) {
|
|
4925
|
+
await withFileLock(this.file, async () => {
|
|
4926
|
+
await this.read();
|
|
4927
|
+
for (const [key, row] of Object.entries(this.data.records)) if (row.status === "auth-invalid" && row.ids.includes(id)) delete this.data.records[key];
|
|
4928
|
+
await writePrivateJson(this.file, this.data);
|
|
4929
|
+
}, { waitMs: 3e4 });
|
|
4930
|
+
}
|
|
4931
|
+
async run(account, automatic = false) {
|
|
4932
|
+
const now = this.now(), day = beijingDay(now);
|
|
4933
|
+
if (now < Date.parse(`${day}T10:05:00+08:00`)) return false;
|
|
4934
|
+
return withFileLock(this.file, async () => {
|
|
4935
|
+
await this.read();
|
|
4936
|
+
if (this.abort.signal.aborted || this.data.pauses[account.provider]) return false;
|
|
4937
|
+
const previousEntry = Object.entries(this.data.records).find(([, r]) => r.day === day && r.ids?.includes(account.id));
|
|
4938
|
+
const previous = previousEntry?.[1];
|
|
4939
|
+
if (previous && !canRetry(previous, now)) return false;
|
|
4940
|
+
if (this.data.lastRequestAt && now - this.data.lastRequestAt < this.spacingMs) return false;
|
|
4941
|
+
this.data.lastRequestAt = now;
|
|
4942
|
+
await writePrivateJson(this.file, this.data);
|
|
4943
|
+
const pendingKey = hash(`${account.provider}:local:${account.id}`);
|
|
4944
|
+
const pending = {
|
|
4945
|
+
day,
|
|
4946
|
+
at: now,
|
|
4947
|
+
status: "retryable",
|
|
4948
|
+
ids: previous?.ids || [account.id],
|
|
4949
|
+
attempts: (previous?.attempts || (previous ? 1 : 0)) + 1,
|
|
4950
|
+
...now < evening(now) ? { retryAt: evening(now) } : {}
|
|
4951
|
+
};
|
|
4952
|
+
if (previousEntry) delete this.data.records[previousEntry[0]];
|
|
4953
|
+
this.data.records[pendingKey] = pending;
|
|
4954
|
+
await writePrivateJson(this.file, this.data);
|
|
4955
|
+
let identity, client;
|
|
4956
|
+
try {
|
|
4957
|
+
client = await this.manager.router.client(account);
|
|
4958
|
+
if (!client.checkin) throw Error("Unsupported check-in");
|
|
4959
|
+
identity = await client.checkin.identity(AbortSignal.any([this.abort.signal, AbortSignal.timeout(3e4)]));
|
|
4960
|
+
if (!identity?.account || account.provider === "trae" && !identity.device) throw Error("Missing check-in identity");
|
|
4961
|
+
} catch (error) {
|
|
4962
|
+
pending.status = checkinFailure(error).status;
|
|
4963
|
+
if (pending.status === "paused") this.data.pauses[account.provider] = { at: now };
|
|
4964
|
+
await writePrivateJson(this.file, this.data);
|
|
4965
|
+
return true;
|
|
4966
|
+
}
|
|
4967
|
+
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;
|
|
4968
|
+
const key = hash(`${account.provider}:${identity.account}`), device = identity.device ? hash(`${account.provider}:${identity.device}`) : void 0;
|
|
4969
|
+
const old = this.data.records[key];
|
|
4970
|
+
delete this.data.records[pendingKey];
|
|
4971
|
+
if (old?.day === day && !canRetry(old, now)) {
|
|
4972
|
+
if (!old.ids.includes(account.id)) {
|
|
4973
|
+
old.ids.push(account.id);
|
|
4974
|
+
await writePrivateJson(this.file, this.data);
|
|
4975
|
+
} else await writePrivateJson(this.file, this.data);
|
|
4976
|
+
return false;
|
|
4977
|
+
}
|
|
4978
|
+
const record2 = {
|
|
4979
|
+
...pending,
|
|
4980
|
+
status: "uncertain",
|
|
4981
|
+
ids: [.../* @__PURE__ */ new Set([...pending.ids, ...old?.ids || [], account.id])],
|
|
4982
|
+
attempts: Math.max(pending.attempts, old?.day === day ? (old.attempts || 1) + 1 : 1)
|
|
4983
|
+
};
|
|
4984
|
+
this.data.records[key] = record2;
|
|
4985
|
+
for (const [k, row] of Object.entries(this.data.records)) if (row.at < now - 30 * 864e5) delete this.data.records[k];
|
|
4986
|
+
for (const [k, row] of Object.entries(this.data.devices)) if (row.until <= now) delete this.data.devices[k];
|
|
4987
|
+
if (device && this.data.devices[device]?.until > now) {
|
|
4988
|
+
record2.status = "device-used";
|
|
4989
|
+
await writePrivateJson(this.file, this.data);
|
|
4990
|
+
return true;
|
|
4991
|
+
}
|
|
4992
|
+
if (device) this.data.devices[device] = { until: nextDay(now) };
|
|
4993
|
+
await writePrivateJson(this.file, this.data);
|
|
4994
|
+
let result;
|
|
4995
|
+
try {
|
|
4996
|
+
result = await client.checkin.claim(AbortSignal.any([this.abort.signal, AbortSignal.timeout(3e4)]));
|
|
4997
|
+
} catch {
|
|
4998
|
+
result = { status: "uncertain" };
|
|
4999
|
+
}
|
|
5000
|
+
record2.status = Object.hasOwn(checkinMessages, result?.status) ? result.status : "uncertain";
|
|
5001
|
+
if (device && ["already-claimed", "no-campaign", "retryable", "before-window", "auth-invalid"].includes(record2.status)) delete this.data.devices[device];
|
|
5002
|
+
if (record2.attempts >= 2 || !["retryable", "before-window"].includes(record2.status)) delete record2.retryAt;
|
|
5003
|
+
if (["claimed", "already-claimed"].includes(record2.status) && Number.isFinite(result.amount) && result.amount >= 0) record2.amount = result.amount;
|
|
5004
|
+
if (result?.activity) record2.activity = Object.fromEntries(["streakDays", "totalCredits", "nextStreakDay", "endsAt"].filter((k) => Number.isFinite(result.activity[k]) && result.activity[k] >= 0).map((k) => [k, result.activity[k]]));
|
|
5005
|
+
if (record2.status === "paused" || result?.paused === true) this.data.pauses[account.provider] = { at: now };
|
|
5006
|
+
await writePrivateJson(this.file, this.data);
|
|
5007
|
+
if (record2.status === "claimed") await this.manager.monitorAccount(account);
|
|
5008
|
+
return true;
|
|
5009
|
+
}, { waitMs: 1e3 });
|
|
5010
|
+
}
|
|
5011
|
+
};
|
|
5012
|
+
|
|
4790
5013
|
// src/stream.mjs
|
|
4791
5014
|
async function preflightStream(response, signal) {
|
|
4792
5015
|
if (!response.body) return { ok: false, status: 502, kind: "empty_stream" };
|
|
@@ -4889,7 +5112,7 @@ var expiryMs = (value) => {
|
|
|
4889
5112
|
};
|
|
4890
5113
|
async function jsonCredential(file) {
|
|
4891
5114
|
try {
|
|
4892
|
-
return JSON.parse(await
|
|
5115
|
+
return JSON.parse(await readFile2(file, "utf8"));
|
|
4893
5116
|
} catch {
|
|
4894
5117
|
throw new RouteError(401, "credential_unreadable");
|
|
4895
5118
|
}
|
|
@@ -4917,7 +5140,7 @@ async function createAccountClient(account, config, attachments) {
|
|
|
4917
5140
|
variant,
|
|
4918
5141
|
ownPath: account.credentialFile,
|
|
4919
5142
|
desktopPath: `${account.credentialFile}.no-desktop`,
|
|
4920
|
-
refresh: (c) => client.refreshToken(c)
|
|
5143
|
+
refresh: (c) => account.provider === "workbuddy" ? refreshWorkBuddyCheckinCredential(c) : client.refreshToken(c)
|
|
4921
5144
|
});
|
|
4922
5145
|
const credential = async () => {
|
|
4923
5146
|
try {
|
|
@@ -4948,6 +5171,7 @@ async function createAccountClient(account, config, attachments) {
|
|
|
4948
5171
|
};
|
|
4949
5172
|
};
|
|
4950
5173
|
chat = async (input, signal) => client.chatStream(await credential(), prepareChatBody(JSON.stringify(input)), signal);
|
|
5174
|
+
if (account.provider === "workbuddy") checkin = createWorkBuddyCheckin(() => store.resolve());
|
|
4951
5175
|
} else if (account.provider.startsWith("trae")) {
|
|
4952
5176
|
const snapshot = await jsonCredential(account.credentialFile);
|
|
4953
5177
|
const saved = snapshot.credential;
|
|
@@ -4975,8 +5199,9 @@ async function createAccountClient(account, config, attachments) {
|
|
|
4975
5199
|
};
|
|
4976
5200
|
const usage = new TraeUsageClient({ credential, deviceId: async () => (await identity()).deviceId });
|
|
4977
5201
|
if (account.provider === "trae") {
|
|
5202
|
+
const checkinCredential = () => store.resolve();
|
|
4978
5203
|
const checkinUsage = new TraeUsageClient({
|
|
4979
|
-
credential,
|
|
5204
|
+
credential: checkinCredential,
|
|
4980
5205
|
deviceId: async () => (await identity()).deviceId,
|
|
4981
5206
|
fetchImpl: async (url, options) => {
|
|
4982
5207
|
const response = await fetch(url, options);
|
|
@@ -4985,11 +5210,12 @@ async function createAccountClient(account, config, attachments) {
|
|
|
4985
5210
|
const body = await response.clone().json();
|
|
4986
5211
|
if (body.code !== void 0 && body.code !== 0 || typeof body.checked_in !== "boolean" || typeof body.did_checked_in !== "boolean") throw Object.assign(Error("checkin_status_rejected"), { status: 403 });
|
|
4987
5212
|
}
|
|
5213
|
+
if (String(url).endsWith("/claim") && !Number.isFinite((await response.clone().json()).code)) throw Error("checkin_claim_invalid");
|
|
4988
5214
|
return response;
|
|
4989
5215
|
}
|
|
4990
5216
|
});
|
|
4991
5217
|
checkin = {
|
|
4992
|
-
identity: async () => ({ account: (await
|
|
5218
|
+
identity: async () => ({ account: (await checkinCredential()).userId, device: (await identity()).deviceId }),
|
|
4993
5219
|
claim: (signal) => claimTraeCheckin(checkinUsage, signal)
|
|
4994
5220
|
};
|
|
4995
5221
|
}
|
|
@@ -5052,27 +5278,7 @@ async function createAccountClient(account, config, attachments) {
|
|
|
5052
5278
|
transport,
|
|
5053
5279
|
...attachments ? { attachments } : {}
|
|
5054
5280
|
});
|
|
5055
|
-
|
|
5056
|
-
region,
|
|
5057
|
-
resolvePat: getPat,
|
|
5058
|
-
resolveMachineId: () => getMachineId(),
|
|
5059
|
-
fetch: async (url, options) => {
|
|
5060
|
-
const response = await fetch(url, options);
|
|
5061
|
-
if (!response.ok) {
|
|
5062
|
-
const restricted = [401, 403, 429].includes(response.status);
|
|
5063
|
-
throw new QoderLlmError(`checkin_http_${response.status}`, restricted ? "QUOTA" : "PROVIDER_ERROR", { status: response.status });
|
|
5064
|
-
}
|
|
5065
|
-
return response;
|
|
5066
|
-
}
|
|
5067
|
-
});
|
|
5068
|
-
checkin = {
|
|
5069
|
-
identity: async (signal) => ({ account: (await checkinTransport.readAccount({ signal })).profile.id }),
|
|
5070
|
-
claim: async (signal) => {
|
|
5071
|
-
const result = await checkinTransport.checkIn(signal);
|
|
5072
|
-
if (result.status !== "error") return { status: result.status };
|
|
5073
|
-
return { status: /401|403|429|rate.?limit|throttl|captcha|verify|verification|风控|验证|频繁|forbidden|unauthor|AUTH/i.test(result.message || "") ? "paused" : "uncertain" };
|
|
5074
|
-
}
|
|
5075
|
-
};
|
|
5281
|
+
checkin = createQoderCheckin(region, getPat);
|
|
5076
5282
|
accountInfo = async (signal) => {
|
|
5077
5283
|
const result = await transport.readAccount({ force: true, signal });
|
|
5078
5284
|
const buckets = [["\u4E2A\u4EBA\u5957\u9910", result.usage?.userQuota], ["\u9644\u52A0\u989D\u5EA6", result.usage?.addOnQuota], ["\u7EC4\u7EC7\u989D\u5EA6", result.usage?.orgResourcePackage]].filter(([, p]) => p).map(([name, p]) => ({ ...p, name }));
|
|
@@ -5101,25 +5307,173 @@ async function createAccountClient(account, config, attachments) {
|
|
|
5101
5307
|
};
|
|
5102
5308
|
}
|
|
5103
5309
|
async function claimTraeCheckin(usage, signal) {
|
|
5310
|
+
let submitted = false;
|
|
5104
5311
|
try {
|
|
5105
5312
|
const status = await usage.checkinStatus(signal);
|
|
5106
5313
|
if (status.checkedIn) return { status: "already-claimed" };
|
|
5107
5314
|
if (status.didCheckedIn) return { status: "device-used" };
|
|
5108
5315
|
if (!status.enabled) return { status: "no-campaign" };
|
|
5316
|
+
submitted = true;
|
|
5109
5317
|
const claim = await usage.claimCheckin(signal);
|
|
5110
5318
|
if (claim.code === 9095) return { status: "device-used" };
|
|
5111
5319
|
if (!claim.claimed) return { status: "paused" };
|
|
5112
5320
|
return { status: "claimed", ...Number.isFinite(status.credits) ? { amount: status.credits + (status.extraCredits || 0) } : {} };
|
|
5113
5321
|
} catch (e) {
|
|
5114
|
-
return
|
|
5322
|
+
return checkinFailure(e, submitted);
|
|
5323
|
+
}
|
|
5324
|
+
}
|
|
5325
|
+
function createQoderCheckin(region, getPat, { fetchImpl = (...args) => fetch(...args), now = Date.now } = {}) {
|
|
5326
|
+
const guardedFetch = async (url, options) => {
|
|
5327
|
+
try {
|
|
5328
|
+
const response = await fetchImpl(url, options);
|
|
5329
|
+
if (!response.ok) throw new QoderLlmError("checkin_http_error", "PROVIDER_ERROR", { status: response.status });
|
|
5330
|
+
if (String(url).endsWith("/campaigns") && !Array.isArray((await response.clone().json()).campaigns)) throw Error("checkin_campaigns_invalid");
|
|
5331
|
+
return response;
|
|
5332
|
+
} catch (error) {
|
|
5333
|
+
if (error instanceof QoderLlmError) throw error;
|
|
5334
|
+
throw new QoderLlmError("checkin_network_error", "PROVIDER_ERROR");
|
|
5335
|
+
}
|
|
5336
|
+
};
|
|
5337
|
+
const auth = new QoderAuthService({ region, fetch: guardedFetch, resolveMachineId: () => getMachineId() });
|
|
5338
|
+
const campaigns = new QoderCheckInService({ region, authService: auth, fetch: guardedFetch });
|
|
5339
|
+
const credentials = async (signal) => auth.getCredentials(await getPat(), signal);
|
|
5340
|
+
return {
|
|
5341
|
+
identity: async (signal) => ({ account: (await credentials(signal)).userID }),
|
|
5342
|
+
claim: async (signal) => {
|
|
5343
|
+
let submitted = false;
|
|
5344
|
+
try {
|
|
5345
|
+
const token = (await credentials(signal)).authToken;
|
|
5346
|
+
const rows = await campaigns.fetchCampaigns(token, signal), time = now();
|
|
5347
|
+
const benefits = rows.filter((c) => c.actionType === "CLAIM_BENEFIT");
|
|
5348
|
+
const active = benefits.filter((c) => (!Number.isFinite(c.startAt) || c.startAt * 1e3 <= time) && (!Number.isFinite(c.endAt) || c.endAt * 1e3 > time));
|
|
5349
|
+
const target = active.find((c) => c.claimStatus === "CLAIMABLE" && typeof c.campaignId === "string" && c.campaignId);
|
|
5350
|
+
if (!target) {
|
|
5351
|
+
if (active.some((c) => c.claimStatus === "CLAIMED")) return { status: "already-claimed" };
|
|
5352
|
+
return { status: benefits.some((c) => c.startAt * 1e3 > time || c.endAt * 1e3 <= time) ? "before-window" : "no-campaign" };
|
|
5353
|
+
}
|
|
5354
|
+
submitted = true;
|
|
5355
|
+
const result = await campaigns.claimCampaign(token, target.campaignId, signal);
|
|
5356
|
+
if (result.status !== "CLAIMED") return { status: "paused" };
|
|
5357
|
+
return {
|
|
5358
|
+
status: result.replayed ? "already-claimed" : "claimed",
|
|
5359
|
+
...Number.isFinite(result.benefit?.amount) && result.benefit.amount >= 0 ? { amount: result.benefit.amount } : {}
|
|
5360
|
+
};
|
|
5361
|
+
} catch (error) {
|
|
5362
|
+
return checkinFailure(error, submitted);
|
|
5363
|
+
}
|
|
5364
|
+
}
|
|
5365
|
+
};
|
|
5366
|
+
}
|
|
5367
|
+
function workbuddyToken(token) {
|
|
5368
|
+
try {
|
|
5369
|
+
const [head, body, signature, extra] = token.split(".");
|
|
5370
|
+
const header = JSON.parse(Buffer.from(head, "base64url")), payload = JSON.parse(Buffer.from(body, "base64url"));
|
|
5371
|
+
if (extra || !signature || header.alg !== "RS256" || payload.iss !== "https://www.codebuddy.cn/auth/realms/copilot" || typeof payload.sub !== "string" || !payload.sub) throw Error();
|
|
5372
|
+
return payload;
|
|
5373
|
+
} catch {
|
|
5374
|
+
throw Object.assign(Error("HTTP 401 invalid_workbuddy_cn_token"), { status: 401 });
|
|
5115
5375
|
}
|
|
5116
5376
|
}
|
|
5377
|
+
async function workbuddyPost(url, headers, signal, fetchImpl) {
|
|
5378
|
+
let response;
|
|
5379
|
+
try {
|
|
5380
|
+
response = await fetchImpl(url, { method: "POST", headers: { "Content-Type": "application/json", "Accept-Encoding": "identity", ...headers }, body: "{}", signal });
|
|
5381
|
+
} catch {
|
|
5382
|
+
throw Object.assign(Error("workbuddy_checkin_network"), { transient: !signal?.aborted });
|
|
5383
|
+
}
|
|
5384
|
+
if (!response.ok) throw Object.assign(Error(`HTTP ${response.status} workbuddy_checkin_http`), { status: response.status, transient: response.status >= 500 });
|
|
5385
|
+
const body = JSON.parse(await readLimitedText(response, 256 * 1024, "Check-in"));
|
|
5386
|
+
if (body?.code === 401 || body?.code === 40100) throw Object.assign(Error("HTTP 401 workbuddy_checkin_auth"), { status: 401 });
|
|
5387
|
+
if ([403, 429].includes(body?.code)) throw Object.assign(Error(`HTTP ${body.code} workbuddy_checkin_restricted`), { status: body.code });
|
|
5388
|
+
return body;
|
|
5389
|
+
}
|
|
5390
|
+
async function refreshWorkBuddyCheckinCredential(credential, { fetchImpl = (...args) => fetch(...args), signal = AbortSignal.timeout(3e4) } = {}) {
|
|
5391
|
+
const body = await workbuddyPost("https://copilot.tencent.com/v2/plugin/auth/token/refresh", {
|
|
5392
|
+
"X-Refresh-Token": credential.refreshToken,
|
|
5393
|
+
"X-Auth-Refresh-Source": "plugin"
|
|
5394
|
+
}, signal, fetchImpl);
|
|
5395
|
+
if (body.code !== 0 || typeof body.data?.accessToken !== "string") throw Error("workbuddy_refresh_rejected");
|
|
5396
|
+
const token = workbuddyToken(body.data.accessToken);
|
|
5397
|
+
if (token.sub !== credential.uid || !(token.exp * 1e3 > Date.now())) throw Object.assign(Error("HTTP 401 workbuddy_refresh_identity"), { status: 401 });
|
|
5398
|
+
return {
|
|
5399
|
+
accessToken: body.data.accessToken,
|
|
5400
|
+
expiresInSec: (token.exp * 1e3 - Date.now()) / 1e3,
|
|
5401
|
+
...typeof body.data.refreshToken === "string" && body.data.refreshToken ? { refreshToken: body.data.refreshToken } : {}
|
|
5402
|
+
};
|
|
5403
|
+
}
|
|
5404
|
+
function createWorkBuddyCheckin(credential, { fetchImpl = (...args) => fetch(...args), sleep = delay2, now = Date.now } = {}) {
|
|
5405
|
+
const login = async () => {
|
|
5406
|
+
const c = await credential(), token = workbuddyToken(c.accessToken);
|
|
5407
|
+
if (c.uid !== token.sub) throw Object.assign(Error("workbuddy_uid_mismatch"), { status: 401 });
|
|
5408
|
+
return { ...c, uid: token.sub };
|
|
5409
|
+
};
|
|
5410
|
+
const post = (path, c, signal) => workbuddyPost(`https://www.workbuddy.cn/v2/billing/meter/${path}`, {
|
|
5411
|
+
Authorization: `Bearer ${c.accessToken}`,
|
|
5412
|
+
"X-User-Id": c.uid,
|
|
5413
|
+
Origin: "https://www.workbuddy.cn",
|
|
5414
|
+
Referer: "https://www.workbuddy.cn/profile/growth-center",
|
|
5415
|
+
"User-Agent": "Mozilla/5.0"
|
|
5416
|
+
}, signal, fetchImpl);
|
|
5417
|
+
const activity = (data) => {
|
|
5418
|
+
const rawEnd = data.end_time;
|
|
5419
|
+
const endsAt = typeof rawEnd === "string" ? Date.parse(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(rawEnd) ? `${rawEnd.replace(" ", "T")}+08:00` : rawEnd) : void 0;
|
|
5420
|
+
return { streakDays: data.streak_days, totalCredits: data.total_credits, nextStreakDay: data.next_streak_day, endsAt };
|
|
5421
|
+
};
|
|
5422
|
+
return {
|
|
5423
|
+
identity: async () => ({ account: (await login()).uid }),
|
|
5424
|
+
claim: async (signal) => {
|
|
5425
|
+
let submitted = false;
|
|
5426
|
+
try {
|
|
5427
|
+
const c = await login();
|
|
5428
|
+
let state;
|
|
5429
|
+
for (let attempt = 0; ; attempt++) {
|
|
5430
|
+
try {
|
|
5431
|
+
state = await post("checkin-activity-status", c, signal);
|
|
5432
|
+
break;
|
|
5433
|
+
} catch (error) {
|
|
5434
|
+
if (!error.transient || attempt >= 2 || signal?.aborted) throw error;
|
|
5435
|
+
await sleep((attempt + 1) * 2e3, void 0, { signal });
|
|
5436
|
+
}
|
|
5437
|
+
}
|
|
5438
|
+
if (![0, 200].includes(state?.code) || !state.data || typeof state.data !== "object") throw Error("workbuddy_status_invalid");
|
|
5439
|
+
const stats = activity(state.data);
|
|
5440
|
+
if (state.data.today_checked_in === true) return { status: "already-claimed", activity: stats };
|
|
5441
|
+
if (state.data.active === false || stats.endsAt <= now()) return { status: "no-campaign", activity: stats };
|
|
5442
|
+
if (state.data.today_checked_in !== false) throw Error("workbuddy_status_unknown");
|
|
5443
|
+
submitted = true;
|
|
5444
|
+
const result = await post("daily-checkin", c, signal);
|
|
5445
|
+
const claimed = [0, 200].includes(result?.code), already = /今天已签到|今日已签到|already\s+(?:checked|signed)/i.test(result?.msg || "");
|
|
5446
|
+
if (!claimed && !already) return { status: Number.isFinite(result?.code) ? "paused" : "uncertain" };
|
|
5447
|
+
let updated = stats, paused = false;
|
|
5448
|
+
try {
|
|
5449
|
+
const after = await post("checkin-activity-status", c, signal);
|
|
5450
|
+
if ([0, 200].includes(after?.code) && after.data) updated = activity(after.data);
|
|
5451
|
+
} catch (error) {
|
|
5452
|
+
paused = checkinFailure(error).status === "paused";
|
|
5453
|
+
}
|
|
5454
|
+
return {
|
|
5455
|
+
status: already ? "already-claimed" : "claimed",
|
|
5456
|
+
activity: updated,
|
|
5457
|
+
...paused ? { paused: true } : {},
|
|
5458
|
+
...claimed && Number.isFinite(result.data?.credit) && result.data.credit >= 0 ? { amount: result.data.credit } : {}
|
|
5459
|
+
};
|
|
5460
|
+
} catch (error) {
|
|
5461
|
+
return checkinFailure(error, submitted);
|
|
5462
|
+
}
|
|
5463
|
+
}
|
|
5464
|
+
};
|
|
5465
|
+
}
|
|
5117
5466
|
|
|
5118
5467
|
export {
|
|
5119
5468
|
qoderPluginDataDir,
|
|
5469
|
+
supportsCheckin,
|
|
5470
|
+
Checkins,
|
|
5120
5471
|
jsonCredential,
|
|
5121
5472
|
cachedModels,
|
|
5122
5473
|
createAccountClient,
|
|
5123
|
-
claimTraeCheckin
|
|
5474
|
+
claimTraeCheckin,
|
|
5475
|
+
createQoderCheckin,
|
|
5476
|
+
refreshWorkBuddyCheckinCredential,
|
|
5477
|
+
createWorkBuddyCheckin
|
|
5124
5478
|
};
|
|
5125
|
-
//# sourceMappingURL=chunk-
|
|
5479
|
+
//# sourceMappingURL=chunk-RPW6DI6O.js.map
|