// Served at /setup/app.js
// No fancy syntax: keep it maximally compatible.
(function () {
var statusEl = document.getElementById('status');
var authGroupEl = document.getElementById('authGroup');
var authChoiceEl = document.getElementById('authChoice');
var logEl = document.getElementById('log');
function setStatus(s) {
statusEl.textContent = s;
}
// Provider template handling
window.useProvider = function(providerId) {
httpJson('/setup/api/templates/' + providerId)
.then(function(tmpl) {
// Set auth choice
if (tmpl.authChoice) {
authChoiceEl.value = tmpl.authChoice;
// Trigger change to update options if needed
if (authGroupEl) {
authGroupEl.value = tmpl.authChoice.split('-')[0] || tmpl.authChoice;
authGroupEl.dispatchEvent(new Event('change'));
}
}
// Set placeholders and help text
var authSecretEl = document.getElementById('authSecret');
if (authSecretEl && tmpl.fields.authSecret) {
authSecretEl.placeholder = tmpl.fields.authSecret.placeholder || '';
var helpEl = document.getElementById('authSecretHelp');
if (helpEl) {
helpEl.textContent = tmpl.fields.authSecret.help || '';
helpEl.style.display = 'block';
}
}
// Set base URL if provided
if (tmpl.fields.baseUrl && tmpl.fields.baseUrl.default) {
var baseUrlEl = document.getElementById('baseUrl');
if (baseUrlEl) {
baseUrlEl.value = tmpl.fields.baseUrl.default;
}
}
logEl.textContent += '\nSelected provider: ' + tmpl.name + '\n';
})
.catch(function(err) {
logEl.textContent += '\nError loading template: ' + String(err) + '\n';
});
};
// Validate token on blur
window.validateToken = function() {
var authChoice = authChoiceEl.value;
var token = document.getElementById('authSecret').value.trim();
var baseUrl = document.getElementById('baseUrl') ? document.getElementById('baseUrl').value.trim() : '';
if (!authChoice || !token) {
return;
}
var validateBtn = document.getElementById('validateBtn');
if (validateBtn) {
validateBtn.textContent = 'Validating...';
validateBtn.disabled = true;
}
httpJson('/setup/api/validate-token', {
method: 'POST',
body: JSON.stringify({ provider: authChoice, token: token, baseUrl: baseUrl })
}).then(function(result) {
if (validateBtn) {
validateBtn.textContent = result.valid ? '✓ Valid' : '✗ Invalid';
validateBtn.disabled = false;
validateBtn.style.backgroundColor = result.valid ? '#28a745' : '#dc3545';
}
var msg = result.valid ? 'Token validated successfully for ' + result.provider : 'Validation failed: ' + result.error;
logEl.textContent += '\n' + msg + '\n';
}).catch(function(err) {
if (validateBtn) {
validateBtn.textContent = 'Validate Token';
validateBtn.disabled = false;
}
logEl.textContent += '\nValidation error: ' + String(err) + '\n';
});
};
// Pre-flight checks
window.runPreflightChecks = function() {
var resultsEl = document.getElementById('preflightResults');
resultsEl.innerHTML = 'Running checks...';
resultsEl.style.color = '#555';
httpJson('/setup/api/check')
.then(function(data) {
var html = '
';
html += '
' + data.summary + '';
data.checks.forEach(function(check) {
var icon = check.status === 'ok' ? '✅' : check.status === 'warning' ? '⚠️' : '❌';
var color = check.status === 'ok' ? '#28a745' : check.status === 'warning' ? '#ffc107' : '#dc3545';
html += '
';
html += icon + ' ' + check.name + ': ' + check.message;
html += '
';
});
html += '
';
resultsEl.innerHTML = html;
})
.catch(function(err) {
resultsEl.innerHTML = 'Error: ' + String(err) + '
';
});
};
function renderAuth(groups) {
authGroupEl.innerHTML = '';
for (var i = 0; i < groups.length; i++) {
var g = groups[i];
var opt = document.createElement('option');
opt.value = g.value;
opt.textContent = g.label + (g.hint ? ' - ' + g.hint : '');
authGroupEl.appendChild(opt);
}
authGroupEl.onchange = function () {
var sel = null;
for (var j = 0; j < groups.length; j++) {
if (groups[j].value === authGroupEl.value) sel = groups[j];
}
authChoiceEl.innerHTML = '';
var opts = (sel && sel.options) ? sel.options : [];
for (var k = 0; k < opts.length; k++) {
var o = opts[k];
var opt2 = document.createElement('option');
opt2.value = o.value;
opt2.textContent = o.label + (o.hint ? ' - ' + o.hint : '');
authChoiceEl.appendChild(opt2);
}
};
authGroupEl.onchange();
}
function httpJson(url, opts) {
opts = opts || {};
opts.credentials = 'same-origin';
return fetch(url, opts).then(function (res) {
if (!res.ok) {
return res.text().then(function (t) {
throw new Error('HTTP ' + res.status + ': ' + (t || res.statusText));
});
}
return res.json();
});
}
function refreshStatus() {
setStatus('Loading...');
return httpJson('/setup/api/status').then(function (j) {
var ver = j.moltbotVersion ? (' | ' + j.moltbotVersion) : '';
setStatus((j.configured ? 'Configured - open /moltbot' : 'Not configured - run setup below') + ver);
renderAuth(j.authGroups || []);
// If channels are unsupported, surface it for debugging.
if (j.channelsAddHelp && j.channelsAddHelp.indexOf('telegram') === -1) {
logEl.textContent += '\nNote: this moltbot build does not list telegram in `channels add --help`. Telegram auto-add will be skipped.\n';
}
}).catch(function (e) {
setStatus('Error: ' + String(e));
});
}
document.getElementById('run').onclick = function () {
var payload = {
flow: document.getElementById('flow').value,
authChoice: authChoiceEl.value,
authSecret: document.getElementById('authSecret').value,
telegramToken: document.getElementById('telegramToken').value,
discordToken: document.getElementById('discordToken').value,
slackBotToken: document.getElementById('slackBotToken').value,
slackAppToken: document.getElementById('slackAppToken').value
};
logEl.textContent = 'Running...\n';
fetch('/setup/api/run', {
method: 'POST',
credentials: 'same-origin',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(payload)
}).then(function (res) {
return res.text();
}).then(function (text) {
var j;
try { j = JSON.parse(text); } catch (_e) { j = { ok: false, output: text }; }
logEl.textContent += (j.output || JSON.stringify(j, null, 2));
return refreshStatus();
}).catch(function (e) {
logEl.textContent += '\nError: ' + String(e) + '\n';
});
};
// Pairing approve helper
var pairingBtn = document.getElementById('pairingApprove');
if (pairingBtn) {
pairingBtn.onclick = function () {
var channel = prompt('Enter channel (telegram or discord):');
if (!channel) return;
channel = channel.trim().toLowerCase();
if (channel !== 'telegram' && channel !== 'discord') {
alert('Channel must be "telegram" or "discord"');
return;
}
var code = prompt('Enter pairing code (e.g. 3EY4PUYS):');
if (!code) return;
logEl.textContent += '\nApproving pairing for ' + channel + '...\n';
fetch('/setup/api/pairing/approve', {
method: 'POST',
credentials: 'same-origin',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ channel: channel, code: code.trim() })
}).then(function (r) { return r.text(); })
.then(function (t) { logEl.textContent += t + '\n'; })
.catch(function (e) { logEl.textContent += 'Error: ' + String(e) + '\n'; });
};
}
document.getElementById('reset').onclick = function () {
if (!confirm('Reset setup? This deletes the config file so onboarding can run again.')) return;
logEl.textContent = 'Resetting...\n';
fetch('/setup/api/reset', { method: 'POST', credentials: 'same-origin' })
.then(function (res) { return res.text(); })
.then(function (t) { logEl.textContent += t + '\n'; return refreshStatus(); })
.catch(function (e) { logEl.textContent += 'Error: ' + String(e) + '\n'; });
};
// Debug button handler
var debugBtn = document.getElementById('debug');
if (debugBtn) {
debugBtn.onclick = function () {
logEl.textContent = 'Fetching debug info...\n';
httpJson('/setup/api/debug')
.then(function (info) {
// Check for error response
if (info.error) {
logEl.textContent = 'ERROR: ' + info.error + '\n';
if (info.stack) {
logEl.textContent += 'Stack: ' + info.stack + '\n';
}
return;
}
logEl.textContent = 'DEBUG INFO:\n';
logEl.textContent += '================\n';
logEl.textContent += 'Configured: ' + info.configured + '\n';
logEl.textContent += 'Config path: ' + info.configPath + '\n';
logEl.textContent += 'Config exists: ' + info.configExists + '\n';
logEl.textContent += 'State dir: ' + info.stateDir + ' (exists: ' + info.stateDirExists + ')\n';
logEl.textContent += 'Workspace dir: ' + info.workspaceDir + ' (exists: ' + info.workspaceDirExists + ')\n';
logEl.textContent += 'Gateway running: ' + info.gatewayRunning + '\n';
logEl.textContent += 'Gateway proc exists: ' + info.gatewayProcExists + '\n';
logEl.textContent += 'Gateway proc PID: ' + info.gatewayProcPid + '\n';
if (info.configContent) {
logEl.textContent += '\nConfig content:\n' + JSON.stringify(info.configContent, null, 2) + '\n';
} else if (info.configError) {
logEl.textContent += '\nConfig error: ' + info.configError + '\n';
}
logEl.textContent += '================\n';
})
.catch(function (e) { logEl.textContent += 'Error: ' + String(e) + '\n'; });
};
}
// Test endpoint button handler
var testBtn = document.getElementById('test');
if (testBtn) {
testBtn.onclick = function () {
logEl.textContent = 'Testing endpoint...\n';
httpJson('/setup/api/test')
.then(function (result) {
logEl.textContent = 'TEST RESULT:\n';
logEl.textContent += '============\n';
logEl.textContent += JSON.stringify(result, null, 2) + '\n';
logEl.textContent += '============\n';
if (result.test === 'ok') {
logEl.textContent += '\n✅ Routing and authentication work!\n';
}
})
.catch(function (e) { logEl.textContent += 'Error: ' + String(e) + '\n'; });
};
}
refreshStatus();
// Run pre-flight checks on load
setTimeout(function() {
runPreflightChecks();
}, 500);
})();