Files
dat-thang/docs/cable-interop.md
T
divorce b735900f2e 0.0.002
ddat interop with dat js
cable interop with cabal js
ddat's frontend = dat-thang
cable fe = cable-thang
dillo support based on cel's dillo-dat
bootstrap node
xplatform support

Signed-off-by: divo <418@cryspace.space>
2026-10-19 00:17:02 -04:00

155 lines
8.0 KiB
Markdown

# Cable and Cabal interoperability notes
This document describes the **test-only Cabal/Hypercore interoperability
harness** under `tests/interop/cabal/`. It is kept to compare historical
behavior and is excluded from production builds and runtime paths.
The production `cable` and `cable-thang` clients are C/S7 applications:
Cesspool handles discovery and transport, Sleep handles persistent local
feeds, and S7 represents room events as S-expressions. Cabal CLI and
Hypercore are test targets, not production dependencies.
## Which client to run
The working historical Cabal terminal client is `cabal-cli`. To join a room,
run:
```sh
cabal-cli cabal://<room-key>
```
The `cable` executable also supports local Sleep feed and Cesspool bootstrap
commands. The native Cable chat client is `cable-thang`, using a terminal-style
SDL2 layout inspired by Cabal's TUI. Build with `make ENABLE_SDL2=1`; create an
address in the terminal with `build/linux/cable --new`, then launch the GUI with
`build/linux/cable-thang <cable://address>`. Use `/join NAME`, `/nick NAME`,
`Ctrl+N`, and `Ctrl+P` in the client.
## Cabal behaviors being ported
The Cabal CLI's `/whoami` (also `/key`) displays the local user key, while
`/nick` changes that user's display name. Those are different things: the
user's public key is the stable identity within that room; the nickname is a
readable label published as an `about` record in that user's room feed.
The CLI's usage and commands are listed in the
[cabal-cli README](https://github.com/cabal-club/cabal-cli#commands). The
[cabal-core API](https://github.com/cabal-club/cabal-core#cabalgetlocalkeycb)
documents `getLocalKey()` as the local user's key and documents messages as
records published to user feeds. Cabal creates its local writer feed inside
each room's storage, so a user's key is room-scoped, stable for that room, and
can differ in another room. A room key and its optional `?admin=<key>`
moderation key are separate from each user's feed key. Cabal text records use
`chat/text` with channel and text fields.
## Dat-era Cabal reference
Cabal Core 5.0.1 is a concrete older reference candidate: it was published about
seven years ago, and a 2019 Cabal walkthrough describes the chat as running
over Dat (the walkthrough was later updated for Cabal Core 5.0). The bundled
Dillo Dat tree supplies a nearby protocol reference with Hypercore 7.7.1,
hypercore-protocol 6.12.0, Hyperdrive 9.16.0, and hyperdiscovery 7.1.1. Use
those versions to guide backwards-adaptation; do not treat current Cabal Core
16 or its Hyper:// networking as the target.
The repeatable JS behavior tests remain useful for room identity, nicknames,
channels, and record shapes. To run them against the historical package, point
CABAL_JS_MODULE and CABAL_CLIENT_MODULE at a Cabal Core 5.0.x install, then run
make test-cabal-interop.
## Current C groundwork
- `cable address` accepts room keys with `cabal://`, `cable://`, or
`hyper://`, including a `?admin=<64 hex>` parameter, and prints canonical
`cable://` room addresses while retaining the admin key separately.
- `cable whoami <room-address>` and dat-thang expose a persistent local user
key as a `cable://<64 hex>` user address. Each room gets its own 64-byte
Ed25519 secret at `~/.cable/rooms/<room-key>/user-feed.key`, with owner-only
permissions. The key is stable in that room across restarts and distinct
from the room and admin keys.
- `hyper://` parsing only aliases the key representation; production Cable
does not implement the newer Hypercore stack.
- The library defines a bounded Cable text-message envelope and libsodium
sealed-box encrypt/decrypt helpers.
- dat-thang's left panel is a peer list again. Double-clicking a discovered
peer opens a direct-message pane; messages use the C-only sealed Cesspool
record and can be exchanged between Cable-enabled dat-thang clients.
- `cable-thang` is a native C/S7 room client. Cesspool handles discovery and
authenticated transport, Sleep persists local feeds, and S7 builds signed
room-event S-expressions. The room UI supports room creation, named
channels, nickname changes, and channel cycling. This path is Cable's own
protocol and does not claim Cabal wire interoperability.
### Hypercore feed storage check
The test-only Cable compatibility writer occupies the `room/0` slot used by Cabal Core 5's
`multifeed`, exposes the expected `localname`, and shares the Hypercore tree,
signature, bitfield, key, and data files. Run
`tests/interop/dat/cable_hypercore_compat.ps1` on Windows with WSL and Node installed. It
writes Cabal-shaped nick and chat JSON blocks from C, opens and verifies them
with the bundled Hypercore 7.7.1, appends a JavaScript block, then confirms C
reads that appended block. This verifies the standalone C feed format against
the legacy Hypercore fixture. It is separate from the native Sleep feeds used
by cable-thang.
## Side-by-side regression harness
`tests/interop/cabal/cabal_cable_side_by_side.js` creates a Cabal JS room, publishes a nick
and `chat/text` entry, and verifies that a second Cabal JS instance receives
both through Cabal's live replication stream. It then gives Cable that exact
room address, including `?admin=`, checks address normalization, and checks
that Cable's local user address persists in the room and changes for a second
room. This covers address normalization and the CLI's local identity utility;
it does not exercise cable-thang's network session.
`tests/interop/cabal/cabal_cli_features.js` uses cabal-cli's own `cabal-client` API to create
a room, execute `/nick` and `/join`, traverse joined channels using the same
channel ordering as the CLI's `Ctrl+N` handler, and exchange chat/text entries
between two independently opened Cabal clients over live Hypercore replication.
The C SDL live harness is `tests/interop/cabal/cable_js_c_live.js`; it launches one Cabal
Core JavaScript peer and one headless SDL/C client, then checks peer discovery
and chat in both directions through the Cabal Hypercore feeds. Run it with
`make test-cable-live ENABLE_SDL2=1` after building SDL2 support and installing
Node.js and Cabal Core. The test uses a local Hyperswarm DHT bootstrap node and
separate client UDP ports.
Run it once the historical JS `cabal-core` package and Node are available. The
test invokes Cabal JS directly; the UI command for people is `cabal-cli`:
```sh
make test-cabal-interop CABAL_JS_MODULE=/path/to/cabal-cli/node_modules/cabal-core
make test-cabal-interop CABAL_CLIENT_MODULE=/path/to/cabal-cli/node_modules/cabal-client
```
On Windows with Cable built in WSL, run the same harness with Windows Node and
the installed Cabal package, routing each Cable CLI call through WSL:
```powershell
$env:CABAL_JS_MODULE = "$env:APPDATA\npm\node_modules\cabal-cli\node_modules\cabal-core"
$env:CABLE_BIN = "$PWD\build\cable"
$env:CABLE_RUNNER = 'wsl'
node tests/interop/cabal/cabal_cable_side_by_side.js
```
The harness maps its temporary Cable home directory into WSL for this mode.
This is useful when the WSL distribution has no Node installation; no second
Node runtime is needed.
The normal `make test` runs this harness when it can resolve `cabal-core`; it
prints `SKIP` when the configured Node runtime cannot resolve the optional JS
package. A standalone `make test-cabal-interop` reports the resolution error
directly.
## Compatibility boundary
The upstream Cabal components documented here use Hypercore feed replication
and their own Cabal database/index conventions. Cable's current GUI messages
use a Cesspool transport record and do not enter Cabal feeds, so they are not
yet readable by Cabal JS clients. `/nick` in Cabal appends a `{ type: "about",
content: { name: nick } }` record to the user's room feed; the public user-feed
key remains its unique identity. Cable has not yet implemented that nickname
record in the Cabal message schema.
The next compatibility layer needs the Hypercore transport/session selected
for the deployed Cabal version, feed discovery, Cabal's multiwriter user-feed
model, and its JSON message/index schema. Dat archive wire identifiers and
`dat://` handling remain independent.