Phase 1-3 of the builder subsystem on the Mac mini: - Express + SQLite + sessions scaffolding, LAN-only service on port 3090 - App Store Connect JWT client (ES256 signing, devices/profiles/bundleIds) - Device management UI with Apple-side registration - Fastlane sigh wrapper with profile cache + auto-install to ~/Library/ - launchd plist + deploy script for Mac mini supervision
75 lines
2.4 KiB
JavaScript
75 lines
2.4 KiB
JavaScript
const $ = (sel) => document.querySelector(sel);
|
|
const toast = (msg, kind = '') => {
|
|
const t = $('#toast');
|
|
t.textContent = msg;
|
|
t.className = 'toast show ' + kind;
|
|
setTimeout(() => t.classList.remove('show'), 3000);
|
|
};
|
|
|
|
async function load() {
|
|
const res = await fetch('/api/settings');
|
|
if (res.status === 401) { location.href = '/login'; return; }
|
|
const s = await res.json();
|
|
|
|
$('[name=asc_key_id]').value = s.asc_key_id || '';
|
|
$('[name=asc_issuer_id]').value = s.asc_issuer_id || '';
|
|
$('[name=unraid_url]').value = s.unraid_url || '';
|
|
$('[name=unraid_token]').value = s.unraid_token || '';
|
|
|
|
$('#p8-status').textContent = s.asc_key_uploaded
|
|
? `✓ .p8 uploaded for key ${s.asc_key_id}`
|
|
: 'No .p8 uploaded yet';
|
|
}
|
|
|
|
async function saveForm(formEl, keys) {
|
|
const data = Object.fromEntries(keys.map(k => [k, formEl.querySelector(`[name=${k}]`)?.value || '']));
|
|
const res = await fetch('/api/settings', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data),
|
|
});
|
|
if (res.ok) toast('Saved', 'success');
|
|
else toast('Save failed', 'error');
|
|
}
|
|
|
|
$('#asc-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
await saveForm(e.target, ['asc_key_id', 'asc_issuer_id']);
|
|
|
|
// Upload .p8 if one was selected
|
|
const file = $('#p8-input').files[0];
|
|
if (file) {
|
|
const fd = new FormData();
|
|
fd.append('p8', file);
|
|
const res = await fetch('/api/settings/p8', { method: 'POST', body: fd });
|
|
if (res.ok) {
|
|
toast('.p8 uploaded', 'success');
|
|
load();
|
|
} else {
|
|
const err = await res.json().catch(() => ({}));
|
|
toast(err.error || 'Upload failed', 'error');
|
|
}
|
|
}
|
|
});
|
|
|
|
$('#unraid-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
await saveForm(e.target, ['unraid_url', 'unraid_token']);
|
|
});
|
|
|
|
$('#test-asc').addEventListener('click', async () => {
|
|
const res = await fetch('/api/settings/test-asc', { method: 'POST' });
|
|
const data = await res.json();
|
|
if (res.ok) toast(`Connected — ${data.device_count} devices in portal`, 'success');
|
|
else toast(data.error || 'Connection failed', 'error');
|
|
});
|
|
|
|
$('#test-unraid').addEventListener('click', async () => {
|
|
const res = await fetch('/api/settings/test-unraid', { method: 'POST' });
|
|
const data = await res.json();
|
|
if (res.ok) toast(`Connected to unraid — ${data.app_count} apps`, 'success');
|
|
else toast(data.error || 'Connection failed', 'error');
|
|
});
|
|
|
|
load();
|