@teamvibe/poller 0.8.4-rc.1 → 0.8.4-rc.2

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.
@@ -1588,7 +1588,9 @@ export async function spawnPoolClaudeCode(msg, sessionLog, selectedDirectory, se
1588
1588
  // fallback must report the fresh attempt's delivery flags independently.
1589
1589
  if (!runtime?.resumePending)
1590
1590
  sawSendMessageCall = false;
1591
- const result = await runClaudeCode(msg, sessionLog, effectiveCwd, directory, id, runtime?.resumePending ? false : first, lastMessageTs, onMessageSent, typingIndicator, runtime);
1591
+ const spawned = await runClaudeCode(msg, sessionLog, effectiveCwd, directory, id, runtime?.resumePending ? false : first, lastMessageTs, onMessageSent, typingIndicator, runtime);
1592
+ const result = prepared?.account && spawned.rateLimitInfo?.status === 'rejected'
1593
+ ? { ...spawned, success: false } : spawned;
1592
1594
  sawSendMessageCall ||= result.sawSendMessageCall === true;
1593
1595
  if (prepared?.account) {
1594
1596
  if (poolAttempts.length >= 1000)
@@ -1622,7 +1624,7 @@ export async function spawnPoolClaudeCode(msg, sessionLog, selectedDirectory, se
1622
1624
  retainWorktree = false;
1623
1625
  return result;
1624
1626
  }
1625
- if (result.quota && !result.killedByPoller) {
1627
+ if ((result.quota || result.rateLimitInfo?.status === 'rejected') && !result.killedByPoller) {
1626
1628
  runtime.resumePending = true;
1627
1629
  retainWorktree = true;
1628
1630
  }
@@ -1645,7 +1647,7 @@ export async function spawnPoolClaudeCode(msg, sessionLog, selectedDirectory, se
1645
1647
  let switched = false;
1646
1648
  const finishQuota = async (initial) => {
1647
1649
  let result = initial;
1648
- while (prepared?.account && result.quota && !result.killedByPoller && poolRuntime && runtime) {
1650
+ while (prepared?.account && (result.quota || result.rateLimitInfo?.status === 'rejected') && !result.killedByPoller && poolRuntime && runtime) {
1649
1651
  attemptedAccounts.add(prepared.account.accountId);
1650
1652
  if (poolRuntime.shouldStop() || attemptedAccounts.size >= 1000)
1651
1653
  throw new PoolDeferredError();
@@ -1653,7 +1655,8 @@ export async function spawnPoolClaudeCode(msg, sessionLog, selectedDirectory, se
1653
1655
  logPoolFetch(sessionLog, prepared.pool);
1654
1656
  if (prepared.pool.kind === 'ready')
1655
1657
  await emitCandidateUsage(msg, prepared.pool.accounts, prepared.store);
1656
- // Reactive evidence was persisted by attempt() before choosing another account.
1658
+ // Quota and passive rejection evidence were persisted before selection.
1659
+ // The chain also excludes attempted accounts even if a concurrent observation replaces that evidence.
1657
1660
  if (prepared.pool.kind === 'ready')
1658
1661
  for (const account of prepared.pool.accounts) {
1659
1662
  if (attemptedAccounts.has(account.accountId))
@@ -3,7 +3,7 @@ import { type StoredAccountUsage, type SubscriptionUsageStore } from './subscrip
3
3
  import type { PoolAttempt } from './subscription-runtime.js';
4
4
  import type { SessionMetrics, TeamVibeQueueMessage } from './types.js';
5
5
  /** Explicit transport DTO: never serialize a pool account/credential envelope. */
6
- export declare function accountUsageTelemetry(account: SubscriptionAccount, state: StoredAccountUsage): {
6
+ export declare function accountUsageTelemetry(account: SubscriptionAccount, state: StoredAccountUsage, reportedAt?: number): {
7
7
  reactive: {
8
8
  observedAt: number;
9
9
  window: import("./claude-rate-limit.js").ClaudeQuotaWindow | undefined;
@@ -1,6 +1,6 @@
1
1
  import { emitEvent } from './event-queue.js';
2
- import { normalizePassiveUsage, reactiveEligibleAt, } from './subscription-selection.js';
3
- import { safeQuota, safeRateLimitInfo, } from './subscription-usage-store.js';
2
+ import { reactiveEligibleAt } from './subscription-selection.js';
3
+ import { usageStateForSelection, safeQuota, safeRateLimitInfo, } from './subscription-usage-store.js';
4
4
  function safeText(value) {
5
5
  return value && value.length <= 128 && !/sk-ant-|Bearer\s|[\r\n]/i.test(value)
6
6
  ? value
@@ -30,18 +30,12 @@ function safeMetrics(metrics) {
30
30
  return result;
31
31
  }
32
32
  /** Explicit transport DTO: never serialize a pool account/credential envelope. */
33
- export function accountUsageTelemetry(account, state) {
34
- const passive = state.passive
35
- ? normalizePassiveUsage(state.passive.rateLimitInfo, state.passive.observedAt)
36
- : undefined;
37
- const probe = state.probe?.usage;
38
- const usage = passive && (!probe || passive.observedAt >= probe.observedAt)
39
- ? passive
40
- : probe;
33
+ export function accountUsageTelemetry(account, state, reportedAt = Date.now()) {
34
+ const { usage } = usageStateForSelection(state, reportedAt);
41
35
  return {
42
36
  accountId: account.accountId,
43
37
  accountLabel: account.label ?? account.accountId,
44
- reportedAt: Date.now(),
38
+ reportedAt,
45
39
  ...(usage ? { usage } : {}),
46
40
  ...(state.probe
47
41
  ? {
@@ -71,5 +71,5 @@ export declare function preparePool(msg: TeamVibeQueueMessage, resolved: Resolve
71
71
  }>;
72
72
  export declare function accountPin(account: SubscriptionAccount, resolved: ResolvedPoolModel): SubscriptionPin;
73
73
  export declare function validateAccount(account: SubscriptionAccount, resolved: ResolvedPoolModel): Promise<void>;
74
- /** A snapshot TTL/recheck is not a provider reset. Report a reset only when reactive evidence establishes it. */
74
+ /** A snapshot TTL/recheck is not a provider reset. Explicit rejections also establish resets. */
75
75
  export declare function poolDeferredError(pool: PoolFetchResult<SubscriptionAccount>, resolved: ResolvedPoolModel, store: SubscriptionUsageStore, eligibleAt?: number, log?: PoolInfoLogger): Promise<PoolDeferredError>;
@@ -6,7 +6,7 @@ import { getPollerId } from './auth-provider.js';
6
6
  import { fetchSubscriptionPool } from './subscription-pool-client.js';
7
7
  import { selectPoolForResolvedModel } from './subscription-pool.js';
8
8
  import { FileSubscriptionUsageStore, usageStateForSelection } from './subscription-usage-store.js';
9
- import { PASSIVE_USAGE_TTL_MS, PROBE_USAGE_TTL_MS, reactiveEligibleAt, USAGE_THRESHOLD_PERCENT, POOL_RECHECK_MS } from './subscription-selection.js';
9
+ import { normalizePassiveUsage, selectSubscriptionAccount, PASSIVE_USAGE_TTL_MS, PROBE_USAGE_TTL_MS, reactiveEligibleAt, USAGE_THRESHOLD_PERCENT, POOL_RECHECK_MS } from './subscription-selection.js';
10
10
  export class PoolDeferredError extends Error {
11
11
  eligibleAt;
12
12
  resetAt;
@@ -64,7 +64,7 @@ export async function validateAccount(account, resolved) {
64
64
  throw new PoolDeferredError(selected.kind === 'deferred' ? selected.eligibleAt : undefined);
65
65
  }
66
66
  /** Message-only evidence; never changes selection, eligibility or durable pause state. */
67
- async function poolUsageNotice(pool, store) {
67
+ async function poolUsageNotice(pool, resolved, store) {
68
68
  if (pool.kind !== 'ready')
69
69
  return {};
70
70
  const now = Date.now();
@@ -75,7 +75,12 @@ async function poolUsageNotice(pool, store) {
75
75
  const ttl = usage?.source === 'passive' ? PASSIVE_USAGE_TTL_MS : PROBE_USAGE_TTL_MS;
76
76
  const windows = usage && usage.observedAt <= now && now < usage.observedAt + ttl
77
77
  ? usage.windows.filter(w => w.resetAt === undefined || w.resetAt > now) : [];
78
- const rejected = state.reactive?.some(r => r.observedAt <= now && reactiveEligibleAt(r) > now) ?? false;
78
+ const rejection = selectSubscriptionAccount({
79
+ pool: { kind: 'ready', accounts: [account] },
80
+ states: { [account.accountId]: { usage: usage ? { ...usage, windows: usage.windows.filter(w => w.status === 'rejected') } : undefined } },
81
+ model: resolved.model, now,
82
+ });
83
+ const rejected = rejection.kind === 'deferred' || (state.reactive?.some(r => r.observedAt <= now && reactiveEligibleAt(r) > now) ?? false);
79
84
  const blockers = windows.filter(w => w.percent !== undefined && w.percent >= (account.useFullQuota ? 100 : USAGE_THRESHOLD_PERCENT));
80
85
  const resets = blockers.map(w => w.resetAt);
81
86
  return {
@@ -94,9 +99,9 @@ async function poolUsageNotice(pool, store) {
94
99
  return {};
95
100
  }
96
101
  }
97
- /** A snapshot TTL/recheck is not a provider reset. Report a reset only when reactive evidence establishes it. */
102
+ /** A snapshot TTL/recheck is not a provider reset. Explicit rejections also establish resets. */
98
103
  export async function poolDeferredError(pool, resolved, store, eligibleAt, log) {
99
- const notice = await poolUsageNotice(pool, store);
104
+ const notice = await poolUsageNotice(pool, resolved, store);
100
105
  let usageDeferred = eligibleAt !== undefined;
101
106
  const deferredError = (resetAt) => {
102
107
  const error = new PoolDeferredError(eligibleAt, resetAt);
@@ -115,6 +120,9 @@ export async function poolDeferredError(pool, resolved, store, eligibleAt, log)
115
120
  if (selected.kind !== 'deferred' || selected.eligibleAt !== eligibleAt)
116
121
  continue;
117
122
  const state = await store.read(account);
123
+ const usage = state.passive ? normalizePassiveUsage(state.passive.rateLimitInfo, state.passive.observedAt) : undefined;
124
+ if (usage?.windows.some(w => w.status === 'rejected' && w.resetAt === eligibleAt))
125
+ return deferredError(new Date(eligibleAt).toISOString());
118
126
  const live = state.reactive.filter(r => !r.quota.resetAt || Date.parse(r.quota.resetAt) > Date.now());
119
127
  if (live.length && live.every(r => r.quota.resetAt && Number.isFinite(Date.parse(r.quota.resetAt))) && live.some(r => Date.parse(r.quota.resetAt) === eligibleAt))
120
128
  return deferredError(new Date(eligibleAt).toISOString());
@@ -5,6 +5,8 @@ export declare const USAGE_THRESHOLD_PERCENT = 90;
5
5
  export declare const PASSIVE_USAGE_TTL_MS: number;
6
6
  export declare const PROBE_USAGE_TTL_MS = 60000;
7
7
  export declare const POOL_RECHECK_MS: number;
8
+ /** Safety hold from the rejection observation when the provider gives no reset. */
9
+ export declare const REJECTED_BLOCK_MS: number;
8
10
  export interface AccountIdentity {
9
11
  workspaceId: string;
10
12
  accountId: string;
@@ -34,6 +36,9 @@ export interface UsageWindow {
34
36
  window: 'five_hour' | 'seven_day';
35
37
  scope: 'global' | 'sonnet' | 'opus' | 'haiku' | 'fable' | 'uncertain';
36
38
  status?: 'allowed' | 'allowed_warning' | 'rejected';
39
+ /** Retained rejections keep their own clock when merged into newer measurements. */
40
+ observedAt?: number;
41
+ source?: 'passive' | 'probe';
37
42
  percent?: number;
38
43
  resetAt?: number;
39
44
  }
@@ -42,6 +47,8 @@ export interface UsageObservation {
42
47
  observedAt: number;
43
48
  windows: readonly UsageWindow[];
44
49
  }
50
+ /** Latest measurements plus durable rejections; omission or success never clears a hold. */
51
+ export declare function mergeUsageObservations(observations: readonly (UsageObservation | undefined)[], now: number): UsageObservation | undefined;
45
52
  export interface ReactiveExhaustion {
46
53
  observedAt: number;
47
54
  quota: ClaudeQuotaFailure;
@@ -3,6 +3,40 @@ export const USAGE_THRESHOLD_PERCENT = 90;
3
3
  export const PASSIVE_USAGE_TTL_MS = 5 * 60_000;
4
4
  export const PROBE_USAGE_TTL_MS = 60_000;
5
5
  export const POOL_RECHECK_MS = 15 * 60_000;
6
+ /** Safety hold from the rejection observation when the provider gives no reset. */
7
+ export const REJECTED_BLOCK_MS = 15 * 60_000;
8
+ /** Latest measurements plus durable rejections; omission or success never clears a hold. */
9
+ export function mergeUsageObservations(observations, now) {
10
+ let latest;
11
+ const rejected = new Map();
12
+ for (const usage of observations) {
13
+ if (!usage || usage.observedAt > now)
14
+ continue;
15
+ if (!latest || usage.observedAt >= latest.observedAt)
16
+ latest = usage;
17
+ for (const w of usage.windows) {
18
+ const observedAt = w.observedAt ?? usage.observedAt;
19
+ if (w.status !== 'rejected' || observedAt > now)
20
+ continue;
21
+ const key = `${w.window}:${w.scope}`;
22
+ const previous = rejected.get(key);
23
+ if (!previous || observedAt >= previous.observedAt)
24
+ rejected.set(key, { ...w, observedAt, source: w.source ?? usage.source });
25
+ }
26
+ }
27
+ if (!latest)
28
+ return undefined;
29
+ const active = [...rejected.values()].filter(w => now < (w.resetAt ?? w.observedAt + REJECTED_BLOCK_MS));
30
+ return {
31
+ ...latest,
32
+ windows: [
33
+ ...latest.windows.filter(w => w.status !== 'rejected' &&
34
+ (w.observedAt ?? latest.observedAt) === latest.observedAt &&
35
+ (w.source ?? latest.source) === latest.source).slice(0, 133 - active.length),
36
+ ...active,
37
+ ],
38
+ };
39
+ }
6
40
  export function record(value) {
7
41
  return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
8
42
  }
@@ -143,9 +177,22 @@ export function selectSubscriptionAccount(input) {
143
177
  blockers.push(until);
144
178
  }
145
179
  const usage = state?.usage;
180
+ // A provider rejection outlives snapshot freshness. Never score it as headroom.
181
+ if (usage && usage.observedAt <= input.now) {
182
+ for (const w of usage.windows) {
183
+ if (w.status !== 'rejected' || !applicable(w.scope, input.model))
184
+ continue;
185
+ const observedAt = w.observedAt ?? usage.observedAt;
186
+ if (observedAt > input.now)
187
+ continue;
188
+ const until = w.resetAt ?? observedAt + REJECTED_BLOCK_MS;
189
+ if (input.now < until)
190
+ blockers.push(until);
191
+ }
192
+ }
146
193
  const expiry = usage ? usage.observedAt + (usage.source === 'passive' ? PASSIVE_USAGE_TTL_MS : PROBE_USAGE_TTL_MS) : 0;
147
194
  const fresh = usage && usage.observedAt <= input.now && input.now < expiry;
148
- const windows = fresh ? usage.windows.filter(w => applicable(w.scope, input.model) && (w.resetAt === undefined || w.resetAt > input.now)) : [];
195
+ const windows = fresh ? usage.windows.filter(w => w.status !== 'rejected' && (w.observedAt ?? usage.observedAt) === usage.observedAt && (w.source ?? usage.source) === usage.source && applicable(w.scope, input.model) && (w.resetAt === undefined || w.resetAt > input.now)) : [];
149
196
  const uncertain = windows.some(w => w.scope === 'uncertain' || (w.scope !== 'global' && !family(input.model)));
150
197
  for (const w of windows) {
151
198
  if (w.percent !== undefined && w.percent >= (account.useFullQuota ? 100 : USAGE_THRESHOLD_PERCENT))
@@ -9,6 +9,8 @@ export interface ProbeObservation {
9
9
  usage?: UsageObservation;
10
10
  }
11
11
  export interface StoredAccountUsage {
12
+ /** Latest measured snapshot plus active rejected windows, persisted across observations. */
13
+ usage?: UsageObservation;
12
14
  passive?: {
13
15
  rateLimitInfo: ClaudeRateLimitInfo;
14
16
  observedAt: number;
@@ -2,12 +2,16 @@ import { createHash, randomUUID } from 'node:crypto';
2
2
  import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
3
3
  import { join, resolve } from 'node:path';
4
4
  import { parseClaudeRateLimitInfo } from './claude-rate-limit.js';
5
- import { normalizePassiveUsage, record, reactiveEligibleAt, PASSIVE_USAGE_TTL_MS } from './subscription-selection.js';
5
+ import { normalizePassiveUsage, mergeUsageObservations, record, reactiveEligibleAt } from './subscription-selection.js';
6
6
  export function usageStateForSelection(state, now) {
7
- const passive = state.passive ? normalizePassiveUsage(state.passive.rateLimitInfo, state.passive.observedAt) : undefined;
8
- // Passive is primary while fresh; a completed optional probe may supplement a stale/missing snapshot.
9
- const fresh = passive && passive.observedAt <= now && now < passive.observedAt + PASSIVE_USAGE_TTL_MS;
10
- return { usage: fresh ? passive : state.probe?.status === 'ok' ? state.probe.usage : passive, reactive: state.reactive };
7
+ return {
8
+ usage: mergeUsageObservations([
9
+ state.usage,
10
+ state.passive ? normalizePassiveUsage(state.passive.rateLimitInfo, state.passive.observedAt) : undefined,
11
+ state.probe?.status === 'ok' ? state.probe.usage : undefined,
12
+ ], now),
13
+ reactive: state.reactive,
14
+ };
11
15
  }
12
16
  export class SubscriptionUsageStoreError extends Error {
13
17
  constructor() { super('Subscription usage store unavailable'); this.name = 'SubscriptionUsageStoreError'; }
@@ -51,6 +55,28 @@ export function safeQuota(quota) {
51
55
  ...(Number.isFinite(reset) && reset > 0 ? { resetAt: new Date(reset).toISOString() } : {}),
52
56
  };
53
57
  }
58
+ function safeUsage(value, source) {
59
+ const usage = record(value);
60
+ if (typeof usage['observedAt'] !== 'number' || !Array.isArray(usage['windows']))
61
+ throw new SubscriptionUsageStoreError();
62
+ validTime(usage['observedAt']);
63
+ const windows = usage['windows'].slice(0, 133).map(raw => {
64
+ const w = record(raw);
65
+ const window = w['window'] === 'five_hour' ? 'five_hour' : 'seven_day';
66
+ const scope = typeof w['scope'] === 'string' && ['global', 'sonnet', 'opus', 'haiku', 'fable'].includes(w['scope']) ? w['scope'] : 'uncertain';
67
+ const percent = typeof w['percent'] === 'number' && Number.isFinite(w['percent']) && w['percent'] >= 0 && w['percent'] <= 100 ? w['percent'] : undefined;
68
+ const resetAt = typeof w['resetAt'] === 'number' && Number.isFinite(w['resetAt']) && w['resetAt'] > 0 && w['resetAt'] <= 253402300799000 ? w['resetAt'] : undefined;
69
+ const status = w['status'] === 'allowed' || w['status'] === 'allowed_warning' || w['status'] === 'rejected' ? w['status'] : undefined;
70
+ const observedAt = typeof w['observedAt'] === 'number' ? w['observedAt'] : undefined;
71
+ if (observedAt !== undefined)
72
+ validTime(observedAt);
73
+ const source = w['source'] === 'passive' || w['source'] === 'probe' ? w['source'] : undefined;
74
+ return { window, scope, percent, resetAt, ...(status ? { status } : {}), ...(observedAt ? { observedAt } : {}), ...(source ? { source } : {}) };
75
+ });
76
+ if (usage['windows'].length > 133)
77
+ windows.push({ window: 'seven_day', scope: 'uncertain' });
78
+ return { source, observedAt: usage['observedAt'], windows };
79
+ }
54
80
  function safeProbe(value) {
55
81
  const obj = record(value);
56
82
  const status = obj['status'];
@@ -62,21 +88,7 @@ function safeProbe(value) {
62
88
  validTime(observedAt);
63
89
  const result = { status: status, observedAt };
64
90
  if (status === 'ok' && obj['usage']) {
65
- const usage = record(obj['usage']);
66
- if (typeof usage['observedAt'] !== 'number' || !Array.isArray(usage['windows']))
67
- throw new SubscriptionUsageStoreError();
68
- validTime(usage['observedAt']);
69
- const windows = usage['windows'].slice(0, 133).map(raw => {
70
- const w = record(raw);
71
- const window = w['window'] === 'five_hour' ? 'five_hour' : 'seven_day';
72
- const scope = typeof w['scope'] === 'string' && ['global', 'sonnet', 'opus', 'haiku', 'fable'].includes(w['scope']) ? w['scope'] : 'uncertain';
73
- const percent = typeof w['percent'] === 'number' && Number.isFinite(w['percent']) && w['percent'] >= 0 && w['percent'] <= 100 ? w['percent'] : undefined;
74
- const resetAt = typeof w['resetAt'] === 'number' && Number.isFinite(w['resetAt']) && w['resetAt'] > 0 && w['resetAt'] <= 253402300799000 ? w['resetAt'] : undefined;
75
- return { window, scope, percent, resetAt };
76
- });
77
- if (usage['windows'].length > 133)
78
- windows.push({ window: 'seven_day', scope: 'uncertain' });
79
- result.usage = { source: 'probe', observedAt: usage['observedAt'], windows };
91
+ result.usage = safeUsage(obj['usage'], 'probe');
80
92
  }
81
93
  return result;
82
94
  }
@@ -88,6 +100,9 @@ function safeVersion(value) {
88
100
  }
89
101
  if (value.probe)
90
102
  state.probe = safeProbe(value.probe);
103
+ if (value.usage) {
104
+ state.usage = safeUsage(value.usage, value.usage.source === 'passive' ? 'passive' : 'probe');
105
+ }
91
106
  return state;
92
107
  }
93
108
  function safeReactive(value) {
@@ -158,7 +173,9 @@ export class FileSubscriptionUsageStore {
158
173
  const state = safeVersion(await this.#load(path, {}));
159
174
  if (state.passive && state.passive.observedAt > observedAt && !options?.expireFutureObservations)
160
175
  return;
176
+ const previous = usageStateForSelection({ ...state, reactive: [] }, observedAt).usage;
161
177
  state.passive = { rateLimitInfo: safeRateLimitInfo(rateLimitInfo), observedAt };
178
+ state.usage = mergeUsageObservations([previous, normalizePassiveUsage(state.passive.rateLimitInfo, observedAt)], observedAt);
162
179
  await this.#save(path, state);
163
180
  });
164
181
  }
@@ -216,7 +233,11 @@ export class FileSubscriptionUsageStore {
216
233
  const path = this.#path(key, true);
217
234
  await serial(path, async () => {
218
235
  const state = safeVersion(await this.#load(path, {}));
236
+ // Network completion order must not discard a newer stored snapshot.
237
+ const mergeAt = Math.max(observation.observedAt, state.usage?.observedAt ?? 0, state.passive?.observedAt ?? 0);
238
+ const previous = usageStateForSelection({ ...state, reactive: [] }, mergeAt).usage;
219
239
  state.probe = safeProbe(observation);
240
+ state.usage = mergeUsageObservations([previous, state.probe.usage], mergeAt);
220
241
  await this.#save(path, state);
221
242
  });
222
243
  }
@@ -3,7 +3,7 @@ import { mkdtemp, rm, mkdir } from 'node:fs/promises';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { join } from 'node:path';
5
5
  import { normalizePassiveUsage } from './subscription-selection.js';
6
- import { safeRateLimitInfo, } from './subscription-usage-store.js';
6
+ import { safeRateLimitInfo, usageStateForSelection, } from './subscription-usage-store.js';
7
7
  import { parseClaudeRateLimitInfo, } from './claude-rate-limit.js';
8
8
  export function isUsageProbe(value) {
9
9
  return (!!value &&
@@ -176,7 +176,7 @@ export async function handleUsageProbe(job, options) {
176
176
  ...metadata,
177
177
  accountLabel: account.label ?? account.accountId,
178
178
  reportedAt: now,
179
- usage,
179
+ usage: usageStateForSelection(await options.store.read(account), now).usage,
180
180
  lastRateLimitInfo: safe,
181
181
  probeStatus: 'ok',
182
182
  probeObservedAt: now,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@teamvibe/poller",
3
- "version": "0.8.4-rc.1",
3
+ "version": "0.8.4-rc.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@teamvibe/poller",
9
- "version": "0.8.4-rc.1",
9
+ "version": "0.8.4-rc.2",
10
10
  "dependencies": {
11
11
  "@aws-sdk/client-dynamodb": "3.1108.0",
12
12
  "@aws-sdk/client-sqs": "3.1108.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamvibe/poller",
3
- "version": "0.8.4-rc.1",
3
+ "version": "0.8.4-rc.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {