What you have to work with
After a video is uploaded, the plugin stores its Bunny identity on the document underbunnyData.stream:
bunnyData.stream.videoId— the video GUID, which the Stream API addresses.bunnyData.stream.libraryId— the library the video lives in (computed from your config on read).
collectionId, so the recipe moves it into a collection after upload with the Update Video API (POST /library/{libraryId}/videos/{videoId}).
Accessing the resolved config
The recipe needs the library id and the Stream API key for the collection the upload landed in — ask the plugin for it.getBunnyStreamForCollection(payload, slug) returns that collection’s resolved { apiKey, libraryId, hostname, tokenSecurityKey? }, with global config and per-collection overrides already applied. See Accessing the resolved config for the full accessor list.
Recipe
Add anafterChange hook to your upload collection. Resolve the target collection however you like — here, one collection per tenant — then call Update Video:
collections/Media.ts
Notes
- Let the accessor resolve the library and key. With per-collection stream libraries, different collections upload to different libraries.
getBunnyStreamForCollection(req.payload, collection.slug)returns that collection’s resolved library and API key directly. Collections are per-library, so atenant-xcollection exists independently in every library that tenant’s videos touch. - Run on create, once the video exists.
videoIdis only present after the plugin has created the video, so gate onoperation === 'create'and bail when it is absent (non-video uploads, or the document before its video is made). - Cache collection lookups. Creating a collection isn’t idempotent — without a cache or an existence check you will spawn duplicates and hit the API on every upload. The module-level
Mapabove is the minimum. - Bulk moves. The dashboard can’t move many videos at once, but the same Update Video call looped over
payload.find(...)results will.