@adonis-agora/agent
Version:
Governed, durable-backed AI agent (chat + tool-calling + governance) for AdonisJS — part of the Agora ecosystem.
83 lines • 3.42 kB
JavaScript
import { createServer } from 'node:http';
import { PoppyError } from './errors.js';
import { normalizeDomain, randomId, requireSecureUrl } from './util.js';
/**
* Builds the browser assertion of section 5 for the current Session, after checking that
* `return_to` is an HTTPS URL on `organization.domain` or a subdomain of it.
*/
export async function createBrowserAssertion(company, returnTo) {
const ep = company.document.web?.browser_session_endpoint;
if (!ep) {
throw new PoppyError('no_browser_session_endpoint', 'Company has no web.browser_session_endpoint: browse as an ordinary signed-out visitor');
}
const endpoint = requireSecureUrl(ep, 'web.browser_session_endpoint', company.security).toString();
const target = requireSecureUrl(returnTo, 'return_to', company.security);
const org = normalizeDomain(company.document.organization.domain.replace(/:\d+$/, ''));
const host = target.hostname.toLowerCase();
if (normalizeDomain(host) !== org && !host.endsWith(`.${org}`)) {
throw new PoppyError('invalid_return_to', `return_to must be on ${org} or a subdomain (section 5)`);
}
const { sessionId } = await company.token();
const assertion = await company.agent.identity.browserAssertion({
userId: company.userId,
endpoint,
sessionId,
returnTo: target.toString(),
});
return { endpoint, assertion, sessionId };
}
function escapeHtml(s) {
return s.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
}
/** A page whose form POSTs the assertion as a top-level navigation. Never in the URL (5). */
export function autoSubmitFormHtml(endpoint, assertion) {
return `<!doctype html>
<html><head><meta charset="utf-8"><meta name="referrer" content="no-referrer"><title>Joining session…</title></head>
<body>
<form method="post" action="${escapeHtml(endpoint)}" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="assertion" value="${escapeHtml(assertion)}">
<noscript><button type="submit">Continue</button></noscript>
</form>
<script>document.forms[0].submit()</script>
</body></html>`;
}
/**
* Serves the auto-submitting page once, on 127.0.0.1 at an unguessable path, so a local
* browser can load it. The page is gone after the first load (the assertion lives 60s anyway).
*/
export async function serveOneShotPage(html, opts = {}) {
const path = `/${randomId('', 16)}`;
let resolveServed;
const served = new Promise((r) => {
resolveServed = r;
});
let used = false;
const server = createServer((req, res) => {
if (req.url !== path || used) {
res.writeHead(404).end();
return;
}
used = true;
res.writeHead(200, {
'content-type': 'text/html; charset=utf-8',
'cache-control': 'no-store',
'referrer-policy': 'no-referrer',
});
res.end(html);
resolveServed();
setTimeout(() => server.close(), 1000).unref();
});
await new Promise((r) => server.listen(0, '127.0.0.1', r));
const timer = setTimeout(() => server.close(), opts.timeoutMs ?? 60_000);
timer.unref();
const { port } = server.address();
return {
url: `http://127.0.0.1:${port}${path}`,
served,
close: () => {
clearTimeout(timer);
server.close();
},
};
}
//# sourceMappingURL=browser.js.map