54 lines
3.2 KiB
TypeScript
54 lines
3.2 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import { createPluginSdkFilesApi } from "../src/plugin-sdk-api-builder-platform-files.js";
|
|
import type { PluginHostCapabilities } from "../src/plugin-sdk-types.js";
|
|
import type { PluginRuntimeState } from "../src/plugin-sdk-state.js";
|
|
|
|
const desktopRoot = process.env.FAMILIAROS_DESKTOP_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const pluginSdkApiBuilderPlatformSource = readFileSync(resolve(desktopRoot, "src/plugin-sdk-api-builder-platform.ts"), "utf8");
|
|
const pluginSdkApiBuilderPlatformFilesSource = readFileSync(resolve(desktopRoot, "src/plugin-sdk-api-builder-platform-files.ts"), "utf8");
|
|
|
|
assert.match(pluginSdkApiBuilderPlatformSource, /from "\.\/plugin-sdk-api-builder-platform-files(?:\.js)?"/, "Plugin SDK platform seam must import the extracted files builder.");
|
|
assert.match(pluginSdkApiBuilderPlatformFilesSource, /export function createPluginSdkFilesApi/, "Plugin SDK platform files seam must export the files namespace builder.");
|
|
|
|
const requiredPermissions: string[] = [];
|
|
const readCalls: Array<{ fileId: string; encoding: "text" | "bytes" }> = [];
|
|
const saveCalls: Array<{ suggestedName: string; data: string | Uint8Array }> = [];
|
|
const api = createPluginSdkFilesApi({
|
|
approvedPermissions: new Set(["files"]),
|
|
capabilities: {
|
|
files: {
|
|
pick: async () => [{ fileId: "picked-1", name: "notes.txt", size: 5, type: "text/plain" }],
|
|
read: async (fileId: string, encoding: "text" | "bytes") => {
|
|
readCalls.push({ fileId, encoding });
|
|
return `${fileId}:${encoding}`;
|
|
},
|
|
save: async (spec: { suggestedName: string; data: string | Uint8Array }) => {
|
|
saveCalls.push(spec);
|
|
},
|
|
},
|
|
} as unknown as PluginHostCapabilities,
|
|
state: {
|
|
pickedFiles: new Set<string>(),
|
|
} as unknown as PluginRuntimeState,
|
|
requirePermission: (permission) => {
|
|
requiredPermissions.push(permission);
|
|
},
|
|
});
|
|
|
|
const picked = await api.pick({ accept: [".txt", ".md"], multiple: true });
|
|
assert.equal(requiredPermissions[0], "files", "File picking must require the files permission.");
|
|
assert.deepEqual(picked, [{ fileId: "picked-1", name: "notes.txt", size: 5, type: "text/plain" }], "File picking must return the host-selected file descriptors.");
|
|
|
|
assert.equal(await api.read("picked-1", "text"), "picked-1:text", "File reads must delegate to host file reads for approved picked handles.");
|
|
assert.deepEqual(readCalls, [{ fileId: "picked-1", encoding: "text" }], "File reads must pass the normalized handle and encoding to host capabilities.");
|
|
await assert.rejects(() => api.read("missing", "text"), /Plugin file handle is invalid/, "Unknown plugin file handles must be rejected.");
|
|
|
|
await api.save({ suggestedName: "notes.txt", data: "hello" });
|
|
assert.deepEqual(saveCalls, [{ suggestedName: "notes.txt", data: "hello" }], "File saves must pass sanitized save payloads to host capabilities.");
|
|
await assert.rejects(() => api.save({ suggestedName: "notes.txt", data: 5 }), /File save data must be a string or bytes/, "Invalid save payloads must be rejected.");
|
|
|
|
console.error("Plugin SDK API builder platform files seam validation passed.");
|