~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs-atirc

atirc channels in a browser page: WebRTC to atirc mesh nodes, no server, no token

0
0
main
93 lines · 3.5 KB Raw History

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