Files
OmniRoute/tests/unit/build/opencode-plugin-esm-only.test.ts
Diego Rodrigues de Sa e Souza 81a37b67ed Release v3.8.26 (#3875)
OmniRoute v3.8.26 — see CHANGELOG.md [3.8.26] for the full notes.

Highlights: Vertex AI media generation (#3929), GLM-5.2 effort-tier routing (#3885),
sticky round-robin combos (#3846), OpenRouter connection presets (#3878), compression
prompt-cache fix (#3936/#3890), and a security pass (form-data/vite + workflow hardening, #3949).

Co-authored-by: artickc <artickc@users.noreply.github.com>
Co-authored-by: rdself <rdself@users.noreply.github.com>
Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>
Co-authored-by: Jack Smith <16862258+YunyunZhai@users.noreply.github.com>
Co-authored-by: dhaern <dhaern@users.noreply.github.com>
Co-authored-by: adivekar-utexas <adivekar-utexas@users.noreply.github.com>
Co-authored-by: megamen32 <megamen32@users.noreply.github.com>
Co-authored-by: zhiru <zhiru@users.noreply.github.com>
Co-authored-by: insoln <insoln@users.noreply.github.com>
Co-authored-by: diego-anselmo <diego-anselmo@users.noreply.github.com>
2026-06-16 01:00:40 -03:00

66 lines
2.9 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
// Regression guard for #3883: the @omniroute/opencode-plugin must ship an
// ESM-only bundle. OpenCode's Bun-based plugin loader resolves the package
// `main`/`exports` and applies CJS-to-ESM interop on a dual CJS bundle, which
// turns `mod.default` into the whole exports namespace, fails V1 plugin
// detection, and makes the loader throw "Plugin export is not a function".
// Shipping ESM-only (with a `./runtime` subpath) keeps `mod.default` the V1
// plugin object so the loader registers it. Do NOT re-introduce a CJS bundle.
const PKG_URL = new URL("../../../@omniroute/opencode-plugin/package.json", import.meta.url);
const TSUP_URL = new URL("../../../@omniroute/opencode-plugin/tsup.config.ts", import.meta.url);
function readJson(url: URL): Record<string, unknown> {
return JSON.parse(readFileSync(fileURLToPath(url), "utf8"));
}
test("opencode-plugin package.json ships ESM-only (no CJS bundle)", () => {
const pkg = readJson(PKG_URL);
// main must point at the ESM build, never the .cjs bundle.
assert.equal(pkg.main, "./dist/index.js", "main must be the ESM build");
assert.equal(
typeof pkg.main === "string" && pkg.main.endsWith(".cjs"),
false,
"main must not be a .cjs bundle"
);
// The legacy dual-bundle `module` field should be gone.
assert.equal("module" in pkg, false, "the dual-bundle `module` field must be removed");
const exports = pkg.exports as Record<string, unknown> | undefined;
assert.ok(exports && typeof exports === "object", "exports map must exist");
const root = exports["."] as Record<string, unknown>;
assert.ok(root && typeof root === "object", 'exports["."] must exist');
assert.equal(root.import, "./dist/index.js", 'exports["."].import must be the ESM build');
// A `require` condition would re-introduce the CJS path the loader chokes on.
assert.equal("require" in root, false, 'exports["."] must not declare a `require` condition');
// The `./runtime` subpath used by the OpenCode loader must resolve to ESM.
const runtime = exports["./runtime"] as Record<string, unknown>;
assert.ok(runtime && typeof runtime === "object", 'exports["./runtime"] must exist');
assert.equal(runtime.import, "./dist/index.js", 'exports["./runtime"].import must be ESM');
});
test("opencode-plugin tsup config builds ESM-only with cjsInterop disabled", () => {
const tsup = readFileSync(fileURLToPath(TSUP_URL), "utf8");
const formatMatch = tsup.match(/format:\s*\[([^\]]*)\]/);
assert.ok(formatMatch, "tsup config must declare a format array");
const formats = formatMatch[1]
.split(",")
.map((s) => s.trim().replace(/['"]/g, ""))
.filter(Boolean);
assert.deepEqual(formats, ["esm"], "tsup must build esm only (no cjs)");
assert.equal(
/cjsInterop:\s*true/.test(tsup),
false,
"cjsInterop must not be true for an ESM-only build"
);
});