@jxgame2020/dsh-token-quota 0.1.11 → 0.1.13
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 +343 -89
- package/lib/index.js +62 -3
- package/lib/types/client/TokenQuotaPanel.d.ts +3 -1
- package/lib/types/client/TokenQuotaPanel.js +36 -2
- package/lib/types/client/index.js +36 -1
- package/lib/types/client/locales.d.ts +24 -0
- package/lib/types/client/locales.js +24 -0
- package/lib/types/client/store.d.ts +24 -0
- package/lib/types/client/store.js +16 -0
- package/lib/types/index.d.ts +10 -0
- package/lib/types/index.js +69 -3
- package/lib/types/types.d.ts +2 -0
- package/package.json +1 -1
package/lib/types/index.js
CHANGED
|
@@ -225,6 +225,8 @@ export class TokenQuotaService extends Service {
|
|
|
225
225
|
checkUpdates = true;
|
|
226
226
|
/** Cached upgrade availability; recomputed by {@link refreshUpgrade}. */
|
|
227
227
|
upgrade = null;
|
|
228
|
+
/** Error message from the most recent update check; null = no error. */
|
|
229
|
+
upgradeError = null;
|
|
228
230
|
/** Timer for the periodic update check. */
|
|
229
231
|
updateTimer;
|
|
230
232
|
/** In-flight update check, to coalesce the periodic and manual triggers. */
|
|
@@ -243,6 +245,8 @@ export class TokenQuotaService extends Service {
|
|
|
243
245
|
disposeRouteLog;
|
|
244
246
|
/** Disposer for the optional manual-check route (`POST /token-quota/check-updates`). */
|
|
245
247
|
disposeRouteCheck;
|
|
248
|
+
/** Disposer for the optional clear-log route (`POST /token-quota/clear-log`). */
|
|
249
|
+
disposeRouteClear;
|
|
246
250
|
/** Disposer for the webServer-arrival watcher when the service mounts later. */
|
|
247
251
|
disposeRouteWatcher;
|
|
248
252
|
/**
|
|
@@ -376,6 +380,37 @@ export class TokenQuotaService extends Service {
|
|
|
376
380
|
});
|
|
377
381
|
},
|
|
378
382
|
});
|
|
383
|
+
this.disposeRouteClear = server.register({
|
|
384
|
+
kind: 'exact',
|
|
385
|
+
path: '/token-quota/clear-log',
|
|
386
|
+
handler: (req, res) => {
|
|
387
|
+
if (req.method !== 'POST') {
|
|
388
|
+
res.writeHead(405);
|
|
389
|
+
res.end();
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const chunks = [];
|
|
393
|
+
req.on('data', (chunk) => { chunks.push(Buffer.from(chunk)); });
|
|
394
|
+
req.on('end', () => {
|
|
395
|
+
let before = '';
|
|
396
|
+
try {
|
|
397
|
+
const raw = Buffer.concat(chunks).toString('utf8');
|
|
398
|
+
if (raw.length > 0) {
|
|
399
|
+
const payload = JSON.parse(raw);
|
|
400
|
+
before = typeof payload.before === 'string' ? payload.before : '';
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
res.writeHead(400, { 'content-type': 'application/json' });
|
|
405
|
+
res.end(JSON.stringify({ error: 'bad payload' }));
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const updated = this.clearLogBefore(before);
|
|
409
|
+
res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-store' });
|
|
410
|
+
res.end(JSON.stringify(updated));
|
|
411
|
+
});
|
|
412
|
+
},
|
|
413
|
+
});
|
|
379
414
|
}
|
|
380
415
|
/** Query the npm registry and rebuild the cached upgrade info (coalesced). */
|
|
381
416
|
refreshUpgrade() {
|
|
@@ -394,6 +429,7 @@ export class TokenQuotaService extends Service {
|
|
|
394
429
|
const current = __TOKEN_QUOTA_VERSION__;
|
|
395
430
|
if (current === undefined || current === '') {
|
|
396
431
|
this.upgrade = null;
|
|
432
|
+
this.upgradeError = null;
|
|
397
433
|
return;
|
|
398
434
|
}
|
|
399
435
|
let latest;
|
|
@@ -404,18 +440,26 @@ export class TokenQuotaService extends Service {
|
|
|
404
440
|
});
|
|
405
441
|
if (!response.ok) {
|
|
406
442
|
this.upgrade = null;
|
|
443
|
+
this.upgradeError = `registry responded ${response.status} ${response.statusText}`;
|
|
407
444
|
return;
|
|
408
445
|
}
|
|
409
446
|
const manifest = await response.json();
|
|
410
447
|
latest = typeof manifest.version === 'string' ? manifest.version : undefined;
|
|
411
448
|
}
|
|
412
|
-
catch {
|
|
413
|
-
// Offline / registry failure: keep showing nothing rather than erroring.
|
|
449
|
+
catch (err) {
|
|
414
450
|
this.upgrade = null;
|
|
451
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
452
|
+
// Common Node fetch error shapes include the URL; surface a short reason.
|
|
453
|
+
this.upgradeError = msg.includes('fetch failed')
|
|
454
|
+
? '无法访问 npm registry(网络超时或被墙)'
|
|
455
|
+
: msg.includes('aborted')
|
|
456
|
+
? '请求超时(10s)'
|
|
457
|
+
: msg;
|
|
415
458
|
return;
|
|
416
459
|
}
|
|
417
460
|
if (latest === undefined || !isNewer(latest, current)) {
|
|
418
461
|
this.upgrade = null;
|
|
462
|
+
this.upgradeError = null;
|
|
419
463
|
return;
|
|
420
464
|
}
|
|
421
465
|
const profile = findProfile();
|
|
@@ -429,6 +473,7 @@ export class TokenQuotaService extends Service {
|
|
|
429
473
|
commands,
|
|
430
474
|
installKind: profile?.installKind ?? 'registry',
|
|
431
475
|
};
|
|
476
|
+
this.upgradeError = null;
|
|
432
477
|
}
|
|
433
478
|
/** Start or stop the periodic update check to match the current setting. */
|
|
434
479
|
syncUpdateChecking() {
|
|
@@ -470,6 +515,25 @@ export class TokenQuotaService extends Service {
|
|
|
470
515
|
entries.sort((left, right) => right.day.localeCompare(left.day) || left.key.localeCompare(right.key));
|
|
471
516
|
return { entries };
|
|
472
517
|
}
|
|
518
|
+
/**
|
|
519
|
+
* Remove all historical cycles whose day portion strictly precedes `before`
|
|
520
|
+
* (format `YYYY-MM-DD`). The current cycle is never cleared. Returns the
|
|
521
|
+
* trimmed log so the client can refresh immediately.
|
|
522
|
+
*/
|
|
523
|
+
clearLogBefore(before) {
|
|
524
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(before))
|
|
525
|
+
return this.readLog();
|
|
526
|
+
const kept = {};
|
|
527
|
+
for (const [cycle, usageByKey] of Object.entries(this.history)) {
|
|
528
|
+
const dayPart = cycle.slice(0, 10);
|
|
529
|
+
if (dayPart >= before) {
|
|
530
|
+
kept[cycle] = usageByKey;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
this.history = kept;
|
|
534
|
+
this.scheduleWrite();
|
|
535
|
+
return this.readLog();
|
|
536
|
+
}
|
|
473
537
|
/** Read the current snapshot (also used by tests and inspection). */
|
|
474
538
|
readSnapshot() {
|
|
475
539
|
this.rollCycleIfNeeded();
|
|
@@ -488,7 +552,7 @@ export class TokenQuotaService extends Service {
|
|
|
488
552
|
});
|
|
489
553
|
}
|
|
490
554
|
entries.sort((left, right) => left.key.localeCompare(right.key));
|
|
491
|
-
return { day: this.cycle, entries, upgrade: this.upgrade };
|
|
555
|
+
return { day: this.cycle, entries, upgrade: this.upgrade, upgradeError: this.upgradeError };
|
|
492
556
|
}
|
|
493
557
|
/** Today's used tokens for one model key, or `0`. */
|
|
494
558
|
usedToday(key) {
|
|
@@ -728,6 +792,8 @@ export class TokenQuotaService extends Service {
|
|
|
728
792
|
this.disposeRouteLog();
|
|
729
793
|
if (this.disposeRouteCheck !== undefined)
|
|
730
794
|
this.disposeRouteCheck();
|
|
795
|
+
if (this.disposeRouteClear !== undefined)
|
|
796
|
+
this.disposeRouteClear();
|
|
731
797
|
this.flush();
|
|
732
798
|
}
|
|
733
799
|
safeSplit(key) {
|
package/lib/types/types.d.ts
CHANGED
|
@@ -125,6 +125,8 @@ export interface TokenQuotaSnapshot {
|
|
|
125
125
|
entries: TokenQuotaEntry[];
|
|
126
126
|
/** Upgrade availability; `null` when no newer version is known. */
|
|
127
127
|
upgrade: TokenQuotaUpgrade | null;
|
|
128
|
+
/** Error from the most recent update check; `null` = no error (or never checked). */
|
|
129
|
+
upgradeError: string | null;
|
|
128
130
|
}
|
|
129
131
|
/** One historical daily usage record, shown in the log dialog. */
|
|
130
132
|
export interface TokenQuotaLogEntry {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxgame2020/dsh-token-quota",
|
|
3
3
|
"description": "Daily per-model token quota accounting, enforcement, and a floating quota panel for the DeepSeek Harness — a fully self-contained plugin (no core-Harness wiring, no generated RPC contract)",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.13",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|