first commit
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.DS_Store
|
||||
*.log
|
||||
.env
|
||||
@@ -0,0 +1,123 @@
|
||||
# BridgeSwarm Website
|
||||
|
||||
Official marketing site, user guide, and developer documentation for
|
||||
**BridgeSwarm** — a browser extension + native messaging host that bridges
|
||||
the [Hyperswarm](https://github.com/holepunchto/hyperswarm) P2P stack into
|
||||
ordinary browsers.
|
||||
|
||||
Live at **[bridgeswarm.dev](https://bridgeswarm.dev)**. Source code for the
|
||||
product itself lives at
|
||||
[git.ssh.surf/snxraven/BridgeSwarm](https://git.ssh.surf/snxraven/BridgeSwarm).
|
||||
|
||||
This repository is a static, multi-page site (Vite + vanilla HTML/CSS/JS —
|
||||
no framework, no client-side router). It is owned and published by
|
||||
**HoneyPeer, LLC** and licensed under **AGPL-3.0** (see [License](#license)).
|
||||
|
||||
## Quick start
|
||||
|
||||
Requires Node.js 18+.
|
||||
|
||||
```bash
|
||||
npm install # install dependencies
|
||||
npm run dev # start the Vite dev server → http://localhost:5174
|
||||
npm run build # produce a static production build in dist/
|
||||
npm start # serve the production build → http://localhost:4174
|
||||
```
|
||||
|
||||
Other scripts:
|
||||
|
||||
```bash
|
||||
npm run preview # Vite's own preview server for a local build (port 5174)
|
||||
npm run serve # alias for `npm start`
|
||||
```
|
||||
|
||||
| Script | Purpose | Port |
|
||||
| --- | --- | --- |
|
||||
| `npm run dev` | Vite dev server with hot reload | `5174` |
|
||||
| `npm run build` | Builds every page in `vite.config.js` into `dist/` | — |
|
||||
| `npm start` / `npm run serve` | Serves `dist/` via `server.mjs` (static files + generated `sitemap.xml`) | `4174` |
|
||||
|
||||
`server.mjs` also proxies `/api/releases` to the Gitea releases API for the
|
||||
[Releases](https://bridgeswarm.dev/releases) page, and excludes noindex stub
|
||||
pages (like `/legal/cookies`) from the generated sitemap.
|
||||
|
||||
## Content map
|
||||
|
||||
```
|
||||
index.html Marketing home page
|
||||
download.html Download / install instructions
|
||||
releases.html Release history (pulled from Gitea)
|
||||
community.html Community & support links
|
||||
learn/ "How it works" walkthrough
|
||||
use-cases/ Use case gallery
|
||||
|
||||
docs/ Documentation
|
||||
index.html Docs overview
|
||||
quickstart.html Quick start guide
|
||||
user-guide.html End-user guide (extension + host)
|
||||
developer-guide.html Building on top of BridgeSwarm
|
||||
architecture.html System architecture (extension ↔ host ↔ Hyperswarm)
|
||||
api.html API reference
|
||||
data.html Data API (Hypercore/Hyperbee/Hyperdrive/Autobase/Hyperdb)
|
||||
protocols.html HRPC / protocol details
|
||||
capabilities.html Capability packs (bare-media, bare-ffmpeg, etc.)
|
||||
examples.html Example apps / local examples server
|
||||
security.html Security model
|
||||
faq.html FAQ
|
||||
release.html Release channels & artifacts
|
||||
|
||||
legal/ Legal hub — see below
|
||||
index.html Overview of all policies
|
||||
terms.html Terms of Service
|
||||
eula.html End User License Agreement (extension + host)
|
||||
aup.html Acceptable Use Policy
|
||||
privacy.html Privacy Policy (local-first, no telemetry)
|
||||
cookies.html Stub → redirects to /legal/privacy#cookies (noindex)
|
||||
license.html AGPL-3.0 explainer, §13 network-use, source link
|
||||
copyright.html Copyright & DMCA notice procedure
|
||||
disclaimer.html "As-is" disclaimer & limitation of liability
|
||||
security.html Vulnerability / responsible-disclosure policy
|
||||
|
||||
src/
|
||||
js/ site.js (shared chrome/nav/footer/theme), home.js, releases.js
|
||||
styles/ global.css, docs.css, legal.css, home.css, theme-light.css
|
||||
|
||||
public/
|
||||
assets/
|
||||
brand/ OG/Twitter card images, hero backgrounds, brand colors.css
|
||||
favicons/ Favicons, site.webmanifest, browserconfig.xml
|
||||
logo/ BridgeSwarm icon & wordmark, all sizes/variants
|
||||
social/ Social preview assets
|
||||
robots.txt
|
||||
|
||||
vite.config.js Multi-page build config (all HTML entry points) + dev proxy
|
||||
server.mjs Production static server + sitemap generator
|
||||
```
|
||||
|
||||
Every HTML page shares the same chrome, injected at runtime by
|
||||
`src/js/site.js` via `data-nav` / `data-footer` (and `data-docs-nav` /
|
||||
`data-legal-nav` for sidebar sections), so navigation, footer, and
|
||||
dark/light theme toggling stay consistent across the whole site without a
|
||||
build-time templating layer.
|
||||
|
||||
## Brand assets
|
||||
|
||||
Logos, icons, wordmarks, and social card images live under
|
||||
[`public/assets/`](public/assets):
|
||||
|
||||
- `public/assets/logo/` — BridgeSwarm icon & wordmark (light/dark/mono/teal variants, multiple sizes)
|
||||
- `public/assets/brand/` — OG/Twitter card images, hero backgrounds, and `colors.css` (brand color tokens)
|
||||
- `public/assets/favicons/` — favicons and PWA manifest
|
||||
|
||||
## License & ownership
|
||||
|
||||
BridgeSwarm — the browser extension, the native messaging host, and this
|
||||
website's source — is owned, operated, and engineered by **HoneyPeer, LLC**
|
||||
(DeKalb County, Georgia, USA), and licensed under the
|
||||
**GNU Affero General Public License v3.0 (AGPL-3.0)**. See
|
||||
[`/legal/license`](https://bridgeswarm.dev/legal/license) for the full
|
||||
open-source notice, including AGPL §13 network-use obligations, and
|
||||
[`/legal/`](https://bridgeswarm.dev/legal/) for the complete set of legal
|
||||
policies (Terms, EULA, AUP, Privacy, Copyright/DMCA, Disclaimer, Security).
|
||||
|
||||
Legal contact: [[email protected]](mailto:[email protected])
|
||||
@@ -0,0 +1,228 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#2dd4bf' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<title>Community & Support — BridgeSwarm</title>
|
||||
<meta name="description" content="BridgeSwarm's source repository, how to contribute, where to get support, who builds and owns BridgeSwarm (HoneyPeer, LLC), and what the AGPL-3.0 license means for you.">
|
||||
<meta name="author" content="HoneyPeer, LLC">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/community">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
<link rel="stylesheet" href="/src/styles/community.css">
|
||||
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png">
|
||||
<link rel="shortcut icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf">
|
||||
<meta name="msapplication-TileImage" content="/assets/favicons/mstile-150x150.png">
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Community & Support — BridgeSwarm">
|
||||
<meta property="og:description" content="Source repo, contributing guide, support channels, HoneyPeer LLC, and what AGPL-3.0 means for BridgeSwarm.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/community">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Community & Support — BridgeSwarm">
|
||||
<meta name="twitter:description" content="Source repo, contributing guide, support channels, HoneyPeer LLC, and what AGPL-3.0 means for BridgeSwarm.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": "https://bridgeswarm.dev/#organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"logo": "https://bridgeswarm.dev/assets/logo/bridgeswarm-icon-512.png",
|
||||
"email": "[email protected]",
|
||||
"sameAs": ["https://git.ssh.surf/snxraven/BridgeSwarm"]
|
||||
},
|
||||
{
|
||||
"@type": "SoftwareApplication",
|
||||
"@id": "https://bridgeswarm.dev/#software",
|
||||
"name": "BridgeSwarm",
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"operatingSystem": "macOS, Linux, Windows",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"publisher": { "@id": "https://bridgeswarm.dev/#organization" },
|
||||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
|
||||
"license": "https://www.gnu.org/licenses/agpl-3.0.html",
|
||||
"downloadUrl": "https://bridgeswarm.dev/download",
|
||||
"softwareVersion": "1.0.0",
|
||||
"description": "Brings the Hyperswarm P2P stack into desktop browsers via a Bare native messaging host."
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="page-community">
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div class="bg-grid" aria-hidden="true"></div>
|
||||
|
||||
<div data-nav></div>
|
||||
|
||||
<main id="main">
|
||||
|
||||
<header class="page-hero">
|
||||
<div class="container">
|
||||
<p class="section-label" style="justify-content:center;">Community</p>
|
||||
<h1>Source, support, and who's behind BridgeSwarm</h1>
|
||||
<p class="lead">BridgeSwarm is source-available under AGPL-3.0, self-hosted on Gitea, and built by a small team that also uses it daily.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="section section-sm" id="source" aria-labelledby="source-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Source</p>
|
||||
<h2 id="source-title">Source repository</h2>
|
||||
<p class="lead">The full history, issues, and CI pipeline live on our self-hosted Gitea instance — not GitHub.</p>
|
||||
</div>
|
||||
<div class="card reveal">
|
||||
<h3><a href="https://git.ssh.surf/snxraven/BridgeSwarm">git.ssh.surf/snxraven/BridgeSwarm</a></h3>
|
||||
<p>Extension, native host, examples, branding package, and documentation — one monorepo.</p>
|
||||
<pre style="margin-top:1rem;"><code>git clone https://git.ssh.surf/snxraven/BridgeSwarm.git</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="contributing" aria-labelledby="contributing-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Contributing</p>
|
||||
<h2 id="contributing-title">Set up a dev environment</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2 reveal">
|
||||
<div class="card">
|
||||
<h3>Get running</h3>
|
||||
<pre><code>git clone https://git.ssh.surf/snxraven/BridgeSwarm.git
|
||||
cd BridgeSwarm
|
||||
npm run setup
|
||||
# Load unpacked: extension/</code></pre>
|
||||
<p>Run <code>npm run examples</code> to serve the demo gallery at <code>127.0.0.1:4173</code>, and <code>npm run sync:examples</code> after editing anything under <code>examples/</code>.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>Where changes tend to land</h3>
|
||||
<ul class="feature-list" style="margin-top:0.75rem;">
|
||||
<li><code>extension/</code> — MV3 background, content script, Control Center UI</li>
|
||||
<li><code>native-host/</code> — <code>host.js</code>, <code>messenger.js</code>, capability packs</li>
|
||||
<li><code>examples/</code> — source of truth for every demo</li>
|
||||
<li><code>docs/</code> — architecture, API, data, capabilities, Protomux, HRPC references</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<p class="lead" style="margin-top:1.5rem;">Please open an issue before a large change — especially anything touching the native messaging protocol, extension IDs, or the install scripts, since those have hard-coded coexistence checks against other tools. Build/verification commands and CI behavior are documented in the repository <a href="https://git.ssh.surf/snxraven/BridgeSwarm/src/branch/main/README.md">README</a>.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="support" aria-labelledby="support-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Support</p>
|
||||
<h2 id="support-title">Get support</h2>
|
||||
</div>
|
||||
|
||||
<div class="docs-cards reveal">
|
||||
<a class="docs-card" href="https://join.discord-linux.com">
|
||||
<span class="card-tag">Live chat</span>
|
||||
<h3>Discord</h3>
|
||||
<p>Live help and discussion on the Discord-Linux server — the fastest way to reach a real person.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="https://git.ssh.surf/snxraven/BridgeSwarm/issues">
|
||||
<span class="card-tag">Tracker</span>
|
||||
<h3>Gitea Issues</h3>
|
||||
<p>Bug reports and feature requests, tracked against the actual codebase.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/download#troubleshooting">
|
||||
<span class="card-tag">Self-serve</span>
|
||||
<h3>Troubleshooting guide</h3>
|
||||
<p>Common install issues — native host exits, extension ID mismatches, missing HRPC spec.</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="honeypeer" aria-labelledby="honeypeer-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Publisher</p>
|
||||
<h2 id="honeypeer-title">HoneyPeer, LLC</h2>
|
||||
</div>
|
||||
<div class="card reveal">
|
||||
<p>BridgeSwarm is owned and engineered by <strong>HoneyPeer, LLC</strong>, based in DeKalb County, Georgia, USA. For legal, licensing, or press inquiries, reach us at <a href="mailto:[email protected]">[email protected]</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="license" aria-labelledby="license-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">License</p>
|
||||
<h2 id="license-title">AGPL-3.0</h2>
|
||||
</div>
|
||||
<div class="callout info reveal">
|
||||
<div class="callout-icon">§</div>
|
||||
<div class="callout-body">
|
||||
<p style="margin-bottom:0.75rem;">BridgeSwarm is released under the <a href="https://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License v3.0</a>. In practice, that means:</p>
|
||||
<ul style="margin:0 0 0.75rem; padding-left:1.1rem; display:flex; flex-direction:column; gap:0.4rem;">
|
||||
<li>You can use, study, modify, and redistribute BridgeSwarm freely.</li>
|
||||
<li>If you modify BridgeSwarm <strong>and let others interact with it over a network</strong> — the AGPL's key difference from plain GPL — you must make your modified source available to those users (AGPL §13).</li>
|
||||
<li>Derivative works must remain under AGPL-3.0; there's no proprietary-relicensing path for forks.</li>
|
||||
<li>Branding assets ship under the same license as the rest of the project.</li>
|
||||
</ul>
|
||||
<p style="margin:0;">This is a summary, not legal advice — read the <a href="https://git.ssh.surf/snxraven/BridgeSwarm/src/branch/main/LICENSE">full license text</a> before shipping a modified deployment, and contact <a href="mailto:[email protected]">[email protected]</a> with licensing questions specific to your use case.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta-band reveal">
|
||||
<div class="container">
|
||||
<div class="cta-card">
|
||||
<h2>Join the swarm</h2>
|
||||
<p class="lead">Install it, break it, tell us on Discord — or send a patch.</p>
|
||||
<div class="cta-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/download">Install BridgeSwarm</a>
|
||||
<a class="btn btn-ghost btn-lg" href="https://join.discord-linux.com">Join Discord</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<div data-footer></div>
|
||||
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,333 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>API Reference · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="Full BridgeSwarm API reference: constructor options, instance methods, events, and every BridgeSwarm.request host type — swarm, core*, bee*, drive*, autobase*, hyperdb*, attach*, cap*, examplesServer*, host.snapshot, and media helpers.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/api.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="API Reference · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Constructor options, methods, events, and the full BridgeSwarm.request catalog.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/api.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="API Reference · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Constructor options, methods, events, and the full BridgeSwarm.request catalog.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html" class="active" aria-current="page">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Build with BridgeSwarm</p>
|
||||
<h1>API Reference</h1>
|
||||
<p class="docs-lead">
|
||||
The complete surface of <code>window.BridgeSwarm</code>: constructor options, instance methods,
|
||||
browser-side events, and every request <code>type</code> the native host accepts via
|
||||
<code>BridgeSwarm.request(type, payload, options)</code>. Binary payloads are base64-encoded on the
|
||||
wire in both directions.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#message-format">Message format</a></li>
|
||||
<li><a href="#constructor">Constructor options</a></li>
|
||||
<li><a href="#instance-methods">Instance methods</a></li>
|
||||
<li><a href="#connection-object">Connection object</a></li>
|
||||
<li><a href="#browser-events">Browser events</a></li>
|
||||
<li><a href="#swarm-lifecycle">Swarm lifecycle</a></li>
|
||||
<li><a href="#connection-requests">Connection requests & events</a></li>
|
||||
<li><a href="#attachment">Connection attachment</a></li>
|
||||
<li><a href="#data-api">Data API</a></li>
|
||||
<li><a href="#capabilities">Capabilities</a></li>
|
||||
<li><a href="#examples-server">Examples server</a></li>
|
||||
<li><a href="#host-snapshot">Host snapshot</a></li>
|
||||
<li><a href="#media-helpers">Media helpers</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="message-format">Message format</h2>
|
||||
<ul>
|
||||
<li><strong>Request</strong> (browser → host): <code>{ id?, type, payload }</code>. The extension adds an <code>id</code> if you omit one; the host uses it to match the response.</li>
|
||||
<li><strong>Response</strong> (host → browser): <code>{ id, type: 'response', payload }</code>. Payload is the command result: <code>{ ok: true, ... }</code> or <code>{ ok: false, error: '...' }</code>.</li>
|
||||
<li><strong>Event</strong> (host → browser): <code>{ type: 'event', event, payload }</code>, forwarded to subscribed tabs and delivered as a <code>bridge-swarm-event</code> custom DOM event.</li>
|
||||
</ul>
|
||||
<div class="docs-callout docs-callout-info">
|
||||
The Promise returned by <code>BridgeSwarm.request()</code> almost always <strong>resolves</strong> —
|
||||
check <code>response.ok</code> and read <code>response.error</code> on failure, rather than relying on
|
||||
a rejected Promise (the exception is client-side timeouts).
|
||||
</div>
|
||||
|
||||
<h2 id="constructor">Constructor options</h2>
|
||||
<pre class="code-block"><code class="language-javascript">const swarm = new BridgeSwarm({
|
||||
appName: 'my-app', // string, optional — falls back to the extension's default app name
|
||||
maxPeers: 50, // number, optional — 0 or omitted means no limit (or extension default)
|
||||
});</code></pre>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Option</th><th>Type</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>appName</code></td><td>string</td><td>Passed to Hyperswarm on the host; if omitted, the extension's configured default app name is used.</td></tr>
|
||||
<tr><td><code>maxPeers</code></td><td>number</td><td>Cap on peer connections for this swarm. <code>0</code> means no limit. Falls back to the extension's default max peers.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
Firewalling is <strong>not</strong> a constructor option and is never a JS predicate function — it is
|
||||
host-managed state, set with <code>swarm.setFirewall(...)</code> after construction.
|
||||
</p>
|
||||
|
||||
<h2 id="instance-methods">Instance methods</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Method</th><th>Returns</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>BridgeSwarm.ready()</code></td><td>Promise<constructor></td><td>Static method. Resolves once the extension has injected the API. Rejects after the configured default ready timeout (ms) if > 0; default is to wait indefinitely.</td></tr>
|
||||
<tr><td><code>swarm.join(topic, opts?)</code></td><td>Promise</td><td>Joins a topic (32-byte hex string). Triggers <code>init</code> once per swarm, then <code>join</code>.</td></tr>
|
||||
<tr><td><code>swarm.leave(topic)</code></td><td>Promise</td><td>Leaves a previously joined topic.</td></tr>
|
||||
<tr><td><code>swarm.getPublicKey()</code></td><td>Promise<string></td><td>Hex-encoded public key for this swarm (backed by the <code>swarmKey</code> request).</td></tr>
|
||||
<tr><td><code>swarm.setFirewall({ mode, keys })</code></td><td>Promise</td><td><code>mode</code>: <code>off</code> | <code>allowlist</code> | <code>denylist</code>; <code>keys</code>: public-key hex strings.</td></tr>
|
||||
<tr><td><code>swarm.ban(publicKeyHex, banned?)</code></td><td>Promise</td><td>Bans (or unbans) a peer and updates the denylist. Also available as <code>peerInfo.ban(banned?)</code> on connection events.</td></tr>
|
||||
<tr><td><code>swarm.setAutoReplicate({ enabled, coreKeyHex?, resourceId? })</code></td><td>Promise</td><td>Opts new connections into automatic Hypercore replication; the host takes over those sockets.</td></tr>
|
||||
<tr><td><code>swarm.connections()</code></td><td>Array</td><td>Snapshot of current connection objects. Returns <code>[]</code> after <code>destroy()</code>.</td></tr>
|
||||
<tr><td><code>swarm.createProtomux(conn)</code></td><td>Protomux | null</td><td>Wraps a connection in a framed stream and returns a Protomux instance, or <code>null</code> if the bundle isn't loaded.</td></tr>
|
||||
<tr><td><code>swarm.hrpcCall(connId, method, args?, { onChunk, timeoutMs })</code></td><td>Promise</td><td>Invokes host HRPC: <code>ping</code>, <code>notify</code>, <code>fetchStream</code>, <code>streamSum</code>, <code>duplex</code>.</td></tr>
|
||||
<tr><td><code>swarm.destroy()</code></td><td>Promise</td><td>Tears down the swarm and all its connections on the host.</td></tr>
|
||||
<tr><td><code>BridgeSwarm.request(type, payload, opts?)</code></td><td>Promise<response></td><td>Generic request bridge. <code>opts.timeoutMs</code> aborts and rejects with <code>"Request timed out after N ms"</code>.</td></tr>
|
||||
<tr><td><code>BridgeSwarm.capabilities</code></td><td>object</td><td><code>list()</code>, <code>has(pack)</code>, <code>call(pack, cmd, payload)</code>, <code>on(event, fn)</code>.</td></tr>
|
||||
<tr><td><code>BridgeSwarm.media</code></td><td>object</td><td>Media pack batch helpers plus <code>liveSession</code> / <code>attachLiveReceiver</code> — see <a href="#media-helpers">Media helpers</a>.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="connection-object">Connection object</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Member</th><th>Notes</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>conn.connId</code></td><td>Host-assigned identifier for this connection.</td></tr>
|
||||
<tr><td><code>conn.write(data)</code></td><td>Accepts a string or bytes; returns a <strong>Promise</strong> that resolves on success and rejects on host error (e.g. "Connection not found"). Also emits an <code>error</code> event.</td></tr>
|
||||
<tr><td><code>conn.on('data', fn)</code></td><td><code>fn(data: Uint8Array)</code> — one event per decrypted frame.</td></tr>
|
||||
<tr><td><code>conn.on('end', fn)</code></td><td>Peer disconnected.</td></tr>
|
||||
<tr><td><code>conn.on('error', fn)</code></td><td>Transport-level error.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="browser-events">Browser events</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Event (on <code>window</code>)</th><th>When</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>bridge-swarm-host-disconnect</code></td><td>The native messaging port disconnected. Existing swarms/connections are stale — call <code>destroy()</code> and rejoin, or prompt a refresh. If the "Show notification when host disconnects" setting is on, the user also gets a browser notification.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="swarm-lifecycle">Swarm lifecycle</h2>
|
||||
<p>All payloads include <code>swarmId</code> (chosen by the client).</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>init</code></td><td><code>{ swarmId, options? }</code> — <code>appName</code>, <code>maxPeers</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>join</code></td><td><code>{ swarmId, topic, opts? }</code></td><td><code>{ ok }</code> or <code>{ ok: false, error }</code></td></tr>
|
||||
<tr><td><code>leave</code></td><td><code>{ swarmId, topic }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>swarmKey</code></td><td><code>{ swarmId }</code></td><td><code>{ ok, publicKey }</code> (hex)</td></tr>
|
||||
<tr><td><code>setFirewall</code></td><td><code>{ swarmId, mode, keys }</code></td><td><code>{ ok, mode, keys }</code></td></tr>
|
||||
<tr><td><code>banPeer</code></td><td><code>{ swarmId, publicKeyHex, banned? }</code></td><td><code>{ ok, banned, publicKeyHex }</code></td></tr>
|
||||
<tr><td><code>setAutoReplicate</code></td><td><code>{ swarmId, enabled, coreKeyHex?, resourceId? }</code></td><td><code>{ ok, enabled }</code></td></tr>
|
||||
<tr><td><code>destroy</code></td><td><code>{ swarmId }</code></td><td><code>{ ok }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="connection-requests">Connection requests & events</h2>
|
||||
<p>Events, host → browser:</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Event</th><th>Payload</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>connection</code></td><td><code>{ connId, swarmId, peerInfo, autoReplicated? }</code> — <code>peerInfo</code>: <code>{ publicKey (hex), topics? (hex[]) }</code>; page API adds <code>peerInfo.ban()</code></td></tr>
|
||||
<tr><td><code>data</code></td><td><code>{ connId, swarmId, data }</code> — data is base64</td></tr>
|
||||
<tr><td><code>end</code></td><td><code>{ connId, swarmId }</code></td></tr>
|
||||
<tr><td><code>error</code></td><td><code>{ connId, swarmId, message }</code></td></tr>
|
||||
<tr><td><code>hrpc-chunk</code></td><td><code>{ connId, swarmId, streamId, method, chunk }</code></td></tr>
|
||||
<tr><td><code>hrpc-end</code></td><td><code>{ connId, swarmId, streamId, method, result? }</code></td></tr>
|
||||
<tr><td><code>hrpc-error</code></td><td><code>{ connId, swarmId, streamId, method, message }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Requests, browser → host:</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>write</code></td><td><code>{ connId, data }</code> — base64</td><td><code>{ ok }</code> or <code>{ ok: false, error }</code></td></tr>
|
||||
<tr><td><code>destroyConnection</code></td><td><code>{ connId }</code></td><td><code>{ ok }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="attachment">Connection attachment</h2>
|
||||
<p>
|
||||
After a connection is established, the browser can ask the host to "take over" it for Hypercore
|
||||
replication or HRPC. The connection then stops forwarding to the browser.
|
||||
</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>attachReplication</code></td><td><code>{ connId, coreKeyHex?, resourceId? }</code></td><td><code>{ ok }</code> or <code>{ ok: false, error }</code></td></tr>
|
||||
<tr><td><code>attachHrpc</code></td><td><code>{ connId }</code></td><td><code>{ ok }</code> or <code>{ ok: false, error }</code> — returns immediately; channel pairs once both sides attach (first RPC may wait up to 12s)</td></tr>
|
||||
<tr><td><code>hrpcInvoke</code></td><td><code>{ connId, method, args?, streamId? }</code> — <code>ping</code>, <code>notify</code>, <code>fetchStream</code>, <code>streamSum</code>, <code>duplex</code></td><td>Unary <code>{ ok, result }</code> or streaming <code>{ ok, streamId, streaming: true }</code> + events</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Prefer <code>swarm.hrpcCall(connId, method, args, { onChunk })</code> for streaming. Full detail: <a href="/docs/protocols.html">Protocols</a>.</p>
|
||||
|
||||
<h2 id="data-api">Data API</h2>
|
||||
<p>All commands return <code>{ ok: true, ... }</code> on success or <code>{ ok: false, error }</code> on failure. Binary data is base64-encoded.</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>coreInfo</code></td><td>—</td><td><code>{ ok, key (hex), length, writable }</code></td></tr>
|
||||
<tr><td><code>coreAppend</code></td><td><code>{ data }</code> or <code>{ base64 }</code></td><td><code>{ ok, length }</code></td></tr>
|
||||
<tr><td><code>coreGet</code></td><td><code>{ index }</code></td><td><code>{ ok, data }</code> (base64 or null)</td></tr>
|
||||
<tr><td><code>beeGet</code></td><td><code>{ key }</code></td><td><code>{ ok, key?, value?, seq? }</code> or <code>{ ok, value: null }</code></td></tr>
|
||||
<tr><td><code>beePut</code></td><td><code>{ key, value }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>beeDel</code></td><td><code>{ key }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>driveGet</code></td><td><code>{ path? }</code> (default <code>'/'</code>)</td><td><code>{ ok, data }</code></td></tr>
|
||||
<tr><td><code>drivePut</code></td><td><code>{ path, data? }</code> or <code>{ path, base64? }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>driveList</code></td><td><code>{ path? }</code></td><td><code>{ ok, entries }</code> (array of <code>{ key, value }</code>)</td></tr>
|
||||
<tr><td><code>driveDel</code></td><td><code>{ path }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>autobaseAppend</code></td><td><code>{ value? }</code> or <code>{ data? }</code></td><td><code>{ ok, length }</code></td></tr>
|
||||
<tr><td><code>autobaseViewGet</code></td><td><code>{ index }</code></td><td><code>{ ok, data }</code></td></tr>
|
||||
<tr><td><code>autobaseInfo</code></td><td>—</td><td><code>{ ok, length, signedLength }</code></td></tr>
|
||||
<tr><td><code>hyperdbGet</code></td><td><code>{ collection, query }</code></td><td><code>{ ok, doc }</code></td></tr>
|
||||
<tr><td><code>hyperdbInsert</code></td><td><code>{ collection, doc }</code> — doc: <code>{ id, value }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>hyperdbDelete</code></td><td><code>{ collection, query }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>hyperdbFindToArray</code></td><td><code>{ collectionOrIndex, query?, limit?, reverse? }</code></td><td><code>{ ok, docs }</code></td></tr>
|
||||
<tr><td><code>hyperdbFlush</code></td><td>—</td><td><code>{ ok }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Named-resource variants (<code>coreOpen</code>, <code>beeOpen</code>, etc.) and full examples: <a href="/docs/data.html">Data API</a>.</p>
|
||||
|
||||
<h2 id="capabilities">Capabilities</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>capabilities.list</code></td><td><code>{}</code></td><td><code>{ ok, packs }</code></td></tr>
|
||||
<tr><td><code>capabilities.has</code></td><td><code>{ pack }</code></td><td><code>{ ok, pack, has }</code></td></tr>
|
||||
<tr><td><code>capability</code></td><td><code>{ pack, cmd, payload }</code></td><td>pack-specific</td></tr>
|
||||
<tr><td><code>media.info</code> / <code>media.imageTransform</code> / <code>media.extractFrame</code> / <code>media.transcode</code> / <code>media.cancel</code> / …</td><td>command payload</td><td>see <a href="/docs/capabilities.html">Capabilities</a></td></tr>
|
||||
<tr><td><code>media.encodeStart</code> / <code>encodePushFrame</code> / <code>encodePush</code> / <code>encodeSubscribe</code> / <code>encodeStop</code></td><td>live session payload</td><td><code>{ ok, sessionId, … }</code> + <code>cap-chunk</code> segments</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Capability events (broadcast to all subscribed tabs, no <code>swarmId</code> filter):</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Event</th><th>Payload</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>cap-chunk</code></td><td><code>{ pack, jobId/sessionId, kind?, seq?, index?, data?, progress?, bytes? }</code></td></tr>
|
||||
<tr><td><code>cap-end</code></td><td><code>{ pack, jobId/sessionId, … }</code></td></tr>
|
||||
<tr><td><code>cap-error</code></td><td><code>{ pack, jobId/sessionId, message }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="examples-server">Examples server</h2>
|
||||
<p>
|
||||
Toggled from Control Center Settings (<code>examplesServerEnabled</code> / <code>examplesServerPort</code>
|
||||
in <code>bridgeSwarmSettings</code>). The background service worker sends these — pages typically
|
||||
don't call them directly.
|
||||
</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>examplesServer.start</code></td><td><code>{ host?, port? }</code> — default <code>127.0.0.1:4173</code></td><td><code>{ ok, running, url, root, … }</code></td></tr>
|
||||
<tr><td><code>examplesServer.stop</code></td><td><code>{}</code></td><td><code>{ ok, running: false, … }</code></td></tr>
|
||||
<tr><td><code>examplesServer.status</code></td><td><code>{}</code></td><td><code>{ ok, running, url, rootFound, … }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="host-snapshot">Host snapshot</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>host.snapshot</code></td><td><code>{}</code></td><td><code>{ ok, version, storagePath, packs, examples, swarmCount, connectionCount, swarms: [{ swarmId, publicKey, firewall, autoReplicate, peerCount, connIds }] }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Read-only inventory used by the Control Center; not required by page apps.</p>
|
||||
|
||||
<h2 id="media-helpers">Media helpers</h2>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.media.info({ dataBase64, filename })
|
||||
await BridgeSwarm.media.imageTransform({ dataBase64, maxWidth: 640, mimetype: 'image/webp' })
|
||||
await BridgeSwarm.media.extractFrame({ dataBase64, frameIndex: 0 })
|
||||
await BridgeSwarm.media.transcode({ dataBase64, format: 'webm' }, { onProgress })
|
||||
await BridgeSwarm.media.cancel(jobId)
|
||||
|
||||
const live = BridgeSwarm.media.liveSession(videoEl)
|
||||
await live.start({ width: 640, height: 360, fps: 10, ingest: 'frames' })
|
||||
await live.pushFrame(canvas)
|
||||
await live.subscribe({ swarm: { connIds: [conn.connId] } })
|
||||
await live.stop()
|
||||
|
||||
BridgeSwarm.media.attachLiveReceiver(conn, videoEl)</code></pre>
|
||||
<p>Full behavior, defaults, and limits: <a href="/docs/capabilities.html">Capabilities</a>.</p>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/architecture.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Architecture</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/data.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Data API</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,292 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Architecture · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="BridgeSwarm architecture: extension and native host components, message and event flow, connection lifecycle, the examples server, and the live media encode path, with diagrams.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/architecture.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Architecture · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Components, message flow, connection lifecycle, and the live media encode path.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/architecture.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Architecture · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Components, message flow, connection lifecycle, and the live media encode path.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html" class="active" aria-current="page">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Build with BridgeSwarm</p>
|
||||
<h1>Architecture</h1>
|
||||
<p class="docs-lead">
|
||||
BridgeSwarm is split into two processes that never trust each other implicitly: a browser
|
||||
extension that only ever sees what a page is allowed to send, and a native host that runs the real
|
||||
Hyperswarm stack with your user's OS-level privileges. This page documents every component, how
|
||||
messages and events flow between them, the connection lifecycle, the local examples server, and the
|
||||
live media encode pipeline.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#layers">Layers</a></li>
|
||||
<li><a href="#components">Components</a></li>
|
||||
<li><a href="#protocol">Wire protocol</a></li>
|
||||
<li><a href="#message-flow">Request/response flow</a></li>
|
||||
<li><a href="#event-flow">Event flow</a></li>
|
||||
<li><a href="#connection-lifecycle">Connection lifecycle</a></li>
|
||||
<li><a href="#examples-server-flow">Examples server flow</a></li>
|
||||
<li><a href="#live-encode-path">Live media encode path</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="layers">Layers</h2>
|
||||
<pre class="mermaid">
|
||||
flowchart TB
|
||||
subgraph Browser["Desktop browser"]
|
||||
Page["Web page: window.BridgeSwarm"]
|
||||
CS["content.js"]
|
||||
BG["background.js (service worker)"]
|
||||
UI["dashboard.js Control Center - Port + autosave settings"]
|
||||
end
|
||||
|
||||
subgraph Host["Native messaging host (Bare)"]
|
||||
MSG["messenger.js - 4-byte LE + JSON"]
|
||||
H["host.js"]
|
||||
SW["Hyperswarm"]
|
||||
DATA["Corestore, Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb"]
|
||||
MUX["Protomux + HRPC"]
|
||||
CAP["capabilities/ - media + live encode"]
|
||||
EX["examples-server.js - 127.0.0.1:4173"]
|
||||
end
|
||||
|
||||
Page <-->|postMessage| CS
|
||||
CS <-->|runtime.sendMessage| BG
|
||||
UI -->|"storage.local bridgeSwarmSettings"| BG
|
||||
BG <-->|"connectNative com.bridgeswarm"| MSG
|
||||
MSG --> H
|
||||
H --> SW
|
||||
H --> DATA
|
||||
H --> MUX
|
||||
H --> CAP
|
||||
H --> EX
|
||||
SW <-->|Noise P2P| Peer["Remote peers"]
|
||||
</pre>
|
||||
|
||||
<p>Four layers, top to bottom:</p>
|
||||
<ol>
|
||||
<li><strong>Page</strong> — your application code, talking only to <code>window.BridgeSwarm</code>.</li>
|
||||
<li><strong>Extension (MV3)</strong> — content script + background service worker + Control Center UI. Owns no P2P state itself; it's a relay and settings store.</li>
|
||||
<li><strong>Native messaging transport</strong> — a length-prefixed JSON pipe between the browser process and a separate OS process.</li>
|
||||
<li><strong>Native host (Bare)</strong> — runs Hyperswarm, all Hyper* data structures, Protomux/HRPC attachment, capability packs, and the optional examples HTTP server.</li>
|
||||
</ol>
|
||||
|
||||
<h2 id="components">Components</h2>
|
||||
<h3>Extension</h3>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Component</th><th>Role</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>background.js</code></td><td>Maintains the native messaging port (<code>chrome.runtime.connectNative('com.bridgeswarm')</code>); tracks pending requests by id; routes swarm events to the tabs that own each <code>swarmId</code>; broadcasts capability events to subscribed tabs; reconnects with backoff on disconnect; starts/stops the examples server per settings.</td></tr>
|
||||
<tr><td><code>content.js</code></td><td>Reads settings; skips injection on <code>file://</code> if configured; otherwise injects <code>api.js</code>, <code>framed-stream.js</code>, and <code>protomux-bundle.js</code> in order; bridges page ↔ background via <code>window.postMessage</code> / <code>chrome.runtime.sendMessage</code>.</td></tr>
|
||||
<tr><td>Control Center (<code>dashboard.html</code>/<code>dashboard.js</code>)</td><td>Overview · Swarms · Connections · Activity · Settings, over a live <code>bridgeswarm-dashboard</code> Port; settings save on change.</td></tr>
|
||||
<tr><td>Options (<code>options.html</code>)</td><td>Opens the Control Center's Settings tab in a full browser tab.</td></tr>
|
||||
<tr><td>Injected scripts (page context)</td><td><code>api.js</code> exposes <code>window.BridgeSwarm</code>, <code>BridgeSwarm.request</code>, and <code>BridgeSwarm.capabilities</code> / <code>BridgeSwarm.media</code>; merges constructor options with injected defaults.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Native host</h3>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Component</th><th>Role</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>index.mjs</code></td><td>Entry point. Loads <code>bare-process</code>, registers default capability packs (media/ffmpeg), starts the messenger and host.</td></tr>
|
||||
<tr><td><code>messenger.js</code></td><td>Chrome/Firefox native messaging framing: 4-byte little-endian length + UTF-8 JSON. Max message size host → browser is <strong>1 MB</strong>.</td></tr>
|
||||
<tr><td><code>host.js</code></td><td>Swarm lifecycle, peer firewall/ban, auto-replicate, connection attachment (Protomux/HRPC), Hyper* data API, capability dispatch, examples-server control.</td></tr>
|
||||
<tr><td><code>examples-server.js</code></td><td>Optional <code>bare-http1</code> static server on <code>127.0.0.1:4173</code> serving the synced <code>examples/</code> tree (or <code>BRIDGESWARM_EXAMPLES_DIR</code>).</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="protocol">Wire protocol</h2>
|
||||
<ul>
|
||||
<li><strong>Wire format</strong> (host ↔ browser): 4-byte LE unsigned length + UTF-8 JSON. Binary I/O — no CRLF translation.</li>
|
||||
<li><strong>Message kinds</strong>: Requests <code>{ id?, type, payload }</code> · Responses <code>{ id, type: 'response', payload }</code> · Events <code>{ type: 'event', event, payload }</code>.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="message-flow">Request/response flow</h2>
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant Page
|
||||
participant ContentScript
|
||||
participant Background
|
||||
participant NativeHost
|
||||
|
||||
Page->>ContentScript: postMessage bridge-swarm-bridge
|
||||
ContentScript->>Background: runtime.sendMessage action send
|
||||
Background->>NativeHost: port.postMessage id, type, payload
|
||||
NativeHost->>NativeHost: handleMessage -> reply(result)
|
||||
NativeHost->>Background: messenger.send id, type response
|
||||
Background->>ContentScript: sendResponse payload
|
||||
ContentScript->>Page: dispatchEvent bridge-swarm-bridge-response
|
||||
</pre>
|
||||
<p>
|
||||
<code>BridgeSwarm.request(type, payload)</code> builds the payload; the background service worker
|
||||
assigns <code>id</code> and resolves the matching pending Promise once the host replies.
|
||||
</p>
|
||||
|
||||
<h2 id="event-flow">Event flow</h2>
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant NativeHost
|
||||
participant Background
|
||||
participant ContentScript
|
||||
participant Page
|
||||
|
||||
NativeHost->>NativeHost: emit(event, payload)
|
||||
NativeHost->>Background: messenger.send type event
|
||||
alt swarm-scoped event
|
||||
Background->>ContentScript: tabs.sendMessage only tabs owning swarmId
|
||||
else capability / global event
|
||||
Background->>ContentScript: tabs.sendMessage all subscribed tabs
|
||||
end
|
||||
ContentScript->>Page: dispatchEvent bridge-swarm-event
|
||||
Page->>Page: api.js _onEvent connection data end error cap-*
|
||||
</pre>
|
||||
|
||||
<h2 id="connection-lifecycle">Connection lifecycle</h2>
|
||||
<pre class="mermaid">
|
||||
stateDiagram-v2
|
||||
[*] --> Init: new BridgeSwarm + join(topic)
|
||||
Init --> Discovering: host Hyperswarm.join
|
||||
Discovering --> Connected: peer Noise handshake
|
||||
Connected --> DataForward: page conn.write / data events
|
||||
Connected --> Attached: attachReplication or attachHrpc
|
||||
DataForward --> Closed: end / error / destroy
|
||||
Attached --> Closed: end / destroy
|
||||
Closed --> [*]
|
||||
</pre>
|
||||
<ol>
|
||||
<li><strong>Init swarm</strong> — <code>join(topic)</code> triggers <code>init</code> (once) then <code>join</code>. The host creates a Hyperswarm instance and joins the topic.</li>
|
||||
<li><strong>Connection</strong> — the host allocates a <code>connId</code>, stores the socket, and emits <code>connection</code> with <code>connId</code>, <code>swarmId</code>, <code>peerInfo</code>.</li>
|
||||
<li><strong>Data</strong> — <code>conn.write</code> sends a <code>write</code> request (base64); the host forwards raw socket bytes back as <code>data</code> events — <em>unless</em> the connection is attached.</li>
|
||||
<li><strong>Attachment</strong> — <code>attachReplication</code> / <code>attachHrpc</code> stops browser data forwarding; the host owns a Protomux instance on that socket instead (for Hypercore replication or HRPC). At most one connection per peer per swarm is kept.</li>
|
||||
</ol>
|
||||
|
||||
<h2 id="examples-server-flow">Examples server flow</h2>
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant UI as Options / Dashboard
|
||||
participant BG as background.js
|
||||
participant Host as Native host
|
||||
participant Browser as Browser tab
|
||||
|
||||
UI->>UI: toggle examplesServerEnabled (autosave bridgeSwarmSettings)
|
||||
UI->>BG: storage.onChanged
|
||||
BG->>Host: examplesServer.start host 127.0.0.1 port 4173
|
||||
Host->>Host: bare-http1 serve examples/
|
||||
Host-->>BG: running url http://127.0.0.1:4173/
|
||||
Browser->>Host: GET /live-encode/
|
||||
Note over Browser: content script injects BridgeSwarm on http origin
|
||||
</pre>
|
||||
<p>
|
||||
The examples server exists purely so demos share a real HTTP origin (required for content-script
|
||||
injection) without you needing to stand up your own dev server. It is bound to
|
||||
<code>127.0.0.1</code> only. See <a href="/docs/examples.html">Examples</a> for the full demo catalog.
|
||||
</p>
|
||||
|
||||
<h2 id="live-encode-path">Live media encode path</h2>
|
||||
<pre class="mermaid">
|
||||
flowchart LR
|
||||
Cam["Page capture - canvas / getDisplayMedia"] -->|"JPEG frames or WebM slices"| API["BridgeSwarm.media.liveSession"]
|
||||
API -->|"encodePushFrame via NMH"| Enc["host bare-ffmpeg - VP9 / WebM"]
|
||||
Enc -->|"cap-chunk kind: segment"| MSE["Page MSE player"]
|
||||
Enc -->|"BSML on socket"| Peer["Remote peer conn"]
|
||||
Enc -->|archive| File["cap-jobs/sessionId/live.webm"]
|
||||
</pre>
|
||||
<p>
|
||||
The page never runs ffmpeg — it captures frames (canvas snapshot, screen share, or camera), compresses
|
||||
them to JPEG client-side, and pushes them to the host under the native-messaging size limit. The host
|
||||
encodes real VP9/WebM with <code>bare-ffmpeg</code> and can simultaneously: stream MSE segments back to
|
||||
the originating page, write BSML-framed binary chunks onto peer Hyperswarm sockets for P2P fan-out, and
|
||||
archive the finished file under <code>cap-jobs/<sessionId>/live.webm</code>. Full command
|
||||
reference in <a href="/docs/capabilities.html">Capabilities</a>.
|
||||
</p>
|
||||
|
||||
<div class="docs-callout docs-callout-info">
|
||||
Want the request/response shape for every message type shown above? See the
|
||||
<a href="/docs/api.html">API Reference</a>.
|
||||
</div>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/developer-guide.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Developer Guide</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/api.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">API Reference</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,223 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Capabilities · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="BridgeSwarm capability packs: batch media transforms and live VP9/WebM encode via bare-media and bare-ffmpeg, the cap-jobs security sandbox, and performance limits.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/capabilities.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Capabilities · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Batch media transforms and live VP9/WebM encode, plus the security model behind Bare capability packs.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/capabilities.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Capabilities · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Batch media transforms and live VP9/WebM encode, plus the security model.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html" class="active" aria-current="page">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Build with BridgeSwarm</p>
|
||||
<h1>Capabilities</h1>
|
||||
<p class="docs-lead">
|
||||
BridgeSwarm exposes selected <a href="https://github.com/holepunchto/bare" target="_blank" rel="noopener">Bare</a>
|
||||
native APIs to the page as <strong>capability packs</strong>. This is intentionally curated — not
|
||||
every <code>bare-*</code> package, only what fits the browser + native-messaging model. The default
|
||||
host includes the <strong>media</strong> pack (<code>bare-media</code> + <code>bare-ffmpeg</code>); see
|
||||
<a href="/docs/faq.html">FAQ</a> for what's bundled but not yet exposed.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#page-api">Page API</a></li>
|
||||
<li><a href="#events">Streaming events</a></li>
|
||||
<li><a href="#security">Security</a></li>
|
||||
<li><a href="#media-pack">Pack — Media (default)</a></li>
|
||||
<li><a href="#live-encode">Live encode notes</a></li>
|
||||
<li><a href="#upcoming">Bundled for upcoming packs</a></li>
|
||||
<li><a href="#host-protocol">Host protocol</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="page-api">Page API</h2>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.capabilities.list() // e.g. ['media']
|
||||
await BridgeSwarm.capabilities.has('media')
|
||||
|
||||
// Generic dispatch
|
||||
await BridgeSwarm.capabilities.call('media', 'info', { path: '…' })
|
||||
|
||||
// Batch wrappers
|
||||
await BridgeSwarm.media.info({ dataBase64, filename })
|
||||
await BridgeSwarm.media.imageTransform({ dataBase64, maxWidth: 640, mimetype: 'image/webp' })
|
||||
await BridgeSwarm.media.extractFrame({ dataBase64, frameIndex: 0 })
|
||||
await BridgeSwarm.media.transcode({ dataBase64, format: 'webm' }, { onProgress })
|
||||
await BridgeSwarm.media.cancel(jobId)
|
||||
|
||||
// Live encode (host bare-ffmpeg -> MSE)
|
||||
const live = BridgeSwarm.media.liveSession(videoEl)
|
||||
await live.start({ width: 640, height: 360, fps: 10, ingest: 'frames' })
|
||||
await live.pushFrame(canvas)
|
||||
await live.subscribe({ swarm: { connIds: [conn.connId] } })
|
||||
await live.stop()</code></pre>
|
||||
|
||||
<h2 id="events">Streaming events</h2>
|
||||
<p>Streaming results use host events, kept under the ~1 MB native-messaging limit:</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Event</th><th>Payload</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>cap-chunk</code></td><td><code>{ pack, jobId/sessionId, kind?, index?, data? (base64), progress?, bytes? }</code></td></tr>
|
||||
<tr><td><code>cap-end</code></td><td><code>{ pack, jobId/sessionId, chunks?, path?, mimetype?, … }</code></td></tr>
|
||||
<tr><td><code>cap-error</code></td><td><code>{ pack, jobId/sessionId, message }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Live sessions emit <code>cap-chunk</code> with <code>kind: 'segment'</code> (WebM fragments for MSE) or <code>kind: 'drop'</code> under backpressure.</p>
|
||||
<pre class="code-block"><code class="language-javascript">const off = BridgeSwarm.capabilities.on('cap-chunk', (p) => console.log(p))</code></pre>
|
||||
|
||||
<h2 id="security">Security</h2>
|
||||
<p>Filesystem access for capability packs is <strong>allowlisted</strong> under:</p>
|
||||
<pre class="code-block"><code>$BRIDGE_SWARM_STORAGE/cap-jobs/
|
||||
# default: ~/.bridgeswarm/bridge-swarm-storage/cap-jobs/</code></pre>
|
||||
<p>Absolute paths outside that tree are rejected by the host.</p>
|
||||
|
||||
<h2 id="media-pack">Pack — Media (default)</h2>
|
||||
<p>Shipped in the standard <code>bridge-swarm-host</code> artifact (<code>bare-media</code> + <code>bare-ffmpeg</code> + image codecs).</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Command</th><th>Behavior</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>media.info</code></td><td>Probe image/video metadata</td></tr>
|
||||
<tr><td><code>media.imageTransform</code></td><td>Decode → optional resize/crop → encode (webp/jpeg/png); stream base64</td></tr>
|
||||
<tr><td><code>media.extractFrame</code></td><td>Extract one video frame → encode; stream base64</td></tr>
|
||||
<tr><td><code>media.transcode</code></td><td>Async job to webm/mp4/mkv (VP9+Opus where supported); progress events</td></tr>
|
||||
<tr><td><code>media.encodeStart</code></td><td>Start a live VP9/WebM session (<code>ingest: frames|segments</code>, egress page/swarm/file)</td></tr>
|
||||
<tr><td><code>media.encodePushFrame</code></td><td>Push a JPEG/WebP frame (base64) into the live session</td></tr>
|
||||
<tr><td><code>media.encodePush</code></td><td>Push a MediaRecorder timeslice, or a frame alias</td></tr>
|
||||
<tr><td><code>media.encodeSubscribe</code></td><td>Update fan-out <code>connIds</code> / page egress mid-session</td></tr>
|
||||
<tr><td><code>media.encodeStop</code></td><td>Flush the encoder, finalize the archive, emit <code>cap-end</code></td></tr>
|
||||
<tr><td><code>media.cancel</code></td><td>Cancel a batch job or a live session</td></tr>
|
||||
<tr><td><code>media.writeInput</code> / <code>media.readOutput</code></td><td>Chunked upload / download under <code>cap-jobs/</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="live-encode">Live encode notes</h2>
|
||||
<pre class="mermaid">
|
||||
flowchart LR
|
||||
In["Page ingest - JPEG frames / WebM slices"] --> Host["media.encode* - bare-ffmpeg VP9"]
|
||||
Host -->|"cap-chunk kind: segment"| PageOut["MSE on page"]
|
||||
Host -->|"BSML socket write"| SwarmOut["Peer connections"]
|
||||
Host --> FileOut["cap-jobs/session/live.webm"]
|
||||
</pre>
|
||||
<ul>
|
||||
<li>Chrome's native messaging host protocol caps messages at ~1 MB per message → ingest <strong>compressed JPEG frames</strong> (or WebM slices), not raw RGBA.</li>
|
||||
<li>Defaults for demos: <strong>640×360 @ 10fps</strong>; soft max around 720p @ 15fps; session max duration 10 minutes.</li>
|
||||
<li>Egress modes: <code>page</code> (MSE segments back to the sender), <code>swarm</code> (BSML-framed binary written directly onto Hyperswarm sockets), <code>file</code> (<code>cap-jobs/<sessionId>/live.webm</code>).</li>
|
||||
<li>Peer fan-out writes happen on the <strong>host socket</strong> (efficient for higher bitrates); the receiving page still reads via native messaging <code>conn.on('data')</code> unless you keep processing host-side.</li>
|
||||
<li>Helpers: <code>BridgeSwarm.media.liveSession(videoEl)</code> and <code>BridgeSwarm.media.attachLiveReceiver(conn, videoEl)</code>.</li>
|
||||
</ul>
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
After installing or updating the host on macOS, run <code>npm run repair:macos</code> so
|
||||
<code>.bare</code> addons (including ffmpeg) are re-extracted and code-signed. Then
|
||||
<strong>fully quit</strong> the browser before testing — a running process can hold a stale, unsigned
|
||||
addon in memory.
|
||||
</div>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.capabilities.has('media') // true</code></pre>
|
||||
<p>Demos: <a href="http://127.0.0.1:4173/live-encode/" target="_blank" rel="noopener">live-encode</a>, <a href="http://127.0.0.1:4173/media-demo/" target="_blank" rel="noopener">media-demo</a>, <a href="http://127.0.0.1:4173/clip-studio/" target="_blank" rel="noopener">clip-studio</a>.</p>
|
||||
|
||||
<h2 id="upcoming">Bundled for upcoming packs</h2>
|
||||
<p>These modules are dependencies of the default host but <strong>not yet</strong> exposed as page packs:</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Module</th><th>Planned pack</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>bare-fs</code> (already used internally)</td><td><code>fs</code> — read/write/list under allowlisted roots</td></tr>
|
||||
<tr><td><code>bare-sqlite</code></td><td><code>sqlite</code> — local DB under storage</td></tr>
|
||||
<tr><td><code>bare-fetch</code></td><td><code>net</code> — CORS-free host fetch</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>UI/mobile/build Bare packages (<code>bare-gtk</code>, <code>bare-ios</code>, <code>bare-build</code>, …) stay out of scope. Full module list: <a href="/docs/faq.html#modules">FAQ</a>.</p>
|
||||
|
||||
<h2 id="host-protocol">Host protocol</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>capabilities.list</code></td><td><code>{}</code></td><td><code>{ ok, packs: string[] }</code></td></tr>
|
||||
<tr><td><code>capabilities.has</code></td><td><code>{ pack }</code></td><td><code>{ ok, pack, has }</code></td></tr>
|
||||
<tr><td><code>capability</code></td><td><code>{ pack, cmd, payload }</code></td><td>pack-specific</td></tr>
|
||||
<tr><td><code>media.<cmd></code></td><td>same as <code>payload</code></td><td>shortcut when the pack is installed</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Unknown pack → <code>{ ok: false, error: "capability '…' not installed" }</code>.</p>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/protocols.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Protocols</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/examples.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Examples</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,268 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Data API · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="Hypercore, Hyperbee, Hyperdrive, Autobase, and Hyperdb over BridgeSwarm: named resources, resourceIds, auto-replicate, and storage paths.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/data.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Data API · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Hypercore, Hyperbee, Hyperdrive, Autobase, and Hyperdb over BridgeSwarm.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/data.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Data API · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Hypercore, Hyperbee, Hyperdrive, Autobase, and Hyperdb over BridgeSwarm.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html" class="active" aria-current="page">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Build with BridgeSwarm</p>
|
||||
<h1>Data API</h1>
|
||||
<p class="docs-lead">
|
||||
The native host runs a real <strong>Corestore</strong>, <strong>Hypercore</strong>,
|
||||
<strong>Hyperbee</strong>, <strong>Hyperdrive</strong>, <strong>Autobase</strong>, and
|
||||
<strong>Hyperdb</strong> — the same modules used server-side in the Holepunch ecosystem. Your page
|
||||
calls into them with <code>BridgeSwarm.request(type, payload[, options])</code>. Optional
|
||||
<code>options.timeoutMs</code> aborts the call after that many milliseconds.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#storage">Storage</a></li>
|
||||
<li><a href="#usage">Basic usage</a></li>
|
||||
<li><a href="#named-resources">Named resources & resourceIds</a></li>
|
||||
<li><a href="#hypercore">Hypercore</a></li>
|
||||
<li><a href="#hyperbee">Hyperbee</a></li>
|
||||
<li><a href="#hyperdrive">Hyperdrive</a></li>
|
||||
<li><a href="#autobase">Autobase</a></li>
|
||||
<li><a href="#hyperdb">Hyperdb</a></li>
|
||||
<li><a href="#attachment-replicate">Connection attachment & auto-replicate</a></li>
|
||||
<li><a href="#peer-control">Peer control</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="storage">Storage</h2>
|
||||
<p>
|
||||
Storage lives under the <code>BRIDGE_SWARM_STORAGE</code> environment variable, or
|
||||
<code>./bridge-swarm-storage</code> relative to the host process if unset. In a standard install this
|
||||
resolves to:
|
||||
</p>
|
||||
<pre class="code-block"><code>~/.bridgeswarm/bridge-swarm-storage/</code></pre>
|
||||
<p>
|
||||
The host keeps <strong>one Corestore</strong> plus a set of default Hyper* instances built on top of
|
||||
it. You can also open additional <strong>named</strong> resources (separate namespaces or specific
|
||||
keys) and target them with <code>resourceId</code> on subsequent operations.
|
||||
</p>
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
Corestore storage is sealed to the underlying device/inode. Copying it across filesystems (rather than
|
||||
moving it) can invalidate the seal and produce <em>"Invalid device file, was modified."</em> See
|
||||
<a href="/docs/user-guide.html#troubleshooting">User Guide → Troubleshooting</a>.
|
||||
</div>
|
||||
|
||||
<h2 id="usage">Basic usage</h2>
|
||||
<pre class="code-block"><code class="language-javascript">const res = await BridgeSwarm.request('beeGet', { key: 'foo' });
|
||||
if (res.ok) console.log(res.value);</code></pre>
|
||||
|
||||
<h2 id="named-resources">Named resources & resourceIds</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>coreOpen</code></td><td><code>{ name? }</code> or <code>{ keyHex }</code> or <code>{ namespace, name }</code></td><td><code>{ ok, resourceId, key, length, writable }</code></td></tr>
|
||||
<tr><td><code>beeOpen</code></td><td><code>{ name?, namespace? }</code></td><td><code>{ ok, resourceId, key }</code></td></tr>
|
||||
<tr><td><code>driveOpen</code></td><td><code>{ name?, namespace? }</code></td><td><code>{ ok, resourceId, key }</code></td></tr>
|
||||
<tr><td><code>autobaseOpen</code></td><td><code>{ name?, namespace?, viewName? }</code></td><td><code>{ ok, resourceId, length }</code></td></tr>
|
||||
<tr><td><code>hyperdbOpen</code></td><td><code>{ name?, namespace? }</code></td><td><code>{ ok, resourceId, key }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Pass <code>resourceId</code> on any data command below to target that resource instead of the default instance.</p>
|
||||
<pre class="code-block"><code class="language-javascript">const opened = await BridgeSwarm.request('coreOpen', { name: 'my-log' });
|
||||
await BridgeSwarm.request('coreAppend', { resourceId: opened.resourceId, data: 'entry-1' });
|
||||
const info = await BridgeSwarm.request('coreInfo', { resourceId: opened.resourceId });
|
||||
// { ok, key, length, writable }</code></pre>
|
||||
|
||||
<h2 id="hypercore">Hypercore</h2>
|
||||
<p>Append-only log. All commands accept an optional <code>resourceId</code>.</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>coreInfo</code></td><td><code>{ resourceId? }</code></td><td><code>{ ok, key (hex), length, writable }</code></td></tr>
|
||||
<tr><td><code>coreAppend</code></td><td><code>{ data | base64, resourceId? }</code></td><td><code>{ ok, length }</code></td></tr>
|
||||
<tr><td><code>coreGet</code></td><td><code>{ index, resourceId? }</code></td><td><code>{ ok, data }</code> (base64 or null)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.request('coreAppend', { data: JSON.stringify({ n: 1 }) });
|
||||
const first = await BridgeSwarm.request('coreGet', { index: 0 });
|
||||
console.log(atob(first.data));</code></pre>
|
||||
|
||||
<h2 id="hyperbee">Hyperbee</h2>
|
||||
<p>Key/value B-tree store, built on a Hypercore.</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>beeGet</code></td><td><code>{ key, resourceId? }</code></td><td><code>{ ok, key, value, seq }</code> or <code>{ ok, value: null }</code></td></tr>
|
||||
<tr><td><code>beePut</code></td><td><code>{ key, value, resourceId? }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>beeDel</code></td><td><code>{ key, resourceId? }</code></td><td><code>{ ok }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.request('beePut', { key: 'name', value: 'Alice' });
|
||||
const result = await BridgeSwarm.request('beeGet', { key: 'name' });
|
||||
console.log(result.value); // 'Alice'</code></pre>
|
||||
|
||||
<h2 id="hyperdrive">Hyperdrive</h2>
|
||||
<p>P2P file system on top of Hyperbee + Hypercore.</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>driveGet</code></td><td><code>{ path?, resourceId? }</code> (default <code>'/'</code>)</td><td><code>{ ok, data }</code> (base64 or null)</td></tr>
|
||||
<tr><td><code>drivePut</code></td><td><code>{ path, data | base64, resourceId? }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>driveList</code></td><td><code>{ path?, resourceId? }</code></td><td><code>{ ok, entries }</code></td></tr>
|
||||
<tr><td><code>driveDel</code></td><td><code>{ path, resourceId? }</code></td><td><code>{ ok }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.request('drivePut', { path: '/notes/hello.txt', data: 'Hello, drive!' });
|
||||
const list = await BridgeSwarm.request('driveList', { path: '/notes' });
|
||||
console.log(list.entries); // [{ key: '/notes/hello.txt', value: {...} }]</code></pre>
|
||||
|
||||
<h2 id="autobase">Autobase</h2>
|
||||
<p>Multi-writer linearized log — useful when several peers append independently and you need a single, deterministic ordering.</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>autobaseAppend</code></td><td><code>{ value | data, resourceId? }</code></td><td><code>{ ok, length }</code></td></tr>
|
||||
<tr><td><code>autobaseViewGet</code></td><td><code>{ index, resourceId? }</code></td><td><code>{ ok, data }</code></td></tr>
|
||||
<tr><td><code>autobaseInfo</code></td><td><code>{ resourceId? }</code></td><td><code>{ ok, length, signedLength }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="hyperdb">Hyperdb</h2>
|
||||
<p>
|
||||
Schema-based P2P database, generated from a <a href="https://github.com/holepunchto/hyperschema" target="_blank" rel="noopener">Hyperschema</a>
|
||||
definition (<code>npm run build:hyperdb</code> in the BridgeSwarm repo). The default schema ships two collections:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>@bridgeswarm/records</code> — <code>{ id, value }</code> (strings)</li>
|
||||
<li><code>@bridgeswarm/notes</code> — <code>{ id, title, body }</code> (strings)</li>
|
||||
</ul>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>hyperdbGet</code></td><td><code>{ collection, query, resourceId? }</code></td><td><code>{ ok, doc }</code></td></tr>
|
||||
<tr><td><code>hyperdbInsert</code></td><td><code>{ collection, doc, resourceId? }</code> — doc: <code>{ id, value }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>hyperdbDelete</code></td><td><code>{ collection, query, resourceId? }</code></td><td><code>{ ok }</code></td></tr>
|
||||
<tr><td><code>hyperdbFindToArray</code></td><td><code>{ collectionOrIndex, query?, limit?, reverse?, resourceId? }</code></td><td><code>{ ok, docs }</code></td></tr>
|
||||
<tr><td><code>hyperdbFlush</code></td><td><code>{ resourceId? }</code></td><td><code>{ ok }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.request('hyperdbInsert', {
|
||||
collection: 'records',
|
||||
doc: { id: '1', value: 'hello hyperdb' },
|
||||
});
|
||||
const rows = await BridgeSwarm.request('hyperdbFindToArray', {
|
||||
collectionOrIndex: 'records',
|
||||
limit: 20,
|
||||
});
|
||||
console.log(rows.docs);</code></pre>
|
||||
|
||||
<h2 id="attachment-replicate">Connection attachment & auto-replicate</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>attachReplication</code></td><td><code>{ connId, coreKeyHex?, resourceId? }</code></td><td><code>{ ok }</code> — host takes over the socket for Hypercore replication (no longer forwarded to the page)</td></tr>
|
||||
<tr><td><code>setAutoReplicate</code></td><td><code>{ swarmId, enabled, coreKeyHex?, resourceId? }</code></td><td><code>{ ok, enabled }</code> — when enabled, every new connection auto-runs <code>attachReplication</code>; those sockets are not usable for page chat/Protomux. Prefer <code>swarm.setAutoReplicate(...)</code>.</td></tr>
|
||||
<tr><td><code>attachHrpc</code></td><td><code>{ connId }</code></td><td><code>{ ok }</code> — see <a href="/docs/protocols.html">Protocols</a></td></tr>
|
||||
<tr><td><code>hrpcInvoke</code></td><td><code>{ connId, method, args?, streamId? }</code></td><td>Unary <code>{ ok, result }</code> or streaming <code>{ ok, streamId, streaming: true }</code> + <code>hrpc-chunk</code> / <code>hrpc-end</code> / <code>hrpc-error</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="peer-control">Peer control</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Type</th><th>Payload</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>setFirewall</code></td><td><code>{ swarmId, mode: 'off'|'allowlist'|'denylist', keys: string[] }</code></td><td><code>{ ok, mode, keys }</code></td></tr>
|
||||
<tr><td><code>banPeer</code></td><td><code>{ swarmId, publicKeyHex, banned? }</code></td><td><code>{ ok, banned, publicKeyHex }</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Prefer the page helpers: <code>swarm.setFirewall(...)</code>, <code>swarm.ban(publicKey)</code>, <code>peerInfo.ban()</code>.</p>
|
||||
|
||||
<div class="docs-callout docs-callout-info">
|
||||
See <a href="http://127.0.0.1:4173/data-demo/" target="_blank" rel="noopener">Data API demo</a> and
|
||||
<a href="http://127.0.0.1:4173/sync-demo/" target="_blank" rel="noopener">Auto-replicate demo</a> in
|
||||
the <a href="/docs/examples.html">Examples</a> gallery for these APIs in a working app.
|
||||
</div>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/api.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">API Reference</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/protocols.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Protocols</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,455 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Developer Guide · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="Build on BridgeSwarm: window.BridgeSwarm lifecycle, joining topics, connections, requests, named Hyper* resources, firewall/ban, auto-replicate, Protomux, HRPC, media, testing, packaging, and AGPL obligations.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/developer-guide.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Developer Guide · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Everything you need to build real applications on window.BridgeSwarm.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/developer-guide.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Developer Guide · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Everything you need to build real applications on window.BridgeSwarm.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html" class="active" aria-current="page">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Build with BridgeSwarm</p>
|
||||
<h1>Developer Guide</h1>
|
||||
<p class="docs-lead">
|
||||
This guide walks through everything you need to build a real application on
|
||||
<code>window.BridgeSwarm</code>: the injected API's lifecycle, joining topics, working with
|
||||
connections, the request/response surface, named Hyper* resources, peer control, Protomux and HRPC,
|
||||
the media capability, packaging pages that depend on the extension, testing, error handling,
|
||||
performance limits, and your AGPL obligations if you modify BridgeSwarm itself.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#architecture-for-builders">Architecture, for builders</a></li>
|
||||
<li><a href="#lifecycle">window.BridgeSwarm lifecycle</a></li>
|
||||
<li><a href="#joining-topics">Joining topics</a></li>
|
||||
<li><a href="#connections-api">Connections API</a></li>
|
||||
<li><a href="#request-types">BridgeSwarm.request types, overview</a></li>
|
||||
<li><a href="#named-resources">Named Hyper* resources</a></li>
|
||||
<li><a href="#firewall-ban">setFirewall and ban</a></li>
|
||||
<li><a href="#auto-replicate">setAutoReplicate</a></li>
|
||||
<li><a href="#protomux">createProtomux</a></li>
|
||||
<li><a href="#hrpc">hrpcCall</a></li>
|
||||
<li><a href="#media">BridgeSwarm.media — live encode</a></li>
|
||||
<li><a href="#settings-injection">Settings injection</a></li>
|
||||
<li><a href="#packaging">Packaging pages that depend on the extension</a></li>
|
||||
<li><a href="#testing">Testing with two tabs</a></li>
|
||||
<li><a href="#capability-allowlist">Capability allowlist under cap-jobs</a></li>
|
||||
<li><a href="#error-handling">Error handling</a></li>
|
||||
<li><a href="#performance">Performance limits (NMH ~1MB)</a></li>
|
||||
<li><a href="#agpl">AGPL obligations</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="architecture-for-builders">Architecture, for builders</h2>
|
||||
<p>
|
||||
Your page never touches the network directly. It calls <code>window.BridgeSwarm</code>, injected by
|
||||
the extension's content script, which relays through the background service worker to a native
|
||||
messaging host running the actual Hyperswarm stack under
|
||||
<a href="https://www.npmjs.com/package/bare" target="_blank" rel="noopener">Bare</a>.
|
||||
</p>
|
||||
<pre class="code-block"><code>Page ⇄(postMessage)⇄ content.js ⇄(runtime.sendMessage)⇄ background.js ⇄(native messaging)⇄ Native host</code></pre>
|
||||
<p>
|
||||
Requests are <code>{ id?, type, payload }</code>; the extension assigns <code>id</code> if you omit
|
||||
it. Responses are <code>{ id, type: 'response', payload }</code> where <code>payload</code> is either
|
||||
<code>{ ok: true, ... }</code> or <code>{ ok: false, error }</code>. Events are
|
||||
<code>{ type: 'event', event, payload }</code>, forwarded to subscribed tabs and delivered to the page
|
||||
as a <code>bridge-swarm-event</code> custom event. See <a href="/docs/architecture.html">Architecture</a>
|
||||
for full sequence diagrams.
|
||||
</p>
|
||||
|
||||
<h2 id="lifecycle">window.BridgeSwarm lifecycle</h2>
|
||||
<p>
|
||||
Because injection happens asynchronously, a script that runs at page load may execute before the API
|
||||
exists. Use <code>BridgeSwarm.ready()</code> to wait for it safely:
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">// Promise-based
|
||||
const BridgeSwarmCtor = await BridgeSwarm.ready();
|
||||
|
||||
// or callback-style
|
||||
BridgeSwarm.ready().then((swarm) => {
|
||||
// swarm here is actually the constructor — see note below
|
||||
});</code></pre>
|
||||
<p>
|
||||
If the extension option <strong>Default ready timeout (ms)</strong> is set above <code>0</code>,
|
||||
<code>ready()</code> rejects after that many milliseconds with
|
||||
<code>"BridgeSwarm not available within N ms"</code> — useful for showing a "please install the
|
||||
extension" message. The default is <code>0</code>, meaning wait indefinitely.
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">const swarm = new BridgeSwarm({
|
||||
appName: 'my-app', // string — passed to Hyperswarm on the host
|
||||
maxPeers: 50, // number — cap on peer connections for this swarm; 0 = unlimited
|
||||
});</code></pre>
|
||||
<p>
|
||||
Omit either option and the extension's configured defaults (from Settings) are used. Note that
|
||||
firewalling is <strong>not</strong> a constructor option or a JS predicate function — it's host-managed
|
||||
state you set after construction with <code>swarm.setFirewall(...)</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="joining-topics">Joining topics</h2>
|
||||
<pre class="code-block"><code class="language-javascript">await swarm.join('my-topic'); // string — hashed/normalized to a 32-byte topic
|
||||
// or with a 32-byte hex string directly:
|
||||
await swarm.join('a1b2c3...'.padEnd(64, '0'));
|
||||
|
||||
// leave later
|
||||
await swarm.leave('my-topic');</code></pre>
|
||||
<p>
|
||||
Under the hood this sends <code>init</code> (once per swarm) then <code>join</code> with
|
||||
<code>{ swarmId, topic }</code> to the host, which creates a Hyperswarm instance and joins the DHT
|
||||
topic. Both anounce and lookup happen by default, so any two peers that join the same topic will find
|
||||
each other.
|
||||
</p>
|
||||
|
||||
<h2 id="connections-api">Connections API</h2>
|
||||
<pre class="code-block"><code class="language-javascript">swarm.on('connection', (conn, peerInfo) => {
|
||||
// peerInfo: { publicKey: hex string, topics?: hex[] }
|
||||
// peerInfo.ban(banned?) is added by the page API for convenience
|
||||
|
||||
conn.on('data', (data) => {
|
||||
// data: Uint8Array (decoded from base64 on the wire)
|
||||
});
|
||||
conn.on('end', () => { /* peer disconnected */ });
|
||||
conn.on('error', (err) => { /* transport-level error */ });
|
||||
|
||||
// conn.write returns a Promise: resolves on success, rejects on host error
|
||||
conn.write('hello').catch((err) => console.error(err));
|
||||
});
|
||||
|
||||
// Snapshot of current connections (e.g. to broadcast to everyone)
|
||||
for (const conn of swarm.connections()) {
|
||||
conn.write('broadcast message');
|
||||
}</code></pre>
|
||||
<p>
|
||||
After <code>swarm.destroy()</code>, <code>swarm.connections()</code> returns <code>[]</code>. Each
|
||||
connection is already a Noise-encrypted, framed stream — you get one decrypted frame per
|
||||
<code>data</code> event.
|
||||
</p>
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
<strong>Host disconnects happen.</strong> Listen for <code>bridge-swarm-host-disconnect</code> on
|
||||
<code>window</code> to detect when the native messaging port drops. After this fires, existing
|
||||
swarms/connections are stale — call <code>swarm.destroy()</code> and rejoin, or prompt the user to
|
||||
refresh.
|
||||
</div>
|
||||
<pre class="code-block"><code class="language-javascript">window.addEventListener('bridge-swarm-host-disconnect', () => {
|
||||
showBanner('Disconnected from BridgeSwarm — reconnecting…');
|
||||
});</code></pre>
|
||||
|
||||
<h2 id="request-types">BridgeSwarm.request types, overview</h2>
|
||||
<p>
|
||||
Everything that isn't covered by a dedicated method goes through the generic request bridge:
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">const res = await BridgeSwarm.request(type, payload, { timeoutMs: 5000 });
|
||||
if (!res.ok) {
|
||||
console.error('request failed:', res.error);
|
||||
}</code></pre>
|
||||
<p>Request families, at a glance (full payload/response shapes in the <a href="/docs/api.html">API Reference</a>):</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Family</th><th>Examples</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Swarm lifecycle</td><td><code>init</code>, <code>join</code>, <code>leave</code>, <code>swarmKey</code>, <code>destroy</code></td></tr>
|
||||
<tr><td>Peer control</td><td><code>setFirewall</code>, <code>banPeer</code>, <code>setAutoReplicate</code></td></tr>
|
||||
<tr><td>Connections</td><td><code>write</code>, <code>destroyConnection</code></td></tr>
|
||||
<tr><td>Attachment</td><td><code>attachReplication</code>, <code>attachHrpc</code>, <code>hrpcInvoke</code></td></tr>
|
||||
<tr><td>Hypercore</td><td><code>coreOpen</code>, <code>coreInfo</code>, <code>coreAppend</code>, <code>coreGet</code></td></tr>
|
||||
<tr><td>Hyperbee</td><td><code>beeOpen</code>, <code>beeGet</code>, <code>beePut</code>, <code>beeDel</code></td></tr>
|
||||
<tr><td>Hyperdrive</td><td><code>driveOpen</code>, <code>driveGet</code>, <code>drivePut</code>, <code>driveList</code>, <code>driveDel</code></td></tr>
|
||||
<tr><td>Autobase</td><td><code>autobaseOpen</code>, <code>autobaseAppend</code>, <code>autobaseViewGet</code>, <code>autobaseInfo</code></td></tr>
|
||||
<tr><td>Hyperdb</td><td><code>hyperdbOpen</code>, <code>hyperdbGet</code>, <code>hyperdbInsert</code>, <code>hyperdbDelete</code>, <code>hyperdbFindToArray</code>, <code>hyperdbFlush</code></td></tr>
|
||||
<tr><td>Capabilities</td><td><code>capabilities.list</code>, <code>capabilities.has</code>, <code>capability</code>, <code>media.*</code></td></tr>
|
||||
<tr><td>Host inventory</td><td><code>host.snapshot</code> (read-only, used by the Control Center)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
Every response follows the same shape: success payloads include <code>ok: true</code> plus
|
||||
command-specific fields; failures are <code>{ ok: false, error: string }</code>. The returned Promise
|
||||
always <em>resolves</em> — check <code>.ok</code> rather than relying on a rejection, except for
|
||||
timeouts (see <a href="#error-handling">Error handling</a>).
|
||||
</p>
|
||||
|
||||
<h2 id="named-resources">Named Hyper* resources</h2>
|
||||
<p>
|
||||
The host keeps one Corestore and a set of default Hyper* instances, but you can also open additional
|
||||
<strong>named</strong> resources — separate namespaces or specific keys — and target them on
|
||||
subsequent calls with <code>resourceId</code>:
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">const opened = await BridgeSwarm.request('beeOpen', { name: 'chat-log' });
|
||||
// { ok, resourceId, key }
|
||||
|
||||
await BridgeSwarm.request('beePut', {
|
||||
resourceId: opened.resourceId,
|
||||
key: 'message-1',
|
||||
value: 'hello',
|
||||
});
|
||||
|
||||
const got = await BridgeSwarm.request('beeGet', {
|
||||
resourceId: opened.resourceId,
|
||||
key: 'message-1',
|
||||
});</code></pre>
|
||||
<p>
|
||||
Omit <code>resourceId</code> to use the default instance for that data type. See the full list of
|
||||
<code>*Open</code> commands in <a href="/docs/data.html">Data API</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="firewall-ban">setFirewall and ban</h2>
|
||||
<pre class="code-block"><code class="language-javascript">// Allowlist mode — only these public keys may connect
|
||||
await swarm.setFirewall({ mode: 'allowlist', keys: ['abc123...'] });
|
||||
|
||||
// Denylist mode — block specific keys, allow everyone else
|
||||
await swarm.setFirewall({ mode: 'denylist', keys: ['def456...'] });
|
||||
|
||||
// Off — no filtering (default)
|
||||
await swarm.setFirewall({ mode: 'off', keys: [] });
|
||||
|
||||
// Ban a peer you're already connected to
|
||||
await swarm.ban('abc123...');
|
||||
// or, from a connection event:
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
// peerInfo.ban() bans and closes this peer
|
||||
});</code></pre>
|
||||
<p>Banning updates the denylist and is enforced on future connection attempts as well.</p>
|
||||
|
||||
<h2 id="auto-replicate">setAutoReplicate</h2>
|
||||
<p>
|
||||
Opt a swarm into automatically taking over every new connection socket for Hypercore replication —
|
||||
no manual <code>attachReplication</code> call needed per peer:
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">await swarm.setAutoReplicate({
|
||||
enabled: true,
|
||||
coreKeyHex: myCore.key, // omit to replicate the default core
|
||||
resourceId: undefined, // or target a named resource instead
|
||||
});</code></pre>
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
Auto-replicated sockets are taken over by the host — they stop being usable for page chat/Protomux.
|
||||
At most one connection per peer, per swarm, is kept. Use this for sync-only swarms, not swarms that
|
||||
also need bidirectional page messaging on the same connections.
|
||||
</div>
|
||||
|
||||
<h2 id="protomux">createProtomux</h2>
|
||||
<p>
|
||||
BridgeSwarm injects a browser bundle of Protomux, compact-encoding (<code>c</code>), and
|
||||
<code>b4a</code> so you can run your own message-oriented mini-protocols directly in the page, on top
|
||||
of a raw connection:
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">swarm.on('connection', (conn, peerInfo) => {
|
||||
const mux = swarm.createProtomux(conn);
|
||||
if (!mux) return; // bundle not loaded — logs a warning
|
||||
|
||||
const ch = mux.createChannel({ protocol: 'my-app/v1' });
|
||||
const msg = ch.addMessage({
|
||||
encoding: window.BridgeSwarmProtomux.c.string,
|
||||
onmessage: (value) => console.log('got:', value),
|
||||
});
|
||||
ch.open();
|
||||
msg.send('hello over protomux');
|
||||
});</code></pre>
|
||||
<p>
|
||||
<code>createProtomux</code> wraps the connection in <code>BridgeSwarmFramedStream.wrapRawFrames(conn)</code>
|
||||
first, since each BridgeSwarm connection already delivers one decrypted Noise frame per chunk. Full
|
||||
reference: <a href="/docs/protocols.html">Protocols</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="hrpc">hrpcCall</h2>
|
||||
<p>
|
||||
For typed RPC (unary calls and streaming), BridgeSwarm's supported path is <strong>host HRPC</strong>,
|
||||
not in-page protomux-rpc. Attach it on a connection, then call:
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.request('attachHrpc', { connId: conn.connId });
|
||||
|
||||
const pong = await swarm.hrpcCall(conn.connId, 'ping', { value: 'hi' });
|
||||
|
||||
const sum = await swarm.hrpcCall(conn.connId, 'fetchStream', { count: 3 }, {
|
||||
onChunk: (chunk) => console.log('chunk:', chunk),
|
||||
timeoutMs: 20000,
|
||||
});</code></pre>
|
||||
<p>
|
||||
Both peers must attach HRPC on the same connection; the first invoke may wait up to 12 seconds for the
|
||||
channel to pair. Full command spec: <a href="/docs/protocols.html#hrpc">Protocols → HRPC</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="media">BridgeSwarm.media — live encode</h2>
|
||||
<p>
|
||||
The default host bundles <code>bare-media</code> + <code>bare-ffmpeg</code>, exposed as the
|
||||
<code>media</code> capability pack. Beyond batch jobs (probe, transform, extract-frame, transcode),
|
||||
it supports a <strong>live</strong> VP9/WebM encode session driven from the page:
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">const live = BridgeSwarm.media.liveSession(videoEl);
|
||||
|
||||
await live.start({ width: 640, height: 360, fps: 10, ingest: 'frames' });
|
||||
|
||||
// Push compressed JPEG frames captured from a canvas — not raw RGBA
|
||||
await live.pushFrame(canvas);
|
||||
|
||||
// Fan out the host-side encode to specific peer connections
|
||||
await live.subscribe({ swarm: { connIds: [conn.connId] } });
|
||||
|
||||
await live.stop();</code></pre>
|
||||
<p>
|
||||
On the receiving side, <code>BridgeSwarm.media.attachLiveReceiver(conn, videoEl)</code> wires up MSE
|
||||
playback of a peer's live stream. Defaults for demos are 640×360 @ 10fps, with a soft ceiling around
|
||||
720p @ 15fps and a 10-minute session cap. See <a href="/docs/capabilities.html">Capabilities</a> for
|
||||
the full command list, event shapes, and security constraints.
|
||||
</p>
|
||||
|
||||
<h2 id="settings-injection">Settings injection</h2>
|
||||
<p>
|
||||
The content script reads <code>bridgeSwarmSettings</code> from extension storage and injects a
|
||||
<code>__BRIDGESWARM_DEFAULTS__</code> object into the page before <code>api.js</code> loads.
|
||||
Constructor options you pass explicitly always take precedence; anything you omit falls back to these
|
||||
injected defaults (default app name, max peers, timeouts, firewall). This is also how the
|
||||
"Disable on <code>file://</code> URLs" setting takes effect — the content script simply skips
|
||||
injection entirely on matching origins.
|
||||
</p>
|
||||
|
||||
<h2 id="packaging">Packaging pages that depend on the extension</h2>
|
||||
<ul>
|
||||
<li><strong>Never rely on <code>file://</code>.</strong> Serve your app over <code>http://</code> or <code>https://</code> — even locally — so injection and same-origin behavior work correctly.</li>
|
||||
<li><strong>Feature-detect, don't assume.</strong> Always gate BridgeSwarm-dependent UI behind <code>await BridgeSwarm.ready()</code> (with a sane timeout) so your page degrades gracefully without the extension installed.</li>
|
||||
<li><strong>Handle host disconnects.</strong> Wire up the <code>bridge-swarm-host-disconnect</code> listener before you create any swarms.</li>
|
||||
<li><strong>Don't hardcode <code>:4173</code> in production.</strong> That port is specific to the bundled examples server; ship your own app on whatever origin makes sense for you.</li>
|
||||
<li><strong>Ship your own protomux protocol strings.</strong> Namespace your <code>protocol</code> (and <code>id</code>, if used) so you don't collide with other BridgeSwarm-enabled apps sharing a topic space.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="testing">Testing with two tabs</h2>
|
||||
<p>
|
||||
Because each browser tab gets its own key pair, the fastest test loop for anything P2P is two tabs on
|
||||
the same machine:
|
||||
</p>
|
||||
<ol>
|
||||
<li>Serve your page locally (or use the bundled examples server as a template — see <a href="/docs/examples.html">Examples</a>).</li>
|
||||
<li>Open it in two tabs (or two profiles, for a cleaner peerInfo separation).</li>
|
||||
<li>Join the same topic in both; watch the Control Center's <strong>Connections</strong> and <strong>Activity</strong> tabs while you interact.</li>
|
||||
<li>Enable <strong>Debug logging</strong> in Settings for verbose console output during development.</li>
|
||||
</ol>
|
||||
|
||||
<h2 id="capability-allowlist">Capability allowlist under cap-jobs</h2>
|
||||
<p>
|
||||
Filesystem access for capability packs is restricted to one allowlisted tree:
|
||||
</p>
|
||||
<pre class="code-block"><code>$BRIDGE_SWARM_STORAGE/cap-jobs/
|
||||
# default: ~/.bridgeswarm/bridge-swarm-storage/cap-jobs/</code></pre>
|
||||
<p>
|
||||
Absolute paths outside that tree are rejected by the host. Chunked upload/download helpers
|
||||
(<code>media.writeInput</code> / <code>media.readOutput</code>) and live-encode file archives all
|
||||
live under this directory. If you extend the host with your own capability pack, keep any file I/O
|
||||
scoped the same way.
|
||||
</p>
|
||||
|
||||
<h2 id="error-handling">Error handling</h2>
|
||||
<ul>
|
||||
<li><strong>Command failures</strong> resolve (not reject) as <code>{ ok: false, error: string }</code> — always check <code>.ok</code>.</li>
|
||||
<li><strong><code>conn.write(data)</code></strong> returns a Promise that <em>does</em> reject on host error (e.g. "Connection not found"), and the connection also emits an <code>error</code> event — handle both, or at least <code>.catch()</code> the write.</li>
|
||||
<li><strong>Timeouts</strong> — pass <code>{ timeoutMs }</code> as the third argument to <code>BridgeSwarm.request</code> (or via <code>hrpcCall</code>'s options) to abort and reject with <code>"Request timed out after N ms"</code>. Without an explicit value, the extension's configured default request timeout applies if set above <code>0</code>.</li>
|
||||
<li><strong>Unknown capability packs</strong> return <code>{ ok: false, error: "capability '…' not installed" }</code> rather than throwing.</li>
|
||||
<li><strong>Host disconnects</strong> invalidate all live swarms/connections — listen for <code>bridge-swarm-host-disconnect</code> and treat existing state as stale.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="performance">Performance limits (NMH ~1MB)</h2>
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
Chrome's native messaging host protocol caps messages from the host to the browser at roughly
|
||||
<strong>1 MB</strong>. This shapes several API design choices you should follow in your own code.
|
||||
</div>
|
||||
<ul>
|
||||
<li>Binary payloads are base64-encoded on the wire, which adds ~33% overhead on top of the raw byte size — budget accordingly.</li>
|
||||
<li>Stream large results as chunked events (<code>cap-chunk</code> / <code>hrpc-chunk</code>) instead of one giant response.</li>
|
||||
<li>For live media, ingest <strong>compressed JPEG frames</strong> (or WebM timeslices) rather than raw RGBA frames from a canvas — raw frames blow past the limit almost immediately at any real resolution.</li>
|
||||
<li>For large file transfers over Hyperdrive, prefer many small <code>drivePut</code> calls (or chunked capability I/O) over one enormous payload.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="agpl">AGPL obligations</h2>
|
||||
<p>
|
||||
BridgeSwarm is licensed under <a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noopener">AGPL-3.0</a>.
|
||||
The AGPL's key difference from GPL is its network clause (§13): if you modify BridgeSwarm itself (the
|
||||
extension or the native host) and let others interact with your modified version <strong>over a
|
||||
network</strong>, you must offer them the corresponding modified source.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Building ordinary pages/apps that merely <em>use</em> <code>window.BridgeSwarm</code> as an API is normal usage and does not, by itself, place your application under AGPL — the copyleft is triggered by distributing or network-serving a <em>modified BridgeSwarm</em>, not by writing a page that talks to it.</li>
|
||||
<li>If you fork the extension or native host and offer it as a service (e.g. a rebranded install flow, a hosted relay, a modified capability pack), you must make your modified source available to users of that service.</li>
|
||||
<li>Review the full license text and talk to counsel for your specific situation — this page is not legal advice.</li>
|
||||
</ul>
|
||||
<p>Questions about licensing: <a href="mailto:[email protected]">[email protected]</a>. More detail in <a href="/docs/security.html#agpl">Security → AGPL</a>.</p>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/user-guide.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">User Guide</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/architecture.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Architecture</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,219 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Examples · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="Full catalog of BridgeSwarm demos — chat, firewall room, whiteboard, screenshare, live encode, media studio, clip studio, data API, auto-replicate, SDK demo, and HRPC demo — with what each teaches and its URL on :4173.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/examples.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Examples · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Every bundled BridgeSwarm demo, with what it teaches and how to run it.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/examples.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Examples · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Every bundled BridgeSwarm demo, with what it teaches.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html" class="active" aria-current="page">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Reference</p>
|
||||
<h1>Examples</h1>
|
||||
<p class="docs-lead">
|
||||
BridgeSwarm ships twelve working demos that double as reference implementations for every major
|
||||
feature. Enable the <strong>examples server</strong> in Settings (or run <code>npm run examples</code>
|
||||
from source) and open <a href="http://127.0.0.1:4173/" target="_blank" rel="noopener"><code>http://127.0.0.1:4173/</code></a>.
|
||||
Most demos are peer-to-peer — open the same URL in two tabs.
|
||||
</p>
|
||||
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
<strong>Do not open examples via <code>file://</code>.</strong> Modern Chrome/Firefox treat each local
|
||||
file as a unique opaque origin, which breaks scripts, styles, and extension injection. Always use
|
||||
<code>http://127.0.0.1:4173/…</code>.
|
||||
</div>
|
||||
|
||||
<h2>Run the examples server</h2>
|
||||
<p>
|
||||
<strong>Recommended:</strong> in the BridgeSwarm extension, open <strong>Settings</strong> (or
|
||||
Dashboard → Settings) and enable <strong>Examples server</strong>. Settings save automatically.
|
||||
</p>
|
||||
<p>From the BridgeSwarm repo root, the dev alternative:</p>
|
||||
<pre class="code-block"><code class="language-bash">npm run examples</code></pre>
|
||||
<p>Either way, use <strong>http://127.0.0.1:4173/</strong>. Shared chrome (theme, layout, boot script) lives in the repo's <code>examples/shared/</code> and is reused by every demo.</p>
|
||||
|
||||
<h2>Demo index</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Demo</th><th>URL</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Landing</td><td><a href="http://127.0.0.1:4173/" target="_blank" rel="noopener">http://127.0.0.1:4173/</a></td></tr>
|
||||
<tr><td>Chat</td><td><a href="http://127.0.0.1:4173/chat/" target="_blank" rel="noopener">http://127.0.0.1:4173/chat/</a></td></tr>
|
||||
<tr><td>Advanced Chat</td><td><a href="http://127.0.0.1:4173/chat-advanced/" target="_blank" rel="noopener">http://127.0.0.1:4173/chat-advanced/</a></td></tr>
|
||||
<tr><td>Firewall Room</td><td><a href="http://127.0.0.1:4173/firewall-room/" target="_blank" rel="noopener">http://127.0.0.1:4173/firewall-room/</a></td></tr>
|
||||
<tr><td>Whiteboard</td><td><a href="http://127.0.0.1:4173/whiteboard/" target="_blank" rel="noopener">http://127.0.0.1:4173/whiteboard/</a></td></tr>
|
||||
<tr><td>Screenshare</td><td><a href="http://127.0.0.1:4173/screenshare/" target="_blank" rel="noopener">http://127.0.0.1:4173/screenshare/</a></td></tr>
|
||||
<tr><td>Data API</td><td><a href="http://127.0.0.1:4173/data-demo/" target="_blank" rel="noopener">http://127.0.0.1:4173/data-demo/</a></td></tr>
|
||||
<tr><td>Auto-replicate</td><td><a href="http://127.0.0.1:4173/sync-demo/" target="_blank" rel="noopener">http://127.0.0.1:4173/sync-demo/</a></td></tr>
|
||||
<tr><td>Live Encode</td><td><a href="http://127.0.0.1:4173/live-encode/" target="_blank" rel="noopener">http://127.0.0.1:4173/live-encode/</a></td></tr>
|
||||
<tr><td>Media Studio</td><td><a href="http://127.0.0.1:4173/media-demo/" target="_blank" rel="noopener">http://127.0.0.1:4173/media-demo/</a></td></tr>
|
||||
<tr><td>Clip Studio</td><td><a href="http://127.0.0.1:4173/clip-studio/" target="_blank" rel="noopener">http://127.0.0.1:4173/clip-studio/</a></td></tr>
|
||||
<tr><td>SDK Demo</td><td><a href="http://127.0.0.1:4173/sdk-demo/" target="_blank" rel="noopener">http://127.0.0.1:4173/sdk-demo/</a></td></tr>
|
||||
<tr><td>HRPC Demo</td><td><a href="http://127.0.0.1:4173/hrpc-demo/" target="_blank" rel="noopener">http://127.0.0.1:4173/hrpc-demo/</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Connect</h2>
|
||||
<div class="docs-card-grid">
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/chat/" target="_blank" rel="noopener">
|
||||
<h3>Chat</h3>
|
||||
<p>Minimal P2P chat over a topic — the smallest complete BridgeSwarm example, good first read.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/chat-advanced/" target="_blank" rel="noopener">
|
||||
<h3>Advanced Chat</h3>
|
||||
<p>Rooms, presence, markdown, emoji, and file sharing on top of the same core primitives.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/firewall-room/" target="_blank" rel="noopener">
|
||||
<h3>Firewall Room</h3>
|
||||
<p><code>setFirewall</code> allowlist/denylist and <code>ban</code> peers, live.</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h2>Collaborate</h2>
|
||||
<div class="docs-card-grid">
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/whiteboard/" target="_blank" rel="noopener">
|
||||
<h3>Whiteboard</h3>
|
||||
<p>Collaborative canvas with color and size tools, synced over raw <code>conn.write</code> messages.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/screenshare/" target="_blank" rel="noopener">
|
||||
<h3>Screenshare</h3>
|
||||
<p>Live <strong>WebRTC</strong> video — BridgeSwarm is signaling only here, not host ffmpeg.</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h2>Media</h2>
|
||||
<div class="docs-card-grid">
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/live-encode/" target="_blank" rel="noopener">
|
||||
<h3>Live Encode</h3>
|
||||
<p>Host <strong>bare-ffmpeg</strong> live VP9/WebM: capture → JPEG frames → MSE preview of the host's own encode, with optional peer fan-out.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/media-demo/" target="_blank" rel="noopener">
|
||||
<h3>Media Studio</h3>
|
||||
<p>Probe, WebP transform, extract frame, and batch transcode via <code>BridgeSwarm.media.*</code>.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/clip-studio/" target="_blank" rel="noopener">
|
||||
<h3>Clip Studio</h3>
|
||||
<p>Record screen/camera → nearline batch <code>transcode</code> / poster generation (not continuous live encode).</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h2>Data</h2>
|
||||
<div class="docs-card-grid">
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/data-demo/" target="_blank" rel="noopener">
|
||||
<h3>Data API</h3>
|
||||
<p>Hypercore / Hyperbee / Hyperdrive / Hyperdb via <code>BridgeSwarm.request</code>.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/sync-demo/" target="_blank" rel="noopener">
|
||||
<h3>Auto-replicate</h3>
|
||||
<p><code>setAutoReplicate</code> Hypercore sync across peers. Note: those sockets are taken over for replication and stop forwarding page data.</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h2>Platform</h2>
|
||||
<div class="docs-card-grid">
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/sdk-demo/" target="_blank" rel="noopener">
|
||||
<h3>SDK Demo</h3>
|
||||
<p>Swarm lifecycle, raw messages, and Protomux end to end.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/hrpc-demo/" target="_blank" rel="noopener">
|
||||
<h3>HRPC Demo</h3>
|
||||
<p>Typed RPC — ping and both streaming directions. See <a href="/docs/protocols.html#hrpc">Protocols → HRPC</a>.</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h2>Troubleshooting</h2>
|
||||
<ol>
|
||||
<li>Wait a moment for content-script injection after the page loads, then retry.</li>
|
||||
<li>Confirm the BridgeSwarm extension and native host are both installed and the browser was restarted after install.</li>
|
||||
<li>Confirm you're on <code>http://127.0.0.1:4173/…</code>, not <code>file://</code>.</li>
|
||||
<li>For media demos on macOS after a host update, run <code>npm run repair:macos</code>, then fully quit the browser.</li>
|
||||
</ol>
|
||||
|
||||
<div class="docs-callout docs-callout-info">
|
||||
The <code>examples/</code> tree in the repository is the source of truth for all demos;
|
||||
<code>npm run sync:examples</code> copies it into <code>extension/examples/</code> and
|
||||
<code>native-host/examples/</code> for packaging into release artifacts.
|
||||
</div>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/capabilities.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Capabilities</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/security.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Security</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,405 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>FAQ · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="Frequently asked questions about BridgeSwarm: supported browsers, mobile support, performance limits, licensing, storage, security, and more.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/faq.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="FAQ · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Answers to the most common BridgeSwarm questions.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/faq.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="FAQ · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Answers to the most common BridgeSwarm questions.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
"mainEntity": [
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What browsers does BridgeSwarm support?",
|
||||
"acceptedAnswer": { "@type": "Answer", "text": "Chrome 88+, Edge, and Firefox 79+ on desktop. Desktop only — native messaging is not available on mobile browsers." }
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "Does BridgeSwarm work on mobile?",
|
||||
"acceptedAnswer": { "@type": "Answer", "text": "No. BridgeSwarm relies on Chrome/Firefox native messaging to talk to a local native host process, which mobile browsers do not support." }
|
||||
},
|
||||
{
|
||||
"@type": "Question",
|
||||
"name": "What license is BridgeSwarm released under?",
|
||||
"acceptedAnswer": { "@type": "Answer", "text": "GNU Affero General Public License v3.0 (AGPL-3.0), owned and engineered by HoneyPeer, LLC." }
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html" class="active" aria-current="page">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Reference</p>
|
||||
<h1>Frequently Asked Questions</h1>
|
||||
<p class="docs-lead">
|
||||
Short answers to the questions that come up most, grouped by topic. If yours isn't here, check the
|
||||
<a href="/docs/user-guide.html#troubleshooting">User Guide's troubleshooting section</a> or the
|
||||
<a href="/docs/security.html">Security</a> page.
|
||||
</p>
|
||||
|
||||
<h2>General</h2>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>What is BridgeSwarm?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
BridgeSwarm brings the real Hyperswarm P2P stack — Hypercore, Hyperbee, Hyperdrive, Autobase,
|
||||
Hyperdb, Protomux, and HRPC — into normal desktop browsers without forking Chrome or Firefox. A
|
||||
<a href="https://www.npmjs.com/package/bare" target="_blank" rel="noopener">Bare</a>-based native
|
||||
host runs the actual modules; a Manifest V3 extension injects <code>window.BridgeSwarm</code> into
|
||||
pages and relays messages over native messaging.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Why not just use WebRTC?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
WebRTC is peer-to-peer transport only — you still need signaling infrastructure, and it doesn't
|
||||
give you durable, replicable append-only data structures. BridgeSwarm gives you Hyperswarm's DHT
|
||||
for discovery/NAT traversal <em>and</em> the full Holepunch data stack (Hypercore, Hyperbee,
|
||||
Hyperdrive, Autobase, Hyperdb) in the same page, with no server to run. That said, BridgeSwarm
|
||||
doesn't replace WebRTC for everything — the <a href="http://127.0.0.1:4173/screenshare/" target="_blank" rel="noopener">screenshare demo</a>
|
||||
actually uses WebRTC for video and BridgeSwarm purely for signaling.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>What browsers does BridgeSwarm support?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>Chrome 88+, Edge, and Firefox 79+ — desktop builds only.</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Does BridgeSwarm work on mobile?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
No. Native messaging — the mechanism the extension uses to talk to the local host process — isn't
|
||||
available on mobile browsers.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Do I need Node.js installed to use BridgeSwarm?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
No, not for a normal install. The release installer downloads prebuilt Bare host binaries for
|
||||
darwin/linux/win32 — no Node required for end users. Node is only needed for from-source
|
||||
development and CI tooling; the host itself runs on Bare (<code>>=1.29.4</code> via the
|
||||
<code>bare</code> npm dependency).
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<h2>Installation & setup</h2>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Do I need to restart my browser after installing?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Yes — fully quit the browser (Cmd+Q / Quit, not just closing windows) so it picks up the
|
||||
native-messaging manifest and any newly signed native addons.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Can BridgeSwarm coexist with other extensions using native messaging (like holesail-browser)?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Yes, by design. BridgeSwarm uses its own install directory (<code>~/.bridgeswarm/</code>), its own
|
||||
native-messaging host name (<code>com.bridgeswarm</code>), and its own extension IDs. The
|
||||
installer explicitly refuses to run if any of its identity values collide with known
|
||||
holesail-browser identifiers, and it never touches holesail-browser's install directory or
|
||||
manifest.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Where does BridgeSwarm store data?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Under <code>BRIDGE_SWARM_STORAGE</code>, or <code>~/.bridgeswarm/bridge-swarm-storage/</code> by
|
||||
default. This holds your Corestore (backing Hypercore/Hyperbee/Hyperdrive/Autobase/Hyperdb) plus
|
||||
capability job output under <code>cap-jobs/</code>. Extension settings live separately, in the
|
||||
browser's own <code>chrome.storage.local</code>.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<h2>Development</h2>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Can I use BridgeSwarm from a plain HTML page, or do I need a framework?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Plain HTML/JS is enough — see <a href="/docs/quickstart.html">Quick Start</a> for a complete
|
||||
working snippet with no build step. The bundled demos are also mostly framework-free.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Why does my page need to run on http://, not file://?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Modern Chrome/Firefox treat each <code>file://</code> document as its own unique opaque origin,
|
||||
which breaks both regular script/style loading and the content script's ability to reliably
|
||||
inject <code>window.BridgeSwarm</code>. Serve your app over <code>http://</code> or
|
||||
<code>https://</code> — even a trivial local static server works.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>How do I test peer-to-peer features without a second machine?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Open your app in two browser tabs. Each tab gets its own cryptographic identity, so two tabs
|
||||
joining the same topic is a fully realistic two-peer test. See
|
||||
<a href="/docs/developer-guide.html#testing">Developer Guide → Testing with two tabs</a>.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>What's the difference between BridgeSwarm.request and the higher-level methods like swarm.join?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
<code>swarm.join()</code>, <code>swarm.setFirewall()</code>, <code>swarm.ban()</code>, and friends
|
||||
are thin, ergonomic wrappers that call <code>BridgeSwarm.request()</code> under the hood with the
|
||||
right <code>type</code>/<code>payload</code> shape. Anything not covered by a dedicated method
|
||||
(Hyper* data commands, capability calls, host snapshot) is available directly via
|
||||
<code>BridgeSwarm.request(type, payload)</code>. See the <a href="/docs/api.html">API
|
||||
Reference</a>.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<h2 id="modules">Capabilities & modules</h2>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>What Bare modules does the default host actually ship?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>Runtime/platform: <code>bare</code>, <code>bare-process</code>, <code>bare-module</code>, <code>bare-fs</code>, <code>bare-path</code>, <code>bare-stream</code>, <code>bare-http1</code>.</p>
|
||||
<p>Holepunch data + swarm: <code>hyperswarm</code>, <code>hypercore</code>/<code>corestore</code>, <code>hyperbee</code>, <code>hyperdrive</code>, <code>autobase</code>, <code>hyperdb</code>/<code>hyperschema</code>, <code>hrpc</code>, <code>protomux</code>/<code>compact-encoding</code>/<code>b4a</code>.</p>
|
||||
<p>Media (default capability): <code>bare-media</code>, <code>bare-ffmpeg</code>, and image codecs (<code>bare-jpeg</code>, <code>bare-png</code>, <code>bare-webp</code>, <code>bare-gif</code>, <code>bare-heif</code>, <code>bare-bmp</code>, <code>bare-ico</code>, <code>bare-tiff</code>, <code>bare-svg</code>, <code>bare-image-resample</code>, <code>bare-exif</code>).</p>
|
||||
<p>Local power (bundled, not yet exposed as page packs): <code>bare-sqlite</code>, <code>bare-fetch</code>.</p>
|
||||
<p>Full list: <a href="/docs/capabilities.html#upcoming">Capabilities → Bundled for upcoming packs</a>.</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Why aren't all ~150 bare-* packages exposed as capabilities?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Curated packs are intentional: page-facing APIs are limited to what fits BridgeSwarm's actual
|
||||
product surface (P2P networking, Hyper* data, and controlled local power like media). UI/mobile/
|
||||
build-tooling packages (<code>bare-gtk</code>, <code>bare-ios</code>, <code>bare-android</code>,
|
||||
<code>bare-build</code>) are the wrong surface entirely. Open subprocess execution and raw LAN
|
||||
socket listening are intentionally not exposed as page APIs — they're too easy to abuse without
|
||||
much more sandboxing than the current model provides.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Can I write my own capability pack?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
The host's capability dispatch (<code>capabilities.list</code> / <code>capabilities.has</code> /
|
||||
<code>capability</code>) is designed to support additional packs beyond media. If you extend the
|
||||
host with your own pack, keep any filesystem access scoped the same way the media pack is —
|
||||
allowlisted under <code>cap-jobs/</code> — and remember that shipping a modified host to others
|
||||
over a network triggers AGPL's source-offer obligation. See
|
||||
<a href="/docs/security.html#agpl-section">Security → AGPL-3.0</a>.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<h2>Performance & limits</h2>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>What's the message size limit, and why?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Chrome's native messaging host protocol caps messages from the host to the browser at roughly
|
||||
<strong>1 MB</strong>. This is a browser-imposed constraint, not a BridgeSwarm choice — it
|
||||
shapes API design toward chunked/streaming transfers (capability <code>cap-chunk</code> events,
|
||||
HRPC streaming) for anything larger. See
|
||||
<a href="/docs/developer-guide.html#performance">Developer Guide → Performance limits</a>.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Why does live encode want JPEG frames instead of raw video?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Raw RGBA frames from a canvas blow past the ~1 MB native-messaging limit almost immediately
|
||||
at any usable resolution. Compressed JPEG frames (or WebM timeslices) keep each message small
|
||||
enough to ingest reliably. Defaults for demos are 640×360 @ 10fps, with a soft ceiling around
|
||||
720p @ 15fps and a 10-minute session cap. See <a href="/docs/capabilities.html#live-encode">Capabilities → Live encode notes</a>.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Is there a limit on peer connections?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
You can cap peers per swarm with the <code>maxPeers</code> constructor option (<code>0</code> =
|
||||
unlimited, or the extension's configured default applies). There's no hardcoded low ceiling beyond
|
||||
what you configure.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<h2>Licensing & trust</h2>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>What license is BridgeSwarm released under?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noopener">GNU Affero
|
||||
General Public License v3.0 (AGPL-3.0)</a>. Owned and engineered by <strong>HoneyPeer, LLC</strong>
|
||||
(DeKalb County, Georgia, USA). Legal contact: <a href="mailto:[email protected]">[email protected]</a>.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Does building an app on top of BridgeSwarm make my app AGPL?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
Using <code>window.BridgeSwarm</code> as an API from your own page is ordinary usage, not
|
||||
modification or distribution of BridgeSwarm itself — it doesn't automatically place your
|
||||
application under AGPL. The copyleft applies if you modify BridgeSwarm's extension or native host
|
||||
and let others interact with that modified version over a network. See
|
||||
<a href="/docs/security.html#agpl-section">Security → AGPL-3.0</a> and
|
||||
<a href="/docs/developer-guide.html#agpl">Developer Guide → AGPL obligations</a>. This is general
|
||||
information, not legal advice.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Is my data sent to any BridgeSwarm-operated server?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
No. There is no backend service and no telemetry. All persistent state lives locally under your
|
||||
own <code>bridge-swarm-storage/</code> directory, and network traffic only ever goes directly to
|
||||
peers you connect to over Hyperswarm — encrypted with Noise. See
|
||||
<a href="/docs/user-guide.html#privacy">User Guide → Privacy & local storage</a>.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="docs-faq-item">
|
||||
<summary>Is it safe to leave the native host running all the time?</summary>
|
||||
<div class="docs-faq-body">
|
||||
<p>
|
||||
It only does work when a BridgeSwarm-enabled page has active swarms, connections, or capability
|
||||
jobs, and it only ever listens on <code>127.0.0.1</code> (the examples server) plus whatever
|
||||
Hyperswarm sockets your pages open. As with any locally installed background process, only run
|
||||
builds you trust.
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<div class="docs-callout docs-callout-info">
|
||||
Still stuck? Check <a href="/docs/user-guide.html#troubleshooting">User Guide → Troubleshooting</a>
|
||||
for specific error messages, or review the full <a href="/docs/security.html">Security</a> model.
|
||||
</div>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/security.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Security</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/release.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Release Notes</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,243 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Documentation · BridgeSwarm</title>
|
||||
<meta name="description" content="BridgeSwarm documentation hub: quick start, user guide, developer guide, architecture, API reference, data API, protocols, capabilities, examples, security, and FAQ.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/index.html">
|
||||
|
||||
<!-- Favicons -->
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Styles -->
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<!-- Open Graph / Twitter -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Documentation · BridgeSwarm">
|
||||
<meta property="og:description" content="Everything you need to install, use, and build on BridgeSwarm: guides, architecture, full API reference, and demo catalog.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/index.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Documentation · BridgeSwarm">
|
||||
<meta name="twitter:description" content="Everything you need to install, use, and build on BridgeSwarm.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "TechArticle",
|
||||
"headline": "BridgeSwarm Documentation",
|
||||
"description": "Documentation hub for BridgeSwarm, a bridge that brings the Hyperswarm P2P stack into desktop browsers.",
|
||||
"publisher": { "@type": "Organization", "name": "HoneyPeer, LLC" }
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article docs-hub">
|
||||
<p class="docs-eyebrow">Documentation</p>
|
||||
<h1>BridgeSwarm Documentation</h1>
|
||||
<p class="docs-lead">
|
||||
BridgeSwarm brings the real <strong>Hyperswarm P2P stack</strong> — Hypercore, Hyperbee, Hyperdrive,
|
||||
Autobase, Hyperdb, Protomux, and HRPC — into normal desktop browsers, without forking Chrome or
|
||||
Firefox. A <a href="https://www.npmjs.com/package/bare" target="_blank" rel="noopener">Bare</a>-based
|
||||
native host runs the modules; a Manifest V3 extension injects <code>window.BridgeSwarm</code> into
|
||||
the page and relays messages over native messaging. Everything below is organized so you can go from
|
||||
zero to a working peer-to-peer page in minutes, then dig as deep as you need.
|
||||
</p>
|
||||
|
||||
<div class="docs-callout docs-callout-info">
|
||||
<strong>New here?</strong> Start with <a href="/docs/quickstart.html">Quick Start</a> — install the
|
||||
extension and native host, load the examples server, and join your first swarm in under five minutes.
|
||||
</div>
|
||||
|
||||
<h2>Browse the docs</h2>
|
||||
<div class="docs-card-grid">
|
||||
|
||||
<a class="docs-card" href="/docs/quickstart.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🚀</span>
|
||||
<h3>Quick Start</h3>
|
||||
<p>Install the host and extension, load the demo gallery, and write your first join/write snippet.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/user-guide.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🧭</span>
|
||||
<h3>User Guide</h3>
|
||||
<p>Installing BridgeSwarm, the Control Center (Overview, Swarms, Connections, Activity, Settings), running demos, troubleshooting, and privacy.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/developer-guide.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🛠️</span>
|
||||
<h3>Developer Guide</h3>
|
||||
<p>Build pages on <code>window.BridgeSwarm</code>: joining topics, connections, requests, Protomux, HRPC, media, testing, and packaging.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/architecture.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🏗️</span>
|
||||
<h3>Architecture</h3>
|
||||
<p>Layered diagram of extension, native host, and protocol; message flow, connection lifecycle, and the live-encode path.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/api.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">📚</span>
|
||||
<h3>API Reference</h3>
|
||||
<p>Constructor options, instance methods, events, and the full <code>BridgeSwarm.request</code> type catalog.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/data.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🗄️</span>
|
||||
<h3>Data API</h3>
|
||||
<p>Hypercore, Hyperbee, Hyperdrive, Autobase, and Hyperdb over the bridge — named resources, auto-replicate, storage paths.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/protocols.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🔀</span>
|
||||
<h3>Protocols</h3>
|
||||
<p>Protomux and compact-encoding in the browser, plus host-side HRPC attach/call/stream methods.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/capabilities.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🎛️</span>
|
||||
<h3>Capabilities</h3>
|
||||
<p>Optional Bare capability packs: batch media transforms and live VP9/WebM encode, plus the security model behind them.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/examples.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🧪</span>
|
||||
<h3>Examples</h3>
|
||||
<p>Every bundled demo — chat, whiteboard, screenshare, media studio, HRPC, and more — with what each one teaches.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/security.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">🛡️</span>
|
||||
<h3>Security</h3>
|
||||
<p>Noise encryption, firewall/ban, the cap-jobs sandbox, native-host threat model, and AGPL-3.0 obligations.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/faq.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">❓</span>
|
||||
<h3>FAQ</h3>
|
||||
<p>Answers to the questions that come up most: browsers, mobile, performance limits, licensing, and more.</p>
|
||||
</a>
|
||||
|
||||
<a class="docs-card" href="/docs/release.html">
|
||||
<span class="docs-card-icon" aria-hidden="true">📦</span>
|
||||
<h3>Release Notes</h3>
|
||||
<p>Release channels, artifact layout, versioning, and the rolling <code>latest-main</code> build.</p>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<h2>How it works, in one picture</h2>
|
||||
<p>
|
||||
The page never talks to the network directly. It calls <code>window.BridgeSwarm</code>, which is
|
||||
injected by the extension's content script. The content script relays through the background service
|
||||
worker to a native messaging host built on <a href="https://www.npmjs.com/package/bare" target="_blank" rel="noopener">Bare</a>,
|
||||
which runs the actual Hyperswarm stack and replies over the same channel.
|
||||
</p>
|
||||
<pre class="code-block"><code>Page (window.BridgeSwarm)
|
||||
⇅ postMessage
|
||||
Content script (content.js)
|
||||
⇅ runtime.sendMessage
|
||||
Background service worker (background.js)
|
||||
⇅ native messaging: 4-byte LE length + JSON
|
||||
Native host (Bare): Hyperswarm · Hypercore/Hyperbee/Hyperdrive · Autobase · Hyperdb · Protomux · HRPC · media
|
||||
⇅ Noise-encrypted P2P
|
||||
Remote peers</code></pre>
|
||||
<p>See <a href="/docs/architecture.html">Architecture</a> for the full component and sequence diagrams.</p>
|
||||
|
||||
<h2>Building blocks</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Technology</th><th>Purpose</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><strong>Hyperswarm</strong></td><td>P2P networking, DHT discovery, NAT traversal</td></tr>
|
||||
<tr><td><strong>Corestore</strong></td><td>Multi-Hypercore storage</td></tr>
|
||||
<tr><td><strong>Hypercore</strong></td><td>Append-only log</td></tr>
|
||||
<tr><td><strong>Hyperbee</strong></td><td>Key/value B-tree</td></tr>
|
||||
<tr><td><strong>Hyperdrive</strong></td><td>P2P file system</td></tr>
|
||||
<tr><td><strong>Autobase</strong></td><td>Multi-writer linearized log</td></tr>
|
||||
<tr><td><strong>Hyperdb</strong></td><td>Schema-based P2P database</td></tr>
|
||||
<tr><td><strong>Protomux</strong></td><td>Protocol multiplexing over a connection</td></tr>
|
||||
<tr><td><strong>HRPC</strong></td><td>Typed RPC with streaming, run on the native host</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
<strong>Trust boundary:</strong> the native host runs with your user privileges — it can open sockets
|
||||
and read/write files. Only install BridgeSwarm builds you trust. See <a href="/docs/security.html">Security</a>.
|
||||
</div>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<span class="docs-pager-link docs-pager-prev docs-pager-disabled" aria-hidden="true">
|
||||
<span class="docs-pager-label">Documentation</span>
|
||||
<span class="docs-pager-title">You are here</span>
|
||||
</span>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/quickstart.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Quick Start</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,295 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Protocols · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="Protomux globals in the BridgeSwarm browser bundle and host-side HRPC attach/call/stream methods, with full code examples.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/protocols.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Protocols · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Protomux in the browser and host-side HRPC.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/protocols.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Protocols · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Protomux in the browser and host-side HRPC.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html" class="active" aria-current="page">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Build with BridgeSwarm</p>
|
||||
<h1>Protocols</h1>
|
||||
<p class="docs-lead">
|
||||
Beyond raw <code>conn.write</code> / <code>data</code> events, BridgeSwarm gives you two ways to run
|
||||
structured protocols over a connection: <strong>Protomux</strong> in the browser for your own
|
||||
message-oriented mini-protocols, and <strong>HRPC</strong> on the native host for typed
|
||||
request/response and streaming RPC.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#setup">Protomux setup</a></li>
|
||||
<li><a href="#globals">Globals</a></li>
|
||||
<li><a href="#create-protomux">createProtomux(conn)</a></li>
|
||||
<li><a href="#compact-encoding">compact-encoding (c)</a></li>
|
||||
<li><a href="#b4a">b4a</a></li>
|
||||
<li><a href="#full-example">Full Protomux example</a></li>
|
||||
<li><a href="#attachment">Native host: connection attachment</a></li>
|
||||
<li><a href="#hrpc">HRPC on the native host</a></li>
|
||||
<li><a href="#hrpc-commands">HRPC commands (spec)</a></li>
|
||||
<li><a href="#hrpc-invoking">Invoking HRPC from the browser</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="setup">Protomux setup</h2>
|
||||
<p>
|
||||
BridgeSwarm injects a browser bundle of <a href="https://github.com/holepunchto/protomux" target="_blank" rel="noopener">Protomux</a>,
|
||||
<a href="https://github.com/compact-encoding/compact-encoding" target="_blank" rel="noopener">compact-encoding</a>
|
||||
(<code>c</code>), and <a href="https://github.com/holepunchto/b4a" target="_blank" rel="noopener">b4a</a>
|
||||
so you can run message-oriented protocols over P2P connections without bundling anything yourself. No
|
||||
extra <code><script></code> tags are needed — the content script injects <code>api.js</code>,
|
||||
<code>framed-stream.js</code>, and <code>protomux-bundle.js</code> into the page, in that order.
|
||||
</p>
|
||||
|
||||
<h2 id="globals">Globals</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Global</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>window.BridgeSwarm</code></td><td>Main API: <code>new BridgeSwarm(opts)</code>, <code>swarm.join(topic)</code>, <code>swarm.on('connection', ...)</code>, <code>swarm.createProtomux(conn)</code></td></tr>
|
||||
<tr><td><code>window.BridgeSwarmFramedStream</code></td><td><code>wrapRawFrames(conn)</code> — wraps a connection so it presents a stream that preserves message boundaries for Protomux</td></tr>
|
||||
<tr><td><code>window.BridgeSwarmProtomux</code></td><td><code>{ Protomux, c, b4a }</code> — the Protomux class, compact-encoding helpers, and b4a buffer utilities</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="create-protomux">createProtomux(conn)</h2>
|
||||
<p>Given a connection from <code>swarm.on('connection', (conn, peerInfo) => { ... })</code>:</p>
|
||||
<pre class="code-block"><code class="language-javascript">const mux = swarm.createProtomux(conn);</code></pre>
|
||||
<p>
|
||||
This wraps the connection in a framed stream and returns a new <code>Protomux</code> instance. If the
|
||||
Protomux bundle or framed-stream script isn't loaded, <code>createProtomux</code> returns
|
||||
<code>null</code> and logs a warning — always check before using it. Note that
|
||||
<code>conn.write(data)</code> returns a Promise that resolves on success and rejects on host error.
|
||||
</p>
|
||||
|
||||
<h2 id="compact-encoding">compact-encoding (c)</h2>
|
||||
<p>Use <code>window.BridgeSwarmProtomux.c</code> for message encodings. Common ones:</p>
|
||||
<ul>
|
||||
<li><code>c.string</code> — UTF-8 string</li>
|
||||
<li><code>c.binary</code> / <code>c.raw</code> — raw buffer</li>
|
||||
<li><code>c.uint</code> — unsigned integer</li>
|
||||
<li><code>c.bool</code> — boolean</li>
|
||||
<li><code>c.json</code> — JSON (if available in the bundle)</li>
|
||||
</ul>
|
||||
<pre class="code-block"><code class="language-javascript">const { Protomux, c, b4a } = window.BridgeSwarmProtomux;
|
||||
|
||||
const channel = mux.createChannel({
|
||||
protocol: 'my-app/v1',
|
||||
onopen() {},
|
||||
onclose() {}
|
||||
});
|
||||
|
||||
const stringMsg = channel.addMessage({
|
||||
encoding: c.string,
|
||||
onmessage(value) { console.log('Got string:', value); }
|
||||
});
|
||||
|
||||
const binaryMsg = channel.addMessage({
|
||||
encoding: c.binary,
|
||||
onmessage(buf) { console.log('Got buffer:', buf); }
|
||||
});
|
||||
|
||||
channel.open();
|
||||
stringMsg.send('hello');
|
||||
binaryMsg.send(b4a.from('data'));</code></pre>
|
||||
|
||||
<h2 id="b4a">b4a</h2>
|
||||
<p><code>window.BridgeSwarmProtomux.b4a</code> provides Node-<code>Buffer</code>-style helpers:</p>
|
||||
<ul>
|
||||
<li><code>b4a.from(str, encoding)</code> — create from string (e.g. <code>'utf8'</code>)</li>
|
||||
<li><code>b4a.toString(buf, encoding)</code> — buffer to string</li>
|
||||
<li><code>b4a.allocUnsafe(n)</code> — allocate (browsers may back this with <code>Uint8Array</code>)</li>
|
||||
</ul>
|
||||
<p>Use these when encoding/decoding binary message payloads.</p>
|
||||
|
||||
<h2 id="full-example">Full Protomux example</h2>
|
||||
<pre class="code-block"><code class="language-html"><!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<button id="join">Join topic</button>
|
||||
<pre id="log"></pre>
|
||||
<script>
|
||||
const log = (msg) => { document.getElementById('log').textContent += msg + '\n'; };
|
||||
const swarm = new BridgeSwarm({ appName: 'protomux-example' });
|
||||
|
||||
document.getElementById('join').onclick = async () => {
|
||||
await swarm.join('protomux-demo-topic');
|
||||
log('Joined. Open this page in another tab and join the same topic.');
|
||||
};
|
||||
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
log('Peer connected: ' + peerInfo.publicKey.slice(0, 16) + '...');
|
||||
const mux = swarm.createProtomux(conn);
|
||||
if (!mux) { log('Protomux not available'); return; }
|
||||
|
||||
const ch = mux.createChannel({
|
||||
protocol: 'chat',
|
||||
onopen() { log('Channel opened'); },
|
||||
onclose() { log('Channel closed'); }
|
||||
});
|
||||
ch.addMessage({
|
||||
encoding: window.BridgeSwarmProtomux.c.string,
|
||||
onmessage(m) { log('Peer said: ' + m); }
|
||||
});
|
||||
ch.open();
|
||||
window.sendChat = (text) => ch.messages[0].send(text);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html></code></pre>
|
||||
|
||||
<h2 id="attachment">Native host: connection attachment</h2>
|
||||
<p>
|
||||
The native host can also attach <strong>Hypercore replication</strong> or <strong>HRPC</strong> to a
|
||||
connection. Once you do this, that connection is no longer forwarded to the browser — the host takes
|
||||
it over entirely.
|
||||
</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Request</th><th>Behavior</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>BridgeSwarm.request('attachReplication', { connId, coreKeyHex? })</code></td><td>Uses the connection identified by <code>connId</code>. If <code>coreKeyHex</code> is given, the host looks up that core from its corestore; otherwise it uses the default core (name <code>'default'</code>). The host creates a Protomux from the socket and runs <code>core.replicate(protomux)</code> so the remote peer can replicate that core.</td></tr>
|
||||
<tr><td><code>BridgeSwarm.request('attachHrpc', { connId })</code></td><td>Enables HRPC on that connection over a Protomux channel named <code>bridgeswarm-hrpc</code>.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
Storage for the host's corestore is under <code>BRIDGE_SWARM_STORAGE</code> or
|
||||
<code>./bridge-swarm-storage</code> relative to the host process.
|
||||
</p>
|
||||
<div class="docs-callout docs-callout-info">
|
||||
Each BridgeSwarm connection is already a <strong>NoiseSecretStream</strong> (framed, encrypted). The
|
||||
extension forwards one decrypted frame per chunk, so <code>wrapRawFrames(conn)</code> presents one
|
||||
chunk per frame to Protomux. Protomux pairs channels by <code>protocol</code> (and optional
|
||||
<code>id</code>) — use the same values on both sides so the channel opens. For RPC-style usage,
|
||||
BridgeSwarm's supported path is host HRPC; in-page
|
||||
<a href="https://www.npmjs.com/package/protomux-rpc" target="_blank" rel="noopener">protomux-rpc</a>
|
||||
remains optional DIY if you bundle it yourself on top of <code>createProtomux</code>.
|
||||
</div>
|
||||
|
||||
<h2 id="hrpc">HRPC on the native host</h2>
|
||||
<p>
|
||||
The native host runs <a href="https://www.npmjs.com/package/hrpc" target="_blank" rel="noopener">hrpc</a>
|
||||
over a connection — schema-defined RPC on a Protomux channel. The browser doesn't run hrpc itself; it
|
||||
attaches HRPC on the host and invokes methods via <code>hrpcInvoke</code> / <code>swarm.hrpcCall</code>.
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">await BridgeSwarm.request('attachHrpc', { connId: conn.connId });</code></pre>
|
||||
<p>Both peers must attach HRPC on the same connection pair. The first invoke may wait up to <strong>12 seconds</strong> for the channel to open.</p>
|
||||
|
||||
<h2 id="hrpc-commands">HRPC commands (spec)</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Command</th><th>Mode</th><th>Request</th><th>Response</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>ping</code></td><td>Unary</td><td><code>{ value? }</code></td><td><code>{ pong }</code></td></tr>
|
||||
<tr><td><code>streamSum</code></td><td>Request-stream → response</td><td>chunks <code>{ n, label }</code> (pass <code>args.chunks</code> from the browser)</td><td><code>{ sum, count }</code> on <code>hrpc-end</code></td></tr>
|
||||
<tr><td><code>fetchStream</code></td><td>Request → response-stream</td><td><code>{ count }</code></td><td>chunks <code>{ i, data }</code> via <code>hrpc-chunk</code></td></tr>
|
||||
<tr><td><code>duplex</code></td><td>Duplex</td><td><code>args.chunks</code> <code>{ x, y }</code></td><td>chunks <code>{ result, n }</code> via <code>hrpc-chunk</code></td></tr>
|
||||
<tr><td><code>notify</code></td><td>Send-only</td><td><code>{ event, payload }</code></td><td>none</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Build the spec with <code>npm run build:hrpc</code> → <code>spec/hrpc/</code> (mirrored into <code>native-host/spec/hrpc/</code>).</p>
|
||||
|
||||
<h2 id="hrpc-invoking">Invoking HRPC from the browser</h2>
|
||||
<h3>Unary / notify</h3>
|
||||
<pre class="code-block"><code class="language-javascript">const res = await swarm.hrpcCall(conn.connId, 'ping', { value: 'hello' });
|
||||
// or: BridgeSwarm.request('hrpcInvoke', { connId, method: 'ping', args })</code></pre>
|
||||
|
||||
<h3>Streaming</h3>
|
||||
<pre class="code-block"><code class="language-javascript">const res = await swarm.hrpcCall(conn.connId, 'fetchStream', { count: 3 }, {
|
||||
onChunk: (chunk) => console.log(chunk),
|
||||
timeoutMs: 20000,
|
||||
});
|
||||
// Host replies immediately with { streaming: true, streamId }, then emits
|
||||
// hrpc-chunk / hrpc-end / hrpc-error events to the page.</code></pre>
|
||||
<pre class="code-block"><code class="language-javascript">await swarm.hrpcCall(conn.connId, 'streamSum', {
|
||||
chunks: [{ n: 1, label: 'a' }, { n: 2, label: 'b' }],
|
||||
});</code></pre>
|
||||
|
||||
<div class="docs-callout docs-callout-info">
|
||||
Try HRPC live in the <a href="http://127.0.0.1:4173/hrpc-demo/" target="_blank" rel="noopener">HRPC Demo</a>
|
||||
and the SDK demo's raw Protomux usage in
|
||||
<a href="http://127.0.0.1:4173/sdk-demo/" target="_blank" rel="noopener">SDK Demo</a>. See <a href="/docs/examples.html">Examples</a>.
|
||||
</div>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/data.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Data API</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/capabilities.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Capabilities</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,245 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Quick Start · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="Install BridgeSwarm, load the extension, enable the examples server, and write your first join/write P2P snippet in under five minutes.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/quickstart.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Quick Start · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Install, load, and join your first BridgeSwarm swarm in under five minutes.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/quickstart.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Quick Start · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Install, load, and join your first BridgeSwarm swarm in under five minutes.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html" class="active" aria-current="page">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Getting Started</p>
|
||||
<h1>Quick Start</h1>
|
||||
<p class="docs-lead">
|
||||
Five steps from a clean machine to a peer-to-peer page: install the native host and extension,
|
||||
load them into your browser, enable the examples server, then write a few lines of JavaScript that
|
||||
join a topic and exchange messages with another tab.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#install">1. Install the host</a></li>
|
||||
<li><a href="#load">2. Load the extension</a></li>
|
||||
<li><a href="#examples">3. Enable the examples server</a></li>
|
||||
<li><a href="#first-app">4. Your first join/write snippet</a></li>
|
||||
<li><a href="#next">5. Next steps</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="install">1. Install the host</h2>
|
||||
<p>
|
||||
The easy installer downloads a prebuilt native-host binary for your platform plus the packaged
|
||||
extension from the rolling <code>latest-main</code> release. No Node.js or git clone required.
|
||||
</p>
|
||||
|
||||
<p><strong>macOS / Linux:</strong></p>
|
||||
<pre class="code-block"><code class="language-bash">curl -fsSL https://git.ssh.surf/snxraven/BridgeSwarm/raw/branch/main/scripts/web-installer.sh | bash</code></pre>
|
||||
|
||||
<p><strong>Windows (PowerShell):</strong></p>
|
||||
<pre class="code-block"><code class="language-powershell">irm https://git.ssh.surf/snxraven/BridgeSwarm/raw/branch/main/scripts/install.ps1 | iex</code></pre>
|
||||
|
||||
<p>
|
||||
This installs the native host to <code>~/.bridgeswarm/</code> (<code>%LOCALAPPDATA%\bridgeswarm\</code>
|
||||
on Windows), registers the native-messaging manifest for Chrome/Edge and Firefox, and saves
|
||||
<code>BridgeSwarm-*.zip</code> / <code>.xpi</code> to <code>~/Downloads</code>.
|
||||
</p>
|
||||
|
||||
<div class="docs-callout docs-callout-info">
|
||||
Prefer to build from source? <code>git clone</code> the repo, run <code>npm run setup</code>
|
||||
(or <code>./scripts/install-from-source.sh</code>), then load <code>extension/</code> unpacked.
|
||||
See the <a href="/docs/developer-guide.html">Developer Guide</a>.
|
||||
</div>
|
||||
|
||||
<h2 id="load">2. Load the extension</h2>
|
||||
|
||||
<p><strong>Chrome / Edge</strong></p>
|
||||
<ol>
|
||||
<li>Open <code>chrome://extensions</code></li>
|
||||
<li>Enable <strong>Developer mode</strong> (top right)</li>
|
||||
<li>Drag & drop <code>~/Downloads/BridgeSwarm-1.0.0.zip</code> onto the page — or extract it
|
||||
and click <strong>Load unpacked</strong></li>
|
||||
<li>Confirm the extension ID is <code>jhmbaojjfkkpoolhkoohklbjokdmbdpm</code></li>
|
||||
<li>Fully restart the browser</li>
|
||||
</ol>
|
||||
|
||||
<p><strong>Firefox</strong></p>
|
||||
<p>
|
||||
Temporary: <code>about:debugging</code> → <strong>This Firefox</strong> → <strong>Load Temporary Add-on</strong>.
|
||||
Permanent (Nightly / Developer Edition only): set <code>xpinstall.signatures.required</code> to
|
||||
<code>false</code> in <code>about:config</code>, then <strong>Install Add-on From File</strong> with the
|
||||
downloaded <code>.xpi</code>.
|
||||
</p>
|
||||
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
<strong>Restart required.</strong> The native messaging manifest is only picked up when the browser
|
||||
fully restarts (Cmd+Q / Quit, not just closing windows).
|
||||
</div>
|
||||
|
||||
<h2 id="examples">3. Enable the examples server</h2>
|
||||
<p>
|
||||
BridgeSwarm ships a full demo gallery. The native host can serve it locally so every demo runs on the
|
||||
same origin (required for the content script to inject <code>window.BridgeSwarm</code>).
|
||||
</p>
|
||||
<ol>
|
||||
<li>Click the BridgeSwarm toolbar icon to open the <strong>Control Center</strong>, or open <strong>Options</strong></li>
|
||||
<li>Go to <strong>Settings → Examples server</strong></li>
|
||||
<li>Toggle <strong>Enable examples server</strong> on — settings save automatically, no Save button</li>
|
||||
<li>Open <a href="http://127.0.0.1:4173/" target="_blank" rel="noopener"><code>http://127.0.0.1:4173/</code></a> in two tabs</li>
|
||||
</ol>
|
||||
<p>
|
||||
Never open demo files via <code>file://</code> — each local file is treated as a unique opaque
|
||||
origin by modern browsers, which breaks both scripts and extension injection.
|
||||
</p>
|
||||
<pre class="code-block"><code># Dev alternative from the repo (equivalent to the Settings toggle)
|
||||
npm run examples</code></pre>
|
||||
|
||||
<h2 id="first-app">4. Your first join/write snippet</h2>
|
||||
<p>
|
||||
Drop this into any page served over <code>http://</code> or <code>https://</code> (not <code>file://</code>).
|
||||
Open the same page in two tabs to see peers connect.
|
||||
</p>
|
||||
<pre class="code-block"><code class="language-javascript">// Wait for the extension to inject the API (safe even if your script runs first)
|
||||
await BridgeSwarm.ready();
|
||||
|
||||
// Create a swarm — appName scopes discovery
|
||||
const swarm = new BridgeSwarm({ appName: 'my-first-app' });
|
||||
|
||||
// Join a topic to discover peers interested in the same thing
|
||||
await swarm.join('hello-bridgeswarm');
|
||||
|
||||
// Handle incoming connections
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
console.log('Peer connected:', peerInfo.publicKey);
|
||||
|
||||
conn.on('data', (data) => {
|
||||
console.log('Received:', new TextDecoder().decode(data));
|
||||
});
|
||||
|
||||
// conn.write returns a Promise — resolves on success, rejects on host error
|
||||
conn.write('Hello, peer!').catch((err) => console.error('write failed:', err));
|
||||
});
|
||||
|
||||
// Later: leave and clean up
|
||||
// await swarm.leave('hello-bridgeswarm');
|
||||
// swarm.destroy();</code></pre>
|
||||
|
||||
<p>
|
||||
That is a complete, working P2P chat primitive: no server, no signaling infrastructure to run
|
||||
yourself — Hyperswarm's DHT handles discovery and NAT traversal, and Noise handles encryption.
|
||||
</p>
|
||||
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Concept</th><th>What it does</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>BridgeSwarm.ready()</code></td><td>Resolves once the extension has injected the API — use if your script may run before injection</td></tr>
|
||||
<tr><td><code>new BridgeSwarm(opts)</code></td><td>Creates a swarm; <code>appName</code> and <code>maxPeers</code> are optional (extension defaults apply otherwise)</td></tr>
|
||||
<tr><td><code>swarm.join(topic)</code></td><td>Joins a 32-byte topic (hex string or a value the API hashes for you) to discover peers</td></tr>
|
||||
<tr><td><code>swarm.on('connection', …)</code></td><td>Fires per peer connection with a <code>conn</code> object and <code>peerInfo</code></td></tr>
|
||||
<tr><td><code>conn.write(data)</code></td><td>Sends bytes or a string to that peer; returns a Promise</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="next">5. Next steps</h2>
|
||||
<div class="docs-card-grid docs-card-grid-compact">
|
||||
<a class="docs-card" href="/docs/user-guide.html">
|
||||
<h3>User Guide</h3>
|
||||
<p>Control Center tour, demo gallery, troubleshooting, and privacy.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/docs/developer-guide.html">
|
||||
<h3>Developer Guide</h3>
|
||||
<p>Firewall, auto-replicate, Protomux, HRPC, media, and packaging pages.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/docs/examples.html">
|
||||
<h3>Examples</h3>
|
||||
<p>Twelve demos covering chat, collaboration, media, and data.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/docs/api.html">
|
||||
<h3>API Reference</h3>
|
||||
<p>Every request type, event, and method signature.</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/index.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Documentation Home</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/user-guide.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">User Guide</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,203 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Release Notes · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="BridgeSwarm release channels, artifact layout, versioning, and the rolling latest-main build produced on every push to main.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/release.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Release Notes · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Release channels, artifacts, versioning, and the rolling latest-main build.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/release.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Release Notes · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Release channels, artifacts, versioning, and the rolling latest-main build.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html" class="active" aria-current="page">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Reference</p>
|
||||
<h1>Release Notes</h1>
|
||||
<p class="docs-lead">
|
||||
BridgeSwarm ships two kinds of Gitea releases: a rolling <code>latest-main</code> build that tracks
|
||||
every push to <code>main</code>, and versioned <code>v*.*.*</code> tags for stable milestones. Both
|
||||
are built by the same CI pipeline and produce the same artifact layout.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#channels">Release channels</a></li>
|
||||
<li><a href="#artifacts">Artifacts</a></li>
|
||||
<li><a href="#versioning">Versioning</a></li>
|
||||
<li><a href="#build-commands">Building artifacts locally</a></li>
|
||||
<li><a href="#verifying">Verifying downloads</a></li>
|
||||
<li><a href="#compatibility">Compatibility</a></li>
|
||||
<li><a href="#current">Current release</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="channels">Release channels</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Channel</th><th>Trigger</th><th>Stability</th><th>Use it if…</th></tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>latest-main</code></td>
|
||||
<td>Every push to <code>main</code> (CI force-updates the tag and release)</td>
|
||||
<td>Prerelease — rolling, always reflects the tip of <code>main</code></td>
|
||||
<td>You want the newest fixes/features and are comfortable with occasional churn. This is what the one-line installer downloads.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>v*.*.*</code></td>
|
||||
<td>Pushing a version tag (e.g. <code>v1.2.0</code>)</td>
|
||||
<td>Stable — pinned to a specific commit, never overwritten</td>
|
||||
<td>You need a reproducible, unchanging install — for production deployments or long-lived documentation references.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="docs-callout docs-callout-info">
|
||||
The rolling release's title reflects the exact commit it was built from — e.g. <em>"Latest build
|
||||
(main @ a1b2c3d)"</em> — and its body links the commit and message, so you can always trace an
|
||||
installed build back to its exact source.
|
||||
</div>
|
||||
|
||||
<h2 id="artifacts">Artifacts</h2>
|
||||
<p>Every release publishes the same set of files:</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>File</th><th>Contents</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>bridge-swarm-host-darwin-x64.zip</code></td><td>Standalone native host binary for macOS (Intel)</td></tr>
|
||||
<tr><td><code>bridge-swarm-host-darwin-arm64.zip</code></td><td>Standalone native host binary for macOS (Apple Silicon)</td></tr>
|
||||
<tr><td><code>bridge-swarm-host-linux-x64.zip</code></td><td>Standalone native host binary for Linux (x64)</td></tr>
|
||||
<tr><td><code>bridge-swarm-host-linux-arm64.zip</code></td><td>Standalone native host binary for Linux (arm64)</td></tr>
|
||||
<tr><td><code>bridge-swarm-host-win32-x64.zip</code></td><td>Standalone native host binary for Windows</td></tr>
|
||||
<tr><td><code>BridgeSwarm-<version>.zip</code></td><td>Packaged Chrome/Edge extension (drag-and-drop installable), including the synced <code>examples/</code> tree</td></tr>
|
||||
<tr><td><code>BridgeSwarm-<version>.xpi</code></td><td>Packaged Firefox extension</td></tr>
|
||||
<tr><td><code>SHA256SUMS.txt</code></td><td>Checksums for every <code>.zip</code>/<code>.xpi</code> in the release</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
The installer scripts (<code>scripts/install.sh</code>, <code>scripts/install.ps1</code>,
|
||||
<code>scripts/web-installer.sh</code>) automatically pick the right host archive for your OS/CPU and
|
||||
download the extension packages into <code>~/Downloads</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="versioning">Versioning</h2>
|
||||
<p>
|
||||
BridgeSwarm's extension and native host share a version number (currently <code>1.0.0</code>),
|
||||
declared in <code>extension/manifest.json</code> and <code>native-host/package.json</code>. Tagged
|
||||
releases follow <a href="https://semver.org/" target="_blank" rel="noopener">semantic versioning</a>:
|
||||
breaking changes to the page API or wire protocol bump the major version; new request types,
|
||||
capabilities, or backward-compatible features bump the minor version; fixes bump the patch version.
|
||||
</p>
|
||||
|
||||
<h2 id="build-commands">Building artifacts locally</h2>
|
||||
<pre class="code-block"><code class="language-bash">npm run build # host launcher + protomux + hrpc
|
||||
npm run pack # package extension (includes examples) -> releases/
|
||||
npm run build:dist # standalone host binary (current platform)
|
||||
npm run build:dist:package # all platforms + zip archives (best on CI)</code></pre>
|
||||
<p>CI runs the equivalent of <code>node scripts/build-distributable.js --all --package</code> to produce every platform archive in one pass, then generates <code>SHA256SUMS.txt</code> before publishing.</p>
|
||||
|
||||
<h2 id="verifying">Verifying downloads</h2>
|
||||
<pre class="code-block"><code class="language-bash"># macOS / Linux
|
||||
shasum -a 256 -c SHA256SUMS.txt
|
||||
|
||||
# or, per file
|
||||
sha256sum bridge-swarm-host-darwin-arm64.zip</code></pre>
|
||||
<p>Compare the output against the matching line in <code>SHA256SUMS.txt</code> from the same release.</p>
|
||||
|
||||
<h2 id="compatibility">Compatibility</h2>
|
||||
<ul>
|
||||
<li>Chrome 88+, Edge, Firefox 79+</li>
|
||||
<li>Desktop only — native messaging is not available on mobile</li>
|
||||
<li><strong>Release install:</strong> prebuilt Bare host binaries (darwin/linux/win32) — no Node.js required for end users</li>
|
||||
<li><strong>From-source / CI:</strong> Node.js for tooling; Bare <code>>=1.29.4</code> via the <code>bare</code> npm dependency</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="current">Current release</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th></th><th></th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Version</td><td><code>1.0.0</code></td></tr>
|
||||
<tr><td>License</td><td><a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noopener">AGPL-3.0</a></td></tr>
|
||||
<tr><td>Publisher</td><td>HoneyPeer, LLC</td></tr>
|
||||
<tr><td>Rolling channel</td><td><a href="https://git.ssh.surf/snxraven/BridgeSwarm/releases/tag/latest-main" target="_blank" rel="noopener">latest-main</a></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Install the current rolling build with the one-liner from <a href="/docs/quickstart.html">Quick Start</a>, or browse all releases and diffs directly on Gitea.</p>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/faq.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">FAQ</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/index.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Documentation Home</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,230 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Security · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="BridgeSwarm security model: Noise encryption, firewall and ban, the trust model, the cap-jobs sandbox, the native-host threat model, and AGPL-3.0 obligations.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/security.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Security · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Noise encryption, firewall/ban, the cap-jobs sandbox, threat model, and AGPL-3.0 obligations.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/security.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Security · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Noise encryption, firewall/ban, the cap-jobs sandbox, threat model, and AGPL-3.0.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html" class="active" aria-current="page">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Reference</p>
|
||||
<h1>Security</h1>
|
||||
<p class="docs-lead">
|
||||
BridgeSwarm gives web pages real peer-to-peer networking and local storage through a native host
|
||||
that runs with your full user privileges. That's powerful, and it's also a real trust boundary you
|
||||
should understand before installing it or building on it.
|
||||
</p>
|
||||
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
<strong>The native host runs with your user privileges</strong> and can make network connections,
|
||||
read/write files (within its allowlisted paths), and access system resources. <strong>Only install
|
||||
BridgeSwarm builds — and only use BridgeSwarm-enabled pages — that you trust.</strong>
|
||||
</div>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#trust-model">Trust model</a></li>
|
||||
<li><a href="#noise">Noise encryption</a></li>
|
||||
<li><a href="#firewall">Firewall & ban</a></li>
|
||||
<li><a href="#protections">Built-in protections</a></li>
|
||||
<li><a href="#cap-jobs">The cap-jobs sandbox</a></li>
|
||||
<li><a href="#nmh-threat-model">Native-host threat model</a></li>
|
||||
<li><a href="#identities">Identity & keys</a></li>
|
||||
<li id="agpl"><a href="#agpl-section">AGPL-3.0</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="trust-model">Trust model</h2>
|
||||
<p>There are three separate trust relationships in play, and it helps to reason about them separately:</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Relationship</th><th>What's at risk</th><th>Mitigation</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>You ↔ the BridgeSwarm build you install</td><td>The native host runs with your user privileges</td><td>Only install from sources you trust; prefer the official signed <code>latest-main</code> release or building from the public repo yourself</td></tr>
|
||||
<tr><td>You ↔ a page that uses BridgeSwarm</td><td>Any page with BridgeSwarm injected can open P2P connections and touch local storage under allowlisted paths</td><td>Only visit BridgeSwarm-enabled pages you trust; use "Disable on file:// URLs" and review a page's source if unsure</td></tr>
|
||||
<tr><td>You ↔ remote peers</td><td>Malicious or noisy peers on a shared topic</td><td>Noise encryption, <code>setFirewall</code>, <code>ban</code>, <code>maxPeers</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="noise">Noise encryption</h2>
|
||||
<p>
|
||||
Every Hyperswarm connection is automatically end-to-end encrypted with the
|
||||
<a href="https://noiseprotocol.org/" target="_blank" rel="noopener">Noise Protocol Framework</a> —
|
||||
there is no plaintext mode and nothing for you to configure. Each connection is a
|
||||
<strong>NoiseSecretStream</strong>; the extension forwards one decrypted frame per <code>data</code>
|
||||
event to the page.
|
||||
</p>
|
||||
|
||||
<h2 id="firewall">Firewall & ban</h2>
|
||||
<pre class="code-block"><code class="language-javascript">// Allowlist — only these public keys may connect
|
||||
await swarm.setFirewall({ mode: 'allowlist', keys: ['abc123...'] });
|
||||
|
||||
// Denylist — block specific keys, allow everyone else
|
||||
await swarm.setFirewall({ mode: 'denylist', keys: ['def456...'] });
|
||||
|
||||
// Ban a peer (updates the denylist too)
|
||||
await swarm.ban('abc123...');
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
// peerInfo.ban() is also available directly on the event
|
||||
});</code></pre>
|
||||
<p>
|
||||
You can also configure a <strong>global default firewall</strong> from extension Settings — mode plus
|
||||
a list of keys — applied automatically whenever any swarm initializes on your machine, independent of
|
||||
what a given page requests. See <a href="/docs/user-guide.html#firewall-defaults">User Guide → Firewall defaults</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="protections">Built-in protections</h2>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Threat</th><th>Protection</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Connection flooding</td><td><code>maxPeers</code> option, per swarm</td></tr>
|
||||
<tr><td>Malicious peers</td><td><code>swarm.setFirewall({ mode, keys })</code>, <code>swarm.ban(publicKey)</code>, <code>peerInfo.ban()</code></td></tr>
|
||||
<tr><td>Data interception</td><td>Noise encryption (automatic, always on)</td></tr>
|
||||
<tr><td>Identity spoofing</td><td>Cryptographic key pairs — each tab has its own identity, and public keys are verifiable</td></tr>
|
||||
<tr><td>DHT attacks</td><td>Rate limiting built into Hyperswarm / the DHT layer</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="cap-jobs">The cap-jobs sandbox</h2>
|
||||
<p>
|
||||
Capability packs (media transforms, live encode) that need to touch the filesystem are restricted to
|
||||
one allowlisted directory tree:
|
||||
</p>
|
||||
<pre class="code-block"><code>$BRIDGE_SWARM_STORAGE/cap-jobs/
|
||||
# default: ~/.bridgeswarm/bridge-swarm-storage/cap-jobs/</code></pre>
|
||||
<p>
|
||||
Absolute paths outside that tree are rejected by the host — a page cannot ask a capability pack to
|
||||
read or write arbitrary files on your machine. Chunked upload/download helpers
|
||||
(<code>media.writeInput</code> / <code>media.readOutput</code>) and live-encode archives all resolve
|
||||
under this directory.
|
||||
</p>
|
||||
|
||||
<h2 id="nmh-threat-model">Native-host threat model</h2>
|
||||
<p>
|
||||
Native messaging is Chrome/Firefox's sanctioned way for an extension to talk to a local process, and
|
||||
it has known, well-understood properties that shape BridgeSwarm's design:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>The host is only reachable by an installed, matching extension.</strong> The native-messaging manifest whitelists a specific extension ID (<code>allowed_origins</code> / <code>allowed_extensions</code>); a random page cannot spawn or talk to the host directly.</li>
|
||||
<li><strong>The host process itself is trusted code you installed</strong> — treat it like any other local binary with your user's privileges. Get it from a source you trust.</li>
|
||||
<li><strong>Message size is capped (~1 MB)</strong> host → browser, which bounds worst-case memory/IPC pressure from any single message and shapes the API toward chunked/streaming transfers for large payloads.</li>
|
||||
<li><strong>Capability packs are curated, not "run anything."</strong> Only specific, reviewed commands are exposed per pack (see <a href="/docs/capabilities.html">Capabilities</a>); there is intentionally no generic "execute shell command" or open filesystem API exposed to pages.</li>
|
||||
<li><strong>Firewall/ban are host-enforced, not just client-side hints.</strong> A denied peer's connection attempts are rejected by the host's Hyperswarm instance itself.</li>
|
||||
</ul>
|
||||
<div class="docs-callout docs-callout-info">
|
||||
BridgeSwarm does not run a backend service and collects no telemetry. All state is local to your
|
||||
machine unless you explicitly replicate it to peers you connect to. See
|
||||
<a href="/docs/user-guide.html#privacy">User Guide → Privacy & local storage</a>.
|
||||
</div>
|
||||
|
||||
<h2 id="identities">Identity & keys</h2>
|
||||
<p>
|
||||
Each browser tab gets its own cryptographic key pair for Hyperswarm, generated fresh unless you
|
||||
persist and reuse one yourself. Hypercore/Hyperbee/Hyperdrive/Autobase/Hyperdb resources each have
|
||||
their own public key, independent of swarm identity — see
|
||||
<a href="/docs/user-guide.html#topics-vs-keys">User Guide → Topics vs. keys</a> for how discovery
|
||||
(topics) and addressing (keys) relate.
|
||||
</p>
|
||||
|
||||
<h2 id="agpl-section">AGPL-3.0</h2>
|
||||
<p>
|
||||
BridgeSwarm is licensed under the
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noopener">GNU Affero General
|
||||
Public License v3.0</a>. AGPL extends GPL's copyleft to cover network use (§13): if you modify
|
||||
BridgeSwarm and let others interact with your modified version over a network — not just by
|
||||
distributing binaries — you must offer them the corresponding source for your modified version.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Writing a normal web app that <em>uses</em> <code>window.BridgeSwarm</code> as an API is not, by itself, what triggers the network clause — that's ordinary usage, not modification/distribution of BridgeSwarm.</li>
|
||||
<li>Forking the extension or native host and offering a modified build as a hosted service, a rebranded installer, or a modified capability pack <em>does</em> trigger it — you must make that modified source available to users of the service.</li>
|
||||
<li>This is a summary, not legal advice. Review the full license text and consult counsel for your specific situation.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Licensing questions: <a href="mailto:[email protected]">[email protected]</a>. BridgeSwarm is
|
||||
owned and engineered by <strong>HoneyPeer, LLC</strong> (DeKalb County, Georgia, USA).
|
||||
</p>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/examples.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Examples</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/faq.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">FAQ</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,338 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>User Guide · BridgeSwarm Docs</title>
|
||||
<meta name="description" content="Full BridgeSwarm user guide: installation, the Control Center (Overview, Swarms, Connections, Activity, Settings), running demos, troubleshooting storage, updating, uninstalling, and privacy.">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/docs/user-guide.html">
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/assets/brand/colors.css">
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="User Guide · BridgeSwarm Docs">
|
||||
<meta property="og:description" content="Install, configure, and troubleshoot BridgeSwarm — the Control Center, demos, storage, updates, and privacy.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/docs/user-guide.html">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/social/social-banner.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="User Guide · BridgeSwarm Docs">
|
||||
<meta name="twitter:description" content="Install, configure, and troubleshoot BridgeSwarm.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
</head>
|
||||
<body class="docs-page">
|
||||
<div data-nav></div>
|
||||
|
||||
<div class="docs-layout">
|
||||
<aside class="docs-sidebar" data-docs-nav>
|
||||
<div class="docs-sidebar-inner">
|
||||
<a class="docs-sidebar-brand" href="/docs/index.html">
|
||||
<img src="/assets/logo/bridgeswarm-icon-32.png" alt="" width="20" height="20">
|
||||
<span>Documentation</span>
|
||||
</a>
|
||||
<input type="search" class="docs-search" placeholder="Search docs…" aria-label="Search documentation" data-docs-search>
|
||||
<nav aria-label="Documentation sections">
|
||||
<p class="docs-nav-heading">Getting Started</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/quickstart.html">Quick Start</a></li>
|
||||
<li><a href="/docs/user-guide.html" class="active" aria-current="page">User Guide</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Build with BridgeSwarm</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/developer-guide.html">Developer Guide</a></li>
|
||||
<li><a href="/docs/architecture.html">Architecture</a></li>
|
||||
<li><a href="/docs/api.html">API Reference</a></li>
|
||||
<li><a href="/docs/data.html">Data API</a></li>
|
||||
<li><a href="/docs/protocols.html">Protocols</a></li>
|
||||
<li><a href="/docs/capabilities.html">Capabilities</a></li>
|
||||
</ul>
|
||||
<p class="docs-nav-heading">Reference</p>
|
||||
<ul class="docs-nav-list">
|
||||
<li><a href="/docs/examples.html">Examples</a></li>
|
||||
<li><a href="/docs/security.html">Security</a></li>
|
||||
<li><a href="/docs/faq.html">FAQ</a></li>
|
||||
<li><a href="/docs/release.html">Release Notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main class="docs-main">
|
||||
<article class="docs-article">
|
||||
<p class="docs-eyebrow">Getting Started</p>
|
||||
<h1>User Guide</h1>
|
||||
<p class="docs-lead">
|
||||
This guide is for people running BridgeSwarm day to day: installing it, understanding the
|
||||
<strong>Control Center</strong>, trying the bundled demos, and fixing the handful of things that can
|
||||
go wrong. If you're writing code against <code>window.BridgeSwarm</code>, see the
|
||||
<a href="/docs/developer-guide.html">Developer Guide</a> instead.
|
||||
</p>
|
||||
|
||||
<nav class="docs-toc" aria-label="On this page">
|
||||
<p class="docs-toc-heading">On this page</p>
|
||||
<ol>
|
||||
<li><a href="#install">Installing BridgeSwarm</a></li>
|
||||
<li><a href="#control-center">The Control Center</a></li>
|
||||
<li><a href="#examples-server">The examples server</a></li>
|
||||
<li><a href="#using-demos">Using the demos</a></li>
|
||||
<li><a href="#firewall-defaults">Firewall defaults</a></li>
|
||||
<li><a href="#troubleshooting">Troubleshooting</a></li>
|
||||
<li><a href="#updating">Updating</a></li>
|
||||
<li><a href="#uninstall">Uninstalling</a></li>
|
||||
<li><a href="#privacy">Privacy & local storage</a></li>
|
||||
<li><a href="#topics-vs-keys">Topics vs. keys — which do I use?</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="install">Installing BridgeSwarm</h2>
|
||||
<p>
|
||||
BridgeSwarm has two parts that must both be installed: a <strong>native host</strong> (a small
|
||||
background program built on the <a href="https://www.npmjs.com/package/bare" target="_blank" rel="noopener">Bare</a>
|
||||
runtime that actually runs Hyperswarm) and a <strong>browser extension</strong> (Manifest V3) that
|
||||
injects the page API and talks to the host over Chrome/Firefox native messaging.
|
||||
</p>
|
||||
<p>The one-line installer handles both — see <a href="/docs/quickstart.html">Quick Start</a> for the exact commands. In short:</p>
|
||||
<ol>
|
||||
<li>Run the installer script for your OS. It downloads a prebuilt host binary and writes the native-messaging manifest to the right OS-specific directory.</li>
|
||||
<li>Load the downloaded extension package into Chrome/Edge (Developer mode → drag the zip, or Load unpacked) or Firefox (temporary add-on or signed install on Nightly/Developer Edition).</li>
|
||||
<li>Fully restart the browser so it picks up the native-messaging manifest.</li>
|
||||
</ol>
|
||||
<p>
|
||||
The installer writes the host to <code>~/.bridgeswarm/</code> on macOS/Linux
|
||||
(<code>%LOCALAPPDATA%\bridgeswarm\</code> on Windows) and is careful to coexist with unrelated
|
||||
extensions on your system — it only ever touches its own install directory and its own native
|
||||
messaging manifest name, <code>com.bridgeswarm</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="control-center">The Control Center</h2>
|
||||
<p>
|
||||
Click the BridgeSwarm toolbar icon to open the <strong>Control Center</strong> — a live dashboard over
|
||||
a persistent port (<code>bridgeswarm-dashboard</code>) into the native host. It has five tabs:
|
||||
</p>
|
||||
|
||||
<h3>Overview</h3>
|
||||
<p>
|
||||
Host health (connected / disconnected), the examples server status and toggle, and a live snapshot of
|
||||
swarm and connection counts. This is the fastest way to confirm the extension is actually talking to
|
||||
the native host.
|
||||
</p>
|
||||
|
||||
<h3>Swarms</h3>
|
||||
<p>
|
||||
Every active <code>Hyperswarm</code> instance created by any tab: its public key, app name, peer
|
||||
count, and firewall mode. Useful for seeing exactly what a page has joined without opening DevTools.
|
||||
</p>
|
||||
|
||||
<h3>Connections</h3>
|
||||
<p>
|
||||
Live peer sockets across all swarms — who's connected, which swarm they belong to, and whether a
|
||||
connection has been "attached" for Hypercore replication or HRPC (and is therefore no longer
|
||||
forwarded to the page).
|
||||
</p>
|
||||
|
||||
<h3>Activity</h3>
|
||||
<p>
|
||||
A structured event stream from both the host and the extension: connections opening and closing,
|
||||
errors, capability job progress, and examples-server lifecycle events. This is the first place to
|
||||
look when something isn't behaving as expected.
|
||||
</p>
|
||||
|
||||
<h3>Settings</h3>
|
||||
<p>Changes here <strong>save automatically</strong> — there is no Save button.</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th>Group</th><th>Setting</th><th>Purpose</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td rowspan="2">General</td><td>Debug logging</td><td>Verbose logs in the Activity tab and browser console</td></tr>
|
||||
<tr><td>Disable on <code>file://</code> URLs</td><td>Skip injecting BridgeSwarm on local files</td></tr>
|
||||
<tr><td rowspan="4">Swarm defaults</td><td>Default app name</td><td>Used when a page omits <code>appName</code></td></tr>
|
||||
<tr><td>Default max peers</td><td><code>0</code> = unlimited</td></tr>
|
||||
<tr><td>Request timeout (ms)</td><td>Default <code>BridgeSwarm.request</code> timeout; <code>0</code> = none</td></tr>
|
||||
<tr><td>Ready timeout (ms)</td><td><code>BridgeSwarm.ready()</code> timeout; <code>0</code> = wait forever</td></tr>
|
||||
<tr><td rowspan="2">Default peer firewall</td><td>Mode</td><td>Off / Allowlist / Denylist, applied automatically on swarm init</td></tr>
|
||||
<tr><td>Peer keys</td><td>One public-key hex per line</td></tr>
|
||||
<tr><td rowspan="2">Examples server</td><td>Enable examples server</td><td>Native host serves the demo gallery on <code>127.0.0.1</code> only</td></tr>
|
||||
<tr><td>Port</td><td>Bound to <code>127.0.0.1</code> only (default <code>4173</code>)</td></tr>
|
||||
<tr><td>Panel</td><td>Refresh interval (ms)</td><td>How often Overview polls host state (1000–10000ms)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
<strong>Options</strong> (the browser's native extension options page) simply opens the Control
|
||||
Center's Settings tab in a full tab — they are the same UI.
|
||||
</p>
|
||||
|
||||
<h2 id="examples-server">The examples server</h2>
|
||||
<p>
|
||||
The bundled demo gallery needs to be served over <code>http://</code>, not opened as local files, so
|
||||
the content script can inject the page API and so relative fetches behave normally. Toggle
|
||||
<strong>Examples server</strong> on in Settings (or Dashboard → Settings) and the native host starts
|
||||
a local static server:
|
||||
</p>
|
||||
<pre class="code-block"><code>http://127.0.0.1:4173/</code></pre>
|
||||
<p>
|
||||
It only binds to <code>127.0.0.1</code> — nothing outside your machine can reach it. Developers
|
||||
running from source can start the same server with <code>npm run examples</code> instead of using the
|
||||
toggle.
|
||||
</p>
|
||||
|
||||
<h2 id="using-demos">Using the demos</h2>
|
||||
<p>
|
||||
Open <a href="http://127.0.0.1:4173/" target="_blank" rel="noopener"><code>http://127.0.0.1:4173/</code></a>
|
||||
and pick a demo from the landing page. Most demos are P2P, so open the same URL in a
|
||||
<strong>second tab</strong> to see two peers connect to each other. See the full catalog with
|
||||
descriptions in <a href="/docs/examples.html">Examples</a>.
|
||||
</p>
|
||||
<div class="docs-callout docs-callout-info">
|
||||
Each browser tab gets its own cryptographic identity, so two tabs on the same machine are a perfectly
|
||||
realistic two-peer test — you don't need a second computer.
|
||||
</div>
|
||||
|
||||
<h2 id="firewall-defaults">Firewall defaults</h2>
|
||||
<p>
|
||||
By default, a new swarm accepts connections from any peer that discovers the same topic (firewall
|
||||
mode <code>off</code>). You can lock this down two ways:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Per-page, at runtime</strong> — the page itself calls <code>swarm.setFirewall({ mode, keys })</code>. This is what the <a href="http://127.0.0.1:4173/firewall-room/" target="_blank" rel="noopener">Firewall Room</a> demo shows.</li>
|
||||
<li><strong>Globally, from Settings</strong> — set a <strong>Default peer firewall</strong> mode (allowlist or denylist) and a list of public keys; it is applied automatically whenever any swarm on your machine initializes.</li>
|
||||
</ul>
|
||||
<p>Whichever a page sets explicitly at runtime takes effect for that swarm going forward. See <a href="/docs/security.html">Security</a> for the full trust model.</p>
|
||||
|
||||
<h2 id="troubleshooting">Troubleshooting</h2>
|
||||
|
||||
<h3>"Native host has exited"</h3>
|
||||
<p>
|
||||
The launcher script starts the Bare runtime; if paths are stale after a manual reinstall, re-run the
|
||||
install script for your platform, or (from source) run <code>npm install</code> in
|
||||
<code>native-host/</code> followed by <code>npm run build:host</code>.
|
||||
</p>
|
||||
|
||||
<h3>"Access to the specified native messaging host is forbidden"</h3>
|
||||
<p>
|
||||
The extension ID in the native-messaging manifest doesn't match your installed extension's actual ID
|
||||
(this can happen if you load an unpacked dev build after installing the packaged release). From
|
||||
source, run <code>./scripts/update-native-manifest-extension-id.sh YOUR_EXTENSION_ID</code>.
|
||||
</p>
|
||||
|
||||
<h3>Device-file / storage errors ("Invalid device file, was modified")</h3>
|
||||
<p>
|
||||
BridgeSwarm's Corestore seals its on-disk storage to the underlying inode. If storage is
|
||||
<strong>copied</strong> across filesystems (rather than moved), the seal can be invalidated and the
|
||||
host will refuse to open it with an error like <em>"Invalid device file, was modified."</em> To avoid
|
||||
this:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Let the installer manage storage — it preserves <code>bridge-swarm-storage/</code> across
|
||||
reinstalls by moving it on the same filesystem whenever possible, and only falls back to a copy
|
||||
(which reseals) when moving across devices.</li>
|
||||
<li>Don't manually <code>cp -a</code> the storage directory between machines or drives if you want to
|
||||
preserve existing Hypercore keys — treat it as a move, not a copy, or expect a reseal.</li>
|
||||
<li>If you do hit this error, the safest recovery is to let the host create fresh storage (effectively
|
||||
new local keys) rather than fight the seal.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Users not showing up in each other's lists</h3>
|
||||
<ul>
|
||||
<li>Confirm both tabs joined the exact same topic string</li>
|
||||
<li>Enable <strong>Debug logging</strong> in Settings and check the Activity tab for join/connection events</li>
|
||||
<li>Confirm both tabs are on the same origin (e.g. both on <code>http://127.0.0.1:4173/...</code>) — a page on <code>file://</code> may not have BridgeSwarm injected at all</li>
|
||||
</ul>
|
||||
|
||||
<h3>Media demos stop working after an update (macOS)</h3>
|
||||
<p>
|
||||
Native ffmpeg/image-codec addons are code-signed on install. After updating the host, run
|
||||
<code>npm run repair:macos</code> (or re-run the installer) and then <strong>fully quit</strong> the
|
||||
browser (Cmd+Q) before testing again — a running browser process can hold a stale, unsigned addon in
|
||||
memory.
|
||||
</p>
|
||||
|
||||
<h2 id="updating">Updating</h2>
|
||||
<p>
|
||||
Run the exact same install command you used the first time (see <a href="/docs/quickstart.html">Quick
|
||||
Start</a>). It downloads the current <code>latest-main</code> artifacts, replaces the host binary, and
|
||||
rewrites the native-messaging manifest — while preserving your existing
|
||||
<code>bridge-swarm-storage/</code> directory (your Hypercore/Hyperbee/Hyperdrive/Autobase/Hyperdb
|
||||
data and keys). Reload the extension package the same way you loaded it initially.
|
||||
</p>
|
||||
|
||||
<h2 id="uninstall">Uninstalling</h2>
|
||||
<ol>
|
||||
<li>Remove the BridgeSwarm extension from <code>chrome://extensions</code> or Firefox's Add-ons manager.</li>
|
||||
<li>Delete the install directory: <code>~/.bridgeswarm/</code> (macOS/Linux) or <code>%LOCALAPPDATA%\bridgeswarm\</code> (Windows). This removes the host binary and your local <code>bridge-swarm-storage/</code>.</li>
|
||||
<li>Delete the native-messaging manifest named <code>com.bridgeswarm.json</code> from your browser's native-messaging-hosts directory (the installer prints this path when it runs, and it's under your browser's application-support / config directory).</li>
|
||||
</ol>
|
||||
<div class="docs-callout docs-callout-warning">
|
||||
Deleting <code>~/.bridgeswarm/</code> deletes local storage permanently, including any Hypercore keys
|
||||
and Hyperbee/Hyperdrive/Hyperdb data you created. Back it up first if you need it.
|
||||
</div>
|
||||
|
||||
<h2 id="privacy">Privacy & local storage</h2>
|
||||
<p>
|
||||
BridgeSwarm does not run a backend service and does not collect telemetry. Everything the native host
|
||||
persists lives locally under <code>BRIDGE_SWARM_STORAGE</code> (default
|
||||
<code>~/.bridgeswarm/bridge-swarm-storage/</code>), including:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Your Corestore — the underlying storage for Hypercore, Hyperbee, Hyperdrive, Autobase, and Hyperdb</li>
|
||||
<li>Capability job output under <code>cap-jobs/</code> (media transforms, live-encode archives)</li>
|
||||
<li>Extension settings, which live in the browser's own <code>chrome.storage.local</code>, not on the host</li>
|
||||
</ul>
|
||||
<p>
|
||||
Data you replicate or send only reaches peers you connect to — over an encrypted Noise channel — and
|
||||
only for topics or keys you explicitly join or open. There is no central server that ever sees your
|
||||
traffic. See <a href="/docs/security.html">Security</a> for the full threat model, and remember that
|
||||
any page you grant BridgeSwarm access to can, by design, open P2P connections and read/write local
|
||||
storage under the allowlisted paths — only use BridgeSwarm-enabled pages you trust.
|
||||
</p>
|
||||
|
||||
<h2 id="topics-vs-keys">Topics vs. keys — which do I use?</h2>
|
||||
<p>
|
||||
BridgeSwarm gives you two different ways to find and identify things, and it's easy to conflate them:
|
||||
</p>
|
||||
<table class="docs-table">
|
||||
<thead><tr><th></th><th>Topic</th><th>Public key</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>What it is</td><td>A 32-byte value (hex string) used with <code>swarm.join(topic)</code></td><td>The identity of a specific Hypercore/Hyperbee/Hyperdrive/Autobase/Hyperdb resource, or of a peer</td></tr>
|
||||
<tr><td>Purpose</td><td><strong>Discovery</strong> — find peers interested in the same thing, via the DHT</td><td><strong>Addressing / replication</strong> — reference one specific resource or peer, e.g. with <code>coreKeyHex</code></td></tr>
|
||||
<tr><td>Use it for</td><td>Chat rooms, shared sessions, "anyone doing X can find each other"</td><td>Replicating a specific append-only log, allowlisting/denylisting one peer, resuming a known dataset</td></tr>
|
||||
<tr><td>Example</td><td><code>swarm.join('my-app-lobby')</code></td><td><code>swarm.setAutoReplicate({ enabled: true, coreKeyHex })</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
Rule of thumb: use a <strong>topic</strong> when you want strangers with the same interest to find each
|
||||
other; use a <strong>key</strong> when you already know exactly which resource or peer you want to talk
|
||||
to. Many apps do both — join a topic to discover peers, then exchange or announce Hypercore keys over
|
||||
that connection to start replicating specific data.
|
||||
</p>
|
||||
|
||||
<nav class="docs-pager" aria-label="Pagination">
|
||||
<a class="docs-pager-link docs-pager-prev" href="/docs/quickstart.html">
|
||||
<span class="docs-pager-label">← Previous</span>
|
||||
<span class="docs-pager-title">Quick Start</span>
|
||||
</a>
|
||||
<a class="docs-pager-link docs-pager-next" href="/docs/developer-guide.html">
|
||||
<span class="docs-pager-label">Next →</span>
|
||||
<span class="docs-pager-title">Developer Guide</span>
|
||||
</a>
|
||||
</nav>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div data-footer></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,286 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#2dd4bf' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<title>Download & Install BridgeSwarm</title>
|
||||
<meta name="description" content="Install BridgeSwarm on macOS, Linux, or Windows: one-line installer, loading the extension in Chrome/Edge/Firefox, building from source, verifying the install, and troubleshooting.">
|
||||
<meta name="author" content="HoneyPeer, LLC">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/download">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
<link rel="stylesheet" href="/src/styles/download.css">
|
||||
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png">
|
||||
<link rel="shortcut icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf">
|
||||
<meta name="msapplication-TileImage" content="/assets/favicons/mstile-150x150.png">
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Download & Install BridgeSwarm">
|
||||
<meta property="og:description" content="One-line installer for macOS, Linux, and Windows. Load the extension, verify the native host, and troubleshoot common issues.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/download">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Download & Install BridgeSwarm">
|
||||
<meta name="twitter:description" content="One-line installer for macOS, Linux, and Windows. Load the extension, verify the native host, and troubleshoot common issues.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": "https://bridgeswarm.dev/#organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"logo": "https://bridgeswarm.dev/assets/logo/bridgeswarm-icon-512.png",
|
||||
"email": "[email protected]",
|
||||
"sameAs": ["https://git.ssh.surf/snxraven/BridgeSwarm"]
|
||||
},
|
||||
{
|
||||
"@type": "SoftwareApplication",
|
||||
"@id": "https://bridgeswarm.dev/#software",
|
||||
"name": "BridgeSwarm",
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"operatingSystem": "macOS, Linux, Windows",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"publisher": { "@id": "https://bridgeswarm.dev/#organization" },
|
||||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
|
||||
"license": "https://www.gnu.org/licenses/agpl-3.0.html",
|
||||
"downloadUrl": "https://bridgeswarm.dev/download",
|
||||
"softwareVersion": "1.0.0",
|
||||
"description": "Brings the Hyperswarm P2P stack into desktop browsers via a Bare native messaging host."
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="page-download">
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div class="bg-grid" aria-hidden="true"></div>
|
||||
|
||||
<div data-nav></div>
|
||||
|
||||
<main id="main">
|
||||
|
||||
<header class="page-hero">
|
||||
<div class="container">
|
||||
<p class="section-label" style="justify-content:center;">Download</p>
|
||||
<h1>Install BridgeSwarm</h1>
|
||||
<p class="lead">Two pieces: a small native host binary and a browser extension. The installer wires them together and registers native messaging so Chrome, Edge, and Firefox can find the host. No Node.js or git clone required for a normal install.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="section section-sm" id="install" aria-labelledby="install-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Step 1</p>
|
||||
<h2 id="install-title">Run the installer</h2>
|
||||
<p class="lead">Downloads prebuilt native-host binaries and the extension from the rolling Gitea release <a href="https://git.ssh.surf/snxraven/BridgeSwarm/releases/tag/latest-main"><code>latest-main</code></a>.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2 reveal">
|
||||
<div class="card">
|
||||
<span class="badge">macOS / Linux</span>
|
||||
<pre style="margin-top:1rem;"><code>curl -fsSL https://git.ssh.surf/snxraven/BridgeSwarm/raw/branch/main/scripts/web-installer.sh | bash</code></pre>
|
||||
<p>Installs the host to <code>~/.bridgeswarm/</code> and saves <code>BridgeSwarm-1.0.0.zip</code> / <code>.xpi</code> to <code>~/Downloads</code>.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<span class="badge badge-info">Windows (PowerShell)</span>
|
||||
<pre style="margin-top:1rem;"><code>irm https://git.ssh.surf/snxraven/BridgeSwarm/raw/branch/main/scripts/install.ps1 | iex</code></pre>
|
||||
<p>Run in a normal PowerShell window (no admin required). Installs to <code>%LOCALAPPDATA%\bridgeswarm\</code> and saves archives to <code>%USERPROFILE%\Downloads</code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="callout info reveal">
|
||||
<div class="callout-icon">i</div>
|
||||
<div class="callout-body">
|
||||
Coexists cleanly with <code>holesail-browser</code> if you have it installed — different install directory, different native messaging host name, different extension IDs. Neither installer touches the other's files.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="what-it-does" aria-labelledby="what-it-does-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Step 2</p>
|
||||
<h2 id="what-it-does-title">What the installer actually does</h2>
|
||||
<p class="lead">Nothing hidden — read <a href="https://git.ssh.surf/snxraven/BridgeSwarm/src/branch/main/scripts/install.sh">scripts/install.sh</a> yourself. In order:</p>
|
||||
</div>
|
||||
|
||||
<div class="card reveal">
|
||||
<ol style="padding-left:1.2rem; display:flex; flex-direction:column; gap:0.75rem; color:var(--text-secondary);">
|
||||
<li>Stops any running <code>bridge-swarm-host</code> process (path-scoped, never touches other native hosts).</li>
|
||||
<li>Preserves your existing <code>bridge-swarm-storage</code> directory (moved aside, not copied, so the Corestore device-file seal survives a reinstall).</li>
|
||||
<li>Downloads and unzips the platform binary for your OS/arch from the <code>latest-main</code> Gitea release.</li>
|
||||
<li>On macOS: clears the quarantine attribute, ad-hoc code-signs the host binary and its extracted <code>.bare</code>/<code>.dylib</code> addons, and writes an entitlements plist so library validation doesn't block unsigned native addons.</li>
|
||||
<li>Writes a small launcher script that sets <code>BRIDGE_SWARM_STORAGE</code> and <code>BRIDGESWARM_EXAMPLES_DIR</code> before starting the binary.</li>
|
||||
<li>Writes native messaging manifests named <code>com.bridgeswarm.json</code> into the Chrome, Chromium, and Firefox native-messaging-hosts directories for your OS — never overwriting any other vendor's manifest.</li>
|
||||
<li>Restores your preserved storage directory.</li>
|
||||
<li>Downloads the extension <code>.zip</code> (Chrome/Edge) and <code>.xpi</code> (Firefox) into your Downloads folder, removing any stale <code>BridgeSwarm-*</code> archives first.</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="load-extension" aria-labelledby="load-extension-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Step 3</p>
|
||||
<h2 id="load-extension-title">Load the extension</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2 reveal">
|
||||
<div class="card">
|
||||
<h3>Chrome / Edge</h3>
|
||||
<ol style="padding-left:1.1rem; display:flex; flex-direction:column; gap:0.6rem; color:var(--text-secondary); font-size:0.92rem;">
|
||||
<li>Open <code>chrome://extensions</code>.</li>
|
||||
<li>Enable <strong>Developer mode</strong> (top right).</li>
|
||||
<li>Drag & drop <code>~/Downloads/BridgeSwarm-1.0.0.zip</code> onto the page — or extract it and use <strong>Load unpacked</strong>.</li>
|
||||
<li>Confirm the extension ID reads exactly <code>jhmbaojjfkkpoolhkoohklbjokdmbdpm</code>. If it doesn't match, re-download rather than editing IDs by hand.</li>
|
||||
<li>Fully restart the browser (quit, don't just close the window).</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>Firefox</h3>
|
||||
<ol style="padding-left:1.1rem; display:flex; flex-direction:column; gap:0.6rem; color:var(--text-secondary); font-size:0.92rem;">
|
||||
<li><strong>Temporary</strong> (any Firefox): <code>about:debugging</code> → <strong>This Firefox</strong> → <strong>Load Temporary Add-on…</strong> → select the downloaded <code>.zip</code>.</li>
|
||||
<li><strong>Permanent</strong> (Nightly / Developer Edition only): set <code>xpinstall.signatures.required</code> to <code>false</code> in <code>about:config</code>, then <code>about:addons</code> → gear → <strong>Install Add-on From File</strong> → select the <code>.xpi</code>.</li>
|
||||
<li>Restart Firefox after installing.</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<p class="lead" style="margin-top:1.5rem;">Both browsers require a full restart after the first install — native messaging hosts are only re-discovered on browser startup.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="from-source" aria-labelledby="from-source-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Step 4</p>
|
||||
<h2 id="from-source-title">Building from source</h2>
|
||||
<p class="lead">For contributors, or if you'd rather build the host yourself instead of trusting a prebuilt binary.</p>
|
||||
</div>
|
||||
<div class="card reveal">
|
||||
<pre><code>git clone https://git.ssh.surf/snxraven/BridgeSwarm.git
|
||||
cd BridgeSwarm
|
||||
npm run setup # or ./scripts/install-from-source.sh
|
||||
# Then in the browser: Load unpacked → the extension/ directory</code></pre>
|
||||
<p>Requires Node.js for tooling; the host itself runs on Bare <code>>=1.29.4</code> pulled in as an npm dependency.</p>
|
||||
<pre><code>npm run pack # extension zip + xpi
|
||||
npm run build:dist:package # all-platform host zips (best run on CI with bare-build)</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="verify" aria-labelledby="verify-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Step 5</p>
|
||||
<h2 id="verify-title">Verify the install</h2>
|
||||
</div>
|
||||
|
||||
<div class="docs-cards reveal">
|
||||
<a class="docs-card" href="#" onclick="return false;" style="cursor:default;">
|
||||
<span class="card-tag">Overview</span>
|
||||
<h3>Open the Control Center</h3>
|
||||
<p>Click the BridgeSwarm toolbar icon → Dashboard. The Overview tab should show the native host as connected.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="http://127.0.0.1:4173/">
|
||||
<span class="card-tag">Examples</span>
|
||||
<h3>Enable the examples server</h3>
|
||||
<p>In Settings, toggle <strong>Examples server</strong> on, then open <strong>http://127.0.0.1:4173/</strong> — not <code>file://</code>.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/learn/#capabilities">
|
||||
<span class="card-tag">Console</span>
|
||||
<h3>Check the page API</h3>
|
||||
<p>Run <code>await BridgeSwarm.ready()</code> then <code>BridgeSwarm.capabilities.list()</code> in devtools.</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="troubleshooting" aria-labelledby="troubleshooting-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Troubleshooting</p>
|
||||
<h2 id="troubleshooting-title">Common issues</h2>
|
||||
</div>
|
||||
|
||||
<div class="card reveal" style="display:flex; flex-direction:column; gap:0.5rem;">
|
||||
<details>
|
||||
<summary style="cursor:pointer; font-weight:650; padding:0.5rem 0;">"Native host has exited"</summary>
|
||||
<p style="padding:0.25rem 0 0.75rem;">The launcher runs Bare via Node. Re-run the installer, or from a source checkout run <code>npm install</code> in <code>native-host/</code> followed by <code>npm run build:host</code>, so the local <code>bare</code> dependency and launcher paths are correct.</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary style="cursor:pointer; font-weight:650; padding:0.5rem 0;">"Access to the specified native messaging host is forbidden"</summary>
|
||||
<p style="padding:0.25rem 0 0.75rem;">Your extension ID doesn't match the native messaging manifest's <code>allowed_origins</code>. From source: <code>./scripts/update-native-manifest-extension-id.sh YOUR_EXTENSION_ID</code>. For a release install, re-run the installer instead of hand-editing the manifest.</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary style="cursor:pointer; font-weight:650; padding:0.5rem 0;">"hrpc not available"</summary>
|
||||
<p style="padding:0.25rem 0 0.75rem;">The HRPC spec hasn't been generated for this build. From a source checkout, run <code>npm run build:hrpc</code>.</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary style="cursor:pointer; font-weight:650; padding:0.5rem 0;">macOS: media capability missing after an update</summary>
|
||||
<p style="padding:0.25rem 0 0.75rem;">Run <code>npm run repair:macos</code> so the <code>.bare</code> addons (including <code>bare-ffmpeg</code>) are re-extracted and codesigned, then fully quit the browser (Cmd+Q) and relaunch.</p>
|
||||
</details>
|
||||
<details>
|
||||
<summary style="cursor:pointer; font-weight:650; padding:0.5rem 0;">Peers aren't showing up in each other's lists</summary>
|
||||
<p style="padding:0.25rem 0 0.75rem;">Confirm every tab is joined to the exact same topic string, enable debug logging in Settings, and check the Dashboard's Activity tab for connection events.</p>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<p class="lead" style="margin-top:1.5rem;">Still stuck? See <a href="/community#support">community & support</a>, or read the full <a href="/learn/">user guide</a> for how the pieces fit together.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta-band reveal">
|
||||
<div class="container">
|
||||
<div class="cta-card">
|
||||
<h2>Ready to write your first P2P app?</h2>
|
||||
<p class="lead">The user guide walks through Hyperswarm topics, Noise, Hyper* storage, and the Control Center from first principles.</p>
|
||||
<div class="cta-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/learn/">Read the user guide</a>
|
||||
<a class="btn btn-ghost btn-lg" href="/use-cases/">Browse use cases</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<div data-footer></div>
|
||||
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,479 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#2dd4bf' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<title>BridgeSwarm — Hyperswarm P2P in your browser</title>
|
||||
<meta name="description" content="BridgeSwarm brings the Hyperswarm P2P stack into ordinary desktop browsers. A Bare native host runs Hyperswarm, Hyper* storage, and Protomux/HRPC; a browser extension injects window.BridgeSwarm into the page. No signaling server, no forked browser.">
|
||||
<meta name="author" content="HoneyPeer, LLC">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
<link rel="stylesheet" href="/src/styles/home.css">
|
||||
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png">
|
||||
<link rel="shortcut icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf">
|
||||
<meta name="msapplication-TileImage" content="/assets/favicons/mstile-150x150.png">
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="BridgeSwarm — Hyperswarm P2P in your browser">
|
||||
<meta property="og:description" content="Peer-to-peer networking, encrypted transport, and Hyper* storage in Chrome, Edge, and Firefox — via a Bare native host, not a server. No signup, AGPL-3.0.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="BridgeSwarm — Hyperswarm P2P in your browser">
|
||||
<meta name="twitter:description" content="Peer-to-peer networking, encrypted transport, and Hyper* storage in Chrome, Edge, and Firefox — via a Bare native host, not a server.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": "https://bridgeswarm.dev/#organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"logo": "https://bridgeswarm.dev/assets/logo/bridgeswarm-icon-512.png",
|
||||
"email": "[email protected]",
|
||||
"sameAs": ["https://git.ssh.surf/snxraven/BridgeSwarm"]
|
||||
},
|
||||
{
|
||||
"@type": "SoftwareApplication",
|
||||
"@id": "https://bridgeswarm.dev/#software",
|
||||
"name": "BridgeSwarm",
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"operatingSystem": "macOS, Linux, Windows",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"publisher": { "@id": "https://bridgeswarm.dev/#organization" },
|
||||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
|
||||
"license": "https://www.gnu.org/licenses/agpl-3.0.html",
|
||||
"downloadUrl": "https://bridgeswarm.dev/download",
|
||||
"softwareVersion": "1.0.0",
|
||||
"description": "Brings the Hyperswarm P2P stack into desktop browsers via a Bare native messaging host, exposing window.BridgeSwarm to web pages."
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="page-home">
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div class="bg-grid" aria-hidden="true"></div>
|
||||
|
||||
<div data-nav></div>
|
||||
|
||||
<main id="main">
|
||||
|
||||
<section class="hero">
|
||||
<canvas class="hero-canvas" aria-hidden="true"></canvas>
|
||||
<div class="hero-veil" aria-hidden="true"></div>
|
||||
<div class="container hero-inner">
|
||||
<p class="hero-badge"><span class="dot" aria-hidden="true"></span> Peer-to-peer for the ordinary browser</p>
|
||||
<div class="hero-brand-lockup">
|
||||
<img src="/assets/logo/bridgeswarm-icon-512.png" width="140" height="140" alt="BridgeSwarm — three peer nodes linked by two bridges" decoding="async">
|
||||
</div>
|
||||
<h1>Hyperswarm in the browser.<br>No server. No fork.</h1>
|
||||
<p class="lead">BridgeSwarm runs a real Hyperswarm node next to Chrome, Edge, or Firefox and hands your page a plain <code>window.BridgeSwarm</code> API for encrypted, NAT-punching P2P connections and Hyper* storage.</p>
|
||||
<div class="hero-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/download">Install BridgeSwarm</a>
|
||||
<a class="btn btn-ghost btn-lg" href="/docs/">Read the docs</a>
|
||||
</div>
|
||||
<div class="hero-stats">
|
||||
<div class="hero-stat">
|
||||
<strong data-count-to="5">0</strong>
|
||||
<span>Hyper* storage modules</span>
|
||||
</div>
|
||||
<div class="hero-stat">
|
||||
<strong data-count-to="0">0</strong>
|
||||
<span>signaling servers required</span>
|
||||
</div>
|
||||
<div class="hero-stat">
|
||||
<strong data-count-to="12" data-count-suffix="+">0+</strong>
|
||||
<span>runnable examples</span>
|
||||
</div>
|
||||
<div class="hero-stat">
|
||||
<strong data-count-to="3" data-count-suffix="">0</strong>
|
||||
<span>supported browsers</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-scroll-cue" aria-hidden="true">
|
||||
<span>Scroll</span>
|
||||
<span class="cue-line"></span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="tech-strip">
|
||||
<div class="container tech-strip-inner">
|
||||
<span class="tech-item"><span></span>Hyperswarm</span>
|
||||
<span class="tech-item"><span></span>Noise</span>
|
||||
<span class="tech-item"><span></span>Hypercore</span>
|
||||
<span class="tech-item"><span></span>Hyperbee</span>
|
||||
<span class="tech-item"><span></span>Hyperdrive</span>
|
||||
<span class="tech-item"><span></span>Autobase</span>
|
||||
<span class="tech-item"><span></span>Hyperdb</span>
|
||||
<span class="tech-item"><span></span>Protomux</span>
|
||||
<span class="tech-item"><span></span>HRPC</span>
|
||||
<span class="tech-item"><span></span>Bare</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="section" id="why" aria-labelledby="why-title">
|
||||
<div class="container">
|
||||
<div class="section-head center reveal">
|
||||
<p class="section-label">Why BridgeSwarm</p>
|
||||
<h2 id="why-title">Stop routing every byte through a server you have to pay for and trust</h2>
|
||||
<p class="lead" style="margin-inline:auto;">The client–server model puts one machine in the middle of every interaction. BridgeSwarm puts your users directly in touch with each other, with the server relegated to an optional convenience instead of a hard dependency.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2 reveal">
|
||||
<div class="card">
|
||||
<h3>Traditional client–server</h3>
|
||||
<ul class="feature-list" style="margin-top:1rem;">
|
||||
<li>Single point of failure — the server goes down, everyone goes down</li>
|
||||
<li>Every message pays a round trip through infrastructure you operate</li>
|
||||
<li>Bandwidth costs scale with your user count, not with peer proximity</li>
|
||||
<li>All traffic and metadata is visible to whoever runs the server</li>
|
||||
<li>Shipping a live feature means shipping a backend</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>BridgeSwarm P2P</h3>
|
||||
<ul class="feature-list" style="margin-top:1rem;">
|
||||
<li>Peers discover and connect directly — no host to keep online</li>
|
||||
<li>Data moves point-to-point over Noise-encrypted sockets</li>
|
||||
<li>Bandwidth is distributed across the swarm, not billed to you</li>
|
||||
<li>Only participants who join a topic ever see that topic's traffic</li>
|
||||
<li>Hyper* storage, replication, and RPC ship in the host — for free</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="use-cases" aria-labelledby="use-cases-title">
|
||||
<div class="container">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Built for</p>
|
||||
<h2 id="use-cases-title">What you can build once every tab is a peer</h2>
|
||||
<p class="lead">Eight shapes of app that get simpler the moment browsers can talk to each other directly.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container usecase-rail-wrap reveal">
|
||||
<div class="usecase-rail">
|
||||
<a class="usecase-card" href="/use-cases/#chat">
|
||||
<span class="usecase-icon" aria-hidden="true">01</span>
|
||||
<h3>P2P chat rooms</h3>
|
||||
<p>Topic-scoped rooms with presence, no message broker, no chat backend to scale.</p>
|
||||
<span class="usecase-link">Learn more →</span>
|
||||
</a>
|
||||
<a class="usecase-card" href="/use-cases/#collab">
|
||||
<span class="usecase-icon" aria-hidden="true">02</span>
|
||||
<h3>Collaborative apps</h3>
|
||||
<p>Shared whiteboards and multiplayer surfaces driven by direct peer connections.</p>
|
||||
<span class="usecase-link">Learn more →</span>
|
||||
</a>
|
||||
<a class="usecase-card" href="/use-cases/#sync">
|
||||
<span class="usecase-icon" aria-hidden="true">03</span>
|
||||
<h3>Data sync</h3>
|
||||
<p>Hypercore auto-replication keeps append-only logs and Hyperbee stores in sync across peers.</p>
|
||||
<span class="usecase-link">Learn more →</span>
|
||||
</a>
|
||||
<a class="usecase-card" href="/use-cases/#live-media">
|
||||
<span class="usecase-icon" aria-hidden="true">04</span>
|
||||
<h3>Live media</h3>
|
||||
<p>Host-side <code>bare-ffmpeg</code> VP9 encode streamed to MSE and fanned out over the swarm.</p>
|
||||
<span class="usecase-link">Learn more →</span>
|
||||
</a>
|
||||
<a class="usecase-card" href="/use-cases/#self-hosted">
|
||||
<span class="usecase-icon" aria-hidden="true">05</span>
|
||||
<h3>Self-hosted web apps</h3>
|
||||
<p>Serve real HTML from the native host on <code>127.0.0.1</code> — no cloud hosting required.</p>
|
||||
<span class="usecase-link">Learn more →</span>
|
||||
</a>
|
||||
<a class="usecase-card" href="/use-cases/#live-domains">
|
||||
<span class="usecase-icon" aria-hidden="true">06</span>
|
||||
<h3>Live topic domains</h3>
|
||||
<p>Treat a Hyperswarm topic like a rendezvous address peers "dial" instead of a DNS name.</p>
|
||||
<span class="usecase-link">Learn more →</span>
|
||||
</a>
|
||||
<a class="usecase-card" href="/use-cases/#firewall">
|
||||
<span class="usecase-icon" aria-hidden="true">07</span>
|
||||
<h3>Firewall-controlled rooms</h3>
|
||||
<p>Allowlist, denylist, and ban peers by public key with <code>swarm.setFirewall</code>.</p>
|
||||
<span class="usecase-link">Learn more →</span>
|
||||
</a>
|
||||
<a class="usecase-card" href="/use-cases/#dev-tooling">
|
||||
<span class="usecase-icon" aria-hidden="true">08</span>
|
||||
<h3>Developer tooling</h3>
|
||||
<p>HRPC and Protomux give you typed, streaming RPC over a P2P transport without hand-rolled framing.</p>
|
||||
<span class="usecase-link">Learn more →</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="features" aria-labelledby="features-title">
|
||||
<div class="container">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">What's in the host</p>
|
||||
<h2 id="features-title">A full P2P stack, not a wrapper around WebRTC</h2>
|
||||
<p class="lead">The native host is a real <a href="https://github.com/holepunchto/bare">Bare</a> runtime running the same modules that power Holepunch's Pear and Keet — reachable from any page through the extension.</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-row reveal">
|
||||
<div class="feature-copy">
|
||||
<p class="section-label">Transport</p>
|
||||
<h2>Peer-to-peer, secured by default</h2>
|
||||
<p class="lead">Every connection is discovered through the Hyperswarm DHT and encrypted before your first byte moves — no certificates, no key exchange to write.</p>
|
||||
<ul class="feature-list">
|
||||
<li><strong>Noise encryption</strong> — every socket is a Noise-protocol secret stream, automatically.</li>
|
||||
<li><strong>NAT traversal</strong> — UDP hole-punching gets peers behind home routers and firewalls talking directly.</li>
|
||||
<li><strong>Unique identities</strong> — each tab gets its own cryptographic key pair.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="feature-visual">
|
||||
<pre><code>const swarm = new BridgeSwarm({ appName: 'my-app' });
|
||||
await swarm.join('my-topic');
|
||||
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
console.log('peer:', peerInfo.publicKey);
|
||||
conn.write('hello, peer');
|
||||
});</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-row reverse reveal">
|
||||
<div class="feature-copy">
|
||||
<p class="section-label">Storage & protocols</p>
|
||||
<h2>A real data stack, not a wrapper</h2>
|
||||
<p class="lead">Hypercore, Hyperbee, Hyperdrive, Autobase, and Hyperdb run in the host and are callable straight from the page.</p>
|
||||
<ul class="feature-list">
|
||||
<li><strong>Hyper* storage</strong> — append-only logs, key/value stores, a P2P filesystem, multi-writer logs, and a schema-based database.</li>
|
||||
<li><strong>Protomux</strong> — multiplex your own message protocols over one connection, in-page.</li>
|
||||
<li><strong>HRPC</strong> — typed, streaming RPC attached on the host with <code>attachHrpc</code>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="feature-visual">
|
||||
<pre><code>await BridgeSwarm.request('beePut', { key: 'title', value: 'Q3 plan' });
|
||||
const doc = await BridgeSwarm.request('beeGet', { key: 'title' });
|
||||
|
||||
await BridgeSwarm.request('attachHrpc', { connId });
|
||||
const res = await swarm.hrpcCall(connId, 'ping', { value: 'hi' });</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-row reveal">
|
||||
<div class="feature-copy">
|
||||
<p class="section-label">Media</p>
|
||||
<h2>Live encode that never touches the page</h2>
|
||||
<p class="lead"><code>bare-ffmpeg</code> runs on the host: probe, transform, batch transcode, and live VP9/WebM encode straight to MSE or a peer connection.</p>
|
||||
<ul class="feature-list">
|
||||
<li><strong>Live sessions</strong> — push captured frames in, stream encoded segments out.</li>
|
||||
<li><strong>Batch jobs</strong> — image/video probing, resizing, and format conversion.</li>
|
||||
<li><strong>Flexible egress</strong> — page playback, swarm fan-out, or archive to disk, in any combination.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="feature-visual">
|
||||
<pre><code>const live = BridgeSwarm.media.liveSession(videoEl);
|
||||
await live.start({ width: 640, height: 360, fps: 10 });
|
||||
await live.pushFrame(canvas);
|
||||
await live.subscribe({ swarm: { connIds: [conn.connId] } });</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feature-row reverse reveal">
|
||||
<div class="feature-copy">
|
||||
<p class="section-label">Operations</p>
|
||||
<h2>Control Center & examples, out of the box</h2>
|
||||
<p class="lead">Everything autosaves. There is no config file to hand-edit and no separate deploy step for the demo gallery.</p>
|
||||
<ul class="feature-list">
|
||||
<li><strong>Control Center</strong> — live Overview, Swarms, Connections, and Activity views, plus Settings.</li>
|
||||
<li><strong>Examples server</strong> — one toggle serves a dozen demos at <code>127.0.0.1:4173</code>.</li>
|
||||
<li><strong>Debug logging</strong> — flip it on in Settings when a connection misbehaves.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="feature-visual">
|
||||
<pre><code>// extension -> host, on settings change
|
||||
examplesServer.start({ host: '127.0.0.1', port: 4173 })
|
||||
// host responds
|
||||
{ running: true, url: 'http://127.0.0.1:4173/' }</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section arch-section" id="architecture" aria-labelledby="architecture-title">
|
||||
<div class="container">
|
||||
<div class="section-head center reveal">
|
||||
<p class="section-label">How it fits together</p>
|
||||
<h2 id="architecture-title">Three layers: page, extension, Bare host</h2>
|
||||
<p class="lead" style="margin-inline:auto;">The page never talks to the operating system directly. Everything crosses a narrow, auditable boundary.</p>
|
||||
</div>
|
||||
|
||||
<div class="arch-diagram reveal">
|
||||
<div class="arch-node">
|
||||
<div class="node-icon" aria-hidden="true">◧</div>
|
||||
<h3>Web page</h3>
|
||||
<p><code>window.BridgeSwarm</code></p>
|
||||
</div>
|
||||
<div class="arch-arrow" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 12h14M13 6l6 6-6 6"/></svg>
|
||||
postMessage
|
||||
</div>
|
||||
<div class="arch-node">
|
||||
<div class="node-icon" aria-hidden="true">⬡</div>
|
||||
<h3>Extension (MV3)</h3>
|
||||
<p>background + content script</p>
|
||||
</div>
|
||||
<div class="arch-arrow" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 12h14M13 6l6 6-6 6"/></svg>
|
||||
native messaging
|
||||
</div>
|
||||
<div class="arch-node">
|
||||
<div class="node-icon" aria-hidden="true">⌘</div>
|
||||
<h3>Bare host</h3>
|
||||
<p>Hyperswarm · Hyper* · HRPC</p>
|
||||
</div>
|
||||
<div class="arch-arrow" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 12h14M13 6l6 6-6 6"/></svg>
|
||||
Noise P2P
|
||||
</div>
|
||||
<div class="arch-node is-info">
|
||||
<div class="node-icon" aria-hidden="true">◎</div>
|
||||
<h3>Remote peers</h3>
|
||||
<p>other browsers running BridgeSwarm</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arch-details reveal">
|
||||
<div class="arch-detail">
|
||||
<h4>postMessage bridge</h4>
|
||||
<p>The content script injects <code>api.js</code>; the page and extension talk only through <code>window.postMessage</code>.</p>
|
||||
</div>
|
||||
<div class="arch-detail">
|
||||
<h4>Native messaging</h4>
|
||||
<p>4-byte little-endian length + UTF-8 JSON between the extension and <code>com.bridgeswarm</code>, ~1 MB per message.</p>
|
||||
</div>
|
||||
<div class="arch-detail">
|
||||
<h4>Noise encryption</h4>
|
||||
<p>Every peer connection is a Noise secret stream, encrypted and authenticated before data moves.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="diagram reveal" style="margin-top:2.5rem;">
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant Page
|
||||
participant ContentScript
|
||||
participant Background
|
||||
participant NativeHost
|
||||
Page->>ContentScript: postMessage (bridge-swarm-bridge)
|
||||
ContentScript->>Background: runtime.sendMessage (send)
|
||||
Background->>NativeHost: port.postMessage {id, type, payload}
|
||||
NativeHost->>NativeHost: handleMessage -> reply(result)
|
||||
NativeHost->>Background: messenger.send {id, type: response}
|
||||
Background->>ContentScript: sendResponse(payload)
|
||||
ContentScript->>Page: dispatchEvent (bridge-swarm-bridge-response)
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="quickstart" aria-labelledby="quickstart-title">
|
||||
<div class="container">
|
||||
<div class="section-head center reveal">
|
||||
<p class="section-label">Quick start</p>
|
||||
<h2 id="quickstart-title">Install, load the extension, join a topic</h2>
|
||||
<p class="lead" style="margin-inline:auto;">The full guide covers Windows, verification, and troubleshooting. This is the fast path.</p>
|
||||
</div>
|
||||
|
||||
<div class="install-tabs reveal">
|
||||
<button type="button" class="install-tab is-active" data-install-tab="mac">macOS / Linux</button>
|
||||
<button type="button" class="install-tab" data-install-tab="win">Windows</button>
|
||||
</div>
|
||||
|
||||
<div class="install-card reveal">
|
||||
<div class="install-panel is-active" data-install-panel="mac">
|
||||
<pre><code>curl -fsSL https://git.ssh.surf/snxraven/BridgeSwarm/raw/branch/main/scripts/web-installer.sh | bash</code></pre>
|
||||
</div>
|
||||
<div class="install-panel" data-install-panel="win">
|
||||
<pre><code>irm https://git.ssh.surf/snxraven/BridgeSwarm/raw/branch/main/scripts/install.ps1 | iex</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="quickstart-steps reveal">
|
||||
<div class="quickstart-step">
|
||||
<div class="step-num">1</div>
|
||||
<h3>Install the host</h3>
|
||||
<p>Installs to <code>~/.bridgeswarm</code> and drops <code>BridgeSwarm-1.0.0.zip</code> / <code>.xpi</code> into <code>~/Downloads</code>.</p>
|
||||
</div>
|
||||
<div class="quickstart-step">
|
||||
<div class="step-num">2</div>
|
||||
<h3>Load the extension</h3>
|
||||
<p>Open <code>chrome://extensions</code>, enable Developer mode, drag the zip in. Confirm the ID reads <code>jhmbaojjfkkpoolhkoohklbjokdmbdpm</code>, then restart.</p>
|
||||
</div>
|
||||
<div class="quickstart-step">
|
||||
<div class="step-num">3</div>
|
||||
<h3>Join a topic</h3>
|
||||
<p><code>await swarm.join('my-topic')</code> and handle the <code>connection</code> event. That's the whole API surface for chat.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-6 reveal">
|
||||
<a class="btn btn-secondary" href="/download">Full install guide →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta-band reveal">
|
||||
<div class="container">
|
||||
<div class="cta-card">
|
||||
<p class="section-label" style="justify-content:center;">Get started</p>
|
||||
<h2>Give your page a real P2P stack</h2>
|
||||
<p class="lead">Free, source-available under AGPL-3.0, and running on the same modules that power Holepunch's Pear runtime.</p>
|
||||
<div class="cta-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/download">Install BridgeSwarm</a>
|
||||
<a class="btn btn-ghost btn-lg" href="/use-cases/">Browse use cases</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<div data-footer></div>
|
||||
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
<script type="module" src="/src/js/home.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,324 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#2dd4bf' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<title>How BridgeSwarm Works — Learn</title>
|
||||
<meta name="description" content="A deep, technical walkthrough of BridgeSwarm: native messaging, the Bare host, Hyperswarm topics as rendezvous, Noise encryption, Hyper* storage, Protomux/HRPC, capability packs, the Control Center, and the mental model behind live domains and self-hosted apps.">
|
||||
<meta name="author" content="HoneyPeer, LLC">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/learn/">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
<link rel="stylesheet" href="/src/styles/learn.css">
|
||||
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png">
|
||||
<link rel="shortcut icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf">
|
||||
<meta name="msapplication-TileImage" content="/assets/favicons/mstile-150x150.png">
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml">
|
||||
|
||||
<meta property="og:type" content="article">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="How BridgeSwarm Works — Learn">
|
||||
<meta property="og:description" content="Native messaging, the Bare host, Hyperswarm topics as rendezvous, Noise, Hyper* storage, Protomux/HRPC, capabilities, and the Control Center — explained from first principles.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/learn/">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="How BridgeSwarm Works — Learn">
|
||||
<meta name="twitter:description" content="Native messaging, the Bare host, Hyperswarm topics as rendezvous, Noise, Hyper* storage, Protomux/HRPC, capabilities, and the Control Center.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": "https://bridgeswarm.dev/#organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"logo": "https://bridgeswarm.dev/assets/logo/bridgeswarm-icon-512.png",
|
||||
"email": "[email protected]",
|
||||
"sameAs": ["https://git.ssh.surf/snxraven/BridgeSwarm"]
|
||||
},
|
||||
{
|
||||
"@type": "SoftwareApplication",
|
||||
"@id": "https://bridgeswarm.dev/#software",
|
||||
"name": "BridgeSwarm",
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"operatingSystem": "macOS, Linux, Windows",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"publisher": { "@id": "https://bridgeswarm.dev/#organization" },
|
||||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
|
||||
"license": "https://www.gnu.org/licenses/agpl-3.0.html",
|
||||
"downloadUrl": "https://bridgeswarm.dev/download",
|
||||
"softwareVersion": "1.0.0",
|
||||
"description": "Brings the Hyperswarm P2P stack into desktop browsers via a Bare native messaging host."
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="page-learn">
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div class="bg-grid" aria-hidden="true"></div>
|
||||
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<main id="main">
|
||||
|
||||
<header class="page-hero">
|
||||
<div class="container">
|
||||
<p class="section-label" style="justify-content:center;">Learn</p>
|
||||
<h1>How BridgeSwarm works</h1>
|
||||
<p class="lead">Everything between <code>window.BridgeSwarm</code> in your page and a live Noise-encrypted socket to a peer's machine — the long version.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<article class="docs-main" style="max-width: var(--docs-max, 58rem); margin-inline: auto; padding-top: 0;">
|
||||
|
||||
<nav class="toc" aria-label="On this page">
|
||||
<strong>On this page</strong>
|
||||
<ol>
|
||||
<li><a href="#native-messaging">Native messaging</a></li>
|
||||
<li><a href="#bare-host">The Bare host</a></li>
|
||||
<li><a href="#topics">Hyperswarm topics as rendezvous</a></li>
|
||||
<li><a href="#noise">Noise encryption</a></li>
|
||||
<li><a href="#hyperstack">Hyper* storage</a></li>
|
||||
<li><a href="#protomux-hrpc">Protomux & HRPC</a></li>
|
||||
<li><a href="#capabilities">Capability packs</a></li>
|
||||
<li><a href="#control-center">Control Center</a></li>
|
||||
<li><a href="#mental-model">Live domains & self-hosted apps</a></li>
|
||||
<li><a href="#flows">Message flows</a></li>
|
||||
<li><a href="#glossary">Glossary</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<section id="native-messaging" aria-labelledby="native-messaging-title">
|
||||
<h2 id="native-messaging-title">Native messaging</h2>
|
||||
<p>Browser extensions cannot open sockets, spawn processes, or touch the filesystem directly — that sandbox is exactly what keeps a random web page from doing the same. <strong>Native messaging</strong> is the narrow, browser-mediated exception: an extension's background script can launch one specific, pre-registered executable and exchange length-prefixed JSON with it over stdin/stdout.</p>
|
||||
<p>BridgeSwarm registers a host named <code>com.bridgeswarm</code>. When you install, the installer writes a manifest — <code>com.bridgeswarm.json</code> — into your browser's native-messaging-hosts directory, pointing at the launcher script for the host binary and listing the extension IDs allowed to connect to it (<code>allowed_origins</code> for Chrome, <code>allowed_extensions</code> for Firefox). The browser enforces that allowlist; nothing else can attach to your BridgeSwarm host.</p>
|
||||
<p>The wire format is deliberately boring: a <strong>4-byte little-endian length prefix</strong> followed by UTF-8 JSON, in both directions. Binary payloads (media chunks, Hyperdrive file contents) are base64-encoded inside that JSON, which caps a single host→browser message at roughly <strong>1 MB</strong> — one reason live media encode streams segments rather than raw frames.</p>
|
||||
<pre><code>// Message shapes on the wire
|
||||
{ id, type, payload } // request (page -> host)
|
||||
{ id, type: 'response', payload } // response (host -> page)
|
||||
{ type: 'event', event, payload } // event (host -> page, unsolicited)</code></pre>
|
||||
</section>
|
||||
|
||||
<section id="bare-host" aria-labelledby="bare-host-title">
|
||||
<h2 id="bare-host-title">The Bare host</h2>
|
||||
<p><a href="https://github.com/holepunchto/bare">Bare</a> is a small JavaScript runtime built by Holepunch specifically to run their P2P stack outside the browser — the same runtime underneath Pear and Keet. BridgeSwarm's native host is a Bare process, not a Node process pretending to be one: a release build ships a self-contained binary, while a from-source build runs Bare via a local <code>bare</code> npm dependency.</p>
|
||||
<p>On startup the host wires up, in order:</p>
|
||||
<ul>
|
||||
<li><strong>bare-process</strong> and default capability packs (media / <code>bare-ffmpeg</code>).</li>
|
||||
<li><strong>messenger.js</strong> — the native messaging framing described above.</li>
|
||||
<li><strong>host.js</strong> — swarm lifecycle, peer firewall/ban, Hyper* data API, Protomux/HRPC attachment, and the optional examples server.</li>
|
||||
</ul>
|
||||
<p>Because it's a real runtime with real native module support, the host can load <code>bare-ffmpeg</code>, <code>bare-fs</code>, and similar packages that would be meaningless inside a browser sandbox — while the page still only ever sees the plain JS object <code>window.BridgeSwarm</code>.</p>
|
||||
<div class="callout warn">
|
||||
<div class="callout-icon">!</div>
|
||||
<div class="callout-body"><strong>The native host runs with your full user privileges</strong> — it can open sockets and read/write files. Only install BridgeSwarm builds you trust, the same way you'd treat any other native application.</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="topics" aria-labelledby="topics-title">
|
||||
<h2 id="topics-title">Hyperswarm topics as rendezvous</h2>
|
||||
<p>There is no BridgeSwarm server that brokers connections. Instead, <strong>Hyperswarm</strong> uses a public, distributed hash table (DHT) purely as a rendezvous mechanism: peers <code>announce</code> and <code>lookup</code> a 32-byte <strong>topic</strong> — usually the hash of a string like <code>"my-app-room-42"</code> — and the DHT tells them about each other's network addresses. The actual connection, once addresses are known, is established directly between peers with UDP hole-punching for NAT traversal.</p>
|
||||
<p>From the page, this collapses into one call:</p>
|
||||
<pre><code>const swarm = new BridgeSwarm({ appName: 'my-app' });
|
||||
await swarm.join('my-topic');
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
console.log('peer:', peerInfo.publicKey);
|
||||
});</code></pre>
|
||||
<p>Because the topic is just a shared secret string (or its hash), you can think of it as an address peers "dial" — see <a href="#mental-model">Live domains</a> below for where that idea leads. Each browser tab gets its own cryptographic identity, so <code>peerInfo.publicKey</code> is a stable way to recognize a specific peer across reconnects within a session.</p>
|
||||
</section>
|
||||
|
||||
<section id="noise" aria-labelledby="noise-title">
|
||||
<h2 id="noise-title">Noise encryption</h2>
|
||||
<p>Once two peers find each other, the connection they get is already a <strong>Noise protocol</strong> secret stream — encrypted and authenticated before a single application byte crosses the wire. You do not configure TLS certificates, manage a CA, or think about key exchange; it's the default and only mode of a Hyperswarm connection.</p>
|
||||
<p>Each connection the page receives via <code>conn.write(data)</code> / <code>conn.on('data', ...)</code> is one decrypted frame per host-side chunk. If you attach Protomux (see below), <code>wrapRawFrames(conn)</code> preserves that one-chunk-per-frame boundary so message-oriented protocols built on top don't need their own length-prefixing.</p>
|
||||
</section>
|
||||
|
||||
<section id="hyperstack" aria-labelledby="hyperstack-title">
|
||||
<h2 id="hyperstack-title">Hyper* storage</h2>
|
||||
<p>The host also runs Holepunch's storage stack on a single <strong>Corestore</strong>, reachable from the page through <code>BridgeSwarm.request(type, payload)</code>. You can use the default instance of each, or open named/keyed resources and pass a <code>resourceId</code> on subsequent calls.</p>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>Module</th><th>Shape</th><th>Typical use</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><strong>Hypercore</strong></td><td>Append-only log</td><td>Event logs, audit trails, replicated feeds</td></tr>
|
||||
<tr><td><strong>Hyperbee</strong></td><td>Key/value B-tree over a Hypercore</td><td>Structured state, lookups (<code>beeGet</code>/<code>beePut</code>)</td></tr>
|
||||
<tr><td><strong>Hyperdrive</strong></td><td>P2P filesystem</td><td>Serving files, drag-and-drop sync (<code>driveGet</code>/<code>drivePut</code>/<code>driveList</code>)</td></tr>
|
||||
<tr><td><strong>Autobase</strong></td><td>Multi-writer linearized log</td><td>Multiple peers appending to one causal history</td></tr>
|
||||
<tr><td><strong>Hyperdb</strong></td><td>Schema-based P2P database</td><td>Typed collections with query/find (<code>hyperdbInsert</code>/<code>hyperdbFindToArray</code>)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>Two connection-attachment commands turn a live swarm connection into a replication channel instead of a raw data pipe: <code>attachReplication</code> (Hypercore replicates over that socket; the page stops receiving raw <code>data</code> events on it) and <code>swarm.setAutoReplicate(...)</code>, which does the same automatically for every new connection on a swarm — see <a href="/use-cases/#sync">the data-sync use case</a> for a worked example.</p>
|
||||
</section>
|
||||
|
||||
<section id="protomux-hrpc" aria-labelledby="protomux-hrpc-title">
|
||||
<h2 id="protomux-hrpc-title">Protomux & HRPC</h2>
|
||||
<p>Two different problems, two different layers:</p>
|
||||
<ul>
|
||||
<li><strong>Protomux</strong> runs <em>in the page</em>. BridgeSwarm injects a bundle of Protomux, <code>compact-encoding</code>, and <code>b4a</code> so you can multiplex several message-oriented protocols over one connection: <code>swarm.createProtomux(conn)</code> gives you a <code>Protomux</code> instance you open channels on with your own <code>protocol</code> name and message encodings.</li>
|
||||
<li><strong>HRPC</strong> runs <em>on the host</em>. Call <code>BridgeSwarm.request('attachHrpc', { connId })</code> on both ends of a connection, then invoke schema-defined methods with <code>swarm.hrpcCall(connId, method, args)</code> — unary, request-stream, response-stream, and duplex modes are all supported, surfaced to the page as <code>hrpc-chunk</code> / <code>hrpc-end</code> / <code>hrpc-error</code> events.</li>
|
||||
</ul>
|
||||
<pre><code>// Protomux, in the page
|
||||
const mux = swarm.createProtomux(conn);
|
||||
const ch = mux.createChannel({ protocol: 'my-app/v1' });
|
||||
const msg = ch.addMessage({ encoding: c.string, onmessage: console.log });
|
||||
ch.open();
|
||||
msg.send('hello');
|
||||
|
||||
// HRPC, via the host
|
||||
await BridgeSwarm.request('attachHrpc', { connId: conn.connId });
|
||||
const res = await swarm.hrpcCall(conn.connId, 'ping', { value: 'hi' });</code></pre>
|
||||
<p>Use Protomux when you're happy hand-rolling a small message protocol in the page. Reach for HRPC when you want typed methods and streaming without writing your own dispatcher.</p>
|
||||
</section>
|
||||
|
||||
<section id="capabilities" aria-labelledby="capabilities-title">
|
||||
<h2 id="capabilities-title">Capability packs</h2>
|
||||
<p>Not every Bare module the host depends on is exposed to the page — that's intentional. <strong>Capability packs</strong> are the curated, explicit surface: <code>BridgeSwarm.capabilities.list()</code>, <code>.has(name)</code>, and <code>.call(pack, cmd, payload)</code>, plus convenience wrappers like <code>BridgeSwarm.media.*</code>.</p>
|
||||
<p>The default host ships the <strong>media</strong> pack (<code>bare-media</code> + <code>bare-ffmpeg</code>): image/video probing, transforms, batch transcoding, and <strong>live VP9/WebM encode</strong> from a capture source straight through to MSE playback or a peer connection. Streaming results arrive as <code>cap-chunk</code> / <code>cap-end</code> / <code>cap-error</code> events to stay under the native-messaging size limit. Filesystem access for packs is allowlisted under <code>$BRIDGE_SWARM_STORAGE/cap-jobs/</code> — absolute paths outside that tree are rejected by the host.</p>
|
||||
<p>See <a href="/use-cases/#live-media">live media</a> for the full flow from camera capture to encoded output.</p>
|
||||
</section>
|
||||
|
||||
<section id="control-center" aria-labelledby="control-center-title">
|
||||
<h2 id="control-center-title">Control Center</h2>
|
||||
<p>The extension's dashboard is a live view into the background service worker's state over a dedicated port (<code>bridgeswarm-dashboard</code>): <strong>Overview</strong> (host connection health), <strong>Swarms</strong>, <strong>Connections</strong>, <strong>Activity</strong> (a log viewer), and <strong>Settings</strong>. Every setting — default app name, max peers, request/ready timeouts, whether to skip injection on <code>file://</code>, disconnect notifications, the examples-server toggle, debug logging — <strong>autosaves on change</strong>. There is no Save button and no separate config file to hand-edit.</p>
|
||||
</section>
|
||||
|
||||
<section id="mental-model" aria-labelledby="mental-model-title">
|
||||
<h2 id="mental-model-title">Mental model: live domains & self-hosted apps</h2>
|
||||
<p>Two ideas that make more sense once the pieces above click into place:</p>
|
||||
<p><strong>A topic as a live domain.</strong> A DNS name resolves to an IP once, statically, through infrastructure you don't control. A Hyperswarm topic is closer to an address you dial directly: whoever currently has the host running and has joined that topic is reachable, with no registrar, no hosting bill, and no server between you and them. You can treat a topic string as a lightweight, ephemeral "domain" for a specific room, session, or shared document — it exists exactly as long as at least one peer is announcing it.</p>
|
||||
<p><strong>Self-hosted web apps, for free.</strong> The native host's optional <strong>examples server</strong> is a small <code>bare-http1</code> static server bound to <code>127.0.0.1:4173</code>. It's a working demonstration of a broader pattern: once BridgeSwarm is installed, the host can serve real HTML/CSS/JS on localhost, and the extension's content script still injects <code>window.BridgeSwarm</code> into pages loaded from it (deliberately <em>not</em> into <code>file://</code> pages, which the browser treats as opaque, unrelated origins). That means a fully self-hosted, offline-capable app — with P2P networking built in — can live entirely on a user's machine with no cloud hosting step at all. See <a href="/use-cases/#self-hosted">self-hosted web apps</a>.</p>
|
||||
</section>
|
||||
|
||||
<section id="flows" aria-labelledby="flows-title">
|
||||
<h2 id="flows-title">Message flows</h2>
|
||||
<p>A request from the page to the host and back:</p>
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant Page
|
||||
participant ContentScript
|
||||
participant Background
|
||||
participant NativeHost
|
||||
Page->>ContentScript: postMessage (bridge-swarm-bridge)
|
||||
ContentScript->>Background: runtime.sendMessage (action: send)
|
||||
Background->>NativeHost: port.postMessage {id, type, payload}
|
||||
NativeHost->>NativeHost: handleMessage -> reply(result)
|
||||
NativeHost->>Background: messenger.send {id, type: response}
|
||||
Background->>ContentScript: sendResponse(payload)
|
||||
ContentScript->>Page: dispatchEvent (bridge-swarm-bridge-response)
|
||||
</pre>
|
||||
<p>An unsolicited event from the host (a new connection, a capability chunk) reaching the page:</p>
|
||||
<pre class="mermaid">
|
||||
sequenceDiagram
|
||||
participant NativeHost
|
||||
participant Background
|
||||
participant ContentScript
|
||||
participant Page
|
||||
NativeHost->>NativeHost: emit(event, payload)
|
||||
NativeHost->>Background: messenger.send {type: event}
|
||||
alt swarm-scoped event
|
||||
Background->>ContentScript: tabs.sendMessage (only tabs owning swarmId)
|
||||
else capability / global event
|
||||
Background->>ContentScript: tabs.sendMessage (all subscribed tabs)
|
||||
end
|
||||
ContentScript->>Page: dispatchEvent (bridge-swarm-event)
|
||||
Page->>Page: api.js _onEvent (connection / data / end / error / cap-*)
|
||||
</pre>
|
||||
<p>And the connection lifecycle underneath every swarm:</p>
|
||||
<pre class="mermaid">
|
||||
stateDiagram-v2
|
||||
[*] --> Init: new BridgeSwarm + join(topic)
|
||||
Init --> Discovering: host Hyperswarm.join
|
||||
Discovering --> Connected: peer Noise handshake
|
||||
Connected --> DataForward: page conn.write / data events
|
||||
Connected --> Attached: attachReplication or attachHrpc
|
||||
DataForward --> Closed: end / error / destroy
|
||||
Attached --> Closed: end / destroy
|
||||
Closed --> [*]
|
||||
</pre>
|
||||
</section>
|
||||
|
||||
<section id="glossary" aria-labelledby="glossary-title">
|
||||
<h2 id="glossary-title">Glossary</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td style="white-space:nowrap;"><strong>Bare</strong></td><td>A small JavaScript runtime for native modules, built by Holepunch to run Pear, Keet, and BridgeSwarm's native host outside the browser sandbox.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Hyperswarm</strong></td><td>Peer discovery and connection library built on a DHT; peers announce/lookup a topic and connect directly, with NAT traversal handled automatically.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Topic</strong></td><td>A 32-byte value (often a hash of a human-readable string) that peers join to discover each other. No central registration required.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Noise protocol</strong></td><td>The handshake and encryption framework used to secure every Hyperswarm connection by default.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Corestore</strong></td><td>A factory/manager for multiple named Hypercores backed by one storage directory.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Hypercore</strong></td><td>An append-only, cryptographically verifiable log — the base primitive under Hyperbee, Hyperdrive, and Autobase.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Hyperbee</strong></td><td>A key/value B-tree store built on a Hypercore.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Hyperdrive</strong></td><td>A P2P filesystem built on Hypercore, with paths, directory listings, and file content.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Autobase</strong></td><td>A multi-writer linearized log that merges several Hypercores from different peers into one causal history.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Hyperdb</strong></td><td>A schema-based (Hyperschema-generated) P2P database with typed collections and queries.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Protomux</strong></td><td>A library for multiplexing multiple named protocols/channels over one connection, used in-page by BridgeSwarm.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>HRPC</strong></td><td>Schema-defined RPC (unary and streaming) that BridgeSwarm runs on the host side of an attached connection.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Native messaging</strong></td><td>The browser API that lets an extension exchange length-prefixed JSON with one specific, registered local executable.</td></tr>
|
||||
<tr><td style="white-space:nowrap;"><strong>Capability pack</strong></td><td>A curated set of host-side commands (e.g. <code>media</code>) exposed to the page through <code>BridgeSwarm.capabilities</code>.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="docs-pager">
|
||||
<span></span>
|
||||
<a class="next" href="/use-cases/"><span>Keep going</span><strong>Use cases →</strong></a>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<section class="cta-band reveal">
|
||||
<div class="container">
|
||||
<div class="cta-card">
|
||||
<h2>See it running</h2>
|
||||
<p class="lead">Every concept above has a runnable demo on the examples server once BridgeSwarm is installed.</p>
|
||||
<div class="cta-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/download">Install BridgeSwarm</a>
|
||||
<a class="btn btn-ghost btn-lg" href="/use-cases/">Browse use cases</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,185 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Acceptable Use Policy · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="Acceptable Use Policy for BridgeSwarm and HoneyPeer, LLC services, including prohibited misuse of peer-to-peer networking." />
|
||||
<meta name="keywords" content="BridgeSwarm Acceptable Use Policy" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/aup" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/aup" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/aup" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/aup" />
|
||||
<meta property="og:title" content="Acceptable Use Policy · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="Acceptable Use Policy for BridgeSwarm and HoneyPeer, LLC services, including prohibited misuse of peer-to-peer networking." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Acceptable Use Policy · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="Acceptable Use Policy for BridgeSwarm and HoneyPeer, LLC services, including prohibited misuse of peer-to-peer networking." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<!-- Article -->
|
||||
<meta property="article:section" content="Legal" />
|
||||
<meta property="article:author" content="HoneyPeer, LLC" />
|
||||
<meta property="article:publisher" content="HoneyPeer, LLC" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Acceptable Use Policy \u00b7 BridgeSwarm Legal",
|
||||
"description": "Acceptable Use Policy for BridgeSwarm and HoneyPeer, LLC services, including prohibited misuse of peer-to-peer networking.",
|
||||
"url": "https://bridgeswarm.dev/legal/aup",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">Legal</p>
|
||||
<h1>Acceptable Use Policy</h1>
|
||||
<p class="docs-lead">
|
||||
This Acceptable Use Policy (“<strong>AUP</strong>”) applies to use of HoneyPeer Sites, installers, and
|
||||
the BridgeSwarm extension and native messaging host in connection with HoneyPeer-operated
|
||||
infrastructure, distribution channels, and the public Hyperswarm network you access through them.
|
||||
</p>
|
||||
<p class="legal-updated">Last updated: <strong>July 27, 2026</strong></p>
|
||||
|
||||
<h2 id="purpose">1. Purpose</h2>
|
||||
<p>
|
||||
BridgeSwarm gives web pages direct access to peer-to-peer networking and local data storage.
|
||||
With that power comes responsibility. This AUP describes prohibited uses so that other peers,
|
||||
the shared DHT infrastructure, and the open-source community remain safe.
|
||||
</p>
|
||||
|
||||
<h2 id="prohibited">2. Prohibited activities</h2>
|
||||
<p>You may not use the Sites, installers, or Software to:</p>
|
||||
<ul>
|
||||
<li><strong>Violate law</strong>, including computer crime, fraud, sanctions evasion, or unlawful surveillance;</li>
|
||||
<li><strong>Attack systems or peers</strong> by scanning, exploiting, flooding, or accessing systems, networks, or peer connections without authorization;</li>
|
||||
<li><strong>Distribute malware</strong> such as ransomware, trojans, botnet command-and-control, or other malicious code over BridgeSwarm connections or Hyper* data stores;</li>
|
||||
<li><strong>Traffic in illegal content</strong>, including child sexual abuse material, or use the P2P transport to store or distribute content that is illegal to possess or share in your jurisdiction;</li>
|
||||
<li><strong>Abuse the DHT and swarm</strong> by flooding topics, spamming peers, sybil-attacking discovery, or otherwise degrading the shared public Hyperswarm network for other users;</li>
|
||||
<li><strong>Interfere with HoneyPeer infrastructure</strong> through DDoS, credential stuffing, scraping that degrades service, or bypassing rate limits on our Sites;</li>
|
||||
<li><strong>Misrepresent identity</strong> by impersonating HoneyPeer, BridgeSwarm, or another person, peer, or entity;</li>
|
||||
<li><strong>Infringe IP</strong> by hosting or distributing content over BridgeSwarm connections that you do not have rights to, in a way that unlawfully uses our distribution channels or brand;</li>
|
||||
<li><strong>Harass or harm</strong> other peers or users by threatening, stalking, doxxing, or encouraging violence.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="operator">3. Peer & host responsibilities</h2>
|
||||
<p>
|
||||
Every BridgeSwarm user runs their own native messaging host and is responsible for their own topics,
|
||||
peer allowlists/denylists, firewall rules, and data. HoneyPeer is not responsible for how you
|
||||
configure discovery, connection acceptance, or exposure of your local storage directory.
|
||||
</p>
|
||||
|
||||
<h2 id="enforcement">4. Enforcement</h2>
|
||||
<p>
|
||||
HoneyPeer may investigate suspected violations involving our Sites or distribution systems and may suspend access,
|
||||
block IPs, remove materials, or report to law enforcement.
|
||||
Because BridgeSwarm connections are direct peer-to-peer, HoneyPeer generally has no visibility into and
|
||||
cannot unilaterally terminate individual peer sessions; enforcement is typically limited to denying
|
||||
access to HoneyPeer-operated download, documentation, or extension-store listings.
|
||||
</p>
|
||||
|
||||
<h2 id="reporting">5. Reporting abuse</h2>
|
||||
<p>
|
||||
Report abuse of HoneyPeer Sites or brand misuse to
|
||||
<a href="mailto:[email protected]">[email protected]</a>.
|
||||
Copyright notices: see <a href="/legal/copyright">Copyright & DMCA</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="changes">6. Changes</h2>
|
||||
<p>We may update this AUP by posting a revised version with a new “Last updated” date.</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<a href="/legal/eula"><span>Previous</span><strong>← EULA</strong></a>
|
||||
<a class="next" href="/legal/privacy"><span>Next</span><strong>Privacy Policy →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,106 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Cookie Policy → Privacy Policy · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="Cookie information is part of the BridgeSwarm Privacy Policy." />
|
||||
<meta name="keywords" content="BridgeSwarm cookies, privacy" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="noindex, follow" />
|
||||
<meta name="googlebot" content="noindex, follow" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/privacy#cookies" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/privacy#cookies" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/privacy#cookies" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/privacy" />
|
||||
<meta property="og:title" content="Cookie Policy → Privacy Policy · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="Cookie information is part of the BridgeSwarm Privacy Policy." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Cookie Policy → Privacy Policy · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="Cookie information is part of the BridgeSwarm Privacy Policy." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Cookie Policy \u2192 Privacy Policy \u00b7 BridgeSwarm Legal",
|
||||
"description": "Cookie information is part of the BridgeSwarm Privacy Policy.",
|
||||
"url": "https://bridgeswarm.dev/legal/privacy",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<meta http-equiv="refresh" content="0;url=/legal/privacy#cookies" />
|
||||
<script>location.replace('/legal/privacy#cookies')</script>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Cookie information is included in the
|
||||
<a href="/legal/privacy#cookies">Privacy Policy</a>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,187 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Copyright & DMCA · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="Copyright ownership and DMCA notice procedure for BridgeSwarm / HoneyPeer, LLC." />
|
||||
<meta name="keywords" content="BridgeSwarm copyright, DMCA, HoneyPeer" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/copyright" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/copyright" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/copyright" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/copyright" />
|
||||
<meta property="og:title" content="Copyright & DMCA · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="Copyright ownership and DMCA notice procedure for BridgeSwarm / HoneyPeer, LLC." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Copyright & DMCA · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="Copyright ownership and DMCA notice procedure for BridgeSwarm / HoneyPeer, LLC." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<!-- Article -->
|
||||
<meta property="article:section" content="Legal" />
|
||||
<meta property="article:author" content="HoneyPeer, LLC" />
|
||||
<meta property="article:publisher" content="HoneyPeer, LLC" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Copyright & DMCA \u00b7 BridgeSwarm Legal",
|
||||
"description": "Copyright ownership and DMCA notice procedure for BridgeSwarm / HoneyPeer, LLC.",
|
||||
"url": "https://bridgeswarm.dev/legal/copyright",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">Legal</p>
|
||||
<h1>Copyright & DMCA</h1>
|
||||
<p class="docs-lead">
|
||||
Copyright in BridgeSwarm product materials and HoneyPeer-operated Sites is held by
|
||||
<strong>HoneyPeer, LLC</strong>, except open-source code licensed under AGPL-3.0 and third-party works.
|
||||
</p>
|
||||
<p class="legal-updated">Last updated: <strong>July 27, 2026</strong></p>
|
||||
|
||||
<h2 id="ownership">1. Copyright ownership</h2>
|
||||
<p>
|
||||
© 2025-<span data-year></span> HoneyPeer, LLC and contributors.
|
||||
Website content, documentation layout, original graphics, and brand materials are protected by copyright.
|
||||
Software source is additionally licensed under AGPL-3.0 as described in
|
||||
<a href="/legal/license">Open Source Notices</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="permission">2. Permission</h2>
|
||||
<p>
|
||||
You may quote short excerpts of documentation with attribution for non-misleading technical purposes.
|
||||
For republication of substantial documentation or brand assets, contact
|
||||
<a href="mailto:[email protected]">[email protected]</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="dmca">3. DMCA / copyright complaints</h2>
|
||||
<p>
|
||||
If you believe content on a HoneyPeer-operated Site infringes your copyright, send a notice that includes:
|
||||
</p>
|
||||
<ol>
|
||||
<li>Your physical or electronic signature;</li>
|
||||
<li>Identification of the copyrighted work claimed to be infringed;</li>
|
||||
<li>Identification of the material that is claimed to be infringing and information reasonably sufficient to locate it (URL);</li>
|
||||
<li>Your contact information (address, telephone, email);</li>
|
||||
<li>A statement that you have a good-faith belief that use of the material is not authorized by the copyright owner, its agent, or the law;</li>
|
||||
<li>A statement that the information in the notification is accurate, and under penalty of perjury, that you are authorized to act on behalf of the owner.</li>
|
||||
</ol>
|
||||
<p>
|
||||
<strong>Designated agent (email):</strong>
|
||||
<a href="mailto:[email protected]">[email protected]</a><br />
|
||||
<strong>Entity:</strong> HoneyPeer, LLC, DeKalb County, Georgia, USA
|
||||
</p>
|
||||
<p>
|
||||
Upon valid notice, HoneyPeer may remove or disable access to the material and, where applicable, notify the poster.
|
||||
Counter-notification procedures under the DMCA may apply.
|
||||
</p>
|
||||
|
||||
<h2 id="repeat">4. Repeat infringers</h2>
|
||||
<p>
|
||||
HoneyPeer may terminate access to Sites or distribution channels for users who are repeat infringers, where accounts or access controls exist.
|
||||
</p>
|
||||
|
||||
<h2 id="peertopeer">5. Peer-to-peer content</h2>
|
||||
<p>
|
||||
Content exchanged directly between peers over the BridgeSwarm network is not hosted by HoneyPeer and
|
||||
is generally outside our control. HoneyPeer cannot remove content from another user’s device or
|
||||
application data store. Send DMCA notices about HoneyPeer-operated Sites only to the address above;
|
||||
for infringement occurring solely between third-party peers, pursue remedies against the responsible party directly.
|
||||
</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<a href="/legal/license"><span>Previous</span><strong>← Open Source</strong></a>
|
||||
<a class="next" href="/legal/disclaimer"><span>Next</span><strong>Disclaimer →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,214 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Disclaimer & Liability · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="Warranty disclaimer and limitation of liability for BridgeSwarm by HoneyPeer, LLC." />
|
||||
<meta name="keywords" content="BridgeSwarm disclaimer, liability" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/disclaimer" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/disclaimer" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/disclaimer" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/disclaimer" />
|
||||
<meta property="og:title" content="Disclaimer & Liability · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="Warranty disclaimer and limitation of liability for BridgeSwarm by HoneyPeer, LLC." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Disclaimer & Liability · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="Warranty disclaimer and limitation of liability for BridgeSwarm by HoneyPeer, LLC." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<!-- Article -->
|
||||
<meta property="article:section" content="Legal" />
|
||||
<meta property="article:author" content="HoneyPeer, LLC" />
|
||||
<meta property="article:publisher" content="HoneyPeer, LLC" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Disclaimer & Liability \u00b7 BridgeSwarm Legal",
|
||||
"description": "Warranty disclaimer and limitation of liability for BridgeSwarm by HoneyPeer, LLC.",
|
||||
"url": "https://bridgeswarm.dev/legal/disclaimer",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">Legal</p>
|
||||
<h1>Disclaimer & Limitation of Liability</h1>
|
||||
<p class="docs-lead">
|
||||
Important risk disclosures for BridgeSwarm software and documentation published by HoneyPeer, LLC.
|
||||
</p>
|
||||
<p class="legal-updated">Last updated: <strong>July 27, 2026</strong></p>
|
||||
|
||||
<div class="callout warn">
|
||||
<div class="callout-icon">!</div>
|
||||
<div class="callout-body">
|
||||
<strong>Native code + open networking.</strong>
|
||||
The native messaging host runs with your user account’s privileges and can make network
|
||||
connections, read and write files, and open direct peer-to-peer connections to the public
|
||||
Hyperswarm DHT. Only install the host and extension from sources you trust. Misconfiguration or a
|
||||
malicious build can expose local data or resources.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="as-is">1. “AS IS” software and documentation</h2>
|
||||
<p>
|
||||
BRIDGESWARM SOFTWARE, DOCUMENTATION, INSTALLERS, WEBSITES, AND RELATED MATERIALS ARE PROVIDED BY HONEYPEER, LLC
|
||||
AND CONTRIBUTORS “AS IS” AND “AS AVAILABLE,” WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY,
|
||||
INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, QUIET ENJOYMENT,
|
||||
ACCURACY, AND NON-INFRINGEMENT.
|
||||
</p>
|
||||
<p>
|
||||
This is consistent with the AGPL-3.0 disclaimer for open-source distributions and applies to the
|
||||
fullest extent permitted by law for HoneyPeer’s Sites and binary distributions.
|
||||
</p>
|
||||
|
||||
<h2 id="no-guarantee">2. No operational guarantees</h2>
|
||||
<p>Without limiting the foregoing, HoneyPeer does not warrant that:</p>
|
||||
<ul>
|
||||
<li>BridgeSwarm will meet your requirements or be compatible with every browser, OS, or Node/Bare runtime version;</li>
|
||||
<li>peer discovery, NAT traversal, or connections over the public Hyperswarm DHT will be available, confidential, or uninterrupted;</li>
|
||||
<li>peers you connect to are trustworthy, non-malicious, or who they claim to be;</li>
|
||||
<li>defects will be corrected within any timeframe;</li>
|
||||
<li>documentation is complete or error-free.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="your-risk">3. Your risk allocation</h2>
|
||||
<p>You are solely responsible for:</p>
|
||||
<ul>
|
||||
<li>testing in non-production environments before relying on BridgeSwarm for critical use cases;</li>
|
||||
<li>reviewing which peers you accept connections from, and what data you expose to them;</li>
|
||||
<li>backups and integrity of any Hyper* data structures you create locally;</li>
|
||||
<li>compliance with your organization’s security policies and applicable law;</li>
|
||||
<li>consequences of running the native messaging host, which has the same filesystem and network access as your user account.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="liability">4. Limitation of liability</h2>
|
||||
<p>
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL HONEYPEER, LLC, ITS MEMBERS, OFFICERS, EMPLOYEES, AGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE DAMAGES; OR ANY LOSS OF PROFITS, REVENUE, DATA, GOODWILL, OR BUSINESS INTERRUPTION;
|
||||
OR COST OF SUBSTITUTE GOODS OR SERVICES; ARISING OUT OF OR RELATED TO BRIDGESWARM OR HONEYPEER SITES, WHETHER BASED IN CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY, OR OTHERWISE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
</p>
|
||||
<p>
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY LAW, HONEYPEER’S TOTAL AGGREGATE LIABILITY FOR ALL CLAIMS RELATING TO BRIDGESWARM OR THE SITES SHALL NOT EXCEED THE GREATER OF
|
||||
(A) THE AMOUNTS YOU PAID TO HONEYPEER FOR THE SPECIFIC PRODUCT OR SERVICE GIVING RISE TO THE CLAIM DURING THE TWELVE (12) MONTHS PRIOR TO THE CLAIM, OR
|
||||
(B) ONE HUNDRED U.S. DOLLARS (US $100).
|
||||
</p>
|
||||
<p>
|
||||
Because some jurisdictions do not allow certain exclusions, some of the above may not apply to you; in that case, liability is limited to the minimum extent required by law.
|
||||
</p>
|
||||
|
||||
<h2 id="high-risk">5. High-risk activities</h2>
|
||||
<p>
|
||||
The Software is not designed for use in hazardous environments requiring fail-safe performance (for example nuclear facilities, air traffic control, or life-support systems)
|
||||
where failure could lead to death, personal injury, or severe environmental damage. You assume all risk of such use.
|
||||
</p>
|
||||
|
||||
<h2 id="related">6. Related documents</h2>
|
||||
<ul>
|
||||
<li><a href="/legal/eula">End User License Agreement</a></li>
|
||||
<li><a href="/legal/terms">Terms of Service</a></li>
|
||||
<li><a href="/legal/license">Open Source Notices (AGPL-3.0)</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="contact">7. Contact</h2>
|
||||
<p>
|
||||
HoneyPeer, LLC · DeKalb County, Georgia, USA<br />
|
||||
<a href="mailto:[email protected]">[email protected]</a>
|
||||
</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<a href="/legal/copyright"><span>Previous</span><strong>← Copyright</strong></a>
|
||||
<a class="next" href="/legal/security"><span>Next</span><strong>Security Policy →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,281 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>End User License Agreement · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="End User License Agreement for the BridgeSwarm browser extension and native messaging host, distributed by HoneyPeer, LLC." />
|
||||
<meta name="keywords" content="BridgeSwarm EULA, End User License Agreement" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/eula" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/eula" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/eula" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/eula" />
|
||||
<meta property="og:title" content="End User License Agreement · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="End User License Agreement for the BridgeSwarm browser extension and native messaging host, distributed by HoneyPeer, LLC." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="End User License Agreement · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="End User License Agreement for the BridgeSwarm browser extension and native messaging host, distributed by HoneyPeer, LLC." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<!-- Article -->
|
||||
<meta property="article:section" content="Legal" />
|
||||
<meta property="article:author" content="HoneyPeer, LLC" />
|
||||
<meta property="article:publisher" content="HoneyPeer, LLC" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "End User License Agreement \u00b7 BridgeSwarm Legal",
|
||||
"description": "End User License Agreement for the BridgeSwarm browser extension and native messaging host, distributed by HoneyPeer, LLC.",
|
||||
"url": "https://bridgeswarm.dev/legal/eula",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">Legal</p>
|
||||
<h1>End User License Agreement</h1>
|
||||
<p class="docs-lead">
|
||||
This End User License Agreement (“<strong>EULA</strong>”) is a legal agreement between you and
|
||||
<strong>HoneyPeer, LLC</strong> (“HoneyPeer”) for BridgeSwarm software products distributed by HoneyPeer,
|
||||
including the browser extension package, the native messaging host binaries, installers, and related
|
||||
documentation (the “<strong>Software</strong>”).
|
||||
</p>
|
||||
<p class="legal-updated">Last updated: <strong>July 27, 2026</strong></p>
|
||||
|
||||
<nav class="toc">
|
||||
<strong>On this page</strong>
|
||||
<ol>
|
||||
<li><a href="#acceptance">Acceptance</a></li>
|
||||
<li><a href="#license">License grant</a></li>
|
||||
<li><a href="#oss">Open-source components</a></li>
|
||||
<li><a href="#restrictions">Restrictions</a></li>
|
||||
<li><a href="#ownership">Ownership</a></li>
|
||||
<li><a href="#updates">Updates</a></li>
|
||||
<li><a href="#data">Your data & network activity</a></li>
|
||||
<li><a href="#third">Third-party software</a></li>
|
||||
<li><a href="#support">Support</a></li>
|
||||
<li><a href="#term">Term & termination</a></li>
|
||||
<li><a href="#export">Export</a></li>
|
||||
<li><a href="#warranty">Warranty disclaimer</a></li>
|
||||
<li><a href="#liability">Limitation of liability</a></li>
|
||||
<li><a href="#law">Governing law</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="acceptance">1. Acceptance</h2>
|
||||
<p>
|
||||
By downloading, installing, copying, or using the Software, you agree to this EULA.
|
||||
If you do not agree, do not install or use the Software.
|
||||
If you accept on behalf of an entity, you represent that you are authorized to bind that entity.
|
||||
</p>
|
||||
|
||||
<h2 id="license">2. License grant</h2>
|
||||
<p>
|
||||
Subject to this EULA, HoneyPeer grants you a limited, non-exclusive, non-transferable (except as permitted below),
|
||||
revocable license to install and use the Software on systems you own or control, for lawful purposes,
|
||||
including establishing peer-to-peer connections and running local Hyperswarm-based applications as documented.
|
||||
</p>
|
||||
<p>
|
||||
Where the Software (or portions of it) is also provided under AGPL-3.0 in source form,
|
||||
your rights under AGPL-3.0 for that source remain available and are not narrowed by this EULA.
|
||||
This EULA primarily governs HoneyPeer’s distribution of packaged extension builds, native-host binaries, installers, and trademarks.
|
||||
</p>
|
||||
|
||||
<h2 id="oss">3. Open-source components</h2>
|
||||
<p>
|
||||
BridgeSwarm is engineered as open-source software under the
|
||||
<strong>GNU Affero General Public License, Version 3 (AGPL-3.0)</strong>.
|
||||
The Software may include third-party open-source components under their own licenses
|
||||
(see <a href="/legal/license">Open Source Notices</a>). Those licenses govern those components,
|
||||
including the underlying Hyperswarm/Holepunch stack (Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb,
|
||||
Protomux, HRPC) and the Bare JavaScript runtime used by the native messaging host.
|
||||
</p>
|
||||
|
||||
<h2 id="restrictions">4. Restrictions</h2>
|
||||
<p>Except as allowed by applicable open-source licenses or mandatory law, you may not:</p>
|
||||
<ul>
|
||||
<li>rent, lease, sell, sublicense, or redistribute the Software in a way that conceals HoneyPeer’s trademarks in a misleading way;</li>
|
||||
<li>remove or alter proprietary notices, copyright legends, or attribution required by licenses;</li>
|
||||
<li>use the Software to violate law, third-party rights, or the <a href="/legal/aup">Acceptable Use Policy</a>;</li>
|
||||
<li>attempt to bypass security, authentication, or access controls of systems or peers you do not own or administer;</li>
|
||||
<li>misrepresent the Software as officially endorsed by another party, or misuse HoneyPeer/BridgeSwarm marks in a misleading way.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="ownership">5. Ownership</h2>
|
||||
<p>
|
||||
HoneyPeer and its licensors retain all right, title, and interest in and to the Software,
|
||||
including intellectual property rights, subject to open-source licenses applicable to specific components.
|
||||
This EULA does not transfer ownership of the Software to you.
|
||||
</p>
|
||||
|
||||
<h2 id="updates">6. Updates and versions</h2>
|
||||
<p>
|
||||
HoneyPeer may provide updates, rolling releases, or patches via the extension store listings or the
|
||||
project’s Gitea releases. Updates may be required for continued compatibility or for the extension and
|
||||
native messaging host to remain paired (they are versioned together).
|
||||
HoneyPeer is not obligated to provide any particular update schedule.
|
||||
Pre-release, experimental, or “rolling” builds may be unstable.
|
||||
</p>
|
||||
|
||||
<h2 id="data">7. Your data and network activity</h2>
|
||||
<p>
|
||||
The Software runs locally on your machine and connects to peers you choose over the public Hyperswarm
|
||||
network. You are solely responsible for the topics you join, the peers you accept, any application data
|
||||
stored locally by Hyper* data structures under your configured storage directory, and any content you
|
||||
exchange with peers. HoneyPeer does not operate a central server that receives your BridgeSwarm application data.
|
||||
</p>
|
||||
<p>
|
||||
Unless you separately enable a HoneyPeer online service that collects data (described in the
|
||||
<a href="/legal/privacy">Privacy Policy</a>), local use of the Software does not require sending operational data to HoneyPeer.
|
||||
</p>
|
||||
|
||||
<h2 id="third">8. Third-party software and services</h2>
|
||||
<p>
|
||||
The Software may interact with your operating system, browser, and the public Hyperswarm DHT and its
|
||||
participants. Those systems are governed by their own terms. HoneyPeer is not responsible for third-party
|
||||
software behavior, peer conduct, or availability of the public DHT.
|
||||
</p>
|
||||
|
||||
<h2 id="support">9. Support</h2>
|
||||
<p>
|
||||
Unless you have a separate written support agreement with HoneyPeer, the Software is provided without guaranteed support, SLA, or uptime commitment.
|
||||
Community documentation may be available on the Sites.
|
||||
</p>
|
||||
|
||||
<h2 id="term">10. Term and termination</h2>
|
||||
<p>
|
||||
This EULA remains in effect until terminated. Your rights terminate automatically if you materially breach this EULA and fail to cure where cure is reasonably possible.
|
||||
Upon termination, you must stop using HoneyPeer-distributed proprietary packaging that is not independently licensed to you under open source, and destroy copies as required.
|
||||
Open-source licenses that have already been granted for source code survive according to their terms.
|
||||
</p>
|
||||
|
||||
<h2 id="export">11. Export and sanctions</h2>
|
||||
<p>
|
||||
You must comply with U.S. and other applicable export control and sanctions laws, including those
|
||||
applicable to encryption software. You may not use or export the Software in violation of those laws.
|
||||
</p>
|
||||
|
||||
<h2 id="warranty">12. Warranty disclaimer</h2>
|
||||
<p>
|
||||
THE SOFTWARE IS PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND.
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY LAW, HONEYPEER DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
|
||||
INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
|
||||
YOU ASSUME ALL RISK FOR USE OF THE SOFTWARE, INCLUDING PEER-TO-PEER CONNECTIVITY, IN PRODUCTION OR CRITICAL ENVIRONMENTS.
|
||||
</p>
|
||||
|
||||
<h2 id="liability">13. Limitation of liability</h2>
|
||||
<p>
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY LAW, HONEYPEER WILL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES,
|
||||
OR LOSS OF PROFITS, DATA, OR BUSINESS, ARISING FROM THE SOFTWARE OR THIS EULA.
|
||||
HONEYPEER’S TOTAL LIABILITY WILL NOT EXCEED THE GREATER OF FEES YOU PAID TO HONEYPEER FOR THE SOFTWARE IN THE TWELVE (12) MONTHS BEFORE THE CLAIM OR US $100.
|
||||
</p>
|
||||
<p>See also the <a href="/legal/disclaimer">Disclaimer & Liability</a> statement.</p>
|
||||
|
||||
<h2 id="law">14. Governing law</h2>
|
||||
<p>
|
||||
This EULA is governed by the laws of the State of Georgia, USA.
|
||||
Venue lies in Georgia courts as described in the <a href="/legal/terms">Terms of Service</a>, except where prohibited.
|
||||
</p>
|
||||
|
||||
<h2 id="contact">15. Contact</h2>
|
||||
<p>
|
||||
HoneyPeer, LLC · DeKalb County, Georgia, USA<br />
|
||||
<a href="mailto:[email protected]">[email protected]</a>
|
||||
</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<a href="/legal/terms"><span>Previous</span><strong>← Terms of Service</strong></a>
|
||||
<a class="next" href="/legal/aup"><span>Next</span><strong>Acceptable Use →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,205 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Legal · BridgeSwarm</title>
|
||||
<meta name="description" content="Legal documents for BridgeSwarm by HoneyPeer, LLC: Terms, EULA, Privacy, AGPL-3.0 license notices, and more." />
|
||||
<meta name="keywords" content="BridgeSwarm legal, HoneyPeer, Terms, Privacy, EULA, AGPL" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/" />
|
||||
<meta property="og:title" content="Legal · BridgeSwarm" />
|
||||
<meta property="og:description" content="Legal documents for BridgeSwarm by HoneyPeer, LLC: Terms, EULA, Privacy, AGPL-3.0 license notices, and more." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Legal · BridgeSwarm" />
|
||||
<meta name="twitter:description" content="Legal documents for BridgeSwarm by HoneyPeer, LLC: Terms, EULA, Privacy, AGPL-3.0 license notices, and more." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Legal \u00b7 BridgeSwarm",
|
||||
"description": "Legal documents for BridgeSwarm by HoneyPeer, LLC: Terms, EULA, Privacy, AGPL-3.0 license notices, and more.",
|
||||
"url": "https://bridgeswarm.dev/legal/",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">HoneyPeer, LLC</p>
|
||||
<h1>Legal</h1>
|
||||
<p class="docs-lead">
|
||||
BridgeSwarm is owned, operated, and engineered by <strong>HoneyPeer, LLC</strong>,
|
||||
a limited liability company organized under the laws of the State of Georgia
|
||||
(DeKalb County), United States. The BridgeSwarm software — the browser extension,
|
||||
the native messaging host, and supporting build tooling — is made available as
|
||||
open source under the <strong>GNU Affero General Public License v3.0 (AGPL-3.0)</strong>.
|
||||
</p>
|
||||
|
||||
<div class="legal-notice callout info">
|
||||
<div class="callout-icon">i</div>
|
||||
<div class="callout-body">
|
||||
<strong>Two layers of rights.</strong>
|
||||
The <em>source code</em> is licensed under AGPL-3.0 (see
|
||||
<a href="/legal/license">Open Source Notices</a>).
|
||||
Use of the <em>website, hosted materials, trademarks, and binary distributions we publish</em>
|
||||
is also governed by the Terms, EULA, and policies linked below.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="docs-cards legal-cards">
|
||||
<a class="docs-card" href="/legal/terms">
|
||||
<span class="card-tag">Website & services</span>
|
||||
<h3>Terms of Service</h3>
|
||||
<p>Rules for using bridgeswarm.dev and related HoneyPeer online properties.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/legal/eula">
|
||||
<span class="card-tag">Software</span>
|
||||
<h3>End User License Agreement</h3>
|
||||
<p>License terms for the BridgeSwarm browser extension and native messaging host binaries.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/legal/aup">
|
||||
<span class="card-tag">Conduct</span>
|
||||
<h3>Acceptable Use Policy</h3>
|
||||
<p>Prohibited misuse of BridgeSwarm's peer-to-peer networking and HoneyPeer infrastructure.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/legal/privacy">
|
||||
<span class="card-tag">Data</span>
|
||||
<h3>Privacy Policy</h3>
|
||||
<p>How HoneyPeer handles information on our sites, and how the local-first extension stores your data.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/legal/license">
|
||||
<span class="card-tag">Open source</span>
|
||||
<h3>Open Source & Notices</h3>
|
||||
<p>AGPL-3.0 license summary, network-use obligations, and third-party components.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/legal/copyright">
|
||||
<span class="card-tag">IP</span>
|
||||
<h3>Copyright & DMCA</h3>
|
||||
<p>Copyright ownership, notice-and-takedown, and reporting infringement.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/legal/disclaimer">
|
||||
<span class="card-tag">Risk</span>
|
||||
<h3>Disclaimer & Liability</h3>
|
||||
<p>Warranty disclaimers and limitation of liability for peer-to-peer infrastructure software.</p>
|
||||
</a>
|
||||
<a class="docs-card" href="/legal/security">
|
||||
<span class="card-tag">Safety</span>
|
||||
<h3>Security Policy</h3>
|
||||
<p>Responsible vulnerability disclosure and security contact for BridgeSwarm.</p>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<h2>Entity</h2>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th scope="row">Product</th><td>BridgeSwarm</td></tr>
|
||||
<tr><th scope="row">Owner / operator / engineer</th><td>HoneyPeer, LLC</td></tr>
|
||||
<tr><th scope="row">Jurisdiction</th><td>State of Georgia, United States (DeKalb County)</td></tr>
|
||||
<tr><th scope="row">Software license</th><td>GNU Affero General Public License, Version 3 (AGPL-3.0)</td></tr>
|
||||
<tr><th scope="row">Primary site</th><td>bridgeswarm.dev</td></tr>
|
||||
<tr><th scope="row">Source repository</th><td><a href="https://git.ssh.surf/snxraven/BridgeSwarm" target="_blank" rel="noopener">git.ssh.surf/snxraven/BridgeSwarm</a></td></tr>
|
||||
<tr><th scope="row">Contact</th><td><a href="mailto:[email protected]">[email protected]</a> (legal, privacy, security, brand, DMCA)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p class="legal-updated">Documents effective as of <strong>July 27, 2026</strong>, unless a page states otherwise. HoneyPeer may update these documents; the “Last updated” line on each page controls.</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<span></span>
|
||||
<a class="next" href="/legal/terms"><span>Start with</span><strong>Terms of Service →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,224 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Open Source Notices · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="AGPL-3.0 license and third-party open source notices for BridgeSwarm by HoneyPeer, LLC." />
|
||||
<meta name="keywords" content="BridgeSwarm AGPL-3.0, open source license, Hyperswarm" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/license" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/license" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/license" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/license" />
|
||||
<meta property="og:title" content="Open Source Notices · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="AGPL-3.0 license and third-party open source notices for BridgeSwarm by HoneyPeer, LLC." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Open Source Notices · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="AGPL-3.0 license and third-party open source notices for BridgeSwarm by HoneyPeer, LLC." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<!-- Article -->
|
||||
<meta property="article:section" content="Legal" />
|
||||
<meta property="article:author" content="HoneyPeer, LLC" />
|
||||
<meta property="article:publisher" content="HoneyPeer, LLC" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Open Source Notices \u00b7 BridgeSwarm Legal",
|
||||
"description": "AGPL-3.0 license and third-party open source notices for BridgeSwarm by HoneyPeer, LLC.",
|
||||
"url": "https://bridgeswarm.dev/legal/license",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">Legal</p>
|
||||
<h1>Open Source & Third-Party Notices</h1>
|
||||
<p class="docs-lead">
|
||||
BridgeSwarm is open-source software engineered by <strong>HoneyPeer, LLC</strong> and licensed under
|
||||
the <strong>GNU Affero General Public License, Version 3 (AGPL-3.0)</strong>, with third-party
|
||||
components under their respective licenses.
|
||||
</p>
|
||||
<p class="legal-updated">Last updated: <strong>July 27, 2026</strong></p>
|
||||
|
||||
<nav class="toc">
|
||||
<strong>On this page</strong>
|
||||
<ol>
|
||||
<li><a href="#copyright">Copyright</a></li>
|
||||
<li><a href="#agpl">AGPL-3.0</a></li>
|
||||
<li><a href="#network">Network use & source offer (§13)</a></li>
|
||||
<li><a href="#third">Third-party components</a></li>
|
||||
<li><a href="#source">Source availability</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="copyright">1. Copyright</h2>
|
||||
<p>
|
||||
Copyright © 2025-<span data-year></span> HoneyPeer, LLC and BridgeSwarm contributors.<br />
|
||||
BridgeSwarm is owned, operated, and engineered by HoneyPeer, LLC (DeKalb County, Georgia, USA).
|
||||
</p>
|
||||
|
||||
<h2 id="agpl">2. GNU Affero General Public License v3.0</h2>
|
||||
<p>
|
||||
BridgeSwarm is licensed under the GNU Affero General Public License, Version 3 (the “License”).
|
||||
You may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at:
|
||||
</p>
|
||||
<p><a href="https://www.gnu.org/licenses/agpl-3.0.html" target="_blank" rel="noopener">https://www.gnu.org/licenses/agpl-3.0.html</a></p>
|
||||
<p>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the
|
||||
GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License,
|
||||
or (at your option) any later version.
|
||||
</p>
|
||||
<p>
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Affero General Public License for more details.
|
||||
</p>
|
||||
<div class="callout info">
|
||||
<div class="callout-icon">i</div>
|
||||
<div class="callout-body">
|
||||
<strong>Full text.</strong> The complete AGPL-3.0 license text is included in the BridgeSwarm source repository
|
||||
as <code>LICENSE</code>. In case of conflict between this summary page and the repository license file, the repository license file controls for the source code.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 id="network">3. Network use and source offer (AGPL §13)</h2>
|
||||
<p>
|
||||
AGPL-3.0 is a strong copyleft license specifically designed for network-facing software. Section 13
|
||||
of the License requires that if you modify BridgeSwarm — the extension, the native messaging host, or
|
||||
both — and let other users interact with your modified version remotely over a computer network
|
||||
(for example, by distributing your own build of the host or extension that other people connect to
|
||||
or run), you must offer those users the corresponding source code of your modified version under
|
||||
AGPL-3.0, generally by providing a prominent, easy-to-find download link from within the modified
|
||||
software itself.
|
||||
</p>
|
||||
<p>
|
||||
This obligation applies whether or not BridgeSwarm’s own peer-to-peer connections are involved:
|
||||
it is triggered by <em>your users interacting with your modified software over a network</em>, which
|
||||
includes typical extension/host deployments. Redistributions must also preserve copyright notices,
|
||||
license notices, and disclaimers as required by AGPL-3.0.
|
||||
</p>
|
||||
|
||||
<h2 id="third">4. Third-party components</h2>
|
||||
<p>
|
||||
BridgeSwarm depends on third-party libraries and tools, most notably the Holepunch/Hyperswarm stack
|
||||
(Hyperswarm, Corestore, Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb, Protomux, HRPC) and the
|
||||
<a href="https://www.npmjs.com/package/bare" target="_blank" rel="noopener">Bare</a> JavaScript
|
||||
runtime that powers the native messaging host, along with optional capability packs such as
|
||||
<code>bare-media</code> and <code>bare-ffmpeg</code>. Each dependency is governed by its own license
|
||||
as declared in its package metadata or upstream repository. Operators redistributing combined builds
|
||||
should review dependency licenses and generate a dependency inventory as appropriate for their
|
||||
compliance process.
|
||||
</p>
|
||||
|
||||
<h2 id="source">5. Source availability</h2>
|
||||
<p>
|
||||
Source code is published at the project repository:
|
||||
<a href="https://git.ssh.surf/snxraven/BridgeSwarm" target="_blank" rel="noopener">git.ssh.surf/snxraven/BridgeSwarm</a>.
|
||||
Release pages there may distribute prebuilt extension packages and native-host binaries
|
||||
corresponding to published releases (including the rolling <code>latest-main</code> channel).
|
||||
</p>
|
||||
|
||||
<h2 id="contact">6. Contact</h2>
|
||||
<p>
|
||||
License questions: <a href="mailto:[email protected]">[email protected]</a><br />
|
||||
HoneyPeer, LLC · DeKalb County, Georgia, USA
|
||||
</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<a href="/legal/privacy"><span>Previous</span><strong>← Privacy</strong></a>
|
||||
<a class="next" href="/legal/copyright"><span>Next</span><strong>Copyright & DMCA →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,359 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Privacy Policy · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="Privacy Policy for BridgeSwarm and HoneyPeer, LLC: local-first storage under ~/.bridgeswarm, no telemetry in the extension or host, and website cookie use." />
|
||||
<meta name="keywords" content="BridgeSwarm Privacy Policy, cookies, HoneyPeer, local-first" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/privacy" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/privacy" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/privacy" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/privacy" />
|
||||
<meta property="og:title" content="Privacy Policy · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="Privacy Policy for BridgeSwarm and HoneyPeer, LLC: local-first storage under ~/.bridgeswarm, no telemetry in the extension or host, and website cookie use." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Privacy Policy · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="Privacy Policy for BridgeSwarm and HoneyPeer, LLC: local-first storage under ~/.bridgeswarm, no telemetry in the extension or host, and website cookie use." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<!-- Article -->
|
||||
<meta property="article:section" content="Legal" />
|
||||
<meta property="article:author" content="HoneyPeer, LLC" />
|
||||
<meta property="article:publisher" content="HoneyPeer, LLC" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Privacy Policy \u00b7 BridgeSwarm Legal",
|
||||
"description": "Privacy Policy for BridgeSwarm and HoneyPeer, LLC: local-first storage under ~/.bridgeswarm, no telemetry in the extension or host, and website cookie use.",
|
||||
"url": "https://bridgeswarm.dev/legal/privacy",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">Legal</p>
|
||||
<h1>Privacy Policy</h1>
|
||||
<p class="docs-lead">
|
||||
This Privacy Policy explains how <strong>HoneyPeer, LLC</strong> (“HoneyPeer,” “we,” “us”) handles
|
||||
information in connection with the BridgeSwarm website (the “<strong>Site</strong>”) and how the
|
||||
BridgeSwarm browser extension and native messaging host (the “<strong>Software</strong>”) handle data
|
||||
on your own device.
|
||||
</p>
|
||||
<p class="legal-updated">Last updated: <strong>July 27, 2026</strong></p>
|
||||
|
||||
<div class="callout success">
|
||||
<div class="callout-icon">✓</div>
|
||||
<div class="callout-body">
|
||||
<strong>Local-first by design.</strong>
|
||||
BridgeSwarm runs entirely on your machine. The extension and native messaging host do not send
|
||||
analytics, telemetry, or usage data to HoneyPeer. Your application data lives in local storage
|
||||
under your control and is exchanged only with the peers you choose to connect to.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="toc">
|
||||
<strong>On this page</strong>
|
||||
<ol>
|
||||
<li><a href="#scope">Scope</a></li>
|
||||
<li><a href="#controller">Controller</a></li>
|
||||
<li><a href="#collect">Information we collect (the Site)</a></li>
|
||||
<li><a href="#local">The BridgeSwarm Software is local-first</a></li>
|
||||
<li><a href="#storage">Where your data lives</a></li>
|
||||
<li><a href="#network">Peer-to-peer network activity</a></li>
|
||||
<li><a href="#use">How we use Site information</a></li>
|
||||
<li><a href="#share">Sharing</a></li>
|
||||
<li id="cookies"><a href="#cookies-section">Cookies & similar technologies</a></li>
|
||||
<li><a href="#retention">Retention</a></li>
|
||||
<li><a href="#security">Security</a></li>
|
||||
<li><a href="#rights">Your rights</a></li>
|
||||
<li><a href="#children">Children</a></li>
|
||||
<li><a href="#intl">International transfers</a></li>
|
||||
<li><a href="#changes">Changes</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="scope">1. Scope</h2>
|
||||
<p>
|
||||
This Policy covers the Site (bridgeswarm.dev and related subdomains) and communications with
|
||||
HoneyPeer about BridgeSwarm. It also describes, for transparency, how the Software itself is
|
||||
architected with respect to data — but the Software runs on <strong>your</strong> device, so most of
|
||||
the data it creates or handles is never sent to us at all.
|
||||
</p>
|
||||
|
||||
<h2 id="controller">2. Data controller</h2>
|
||||
<p>
|
||||
HoneyPeer, LLC<br />
|
||||
DeKalb County, Georgia, United States<br />
|
||||
Contact: <a href="mailto:[email protected]">[email protected]</a>
|
||||
</p>
|
||||
|
||||
<h2 id="collect">3. Information we collect (the Site)</h2>
|
||||
<h3>3.1 Information you provide</h3>
|
||||
<ul>
|
||||
<li>Contact details if you email us (name, email address, message content);</li>
|
||||
<li>Security vulnerability reports or legal notices you send;</li>
|
||||
<li>Any other information you voluntarily submit via forms or email.</li>
|
||||
</ul>
|
||||
<h3>3.2 Information collected automatically</h3>
|
||||
<ul>
|
||||
<li>Standard server logs (IP address, user agent, request path, timestamps, referrer) generated by serving the Site;</li>
|
||||
<li>Approximate location derived from IP (city/region level at most, if used by our hosting provider’s logs);</li>
|
||||
<li>Diagnostic data only if a future feature explicitly asks for opt-in telemetry and discloses it at collection time.</li>
|
||||
</ul>
|
||||
<h3>3.3 We do not sell personal data</h3>
|
||||
<p>HoneyPeer does not sell your personal information.</p>
|
||||
|
||||
<h2 id="local">4. The BridgeSwarm Software is local-first</h2>
|
||||
<p>
|
||||
The BridgeSwarm extension (Manifest V3) and its companion native messaging host run entirely on your
|
||||
computer. As designed and as of this writing:
|
||||
</p>
|
||||
<ul>
|
||||
<li>the extension and host do <strong>not</strong> phone home to HoneyPeer with analytics, crash reports, or usage telemetry;</li>
|
||||
<li>the native host communicates only with the browser extension over the standard native-messaging
|
||||
stdio channel, and with peers you explicitly connect to over the Hyperswarm network;</li>
|
||||
<li>settings such as default app name, max peers, timeouts, and the optional local examples server
|
||||
toggle are stored in your browser’s extension storage (<code>bridgeSwarmSettings</code>), not on HoneyPeer servers.</li>
|
||||
</ul>
|
||||
<p>
|
||||
If a future version of the Software ever introduces optional telemetry or a HoneyPeer-hosted online
|
||||
service, it will be off by default, clearly disclosed, and this Policy will be updated accordingly
|
||||
before that feature ships.
|
||||
</p>
|
||||
|
||||
<h2 id="storage">5. Where your data lives</h2>
|
||||
<p>
|
||||
BridgeSwarm’s data APIs (Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb via a local Corestore)
|
||||
persist to disk on your machine, under a storage directory you or the installer control:
|
||||
</p>
|
||||
<ul>
|
||||
<li>the official installer places the native host binary and its default working directory under
|
||||
<code>~/.bridgeswarm/</code> on macOS/Linux (or <code>%LOCALAPPDATA%\bridgeswarm\</code> on Windows);</li>
|
||||
<li>the storage location for Hyper* data structures can be overridden with the
|
||||
<code>BRIDGE_SWARM_STORAGE</code> environment variable when running the host from source;</li>
|
||||
<li>optional capability packs (for example media processing jobs) write only within a sandboxed
|
||||
<code>cap-jobs</code> subdirectory of that same storage root — never to arbitrary paths on your filesystem.</li>
|
||||
</ul>
|
||||
<p>
|
||||
None of this data is uploaded to HoneyPeer. It stays on your device unless your own application code
|
||||
replicates it to peers you have chosen to connect with.
|
||||
</p>
|
||||
|
||||
<h2 id="network">6. Peer-to-peer network activity</h2>
|
||||
<p>
|
||||
When you join a topic, BridgeSwarm uses the public Hyperswarm distributed hash table to discover
|
||||
peers and negotiate direct, Noise-encrypted connections. This discovery process is inherently visible
|
||||
to the DHT and to peers you connect with (for example, your public key and the topics you announce).
|
||||
HoneyPeer is not a party to, and does not log or relay, the content of your peer connections.
|
||||
</p>
|
||||
|
||||
<h2 id="use">7. How we use Site information</h2>
|
||||
<ul>
|
||||
<li>Operate, secure, and improve the Site and release/installer pages;</li>
|
||||
<li>Respond to support, legal, and security requests;</li>
|
||||
<li>Prevent abuse, fraud, and violations of our <a href="/legal/aup">Acceptable Use Policy</a>;</li>
|
||||
<li>Comply with law and enforce our agreements;</li>
|
||||
<li>Communicate about BridgeSwarm if you contact us or subscribe to updates (where offered).</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="share">8. Sharing</h2>
|
||||
<p>We may share information with:</p>
|
||||
<ul>
|
||||
<li><strong>Service providers</strong> who host the Site, DNS, CDN, or email under contractual confidentiality obligations;</li>
|
||||
<li><strong>Professional advisors</strong> (legal, accounting) as needed;</li>
|
||||
<li><strong>Authorities</strong> when required by law or to protect rights, safety, and security;</li>
|
||||
<li><strong>Business transfers</strong> in connection with a merger, acquisition, or asset sale, subject to appropriate protections.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="cookies-section">9. Cookies and similar technologies</h2>
|
||||
<p>
|
||||
Cookies are small text files stored on your device. Similar technologies include local storage,
|
||||
session storage, and pixels. We use “cookies” to refer to these technologies collectively.
|
||||
</p>
|
||||
<h3>9.1 How the Site uses cookies today</h3>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Category</th><th>Purpose</th><th>Examples</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Essential / functional</strong></td>
|
||||
<td>Remember your theme preference and, where applicable, dismissed banners</td>
|
||||
<td><code>localStorage</code> key <code>bridgeswarm.site.theme</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Analytics</strong> (not currently enabled)</td>
|
||||
<td>Understand aggregate traffic and improve documentation</td>
|
||||
<td>None active as of the Last updated date above</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p>
|
||||
As of the Last updated date, the Site does not set third-party advertising or analytics cookies.
|
||||
It uses browser <code>localStorage</code> only for interface preferences (such as light/dark theme),
|
||||
which does not identify you personally. If we enable non-essential analytics cookies in the future,
|
||||
we will update this Policy and, where required, provide consent controls.
|
||||
</p>
|
||||
<h3>9.2 Your choices</h3>
|
||||
<ul>
|
||||
<li>Browser settings can block or delete cookies and local storage; theme preference will simply reset to default if cleared.</li>
|
||||
<li>Where consent is required for non-essential cookies, we will request it before setting them.</li>
|
||||
</ul>
|
||||
<h3>9.3 Third parties</h3>
|
||||
<p>
|
||||
Embedded third-party content (fonts, linked source repository) may set their own cookies under their
|
||||
policies. We do not control third-party cookies on external sites you navigate to.
|
||||
</p>
|
||||
|
||||
<h2 id="retention">10. Retention</h2>
|
||||
<p>
|
||||
We retain personal information only as long as needed for the purposes above, including legal,
|
||||
security, and accounting requirements. Server logs are typically rotated on a limited schedule
|
||||
determined by our hosting configuration.
|
||||
</p>
|
||||
|
||||
<h2 id="security">11. Security</h2>
|
||||
<p>
|
||||
We implement reasonable administrative and technical measures appropriate to the nature of the Site.
|
||||
No method of transmission or storage is perfectly secure. Report suspected Site or product
|
||||
vulnerabilities to <a href="mailto:[email protected]">[email protected]</a> (see
|
||||
<a href="/legal/security">Security Policy</a>).
|
||||
</p>
|
||||
|
||||
<h2 id="rights">12. Your rights</h2>
|
||||
<p>
|
||||
Depending on your location, you may have rights to access, correct, delete, or restrict processing of
|
||||
personal data, or to object to certain processing. To exercise rights, contact
|
||||
<a href="mailto:[email protected]">[email protected]</a>.
|
||||
We may need to verify your request. You may also lodge a complaint with a supervisory authority where applicable.
|
||||
</p>
|
||||
<p>
|
||||
Residents of certain U.S. states may have additional rights under state privacy laws; contact us to
|
||||
exercise them. We do not use sensitive personal information for “sale” or “sharing” as those terms
|
||||
are defined under the CCPA/CPRA.
|
||||
</p>
|
||||
|
||||
<h2 id="children">13. Children</h2>
|
||||
<p>
|
||||
The Site and Software are directed to developers and technical users, not children under 16 (or the
|
||||
age of digital consent in your jurisdiction). We do not knowingly collect personal information from children.
|
||||
</p>
|
||||
|
||||
<h2 id="intl">14. International transfers</h2>
|
||||
<p>
|
||||
HoneyPeer is based in the United States. If you access the Site from outside the U.S., your
|
||||
information may be processed in the U.S. or other countries where our providers operate.
|
||||
</p>
|
||||
|
||||
<h2 id="changes">15. Changes</h2>
|
||||
<p>
|
||||
We may update this Policy by posting a new version with a revised “Last updated” date.
|
||||
Material changes — especially any change that adds telemetry to the Software — will be indicated
|
||||
prominently on this page.
|
||||
</p>
|
||||
|
||||
<h2 id="contact">16. Contact</h2>
|
||||
<p>
|
||||
HoneyPeer, LLC · DeKalb County, Georgia, USA<br />
|
||||
<a href="mailto:[email protected]">[email protected]</a>
|
||||
</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<a href="/legal/aup"><span>Previous</span><strong>← Acceptable Use</strong></a>
|
||||
<a class="next" href="/legal/license"><span>Next</span><strong>Open Source Notices →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,217 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Security Policy · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="How to report security vulnerabilities in BridgeSwarm to HoneyPeer, LLC." />
|
||||
<meta name="keywords" content="BridgeSwarm security policy, vulnerability disclosure" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/security" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/security" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/security" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/security" />
|
||||
<meta property="og:title" content="Security Policy · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="How to report security vulnerabilities in BridgeSwarm to HoneyPeer, LLC." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Security Policy · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="How to report security vulnerabilities in BridgeSwarm to HoneyPeer, LLC." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<!-- Article -->
|
||||
<meta property="article:section" content="Legal" />
|
||||
<meta property="article:author" content="HoneyPeer, LLC" />
|
||||
<meta property="article:publisher" content="HoneyPeer, LLC" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Security Policy \u00b7 BridgeSwarm Legal",
|
||||
"description": "How to report security vulnerabilities in BridgeSwarm to HoneyPeer, LLC.",
|
||||
"url": "https://bridgeswarm.dev/legal/security",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">Legal</p>
|
||||
<h1>Security Policy</h1>
|
||||
<p class="docs-lead">
|
||||
HoneyPeer, LLC takes the security of BridgeSwarm’s extension, native messaging host, and websites
|
||||
seriously, and welcomes responsible disclosure from the security community.
|
||||
</p>
|
||||
<p class="legal-updated">Last updated: <strong>July 27, 2026</strong></p>
|
||||
|
||||
<nav class="toc">
|
||||
<strong>On this page</strong>
|
||||
<ol>
|
||||
<li><a href="#scope">Scope</a></li>
|
||||
<li><a href="#report">Reporting a vulnerability</a></li>
|
||||
<li><a href="#process">Our process</a></li>
|
||||
<li><a href="#guidelines">Responsible testing guidelines</a></li>
|
||||
<li><a href="#recognition">Recognition</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="scope">1. Scope</h2>
|
||||
<p>This policy covers:</p>
|
||||
<ul>
|
||||
<li>the BridgeSwarm browser extension (Manifest V3);</li>
|
||||
<li>the native messaging host (Bare runtime) and its bundled capability packs;</li>
|
||||
<li>the official installer/uninstaller scripts for macOS, Linux, and Windows;</li>
|
||||
<li>bridgeswarm.dev and other HoneyPeer-operated Sites related to BridgeSwarm.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Out of scope: vulnerabilities in third-party dependencies that should be reported upstream (though we
|
||||
appreciate a heads-up), and issues arising purely from a peer’s own application-layer misuse of the
|
||||
public Hyperswarm network that do not involve a flaw in BridgeSwarm itself.
|
||||
</p>
|
||||
|
||||
<h2 id="report">2. Reporting a vulnerability</h2>
|
||||
<p>
|
||||
Please email <strong><a href="mailto:[email protected]">[email protected]</a></strong> with the subject line
|
||||
<code>SECURITY: BridgeSwarm</code>. Include, where possible:
|
||||
</p>
|
||||
<ul>
|
||||
<li>a clear description of the issue and its potential impact;</li>
|
||||
<li>affected component (extension, native host, capability pack, installer, or website) and version/commit;</li>
|
||||
<li>step-by-step reproduction instructions or a proof-of-concept;</li>
|
||||
<li>your assessment of severity and any suggested remediation.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Please do <strong>not</strong> open a public GitHub/Gitea issue for suspected security vulnerabilities.
|
||||
Use email so we can coordinate a fix before public disclosure.
|
||||
</p>
|
||||
|
||||
<h2 id="process">3. Our process</h2>
|
||||
<ol>
|
||||
<li><strong>Acknowledgment</strong> — we aim to acknowledge new reports within a few business days.</li>
|
||||
<li><strong>Triage</strong> — we assess scope, severity, and affected versions.</li>
|
||||
<li><strong>Fix</strong> — we develop and test a patch, prioritized by severity.</li>
|
||||
<li><strong>Disclosure</strong> — we coordinate an appropriate disclosure timeline with the reporter, and publish release notes or an advisory once a fix is available.</li>
|
||||
</ol>
|
||||
<p>
|
||||
As BridgeSwarm is an actively developed open-source project without a dedicated 24/7 security team,
|
||||
response times are best-effort. Critical issues affecting the native host or extension’s handling of
|
||||
untrusted peer data are treated as highest priority.
|
||||
</p>
|
||||
|
||||
<h2 id="guidelines">4. Responsible testing guidelines</h2>
|
||||
<p>When researching security issues, please:</p>
|
||||
<ul>
|
||||
<li>test only against your own local installation of the extension/host, or infrastructure you own or are explicitly authorized to test;</li>
|
||||
<li>do not access, modify, or exfiltrate data belonging to other users or peers;</li>
|
||||
<li>do not perform testing that could degrade the shared public Hyperswarm DHT for other users (e.g. flooding, denial-of-service);</li>
|
||||
<li>give us a reasonable opportunity to remediate before any public disclosure.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Good-faith research conducted consistently with this policy is authorized under the
|
||||
<a href="/legal/aup">Acceptable Use Policy</a>, and HoneyPeer will not pursue legal action for such research.
|
||||
</p>
|
||||
|
||||
<h2 id="recognition">5. Recognition</h2>
|
||||
<p>
|
||||
With your permission, we’re happy to credit researchers who report valid issues in release notes or an
|
||||
acknowledgments page. HoneyPeer does not currently operate a paid bug bounty program.
|
||||
</p>
|
||||
|
||||
<h2 id="contact">6. Contact</h2>
|
||||
<p>
|
||||
Security: <a href="mailto:[email protected]">[email protected]</a><br />
|
||||
HoneyPeer, LLC · DeKalb County, Georgia, USA
|
||||
</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<a href="/legal/disclaimer"><span>Previous</span><strong>← Disclaimer</strong></a>
|
||||
<a class="next" href="/legal/"><span>Back to</span><strong>Legal overview →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,287 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<!-- Theme: FOUC-safe bootstrap (localStorage bridgeswarm.site.theme) -->
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>Terms of Service · BridgeSwarm Legal</title>
|
||||
<meta name="description" content="Terms of Service for BridgeSwarm websites and online properties operated by HoneyPeer, LLC." />
|
||||
<meta name="keywords" content="BridgeSwarm Terms of Service, HoneyPeer" />
|
||||
<meta name="author" content="HoneyPeer, LLC" />
|
||||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="googlebot" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
|
||||
<meta name="theme-color" content="#2dd4bf" />
|
||||
<meta name="color-scheme" content="dark light" />
|
||||
<meta name="application-name" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-title" content="BridgeSwarm" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="msapplication-TileColor" content="#2dd4bf" />
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/legal/terms" />
|
||||
<link rel="alternate" hreflang="en" href="https://bridgeswarm.dev/legal/terms" />
|
||||
<link rel="alternate" hreflang="x-default" href="https://bridgeswarm.dev/legal/terms" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:site_name" content="BridgeSwarm" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/legal/terms" />
|
||||
<meta property="og:title" content="Terms of Service · BridgeSwarm Legal" />
|
||||
<meta property="og:description" content="Terms of Service for BridgeSwarm websites and online properties operated by HoneyPeer, LLC." />
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:secure_url" content="https://bridgeswarm.dev/assets/brand/og-image.png" />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Twitter / X -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Terms of Service · BridgeSwarm Legal" />
|
||||
<meta name="twitter:description" content="Terms of Service for BridgeSwarm websites and online properties operated by HoneyPeer, LLC." />
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png" />
|
||||
<meta name="twitter:image:alt" content="BridgeSwarm: Hyperswarm P2P for the browser" />
|
||||
|
||||
<!-- Icons & PWA -->
|
||||
<link rel="icon" href="/assets/favicons/favicon.ico" sizes="any" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png" />
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf" />
|
||||
|
||||
<!-- Article -->
|
||||
<meta property="article:section" content="Legal" />
|
||||
<meta property="article:author" content="HoneyPeer, LLC" />
|
||||
<meta property="article:publisher" content="HoneyPeer, LLC" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
"name": "Terms of Service \u00b7 BridgeSwarm Legal",
|
||||
"description": "Terms of Service for BridgeSwarm websites and online properties operated by HoneyPeer, LLC.",
|
||||
"url": "https://bridgeswarm.dev/legal/terms",
|
||||
"isPartOf": {
|
||||
"@type": "WebSite",
|
||||
"name": "BridgeSwarm",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev"
|
||||
},
|
||||
"inLanguage": "en-US",
|
||||
"primaryImageOfPage": {
|
||||
"@type": "ImageObject",
|
||||
"url": "https://bridgeswarm.dev/assets/brand/og-image.png",
|
||||
"width": 1200,
|
||||
"height": 630
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
||||
<link rel="stylesheet" href="/src/styles/global.css" />
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css" />
|
||||
<link rel="stylesheet" href="/src/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/src/styles/legal.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<div class="docs-layout legal-layout">
|
||||
<aside class="docs-sidebar" data-legal-nav></aside>
|
||||
<button type="button" class="docs-sidebar-toggle" aria-label="Legal menu">☰</button>
|
||||
|
||||
<article class="docs-main legal-main">
|
||||
<p class="legal-kicker">Legal</p>
|
||||
<h1>Terms of Service</h1>
|
||||
<p class="docs-lead">
|
||||
These Terms of Service (“<strong>Terms</strong>”) govern your access to and use of websites,
|
||||
documentation, download portals, and related online properties operated by HoneyPeer, LLC
|
||||
in connection with BridgeSwarm (collectively, the “<strong>Sites</strong>”).
|
||||
</p>
|
||||
<p class="legal-updated">Last updated: <strong>July 27, 2026</strong></p>
|
||||
|
||||
<nav class="toc">
|
||||
<strong>On this page</strong>
|
||||
<ol>
|
||||
<li><a href="#agreement">Agreement</a></li>
|
||||
<li><a href="#entity">Who we are</a></li>
|
||||
<li><a href="#sites">The Sites</a></li>
|
||||
<li><a href="#oss">Relationship to open source</a></li>
|
||||
<li><a href="#network">The BridgeSwarm network</a></li>
|
||||
<li><a href="#acceptable">Acceptable use</a></li>
|
||||
<li><a href="#ip">Intellectual property</a></li>
|
||||
<li><a href="#third">Third-party services</a></li>
|
||||
<li><a href="#disclaimers">Disclaimers</a></li>
|
||||
<li><a href="#liability">Limitation of liability</a></li>
|
||||
<li><a href="#indemnity">Indemnity</a></li>
|
||||
<li><a href="#law">Governing law</a></li>
|
||||
<li><a href="#changes">Changes</a></li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="agreement">1. Agreement to these Terms</h2>
|
||||
<p>
|
||||
By accessing or using the Sites, you agree to these Terms and to our
|
||||
<a href="/legal/privacy">Privacy Policy</a>
|
||||
(including cookies and similar technologies) and
|
||||
<a href="/legal/aup">Acceptable Use Policy</a>.
|
||||
If you do not agree, do not use the Sites.
|
||||
</p>
|
||||
<p>
|
||||
If you use the Sites on behalf of an organization, you represent that you have authority to bind that organization, and “you” includes that organization.
|
||||
</p>
|
||||
|
||||
<h2 id="entity">2. Who we are</h2>
|
||||
<p>
|
||||
The Sites are owned and operated by <strong>HoneyPeer, LLC</strong> (“<strong>HoneyPeer</strong>,” “<strong>we</strong>,” “<strong>us</strong>”),
|
||||
a Georgia limited liability company with its principal place of business in DeKalb County, Georgia, USA.
|
||||
BridgeSwarm is a product owned, operated, and engineered by HoneyPeer.
|
||||
</p>
|
||||
|
||||
<h2 id="sites">3. The Sites</h2>
|
||||
<p>The Sites include, without limitation:</p>
|
||||
<ul>
|
||||
<li>https://bridgeswarm.dev and related subdomains (including documentation and marketing pages);</li>
|
||||
<li>the source repository and release/installer pages we operate or link to for distributing BridgeSwarm;</li>
|
||||
<li>any related web properties, APIs, or portals we designate as part of BridgeSwarm online services.</li>
|
||||
</ul>
|
||||
<p>
|
||||
The Sites provide information, documentation, and software distribution for BridgeSwarm — a browser
|
||||
extension and a companion native messaging host that bring the Hyperswarm peer-to-peer stack into
|
||||
ordinary desktop browsers. HoneyPeer may modify, suspend, or discontinue any part of the Sites at any time.
|
||||
</p>
|
||||
|
||||
<h2 id="oss">4. Relationship to open-source software</h2>
|
||||
<p>
|
||||
BridgeSwarm <strong>source code</strong> — the extension, the native messaging host, and build
|
||||
tooling — is generally available under the
|
||||
<a href="/legal/license">GNU Affero General Public License v3.0 (AGPL-3.0)</a> (and any additional notices in the repository).
|
||||
Nothing in these Terms limits rights you already have under a valid open-source license to code you obtained under that license.
|
||||
</p>
|
||||
<p>
|
||||
These Terms apply to the Sites and to materials and services HoneyPeer provides online.
|
||||
Your use of compiled extension packages, native-host binaries, or installers we distribute may also be subject to the
|
||||
<a href="/legal/eula">End User License Agreement</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="network">5. The BridgeSwarm network</h2>
|
||||
<p>
|
||||
BridgeSwarm establishes direct, encrypted peer-to-peer connections between browsers and other
|
||||
Hyperswarm-compatible peers via the public Hyperswarm DHT. HoneyPeer does not operate a central
|
||||
server that relays your application traffic, and does not act as a party to the content exchanged
|
||||
between peers you choose to connect with. You are solely responsible for:
|
||||
</p>
|
||||
<ul>
|
||||
<li>the topics you join and the peers you accept connections from;</li>
|
||||
<li>any application-layer data you store locally (Hypercore, Hyperbee, Hyperdrive, Autobase, or Hyperdb) or transmit to peers;</li>
|
||||
<li>compliance with laws applicable to the content and connections you create;</li>
|
||||
<li>securing the machine running the native messaging host, which operates with your user account's privileges.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="acceptable">6. Acceptable use</h2>
|
||||
<p>
|
||||
You must comply with our <a href="/legal/aup">Acceptable Use Policy</a>.
|
||||
You may not misuse the Sites, installers, or HoneyPeer infrastructure, including attempts to disrupt, scrape abusively, distribute malware, or violate law.
|
||||
</p>
|
||||
|
||||
<h2 id="ip">7. Intellectual property</h2>
|
||||
<p>
|
||||
Except for open-source software licensed separately, the Sites (including text, graphics, logos, and arrangement) are owned by HoneyPeer or its licensors and protected by intellectual property laws.
|
||||
See our <a href="/legal/copyright">Copyright & DMCA</a> page for intellectual property notices.
|
||||
</p>
|
||||
<p>
|
||||
You may not use HoneyPeer or BridgeSwarm branding in a way that implies endorsement, partnership, or official status without prior written permission, except as allowed by fair use or other applicable law.
|
||||
</p>
|
||||
|
||||
<h2 id="third">8. Third-party services and links</h2>
|
||||
<p>
|
||||
The Sites may link to third-party sites (for example source hosting, the public Hyperswarm/DHT
|
||||
infrastructure, or dependency projects). HoneyPeer is not responsible for third-party content,
|
||||
licenses, network behavior, or practices. Some BridgeSwarm features integrate third-party
|
||||
components (see <a href="/legal/license">Open Source Notices</a>).
|
||||
</p>
|
||||
|
||||
<h2 id="disclaimers">9. Disclaimers</h2>
|
||||
<p>
|
||||
THE SITES AND ALL MATERIALS ARE PROVIDED “AS IS” AND “AS AVAILABLE.”
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY LAW, HONEYPEER DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, OR STATUTORY,
|
||||
INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT.
|
||||
WE DO NOT WARRANT THAT THE SITES WILL BE UNINTERRUPTED, SECURE, OR ERROR-FREE.
|
||||
</p>
|
||||
<p>Additional product-level disclaimers appear in the <a href="/legal/disclaimer">Disclaimer & Liability</a> document and the EULA.</p>
|
||||
|
||||
<h2 id="liability">10. Limitation of liability</h2>
|
||||
<p>
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY LAW, HONEYPEER AND ITS OFFICERS, MEMBERS, EMPLOYEES, AND AGENTS WILL NOT BE LIABLE FOR
|
||||
ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE DAMAGES, OR ANY LOSS OF PROFITS, DATA, GOODWILL,
|
||||
OR BUSINESS INTERRUPTION, ARISING OUT OF OR RELATED TO YOUR USE OF THE SITES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
</p>
|
||||
<p>
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY LAW, HONEYPEER’S TOTAL LIABILITY FOR ANY CLAIM ARISING OUT OF OR RELATING TO THE SITES
|
||||
WILL NOT EXCEED THE GREATER OF (A) AMOUNTS YOU PAID TO HONEYPEER FOR THE SITES IN THE TWELVE (12) MONTHS BEFORE THE CLAIM, OR (B) ONE HUNDRED U.S. DOLLARS (US $100).
|
||||
</p>
|
||||
<p>Some jurisdictions do not allow certain limitations; in those cases, our liability is limited to the fullest extent permitted.</p>
|
||||
|
||||
<h2 id="indemnity">11. Indemnification</h2>
|
||||
<p>
|
||||
You will defend, indemnify, and hold harmless HoneyPeer and its members, officers, and agents from and against any claims, damages, losses, and expenses
|
||||
(including reasonable attorneys’ fees) arising out of or related to your misuse of the Sites, your peer-to-peer activity, your violation of these Terms, or your violation of law or third-party rights.
|
||||
</p>
|
||||
|
||||
<h2 id="law">12. Governing law and venue</h2>
|
||||
<p>
|
||||
These Terms are governed by the laws of the State of Georgia, USA, without regard to conflict-of-law principles.
|
||||
Exclusive venue for disputes lies in the state or federal courts located in Georgia (including courts serving DeKalb County, Georgia),
|
||||
and you consent to personal jurisdiction there, except where prohibited by law.
|
||||
</p>
|
||||
|
||||
<h2 id="changes">13. Changes</h2>
|
||||
<p>
|
||||
We may update these Terms by posting a revised version on the Sites with a new “Last updated” date.
|
||||
Continued use after changes become effective constitutes acceptance of the revised Terms.
|
||||
</p>
|
||||
|
||||
<h2 id="contact">14. Contact</h2>
|
||||
<p>
|
||||
HoneyPeer, LLC<br />
|
||||
DeKalb County, Georgia, United States<br />
|
||||
Legal: <a href="mailto:[email protected]">[email protected]</a>
|
||||
</p>
|
||||
|
||||
<div class="docs-pager">
|
||||
<a href="/legal/"><span>Legal hub</span><strong>← All documents</strong></a>
|
||||
<a class="next" href="/legal/eula"><span>Next</span><strong>EULA →</strong></a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "bridgeswarm-website",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"description": "Official BridgeSwarm marketing site, user guide, and developer documentation",
|
||||
"type": "module",
|
||||
"license": "AGPL-3.0",
|
||||
"author": "HoneyPeer, LLC",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"start": "node server.mjs",
|
||||
"serve": "node server.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^6.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"mermaid": "^11.16.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* BridgeSwarm Brand Color Tokens
|
||||
Source of truth — synced into assets/brand/colors.css
|
||||
Keep in sync with extension/panel.css Control Center
|
||||
*/
|
||||
:root {
|
||||
--bs-bg-primary: #0c0c10;
|
||||
--bs-bg-secondary: #141418;
|
||||
--bs-bg-tertiary: #1a1a20;
|
||||
--bs-bg-elevated: #1a1a20;
|
||||
--bs-bg-hover: #22222a;
|
||||
|
||||
--bs-accent-primary: #2dd4bf;
|
||||
--bs-accent-secondary: #14b8a6;
|
||||
--bs-accent-success: #34d399;
|
||||
--bs-accent-warning: #fbbf24;
|
||||
--bs-accent-danger: #fb7185;
|
||||
--bs-accent-info: #60a5fa;
|
||||
|
||||
--bs-text-primary: #ececf1;
|
||||
--bs-text-secondary: #c8c8d4;
|
||||
--bs-text-muted: #8b8b9a;
|
||||
--bs-text-faint: #5c5c6c;
|
||||
|
||||
--bs-border: rgba(255, 255, 255, 0.1);
|
||||
--bs-border-strong: #3a3a46;
|
||||
|
||||
--bs-logo-node: #2dd4bf;
|
||||
--bs-logo-node-alt: #38bdf8;
|
||||
--bs-logo-bridge: #2dd4bf;
|
||||
--bs-logo-plate: #0c0c10;
|
||||
|
||||
--bs-radius: 10px;
|
||||
--bs-radius-sm: 7px;
|
||||
|
||||
--bs-font: "Avenir Next", "Segoe UI", "Helvetica Neue", sans-serif;
|
||||
--bs-mono: "Cascadia Code", "SF Mono", Consolas, monospace;
|
||||
}
|
||||
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="mstile-150x150.png"/>
|
||||
<TileColor>#0c0c10</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
After Width: | Height: | Size: 557 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "BridgeSwarm",
|
||||
"short_name": "BridgeSwarm",
|
||||
"description": "P2P Hyperswarm in the browser via native messaging host",
|
||||
"icons": [
|
||||
{
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#2dd4bf",
|
||||
"background_color": "#0c0c10",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
After Width: | Height: | Size: 207 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 557 B |
|
After Width: | Height: | Size: 467 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 606 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 467 KiB |
|
After Width: | Height: | Size: 467 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 207 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 56 KiB |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="720" height="160" viewBox="0 0 720 160" fill="none">
|
||||
<g transform="translate(16,28)">
|
||||
<circle cx="28" cy="52" r="14" fill="#2dd4bf"/>
|
||||
<circle cx="84" cy="28" r="14" fill="#2dd4bf"/>
|
||||
<circle cx="84" cy="76" r="14" fill="#2dd4bf"/>
|
||||
<path d="M40 48 L72 32" stroke="#2dd4bf" stroke-width="8" stroke-linecap="round"/>
|
||||
<path d="M40 56 L72 72" stroke="#2dd4bf" stroke-width="8" stroke-linecap="round"/>
|
||||
</g>
|
||||
<text x="140" y="102" font-family="Avenir Next, Segoe UI, Helvetica Neue, sans-serif"
|
||||
font-size="72" font-weight="700" fill="#0c0c10" letter-spacing="-1.5">Bridge</text>
|
||||
<text x="370" y="102" font-family="Avenir Next, Segoe UI, Helvetica Neue, sans-serif"
|
||||
font-size="72" font-weight="700" fill="#2dd4bf" letter-spacing="-1.5">Swarm</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 877 B |
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="720" height="160" viewBox="0 0 720 160" fill="none">
|
||||
<g transform="translate(16,28)">
|
||||
<circle cx="28" cy="52" r="14" fill="#2dd4bf"/>
|
||||
<circle cx="84" cy="28" r="14" fill="#2dd4bf"/>
|
||||
<circle cx="84" cy="76" r="14" fill="#2dd4bf"/>
|
||||
<path d="M40 48 L72 32" stroke="#2dd4bf" stroke-width="8" stroke-linecap="round"/>
|
||||
<path d="M40 56 L72 72" stroke="#2dd4bf" stroke-width="8" stroke-linecap="round"/>
|
||||
</g>
|
||||
<text x="140" y="102" font-family="Avenir Next, Segoe UI, Helvetica Neue, sans-serif"
|
||||
font-size="72" font-weight="700" fill="#ececf1" letter-spacing="-1.5">Bridge</text>
|
||||
<text x="370" y="102" font-family="Avenir Next, Segoe UI, Helvetica Neue, sans-serif"
|
||||
font-size="72" font-weight="700" fill="#2dd4bf" letter-spacing="-1.5">Swarm</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 877 B |
|
After Width: | Height: | Size: 531 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 95 KiB |
@@ -0,0 +1,4 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: https://bridgeswarm.dev/sitemap.xml
|
||||
@@ -0,0 +1,170 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#2dd4bf' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<title>Releases — BridgeSwarm</title>
|
||||
<meta name="description" content="BridgeSwarm release history: the rolling latest-main prerelease build and tagged versions, with download links for every platform, pulled live from Gitea.">
|
||||
<meta name="author" content="HoneyPeer, LLC">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/releases">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
<link rel="stylesheet" href="/src/styles/releases.css">
|
||||
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png">
|
||||
<link rel="shortcut icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf">
|
||||
<meta name="msapplication-TileImage" content="/assets/favicons/mstile-150x150.png">
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Releases — BridgeSwarm">
|
||||
<meta property="og:description" content="Rolling latest-main builds and tagged versions of BridgeSwarm, with download links for macOS, Linux, and Windows.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/releases">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Releases — BridgeSwarm">
|
||||
<meta name="twitter:description" content="Rolling latest-main builds and tagged versions of BridgeSwarm, with download links for macOS, Linux, and Windows.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": "https://bridgeswarm.dev/#organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"logo": "https://bridgeswarm.dev/assets/logo/bridgeswarm-icon-512.png",
|
||||
"email": "[email protected]",
|
||||
"sameAs": ["https://git.ssh.surf/snxraven/BridgeSwarm"]
|
||||
},
|
||||
{
|
||||
"@type": "SoftwareApplication",
|
||||
"@id": "https://bridgeswarm.dev/#software",
|
||||
"name": "BridgeSwarm",
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"operatingSystem": "macOS, Linux, Windows",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"publisher": { "@id": "https://bridgeswarm.dev/#organization" },
|
||||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
|
||||
"license": "https://www.gnu.org/licenses/agpl-3.0.html",
|
||||
"downloadUrl": "https://bridgeswarm.dev/download",
|
||||
"softwareVersion": "1.0.0",
|
||||
"description": "Brings the Hyperswarm P2P stack into desktop browsers via a Bare native messaging host."
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="page-releases">
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div class="bg-grid" aria-hidden="true"></div>
|
||||
|
||||
<div data-nav></div>
|
||||
|
||||
<main id="main">
|
||||
|
||||
<header class="page-hero">
|
||||
<div class="container">
|
||||
<p class="section-label" style="justify-content:center;">Releases</p>
|
||||
<h1>Release history</h1>
|
||||
<p class="lead">Every build is published to our self-hosted Gitea. <code>latest-main</code> is a rolling prerelease rebuilt on every push to <code>main</code>; tags like <code>v1.0.0</code> are stable, versioned releases.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="section section-sm" id="channels" aria-labelledby="channels-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal">
|
||||
<p class="section-label">Channels</p>
|
||||
<h2 id="channels-title">Release channels</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-2 reveal">
|
||||
<div class="card">
|
||||
<span class="badge">Rolling</span>
|
||||
<h3 style="margin-top:0.85rem;">latest-main</h3>
|
||||
<p>Rebuilt automatically on every push to <code>main</code>. This is what <code>web-installer.sh</code> and <code>install.ps1</code> pull from — always current, not guaranteed stable.</p>
|
||||
<p style="margin-top:0.75rem;"><a href="https://git.ssh.surf/snxraven/BridgeSwarm/releases/tag/latest-main">View on Gitea →</a></p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<span class="badge badge-info">Stable</span>
|
||||
<h3 style="margin-top:0.85rem;">Tagged versions</h3>
|
||||
<p>Pushing a <code>v*.*.*</code> tag cuts a versioned Gitea release with the same platform artifacts as the rolling build.</p>
|
||||
<p style="margin-top:0.75rem;"><a href="https://git.ssh.surf/snxraven/BridgeSwarm/releases">Browse all releases →</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section section-sm" id="release-history" aria-labelledby="release-history-title">
|
||||
<div class="container install-wide">
|
||||
<div class="section-head reveal" style="display:flex; align-items:flex-end; justify-content:space-between; gap:1rem; flex-wrap:wrap;">
|
||||
<div>
|
||||
<p class="section-label">Latest</p>
|
||||
<h2 id="release-history-title" style="margin:0;">Latest builds</h2>
|
||||
</div>
|
||||
<a class="btn btn-ghost btn-sm" href="https://git.ssh.surf/snxraven/BridgeSwarm/releases">All releases on Gitea →</a>
|
||||
</div>
|
||||
|
||||
<div id="release-list" class="release-list reveal" data-release-list aria-live="polite">
|
||||
<div class="release-skeleton" aria-hidden="true">
|
||||
<div class="card release-skeleton__card"></div>
|
||||
<div class="card release-skeleton__card"></div>
|
||||
<div class="card release-skeleton__card"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<noscript>
|
||||
<p class="lead">Enable JavaScript to see release cards here, or go straight to <a href="https://git.ssh.surf/snxraven/BridgeSwarm/releases">the release list on Gitea</a>.</p>
|
||||
</noscript>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta-band reveal">
|
||||
<div class="container">
|
||||
<div class="cta-card">
|
||||
<h2>Most people don't need this page</h2>
|
||||
<p class="lead">The one-line installer always grabs the current <code>latest-main</code> build for you.</p>
|
||||
<div class="cta-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/download">Install BridgeSwarm</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<div data-footer></div>
|
||||
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
<script type="module" src="/src/js/releases.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,428 @@
|
||||
/**
|
||||
* BridgeSwarm website server: static dist/ + Gitea releases API proxy + dynamic sitemap.
|
||||
*
|
||||
* Routes:
|
||||
* GET /sitemap.xml → Google-compatible sitemap (generated from dist/)
|
||||
* GET /api/releases → list releases
|
||||
* GET /api/releases/tags/:tag → single release by tag
|
||||
* GET /api/releases/latest → latest non-draft (or rolling if present)
|
||||
*
|
||||
* Env:
|
||||
* PORT (default 4174)
|
||||
* DIST (default ./dist)
|
||||
* SITE_ORIGIN (default https://bridgeswarm.dev)
|
||||
* GITEA_API (default https://git.ssh.surf/api/v1/repos/snxraven/BridgeSwarm)
|
||||
*/
|
||||
import http from 'node:http'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const PORT = Number(process.env.PORT || 4174)
|
||||
const DIST = path.resolve(process.env.DIST || path.join(__dirname, 'dist'))
|
||||
const SITE_ORIGIN = String(process.env.SITE_ORIGIN || 'https://bridgeswarm.dev').replace(
|
||||
/\/+$/,
|
||||
''
|
||||
)
|
||||
const GITEA_API =
|
||||
process.env.GITEA_API || 'https://git.ssh.surf/api/v1/repos/snxraven/BridgeSwarm'
|
||||
const GITEA_WEB =
|
||||
process.env.GITEA_WEB || 'https://git.ssh.surf/snxraven/BridgeSwarm'
|
||||
|
||||
/** Paths that must not appear in the public sitemap (noindex / redirect stubs). */
|
||||
const SITEMAP_EXCLUDE = new Set(['/legal/cookies'])
|
||||
|
||||
const MIME = {
|
||||
'.html': 'text/html; charset=utf-8',
|
||||
'.js': 'text/javascript; charset=utf-8',
|
||||
'.mjs': 'text/javascript; charset=utf-8',
|
||||
'.css': 'text/css; charset=utf-8',
|
||||
'.json': 'application/json; charset=utf-8',
|
||||
'.svg': 'image/svg+xml',
|
||||
'.png': 'image/png',
|
||||
'.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg',
|
||||
'.webp': 'image/webp',
|
||||
'.ico': 'image/x-icon',
|
||||
'.woff': 'font/woff',
|
||||
'.woff2': 'font/woff2',
|
||||
'.map': 'application/json',
|
||||
'.txt': 'text/plain; charset=utf-8',
|
||||
'.xml': 'application/xml; charset=utf-8',
|
||||
'.webmanifest': 'application/manifest+json',
|
||||
}
|
||||
|
||||
function send(res, status, body, headers = {}) {
|
||||
const buf = Buffer.isBuffer(body) ? body : Buffer.from(body ?? '')
|
||||
res.writeHead(status, {
|
||||
'Content-Length': buf.length,
|
||||
...headers,
|
||||
})
|
||||
res.end(buf)
|
||||
}
|
||||
|
||||
function sendJson(res, status, obj) {
|
||||
send(res, status, JSON.stringify(obj), {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Cache-Control': 'public, max-age=60',
|
||||
})
|
||||
}
|
||||
|
||||
async function proxyGitea(apiPath, search = '') {
|
||||
const url = `${GITEA_API}${apiPath}${search || ''}`
|
||||
const r = await fetch(url, {
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'bridgeswarm-website-releases/1.0',
|
||||
},
|
||||
})
|
||||
const text = await r.text()
|
||||
let data
|
||||
try {
|
||||
data = text ? JSON.parse(text) : null
|
||||
} catch {
|
||||
data = { message: text || 'Invalid JSON from Gitea' }
|
||||
}
|
||||
return { status: r.status, data, url }
|
||||
}
|
||||
|
||||
async function handleApi(req, res, url) {
|
||||
if (req.method === 'OPTIONS') {
|
||||
send(res, 204, '', {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
||||
sendJson(res, 405, { error: 'Method not allowed' })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// GET /api/releases
|
||||
if (url.pathname === '/api/releases' || url.pathname === '/api/releases/') {
|
||||
const qs = new URLSearchParams(url.search)
|
||||
if (!qs.has('limit')) qs.set('limit', '25')
|
||||
const { status, data } = await proxyGitea('/releases', `?${qs}`)
|
||||
// Annotate with canonical web links
|
||||
if (Array.isArray(data)) {
|
||||
for (const rel of data) {
|
||||
if (rel && !rel.html_url && rel.tag_name) {
|
||||
rel.html_url = `${GITEA_WEB}/releases/tag/${encodeURIComponent(rel.tag_name)}`
|
||||
}
|
||||
}
|
||||
}
|
||||
sendJson(res, status, {
|
||||
source: GITEA_WEB + '/releases',
|
||||
api: GITEA_API + '/releases',
|
||||
releases: data,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// GET /api/releases/latest
|
||||
if (url.pathname === '/api/releases/latest') {
|
||||
// Prefer rolling tag if present, else first non-draft
|
||||
const list = await proxyGitea('/releases', '?limit=50')
|
||||
if (!Array.isArray(list.data)) {
|
||||
sendJson(res, list.status, list.data)
|
||||
return
|
||||
}
|
||||
const rolling = list.data.find(
|
||||
(r) => (r.tag_name === 'rolling' || r.tag_name === 'latest-main') && !r.draft
|
||||
)
|
||||
const first = list.data.find((r) => !r.draft) || list.data[0]
|
||||
const pick = rolling || first
|
||||
if (!pick) {
|
||||
sendJson(res, 404, { error: 'No releases found' })
|
||||
return
|
||||
}
|
||||
sendJson(res, 200, {
|
||||
source: GITEA_WEB + '/releases',
|
||||
release: pick,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// GET /api/releases/tags/:tag
|
||||
const tagMatch = url.pathname.match(/^\/api\/releases\/tags\/([^/]+)\/?$/)
|
||||
if (tagMatch) {
|
||||
const tag = decodeURIComponent(tagMatch[1])
|
||||
const { status, data } = await proxyGitea(
|
||||
`/releases/tags/${encodeURIComponent(tag)}`
|
||||
)
|
||||
sendJson(res, status, {
|
||||
source: `${GITEA_WEB}/releases/tag/${encodeURIComponent(tag)}`,
|
||||
release: data,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
sendJson(res, 404, {
|
||||
error: 'Unknown API route',
|
||||
routes: [
|
||||
'GET /api/releases',
|
||||
'GET /api/releases/latest',
|
||||
'GET /api/releases/tags/:tag',
|
||||
],
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('[api]', err)
|
||||
sendJson(res, 502, {
|
||||
error: 'Failed to reach Gitea releases API',
|
||||
message: err?.message || String(err),
|
||||
upstream: GITEA_API,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function safeJoin(root, reqPath) {
|
||||
const decoded = decodeURIComponent(reqPath.split('?')[0])
|
||||
const cleaned = path.normalize(decoded).replace(/^(\.\.(\/|\\|$))+/, '')
|
||||
const full = path.join(root, cleaned)
|
||||
if (!full.startsWith(root)) return null
|
||||
return full
|
||||
}
|
||||
|
||||
function escapeXml(s) {
|
||||
return String(s)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
}
|
||||
|
||||
/** dist-relative path → public URL path (clean URLs used by the site). */
|
||||
function distHtmlToUrlPath(relPosix) {
|
||||
const rel = relPosix.replace(/\\/g, '/').replace(/^\//, '')
|
||||
if (rel === 'index.html') return '/'
|
||||
if (rel.endsWith('/index.html')) {
|
||||
return `/${rel.slice(0, -'index.html'.length)}`
|
||||
}
|
||||
if (rel.endsWith('.html')) return `/${rel.slice(0, -'.html'.length)}`
|
||||
return `/${rel}`
|
||||
}
|
||||
|
||||
function walkHtmlFiles(dir, baseRel = '') {
|
||||
/** @type {{ rel: string, abs: string, mtime: Date }[]} */
|
||||
const out = []
|
||||
let entries
|
||||
try {
|
||||
entries = fs.readdirSync(dir, { withFileTypes: true })
|
||||
} catch {
|
||||
return out
|
||||
}
|
||||
for (const ent of entries) {
|
||||
if (ent.name.startsWith('.')) continue
|
||||
if (ent.name === 'assets' || ent.name === 'node_modules') continue
|
||||
const abs = path.join(dir, ent.name)
|
||||
const rel = baseRel ? `${baseRel}/${ent.name}` : ent.name
|
||||
if (ent.isDirectory()) {
|
||||
out.push(...walkHtmlFiles(abs, rel))
|
||||
continue
|
||||
}
|
||||
if (ent.isFile() && ent.name.endsWith('.html')) {
|
||||
let mtime = new Date()
|
||||
try {
|
||||
mtime = fs.statSync(abs).mtime
|
||||
} catch {
|
||||
/* keep now */
|
||||
}
|
||||
out.push({ rel: rel.replace(/\\/g, '/'), abs, mtime })
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
function sitemapPriority(urlPath) {
|
||||
if (urlPath === '/') return '1.0'
|
||||
if (urlPath === '/download' || urlPath === '/releases') return '0.95'
|
||||
if (urlPath === '/learn/' || urlPath === '/docs/' || urlPath === '/use-cases/') return '0.9'
|
||||
if (urlPath === '/community') return '0.8'
|
||||
if (urlPath.startsWith('/docs/')) return '0.85'
|
||||
if (urlPath === '/legal/') return '0.5'
|
||||
if (urlPath.startsWith('/legal/')) return '0.4'
|
||||
return '0.7'
|
||||
}
|
||||
|
||||
function sitemapChangefreq(urlPath) {
|
||||
if (urlPath === '/releases') return 'daily'
|
||||
if (urlPath === '/' || urlPath === '/download' || urlPath.startsWith('/docs')) return 'weekly'
|
||||
if (urlPath.startsWith('/legal')) return 'yearly'
|
||||
return 'monthly'
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Google Search-compatible sitemap 0.9 document from dist HTML pages.
|
||||
* Strict sitemaps.org protocol only (loc, lastmod, changefreq, priority).
|
||||
* @see https://www.sitemaps.org/protocol.html
|
||||
* @see https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap
|
||||
*/
|
||||
function buildSitemapXml() {
|
||||
const pages = walkHtmlFiles(DIST)
|
||||
/** @type {Map<string, { loc: string, lastmod: string, changefreq: string, priority: string }>} */
|
||||
const byPath = new Map()
|
||||
|
||||
for (const page of pages) {
|
||||
const urlPath = distHtmlToUrlPath(page.rel)
|
||||
const excludeKey = urlPath.replace(/\/+$/, '') || '/'
|
||||
if (SITEMAP_EXCLUDE.has(excludeKey) || SITEMAP_EXCLUDE.has(urlPath)) continue
|
||||
|
||||
// W3C Datetime (date only is accepted by Google)
|
||||
const lastmod = page.mtime.toISOString().slice(0, 10)
|
||||
const existing = byPath.get(urlPath)
|
||||
if (existing && existing.lastmod >= lastmod) continue
|
||||
|
||||
// Absolute HTTPS loc only · required by the protocol
|
||||
const loc = SITE_ORIGIN + (urlPath === '/' ? '/' : urlPath)
|
||||
byPath.set(urlPath, {
|
||||
loc,
|
||||
lastmod,
|
||||
changefreq: sitemapChangefreq(urlPath),
|
||||
priority: sitemapPriority(urlPath),
|
||||
})
|
||||
}
|
||||
|
||||
const entries = [...byPath.values()].sort((a, b) => {
|
||||
if (a.loc === `${SITE_ORIGIN}/`) return -1
|
||||
if (b.loc === `${SITE_ORIGIN}/`) return 1
|
||||
return a.loc.localeCompare(b.loc)
|
||||
})
|
||||
|
||||
// One declaration + default namespace only (no xhtml extras · single-language site)
|
||||
const parts = [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
|
||||
]
|
||||
|
||||
for (const e of entries) {
|
||||
parts.push(
|
||||
' <url>',
|
||||
` <loc>${escapeXml(e.loc)}</loc>`,
|
||||
` <lastmod>${escapeXml(e.lastmod)}</lastmod>`,
|
||||
` <changefreq>${escapeXml(e.changefreq)}</changefreq>`,
|
||||
` <priority>${escapeXml(e.priority)}</priority>`,
|
||||
' </url>'
|
||||
)
|
||||
}
|
||||
|
||||
parts.push('</urlset>')
|
||||
// Trailing newline for POSIX-friendly files
|
||||
return parts.join('\n') + '\n'
|
||||
}
|
||||
|
||||
function serveSitemap(req, res) {
|
||||
try {
|
||||
const xml = buildSitemapXml()
|
||||
// text/xml is what Google documents for sitemaps; charset for clarity
|
||||
const headers = {
|
||||
'Content-Type': 'text/xml; charset=utf-8',
|
||||
'Cache-Control': 'public, max-age=300',
|
||||
}
|
||||
if (req.method === 'HEAD') {
|
||||
res.writeHead(200, {
|
||||
...headers,
|
||||
'Content-Length': Buffer.byteLength(xml, 'utf8'),
|
||||
})
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
send(res, 200, xml, headers)
|
||||
} catch (err) {
|
||||
console.error('[sitemap]', err)
|
||||
send(res, 500, 'Sitemap generation failed', {
|
||||
'Content-Type': 'text/plain; charset=utf-8',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function resolveStatic(urlPath) {
|
||||
let p = urlPath
|
||||
if (p.endsWith('/')) p += 'index.html'
|
||||
let file = safeJoin(DIST, p)
|
||||
if (!file) return null
|
||||
|
||||
if (existsFile(file)) return file
|
||||
|
||||
// clean URLs: /releases → releases.html, /docs/foo → docs/foo.html
|
||||
if (!path.extname(file)) {
|
||||
const asHtml = file + '.html'
|
||||
if (existsFile(asHtml)) return asHtml
|
||||
const asIndex = path.join(file, 'index.html')
|
||||
if (existsFile(asIndex)) return asIndex
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function existsFile(f) {
|
||||
try {
|
||||
return fs.statSync(f).isFile()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function serveStatic(req, res, url) {
|
||||
const file = resolveStatic(url.pathname === '/' ? '/index.html' : url.pathname)
|
||||
if (!file) {
|
||||
send(res, 404, 'Not found', { 'Content-Type': 'text/plain; charset=utf-8' })
|
||||
return
|
||||
}
|
||||
const ext = path.extname(file).toLowerCase()
|
||||
const type = MIME[ext] || 'application/octet-stream'
|
||||
const stream = fs.createReadStream(file)
|
||||
res.writeHead(200, {
|
||||
'Content-Type': type,
|
||||
'Cache-Control': ext === '.html' ? 'no-cache' : 'public, max-age=3600',
|
||||
})
|
||||
if (req.method === 'HEAD') {
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
stream.pipe(res)
|
||||
stream.on('error', () => {
|
||||
if (!res.headersSent) send(res, 500, 'Read error')
|
||||
else res.end()
|
||||
})
|
||||
}
|
||||
|
||||
const server = http.createServer(async (req, res) => {
|
||||
const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`)
|
||||
|
||||
// Health
|
||||
if (url.pathname === '/api/health') {
|
||||
sendJson(res, 200, { ok: true, gitea: GITEA_API, site: SITE_ORIGIN })
|
||||
return
|
||||
}
|
||||
|
||||
if (url.pathname.startsWith('/api/')) {
|
||||
await handleApi(req, res, url)
|
||||
return
|
||||
}
|
||||
|
||||
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
||||
send(res, 405, 'Method not allowed', { 'Content-Type': 'text/plain' })
|
||||
return
|
||||
}
|
||||
|
||||
// Dynamic sitemap (overrides any static dist/sitemap.xml)
|
||||
if (url.pathname === '/sitemap.xml' || url.pathname === '/sitemap.xml/') {
|
||||
serveSitemap(req, res)
|
||||
return
|
||||
}
|
||||
|
||||
serveStatic(req, res, url)
|
||||
})
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`[bridgeswarm-website] http://127.0.0.1:${PORT}`)
|
||||
console.log(`[bridgeswarm-website] dist=${DIST}`)
|
||||
console.log(`[bridgeswarm-website] origin=${SITE_ORIGIN}`)
|
||||
console.log(`[bridgeswarm-website] gitea=${GITEA_API}`)
|
||||
console.log(`[bridgeswarm-website] sitemap=/sitemap.xml releases=/releases api=/api/releases`)
|
||||
})
|
||||
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
* BridgeSwarm home page: hero swarm-mesh animation, install tabs, stat count-up.
|
||||
* Kept intentionally tasteful — a handful of purposeful motions, nothing busy.
|
||||
*/
|
||||
|
||||
const REDUCED_MOTION = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
|
||||
/**
|
||||
* Read a CSS custom property from :root, with fallback.
|
||||
* @param {string} name
|
||||
* @param {string} fallback
|
||||
*/
|
||||
function cssVar(name, fallback) {
|
||||
const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim()
|
||||
return v || fallback
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hex color (#rrggbb) to an "r, g, b" string for use in rgba().
|
||||
* @param {string} hex
|
||||
*/
|
||||
function hexToRgb(hex) {
|
||||
const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex.trim())
|
||||
if (!m) return '45, 212, 191'
|
||||
return `${parseInt(m[1], 16)}, ${parseInt(m[2], 16)}, ${parseInt(m[3], 16)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtle animated swarm mesh: a field of drifting nodes that connect with
|
||||
* faint lines when close together, occasionally pulsing — evokes P2P peers
|
||||
* discovering one another. Pauses off-screen and on tab blur; respects
|
||||
* prefers-reduced-motion (renders one static frame instead of animating).
|
||||
*/
|
||||
function initHeroMesh() {
|
||||
const canvas = document.querySelector('.hero-canvas')
|
||||
if (!canvas || !(canvas instanceof HTMLCanvasElement)) return
|
||||
const ctx = canvas.getContext('2d')
|
||||
if (!ctx) return
|
||||
|
||||
let width = 0
|
||||
let height = 0
|
||||
let dpr = Math.min(window.devicePixelRatio || 1, 2)
|
||||
/** @type {{x:number,y:number,vx:number,vy:number,r:number,pulse:number,pulseSpeed:number}[]} */
|
||||
let nodes = []
|
||||
let accentRgb = hexToRgb(cssVar('--accent', '#2dd4bf'))
|
||||
let infoRgb = hexToRgb(cssVar('--info', '#60a5fa'))
|
||||
let running = false
|
||||
let rafId = 0
|
||||
|
||||
const NODE_COUNT_PER_100K_PX = 1.1
|
||||
const MAX_LINK_DIST = 150
|
||||
const MAX_NODES = 90
|
||||
|
||||
function syncColors() {
|
||||
accentRgb = hexToRgb(cssVar('--accent', '#2dd4bf'))
|
||||
infoRgb = hexToRgb(cssVar('--info', '#60a5fa'))
|
||||
}
|
||||
|
||||
function makeNodes() {
|
||||
const area = width * height
|
||||
const count = Math.max(24, Math.min(MAX_NODES, Math.round((area / 100000) * NODE_COUNT_PER_100K_PX)))
|
||||
nodes = Array.from({ length: count }, () => ({
|
||||
x: Math.random() * width,
|
||||
y: Math.random() * height,
|
||||
vx: (Math.random() - 0.5) * 0.18,
|
||||
vy: (Math.random() - 0.5) * 0.18,
|
||||
r: 1.1 + Math.random() * 1.6,
|
||||
pulse: Math.random() * Math.PI * 2,
|
||||
pulseSpeed: 0.006 + Math.random() * 0.01,
|
||||
}))
|
||||
}
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
width = Math.max(1, Math.round(rect.width))
|
||||
height = Math.max(1, Math.round(rect.height))
|
||||
dpr = Math.min(window.devicePixelRatio || 1, 2)
|
||||
canvas.width = Math.round(width * dpr)
|
||||
canvas.height = Math.round(height * dpr)
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
|
||||
makeNodes()
|
||||
}
|
||||
|
||||
function step() {
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
|
||||
// Update + draw links first (so nodes sit on top)
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const a = nodes[i]
|
||||
a.x += a.vx
|
||||
a.y += a.vy
|
||||
a.pulse += a.pulseSpeed
|
||||
|
||||
if (a.x < -20) a.x = width + 20
|
||||
if (a.x > width + 20) a.x = -20
|
||||
if (a.y < -20) a.y = height + 20
|
||||
if (a.y > height + 20) a.y = -20
|
||||
|
||||
for (let j = i + 1; j < nodes.length; j++) {
|
||||
const b = nodes[j]
|
||||
const dx = a.x - b.x
|
||||
const dy = a.y - b.y
|
||||
const dist = Math.hypot(dx, dy)
|
||||
if (dist < MAX_LINK_DIST) {
|
||||
const alpha = (1 - dist / MAX_LINK_DIST) * 0.22
|
||||
ctx.strokeStyle = `rgba(${accentRgb}, ${alpha.toFixed(3)})`
|
||||
ctx.lineWidth = 1
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(a.x, a.y)
|
||||
ctx.lineTo(b.x, b.y)
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes on top, gently pulsing; every 5th node tinted with the info color
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const n = nodes[i]
|
||||
const pulseAlpha = 0.35 + Math.sin(n.pulse) * 0.25
|
||||
const rgb = i % 5 === 0 ? infoRgb : accentRgb
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = `rgba(${rgb}, ${Math.max(0.12, pulseAlpha).toFixed(3)})`
|
||||
ctx.arc(n.x, n.y, n.r + Math.sin(n.pulse) * 0.4, 0, Math.PI * 2)
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
rafId = window.requestAnimationFrame(step)
|
||||
}
|
||||
|
||||
function start() {
|
||||
if (running) return
|
||||
running = true
|
||||
rafId = window.requestAnimationFrame(step)
|
||||
}
|
||||
|
||||
function stop() {
|
||||
running = false
|
||||
if (rafId) window.cancelAnimationFrame(rafId)
|
||||
rafId = 0
|
||||
}
|
||||
|
||||
resize()
|
||||
|
||||
if (REDUCED_MOTION) {
|
||||
// Draw a single static frame — no animation loop.
|
||||
step()
|
||||
stop()
|
||||
window.addEventListener('resize', () => {
|
||||
resize()
|
||||
step()
|
||||
stop()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
start()
|
||||
|
||||
let resizeTimer = 0
|
||||
window.addEventListener('resize', () => {
|
||||
window.clearTimeout(resizeTimer)
|
||||
resizeTimer = window.setTimeout(resize, 120)
|
||||
})
|
||||
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.hidden) stop()
|
||||
else start()
|
||||
})
|
||||
|
||||
if ('IntersectionObserver' in window) {
|
||||
const io = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting && !document.hidden) start()
|
||||
else stop()
|
||||
}
|
||||
},
|
||||
{ threshold: 0.05 }
|
||||
)
|
||||
io.observe(canvas)
|
||||
}
|
||||
|
||||
window.addEventListener('bridgeswarm:theme', syncColors)
|
||||
}
|
||||
|
||||
/**
|
||||
* Install command tabs (macOS/Linux, Windows, from source, …).
|
||||
* Buttons: [data-install-tab="key"] · Panels: [data-install-panel="key"]
|
||||
*/
|
||||
function initInstallTabs() {
|
||||
const tabs = [...document.querySelectorAll('[data-install-tab]')]
|
||||
const panels = [...document.querySelectorAll('[data-install-panel]')]
|
||||
if (!tabs.length || !panels.length) return
|
||||
|
||||
const activate = (key) => {
|
||||
tabs.forEach((t) => t.classList.toggle('is-active', t.getAttribute('data-install-tab') === key))
|
||||
panels.forEach((p) =>
|
||||
p.classList.toggle('is-active', p.getAttribute('data-install-panel') === key)
|
||||
)
|
||||
}
|
||||
|
||||
tabs.forEach((tab) => {
|
||||
tab.addEventListener('click', () => activate(tab.getAttribute('data-install-tab')))
|
||||
})
|
||||
|
||||
const initial = tabs.find((t) => t.classList.contains('is-active')) || tabs[0]
|
||||
if (initial) activate(initial.getAttribute('data-install-tab'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Count-up animation for hero / stat numbers.
|
||||
* Usage: <strong data-count-to="5" data-count-suffix="">0</strong>
|
||||
* Triggers once, when the element scrolls into view.
|
||||
*/
|
||||
function initCountUp() {
|
||||
const els = [...document.querySelectorAll('[data-count-to]')]
|
||||
if (!els.length) return
|
||||
|
||||
const animate = (el) => {
|
||||
const to = Number(el.getAttribute('data-count-to') || '0')
|
||||
const suffix = el.getAttribute('data-count-suffix') || ''
|
||||
const decimals = Number(el.getAttribute('data-count-decimals') || '0')
|
||||
|
||||
if (REDUCED_MOTION || !Number.isFinite(to)) {
|
||||
el.textContent = `${to.toFixed(decimals)}${suffix}`
|
||||
return
|
||||
}
|
||||
|
||||
const duration = 1100
|
||||
const start = performance.now()
|
||||
const from = 0
|
||||
|
||||
const tick = (now) => {
|
||||
const t = Math.min(1, (now - start) / duration)
|
||||
// easeOutCubic
|
||||
const eased = 1 - Math.pow(1 - t, 3)
|
||||
const value = from + (to - from) * eased
|
||||
el.textContent = `${value.toFixed(decimals)}${suffix}`
|
||||
if (t < 1) window.requestAnimationFrame(tick)
|
||||
}
|
||||
window.requestAnimationFrame(tick)
|
||||
}
|
||||
|
||||
if (!('IntersectionObserver' in window)) {
|
||||
els.forEach(animate)
|
||||
return
|
||||
}
|
||||
|
||||
const io = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
animate(entry.target)
|
||||
io.unobserve(entry.target)
|
||||
}
|
||||
}
|
||||
},
|
||||
{ threshold: 0.5 }
|
||||
)
|
||||
els.forEach((el) => io.observe(el))
|
||||
}
|
||||
|
||||
function init() {
|
||||
initHeroMesh()
|
||||
initInstallTabs()
|
||||
initCountUp()
|
||||
}
|
||||
|
||||
export { init }
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init)
|
||||
@@ -0,0 +1,128 @@
|
||||
// Fetches release metadata for the /releases.html page and renders release
|
||||
// cards into [data-release-list]. Talks to a same-origin /api/releases
|
||||
// endpoint (a thin proxy in front of the Gitea releases API) so the page
|
||||
// never needs a Gitea token in the browser.
|
||||
//
|
||||
// Expected response shape (array, newest first):
|
||||
// [{
|
||||
// tag_name: 'latest-main' | 'v1.0.0',
|
||||
// name: 'latest-main' | 'v1.0.0',
|
||||
// prerelease: boolean,
|
||||
// published_at: '2026-07-20T12:00:00Z',
|
||||
// html_url: 'https://git.ssh.surf/snxraven/BridgeSwarm/releases/tag/...',
|
||||
// body: 'markdown changelog text',
|
||||
// assets: [{ name, browser_download_url, size }]
|
||||
// }]
|
||||
|
||||
const REPO_RELEASES_URL = 'https://git.ssh.surf/snxraven/BridgeSwarm/releases';
|
||||
const API_ENDPOINT = '/api/releases';
|
||||
|
||||
function formatDate(iso) {
|
||||
if (!iso) return '';
|
||||
try {
|
||||
return new Date(iso).toLocaleDateString(undefined, {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
});
|
||||
} catch (err) {
|
||||
return iso;
|
||||
}
|
||||
}
|
||||
|
||||
function formatBytes(bytes) {
|
||||
if (!Number.isFinite(bytes) || bytes <= 0) return '';
|
||||
const units = ['B', 'KB', 'MB', 'GB'];
|
||||
let value = bytes;
|
||||
let unit = 0;
|
||||
while (value >= 1024 && unit < units.length - 1) {
|
||||
value /= 1024;
|
||||
unit += 1;
|
||||
}
|
||||
return `${value.toFixed(unit === 0 ? 0 : 1)} ${units[unit]}`;
|
||||
}
|
||||
|
||||
function assetIcon(name) {
|
||||
if (/\.xpi$/i.test(name)) return 'Firefox';
|
||||
if (/\.zip$/i.test(name)) return 'Zip';
|
||||
if (/win32|\.exe$/i.test(name)) return 'Windows';
|
||||
if (/darwin/i.test(name)) return 'macOS';
|
||||
if (/linux/i.test(name)) return 'Linux';
|
||||
return 'File';
|
||||
}
|
||||
|
||||
function releaseCardHTML(release) {
|
||||
const tag = release.tag_name || release.name || 'unknown';
|
||||
const isRolling = tag === 'latest-main';
|
||||
const title = isRolling ? 'latest-main (rolling)' : tag;
|
||||
const dateLabel = formatDate(release.published_at || release.created_at);
|
||||
const assets = Array.isArray(release.assets) ? release.assets : [];
|
||||
|
||||
const assetsHTML = assets.length
|
||||
? assets
|
||||
.map(
|
||||
(asset) => `
|
||||
<a class="release-card__asset" href="${asset.browser_download_url}" rel="noopener">
|
||||
<span class="release-card__asset-kind">${assetIcon(asset.name)}</span>
|
||||
<span class="release-card__asset-name">${asset.name}</span>
|
||||
${asset.size ? `<span class="release-card__asset-size">${formatBytes(asset.size)}</span>` : ''}
|
||||
</a>`
|
||||
)
|
||||
.join('')
|
||||
: '<p class="release-card__no-assets">No downloadable assets on this release.</p>';
|
||||
|
||||
return `
|
||||
<article class="card release-card${isRolling ? ' release-card--rolling' : ''}">
|
||||
<header class="release-card__header">
|
||||
<h3 class="release-card__title">${title}</h3>
|
||||
${isRolling ? '<span class="badge">rolling</span>' : '<span class="badge badge-info">stable</span>'}
|
||||
</header>
|
||||
${dateLabel ? `<p class="release-card__date">${dateLabel}</p>` : ''}
|
||||
<div class="release-card__assets">${assetsHTML}</div>
|
||||
<a class="release-card__link" href="${release.html_url || REPO_RELEASES_URL}" rel="noopener">View on Gitea →</a>
|
||||
</article>`;
|
||||
}
|
||||
|
||||
function renderError(container) {
|
||||
container.innerHTML = `
|
||||
<div class="card release-empty">
|
||||
<p class="release-empty__title">Couldn't load releases from the API.</p>
|
||||
<p>Go straight to the source instead:</p>
|
||||
<a class="btn btn-secondary" href="${REPO_RELEASES_URL}" rel="noopener">Open releases on Gitea →</a>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function renderEmpty(container) {
|
||||
container.innerHTML = `
|
||||
<div class="card release-empty">
|
||||
<p class="release-empty__title">No releases published yet.</p>
|
||||
<a class="btn btn-secondary" href="${REPO_RELEASES_URL}" rel="noopener">Open releases on Gitea →</a>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
async function loadReleases() {
|
||||
const container = document.querySelector('[data-release-list]');
|
||||
if (!container) return;
|
||||
|
||||
try {
|
||||
const res = await fetch(API_ENDPOINT, { headers: { Accept: 'application/json' } });
|
||||
if (!res.ok) throw new Error(`releases API responded ${res.status}`);
|
||||
const releases = await res.json();
|
||||
|
||||
if (!Array.isArray(releases) || releases.length === 0) {
|
||||
renderEmpty(container);
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = releases.map(releaseCardHTML).join('');
|
||||
} catch (err) {
|
||||
console.warn('[bridgeswarm] failed to load /api/releases:', err);
|
||||
renderError(container);
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', loadReleases);
|
||||
} else {
|
||||
loadReleases();
|
||||
}
|
||||
@@ -0,0 +1,751 @@
|
||||
/**
|
||||
* BridgeSwarm site: shared chrome, nav, theme, reveal, code copy, mermaid, docs
|
||||
*/
|
||||
|
||||
const REPO = 'https://git.ssh.surf/snxraven/BridgeSwarm'
|
||||
const ROLLING_RELEASE = 'https://git.ssh.surf/snxraven/BridgeSwarm/releases/tag/latest-main'
|
||||
const RELEASES_PAGE = '/releases'
|
||||
const COMMUNITY_PAGE = '/community'
|
||||
const USE_CASES_PAGE = '/use-cases/'
|
||||
const LEARN_PAGE = '/learn/'
|
||||
|
||||
/** localStorage key for site color theme (dark | light) */
|
||||
const THEME_STORAGE_KEY = 'bridgeswarm.site.theme'
|
||||
|
||||
/**
|
||||
* @returns {'dark' | 'light'}
|
||||
*/
|
||||
function getStoredTheme() {
|
||||
try {
|
||||
const raw = localStorage.getItem(THEME_STORAGE_KEY)
|
||||
if (raw === 'light' || raw === 'dark') return raw
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return 'dark'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {'dark' | 'light'} theme
|
||||
*/
|
||||
function applyTheme(theme) {
|
||||
const t = theme === 'light' ? 'light' : 'dark'
|
||||
document.documentElement.setAttribute('data-theme', t)
|
||||
try {
|
||||
localStorage.setItem(THEME_STORAGE_KEY, t)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
// Browser chrome / PWA status bar
|
||||
const meta = document.querySelector('meta[name="theme-color"]')
|
||||
if (meta) {
|
||||
meta.setAttribute('content', t === 'light' ? '#f4f5f7' : '#0c0c10')
|
||||
}
|
||||
const tile = document.querySelector('meta[name="msapplication-TileColor"]')
|
||||
if (tile) {
|
||||
tile.setAttribute('content', t === 'light' ? '#f4f5f7' : '#141418')
|
||||
}
|
||||
// Sync toggle labels
|
||||
document.querySelectorAll('.theme-toggle').forEach((btn) => {
|
||||
const next = t === 'light' ? 'dark' : 'light'
|
||||
btn.setAttribute('aria-label', `Switch to ${next} mode`)
|
||||
btn.setAttribute('title', `Switch to ${next} mode`)
|
||||
btn.setAttribute('aria-pressed', t === 'light' ? 'true' : 'false')
|
||||
})
|
||||
// Notify optional listeners (mermaid re-theme, hero canvas, …)
|
||||
try {
|
||||
window.dispatchEvent(new CustomEvent('bridgeswarm:theme', { detail: { theme: t } }))
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
const cur = document.documentElement.getAttribute('data-theme') === 'light' ? 'light' : 'dark'
|
||||
applyTheme(cur === 'light' ? 'dark' : 'light')
|
||||
}
|
||||
|
||||
function initTheme() {
|
||||
// FOUC script may have already set data-theme; re-apply for meta + a11y
|
||||
applyTheme(getStoredTheme())
|
||||
document.querySelectorAll('.theme-toggle').forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
toggleTheme()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const THEME_TOGGLE_HTML = `
|
||||
<button type="button" class="theme-toggle" aria-label="Switch to light mode" title="Switch to light mode" aria-pressed="false">
|
||||
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="4"/>
|
||||
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
|
||||
</svg>
|
||||
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M21 14.5A8.5 8.5 0 1 1 9.5 3a7 7 0 0 0 11.5 11.5z"/>
|
||||
</svg>
|
||||
</button>`
|
||||
|
||||
function injectChrome() {
|
||||
const navHost = document.querySelector('[data-nav]')
|
||||
if (navHost) {
|
||||
navHost.outerHTML = `
|
||||
<header class="site-nav" id="site-nav">
|
||||
<div class="nav-inner">
|
||||
<a class="nav-brand" href="/" aria-label="BridgeSwarm home">
|
||||
<img
|
||||
class="nav-brand-logo"
|
||||
src="/assets/logo/bridgeswarm-icon-64.png"
|
||||
srcset="/assets/logo/bridgeswarm-icon-64.png 1x, /assets/logo/bridgeswarm-icon-128.png 2x"
|
||||
alt=""
|
||||
width="36"
|
||||
height="36"
|
||||
decoding="async"
|
||||
/>
|
||||
<span class="nav-brand-text">Bridge<span class="brand-accent">Swarm</span></span>
|
||||
</a>
|
||||
<button type="button" class="nav-toggle" aria-label="Menu" aria-expanded="false">☰</button>
|
||||
<ul class="nav-links">
|
||||
<li><a href="/#features">Features</a></li>
|
||||
<li><a href="${USE_CASES_PAGE}">Use cases</a></li>
|
||||
<li><a href="${LEARN_PAGE}">How it works</a></li>
|
||||
<li><a href="/docs/">Docs</a></li>
|
||||
<li><a href="/download">Download</a></li>
|
||||
<li><a href="${RELEASES_PAGE}">Releases</a></li>
|
||||
<li><a href="${COMMUNITY_PAGE}">Community</a></li>
|
||||
<li><a href="/legal/">Legal</a></li>
|
||||
<li><a href="${REPO}" target="_blank" rel="noopener">Source</a></li>
|
||||
</ul>
|
||||
<div class="nav-cta">
|
||||
${THEME_TOGGLE_HTML}
|
||||
<a class="btn btn-ghost btn-sm" href="/docs/quickstart">Quick start</a>
|
||||
<a class="btn btn-primary btn-sm" href="/download">Install</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>`
|
||||
}
|
||||
|
||||
const footHost = document.querySelector('[data-footer]')
|
||||
if (footHost) {
|
||||
footHost.outerHTML = `
|
||||
<footer class="site-footer">
|
||||
<div class="container-wide">
|
||||
<div class="footer-grid">
|
||||
<div class="footer-brand">
|
||||
<img src="/assets/logo/bridgeswarm-icon-64.png" alt="BridgeSwarm" width="40" height="40" />
|
||||
<p>A native bridge that brings the Hyperswarm P2P stack into ordinary desktop browsers. Owned & engineered by HoneyPeer, LLC.</p>
|
||||
<span class="badge">AGPL-3.0</span>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Product</h4>
|
||||
<a href="/#features">Features</a>
|
||||
<a href="${USE_CASES_PAGE}">Use cases</a>
|
||||
<a href="/download">Download</a>
|
||||
<a href="${RELEASES_PAGE}">Releases</a>
|
||||
<a href="${COMMUNITY_PAGE}">Community</a>
|
||||
<a href="${REPO}" target="_blank" rel="noopener">Source code</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Documentation</h4>
|
||||
<a href="${LEARN_PAGE}">How BridgeSwarm works</a>
|
||||
<a href="/docs/quickstart">Quick start</a>
|
||||
<a href="/docs/user-guide">User guide</a>
|
||||
<a href="/docs/developer-guide">Developer guide</a>
|
||||
<a href="/docs/architecture">Architecture</a>
|
||||
<a href="/docs/security">Security</a>
|
||||
</div>
|
||||
<div class="footer-col">
|
||||
<h4>Legal</h4>
|
||||
<a href="/legal/">Legal hub</a>
|
||||
<a href="/legal/terms">Terms of Service</a>
|
||||
<a href="/legal/privacy">Privacy Policy</a>
|
||||
<a href="/legal/eula">EULA</a>
|
||||
<a href="/legal/license">Open Source (AGPL-3.0)</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<span>© <span data-year></span> HoneyPeer, LLC · BridgeSwarm</span>
|
||||
<span>
|
||||
<a href="${COMMUNITY_PAGE}">Community</a> ·
|
||||
<a href="/legal/">Legal</a> ·
|
||||
<a href="/legal/privacy">Privacy</a> ·
|
||||
<a href="${REPO}" target="_blank" rel="noopener">Source</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>`
|
||||
}
|
||||
|
||||
const sideHost = document.querySelector('[data-docs-nav]')
|
||||
if (sideHost) {
|
||||
// Always root-absolute so /docs (no trailing slash) does not break relative links
|
||||
sideHost.innerHTML = `
|
||||
<a class="docs-sidebar-brand" href="/docs/">
|
||||
<span class="docs-sidebar-brand-text">
|
||||
<strong>BridgeSwarm</strong>
|
||||
<span>Documentation</span>
|
||||
</span>
|
||||
</a>
|
||||
<p class="docs-sidebar-title">Guides</p>
|
||||
<ul class="docs-nav">
|
||||
<li><a href="/docs/"><span class="nav-ico">◈</span> Overview</a></li>
|
||||
<li><a href="${LEARN_PAGE}"><span class="nav-ico">◎</span> How it works</a></li>
|
||||
<li><a href="/docs/quickstart"><span class="nav-ico">→</span> Quick start</a></li>
|
||||
<li><a href="/docs/user-guide"><span class="nav-ico">▤</span> User guide</a></li>
|
||||
<li><a href="/docs/architecture"><span class="nav-ico">⬡</span> Architecture</a></li>
|
||||
<li><a href="/docs/security"><span class="nav-ico">⛨</span> Security</a></li>
|
||||
</ul>
|
||||
<p class="docs-sidebar-title">Develop</p>
|
||||
<ul class="docs-nav">
|
||||
<li><a href="/docs/developer-guide"><span class="nav-ico">⌘</span> Developer guide</a></li>
|
||||
<li><a href="/docs/api"><span class="nav-ico">{ }</span> API reference</a></li>
|
||||
<li><a href="/docs/data"><span class="nav-ico">▦</span> Data API</a></li>
|
||||
<li><a href="/docs/protocols"><span class="nav-ico">⇄</span> Protocols</a></li>
|
||||
<li><a href="/docs/capabilities"><span class="nav-ico">✦</span> Capabilities</a></li>
|
||||
<li><a href="/docs/examples"><span class="nav-ico">◆</span> Examples</a></li>
|
||||
</ul>
|
||||
<p class="docs-sidebar-title">Project</p>
|
||||
<ul class="docs-nav">
|
||||
<li><a href="/docs/faq"><span class="nav-ico">?</span> FAQ</a></li>
|
||||
<li><a href="${RELEASES_PAGE}"><span class="nav-ico">↓</span> Releases</a></li>
|
||||
<li><a href="/download"><span class="nav-ico">⇩</span> Download</a></li>
|
||||
<li><a href="${COMMUNITY_PAGE}"><span class="nav-ico">◎</span> Community</a></li>
|
||||
<li><a href="/legal/"><span class="nav-ico">§</span> Legal</a></li>
|
||||
<li><a href="${REPO}" target="_blank" rel="noopener"><span class="nav-ico">⌥</span> Source</a></li>
|
||||
<li><a href="${ROLLING_RELEASE}" target="_blank" rel="noopener"><span class="nav-ico">★</span> Rolling on Gitea</a></li>
|
||||
</ul>`
|
||||
}
|
||||
|
||||
const legalHost = document.querySelector('[data-legal-nav]')
|
||||
if (legalHost) {
|
||||
legalHost.innerHTML = `
|
||||
<a class="docs-sidebar-brand" href="/legal/">
|
||||
<span class="docs-sidebar-brand-text">
|
||||
<strong>HoneyPeer, LLC</strong>
|
||||
<span>Legal</span>
|
||||
</span>
|
||||
</a>
|
||||
<p class="docs-sidebar-title">Agreements</p>
|
||||
<ul class="docs-nav">
|
||||
<li><a href="/legal/"><span class="nav-ico">◈</span> Overview</a></li>
|
||||
<li><a href="/legal/terms"><span class="nav-ico">§</span> Terms of Service</a></li>
|
||||
<li><a href="/legal/eula"><span class="nav-ico">▣</span> EULA</a></li>
|
||||
<li><a href="/legal/aup"><span class="nav-ico">✓</span> Acceptable Use</a></li>
|
||||
</ul>
|
||||
<p class="docs-sidebar-title">Privacy & data</p>
|
||||
<ul class="docs-nav">
|
||||
<li><a href="/legal/privacy"><span class="nav-ico">◉</span> Privacy & cookies</a></li>
|
||||
</ul>
|
||||
<p class="docs-sidebar-title">IP & open source</p>
|
||||
<ul class="docs-nav">
|
||||
<li><a href="/legal/license"><span class="nav-ico">⚖</span> AGPL-3.0 & notices</a></li>
|
||||
<li><a href="/legal/copyright"><span class="nav-ico">©</span> Copyright & DMCA</a></li>
|
||||
</ul>
|
||||
<p class="docs-sidebar-title">Risk & safety</p>
|
||||
<ul class="docs-nav">
|
||||
<li><a href="/legal/disclaimer"><span class="nav-ico">!</span> Disclaimer</a></li>
|
||||
<li><a href="/legal/security"><span class="nav-ico">⛨</span> Security policy</a></li>
|
||||
</ul>
|
||||
<p class="docs-sidebar-title">Product</p>
|
||||
<ul class="docs-nav">
|
||||
<li><a href="${LEARN_PAGE}"><span class="nav-ico">◎</span> How it works</a></li>
|
||||
<li><a href="/docs/"><span class="nav-ico">→</span> Documentation</a></li>
|
||||
<li><a href="${COMMUNITY_PAGE}"><span class="nav-ico">◎</span> Community</a></li>
|
||||
<li><a href="/download"><span class="nav-ico">⇩</span> Download</a></li>
|
||||
</ul>`
|
||||
}
|
||||
}
|
||||
|
||||
function ensureBackdrop(className) {
|
||||
let el = document.querySelector(`.${className}`)
|
||||
if (!el) {
|
||||
el = document.createElement('button')
|
||||
el.type = 'button'
|
||||
el.className = className
|
||||
el.setAttribute('aria-label', 'Close menu')
|
||||
document.body.appendChild(el)
|
||||
}
|
||||
return el
|
||||
}
|
||||
|
||||
function setNavOpen(nav, toggle, open) {
|
||||
nav.classList.toggle('open', open)
|
||||
toggle?.setAttribute('aria-expanded', open ? 'true' : 'false')
|
||||
document.body.classList.toggle('nav-open', open)
|
||||
const backdrop = ensureBackdrop('nav-backdrop')
|
||||
backdrop.classList.toggle('is-visible', open)
|
||||
}
|
||||
|
||||
function initNav() {
|
||||
const nav = document.querySelector('.site-nav')
|
||||
const toggle = document.querySelector('.nav-toggle')
|
||||
if (!nav) return
|
||||
|
||||
const onScroll = () => {
|
||||
nav.classList.toggle('scrolled', window.scrollY > 12 || nav.classList.contains('open'))
|
||||
}
|
||||
onScroll()
|
||||
window.addEventListener('scroll', onScroll, { passive: true })
|
||||
|
||||
const backdrop = ensureBackdrop('nav-backdrop')
|
||||
backdrop.addEventListener('click', () => setNavOpen(nav, toggle, false))
|
||||
|
||||
if (toggle) {
|
||||
toggle.addEventListener('click', () => {
|
||||
const open = !nav.classList.contains('open')
|
||||
setNavOpen(nav, toggle, open)
|
||||
onScroll()
|
||||
})
|
||||
}
|
||||
|
||||
// Close mobile menu when a link is followed
|
||||
nav.querySelectorAll('a').forEach((a) => {
|
||||
a.addEventListener('click', () => setNavOpen(nav, toggle, false))
|
||||
})
|
||||
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && nav.classList.contains('open')) {
|
||||
setNavOpen(nav, toggle, false)
|
||||
}
|
||||
})
|
||||
|
||||
// Active link by path (+ hash for homepage section links)
|
||||
const normalize = (p) => {
|
||||
let s = (p || '/').replace(/\/index\.html$/i, '').replace(/\.html$/i, '')
|
||||
if (s.length > 1) s = s.replace(/\/$/, '')
|
||||
return s || '/'
|
||||
}
|
||||
|
||||
const syncActiveNav = () => {
|
||||
const path = normalize(location.pathname)
|
||||
const hash = location.hash || ''
|
||||
|
||||
document.querySelectorAll('.nav-links a, .docs-nav a, .docs-sidebar-brand').forEach((a) => {
|
||||
a.classList.remove('active')
|
||||
try {
|
||||
const url = new URL(a.href, location.origin)
|
||||
const target = normalize(url.pathname)
|
||||
const linkHash = url.hash || ''
|
||||
|
||||
// Docs sidebar / brand: exact path only
|
||||
if (a.closest('.docs-nav') || a.classList.contains('docs-sidebar-brand')) {
|
||||
if (path === target) a.classList.add('active')
|
||||
return
|
||||
}
|
||||
|
||||
// Top nav section links (e.g. /#features): only when hash matches
|
||||
if (linkHash) {
|
||||
if (path === target && hash === linkHash) a.classList.add('active')
|
||||
return
|
||||
}
|
||||
|
||||
// Full-page links (Docs, Download, Releases, Legal, …)
|
||||
if (path === target) {
|
||||
a.classList.add('active')
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
syncActiveNav()
|
||||
window.addEventListener('hashchange', syncActiveNav)
|
||||
}
|
||||
|
||||
function initReveal() {
|
||||
const els = document.querySelectorAll('.reveal')
|
||||
if (!els.length || !('IntersectionObserver' in window)) {
|
||||
els.forEach((el) => el.classList.add('visible'))
|
||||
return
|
||||
}
|
||||
const io = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const e of entries) {
|
||||
if (e.isIntersecting) {
|
||||
e.target.classList.add('visible')
|
||||
io.unobserve(e.target)
|
||||
}
|
||||
}
|
||||
},
|
||||
{ threshold: 0.12, rootMargin: '0px 0px -40px 0px' }
|
||||
)
|
||||
els.forEach((el) => io.observe(el))
|
||||
}
|
||||
|
||||
function isMermaidBlock(el) {
|
||||
if (!el) return false
|
||||
if (el.classList?.contains('mermaid')) return true
|
||||
if (el.closest?.('.mermaid-wrap, .mermaid')) return true
|
||||
const code = el.tagName === 'CODE' ? el : el.querySelector?.('code')
|
||||
if (code?.classList?.contains('language-mermaid') || code?.classList?.contains('mermaid')) return true
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect mermaid diagram sources from the page and normalize to .mermaid nodes.
|
||||
* Supports:
|
||||
* <pre class="mermaid">…</pre>
|
||||
* <div class="mermaid">…</div>
|
||||
* <pre><code class="language-mermaid">…</code></pre>
|
||||
*/
|
||||
function collectMermaidNodes() {
|
||||
/** @type {HTMLElement[]} */
|
||||
const targets = []
|
||||
|
||||
document.querySelectorAll('pre > code.language-mermaid, pre > code.mermaid').forEach((code) => {
|
||||
const pre = code.parentElement
|
||||
if (!pre || pre.tagName !== 'PRE') return
|
||||
const div = document.createElement('div')
|
||||
div.className = 'mermaid'
|
||||
div.textContent = code.textContent || ''
|
||||
const wrap = document.createElement('div')
|
||||
wrap.className = 'mermaid-wrap'
|
||||
wrap.setAttribute('role', 'img')
|
||||
wrap.setAttribute('aria-label', 'Diagram')
|
||||
pre.replaceWith(wrap)
|
||||
wrap.appendChild(div)
|
||||
targets.push(div)
|
||||
})
|
||||
|
||||
document.querySelectorAll('pre.mermaid').forEach((pre) => {
|
||||
const div = document.createElement('div')
|
||||
div.className = 'mermaid'
|
||||
div.textContent = pre.textContent || ''
|
||||
const wrap = document.createElement('div')
|
||||
wrap.className = 'mermaid-wrap'
|
||||
wrap.setAttribute('role', 'img')
|
||||
wrap.setAttribute('aria-label', 'Diagram')
|
||||
pre.replaceWith(wrap)
|
||||
wrap.appendChild(div)
|
||||
targets.push(div)
|
||||
})
|
||||
|
||||
document.querySelectorAll('div.mermaid').forEach((div) => {
|
||||
if (div.closest('.mermaid-wrap')) {
|
||||
if (!targets.includes(div)) targets.push(div)
|
||||
return
|
||||
}
|
||||
if (!div.parentElement?.classList.contains('mermaid-wrap')) {
|
||||
const wrap = document.createElement('div')
|
||||
wrap.className = 'mermaid-wrap'
|
||||
wrap.setAttribute('role', 'img')
|
||||
wrap.setAttribute('aria-label', 'Diagram')
|
||||
div.parentNode.insertBefore(wrap, div)
|
||||
wrap.appendChild(div)
|
||||
}
|
||||
if (!targets.includes(div)) targets.push(div)
|
||||
})
|
||||
|
||||
return targets
|
||||
}
|
||||
|
||||
function mermaidThemeVariables(isLight) {
|
||||
if (isLight) {
|
||||
return {
|
||||
darkMode: false,
|
||||
background: '#ffffff',
|
||||
primaryColor: '#ccfbf1',
|
||||
primaryTextColor: '#101014',
|
||||
primaryBorderColor: '#0f766e',
|
||||
secondaryColor: '#f1f1f4',
|
||||
secondaryTextColor: '#35353f',
|
||||
secondaryBorderColor: '#d8d8de',
|
||||
tertiaryColor: '#e9eaee',
|
||||
tertiaryTextColor: '#35353f',
|
||||
tertiaryBorderColor: '#0f766e55',
|
||||
lineColor: '#0d9488',
|
||||
textColor: '#101014',
|
||||
mainBkg: '#f7f8fa',
|
||||
nodeBorder: '#0f766e',
|
||||
clusterBkg: '#f1f1f4',
|
||||
clusterBorder: '#0f766e55',
|
||||
titleColor: '#101014',
|
||||
edgeLabelBackground: '#ffffff',
|
||||
actorBkg: '#f7f8fa',
|
||||
actorBorder: '#0f766e',
|
||||
actorTextColor: '#101014',
|
||||
signalColor: '#0d9488',
|
||||
signalTextColor: '#101014',
|
||||
labelBoxBkgColor: '#f7f8fa',
|
||||
labelBoxBorderColor: '#0f766e',
|
||||
labelTextColor: '#101014',
|
||||
loopTextColor: '#35353f',
|
||||
noteBkgColor: '#ccfbf1',
|
||||
noteTextColor: '#101014',
|
||||
noteBorderColor: '#0f766e',
|
||||
activationBkgColor: '#99f6e4',
|
||||
sequenceNumberColor: '#04211e',
|
||||
}
|
||||
}
|
||||
return {
|
||||
darkMode: true,
|
||||
background: '#141418',
|
||||
primaryColor: '#134e4a',
|
||||
primaryTextColor: '#ececf1',
|
||||
primaryBorderColor: '#2dd4bf',
|
||||
secondaryColor: '#1e1e25',
|
||||
secondaryTextColor: '#c7c7d1',
|
||||
secondaryBorderColor: '#33333c',
|
||||
tertiaryColor: '#1a1a20',
|
||||
tertiaryTextColor: '#c7c7d1',
|
||||
tertiaryBorderColor: '#2dd4bf55',
|
||||
lineColor: '#5eead4',
|
||||
textColor: '#ececf1',
|
||||
mainBkg: '#1e1e25',
|
||||
nodeBorder: '#2dd4bf',
|
||||
clusterBkg: '#141418',
|
||||
clusterBorder: '#2dd4bf55',
|
||||
titleColor: '#ececf1',
|
||||
edgeLabelBackground: '#141418',
|
||||
actorBkg: '#1e1e25',
|
||||
actorBorder: '#2dd4bf',
|
||||
actorTextColor: '#ececf1',
|
||||
signalColor: '#5eead4',
|
||||
signalTextColor: '#ececf1',
|
||||
labelBoxBkgColor: '#1e1e25',
|
||||
labelBoxBorderColor: '#2dd4bf',
|
||||
labelTextColor: '#ececf1',
|
||||
loopTextColor: '#c7c7d1',
|
||||
noteBkgColor: '#134e4a',
|
||||
noteTextColor: '#ececf1',
|
||||
noteBorderColor: '#2dd4bf',
|
||||
activationBkgColor: '#0f766e',
|
||||
sequenceNumberColor: '#04211e',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy-load mermaid and render diagrams (theme matched to site dark/light).
|
||||
*/
|
||||
async function initMermaid() {
|
||||
const nodes = collectMermaidNodes()
|
||||
if (!nodes.length) return
|
||||
|
||||
const isLight = document.documentElement.getAttribute('data-theme') === 'light'
|
||||
|
||||
try {
|
||||
const { default: mermaid } = await import('mermaid')
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
securityLevel: 'strict',
|
||||
theme: isLight ? 'base' : 'dark',
|
||||
fontFamily: 'DM Sans, system-ui, sans-serif',
|
||||
themeVariables: mermaidThemeVariables(isLight),
|
||||
flowchart: {
|
||||
curve: 'basis',
|
||||
padding: 16,
|
||||
htmlLabels: true,
|
||||
useMaxWidth: true,
|
||||
},
|
||||
sequence: {
|
||||
useMaxWidth: true,
|
||||
mirrorActors: false,
|
||||
bottomMarginAdj: 8,
|
||||
},
|
||||
})
|
||||
|
||||
// Stash diagram source so theme switches can re-render
|
||||
nodes.forEach((n) => {
|
||||
if (!n.getAttribute('data-mermaid-src')) {
|
||||
n.setAttribute('data-mermaid-src', n.textContent || '')
|
||||
}
|
||||
})
|
||||
|
||||
await mermaid.run({ nodes, suppressErrors: false })
|
||||
nodes.forEach((n) => {
|
||||
const wrap = n.closest('.mermaid-wrap')
|
||||
if (wrap) wrap.classList.add('mermaid-wrap--ready')
|
||||
})
|
||||
} catch (err) {
|
||||
console.warn('[bridgeswarm] mermaid render failed', err)
|
||||
nodes.forEach((n) => {
|
||||
const wrap = n.closest('.mermaid-wrap') || n
|
||||
wrap.classList?.add('mermaid-wrap--error')
|
||||
if (!wrap.querySelector?.('.mermaid-error-msg')) {
|
||||
const msg = document.createElement('p')
|
||||
msg.className = 'mermaid-error-msg'
|
||||
msg.textContent = 'Diagram failed to render. Check Mermaid syntax.'
|
||||
wrap.appendChild?.(msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/** Soft reload of mermaid when theme flips (preserves source from data attribute). */
|
||||
function bindMermaidThemeReload() {
|
||||
window.addEventListener('bridgeswarm:theme', () => {
|
||||
document.querySelectorAll('.mermaid-wrap .mermaid, div.mermaid').forEach((node) => {
|
||||
const src = node.getAttribute('data-mermaid-src')
|
||||
if (!src || !String(src).trim()) return
|
||||
node.removeAttribute('data-processed')
|
||||
node.removeAttribute('data-mermaid-id')
|
||||
node.innerHTML = ''
|
||||
node.textContent = src
|
||||
const wrap = node.closest('.mermaid-wrap')
|
||||
wrap?.classList.remove('mermaid-wrap--ready', 'mermaid-wrap--error')
|
||||
wrap?.querySelector('.mermaid-error-msg')?.remove()
|
||||
})
|
||||
initMermaid().catch(() => {})
|
||||
})
|
||||
}
|
||||
|
||||
function initCodeCopy() {
|
||||
document.querySelectorAll('pre').forEach((pre) => {
|
||||
if (pre.closest('.code-block')) return
|
||||
if (isMermaidBlock(pre)) return
|
||||
const wrap = document.createElement('div')
|
||||
wrap.className = 'code-block'
|
||||
pre.parentNode.insertBefore(wrap, pre)
|
||||
wrap.appendChild(pre)
|
||||
|
||||
const btn = document.createElement('button')
|
||||
btn.type = 'button'
|
||||
btn.className = 'copy-btn'
|
||||
btn.textContent = 'Copy'
|
||||
btn.addEventListener('click', async () => {
|
||||
const text = pre.innerText
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
btn.textContent = 'Copied'
|
||||
btn.classList.add('copied')
|
||||
setTimeout(() => {
|
||||
btn.textContent = 'Copy'
|
||||
btn.classList.remove('copied')
|
||||
}, 1600)
|
||||
} catch {
|
||||
btn.textContent = 'Failed'
|
||||
}
|
||||
})
|
||||
wrap.appendChild(btn)
|
||||
})
|
||||
}
|
||||
|
||||
function setDocsSidebarOpen(sidebar, open) {
|
||||
sidebar.classList.toggle('open', open)
|
||||
document.body.classList.toggle('docs-sidebar-open', open)
|
||||
const backdrop = ensureBackdrop('docs-sidebar-backdrop')
|
||||
backdrop.classList.toggle('is-visible', open)
|
||||
}
|
||||
|
||||
function initDocsSidebar() {
|
||||
const sidebar = document.querySelector('.docs-sidebar')
|
||||
const toggle = document.querySelector('.docs-sidebar-toggle')
|
||||
if (!sidebar || !toggle) return
|
||||
|
||||
const backdrop = ensureBackdrop('docs-sidebar-backdrop')
|
||||
backdrop.addEventListener('click', () => setDocsSidebarOpen(sidebar, false))
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
setDocsSidebarOpen(sidebar, !sidebar.classList.contains('open'))
|
||||
})
|
||||
|
||||
sidebar.querySelectorAll('a').forEach((a) => {
|
||||
a.addEventListener('click', () => setDocsSidebarOpen(sidebar, false))
|
||||
})
|
||||
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && sidebar.classList.contains('open')) {
|
||||
setDocsSidebarOpen(sidebar, false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** Mark active legal / docs nav items (exact path). */
|
||||
function initLegalActiveNav() {
|
||||
const normalize = (p) => {
|
||||
let s = (p || '/').replace(/\/index\.html$/i, '').replace(/\.html$/i, '')
|
||||
if (s.length > 1) s = s.replace(/\/$/, '')
|
||||
return s || '/'
|
||||
}
|
||||
const path = normalize(location.pathname)
|
||||
document.querySelectorAll('.docs-nav a').forEach((a) => {
|
||||
try {
|
||||
const target = normalize(new URL(a.href, location.origin).pathname)
|
||||
if (path === target) a.classList.add('active')
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Docs / legal page polish: body class + breadcrumb.
|
||||
*/
|
||||
function initDocsPage() {
|
||||
const main = document.querySelector('.docs-main')
|
||||
const layout = document.querySelector('.docs-layout')
|
||||
if (!main || !layout) return
|
||||
|
||||
document.body.classList.add('is-docs')
|
||||
const isLegal = Boolean(layout.classList.contains('legal-layout') || location.pathname.includes('/legal'))
|
||||
if (isLegal) document.body.classList.add('is-legal')
|
||||
|
||||
if (main.querySelector('.docs-breadcrumb')) return
|
||||
|
||||
const h1 = main.querySelector(':scope > h1')
|
||||
if (!h1) return
|
||||
|
||||
const title = (h1.textContent || '').trim() || (isLegal ? 'Legal' : 'Docs')
|
||||
const path = location.pathname.replace(/\/$/, '') || '/'
|
||||
const isOverview = isLegal
|
||||
? /\/legal\/?(index\.html)?$/.test(path) || title === 'Legal'
|
||||
: /\/docs\/?(index\.html)?$/.test(path) || title === 'Documentation'
|
||||
|
||||
const crumb = document.createElement('nav')
|
||||
crumb.className = 'docs-breadcrumb'
|
||||
crumb.setAttribute('aria-label', 'Breadcrumb')
|
||||
|
||||
const escape = (s) =>
|
||||
String(s)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
|
||||
if (isLegal) {
|
||||
if (isOverview) {
|
||||
crumb.innerHTML = `<span class="docs-bc-current">Legal</span>`
|
||||
} else {
|
||||
crumb.innerHTML = `
|
||||
<a href="/legal/">Legal</a>
|
||||
<span class="docs-bc-sep" aria-hidden="true">/</span>
|
||||
<span class="docs-bc-current">${escape(title)}</span>`
|
||||
}
|
||||
} else if (isOverview) {
|
||||
crumb.innerHTML = `<span class="docs-bc-current">Documentation</span>`
|
||||
} else {
|
||||
crumb.innerHTML = `
|
||||
<a href="/docs/">Docs</a>
|
||||
<span class="docs-bc-sep" aria-hidden="true">/</span>
|
||||
<span class="docs-bc-current">${escape(title)}</span>`
|
||||
}
|
||||
|
||||
main.insertBefore(crumb, main.firstChild)
|
||||
}
|
||||
|
||||
function setYear() {
|
||||
document.querySelectorAll('[data-year]').forEach((el) => {
|
||||
el.textContent = String(new Date().getFullYear())
|
||||
})
|
||||
}
|
||||
|
||||
function init() {
|
||||
injectChrome()
|
||||
initTheme()
|
||||
initNav()
|
||||
initReveal()
|
||||
// Mermaid before code-copy so diagram blocks are not wrapped as copyable code
|
||||
initMermaid()
|
||||
bindMermaidThemeReload()
|
||||
initCodeCopy()
|
||||
initDocsSidebar()
|
||||
initDocsPage()
|
||||
initLegalActiveNav()
|
||||
setYear()
|
||||
}
|
||||
|
||||
export { init, THEME_STORAGE_KEY }
|
||||
|
||||
document.addEventListener('DOMContentLoaded', init)
|
||||
@@ -0,0 +1,21 @@
|
||||
/* Download page */
|
||||
.install-tabs { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 1rem 0 0.75rem; }
|
||||
.install-tab {
|
||||
border: 1px solid var(--border); background: var(--bg-elevated); color: var(--text-muted);
|
||||
border-radius: var(--radius-full); padding: 0.4rem 0.85rem; font-size: 0.8rem; font-weight: 600; cursor: pointer;
|
||||
}
|
||||
.install-tab[aria-selected="true"], .install-tab.active {
|
||||
background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent);
|
||||
}
|
||||
.install-panel[hidden] { display: none !important; }
|
||||
.download-steps { counter-reset: step; list-style: none; padding: 0; margin: 1.25rem 0; }
|
||||
.download-steps li {
|
||||
position: relative; padding: 0.85rem 0 0.85rem 3rem; border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.download-steps li::before {
|
||||
counter-increment: step; content: counter(step);
|
||||
position: absolute; left: 0; top: 0.85rem;
|
||||
width: 2rem; height: 2rem; border-radius: 50%;
|
||||
display: grid; place-items: center;
|
||||
background: var(--accent-dim); color: var(--accent); font-family: var(--mono); font-weight: 600; font-size: 0.85rem;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/* Download page */
|
||||
.install-tabs { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 1rem 0 0.75rem; }
|
||||
.install-tab {
|
||||
border: 1px solid var(--border); background: var(--bg-elevated); color: var(--text-muted);
|
||||
border-radius: var(--radius-full); padding: 0.4rem 0.85rem; font-size: 0.8rem; font-weight: 600; cursor: pointer;
|
||||
}
|
||||
.install-tab[aria-selected="true"], .install-tab.active {
|
||||
background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent);
|
||||
}
|
||||
.install-panel[hidden] { display: none !important; }
|
||||
.download-steps { counter-reset: step; list-style: none; padding: 0; margin: 1.25rem 0; }
|
||||
.download-steps li {
|
||||
position: relative; padding: 0.85rem 0 0.85rem 3rem; border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.download-steps li::before {
|
||||
counter-increment: step; content: counter(step);
|
||||
position: absolute; left: 0; top: 0.85rem;
|
||||
width: 2rem; height: 2rem; border-radius: 50%;
|
||||
display: grid; place-items: center;
|
||||
background: var(--accent-dim); color: var(--accent); font-family: var(--mono); font-weight: 600; font-size: 0.85rem;
|
||||
}
|
||||
@@ -0,0 +1,694 @@
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
BridgeSwarm · Home page
|
||||
Full-bleed hero (brand first, no inset cards) · use-case rails ·
|
||||
feature rows · architecture strip · quickstart · CTA
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
|
||||
/* ─── Hero (full-bleed, brand-first) ─── */
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: calc(var(--nav-h) + 3rem) 0 4rem;
|
||||
overflow: hidden;
|
||||
isolation: isolate;
|
||||
}
|
||||
|
||||
.hero-canvas {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.hero-veil {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
background:
|
||||
linear-gradient(180deg, transparent 0%, var(--bg-primary) 92%),
|
||||
radial-gradient(ellipse 60% 55% at 50% 30%, rgba(45, 212, 191, 0.1), transparent 60%);
|
||||
}
|
||||
|
||||
.hero-inner {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
padding: 0.42rem 0.9rem 0.42rem 0.5rem;
|
||||
background: rgba(45, 212, 191, 0.08);
|
||||
border: 1px solid var(--accent-border);
|
||||
border-radius: var(--radius-full);
|
||||
font-family: var(--mono);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.02em;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.hero-badge .dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 12px var(--accent-glow);
|
||||
animation: pulse-dot 2.2s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-dot {
|
||||
0%, 100% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.55; transform: scale(0.82); }
|
||||
}
|
||||
|
||||
.hero-brand-lockup {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1.1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.hero-brand-lockup img {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
max-width: 20ch;
|
||||
margin: 0 auto 1.5rem;
|
||||
}
|
||||
|
||||
.hero .lead {
|
||||
max-width: 56ch;
|
||||
margin: 0 auto 2.5rem;
|
||||
font-size: clamp(1.05rem, 2vw, 1.3rem);
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 0.9rem;
|
||||
margin-bottom: 3.5rem;
|
||||
}
|
||||
|
||||
.hero-stats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 2.5rem;
|
||||
padding-top: 2.25rem;
|
||||
border-top: 1px solid var(--border);
|
||||
max-width: 780px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.hero-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
min-width: 7rem;
|
||||
}
|
||||
|
||||
.hero-stat strong {
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.65rem;
|
||||
font-weight: 750;
|
||||
letter-spacing: -0.02em;
|
||||
background: linear-gradient(135deg, var(--text), var(--accent));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.hero-stat span {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-faint);
|
||||
}
|
||||
|
||||
.hero-scroll-cue {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 1.75rem;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
color: var(--text-faint);
|
||||
font-family: var(--mono);
|
||||
font-size: 0.68rem;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.hero-scroll-cue .cue-line {
|
||||
width: 1px;
|
||||
height: 28px;
|
||||
background: linear-gradient(180deg, var(--accent), transparent);
|
||||
animation: cue-pulse 2.4s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes cue-pulse {
|
||||
0%, 100% { opacity: 0.25; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* ─── Tech / protocol strip ─── */
|
||||
|
||||
.tech-strip {
|
||||
padding: 2rem 0 3rem;
|
||||
border-top: 1px solid var(--border);
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--bg-tertiary);
|
||||
}
|
||||
|
||||
.tech-strip-inner {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 1rem 2.5rem;
|
||||
}
|
||||
|
||||
.tech-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.55rem;
|
||||
color: var(--text-faint);
|
||||
font-family: var(--mono);
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.tech-item span {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
/* ─── Use-case rail (horizontal scroll) ─── */
|
||||
|
||||
.usecase-rail-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.usecase-rail {
|
||||
display: flex;
|
||||
gap: 1.1rem;
|
||||
overflow-x: auto;
|
||||
overflow-y: visible;
|
||||
padding: 0.5rem 0.25rem 1.5rem;
|
||||
margin: 0 -0.25rem;
|
||||
scroll-snap-type: x proximity;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(45, 212, 191, 0.35) transparent;
|
||||
}
|
||||
|
||||
.usecase-rail::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.usecase-rail::-webkit-scrollbar-thumb {
|
||||
background: rgba(45, 212, 191, 0.3);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.usecase-card {
|
||||
scroll-snap-align: start;
|
||||
flex: 0 0 auto;
|
||||
width: min(320px, 82vw);
|
||||
padding: 1.6rem 1.5rem;
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--border);
|
||||
background: linear-gradient(165deg, var(--bg-elevated), var(--bg-tertiary));
|
||||
transition: border-color 0.3s var(--ease), transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
|
||||
}
|
||||
|
||||
.usecase-card:hover {
|
||||
border-color: var(--accent-border);
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.usecase-card .usecase-icon {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 12px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: var(--accent-dim);
|
||||
border: 1px solid var(--accent-border);
|
||||
color: var(--accent);
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 1.1rem;
|
||||
}
|
||||
|
||||
.usecase-card:nth-child(3n+2) .usecase-icon {
|
||||
background: var(--info-dim);
|
||||
border-color: var(--info-border);
|
||||
color: var(--info);
|
||||
}
|
||||
|
||||
.usecase-card h3 {
|
||||
font-size: 1.05rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.usecase-card p {
|
||||
font-size: 0.88rem;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.usecase-card a.usecase-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
margin-top: 1rem;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* ─── Feature rows (alternating) ─── */
|
||||
|
||||
.feature-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3.5rem;
|
||||
align-items: center;
|
||||
margin-top: 4.5rem;
|
||||
}
|
||||
|
||||
.feature-row:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.feature-row.reverse {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.feature-row.reverse > * {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.feature-copy .section-label {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.feature-copy h2 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.feature-copy .lead {
|
||||
margin-bottom: 1.5rem;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.feature-list li {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.feature-list li::before {
|
||||
content: '';
|
||||
flex-shrink: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: 2px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent-dim);
|
||||
border: 1px solid var(--accent-border);
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%232dd4bf'%3E%3Cpath d='M6.5 11.2 3.3 8l1-1 2.2 2.2L11.7 4l1 1z'/%3E%3C/svg%3E");
|
||||
background-size: 12px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.feature-visual {
|
||||
position: relative;
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--border);
|
||||
background: linear-gradient(165deg, var(--bg-elevated), var(--bg-tertiary));
|
||||
padding: 2rem;
|
||||
min-height: 280px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.feature-visual::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: radial-gradient(ellipse 70% 60% at 30% 0%, rgba(45, 212, 191, 0.1), transparent 60%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.feature-visual pre {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* ─── Architecture strip ─── */
|
||||
|
||||
.arch-section {
|
||||
background:
|
||||
radial-gradient(ellipse 60% 50% at 50% 100%, rgba(45, 212, 191, 0.06), transparent),
|
||||
var(--bg-secondary);
|
||||
border-top: 1px solid var(--border);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.arch-diagram {
|
||||
margin-top: 2.5rem;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr) auto minmax(0, 1fr);
|
||||
gap: 1rem;
|
||||
align-items: stretch;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.arch-diagram > * {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.arch-node {
|
||||
background: linear-gradient(165deg, var(--bg-elevated), var(--bg-tertiary));
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 1.4rem 1.1rem;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.arch-node::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, var(--accent), transparent);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.arch-node h3 {
|
||||
font-size: 0.98rem;
|
||||
margin: 0.7rem 0 0.35rem;
|
||||
}
|
||||
|
||||
.arch-node p {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.arch-node .node-icon {
|
||||
width: 46px;
|
||||
height: 46px;
|
||||
margin: 0 auto;
|
||||
border-radius: 14px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: var(--accent-dim);
|
||||
border: 1px solid var(--accent-border);
|
||||
color: var(--accent);
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.arch-node.is-info .node-icon {
|
||||
background: var(--info-dim);
|
||||
border-color: var(--info-border);
|
||||
color: var(--info);
|
||||
}
|
||||
|
||||
.arch-arrow {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--accent);
|
||||
font-size: 0.66rem;
|
||||
font-family: var(--mono);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.03em;
|
||||
text-transform: uppercase;
|
||||
gap: 0.3rem;
|
||||
min-width: 40px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.arch-arrow svg {
|
||||
width: 32px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.arch-details {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 1.25rem;
|
||||
margin-top: 2.25rem;
|
||||
}
|
||||
|
||||
.arch-detail {
|
||||
padding: 1.4rem;
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg-elevated);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.arch-detail h4 {
|
||||
color: var(--accent);
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.arch-detail p {
|
||||
font-size: 0.86rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* ─── Quickstart install ─── */
|
||||
|
||||
.section#quickstart > .container {
|
||||
width: min(100% - 2rem, var(--max, 1200px));
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.install-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
margin: 0 auto 1.5rem;
|
||||
padding: 0.3rem;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
background: var(--bg-tertiary);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.install-tab {
|
||||
appearance: none;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
font: inherit;
|
||||
font-family: var(--mono);
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s, color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.install-tab:hover {
|
||||
color: var(--text);
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
.install-tab.is-active {
|
||||
color: var(--accent-on);
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
|
||||
box-shadow: 0 4px 16px var(--accent-glow);
|
||||
}
|
||||
|
||||
.install-card {
|
||||
max-width: min(var(--install-max, 720px), 100%);
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
overflow-x: clip;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.install-card .code-block,
|
||||
.install-card pre {
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
overflow-x: clip !important;
|
||||
white-space: pre-wrap !important;
|
||||
word-break: break-word;
|
||||
overflow-wrap: anywhere;
|
||||
font-size: clamp(0.78rem, 1.4vw, 0.88rem);
|
||||
}
|
||||
|
||||
.install-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.install-panel.is-active {
|
||||
display: block;
|
||||
animation: install-panel-in 0.35s var(--ease);
|
||||
}
|
||||
|
||||
@keyframes install-panel-in {
|
||||
from { opacity: 0; transform: translateY(8px); }
|
||||
to { opacity: 1; transform: none; }
|
||||
}
|
||||
|
||||
.quickstart-steps {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 1.1rem;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.quickstart-step {
|
||||
padding: 1.4rem 1.3rem;
|
||||
border-radius: var(--radius-lg);
|
||||
border: 1px solid var(--border);
|
||||
background: linear-gradient(165deg, var(--bg-elevated), var(--bg-tertiary));
|
||||
}
|
||||
|
||||
.quickstart-step .step-num {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 10px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
font-family: var(--mono);
|
||||
font-weight: 700;
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 0.85rem;
|
||||
background: var(--accent-dim);
|
||||
border: 1px solid var(--accent-border);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.quickstart-step h3 {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.quickstart-step p {
|
||||
font-size: 0.86rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* ─── Responsive ─── */
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
.feature-row,
|
||||
.feature-row.reverse {
|
||||
grid-template-columns: 1fr;
|
||||
direction: ltr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.arch-diagram {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.arch-arrow {
|
||||
flex-direction: row;
|
||||
transform: rotate(90deg);
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.arch-details {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.quickstart-steps {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.hero {
|
||||
padding: calc(var(--nav-h) + 1.75rem) 0 3rem;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.hero-brand-lockup img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.hero-stats {
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.tech-strip-inner {
|
||||
gap: 0.75rem 1.25rem;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.tech-item {
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.arch-details {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.usecase-card {
|
||||
width: min(280px, 78vw);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.hero-badge .dot,
|
||||
.hero-scroll-cue .cue-line {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
/* Learn long-form */
|
||||
.learn-hero { padding-bottom: 1.5rem; }
|
||||
.learn-toc { margin: 1.25rem 0 2rem; }
|
||||
@@ -0,0 +1,62 @@
|
||||
/* ─── Legal area (extends docs layout) ─── */
|
||||
|
||||
.legal-kicker {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
font-family: var(--mono);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 650;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent);
|
||||
margin: 0 0 0.75rem;
|
||||
}
|
||||
|
||||
.legal-updated {
|
||||
font-size: 0.88rem;
|
||||
color: var(--text-faint);
|
||||
margin: -0.5rem 0 1.5rem;
|
||||
}
|
||||
|
||||
.legal-main .docs-lead {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.legal-notice {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.legal-cards {
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
/* Entity table: first column as labels */
|
||||
.legal-main .table-wrap th[scope='row'] {
|
||||
width: 38%;
|
||||
text-transform: none;
|
||||
letter-spacing: -0.01em;
|
||||
font-size: 0.88rem;
|
||||
font-weight: 600;
|
||||
color: var(--text-muted);
|
||||
background: var(--bg-tertiary);
|
||||
}
|
||||
|
||||
.legal-layout .docs-sidebar-brand-text span {
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
/* Compact ordered legal sections */
|
||||
.legal-main h2 {
|
||||
margin-top: 2.25rem;
|
||||
}
|
||||
|
||||
.legal-main ol > li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* Legal hub overview cards keep the same visual weight as docs cards
|
||||
but read a touch more formal (square tag, no hover lift on tag). */
|
||||
.legal-main .docs-card .card-tag {
|
||||
border-radius: 6px;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Releases page */
|
||||
.releases-list { display: flex; flex-direction: column; gap: 1rem; margin-top: 1.25rem; }
|
||||
.releases-list .card { padding: 1.25rem 1.35rem; }
|
||||
.releases-list .card h3 { font-family: var(--font-display); font-size: 1.15rem; margin: 0 0 0.35rem; }
|
||||
.releases-list .card p { color: var(--text-muted); font-size: 0.9rem; margin: 0.35rem 0 0.85rem; }
|
||||
.releases-meta { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem; }
|
||||
.releases-assets { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.releases-empty, .releases-error { padding: 2rem 1rem; text-align: center; color: var(--text-muted); }
|
||||
.releases-loading { color: var(--text-muted); font-family: var(--mono); font-size: 0.85rem; }
|
||||
@@ -0,0 +1,394 @@
|
||||
/**
|
||||
* BridgeSwarm website — light theme surface overrides.
|
||||
* Applied when html[data-theme="light"]. Tokens live in global.css.
|
||||
* Covers hard-coded dark gradients / colors that don't route through vars.
|
||||
*/
|
||||
|
||||
html[data-theme='light'] body {
|
||||
background:
|
||||
radial-gradient(1100px 560px at 12% -10%, rgba(15, 118, 110, 0.05), transparent 55%),
|
||||
radial-gradient(900px 500px at 100% 0%, rgba(37, 99, 235, 0.035), transparent 50%),
|
||||
var(--bg-primary);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
html[data-theme='light'] ::selection {
|
||||
background: rgba(15, 118, 110, 0.16);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* ─── Ambient mesh ─── */
|
||||
html[data-theme='light'] .bg-mesh {
|
||||
background:
|
||||
radial-gradient(ellipse 70% 46% at 18% -8%, rgba(15, 118, 110, 0.08), transparent 55%),
|
||||
radial-gradient(ellipse 46% 42% at 88% 6%, rgba(37, 99, 235, 0.05), transparent 52%),
|
||||
radial-gradient(ellipse 50% 44% at 8% 66%, rgba(15, 118, 110, 0.04), transparent 55%),
|
||||
var(--bg-primary);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .bg-grid {
|
||||
opacity: 0.35;
|
||||
background-image:
|
||||
linear-gradient(60deg, rgba(16, 16, 20, 0.035) 1px, transparent 1px),
|
||||
linear-gradient(-60deg, rgba(16, 16, 20, 0.035) 1px, transparent 1px),
|
||||
linear-gradient(rgba(16, 16, 20, 0.03) 1px, transparent 1px);
|
||||
}
|
||||
|
||||
/* ─── Nav ─── */
|
||||
html[data-theme='light'] .site-nav.scrolled {
|
||||
background: #ffffff;
|
||||
border-bottom-color: var(--border);
|
||||
backdrop-filter: none;
|
||||
-webkit-backdrop-filter: none;
|
||||
box-shadow: 0 1px 0 rgba(16, 16, 20, 0.04);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .nav-links a:hover,
|
||||
html[data-theme='light'] .nav-links a.active {
|
||||
background: var(--bg-hover);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .nav-toggle {
|
||||
background: var(--bg-elevated);
|
||||
border-color: var(--border);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .site-nav.open,
|
||||
html[data-theme='light'] body.nav-open .site-nav {
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .nav-backdrop.is-visible,
|
||||
html[data-theme='light'] .docs-sidebar-backdrop.is-visible {
|
||||
background: rgba(16, 16, 20, 0.35);
|
||||
}
|
||||
|
||||
/* ─── Footer ─── */
|
||||
html[data-theme='light'] .site-footer {
|
||||
background: var(--bg-secondary);
|
||||
border-top-color: var(--border);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .badge {
|
||||
background: var(--accent-dim);
|
||||
color: var(--accent);
|
||||
border-color: var(--accent-border);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .badge-info {
|
||||
background: var(--info-dim);
|
||||
color: var(--info);
|
||||
border-color: var(--info-border);
|
||||
}
|
||||
|
||||
/* ─── Code / pre ─── */
|
||||
html[data-theme='light'] .code-block .copy-btn {
|
||||
background: var(--bg-elevated);
|
||||
border-color: var(--border);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .code-block .copy-btn:hover {
|
||||
color: var(--accent);
|
||||
border-color: var(--accent-border);
|
||||
background: var(--accent-dim);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .code-block .copy-btn.copied {
|
||||
color: var(--success);
|
||||
border-color: rgba(21, 128, 61, 0.35);
|
||||
}
|
||||
|
||||
html[data-theme='light'] pre,
|
||||
html[data-theme='light'] .code-block pre,
|
||||
html[data-theme='light'] .docs-main pre,
|
||||
html[data-theme='light'] .docs-main .code-block pre,
|
||||
html[data-theme='light'] .feature-visual pre {
|
||||
background: #f1f1f4 !important;
|
||||
border-color: var(--border) !important;
|
||||
color: #35353f !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] :not(pre) > code {
|
||||
background: rgba(15, 118, 110, 0.08);
|
||||
border-color: rgba(15, 118, 110, 0.2);
|
||||
color: #0f766e;
|
||||
}
|
||||
|
||||
/* ─── Cards ─── */
|
||||
html[data-theme='light'] .card,
|
||||
html[data-theme='light'] .docs-card,
|
||||
html[data-theme='light'] .usecase-card,
|
||||
html[data-theme='light'] .arch-node,
|
||||
html[data-theme='light'] .arch-detail,
|
||||
html[data-theme='light'] .feature-visual,
|
||||
html[data-theme='light'] .quickstart-step,
|
||||
html[data-theme='light'] .install-card {
|
||||
background: #ffffff !important;
|
||||
border-color: var(--border) !important;
|
||||
color: var(--text);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .card:hover,
|
||||
html[data-theme='light'] .docs-card:hover,
|
||||
html[data-theme='light'] .usecase-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
/* ─── Hero ─── */
|
||||
html[data-theme='light'] .hero-veil {
|
||||
background:
|
||||
linear-gradient(180deg, transparent 0%, var(--bg-primary) 92%),
|
||||
radial-gradient(ellipse 60% 55% at 50% 30%, rgba(15, 118, 110, 0.07), transparent 60%);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .hero-badge {
|
||||
background: rgba(15, 118, 110, 0.06);
|
||||
border-color: var(--accent-border);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .hero-canvas {
|
||||
opacity: 0.55;
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
|
||||
/* ─── Tech strip ─── */
|
||||
html[data-theme='light'] .tech-strip {
|
||||
background: #eef0f3 !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .tech-item {
|
||||
color: var(--text-muted) !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .tech-item span {
|
||||
background: var(--accent) !important;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* ─── Install tabs ─── */
|
||||
html[data-theme='light'] .install-tabs {
|
||||
background: #eef0f3 !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .install-tab {
|
||||
color: var(--text-muted) !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .install-tab:hover {
|
||||
color: var(--text) !important;
|
||||
background: rgba(16, 16, 20, 0.05) !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .install-tab.is-active {
|
||||
background: var(--accent) !important;
|
||||
color: #ffffff !important;
|
||||
box-shadow: 0 4px 14px rgba(15, 118, 110, 0.22);
|
||||
}
|
||||
|
||||
/* ─── CTA band ─── */
|
||||
html[data-theme='light'] .cta-card {
|
||||
background:
|
||||
radial-gradient(ellipse 80% 80% at 20% 0%, rgba(15, 118, 110, 0.1), transparent 55%),
|
||||
radial-gradient(ellipse 60% 60% at 90% 100%, rgba(37, 99, 235, 0.06), transparent 50%),
|
||||
linear-gradient(165deg, #ffffff, #f4f5f7) !important;
|
||||
border-color: var(--border) !important;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* ─── Docs layout ─── */
|
||||
html[data-theme='light'] .docs-sidebar {
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f7f8fa 100%) !important;
|
||||
border-color: var(--border) !important;
|
||||
box-shadow: 1px 0 0 var(--border);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-sidebar-brand,
|
||||
html[data-theme='light'] .docs-sidebar-title {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-sidebar-brand strong {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-nav a {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-nav a:hover,
|
||||
html[data-theme='light'] .docs-nav a.active {
|
||||
color: var(--text);
|
||||
background: var(--accent-dim);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-nav a.active::before {
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-main {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-main h1,
|
||||
html[data-theme='light'] .docs-main h2,
|
||||
html[data-theme='light'] .docs-main h3,
|
||||
html[data-theme='light'] .docs-main h4 {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-main a:not(.docs-card):not(.docs-pager a) {
|
||||
color: #0f766e !important;
|
||||
text-decoration-color: rgba(15, 118, 110, 0.35) !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-main a:not(.docs-card):not(.docs-pager a):hover {
|
||||
color: #0d9488 !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-main :not(pre) > code {
|
||||
background: rgba(15, 118, 110, 0.08) !important;
|
||||
border-color: rgba(15, 118, 110, 0.18) !important;
|
||||
color: #0f766e !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-breadcrumb {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-breadcrumb a {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-sidebar-toggle {
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
|
||||
border-color: var(--accent-border);
|
||||
color: #ffffff;
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
/* Docs tables */
|
||||
html[data-theme='light'] .docs-main table,
|
||||
html[data-theme='light'] .docs-main th,
|
||||
html[data-theme='light'] .docs-main td {
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-main th {
|
||||
background: #f1f1f4;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-main tr:nth-child(even) td {
|
||||
background: rgba(16, 16, 20, 0.02);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-main tr:hover td {
|
||||
background: rgba(15, 118, 110, 0.05);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .table-wrap,
|
||||
html[data-theme='light'] table,
|
||||
html[data-theme='light'] th,
|
||||
html[data-theme='light'] td {
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
html[data-theme='light'] th {
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* Docs pager */
|
||||
html[data-theme='light'] .docs-pager a {
|
||||
background: #ffffff !important;
|
||||
border-color: var(--border) !important;
|
||||
color: var(--text-muted) !important;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-pager a strong {
|
||||
color: var(--text) !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .docs-pager a:hover {
|
||||
border-color: rgba(15, 118, 110, 0.35) !important;
|
||||
background: rgba(15, 118, 110, 0.06) !important;
|
||||
color: var(--accent) !important;
|
||||
}
|
||||
|
||||
/* Callouts */
|
||||
html[data-theme='light'] .callout {
|
||||
background: #ffffff !important;
|
||||
border-color: var(--border) !important;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* TOC */
|
||||
html[data-theme='light'] .toc {
|
||||
background: #ffffff !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .toc a:hover {
|
||||
background: rgba(15, 118, 110, 0.06) !important;
|
||||
}
|
||||
|
||||
/* Mermaid */
|
||||
html[data-theme='light'] .mermaid-wrap {
|
||||
background: #ffffff !important;
|
||||
border-color: var(--border) !important;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .mermaid-wrap--error,
|
||||
html[data-theme='light'] .mermaid-error-msg {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
/* Gradient text stays vivid on light */
|
||||
html[data-theme='light'] .gradient-text {
|
||||
background: linear-gradient(135deg, #0d9488 0%, #0f766e 45%, #2563eb 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
html[data-theme='light'] .hero-stat strong {
|
||||
background: linear-gradient(135deg, var(--text), var(--accent));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
/* Form controls if any */
|
||||
html[data-theme='light'] input,
|
||||
html[data-theme='light'] select,
|
||||
html[data-theme='light'] textarea {
|
||||
background: var(--bg-elevated);
|
||||
border-color: var(--border);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
html[data-theme='light'] hr {
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
/* Mobile nav drawer */
|
||||
@media (max-width: 900px) {
|
||||
html[data-theme='light'] .site-nav .nav-links {
|
||||
background: var(--bg-secondary);
|
||||
border-color: var(--border);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
html[data-theme='light'] .site-nav .nav-cta {
|
||||
background: var(--bg-secondary);
|
||||
border-color: var(--border);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* Use cases */
|
||||
.uc-block { padding: 2.5rem 0; border-top: 1px solid var(--border); }
|
||||
.uc-block:first-of-type { border-top: 0; }
|
||||
.uc-meta { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.75rem 0 1rem; }
|
||||
@@ -0,0 +1,281 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#0c0c10">
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('bridgeswarm.site.theme');
|
||||
if (t !== 'light' && t !== 'dark') t = 'dark';
|
||||
document.documentElement.setAttribute('data-theme', t);
|
||||
var meta = document.querySelector('meta[name="theme-color"]');
|
||||
if (meta) meta.setAttribute('content', t === 'light' ? '#2dd4bf' : '#0c0c10');
|
||||
} catch (e) {
|
||||
document.documentElement.setAttribute('data-theme', 'dark');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<title>Use Cases — BridgeSwarm</title>
|
||||
<meta name="description" content="Eight things you can build with BridgeSwarm: P2P chat rooms, collaborative apps, data sync, live media, self-hosted web apps, live topic domains, firewall-controlled rooms, and developer tooling — with concrete APIs and runnable examples.">
|
||||
<meta name="author" content="HoneyPeer, LLC">
|
||||
<link rel="canonical" href="https://bridgeswarm.dev/use-cases/">
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Syne:wght@600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<link rel="stylesheet" href="/src/styles/global.css">
|
||||
<link rel="stylesheet" href="/src/styles/theme-light.css">
|
||||
<link rel="stylesheet" href="/src/styles/docs.css">
|
||||
<link rel="stylesheet" href="/src/styles/use-cases.css">
|
||||
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="48x48" href="/assets/favicons/favicon-48x48.png">
|
||||
<link rel="shortcut icon" href="/assets/favicons/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicons/apple-touch-icon.png">
|
||||
<link rel="manifest" href="/assets/favicons/site.webmanifest">
|
||||
<link rel="mask-icon" href="/assets/logo/bridgeswarm-wordmark.svg" color="#2dd4bf">
|
||||
<meta name="msapplication-TileImage" content="/assets/favicons/mstile-150x150.png">
|
||||
<meta name="msapplication-config" content="/assets/favicons/browserconfig.xml">
|
||||
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="BridgeSwarm">
|
||||
<meta property="og:title" content="Use Cases — BridgeSwarm">
|
||||
<meta property="og:description" content="P2P chat, collaborative apps, data sync, live media, self-hosted apps, live topic domains, firewall-controlled rooms, and developer tooling — with the actual BridgeSwarm APIs behind each one.">
|
||||
<meta property="og:url" content="https://bridgeswarm.dev/use-cases/">
|
||||
<meta property="og:image" content="https://bridgeswarm.dev/assets/brand/og-image.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="Use Cases — BridgeSwarm">
|
||||
<meta name="twitter:description" content="P2P chat, collaborative apps, data sync, live media, self-hosted apps, live topic domains, firewall-controlled rooms, and developer tooling.">
|
||||
<meta name="twitter:image" content="https://bridgeswarm.dev/assets/brand/twitter-card.png">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"@id": "https://bridgeswarm.dev/#organization",
|
||||
"name": "HoneyPeer, LLC",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"logo": "https://bridgeswarm.dev/assets/logo/bridgeswarm-icon-512.png",
|
||||
"email": "[email protected]",
|
||||
"sameAs": ["https://git.ssh.surf/snxraven/BridgeSwarm"]
|
||||
},
|
||||
{
|
||||
"@type": "SoftwareApplication",
|
||||
"@id": "https://bridgeswarm.dev/#software",
|
||||
"name": "BridgeSwarm",
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"operatingSystem": "macOS, Linux, Windows",
|
||||
"url": "https://bridgeswarm.dev/",
|
||||
"publisher": { "@id": "https://bridgeswarm.dev/#organization" },
|
||||
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
|
||||
"license": "https://www.gnu.org/licenses/agpl-3.0.html",
|
||||
"downloadUrl": "https://bridgeswarm.dev/download",
|
||||
"softwareVersion": "1.0.0",
|
||||
"description": "Brings the Hyperswarm P2P stack into desktop browsers via a Bare native messaging host."
|
||||
}
|
||||
]
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="page-use-cases">
|
||||
<div class="bg-mesh" aria-hidden="true"></div>
|
||||
<div class="bg-grid" aria-hidden="true"></div>
|
||||
|
||||
<div data-nav data-prefix="../"></div>
|
||||
|
||||
<main id="main">
|
||||
|
||||
<header class="page-hero">
|
||||
<div class="container">
|
||||
<p class="section-label" style="justify-content:center;">Use cases</p>
|
||||
<h1>What to build with BridgeSwarm</h1>
|
||||
<p class="lead">Every example below runs on the bundled demos server. <a href="/download">Install BridgeSwarm</a>, enable <strong>Examples server</strong> in Settings, and open <a href="http://127.0.0.1:4173/" target="_blank" rel="noopener">http://127.0.0.1:4173/</a> in two tabs.</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="jump-nav reveal" aria-label="Jump to use case">
|
||||
<div class="container jump-nav-inner">
|
||||
<a href="#chat">Chat rooms</a>
|
||||
<a href="#collab">Collaborative apps</a>
|
||||
<a href="#sync">Data sync</a>
|
||||
<a href="#live-media">Live media</a>
|
||||
<a href="#self-hosted">Self-hosted apps</a>
|
||||
<a href="#live-domains">Live topic domains</a>
|
||||
<a href="#firewall">Firewall rooms</a>
|
||||
<a href="#dev-tooling">Developer tooling</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container usecase-list">
|
||||
|
||||
<section class="usecase reveal" id="chat" aria-labelledby="chat-title">
|
||||
<div class="usecase-index">01</div>
|
||||
<div class="usecase-body">
|
||||
<h2 id="chat-title">P2P chat rooms</h2>
|
||||
<p class="usecase-lede">A topic is a room. Everyone who joins the same topic string finds each other through Hyperswarm and exchanges messages over direct, Noise-encrypted connections — no chat server, no message broker, no accounts.</p>
|
||||
<p>The <code>chat</code> example is a minimal single-file room: join a topic, broadcast text, render an inbox. <code>chat-advanced</code> builds rooms, presence, markdown rendering, emoji, and peer-to-peer file sharing on the same primitives.</p>
|
||||
<pre><code>const swarm = new BridgeSwarm({ appName: 'chat-demo' });
|
||||
await swarm.join('room:general');
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
conn.on('data', (data) => render(peerInfo.publicKey, data));
|
||||
});
|
||||
function broadcast(text) {
|
||||
for (const conn of swarm.connections()) conn.write(text);
|
||||
}</code></pre>
|
||||
<div class="usecase-links">
|
||||
<a class="btn btn-secondary" href="http://127.0.0.1:4173/chat/" target="_blank" rel="noopener">Try chat →</a>
|
||||
<a class="btn btn-ghost" href="http://127.0.0.1:4173/chat-advanced/" target="_blank" rel="noopener">Try chat-advanced →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="usecase reveal" id="collab" aria-labelledby="collab-title">
|
||||
<div class="usecase-index">02</div>
|
||||
<div class="usecase-body">
|
||||
<h2 id="collab-title">Collaborative apps</h2>
|
||||
<p class="usecase-lede">Anything that broadcasts small structured events to everyone in a session — cursors, strokes, edits — maps directly onto swarm connections. The <code>whiteboard</code> example is a shared canvas where every stroke is written to every connected peer as it happens.</p>
|
||||
<p>For richer protocols than "write JSON, parse JSON," attach <a href="/learn/#protomux-hrpc">Protomux</a> to the connection and define named message channels instead of hand-rolling a dispatch table.</p>
|
||||
<pre><code>swarm.on('connection', (conn) => {
|
||||
conn.on('data', (buf) => applyRemoteStroke(JSON.parse(buf)));
|
||||
});
|
||||
canvas.addEventListener('pointermove', (e) => {
|
||||
const stroke = strokeFrom(e);
|
||||
for (const conn of swarm.connections()) conn.write(JSON.stringify(stroke));
|
||||
});</code></pre>
|
||||
<div class="usecase-links">
|
||||
<a class="btn btn-secondary" href="http://127.0.0.1:4173/whiteboard/" target="_blank" rel="noopener">Try whiteboard →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="usecase reveal" id="sync" aria-labelledby="sync-title">
|
||||
<div class="usecase-index">03</div>
|
||||
<div class="usecase-body">
|
||||
<h2 id="sync-title">Data sync</h2>
|
||||
<p class="usecase-lede">When you don't want to hand-roll message protocols at all, let the host replicate structured storage directly. <code>swarm.setAutoReplicate({ swarmId, enabled: true })</code> takes over every new connection on a swarm for Hypercore replication — those sockets stop forwarding raw data to the page and instead keep a Hypercore (or Hyperbee/Hyperdrive built on one) in sync across every peer automatically.</p>
|
||||
<p>The <code>data-demo</code> example exercises Hyperbee, Hyperdrive, and Hyperdb directly through <code>BridgeSwarm.request</code>; <code>sync-demo</code> shows the auto-replicate path end to end.</p>
|
||||
<pre><code>await BridgeSwarm.request('beePut', { key: 'title', value: 'Q3 plan' });
|
||||
const doc = await BridgeSwarm.request('beeGet', { key: 'title' });
|
||||
|
||||
await swarm.setAutoReplicate({ enabled: true }); // new connections auto-sync</code></pre>
|
||||
<div class="usecase-links">
|
||||
<a class="btn btn-secondary" href="http://127.0.0.1:4173/data-demo/" target="_blank" rel="noopener">Try data-demo →</a>
|
||||
<a class="btn btn-ghost" href="http://127.0.0.1:4173/sync-demo/" target="_blank" rel="noopener">Try sync-demo →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="usecase reveal" id="live-media" aria-labelledby="live-media-title">
|
||||
<div class="usecase-index">04</div>
|
||||
<div class="usecase-body">
|
||||
<h2 id="live-media-title">Live media</h2>
|
||||
<p class="usecase-lede">The host's media capability pack wraps <code>bare-ffmpeg</code> for real encode work, including a <strong>live</strong> session mode: push captured frames in, get VP9/WebM segments out — to a Media Source Extensions player on the page, fanned out to swarm peers, or archived to disk, in any combination.</p>
|
||||
<pre><code>const live = BridgeSwarm.media.liveSession(videoEl);
|
||||
await live.start({ width: 640, height: 360, fps: 10, ingest: 'frames' });
|
||||
await live.pushFrame(canvas);
|
||||
await live.subscribe({ swarm: { connIds: [conn.connId] } }); // fan out to a peer
|
||||
await live.stop();</code></pre>
|
||||
<p>See <code>live-encode</code> for the host-encode → MSE pipeline, <code>media-demo</code> for batch probe/transform/transcode, and <code>clip-studio</code> for nearline recording workflows.</p>
|
||||
<div class="usecase-links">
|
||||
<a class="btn btn-secondary" href="http://127.0.0.1:4173/live-encode/" target="_blank" rel="noopener">Try live-encode →</a>
|
||||
<a class="btn btn-ghost" href="http://127.0.0.1:4173/media-demo/" target="_blank" rel="noopener">Try media-demo →</a>
|
||||
<a class="btn btn-ghost" href="http://127.0.0.1:4173/clip-studio/" target="_blank" rel="noopener">Try clip-studio →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="usecase reveal" id="self-hosted" aria-labelledby="self-hosted-title">
|
||||
<div class="usecase-index">05</div>
|
||||
<div class="usecase-body">
|
||||
<h2 id="self-hosted-title">Self-hosted web apps</h2>
|
||||
<p class="usecase-lede">The bundled demos server is itself proof of a pattern worth building on: the Bare host can run a small <code>bare-http1</code> static server on <code>127.0.0.1</code> and serve a full HTML/CSS/JS app with no cloud hosting step. Because the content script injects <code>window.BridgeSwarm</code> into pages served from real HTTP origins (not <code>file://</code>), an app served this way gets P2P networking for free — it's a normal page as far as the browser is concerned.</p>
|
||||
<p>This is the same mechanism the extension itself uses: toggle <strong>Examples server</strong> in Settings and the host starts serving on <code>127.0.0.1:4173</code> with no separate deploy step.</p>
|
||||
<pre><code>// extension -> host, on settings change
|
||||
examplesServer.start({ host: '127.0.0.1', port: 4173 })
|
||||
// host responds
|
||||
{ running: true, url: 'http://127.0.0.1:4173/' }</code></pre>
|
||||
<div class="usecase-links">
|
||||
<a class="btn btn-secondary" href="http://127.0.0.1:4173/" target="_blank" rel="noopener">Open the examples server →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="usecase reveal" id="live-domains" aria-labelledby="live-domains-title">
|
||||
<div class="usecase-index">06</div>
|
||||
<div class="usecase-body">
|
||||
<h2 id="live-domains-title">Live topic domains</h2>
|
||||
<p class="usecase-lede">A DNS name is a static pointer maintained by infrastructure you rent. A Hyperswarm <strong>topic</strong> behaves more like an address you dial directly — whoever is currently announcing it is reachable, for as long as they keep at least one connection to the DHT. Nothing to register, nothing to renew, no hosting bill if nobody's listening.</p>
|
||||
<p>You can lean on this directly: derive a topic from a room name, an invite code, or a content hash, and treat "join this topic" as the entire addressing scheme for a feature. The <code>chat</code> and <code>whiteboard</code> examples both do exactly this — the topic string <em>is</em> the room.</p>
|
||||
<pre><code>const topic = await sha256(`my-app:${roomSlug}`);
|
||||
await swarm.join(topic); // this room now "exists" for as long as someone's in it</code></pre>
|
||||
<div class="usecase-links">
|
||||
<a class="btn btn-ghost" href="/learn/#topics">Read: Hyperswarm topics as rendezvous →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="usecase reveal" id="firewall" aria-labelledby="firewall-title">
|
||||
<div class="usecase-index">07</div>
|
||||
<div class="usecase-body">
|
||||
<h2 id="firewall-title">Firewall-controlled rooms</h2>
|
||||
<p class="usecase-lede">Discovery is open by design — that's the point of a DHT — but connections don't have to be. <code>swarm.setFirewall({ mode, keys })</code> switches a swarm between <code>off</code>, <code>allowlist</code>, and <code>denylist</code> modes keyed on peer public keys, and <code>swarm.ban(publicKey)</code> / <code>peerInfo.ban()</code> drops a specific peer outright.</p>
|
||||
<pre><code>await swarm.setFirewall({ mode: 'allowlist', keys: [trustedKeyHex] });
|
||||
|
||||
swarm.on('connection', (conn, peerInfo) => {
|
||||
if (isSpamming(peerInfo)) peerInfo.ban();
|
||||
});</code></pre>
|
||||
<p>The <code>firewall-room</code> example wires this up as a live allowlist/denylist/ban UI you can test against a second tab.</p>
|
||||
<div class="usecase-links">
|
||||
<a class="btn btn-secondary" href="http://127.0.0.1:4173/firewall-room/" target="_blank" rel="noopener">Try firewall-room →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="usecase reveal" id="dev-tooling" aria-labelledby="dev-tooling-title">
|
||||
<div class="usecase-index">08</div>
|
||||
<div class="usecase-body">
|
||||
<h2 id="dev-tooling-title">Developer tooling</h2>
|
||||
<p class="usecase-lede">Two building blocks for anyone shipping a protocol on top of BridgeSwarm rather than a demo app: <strong>Protomux</strong> for hand-designed message channels in the page, and <strong>HRPC</strong> for schema-defined, streaming RPC on the host.</p>
|
||||
<pre><code>// HRPC: unary + streaming from the page
|
||||
await BridgeSwarm.request('attachHrpc', { connId: conn.connId });
|
||||
const pong = await swarm.hrpcCall(conn.connId, 'ping', { value: 'hi' });
|
||||
await swarm.hrpcCall(conn.connId, 'fetchStream', { count: 3 }, {
|
||||
onChunk: (c) => console.log(c),
|
||||
});</code></pre>
|
||||
<p><code>sdk-demo</code> exercises swarm lifecycle and raw Protomux; <code>hrpc-demo</code> covers unary calls and both streaming directions end to end.</p>
|
||||
<div class="usecase-links">
|
||||
<a class="btn btn-secondary" href="http://127.0.0.1:4173/sdk-demo/" target="_blank" rel="noopener">Try sdk-demo →</a>
|
||||
<a class="btn btn-ghost" href="http://127.0.0.1:4173/hrpc-demo/" target="_blank" rel="noopener">Try hrpc-demo →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<section class="cta-band reveal">
|
||||
<div class="container">
|
||||
<div class="cta-card">
|
||||
<h2>Pick one and go build it</h2>
|
||||
<p class="lead">Every demo above is source-available in the repo's <code>examples/</code> directory as a starting point.</p>
|
||||
<div class="cta-actions">
|
||||
<a class="btn btn-primary btn-lg" href="/download">Install BridgeSwarm</a>
|
||||
<a class="btn btn-ghost btn-lg" href="/learn/">Read the docs</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<div data-footer data-prefix="../"></div>
|
||||
|
||||
<script type="module" src="/src/js/site.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,76 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
root: '.',
|
||||
publicDir: 'public',
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
// ── Marketing ──
|
||||
main: resolve(__dirname, 'index.html'),
|
||||
download: resolve(__dirname, 'download.html'),
|
||||
releases: resolve(__dirname, 'releases.html'),
|
||||
community: resolve(__dirname, 'community.html'),
|
||||
learn: resolve(__dirname, 'learn/index.html'),
|
||||
useCases: resolve(__dirname, 'use-cases/index.html'),
|
||||
|
||||
// ── Docs ──
|
||||
docs: resolve(__dirname, 'docs/index.html'),
|
||||
quickstart: resolve(__dirname, 'docs/quickstart.html'),
|
||||
userGuide: resolve(__dirname, 'docs/user-guide.html'),
|
||||
developerGuide: resolve(__dirname, 'docs/developer-guide.html'),
|
||||
architecture: resolve(__dirname, 'docs/architecture.html'),
|
||||
api: resolve(__dirname, 'docs/api.html'),
|
||||
data: resolve(__dirname, 'docs/data.html'),
|
||||
protocols: resolve(__dirname, 'docs/protocols.html'),
|
||||
capabilities: resolve(__dirname, 'docs/capabilities.html'),
|
||||
examples: resolve(__dirname, 'docs/examples.html'),
|
||||
security: resolve(__dirname, 'docs/security.html'),
|
||||
faq: resolve(__dirname, 'docs/faq.html'),
|
||||
release: resolve(__dirname, 'docs/release.html'),
|
||||
|
||||
// ── Legal ──
|
||||
legal: resolve(__dirname, 'legal/index.html'),
|
||||
legalTerms: resolve(__dirname, 'legal/terms.html'),
|
||||
legalEula: resolve(__dirname, 'legal/eula.html'),
|
||||
legalPrivacy: resolve(__dirname, 'legal/privacy.html'),
|
||||
legalLicense: resolve(__dirname, 'legal/license.html'),
|
||||
legalAup: resolve(__dirname, 'legal/aup.html'),
|
||||
legalCookies: resolve(__dirname, 'legal/cookies.html'),
|
||||
legalCopyright: resolve(__dirname, 'legal/copyright.html'),
|
||||
legalDisclaimer: resolve(__dirname, 'legal/disclaimer.html'),
|
||||
legalSecurity: resolve(__dirname, 'legal/security.html'),
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 5174,
|
||||
open: true,
|
||||
proxy: {
|
||||
// Mirror production /api/releases → Gitea (see server.mjs)
|
||||
'/api/releases': {
|
||||
target: 'https://git.ssh.surf',
|
||||
changeOrigin: true,
|
||||
rewrite: (p) => {
|
||||
const base = '/api/v1/repos/snxraven/BridgeSwarm'
|
||||
if (p === '/api/releases' || p.startsWith('/api/releases?')) {
|
||||
return p.replace('/api/releases', `${base}/releases`)
|
||||
}
|
||||
if (p.startsWith('/api/releases/tags/')) {
|
||||
return p.replace('/api/releases/tags/', `${base}/releases/tags/`)
|
||||
}
|
||||
if (p.startsWith('/api/releases/latest')) {
|
||||
return `${base}/releases?limit=50`
|
||||
}
|
||||
return p.replace(/^\/api\/releases/, `${base}/releases`)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
preview: {
|
||||
port: 5174,
|
||||
},
|
||||
})
|
||||