Initial import of verae-middleware from zapier monorepo

This commit is contained in:
George Lambert 2026-09-11 16:05:22 -04:00
commit 16c439bb7b
67 changed files with 6630 additions and 0 deletions

102
src/store/usage.js Normal file
View file

@ -0,0 +1,102 @@
/**
* @fileoverview Per-tenant usage metering counters.
* @module store/usage
*/
import { getStore, persist } from './db.js';
import { getTenant, resolveLimits } from './tenants.js';
import { createDebugger } from '../debug/logger.js';
const log = createDebugger('billing');
/**
* @returns {string} YYYY-MM period key
*/
function currentPeriod() {
const d = new Date();
return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}`;
}
/**
* @param {string} tenantId
* @returns {{ period: string, timestamps: number, verifications: number, statusChecks: number, batchTimestamps: number, overage: object }}
*/
function emptyUsage(tenantId) {
return {
tenantId,
period: currentPeriod(),
timestamps: 0,
verifications: 0,
statusChecks: 0,
batchTimestamps: 0,
overage: { timestamps: 0, verifications: 0 },
};
}
/**
* Get usage for tenant, rolling period if month changed.
* @param {string} tenantId
* @returns {ReturnType<typeof emptyUsage>}
*/
export function getUsage(tenantId) {
const store = getStore();
let usage = store.usage[tenantId];
const period = currentPeriod();
if (!usage || usage.period !== period) {
usage = emptyUsage(tenantId);
store.usage[tenantId] = usage;
}
return usage;
}
/**
* Public summary for /auth/me.
* @param {string} tenantId
* @returns {object}
*/
export function getUsageSummary(tenantId) {
const usage = getUsage(tenantId);
const tenant = getTenant(tenantId);
const limits = tenant ? resolveLimits(tenant) : null;
return {
period: usage.period,
timestamps: usage.timestamps,
verifications: usage.verifications,
statusChecks: usage.statusChecks,
batchTimestamps: usage.batchTimestamps,
limits: limits
? {
timestamps: limits.timestamps,
verifications: limits.verifications,
batch: limits.batch,
batchMaxItems: limits.batchMaxItems,
}
: null,
};
}
/**
* Increment a usage metric.
*
* @param {string} tenantId
* @param {string} metric - e.g. `timestamps`, `verifications`, `statusChecks`, `batchTimestamps`, `overage.timestamps`
* @param {number} [amount=1]
* @returns {void}
*/
export function incrementUsage(tenantId, metric, amount = 1) {
const usage = getUsage(tenantId);
if (metric.startsWith('overage.')) {
const key = metric.slice('overage.'.length);
usage.overage[key] = (usage.overage[key] ?? 0) + amount;
} else {
usage[metric] = (usage[metric] ?? 0) + amount;
}
getStore().usage[tenantId] = usage;
persist();
log.debug('usage incremented', { tenantId, metric, amount, value: usage[metric] ?? usage.overage });
}