import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; import { join, resolve } from "node:path"; import { describe, expect, it } from "@suaveplan/testing/runner"; const PKG_ROOT = resolve(__dirname, ".."); const DIST = join(PKG_ROOT, "dist"); /** * Chunk-A runtime dependency allowlist. Chunks B/C/D may extend this * (`@suaveplan/network-transport-websockets`, `@suaveplan/retry`, etc.); * the parent spec's `tests/exports.test.ts` enforces the full union * once every chunk has landed. */ const ALLOWED_RUNTIME_DEPS = new Set([ "@suaveplan/audio-fx-plugin-base", "@suaveplan/audio-transport", "@suaveplan/error", "@suaveplan/events", "@suaveplan/fsm", "@suaveplan/network-transport-websockets", "@suaveplan/opentelemetry", "@suaveplan/react-audio", "@suaveplan/retry", "@suaveplan/types", "@opentelemetry/api", "tslib", "zod", "zustand", ]); function walk(dir: string, out: string[] = []): string[] { if (!existsSync(dir)) return out; for (const name of readdirSync(dir)) { const p = join(dir, name); if (statSync(p).isDirectory()) walk(p, out); else if (/\.(js|mjs|cjs)$/.test(name)) out.push(p); } return out; } describe("react-audio-stream purity gates", () => { it("runtime dependency set matches the allowlist", { timeout: 5000, }, () => { const pkg = JSON.parse( readFileSync(join(PKG_ROOT, "package.json"), "utf8") ) as { dependencies?: Record }; const deps = Object.keys(pkg.dependencies ?? {}); for (const dep of deps) { expect(ALLOWED_RUNTIME_DEPS.has(dep)).toBe(true); } for (const allowed of ALLOWED_RUNTIME_DEPS) { expect(deps.includes(allowed)).toBe(true); } }); it("dist references no audio context", { timeout: 30000 }, () => { if (!existsSync(DIST)) { // Skip pre-build — the package's own test stage runs before // `vite build`; the CI pipeline reruns this after `turbo // build` so the negative gate is enforced there. return; } const files = walk(DIST); const forbidden = [ /\bnew\s+AudioContext\b/, /\bnew\s+OfflineAudioContext\b/, /\binstanceof\s+AudioNode\b/, /\bAudioWorkletNode\b/, /\bregisterProcessor\b/, ]; for (const file of files) { const text = readFileSync(file, "utf8"); for (const rx of forbidden) { expect(rx.test(text)).toBe(false); } } }); });