locqr/website/index.html
2026-08-16 22:00:08 +02:00

119 lines
4.8 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>LOCQR test site</title>
<style>
/* Intentionally bare (website/claude.md) — readability only, no application logic. */
body { font-family: system-ui, sans-serif; max-width: 640px; margin: 40px auto; padding: 0 16px; color: #111; }
h1 { font-size: 20px; }
form { display: flex; flex-direction: column; gap: 8px; max-width: 280px; margin-bottom: 32px; }
input, button { padding: 8px; font-size: 14px; }
button { cursor: pointer; }
#log { font-family: ui-monospace, monospace; font-size: 12px; background: #f5f5f5; border: 1px solid #ddd;
padding: 12px; height: 320px; overflow-y: auto; white-space: pre-wrap; }
#log .entry { border-bottom: 1px solid #e5e5e5; padding: 4px 0; }
#log .time { color: #888; }
</style>
</head>
<body>
<h1>LOCQR test site</h1>
<p id="status">Loading registration certificate…</p>
<form id="login-form">
<input id="username" type="text" placeholder="Username" readonly />
<input id="password" type="password" placeholder="Password" readonly />
<button id="sign-in-btn" type="button" disabled>Sign in with LOCQR</button>
</form>
<h2 style="font-size: 14px;">Event log</h2>
<div id="log"></div>
<script type="module">
import locqr from '/sdk/index.js';
const logEl = document.getElementById('log');
const statusEl = document.getElementById('status');
// "Every SDK event, Promise resolution, rejection, and error — including
// the full payload — is appended to the log in real time with a
// timestamp." (website/claude.md — this is the primary debugging tool.)
function log(label, payload) {
const time = new Date().toISOString().split('T')[1].replace('Z', '');
const entry = document.createElement('div');
entry.className = 'entry';
entry.innerHTML = `<span class="time">${time}</span> <strong>${label}</strong> ${payload !== undefined ? JSON.stringify(payload) : ''}`;
logEl.appendChild(entry);
logEl.scrollTop = logEl.scrollHeight;
}
// Dev extension ID, derived from extension/key.pem (dev.md, "Extension ID
// in development"). Stable as long as key.pem doesn't change.
const DEV_EXTENSION_ID = 'daijigbjegngkjckedcbhhdjkampjgia';
async function main() {
log('page:loaded');
let cert;
try {
// Registration cert served by the backend rather than hand-copied
// into this page (website/claude.md leaves the mechanism open;
// server/claude.md's GET /domain/registration implements this option).
const response = await fetch('https://api.locqr.dev:3000/domain/registration?domain=test.locqr.dev');
if (!response.ok) throw new Error(`registration fetch failed: ${response.status}`);
({ cert } = await response.json());
log('cert:fetched', { length: cert.length });
} catch (err) {
statusEl.textContent = 'Could not fetch registration certificate — is the server running?';
log('cert:fetch_error', { message: String(err) });
return;
}
statusEl.textContent = 'Initializing LOCQR…';
log('locqr:init', { extensionId: DEV_EXTENSION_ID });
locqr.on('ready', (payload) => log('event:ready', payload));
locqr.on('run:started', (payload) => log('event:run:started', payload));
locqr.on('run:delivered', (payload) => log('event:run:delivered', payload));
locqr.on('run:error', (payload) => log('event:run:error', payload));
locqr.init({ cert, extensionId: DEV_EXTENSION_ID });
try {
const result = await locqr.ready;
statusEl.textContent = `Ready — features: ${result.features.join(', ')}`;
log('ready:resolved', result);
signInBtn.disabled = false;
} catch (error) {
statusEl.textContent = `Not ready — ${error.code}${error.reason ? ' / ' + error.reason : ''}`;
log('ready:rejected', error);
}
}
const signInBtn = document.getElementById('sign-in-btn');
const usernameEl = document.getElementById('username');
const passwordEl = document.getElementById('password');
signInBtn.addEventListener('click', async () => {
signInBtn.disabled = true;
usernameEl.value = '';
passwordEl.value = '';
log('requestCredential:called');
try {
const credential = await locqr.requestCredential();
usernameEl.value = credential.username;
passwordEl.value = credential.password;
log('requestCredential:resolved', { username: credential.username });
} catch (error) {
statusEl.textContent = `Sign-in didn't complete — ${error.code}${error.reason ? ' / ' + error.reason : ''}`;
log('requestCredential:rejected', error);
} finally {
signInBtn.disabled = false;
}
});
main();
</script>
</body>
</html>