johnandersen777.bsky.social/atlibs-agents
agents and atirc modules for atlibs: launch agents from a composition, chat on atirc; pages and the agents service
0
0
import { BrowserOAuthClient } from '@atproto/oauth-client-browser'
import { Agent } from '@atproto/api'
import { AtircCubit } from './atirc-cubit.js'
import { pageClientId } from 'atlibs/oauth/index.js'
import { createPluginContext } from 'atlibs/plugin-context/index.js'
import { loadModule, localModule } from 'atlibs/run-module/index.js'
// Wiring only: user events go to the cubit, cubit state goes to the views.
// The atirc wasm module plans every call. By default the page runs the `cargo wasm` build
// through the modules/ symlinks; ?module=<handle>/<name> (or at://...) runs a published module record instead.
const MODULE = new URLSearchParams(location.search).get('module') ?? 'local';
const MODULES = new URL('./modules/', import.meta.url);
const ATIRC = 'did:web:irc.fedfork.com%23atirc';
const POLL_MS = 5000;
const ctx = createPluginContext({ id: 'atirc' });
// rpc scopes let the PDS mint service-auth for atirc on these two methods only. On localhost the
// loopback development client; deployed, the client `atlibs stage --target spa` wrote next to the page.
const SCOPE = `atproto rpc:chat.atirc.list?aud=${ATIRC} rpc:chat.atirc.post?aud=${ATIRC}`;
const cubit = new AtircCubit({
client: pageClientId(SCOPE).then((clientId) => BrowserOAuthClient.load({ clientId, handleResolver: 'https://bsky.social' })),
makeAgent: (session) => new Agent(session),
module: MODULE === 'local' ? localModule(new URL('atirc.wasm', MODULES), new URL('atirc.json', MODULES)) : loadModule(ctx, MODULE),
ctx,
});
const show = (id, on) => (document.getElementById(id).style.display = on ? "inherit" : "none");
function renderPage(state) {
show("loading-spinner", state.session === "loading" || state.session === "error");
show("loading-error", state.session === "error");
document.getElementById("loading-error").innerText = state.error ?? "";
show("login-container", state.session === "signed-out");
show("logout-nav", state.session === "signed-in");
const loginButton = document.getElementById("login-button");
if (state.login.busy) loginButton.setAttribute("aria-busy", "true");
else loginButton.removeAttribute("aria-busy");
document.getElementById("login-form-error").innerText = state.login.error ?? "";
}
async function init() {
await Promise.all(["atirc-post-form", "atirc-messages"].map((name) => customElements.whenDefined(name)));
const form = document.querySelector("atirc-post-form");
const messages = document.querySelector("atirc-messages");
document.getElementById("login-form").onsubmit = (e) => {
e.preventDefault();
cubit.login(e.target.username.value);
};
document.getElementById("logout-nav").onclick = (e) => {
e.preventDefault();
cubit.logout();
};
document.addEventListener("set-channel", (e) => cubit.setChannel(e.detail.channel.trim()));
document.addEventListener("post-line", (e) => cubit.post(e.detail.text));
cubit.subscribe((state, previous) => {
renderPage(state);
form.render(state, previous);
messages.render(state, previous);
});
await cubit.init();
setInterval(() => cubit.state.session === "signed-in" && cubit.refresh(), POLL_MS);
}
document.addEventListener('DOMContentLoaded', init);