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.

Val-Scoped Blob Admin

A little admin UI for browsing, creating, viewing, editing, uploading to, downloading from, and deleting Val Town blobs — right from your browser.

This is a fork of Steve Krouse's Global Blob Admin, updated to:

  • add JSON syntax highlighting when viewing a blob (numbers, strings, keys, booleans, and null are colored)
  • work against val-scoped blob storage (std/blob/main.ts) instead of only account-global blobs, so you can run one of these per-project and it only ever sees that project's blobs

How it's organized

FileWhat it does
helper.tsShared types (BlobStore, BlobAdminOptions) + the JSON syntax highlighter. Plain TS, no Val Town–specific code.
blob-admin.tsxcreateBlobAdmin() — builds the Hono app (all the routes/pages). This is the reusable part.
main.tsxStandalone demo: wires createBlobAdmin() to this val's own blobs, behind password auth. This is what's deployed at this val's URL.
example.tsxThe exact snippet you'd copy into your own val (see below).
minimal.tsxA single-file, compact version of the same app for quick reference/remixing without the multi-file split.

The refactor's whole point is that blob-admin.tsx doesn't know anything about this val — you give it a blob client and it gives you back a Hono app. main.tsx is just one particular way of using it.

Using this in your own val

You don't need to copy the full app. Import createBlobAdmin and pass it your own val's blob import — that's the whole integration:

/** @jsxImportSource https://esm.sh/hono@4.0.8/jsx **/ import { passwordAuth } from "https://esm.town/v/pomdtr/password_auth/main.tsx"; import { verifyToken } from "https://esm.town/v/pomdtr/verifyToken"; import { blob } from "https://esm.town/v/std/blob/main.ts"; // your val's own blobs import { createBlobAdmin } from "https://esm.town/v/gwoods22/val_scoped_blob_admin/blob-admin.tsx"; const app = createBlobAdmin({ blob, valName: "My App's" }); // createBlobAdmin has no auth of its own — always wrap it before exporting. export default passwordAuth(app.fetch, { verifyPassword: verifyToken });

That's it — no copy-pasting the routes, the JSX, or the syntax highlighter. See example.tsx in this val for the same snippet, ready to remix.

Why you pass in your own blob

createBlobAdmin() takes a blob client as a required option instead of importing one itself. Two reasons, both about security:

  1. Scoping. Val Town's std/blob/main.ts import is scoped to the val it's imported into — when your val imports it, it can only ever reach your val's blobs. If this library imported its own blob client instead, every val using it would be sharing (and could accidentally clobber) the same storage.
  2. No hidden network access. The library never reaches out on its own — it only ever touches whatever store object you hand it. You can audit exactly what it does to your data by reading blob-admin.tsx.

If you'd rather manage blobs globally across your whole account, swap the import for https://esm.town/v/std/blob/global.ts — same shape, so nothing else changes.

Add your own auth

createBlobAdmin() deliberately ships with no authentication. This admin panel can read, overwrite, and delete every blob in whatever store you give it, so an unauthenticated deployment means anyone with the URL has full read/write/delete access to that data.

The example above uses Val Town's built-in passwordAuth + verifyToken pattern (same as this val's own main.tsx), which is a nice fit for personal projects: the "password" you sign in with is your own Val Town API token, so only you can get in. You're of course free to swap in any other auth middleware that wraps a fetch handler.

Local development

Everything here is plain Hono + JSX, no build step. Edit blob-admin.tsx to change routes or markup, helper.ts for shared types/utilities, and main.tsx to change how the standalone deployment of this val is configured. minimal.tsx is a self-contained, single-file version kept around for anyone who'd rather grab one compact file than wire up the multi-file split.