Skip to content

feat(stream): video libraries, directory linking, uploads, and video management - #203

Draft
amir-at-bunny wants to merge 2 commits into
mainfrom
feat/stream
Draft

feat(stream): video libraries, directory linking, uploads, and video management#203
amir-at-bunny wants to merge 2 commits into
mainfrom
feat/stream

Conversation

@amir-at-bunny

Copy link
Copy Markdown
Collaborator

What

A new experimental stream namespace (hidden from --help while it stabilizes, like sites and storage):

  • bunny stream library (aliases libraries, lib): list, create (with create-time --replication-regions), show, credentials, delete
  • bunny stream link [library] / bunny stream unlink: bind a directory to a library via .bunny/stream.json, mirroring bunny storage link
  • bunny stream upload <file-or-url>: local files go up as a binary PUT streamed off disk; a URL is fetched server side by bunny.net (--header for authenticated origins). Library comes from --lib <id>, the linked directory, or an interactive picker
  • bunny stream videos: list (with --search), show, update --title, delete, all by video GUID. There is deliberately no videos create; upload is the create path

A separate first commit improves the shared client: verbose logging no longer reads non-JSON request bodies (an octet-stream upload would have been buffered into memory just to be logged), and error extraction learns the Stream API's StatusModel shape so 400/422/429 responses surface the API's message.

Design notes

  • Library CRUD runs on the core API (api.bunny.net/videolibrary) with the account key. Uploads and video commands authenticate with the library's own Stream API key against video.bunnycdn.com, resolved automatically, so nothing extra needs configuring.
  • No output format prints API keys. JSON output strips ApiKey, ReadOnlyApiKey, and the deprecated ApiAccessKey (which carries the same value as ApiKey). credentials --show-secret is the single deliberate reveal path.
  • Non-interactive safety follows the storage conventions: prompts never fire under --output json or without a TTY, --force both skips confirmations and disables destructive pickers, and upload cleanup only deletes a video shell whose status proves the bytes never landed.
  • GET /videolibrary returns a plain array at the default page=0 and the pagination envelope only for page >= 1; name resolution pins page: 1 (with a regression test whose fake client mimics the real shape). The videos endpoint paginates by totalItems with an empty-page guard.

Testing

  • 726 tests pass across packages/cli and packages/openapi-client (about 90 new), including a stubbed-fetch test pinning the exact binary upload request (URL, AccessKey, content type, byte-for-byte body).
  • bun run typecheck clean apart from the 4 pre-existing @bunny.net/database-adapter errors on main; biome and prettier clean.
  • Reviewed twice (independent model review with findings verified and applied: secret-field leak, ambiguous-failure cleanup, --force picker safety, stale manifest cleanup) plus a dedicated secret/internal-info sweep of the diff.

…face Stream error messages

Verbose debug logging read every request body as JSON, which would buffer
an entire video into memory on octet-stream uploads; non-JSON bodies are
now described from their headers instead. Error extraction also learns the
Stream API's StatusModel shape (lowercase message), so 400/422/429 responses
carry the API's explanation instead of a generic HTTP error.
…management

New experimental stream namespace:
- stream library: list, create, show, credentials, delete (aliases: libraries, lib)
- stream link / unlink: bind a directory to a library via .bunny/stream.json
- stream upload: local file via binary PUT, or a URL fetched server side
  (--header for authenticated origins); library from --lib <id>, the linked
  directory, or an interactive picker
- stream videos: list, show, update, delete by GUID

Library CRUD runs on the core API with the account key; uploads and video
commands use the library's own Stream API key, resolved automatically.
No output format prints API keys (credentials --show-secret is the
deliberate reveal path); JSON output strips ApiKey, ReadOnlyApiKey, and
the deprecated ApiAccessKey.
@changeset-bot

changeset-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1d2704d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant