Files
plainleaf/client/components/plainleaf_sharing.test.ts
wushenghuaandCodex 9fa3727cb1
Plainleaf 自动发布 / release (push) Failing after 2m4s
feat: 增加无需登录的笔记分享
Co-Authored-By: Codex <noreply@anthropic.com>
2026-08-13 12:58:22 +08:00

104 lines
2.9 KiB
TypeScript

import type { FileMeta } from "@silverbulletmd/silverbullet/type/index";
import { expect, test } from "vitest";
import { CheckedSpacePrimitives } from "../spaces/checked_space_primitives.ts";
import type { SpacePrimitives } from "../spaces/space_primitives.ts";
import {
createPlainleafShare,
deletePlainleafSharesForPaths,
findPlainleafShare,
listPlainleafShares,
movePlainleafShares,
} from "./plainleaf_sharing.ts";
class MemoryStorage implements SpacePrimitives {
files = new Map<string, { data: Uint8Array; meta: FileMeta }>();
async fetchFileList() {
return [...this.files.values()].map((file) => file.meta);
}
async getFileMeta(path: string) {
const file = this.files.get(path);
if (!file) throw new Error("missing");
return file.meta;
}
async readFile(path: string) {
const file = this.files.get(path);
if (!file) throw new Error("missing");
return { data: file.data.slice(), meta: file.meta };
}
async writeFile(path: string, data: Uint8Array) {
const meta: FileMeta = {
name: path,
created: 1,
lastModified: 2,
contentType: "application/json",
size: data.byteLength,
perm: "rw",
};
this.files.set(path, { data: data.slice(), meta });
return meta;
}
async deleteFile(path: string) {
if (!this.files.delete(path)) throw new Error("missing");
}
}
const token = "0123456789abcdef0123456789abcdef";
test("creates, finds, moves, and revokes a private share manifest", async () => {
const storage = new CheckedSpacePrimitives(new MemoryStorage(), false);
const share = await createPlainleafShare(
storage,
{ path: "旅行/计划.md", title: "旅行计划", format: "markdown" },
new Date("2026-08-13T00:00:00.000Z"),
token,
);
expect(share.token).toBe(token);
await expect(findPlainleafShare(storage, "旅行/计划.md")).resolves.toEqual(
share,
);
await expect(
movePlainleafShares(storage, [
{
from: "旅行/计划.md",
to: "归档/计划.md",
title: "计划归档",
},
]),
).resolves.toBe(1);
expect((await listPlainleafShares(storage))[0]).toMatchObject({
path: "归档/计划.md",
title: "计划归档",
token,
});
await expect(
deletePlainleafSharesForPaths(storage, ["归档/计划.md"]),
).resolves.toBe(1);
await expect(listPlainleafShares(storage)).resolves.toEqual([]);
});
test("rejects unsafe paths and ignores damaged manifests", async () => {
const source = new MemoryStorage();
const storage = new CheckedSpacePrimitives(source, false);
await expect(
createPlainleafShare(
storage,
{ path: "../秘密.md", title: "秘密", format: "markdown" },
new Date(),
token,
),
).rejects.toThrow("安全的分享链接");
await source.writeFile(
".plainleaf/shares/broken.json",
new TextEncoder().encode("not json"),
);
await expect(listPlainleafShares(storage)).resolves.toEqual([]);
});