From dc324b03a36c797da398d391742fb921c2d4e47c Mon Sep 17 00:00:00 2001 From: Matiss Jurevics Date: Thu, 22 Jan 2026 16:30:00 +0000 Subject: [PATCH] docs(media): document phase5 stream media credential endpoints --- Backend/README.md | 13 ++++++--- Backend/docs/openapi.ts | 65 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/Backend/README.md b/Backend/README.md index f070c88..b8c0914 100644 --- a/Backend/README.md +++ b/Backend/README.md @@ -31,12 +31,15 @@ Required env vars: | --- | --- | | `DATABASE_URL` | Postgres connection string | | `BETTER_AUTH_SECRET` | Secret used to sign sessions | -| `BETTER_AUTH_URL` | Public base URL for the backend (e.g., `http://localhost:3000`) | +| `BETTER_AUTH_BASE_URL` | Public base URL for the backend (e.g., `http://localhost:3000`) | | `BETTER_AUTH_TRUSTED_ORIGINS` | Comma-separated list of allowed frontend origins | | `PORT` | HTTP port (default `3000`) | +| `MEDIA_PROVIDER` | Media backend provider (`mock` by default) | | `MINIO_*` | Connection settings for the MinIO/S3 endpoint | | `ADMIN_USERNAME` / `ADMIN_PASSWORD` | Basic auth for `/admin` dashboard | +`BETTER_AUTH_URL` is still accepted as a legacy fallback, but `BETTER_AUTH_BASE_URL` is preferred. + ## Running - Start the server in development: @@ -122,11 +125,13 @@ Motion realtime events: - Linked clients receive `motion:detected` as soon as camera starts event. - Linked clients receive `motion:ended` when camera ends event. -### On-Demand Streams (Phase 4) +### On-Demand Streams + Media Credentials (Phase 4 + 5) | Endpoint | Purpose | | --- | --- | | `POST /streams/request` | Client device requests a linked camera to start a live stream | | `POST /streams/:streamSessionId/accept` | Camera device accepts and transitions stream session to `streaming` | +| `GET /streams/:streamSessionId/publish-credentials` | Camera fetches media ingest credentials for the active stream session | +| `GET /streams/:streamSessionId/subscribe-credentials` | Viewer fetches media subscribe credentials for the active stream session | | `POST /streams/:streamSessionId/end` | Requester/camera ends an existing stream session | | `GET /streams/:streamSessionId/playback-token` | Obtain short-lived playback token for active stream | | `GET /streams/me/list` | List stream sessions for the current device | @@ -148,8 +153,8 @@ OpenAPI docs are generated from Zod/OpenAPI definitions: Use `GET /sim/mobile-sim.html` to run a browser simulator that behaves like the mobile app: - Register as `camera` or `client` - Connect Socket.IO with bearer device token -- Camera: process incoming `start_stream` commands, start/end motion events -- Client: create links, request streams, and fetch playback tokens +- Camera: process incoming `start_stream` commands, fetch publish credentials, start/end motion events +- Client: create links, request streams, fetch subscribe credentials, and fetch playback tokens ### Admin Dashboard Access `/admin` with Basic auth to: diff --git a/Backend/docs/openapi.ts b/Backend/docs/openapi.ts index c74bf8c..1e4a2f6 100644 --- a/Backend/docs/openapi.ts +++ b/Backend/docs/openapi.ts @@ -1,5 +1,6 @@ import { OpenAPIRegistry, OpenApiGeneratorV3, extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi'; import { z } from 'zod'; +import { getBetterAuthBaseUrl } from '../utils/env'; extendZodWithOpenApi(z); @@ -806,6 +807,10 @@ registry.registerPath({ id: z.string().uuid(), status: z.string(), streamKey: z.string().nullable(), + mediaProvider: z.string(), + mediaSessionId: z.string().nullable(), + publishEndpoint: z.string().nullable(), + subscribeEndpoint: z.string().nullable(), startedAt: z.string().datetime().nullable(), }), }), @@ -852,6 +857,60 @@ registry.registerPath({ }, }); +registry.registerPath({ + method: 'get', + path: '/streams/{streamSessionId}/publish-credentials', + summary: 'Get publish credentials for camera ingest to media provider', + tags: ['Streams'], + security: [{ bearerDeviceToken: [] }], + request: { + params: z.object({ streamSessionId: z.string().uuid() }), + }, + responses: { + 200: { + description: 'Publish credentials', + content: { + 'application/json': { + schema: z.object({ + provider: z.string(), + mediaSessionId: z.string(), + publishToken: z.string(), + publishUrl: z.string(), + expiresInSeconds: z.number().int(), + }), + }, + }, + }, + }, +}); + +registry.registerPath({ + method: 'get', + path: '/streams/{streamSessionId}/subscribe-credentials', + summary: 'Get subscribe credentials for viewing stream from media provider', + tags: ['Streams'], + security: [{ bearerDeviceToken: [] }], + request: { + params: z.object({ streamSessionId: z.string().uuid() }), + }, + responses: { + 200: { + description: 'Subscribe credentials', + content: { + 'application/json': { + schema: z.object({ + provider: z.string(), + mediaSessionId: z.string(), + subscribeToken: z.string(), + subscribeUrl: z.string(), + expiresInSeconds: z.number().int(), + }), + }, + }, + }, + }, +}); + registry.registerPath({ method: 'get', path: '/streams/{streamSessionId}/playback-token', @@ -871,6 +930,8 @@ registry.registerPath({ streamKey: z.string(), status: z.string(), playbackToken: z.string(), + subscribeUrl: z.string(), + mediaProvider: z.string(), expiresInSeconds: z.number().int(), }), }, @@ -906,6 +967,8 @@ registry.registerPath({ status: z.string(), reason: z.string(), streamKey: z.string().nullable(), + mediaProvider: z.string(), + mediaSessionId: z.string().nullable(), }), ), }), @@ -924,7 +987,7 @@ export function buildOpenApiDocument() { version: '1.0.0', description: 'Auto-generated API documentation from Zod schemas.', }, - servers: [{ url: process.env.BETTER_AUTH_URL ?? 'http://localhost:3000' }], + servers: [{ url: getBetterAuthBaseUrl() }], tags: [ { name: 'System', description: 'Service endpoints' }, { name: 'Videos', description: 'Authenticated video object operations' },