Unified endpoint config type: one Host/IP : Port control in admin

New configSchema type 'endpoint' declared in the module spec: anything
that points at a device or service on the network must be one endpoint
field, rendered identically for every module in /admin as a joined
Host/IP : Port control and stored/handed to the module server as
{ host, port }. Migrates all three connection modules — ProdCom (was a
full URL field), ProPresenter and Timers (were separate host + port
fields). Legacy stored configs (prodcomUrl / flat host+port) keep
working until the admin form is re-saved, at which point the new shape
replaces them. MODULE-GUIDE documents the type and the presentation
rule: no split host/port fields, and full URLs only for genuine web
addresses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RNYUv9EyrGSFmCnmH7WYKH
This commit is contained in:
Claude
2026-08-31 19:33:08 +00:00
parent 6412dd9524
commit a06bc921ce
11 changed files with 116 additions and 39 deletions
+4 -9
View File
@@ -9,15 +9,10 @@
"minSize": { "w": 3, "h": 3 },
"defaultSize": { "w": 4, "h": 5 },
"configSchema": {
"host": {
"type": "string",
"label": "ProPresenter host / IP",
"default": ""
},
"port": {
"type": "number",
"label": "ProPresenter network port",
"default": 1025
"propresenter": {
"type": "endpoint",
"label": "ProPresenter",
"default": { "host": "", "port": 1025 }
},
"password": {
"type": "password",
+11 -5
View File
@@ -23,7 +23,13 @@ let current = null;
module.exports = {
init({ config, log }) {
const streams = new Set();
const enabled = Boolean(config.host && Number(config.port));
// Endpoint config. Legacy flat host/port keys (saved before the endpoint
// field existed) can only still be present until the admin form is
// re-saved, so when they exist they win over the endpoint's default.
const ep = config.propresenter && typeof config.propresenter === 'object' ? config.propresenter : {};
const host = String(config.host ?? ep.host ?? '');
const port = Number(config.port ?? ep.port) || 1025;
const enabled = Boolean(host && port);
let latest = clearedViewModel();
let lastFrame = '';
@@ -54,14 +60,14 @@ module.exports = {
client.configure({
enabled,
host: String(config.host || ''),
port: Number(config.port) || 1025,
host,
port,
password: String(config.password || ''),
});
if (enabled) {
client.start();
log(`following ProPresenter at ${config.host}:${config.port}`);
log(`following ProPresenter at ${host}:${port}`);
} else {
log('no ProPresenter host configured — set one in /admin');
}
@@ -91,7 +97,7 @@ module.exports = {
},
health() {
if (!enabled) return { status: 'error', message: 'No ProPresenter host configured' };
if (latest.reachable) return { status: 'ok', message: `Following ${config.host}:${config.port}` };
if (latest.reachable) return { status: 'ok', message: `Following ${host}:${port}` };
return {
status: 'error',
message: latest.lastError