Current Status
Storage has a first-class CLI command group in Sources/FirestructCLIKit/StorageCommand.swift. It reuses StorageService, so emulator behavior and guarded production URL/request shapes match the macOS Storage module. Approved live bucket verification is still required before live Storage hardening is claimed.
Project Selection
Commands use the selected project from project select unless --project <name|firebaseProjectID|uuid> is passed.
If --bucket is omitted, the CLI defaults to:
<firebaseProjectID>.appspot.com
Live Storage requests can pass either:
--authorization "Bearer <token>"
--access-token <token>
Commands
Bucket discovery:
storage buckets [--bucket fallback-bucket]
Object browsing:
storage list --bucket demo.appspot.com [--prefix avatars/] [--recursive] [--browser]
storage list --bucket demo.appspot.com --browser --sort-by updated --descending
storage inspect --bucket demo.appspot.com --path avatars/alice.png
--browser adds GUI-like folder/file entries built with StorageService.browserEntries.
inspect returns object metadata, preview kind, metadata rows, and the object download URL.
Uploads:
storage upload --bucket demo.appspot.com --file ./avatar.png --path avatars/alice.png --confirm
storage upload --bucket demo.appspot.com --file ./data.json --path imports/data.json --content-type application/json --metadata '{"owner":"alice"}' --confirm
storage upload-folder --bucket demo.appspot.com --folder ./avatars --target avatars --confirm
Downloads:
storage download --bucket demo.appspot.com --path avatars/alice.png --output ./avatar.png
storage download-batch --bucket demo.appspot.com --paths avatars/a.png,avatars/b.png --output-dir ./downloads [--concurrency 4]
storage zip --bucket demo.appspot.com --paths avatars/a.png,avatars/b.png --output ./selection.zip
storage zip-folder --bucket demo.appspot.com --path avatars --output ./avatars.zip
Mutations:
storage delete --bucket demo.appspot.com --path avatars/alice.png --confirm
storage delete --bucket demo.appspot.com --paths avatars/a.png,avatars/b.png --confirm
storage delete-folder --bucket demo.appspot.com --path avatars --confirm
storage copy --bucket demo.appspot.com --path avatars/a.png --target avatars/b.png --confirm
storage move --bucket demo.appspot.com --path avatars/a.png --target archive/a.png --confirm
storage copy-folder --bucket demo.appspot.com --path avatars --target avatars-copy --confirm
storage move-folder --bucket demo.appspot.com --path avatars --target archive/avatars --confirm
storage rename-folder --bucket demo.appspot.com --path avatars --name archived-avatars --confirm
storage duplicate-folder --bucket demo.appspot.com --path avatars --confirm
URL helpers:
storage url --bucket demo.appspot.com --path avatars/alice.png
storage signed-url --bucket demo.appspot.com --path avatars/alice.png --expires 3600
storage signed-url --bucket demo.appspot.com --path avatars/alice.png --expires 3600 --service-account-file ./service-account.json
For emulator projects, signed-url returns a deterministic emulator download URL with the requested expiration. For production projects, V4 signing requires --service-account-file.
Safety
- Upload, delete, copy, move, folder upload, folder delete, folder copy, folder move, folder rename, and folder duplicate require
--confirm. - Read-only project links reject Storage mutations.
- Folder copy/move checks for nested targets and duplicate destination objects before mutating.
- Object copy/move validates that source and target paths differ.
- Long multi-object operations run through
TaskOrchestratorand return task status, counters, duration, and errors in JSON output.
Output
All commands emit JSON. Long-running commands include a task object:
{
"status": "success",
"processedOperations": 2,
"totalOperations": 2,
"attemptCount": 1
}
Current Verification
FirestructCLIIntegrationTests/testCLICommandsRoundTripAgainstFirebaseEmulators
uploads two real Storage emulator objects, lists them through selected-module
browser output, inspects and downloads one object, builds both selected-object
and folder ZIP archives, validates archive payload bytes with /usr/bin/unzip,
copies the folder, moves the copied folder, lists emulator source/target paths
afterward, deletes an object, and verifies Storage folder/delete task titles are
retained by tasks list.
FirestructCLIIntegrationTests/testStorageMoveSignedURLAndReadOnlyGuard
verifies read-only project links reject Storage mutations and emulator signed
URLs are deterministic. Approved live bucket verification is still required
before live Storage hardening is claimed.
Source Anchors
Sources/FirestructCLIKit/StorageCommand.swiftSources/FirestructCLIKit/FirestructCLI.swiftSources/FirestructCLIKit/JSONOutput.swiftSources/FirestructCore/StorageService.swiftTests/FirestructCLIIntegrationTests/FirestructCLIIntegrationTests.swift