feat(my-videos): delete-by-key primitive for orphan cleanup (Phase 2, step 3a)

The bucket listing returns raw keys, but deleteVideoStorage only works from note
objects — so orphan cleanup needs a key-based delete. Adds
r2Service.deleteStorageKeys({ keys, npub|pubkey }) (unlock-gated; deletes exactly
the given keys, records per-key failures without aborting the batch). Extracts a
shared resolveStorageClient (unlock-gated connection+client resolution) now used
by both listVideoStorageObjects and deleteStorageKeys, removing the duplication.

Tests + mutation-verified: never deletes while locked, empty-list no-op, deletes
exactly the given keys, per-key failure isolation. The shared lock gate is
mutation-verified across both list and delete paths.

Build + full lint green (r2Service under its file-size budget).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-20 14:58:29 -04:00
1 parent 513f75e4da
commit 41505c2e51
3 files changed
+141 -17

No files matched your search

+9
View File
@@ -62,6 +62,7 @@ import {
safeDecodeNpub,
verifyPublicAccess as verifyPublicAccessHelper,
listVideoStorageObjects as listVideoStorageObjectsHelper,
deleteStorageKeys as deleteStorageKeysHelper,
} from "./r2ServiceHelpers.js";
const STATUS_VARIANTS = new Set(["info", "success", "error", "warning"]);
@@ -239,6 +240,14 @@ export class R2Service {
return listVideoStorageObjectsHelper(this, args);
}
/**
* Delete specific bucket object keys (orphan cleanup). Unlock-gated; returns
* { ok, deleted, failed, reason }.
*/
async deleteStorageKeys(args = {}) {
return deleteStorageKeysHelper(this, args);
}
on(event, handler) {
if (typeof handler !== "function") {
return () => {};