feat(scripting): discover scoped @punktfunk/plugin-* packages
apple / swift (push) Successful in 1m24s
apple / screenshots (push) Successful in 6m27s
windows-host / package (push) Failing after 15m41s
ci / web (push) Successful in 1m33s
ci / docs-site (push) Successful in 1m26s
android / android (push) Successful in 14m3s
decky / build-publish (push) Successful in 21s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 16s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 15s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
ci / bench (push) Successful in 7m40s
deb / build-publish (push) Successful in 8m58s
deb / build-publish-host (push) Successful in 9m32s
arch / build-publish (push) Successful in 17m35s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m33s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 19m33s
ci / rust (push) Successful in 28m32s
docker / deploy-docs (push) Failing after 12s
apple / swift (push) Successful in 1m24s
apple / screenshots (push) Successful in 6m27s
windows-host / package (push) Failing after 15m41s
ci / web (push) Successful in 1m33s
ci / docs-site (push) Successful in 1m26s
android / android (push) Successful in 14m3s
decky / build-publish (push) Successful in 21s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 16s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 15s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
ci / bench (push) Successful in 7m40s
deb / build-publish (push) Successful in 8m58s
deb / build-publish-host (push) Successful in 9m32s
arch / build-publish (push) Successful in 17m35s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m33s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 19m33s
ci / rust (push) Successful in 28m32s
docker / deploy-docs (push) Failing after 12s
The runner only found unscoped `punktfunk-plugin-*` packages. An unscoped package can't be split across registries, which forced plugins to bundle their own copy of @punktfunk/host + effect (the plugin's Gitea registry has no `effect`; `--registry <gitea>` 404s it). Discovering the scoped `@punktfunk/plugin-*` convention lets a plugin resolve cleanly from one scope map and depend on @punktfunk/host + effect as SHARED (hoisted) deps instead of bundling — no per-plugin duplication. Additive: unscoped names still work. Bumps @punktfunk/host to 0.1.1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@punktfunk/host",
|
"name": "@punktfunk/host",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"description": "TypeScript SDK for the punktfunk streaming host: typed management-API client + lifecycle event stream, built on Effect.",
|
"description": "TypeScript SDK for the punktfunk streaming host: typed management-API client + lifecycle event stream, built on Effect.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
|
|||||||
+29
-8
@@ -92,19 +92,40 @@ export const discoverUnits = (
|
|||||||
// no scripts dir — fine
|
// no scripts dir — fine
|
||||||
}
|
}
|
||||||
const modules = path.join(pluginsDir, "node_modules");
|
const modules = path.join(pluginsDir, "node_modules");
|
||||||
try {
|
// Read a plugin package's manifest (`module`/`main` entry) and add it as a unit.
|
||||||
for (const pkg of fs.readdirSync(modules).sort()) {
|
const addPlugin = (dir: string, name: string): void => {
|
||||||
if (!pkg.startsWith("punktfunk-plugin-")) continue;
|
|
||||||
try {
|
try {
|
||||||
const manifest = JSON.parse(
|
const manifest = JSON.parse(
|
||||||
fs.readFileSync(path.join(modules, pkg, "package.json"), "utf8"),
|
fs.readFileSync(path.join(dir, "package.json"), "utf8"),
|
||||||
) as { main?: string; module?: string };
|
) as { main?: string; module?: string };
|
||||||
const rel = manifest.module ?? manifest.main ?? "index.js";
|
const rel = manifest.module ?? manifest.main ?? "index.js";
|
||||||
const file = path.join(modules, pkg, rel);
|
const file = path.join(dir, rel);
|
||||||
if (!fileIsSafe(file, log)) continue;
|
if (!fileIsSafe(file, log)) return;
|
||||||
units.push({ name: pkg, file });
|
units.push({ name, file });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(`[runner] skipping ${pkg}: unreadable package.json (${e})`);
|
log(`[runner] skipping ${name}: unreadable package.json (${e})`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
for (const pkg of fs.readdirSync(modules).sort()) {
|
||||||
|
// Unscoped convention: `punktfunk-plugin-*`.
|
||||||
|
if (pkg.startsWith("punktfunk-plugin-")) {
|
||||||
|
addPlugin(path.join(modules, pkg), pkg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Scoped convention: `@punktfunk/plugin-*` (first-party). A scoped name resolves cleanly
|
||||||
|
// from a single registry scope-map, so a plugin can depend on `@punktfunk/host` + `effect`
|
||||||
|
// as shared (hoisted) deps rather than bundling its own copy of each.
|
||||||
|
if (pkg === "@punktfunk") {
|
||||||
|
try {
|
||||||
|
for (const scoped of fs.readdirSync(path.join(modules, pkg)).sort()) {
|
||||||
|
if (scoped.startsWith("plugin-")) {
|
||||||
|
addPlugin(path.join(modules, pkg, scoped), `${pkg}/${scoped}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// no @punktfunk scope dir — fine
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -83,6 +83,25 @@ describe("discovery", () => {
|
|||||||
expect(logs.join("\n")).toContain("REFUSING");
|
expect(logs.join("\n")).toContain("REFUSING");
|
||||||
expect(logs.join("\n")).toContain("evil.ts");
|
expect(logs.join("\n")).toContain("evil.ts");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("discovers scoped @punktfunk/plugin-* packages (not other scoped pkgs)", () => {
|
||||||
|
const d = mkdirs("discover-scoped");
|
||||||
|
write(
|
||||||
|
path.join(d.pluginsDir, "node_modules", "@punktfunk", "plugin-y", "package.json"),
|
||||||
|
JSON.stringify({ name: "@punktfunk/plugin-y", module: "dist/index.js" }),
|
||||||
|
);
|
||||||
|
write(
|
||||||
|
path.join(d.pluginsDir, "node_modules", "@punktfunk", "plugin-y", "dist", "index.js"),
|
||||||
|
"export default { name: 'y', main: async () => {} };",
|
||||||
|
);
|
||||||
|
// A non-plugin scoped package (e.g. the SDK itself) is ignored.
|
||||||
|
write(
|
||||||
|
path.join(d.pluginsDir, "node_modules", "@punktfunk", "host", "package.json"),
|
||||||
|
JSON.stringify({ name: "@punktfunk/host" }),
|
||||||
|
);
|
||||||
|
const units = discoverUnits(d);
|
||||||
|
expect(units.map((u) => u.name)).toEqual(["@punktfunk/plugin-y"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("supervision", () => {
|
describe("supervision", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user