- Add ffmpeg-based media asset generation (poster, thumbnail, clip) for previews and videos
- Add GET /media/thumbnails/:filename serving route
- Add filter=mine to feed endpoint for user's own published streams
- Feed response now includes posterUrl, thumbnailUrl, clipUrl
- Deleting an ENDED plan with preview preserves it as a Video record
- Add sourcePlanId to Video schema
- Add POST /providers/accounts/custom-rtmp endpoint for saved RTMP servers
- Encrypt rtmpUrl/streamKey in accessTokenEnc/refreshTokenEnc fields
- Decrypt and return rtmpUrl/streamKey in GET /providers/accounts for CUSTOM_RTMP
- Skip token revocation on DELETE for CUSTOM_RTMP accounts
- Decrypt CUSTOM_RTMP credentials into CUSTOM destinations on plan create/update
- Handle CUSTOM destinations in prepare lifecycle (already READY, skip provider auth)
- Add debug logging for plan operations and user upsert
- Add executionMode and gameId columns to StreamPlan schema
- Add migration for new columns
- Support executionMode/gameId in plan create and update endpoints
- Add version field to health check response from package.json
- Change LinkedAccount unique constraint to (userId, serviceId, accountId)
- Add linkedAccountId to StreamDestination for per-account targeting
- OAuth callbacks upsert by accountId so different accounts create new rows
- Delete endpoint changed to /providers/accounts/:id
- getDecryptedToken resolves tokens by linkedAccountId instead of serviceId
- /start transition wrapped in try-catch (enableAutoStart compatibility)
- /end always attempts YouTube complete transition regardless of plan status
- autoDetectEndedPlans loads tokens per-destination
When the Data Use Checkup hasn't granted numeric ID access, the SDK
returns oculusId (string username) instead. This makes nonce optional,
skips nonce verification for non-numeric userIds, and uses oculusId as
the metaId when numeric ID is unavailable.