@tokenbuddy/tokenbuddy 1.0.35 → 1.0.37
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/dist/src/buyer-store.d.ts +6 -1
- package/dist/src/buyer-store.js +43 -4
- package/dist/src/cli.js +2 -2
- package/dist/src/daemon.d.ts +12 -0
- package/dist/src/daemon.js +791 -61
- package/dist/src/doctor-diagnostics.js +1 -6
- package/dist/src/provider-install.d.ts +2 -2
- package/dist/src/provider-install.js +248 -2
- package/dist/src/seller-catalog.d.ts +21 -0
- package/dist/src/seller-catalog.js +17 -0
- package/dist/src/seller-route-planner.d.ts +4 -1
- package/dist/src/seller-route-planner.js +3 -0
- package/dist/src/seller-routing-strategy.d.ts +3 -0
- package/dist/src/terminal-detect.d.ts +1 -1
- package/dist/src/terminal-detect.js +3 -2
- package/package.json +15 -2
- package/static/ui/assets/index-Djfl9tw5.js +271 -0
- package/static/ui/assets/index-DkfztCkn.css +1 -0
- package/static/ui/index.html +2 -2
- package/dist/src/buyer-store.d.ts.map +0 -1
- package/dist/src/buyer-store.js.map +0 -1
- package/dist/src/clawtip-bootstrap.d.ts.map +0 -1
- package/dist/src/clawtip-bootstrap.js.map +0 -1
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js.map +0 -1
- package/dist/src/credit-tracker.d.ts.map +0 -1
- package/dist/src/credit-tracker.js.map +0 -1
- package/dist/src/daemon.d.ts.map +0 -1
- package/dist/src/daemon.js.map +0 -1
- package/dist/src/doctor-clawtip-wallet.d.ts.map +0 -1
- package/dist/src/doctor-clawtip-wallet.js.map +0 -1
- package/dist/src/doctor-diagnostics.d.ts.map +0 -1
- package/dist/src/doctor-diagnostics.js.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/init-clawtip-activation.d.ts.map +0 -1
- package/dist/src/init-clawtip-activation.js.map +0 -1
- package/dist/src/init-payment-options.d.ts.map +0 -1
- package/dist/src/init-payment-options.js.map +0 -1
- package/dist/src/init-setup.d.ts.map +0 -1
- package/dist/src/init-setup.js.map +0 -1
- package/dist/src/model-index.d.ts.map +0 -1
- package/dist/src/model-index.js.map +0 -1
- package/dist/src/package-update.d.ts.map +0 -1
- package/dist/src/package-update.js.map +0 -1
- package/dist/src/prewarm-cache.d.ts.map +0 -1
- package/dist/src/prewarm-cache.js.map +0 -1
- package/dist/src/prewarm-scheduler.d.ts.map +0 -1
- package/dist/src/prewarm-scheduler.js.map +0 -1
- package/dist/src/provider-install.d.ts.map +0 -1
- package/dist/src/provider-install.js.map +0 -1
- package/dist/src/provider-routing-config.d.ts.map +0 -1
- package/dist/src/provider-routing-config.js.map +0 -1
- package/dist/src/registry-trust.d.ts.map +0 -1
- package/dist/src/registry-trust.js.map +0 -1
- package/dist/src/route-failover.d.ts.map +0 -1
- package/dist/src/route-failover.js.map +0 -1
- package/dist/src/seller-catalog.d.ts.map +0 -1
- package/dist/src/seller-catalog.js.map +0 -1
- package/dist/src/seller-concurrency-limiter.d.ts.map +0 -1
- package/dist/src/seller-concurrency-limiter.js.map +0 -1
- package/dist/src/seller-metadata-cache.d.ts.map +0 -1
- package/dist/src/seller-metadata-cache.js.map +0 -1
- package/dist/src/seller-pool.d.ts.map +0 -1
- package/dist/src/seller-pool.js.map +0 -1
- package/dist/src/seller-route-planner.d.ts.map +0 -1
- package/dist/src/seller-route-planner.js.map +0 -1
- package/dist/src/seller-routing-config.d.ts.map +0 -1
- package/dist/src/seller-routing-config.js.map +0 -1
- package/dist/src/seller-routing-strategy.d.ts.map +0 -1
- package/dist/src/seller-routing-strategy.js.map +0 -1
- package/dist/src/stream-failover.d.ts.map +0 -1
- package/dist/src/stream-failover.js.map +0 -1
- package/dist/src/tb-clawtip-proof.d.ts.map +0 -1
- package/dist/src/tb-clawtip-proof.js.map +0 -1
- package/dist/src/tb-proxyd.d.ts.map +0 -1
- package/dist/src/tb-proxyd.js.map +0 -1
- package/dist/src/terminal-detect.d.ts.map +0 -1
- package/dist/src/terminal-detect.js.map +0 -1
- package/dist/src/terminal-image.d.ts.map +0 -1
- package/dist/src/terminal-image.js.map +0 -1
- package/src/buyer-store.ts +0 -1090
- package/src/clawtip-bootstrap.ts +0 -65
- package/src/cli.ts +0 -2243
- package/src/credit-tracker.ts +0 -295
- package/src/daemon.ts +0 -5475
- package/src/doctor-clawtip-wallet.ts +0 -95
- package/src/doctor-diagnostics.ts +0 -1026
- package/src/index.ts +0 -16
- package/src/init-clawtip-activation.ts +0 -695
- package/src/init-payment-options.ts +0 -373
- package/src/init-setup.ts +0 -165
- package/src/model-index.ts +0 -278
- package/src/package-update.ts +0 -311
- package/src/prewarm-cache.ts +0 -485
- package/src/prewarm-scheduler.ts +0 -675
- package/src/provider-install.ts +0 -1006
- package/src/provider-routing-config.ts +0 -410
- package/src/registry-trust.ts +0 -51
- package/src/route-failover.ts +0 -304
- package/src/seller-catalog.ts +0 -505
- package/src/seller-concurrency-limiter.ts +0 -161
- package/src/seller-metadata-cache.ts +0 -91
- package/src/seller-pool.ts +0 -557
- package/src/seller-route-planner.ts +0 -513
- package/src/seller-routing-config.ts +0 -211
- package/src/seller-routing-strategy.ts +0 -362
- package/src/stream-failover.ts +0 -152
- package/src/tb-clawtip-proof.ts +0 -28
- package/src/tb-proxyd.ts +0 -101
- package/src/terminal-detect.ts +0 -333
- package/src/terminal-image.ts +0 -228
- package/static/ui/assets/index-0MVXD7bH.css +0 -1
- package/static/ui/assets/index-BVbeDEwq.js +0 -271
- package/static/ui/assets/index-BVbeDEwq.js.map +0 -1
- package/tests/cli-routing.test.ts +0 -363
- package/tests/control-plane-ui-endpoints.test.ts +0 -1630
- package/tests/credit-tracker.test.ts +0 -165
- package/tests/daemon-413-fallback.test.ts +0 -92
- package/tests/daemon-classify.test.ts +0 -452
- package/tests/daemon-roles.test.ts +0 -92
- package/tests/daemon-trusted-registry-cache.test.ts +0 -132
- package/tests/e2e.test.ts +0 -366
- package/tests/image-generation-e2e.test.ts +0 -230
- package/tests/model-index.test.ts +0 -198
- package/tests/package-update.test.ts +0 -147
- package/tests/prewarm-cache.test.ts +0 -296
- package/tests/prewarm-scheduler.test.ts +0 -367
- package/tests/provider-routing-config.test.ts +0 -150
- package/tests/registry-trust.test.ts +0 -28
- package/tests/route-failover.test.ts +0 -222
- package/tests/seller-catalog-413.test.ts +0 -120
- package/tests/seller-catalog-utilities.test.ts +0 -124
- package/tests/seller-concurrency-limiter.test.ts +0 -83
- package/tests/seller-metadata-cache.test.ts +0 -89
- package/tests/seller-pool.test.ts +0 -365
- package/tests/seller-route-planner.test.ts +0 -312
- package/tests/seller-routing-config.test.ts +0 -124
- package/tests/seller-routing-strategy.test.ts +0 -167
- package/tests/stream-failover.test.ts +0 -52
- package/tests/thousand-seller.test.ts +0 -151
- package/tests/tokenbuddy.test.ts +0 -4043
- package/tsconfig.json +0 -8
package/src/credit-tracker.ts
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
import { createModuleLogger } from "@tokenbuddy/logging";
|
|
2
|
-
|
|
3
|
-
const logger = createModuleLogger("tb-proxyd:credit-tracker");
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Default window after a successful purchase during which failover is
|
|
7
|
-
* softened (see buyer-driven-fallback-design.md §17.3). 30 seconds is the
|
|
8
|
-
* v1.1 starting point; v1.2 keeps the same value.
|
|
9
|
-
*/
|
|
10
|
-
export const DEFAULT_FRESH_PURCHASE_WINDOW_MS = 30_000;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Default threshold of "still considered fresh": the current balance must
|
|
14
|
-
* still cover this fraction of the last purchase amount for the entry to
|
|
15
|
-
* be treated as "刚买". 0.5 means "at least half of the purchased credit is
|
|
16
|
-
* still untouched".
|
|
17
|
-
*/
|
|
18
|
-
export const DEFAULT_FRESH_PURCHASE_THRESHOLD = 0.5;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Maximum number of automatic purchases a single session may trigger per
|
|
22
|
-
* minute. When the budget is exhausted, route-failover must `切` rather than
|
|
23
|
-
* `重买` (see §17.5).
|
|
24
|
-
*/
|
|
25
|
-
export const DEFAULT_PURCHASE_BUDGET_PER_MINUTE = 3;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* `CreditTracker` 构造选项。
|
|
29
|
-
*/
|
|
30
|
-
export interface CreditTrackerOptions {
|
|
31
|
-
/** "新鲜购买" 判定窗口(毫秒),默认 30s */
|
|
32
|
-
freshPurchaseWindowMs?: number;
|
|
33
|
-
/** "新鲜购买" 剩余比例阈值,默认 0.5(剩余 ≥ 50% 才算 fresh) */
|
|
34
|
-
freshPurchaseThreshold?: number;
|
|
35
|
-
/** 单 session 每分钟自动购买上限,默认 3 */
|
|
36
|
-
purchaseBudgetPerMinute?: number;
|
|
37
|
-
/** 时间源,默认 `Date.now`;测试可注入 */
|
|
38
|
-
now?: () => number;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface SellerCredit {
|
|
42
|
-
sellerId: string;
|
|
43
|
-
lastPurchaseAt: number;
|
|
44
|
-
lastPurchaseAmountMicros: number;
|
|
45
|
-
currentBalanceMicros: number;
|
|
46
|
-
leftoverCreditMicros: number;
|
|
47
|
-
lastUpdatedAt: number;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Tracks per-seller credit state for the buyer-driven-fallback design's
|
|
52
|
-
* "balance protection" rules. The tracker is intentionally agnostic of the
|
|
53
|
-
* actual seller HTTP layer: callers feed in `recordPurchase`,
|
|
54
|
-
* `recordSpend`, and `transferLeftover` events as they observe them, and
|
|
55
|
-
* the tracker answers "is this seller still inside its fresh-purchase
|
|
56
|
-
* window?" / "may I auto-purchase again this minute?".
|
|
57
|
-
*
|
|
58
|
-
* The tracker is process-local: a buyer restart resets the session
|
|
59
|
-
* counters. See §17.11.4 for the rationale.
|
|
60
|
-
*/
|
|
61
|
-
/**
|
|
62
|
-
* buyer-driven-fallback 设计的"余额保护"决策器。
|
|
63
|
-
* 跟踪每个 seller 的余额、最近购买时间、累计浪费 micros,回答:
|
|
64
|
-
* - "该 seller 是否还在 fresh-purchase window 内?"
|
|
65
|
-
* - "本 session 是否还能自动购买?"
|
|
66
|
-
*
|
|
67
|
-
* 仅进程内状态(buyer 重启会重置 session 计数器;详见 §17.11.4)。
|
|
68
|
-
*/
|
|
69
|
-
export class CreditTracker {
|
|
70
|
-
private readonly freshPurchaseWindowMs: number;
|
|
71
|
-
private readonly freshPurchaseThreshold: number;
|
|
72
|
-
private readonly purchaseBudgetPerMinute: number;
|
|
73
|
-
private readonly now: () => number;
|
|
74
|
-
|
|
75
|
-
private readonly entries = new Map<string, SellerCredit>();
|
|
76
|
-
private readonly purchaseTimestamps: number[] = [];
|
|
77
|
-
private totalWastedMicros = 0;
|
|
78
|
-
private wastedSinceLastDoctorRun = 0;
|
|
79
|
-
|
|
80
|
-
constructor(options: CreditTrackerOptions = {}) {
|
|
81
|
-
this.freshPurchaseWindowMs = options.freshPurchaseWindowMs ?? DEFAULT_FRESH_PURCHASE_WINDOW_MS;
|
|
82
|
-
this.freshPurchaseThreshold = options.freshPurchaseThreshold ?? DEFAULT_FRESH_PURCHASE_THRESHOLD;
|
|
83
|
-
this.purchaseBudgetPerMinute = options.purchaseBudgetPerMinute ?? DEFAULT_PURCHASE_BUDGET_PER_MINUTE;
|
|
84
|
-
this.now = options.now ?? Date.now;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Register a successful purchase. Updates the seller's balance, the
|
|
89
|
-
* session-wide budget window, and the "fresh purchase" timestamps. If
|
|
90
|
-
* the seller is unknown, an entry is created.
|
|
91
|
-
*/
|
|
92
|
-
recordPurchase(sellerId: string, amountMicros: number, balanceMicros: number): SellerCredit {
|
|
93
|
-
if (!Number.isFinite(amountMicros) || amountMicros <= 0) {
|
|
94
|
-
throw new Error("recordPurchase requires a positive amountMicros");
|
|
95
|
-
}
|
|
96
|
-
const ts = this.now();
|
|
97
|
-
const previous = this.entries.get(sellerId);
|
|
98
|
-
const entry: SellerCredit = {
|
|
99
|
-
sellerId,
|
|
100
|
-
lastPurchaseAt: ts,
|
|
101
|
-
lastPurchaseAmountMicros: amountMicros,
|
|
102
|
-
currentBalanceMicros: Math.max(0, balanceMicros),
|
|
103
|
-
leftoverCreditMicros: previous?.leftoverCreditMicros ?? 0,
|
|
104
|
-
lastUpdatedAt: ts
|
|
105
|
-
};
|
|
106
|
-
this.entries.set(sellerId, entry);
|
|
107
|
-
this.purchaseTimestamps.push(ts);
|
|
108
|
-
this.prunePurchaseTimestamps(ts);
|
|
109
|
-
logger.info("credit.purchase.recorded", "seller credit purchase recorded", {
|
|
110
|
-
sellerId,
|
|
111
|
-
amountMicros,
|
|
112
|
-
balanceMicros: entry.currentBalanceMicros,
|
|
113
|
-
purchasesInLastMinute: this.purchaseTimestamps.length
|
|
114
|
-
});
|
|
115
|
-
return entry;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Update the seller's current balance after a successful inference. The
|
|
120
|
-
* amount spent is implicit (`previous - next`) so the caller does not
|
|
121
|
-
* have to track it. A non-positive `balanceMicros` is treated as 0.
|
|
122
|
-
*/
|
|
123
|
-
recordSpend(sellerId: string, balanceMicros: number): SellerCredit | undefined {
|
|
124
|
-
const previous = this.entries.get(sellerId);
|
|
125
|
-
if (!previous) {
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
|
-
const next: SellerCredit = {
|
|
129
|
-
...previous,
|
|
130
|
-
currentBalanceMicros: Math.max(0, balanceMicros),
|
|
131
|
-
lastUpdatedAt: this.now()
|
|
132
|
-
};
|
|
133
|
-
this.entries.set(sellerId, next);
|
|
134
|
-
return next;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Move the seller's remaining balance to the `leftoverCreditMicros`
|
|
139
|
-
* bucket. Called when failover triggers while a balance is still
|
|
140
|
-
* available. The pool's pre-warm / probe logic can later attempt to
|
|
141
|
-
* consume the leftover credit (see PR-3.1). The wasted amount is also
|
|
142
|
-
* added to the session-level counters.
|
|
143
|
-
*/
|
|
144
|
-
transferLeftoverToWasted(sellerId: string, reason: string): number {
|
|
145
|
-
const previous = this.entries.get(sellerId);
|
|
146
|
-
if (!previous) {
|
|
147
|
-
return 0;
|
|
148
|
-
}
|
|
149
|
-
const wasted = previous.currentBalanceMicros;
|
|
150
|
-
if (wasted <= 0) {
|
|
151
|
-
return 0;
|
|
152
|
-
}
|
|
153
|
-
const next: SellerCredit = {
|
|
154
|
-
...previous,
|
|
155
|
-
currentBalanceMicros: 0,
|
|
156
|
-
leftoverCreditMicros: previous.leftoverCreditMicros + wasted,
|
|
157
|
-
lastUpdatedAt: this.now()
|
|
158
|
-
};
|
|
159
|
-
this.entries.set(sellerId, next);
|
|
160
|
-
this.totalWastedMicros += wasted;
|
|
161
|
-
this.wastedSinceLastDoctorRun += wasted;
|
|
162
|
-
logger.warn("credit.leftover.wasted", "leftover credit logged as wasted on failover", {
|
|
163
|
-
sellerId,
|
|
164
|
-
wastedMicros: wasted,
|
|
165
|
-
reason,
|
|
166
|
-
totalWastedMicros: this.totalWastedMicros
|
|
167
|
-
});
|
|
168
|
-
return wasted;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Consume leftover credit when the seller recovers and a probe
|
|
173
|
-
* successfully burns it down. Returns the amount actually consumed.
|
|
174
|
-
*/
|
|
175
|
-
consumeLeftover(sellerId: string, amountMicros: number): number {
|
|
176
|
-
const previous = this.entries.get(sellerId);
|
|
177
|
-
if (!previous || previous.leftoverCreditMicros <= 0) {
|
|
178
|
-
return 0;
|
|
179
|
-
}
|
|
180
|
-
const consume = Math.max(0, Math.min(amountMicros, previous.leftoverCreditMicros));
|
|
181
|
-
if (consume <= 0) {
|
|
182
|
-
return 0;
|
|
183
|
-
}
|
|
184
|
-
const next: SellerCredit = {
|
|
185
|
-
...previous,
|
|
186
|
-
leftoverCreditMicros: previous.leftoverCreditMicros - consume,
|
|
187
|
-
lastUpdatedAt: this.now()
|
|
188
|
-
};
|
|
189
|
-
this.entries.set(sellerId, next);
|
|
190
|
-
logger.info("credit.leftover.consumed", "leftover credit consumed by recovery probe", {
|
|
191
|
-
sellerId,
|
|
192
|
-
consumedMicros: consume,
|
|
193
|
-
remainingMicros: next.leftoverCreditMicros
|
|
194
|
-
});
|
|
195
|
-
return consume;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Returns `true` when the seller is still inside the fresh-purchase
|
|
200
|
-
* window: at least `freshPurchaseThreshold` of the most recent
|
|
201
|
-
* purchase is still unused, and the window has not elapsed. Sellers
|
|
202
|
-
* with no recorded purchase are never "fresh".
|
|
203
|
-
*/
|
|
204
|
-
isInFreshPurchaseWindow(sellerId: string, now: number = this.now()): boolean {
|
|
205
|
-
const entry = this.entries.get(sellerId);
|
|
206
|
-
if (!entry || entry.lastPurchaseAmountMicros <= 0) {
|
|
207
|
-
return false;
|
|
208
|
-
}
|
|
209
|
-
if (now - entry.lastPurchaseAt > this.freshPurchaseWindowMs) {
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
212
|
-
const ratio = entry.currentBalanceMicros / entry.lastPurchaseAmountMicros;
|
|
213
|
-
return ratio >= this.freshPurchaseThreshold;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Returns `true` when the per-minute auto-purchase budget is still
|
|
218
|
-
* available. Used by `route-failover` to refuse auto-repurchase and
|
|
219
|
-
* force a clean `切` once the session is at risk of over-spending.
|
|
220
|
-
*/
|
|
221
|
-
canAutoPurchase(now: number = this.now()): boolean {
|
|
222
|
-
this.prunePurchaseTimestamps(now);
|
|
223
|
-
return this.purchaseTimestamps.length < this.purchaseBudgetPerMinute;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Snapshot for `tb doctor`. Mirrors the design's "Credit Usage" block.
|
|
228
|
-
*/
|
|
229
|
-
summary(): CreditSummary {
|
|
230
|
-
return {
|
|
231
|
-
totalWastedMicros: this.totalWastedMicros,
|
|
232
|
-
wastedSinceLastDoctorRun: this.wastedSinceLastDoctorRun,
|
|
233
|
-
purchasesInLastMinute: this.purchaseTimestamps.length,
|
|
234
|
-
purchaseBudgetPerMinute: this.purchaseBudgetPerMinute,
|
|
235
|
-
freshPurchaseWindowMs: this.freshPurchaseWindowMs,
|
|
236
|
-
freshPurchaseThreshold: this.freshPurchaseThreshold,
|
|
237
|
-
perSeller: Array.from(this.entries.values()).map((entry) => ({
|
|
238
|
-
sellerId: entry.sellerId,
|
|
239
|
-
currentBalanceMicros: entry.currentBalanceMicros,
|
|
240
|
-
lastPurchaseAmountMicros: entry.lastPurchaseAmountMicros,
|
|
241
|
-
lastPurchaseAt: entry.lastPurchaseAt,
|
|
242
|
-
leftoverCreditMicros: entry.leftoverCreditMicros
|
|
243
|
-
}))
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
getEntry(sellerId: string): SellerCredit | undefined {
|
|
248
|
-
return this.entries.get(sellerId);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
resetDoctorRunCounter(): void {
|
|
252
|
-
this.wastedSinceLastDoctorRun = 0;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
clear(): void {
|
|
256
|
-
this.entries.clear();
|
|
257
|
-
this.purchaseTimestamps.length = 0;
|
|
258
|
-
this.totalWastedMicros = 0;
|
|
259
|
-
this.wastedSinceLastDoctorRun = 0;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
private prunePurchaseTimestamps(now: number): void {
|
|
263
|
-
const cutoff = now - 60_000;
|
|
264
|
-
while (this.purchaseTimestamps.length > 0 && this.purchaseTimestamps[0] < cutoff) {
|
|
265
|
-
this.purchaseTimestamps.shift();
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* `CreditTracker.summary()` 的返回结构,对应 design doc 的 "Credit Usage" 块。
|
|
272
|
-
* `tb doctor` 直接消费此结构展示给用户。
|
|
273
|
-
*/
|
|
274
|
-
export interface CreditSummary {
|
|
275
|
-
/** 自 tracker 创建以来累计浪费的 micros(含 failover 触发时的余额残留) */
|
|
276
|
-
totalWastedMicros: number;
|
|
277
|
-
/** 上次 `resetDoctorRunCounter()` 之后又新产生的浪费 micros(doctor 显示 delta) */
|
|
278
|
-
wastedSinceLastDoctorRun: number;
|
|
279
|
-
/** 过去 60 秒内自动购买次数 */
|
|
280
|
-
purchasesInLastMinute: number;
|
|
281
|
-
/** 每分钟自动购买上限 */
|
|
282
|
-
purchaseBudgetPerMinute: number;
|
|
283
|
-
/** 当前 fresh-purchase 窗口长度(毫秒) */
|
|
284
|
-
freshPurchaseWindowMs: number;
|
|
285
|
-
/** 当前 fresh-purchase 比例阈值 */
|
|
286
|
-
freshPurchaseThreshold: number;
|
|
287
|
-
/** 每个 seller 的余额快照 */
|
|
288
|
-
perSeller: Array<{
|
|
289
|
-
sellerId: string;
|
|
290
|
-
currentBalanceMicros: number;
|
|
291
|
-
lastPurchaseAmountMicros: number;
|
|
292
|
-
lastPurchaseAt: number;
|
|
293
|
-
leftoverCreditMicros: number;
|
|
294
|
-
}>;
|
|
295
|
-
}
|