import { templated } from 'atlibs/component/index.js' const Base = await templated(new URL('./webrtc-connect.html', import.meta.url)); const BUSY = ["finding", "offering", "answering", "connecting"]; // Emits find-guest {receipt, tag}, create-offer and wait-answer; renders the cubit's state. customElements.define('webrtc-connect', class extends Base { connectedCallback() { super.connectedCallback(); this.querySelector(".find").onsubmit = (e) => { e.preventDefault(); this.dispatchEvent(new CustomEvent("find-guest", { bubbles: true, detail: { receipt: e.target.receipt.value, tag: e.target.tag.value } })); }; this.querySelector(".offer-button").onclick = () => this.dispatchEvent(new CustomEvent("create-offer", { bubbles: true })); this.querySelector(".ssh-key-button").onclick = () => this.dispatchEvent(new CustomEvent("ssh-key", { bubbles: true })); this.querySelector(".answer-button").onclick = () => this.dispatchEvent(new CustomEvent("wait-answer", { bubbles: true })); } render(state) { const busy = BUSY.includes(state.phase); this.querySelector(".find-button").toggleAttribute("aria-busy", state.phase === "finding"); this.querySelector(".guest").textContent = state.guest ? `guest key ${state.guest.key}\nfingerprint ${state.guest.fingerprint}` : ""; const offer = this.querySelector(".offer-button"); offer.disabled = !state.guest || busy || state.phase === "open"; offer.toggleAttribute("aria-busy", state.phase === "offering"); this.querySelector(".signal").style.display = state.signal ? "block" : "none"; this.querySelector(".signal-json").value = state.signal ? JSON.stringify(state.signal) : ""; const answer = this.querySelector(".answer-button"); answer.disabled = state.phase !== "offered"; answer.toggleAttribute("aria-busy", state.phase === "answering" || state.phase === "connecting"); const { authorizedKey, hostKey, pinned, error } = state.ssh; this.querySelector(".ssh").textContent = [authorizedKey, hostKey && `host key ${hostKey.type} ${hostKey.fingerprint} ${pinned ? "(in vm.hostKeys)" : "(not in vm.hostKeys: the guest is pinned by its DTLS fingerprint)"}`, error].filter(Boolean).join("\n"); this.querySelector(".phase").textContent = `phase: ${state.phase}`; this.querySelector(".error").textContent = state.error ?? ""; } });