import type { FilesOperation, FilesPlugin } from "../index.js"; /** Every public verb, so {@link UsageStats.operationsByKind} has a stable shape. */ declare const KINDS: readonly ["upload", "download", "head", "exists", "delete", "copy", "move", "list", "url", "signedUploadUrl"]; /** * A point-in-time snapshot of metered usage, returned by {@link UsageApi.usage} * and {@link UsageApi.usageByGroup}. Each call returns a fresh copy — mutating * it never touches the plugin's running totals. */ export interface UsageStats { /** Successful operations counted (each item of a bulk call counts once). */ operations: number; /** The same count, broken down per verb; every verb is always present. */ operationsByKind: Record<(typeof KINDS)[number], number>; /** Bytes uploaded, summed from each upload's reported result size. */ bytesUp: number; /** Bytes read back out of `download` / `head` bodies, metered as they flow. */ bytesDown: number; } export interface UsageOptions { /** * Bucket usage by a label derived from each operation — e.g. a tenant id or a * key prefix — so {@link UsageApi.usageByGroup} breaks the totals down. It * receives the full {@link FilesOperation}, so branch on `op.kind` to read * `op.key` (most verbs), `op.from` / `op.to` (`copy` / `move`), or nothing * (`list`). Return the same string to attribute ops to the same bucket. Omit * to keep a single global total. */ group?: (op: FilesOperation) => string; } /** * The methods {@link usage} grafts onto a {@link Files} instance. A `type` * rather than an `interface` so it satisfies the `Record` * constraint on {@link FilesPlugin}'s extension parameter — an interface has no * implicit index signature and wouldn't be assignable. */ export type UsageApi = { /** Snapshot the totals, aggregated across every group. */ usage(): UsageStats; /** Snapshot the totals per group, keyed by the {@link UsageOptions.group} label. */ usageByGroup(): Record; /** Zero every counter, starting a fresh accounting window. */ resetUsage(): void; }; /** * Meter storage, bandwidth, and operation counts across a {@link Files} * instance, and surface the running totals via `files.usage()`. Every operation * is counted once; `upload` adds its result size to `bytesUp`, and `download` / * `head` wrap the returned body so the bytes you actually read add to * `bytesDown` — the lazy, stream-level accounting a fire-and-forget * {@link FilesHooks} `onAction` can't do. Pass {@link UsageOptions.group} to * break the totals down per tenant or prefix. * * Body-transparent: it never buffers, transforms, or reads the body itself * (`bytesDown` is tallied only when *you* consume it), so streaming, range * downloads, `url()`, and `signedUploadUrl()` all keep working. It uses no * metadata and no native deps, so it works on any adapter. * * Plugins run **outside** retries, so a call counts as one operation no matter * how many times it's retried, and a call that throws isn't counted at all. * Place `usage()` **first** (outermost) so it meters caller-facing operations * and logical bytes: a later body-transforming plugin (`compression()`, * `encryption()`) reports the logical size up the chain, and the internal * sub-operations a plugin like `dedup()` issues stay below it, unmetered. * Placed last (innermost) it instead meters the bytes-on-the-wire to the * provider and the provider operations those plugins expand into. * * @param options optional `{ group }` — bucket usage per tenant/prefix. * @example * ```ts * import { createFiles } from "files-sdk"; * import { s3 } from "files-sdk/s3"; * import { usage } from "files-sdk/usage"; * * const files = createFiles({ * adapter: s3({ bucket: "uploads" }), * plugins: [usage()], * }); * * await files.upload("a.txt", "hello"); * await (await files.download("a.txt")).text(); * files.usage(); // { operations: 2, bytesUp: 5, bytesDown: 5, operationsByKind: {…} } * ``` */ export declare const usage: (options?: UsageOptions) => FilesPlugin; export {}; //# sourceMappingURL=index.d.ts.map