import type { FilesPlugin, StoredFile } from "../index.js"; /** * A saved snapshot of a key, as returned by {@link VersioningApi.versions}. * Pass {@link FileVersion.versionId} back to {@link VersioningApi.restore} to * roll a key back to this point. */ export interface FileVersion { /** Opaque, time-ordered id for this version; hand it to `restore()`. */ versionId: string; /** The underlying storage key this snapshot lives at, under the version prefix. */ key: string; /** Byte length of the snapshot (the logical size, after inner plugins). */ size: number; /** When the snapshotted object was last modified (ms epoch), parsed from the id. */ lastModified: number; /** The snapshot's ETag, when the adapter reports one. */ etag?: string; } /** * The methods {@link versioning} 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 VersioningApi = { /** * List the saved versions of `key`, **newest first**. Each entry's * `versionId` can be passed to {@link VersioningApi.restore}. Returns an empty * array when the key has no history. */ versions(key: string): Promise; /** * Roll `key` back to a prior version — the newest one when `versionId` is * omitted (an undo of the last change). The current bytes are snapshotted * first, so a restore is itself reversible. Resolves to the restored * {@link StoredFile} (via `head`). Throws when the key has no versions, or the * given `versionId` doesn't exist. */ restore(key: string, versionId?: string): Promise; }; export interface VersioningOptions { /** * Where snapshots are stored, as a key prefix. Defaults to `".versions"`. * Versions of `photos/a.jpg` live at `".versions/photos/a.jpg/"`. Objects * under this prefix are hidden from `list()` (unless you list within it) and * are never themselves versioned. Don't store your own data under it. */ prefix?: string; /** * Cap the number of versions kept per key. After each snapshot the oldest * versions beyond this many are pruned. Omit to keep every version (history * grows unbounded). Must be a positive integer. */ limit?: number; } /** * Snapshot the prior bytes of any object before an overwrite or delete, and add * `versions()` / `restore()` so you can roll a key back. Before an `upload`, * `delete`, or the destination of a `copy` / `move` clobbers an existing object, * the plugin server-side-copies it to a time-stamped key under a version prefix * (`.versions/` by default); the live object is untouched. * * Snapshots are plain object copies, so it's **body-transparent** — unlike * `encryption()` / `compression()` it never buffers, transforms, or reads the * body, which leaves streaming, range downloads, `url()`, and `signedUploadUrl()` * all working normally. It composes with the transforming plugins by copying * whatever they stored (a version of an encrypted object stays encrypted and * still restores cleanly), so place it **first** (outermost): * `plugins: [versioning(), compression(), encryption(key)]`. * * This is the first plugin to use `extend`, so reach for {@link createFiles} to * surface `files.versions()` / `files.restore()` on the type. * * Trade-offs, by design: * - **A `head` + `copy` per overwrite/delete.** Snapshotting costs two extra * adapter round-trips on writes that hit an existing object; first writes * (nothing to snapshot) cost only the `head`. * - **Direct presigned writes bypass it.** A client `PUT` to a `signedUploadUrl` * never runs the plugin, so no snapshot is taken; write through the instance * to version. (It's a safety net, not a security control, so it doesn't fail * closed the way `validation()` does.) * - **`move` snapshots only its destination.** A rename relocates the bytes * rather than destroying them, so the source isn't snapshotted. * - **History is unbounded** unless you set `limit`. * * @param options optional `{ prefix, limit }` — where snapshots live and how * many to keep per key. * @example * ```ts * import { createFiles } from "files-sdk"; * import { s3 } from "files-sdk/s3"; * import { versioning } from "files-sdk/versioning"; * * const files = createFiles({ * adapter: s3({ bucket: "uploads" }), * plugins: [versioning({ limit: 10 })], * }); * * await files.upload("notes.txt", "v1"); * await files.upload("notes.txt", "v2"); // "v1" snapshotted first * * const [previous] = await files.versions("notes.txt"); * await files.restore("notes.txt", previous.versionId); // back to "v1" * ``` */ export declare const versioning: (options?: VersioningOptions) => FilesPlugin; //# sourceMappingURL=index.d.ts.map