simplex-web is a browser-side toolkit for putting SimpleX-style private chat
inside a website without sending chat plaintext through the website's server.
The goal is simple: a site should be able to mount a chat panel, keep local chat
state in the visitor's browser, create SimpleX queues and contacts, encrypt
messages and files in the browser, and talk to browser-compatible SimpleX relay
profiles using ordinary web APIs such as WebSocket and fetch.
This repository exists because the normal upstream SimpleX stack is built around
native clients, native Haskell libraries, and raw TCP/TLS transports. Ordinary
browser JavaScript cannot open raw TCP sockets or inspect the TLS channel-binding
data that native SimpleX clients use. simplex-web therefore implements the
browser-facing pieces directly and refuses to fall back to a website/server
bridge that would see plaintext.
In practical website terms, simplex-web gives you three layers:
- A framework-free Secure Chat UI and local browser session store.
- Browser-native SimpleX protocol building blocks: SMP queue commands, signed transmissions, encrypted agent envelopes, contact setup, ratchets, retries, and encrypted XFTP-style file chunks.
- Browser transport profiles for compatible servers: SMP over binary WebSocket
blocks and upstream-style XFTP web blocks over HTTPS/
fetch. - A first-party adapter that registers those browser-native pieces with
window.SimplexWebTransportfor website integration. - A queue-server transport router, because native SimpleX peers can place the reply queue on a different SMP relay than the original contact address.
It is independent of SimpleX while implementing the same protocol concepts. SimpleX, SimpleX Chat, and related marks belong to their respective owners.
This is the real browser-native simplex-web codebase, not the old placeholder
bridge:
- No SimpleX Chat command API adapter is shipped.
- No loopback file bridge is shipped.
- No mock chat transport is shipped.
- No plaintext website/server bridge is shipped.
- The default public transport facade fails closed until a browser-native adapter is registered.
- A first-party browser-native adapter is shipped for the public facade; it wires SMP WebSocket, durable browser state, the contact client, and optional XFTP web file transfer.
What works locally today:
- Browser-native SMP encoding, signing, transport blocks, handshakes, and queue command helpers.
- Browser contact creation, invitation URI creation, encrypted contact requests, reply queues, encrypted accept confirmations, queue securing, ACKs, active contact messaging, requester-first post-accept delivery, durable ACK retry, retry scheduling, and durable browser state.
- Browser-owned double-ratchet message encryption.
- Encrypted XFTP-style file chunking, upload/download sequencing, verified
reassembly, and an HTTPS/
fetchencrypted chunk transport. - Upstream-style XFTP web hello, identity-proof verification, padded handshake, binary command blocks, PING, authenticated file-command wrappers, file-level envelope encryption, deterministic chunk planning, serializable file descriptions, verified file upload/download assembly, and transport-encrypted download chunks.
- Binary SMP-over-WebSocket transport for browser-compatible SMP servers.
- A public website adapter that can register with
window.SimplexWebTransportand send/receive through the browser contact client, including encrypted text, encrypted file descriptors, and encrypted read receipts. - Per-queue SMP transport routing, so SKEY/SEND/ACK/DEL commands go to the SMP relay that owns that specific queue instead of assuming one relay per contact.
- A native SMP TLS byte relay for local/server-side interop with existing SMP relays. It forwards encrypted SMP blocks only; it is not a SimpleX Chat API bridge and does not receive chat plaintext.
- Local live Owl Native text interop through contact request, native accept,
reply-queue confirmation,
contactConnected, broker-accepted SEND, and an OwlnewChatItemsevent for the delivered text. - Live Firefox-to-Owl Native Secure Chat file sending on the production Secure
Chat deployment: browser XFTP upload, ratcheted native file invitation, native
x.msg.file.descrbatch delivery, and Owl-side XFTPrcv_invitationstorage. - Deterministic native Owl-style bidirectional text and receipt interop coverage:
the browser decrypts a post-accept Owl
A_MSG, returns an encrypted nativeA_RCVD, and verifies the receipt hash against the Owl-side ratchet state. - Native Owl-style file invitation coverage: browser XFTP uploads are announced
as native
x.msg.newfile invitations batched withx.msg.file.descrYAML parts over the ratcheted Owl queue. - Local deterministic wire-format vectors, loopback WebSocket/fetch transport tests, skipped-by-default live interop tests, fuzz/property tests, browser rendering tests, and Haskell/WASM smoke checks.
What is still required before claiming full production SimpleX browser-client interoperability:
- More browser-matrix evidence beyond the current Firefox live path.
- Live Owl-to-browser receive, native receipts, and native file attachment receive against a compatible XFTP server; those paths are covered in deterministic protocol tests, while the production live pass currently proves browser-to-Owl text and file sending for the Secure Chat form.
- Reviewed non-loopback browser-profile SMP and XFTP servers.
- Passing live compatibility runs against those servers.
- Upstream-certified SimpleX protocol vectors for every encoded layer.
- A security review outside this Codex Desktop environment.
The current tree includes a handwritten browser-native SMP protocol core in
src/browser-smp-core.mjs, SimpleX agent-envelope/queue lifecycle helpers in
src/browser-simplex-agent.mjs, a queue-level client orchestrator in
src/browser-simplex-client.mjs, durable browser state in
src/browser-simplex-store.mjs, browser-owned double-ratchet state in
src/browser-simplex-ratchet.mjs, a contact client in
src/browser-simplex-contact-client.mjs, retry scheduling in
src/browser-simplex-scheduler.mjs, a first-party facade adapter in
src/browser-simplex-web-transport-adapter.mjs, XFTP chunk/manifest helpers in
src/browser-xftp-core.mjs, an encrypted-chunk XFTP client in
src/browser-xftp-client.mjs, an HTTPS/fetch encrypted-chunk transport in
src/browser-xftp-http-transport.mjs, an upstream-style XFTP web client in
src/browser-xftp-web-client.mjs, reviewed browser SMP/XFTP server profile
validation in src/browser-smp-server-profile.mjs and
src/browser-xftp-server-profile.mjs, and a binary SMP-over-WebSocket browser
transport profile in src/browser-smp-websocket-transport.mjs.
simplex-web was made by AI and was adversarially tested as much as
conceivably possible by Codex Desktop with ChatGPT 5.5 in the local and live
environment described in docs/SECURITY_REVIEW.md.
A website can use simplex-web in the same way it would use any other
front-end library:
- Mount the default chat UI, or build its own UI on top of the lower-level modules.
- Store drafts, recent messages, contacts, queues, ratchets, and pending work in browser-local storage.
- Register the first-party browser-native transport adapter with
window.SimplexWebTransport. - Use browser-compatible SMP/XFTP server profiles for relay and file storage.
- Provide a per-server SMP transport factory when contacts can reply from a different SMP relay than the original contact link.
The important boundary is that the website server should serve static assets and application pages. It should not receive chat plaintext, file plaintext, or file root keys. Messages are encrypted before they leave the browser. XFTP storage receives encrypted chunks only; the file root key is delivered through the ratcheted chat layer.
- Ships a plain-JavaScript default chat UI that can be embedded into a hosted site and refuses network attachment autoloads from imported history.
- Ships a plain-JavaScript browser session store so hosted sites can preserve a chat thread locally without pushing plaintext history back into a server database.
- Ships a closed-by-default browser transport API boundary at
window.SimplexWebTransport, so host sites can call a stable API without silently falling back to a plaintext website bridge. - Ships browser-native SMP protocol primitives for binary encodings, queue URIs, command codecs, signed transmissions, transport blocks, handshakes, and browser-compatible cryptographic helpers.
- Ships browser-native agent helpers for SimpleX client-message envelopes, queue creation state, queue-scoped recipient commands, and initial sender confirmation messages.
- Ships a low-level queue client orchestrator over an abstract SMP transport.
- Ships durable browser queue/contact/ratchet/pending-task storage with bounded visible lists, poisoned-list recovery, and full-scan cleanup for privacy-sensitive deletes.
- Ships browser-owned double-ratchet encryption with skipped-message-key handling.
- Ships a contact lifecycle client that creates invitation URIs, sends and accepts encrypted contact requests, exchanges encrypted accept confirmations over requester reply queues, persists contacts, sends and receives ratcheted messages, XFTP file descriptors, and read receipts, acknowledges received queue messages with durable ACK retry and duplicate-redelivery suppression, downloads received encrypted files, queues failed sends as already-ratcheted packet retry tasks, sends remote SMP
DELfor browser-owned inbox queues before optional local deletion, and scrubs contact queue/ratchet/received-fingerprint/retry records on delete. - Ships bounded retry scheduling for offline/transient transport failure.
- Ships a first-party
window.SimplexWebTransportadapter for browser-native SMP WebSocket contact messaging and optional XFTP web file transfer. - Ships per-queue SMP transport routing so native reply queues on different relays are handled without a plaintext bridge.
- Ships XFTP-style encrypted chunk manifests, an encrypted-chunk upload/download client, tamper detection, and download assembly.
- Ships a browser XFTP-over-HTTPS/fetch transport for encrypted chunk upload, download, and deletion.
- Ships an upstream-style browser XFTP web client for binary HTTPS/fetch hello, identity proof verification, padded handshake, PING, authenticated FNEW/FPUT/FGET/FDEL command wrappers, file-level envelope encryption, deterministic chunk planning, serializable encrypted-file descriptions, full encrypted file upload/download/delete helpers, and transport-encrypted FGET body decryption.
- Ships production browser SMP server profile validation for binary frames, origin policy, padding, and session-binding requirements.
- Ships production browser XFTP server profile validation for encrypted chunk storage endpoints.
- Ships a binary SMP-over-WebSocket transport profile for browser-reachable SMP servers that expose one padded SMP block per WebSocket frame.
- Includes Haskell-to-wasm validation slices so browser-targeted Haskell can be tested honestly.
- Uses the Secure Chat interface from
nostr-blogas the default/example presentation layer. - Keeps the browser surface framework-free so it can be mounted in existing sites without a build step.
Not shipped:
- A SimpleX Chat command API adapter.
- A loopback file bridge.
- A mock chat transport.
- A plaintext website/server bridge.
- Direct JavaScript transport to existing raw TCP/TLS SMP/XFTP servers. Browsers do not expose raw TCP sockets, server certificate bytes for SimpleX server-identity pinning, or RFC5929
tls-uniquechannel binding to JavaScript, so a production browser transport needs a browser-compatible SMP server transport profile rather than a pretend downgrade. - A plaintext relay. The native TLS relay that is included for interop forwards encrypted SMP protocol blocks only and does not implement the SimpleX Chat command API.
- Checked-in Haskell/WASM build output.
src/default-chat.js: default/example chat renderer and DOM mount helper.src/default-chat.css: default/example chat styles extracted from the currentnostr-blogcontact chat.src/session-store.js: bounded browser-local persistence helpers for per-user secure-chat session state.src/transport.js: browser transport facade that fails closed until a browser-native adapter is registered.src/browser-smp-core.mjs: browser-native SMP protocol primitives and crypto helpers.src/browser-simplex-agent.mjs: browser-native SimpleX agent envelope and queue lifecycle helpers.src/browser-simplex-client.mjs: queue-level browser SimpleX client orchestrator over an abstract SMP transport.src/browser-simplex-contact-client.mjs: contact lifecycle, active contact sends, ratchet persistence, and retry enqueueing.src/browser-simplex-ratchet.mjs: browser-owned double-ratchet state and message encryption.src/browser-simplex-scheduler.mjs: bounded retry scheduling for pending browser work.src/browser-simplex-store.mjs: durable browser queue, contact, ratchet, and pending-task records.src/browser-simplex-web-transport-adapter.mjs: first-party adapter that registers the browser contact client withwindow.SimplexWebTransport.src/browser-smp-server-profile.mjs: production browser SMP server profile validation.src/browser-smp-websocket-transport.mjs: browser binary WebSocket transport profile for padded SMP blocks.src/browser-smp-native-tls-relay.mjs: Node-side encrypted SMP byte relay for local/server-side interop with existing native TLS SMP relays.src/browser-xftp-core.mjs: encrypted XFTP-style file chunking, manifests, and reassembly checks.src/browser-xftp-client.mjs: browser XFTP encrypted chunk upload/download sequencing over a reviewed server boundary.src/browser-xftp-http-transport.mjs: browser XFTP-over-HTTPS/fetch encrypted chunk transport.src/browser-xftp-web-client.mjs: upstream-style browser XFTP web handshake, identity proof, binary command transport, command wrappers, file envelope encryption, chunk planning, serializable descriptions, upload/download/delete helpers, and transport chunk decryption.src/browser-xftp-server-profile.mjs: production browser XFTP server profile validation.tests/default-chat.test.js: Node unit tests for HTML contract, escaping, and status mapping.tests/interop-vectors.test.mjs: deterministic local interoperability-vector checks for SMP, agent envelopes, and XFTP chunks.tests/vectors/simplex-web-interop-v1.json: checked hex fixtures for local wire-format drift detection.tests/session-store.test.js: Node unit tests for bounded local persistence and key normalization.tests/transport.test.js: Node unit tests for the closed transport contract and adapter normalization.tests/browser-smp-core.test.mjs: Node unit and fuzz tests for the handwritten SMP protocol core.tests/browser-simplex-agent.test.mjs: Node unit and fuzz tests for browser-native agent envelopes and queue lifecycle helpers.tests/browser-simplex-client.test.mjs: Node tests for queue-level client orchestration and fail-closed response handling.tests/browser-simplex-contact-client.test.mjs: Node tests for contact state, ratcheted sends, and retry enqueueing.tests/browser-simplex-e2e-broker.test.mjs: in-process browser-profile SMP broker E2E for two clients, ratcheted messages, ACKs, and forged-signature rejection.tests/browser-simplex-ratchet.test.mjs: Node tests for double-ratchet send/receive, skipped messages, and tamper rejection.tests/browser-simplex-scheduler.test.mjs: Node tests for retry timing and completion.tests/browser-simplex-store.test.mjs: Node tests for durable store serialization and hostile keys.tests/browser-simplex-web-transport-adapter.test.mjs: Node tests for the first-party facade adapter and in-process browser-contact E2E send/receive.tests/browser-smp-server-profile.test.mjs: Node tests for browser SMP server profile downgrade rejection.tests/browser-smp-websocket-transport.test.mjs: Node tests for the binary browser WebSocket SMP transport profile.tests/browser-smp-websocket-live.test.mjs: Node loopback WebSocket server test for real browser transport framing, handshake, send, and receive.tests/live-interop.test.mjs: skipped-by-default live SMP/XFTP interoperability harness for reviewed non-loopback endpoints.tests/browser-xftp-core.test.mjs: Node tests for XFTP chunk encryption, manifest verification, and tamper rejection.tests/browser-xftp-client.test.mjs: Node tests for encrypted XFTP upload/download, deletion, and tamper rejection.tests/browser-xftp-http-transport.test.mjs: Node loopback HTTP/fetch test for encrypted XFTP chunk upload, download, and deletion.tests/browser-xftp-web-client.test.mjs: Node loopback HTTP/fetch tests for XFTP web identity proof, PING, authenticated file commands, encrypted file envelopes, description serialization, upload/download/delete assembly, transport chunk decryption, and tamper rejection.tests/browser-xftp-server-profile.test.mjs: Node tests for browser XFTP server profile downgrade rejection.tests-simplex-web-runtime.sh: Wizardry-style shell wrapper around the focused runtime checks.haskell/src/Simplex/Web/Smoke.hs: first Haskell/WASM smoke module exported as a reactor.haskell/src/Simplex/Web/Core.hs: first Haskell-owned chat-state core slice with browser-callable exports.tests/haskell-smoke.test.cjs: Node/WASI runtime checks for the compiled reactor exports.tests-haskell-wasm-runtime.sh: Wizardry-style shell wrapper that compiles the Haskell smoke module and executes the runtime checks.tests/haskell-core.test.mjs: Node/WASI runtime checks for the string-capable Haskell chat core.tests-haskell-core-runtime.sh: Wizardry-style shell wrapper that compiles the Haskell chat core, runs post-link JSFFI glue generation, and executes the runtime checks.examples/haskell-smoke.html: browser smoke page for the compiled Haskell reactor.examples/haskell-core-chat.html: browser example that mounts the default Secure Chat UI against the Haskell core.docs/ARCHITECTURE.md: current boundaries and next protocol steps.docs/HASKELL_BROWSER_STATUS.md: current Haskell/browser status and why the UI ships first.docs/SECURITY_REVIEW.md: adversarial review scope, findings, coverage, and release posture.docs/LIVE_INTEROP.md: live SMP/XFTP endpoint contract and environment variables.
npm testOptional browser and Haskell/WASM checks:
npm run test:browser
npm run test:live
./tests-haskell-wasm-runtime.sh
./tests-haskell-core-runtime.shnpm run test:live skips by default. Set the environment variables described
in docs/LIVE_INTEROP.md to run it against reviewed browser-profile SMP/XFTP
servers.
The Haskell/WASM checks require wasm32-wasi-ghc. Source the
ghc-wasm-meta environment first when it is installed outside the default shell
path.
Load src/transport.js to expose window.SimplexWebTransport.
By default it is intentionally unavailable:
window.SimplexWebTransport.getStatus();
// {
// available: false,
// transport_status: "browser-native-unavailable",
// transport_error: "browser-native simplex-web transport is not available"
// }
await window.SimplexWebTransport.sendText({ contact_id: "contact-1", text: "hello" });
// rejects with code SIMPLEX_WEB_TRANSPORT_UNAVAILABLE
await window.SimplexWebTransport.deleteContact({ contact_id: "contact-1" });
// rejects with code SIMPLEX_WEB_TRANSPORT_UNAVAILABLE until an adapter is registeredThe first-party adapter can register itself with the facade:
import { registerSimplexWebTransportAdapter } from "simplex-web/browser-simplex-web-transport-adapter";
registerSimplexWebTransportAdapter({
namespace: "site-chat",
smp: {
url: "wss://smp.example.test/",
keyHash: "BASE64URL_OR_HEX_HASH"
},
xftp: {
url: "https://xftp.example.test/",
keyHash: "BASE64URL_OR_HEX_HASH"
}
});
await window.SimplexWebTransport.connect();
await window.SimplexWebTransport.sendText({
contact_id: "alice",
text: "hello",
client_message_id: "local-message-1"
});
// Poll receives inbound messages. For messages sent by simplex-web peers, the
// adapter automatically sends an encrypted read receipt unless disabled.
await window.SimplexWebTransport.getMessages({ contact_id: "alice" });
// The sender can check whether a message has been read after the peer's
// encrypted receipt arrives.
await window.SimplexWebTransport.getMessageStatus({
contact_id: "alice",
message_ref: "local-message-1"
});After registration, deleteContact() asks the adapter to remove the contact's
browser-owned SMP inbox queue remotely before scrubbing local queue and ratchet
state. Pass { local_only: true } for an explicit local-only privacy scrub.
Host pages may also register their own browser-native adapter with the same contract:
window.SimplexWebTransport.registerBrowserTransport({
getStatus() {
return { transport_status: "direct-browser-smp", transport_error: "" };
},
async connect(params) {
// Initialize browser-native durable state, keys, contacts, and queues.
},
async sendText(message) {
// Send without a plaintext server bridge.
// message: { contact_id, text, client_message_id }
return { message_ref: "browser-message-ref" };
},
async sendReadReceipt(message) {
// Send an encrypted receipt for message.message_ref or
// message.read_message_ref.
return { message_ref: "receipt-ref", read_message_ref: message.message_ref };
},
async disconnect() {}
});The facade keeps integration code stable while preserving secure failure when no browser-native transport is present.
Import the protocol primitives as ESM:
import {
encodeSignedTransmission,
encodeTransportBlock,
generateEd25519KeyPair,
parseSmpQueueUri
} from "simplex-web/browser-smp-core";
const queue = parseSmpQueueUri("smp://...");
const senderKey = generateEd25519KeyPair();
const tx = encodeSignedTransmission(4, sessionIdBytes, {
privateKey: senderKey.secretKey,
corrId: new TextEncoder().encode("corr-1"),
queueId: queue.queueId,
command: {
type: "SEND",
flags: { notification: false },
body: encryptedMessageBytes
}
});
const block = encodeTransportBlock(4, [tx]);This is protocol-core code. The higher-level modules own contacts, ratchets, durable state, retry scheduling, and XFTP-style file chunks.
The next agent layer can be imported separately:
import {
completeNewQueueRequest,
prepareNewQueueRequest,
prepareRecipientCommand
} from "simplex-web/browser-simplex-agent";
const pending = prepareNewQueueRequest({
sessionId,
corrId,
rcvSignSeed,
rcvDhSeed
});
const queue = completeNewQueueRequest(pending, idsBrokerMessage);
const sub = prepareRecipientCommand(queue, {
sessionId,
corrId: new TextEncoder().encode("sub-1"),
command: { type: "SUB" }
});The queue-level client orchestrator wires the helper layer to any compatible SMP transport:
import { createBrowserSimplexClient } from "simplex-web/browser-simplex-client";
const client = createBrowserSimplexClient({ transport: smpTransport });
const queue = await client.createQueue({ label: "inbox" });
await client.subscribeQueue("inbox");
await client.acknowledgeMessage(queue, msgIdBytes);The browser WebSocket transport profile is the first network-facing browser primitive:
import { connectBrowserSmpWebSocketTransport } from "simplex-web/browser-smp-websocket-transport";
const smpTransport = await connectBrowserSmpWebSocketTransport({
url: "wss://smp.example.net/smp",
keyHash: expectedServerIdentityHashBytes
});
smpTransport.sendSignedTransmissions([sub]);
const incoming = await smpTransport.receiveSignedTransmissions({ kind: "broker" });This transport only moves binary SMP blocks. It does not call the SimpleX Chat command API. Because browser JavaScript cannot inspect raw TLS channel binding, this module is explicitly a browser WebSocket profile for compatible SMP servers, not a claim that existing raw TCP/TLS SMP servers can be reached directly from ordinary browser JavaScript.
The contact client combines the queue client, durable store, retry scheduler, and ratchet helpers:
import { createBrowserSimplexContactClient } from "simplex-web/browser-simplex-contact-client";
import { createBrowserSimplexStore } from "simplex-web/browser-simplex-store";
const aliceContacts = createBrowserSimplexContactClient({
client: aliceClient,
store: createBrowserSimplexStore({ namespace: "alice-site-chat" })
});
const bobContacts = createBrowserSimplexContactClient({
client: bobClient,
store: createBrowserSimplexStore({ namespace: "bob-site-chat" })
});
const invitation = await bobContacts.createInvitation({ id: "alice", corrId: "bob-new-1" });
await aliceContacts.requestContact("bob", bobContacts.invitationUri("alice"), { corrId: "alice-req-1" });
await bobContacts.receiveContactRequest("alice", { keyCorrId: "bob-key-1", ackCorrId: "bob-ack-1" });
await aliceContacts.receiveContactAccept("bob", { keyCorrId: "alice-accept-key-1", ackCorrId: "alice-accept-ack-1" });
await aliceContacts.sendText("bob", "hello");
const received = await bobContacts.receiveNext("alice", { ackCorrId: "bob-msg-ack-1" });Failed sends are persisted as encrypted packet retry tasks, not chat plaintext
retry tasks. Contact sends require active contact state, a ratchet, and an
outbound queue; otherwise they fail closed. deleteContactEverywhere() first
sends authenticated SMP DEL commands for browser-owned inbox queues, then
does the local scrub. If the remote delete fails, local queue credentials are
preserved so the operation can be retried. deleteContact() is the local-only
privacy scrub: it removes durable inbox/outbox queue records, ratchet state,
received-message fingerprints, and pending retry payloads before leaving only a
small tombstone. File sends first upload encrypted XFTP
chunks, then ratchet-send the manifest and file root key as a contact payload:
const sent = await contacts.sendFile("alice", fileBytes, { name: "notes.txt" });Inbound queue messages decrypt the server-wrapped received body, decrypt the contact ratchet packet, persist the updated ratchet, and acknowledge the SMP message. The client stores only a message-id/body fingerprint for received messages, so duplicate broker redelivery can be ACKed without replaying the ratchet or returning plaintext twice:
const received = await contacts.receiveNext("alice", { ackCorrId: "ack-1" });
if (received.file) {
const fileBytes = await contacts.downloadReceivedFile(received);
}Retryable failed sends can be drained explicitly:
await contacts.drainDueRetries();The E2E broker test exercises two browser clients through queue creation,
recipient KEY, signed SEND, encrypted server-wrapped MSG, ratchet
decryption, and ACK. It is still an in-process browser-profile harness, not a
claim of interoperability with existing raw TCP/TLS SimpleX servers.
import { createXftpUpload, assembleXftpDownload } from "simplex-web/browser-xftp-core";
import { createBrowserXftpClient } from "simplex-web/browser-xftp-client";
import {
connectBrowserXftpWebClient,
encodeXftpWebFileDescription,
downloadXftpWebFile,
pingXftpWeb,
uploadXftpWebFile
} from "simplex-web/browser-xftp-web-client";
const upload = createXftpUpload(fileBytes, { name: "notes.txt" });
const fileBytesAgain = assembleXftpDownload(upload.manifest, upload.chunks, upload.rootKey);
const client = createBrowserXftpClient({ server, profile });
const sent = await client.uploadFile(fileBytes, { name: "notes.txt" });
const received = await client.downloadFile(sent.manifest, sent.rootKey);
const xftpWeb = await connectBrowserXftpWebClient({
url: "https://xftp.example.test/",
keyHash
});
await pingXftpWeb(xftpWeb);
const webUpload = await uploadXftpWebFile(xftpWeb, fileBytes, { fileName: "notes.txt" });
const descriptorText = encodeXftpWebFileDescription(webUpload.recipientDescription);
const webDownload = await downloadXftpWebFile(xftpWeb, descriptorText);The older browser-xftp-core and browser-xftp-client modules are local
encrypted-chunk helpers used by the contact-file workbench and tests. They keep
plaintext file bytes and root keys on the browser/client side.
The newer browser-xftp-web-client module is the upstream-style browser XFTP
web transport: binary fetch requests, web challenge, server identity proof,
padded handshake, PING, authenticated file-command wrappers, and
transport-encrypted download chunk verification. It also builds the file-level
XFTP envelope, plans deterministic encrypted chunks, serializes file
descriptions into a strict text form for ratcheted delivery, rejects malformed
or wrong-server descriptions before any network side effect, uploads and
downloads those chunks through FNEW/FPUT/FGET, and deletes uploaded chunks
through FDEL. That is the path to use for real browser-profile XFTP server
interoperability.
The repository intentionally does not track generated outputs such as build/,
node_modules/, coverage output, logs, or packed .tgz files. A push-ready 1.0
tree should have git status --short --branch clean after running:
npm test
npm run test:browser
npm run test:haskell
npm audit --audit-level=moderate
npm pack --dry-run --jsonsimplex-web is licensed under the GNU Affero General Public License version 3
only (AGPL-3.0-only). See LICENSE.
SimpleX, SimpleX Chat, and related marks belong to their respective owners. This project is independent of SimpleX while implementing the same protocol.