UNPKG

@adonis-agora/agent

Version:

Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.

217 lines • 12.4 kB
const escapeHtml = (value) => value.replace(/[&<>"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]); function fill(template, values) { return escapeHtml(template).replace(/\{(\w+)\}/g, (_, k) => values[k] !== undefined ? escapeHtml(values[k]) : `{${k}}`); } /** The built-in pages: plain, accessible HTML; an app gives its own look with `render`. */ export const defaultConnectRenderer = (view, t) => { const org = 'organization' in view && view.organization ? view.organization : ''; const button = (label) => `<button type="submit" style="width:100%;padding:.75rem;border:0;border-radius:.75rem;background:#111;color:#fff;font-weight:600;font-size:1rem">${label}</button>`; let body = ''; switch (view.view) { case 'expired': body = `<h1>${fill(t.expiredTitle, {})}</h1><p>${fill(t.expiredBody, {})}</p>`; break; case 'connected': body = `<h1>${fill(t.connectedTitle, { company: org })}</h1><p>${fill(t.connectedBody, {})}</p>`; break; case 'failed': body = `<h1>${fill(t.failedTitle, {})}</h1><p>${fill(t.failedBody, {})}</p>${view.retryUrl ? `<p><a href="${escapeHtml(view.retryUrl)}">${fill(t.connectTitle, { company: org })}</a></p>` : ''}`; break; case 'choose': { body = `<h1>${fill(t.connectTitle, { company: org })}</h1><p>${fill(t.connectBody, { company: org })}</p>`; if (view.directUrl) { body += `<form method="POST" action="${escapeHtml(view.directUrl)}">${button(fill(t.direct, { company: org }))}</form>`; } if (view.mediated) { body += `<h2>${fill(t.mediatedTitle, {})}</h2><form method="POST" action="${escapeHtml(view.mediated.action)}">`; for (const f of view.mediated.fields) { body += `<label style="display:block;margin:.5rem 0">${escapeHtml(f.label)}<input name="${escapeHtml(f.name)}" type="${f.secret ? 'password' : 'text'}" autocomplete="${f.secret ? 'current-password' : 'off'}" required style="display:block;width:100%;padding:.6rem;margin-top:.25rem;border:1px solid #ccc;border-radius:.5rem"></label>`; } body += `${button(fill(t.mediatedSubmit, {}))}</form>`; } if (view.deviceUrl) { body += `<form method="POST" action="${escapeHtml(view.deviceUrl)}" style="margin-top:1rem"><button type="submit" style="background:none;border:0;text-decoration:underline;cursor:pointer">${fill(t.device, {})}</button></form>`; } break; } case 'code': body = `<h1>${fill(t.codeTitle, {})}</h1><form method="POST" action="${escapeHtml(view.action)}"><label style="display:block;margin:.5rem 0">${fill(t.codeLabel, { sentTo: view.sentTo })}<input name="code" inputmode="numeric" autocomplete="one-time-code" required style="display:block;width:100%;padding:.6rem;margin-top:.25rem;border:1px solid #ccc;border-radius:.5rem"></label>${button(fill(t.codeSubmit, {}))}</form>`; break; case 'device': body = `<h1>${fill(t.connectTitle, { company: org })}</h1><p>${fill(t.deviceBody, { link: view.verificationUri, code: view.userCode })}</p><p><a href="${escapeHtml(view.verificationUri)}">${escapeHtml(view.verificationUri)}</a></p>${view.pending ? `<p>${fill(t.pendingBody, {})}</p>` : ''}<form method="POST" action="${escapeHtml(view.checkUrl)}">${button(fill(t.deviceCheck, {}))}</form>`; break; } return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="referrer" content="no-referrer"><title>${fill(t.pageTitle, {})}</title></head><body style="font-family:system-ui,sans-serif;max-width:28rem;margin:3rem auto;padding:0 1rem;line-height:1.5">${body}</body></html>`; }; const SECURITY_HEADERS = { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-store', 'x-frame-options': 'DENY', 'content-security-policy': "default-src 'none'; style-src 'unsafe-inline'; img-src * data:; form-action *; frame-ancestors 'none'", 'referrer-policy': 'no-referrer', }; /** The default identity logo: the name's initial on a rounded square. */ export function defaultLogoSvg(name) { const initial = escapeHtml(([...name.trim()][0] ?? 'A').toUpperCase()); return `<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#334155"/><text x="32" y="42" font-family="sans-serif" font-size="30" text-anchor="middle" fill="#fff">${initial}</text></svg>`; } /** * The routes under `/{path}`: the agent identity (`agent.json`, `jwks.json`), the connect pages and * the Direct Sign-In callback. Returns `false` for anything else. Mounted ahead of the router: no * session, no CSRF token — the connect id in the URL is the capability (128 bits, single-purpose, * expiring), and the forms only ever post back to the same id. */ export function createPoppyConnectionsHandler(connections, options = {}) { const render = options.render ?? defaultConnectRenderer; const base = `/${connections.path}`; const page = (ex, status, view) => ex.send(status, SECURITY_HEADERS, render(view, connections.texts)); const url = (suffix) => `${connections.baseUrl}${base}${suffix}`; const choose = async (ex, id) => { const data = await connections.page(id); if (data.kind === 'expired') return page(ex, 410, { view: 'expired' }); if (data.kind === 'connected') return page(ex, 200, { view: 'connected', organization: data.organization }); return page(ex, 200, { view: 'choose', organization: data.organization, directUrl: data.direct ? url(`/connect/${id}/direct`) : null, deviceUrl: data.device ? url(`/connect/${id}/device`) : null, mediated: data.mediated ? { action: url(`/connect/${id}/mediated`), fields: data.mediated } : null, }); }; return async (ex) => { if (ex.path !== base && !ex.path.startsWith(`${base}/`)) return false; const rest = ex.path.slice(base.length); try { if (ex.method === 'GET' && rest === '/agent.json') { const identity = await connections.identity(); ex.send(200, { 'content-type': 'application/json', 'cache-control': 'public, max-age=300' }, JSON.stringify(identity.metadata())); return true; } if (ex.method === 'GET' && rest === '/logo.svg') { // The default `logo_uri` (when `identity.logoUri` is not set) — a Company's consent screen // shows it, so it must not 404: a mark with the name's initial. ex.send(200, { 'content-type': 'image/svg+xml', 'cache-control': 'public, max-age=86400' }, defaultLogoSvg(connections.identityName)); return true; } if (ex.method === 'GET' && rest === '/jwks.json') { const identity = await connections.identity(); ex.send(200, { 'content-type': 'application/json', 'cache-control': 'public, max-age=300' }, JSON.stringify(identity.jwks())); return true; } if (ex.method === 'GET' && rest === '/oauth/callback') { const result = await connections.directCallback(ex.query); if (result.ok) page(ex, 200, { view: 'connected', organization: result.organization ?? '' }); else { const id = (ex.query.get('state') ?? '').split('.')[0] ?? ''; page(ex, 400, { view: 'failed', organization: result.organization, retryUrl: id ? url(`/connect/${id}`) : null, }); } return true; } const match = /^\/connect\/([A-Za-z0-9_-]{16,64})(\/[a-z/]+)?$/.exec(rest); if (!match) return false; const id = match[1]; const action = match[2] ?? ''; if (ex.method === 'GET' && action === '') { await choose(ex, id); return true; } if (ex.method !== 'POST') { ex.send(405, { allow: 'GET, POST' }, ''); return true; } const form = new URLSearchParams(await ex.readBody(16 * 1024)); if (action === '/direct') { const to = await connections.directUrl(id); if (to === null) page(ex, 410, { view: 'expired' }); else ex.send(303, { location: to, 'cache-control': 'no-store' }, ''); return true; } if (action === '/mediated' || action === '/code') { const outcome = action === '/mediated' ? await connections.mediated(id, Object.fromEntries(form)) : await connections.mediatedCode(id, form.get('code') ?? ''); const data = await connections.page(id); const organization = data.kind === 'open' || data.kind === 'connected' ? data.organization : ''; if (outcome.status === 'connected') page(ex, 200, { view: 'connected', organization }); else if (outcome.status === 'code_required') { page(ex, 200, { view: 'code', organization, action: url(`/connect/${id}/code`), sentTo: outcome.sentTo ?? '', }); } else if (outcome.status === 'expired') page(ex, 410, { view: 'expired' }); else page(ex, 400, { view: 'failed', organization, retryUrl: url(`/connect/${id}`) }); return true; } if (action === '/device' || action === '/device/check') { const data = await connections.page(id); if (data.kind === 'expired') { page(ex, 410, { view: 'expired' }); return true; } const organization = data.organization; if (action === '/device') { const started = await connections.deviceStart(id); if (started === null) page(ex, 410, { view: 'expired' }); else page(ex, 200, { view: 'device', organization, ...started, checkUrl: url(`/connect/${id}/device/check`), pending: false, }); return true; } const status = await connections.deviceCheck(id); if (status === 'connected') page(ex, 200, { view: 'connected', organization }); else if (status === 'pending') { const again = await connections.deviceInfo(id); page(ex, 200, again === null ? { view: 'expired' } : { view: 'device', organization, ...again, checkUrl: url(`/connect/${id}/device/check`), pending: true, }); } else if (status === 'expired') page(ex, 410, { view: 'expired' }); else page(ex, 400, { view: 'failed', organization, retryUrl: url(`/connect/${id}`) }); return true; } return false; } catch (error) { options.onError?.(error); page(ex, 500, { view: 'failed', organization: null, retryUrl: null }); return true; } }; } //# sourceMappingURL=http.js.map