Schema: - Add VideoPost model (muxUploadId, muxAssetId, muxPlaybackId, status, durationSecs, aspectRatio) linked 1-to-1 with Post - Add VideoStatus enum (PROCESSING/READY/ERROR) - Add PostType.VIDEO Backend: - src/lib/mux.ts — singleton Mux client + webhook secret - videos router: createUpload (Mux direct upload URL + PROCESSING post), getByPostId (status polling), updateCaption - POST /api/webhooks/mux: verifies signature; handles video.upload.asset_created (store muxAssetId), video.asset.ready (set READY + playbackId + fan-out to feed), video.asset.errored (set ERROR) - feed.ts + posts.byPetId: include videoPost in all post queries UI: - VideoUploadForm: drop zone → XHR PUT to Mux upload URL with progress bar; caption field; transitions to "Processing…" on success - VideoCard: PROCESSING shows spinner; READY renders MuxPlayer (HLS, orange accent); polls every 5s until status changes - PostTypeSheet: "Video Post" option added (between Photo and Milestone) - PostCard: VIDEO type renders VideoCard instead of image carousel Env vars: MUX_TOKEN_ID, MUX_TOKEN_SECRET, MUX_WEBHOOK_SECRET, NEXT_PUBLIC_APP_URL — placeholders added to .env.local Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 lines
415 B
TypeScript
12 lines
415 B
TypeScript
import "server-only";
|
|
import Mux from "@mux/mux-node";
|
|
|
|
// Singleton Mux client — MUX_TOKEN_ID and MUX_TOKEN_SECRET must be set in .env.local
|
|
// Get credentials at dashboard.mux.com → Settings → Access Tokens
|
|
export const mux = new Mux({
|
|
tokenId: process.env.MUX_TOKEN_ID ?? "",
|
|
tokenSecret: process.env.MUX_TOKEN_SECRET ?? "",
|
|
});
|
|
|
|
export const MUX_WEBHOOK_SECRET = process.env.MUX_WEBHOOK_SECRET ?? "";
|