Files
wehub-resource-sync b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:53 +08:00

76 lines
2.5 KiB
TypeScript

/**
* Manifest assertions for the AT Protocol plugin.
*
* The redesigned sandboxed-plugin layout puts identity, trust contract,
* and admin surface in `emdash-plugin.jsonc` (the source of truth) and
* leaves `src/plugin.ts` for runtime code only. This test snapshots the
* manifest's structural shape so a refactor can't silently change the
* published trust contract or admin surface.
*/
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { parse as parseJsonc } from "jsonc-parser";
import { describe, expect, it } from "vitest";
import { version } from "../package.json";
const MANIFEST_PATH = fileURLToPath(new URL("../emdash-plugin.jsonc", import.meta.url));
interface Manifest {
slug: string;
version: string;
publisher: string;
capabilities: string[];
allowedHosts: string[];
storage: Record<string, { indexes: string[] }>;
admin: {
pages: Array<{ path: string; label: string; icon?: string }>;
widgets: Array<{ id: string; title?: string; size?: string }>;
};
}
async function loadManifest(): Promise<Manifest> {
const source = await readFile(MANIFEST_PATH, "utf8");
const errors: import("jsonc-parser").ParseError[] = [];
const value: unknown = parseJsonc(source, errors, {
allowTrailingComma: true,
disallowComments: false,
});
if (errors.length > 0) {
throw new Error(`Manifest parse failed: ${JSON.stringify(errors)}`);
}
return value as Manifest;
}
describe("atproto plugin manifest", () => {
it("declares the expected identity", async () => {
const manifest = await loadManifest();
expect(manifest.slug).toBe("atproto");
expect(manifest.version).toBe(version);
});
it("declares the required capabilities", async () => {
const manifest = await loadManifest();
expect(manifest.capabilities).toContain("content:read");
expect(manifest.capabilities).toContain("network:request:unrestricted");
});
it("declares the storage used by the runtime", async () => {
const manifest = await loadManifest();
expect(manifest.storage).toHaveProperty("records");
expect(manifest.storage.records.indexes).toContain("contentId");
expect(manifest.storage.records.indexes).toContain("status");
expect(manifest.storage.records.indexes).toContain("lastSyncedAt");
});
it("declares the admin pages and widgets", async () => {
const manifest = await loadManifest();
expect(manifest.admin.pages).toHaveLength(1);
expect(manifest.admin.pages[0]?.path).toBe("/status");
expect(manifest.admin.widgets).toHaveLength(1);
expect(manifest.admin.widgets[0]?.id).toBe("sync-status");
});
});