29 lines
1.6 KiB
JavaScript
29 lines
1.6 KiB
JavaScript
// Core selection only: modules receive a business-bound call, never a proof or writer.
|
|
import { createLoader } from "./loader.mjs";
|
|
import { NAME, PluginError } from "./kinds.mjs";
|
|
|
|
export const CHANNEL_RECOVERY = 'Run mosaic plugins to read the revision, then mosaic plugins set --file PATCH with plugins.channel set to ["cli","webui"].';
|
|
const record = value => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
const report = entry => process.stderr.write(`channel: ${JSON.stringify({
|
|
event: entry.event, kind: entry.kind, name: entry.name, code: entry.code, kept: entry.kept,
|
|
})}\n`);
|
|
|
|
export function createChannelCaller({ name, call, log = report, dataRoot = null }) {
|
|
if (typeof name !== "string" || !NAME.test(name)) throw new PluginError("bad-name", "invalid channel name");
|
|
if (typeof call !== "function") throw new TypeError("channel needs a core caller");
|
|
const loader = createLoader({ log, dataRoot });
|
|
return async (verb, args = {}) => {
|
|
const settings = await call("plugins", {});
|
|
if (!record(settings) || !record(settings.plugins)) {
|
|
throw new PluginError("channel-config", "invalid channel settings response");
|
|
}
|
|
const selection = Object.hasOwn(settings.plugins, "channel") ? { channel: settings.plugins.channel } : {};
|
|
await loader.load(selection);
|
|
const snapshot = loader.snapshot("channel");
|
|
const entry = snapshot.find(item => item.name === name);
|
|
if (!entry) throw new PluginError("channel-disabled", CHANNEL_RECOVERY, name);
|
|
// No lock spans dispatch. Concurrent reads can proceed while a send awaits.
|
|
return entry.module.dispatch({ verb, args }, { call });
|
|
};
|
|
}
|