尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
Pombo Web Client - Vertically integrated client and reference implementation for the open Pombo Protocol.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Pombo is a peer-to-peer messaging and social media app, built on open infrastructure instead of a company's servers. Your people. Your rules. Your money.
This is the web client, also installable as a PWA, live at app.pombo.cc. It is the reference implementation of the Pombo wire protocol.
· Website: pombo.cc · App: app.pombo.cc · Docs: docs.pombo.cc
The client is a static site. It has no backend of its own, and everything it reads comes from public infrastructure:
| What | Where it comes from |
|---|---|
| Message transport | Streamr network |
| Channel ownership and access | Polygon contracts |
| Channel discovery and permissions | Streamr subgraph on The Graph |
| History | Storage nodes, chosen per channel |
Every one of those endpoints is replaceable by the user, in Settings: Polygon RPCs are an ordered list you enable and reorder, with a custom slot; The Graph runs on your own API key if you supply one; storage providers are your choice per channel. The project operates two things, both optional and both replaceable: the default storage cluster, and the push relay, which is blind by construction.
Four streams derived from one base ID, five when membership is contract-backed. Protocol constants, not configuration.
| Stream | Storage | Carries |
|---|---|---|
-1 message | yes | conversation, edits and deletes, moderator deltas, file chunks |
-2 ephemeral | no | presence, typing, peer-to-peer media signalling |
-3 admin | yes | moderation snapshot, channel image, password challenge. Owner publishes, everyone reads |
-4 keys | yes | key announces, requests and answers, the sealed member roster. Contract-backed channels only; members publish and read |
-5 interactions | yes | reactions |
DM inboxes use the same -1 layout with extra partitions for sync and invites,
so one inbox serves everything.
Streamr streams are broadcast, not memory. History exists because a storage node retains it, and the channel owner chooses which.
| Model | What it is | How you get it |
|---|---|---|
| Pombo | The cluster the project runs | Default, plug and play |
| Third-party | Any storage provider someone else runs | Paste its address into the channel's Storage panel |
| Self-hosted | Your own node or cluster | Run it, register it, paste its address |
All three are the same mechanism: "Pombo" is just a preset address, with no privileged path for the project's cluster. A custom provider is validated before it is accepted, since a browser cannot read from a node that publishes no HTTPS URL.
They combine. A channel can hold several providers at once, added or removed on-chain at any point in its life, so its history can have independent copies under different operators and no single one can erase it. Reads rotate across every healthy URL a provider publishes, and one that keeps failing is dropped from the rotation for the session.
The node software the project publishes and runs, pombo-storage-node, is a build of the Streamr storage node that validates every message before storing it, serves the history of private channels and inboxes only to a request signed by someone with current access, stamps each message with the time it arrived, deletes on request from whoever can prove authorship or moderates the channel, and enforces retention itself. The client detects those capabilities per provider and works against a plain Streamr node without them.
Retention is per stream, 1 to 365 days. Artifacts that are written once and then only read (moderation state, channel image, password challenge) are republished by the owner before their retention expires, so bans and pins do not quietly vanish.
Encryption protects what you said; this is about who can see that it was you. A channel session publishes under a throwaway keypair, created on first publish, never persisted, discarded when you leave, and your account travels as a signed proof inside the payload: in the clear in open channels, inside the encryption everywhere else. DMs go further, with the sender sealed inside the envelope so that even the recipient's inbox names nobody.
Contract-backed channels are the one place the throwaway identity does not apply, because anything the network checks has to be readable by non-members. The creator picks once, at creation, whether authorship is Sealed (everyone publishes under one shared key; members attribute, the network cannot) or Visible (your account signs each message and the network validates it against the contract). Sealed is the default; the choice is shown on the channel's card in Explore. The full table of who learns your account in each context is in the docs: Publisher identity.
There is no per-channel anonymous toggle. Taking part unlinked means a second account, which is free, instant and completely separate.
Content is encrypted with a channel-wide epoch key, distributed on -4.
The admin announces each key by its hash and never the key itself; any member
holding it can answer a request, and a key is adopted only if it hashes to
what was announced. Requests and answers are stored, so a request made when
nobody is online is answered later by whoever comes back. Removing or banning
a member rotates the key at once. Sealed channels carry two more keys on the
same stream, a shared publish key and an interactions key, which is what lets
a read-only channel have reactions from members who cannot post. The protocol
is described in the docs: Encryption.
Channels
| Type | Access rule | Read | Write |
|---|---|---|---|
| Open | Streamr permissions | Public | Public |
| Protected | A shared password | Public stream, encrypted content | Anyone with the password |
| Closed | PomboGate contract, owner allowlist | Members | Members |
| Gated | PomboGate contract, token or NFT holding | Holders | Holders |
| Paid | PomboGate contract, subscription paid to the owner | Subscribers | Subscribers |
Those two columns are enforced by different layers, and it is worth knowing which:
| What holds the line | |
|---|---|
| Write | The network and the storage node, in Visible: every message is validated against the contract at ingest, so selling the token, letting a subscription lapse or being banned cuts writing on any node. In Sealed the network only sees the shared publish key and never consults the contract. |
| Read | Key distribution: no key ever reaches a non-member. On a Pombo storage node, stored history of a private channel is served only to a signed request from someone the gate accepts right now. |
| History | The storage node, which validates signature and publish permission before storing, and the client, which verifies signer and key generation on read. |
PomboGate clone per channel, minted on Polygon. It answers a single
question, "does this signer have access right now?", to the network at
ingest, to storage nodes on read, and to our clients before they hand over a
key, so none of them can disagree about who is in.Messaging
youtube-nocookie.Moderation
-3, which only they can
write. A moderator publishes signed deltas on the message stream instead, and
every client folds them onto the snapshot. The owner later absorbs them into
a snapshot of their own, and that is what makes a moderator's decisions
outlive the moderator.Media and files
Identity
Sync and backup
Discovery
@streamr/sdk, ethers 6, dompurify, qrcode.npm run test:run runs the full suite. Three kinds carry most
of the weight:
Built and tested on Node.js 24.
npm install
npm run build # CSS + JS bundles
npm run watch # rebuild on change
npm run serve # build and serve locally
npm run build:minify # production bundles
npm run test:run # full suite
npm run test:coverage # with V8 coverage
src/js/
├── streamConstants.js the stream layout, as protocol constants
├── streamr.js, streamr/ Streamr client: publish, subscribe, raw resend
├── channels.js, channels/ messaging core, admin state, moderator deltas
├── dm.js direct messages over the inbox stream
├── gate.js PomboGate client, one clone per channel
├── epochKey*.js key protocol for contract-backed channels
├── keyResponder.js answering key requests made while nobody was online
├── publisherProof.js throwaway publisher bound to an account
├── envelopeSigner.js author recovery in Visible mode
├── authorship.js author sealed inside the payload, Sealed mode
├── dmCrypto.js ECDH + HKDF + AES-GCM, sealed sender
├── storageEndpoints.js on-chain provider resolution, rotation, health
├── storageFetch.js signed reads, receipt timestamps, 401/403/503 handling
├── storageMedia.js file sharing over storage nodes
├── streamRetention.js per-stream retention (ttlRepublish.js resets the clock)
├── secureStorage.js encrypted localStorage + IndexedDB
├── syncManager.js cross-device sync (syncMerge.js is the pure part)
├── pushProtocol.js K-anonymous tags and proof of work
├── ui/ one module per surface
├── workers/ crypto pool and sync worker
└── utils/ retry, errors, retention
tests/ unit, smoke, cross-client parity vectors
sw.js service worker: offline and push
PomboGate and PomboGateFactory.