| … | … | @@ -2,7 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | A local-first peer-to-peer browser, app store, search engine, naming layer, Nostr bridge, and site publisher for macOS, Windows, and Linux, built on the Pear Runtime. |
| 4 | 4 | |
| 5 | **No accounts. No DNS. No manual app updates.** Sites and apps are addressed by stable Pear/Hyperdrive keys and pinned 24/7 on the [HiveRelay](https://github.com/bigdestiny2/P2P-Hiverelay) backbone. The publisher's laptop being offline doesn't matter — the relays carry the bytes, and users launch the current release from the catalogue without hunting for a download or applying an updater. | |
| 5 | **No accounts. No DNS. Local-first data.** Sites are addressed by stable Hyperdrive keys and can be pinned on the [HiveRelay](https://github.com/bigdestiny2/P2P-Hiverelay) backbone. Native applications are installed from verified packages; a catalogue never turns a remote executable link into a runtime command. | |
| 6 | 6 | |
| 7 | 7 | **Current release:** `v0.7.1` · stable Pear production length `92858`. The current hot-synced app adds private DuckDuckGo search on the browser-owned home tab: PearBrowser sends no search analytics and excludes submitted searches from the optional persistent visit log, while DuckDuckGo still receives the query and network address. The release also makes the renderer/backend RPC transport survive reload and live-update handoffs: pending calls fail immediately on disconnect, the per-launch authenticated socket reconnects during a bounded grace window, and the shell visibly resumes instead of reporting unrelated 30-second command timeouts. It retains all `v0.7.0` Content Shield, Pear Plugins, and P2P catalogue features. Catalogue version `9` advertises the release. See [docs/RELEASE_v0.7.1_OPERATOR.md](./docs/RELEASE_v0.7.1_OPERATOR.md) for the coordinated publish record. |
| 8 | 8 | |
| … | … | @@ -51,15 +51,16 @@ your platform, and use the migration guidance in |
| 51 | 51 | - **Plugin catalogue:** one-click discovery in Settings — curated entries install without pasting keys, `kind: "app"` entries like **anonGPT** open directly as P2P apps, and additional catalogues load from any drive with a `/plugins.json`; the public catalogue is live at `01b74736…` |
| 52 | 52 | |
| 53 | 53 | ### Apps |
| 54 | - Paste any `pear://` link → opens in its own isolated window | |
| 55 | - Launch the latest available release from a stable catalogue row or app link; users do not need to revisit a project page, download a package, or manually update installed app bytes | |
| 54 | - Open `hyper://` sites in a browser tab. | |
| 55 | - A compatible AppRelease v2 desktop package is a separate, verified install action; it is not a tab-runtime input. | |
| 56 | - A `pear://` or `file://` row is a **legacy migration record**. PearBrowser displays migration guidance and never launches it. | |
| 56 | 57 | - Load decentralized catalogues from Hyperdrive JSON, signed Hyperbee, Autobee, schema-sheets rooms, HiveRelay index rooms, default curated seeds, community submissions, and your own writable catalogues |
| 57 | 58 | - Keep multiple catalogs loaded at once with search, category, and source filters across the aggregated app store |
| 58 | 59 | - **My Catalog:** create a writable personal catalog, add apps from loaded catalogs or installed apps, rename it, edit saved metadata (name, description, version, author, categories), and share the catalog key; copies opened without the writer key stay read-only |
| 59 | - Safe catalogue normalization accepts `apps[]`, `items[]`, or `entries[]`, preserves safe link-only rows (`hyper://`, `pear://`, `file://`), rejects malformed targets, and strips prototype-pollution keys before rendering | |
| 60 | - Safe catalogue normalization accepts `apps[]`, `items[]`, or `entries[]`, classifies `hyper://` as browsable content, classifies compatible signed package releases for install, retains `pear://`/`file://` only for migration, rejects malformed targets, and strips prototype-pollution keys before rendering | |
| 60 | 61 | - Default catalog auto-loads on first Apps-tab visit (the "PearBrowser Network" Hyperbee `hyperbee://f5fb7500bccd…` — PearBrowser, peerit, HiveRelay, P2P Builders, Pear Dealroom, Paste, PearPoker, Keet, PearPass, Peercord, anonGPT, Pear POS, Pear Tickets, HiveWorm), generated from a single source manifest and mirrored into the offline seed |
| 61 | - **peerit — "the front page of the P2P internet"** (a peer-to-peer Reddit, `hyper://ec6e2d6d…/`): a browsable `hypersite` whose communities, posts, threaded comments and votes live in a shared Autobase+Hyperbee log. It opens as a startup tab beside the private-search home and landing page, and is **pinned to the top** of the Sites discovery grid. Source: `02-apps/peerit`. | |
| 62 | - Featured apps: **Keet** · **PearPass** · **anonGPT** · **Paste** · **[Peercord](https://git.churchofmalware.org/mastercodeon/Peercord)**. Peercord's current Pear release is a full desktop app (`pear.json` `type:"desktop"`), so PearBrowser launches it via the standalone `pear://` window path; it should only move to headless "Run in tab" once Peercord publishes a pear-request worker entry. | |
| 62 | - **peerit — "the front page of the P2P internet"** (a peer-to-peer Reddit, `hyper://ec6e2d6d…/`): a browsable `hypersite` whose communities, posts, threaded comments and votes live in a shared Autobase+Hyperbee log. It opens as the **active front tab on every fresh launch** (alongside the landing page) and is **pinned to the top** of the Sites discovery grid. Source: `02-apps/peerit`. | |
| 63 | - Featured projects include **Keet**, **PearPass**, **anonGPT**, **Paste**, and **[Peercord](https://git.churchofmalware.org/mastercodeon/Peercord)**. Legacy Pear desktop releases remain visible as migration-required records until their owners publish compatible native v3 package metadata. | |
| 63 | 64 | |
| 64 | 65 | ### Publish (P2P Sites) |
| 65 | 66 | - Block editor: heading, paragraph, image, link, list, quote, code, raw HTML/CSS/JS, divider |
| … | … | @@ -188,13 +189,13 @@ human approval of clean-install, upgrade, rollback, and data-continuity proof. |
| 188 | 189 | |
| 189 | 190 | | Script | What | |
| 190 | 191 | |---|---| |
| 191 | | `scripts/pin-self-on-hiverelay.js` | Seed the desktop's own production drive on the HiveRelay backbone. Run after every release. | | |
| 192 | | `scripts/pin-self-on-hiverelay.js <64-hex-key>` | Pin an explicit non-executable content or release-evidence drive on HiveRelay. Availability does not approve a package. | | |
| 192 | 193 | | `scripts/publish-and-pin.js <dir>` | Publish a directory as a Hyperdrive + auto-pin to relays. | |
| 193 | 194 | | `scripts/unseed-drive.js <key>` | Send a signed unseed (publisher-only). | |
| 194 | 195 | | `scripts/extract-drive.js <key>` | Pull a drive's full content out to a local directory. | |
| 195 | 196 | | `scripts/list-drive.js <key>` | Diagnose what's inside a drive's manifest. | |
| 196 | 197 | | `scripts/check-relays.js` | Discovery probe — print all HiveRelays reachable via DHT. | |
| 197 | | `scripts/verify-pin.js --expect <length> --hiverelay` | Fresh-peer production-drive check plus optional HiveRelay `proveSeeded` evidence when upgraded relays expose storage-proof. | | |
| 198 | | `scripts/verify-pin.js --key <64-hex> --expect <length> --hiverelay` | Fresh-peer content/evidence-drive check plus optional HiveRelay `proveSeeded` evidence when upgraded relays expose storage-proof. | | |
| 198 | 199 | | `scripts/verify-release-contents.js --expect <length> --missing <path>` | Fresh-peer release metadata scan: proves ignored scratch/docs/scripts/tests paths are absent from the production drive after purge staging. | |
| 199 | 200 | | `scripts/verify-live-catalog.js --expect-app peercord --expect-app peerit --expect-app hiveworm` | Fresh-peer Hyperbee catalogue check: proves the live app catalogue key is reachable and contains expected release rows and Peercord launch metadata. | |
| 200 | 201 | | `scripts/runtime-rpc-smoke.mjs` | Runtime GUI smoke: after launching PearBrowser, checks the diagnostic RPC path reports DHT, proxy, relay, peer-count, and storage readiness without becoming the renderer. | |
| … | … | @@ -170,7 +170,7 @@ breaking the feature with no error. The drift guard fails CI if they disagree. |
| 170 | 170 | ## 9. How to run & test · concurrent-session hazard |
| 171 | 171 | |
| 172 | 172 | ```bash |
| 173 | npm start # pear run --dev . (dev shell) | |
| 173 | npm start # fails closed until the embedded v3 host is configured | |
| 174 | 174 | npm test # node --test 'test/*.test.js' → 469 passing on the release PR branch |
| 175 | 175 | node scripts/check-hiverelay-layout.mjs # confirms HiveRelay installs from npm (^0.20.2 / lockfile 0.20.2); sibling checkout optional unless using file: deps |
| 176 | 176 | gh pr checks 4 --repo bigdestiny2/pearbrowser-desktop # GitHub Actions desktop CI, if enabled for the PR branch |
| … | … | @@ -100,17 +100,11 @@ chmod +x PearBrowser-0.7.1-linux-x64.AppImage |
| 100 | 100 | ./PearBrowser-0.7.1-linux-x64.AppImage |
| 101 | 101 | ``` |
| 102 | 102 | |
| 103 | ## Recovery Fallback | |
| 104 | ||
| 105 | The stable Pear link remains available for testers and recovery while native | |
| 106 | packaging matures: | |
| 107 | ||
| 108 | ```sh | |
| 109 | npm i -g pear | |
| 110 | pear | |
| 111 | pear run pear://tco5k7h38uoxatedp1wongdbhjxow1x7jiwm3t1i9cujbebhsbty | |
| 112 | ``` | |
| 113 | ||
| 114 | This fallback is not the preferred public install path because `pear run` is | |
| 115 | deprecated in Pear runtime `v2.4.0`, but it is still useful when diagnosing a | |
| 116 | native package issue. | |
| 103 | ## Legacy Pear records | |
| 104 | ||
| 105 | There is no Pear-runtime fallback for this v3 release. A legacy `pear://` | |
| 106 | record is migration metadata, not an install or troubleshooting instruction. | |
| 107 | If a native package fails, keep the old installation and its data intact, | |
| 108 | collect the package checksum and local diagnostics, then follow the | |
| 109 | [PearBrowser v3 migration guide](./PEAR_V3_MIGRATION.md). Do not run a remote | |
| 110 | link through a local runtime. |
| … | … | @@ -582,33 +582,46 @@ Run before release. Grouped by tier; **Tier A items are the universal floor**. |
| 582 | 582 | |
| 583 | 583 | --- |
| 584 | 584 | |
| 585 | ## 13. Release Build, Pinning & Verification Runbook (NORMATIVE — added v0.2) | |
| 586 | ||
| 587 | §9/§10.3 specify *what* a publishable record and a seeded drive look like. This section is the *how* — the end-to-end process to take an app from source to a clean, durably-pinned, catalogue-listed release. Every rule here was validated against the live system 2026-06. | |
| 588 | ||
| 589 | ### 13.1 Build a clean, lean release key (desktop standalone / `pear://` apps) | |
| 590 | ||
| 591 | - **PB-RELEASE-1 (MUST).** Publish from a **fresh, history-free key**, not your day-to-day dev/stage key. A Hyperdrive is an **append-only log**: each `pear stage` re-imports the changed bundle forever, so re-staging one key throughout development accumulates **gigabytes of dead history** (observed: a "lightweight" app's dev key at 35 GB blob-core / 480k metadata ops while the live checkout was a fraction of that — dominated by native prebuilds for all platforms re-imported every stage). Relays will **not** fully replicate a history-heavy drive (PB-RELEASE-9) and cold reads must traverse a huge metadata core. Mint a clean key with **`pear touch`** and stage to it once. (`pear init` is removed; current `pear stage` requires a real `pear://` link — bare channel names like `dev` are rejected.) | |
| 592 | - **PB-RELEASE-2 (SHOULD).** Stage **lean**: `pear stage --compact <link> .` tree-shakes to the runtime-reachable file set (dropping devDependencies, build tools, tests, and non-target native prebuilds) — typically a 5–40× size reduction (observed: 2.7 GB→172 MB, 35 GB→413 MB). | |
| 593 | - **PB-RELEASE-3 (MUST, when using --compact).** Declare **every** entry in `package.json` `pear.stage.entrypoints` — including workers spawned **by string path** (e.g. a renderer doing `applink + '/app/backend/worker.js'`). `--compact` follows only the static import graph from declared entrypoints; an undeclared worker (and its entire dependency subtree) is silently dropped → the app boots to `MODULE_NOT_FOUND`. | |
| 594 | - **PB-RELEASE-4 (MUST, when using --compact).** `--compact` follows `<script src>` but **not** `<link href>` CSS or other HTML-referenced assets. After the compact stage, **patch** them back: `pear stage --only /<ui-or-dist-dir> <link> .`. Then confirm every asset `index.html` references actually exists in the drive. | |
| 595 | - **PB-RELEASE-5 (MUST).** **Test-run the staged key** (`pear run <link>`) before releasing — boot logs catch dropped modules, missing assets, and dependency-version bugs that staging alone won't. Keep `hyperbee`/`hypercore`/`corestore`/`autobase` **majors aligned**: hyperbee ≥2.22 requires hypercore 11; a hyperbee 2.27 + hypercore 10 mismatch crashes on boot at `Hyperbee._open` (`setInflightRange` of undefined). | |
| 596 | - **PB-RELEASE-6 (SHOULD).** A production app whose key is the **auto-update identity** users already hold (a `pear release` link) **cannot** be re-keyed to shed history without breaking their upgrade path — keep the stable key and lean on a persistent seeder (PB-RELEASE-9). Re-keying is only for apps not yet distributed. | |
| 597 | ||
| 598 | ### 13.2 Pin durably on HiveRelay | |
| 599 | ||
| 600 | - **PB-RELEASE-7 (MUST).** Apps **are** durably HiveRelay-pinnable by **anyone** — not just the author — via a **read-only foreign-key seed**: `HiveRelayClient.seed()` signs the seed-request with the seeder's own swarm keypair, not the drive author's. Tool: `scripts/pin-app-on-hiverelay.js <pear://|hex> --name <x> --maxStorage <MB> --hold <s>` opens the drive, pre-fetches the current checkout (becoming a complete source), broadcasts an archive-tier seed-request, and holds online while relays replicate. The tool MUST refuse a zero-file current checkout before broadcasting a seed request; a reachable but empty checkout is availability failure, not a successful pin. | |
| 601 | - **PB-RELEASE-8 (MUST).** Size `maxStorage` to the **current checkout + metadata**, never the (bloated) blob-core byteLength — relays reject multi-GB reservations (256–600 MB requests accepted; 11 GB/140 GB rejected). Relay **acceptances arrive *after*** the initial broadcast window, so confirm over a `--hold` of a few minutes, not the first 15 s. | |
| 602 | - **PB-RELEASE-9 (MUST, large / history-heavy production keys).** If relays accept the pin but each replicates only **part** of a heavy drive (no complete per-relay copy → a fresh peer gets 0 useful peers), the publisher MUST run a **persistent seeder** so the app stays reachable 24/7. Template: `scripts/durable-seed.sh` driven by a launchd/systemd agent with run-at-login + restart-on-crash (`~/Library/LaunchAgents/com.pearbrowser.seed.plist`). For true off-machine durability, run it on an always-on host. | |
| 603 | ||
| 604 | ### 13.3 Verify from a fresh peer, then register | |
| 605 | ||
| 606 | - **PB-RELEASE-10 (MUST).** **Prove durability from a fresh peer with every local source stopped** before listing: `scripts/verify-app-full.js --key <hex>` opens the drive from a clean corestore, joins the swarm, and fetches a spread of blobs across the whole tree. 0 peers, 0 file entries, or any missing blob = not durable — do not list it. (This is the teeth behind PB-AVAIL-2's cold-node check.) | |
| 607 | - **PB-RELEASE-11 (MUST).** Only after a passing fresh-peer verify, publish the catalogue row (§9) and, for the unified Hyperbee, regenerate + re-publish with the persistent `--storage` (PB-DISCOVERYCATALOGUE-18). Cards surface the app's **size and live peer count** from `CMD_GET_DRIVE_INFO`; a row whose drive shows **0 peers** reads as dead. | |
| 608 | ||
| 609 | ### 13.4 What a complete catalogue submission carries | |
| 610 | ||
| 611 | Beyond the `APPS_SCHEMA`-required `name`+`type`+(`driveKey`|`link`), a quality submission SHOULD carry `description`, `author`, `version`, `categories`, and an in-drive **icon** (PB-ICON-1). A unified-bee catalogue (not the strict sheets `APPS_SCHEMA`) MAY additionally carry `source`, `license`, `platforms`, and `homepage`. The desktop **My Catalog** publisher form collects these; **`type` is the single most common omission** (PB-DISCOVERYCATALOGUE-2/3) — set it explicitly to `standalone` (own window) or `hypersite` (inline tab). | |
| 585 | ## 13. V3 release, availability, and catalogue runbook (NORMATIVE) | |
| 586 | ||
| 587 | Pear v2 staging, `pear run`, `pear release`, and a persistent executable-key | |
| 588 | seeder are retired workflows. They are not compatibility paths for a v3 | |
| 589 | application. | |
| 590 | ||
| 591 | ### 13.1 Build and package | |
| 592 | ||
| 593 | - **PB-RELEASE-1 (MUST).** Build a native package for each declared desktop | |
| 594 | target. The package must have a signed AppRelease v2 (`apr_`) record, | |
| 595 | immutable digest, platform target, and rollback metadata before it is shown | |
| 596 | as installable. | |
| 597 | - **PB-RELEASE-2 (MUST).** The embedded runtime starts only a bundled local | |
| 598 | entrypoint (for example `PearRuntime.run(require.resolve('./worker.js'))`). | |
| 599 | A catalogue link, release identifier, or remote path must never become a | |
| 600 | runtime argument. | |
| 601 | - **PB-RELEASE-3 (MUST).** Test clean install, upgrade, data preservation, | |
| 602 | rollback, and local worker boot/shutdown for every supported target. A | |
| 603 | checksum alone is insufficient release evidence. | |
| 604 | ||
| 605 | ### 13.2 HiveRelay availability | |
| 606 | ||
| 607 | - **PB-RELEASE-4 (MUST).** HiveRelay may pin non-executable content, catalogue, | |
| 608 | and evidence Hyperdrives. Pass an explicit 64-hex key to | |
| 609 | `scripts/pin-self-on-hiverelay.js`; a pin proves availability only and never | |
| 610 | approves a package. | |
| 611 | - **PB-RELEASE-5 (MUST).** Prove a pinned content drive from a fresh peer with | |
| 612 | every local source stopped: `scripts/verify-app-full.js --key <hex>` or | |
| 613 | `scripts/verify-pin.js --key <hex> --hiverelay`. Zero peers, zero files, or a | |
| 614 | missing blob is availability failure. | |
| 615 | ||
| 616 | ### 13.3 Catalogue actions | |
| 617 | ||
| 618 | - **PB-RELEASE-6 (MUST).** A `hyper://` entry is browsable content. A compatible | |
| 619 | signed AppRelease v2 record is an explicit native install action. A | |
| 620 | `pear://` or `file://` entry is legacy discovery metadata and must display | |
| 621 | **migration required**, never an install or run action. | |
| 622 | - **PB-RELEASE-7 (MUST).** Catalogue records include name, description, author, | |
| 623 | version, categories, provenance, platform targets, and the delivery kind. | |
| 624 | They must not rely on inference from an executable URL. | |
| 612 | 625 | |
| 613 | 626 | --- |
| 614 | 627 |
| … | … | @@ -226,7 +226,8 @@ The HTTP `/api/swarm/*` endpoints are similarly versioned in their request body: |
| 226 | 226 | 5. **`backend/pear-bridge.js`** — page-side injected shim adds `window.pear.swarm.v1`. |
| 227 | 227 | 6. **`ui/shell.js`** — adds swarm-join consent path to `LoginConsent` (or a sibling `SwarmConsent` component, depending on UX) + a "Swarm topics" sub-table to Connected Apps. |
| 228 | 228 | 7. **Demo:** `examples/echo-peer/` — 30-line `hyper://` page that joins a known topic, sends "hello", logs replies. Doubles as a smoke test. |
| 229 | 8. **`pear stage` + `pear release production .`** — ship. | |
| 229 | 8. **Native package build + signed AppRelease v2 record** — ship only after | |
| 230 | clean-install, worker boot/shutdown, and data-continuity evidence pass. | |
| 230 | 231 | |
| 231 | 232 | --- |
| 232 | 233 |
| … | … | @@ -1,22 +1,8 @@ |
| 1 | 1 | #!/bin/bash |
| 2 | # Durable HiveRelay seeder for the PearBrowser production release. | |
| 3 | # | |
| 4 | # Why this exists: the desktop production key (pear://tco5k7…) carries ~705 MB | |
| 5 | # of append-only staging history (16k+ versions). HiveRelay relays accept the | |
| 6 | # pin but won't each replicate a complete copy of that heavy-history drive, so | |
| 7 | # a fresh `pear run pear://tco5k7…` can't be served by relays alone. Until the | |
| 8 | # release is re-cut on a lean key (which would break existing users' auto-update) | |
| 9 | # the publisher must seed it — this script is that always-on seeder. | |
| 10 | # | |
| 11 | # Run by launchd (~/Library/LaunchAgents/com.pearbrowser.seed.plist) with | |
| 12 | # RunAtLoad + KeepAlive, so it starts on login and auto-restarts if it dies. | |
| 13 | # | |
| 14 | # To seed additional keys, run one launchd agent per key (copy the plist with a | |
| 15 | # new Label + this script's link) — `pear seed` takes one link per process, and | |
| 16 | # per-key agents give each its own KeepAlive supervision. | |
| 2 | # Retired: this used to keep a Pear v2 executable project key alive with | |
| 3 | # `pear seed`. V3 ships verified native packages and must not revive that | |
| 4 | # remote-execution path. Pin non-executable content/evidence explicitly with | |
| 5 | # `node scripts/pin-self-on-hiverelay.js <64-hex-hyperdrive-key>`. | |
| 17 | 6 | |
| 18 | export PATH="/opt/homebrew/bin:$HOME/Library/Application Support/pear/bin:/usr/local/bin:/usr/bin:/bin" | |
| 19 | ||
| 20 | # Production browser release. `exec` so launchd supervises the pear process | |
| 21 | # directly (its KeepAlive restarts THIS pid if it exits). | |
| 22 | exec pear seed --no-tty pear://tco5k7h38uoxatedp1wongdbhjxow1x7jiwm3t1i9cujbebhsbty | |
| 7 | echo "durable-seed.sh is retired: legacy Pear v2 executable seeding is not a v3 release workflow." >&2 | |
| 8 | exit 2 |
| … | … | @@ -1,7 +1,6 @@ |
| 1 | 1 | /** |
| 2 | * Pin a drive (the pearbrowser-desktop bundle itself, the welcome | |
| 3 | * landing-page drive, or any other 64-hex Hyperdrive / Pear project | |
| 4 | * key) onto the HiveRelay backbone. | |
| 2 | * Pin a non-executable Hyperdrive artifact (a site, catalogue, or release | |
| 3 | * evidence drive) onto the HiveRelay backbone. | |
| 5 | 4 | * |
| 6 | 5 | * Why: drives normally rely on whoever published them being online to |
| 7 | 6 | * serve. Pinning on HiveRelay means a multi-region always-on backbone |
| … | … | @@ -21,14 +20,11 @@ |
| 21 | 20 | * Idempotent. Re-running just refreshes the seed window. |
| 22 | 21 | * |
| 23 | 22 | * Usage: |
| 24 | * # Pin the pearbrowser-desktop production channel (default) | |
| 25 | * node scripts/pin-self-on-hiverelay.js | |
| 26 | * | |
| 27 | * # Pin any other drive — pass the 64-hex project/drive key: | |
| 23 | * # Pin an explicit v3-compatible content or evidence drive: | |
| 28 | 24 | * node scripts/pin-self-on-hiverelay.js <64-hex-key> [friendly-name] |
| 29 | 25 | * |
| 30 | * # Or via env var (legacy): | |
| 31 | * PEAR_PROJECT_KEY=<64-hex> node scripts/pin-self-on-hiverelay.js | |
| 26 | * # Or via env var: | |
| 27 | * HYPERDRIVE_KEY=<64-hex> node scripts/pin-self-on-hiverelay.js | |
| 32 | 28 | */ |
| 33 | 29 | |
| 34 | 30 | // The client SDK lives in the dedicated `p2p-hiverelay-client` package. Keep |
| … | … | @@ -39,25 +35,21 @@ import { mkdtempSync } from 'node:fs' |
| 39 | 35 | import { tmpdir } from 'node:os' |
| 40 | 36 | import { join } from 'node:path' |
| 41 | 37 | |
| 42 | // pearbrowser-desktop production channel project key. Get this from | |
| 43 | // `pear info production .` — first line of output. | |
| 44 | const DEFAULT_PROJECT_KEY = '8b21b577993ce0fc45036ca9011861e25f0a49fd4d68bcc655fb2690a03cb062' | |
| 45 | const projectKey = process.env.PEAR_PROJECT_KEY || DEFAULT_PROJECT_KEY | |
| 38 | const projectKey = process.argv[2] || process.env.HYPERDRIVE_KEY | |
| 39 | if (!/^[0-9a-f]{64}$/i.test(projectKey || '')) { | |
| 40 | console.error('usage: node scripts/pin-self-on-hiverelay.js <64-hex-hyperdrive-key>') | |
| 41 | console.error(' HYPERDRIVE_KEY=<64-hex> node scripts/pin-self-on-hiverelay.js') | |
| 42 | console.error('A legacy pear:// executable key is not a valid v3 release target.') | |
| 43 | process.exit(2) | |
| 44 | } | |
| 46 | 45 | |
| 47 | 46 | // Seed parameters. Generous defaults — this is critical infra, not |
| 48 | 47 | // throwaway content. |
| 49 | 48 | // |
| 50 | // IMPORTANT: maxStorage must exceed the drive's full size (metadata + | |
| 51 | // blobs). pear-electron's `pre` step bundles the Chromium runtime into | |
| 52 | // the staged drive, so even a small app produces a ~400 MB drive. | |
| 53 | // `pear info pear://<key>` shows `byteLength` + `blobs.byteLength` — | |
| 54 | // keep maxStorage at least 2× that with headroom for future growth. | |
| 55 | // Today (v0.4.3): metadata 1.2 MB + blobs 364 MB ≈ 365 MB. We cap at | |
| 56 | // 1 GB to absorb the next few releases without revisiting this. | |
| 57 | // | |
| 58 | // If maxStorage is too low, relays accept the seed request, replicate | |
| 59 | // metadata fully, and then stall mid-blob-download — producing exactly | |
| 60 | // the symptom of `pear run pear://...` hanging silently for end users. | |
| 49 | // IMPORTANT: maxStorage must exceed the artifact's full size (metadata + | |
| 50 | // blobs). Keep the cap at least 2x the observed size with future headroom. | |
| 51 | // A partial seed is availability evidence failure; it is never a substitute | |
| 52 | // for native package signature verification or a local install. | |
| 61 | 53 | const SEED_OPTS = { |
| 62 | 54 | replicas: 5, // ask 5 relays to pin |
| 63 | 55 | ttlDays: 365, // pin for a year |
| … | … | @@ -66,8 +58,8 @@ const SEED_OPTS = { |
| 66 | 58 | } |
| 67 | 59 | |
| 68 | 60 | async function main () { |
| 69 | console.log('🍐 Pinning pearbrowser-desktop on HiveRelay') | |
| 70 | console.log(' project key:', projectKey) | |
| 61 | console.log('🍐 Pinning a v3 content/evidence drive on HiveRelay') | |
| 62 | console.log(' drive key:', projectKey) | |
| 71 | 63 | console.log(' replicas:', SEED_OPTS.replicas, '· ttl:', SEED_OPTS.ttlDays, 'days') |
| 72 | 64 | console.log() |
| 73 | 65 | |
| … | … | @@ -179,9 +171,9 @@ async function main () { |
| 179 | 171 | console.log(' · ' + id + '…') |
| 180 | 172 | } |
| 181 | 173 | console.log() |
| 182 | console.log(' PearBrowser desktop is now pinned on the HiveRelay backbone.') | |
| 183 | console.log(' Anyone running `pear run pear://tco5k7h38uo…` will pull bytes') | |
| 184 | console.log(' from these relays whenever the publisher machine is offline.') | |
| 174 | console.log(' The requested drive is now pinned on the HiveRelay backbone.') | |
| 175 | console.log(' This proves availability only; native packages still require') | |
| 176 | console.log(' their signed AppRelease v2 record and local verification.') | |
| 185 | 177 | } |
| 186 | 178 | |
| 187 | 179 | // Linger 2s so any in-flight messages flush before exit. |
| … | … | @@ -6,28 +6,25 @@ |
| 6 | 6 | * accept seed requests). This script does the real round-trip: |
| 7 | 7 | * |
| 8 | 8 | * 1. Boot a fresh Corestore + Hyperswarm with NO local cache |
| 9 | * 2. Open the Hyperdrive at the production key | |
| 9 | * 2. Open an explicitly supplied Hyperdrive key | |
| 10 | 10 | * 3. Join the swarm and wait for any peer (relay or otherwise) |
| 11 | 11 | * 4. Read the drive's current length and a sample blob |
| 12 | 12 | * 5. Compare against an expected length, if provided |
| 13 | 13 | * 6. Exit 0 on success, non-zero on failure |
| 14 | 14 | * |
| 15 | * If this exits 0, the drive is genuinely available from a third | |
| 16 | * party — meaning a fresh `pear run pear://tco5...` from anywhere | |
| 17 | * will find content. | |
| 15 | * If this exits 0, the drive is genuinely available from a third party. It is | |
| 16 | * content availability evidence only; it does not approve a native package or | |
| 17 | * execute a legacy Pear v2 project. | |
| 18 | 18 | * |
| 19 | 19 | * Usage: |
| 20 | * # Verify the pearbrowser-desktop production drive is reachable | |
| 21 | * node scripts/verify-pin.js | |
| 20 | * # Verify an explicit content/evidence drive is reachable | |
| 21 | * node scripts/verify-pin.js --key <64-hex> | |
| 22 | 22 | * |
| 23 | * # Verify a specific length is being served (use after release) | |
| 24 | * node scripts/verify-pin.js --expect 4914 | |
| 23 | * # Verify a specific length is being served | |
| 24 | * node scripts/verify-pin.js --key <64-hex> --expect 4914 | |
| 25 | 25 | * |
| 26 | 26 | * # Also ask upgraded HiveRelay relays for signed proveSeeded evidence |
| 27 | * node scripts/verify-pin.js --expect 4914 --hiverelay | |
| 28 | * | |
| 29 | * # Verify any other key | |
| 30 | * node scripts/verify-pin.js --key <64-hex> | |
| 27 | * node scripts/verify-pin.js --key <64-hex> --expect 4914 --hiverelay | |
| 31 | 28 | * |
| 32 | 29 | * Designed to be called from CI / release-prod.sh — fails loudly if |
| 33 | 30 | * the release hasn't propagated to the network within the timeout. |
| … | … | @@ -42,7 +39,6 @@ import { mkdtempSync, rmSync } from 'node:fs' |
| 42 | 39 | import { join } from 'node:path' |
| 43 | 40 | import { tmpdir } from 'node:os' |
| 44 | 41 | |
| 45 | const DEFAULT_KEY = '8b21b577993ce0fc45036ca9011861e25f0a49fd4d68bcc655fb2690a03cb062' | |
| 46 | 42 | const PEER_TIMEOUT_MS = 30_000 |
| 47 | 43 | const LENGTH_TIMEOUT_MS = 20_000 |
| 48 | 44 | const BLOB_SAMPLE_TIMEOUT_MS = 20_000 |
| … | … | @@ -53,7 +49,7 @@ const DEFAULT_SAMPLE_PATHS = ['/index.html', '/package.json', '/pear.json'] |
| 53 | 49 | |
| 54 | 50 | function parseArgs (argv) { |
| 55 | 51 | const args = { |
| 56 | key: DEFAULT_KEY, | |
| 52 | key: null, | |
| 57 | 53 | expect: null, |
| 58 | 54 | hiverelay: false, |
| 59 | 55 | requireHiverelay: false, |
| … | … | @@ -78,7 +74,7 @@ function parseArgs (argv) { |
| 78 | 74 | |
| 79 | 75 | const args = parseArgs(process.argv.slice(2)) |
| 80 | 76 | if (!/^[0-9a-f]{64}$/i.test(args.key)) { |
| 81 | console.error('error: key must be 64-char hex') | |
| 77 | console.error('error: --key <64-char-hex-hyperdrive-key> is required') | |
| 82 | 78 | process.exit(2) |
| 83 | 79 | } |
| 84 | 80 |