Public
Library to migrate selected blobs from global to scoped storage
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

migrate-blob

A small library to migrate a specific list of blobs from global blob storage (account-wide, Cloudflare R2) to scoped blob storage (per-val, S3).

Migration streams the raw body of each blob, so it is safe for binary, text, and JSON alike, and preserves keys exactly. Defaults are conservative: dry-run, no overwrite, and copy (not move).

Library usage

Import migrateBlobs from main.ts:

import { migrateBlobs } from "https://esm.town/v/nbbaier/migrate-blob/main.ts"; const summary = await migrateBlobs(["my-config", "images/logo.png"], { commit: true, // default false (dry run) }); console.log(summary.counts); // { ok, skip, miss, dry, err }

migrateBlobs(targets, options)

OptionDefaultBehavior
prefixfalseWhen true, targets are expanded as prefixes into global keys.
commitfalseWhen false, nothing is written — only reports what would happen.
overwritefalseWhen false, keys already in scoped storage are skipped (idempotent).
deleteSourcefalseWhen true, deletes from global after a successful copy (i.e. a move). Ignored unless commit.
onProgressCallback (result) => void invoked after each key.

Returns a MigrateSummary: { results, counts, dryRun }, where each result is { key, status, sourceDeleted?, error? }.

Result statuses

  • ok — copied from global to scoped.
  • skip — already present in scoped storage (re-run safe).
  • miss — not found in global storage.
  • dry — would have migrated, but commit was false.
  • err — see the error field.

How it works

Rendering mermaid diagram...

Notes

  • Global and scoped blobs are stored separately; you can't reach one through the other's interface — hence this migration.
  • Keys can be up to 512 chars. Total storage counts toward your plan limit (1 GB on Pro); during a copy (not move) the data exists in both stores.