/** * API-key persistence over the app's KV state store (`App.create({ kv })`). * * Records are keyed by token hash (`ApiKey.keyFor`) — the plaintext token is * never stored — and validated against the scope catalog on read; unknown, * corrupt, expired, or invalid records resolve to `null`. Mutable billing * snapshots persist separately so reconciliation cannot overwrite newer key * metadata. An `id → recordKey` index makes revoke-by-id O(1). The persisted * {@link Record}/{@link MintInput} shapes live here (derived from * `ApiKey.schema` so they cannot drift from the resolved shape), while the * shared credential primitives (token format/generation, storage-key * derivation, redaction) live in `./ApiKey.js`. */ import * as z from 'zod/mini'; import * as ApiKey from './ApiKey.js'; import type * as Db from './db/Db.js'; import * as Store from './internal/Store.js'; import * as Scope from './Scope.js'; /** Maximum live API keys attributed to one organization. */ export declare const maxLiveKeysPerOrganization = 100; /** Maximum legacy organization-index entries examined during one admission attempt. */ export declare const maxLegacyAdmissionIndexes = 1000; /** Zod schemas owned by the API-keys module. */ export declare namespace schema { /** * Fields accepted when minting a key, and the single source of truth for the * {@link MintInput} type and structural validation. {@link mint} validates * scope identifiers against its configured catalog. */ const MintInput: z.ZodMiniObject<{ allowedIps: z.ZodMiniDefault>>>; billingActive: z.ZodMiniOptional>; environment: z.ZodMiniDefault>; name: z.ZodMiniOptional>; projectId: z.ZodMiniOptional>; rateLimits: z.ZodMiniOptional, z.ZodMiniObject<{ limit: z.ZodMiniNumber; period: z.ZodMiniUnion, z.ZodMiniLiteral<"second">]>; }, z.core.$strip>>>; createdBy: z.ZodMiniOptional>; expiresAt: z.ZodMiniOptional; orgId: z.ZodMiniOptional>; scopes: z.ZodMiniReadonly>>; }, z.core.$strip>; /** * A persisted API-key record: the resolved `ApiKey.schema` plus * persistence/display fields. Extending the resolved schema keeps the resolved * and persisted shapes in lockstep. */ const Record: z.ZodMiniObject<{ allowedIps: z.ZodMiniDefault>>>; billingActive: z.ZodMiniOptional>; environment: z.ZodMiniDefault>; id: z.ZodMiniString; name: z.ZodMiniOptional>; orgId: z.ZodMiniString; projectId: z.ZodMiniOptional>; rateLimits: z.ZodMiniOptional, z.ZodMiniObject<{ limit: z.ZodMiniNumber; period: z.ZodMiniUnion, z.ZodMiniLiteral<"second">]>; }, z.core.$strip>>>; scopes: z.ZodMiniReadonly>>; createdAt: z.ZodMiniString; createdBy: z.ZodMiniOptional>; expiresAt: z.ZodMiniOptional>; tokenLast4: z.ZodMiniString; }, z.core.$strip>; } /** * A durable API-key record as persisted. A superset of the resolved * `ApiKey.ApiKey` with provisioning/display metadata. The plaintext token is * never stored — records are keyed by its hash (`ApiKey.keyFor`) and carry only * `tokenLast4` for display. */ export type Record = z.output; /** * Fields accepted when minting a key via {@link mint}. Uses the schema's * *input* type so defaulted fields (e.g. `environment`) are optional for * callers — the default is applied during `mint`'s validation. */ export type MintInput = z.input; /** Result of {@link mint}: the persisted record and its one-time token. */ export type MintResult = { /** The persisted key record (metadata only — never the token). */ record: Record; /** The plaintext token, shown once and unrecoverable afterward. */ token: string; }; /** * Mints a key: validates the input (e.g. rejects an unknown scope at the write * boundary), persists its hashed record, and returns the record plus the * one-time plaintext token (shown once, unrecoverable afterward). * * @param state - The KV state store holding key records. * @param input - The key to mint. * @param options - Scope catalog used for validation. * @returns The persisted record and its one-time token. */ export declare function mint(state: Store.State, input: MintInput, options?: mint.Options): Promise; /** Mints an attributed key after atomically reserving an organization-wide live-key slot. */ export declare function mintBounded(db: Db.Db, state: Store.State, input: MintInput, options?: mint.Options): Promise; /** Durably fences key use before deleting its organization or project. The idempotent fence remains on failure so concurrent attempts cannot reopen the owner. */ export declare function markOwnerDeleting(state: Store.State, owner: markOwnerDeleting.Owner): Promise; export declare namespace markOwnerDeleting { /** API-key owner being deleted. */ type Owner = { /** Owning organization id. */ orgId: string; /** Project id when deleting only one project. */ projectId?: string | undefined; }; } export declare namespace mint { /** Options for {@link mint}. */ type Options = { /** Scope catalog accepted while minting the key. */ scopeCatalog?: Scope.Catalog | undefined; }; } /** * Resolves a plaintext API key token to its metadata, or `null`. Expiry is * enforced on read — not just via the store's native TTL — so it holds on * backends that evict lazily and regardless of TTL granularity. * * @param state - The KV state store holding key records. * @param token - The presented plaintext token. * @param options - Scope catalog used for validation. * @returns The resolved key metadata, or `null`. */ export declare function resolve(state: Store.State, token: string, options?: resolve.Options): Promise; export declare namespace resolve { /** Options for {@link resolve}. */ type Options = { /** Scope catalog accepted while resolving the key. */ scopeCatalog?: Scope.Catalog | undefined; }; } /** * Reads a key record by id (metadata only — never the token), or `null`. * * @param state - The KV state store holding key records. * @param id - The key id (`key_…`). * @param options - Scope catalog used for validation. * @returns The record, or `null`. */ export declare function get(state: Store.State, id: string, options?: get.Options): Promise; export declare namespace get { /** Options for {@link get}. */ type Options = { /** Scope catalog accepted while reading the key. */ scopeCatalog?: Scope.Catalog | undefined; }; } /** * Lists key records (metadata only — never tokens), newest first. Expired or * catalog-invalid records are skipped. * * @param state - The KV state store holding key records. * @param options - Optional owner filter. * @returns The records. */ export declare function list(state: Store.State, options?: list.Options): Promise; export declare namespace list { /** Options for {@link list}. */ type Options = { /** Restrict results to keys owned by this organization. */ orgId?: string | undefined; /** Scope catalog accepted while listing keys. */ scopeCatalog?: Scope.Catalog | undefined; }; } /** * Lists an organization's key records through the org index (no full scan), * newest first. Dangling index entries (revoked or expired records) are * skipped and lazily deleted. * * @param state - The KV state store holding key records. * @param orgId - The owning organization id (`org_…`). * @param options - Optional environment/project filters. * @returns The records. */ export declare function listByOrg(state: Store.State, orgId: string, options?: listByOrg.Options): Promise; /** Reads one bounded page through an organization's key index. */ export declare function listByOrgPage(state: Store.State, orgId: string, options: listByOrgPage.Options): Promise; export declare namespace listByOrgPage { /** Bounded organization-key page inputs. */ type Options = listByOrg.Options & { /** Whether dangling index entries should be deleted while reading. */ cleanupDangling?: boolean | undefined; /** Continue after a previous page. */ cursor?: string | undefined; /** Maximum index entries to read. */ limit: number; }; /** Bounded organization-key page. */ type Result = { /** Cursor for the following page, when present. */ cursor?: string | undefined; /** Number of index entries examined in this page. */ indexCount: number; /** Whether every matching index was returned. */ listComplete: boolean; /** Valid key records in this page. */ records: readonly Record[]; }; } export declare namespace listByOrg { /** Options for {@link listByOrg}. */ type Options = { /** Restrict results to keys in this environment. */ environment?: 'production' | 'sandbox' | undefined; /** Restrict results to keys attributed to this project. */ projectId?: string | undefined; /** Scope catalog accepted while listing keys. */ scopeCatalog?: Scope.Catalog | undefined; }; } /** * Revokes a key by id, deleting its record and index entries. * * @param state - The KV state store holding key records. * @param id - The key id (`key_…`). * @returns Whether a matching record was deleted. */ export declare function revoke(state: Store.State, id: string): Promise; /** Fences and revokes a key, then idempotently removes its authoritative live-key slot. */ export declare function revokeBounded(db: Db.Db, state: Store.State, id: string): Promise; /** * Updates a key's IP allowlist, display name, quotas, scopes, and attribution, * rewriting its record in place and moving the org index entry when the org changes. * * @param state - The KV state store holding key records. * @param id - The key id (`key_…`). * @param input - Key metadata to apply. * @param options - Scope catalog used for validation. * @returns The updated record, or `null` when the key is absent. */ export declare function update(state: Store.State, id: string, input: update.Input, options?: update.Options): Promise; /** Updates a key while atomically enforcing owner fences and admission accounting. */ export declare function updateBounded(db: Db.Db, state: Store.State, id: string, input: update.Input, options?: updateBounded.Options): Promise; export declare namespace updateBounded { /** Options for an admission-accounted key update. */ type Options = update.Options & { /** Owner the locked record must still belong to. */ expectedOwner?: Owner | undefined; }; /** Expected owner checked under the per-key lock. */ type Owner = { /** Owning organization id (`org_…`). */ orgId: string; /** Attributed project id, or absent for an organization key. */ projectId?: string | undefined; }; } export declare namespace update { /** Metadata applied by {@link update}; omitted fields keep their current value. */ type Input = { /** Replacement client IP/CIDR allowlist. An empty list clears the restriction. */ allowedIps?: readonly string[] | undefined; /** New human-readable key name. */ name?: string | undefined; /** New owning organization id (`org_…`). */ orgId?: string | undefined; /** New attributed project id (`prj_…`). */ projectId?: string | undefined; /** Replacement per-key quota overrides. */ rateLimits?: ApiKey.ApiKey['rateLimits'] | undefined; /** Replacement granted scopes. */ scopes?: readonly Scope.Id[] | undefined; }; /** Options for {@link update}. */ type Options = { /** Scope catalog accepted while reading the key. */ scopeCatalog?: Scope.Catalog | undefined; }; } /** * Re-attributes a key while preserving the existing public API. * * @param state - The KV state store holding key records. * @param id - The key id (`key_…`). * @param input - Attribution to apply. * @param options - Scope catalog used for validation. * @returns The updated record, or `null` when the key is absent. */ export declare function attribute(state: Store.State, id: string, input: attribute.Input, options?: attribute.Options): Promise; export declare namespace attribute { /** Attribution applied by {@link attribute}; omitted fields keep their current value. */ type Input = Pick; /** Options for reading and updating the key record. */ type Options = update.Options; } /** * Stamps `billingActive` onto every key an organization owns in an environment, * re-syncing the snapshot the auth path reads when billing flips (activation or * lapse). The snapshot is stored separately so this background writer never * overwrites newer key metadata. Records already carrying the target value are * left untouched. * * @param state - The KV state store holding key records. * @param options - Owner, environment, and the new billing-active value. * @returns The number of records updated. */ export declare function setBillingActive(state: Store.State, options: setBillingActive.Options): Promise; export declare namespace setBillingActive { /** Options for {@link setBillingActive}. */ type Options = { /** The new billing-active value to stamp. */ active: boolean; /** Environment whose keys are re-stamped. */ environment: 'production' | 'sandbox'; /** Owning organization id (`org_…`). */ orgId: string; /** Scope catalog accepted while updating keys. */ scopeCatalog?: Scope.Catalog | undefined; }; } /** * Rebuilds the `id` and `org` index entries for every stored record — the * run-once backfill making legacy keys visible to org-scoped listing. Records * themselves are never modified, so existing tokens keep resolving. * * @param state - The KV state store holding key records. * @param options - Scope catalog used for validation. * @returns Scanned and indexed record counts. */ export declare function backfill(state: Store.State, options?: backfill.Options): Promise; export declare namespace backfill { /** Options for {@link backfill}. */ type Options = { /** Scope catalog accepted while reading keys. */ scopeCatalog?: Scope.Catalog | undefined; }; /** Result of {@link backfill}. */ type Result = { /** Records whose index entries were written. */ indexed: number; /** Stored records scanned (including invalid or expired ones, skipped). */ scanned: number; }; } /** Returns whether the organization or attributed project has been deleted. */ export declare function isOwnerDeleted(state: Store.State, owner: isOwnerDeleted.Owner): Promise; export declare namespace isOwnerDeleted { /** API-key owner whose deletion state is checked. */ type Owner = markOwnerDeleting.Owner; } /** Thrown when an API key owner is being deleted or is already deleted. */ export declare class OwnerDeletedError extends Error { name: string; constructor(); } /** Thrown when an organization has reached its live API-key cap. */ export declare class LiveKeyLimitError extends Error { name: string; constructor(limit: number); } //# sourceMappingURL=ApiKeys.d.ts.map