@gamegeek-saikel/dsh-cost-meter 0.1.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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +116 -0
  3. package/README.zh-CN.md +116 -0
  4. package/cordis.patch.yml +12 -0
  5. package/lib/client.js +1481 -0
  6. package/lib/client.js.map +1 -0
  7. package/lib/index.js +2403 -0
  8. package/lib/invariant.js +38 -0
  9. package/lib/types/client/AssistantCostChip.d.ts +29 -0
  10. package/lib/types/client/AssistantCostChip.d.ts.map +1 -0
  11. package/lib/types/client/AssistantCostChip.js +75 -0
  12. package/lib/types/client/CostPluginCard.d.ts +10 -0
  13. package/lib/types/client/CostPluginCard.d.ts.map +1 -0
  14. package/lib/types/client/CostPluginCard.js +124 -0
  15. package/lib/types/client/CostView.d.ts +10 -0
  16. package/lib/types/client/CostView.d.ts.map +1 -0
  17. package/lib/types/client/CostView.js +66 -0
  18. package/lib/types/client/SessionCostLine.d.ts +21 -0
  19. package/lib/types/client/SessionCostLine.d.ts.map +1 -0
  20. package/lib/types/client/SessionCostLine.js +173 -0
  21. package/lib/types/client/SessionCostPill.d.ts +13 -0
  22. package/lib/types/client/SessionCostPill.d.ts.map +1 -0
  23. package/lib/types/client/SessionCostPill.js +123 -0
  24. package/lib/types/client/cost-math.d.ts +88 -0
  25. package/lib/types/client/cost-math.d.ts.map +1 -0
  26. package/lib/types/client/cost-math.js +199 -0
  27. package/lib/types/client/format.d.ts +35 -0
  28. package/lib/types/client/format.d.ts.map +1 -0
  29. package/lib/types/client/format.js +61 -0
  30. package/lib/types/client/index.d.ts +28 -0
  31. package/lib/types/client/index.d.ts.map +1 -0
  32. package/lib/types/client/index.js +59 -0
  33. package/lib/types/client/locales.d.ts +78 -0
  34. package/lib/types/client/locales.d.ts.map +1 -0
  35. package/lib/types/client/locales.js +149 -0
  36. package/lib/types/index.d.ts +136 -0
  37. package/lib/types/index.d.ts.map +1 -0
  38. package/lib/types/index.js +401 -0
  39. package/lib/types/invariant.d.ts +16 -0
  40. package/lib/types/invariant.d.ts.map +1 -0
  41. package/lib/types/invariant.js +38 -0
  42. package/lib/types/pricebook.d.ts +467 -0
  43. package/lib/types/pricebook.d.ts.map +1 -0
  44. package/lib/types/pricebook.js +696 -0
  45. package/lib/types/pricing.d.ts +93 -0
  46. package/lib/types/pricing.d.ts.map +1 -0
  47. package/lib/types/pricing.js +346 -0
  48. package/lib/types/session-cost-projection.d.ts +70 -0
  49. package/lib/types/session-cost-projection.d.ts.map +1 -0
  50. package/lib/types/session-cost-projection.js +198 -0
  51. package/lib/types/subagent-cost.d.ts +51 -0
  52. package/lib/types/subagent-cost.d.ts.map +1 -0
  53. package/lib/types/subagent-cost.js +79 -0
  54. package/lib/types/types.d.ts +334 -0
  55. package/lib/types/types.d.ts.map +1 -0
  56. package/lib/types/types.js +6 -0
  57. package/package.json +134 -0
  58. package/src/client/AssistantCostChip.module.css +81 -0
  59. package/src/client/AssistantCostChip.tsx +109 -0
  60. package/src/client/CostPluginCard.module.css +186 -0
  61. package/src/client/CostPluginCard.tsx +264 -0
  62. package/src/client/CostView.module.css +168 -0
  63. package/src/client/CostView.tsx +145 -0
  64. package/src/client/SessionCostLine.module.css +19 -0
  65. package/src/client/SessionCostLine.tsx +186 -0
  66. package/src/client/SessionCostPill.module.css +118 -0
  67. package/src/client/SessionCostPill.tsx +192 -0
  68. package/src/client/cost-math.ts +230 -0
  69. package/src/client/format.ts +63 -0
  70. package/src/client/index.ts +108 -0
  71. package/src/client/locales.ts +165 -0
  72. package/src/css-modules.d.ts +4 -0
  73. package/src/index.ts +489 -0
  74. package/src/invariant.ts +47 -0
  75. package/src/pricebook.ts +825 -0
  76. package/src/pricing.ts +378 -0
  77. package/src/session-cost-projection.ts +238 -0
  78. package/src/subagent-cost.ts +105 -0
  79. package/src/types.ts +364 -0
@@ -0,0 +1,467 @@
1
+ /**
2
+ * The pricebook: the durable price source with append-only snapshot history.
3
+ *
4
+ * Every model resolves its price through a fixed priority chain — manual
5
+ * override > official pricing page > built-in fallback > OpenRouter (fallback
6
+ * only, USD→CNY) > none. Any change to the resolved per-model table starts a
7
+ * new immutable {@link PricebookSnapshot} (monotonic `version`); every
8
+ * session-cost fold anchors to the snapshot effective at the priced event's
9
+ * own time, so a later price change never rewrites an already-written row.
10
+ *
11
+ * The pricebook state persists on the `pricebook` storage domain (global
12
+ * slot): snapshot history plus the editable configuration (overrides,
13
+ * aliases, cache-read discount, exchange rate, toggles). The in-memory
14
+ * mirror is the synchronous read face for the projection fold; the domain
15
+ * write is a queued, fail-soft side effect.
16
+ *
17
+ * @module @gamegeek-saikel/dsh-cost-meter/pricebook
18
+ */
19
+ import type { Context } from '@deepseek-ai/cordis';
20
+ import { z } from 'zod';
21
+ import type { Currency, CurrentPricing, FxConfig, ModelPrice, PeakPricing, PriceBand, PricebookSnapshot, PricebookState, PricebookView, PriceBucket, PriceSource, PricingSnapshot } from './types.ts';
22
+ /** Default manual rate used when auto-fetch fails and nothing was ever fetched. */
23
+ export declare const DEFAULT_FX_RATE = 7.2;
24
+ /** Default OpenRouter cache-read fraction of the uncached input price. */
25
+ export declare const DEFAULT_CACHE_READ_DISCOUNT = 0.25;
26
+ /** Default OpenRouter model-id → canonical key aliases (editable). */
27
+ export declare const DEFAULT_ALIASES: Record<string, string>;
28
+ /** Free exchange-rate endpoint (no key); returns `rates.CNY` for USD base. */
29
+ export declare const FX_API_URL = "https://open.er-api.com/v6/latest/USD";
30
+ /** OpenRouter models directory (prices in USD per token). */
31
+ export declare const OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
32
+ /** Default cap on the persisted snapshot history. */
33
+ export declare const DEFAULT_SNAPSHOT_HISTORY_LIMIT = 50;
34
+ /** Fresh pricebook state before any user configuration exists. */
35
+ export declare function initialPricebookState(): PricebookState;
36
+ /**
37
+ * The pricebook storage domain. One global slot holds the whole state; the
38
+ * domain name (`pricebook`) is unused by any shipped row, so the open never
39
+ * collides with `already-open`.
40
+ */
41
+ export declare const PRICEBOOK_DOMAIN: {
42
+ name: string;
43
+ version: number;
44
+ global: {
45
+ schema: z.ZodObject<{
46
+ snapshots: z.ZodArray<z.ZodObject<{
47
+ version: z.ZodNumber;
48
+ currency: z.ZodDefault<z.ZodEnum<{
49
+ CNY: "CNY";
50
+ USD: "USD";
51
+ }>>;
52
+ effectiveAt: z.ZodNumber;
53
+ source: z.ZodEnum<{
54
+ manual: "manual";
55
+ official: "official";
56
+ fallback: "fallback";
57
+ openrouter: "openrouter";
58
+ none: "none";
59
+ }>;
60
+ usdCnyRate: z.ZodNullable<z.ZodNumber>;
61
+ prices: z.ZodRecord<z.ZodString, z.ZodObject<{
62
+ source: z.ZodEnum<{
63
+ manual: "manual";
64
+ official: "official";
65
+ fallback: "fallback";
66
+ openrouter: "openrouter";
67
+ none: "none";
68
+ }>;
69
+ single: z.ZodOptional<z.ZodObject<{
70
+ cacheReadPerMillion: z.ZodNumber;
71
+ inputPerMillion: z.ZodNumber;
72
+ outputPerMillion: z.ZodNumber;
73
+ }, z.core.$strict>>;
74
+ offPeak: z.ZodOptional<z.ZodObject<{
75
+ cacheReadPerMillion: z.ZodNumber;
76
+ inputPerMillion: z.ZodNumber;
77
+ outputPerMillion: z.ZodNumber;
78
+ }, z.core.$strict>>;
79
+ peak: z.ZodOptional<z.ZodObject<{
80
+ cacheReadPerMillion: z.ZodNumber;
81
+ inputPerMillion: z.ZodNumber;
82
+ outputPerMillion: z.ZodNumber;
83
+ }, z.core.$strict>>;
84
+ }, z.core.$strict>>;
85
+ }, z.core.$strict>>;
86
+ overrides: z.ZodRecord<z.ZodString, z.ZodObject<{
87
+ source: z.ZodEnum<{
88
+ manual: "manual";
89
+ official: "official";
90
+ fallback: "fallback";
91
+ openrouter: "openrouter";
92
+ none: "none";
93
+ }>;
94
+ single: z.ZodOptional<z.ZodObject<{
95
+ cacheReadPerMillion: z.ZodNumber;
96
+ inputPerMillion: z.ZodNumber;
97
+ outputPerMillion: z.ZodNumber;
98
+ }, z.core.$strict>>;
99
+ offPeak: z.ZodOptional<z.ZodObject<{
100
+ cacheReadPerMillion: z.ZodNumber;
101
+ inputPerMillion: z.ZodNumber;
102
+ outputPerMillion: z.ZodNumber;
103
+ }, z.core.$strict>>;
104
+ peak: z.ZodOptional<z.ZodObject<{
105
+ cacheReadPerMillion: z.ZodNumber;
106
+ inputPerMillion: z.ZodNumber;
107
+ outputPerMillion: z.ZodNumber;
108
+ }, z.core.$strict>>;
109
+ }, z.core.$strict>>;
110
+ aliases: z.ZodRecord<z.ZodString, z.ZodString>;
111
+ cacheReadDiscount: z.ZodNumber;
112
+ fx: z.ZodObject<{
113
+ mode: z.ZodEnum<{
114
+ manual: "manual";
115
+ auto: "auto";
116
+ }>;
117
+ manualRate: z.ZodNumber;
118
+ lastAutoRate: z.ZodOptional<z.ZodNumber>;
119
+ rateFetchedAt: z.ZodOptional<z.ZodNumber>;
120
+ }, z.core.$strict>;
121
+ balanceEnabled: z.ZodBoolean;
122
+ openRouterEnabled: z.ZodBoolean;
123
+ updatedAt: z.ZodNumber;
124
+ }, z.core.$strict>;
125
+ initial: PricebookState;
126
+ };
127
+ tables: {};
128
+ };
129
+ /** USD pricebook storage domain, kept separate from the CNY domain. */
130
+ export declare const PRICEBOOK_DOMAIN_USD: {
131
+ name: string;
132
+ version: number;
133
+ global: {
134
+ schema: z.ZodObject<{
135
+ snapshots: z.ZodArray<z.ZodObject<{
136
+ version: z.ZodNumber;
137
+ currency: z.ZodDefault<z.ZodEnum<{
138
+ CNY: "CNY";
139
+ USD: "USD";
140
+ }>>;
141
+ effectiveAt: z.ZodNumber;
142
+ source: z.ZodEnum<{
143
+ manual: "manual";
144
+ official: "official";
145
+ fallback: "fallback";
146
+ openrouter: "openrouter";
147
+ none: "none";
148
+ }>;
149
+ usdCnyRate: z.ZodNullable<z.ZodNumber>;
150
+ prices: z.ZodRecord<z.ZodString, z.ZodObject<{
151
+ source: z.ZodEnum<{
152
+ manual: "manual";
153
+ official: "official";
154
+ fallback: "fallback";
155
+ openrouter: "openrouter";
156
+ none: "none";
157
+ }>;
158
+ single: z.ZodOptional<z.ZodObject<{
159
+ cacheReadPerMillion: z.ZodNumber;
160
+ inputPerMillion: z.ZodNumber;
161
+ outputPerMillion: z.ZodNumber;
162
+ }, z.core.$strict>>;
163
+ offPeak: z.ZodOptional<z.ZodObject<{
164
+ cacheReadPerMillion: z.ZodNumber;
165
+ inputPerMillion: z.ZodNumber;
166
+ outputPerMillion: z.ZodNumber;
167
+ }, z.core.$strict>>;
168
+ peak: z.ZodOptional<z.ZodObject<{
169
+ cacheReadPerMillion: z.ZodNumber;
170
+ inputPerMillion: z.ZodNumber;
171
+ outputPerMillion: z.ZodNumber;
172
+ }, z.core.$strict>>;
173
+ }, z.core.$strict>>;
174
+ }, z.core.$strict>>;
175
+ overrides: z.ZodRecord<z.ZodString, z.ZodObject<{
176
+ source: z.ZodEnum<{
177
+ manual: "manual";
178
+ official: "official";
179
+ fallback: "fallback";
180
+ openrouter: "openrouter";
181
+ none: "none";
182
+ }>;
183
+ single: z.ZodOptional<z.ZodObject<{
184
+ cacheReadPerMillion: z.ZodNumber;
185
+ inputPerMillion: z.ZodNumber;
186
+ outputPerMillion: z.ZodNumber;
187
+ }, z.core.$strict>>;
188
+ offPeak: z.ZodOptional<z.ZodObject<{
189
+ cacheReadPerMillion: z.ZodNumber;
190
+ inputPerMillion: z.ZodNumber;
191
+ outputPerMillion: z.ZodNumber;
192
+ }, z.core.$strict>>;
193
+ peak: z.ZodOptional<z.ZodObject<{
194
+ cacheReadPerMillion: z.ZodNumber;
195
+ inputPerMillion: z.ZodNumber;
196
+ outputPerMillion: z.ZodNumber;
197
+ }, z.core.$strict>>;
198
+ }, z.core.$strict>>;
199
+ aliases: z.ZodRecord<z.ZodString, z.ZodString>;
200
+ cacheReadDiscount: z.ZodNumber;
201
+ fx: z.ZodObject<{
202
+ mode: z.ZodEnum<{
203
+ manual: "manual";
204
+ auto: "auto";
205
+ }>;
206
+ manualRate: z.ZodNumber;
207
+ lastAutoRate: z.ZodOptional<z.ZodNumber>;
208
+ rateFetchedAt: z.ZodOptional<z.ZodNumber>;
209
+ }, z.core.$strict>;
210
+ balanceEnabled: z.ZodBoolean;
211
+ openRouterEnabled: z.ZodBoolean;
212
+ updatedAt: z.ZodNumber;
213
+ }, z.core.$strict>;
214
+ initial: PricebookState;
215
+ };
216
+ tables: {};
217
+ };
218
+ /**
219
+ * Map a model id to its official pricing key: anything containing `pro`
220
+ * prices as pro, `flash` as flash. Mirror of the client-side helper.
221
+ * @param model - the model id.
222
+ * @returns the pricing key.
223
+ */
224
+ export declare function pricingKeyOfModel(model: string): 'pro' | 'flash';
225
+ /**
226
+ * Candidate canonical price keys for one model, most specific first. The
227
+ * pricing-key fallbacks (`pro`/`flash`) only apply to DeepSeek-family models
228
+ * (id or provider names deepseek): an unrelated model must NOT silently pick
229
+ * up the flash list price — it either resolves through an override, an
230
+ * OpenRouter alias, or stays unpriced.
231
+ * @param provider - the provider route, when known.
232
+ * @param model - the model id.
233
+ * @returns candidate keys in lookup order.
234
+ */
235
+ export declare function modelKeys(provider: string | undefined, model: string): string[];
236
+ /**
237
+ * The price band in effect at one instant: pre-rollout single price, or the
238
+ * peak/off-peak band once the rollout is live.
239
+ * @param time - epoch millis.
240
+ * @returns the band.
241
+ */
242
+ export declare function bandForTime(time: number): PriceBand;
243
+ /**
244
+ * The bucket of one model's price entry for one band, with graceful
245
+ * degradation to whatever tier exists.
246
+ * @param modelPrice - the model's price entry.
247
+ * @param band - the band to price for.
248
+ * @returns the bucket, or undefined when the entry carries no tier at all.
249
+ */
250
+ export declare function bucketOf(modelPrice: ModelPrice, band: PriceBand): PriceBucket | undefined;
251
+ /**
252
+ * Resolve one model's bucket at one instant from its price entry.
253
+ * @param modelPrice - the model's price entry.
254
+ * @param time - the instant to price for.
255
+ * @returns the bucket and band, or null when the entry has no tier.
256
+ */
257
+ export declare function priceAt(modelPrice: ModelPrice, time: number): {
258
+ bucket: PriceBucket;
259
+ band: PriceBand;
260
+ } | null;
261
+ /**
262
+ * Pick the snapshot effective at `time`: the newest with `effectiveAt <=
263
+ * time`, or the earliest available when no snapshot predates it (pre-install
264
+ * sessions anchor to the first snapshot once, as required).
265
+ * @param snapshots - the snapshot history, any order.
266
+ * @param time - the instant to anchor.
267
+ * @returns the snapshot, or undefined when the history is empty.
268
+ */
269
+ export declare function snapshotForTime(snapshots: readonly PricebookSnapshot[], time: number): PricebookSnapshot | undefined;
270
+ /** The disjoint usage buckets one step reports. */
271
+ export interface StepUsage {
272
+ uncached: number;
273
+ cacheRead: number;
274
+ cacheWrite: number;
275
+ output: number;
276
+ }
277
+ /**
278
+ * The official cost formula, per million tokens: uncached input + cache
279
+ * reads at the hit rate + cache writes at the uncached input rate (DeepSeek
280
+ * reports only hit/miss buckets and bills writes as misses) + output.
281
+ * @param usage - the step's token buckets.
282
+ * @param bucket - the effective price bucket.
283
+ * @returns the cost in the bucket's currency (CNY).
284
+ */
285
+ export declare function stepCost(usage: StepUsage, bucket: PriceBucket): number;
286
+ /**
287
+ * Whether two per-model price tables are equivalent (epsilon-compared).
288
+ * Used to skip a new snapshot when a refresh changed nothing user-visible.
289
+ */
290
+ export declare function pricesEqual(left: Record<string, ModelPrice>, right: Record<string, ModelPrice>): boolean;
291
+ /** Normalized official-page input: the parsed lists plus the failure marker. */
292
+ export interface OfficialPricingInput {
293
+ /** Current (pre-rollout) list — the built-in fallback when the fetch failed. */
294
+ current: CurrentPricing;
295
+ /** Peak/off-peak table, when the page carried it. */
296
+ peak?: PeakPricing;
297
+ /** Fetch/parse failure reason; set when `current` is the fallback table. */
298
+ error?: string;
299
+ }
300
+ /** Normalized OpenRouter input: USD per 1M tokens per model id. */
301
+ export interface OpenRouterInput {
302
+ /** Model id → USD per 1M tokens (already scaled from the per-token wire values). */
303
+ usdPrices: Record<string, {
304
+ inputPerMillionUsd: number;
305
+ outputPerMillionUsd: number;
306
+ }>;
307
+ /** Fetch failure reason. */
308
+ error?: string;
309
+ }
310
+ /** Effective USD→CNY rate from the configured mode plus fallbacks. */
311
+ export declare function effectiveRate(fx: FxConfig, defaultRate: number): number;
312
+ /**
313
+ * Merge every source into one per-model price table through the priority
314
+ * chain: manual overrides win; official (or the built-in fallback when the
315
+ * page failed) covers the flash/pro pricing keys; OpenRouter covers only
316
+ * models with no domestic price (fallback-only, USD→CNY, cache reads at the
317
+ * configured discount). OpenRouter prices land under the aliased canonical
318
+ * key so unaliased model ids still resolve through the key chain.
319
+ * @param state - the pricebook state (overrides, aliases, discount, fx).
320
+ * @param official - the official-page input (fallback table on failure).
321
+ * @param openrouter - the OpenRouter input, or null when disabled/failed.
322
+ * @param usdCnyRate - the effective exchange rate.
323
+ * @param defaultRate - the configuration default rate (fallback chain end).
324
+ * @returns the merged table and the highest-priority contributing source.
325
+ */
326
+ export declare function computePricebook(state: PricebookState, official: OfficialPricingInput, openrouter: OpenRouterInput | null, usdCnyRate: number, defaultRate: number, fallbackPeak?: PeakPricing, currency?: Currency): {
327
+ prices: Record<string, ModelPrice>;
328
+ primarySource: PriceSource;
329
+ };
330
+ /**
331
+ * Fetch the USD→CNY rate from the free endpoint. Never throws; the caller
332
+ * applies the fallback chain (last auto rate → manual/default rate).
333
+ * @param fetchImpl - fetch-compatible function (injected for testability).
334
+ * @param url - the endpoint.
335
+ * @param timeoutMs - abort timeout.
336
+ * @returns the fresh rate, or an error result.
337
+ */
338
+ export declare function fetchFxRate(fetchImpl?: typeof fetch, url?: string, timeoutMs?: number): Promise<{
339
+ rate: number | null;
340
+ error?: string;
341
+ }>;
342
+ /**
343
+ * Fetch the OpenRouter models directory and fold it into USD-per-1M-token
344
+ * buckets. Every entry with a valid prompt/completion price is kept: the
345
+ * directory is small (a few hundred rows) and the alias map is editable, so
346
+ * a newly aliased model must resolve without waiting for the next refresh.
347
+ * Never throws.
348
+ * @param fetchImpl - fetch-compatible function (injected for testability).
349
+ * @param url - the directory endpoint.
350
+ * @param timeoutMs - abort timeout.
351
+ * @param aliases - the current alias map (kept for parity, not used as a filter).
352
+ * @returns the model price table, or an error result.
353
+ */
354
+ export declare function fetchOpenRouter(fetchImpl?: typeof fetch, url?: string, timeoutMs?: number, aliases?: Record<string, string>): Promise<OpenRouterInput>;
355
+ /** Fold a raw {@link PricingSnapshot} into the pricebook's official input. */
356
+ export declare function officialInputOf(snapshot: PricingSnapshot): OfficialPricingInput;
357
+ export interface PricebookResolvedConfig {
358
+ fxApiUrl: string;
359
+ defaultFxRate: number;
360
+ openRouterModelsUrl: string;
361
+ openRouterEnabled: boolean;
362
+ snapshotHistoryLimit: number;
363
+ }
364
+ /** Result of one price lookup: the bucket, band, and the snapshot it anchored to. */
365
+ export interface PriceHit {
366
+ bucket: PriceBucket;
367
+ band: PriceBand;
368
+ source: PriceSource;
369
+ snapshotVersion: number;
370
+ snapshotEffectiveAt: number;
371
+ }
372
+ /**
373
+ * The synchronous read face the sessionCost projection folds against, plus
374
+ * the mutation/refresh/persist surface the plugin's apply and route use.
375
+ * Reads never touch the domain (mirror only); writes update the mirror first,
376
+ * then queue a fail-soft durable write.
377
+ */
378
+ export declare class PricebookHandle {
379
+ private readonly ctx;
380
+ private readonly config;
381
+ private readonly currency;
382
+ /** The authoritative in-memory state (mirror of the domain global). */
383
+ state: PricebookState;
384
+ private domain;
385
+ private persistTail;
386
+ private lastOfficial;
387
+ private lastOpenRouter;
388
+ private lastFxError;
389
+ private fetchedAt;
390
+ constructor(ctx: Context, config: PricebookResolvedConfig, persisted: PricebookState | undefined, currency?: Currency);
391
+ /**
392
+ * Open the storage domain and adopt the persisted state. Never throws:
393
+ * a missing storageDomain or a failed open degrades to in-memory only.
394
+ */
395
+ init(): Promise<void>;
396
+ /** Queue one durable write of the whole state (fail-soft, serialized). */
397
+ private persist;
398
+ /** Resolve once every queued durable write has settled. */
399
+ whenIdle(): Promise<void>;
400
+ /** Release the domain (called from the plugin's disposer). */
401
+ close(): Promise<void>;
402
+ /** The newest snapshot, or undefined before the first refresh. */
403
+ currentSnapshot(): PricebookSnapshot | undefined;
404
+ /** Pick the snapshot effective at `time`. */
405
+ snapshotFor(time: number): PricebookSnapshot | undefined;
406
+ /**
407
+ * Resolve the price of one model at one instant through the key chain and
408
+ * the anchored snapshot. Synchronous: the fold calls this per usage event.
409
+ * @param provider - the provider route, when known.
410
+ * @param model - the model id.
411
+ * @param time - the instant to price for.
412
+ * @returns the hit, or null when no source carries a price.
413
+ */
414
+ priceFor(provider: string | undefined, model: string, time: number): PriceHit | null;
415
+ /** The effective USD→CNY rate under the current configuration. */
416
+ private rate;
417
+ /** Cap the snapshot history to the configured limit (newest kept). */
418
+ private capSnapshots;
419
+ /**
420
+ * Recompute the resolved table from the cached inputs and start a new
421
+ * snapshot when anything user-visible changed. Shared by the startup
422
+ * refresh, the periodic refresh, the manual refresh, and every settings
423
+ * mutation.
424
+ */
425
+ private recompute;
426
+ /**
427
+ * Refresh every remote source (official page, exchange rate, OpenRouter
428
+ * when enabled) and re-anchor a snapshot on change. Never throws.
429
+ * @param options - injected results (testability); omitted values are fetched.
430
+ */
431
+ refresh(options?: {
432
+ official?: PricingSnapshot;
433
+ fx?: {
434
+ rate: number | null;
435
+ error?: string;
436
+ };
437
+ openrouter?: OpenRouterInput;
438
+ }): Promise<void>;
439
+ private applyFxResult;
440
+ /** Apply a settings mutation and re-anchor (snapshot on change). */
441
+ private mutate;
442
+ setOverrides(overrides: Record<string, ModelPrice>): Promise<void>;
443
+ setAliases(aliases: Record<string, string>): Promise<void>;
444
+ setCacheReadDiscount(discount: number): Promise<void>;
445
+ setFx(mode: FxConfig['mode'], manualRate: number): Promise<void>;
446
+ setBalanceEnabled(enabled: boolean): Promise<void>;
447
+ setOpenRouterEnabled(enabled: boolean): Promise<void>;
448
+ /**
449
+ * Apply a resolved plugin-settings snapshot (the `cost-meter`
450
+ * settings namespace) to the pricebook: the editable configuration fields
451
+ * overwrite the persisted state and the resolved table re-anchors (a new
452
+ * snapshot starts when anything user-visible changed). Never throws.
453
+ * @param settings - the settings-section value (may carry only a subset).
454
+ */
455
+ applySettings(settings: Partial<{
456
+ overrides: Record<string, ModelPrice> | undefined;
457
+ aliases: Record<string, string> | undefined;
458
+ cacheReadDiscount: number | undefined;
459
+ fxMode: 'auto' | 'manual' | undefined;
460
+ manualRate: number | undefined;
461
+ balanceEnabled: boolean | undefined;
462
+ openRouterEnabled: boolean | undefined;
463
+ }>): void;
464
+ /** The read-side payload for the route. */
465
+ view(): PricebookView;
466
+ }
467
+ //# sourceMappingURL=pricebook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricebook.d.ts","sourceRoot":"","sources":["../../src/pricebook.ts"],"names":[],"mappings":"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"}