import type { ClientMediaItem } from "@rakazo/contracts"; import { describe, expect, it } from "vitest"; import type { MediaAsset as MediaAssetRow, MediaMark as MediaMarkRow, MediaRender as MediaRenderRow, MediaUpload as MediaUploadRow, } from "./client.js"; import { clientMediaItemToSourceItem, decodeKeysetCursor, encodeKeysetCursor, InvalidMediaInputError, likeContains, mapMediaAsset, mapMediaMark, mapMediaRender, mapMediaSegment, mapMediaUpload, pageLimit, toPage, } from "./media.js"; const at = new Date("2026-01-01T08:00:00.000Z"); describe("media keyset cursors", () => { it("round-trips dated and undated positions as opaque base64url", () => { for (const cursor of [ { at, id: "asset-1" }, { at: null, id: "asset-2" }, ]) { const token = encodeKeysetCursor(cursor); expect(token).toMatch(/^[A-Za-z0-9_-]+$/); expect(decodeKeysetCursor(token)).toEqual(cursor); } }); it("rejects tampered or malformed cursors", () => { const bad = [ "not json", Buffer.from("{}").toString("base64url"), Buffer.from(JSON.stringify(["2026-01-01T00:00:00Z"])).toString("base64url"), Buffer.from(JSON.stringify(["yesterday", "id"])).toString("base64url"), Buffer.from(JSON.stringify([null, ""])).toString("base64url"), Buffer.from(JSON.stringify([42, "id"])).toString("base64url"), ]; for (const token of bad) { expect(() => decodeKeysetCursor(token), token).toThrow(InvalidMediaInputError); } }); it("slices a limit+1 result into a page with the last row as cursor", () => { const rows = [ { id: "c", at }, { id: "b", at: null }, { id: "a", at: null }, ]; const page = toPage( rows, 2, (row) => ({ at: row.at, id: row.id }), (row) => row.id, ); expect(page.items).toEqual(["c", "b"]); expect(decodeKeysetCursor(page.nextCursor as string)).toEqual({ at: null, id: "b" }); expect( toPage( rows, 3, (row) => ({ at: row.at, id: row.id }), (row) => row.id, ).nextCursor, ).toBe(null); }); it("clamps page sizes and escapes LIKE wildcards", () => { expect(pageLimit(undefined)).toBe(100); expect(pageLimit(0)).toBe(1); expect(pageLimit(10_000)).toBe(500); expect(likeContains("50%_off\\")).toBe("%50\\%\\_off\\\\%"); }); }); describe("media DTO mappers", () => { const asset: MediaAssetRow = { id: "asset-1", spaceId: "space-1", sourceId: "source-1", externalId: "a.mp4", revision: "r1", contentHash: "hash", kind: "video", storage: "referenced", storagePath: "originals/a.mp4", fileName: "a.mp4", sizeBytes: 10n, capturedAt: at, durationMs: 1000, width: 1920, height: 1080, fps: 30, codec: "h264", orientation: 0, gpsLat: 48.21, gpsLon: 16.37, deviceModel: "Camera", albumNames: ["Trip"], isFavorite: true, proxyPath: "proxy.mp4", thumbPath: null, spritePath: null, qualityScore: 0.5, analysisVersion: 1, ingestState: "proxied", ingestError: null, createdAt: at, updatedAt: at, }; it("maps assets without leaking paths or hashes", () => { const dto = mapMediaAsset(asset); expect(dto).toEqual({ id: "asset-1", sourceId: "source-1", externalId: asset.externalId, kind: "video", storage: "referenced", capturedAt: at.toISOString(), durationMs: 1000, width: 1920, height: 1080, fps: 30, gpsLat: 48.21, gpsLon: 16.37, deviceModel: "Camera", albumNames: ["Trip"], isFavorite: true, ingestState: "proxied", hasProxy: true, hasThumbnail: false, qualityScore: 0.5, createdAt: at.toISOString(), }); expect(JSON.stringify(dto)).not.toContain("proxy.mp4"); expect(JSON.stringify(dto)).not.toContain("originals"); }); it("keeps only numeric segment scores", () => { const segment = mapMediaSegment({ id: "seg-1", spaceId: "space-1", assetId: "asset-1", kind: "shot", startMs: 0, endMs: 100, scores: { motion: 0.4, faces: "many", sharpness: null }, teaserScore: null, transcriptExcerpt: null, labels: [], paidOnly: true, analysisVersion: 1, createdAt: at, }); expect(segment.scores).toEqual({ motion: 0.4 }); expect(segment.paidOnly).toBe(true); }); it("drops internal render output paths and invalid reports", () => { const row: MediaRenderRow = { id: "render-1", spaceId: "space-1", projectId: "project-1", planId: "plan-1", profileId: "example-short-vertical", quality: "draft", status: "done", progress: 1.5, outputs: [ { kind: "video", artifactId: null, fileName: "a.mp4", sizeBytes: 1, path: "/abs/a.mp4" }, { kind: "nonsense" }, ], gateReport: { passed: "maybe" }, ffprobe: null, autoFixRound: 0, error: null, createdBy: "user-1", createdAt: at, updatedAt: at, }; const dto = mapMediaRender(row); expect(dto.progress).toBe(1); expect(dto.outputs).toEqual([ { kind: "video", artifactId: null, fileName: "a.mp4", sizeBytes: 1 }, ]); expect(dto.gateReport).toBeNull(); }); it("sorts upload chunks and converts sizes", () => { const row: MediaUploadRow = { id: "upload-1", spaceId: "space-1", assetId: "asset-1", userId: "user-1", sizeBytes: 21n * 1024n * 1024n * 1024n, chunkBytes: 8, sha256: "a".repeat(64), fileName: "a.mov", receivedChunks: [3, 0, 2], status: "open", createdAt: at, updatedAt: at, }; expect(mapMediaUpload(row)).toEqual({ id: "upload-1", assetId: "asset-1", sizeBytes: 21 * 1024 * 1024 * 1024, chunkBytes: 8, receivedChunks: [0, 2, 3], status: "open", }); }); it("maps mark prompts and drops malformed ones", () => { const row: MediaMarkRow = { id: "mark-1", spaceId: "space-1", kind: "tattoo", label: null, personId: null, assetId: "asset-1", prompt: { tMs: 10, point: { x: 0.5, y: 0.5 } }, treatment: "blur", maskDir: "masks/mark-1", qualityScore: null, suggestedFallback: null, createdAt: at, updatedAt: at, }; expect(mapMediaMark(row).prompt).toEqual({ tMs: 10, point: { x: 0.5, y: 0.5 } }); expect(mapMediaMark({ ...row, prompt: { tMs: -1 } }).prompt).toBeNull(); expect(mapMediaMark(row)).not.toHaveProperty("maskDir"); }); }); describe("client media items", () => { const item: ClientMediaItem = { externalId: "local-1", kind: "video", capturedAt: at.toISOString(), durationMs: 1000, width: 1080, height: 1920, fps: 30, gpsLat: 48.2085, gpsLon: 16.3721, deviceModel: "Phone", albumNames: ["Trip"], isFavorite: false, fileName: "IMG_0001.MOV", }; it("derives a revision that changes with any metadata change", () => { const base = clientMediaItemToSourceItem(item); expect(base).toMatchObject({ externalId: "local-1", capturedAt: at, sizeBytes: null }); expect(clientMediaItemToSourceItem({ ...item }).revision).toBe(base.revision); expect(clientMediaItemToSourceItem({ ...item, isFavorite: true }).revision).not.toBe( base.revision, ); expect(clientMediaItemToSourceItem({ ...item, albumNames: [] }).revision).not.toBe( base.revision, ); }); });