This repository has no description
1import { describe, expect, it, vi } from "vitest";
2import * as knotmirror from "./knotmirror";
3
4const jsonResponse = (body: unknown): Response =>
5 new Response(JSON.stringify(body), {
6 status: 200,
7 headers: { "content-type": "application/json" }
8 });
9
10describe("knotmirror.tree", () => {
11 it("fetches the readme blob", async () => {
12 const fetchMock = vi.fn<typeof globalThis.fetch>().mockImplementation(async (input) => {
13 const url = new URL(String(input));
14 if (url.pathname.endsWith("getTree")) {
15 return jsonResponse({
16 ref: "main",
17 files: [
18 {
19 name: "README.md",
20 mode: "100644",
21 size: 12,
22 last_commit: {
23 hash: "abc",
24 message: "docs",
25 when: "2026-07-01T00:00:00Z"
26 }
27 }
28 ]
29 });
30 }
31 return new Response("# hello", {
32 status: 200,
33 headers: { "content-type": "text/plain" }
34 });
35 });
36
37 const ctx = knotmirror.createKnotMirrorClient("https://mirror.test", fetchMock);
38 const tree = await knotmirror.tree(ctx, {
39 repo: "did:plc:repo",
40 ref: "main",
41 path: "docs"
42 });
43
44 expect(tree.readme).toEqual({ filename: "README.md", contents: "# hello" });
45 expect(tree.files[0]).toMatchObject({ name: "README.md", mode: "100644" });
46 expect(fetchMock).toHaveBeenCalledTimes(2);
47 const blobUrl = new URL(String(fetchMock.mock.calls[1][0]));
48 expect(blobUrl.pathname).toBe("/xrpc/sh.tangled.git.temp.getBlob");
49 expect(blobUrl.searchParams.get("path")).toBe("docs/README.md");
50 });
51});
52
53describe("knotmirror.languages", () => {
54 it("uses the languages endpoint", async () => {
55 const fetchMock = vi
56 .fn<typeof globalThis.fetch>()
57 .mockResolvedValue(
58 jsonResponse({ ref: "main", languages: [{ name: "TypeScript", size: 10 }] })
59 );
60 const ctx = knotmirror.createKnotMirrorClient("https://mirror.test", fetchMock);
61
62 await knotmirror.languages(ctx, { repo: "did:plc:repo", ref: "main" });
63
64 const url = new URL(String(fetchMock.mock.calls[0][0]));
65 expect(url.pathname).toBe("/xrpc/sh.tangled.git.temp.listLanguages");
66 });
67});
68
69describe("knotmirror.blob", () => {
70 const entryBody = {
71 name: "hello.txt",
72 mode: "0100644",
73 size: 5,
74 lastCommit: {
75 hash: "abc",
76 message: "hi",
77 author: { name: "dawn", email: "dawn@tangled.org", when: "2026-07-01T00:00:00Z" }
78 }
79 };
80
81 const blobFetch = (content: Uint8Array, entry: unknown = entryBody) =>
82 vi.fn<typeof globalThis.fetch>().mockImplementation(async (input) => {
83 const url = new URL(String(input));
84 return url.pathname.endsWith("getEntry")
85 ? jsonResponse(entry)
86 : new Response(content.slice().buffer, { status: 200 });
87 });
88
89 it("creates the repo blob shape from getEntry plus raw content", async () => {
90 const fetchMock = blobFetch(new TextEncoder().encode("hello"));
91 const ctx = knotmirror.createKnotMirrorClient("https://mirror.test", fetchMock);
92
93 const output = await knotmirror.blob(
94 ctx,
95 { repo: "did:plc:repo", ref: "main", path: "hello.txt" },
96 1024
97 );
98
99 expect(output).toMatchObject({
100 path: "hello.txt",
101 size: 5,
102 isBinary: false,
103 encoding: "utf-8",
104 content: "hello",
105 lastCommit: { hash: "abc", when: "2026-07-01T00:00:00Z" }
106 });
107 });
108
109 it("skips the content fetch when the entry is over the inline cap", async () => {
110 const fetchMock = blobFetch(new TextEncoder().encode("hello"), { ...entryBody, size: 2048 });
111 const ctx = knotmirror.createKnotMirrorClient("https://mirror.test", fetchMock);
112
113 const output = await knotmirror.blob(
114 ctx,
115 { repo: "did:plc:repo", ref: "main", path: "hello.txt" },
116 1024
117 );
118
119 expect(output.fileTooLarge).toBe(true);
120 expect(output.content).toBeUndefined();
121 expect(fetchMock).toHaveBeenCalledTimes(1);
122 });
123
124 it("marks content with null bytes as binary", async () => {
125 const fetchMock = blobFetch(new Uint8Array([0x50, 0x4b, 0x00, 0x00]));
126 const ctx = knotmirror.createKnotMirrorClient("https://mirror.test", fetchMock);
127
128 const output = await knotmirror.blob(
129 ctx,
130 { repo: "did:plc:repo", ref: "main", path: "hello.txt" },
131 1024
132 );
133
134 expect(output.isBinary).toBe(true);
135 expect(output.content).toBeUndefined();
136 });
137
138 it("treats a gitlink mode as a submodule", async () => {
139 const fetchMock = blobFetch(new Uint8Array(), { ...entryBody, mode: "0160000" });
140 const ctx = knotmirror.createKnotMirrorClient("https://mirror.test", fetchMock);
141
142 const output = await knotmirror.blob(
143 ctx,
144 { repo: "did:plc:repo", ref: "main", path: "hello.txt" },
145 1024
146 );
147
148 expect(output.submodule).toEqual({ name: "hello.txt", url: "" });
149 });
150});