@goodandready/dsh-subscriptions 0.6.21 → 0.6.23
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-view.js +84 -0
- package/lib/accounts.js +5 -2
- package/lib/adapter-manager.js +300 -0
- package/lib/adapter.js +7 -7
- package/lib/alerts.js +2 -2
- package/lib/backoff.js +1 -1
- package/lib/client.js +89 -75
- package/lib/code-assist.js +1 -1
- package/lib/config-schema.js +46 -6
- package/lib/diagnostics.js +60 -0
- package/lib/history.js +21 -1
- package/lib/http.js +58 -11
- package/lib/index.js +143 -543
- package/lib/mask.js +1 -1
- package/lib/ollama.js +4 -4
- package/lib/routes/accounts.js +9 -1
- package/lib/routes/proxy.js +1 -1
- package/lib/routes/status.js +58 -7
- package/lib/routes.js +0 -1
- package/lib/session-pin.js +0 -8
- package/lib/subscriptions.js +5 -6
- package/lib/vault.js +2 -2
- package/lib/vendor-factory.js +0 -1
- package/lib/vendors/antigravity.js +1 -1
- package/lib/vendors/codex.js +1 -1
- package/lib/vendors/grok.js +1 -1
- package/lib/vendors/index.js +0 -1
- package/lib/vendors/qwen.js +1 -1
- package/lib/vendors/spark.js +1 -1
- package/package.json +3 -1
package/lib/mask.js
CHANGED
|
@@ -30,7 +30,7 @@ export function cleanErrorMessage(raw) {
|
|
|
30
30
|
if (parsed.error && parsed.error.message) text = parsed.error.message
|
|
31
31
|
else if (parsed.message) text = parsed.message
|
|
32
32
|
else if (parsed.code) text = parsed.code
|
|
33
|
-
} catch
|
|
33
|
+
} catch { /* ignore JSON parse failure */ }
|
|
34
34
|
}
|
|
35
35
|
const firstLine = text.split('\n')[0].trim()
|
|
36
36
|
if (firstLine.length > 160) {
|
package/lib/ollama.js
CHANGED
|
@@ -37,19 +37,19 @@ export class OllamaAdapter extends LlmAdapter {
|
|
|
37
37
|
return { id: provider, name: 'Ollama (local)' }
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
providerRetryPolicy(
|
|
40
|
+
providerRetryPolicy() {
|
|
41
41
|
return undefined
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
async listModels(
|
|
44
|
+
async listModels() {
|
|
45
45
|
return ollamaModels(this.deps.baseUrl(), this.deps.fetchImpl || fetch)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
imageRequestPricing(
|
|
48
|
+
imageRequestPricing() {
|
|
49
49
|
return undefined
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
async resolveModel(provider, model
|
|
52
|
+
async resolveModel(provider, model) {
|
|
53
53
|
return { provider, id: model, name: model }
|
|
54
54
|
}
|
|
55
55
|
|
package/lib/routes/accounts.js
CHANGED
|
@@ -29,6 +29,10 @@ export function registerAccountsRoutes(ctx, state) {
|
|
|
29
29
|
writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET only' } })
|
|
30
30
|
return
|
|
31
31
|
}
|
|
32
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
33
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
34
|
+
return
|
|
35
|
+
}
|
|
32
36
|
const q = queryOf(req)
|
|
33
37
|
const provider = q.get('provider') || ''
|
|
34
38
|
const index = Number(q.get('index') || '1')
|
|
@@ -107,6 +111,10 @@ export function registerAccountsRoutes(ctx, state) {
|
|
|
107
111
|
writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET only' } })
|
|
108
112
|
return
|
|
109
113
|
}
|
|
114
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
115
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
116
|
+
return
|
|
117
|
+
}
|
|
110
118
|
try {
|
|
111
119
|
const detected = await discoverLocalCliSessions()
|
|
112
120
|
writeJson(res, 200, { ok: true, detected })
|
|
@@ -246,7 +254,7 @@ export function registerAccountsRoutes(ctx, state) {
|
|
|
246
254
|
let bundle
|
|
247
255
|
try {
|
|
248
256
|
bundle = JSON.parse(decryptWithPassphrase(encrypted, passphrase))
|
|
249
|
-
} catch
|
|
257
|
+
} catch {
|
|
250
258
|
writeJson(res, 400, { ok: false, error: { code: 'decrypt', message: 'wrong passphrase or corrupted bundle' } })
|
|
251
259
|
return
|
|
252
260
|
}
|
package/lib/routes/proxy.js
CHANGED
|
@@ -21,7 +21,7 @@ export function registerProxyRoutes(ctx, state) {
|
|
|
21
21
|
}
|
|
22
22
|
const raw = await readBody(req, 128 * 1024).catch(() => Buffer.alloc(0))
|
|
23
23
|
let body = {}
|
|
24
|
-
try { body = JSON.parse(raw.toString('utf8') || '{}') } catch
|
|
24
|
+
try { body = JSON.parse(raw.toString('utf8') || '{}') } catch { body = {} }
|
|
25
25
|
const events = Array.isArray(body && body.events) ? body.events : []
|
|
26
26
|
const analysis = analyzeSessionEvents(events)
|
|
27
27
|
writeJson(res, 200, { ok: true, analysis })
|
package/lib/routes/status.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getRecentAlerts } from '../alerts.js'
|
|
1
|
+
import { getRecentAlerts, clearAlerts } from '../alerts.js'
|
|
2
2
|
import { normalizeSlots, vendorConfig } from '../accounts.js'
|
|
3
3
|
import { Config, publicConfig } from '../config-schema.js'
|
|
4
4
|
import { isTrustedSettingsRequest, queryOf, readBody, safeJsonHandler, writeJson } from '../http.js'
|
|
@@ -22,9 +22,12 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
22
22
|
fetchForRef,
|
|
23
23
|
} = state
|
|
24
24
|
|
|
25
|
+
let currentRevision = 1
|
|
26
|
+
|
|
25
27
|
async function configResponse() {
|
|
26
28
|
return {
|
|
27
29
|
ok: true,
|
|
30
|
+
revision: currentRevision,
|
|
28
31
|
config: publicConfig(live()),
|
|
29
32
|
accounts: await accountsView(),
|
|
30
33
|
providers: PROVIDERS.map((id) => ({ id, name: displayName(id) })),
|
|
@@ -36,6 +39,10 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
36
39
|
path: '/dsh-subscriptions/config',
|
|
37
40
|
handler: safeJsonHandler(async (req, res) => {
|
|
38
41
|
if (req.method === 'GET') {
|
|
42
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
43
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
44
|
+
return
|
|
45
|
+
}
|
|
39
46
|
writeJson(res, 200, await configResponse())
|
|
40
47
|
return
|
|
41
48
|
}
|
|
@@ -56,12 +63,27 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
56
63
|
writeJson(res, 400, { ok: false, error: { code: 'json', message: 'invalid json' } })
|
|
57
64
|
return
|
|
58
65
|
}
|
|
66
|
+
// #379: revision conflict detection (CAS)
|
|
67
|
+
const baseRev = payload?.revision != null ? Number(payload.revision) : (req.headers?.['if-match'] ? Number(req.headers['if-match']) : null)
|
|
68
|
+
if (baseRev != null && !Number.isNaN(baseRev) && baseRev !== currentRevision) {
|
|
69
|
+
writeJson(res, 409, {
|
|
70
|
+
ok: false,
|
|
71
|
+
error: {
|
|
72
|
+
code: 'conflict',
|
|
73
|
+
message: 'configuration has been modified concurrently',
|
|
74
|
+
currentRevision,
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
59
80
|
if (payload && typeof payload.config === 'object') payload = payload.config
|
|
60
81
|
try {
|
|
61
82
|
if (Array.isArray(payload.slots)) payload.slots = stripLegacySlots(payload.slots)
|
|
62
83
|
const parsed = Config(payload)
|
|
63
84
|
const dropped = droppedCredentialRefs(live().slots, parsed.slots)
|
|
64
85
|
await getSettingsApi().replace(parsed)
|
|
86
|
+
currentRevision++
|
|
65
87
|
syncCustomVendors()
|
|
66
88
|
for (const ref of dropped) await store.clearRef(ref)
|
|
67
89
|
await syncAdapter()
|
|
@@ -77,8 +99,21 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
77
99
|
kind: 'exact',
|
|
78
100
|
path: '/dsh-subscriptions/status',
|
|
79
101
|
handler: safeJsonHandler(async (req, res) => {
|
|
102
|
+
if (req.method === 'DELETE') {
|
|
103
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
104
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
clearAlerts()
|
|
108
|
+
writeJson(res, 200, { ok: true })
|
|
109
|
+
return
|
|
110
|
+
}
|
|
80
111
|
if (req.method !== 'GET') {
|
|
81
|
-
writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET only' } })
|
|
112
|
+
writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET or DELETE only' } })
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
116
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
82
117
|
return
|
|
83
118
|
}
|
|
84
119
|
const logged = await store.loggedInProviders()
|
|
@@ -97,7 +132,7 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
97
132
|
expires[slot.provider] = Math.max(expires[slot.provider] || 0, slot.expiresAt)
|
|
98
133
|
labels[slot.provider] = pmL(slot.label || info.label || slot.provider)
|
|
99
134
|
}
|
|
100
|
-
} catch
|
|
135
|
+
} catch { /* ignore status inspection error */ }
|
|
101
136
|
}
|
|
102
137
|
// #69/#72: active subscription = last successful request (newest first).
|
|
103
138
|
let active = null
|
|
@@ -120,7 +155,7 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
120
155
|
.filter((w) => w && typeof w.usedPercent === 'number')
|
|
121
156
|
.map((w) => ({ id: w.id || w.en || w.ru, label: w.en || w.ru || w.id, usedPercent: w.usedPercent }))
|
|
122
157
|
}
|
|
123
|
-
} catch
|
|
158
|
+
} catch { /* ignore status inspection error */ }
|
|
124
159
|
active = {
|
|
125
160
|
provider: lastRow.provider,
|
|
126
161
|
index,
|
|
@@ -156,6 +191,10 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
156
191
|
writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET only' } })
|
|
157
192
|
return
|
|
158
193
|
}
|
|
194
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
195
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
196
|
+
return
|
|
197
|
+
}
|
|
159
198
|
writeJson(res, 200, { ok: true, report: await diagnosticsReport() })
|
|
160
199
|
}),
|
|
161
200
|
}), 'dsh-subscriptions: /diagnostics')
|
|
@@ -220,7 +259,7 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
220
259
|
try {
|
|
221
260
|
const snap = quotaSnapshot(provider, res2.headers, null, Date.now())
|
|
222
261
|
if (snap) { capturedQuota = snap; store.rememberQuota(ref, snap) }
|
|
223
|
-
} catch
|
|
262
|
+
} catch { /* ignore status inspection error */ }
|
|
224
263
|
return res2
|
|
225
264
|
}
|
|
226
265
|
try {
|
|
@@ -250,6 +289,10 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
250
289
|
writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET only' } })
|
|
251
290
|
return
|
|
252
291
|
}
|
|
292
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
293
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
294
|
+
return
|
|
295
|
+
}
|
|
253
296
|
const host = (req.headers.host || '').split(':')[0]
|
|
254
297
|
if (host !== 'localhost' && host !== '127.0.0.1') {
|
|
255
298
|
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'localhost only' } })
|
|
@@ -269,6 +312,10 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
269
312
|
writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET only' } })
|
|
270
313
|
return
|
|
271
314
|
}
|
|
315
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
316
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
317
|
+
return
|
|
318
|
+
}
|
|
272
319
|
const summary = typeof history.telemetrySummary === 'function'
|
|
273
320
|
? history.telemetrySummary()
|
|
274
321
|
: { totalRequests: history.size(), requests24h: 0, successRequests: 0, errorRequests: 0, successRate: 100, avgLatencyMs: 0 }
|
|
@@ -290,7 +337,7 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
290
337
|
return
|
|
291
338
|
}
|
|
292
339
|
let payload = {}
|
|
293
|
-
try { payload = JSON.parse((await readBody(req, 64 * 1024)).toString('utf8') || '{}') } catch
|
|
340
|
+
try { payload = JSON.parse((await readBody(req, 64 * 1024)).toString('utf8') || '{}') } catch { /* ignore status inspection error */ }
|
|
294
341
|
|
|
295
342
|
let provider = payload.provider
|
|
296
343
|
let index = payload.index || 1
|
|
@@ -339,7 +386,7 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
339
386
|
try {
|
|
340
387
|
const snap = quotaSnapshot(provider, res2.headers, null, Date.now())
|
|
341
388
|
if (snap) { capturedQuota = snap; store.rememberQuota(ref, snap) }
|
|
342
|
-
} catch
|
|
389
|
+
} catch { /* ignore status inspection error */ }
|
|
343
390
|
return res2
|
|
344
391
|
}
|
|
345
392
|
try {
|
|
@@ -397,6 +444,10 @@ export function registerStatusRoutes(ctx, state) {
|
|
|
397
444
|
writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET only' } })
|
|
398
445
|
return
|
|
399
446
|
}
|
|
447
|
+
if (!isTrustedSettingsRequest(req)) {
|
|
448
|
+
writeJson(res, 403, { ok: false, error: { code: 'forbidden', message: 'same-origin only' } })
|
|
449
|
+
return
|
|
450
|
+
}
|
|
400
451
|
const limit = Math.min(Number(queryOf(req).get('limit') || '50'), 100)
|
|
401
452
|
writeJson(res, 200, { ok: true, alerts: getRecentAlerts(limit) })
|
|
402
453
|
}),
|
package/lib/routes.js
CHANGED
package/lib/session-pin.js
CHANGED
|
@@ -41,11 +41,3 @@ export function getPinnedAccountRef(sessionId) {
|
|
|
41
41
|
}
|
|
42
42
|
return entry.accountRef
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
export function unpinSession(sessionId) {
|
|
46
|
-
if (sessionId) sessionPins.delete(sessionId)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function clearSessionPins() {
|
|
50
|
-
sessionPins.clear()
|
|
51
|
-
}
|
package/lib/subscriptions.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { isProvider } from "./refs.js"
|
|
2
2
|
import { pickAccount, markCooldown, isSwitchableError, modelFamily } from "./rotate.js"
|
|
3
3
|
import { quotaSnapshot } from "./ratelimit.js"
|
|
4
|
-
import { getVendor } from "./vendors/index.js"
|
|
5
4
|
import { pickFetch } from "./proxy.js"
|
|
6
5
|
|
|
7
6
|
// ponytail: allowlist per provider — add path to extend without touching request logic
|
|
@@ -20,7 +19,7 @@ export function isAllowed(provider, path) {
|
|
|
20
19
|
p = p.split("?")[0].split("#")[0]
|
|
21
20
|
try {
|
|
22
21
|
if (p.startsWith("http://") || p.startsWith("https://")) p = new URL(p).pathname
|
|
23
|
-
} catch
|
|
22
|
+
} catch { /* ignore subscriptions error */ }
|
|
24
23
|
if (!p.startsWith("/")) p = "/" + p
|
|
25
24
|
for (const allowed of list) {
|
|
26
25
|
const a = allowed.split("?")[0]
|
|
@@ -140,17 +139,17 @@ export function createSubscriptionsService(deps) {
|
|
|
140
139
|
try {
|
|
141
140
|
const snap = quotaSnapshot(provider, res.headers, null, Date.now())
|
|
142
141
|
if (snap && typeof deps.rememberQuota === "function") deps.rememberQuota(account.ref, snap)
|
|
143
|
-
} catch
|
|
142
|
+
} catch { /* ignore subscriptions error */ }
|
|
144
143
|
if (!res.ok && res.clone) {
|
|
145
144
|
try {
|
|
146
145
|
const txt = await res.clone().text()
|
|
147
146
|
let j = null
|
|
148
|
-
try { j = JSON.parse(txt) } catch
|
|
147
|
+
try { j = JSON.parse(txt) } catch { /* ignore subscriptions error */ }
|
|
149
148
|
if (j) {
|
|
150
149
|
const snap2 = quotaSnapshot(provider, res.headers, j, Date.now())
|
|
151
150
|
if (snap2 && typeof deps.rememberQuota === "function") deps.rememberQuota(account.ref, snap2)
|
|
152
151
|
}
|
|
153
|
-
} catch
|
|
152
|
+
} catch { /* ignore subscriptions error */ }
|
|
154
153
|
}
|
|
155
154
|
if (!res.ok) {
|
|
156
155
|
const txt = await res.text().catch(() => "")
|
|
@@ -174,7 +173,7 @@ export function createSubscriptionsService(deps) {
|
|
|
174
173
|
ms: Date.now() - t0,
|
|
175
174
|
kind: "request",
|
|
176
175
|
})
|
|
177
|
-
} catch
|
|
176
|
+
} catch { /* ignore subscriptions error */ }
|
|
178
177
|
}
|
|
179
178
|
return res
|
|
180
179
|
} catch (err) {
|
package/lib/vault.js
CHANGED
|
@@ -50,14 +50,14 @@ export function importVault(encryptedPayload, passphrase) {
|
|
|
50
50
|
let jsonStr
|
|
51
51
|
try {
|
|
52
52
|
jsonStr = decryptWithPassphrase(raw, pass)
|
|
53
|
-
} catch
|
|
53
|
+
} catch {
|
|
54
54
|
throw new Error('failed to decrypt vault: invalid passphrase or corrupted payload')
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
let data
|
|
58
58
|
try {
|
|
59
59
|
data = JSON.parse(jsonStr)
|
|
60
|
-
} catch
|
|
60
|
+
} catch {
|
|
61
61
|
throw new Error('malformed vault content: invalid JSON')
|
|
62
62
|
}
|
|
63
63
|
|
package/lib/vendor-factory.js
CHANGED
|
@@ -12,7 +12,6 @@ import { buildAuthorizeUrl } from "./oauth.js"
|
|
|
12
12
|
import { codexResponsesBody, modelCatalog } from "./messages.js"
|
|
13
13
|
import { formTokenRequest, jsonTokenRequest, codexResponsesStream, readJson, tokenBlobFromOAuth, httpError } from "./wire.js"
|
|
14
14
|
import { emailFromToken } from "./jwt.js"
|
|
15
|
-
import { asUsageSnapshot } from "./usage.js"
|
|
16
15
|
|
|
17
16
|
function defaultModels(models) {
|
|
18
17
|
return modelCatalog("custom", (models || []).map((row) => (typeof row === "string" ? { id: row, name: row } : row)))
|
|
@@ -152,7 +152,7 @@ export async function usage(blob, _cfg, fetchImpl) {
|
|
|
152
152
|
return retrieveQuotaPercent(fetchImpl || fetch, blob.accessToken, headersFor(blob.projectId || ''))
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
export async function* streamOnce({ blob, options, fetchImpl, headers,
|
|
155
|
+
export async function* streamOnce({ blob, options, fetchImpl, headers, signal, saveBlob }) {
|
|
156
156
|
// Abort must cover the project pre-flight as well as the stream.
|
|
157
157
|
const preflight = (u, i) => fetchImpl(u, { ...(i || {}), signal })
|
|
158
158
|
const ready = await withProject(blob, preflight, saveBlob)
|
package/lib/vendors/codex.js
CHANGED
|
@@ -174,7 +174,7 @@ export async function listModels(blob, cfg, fetchImpl) {
|
|
|
174
174
|
}
|
|
175
175
|
if (!rows.length) throw new Error('empty codex catalog')
|
|
176
176
|
rows.sort((a, b) => a.priority - b.priority)
|
|
177
|
-
return modelCatalog(id, rows.map(({
|
|
177
|
+
return modelCatalog(id, rows.map((row) => { const copy = { ...row }; delete copy.priority; return copy }))
|
|
178
178
|
} catch { /* catalog fallback */ }
|
|
179
179
|
return catalog
|
|
180
180
|
}
|
package/lib/vendors/grok.js
CHANGED
|
@@ -220,7 +220,7 @@ export async function usage(blob, cfg, fetchImpl) {
|
|
|
220
220
|
const decoded = decodeGrokCreditsFrame(Buffer.from(buf))
|
|
221
221
|
if (decoded != null) pct = decoded
|
|
222
222
|
}
|
|
223
|
-
} catch
|
|
223
|
+
} catch { /* ignore grok usage capture error */ }
|
|
224
224
|
}
|
|
225
225
|
const snap = asUsageSnapshot(pct)
|
|
226
226
|
if (snap) snap.windows = usageWindows(json)
|
package/lib/vendors/index.js
CHANGED
package/lib/vendors/qwen.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages, openaiTools } from '../messages.js'
|
|
3
|
-
import { openaiChatStream,
|
|
3
|
+
import { openaiChatStream, httpError } from '../wire.js'
|
|
4
4
|
import { asUsageSnapshot } from '../usage.js'
|
|
5
5
|
|
|
6
6
|
export const id = 'qwen'
|
package/lib/vendors/spark.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LlmError } from '@deepseek-ai/dsh-llm'
|
|
2
2
|
import { openaiMessages } from '../messages.js'
|
|
3
|
-
import { openaiChatStream,
|
|
3
|
+
import { openaiChatStream, httpError } from '../wire.js'
|
|
4
4
|
import { asUsageSnapshot } from '../usage.js'
|
|
5
5
|
|
|
6
6
|
export const id = 'spark'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-subscriptions",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.23",
|
|
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",
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"lib/",
|
|
16
16
|
"cordis.patch.yml",
|
|
17
17
|
"README.md",
|
|
18
|
+
"README.ru.md",
|
|
19
|
+
"README.zh.md",
|
|
18
20
|
"LICENSE"
|
|
19
21
|
],
|
|
20
22
|
"keywords": [
|