@cat-factory/spend 0.14.15 → 0.15.1

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.
@@ -2,6 +2,7 @@ import type { BudgetCaps, OpenRouterModelMeta, SpendStatus } from '@cat-factory/
2
2
  import type { AgentTokenUsage } from '@cat-factory/kernel';
3
3
  import type { Clock, IdGenerator } from '@cat-factory/kernel';
4
4
  import type { AccountRepository, BudgetLimitCacheValue, GroupCacheHandle, TokenUsageRepository, UsageBilling, UsageBreakdownRow, UserSettingsRepository, WorkspaceSettingsCacheValue, WorkspaceSettingsRepository } from '@cat-factory/kernel';
5
+ import { type SpendAlertState, type SpendForecast } from './forecast.logic.js';
5
6
  import { type InputTokenClassUsage, type SpendPricing } from './pricing.js';
6
7
  export interface SpendServiceDependencies {
7
8
  tokenUsageRepository: TokenUsageRepository;
@@ -86,6 +87,25 @@ export interface RecordUsageInput {
86
87
  /** The subscription vendor for a `'subscription'` row (claude/codex/glm/kimi/deepseek). */
87
88
  vendor?: string | null;
88
89
  }
90
+ /**
91
+ * One scope's forward-looking spend position: where it stands, where it is heading, and which
92
+ * alert state that puts it in. Returned by {@link SpendService.forecastWorkspaces} /
93
+ * {@link SpendService.forecastAccounts}.
94
+ *
95
+ * `costLimit` and `currency` travel WITH the figures, never resolved again by a consumer: a
96
+ * workspace can override both, so a caller pairing an amount with the deployment's currency (or
97
+ * with another tier's limit) would put a wrong label on a right number.
98
+ */
99
+ export interface ScopedSpendForecast {
100
+ /** Metered spend so far this period, in `currency`. */
101
+ costSpent: number;
102
+ /** The scope's effective limit for the period, in `currency`. */
103
+ costLimit: number;
104
+ /** ISO 4217 currency both amounts are expressed in. */
105
+ currency: string;
106
+ forecast: SpendForecast;
107
+ alert: SpendAlertState;
108
+ }
89
109
  /** Which budget tiers to check when gating a run (the caller passes what ids it has). */
90
110
  export interface BudgetTierScope {
91
111
  accountId?: string | null;
@@ -128,6 +148,20 @@ export declare class SpendService {
128
148
  * next call). Falls back to the base table when no settings repository is wired.
129
149
  */
130
150
  private resolvePricing;
151
+ /**
152
+ * The same for MANY workspaces, as ONE batched settings read.
153
+ *
154
+ * Deliberately not `resolvePricing` in a loop: that is a point read per workspace, which is the
155
+ * banned N+1 the moment a caller holds a list, and the alert sweep holds every spending
156
+ * workspace in the deployment. The shared cache is bypassed rather than consulted per id
157
+ * because it would not help and would hurt: the isolate-safe (Worker) profile disables the
158
+ * `workspaceSettings` slice outright, so every lookup there is a real D1 round trip, and on Node
159
+ * a sweep touching every tenant would churn a cache sized for the hot single-workspace gate.
160
+ *
161
+ * Every requested id is present in the result; a workspace with no persisted overrides maps to
162
+ * the base table, exactly as the single-workspace read resolves it.
163
+ */
164
+ private resolvePricingMany;
131
165
  /**
132
166
  * Invalidate a cached account effective limit (called after an account-budget edit, via
133
167
  * `AccountService`'s budget-change callback). A no-op when no cache is wired.
@@ -144,6 +178,12 @@ export declare class SpendService {
144
178
  * limit is read through the shared `accountBudgetLimit` cache slice.
145
179
  */
146
180
  private resolveAccountLimit;
181
+ /**
182
+ * The same for MANY accounts, as ONE batched account read (see {@link resolvePricingMany} for
183
+ * why the per-id cache is bypassed rather than consulted). Every requested id is present:
184
+ * an account with no configured limit resolves to the env cap alone, `Infinity` when unset.
185
+ */
186
+ private resolveAccountLimits;
147
187
  /** The user tier's effective monthly limit (configured user limit clamped by the env cap). */
148
188
  private resolveUserLimit;
149
189
  /** Meter and persist one LLM call; returns its estimated cost. */
@@ -194,6 +234,23 @@ export declare class SpendService {
194
234
  userStatus(userId: string, preloaded?: {
195
235
  configuredLimit: number | null;
196
236
  }): Promise<SpendStatus | null>;
237
+ /**
238
+ * The forward-looking position of many WORKSPACES at once: burn rate, projected period
239
+ * total, and the alert state each is in. Advisory only: nothing here can pause a run.
240
+ *
241
+ * Batched because the alert sweep asks about every workspace in the deployment on every
242
+ * pass: two grouped ledger reads (period-to-date and the trailing burn-rate window) plus one
243
+ * batched settings read serve the whole set, where a per-workspace point read would be the
244
+ * banned N+1 run every few minutes across every tenant. Workspaces with no metered spend this
245
+ * period are absent from the result: they have nothing to forecast, and skipping them is what
246
+ * keeps a deployment full of quiet boards cheap to sweep. Their pricing is never resolved
247
+ * either, which is why the settings read follows the ledger reads instead of joining them.
248
+ */
249
+ forecastWorkspaces(workspaceIds: string[], now: number): Promise<Map<string, ScopedSpendForecast>>;
250
+ /** The same for the ACCOUNT tier, priced in the base currency (an account spans workspaces). */
251
+ forecastAccounts(accountIds: string[], now: number): Promise<Map<string, ScopedSpendForecast>>;
252
+ /** Assemble one scope's forecast + alert state from the reads above (pure beyond this point). */
253
+ private buildForecast;
197
254
  /** The operator hard ceilings on the account/user tiers, for the SPA budget screens. */
198
255
  budgetCaps(): BudgetCaps;
199
256
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"SpendService.d.ts","sourceRoot":"","sources":["../src/SpendService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SpendService.d.ts","sourceRoot":"","sources":["../src/SpendService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAC1F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAE1D,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAEhB,oBAAoB,EACpB,YAAY,EACZ,iBAAiB,EACjB,sBAAsB,EACtB,2BAA2B,EAC3B,2BAA2B,EAC5B,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,aAAa,EAGnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,YAAY,EAQlB,MAAM,cAAc,CAAA;AAErB,MAAM,WAAW,wBAAwB;IACvC,oBAAoB,EAAE,oBAAoB,CAAA;IAC1C,WAAW,EAAE,WAAW,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,8FAA8F;IAC9F,OAAO,EAAE,YAAY,CAAA;IACrB;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,2BAA2B,CAAA;IACzD;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,sBAAsB,CAAA;IAC/C;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAA;IAC1E;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,gBAAgB,CAAC,2BAA2B,CAAC,CAAA;IACtE,4FAA4F;IAC5F,uBAAuB,CAAC,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;IACjE,yFAAyF;IACzF,oBAAoB,CAAC,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;CAC/D;AAED,+EAA+E;AAC/E,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAA;IACnB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,KAAK,EAAE,eAAe,CAAA;IACtB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAA;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAA;IACjB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,aAAa,CAAA;IACvB,KAAK,EAAE,eAAe,CAAA;CACvB;AAED,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAsB;IAC3D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAA6B;IAC1E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAmB;IACtD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAwB;IAChE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAyD;IAC3F,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAA+C;IACvF,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAyC;IAClF,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAyC;IAE/E,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,KAAK,EACL,OAAO,EACP,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,GACrB,EAAE,wBAAwB,EAY1B;IAED,mEAAmE;IACnE,OAAO,CAAC,UAAU;IAMlB;;;;;OAKG;YACW,cAAc;IAU5B;;;;;;;;;;;;OAYG;YACW,kBAAkB;IAchC;;;OAGG;IACG,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7D;IAED;;;OAGG;IACG,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvD;IAED;;;;OAIG;YACW,mBAAmB;IAajC;;;;OAIG;YACW,oBAAoB;IAelC,8FAA8F;YAChF,gBAAgB;IAa9B,kEAAkE;IAC5D,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwCrD;IAED;;;;;;OAMG;IACG,cAAc,CAClB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,iBAAiB,EAAE,CAAA;KAAE,CAAC,CAQ/E;IAED;;;;;;;;;;OAUG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAC9C,WAAW,EAAE,MAAM,CAAA;QACnB,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,UAAU,CAAC,CAAA;QACrD,IAAI,EAAE,iBAAiB,EAAE,CAAA;KAC1B,CAAC,CAmBD;IAED,uEAAuE;IACjE,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAatD;IAED;;;;OAIG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAclE;IAED;;;;;OAKG;IACG,UAAU,CACd,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE;QAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAC7C,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAgB7B;IAED;;;;;;;;;;;OAWG;IACG,kBAAkB,CACtB,YAAY,EAAE,MAAM,EAAE,EACtB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAyB3C;IAED,gGAAgG;IAC1F,gBAAgB,CACpB,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CA4B3C;IAED,iGAAiG;IACjG,OAAO,CAAC,aAAa;IA4BrB,wFAAwF;IACxF,UAAU,IAAI,UAAU,CAMvB;IAED;;;;OAIG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,GAAE,eAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BrF;CACF"}
@@ -1,5 +1,6 @@
1
1
  import { readCachedWorkspaceSettings } from '@cat-factory/kernel';
2
- import { effectiveTierLimit, estimateClassedCost, estimateCost, mergeSpendPricing, startOfMonthUtc, withDynamicPrices, } from './pricing.js';
2
+ import { BURN_RATE_WINDOW_MS, forecastSpend, spendAlertState, } from './forecast.logic.js';
3
+ import { effectiveTierLimit, estimateClassedCost, estimateCost, mergeSpendPricing, startOfMonthUtc, startOfNextMonthUtc, withDynamicPrices, } from './pricing.js';
3
4
  /**
4
5
  * The spend safeguard. It meters token usage into a persistent ledger, prices
5
6
  * each call into a single currency, and reports the current billing period's
@@ -59,6 +60,33 @@ export class SpendService {
59
60
  const settings = await readCachedWorkspaceSettings(this.workspaceSettingsCache, this.workspaceSettingsRepository, workspaceId);
60
61
  return mergeSpendPricing(this.pricing, settings);
61
62
  }
63
+ /**
64
+ * The same for MANY workspaces, as ONE batched settings read.
65
+ *
66
+ * Deliberately not `resolvePricing` in a loop: that is a point read per workspace, which is the
67
+ * banned N+1 the moment a caller holds a list, and the alert sweep holds every spending
68
+ * workspace in the deployment. The shared cache is bypassed rather than consulted per id
69
+ * because it would not help and would hurt: the isolate-safe (Worker) profile disables the
70
+ * `workspaceSettings` slice outright, so every lookup there is a real D1 round trip, and on Node
71
+ * a sweep touching every tenant would churn a cache sized for the hot single-workspace gate.
72
+ *
73
+ * Every requested id is present in the result; a workspace with no persisted overrides maps to
74
+ * the base table, exactly as the single-workspace read resolves it.
75
+ */
76
+ async resolvePricingMany(workspaceIds) {
77
+ const out = new Map();
78
+ const repository = this.workspaceSettingsRepository;
79
+ if (!repository) {
80
+ for (const id of workspaceIds)
81
+ out.set(id, this.pricing);
82
+ return out;
83
+ }
84
+ const settings = await repository.listByWorkspaceIds(workspaceIds);
85
+ for (const id of workspaceIds) {
86
+ out.set(id, mergeSpendPricing(this.pricing, settings.get(id) ?? null));
87
+ }
88
+ return out;
89
+ }
62
90
  /**
63
91
  * Invalidate a cached account effective limit (called after an account-budget edit, via
64
92
  * `AccountService`'s budget-change callback). A no-op when no cache is wired.
@@ -91,6 +119,25 @@ export class SpendService {
91
119
  : await load();
92
120
  return effectiveTierLimit(limit, cap);
93
121
  }
122
+ /**
123
+ * The same for MANY accounts, as ONE batched account read (see {@link resolvePricingMany} for
124
+ * why the per-id cache is bypassed rather than consulted). Every requested id is present:
125
+ * an account with no configured limit resolves to the env cap alone, `Infinity` when unset.
126
+ */
127
+ async resolveAccountLimits(accountIds) {
128
+ const cap = this.pricing.accountMonthlyLimitCap;
129
+ const out = new Map();
130
+ const repository = this.accountRepository;
131
+ if (!repository) {
132
+ for (const id of accountIds)
133
+ out.set(id, effectiveTierLimit(null, cap));
134
+ return out;
135
+ }
136
+ const configured = new Map((await repository.listByIds(accountIds)).map((a) => [a.id, a.spendMonthlyLimit ?? null]));
137
+ for (const id of accountIds)
138
+ out.set(id, effectiveTierLimit(configured.get(id) ?? null, cap));
139
+ return out;
140
+ }
94
141
  /** The user tier's effective monthly limit (configured user limit clamped by the env cap). */
95
142
  async resolveUserLimit(userId) {
96
143
  const cap = this.pricing.userMonthlyLimitCap;
@@ -250,6 +297,89 @@ export class SpendService {
250
297
  exceeded: totals.costEstimate >= limit,
251
298
  };
252
299
  }
300
+ /**
301
+ * The forward-looking position of many WORKSPACES at once: burn rate, projected period
302
+ * total, and the alert state each is in. Advisory only: nothing here can pause a run.
303
+ *
304
+ * Batched because the alert sweep asks about every workspace in the deployment on every
305
+ * pass: two grouped ledger reads (period-to-date and the trailing burn-rate window) plus one
306
+ * batched settings read serve the whole set, where a per-workspace point read would be the
307
+ * banned N+1 run every few minutes across every tenant. Workspaces with no metered spend this
308
+ * period are absent from the result: they have nothing to forecast, and skipping them is what
309
+ * keeps a deployment full of quiet boards cheap to sweep. Their pricing is never resolved
310
+ * either, which is why the settings read follows the ledger reads instead of joining them.
311
+ */
312
+ async forecastWorkspaces(workspaceIds, now) {
313
+ const periodStart = startOfMonthUtc(now);
314
+ const windowStart = now - BURN_RATE_WINDOW_MS;
315
+ const [period, window] = await Promise.all([
316
+ this.tokenUsageRepository.meteredSpendByWorkspaceSince(workspaceIds, periodStart),
317
+ this.tokenUsageRepository.meteredSpendByWorkspaceSince(workspaceIds, windowStart),
318
+ ]);
319
+ const pricingByWorkspace = await this.resolvePricingMany([...period.keys()]);
320
+ const out = new Map();
321
+ for (const [workspaceId, spent] of period) {
322
+ const pricing = pricingByWorkspace.get(workspaceId) ?? this.pricing;
323
+ out.set(workspaceId, this.buildForecast({
324
+ costSpent: spent.costEstimate,
325
+ costLimit: pricing.monthlyLimit,
326
+ currency: pricing.currency,
327
+ window: window.get(workspaceId),
328
+ windowStart,
329
+ periodStart,
330
+ now,
331
+ }));
332
+ }
333
+ return out;
334
+ }
335
+ /** The same for the ACCOUNT tier, priced in the base currency (an account spans workspaces). */
336
+ async forecastAccounts(accountIds, now) {
337
+ const periodStart = startOfMonthUtc(now);
338
+ const windowStart = now - BURN_RATE_WINDOW_MS;
339
+ const [period, window] = await Promise.all([
340
+ this.tokenUsageRepository.meteredSpendByAccountSince(accountIds, periodStart),
341
+ this.tokenUsageRepository.meteredSpendByAccountSince(accountIds, windowStart),
342
+ ]);
343
+ const limitByAccount = await this.resolveAccountLimits([...period.keys()]);
344
+ const out = new Map();
345
+ for (const [accountId, spent] of period) {
346
+ const costLimit = limitByAccount.get(accountId) ?? Number.POSITIVE_INFINITY;
347
+ // An inactive tier (no configured limit, no operator cap) is skipped outright rather
348
+ // than forecast against `Infinity`: there is no ceiling to warn about approaching.
349
+ if (!Number.isFinite(costLimit))
350
+ continue;
351
+ out.set(accountId, this.buildForecast({
352
+ costSpent: spent.costEstimate,
353
+ costLimit,
354
+ currency: this.pricing.currency,
355
+ window: window.get(accountId),
356
+ windowStart,
357
+ periodStart,
358
+ now,
359
+ }));
360
+ }
361
+ return out;
362
+ }
363
+ /** Assemble one scope's forecast + alert state from the reads above (pure beyond this point). */
364
+ buildForecast(input) {
365
+ const forecast = forecastSpend({
366
+ costSpent: input.costSpent,
367
+ costLimit: input.costLimit,
368
+ windowCost: input.window?.costEstimate ?? 0,
369
+ windowFirstSeenAt: input.window?.firstSeenAt ?? null,
370
+ windowStart: input.windowStart,
371
+ periodStart: input.periodStart,
372
+ periodEnd: startOfNextMonthUtc(input.periodStart),
373
+ now: input.now,
374
+ });
375
+ return {
376
+ costSpent: input.costSpent,
377
+ costLimit: input.costLimit,
378
+ currency: input.currency,
379
+ forecast,
380
+ alert: spendAlertState(forecast, input.periodStart, input.costLimit),
381
+ };
382
+ }
253
383
  /** The operator hard ceilings on the account/user tiers, for the SPA budget screens. */
254
384
  budgetCaps() {
255
385
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"SpendService.js","sourceRoot":"","sources":["../src/SpendService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SpendService.js","sourceRoot":"","sources":["../src/SpendService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The trailing span the burn rate is measured over. A week smooths the working-week shape
3
+ * (a team that runs pipelines Monday to Friday would project wildly off a Sunday sample)
4
+ * while still reacting within a day or two to a genuine change of pace.
5
+ *
6
+ * Deliberately NOT the period-to-date average: on the 28th, a month-to-date rate is
7
+ * dominated by spend from three weeks ago and barely moves when a runaway starts today,
8
+ * which is the one moment the forecast has to earn its keep.
9
+ */
10
+ export declare const BURN_RATE_WINDOW_MS: number;
11
+ /**
12
+ * The shortest observed span a burn rate may be derived from. Under it the rate is an
13
+ * artefact of when the sample happened to start: a workspace that spent 20 EUR in its first
14
+ * ten minutes is not spending 2,880 EUR/day, and saying so would train people to ignore the
15
+ * alert. Below this the forecast reports `insufficient-history` and withholds the
16
+ * projection rather than publishing a number it cannot stand behind.
17
+ */
18
+ export declare const MIN_OBSERVED_SPAN_MS: number;
19
+ /**
20
+ * The default fraction of the limit at which a proactive alert fires. Configurable
21
+ * thresholds beside the budget limits are a later slice of the forecasting initiative; until
22
+ * then every deployment alerts at the same 80%.
23
+ */
24
+ export declare const DEFAULT_SPEND_ALERT_THRESHOLDS: readonly number[];
25
+ /**
26
+ * Whether the projection is worth publishing.
27
+ *
28
+ * `insufficient-history` is a REAL state, not a zero: it says the ledger has not been
29
+ * observed long enough for a rate to mean anything, which is a different fact from "this
30
+ * scope is not spending". Rendering the two the same is how a brand-new runaway ends up
31
+ * looking calm.
32
+ */
33
+ export type SpendForecastConfidence = 'ok' | 'insufficient-history';
34
+ /** What {@link forecastSpend} needs. Every field is a fact the caller already read or holds. */
35
+ export interface SpendForecastInput {
36
+ /** Metered spend so far in the current period, in the scope's currency. */
37
+ costSpent: number;
38
+ /** The scope's effective limit for the period. `Infinity` ⇒ the tier is inactive. */
39
+ costLimit: number;
40
+ /** Metered spend over the trailing window, in the same currency. */
41
+ windowCost: number;
42
+ /**
43
+ * Epoch ms of the OLDEST metered row inside the trailing window, or null when the window
44
+ * holds none. It is what makes the rate honest for a scope younger than the window: without
45
+ * it, a workspace that started spending two hours ago is divided by seven days and reads as
46
+ * 1/84th of its real pace, understating exactly the case the alert exists for.
47
+ */
48
+ windowFirstSeenAt: number | null;
49
+ /** Start of the trailing window (epoch ms), i.e. `now - BURN_RATE_WINDOW_MS` by default. */
50
+ windowStart: number;
51
+ /** Start of the current billing period (epoch ms, UTC month start). */
52
+ periodStart: number;
53
+ /** End of the current billing period, exclusive (epoch ms): the next month start. */
54
+ periodEnd: number;
55
+ /** The observation time (epoch ms). */
56
+ now: number;
57
+ }
58
+ /** The forward-looking half of a scope's spend position. */
59
+ export interface SpendForecast {
60
+ /**
61
+ * Metered spend per day over the trailing window, divided by the span actually OBSERVED
62
+ * rather than the nominal window (see {@link SpendForecastInput.windowFirstSeenAt}). Zero
63
+ * when nothing was spent in the window.
64
+ */
65
+ burnRatePerDay: number;
66
+ /**
67
+ * Projected spend for the whole period: what is already spent plus the burn rate applied to
68
+ * the period's remaining days. Null when {@link SpendForecast.confidence} is not `ok`: an
69
+ * unpublishable projection is ABSENT, never a plausible-looking number.
70
+ */
71
+ projectedTotal: number | null;
72
+ /**
73
+ * Epoch ms the projection expects the limit to be reached, or null when it is not expected
74
+ * within this period (including when the limit is already reached, which is the reactive
75
+ * safeguard's business, not the forecast's).
76
+ */
77
+ projectedExhaustionAt: number | null;
78
+ /** `costSpent / costLimit`, or 0 for an inactive (`Infinity`-limit) tier. */
79
+ consumedFraction: number;
80
+ confidence: SpendForecastConfidence;
81
+ }
82
+ /**
83
+ * The forward-looking position of one scope. Pure: the same inputs always produce the same
84
+ * forecast, which is what lets the sweep and the UI agree without sharing state.
85
+ */
86
+ export declare function forecastSpend(input: SpendForecastInput): SpendForecast;
87
+ /**
88
+ * The alert position of a scope in one period: the highest threshold its ACTUAL spend has
89
+ * crossed, and whether its PROJECTION overruns the limit.
90
+ *
91
+ * This is the card's dedup identity, which is why it holds only state and no live figures.
92
+ * A payload carrying the current burn rate would differ on every sweep, and the notification
93
+ * service re-delivers a card whose content changed, so the very field that made the alert
94
+ * informative would re-toast the inbox every few minutes for the rest of the month.
95
+ */
96
+ export interface SpendAlertState {
97
+ /** The period the state belongs to; a rollover re-arms every signal below. */
98
+ periodStart: number;
99
+ /** The highest crossed threshold as a fraction (e.g. `0.8`), or null when none is crossed. */
100
+ threshold: number | null;
101
+ /** Whether the projection exceeds the limit while actual spend has not yet reached it. */
102
+ projectedOverrun: boolean;
103
+ }
104
+ /**
105
+ * The alert state implied by a forecast. `thresholds` are fractions of the limit; an empty
106
+ * list (or an inactive tier) yields a state that fires nothing.
107
+ *
108
+ * `projectedOverrun` is deliberately suppressed once the limit is ALREADY reached: at that
109
+ * point the projection is no longer a warning about the future, and the reactive safeguard
110
+ * owns the message. It is likewise suppressed when the projection is unpublishable, because
111
+ * "we cannot forecast this yet" must not be reported as "you are fine".
112
+ */
113
+ export declare function spendAlertState(forecast: SpendForecast, periodStart: number, costLimit: number, thresholds?: readonly number[]): SpendAlertState;
114
+ /** Whether an alert state says anything at all (nothing crossed, nothing projected ⇒ no card). */
115
+ export declare function spendAlertFiring(state: SpendAlertState): boolean;
116
+ /**
117
+ * The signals one tier contributes to a fold: {@link SpendAlertState} minus the period, which
118
+ * belongs to the scope rather than to any one tier.
119
+ */
120
+ export type SpendAlertSignals = Pick<SpendAlertState, 'threshold' | 'projectedOverrun'>;
121
+ /**
122
+ * Fold the per-tier states a scope is in into the ONE state {@link spendAlertEscalated} compares:
123
+ * the highest threshold any tier crossed, and whether any tier projects an overrun.
124
+ *
125
+ * BOTH sides of that comparison must come from here. A card lists every tier that was firing when
126
+ * it was raised, so pitting it against a single tier's state is not a stricter test but a
127
+ * different one, and it loses real warnings: an account tier that newly starts projecting an
128
+ * overrun beside a workspace tier already sitting at 80% moves the fold and leaves the worst tier
129
+ * untouched, so the card is never re-raised and the account's overrun is never announced. Folding
130
+ * both sides through one function is what makes that asymmetry impossible to reintroduce.
131
+ */
132
+ export declare function mergeSpendAlertStates(periodStart: number, tiers: readonly SpendAlertSignals[]): SpendAlertState;
133
+ /**
134
+ * Whether `next` is an ESCALATION over what was last notified: the once-per-crossing rule.
135
+ *
136
+ * Only an upward move earns a fresh notification: a new period re-arms everything, a higher
137
+ * threshold is news, and a projection that has newly turned to overrun is news. Staying at
138
+ * 80% for three weeks is not, and neither is falling back from 80% to nothing, because
139
+ * un-crossing a threshold is not something anyone needs to be told about.
140
+ *
141
+ * A null `previous` means nothing has been notified for this scope yet, so any firing state
142
+ * escalates.
143
+ *
144
+ * Both arguments must be folds over the SAME tier set (see {@link mergeSpendAlertStates}).
145
+ */
146
+ export declare function spendAlertEscalated(previous: SpendAlertState | null, next: SpendAlertState): boolean;
147
+ //# sourceMappingURL=forecast.logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forecast.logic.d.ts","sourceRoot":"","sources":["../src/forecast.logic.ts"],"names":[],"mappings":"AAgBA;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,QAAa,CAAA;AAE7C;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,QAAqB,CAAA;AAEtD;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,SAAS,MAAM,EAAU,CAAA;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,GAAG,sBAAsB,CAAA;AAEnE,gGAAgG;AAChG,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;IACjB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAA;IACjB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,4FAA4F;IAC5F,WAAW,EAAE,MAAM,CAAA;IACnB,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAA;IACnB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAA;IACjB,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAA;CACZ;AAED,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B;;;;OAIG;IACH,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,6EAA6E;IAC7E,gBAAgB,EAAE,MAAM,CAAA;IACxB,UAAU,EAAE,uBAAuB,CAAA;CACpC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa,CAmCtE;AAmBD;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAA;IACnB,8FAA8F;IAC9F,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,0FAA0F;IAC1F,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,EACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,SAAS,MAAM,EAAmC,GAC7D,eAAe,CAejB;AAED,kGAAkG;AAClG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAEhE;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,kBAAkB,CAAC,CAAA;AAEvF;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,iBAAiB,EAAE,GAClC,eAAe,CAUjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,GAAG,IAAI,EAChC,IAAI,EAAE,eAAe,GACpB,OAAO,CAKT"}
@@ -0,0 +1,157 @@
1
+ // Forward-looking spend: burn rate, month-end projection, and the alert state a scope is in.
2
+ //
3
+ // The spend safeguard proper (`SpendService`) is REACTIVE: it sums the period's metered
4
+ // ledger and pauses a run at the ceiling. Everything here is ADVISORY and pure: no clock,
5
+ // no repository, no LLM. It exists so a team learns it is running out while there is still
6
+ // time to raise the limit or stop a runaway, instead of learning it from a run that paused
7
+ // mid-pipeline. Nothing in this module may change gating: a projection bug must never pause
8
+ // or unpause a run.
9
+ //
10
+ // Both consumers (the alert sweep and, later, the Usage surface) go through the SAME
11
+ // functions, so what a card says and what a chart draws cannot disagree about the same
12
+ // workspace.
13
+ /** One day in ms: the unit every rate below is expressed in. */
14
+ const DAY_MS = 24 * 60 * 60 * 1000;
15
+ /**
16
+ * The trailing span the burn rate is measured over. A week smooths the working-week shape
17
+ * (a team that runs pipelines Monday to Friday would project wildly off a Sunday sample)
18
+ * while still reacting within a day or two to a genuine change of pace.
19
+ *
20
+ * Deliberately NOT the period-to-date average: on the 28th, a month-to-date rate is
21
+ * dominated by spend from three weeks ago and barely moves when a runaway starts today,
22
+ * which is the one moment the forecast has to earn its keep.
23
+ */
24
+ export const BURN_RATE_WINDOW_MS = 7 * DAY_MS;
25
+ /**
26
+ * The shortest observed span a burn rate may be derived from. Under it the rate is an
27
+ * artefact of when the sample happened to start: a workspace that spent 20 EUR in its first
28
+ * ten minutes is not spending 2,880 EUR/day, and saying so would train people to ignore the
29
+ * alert. Below this the forecast reports `insufficient-history` and withholds the
30
+ * projection rather than publishing a number it cannot stand behind.
31
+ */
32
+ export const MIN_OBSERVED_SPAN_MS = 6 * 60 * 60 * 1000;
33
+ /**
34
+ * The default fraction of the limit at which a proactive alert fires. Configurable
35
+ * thresholds beside the budget limits are a later slice of the forecasting initiative; until
36
+ * then every deployment alerts at the same 80%.
37
+ */
38
+ export const DEFAULT_SPEND_ALERT_THRESHOLDS = [0.8];
39
+ /**
40
+ * The forward-looking position of one scope. Pure: the same inputs always produce the same
41
+ * forecast, which is what lets the sweep and the UI agree without sharing state.
42
+ */
43
+ export function forecastSpend(input) {
44
+ const { costSpent, costLimit, windowCost, windowFirstSeenAt, windowStart, periodEnd, now } = input;
45
+ const consumedFraction = Number.isFinite(costLimit) && costLimit > 0 ? costSpent / costLimit : 0;
46
+ // The span the window's rows actually cover: from the older of the window's start and the
47
+ // first row seen inside it, to now. A scope with rows spanning the whole window measures the
48
+ // whole window; a younger one measures only as far back as it has evidence for.
49
+ const observedFrom = windowFirstSeenAt == null ? windowStart : Math.max(windowStart, windowFirstSeenAt);
50
+ const observedMs = Math.max(0, now - observedFrom);
51
+ const burnRatePerDay = observedMs > 0 ? (windowCost / observedMs) * DAY_MS : 0;
52
+ // A scope with no metered rows in the window has a genuine, confident rate of zero. There
53
+ // is nothing uncertain about "spent nothing all week". Short history is the uncertain case.
54
+ const confidence = windowFirstSeenAt != null && observedMs < MIN_OBSERVED_SPAN_MS ? 'insufficient-history' : 'ok';
55
+ if (confidence !== 'ok') {
56
+ return {
57
+ burnRatePerDay,
58
+ projectedTotal: null,
59
+ projectedExhaustionAt: null,
60
+ consumedFraction,
61
+ confidence,
62
+ };
63
+ }
64
+ const remainingDays = Math.max(0, periodEnd - now) / DAY_MS;
65
+ const projectedTotal = costSpent + burnRatePerDay * remainingDays;
66
+ return {
67
+ burnRatePerDay,
68
+ projectedTotal,
69
+ projectedExhaustionAt: exhaustionAt(costSpent, costLimit, burnRatePerDay, now, periodEnd),
70
+ consumedFraction,
71
+ confidence,
72
+ };
73
+ }
74
+ /**
75
+ * When the limit is projected to be reached, or null when that is not expected inside this
76
+ * period. Already-exhausted returns null on purpose: the budget gate has already acted, so a
77
+ * forecast pointing at the past would be a second, weaker statement of a settled fact.
78
+ */
79
+ function exhaustionAt(costSpent, costLimit, burnRatePerDay, now, periodEnd) {
80
+ if (!Number.isFinite(costLimit) || costSpent >= costLimit || burnRatePerDay <= 0)
81
+ return null;
82
+ const at = now + ((costLimit - costSpent) / burnRatePerDay) * DAY_MS;
83
+ return at < periodEnd ? at : null;
84
+ }
85
+ /**
86
+ * The alert state implied by a forecast. `thresholds` are fractions of the limit; an empty
87
+ * list (or an inactive tier) yields a state that fires nothing.
88
+ *
89
+ * `projectedOverrun` is deliberately suppressed once the limit is ALREADY reached: at that
90
+ * point the projection is no longer a warning about the future, and the reactive safeguard
91
+ * owns the message. It is likewise suppressed when the projection is unpublishable, because
92
+ * "we cannot forecast this yet" must not be reported as "you are fine".
93
+ */
94
+ export function spendAlertState(forecast, periodStart, costLimit, thresholds = DEFAULT_SPEND_ALERT_THRESHOLDS) {
95
+ if (!Number.isFinite(costLimit) || costLimit <= 0) {
96
+ return { periodStart, threshold: null, projectedOverrun: false };
97
+ }
98
+ const crossed = thresholds.filter((t) => t > 0 && forecast.consumedFraction >= t);
99
+ const projectedOverrun = forecast.confidence === 'ok' &&
100
+ forecast.projectedTotal != null &&
101
+ forecast.consumedFraction < 1 &&
102
+ forecast.projectedTotal > costLimit;
103
+ return {
104
+ periodStart,
105
+ threshold: crossed.length > 0 ? Math.max(...crossed) : null,
106
+ projectedOverrun,
107
+ };
108
+ }
109
+ /** Whether an alert state says anything at all (nothing crossed, nothing projected ⇒ no card). */
110
+ export function spendAlertFiring(state) {
111
+ return state.threshold != null || state.projectedOverrun;
112
+ }
113
+ /**
114
+ * Fold the per-tier states a scope is in into the ONE state {@link spendAlertEscalated} compares:
115
+ * the highest threshold any tier crossed, and whether any tier projects an overrun.
116
+ *
117
+ * BOTH sides of that comparison must come from here. A card lists every tier that was firing when
118
+ * it was raised, so pitting it against a single tier's state is not a stricter test but a
119
+ * different one, and it loses real warnings: an account tier that newly starts projecting an
120
+ * overrun beside a workspace tier already sitting at 80% moves the fold and leaves the worst tier
121
+ * untouched, so the card is never re-raised and the account's overrun is never announced. Folding
122
+ * both sides through one function is what makes that asymmetry impossible to reintroduce.
123
+ */
124
+ export function mergeSpendAlertStates(periodStart, tiers) {
125
+ let threshold = null;
126
+ let projectedOverrun = false;
127
+ for (const tier of tiers) {
128
+ if (tier.threshold != null && (threshold == null || tier.threshold > threshold)) {
129
+ threshold = tier.threshold;
130
+ }
131
+ projectedOverrun ||= tier.projectedOverrun;
132
+ }
133
+ return { periodStart, threshold, projectedOverrun };
134
+ }
135
+ /**
136
+ * Whether `next` is an ESCALATION over what was last notified: the once-per-crossing rule.
137
+ *
138
+ * Only an upward move earns a fresh notification: a new period re-arms everything, a higher
139
+ * threshold is news, and a projection that has newly turned to overrun is news. Staying at
140
+ * 80% for three weeks is not, and neither is falling back from 80% to nothing, because
141
+ * un-crossing a threshold is not something anyone needs to be told about.
142
+ *
143
+ * A null `previous` means nothing has been notified for this scope yet, so any firing state
144
+ * escalates.
145
+ *
146
+ * Both arguments must be folds over the SAME tier set (see {@link mergeSpendAlertStates}).
147
+ */
148
+ export function spendAlertEscalated(previous, next) {
149
+ if (!spendAlertFiring(next))
150
+ return false;
151
+ if (!previous || previous.periodStart !== next.periodStart)
152
+ return true;
153
+ if ((next.threshold ?? 0) > (previous.threshold ?? 0))
154
+ return true;
155
+ return next.projectedOverrun && !previous.projectedOverrun;
156
+ }
157
+ //# sourceMappingURL=forecast.logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forecast.logic.js","sourceRoot":"","sources":["../src/forecast.logic.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- export { SpendService, type SpendServiceDependencies, type RecordUsageInput, type BudgetTierScope, } from './SpendService.js';
2
- export { type ModelPrice, type ResolvedModelPrice, type InputTokenClassUsage, type SpendPricing, CACHE_READ_MULTIPLIER, CACHE_WRITE_MULTIPLIER, DEFAULT_MODEL_PRICES, DEFAULT_MONTHLY_LIMIT_EUR, DEFAULT_SPEND_PRICING, budgetCapsOverlay, effectiveTierLimit, priceFor, ratesFor, modelCostResolver, estimateCost, estimateClassedCost, withDynamicPrices, startOfMonthUtc, } from './pricing.js';
1
+ export { SpendService, type SpendServiceDependencies, type RecordUsageInput, type ScopedSpendForecast, type BudgetTierScope, } from './SpendService.js';
2
+ export { type ModelPrice, type ResolvedModelPrice, type InputTokenClassUsage, type SpendPricing, CACHE_READ_MULTIPLIER, CACHE_WRITE_MULTIPLIER, DEFAULT_MODEL_PRICES, DEFAULT_MONTHLY_LIMIT_EUR, DEFAULT_SPEND_PRICING, budgetCapsOverlay, effectiveTierLimit, priceFor, ratesFor, modelCostResolver, estimateCost, estimateClassedCost, withDynamicPrices, startOfMonthUtc, startOfNextMonthUtc, } from './pricing.js';
3
+ export { type SpendAlertSignals, type SpendAlertState, type SpendForecast, type SpendForecastConfidence, type SpendForecastInput, BURN_RATE_WINDOW_MS, DEFAULT_SPEND_ALERT_THRESHOLDS, MIN_OBSERVED_SPAN_MS, forecastSpend, mergeSpendAlertStates, spendAlertEscalated, spendAlertFiring, spendAlertState, } from './forecast.logic.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EACZ,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GAChB,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,YAAY,EACZ,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,eAAe,GACrB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,mBAAmB,EACnB,8BAA8B,EAC9B,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // Pricing tables and spend metering/gating for @cat-factory.
2
2
  export { SpendService, } from './SpendService.js';
3
- export { CACHE_READ_MULTIPLIER, CACHE_WRITE_MULTIPLIER, DEFAULT_MODEL_PRICES, DEFAULT_MONTHLY_LIMIT_EUR, DEFAULT_SPEND_PRICING, budgetCapsOverlay, effectiveTierLimit, priceFor, ratesFor, modelCostResolver, estimateCost, estimateClassedCost, withDynamicPrices, startOfMonthUtc, } from './pricing.js';
3
+ export { CACHE_READ_MULTIPLIER, CACHE_WRITE_MULTIPLIER, DEFAULT_MODEL_PRICES, DEFAULT_MONTHLY_LIMIT_EUR, DEFAULT_SPEND_PRICING, budgetCapsOverlay, effectiveTierLimit, priceFor, ratesFor, modelCostResolver, estimateCost, estimateClassedCost, withDynamicPrices, startOfMonthUtc, startOfNextMonthUtc, } from './pricing.js';
4
+ export { BURN_RATE_WINDOW_MS, DEFAULT_SPEND_ALERT_THRESHOLDS, MIN_OBSERVED_SPAN_MS, forecastSpend, mergeSpendAlertStates, spendAlertEscalated, spendAlertFiring, spendAlertState, } from './forecast.logic.js';
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,EACL,YAAY,GAIb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAKL,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GAChB,MAAM,cAAc,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,OAAO,EACL,YAAY,GAKb,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAKL,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,GACpB,MAAM,cAAc,CAAA;AACrB,OAAO,EAML,mBAAmB,EACnB,8BAA8B,EAC9B,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,GAChB,MAAM,qBAAqB,CAAA"}
package/dist/pricing.d.ts CHANGED
@@ -161,4 +161,10 @@ export declare function estimateCost(pricing: SpendPricing, ref: ModelRef, usage
161
161
  export declare function budgetCapsOverlay(accountCap: number | undefined, userCap: number | undefined): Partial<Pick<SpendPricing, 'accountMonthlyLimitCap' | 'userMonthlyLimitCap'>>;
162
162
  /** Start of the calendar month containing `epochMs`, in UTC (epoch ms). */
163
163
  export declare function startOfMonthUtc(epochMs: number): number;
164
+ /**
165
+ * Start of the month AFTER the one containing `epochMs`, in UTC: the exclusive end of a
166
+ * billing period, which is what the spend forecast extrapolates to. `Date.UTC` normalises a
167
+ * month index of 12 into the next January, so no year wrap is needed here.
168
+ */
169
+ export declare function startOfNextMonthUtc(epochMs: number): number;
164
170
  //# sourceMappingURL=pricing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
package/dist/pricing.js CHANGED
@@ -279,4 +279,13 @@ export function startOfMonthUtc(epochMs) {
279
279
  const d = new Date(epochMs);
280
280
  return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);
281
281
  }
282
+ /**
283
+ * Start of the month AFTER the one containing `epochMs`, in UTC: the exclusive end of a
284
+ * billing period, which is what the spend forecast extrapolates to. `Date.UTC` normalises a
285
+ * month index of 12 into the next January, so no year wrap is needed here.
286
+ */
287
+ export function startOfNextMonthUtc(epochMs) {
288
+ const d = new Date(epochMs);
289
+ return Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1);
290
+ }
282
291
  //# sourceMappingURL=pricing.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cat-factory/spend",
3
- "version": "0.14.15",
3
+ "version": "0.15.1",
4
4
  "description": "Pricing tables and spend metering for the Agent Architecture Board.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,8 +24,8 @@
24
24
  "access": "public"
25
25
  },
26
26
  "dependencies": {
27
- "@cat-factory/contracts": "0.237.0",
28
- "@cat-factory/kernel": "0.236.1"
27
+ "@cat-factory/contracts": "0.239.0",
28
+ "@cat-factory/kernel": "0.238.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "typescript": "7.0.2",