import type { Instant, MeterReading, ScopeStatus, TenantId, TenantStatus } from '@substrat-run/contracts'; /** * §5's meters, folded once (#38). * * Every adapter has the same three directory tables and could each write the same * `GROUP BY`. They must not: the billable rule is a *commercial* definition, and two * copies of it in two dialects is how the Cloudflare fleet and the SQLite fleet end up * quoting different numbers for the same month. So the adapters fetch rows — a job SQL * is genuinely better at — and the arithmetic that decides what counts lives here, in * one pure function, testable without a database. * * The counterpart to `migration-progress.ts`: the same shape of directory-derived * answer, computed above the storage seam rather than inside each adapter. */ /** One tenant row the fold needs — the directory's `tenants`, narrowed. */ export interface MeterTenantInput { tenantId: TenantId; slug: string; status: TenantStatus; } /** One scope row the fold needs. Only its tenant and status matter to a meter. */ export interface MeterScopeInput { tenantId: TenantId; status: ScopeStatus; } /** One entitlement grant the fold needs; `quota` is expression only, so it is absent. */ export interface MeterEntitlementInput { tenantId: TenantId; entitlementKey: string; plan: string | null; expiresAt: string | null; } export interface MeterInput { /** * The instant the directory was read — supplied by the caller, never taken from a * clock in here, so the reading's stamp and every expiry comparison are the SAME * instant and a test can pin both. */ readAt: Instant; tenants: MeterTenantInput[]; scopes: MeterScopeInput[]; entitlements: MeterEntitlementInput[]; } /** * Fold directory rows into one reading. Pure: same rows in, same numbers out, no clock * of its own — `readAt` is supplied so the reading's instant and the expiry comparisons * are the same instant, and so a test can pin it. * * Rows belonging to a tenant that is not in `tenants` are IGNORED rather than counted * against nothing. That is what makes a `{ tenantId }`-narrowed reading come out of the * same code path as the fleet one: the caller narrows the tenant set, and everything * else follows from it. */ export declare function foldMeterReading(input: MeterInput): MeterReading; //# sourceMappingURL=meters.d.ts.map