import type { FilesPlugin, StoredFile } from "../index.js"; /** * A trashed object, as returned by {@link SoftDeleteApi.trashed}. Pass its * {@link TrashedFile.key} (the original, live key) back to * {@link SoftDeleteApi.restore} to bring it back, or * {@link SoftDeleteApi.purge} to delete it for good. */ export interface TrashedFile { /** The original key the object was deleted from — hand it to `restore()` / `purge()`. */ key: string; /** The underlying storage key the trashed copy lives at, under the trash prefix. */ trashKey: string; /** Byte length of the trashed object. */ size: number; /** * The trashed copy's last-modified time (ms epoch), when the adapter reports * one. On most adapters a soft delete is a server-side copy, so this is * roughly when the object was trashed. */ lastModified?: number; /** The trashed copy's ETag, when the adapter reports one. */ etag?: string; } /** * The methods {@link softDelete} 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 SoftDeleteApi = { /** * List everything currently in the trash, each entry carrying the original * `key` you'd pass to {@link SoftDeleteApi.restore}. Returns an empty array * when the trash is empty. */ trashed(): Promise; /** * Bring a soft-deleted object back to its original key, removing it from the * trash. Resolves to the restored {@link StoredFile} (via `head`). Throws when * nothing is trashed for `key`. A live object at `key` (e.g. one re-created * after the delete) is overwritten. */ restore(key: string): Promise; /** * Permanently delete a trashed object — the one for `key`, or the **entire** * trash when `key` is omitted. Idempotent: purging a key with nothing trashed * is a no-op. This is the only way the data actually leaves storage. */ purge(key?: string): Promise; }; export interface SoftDeleteOptions { /** * Where deleted objects are moved, as a key prefix. Defaults to `".trash"`. * A delete of `photos/a.jpg` relocates it to `".trash/photos/a.jpg"`. Objects * under this prefix are hidden from `list()` (unless you list within it) and a * `delete` of one is a **real** delete — that's how `purge()` works. Don't * store your own data under it. */ prefix?: string; } /** * Turn `delete` into a recoverable move into a trash prefix, and add `trashed()` * / `restore()` / `purge()` so you can list, recover, and permanently remove * what's been deleted. Instead of destroying an object, a `delete` server-side * **moves** it to a time-of-deletion copy under a trash prefix (`.trash/` by * default); the bytes only ever leave storage when you `purge()`. * * Like `versioning()`, it's **body-transparent** — it never buffers, transforms, * or reads the body, so streaming, range downloads, `url()`, and * `signedUploadUrl()` all keep working — and it has **no native dependencies**. * Because it relocates whatever the rest of the pipeline stored, place it * **first** (outermost): `plugins: [softDelete(), encryption(key)]`. * * It uses `extend`, so reach for {@link createFiles} to surface * `files.trashed()` / `files.restore()` / `files.purge()` on the type. * * Trade-offs, by design: * - **One copy per key.** A delete relocates to `"/"`, so deleting * a key whose trashed copy still exists **replaces** that copy (latest delete * wins). Reach for `versioning()` if you need every deleted generation kept. * - **`delete` becomes a `copy` + `delete`.** A soft delete is a move, so it * costs an extra round-trip versus a hard delete. Deleting a key that doesn't * exist stays a no-op, the same as a plain `delete`. * - **Direct presigned writes bypass it.** Only deletes through the instance are * trashed; it's a safety net, not a security control, so it doesn't fail * closed the way `validation()` does. * - **Trash grows until you `purge()`.** Nothing expires on its own. * * @param options optional `{ prefix }` — where trashed objects live. * @example * ```ts * import { createFiles } from "files-sdk"; * import { s3 } from "files-sdk/s3"; * import { softDelete } from "files-sdk/soft-delete"; * * const files = createFiles({ * adapter: s3({ bucket: "uploads" }), * plugins: [softDelete()], * }); * * await files.upload("notes.txt", "hi"); * await files.delete("notes.txt"); // moved to .trash/notes.txt, not destroyed * * await files.trashed(); // [{ key: "notes.txt", trashKey: ".trash/notes.txt", … }] * await files.restore("notes.txt"); // back to "notes.txt" * await files.delete("notes.txt"); * await files.purge("notes.txt"); // now it's really gone * ``` */ export declare const softDelete: (options?: SoftDeleteOptions) => FilesPlugin; //# sourceMappingURL=index.d.ts.map