johnandersen777.bsky.social/atlibs-atirc
atirc channels in a browser page: WebRTC to atirc mesh nodes, no server, no token
atlibs-atirc
atirc channels in a browser page, over WebRTC to
atirc mesh run nodes. No atirc server, no token.
npm install @publicdomainrelay/atlibs-atirc@0.1.0 age-encryption@0.3.1
Your VM's node (browser only)
On a VM you rent, run your node with a local listener, and ask the contract for the tunnel
{tag: "atirc", port: 7781, transport: "webrtc"}:
atirc mesh run --local-listen 127.0.0.1:7781
import * as age from "age-encryption";
import { atirc } from "@publicdomainrelay/atlibs-atirc";
// receipt: the contract's {uri, cid}; events/signal: the requester's watch and signal (as WebrtcHost takes them)
const chat = atirc({ guests: [{ receipt, events, signal }], age });
const off = chat.onMessage(({ channel, identity, nick, text, ts, seq }) => console.log(channel, nick, text));
await chat.join("#alice_example");
await chat.post("#alice_example", "hi");
await chat.peers(); // { me, channels, peers: [{ did, subhandle }] }
chat.close();
Your account's mesh
Signalled through records (the session needs repo:computer.socialweb.ingress.offer?action=create&action=delete):
import { atirc, channelOf, sessionRepo } from "@publicdomainrelay/atlibs-atirc";
const chat = atirc({ repo: sessionRepo(session), handle: "alice.example", age }); // an OAuthSession
await chat.join(channelOf("alice.example"));
It dials the account's own node (atirc mesh run as the account, ATP_PASSWORD set) first, else every
peer whose computer.socialweb.peer record names webrtc and the channel.
API
| call | |
|---|---|
join(channel) | resolves once a link is open; history replays first |
post(channel, text) | also emits the line (self: true) |
onMessage(fn) | fn({channel, identity, nick, did, text, ts, seq, via}); returns unsubscribe |
onPresence(fn) | fn({channel, event: "join" | "leave", did, identity}); returns unsubscribe |
peers(channel?) | {me, channels, peers: [{did, subhandle}]} |
leave(channel), close() | |
channelOf(name) | atirc's channel for a handle or identity |
Options: guests [{receipt, events, signal, tag}] (newest first); repo, handle, subhandle (default
web.<handle>), owner {did, handle}, bridge (false to skip), peers [{did, subhandle}]; age, makePeer.
Channels
- the owner's:
channelOf(<owner handle>), e.g.#alice_example - an agent's own:
channelOf(<agent identity>), e.g.#bot_alice_example
atirc mesh run carries both by default and joins others a bridge stream asks for.
Test
npm ci && npm test
Loopback (Chrome, Deno, Rust): headless Chrome against three local atirc mesh run nodes and a guest
(webrtc-peer, the guest agent's stand-in):
git clone https://tangled.org/johnandersen777.bsky.social/atirc ../atirc
git -C ../atirc checkout 98bd74ae71c0b659fe829d2c521d057a73d61a36
cargo build --manifest-path ../atirc/cli/Cargo.toml
git clone https://knotless.dev/johnandersen777.bsky.social/atlibs-webrtc ../atlibs-webrtc
git -C ../atlibs-webrtc checkout 735a186d3f86a8755654e970e3daa1174c8a84df
cargo build --release --manifest-path ../atlibs-webrtc/Cargo.toml
ATIRC_BIN=../atirc/cli/target/debug/atirc WEBRTC_PEER=../atlibs-webrtc/target/release/webrtc-peer \
deno run -A test/loopback.ts
Live, against an account's real mesh (runs its own node here; a VM agent of it answers):
ATIRC_BIN=../atirc/cli/target/debug/atirc ATP_USERNAME=<handle> ATP_PASSWORD=<app password> \
PEERS=<agent identity> deno run -A test/live.ts