@goodandready/dsh-subscriptions 0.6.40 → 0.6.43
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/accounts.js +88 -53
- package/lib/adapter-manager.js +3 -2
- package/lib/adapter.js +90 -41
- package/lib/backoff.js +13 -1
- package/lib/client.js +64 -11
- package/lib/code-assist.js +1 -0
- package/lib/google-validation.js +1 -1
- package/lib/history.js +12 -0
- package/lib/http.js +90 -6
- package/lib/import-auth.js +91 -44
- package/lib/oauth.js +12 -0
- package/lib/routes/accounts.js +5 -4
- package/lib/routes/status.js +6 -8
- package/lib/runaway-guard.js +13 -1
- package/lib/session-pin.js +9 -4
- package/lib/sse.js +6 -1
- package/lib/stream-rotate.js +13 -2
- package/lib/vendor-factory.js +9 -7
- package/lib/vendors/claude-cli.js +2 -1
- package/lib/vendors/codex.js +4 -2
- package/lib/vendors/cody.js +1 -4
- package/lib/vendors/copilot.js +9 -4
- package/lib/vendors/cursor.js +1 -0
- package/lib/vendors/ernie.js +1 -5
- package/lib/vendors/glm.js +1 -0
- package/lib/vendors/jetbrains.js +1 -5
- package/lib/vendors/kimi.js +1 -0
- package/lib/vendors/kiro.js +1 -0
- package/lib/vendors/perplexity.js +1 -4
- package/lib/vendors/qwen.js +2 -5
- package/lib/vendors/replit.js +1 -4
- package/lib/vendors/spark.js +1 -5
- package/lib/wire.js +12 -11
- package/package.json +13 -8
|
@@ -18,7 +18,8 @@ export async function readClaudeCredentials(home) {
|
|
|
18
18
|
accessToken: oauth.accessToken || oauth.access_token,
|
|
19
19
|
refreshToken: oauth.refreshToken || oauth.refresh_token || '',
|
|
20
20
|
expiresAt: oauth.expiresAt || (oauth.expires_in ? Date.now() + oauth.expires_in * 1000 : Date.now() + 3600000),
|
|
21
|
-
subscriptionType: oauth.subscriptionType || 'Claude Code'
|
|
21
|
+
subscriptionType: oauth.subscriptionType || 'Claude Code',
|
|
22
|
+
email: oauth.email || json.email || 'Claude Code CLI User',
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
return null
|
package/lib/vendors/codex.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isTimeoutError } from "../http.js"
|
|
1
2
|
import { randomUUID, createHash } from 'node:crypto'
|
|
2
3
|
import { buildAuthorizeUrl } from '../oauth.js'
|
|
3
4
|
import { codexResponsesBody, modelCatalog } from '../messages.js'
|
|
@@ -203,14 +204,15 @@ export async function usage(blob, cfg, fetchImpl) {
|
|
|
203
204
|
const snap = asUsageSnapshot(deepestUsedPercent(json))
|
|
204
205
|
if (snap) snap.windows = usageWindows(json)
|
|
205
206
|
return snap
|
|
206
|
-
} catch {
|
|
207
|
+
} catch (err) {
|
|
208
|
+
if (isTimeoutError(err)) throw err
|
|
207
209
|
return null
|
|
208
210
|
}
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
export async function* streamOnce({ blob, options, fetchImpl, headers, config, signal }) {
|
|
212
214
|
const base = (config.baseUrl || defaults().baseUrl).replace(/\/$/, '')
|
|
213
|
-
const body = codexResponsesBody(options, INSTRUCTIONS, config)
|
|
215
|
+
const body = /** @type {Record<string, any>} */ (codexResponsesBody(options, INSTRUCTIONS, config))
|
|
214
216
|
const sessionId = deriveSessionId(options)
|
|
215
217
|
|
|
216
218
|
// Prompt Cache Affinity
|
package/lib/vendors/cody.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages } from '../messages.js'
|
|
3
3
|
import { openaiChatStream, httpError } from '../wire.js'
|
|
4
|
-
import { asUsageSnapshot } from '../usage.js'
|
|
5
4
|
|
|
6
5
|
export const id = 'cody'
|
|
7
6
|
const CODY_API_BASE = 'https://sourcegraph.com/.api'
|
|
@@ -42,9 +41,7 @@ export async function listModels() {
|
|
|
42
41
|
|
|
43
42
|
export async function usage(blob) {
|
|
44
43
|
if (blob && (blob.accessToken || blob.token)) {
|
|
45
|
-
|
|
46
|
-
if (snap) snap.plan = 'Cody Pro'
|
|
47
|
-
return snap
|
|
44
|
+
return { usedPercent: null, plan: 'Cody Pro', timestamp: Date.now() }
|
|
48
45
|
}
|
|
49
46
|
return null
|
|
50
47
|
}
|
package/lib/vendors/copilot.js
CHANGED
|
@@ -2,7 +2,6 @@ import { LlmError } from "@deepseek-ai/dsh-llm"
|
|
|
2
2
|
import { openaiMessages, openaiTools, modelCatalog } from "../messages.js"
|
|
3
3
|
import { fetchWithTimeout } from "../http.js"
|
|
4
4
|
import { openaiChatStream, readJson, httpError } from "../wire.js"
|
|
5
|
-
import { asUsageSnapshot } from "../usage.js"
|
|
6
5
|
|
|
7
6
|
export const id = "copilot"
|
|
8
7
|
|
|
@@ -268,9 +267,14 @@ export async function usage(blob, config, fetchImpl) {
|
|
|
268
267
|
})
|
|
269
268
|
if (!res.ok) return null
|
|
270
269
|
const user = await readJson(res)
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
270
|
+
const usedPercent = user && typeof user.used_percent === "number" && Number.isFinite(user.used_percent)
|
|
271
|
+
? user.used_percent
|
|
272
|
+
: null
|
|
273
|
+
return {
|
|
274
|
+
usedPercent,
|
|
275
|
+
plan: user && user.plan ? (user.plan.name || String(user.plan)) : "Copilot",
|
|
276
|
+
timestamp: Date.now(),
|
|
277
|
+
}
|
|
274
278
|
} catch {
|
|
275
279
|
return null
|
|
276
280
|
}
|
|
@@ -292,6 +296,7 @@ export async function* streamOnce({ blob, options, fetchImpl, headers, config, s
|
|
|
292
296
|
|
|
293
297
|
if (!copilotToken) throw new LlmError("GitHub Copilot not authenticated", "AUTH")
|
|
294
298
|
|
|
299
|
+
/** @type {Record<string, any>} */
|
|
295
300
|
const body = {
|
|
296
301
|
model: options.model || "claude-3.7-sonnet",
|
|
297
302
|
messages: openaiMessages(options),
|
package/lib/vendors/cursor.js
CHANGED
|
@@ -175,6 +175,7 @@ export async function* streamOnce({ blob, options, fetchImpl, headers, config, s
|
|
|
175
175
|
const token = blob && (blob.accessToken || blob.access_token)
|
|
176
176
|
if (!token) throw new LlmError('Cursor not authenticated', 'AUTH')
|
|
177
177
|
|
|
178
|
+
/** @type {Record<string, any>} */
|
|
178
179
|
const body = {
|
|
179
180
|
model: options.model || 'composer-2',
|
|
180
181
|
messages: openaiMessages(options),
|
package/lib/vendors/ernie.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages } from '../messages.js'
|
|
3
3
|
import { openaiChatStream, readJson, httpError } from '../wire.js'
|
|
4
|
-
import { asUsageSnapshot } from '../usage.js'
|
|
5
4
|
|
|
6
5
|
export const id = 'ernie'
|
|
7
6
|
export const ERNIE_OAUTH_URL = 'https://aip.baidubce.com/oauth/2.0/token'
|
|
@@ -51,10 +50,7 @@ async function refreshErnieToken(apiKey, secretKey, fetchImpl) {
|
|
|
51
50
|
return readJson(res)
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
export async function usage(
|
|
55
|
-
if (blob && (blob.accessToken || blob.apiKey)) {
|
|
56
|
-
return asUsageSnapshot(20)
|
|
57
|
-
}
|
|
53
|
+
export async function usage() {
|
|
58
54
|
return null
|
|
59
55
|
}
|
|
60
56
|
|
package/lib/vendors/glm.js
CHANGED
|
@@ -84,6 +84,7 @@ export async function* streamOnce({ blob, options, fetchImpl, headers, config, s
|
|
|
84
84
|
const token = blob && (blob.accessToken || blob.access_token)
|
|
85
85
|
if (!token) throw new LlmError('GLM not authenticated', 'AUTH')
|
|
86
86
|
|
|
87
|
+
/** @type {Record<string, any>} */
|
|
87
88
|
const body = {
|
|
88
89
|
model: options.model || 'glm-4-plus',
|
|
89
90
|
messages: openaiMessages(options),
|
package/lib/vendors/jetbrains.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages } from '../messages.js'
|
|
3
3
|
import { openaiChatStream, httpError } from '../wire.js'
|
|
4
|
-
import { asUsageSnapshot } from '../usage.js'
|
|
5
4
|
|
|
6
5
|
export const id = 'jetbrains'
|
|
7
6
|
const JETBRAINS_API_BASE = 'https://api.jetbrains.ai'
|
|
@@ -42,10 +41,7 @@ export async function listModels() {
|
|
|
42
41
|
return JETBRAINS_MODELS
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
export async function usage(
|
|
46
|
-
if (blob && (blob.accessToken || blob.token)) {
|
|
47
|
-
return asUsageSnapshot(30)
|
|
48
|
-
}
|
|
44
|
+
export async function usage() {
|
|
49
45
|
return null
|
|
50
46
|
}
|
|
51
47
|
|
package/lib/vendors/kimi.js
CHANGED
|
@@ -88,6 +88,7 @@ export async function* streamOnce({ blob, options, fetchImpl, headers, config, s
|
|
|
88
88
|
const token = blob && (blob.accessToken || blob.access_token)
|
|
89
89
|
if (!token) throw new LlmError('Kimi not authenticated', 'AUTH')
|
|
90
90
|
|
|
91
|
+
/** @type {Record<string, any>} */
|
|
91
92
|
const body = {
|
|
92
93
|
model: options.model || 'kimi-for-coding',
|
|
93
94
|
messages: openaiMessages(options),
|
package/lib/vendors/kiro.js
CHANGED
|
@@ -87,6 +87,7 @@ export async function* streamOnce({ blob, options, fetchImpl, headers, config, s
|
|
|
87
87
|
const token = blob && (blob.accessToken || blob.access_token)
|
|
88
88
|
if (!token) throw new LlmError('AWS Kiro not authenticated', 'AUTH')
|
|
89
89
|
|
|
90
|
+
/** @type {Record<string, any>} */
|
|
90
91
|
const body = {
|
|
91
92
|
model: options.model || 'claude-sonnet-5',
|
|
92
93
|
messages: openaiMessages(options),
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages } from '../messages.js'
|
|
3
3
|
import { openaiChatStream, httpError } from '../wire.js'
|
|
4
|
-
import { asUsageSnapshot } from '../usage.js'
|
|
5
4
|
|
|
6
5
|
export const id = 'perplexity'
|
|
7
6
|
const PERPLEXITY_API_BASE = 'https://api.perplexity.ai'
|
|
@@ -44,9 +43,7 @@ export async function listModels() {
|
|
|
44
43
|
|
|
45
44
|
export async function usage(blob) {
|
|
46
45
|
if (blob && (blob.accessToken || blob.apiKey)) {
|
|
47
|
-
|
|
48
|
-
if (snap) snap.plan = 'Perplexity Pro'
|
|
49
|
-
return snap
|
|
46
|
+
return { usedPercent: null, plan: 'Perplexity Pro', timestamp: Date.now() }
|
|
50
47
|
}
|
|
51
48
|
return null
|
|
52
49
|
}
|
package/lib/vendors/qwen.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages, openaiTools } from '../messages.js'
|
|
3
3
|
import { openaiChatStream, httpError } from '../wire.js'
|
|
4
|
-
import { asUsageSnapshot } from '../usage.js'
|
|
5
4
|
|
|
6
5
|
export const id = 'qwen'
|
|
7
6
|
const QWEN_API_BASE = 'https://dashscope.aliyuncs.com/compatible-mode/v1'
|
|
@@ -49,10 +48,7 @@ export async function listModels() {
|
|
|
49
48
|
return QWEN_MODELS
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
export async function usage(
|
|
53
|
-
if (blob && (blob.accessToken || blob.apiKey)) {
|
|
54
|
-
return asUsageSnapshot(15)
|
|
55
|
-
}
|
|
51
|
+
export async function usage() {
|
|
56
52
|
return null
|
|
57
53
|
}
|
|
58
54
|
|
|
@@ -61,6 +57,7 @@ export async function* streamOnce({ blob, options, fetchImpl, headers, config, s
|
|
|
61
57
|
const key = blob && (blob.accessToken || blob.apiKey)
|
|
62
58
|
if (!key) throw new LlmError('Qwen API Key or Token is required', 'AUTH')
|
|
63
59
|
|
|
60
|
+
/** @type {Record<string, any>} */
|
|
64
61
|
const body = {
|
|
65
62
|
model: options.model || 'qwen-2.5-coder-32b-instruct',
|
|
66
63
|
messages: openaiMessages(options),
|
package/lib/vendors/replit.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages } from '../messages.js'
|
|
3
3
|
import { openaiChatStream, httpError } from '../wire.js'
|
|
4
|
-
import { asUsageSnapshot } from '../usage.js'
|
|
5
4
|
|
|
6
5
|
export const id = 'replit'
|
|
7
6
|
const REPLIT_API_BASE = 'https://replit.com/api/v1/ai'
|
|
@@ -37,9 +36,7 @@ export async function listModels() {
|
|
|
37
36
|
|
|
38
37
|
export async function usage(blob) {
|
|
39
38
|
if (blob && (blob.accessToken || blob.token)) {
|
|
40
|
-
|
|
41
|
-
if (snap) snap.plan = 'Replit Core'
|
|
42
|
-
return snap
|
|
39
|
+
return { usedPercent: null, plan: 'Replit Core', timestamp: Date.now() }
|
|
43
40
|
}
|
|
44
41
|
return null
|
|
45
42
|
}
|
package/lib/vendors/spark.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages } from '../messages.js'
|
|
3
3
|
import { openaiChatStream, httpError } from '../wire.js'
|
|
4
|
-
import { asUsageSnapshot } from '../usage.js'
|
|
5
4
|
|
|
6
5
|
export const id = 'spark'
|
|
7
6
|
const SPARK_API_BASE = 'https://spark-api-open.xf-yun.com/v1'
|
|
@@ -42,10 +41,7 @@ export async function listModels() {
|
|
|
42
41
|
return SPARK_MODELS
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
export async function usage(
|
|
46
|
-
if (blob && (blob.accessToken || blob.apiKey)) {
|
|
47
|
-
return asUsageSnapshot(12)
|
|
48
|
-
}
|
|
44
|
+
export async function usage() {
|
|
49
45
|
return null
|
|
50
46
|
}
|
|
51
47
|
|
package/lib/wire.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import { fetchWithTimeout } from "./http.js"
|
|
1
2
|
import { iterateSse, jsonSse } from './sse.js'
|
|
2
3
|
import { validationFromHttpError, validationRequiredError, googleRateLimitMessage, googleLicenseMessage } from './google-validation.js'
|
|
3
4
|
|
|
5
|
+
/**
|
|
6
|
+
* @param {number} status
|
|
7
|
+
* @param {string} [bodyText]
|
|
8
|
+
* @param {string} [code]
|
|
9
|
+
* @returns {Error & { status?: number, code?: string }}
|
|
10
|
+
*/
|
|
4
11
|
export function httpError(status, bodyText, code) {
|
|
5
12
|
const snippet = String(bodyText || '').slice(0, 400)
|
|
6
|
-
const err = new Error(snippet ? `vendor http ${status}: ${snippet}` : `vendor http ${status}`)
|
|
13
|
+
const err = /** @type {Error & { status?: number, code?: string }} */ (new Error(snippet ? `vendor http ${status}: ${snippet}` : `vendor http ${status}`))
|
|
7
14
|
err.status = status
|
|
8
15
|
if (code) {
|
|
9
16
|
err.code = code
|
|
@@ -401,25 +408,19 @@ export async function* googleStream(body) {
|
|
|
401
408
|
}
|
|
402
409
|
|
|
403
410
|
export async function formTokenRequest(url, params, fetchImpl, headers, { timeoutMs = 25000 } = {}) {
|
|
404
|
-
const
|
|
405
|
-
const timeoutSignal = AbortSignal.timeout(timeoutMs)
|
|
406
|
-
const res = await impl(url, {
|
|
411
|
+
const res = await fetchWithTimeout(fetchImpl || fetch, url, {
|
|
407
412
|
method: 'POST',
|
|
408
413
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json', ...(headers || {}) },
|
|
409
414
|
body: new URLSearchParams(params),
|
|
410
|
-
|
|
411
|
-
})
|
|
415
|
+
}, { timeoutMs })
|
|
412
416
|
return readJson(res)
|
|
413
417
|
}
|
|
414
418
|
|
|
415
419
|
export async function jsonTokenRequest(url, body, fetchImpl, headers, { timeoutMs = 25000 } = {}) {
|
|
416
|
-
const
|
|
417
|
-
const timeoutSignal = AbortSignal.timeout(timeoutMs)
|
|
418
|
-
const res = await impl(url, {
|
|
420
|
+
const res = await fetchWithTimeout(fetchImpl || fetch, url, {
|
|
419
421
|
method: 'POST',
|
|
420
422
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json', ...(headers || {}) },
|
|
421
423
|
body: JSON.stringify(body),
|
|
422
|
-
|
|
423
|
-
})
|
|
424
|
+
}, { timeoutMs })
|
|
424
425
|
return readJson(res)
|
|
425
426
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-subscriptions",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.43",
|
|
4
4
|
"description": "Use ChatGPT Codex, Claude, Grok, Antigravity, Kimi, GLM, Cursor, Kiro, Copilot, Qwen, ERNIE, Spark, JetBrains, Perplexity, Replit, and Cody subscriptions as DeepSeek Harness LLM providers via OAuth.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
57
|
-
"@deepseek-ai/dsh-credentials": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
58
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
59
|
-
"@deepseek-ai/dsh-llm": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
60
|
-
"@deepseek-ai/dsh-settings": "^0.1.7-rc.2 || ^0.2.0-rc.1",
|
|
57
|
+
"@deepseek-ai/dsh-credentials": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.0-rc.2",
|
|
58
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.0-rc.2",
|
|
59
|
+
"@deepseek-ai/dsh-llm": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.0-rc.2",
|
|
60
|
+
"@deepseek-ai/dsh-settings": "^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.0-rc.2",
|
|
61
61
|
"@deepseek-ai/schemastery": "^3.18.4"
|
|
62
62
|
},
|
|
63
63
|
"publishConfig": {
|
|
@@ -68,9 +68,14 @@
|
|
|
68
68
|
"undici": "^8.10.1"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
-
"@deepseek-ai/
|
|
71
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
72
|
+
"@deepseek-ai/dsh-credentials": "^0.2.0-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-llm": "^0.2.0-rc.2",
|
|
75
|
+
"@deepseek-ai/dsh-settings": "^0.2.0-rc.2",
|
|
76
|
+
"@deepseek-ai/schemastery": "^3.18.4",
|
|
72
77
|
"@types/node": "^22.20.2",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
78
|
+
"eslint": "^10.4.0",
|
|
79
|
+
"typescript": "^7.0.2"
|
|
75
80
|
}
|
|
76
81
|
}
|