@goodandready/dsh-subscriptions 0.6.88 → 0.6.90

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/client.js CHANGED
@@ -726,6 +726,27 @@ window.__ModuleLoader__.load({
726
726
  return label ? h('span', { className: 'dsub-planBadge' }, label) : null
727
727
  }
728
728
 
729
+ function pad2(n) {
730
+ return String(n).padStart(2, '0')
731
+ }
732
+
733
+ function formatMmSs(totalSeconds) {
734
+ const total = Math.max(0, Math.ceil(Number(totalSeconds) || 0))
735
+ return pad2(Math.floor(total / 60)) + ':' + pad2(total % 60)
736
+ }
737
+
738
+ function barTone(pct, normalColor = 'var(--dsw-alias-state-success-primary)') {
739
+ const p = Number(pct) || 0
740
+ if (p >= 90) return { cls: 'dsub-barFull', tag: 'dsub-tag-bad', color: 'var(--dsw-alias-state-error-primary)' }
741
+ if (p >= 70) return { cls: 'dsub-barWarn', tag: 'dsub-tag-warn', color: 'var(--dsw-alias-state-warn-primary)' }
742
+ return { cls: '', tag: 'dsub-tag-ok', color: normalColor }
743
+ }
744
+
745
+ function ledClass(pct) {
746
+ const p = Number(pct) || 0
747
+ return p >= 90 ? 'dsub-ledBad' : (p >= 70 ? 'dsub-ledWarn' : 'dsub-ledOk')
748
+ }
749
+
729
750
  function formatRelativeReset(resetAt, lang, now) {
730
751
  if (!resetAt || !Number.isFinite(resetAt) || resetAt <= 0) return ''
731
752
  var delta = resetAt - (now || Date.now())
@@ -752,17 +773,14 @@ window.__ModuleLoader__.load({
752
773
  if (ms <= 0) return null
753
774
  const total = Math.floor(ms / 1000)
754
775
  const d = new Date(props.resetAt)
755
- const pad = (n) => String(n).padStart(2, '0')
756
- const timeStr = pad(d.getHours()) + ':' + pad(d.getMinutes())
776
+ const timeStr = pad2(d.getHours()) + ':' + pad2(d.getMinutes())
757
777
  const relStr = formatRelativeReset(props.resetAt, t('lang'), now)
758
778
  if (total > 3600) {
759
779
  return h('span', { className: 'dsub-sub', style: { fontVariantNumeric: 'tabular-nums' } },
760
780
  '⏳ ' + t('windowResetsAt') + ' ' + timeStr + ' (' + relStr + ')')
761
781
  }
762
- const m = Math.floor(total / 60)
763
- const sec = total % 60
764
782
  return h('span', { className: 'dsub-sub', style: { fontVariantNumeric: 'tabular-nums' } },
765
- '⏳ ' + t('windowResetsAt') + ' ' + timeStr + ' (' + relStr + ' · ' + pad(m) + ':' + pad(sec) + ')')
783
+ '⏳ ' + t('windowResetsAt') + ' ' + timeStr + ' (' + relStr + ' · ' + formatMmSs(total) + ')')
766
784
  }
767
785
 
768
786
  function badgeFor(account, t) {
@@ -776,10 +794,7 @@ window.__ModuleLoader__.load({
776
794
  }
777
795
  if (account.cooldownUntil && account.cooldownUntil > Date.now()) {
778
796
  const leftSec = Math.max(0, Math.ceil((account.cooldownUntil - Date.now()) / 1000))
779
- const m = Math.floor(leftSec / 60)
780
- const s = leftSec % 60
781
- const pad = (n) => String(n).padStart(2, "0")
782
- return t("coolingDown") + " (" + pad(m) + ":" + pad(s) + ")"
797
+ return t("coolingDown") + " (" + formatMmSs(leftSec) + ")"
783
798
  }
784
799
  if (account.usagePercent != null && account.usagePercent >= 100) return t('usageFull')
785
800
  return t('connected')
@@ -2767,8 +2782,9 @@ window.__ModuleLoader__.load({
2767
2782
 
2768
2783
  function renderItem(label, pct, detail){
2769
2784
  var p = Math.min(100, Math.max(0, Math.round(pct)))
2770
- var tagCls = p >= 90 ? 'dsub-tag-bad' : (p >= 70 ? 'dsub-tag-warn' : 'dsub-tag-ok')
2771
- var fillBg = p >= 90 ? 'var(--dsw-alias-state-error-primary)' : (p >= 70 ? 'var(--dsw-alias-state-warn-primary)' : 'var(--dsw-alias-state-success-primary)')
2785
+ var tone = barTone(p)
2786
+ var tagCls = tone.tag
2787
+ var fillBg = tone.color
2772
2788
  return h('div', { key: label, className: 'dsub-usage-card' },
2773
2789
  h('div', { className: 'dsub-usage-head' },
2774
2790
  h('span', null, label),
@@ -3173,108 +3189,6 @@ window.__ModuleLoader__.load({
3173
3189
  return { label: (p.charAt(0).toUpperCase() || 'P'), cls: 'dsub-brandCodex', icon: '●' }
3174
3190
  }
3175
3191
 
3176
- const PLUGIN_LABELS = new Set(['plugins', '插件', 'plugin'])
3177
-
3178
- function resolvePluginLabels(customCtx) {
3179
- const labels = new Set(PLUGIN_LABELS)
3180
- const loc = (customCtx && customCtx.locale) || (typeof window !== 'undefined' && window.__dshCtx && window.__dshCtx.locale)
3181
- if (loc && typeof loc.bind === 'function') {
3182
- try {
3183
- const sp = loc.bind('settings.plugins')
3184
- const nav = typeof sp === 'function' ? sp('nav') : null
3185
- if (nav && typeof nav === 'string') labels.add(nav.trim().toLowerCase())
3186
- } catch { /* bestEffort */ }
3187
- try {
3188
- const pm = loc.bind('pluginManager')
3189
- const panel = typeof pm === 'function' ? (pm('panel') || pm('title')) : null
3190
- if (panel && typeof panel === 'string') labels.add(panel.trim().toLowerCase())
3191
- } catch { /* bestEffort */ }
3192
- }
3193
- return labels
3194
- }
3195
-
3196
- function matchesPluginLabel(el, customLabels) {
3197
- if (!el) return false
3198
- const dataTab = (el.getAttribute('data-tab') || '').trim().toLowerCase()
3199
- const dataSection = (el.getAttribute('data-section') || '').trim().toLowerCase()
3200
- const dataKey = (el.getAttribute('data-key') || '').trim().toLowerCase()
3201
- const id = (el.getAttribute('id') || '').trim().toLowerCase()
3202
- if (dataTab === 'plugins' || dataSection === 'plugins' || dataKey === 'plugins' || id === 'plugins') return true
3203
-
3204
- if (el.querySelector && el.querySelector('path[d*="M10.3232"]')) return true
3205
-
3206
- const txt = (el.textContent || '').trim().toLowerCase()
3207
- const aria = (el.getAttribute('aria-label') || '').trim().toLowerCase()
3208
- const title = (el.getAttribute('title') || '').trim().toLowerCase()
3209
- const labels = customLabels || PLUGIN_LABELS
3210
- return labels.has(txt) || labels.has(aria) || labels.has(title) || labels.has(dataTab)
3211
- }
3212
-
3213
- function findAndClickCard(doc) {
3214
- for (const key of [PKG, 'dsh-subscriptions', '@goodandready/dsh-subscriptions']) {
3215
- const card = doc.querySelector(`[data-plugin-package="${key}"]`) || doc.querySelector(`[data-plugin-item="${ROW_ID}"]`)
3216
- if (card) {
3217
- const open = [...card.querySelectorAll('button')].filter((b) => b.getAttribute('role') !== 'switch')
3218
- const target = open.length >= 1 ? open[0] : card
3219
- if (typeof target.click === 'function') {
3220
- target.click()
3221
- return true
3222
- }
3223
- }
3224
- }
3225
- return false
3226
- }
3227
-
3228
- let pluginSettingsGeneration = 0
3229
- function openPluginSettings(doc = document, schedule = (run, ms) => window.setTimeout(run, ms), navCtx) {
3230
- try {
3231
- if (findAndClickCard(doc)) return
3232
- const generation = ++pluginSettingsGeneration
3233
- const runIfCurrent = (fn, ms) => schedule(() => {
3234
- if (generation !== pluginSettingsGeneration) return
3235
- fn()
3236
- }, ms)
3237
-
3238
- const activeLabels = resolvePluginLabels(navCtx)
3239
- const checkEl = (el) => matchesPluginLabel(el, activeLabels)
3240
-
3241
- const buttons = [...doc.querySelectorAll('button, a, div[role="button"], div[role="tab"]')]
3242
- const panel = buttons.find(checkEl)
3243
- if (panel) {
3244
- panel.click()
3245
- const poll = (left) => {
3246
- if (findAndClickCard(doc)) return
3247
- if (left > 0) runIfCurrent(() => poll(left - 1), 100)
3248
- }
3249
- runIfCurrent(() => poll(40), 100)
3250
- return
3251
- }
3252
-
3253
- const triggers = buttons.filter((b) => b.getAttribute('aria-haspopup') === 'dialog' && b.hasAttribute('aria-expanded'))
3254
- if (triggers.length > 0) {
3255
- const trigger = triggers.find((b) => b.getAttribute('aria-expanded') !== 'true') || triggers[0]
3256
- if (trigger && typeof trigger.click === 'function') {
3257
- trigger.click()
3258
- const pollSection = (left) => {
3259
- try {
3260
- const section = [...doc.querySelectorAll('button, a, div[role="tab"], [role="button"]')].find(checkEl)
3261
- if (section && typeof section.click === 'function') {
3262
- section.click()
3263
- const poll = (cLeft) => {
3264
- if (findAndClickCard(doc)) return
3265
- if (cLeft > 0) runIfCurrent(() => poll(cLeft - 1), 100)
3266
- }
3267
- runIfCurrent(() => poll(40), 100)
3268
- return
3269
- }
3270
- } catch { /* bestEffort */ }
3271
- if (left > 0) runIfCurrent(() => pollSection(left - 1), 80)
3272
- }
3273
- runIfCurrent(() => pollSection(20), 80)
3274
- }
3275
- }
3276
- } catch { /* bestEffort */ }
3277
- }
3278
3192
  function SubsPill(props) {
3279
3193
  const t = (props && props.t) || ((k) => k)
3280
3194
  const [state, setState] = React.useState({ logged: [], usage: 0, accounts: [], open: false, active: null, loading: false })
@@ -3349,7 +3263,7 @@ window.__ModuleLoader__.load({
3349
3263
 
3350
3264
  const n = state.logged.length
3351
3265
  const total = state.accounts.length || n
3352
- const led = n === 0 ? 'dsub-ledOff' : (state.usage >= 90 ? 'dsub-ledBad' : (state.usage >= 50 ? 'dsub-ledWarn' : 'dsub-ledOk'))
3266
+ const led = n === 0 ? 'dsub-ledOff' : ledClass(state.usage)
3353
3267
  const now = Date.now()
3354
3268
 
3355
3269
  // Header Pill Label
@@ -3399,7 +3313,7 @@ window.__ModuleLoader__.load({
3399
3313
  className: 'dsub-barFillGrad',
3400
3314
  style: {
3401
3315
  width: Math.min(100, Math.max(0, primPct)) + '%',
3402
- background: primPct >= 90 ? 'var(--dsw-alias-state-error-primary)' : (primPct >= 50 ? 'var(--dsw-alias-state-warn-primary)' : 'var(--dsw-alias-state-success-primary)'),
3316
+ background: barTone(primPct).color,
3403
3317
  },
3404
3318
  }),
3405
3319
  ),
@@ -3414,7 +3328,7 @@ window.__ModuleLoader__.load({
3414
3328
  className: 'dsub-barFillGrad',
3415
3329
  style: {
3416
3330
  width: Math.min(100, Math.max(0, secPct)) + '%',
3417
- background: secPct >= 90 ? 'var(--dsw-alias-state-error-primary)' : (secPct >= 50 ? 'var(--dsw-alias-state-warn-primary)' : 'var(--dsw-alias-brand-primary)'),
3331
+ background: barTone(secPct, 'var(--dsw-alias-brand-primary)').color,
3418
3332
  },
3419
3333
  }),
3420
3334
  ),
@@ -3458,11 +3372,8 @@ window.__ModuleLoader__.load({
3458
3372
  } else if (cooled) {
3459
3373
  statusClass = 'dsub-statusWarn'
3460
3374
  const leftSec = Math.max(0, Math.ceil((a.cooldownUntil - now) / 1000))
3461
- const m = Math.floor(leftSec / 60)
3462
- const s = leftSec % 60
3463
- const pad = (n) => String(n).padStart(2, '0')
3464
3375
  const fams = Array.isArray(a.cooldownFamilies) && a.cooldownFamilies.length ? ' · ' + a.cooldownFamilies.join('/') : ''
3465
- statusText = t('subsCooldown') + ' (' + pad(m) + ':' + pad(s) + ')' + fams
3376
+ statusText = t('subsCooldown') + ' (' + formatMmSs(leftSec) + ')' + fams
3466
3377
  } else if (isLogged) {
3467
3378
  if (pct >= 90) { statusClass = 'dsub-statusBad'; statusText = '90%+ ' + t('subsUsed') }
3468
3379
  else if (pct >= 50) { statusClass = 'dsub-statusWarn'; statusText = pct + '% ' + t('subsUsed') }
@@ -3485,7 +3396,7 @@ window.__ModuleLoader__.load({
3485
3396
  className: 'dsub-barFillGrad',
3486
3397
  style: {
3487
3398
  width: Math.min(100, Math.max(0, pct)) + '%',
3488
- background: pct >= 90 ? 'var(--dsw-alias-state-error-primary)' : (pct >= 50 ? 'var(--dsw-alias-state-warn-primary)' : 'var(--dsw-alias-state-success-primary)'),
3399
+ background: barTone(pct).color,
3489
3400
  },
3490
3401
  }),
3491
3402
  ) : null,
@@ -3570,8 +3481,6 @@ window.__ModuleLoader__.load({
3570
3481
  layout.selectPanel('plugins')
3571
3482
  }
3572
3483
  } catch { /* bestEffort */ }
3573
-
3574
- openPluginSettings(document, undefined, clientCtx)
3575
3484
  },
3576
3485
  }, t('subsOpenSettings')),
3577
3486
  ),
package/lib/http.js CHANGED
@@ -366,64 +366,6 @@ export async function fetchWithTimeout(fetchImpl, url, init = {}, { timeoutMs =
366
366
  return res
367
367
  }
368
368
  if (typeof timer?.unref === 'function') timer.unref()
369
- const origJson = typeof res.json === 'function' ? res.json.bind(res) : null
370
- const origText = typeof res.text === 'function' ? res.text.bind(res) : null
371
- if (origJson) {
372
- res.json = () => {
373
- if (typeof timer?.ref === 'function') timer.ref()
374
- if (controller.signal.aborted) {
375
- return Promise.reject(new DOMException('The operation was aborted due to timeout', 'TimeoutError'))
376
- }
377
- return new Promise((resolve, reject) => {
378
- const onAbort = () => reject(new DOMException('The operation was aborted due to timeout', 'TimeoutError'))
379
- controller.signal.addEventListener('abort', onAbort, { once: true })
380
- origJson().then(
381
- (val) => {
382
- controller.signal.removeEventListener('abort', onAbort)
383
- clearTimeout(timer)
384
- resolve(val)
385
- },
386
- (err) => {
387
- controller.signal.removeEventListener('abort', onAbort)
388
- clearTimeout(timer)
389
- if (controller.signal.aborted) {
390
- reject(new DOMException('The operation was aborted due to timeout', 'TimeoutError'))
391
- } else {
392
- reject(err)
393
- }
394
- }
395
- )
396
- })
397
- }
398
- }
399
- if (origText) {
400
- res.text = () => {
401
- if (typeof timer?.ref === 'function') timer.ref()
402
- if (controller.signal.aborted) {
403
- return Promise.reject(new DOMException('The operation was aborted due to timeout', 'TimeoutError'))
404
- }
405
- return new Promise((resolve, reject) => {
406
- const onAbort = () => reject(new DOMException('The operation was aborted due to timeout', 'TimeoutError'))
407
- controller.signal.addEventListener('abort', onAbort, { once: true })
408
- origText().then(
409
- (val) => {
410
- controller.signal.removeEventListener('abort', onAbort)
411
- clearTimeout(timer)
412
- resolve(val)
413
- },
414
- (err) => {
415
- controller.signal.removeEventListener('abort', onAbort)
416
- clearTimeout(timer)
417
- if (controller.signal.aborted) {
418
- reject(new DOMException('The operation was aborted due to timeout', 'TimeoutError'))
419
- } else {
420
- reject(err)
421
- }
422
- }
423
- )
424
- })
425
- }
426
- }
427
369
  return res
428
370
  } catch (err) {
429
371
  clearTimeout(timer)
@@ -0,0 +1,64 @@
1
+ export const BUILTIN_PROVIDERS = Object.freeze([
2
+ 'codex',
3
+ 'claude',
4
+ 'grok',
5
+ 'antigravity',
6
+ 'kimi',
7
+ 'glm',
8
+ 'cursor',
9
+ 'kiro',
10
+ 'copilot',
11
+ 'qwen',
12
+ 'ernie',
13
+ 'spark',
14
+ 'jetbrains',
15
+ 'perplexity',
16
+ 'replit',
17
+ 'cody',
18
+ ])
19
+
20
+ const DISPLAY = {
21
+ codex: 'ChatGPT Codex',
22
+ claude: 'Claude',
23
+ grok: 'Grok',
24
+ antigravity: 'Antigravity',
25
+ kimi: 'Moonshot Kimi',
26
+ glm: 'Zhipu GLM',
27
+ cursor: 'Cursor',
28
+ kiro: 'AWS Kiro',
29
+ copilot: 'GitHub Copilot',
30
+ perplexity: 'Perplexity Pro',
31
+ jetbrains: 'JetBrains AI',
32
+ }
33
+
34
+ const dynamicIds = new Set()
35
+ const displayExtra = {}
36
+
37
+ export let PROVIDERS = [...BUILTIN_PROVIDERS]
38
+
39
+ export function registerCustomProviderIds(ids) {
40
+ let changed = false
41
+ for (const id of ids || []) {
42
+ if (typeof id === 'string' && /^[a-z][a-z0-9_]*$/.test(id) && !dynamicIds.has(id)) {
43
+ dynamicIds.add(id)
44
+ changed = true
45
+ }
46
+ }
47
+ if (changed) PROVIDERS = listProviders()
48
+ }
49
+
50
+ export function listProviders() {
51
+ return [...BUILTIN_PROVIDERS, ...dynamicIds]
52
+ }
53
+
54
+ export function registerDisplayName(id, name) {
55
+ if (id && name) displayExtra[id] = name
56
+ }
57
+
58
+ export function isProvider(value) {
59
+ return BUILTIN_PROVIDERS.includes(value) || dynamicIds.has(value)
60
+ }
61
+
62
+ export function displayName(provider) {
63
+ return DISPLAY[provider] || displayExtra[provider] || provider
64
+ }
package/lib/refs.js CHANGED
@@ -1,68 +1,12 @@
1
- // Built-in providers + dynamic ones from Config.customVendors.
2
- export const BUILTIN_PROVIDERS = Object.freeze([
3
- 'codex',
4
- 'claude',
5
- 'grok',
6
- 'antigravity',
7
- 'kimi',
8
- 'glm',
9
- 'cursor',
10
- 'kiro',
11
- 'copilot',
12
- 'qwen',
13
- 'ernie',
14
- 'spark',
15
- 'jetbrains',
16
- 'perplexity',
17
- 'replit',
18
- 'cody',
19
- ])
20
-
21
- const dynamicIds = new Set()
22
- const displayExtra = {}
23
-
24
- export let PROVIDERS = [...BUILTIN_PROVIDERS]
25
-
26
- export function registerCustomProviderIds(ids) {
27
- let changed = false
28
- for (const id of ids || []) {
29
- if (typeof id === 'string' && /^[a-z][a-z0-9_]*$/.test(id) && !dynamicIds.has(id)) {
30
- dynamicIds.add(id)
31
- changed = true
32
- }
33
- }
34
- if (changed) PROVIDERS = listProviders()
35
- }
36
-
37
- export function listProviders() {
38
- return [...BUILTIN_PROVIDERS, ...dynamicIds]
39
- }
40
-
41
- export function registerDisplayName(id, name) {
42
- if (id && name) displayExtra[id] = name
43
- }
44
-
45
- export function isProvider(value) {
46
- return BUILTIN_PROVIDERS.includes(value) || dynamicIds.has(value)
47
- }
48
-
49
- const DISPLAY = {
50
- codex: 'ChatGPT Codex',
51
- claude: 'Claude',
52
- grok: 'Grok',
53
- antigravity: 'Antigravity',
54
- kimi: 'Moonshot Kimi',
55
- glm: 'Zhipu GLM',
56
- cursor: 'Cursor',
57
- kiro: 'AWS Kiro',
58
- copilot: 'GitHub Copilot',
59
- perplexity: 'Perplexity Pro',
60
- jetbrains: 'JetBrains AI',
61
- }
62
-
63
- export function displayName(provider) {
64
- return DISPLAY[provider] || displayExtra[provider] || provider
65
- }
1
+ export {
2
+ BUILTIN_PROVIDERS,
3
+ PROVIDERS,
4
+ registerCustomProviderIds,
5
+ listProviders,
6
+ registerDisplayName,
7
+ displayName,
8
+ isProvider,
9
+ } from './providers.js'
66
10
 
67
11
  /**
68
12
  * @param {string} provider
@@ -224,6 +224,12 @@ export function registerOauthRoutes(ctx, state) {
224
224
  writeJson(res, 405, { ok: false, error: { code: 'method', message: 'GET only' } })
225
225
  return
226
226
  }
227
+ const secFetchMode = String((req.headers && req.headers['sec-fetch-mode']) || '').toLowerCase()
228
+ const isNavigation = secFetchMode === 'navigate'
229
+ if (!isNavigation && !isTrustedSettingsRequest(req, ctx)) {
230
+ writeHtml(res, 403, '<!doctype html><meta charset="utf-8"><title>Subscriptions</title><p>Forbidden: untrusted OAuth callback request.</p>')
231
+ return
232
+ }
227
233
  const q = queryOf(req)
228
234
  const code = q.get('code') || ''
229
235
  const state = q.get('state') || ''
@@ -262,26 +262,7 @@ export async function usage(blob, cfg, fetchImpl) {
262
262
  headers: { ...identityHeaders(blob, cfg), Accept: 'application/json' },
263
263
  })
264
264
  const json = await readJson(res)
265
- let pct = grokBillingPercent(json)
266
- if (pct == null) {
267
- // Fallback to gRPC-web GetGrokCreditsConfig
268
- try {
269
- const gRes = await impl('https://grok.com/rest/app-chat/get-grok-credits-config', {
270
- method: 'POST',
271
- headers: {
272
- ...identityHeaders(blob, cfg),
273
- 'Content-Type': 'application/grpc-web+proto',
274
- 'X-User-Agent': 'grpc-web-javascript/0.1',
275
- },
276
- body: Buffer.from([0, 0, 0, 0, 0]),
277
- })
278
- if (gRes.ok) {
279
- const buf = await gRes.arrayBuffer()
280
- const decoded = decodeGrokCreditsFrame(Buffer.from(buf))
281
- if (decoded != null) pct = decoded
282
- }
283
- } catch { /* ignore grok usage capture error */ }
284
- }
265
+ const pct = grokBillingPercent(json)
285
266
  const snap = asUsageSnapshot(pct)
286
267
  if (snap) snap.windows = usageWindows(json)
287
268
  return snap
@@ -394,81 +375,3 @@ export async function* streamOnce({ blob, options, fetchImpl, headers, config, s
394
375
  if (!res.ok) throw httpError(res.status, await readErrorBody(res))
395
376
  yield* codexResponsesStream(res.body)
396
377
  }
397
-
398
- function readVarint(bytes, offset) {
399
- let value = 0, shift = 0, index = offset
400
- while (index < bytes.length) {
401
- const byte = bytes[index]
402
- index += 1
403
- value += (byte & 0x7f) * (2 ** shift)
404
- if ((byte & 0x80) === 0) return { value, next: index }
405
- shift += 7
406
- if (shift > 63) return undefined
407
- }
408
- return undefined
409
- }
410
- function readLength(bytes, offset, size) {
411
- if (offset + size > bytes.length) return undefined
412
- return { bytes: bytes.subarray(offset, offset + size), next: offset + size }
413
- }
414
- function decodeFields(bytes) {
415
- const fields = new Map()
416
- let offset = 0
417
- while (offset < bytes.length) {
418
- const tag = readVarint(bytes, offset)
419
- if (!tag) break
420
- const fieldNumber = Math.floor(tag.value / 8)
421
- const wireType = tag.value % 8
422
- offset = tag.next
423
- if (fieldNumber <= 0) return undefined
424
- let value
425
- if (wireType === 0) {
426
- const next = readVarint(bytes, offset)
427
- if (!next) return undefined
428
- value = { wireType, value: next.value }
429
- offset = next.next
430
- } else if (wireType === 5) {
431
- const next = readLength(bytes, offset, 4)
432
- if (!next) return undefined
433
- value = { wireType, bytes: next.bytes }
434
- offset = next.next
435
- } else if (wireType === 1) {
436
- const next = readLength(bytes, offset, 8)
437
- if (!next) return undefined
438
- value = { wireType, bytes: next.bytes }
439
- offset = next.next
440
- } else if (wireType === 2) {
441
- const length = readVarint(bytes, offset)
442
- if (!length) return undefined
443
- const next = readLength(bytes, length.next, length.value)
444
- if (!next) return undefined
445
- value = { wireType, bytes: next.bytes }
446
- offset = next.next
447
- } else return undefined
448
- if (!fields.has(fieldNumber)) fields.set(fieldNumber, value)
449
- }
450
- return fields
451
- }
452
- function float32Le(field) {
453
- if (!field || field.wireType !== 5 || !field.bytes || field.bytes.length < 4) return undefined
454
- const val = Buffer.from(field.bytes).readFloatLE(0)
455
- return Number.isFinite(val) ? val : undefined
456
- }
457
- export function decodeGrokCreditsFrame(buffer) {
458
- try {
459
- const bytes = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer)
460
- if (!bytes.length) return undefined
461
- const payload = bytes.length > 5 && bytes[0] === 0 ? bytes.subarray(5) : bytes
462
- const top = decodeFields(payload)
463
- if (!top) return undefined
464
- const nested = top.get(1)?.wireType === 2 ? decodeFields(top.get(1).bytes) : undefined
465
- const credits = nested ?? top
466
- if (!credits) return undefined
467
- const ratio = float32Le(credits.get(1))
468
- if (ratio == null) return undefined
469
- const pct = ratio <= 1 ? Math.round(ratio * 100) : Math.round(ratio)
470
- return Math.max(0, Math.min(100, pct))
471
- } catch {
472
- return undefined
473
- }
474
- }
@@ -14,8 +14,9 @@ import * as grok from './grok.js'
14
14
  import * as antigravity from './antigravity.js'
15
15
  import * as kimi from './kimi.js'
16
16
  import * as glm from './glm.js'
17
+ import { BUILTIN_PROVIDERS, isProvider as isRegisteredProvider, registerCustomProviderIds } from '../providers.js'
17
18
 
18
- const builtins = {
19
+ const BUILTIN_MODULES = {
19
20
  codex,
20
21
  claude,
21
22
  grok,
@@ -31,14 +32,17 @@ const builtins = {
31
32
  jetbrains,
32
33
  perplexity,
33
34
  replit,
34
- cody
35
+ cody,
35
36
  }
36
37
 
38
+ const builtins = Object.fromEntries(BUILTIN_PROVIDERS.map((id) => [id, BUILTIN_MODULES[id]]))
39
+
37
40
  const customVendors = new Map()
38
41
 
39
42
  export function registerCustomVendor(vendor) {
40
43
  if (!vendor || !vendor.id) throw new Error('custom vendor needs id')
41
44
  customVendors.set(vendor.id, vendor)
45
+ registerCustomProviderIds([vendor.id])
42
46
  }
43
47
 
44
48
  export function clearCustomVendors() {
@@ -62,7 +66,7 @@ const vendors = new Proxy({}, {
62
66
  })
63
67
 
64
68
  export function isProvider(value) {
65
- return Boolean(vendors[value])
69
+ return isRegisteredProvider(value) && Boolean(vendors[value])
66
70
  }
67
71
 
68
72
  export function getVendor(provider) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-subscriptions",
3
- "version": "0.6.88",
3
+ "version": "0.6.90",
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",