Files
edgeever/packages/plugin-api/src/index.test.mjs
T

198 lines
7.1 KiB
JavaScript

import { describe, expect, test } from "bun:test";
import { parseExtensionManifest, parseMarketplaceRegistry } from "./index.ts";
describe("extension manifests", () => {
test("normalizes a plugin manifest", () => {
expect(parseExtensionManifest({
type: "plugin",
id: "org.edgeever.example",
name: "Example",
version: "1.0.0",
apiVersion: "2",
settingsUi: "host",
entry: "./main.js",
permissions: ["notes:read", "notes:read", "templates:read", "templates:write", "schedules", "ui:commands", "ui:navigation", "ui:embeds"],
})).toMatchObject({ permissions: ["notes:read", "templates:read", "templates:write", "schedules", "ui:commands", "ui:navigation", "ui:embeds"] });
});
test("rejects unsupported capability metadata", () => {
expect(() => parseExtensionManifest({
type: "plugin",
id: "org.edgeever.bad",
name: "Bad",
version: "1.0.0",
apiVersion: "2",
settingsUi: "host",
entry: "./main.js",
permissions: ["database:raw"],
})).toThrow("Unsupported plugin permission");
});
test("requires API v2 plugins to use host-rendered settings", () => {
const base = {
type: "plugin",
id: "org.edgeever.policy",
name: "Policy",
version: "1.0.0",
entry: "./main.js",
permissions: [],
};
expect(() => parseExtensionManifest({ ...base, apiVersion: "1", settingsUi: "host" })).toThrow("Unsupported plugin API version");
expect(() => parseExtensionManifest({ ...base, apiVersion: "2" })).toThrow('settingsUi to be "host"');
expect(() => parseExtensionManifest({ ...base, apiVersion: "2", settingsUi: "custom" })).toThrow('settingsUi to be "host"');
});
test("rejects unknown theme tokens", () => {
expect(() => parseExtensionManifest({
type: "theme",
id: "org.edgeever.theme",
name: "Theme",
version: "1.0.0",
themeApiVersion: "1",
modes: ["light"],
light: { "unsafe.selector": "body" },
})).toThrow("Unsupported theme token");
});
test("rejects CSS injection through theme values", () => {
expect(() => parseExtensionManifest({
type: "theme",
id: "org.edgeever.remote-theme",
name: "Remote Theme",
version: "1.0.0",
themeApiVersion: "1",
modes: ["light"],
light: { "color.background": "url(https://example.com/track)" },
})).toThrow("must use #RRGGBB");
});
test("allows direct network plugins without a static host list", () => {
expect(parseExtensionManifest({
type: "plugin",
id: "org.edgeever.network",
name: "Network",
version: "1.0.0",
apiVersion: "2",
settingsUi: "host",
entry: "./main.js",
permissions: ["network"],
})).toMatchObject({ permissions: ["network"] });
});
test("normalizes an Obsidian-style trusted plugin without capability declarations", () => {
expect(parseExtensionManifest({
type: "plugin",
id: "org.edgeever.trusted",
name: "Trusted",
version: "1.0.0",
apiVersion: "2",
settingsUi: "host",
entry: "./main.js",
})).toMatchObject({ permissions: [] });
});
test("allows public read-only network plugins without a static host list", () => {
expect(parseExtensionManifest({
type: "plugin",
id: "org.edgeever.public-network",
name: "Public network",
version: "1.0.0",
apiVersion: "2",
settingsUi: "host",
entry: "./main.js",
permissions: ["network", "network:public"],
})).toMatchObject({ permissions: ["network", "network:public"] });
});
test("normalizes a host-rendered plugin settings schema", () => {
const manifest = parseExtensionManifest({
type: "plugin",
id: "org.edgeever.settings",
name: "Settings",
version: "1.0.0",
apiVersion: "2",
settingsUi: "host",
entry: "./main.js",
permissions: [],
settings: {
fields: [
{
key: "endpoint",
type: "text",
label: "Endpoint",
default: "https://example.com",
className: "plugin-owned-layout",
style: { color: "red" },
html: "<script>alert(1)</script>",
},
{ key: "token", type: "secret", label: "Token", required: true },
{ key: "limit", type: "number", label: "Limit", default: 10, min: 1, max: 100 },
{ key: "enabled", type: "boolean", label: "Enabled", default: true },
{ key: "format", type: "select", label: "Format", options: [{ value: "md", label: "Markdown" }] },
],
},
});
expect(manifest.type).toBe("plugin");
expect(manifest.settings?.fields).toHaveLength(5);
expect(manifest.settings?.fields[0]).toMatchObject({ key: "endpoint", default: "https://example.com" });
expect(manifest.settings?.fields[0]).not.toHaveProperty("className");
expect(manifest.settings?.fields[0]).not.toHaveProperty("style");
expect(manifest.settings?.fields[0]).not.toHaveProperty("html");
});
test("rejects unsafe or ambiguous plugin settings", () => {
const base = {
type: "plugin",
id: "org.edgeever.settings-invalid",
name: "Settings",
version: "1.0.0",
apiVersion: "2",
settingsUi: "host",
entry: "./main.js",
permissions: [],
};
expect(() => parseExtensionManifest({
...base,
settings: { fields: [{ key: "token", type: "secret", label: "Token", default: "plaintext" }] },
})).toThrow("cannot declare a default");
expect(() => parseExtensionManifest({
...base,
settings: { fields: [{ key: "mode", type: "select", label: "Mode", options: [{ value: "a", label: "A" }, { value: "a", label: "Again" }] }] },
})).toThrow("duplicate select value");
});
});
describe("marketplace registry", () => {
test("accepts a verified GitHub entry", () => {
expect(parseMarketplaceRegistry({
registryVersion: "1",
updatedAt: "2026-08-16T00:00:00.000Z",
entries: [{
id: "org.edgeever.example",
name: "Example",
description: "Example plugin",
author: "EdgeEver",
category: "Productivity",
repositoryUrl: "https://github.com/edgeever/example",
distribution: { type: "github", repositoryUrl: "https://github.com/edgeever/example" },
verification: { version: "1.0.0", checksums: { manifestJson: "a".repeat(64), mainJs: "b".repeat(64) } },
}],
}).entries[0]).toMatchObject({ id: "org.edgeever.example", verification: { version: "1.0.0" } });
});
test("rejects duplicate plugin ids", () => {
const entry = {
id: "org.edgeever.example",
name: "Example",
description: "Example plugin",
author: "EdgeEver",
category: "Productivity",
repositoryUrl: "https://github.com/edgeever/example",
distribution: { type: "github", repositoryUrl: "https://github.com/edgeever/example" },
verification: { version: "1.0.0", checksums: { manifestJson: "a".repeat(64) } },
};
expect(() => parseMarketplaceRegistry({ registryVersion: "1", updatedAt: "2026-08-16T00:00:00Z", entries: [entry, entry] })).toThrow("Duplicate");
});
});