import { all, run } from "../db";
import { domainSites } from "../sites/store";
import { locate, registerLocator } from "../scoped-db/locators";
/**
* Directory lookups for metering fan-outs. Usage lives in each account's AccountState; these list which
* objects to visit. Anonymous `scratch:` ids have no accounts row, so they register a `scratch_account`
* locator the first time they hold or record usage.
*/
export async function directoryAccountIds(): Promise<string[]> {
return (await all<{ id: string }>("SELECT id FROM accounts ORDER BY id")).map((row) => row.id);
}
export async function scratchAccountIds(): Promise<string[]> {
return (await all<{ key: string }>("SELECT key FROM scope_locators WHERE kind = 'scratch_account' ORDER BY key")).map(
(row) => row.key,
);
}
/** Every object that may hold usage: directory accounts plus registered scratch ids. */
export async function meteredAccountIds(): Promise<string[]> {
return [...(await directoryAccountIds()), ...(await scratchAccountIds())];
}
/** Makes a scratch id reachable by sweeps (anonymous usage is low volume, so this is one small upsert). */
export async function noteScratchAccount(accountId: string): Promise<void> {
if (!accountId.startsWith("scratch:")) return;
await registerLocator("scratch_account", accountId, accountId);
}
/** Registers `key` only when it is unclaimed; returns the scope that owns it afterwards (first claim wins). */
export async function claimLocator(
kind: "stripe_customer" | "scratch_claim",
key: string,
scopeId: string,
): Promise<string> {
await run(
"INSERT INTO scope_locators (kind, key, scope_id) VALUES (?, ?, ?) ON CONFLICT (kind, key) DO NOTHING",
kind,
key,