1import { ThreadId } from "@t3tools/contracts";
2import { describe, expect, it } from "vite-plus/test";
3
4import { resolveMediaSource } from "./mediaSource.ts";
5
6const threadId = ThreadId.make("thread-1");
7const attachmentId =
8 "11111111-1111-4111-8111-111111111111-22222222-2222-4222-8222-222222222222-mp4";
9
10describe("resolveMediaSource", () => {
11 describe("direct URLs", () => {
12 it("keeps the authored URL and decodes the display name once", () => {
13 const href = "https://cdn.example.com/clip%20one%2520%2Emp4?signature=a%2fb#t=2";
14 expect(resolveMediaSource(href, { threadId })).toEqual({
15 kind: "video",
16 mimeType: "video/mp4",
17 name: "clip one%20.mp4",
18 reference: { kind: "url", url: href },
19 srcFragment: "#t=2",
20 access: "direct",
21 uri: href,
22 });
23 });
24
25 it("keeps protocol-relative URLs as authored; clients add the scheme", () => {
26 const href = "//cdn.example.com/clip.mp4?sig=1#t=2";
27 expect(resolveMediaSource(href, { threadId })).toMatchObject({
28 access: "direct",
29 uri: href,
30 reference: { kind: "url", url: href },
31 });
32 });
33
34 it("accepts extensionless image embeds only when asked", () => {
35 const href = "https://cdn.example.com/render?id=42";
36 expect(resolveMediaSource(href, { threadId })).toBeNull();
37 expect(resolveMediaSource(href, { threadId, imageEmbed: true })).toMatchObject({
38 kind: "image",
39 mimeType: "image/*",
40 name: "render",
41 });
42 });
43
44 it.each(["data:image/png;base64,AAAA", "blob:https://app.t3.codes/id"])(
45 "loads %s directly",
46 (href) => {
47 expect(resolveMediaSource(href, { threadId, imageEmbed: true })).toMatchObject({
48 access: "direct",
49 uri: href,
50 });
51 },
52 );
53 });
54
55 describe("host paths", () => {
56 // POSIX, Windows, UNC, and file URLs must all reach the same media-file resource.
57 it.each([
58 ["/tmp/frame%23one.png:12", "/tmp/frame#one.png"],
59 ["/tmp/frame%3Fone.png:12:3", "/tmp/frame?one.png"],
60 ["/tmp/frame%2523one.png:12", "/tmp/frame%23one.png"],
61 ["C:\\Users\\demo\\frame.png", "C:\\Users\\demo\\frame.png"],
62 ["/C:/Users/demo/frame.png", "C:/Users/demo/frame.png"],
63 ["file:///C:/Users/demo/frame.png", "C:/Users/demo/frame.png"],
64 ["file://server/share/frame.png", "\\\\server\\share\\frame.png"],
65 ["\\\\server\\share\\frame.png", "\\\\server\\share\\frame.png"],
66 ])("resolves %s through the environment", (href, path) => {
67 expect(resolveMediaSource(href, { threadId, workspaceRoot: "/repo" })).toEqual({
68 kind: "image",
69 mimeType: "image/png",
70 name: path.split(/[\\/]/).at(-1),
71 reference: { kind: "file", path },
72 srcFragment: "",
73 access: "environment",
74 resource: { _tag: "media-file", threadId, path },
75 });
76 });
77
78 it("joins relative paths to the workspace and records the relative reference", () => {
79 expect(
80 resolveMediaSource("screens/logo.svg?v=2#mark", { threadId, workspaceRoot: "/repo" }),
81 ).toEqual({
82 kind: "image",
83 mimeType: "image/svg+xml",
84 name: "logo.svg",
85 reference: {
86 kind: "file",
87 path: "/repo/screens/logo.svg",
88 relativePath: "screens/logo.svg",
89 },
90 srcFragment: "#mark",
91 access: "environment",
92 resource: { _tag: "media-file", threadId, path: "/repo/screens/logo.svg" },
93 });
94 });
95
96 it("prefers a caller-resolved path over classifying the source", () => {
97 expect(
98 resolveMediaSource("logo.svg", {
99 threadId,
100 workspaceRoot: "/repo",
101 resolvedFilePath: "/repo/docs/logo.svg",
102 }),
103 ).toMatchObject({
104 access: "environment",
105 resource: { _tag: "media-file", path: "/repo/docs/logo.svg" },
106 reference: { relativePath: "docs/logo.svg" },
107 });
108 });
109
110 it("separates a playback fragment from literal filename characters", () => {
111 expect(resolveMediaSource("/tmp/clip%23one.mp4#t=2", { threadId })).toMatchObject({
112 kind: "video",
113 srcFragment: "#t=2",
114 resource: { path: "/tmp/clip#one.mp4" },
115 });
116 });
117
118 it("cannot be loaded without a thread to mint through", () => {
119 expect(resolveMediaSource("/tmp/clip.mp4", { threadId: undefined })).toMatchObject({
120 kind: "video",
121 access: "unavailable",
122 });
123 });
124
125 it.each(["notes.txt", "/repo/README", "/repo/archive.zip"])(
126 "returns null for the non-media path %s",
127 (href) => {
128 expect(resolveMediaSource(href, { threadId, workspaceRoot: "/repo" })).toBeNull();
129 },
130 );
131 });
132
133 it("serves T3 attachment files in place like any other host path", () => {
134 const path = `/home/demo/.t3/userdata/attachments/${attachmentId}.mp4`;
135 expect(resolveMediaSource(path, { threadId, workspaceRoot: "/repo" })).toMatchObject({
136 kind: "video",
137 access: "environment",
138 resource: { _tag: "media-file", threadId, path },
139 });
140 });
141});