Remove WASM plugin support
This commit is contained in:
@@ -146,24 +146,19 @@ function renderPlugins(plugins) {
|
||||
titleRow.appendChild(trustBadge);
|
||||
|
||||
const runtimeBadge = document.createElement("span");
|
||||
const isWasm = plugin.runtime === "wasm";
|
||||
const isV2 = Number(plugin.apiVersion || 1) >= 2;
|
||||
runtimeBadge.className = `inline-flex items-center gap-1 text-[10px] uppercase tracking-wider px-2 py-0.5 rounded-full border ${
|
||||
isServerOnly
|
||||
? "text-fuchsia-200 border-fuchsia-700 bg-fuchsia-950/50"
|
||||
: isWasm
|
||||
? "text-cyan-300 border-cyan-700 bg-cyan-950/40"
|
||||
: isV2
|
||||
? "text-emerald-300 border-emerald-700 bg-emerald-950/40"
|
||||
: "text-slate-300 border-slate-700 bg-slate-900/60"
|
||||
}`;
|
||||
runtimeBadge.innerHTML = isServerOnly
|
||||
? '<i class="fa-solid fa-server"></i> Server Extension'
|
||||
: isWasm
|
||||
? '<i class="fa-solid fa-cube"></i> WASM 2.0'
|
||||
: isV2
|
||||
? '<i class="fa-solid fa-code"></i> Plugin 2.0'
|
||||
: '<i class="fa-solid fa-puzzle-piece"></i> Native Legacy';
|
||||
: '<i class="fa-solid fa-puzzle-piece"></i> Native';
|
||||
titleRow.appendChild(runtimeBadge);
|
||||
|
||||
const subtitle = document.createElement("div");
|
||||
|
||||
@@ -343,7 +343,7 @@ export type PluginManifest = {
|
||||
id: string;
|
||||
name: string;
|
||||
apiVersion?: number;
|
||||
runtime?: "native" | "wasm" | "server" | string;
|
||||
runtime?: "native" | "server" | string;
|
||||
nativeLoader?: "memory" | "os" | string;
|
||||
autoLoadByDefault?: boolean;
|
||||
nativeEntrypoints?: PluginNativeEntrypoints;
|
||||
@@ -351,7 +351,6 @@ export type PluginManifest = {
|
||||
description?: string;
|
||||
binary?: string;
|
||||
binaries?: Record<string, string>;
|
||||
wasm?: string;
|
||||
needs?: PluginNeeds;
|
||||
entry?: string;
|
||||
assets?: {
|
||||
|
||||
@@ -45,7 +45,7 @@ describe("loadPluginBundle", () => {
|
||||
expect(bundle.size).toBe("test-binary".length);
|
||||
});
|
||||
|
||||
test("loads wasm manifest independently of client platform", async () => {
|
||||
test("rejects an extracted WASM manifest", async () => {
|
||||
const root = await createTempRoot();
|
||||
const pluginDir = join(root, "wasm-demo");
|
||||
await mkdir(pluginDir, { recursive: true });
|
||||
@@ -62,13 +62,23 @@ describe("loadPluginBundle", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const bundle = await loadPluginBundle(root, "wasm-demo", async () => {}, "Windows 11", "amd64");
|
||||
await expect(loadPluginBundle(root, "wasm-demo", async () => {}, "Windows 11", "amd64"))
|
||||
.rejects.toThrow("WASM plugins are not supported");
|
||||
});
|
||||
|
||||
expect(bundle.manifest.apiVersion).toBe(2);
|
||||
expect(bundle.manifest.runtime).toBe("wasm");
|
||||
expect(bundle.manifest.wasm).toBe("plugin.wasm");
|
||||
expect(bundle.binaryPath).toBe(join(root, "wasm-demo", "plugin.wasm"));
|
||||
expect(bundle.size).toBe(4);
|
||||
test("rejects a bundle containing a WASM module", async () => {
|
||||
const root = await createTempRoot();
|
||||
const AdmZip = require("adm-zip");
|
||||
const zip = new AdmZip();
|
||||
zip.addFile("config.json", Buffer.from(JSON.stringify({ name: "WASM Demo", runtime: "wasm" })));
|
||||
zip.addFile("wasm-demo.html", Buffer.from("<div></div>"));
|
||||
zip.addFile("wasm-demo.css", Buffer.from("body {}"));
|
||||
zip.addFile("wasm-demo.js", Buffer.from("console.log('demo')"));
|
||||
zip.addFile("wasm-demo.wasm", Buffer.from([0x00, 0x61, 0x73, 0x6d]));
|
||||
zip.writeZip(join(root, "wasm-demo.zip"));
|
||||
|
||||
await expect(ensurePluginExtracted(root, "wasm-demo", (name) => name))
|
||||
.rejects.toThrow("WASM plugins are not supported");
|
||||
});
|
||||
|
||||
test("keeps helper DLLs out of the native platform binary map", async () => {
|
||||
|
||||
@@ -66,11 +66,15 @@ export async function ensurePluginExtracted(
|
||||
}
|
||||
|
||||
if (!zipStat) {
|
||||
if (manifestStat) return;
|
||||
if (manifestStat) {
|
||||
await rejectUnsupportedWasmManifest(manifestPath, safeId);
|
||||
return;
|
||||
}
|
||||
throw new Error(`Plugin bundle not found: ${safeId}`);
|
||||
}
|
||||
|
||||
if (manifestStat && manifestStat.mtimeMs >= zipStat.mtimeMs) {
|
||||
await rejectUnsupportedWasmManifest(manifestPath, safeId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -101,7 +105,6 @@ export async function ensurePluginExtracted(
|
||||
let jsEntry: Buffer | null = null;
|
||||
let serverEntry: Buffer | null = null;
|
||||
let configEntry: Buffer | null = null;
|
||||
let wasmEntry: { filename: string; data: Buffer } | null = null;
|
||||
const sourceEntries: Map<string, Buffer> = new Map();
|
||||
const nativeBinaries: Map<string, Buffer> = new Map();
|
||||
|
||||
@@ -113,7 +116,7 @@ export async function ensurePluginExtracted(
|
||||
if (lower.endsWith(".so") || lower.endsWith(".dll") || lower.endsWith(".dylib")) {
|
||||
nativeBinaries.set(base, entry.getData());
|
||||
} else if (lower.endsWith(".wasm")) {
|
||||
wasmEntry = { filename: base, data: entry.getData() };
|
||||
throw new Error(`Invalid plugin bundle: ${safeId} (WASM plugins are not supported)`);
|
||||
} else if (lower === "server.js") {
|
||||
serverEntry = entry.getData();
|
||||
} else if (lower.endsWith(".html")) {
|
||||
@@ -139,6 +142,10 @@ export async function ensurePluginExtracted(
|
||||
}
|
||||
}
|
||||
|
||||
if (declaresWasmPlugin(extraConfig)) {
|
||||
throw new Error(`Invalid plugin bundle: ${safeId} (WASM plugins are not supported)`);
|
||||
}
|
||||
|
||||
const uiTsEntry = getConfiguredSourceEntry(extraConfig, ["uiEntry", "ui.entry", "build.ui", "build.uiEntry"], sourceEntries)
|
||||
|| (sourceEntries.has("src/ui.ts") ? "src/ui.ts" : "")
|
||||
|| (sourceEntries.has("src/index.ts") ? "src/index.ts" : "");
|
||||
@@ -163,11 +170,6 @@ export async function ensurePluginExtracted(
|
||||
binariesMap[platformKey] = filename;
|
||||
}
|
||||
}
|
||||
if (wasmEntry) {
|
||||
await fs.writeFile(path.join(pluginDir, wasmEntry.filename), wasmEntry.data);
|
||||
binariesMap["wasm32-wasi"] = wasmEntry.filename;
|
||||
}
|
||||
|
||||
if (sourceEntries.size > 0) {
|
||||
await fs.rm(path.join(pluginDir, "src"), { recursive: true, force: true });
|
||||
for (const [relPath, data] of sourceEntries) {
|
||||
@@ -199,7 +201,7 @@ export async function ensurePluginExtracted(
|
||||
try { await fs.rm(serverScriptPath, { force: true }); } catch {}
|
||||
}
|
||||
|
||||
const runtime = normalizePluginRuntime(extraConfig.runtime, wasmEntry !== null);
|
||||
const runtime = normalizePluginRuntime(extraConfig.runtime);
|
||||
const nativeLoader = normalizeNativeLoader(extraConfig.nativeLoader);
|
||||
const nativeEntrypoints = normalizeNativeEntrypoints(extraConfig.nativeEntrypoints);
|
||||
const needs = normalizePluginNeeds(extraConfig.needs);
|
||||
@@ -207,7 +209,7 @@ export async function ensurePluginExtracted(
|
||||
const manifest: PluginManifest = {
|
||||
id: safeId,
|
||||
name: extraConfig.name || safeId,
|
||||
apiVersion: Number(extraConfig.apiVersion) === 2 || runtime === "wasm" ? 2 : 1,
|
||||
apiVersion: Number(extraConfig.apiVersion) === 2 ? 2 : 1,
|
||||
runtime,
|
||||
...(nativeLoader && { nativeLoader }),
|
||||
...(extraConfig.autoLoadByDefault === true && { autoLoadByDefault: true }),
|
||||
@@ -215,7 +217,6 @@ export async function ensurePluginExtracted(
|
||||
version: extraConfig.version || "1.0.0",
|
||||
description: extraConfig.description,
|
||||
...(typeof extraConfig.binary === "string" && extraConfig.binary && { binary: extraConfig.binary }),
|
||||
...(runtime === "wasm" && { wasm: String(extraConfig.wasm || wasmEntry?.filename || binariesMap["wasm32-wasi"] || "") }),
|
||||
...(needs && { needs }),
|
||||
binaries: binariesMap,
|
||||
entry: `${safeId}.html`,
|
||||
@@ -280,6 +281,10 @@ export async function listPluginManifests(
|
||||
try {
|
||||
const raw = await fs.readFile(manifestPath, "utf-8");
|
||||
const manifest = JSON.parse(raw) as PluginManifest;
|
||||
if (declaresWasmPlugin(manifest)) {
|
||||
warnPlugin(`[plugin] skipped ${ent.name}: WASM plugins are not supported`);
|
||||
continue;
|
||||
}
|
||||
const id = manifest.id || ent.name;
|
||||
const name = manifest.name || ent.name;
|
||||
if (pluginState.enabled[id] === undefined) {
|
||||
@@ -318,14 +323,8 @@ export async function loadPluginBundle(
|
||||
manifest.id = manifest.id || pluginId;
|
||||
manifest.name = manifest.name || pluginId;
|
||||
|
||||
if (manifest.runtime === "wasm" || manifest.wasm || manifest.binaries?.["wasm32-wasi"]) {
|
||||
const wasmName = manifest.wasm || manifest.binaries?.["wasm32-wasi"];
|
||||
if (!wasmName) {
|
||||
throw new Error(`No WASM module configured for ${pluginId}`);
|
||||
}
|
||||
const binaryPath = path.join(dir, wasmName);
|
||||
const stat = await fs.stat(binaryPath);
|
||||
return { manifest: { ...manifest, runtime: "wasm", apiVersion: 2 }, binaryPath, size: stat.size };
|
||||
if (declaresWasmPlugin(manifest)) {
|
||||
throw new Error(`WASM plugins are not supported: ${pluginId}`);
|
||||
}
|
||||
|
||||
manifest.runtime = manifest.runtime || "native";
|
||||
@@ -632,13 +631,30 @@ export function normalizePluginNeeds(raw: any): PluginNeeds | undefined {
|
||||
return files.length > 0 ? { files } : undefined;
|
||||
}
|
||||
|
||||
function normalizePluginRuntime(runtime: any, hasWasm: boolean): "native" | "wasm" | "server" {
|
||||
function normalizePluginRuntime(runtime: any): "native" | "server" {
|
||||
const value = typeof runtime === "string" ? runtime.trim().toLowerCase() : "";
|
||||
if (value === "wasm" || hasWasm) return "wasm";
|
||||
if (value === "server") return "server";
|
||||
return "native";
|
||||
}
|
||||
|
||||
function declaresWasmPlugin(value: any): boolean {
|
||||
if (!value || typeof value !== "object") return false;
|
||||
if (typeof value.runtime === "string" && value.runtime.trim().toLowerCase() === "wasm") return true;
|
||||
if (typeof value.wasm === "string" && value.wasm.trim()) return true;
|
||||
if (!value.binaries || typeof value.binaries !== "object" || Array.isArray(value.binaries)) return false;
|
||||
return Object.entries(value.binaries).some(([key, filename]) =>
|
||||
key.trim().toLowerCase().includes("wasm")
|
||||
|| (typeof filename === "string" && filename.trim().toLowerCase().endsWith(".wasm"))
|
||||
);
|
||||
}
|
||||
|
||||
async function rejectUnsupportedWasmManifest(manifestPath: string, pluginId: string): Promise<void> {
|
||||
const manifest = JSON.parse(await fs.readFile(manifestPath, "utf-8"));
|
||||
if (declaresWasmPlugin(manifest)) {
|
||||
throw new Error(`WASM plugins are not supported: ${pluginId}`);
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeNativeLoader(loader: any): "memory" | "os" | undefined {
|
||||
const value = typeof loader === "string" ? loader.trim().toLowerCase() : "";
|
||||
if (["memory", "mem", "reflective", "manual"].includes(value)) return "memory";
|
||||
|
||||
Reference in New Issue
Block a user