dsh-any-deepseek 0.0.13 → 0.0.14
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/balance.d.ts +19 -0
- package/lib/index.js +97 -8
- package/lib/presets.d.ts +15 -12
- package/package.json +1 -1
package/lib/balance.d.ts
CHANGED
|
@@ -119,6 +119,25 @@ export declare function parseOllamaBalance(body: unknown): BalanceReading | unde
|
|
|
119
119
|
* @returns the reading, or undefined when neither body is this shape.
|
|
120
120
|
*/
|
|
121
121
|
export declare function parseOpenAIBilling(subscription: unknown, usage: unknown): BalanceReading | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Parse OpenCode Go's `GET /zen/go/v1/usage`.
|
|
124
|
+
*
|
|
125
|
+
* 🔴 **This surface reports WINDOWS, never money.** The owner remembered correctly that OpenCode
|
|
126
|
+
* exposes a usage query — and it does; what it does not expose (to an API key) is the credit
|
|
127
|
+
* wallet, which lives behind a logged-in browser session. The only key-authenticated money signal
|
|
128
|
+
* is the error thrown at $0 (anomalyco/opencode#44189), which is why the feature request asks for
|
|
129
|
+
* a `balance` object to be added to this very endpoint.
|
|
130
|
+
*
|
|
131
|
+
* Two response shapes are accepted, because a monitor should not break when the provider ships
|
|
132
|
+
* the requested addition:
|
|
133
|
+
* · `{ usage: { rolling: {percent, resetsAt}, weekly: … , monthly: … } }`
|
|
134
|
+
* · the same keys hoisted to the top level.
|
|
135
|
+
* A `balance` object is read IF PRESENT — so the day they merge that request, the number appears
|
|
136
|
+
* with no code change here.
|
|
137
|
+
* @param body - the parsed JSON body.
|
|
138
|
+
* @returns the reading, or undefined when the body carries no recognizable window.
|
|
139
|
+
*/
|
|
140
|
+
export declare function parseOpencodeWindows(body: unknown): BalanceReading | undefined;
|
|
122
141
|
/**
|
|
123
142
|
* Map one channel's raw bodies onto a reading, dispatching on the declared shape.
|
|
124
143
|
* @param probe - the preset's declared probe.
|
package/lib/index.js
CHANGED
|
@@ -278,7 +278,25 @@ const CHANNEL_PRESETS = {
|
|
|
278
278
|
...V41_FLASH_CAPS,
|
|
279
279
|
compat: { ...DEEPSEEK_THINKING_COMPAT },
|
|
280
280
|
headers: { ...OPENCODE_HEADERS },
|
|
281
|
-
|
|
281
|
+
/**
|
|
282
|
+
* 🔴 **The owner was right that OpenCode has a query surface — and it reports WINDOWS, not
|
|
283
|
+
* money.** Both halves of that sentence were measured, in that order:
|
|
284
|
+
*
|
|
285
|
+
* 1. A route exists at `/zen/go/v1/usage`. Proven by status code discrimination without a
|
|
286
|
+
* key: a made-up path under the same prefix answers **404**, while `/usage` answers
|
|
287
|
+
* **401** (route present, auth required). `/zen/v1/balance` answers 404 — that one really
|
|
288
|
+
* does not exist (it is what anomalyco/opencode#44189 is asking for).
|
|
289
|
+
* 2. What it returns is Go-subscription usage windows (rolling / weekly / monthly), **not**
|
|
290
|
+
* the credit wallet. The balance is only reachable from a logged-in browser session
|
|
291
|
+
* (`BillingTable.balance` behind a SolidStart server function), so a key cannot read it —
|
|
292
|
+
* the only key-authenticated money signal is the error thrown at $0.
|
|
293
|
+
*
|
|
294
|
+
* ⇒ Declared as a `windows` shape, which is exactly what this endpoint honestly provides.
|
|
295
|
+
* The credit balance stays absent rather than invented; the panel shows the windows and does
|
|
296
|
+
* not pretend a currency amount exists.
|
|
297
|
+
*/
|
|
298
|
+
balance: { shape: "opencode-windows" },
|
|
299
|
+
note: "Requires the OpenCode session headers; shipped with the preset. Usage windows only — the credit balance is not readable with an API key."
|
|
282
300
|
},
|
|
283
301
|
commandcode: {
|
|
284
302
|
displayName: "CommandCode",
|
|
@@ -304,8 +322,7 @@ const CHANNEL_PRESETS = {
|
|
|
304
322
|
api: "openai-completions",
|
|
305
323
|
baseURL: "https://amr-link.open-design.ai/v1",
|
|
306
324
|
model: "deepseek-v4.1-flash",
|
|
307
|
-
...V41_FLASH_CAPS
|
|
308
|
-
balance: { shape: "openai-billing" }
|
|
325
|
+
...V41_FLASH_CAPS
|
|
309
326
|
},
|
|
310
327
|
"deepseek-official": {
|
|
311
328
|
displayName: "DeepSeek Official",
|
|
@@ -1792,6 +1809,7 @@ function balanceUrls(probe, channelBaseURL) {
|
|
|
1792
1809
|
switch (probe.shape) {
|
|
1793
1810
|
case "deepseek": return [`${root}/user/balance`];
|
|
1794
1811
|
case "ollama": return [`${root}/api/balance`];
|
|
1812
|
+
case "opencode-windows": return [`${root}/usage`];
|
|
1795
1813
|
case "openai-billing": return [`${root}/dashboard/billing/subscription`, `${root}/dashboard/billing/usage`];
|
|
1796
1814
|
}
|
|
1797
1815
|
}
|
|
@@ -1951,6 +1969,58 @@ function parseOpenAIBilling(subscription, usage) {
|
|
|
1951
1969
|
};
|
|
1952
1970
|
}
|
|
1953
1971
|
/**
|
|
1972
|
+
* Parse OpenCode Go's `GET /zen/go/v1/usage`.
|
|
1973
|
+
*
|
|
1974
|
+
* 🔴 **This surface reports WINDOWS, never money.** The owner remembered correctly that OpenCode
|
|
1975
|
+
* exposes a usage query — and it does; what it does not expose (to an API key) is the credit
|
|
1976
|
+
* wallet, which lives behind a logged-in browser session. The only key-authenticated money signal
|
|
1977
|
+
* is the error thrown at $0 (anomalyco/opencode#44189), which is why the feature request asks for
|
|
1978
|
+
* a `balance` object to be added to this very endpoint.
|
|
1979
|
+
*
|
|
1980
|
+
* Two response shapes are accepted, because a monitor should not break when the provider ships
|
|
1981
|
+
* the requested addition:
|
|
1982
|
+
* · `{ usage: { rolling: {percent, resetsAt}, weekly: … , monthly: … } }`
|
|
1983
|
+
* · the same keys hoisted to the top level.
|
|
1984
|
+
* A `balance` object is read IF PRESENT — so the day they merge that request, the number appears
|
|
1985
|
+
* with no code change here.
|
|
1986
|
+
* @param body - the parsed JSON body.
|
|
1987
|
+
* @returns the reading, or undefined when the body carries no recognizable window.
|
|
1988
|
+
*/
|
|
1989
|
+
function parseOpencodeWindows(body) {
|
|
1990
|
+
const root = asRecord(body);
|
|
1991
|
+
if (root === void 0) return void 0;
|
|
1992
|
+
const usage = asRecord(root.usage) ?? root;
|
|
1993
|
+
const windows = [];
|
|
1994
|
+
for (const name of [
|
|
1995
|
+
"rolling",
|
|
1996
|
+
"weekly",
|
|
1997
|
+
"monthly"
|
|
1998
|
+
]) {
|
|
1999
|
+
const window = asRecord(usage[name]);
|
|
2000
|
+
if (window === void 0) continue;
|
|
2001
|
+
const used = num(window.percent);
|
|
2002
|
+
if (used === void 0) continue;
|
|
2003
|
+
windows.push({
|
|
2004
|
+
name,
|
|
2005
|
+
remainingPercent: Math.max(0, Math.min(100, 100 - used)),
|
|
2006
|
+
...text(window.resetsAt) === void 0 ? {} : { resetsAt: text(window.resetsAt) }
|
|
2007
|
+
});
|
|
2008
|
+
}
|
|
2009
|
+
const amounts = [];
|
|
2010
|
+
const balance = asRecord(root.balance);
|
|
2011
|
+
const usd = num(balance?.usd);
|
|
2012
|
+
if (usd !== void 0) amounts.push({
|
|
2013
|
+
currency: text(balance?.currency) ?? "USD",
|
|
2014
|
+
remaining: usd
|
|
2015
|
+
});
|
|
2016
|
+
if (windows.length === 0 && amounts.length === 0) return void 0;
|
|
2017
|
+
return {
|
|
2018
|
+
amounts,
|
|
2019
|
+
windows,
|
|
2020
|
+
note: amounts.length === 0 ? "subscription usage windows; the credit balance is not readable with an API key" : void 0
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
/**
|
|
1954
2024
|
* Map one channel's raw bodies onto a reading, dispatching on the declared shape.
|
|
1955
2025
|
* @param probe - the preset's declared probe.
|
|
1956
2026
|
* @param bodies - response bodies in the order {@link balanceUrls} returned URLs.
|
|
@@ -1960,6 +2030,7 @@ function readBalance(probe, bodies) {
|
|
|
1960
2030
|
switch (probe.shape) {
|
|
1961
2031
|
case "deepseek": return parseDeepSeekBalance(bodies[0]);
|
|
1962
2032
|
case "ollama": return parseOllamaBalance(bodies[0]);
|
|
2033
|
+
case "opencode-windows": return parseOpencodeWindows(bodies[0]);
|
|
1963
2034
|
case "openai-billing": return parseOpenAIBilling(bodies[0], bodies[1]);
|
|
1964
2035
|
}
|
|
1965
2036
|
}
|
|
@@ -2200,11 +2271,29 @@ async function fetchBalance(channel, key, signal) {
|
|
|
2200
2271
|
...signal === void 0 ? {} : { signal }
|
|
2201
2272
|
});
|
|
2202
2273
|
const text = await response.text();
|
|
2203
|
-
if (!response.ok)
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2274
|
+
if (!response.ok) {
|
|
2275
|
+
/**
|
|
2276
|
+
* 🔴 **404 means "this relay has no such route", not "the read failed".**
|
|
2277
|
+
*
|
|
2278
|
+
* The distinction decides what the user does next: `unsupported` says "this endpoint
|
|
2279
|
+
* does not publish a balance — stop looking", while `unavailable` says "it should have
|
|
2280
|
+
* but did not answer — try again". Reporting a 404 as a failure invites a retry loop
|
|
2281
|
+
* against a route that will never exist.
|
|
2282
|
+
*
|
|
2283
|
+
* Measured: Open Design answers 404 on every billing candidate while `/v1/models`
|
|
2284
|
+
* answers 401 (route exists, auth required) — that difference is how the two were told
|
|
2285
|
+
* apart without a key.
|
|
2286
|
+
*/
|
|
2287
|
+
if (response.status === 404) return {
|
|
2288
|
+
status: "unsupported",
|
|
2289
|
+
detail: "this relay has no balance route (HTTP 404)"
|
|
2290
|
+
};
|
|
2291
|
+
return {
|
|
2292
|
+
status: "unavailable",
|
|
2293
|
+
code: `HTTP_${response.status}`,
|
|
2294
|
+
detail: `balance endpoint answered HTTP ${response.status}`
|
|
2295
|
+
};
|
|
2296
|
+
}
|
|
2208
2297
|
try {
|
|
2209
2298
|
bodies.push(JSON.parse(text));
|
|
2210
2299
|
} catch {
|
package/lib/presets.d.ts
CHANGED
|
@@ -32,23 +32,26 @@ export type ChannelModality = 'text' | 'image';
|
|
|
32
32
|
* How to read one endpoint's remaining balance.
|
|
33
33
|
*
|
|
34
34
|
* Owner request (2026-10-23): 「其它渠道的查看方式你需要找到并实现它们的」. There is no single
|
|
35
|
-
* answer — every provider invented its own surface, and some
|
|
36
|
-
* fact written down instead of guessed: a preset either names a known shape or
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* · `
|
|
41
|
-
* · `
|
|
35
|
+
* answer — every provider invented its own surface, and some report windows instead of money.
|
|
36
|
+
* This type is that fact written down instead of guessed: a preset either names a known shape or
|
|
37
|
+
* says it has none.
|
|
38
|
+
*
|
|
39
|
+
* Four shapes were verified against real endpoints (see `balance.ts` for the response mapping):
|
|
40
|
+
* · `deepseek` — DeepSeek's own `GET /user/balance`.
|
|
41
|
+
* · `ollama` — `GET /api/balance` (note: under `/api`, NOT the `/v1` used for inference).
|
|
42
|
+
* · `opencode-windows` — OpenCode Go's `GET /zen/go/v1/usage`: rolling/weekly/monthly WINDOWS.
|
|
43
|
+
* No currency amount — the credit wallet is not API-readable.
|
|
44
|
+
* · `openai-billing` — the OpenAI-legacy billing pair that new-api / one-api relays clone:
|
|
42
45
|
* `GET /v1/dashboard/billing/subscription` + `GET /v1/dashboard/billing/usage`.
|
|
43
46
|
*
|
|
44
|
-
* 🔴 **
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
47
|
+
* 🔴 **"This endpoint has no balance API" must be representable, and is**: a preset simply omits
|
|
48
|
+
* `balance`. Open Design is a measured case (every billing candidate answers 404 while
|
|
49
|
+
* `/v1/models` answers 401, i.e. inference only). Pretending otherwise would mean showing a
|
|
50
|
+
* number nobody measured.
|
|
48
51
|
*/
|
|
49
52
|
export interface BalanceProbe {
|
|
50
53
|
/** Which response shape to read. */
|
|
51
|
-
shape: 'deepseek' | 'ollama' | 'openai-billing';
|
|
54
|
+
shape: 'deepseek' | 'ollama' | 'opencode-windows' | 'openai-billing';
|
|
52
55
|
/**
|
|
53
56
|
* Overrides the base URL for the balance call.
|
|
54
57
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-any-deepseek",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "One DeepSeek V4.1 Flash provider for DeepSeek Harness: paste a key per channel, switch channels manually, token usage booked per real upstream.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|