@cassius0924/dsh-usage-dashboard 0.3.0
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/LICENSE +21 -0
- package/README.md +190 -0
- package/cordis.patch.yml +10 -0
- package/lib/client.js +1607 -0
- package/lib/client.js.map +7 -0
- package/lib/index.js +433 -0
- package/lib/index.js.map +7 -0
- package/lib/types/client/api.d.ts +9 -0
- package/lib/types/client/cache.d.ts +22 -0
- package/lib/types/client/charts.d.ts +43 -0
- package/lib/types/client/context.d.ts +16 -0
- package/lib/types/client/dashboard.d.ts +12 -0
- package/lib/types/client/index.d.ts +15 -0
- package/lib/types/client/prefs.d.ts +14 -0
- package/lib/types/client/store.d.ts +10 -0
- package/lib/types/client/styles.d.ts +2 -0
- package/lib/types/client/widget.d.ts +9 -0
- package/lib/types/context.d.ts +63 -0
- package/lib/types/contract.d.ts +157 -0
- package/lib/types/index.d.ts +21 -0
- package/lib/types/memo.d.ts +23 -0
- package/lib/types/pricing.d.ts +43 -0
- package/lib/types/trust-fence.d.ts +8 -0
- package/lib/types/usage.d.ts +12 -0
- package/lib/types/wire.d.ts +2 -0
- package/package.json +82 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface Store<T> {
|
|
2
|
+
get(): T;
|
|
3
|
+
set(value: T): void;
|
|
4
|
+
subscribe(fn: () => void): () => void;
|
|
5
|
+
}
|
|
6
|
+
/** Whether the floating balance widget is shown. */
|
|
7
|
+
export declare const widgetVisibleStore: Store<boolean>;
|
|
8
|
+
/** Balance (in the account's own currency) below which both surfaces warn.
|
|
9
|
+
* 0 turns the warning off. */
|
|
10
|
+
export declare const lowBalanceStore: Store<number>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** All plugin styles in one sheet, injected once at client load. */
|
|
2
|
+
export declare const css = "\n.dsh-quota-root{position:absolute;right:16px;bottom:16px;z-index:2147483000;pointer-events:auto;font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;font-size:13px;line-height:1.45;color:var(--dsw-alias-label-primary,#1f2328);transition:left .28s cubic-bezier(.22,1,.36,1),top .28s cubic-bezier(.22,1,.36,1)}\n.dsh-quota-root.dsh-quota-dragging{transition:none}\n.dsh-quota-card,.dsh-quota-card *{box-sizing:border-box}\n.dsh-quota-card{background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:12px 14px;min-width:208px;max-width:270px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}\n.dsh-quota-root.dsh-quota-dragging .dsh-quota-card{cursor:grabbing;box-shadow:0 12px 32px rgba(0,0,0,.28)}\n.dsh-quota-header{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;min-width:0}\n.dsh-quota-title{font-weight:600;font-size:13px;color:var(--dsw-alias-label-primary,#1f2328);display:flex;align-items:center;gap:6px;min-width:0;overflow:hidden}\n.dsh-quota-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-quota-grip{color:var(--dsw-alias-label-secondary,#59636e);opacity:.7;font-size:11px;letter-spacing:0;cursor:grab;flex:none}\n.dsh-quota-dot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-state-success-primary,#2da44e);flex:none}\n.dsh-quota-dot--error{background:var(--dsw-alias-state-error-primary,#cf222e)}\n.dsh-quota-dot--warn{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dsh-quota-total--low{color:var(--dsw-alias-state-warning-primary,#9a6700)!important}\n.dsh-quota-dot--idle{background:var(--dsw-alias-label-secondary,#59636e);opacity:.6}\n.dsh-quota-collapsed-total{font-weight:700;font-size:13px;color:var(--dsw-alias-brand-primary,#0969da);flex:none;font-variant-numeric:tabular-nums}\n.dsh-quota-actions{display:flex;gap:2px;flex:none}\n.dsh-quota-btn{border:none;background:transparent;cursor:pointer;color:var(--dsw-alias-label-secondary,#59636e);padding:3px 7px;border-radius:6px;font-size:13px;line-height:1}\n.dsh-quota-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));color:var(--dsw-alias-label-primary,#1f2328)}\n.dsh-quota-btn:active:not(:disabled){transform:scale(.92)}\n.dsh-quota-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px}\n.dsh-quota-btn:disabled{opacity:.5;cursor:default}\n.dsh-quota-body{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-remaining-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e);margin-bottom:2px}\n.dsh-quota-total{font-size:24px;font-weight:700;color:var(--dsw-alias-label-primary,#1f2328);letter-spacing:-.02em;font-variant-numeric:tabular-nums}\n.dsh-quota-currency{font-size:14px;font-weight:600;margin-left:3px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-row{display:flex;justify-content:space-between;gap:12px;margin-top:6px;font-size:12px}\n.dsh-quota-label{color:var(--dsw-alias-label-secondary,#59636e)}\n.dsh-quota-value{color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dsh-quota-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-balance{display:flex;flex-direction:column;gap:16px;padding:20px 24px 48px;max-width:860px;margin:0 auto;font-family:system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;font-size:13px;line-height:1.5;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-card{background:var(--dsw-alias-bg-layer-1,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));border-radius:12px;padding:16px}\n.dq-card-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e);margin:0 0 12px;letter-spacing:.02em}\n.dq-balance-grid{display:flex;flex-wrap:wrap;gap:12px 24px}\n.dq-stat{min-width:110px}\n.dq-stat-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e);margin-bottom:2px}\n.dq-stat-value{font-size:18px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-stat-value--ok{color:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-stat-value--bad{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-runway{cursor:help;text-decoration:underline dotted var(--dsw-alias-border-l2,rgba(0,0,0,.25));text-underline-offset:4px}\n.dq-remaining{position:relative;cursor:help}\n.dq-remaining-breakdown{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:20;flex-direction:column;gap:4px;padding:8px 10px;background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.15);white-space:nowrap;font-size:12px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-remaining:hover .dq-remaining-breakdown{display:flex}\n.dq-remaining-granted{color:var(--dsw-alias-label-tertiary,#59636e);font-weight:400;font-size:11px}\n.dq-period-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}\n@media (max-width:620px){.dq-period-grid{grid-template-columns:1fr}}\n.dq-period{background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.06));border-radius:10px;padding:12px 14px;min-width:0}\n.dq-period-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:4px}\n.dq-period-label{font-size:11px;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-period-cost{font-size:22px;font-weight:680;letter-spacing:-.01em;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;line-height:1.25}\n.dq-period-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);margin-top:2px;font-variant-numeric:tabular-nums;line-height:1.45}\n.dq-delta{display:inline-flex;align-items:center;gap:3px;font-size:11px;font-weight:600;padding:1px 6px;border-radius:999px;white-space:nowrap;cursor:help;font-variant-numeric:tabular-nums}\n.dq-delta--up{color:var(--dsw-alias-state-warning-primary,#9a6700);background:rgba(191,135,0,.14)}\n.dq-delta--down{color:var(--dsw-alias-state-success-primary,#1a7f37);background:rgba(45,164,78,.14)}\n.dq-delta--flat,.dq-delta--new{color:var(--dsw-alias-label-tertiary,#59636e);background:rgba(120,130,150,.14);font-weight:500}\n.dq-delta-label{font-weight:400;opacity:.8}\n.dq-pricing{margin-top:12px;border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));padding-top:10px}\n.dq-pricing-summary{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e);cursor:pointer;list-style:none;width:fit-content;border-radius:6px;padding:2px 4px;margin-left:-4px}\n.dq-pricing-summary::-webkit-details-marker{display:none}\n.dq-pricing-summary::before{content:\"\u25B8\";display:inline-block;font-size:10px;opacity:.7;transition:transform .15s ease}\n.dq-pricing[open] .dq-pricing-summary::before{transform:rotate(90deg)}\n.dq-pricing-summary:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-pricing-summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-pricing-now{font-size:11px;font-weight:600;padding:1px 7px;border-radius:999px;color:var(--dsw-alias-label-tertiary,#59636e);background:rgba(120,130,150,.14)}\n.dq-pricing-now--peak{color:var(--dsw-alias-state-warning-primary,#9a6700);background:rgba(191,135,0,.14)}\n.dq-pricing-body{margin-top:10px;overflow-x:auto}\n.dq-pricing-table{border-collapse:collapse;font-size:11.5px;font-variant-numeric:tabular-nums;min-width:100%}\n.dq-pricing-table th{text-align:left;font-weight:500;color:var(--dsw-alias-label-tertiary,#59636e);padding:4px 12px 4px 0;white-space:nowrap;border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}\n.dq-pricing-table td{padding:4px 12px 4px 0;color:var(--dsw-alias-label-primary,#1f2328);white-space:nowrap;vertical-align:top}\n.dq-pricing-table tbody tr+tr td{border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.05))}\n.dq-pricing-foot{margin:8px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-peak-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85;overflow:hidden}\n.dq-peak-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-peak-legend{display:flex;flex-wrap:wrap;gap:6px 20px;margin-top:8px;font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-peak-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--peak{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-legend-swatch--offpeak{background:var(--dsw-alias-state-success-primary,#2da44e);opacity:.85}\n.dq-peak-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-top:14px}\n.dq-peak-delta{font-size:11px;font-weight:500;margin-left:8px;color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-peak-delta--save{color:var(--dsw-alias-state-success-primary,#1a7f37)}\n.dq-peak-foot{margin:10px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-cache-figures{display:flex;flex-wrap:wrap;gap:12px 32px;margin-bottom:12px}\n.dq-muted-value{color:var(--dsw-alias-label-secondary,#59636e)!important;font-weight:550}\n.dq-stat-value--warn{color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-cache-track{height:8px;border-radius:999px;background:var(--dsw-alias-state-warning-primary,#bf8700);overflow:hidden}\n.dq-cache-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-success-primary,#2da44e);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-cache-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin-top:8px;font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums}\n.dq-cache-legend span{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch--hit{background:var(--dsw-alias-state-success-primary,#2da44e)}\n.dq-legend-swatch--miss{background:var(--dsw-alias-state-warning-primary,#bf8700)}\n.dq-cache-foot{margin:10px 0 0;font-size:11.5px;line-height:1.6;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-sessions{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:14px}\n.dq-session{display:flex;flex-direction:column;gap:5px;min-width:0}\n.dq-session-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-session-title{font-size:13px;font-weight:550;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-session-cost{font-size:14px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-session-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-session-fill{height:100%;border-radius:999px;background:var(--dsw-alias-state-business-primary,#4176e6);transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-session-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-session-foot{margin:12px 0 0;font-size:11.5px;color:var(--dsw-alias-label-tertiary,#59636e)}\n.dq-rank{display:flex;flex-direction:column;gap:14px}\n.dq-rank-row{display:flex;flex-direction:column;gap:5px;min-width:0}\n.dq-rank-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}\n.dq-rank-name{display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:550;color:var(--dsw-alias-label-primary,#1f2328);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-rank-cost{display:inline-flex;align-items:baseline;gap:8px;font-size:14px;font-weight:650;color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums;flex:none}\n.dq-rank-share{font-size:11px;font-weight:500;color:var(--dsw-alias-label-tertiary,#59636e);min-width:30px;text-align:right}\n.dq-rank-track{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,rgba(120,130,150,.12));overflow:hidden}\n.dq-rank-fill{height:100%;border-radius:999px;transition:width .35s cubic-bezier(.22,1,.36,1)}\n.dq-rank-sub{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);font-variant-numeric:tabular-nums;line-height:1.5}\n.dq-alert{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border-radius:10px;font-size:12.5px;line-height:1.6;color:var(--dsw-alias-state-warning-primary,#7a5200);background:rgba(191,135,0,.12);border:1px solid rgba(191,135,0,.35)}\n.dq-alert-icon{flex:none;width:18px;height:18px;border-radius:50%;background:var(--dsw-alias-state-warning-primary,#bf8700);color:#fff;font-weight:700;font-size:12px;line-height:18px;text-align:center}\n.dq-alert strong{font-weight:650}\n.dq-alert-link{margin-left:8px;color:inherit;text-decoration:underline;text-underline-offset:2px;white-space:nowrap}\n.dq-setting{display:flex;align-items:flex-start;gap:12px;margin-top:14px;padding-top:14px;border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}\n.dq-setting-label{font-size:13px;color:var(--dsw-alias-label-primary,#1f2328);padding-top:6px;flex:none}\n.dq-setting-control{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0}\n.dq-setting-hint{font-size:11.5px;color:var(--dsw-alias-label-secondary,#59636e);line-height:1.5}\n.dq-number{width:82px;padding:5px 8px;font-size:13px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.16));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}\n.dq-number:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:1px;border-color:transparent}\n.dq-links{display:flex;flex-wrap:wrap;gap:8px}\n.dq-link{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));border-radius:8px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-state-business-primary,#0969da);text-decoration:none;font-size:13px;font-weight:500;cursor:pointer}\n.dq-link:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04))}\n.dq-toggle{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:13px}\n.dq-toggle input{width:16px;height:16px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer}\n.dq-toggle input:focus-visible,.dq-model-item input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-link:focus-visible,.dq-model-btn:focus-visible,.dq-chart-switch-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-usage-totals{display:flex;flex-wrap:wrap;gap:12px 24px;margin-bottom:16px}\n.dq-chart-peak{margin-left:10px;font-size:11px;font-weight:400;color:var(--dsw-alias-label-tertiary,#59636e);font-variant-numeric:tabular-nums}\n.dq-chart-title{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary,#59636e);margin:18px 0 8px}\n.dq-chart-title:first-of-type{margin-top:0}\n.dq-chart-block-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:18px 0 8px}\n.dq-chart-block-head .dq-chart-title{margin:0}\n.dq-chart-controls{display:flex;align-items:center;gap:8px;flex:none}\n.dq-model-picker{position:relative}\n.dq-model-btn{border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px}\n.dq-model-btn:hover{border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-model-btn::after{content:\"\u25BE\";font-size:10px;opacity:.7}\n.dq-model-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:190px;max-height:280px;overflow-y:auto;background:var(--dsw-alias-bg-overlay,#fff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.16);padding:6px;display:flex;flex-direction:column;gap:2px}\n.dq-model-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;font-size:12px;cursor:pointer;color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-model-item:hover{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06))}\n.dq-model-item input{width:14px;height:14px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer;flex:none}\n.dq-model-item span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-model-item--all{border-bottom:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08));padding-bottom:8px;margin-bottom:2px;border-radius:6px}\n.dq-model-tag{color:var(--dsw-alias-label-tertiary,#59636e);font-size:11px;flex:none}\n.dq-bar-group{display:flex;align-items:flex-end;gap:2px;height:100%;width:100%}\n.dq-bar-group .dq-bar{flex:1 1 0;min-width:0}\n.dq-legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-legend-item{display:inline-flex;align-items:center;gap:6px}\n.dq-legend-swatch{width:10px;height:10px;border-radius:3px;flex:none}\n.dq-chart-switch{display:inline-flex;align-items:center;gap:2px;padding:2px;background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.06));border-radius:999px;flex:none}\n.dq-chart-switch-btn{border:none;background:transparent;color:var(--dsw-alias-label-secondary,#59636e);font-size:12px;line-height:1;padding:5px 12px;border-radius:999px;cursor:pointer;transition:background .15s ease,color .15s ease}\n.dq-chart-switch-btn:hover{color:var(--dsw-alias-label-primary,#1f2328)}\n.dq-chart-switch-btn--on{background:var(--dsw-alias-bg-overlay,#fff);color:var(--dsw-alias-label-primary,#1f2328);box-shadow:0 1px 3px rgba(0,0,0,.14)}\n.dq-chart-wrap{position:relative}\n.dq-tip{position:absolute;transform:translate(-50%,14px);z-index:40;pointer-events:none;background:var(--dsw-alias-bg-inverse,#1f2328);color:var(--dsw-alias-label-inverse,#fff);border-radius:8px;padding:7px 10px;font-size:11.5px;line-height:1.55;white-space:nowrap;box-shadow:0 6px 20px rgba(0,0,0,.28);font-variant-numeric:tabular-nums}\n.dq-tip-head{font-weight:650;margin-bottom:2px}\n.dq-tip-row{opacity:.85}\n.dq-bars{display:flex;align-items:flex-end;gap:2px;width:100%}\n.dq-bar-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;justify-content:flex-end;align-items:stretch}\n.dq-bar{background:var(--dsw-alias-state-business-primary,#4176e6);border-radius:2px 2px 0 0;min-height:1px;transition:filter .12s ease}\n.dq-bar-col{cursor:default}\n.dq-bar-col:hover .dq-bar{filter:brightness(1.18) saturate(1.1)}\n.dq-heat-cell:not(.dq-heat-cell--pad):hover{outline:1.5px solid var(--dsw-alias-label-primary,#1f2328);outline-offset:1px}\n.dq-bar-label{font-size:9px;color:var(--dsw-alias-label-tertiary,#59636e);text-align:center;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dq-heat{display:flex;flex-direction:column;gap:8px;max-width:100%}\n.dq-heat-grid{display:flex;gap:6px;overflow-x:auto;padding-bottom:2px}\n.dq-heat-dows{display:flex;flex-direction:column;gap:3px;padding-top:17px;flex:none}\n.dq-heat-dow{height:12px;line-height:12px;font-size:9px;color:var(--dsw-alias-label-tertiary,#59636e);text-align:right;width:12px}\n.dq-heat-cols{display:flex;flex-direction:column;gap:2px;min-width:0}\n.dq-heat-months{display:flex;gap:3px;height:12px}\n.dq-heat-month{width:12px;flex:none;font-size:9px;line-height:12px;color:var(--dsw-alias-label-tertiary,#59636e);white-space:nowrap;overflow:visible}\n.dq-heatmap{display:flex;gap:3px;width:max-content}\n.dq-heat-week{display:flex;flex-direction:column;gap:3px}\n.dq-heat-cell{width:12px;height:12px;border-radius:2px;flex:none}\n.dq-heat-cell--pad{background:transparent}\n.dq-heat-key{width:12px;height:12px;border-radius:2px;flex:none}\n.dq-heat-scale{display:flex;align-items:center;gap:3px;font-size:10px;color:var(--dsw-alias-label-tertiary,#59636e);align-self:flex-end}\n.dq-heat-scale>span:first-child{margin-right:2px}\n.dq-heat-scale>span:last-child{margin-left:2px}\n.dq-muted{color:var(--dsw-alias-label-secondary,#59636e)}\n.dq-error{color:var(--dsw-alias-state-error-primary,#cf222e)}\n.dq-warn{color:var(--dsw-alias-state-warning-primary,#9a6700)}\n.dq-empty{color:var(--dsw-alias-label-secondary,#59636e);font-size:12.5px;line-height:1.6;padding:6px 0}\n.dq-skel{background:linear-gradient(90deg,rgba(125,135,155,.10) 25%,rgba(125,135,155,.20) 37%,rgba(125,135,155,.10) 63%);background-size:400% 100%;border-radius:5px;animation:dq-shimmer 1.5s ease-in-out infinite}\n.dq-stat .dq-skel+.dq-skel{margin-top:6px}\n.dq-skel-bars{display:flex;align-items:flex-end;gap:2px;width:100%;height:120px;margin-top:10px}\n.dq-skel-bar{flex:1 1 0;min-width:0;border-radius:2px 2px 0 0}\n@keyframes dq-shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}\n@media (prefers-reduced-motion:reduce){.dq-skel{animation:none}.dq-refresh-icon--spin{animation:none}}\n.dq-status-row{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:20px}\n.dq-status-row .dq-muted,.dq-status-row .dq-error{font-size:12px}\n.dq-refresh-btn{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.12));background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-secondary,#59636e);border-radius:8px;padding:5px 10px;font-size:12px;cursor:pointer;transition:border-color .15s ease,color .15s ease}\n.dq-refresh-btn:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary,#0969da);color:var(--dsw-alias-state-business-primary,#0969da)}\n.dq-refresh-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}\n.dq-refresh-btn:disabled{cursor:default;opacity:.6}\n.dq-refresh-icon{display:inline-block;line-height:1}\n.dq-refresh-icon--spin{animation:dq-spin .9s linear infinite}\n@keyframes dq-spin{to{transform:rotate(360deg)}}\n";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** The draggable bottom-right floating balance widget.
|
|
2
|
+
*
|
|
3
|
+
* Where it sits (corner) and whether it is collapsed are user choices, so both
|
|
4
|
+
* are persisted (see ./prefs.ts) and restored before the first paint; the
|
|
5
|
+
* widget also re-snaps to its corner when the frame resizes (window resize,
|
|
6
|
+
* sidebar collapse) instead of stranding itself at stale pixel coordinates.
|
|
7
|
+
*/
|
|
8
|
+
import { type ReactElement } from 'react';
|
|
9
|
+
export declare function QuotaWidget(): ReactElement | null;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural service faces this plugin reads from the host Cordis context.
|
|
3
|
+
* They are deliberately minimal: the plugin only touches the methods it
|
|
4
|
+
* needs, so no extra `@deepseek-ai/dsh-*` type packages are required to
|
|
5
|
+
* build it.
|
|
6
|
+
*/
|
|
7
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
8
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
9
|
+
/** One HTTP route served by the host web server. */
|
|
10
|
+
export interface WebRoute {
|
|
11
|
+
kind: 'exact' | 'prefix';
|
|
12
|
+
path: string;
|
|
13
|
+
handler: (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
/** Structural face of the host `webServer` service. */
|
|
16
|
+
export interface WebServerFace {
|
|
17
|
+
register(route: WebRoute): () => void;
|
|
18
|
+
}
|
|
19
|
+
/** Structural face of the `credentials` service. */
|
|
20
|
+
export interface CredentialsFace {
|
|
21
|
+
resolve(ref: string): Promise<{
|
|
22
|
+
value: string;
|
|
23
|
+
source: string;
|
|
24
|
+
} | undefined>;
|
|
25
|
+
}
|
|
26
|
+
/** Structural face of the `sessionPersistence` service. */
|
|
27
|
+
export interface SessionHeaderFace {
|
|
28
|
+
id?: string;
|
|
29
|
+
sessionId?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface TokenUsageFace {
|
|
32
|
+
inputTokens?: number;
|
|
33
|
+
outputTokens?: number;
|
|
34
|
+
cacheReadTokens?: number;
|
|
35
|
+
reasoningTokens?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface SessionEventFace {
|
|
38
|
+
type?: string;
|
|
39
|
+
time?: number;
|
|
40
|
+
data?: {
|
|
41
|
+
usage?: TokenUsageFace;
|
|
42
|
+
header?: {
|
|
43
|
+
config?: {
|
|
44
|
+
provider?: string;
|
|
45
|
+
model?: string;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
/** Payload of a `session/title` event. */
|
|
49
|
+
title?: string;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export interface SessionPersistenceFace {
|
|
53
|
+
list(): Promise<SessionHeaderFace[]>;
|
|
54
|
+
readFrom(id: string, fromSeq: number): Promise<{
|
|
55
|
+
events?: SessionEventFace[];
|
|
56
|
+
}>;
|
|
57
|
+
}
|
|
58
|
+
/** The host context this plugin's apply() receives. */
|
|
59
|
+
export interface HostContext extends Context {
|
|
60
|
+
webServer: WebServerFace;
|
|
61
|
+
credentials: CredentialsFace;
|
|
62
|
+
sessionPersistence: SessionPersistenceFace;
|
|
63
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/** Wire contracts shared by the host API and the client fetchers. */
|
|
2
|
+
export interface BalanceInfo {
|
|
3
|
+
currency: string;
|
|
4
|
+
total: string;
|
|
5
|
+
granted: string;
|
|
6
|
+
toppedUp: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BalanceData {
|
|
9
|
+
isAvailable: boolean;
|
|
10
|
+
balances: BalanceInfo[];
|
|
11
|
+
}
|
|
12
|
+
export interface BalanceResponse {
|
|
13
|
+
ok: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
data?: BalanceData;
|
|
16
|
+
}
|
|
17
|
+
export interface DailyUsage {
|
|
18
|
+
date: string;
|
|
19
|
+
input: number;
|
|
20
|
+
output: number;
|
|
21
|
+
cache: number;
|
|
22
|
+
total: number;
|
|
23
|
+
cost: number;
|
|
24
|
+
calls: number;
|
|
25
|
+
}
|
|
26
|
+
export interface HourlyUsage {
|
|
27
|
+
hour: number;
|
|
28
|
+
total: number;
|
|
29
|
+
cost: number;
|
|
30
|
+
calls: number;
|
|
31
|
+
}
|
|
32
|
+
export interface HeatmapUsage {
|
|
33
|
+
date: string;
|
|
34
|
+
total: number;
|
|
35
|
+
cost: number;
|
|
36
|
+
calls: number;
|
|
37
|
+
}
|
|
38
|
+
export interface UsageTotals {
|
|
39
|
+
input: number;
|
|
40
|
+
output: number;
|
|
41
|
+
cache: number;
|
|
42
|
+
reasoning: number;
|
|
43
|
+
total: number;
|
|
44
|
+
cost: number;
|
|
45
|
+
calls: number;
|
|
46
|
+
/**
|
|
47
|
+
* What the cache-hit tokens would have cost at cache-miss rates, minus what
|
|
48
|
+
* they actually cost — i.e. the money prefix caching saved. Folded per
|
|
49
|
+
* record so it respects each record's model and time-of-day rates.
|
|
50
|
+
*/
|
|
51
|
+
cacheSavings: number;
|
|
52
|
+
}
|
|
53
|
+
/** One per-day / per-hour point of a single model's series. */
|
|
54
|
+
export interface ModelSeriesPoint {
|
|
55
|
+
total: number;
|
|
56
|
+
cost: number;
|
|
57
|
+
calls: number;
|
|
58
|
+
}
|
|
59
|
+
/** Per-model usage aggregation: overall totals plus 30-day and 24-hour series. */
|
|
60
|
+
export interface ModelUsage {
|
|
61
|
+
provider: string;
|
|
62
|
+
model: string;
|
|
63
|
+
input: number;
|
|
64
|
+
output: number;
|
|
65
|
+
cache: number;
|
|
66
|
+
total: number;
|
|
67
|
+
cost: number;
|
|
68
|
+
calls: number;
|
|
69
|
+
daily: ModelSeriesPoint[];
|
|
70
|
+
hourly: ModelSeriesPoint[];
|
|
71
|
+
}
|
|
72
|
+
/** Usage rolled up over one time window. */
|
|
73
|
+
export interface PeriodUsage {
|
|
74
|
+
total: number;
|
|
75
|
+
cost: number;
|
|
76
|
+
calls: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Time-anchored rollups. "Accumulated since forever" answers no question a
|
|
80
|
+
* user actually has; these do: what did today cost, what has this month cost,
|
|
81
|
+
* and is that more or less than the comparable window before it.
|
|
82
|
+
*/
|
|
83
|
+
export interface UsageSummary {
|
|
84
|
+
today: PeriodUsage;
|
|
85
|
+
yesterday: PeriodUsage;
|
|
86
|
+
/** Current calendar month, to date. */
|
|
87
|
+
month: PeriodUsage;
|
|
88
|
+
/** Previous calendar month up to the same day-of-month, so a mid-month
|
|
89
|
+
* comparison is against a same-length window rather than a full month. */
|
|
90
|
+
lastMonthToDate: PeriodUsage;
|
|
91
|
+
}
|
|
92
|
+
/** CNY per 1M tokens for one model tier. */
|
|
93
|
+
export interface PricingRates {
|
|
94
|
+
cacheHit: number;
|
|
95
|
+
input: number;
|
|
96
|
+
output: number;
|
|
97
|
+
}
|
|
98
|
+
export interface PricingTier {
|
|
99
|
+
model: string;
|
|
100
|
+
peak: PricingRates;
|
|
101
|
+
/** Null while flat pricing is in effect (before the peak/off-peak switch). */
|
|
102
|
+
offPeak: PricingRates | null;
|
|
103
|
+
}
|
|
104
|
+
/** What the cost column was computed with, so the estimate can be audited. */
|
|
105
|
+
export interface PricingInfo {
|
|
106
|
+
currency: string;
|
|
107
|
+
/** Date peak/off-peak pricing takes effect. */
|
|
108
|
+
switchDate: string;
|
|
109
|
+
splitActive: boolean;
|
|
110
|
+
inPeakNow: boolean;
|
|
111
|
+
peakWindows: string[];
|
|
112
|
+
tiers: PricingTier[];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* How usage divides between DeepSeek's peak and off-peak windows, plus the
|
|
116
|
+
* same usage re-priced two ways — so the 2026-08-17 change can be answered
|
|
117
|
+
* before it lands ("what will this cost me") and after ("what would shifting
|
|
118
|
+
* off-peak save me").
|
|
119
|
+
*/
|
|
120
|
+
export interface PeakSplit {
|
|
121
|
+
peak: PeriodUsage;
|
|
122
|
+
offPeak: PeriodUsage;
|
|
123
|
+
/** Every record priced under the peak/off-peak table, as actually classified. */
|
|
124
|
+
peakEraCost: number;
|
|
125
|
+
/** Every record priced under that table as if it had landed off-peak. */
|
|
126
|
+
offPeakEraCost: number;
|
|
127
|
+
}
|
|
128
|
+
/** One session's share of the bill. */
|
|
129
|
+
export interface SessionCost {
|
|
130
|
+
id: string;
|
|
131
|
+
/** The session's title from its log; falls back to a short id. */
|
|
132
|
+
title: string;
|
|
133
|
+
total: number;
|
|
134
|
+
cost: number;
|
|
135
|
+
calls: number;
|
|
136
|
+
/** Epoch ms of the last usage record in this session. */
|
|
137
|
+
lastActive: number;
|
|
138
|
+
}
|
|
139
|
+
export interface UsageData {
|
|
140
|
+
daily: DailyUsage[];
|
|
141
|
+
hourly: HourlyUsage[];
|
|
142
|
+
heatmap: HeatmapUsage[];
|
|
143
|
+
totals: UsageTotals;
|
|
144
|
+
models: ModelUsage[];
|
|
145
|
+
summary: UsageSummary;
|
|
146
|
+
pricing: PricingInfo;
|
|
147
|
+
peakSplit: PeakSplit;
|
|
148
|
+
/** Most expensive sessions first, capped — see SESSION_TOP_N. */
|
|
149
|
+
sessions: SessionCost[];
|
|
150
|
+
/** How many sessions contributed usage in total. */
|
|
151
|
+
sessionCount: number;
|
|
152
|
+
}
|
|
153
|
+
export interface UsageResponse {
|
|
154
|
+
ok: boolean;
|
|
155
|
+
error?: string;
|
|
156
|
+
data?: UsageData;
|
|
157
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-usage-dashboard host plugin.
|
|
3
|
+
*
|
|
4
|
+
* Registers the package's own fenced JSON API under
|
|
5
|
+
* `/api/dsh-usage-dashboard` (balance + usage), consumed by the client half
|
|
6
|
+
* through same-origin fetch. Both endpoints are memoized with a TTL so that
|
|
7
|
+
* tab switches and the widget's polling don't replay session logs or hammer
|
|
8
|
+
* the DeepSeek API; responses carry `Cache-Control` so the browser's HTTP
|
|
9
|
+
* cache serves repeat requests without a network round trip. `?refresh=1`
|
|
10
|
+
* bypasses the memo for an explicit force refresh.
|
|
11
|
+
*/
|
|
12
|
+
import type { HostContext } from './context.ts';
|
|
13
|
+
/** Plugin identity for the cordis.patch.yml row (and the client bundle id). */
|
|
14
|
+
export declare const name = "dsh-usage-dashboard";
|
|
15
|
+
/** Services required before load: the web server plus the two data sources. */
|
|
16
|
+
export declare const inject: string[];
|
|
17
|
+
/**
|
|
18
|
+
* Mount the /api/dsh-usage-dashboard routes.
|
|
19
|
+
* @param ctx - host Cordis context.
|
|
20
|
+
*/
|
|
21
|
+
export declare function apply(ctx: HostContext): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny TTL memo for the /api routes.
|
|
3
|
+
*
|
|
4
|
+
* The usage endpoint replays every session log, so it must not run on every
|
|
5
|
+
* tab click; the balance endpoint also calls the DeepSeek API. The memo:
|
|
6
|
+
*
|
|
7
|
+
* - `get()` serves a successful cached response while it is within `ttlMs`,
|
|
8
|
+
* otherwise recomputes;
|
|
9
|
+
* - `refresh()` recomputes unconditionally and reseeds the cache;
|
|
10
|
+
* - concurrent recomputes (of either kind) are deduped into one upstream
|
|
11
|
+
* call;
|
|
12
|
+
* - `ok:false` responses are never cached, so a transient failure is retried
|
|
13
|
+
* on the next request.
|
|
14
|
+
*
|
|
15
|
+
* No timers are held, so nothing needs disposal on plugin unload.
|
|
16
|
+
*/
|
|
17
|
+
export interface Memo<T> {
|
|
18
|
+
get(): Promise<T>;
|
|
19
|
+
refresh(): Promise<T>;
|
|
20
|
+
}
|
|
21
|
+
export declare function memoize<T extends {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
}>(ttlMs: number, compute: () => Promise<T>): Memo<T>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSeek API price table and cost estimation.
|
|
3
|
+
*
|
|
4
|
+
* Two things the previous flat constant got wrong: every model was billed at
|
|
5
|
+
* deepseek-v4-pro rates (flash is ~3x cheaper), and the 2026-08-17 switch to
|
|
6
|
+
* peak/off-peak pricing was not modelled at all.
|
|
7
|
+
*
|
|
8
|
+
* Rates are CNY per 1M tokens, from DeepSeek's 2026-08-13 price announcement.
|
|
9
|
+
* Peak window is Beijing time 09:00–12:00 and 14:00–18:00; off-peak is half of
|
|
10
|
+
* peak. Usage recorded before the switch is still costed at the old flat rates,
|
|
11
|
+
* so historical days keep the price that was actually charged.
|
|
12
|
+
*
|
|
13
|
+
* Editing this table is the one place to touch when DeepSeek changes prices.
|
|
14
|
+
*/
|
|
15
|
+
import type { PricingInfo, PricingRates } from './contract.ts';
|
|
16
|
+
/** 2026-08-17 00:00 Beijing time (UTC+8), when peak/off-peak pricing starts. */
|
|
17
|
+
export declare const PEAK_PRICING_FROM_MS: number;
|
|
18
|
+
type Tier = 'pro' | 'flash';
|
|
19
|
+
/** Which price tier a model name falls into; anything unrecognised is billed
|
|
20
|
+
* as pro, the conservative (more expensive) guess. */
|
|
21
|
+
export declare function tierOf(model: string): Tier;
|
|
22
|
+
/** Whether a moment falls in a peak window, judged in Beijing time so the
|
|
23
|
+
* estimate does not drift with the machine's timezone. */
|
|
24
|
+
export declare function isPeak(timeMs: number): boolean;
|
|
25
|
+
/** Rates applying to one model at one moment. */
|
|
26
|
+
export declare function ratesAt(timeMs: number, model: string): PricingRates;
|
|
27
|
+
/**
|
|
28
|
+
* What prefix caching saved on one record: the cache-hit tokens re-priced at
|
|
29
|
+
* the cache-miss rate, minus what they actually cost.
|
|
30
|
+
*/
|
|
31
|
+
export declare function cacheSavingOf(timeMs: number, model: string, cache: number): number;
|
|
32
|
+
/** Estimated CNY cost of one usage record. */
|
|
33
|
+
export declare function costOf(timeMs: number, model: string, input: number, cache: number, output: number): number;
|
|
34
|
+
/**
|
|
35
|
+
* The same record priced under the peak/off-peak table regardless of when it
|
|
36
|
+
* happened — `forceOffPeak` prices it as if it had landed in an idle window.
|
|
37
|
+
* Used to answer "what will the new pricing cost me" before the switch and
|
|
38
|
+
* "what would shifting off-peak save" after it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function costUnderPeakEra(timeMs: number, model: string, input: number, cache: number, output: number, forceOffPeak?: boolean): number;
|
|
41
|
+
/** The price table to show the user, describing whatever is in effect now. */
|
|
42
|
+
export declare function pricingInfo(nowMs: number): PricingInfo;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-trust fence for the plugin's own /api route — the same fences the
|
|
3
|
+
* harness's /api gateway applies: the Host header must name a loopback
|
|
4
|
+
* authority, a browser-marked cross-site request is refused, and an attached
|
|
5
|
+
* Origin must be exactly this authority.
|
|
6
|
+
*/
|
|
7
|
+
import type { IncomingMessage } from 'node:http';
|
|
8
|
+
export declare function isTrustedApiRequest(req: IncomingMessage): boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Balance and usage data sources.
|
|
3
|
+
*
|
|
4
|
+
* - Balance: DeepSeek API `GET /user/balance` with the key resolved through
|
|
5
|
+
* the credentials service (`DEEPSEEK_API_KEY`).
|
|
6
|
+
* - Usage: token usage folded from the DSH session logs (`sessionPersistence`),
|
|
7
|
+
* one record per `assistant/message` event, bucketed by local day / hour.
|
|
8
|
+
*/
|
|
9
|
+
import type { BalanceResponse, UsageResponse } from './contract.ts';
|
|
10
|
+
import type { CredentialsFace, SessionPersistenceFace } from './context.ts';
|
|
11
|
+
export declare function fetchBalance(credentials: CredentialsFace | undefined): Promise<BalanceResponse>;
|
|
12
|
+
export declare function fetchUsage(persistence: SessionPersistenceFace | undefined): Promise<UsageResponse>;
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cassius0924/dsh-usage-dashboard",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "DeepSeek 额度与用量仪表盘 —— DSH (DeepSeek Harness) Web 插件:余额还能撑几天、今日/本月花了多少、哪个模型和哪个会话最贵、缓存省了多少,以及 2026-08-17 峰谷定价后的账单预估",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"deepseek",
|
|
7
|
+
"dsh",
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"plugin",
|
|
10
|
+
"dashboard",
|
|
11
|
+
"usage",
|
|
12
|
+
"quota",
|
|
13
|
+
"cost",
|
|
14
|
+
"tokens"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/Cassius0924/dsh-usage-dashboard#readme",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/Cassius0924/dsh-usage-dashboard.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/Cassius0924/dsh-usage-dashboard/issues"
|
|
23
|
+
},
|
|
24
|
+
"author": "Cassius0924",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "lib/index.js",
|
|
27
|
+
"types": "lib/types/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./lib/types/index.d.ts",
|
|
31
|
+
"default": "./lib/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./client": {
|
|
34
|
+
"types": "./lib/types/client/index.d.ts",
|
|
35
|
+
"default": "./lib/client.js"
|
|
36
|
+
},
|
|
37
|
+
"./package.json": "./package.json"
|
|
38
|
+
},
|
|
39
|
+
"dsh": {
|
|
40
|
+
"bundle": {
|
|
41
|
+
"patch": "./cordis.patch.yml"
|
|
42
|
+
},
|
|
43
|
+
"client": {
|
|
44
|
+
"platform": "web",
|
|
45
|
+
"immediately": true,
|
|
46
|
+
"inject": [
|
|
47
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
48
|
+
"@deepseek-ai/dsh-client-ui-conversation"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"lib",
|
|
54
|
+
"cordis.patch.yml",
|
|
55
|
+
"README.md",
|
|
56
|
+
"LICENSE"
|
|
57
|
+
],
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "node build.mjs",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"prepare": "node build.mjs"
|
|
62
|
+
},
|
|
63
|
+
"license": "MIT",
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=20"
|
|
66
|
+
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"@deepseek-ai/cordis": "^4.0.0",
|
|
69
|
+
"react": "^18.2.0"
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
73
|
+
"@types/node": "^24.0.0",
|
|
74
|
+
"@types/react": "^18.2.0",
|
|
75
|
+
"esbuild": "^0.25.0",
|
|
76
|
+
"react": "^18.2.0",
|
|
77
|
+
"typescript": "^5.6.0"
|
|
78
|
+
},
|
|
79
|
+
"publishConfig": {
|
|
80
|
+
"access": "public"
|
|
81
|
+
}
|
|
82
|
+
}
|