@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.
@@ -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
@@ -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
@@ -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
- const snap = asUsageSnapshot(15)
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
  }
@@ -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 snap = asUsageSnapshot(10)
272
- if (snap) snap.plan = user && user.plan ? user.plan.name : "Copilot"
273
- return snap
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),
@@ -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),
@@ -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(blob) {
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
 
@@ -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),
@@ -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(blob) {
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
 
@@ -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),
@@ -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
- const snap = asUsageSnapshot(18)
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
  }
@@ -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(blob) {
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),
@@ -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
- const snap = asUsageSnapshot(25)
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
  }
@@ -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(blob) {
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 impl = fetchImpl || fetch
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
- signal: timeoutSignal,
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 impl = fetchImpl || fetch
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
- signal: timeoutSignal,
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.40",
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/dsh-llm": "0.1.0-rc.8",
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
- "typescript": "^7.0.2",
74
- "@deepseek-ai/schemastery": "^3.18.4"
78
+ "eslint": "^10.4.0",
79
+ "typescript": "^7.0.2"
75
80
  }
76
81
  }