OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / examples / pear-app / index.js

79 lines · javascript ref:
/**
 * Minimal HiveRelay + Pear Example
 *
 * This shows the Bare-compatible way to use HiveRelay in a Pear app.
 * Key difference from Node.js: pass { swarm, store } instead of a path string.
 *
 * Run with: pear run .
 */

import Hyperswarm from 'hyperswarm'
import Corestore from 'corestore'
import { HiveRelayClient } from 'p2p-hiverelay-client'

// In a real Pear app, use Pear.config.storage for persistent storage.
// For terminal testing, a local path works too.
const storagePath = typeof globalThis.Pear !== 'undefined'
  ? Pear.config.storage
  : './hiverelay-example-storage'

// IMPORTANT: let Corestore manage its own primaryKey.
//
// DO NOT do `new Corestore(path, { primaryKey: someIdentitySeed, unsafe: true })`.
// Tying Corestore's primaryKey to an external identity seed looks clean but
// is a data-loss hazard:
//   1. If the identity file gets corrupted or regenerated (unclean shutdown,
//      partial write, etc.), Corestore sees a new primaryKey != stored one
//      and throws "Another corestore is stored here".
//   2. In-process auto-recovery can't rm -rf the dir because rocksdb already
//      holds db/LOCK.
//   3. Manual recovery wipes the publisher keypair, orphaning every
//      HiveRelay-pinned drive (signed unseed requires the original keypair).
// Corestore persists its own primaryKey independently. Drives survive
// identity regeneration. See docs/IDENTITY-AND-STORAGE.md for the full
// reasoning and a recovery-safe pattern.
const store = new Corestore(storagePath)
const swarm = new Hyperswarm()

const relay = new HiveRelayClient({ swarm, store })

relay.on('relay-connected', ({ pubkey }) => {
  console.log('Connected to relay:', pubkey.slice(0, 12) + '...')
})

await relay.start()
console.log('HiveRelay client started')

// Publish some content
const drive = await relay.publish([
  { path: '/index.html', content: '<h1>Hello from Pear!</h1><p>This app is always online via HiveRelay.</p>' },
  { path: '/manifest.json', content: JSON.stringify({ name: 'pear-example', version: '1.0.0' }) }
])

console.log('Published! Share this key:')
console.log('  ' + drive.key.toString('hex'))

// Check which relays picked it up
const relays = relay.getRelays()
console.log(`Connected to ${relays.length} relay(s)`)

// Seed the content for persistence
const appKeyHex = drive.key.toString('hex')
await relay.seed(appKeyHex, { replicationFactor: 3 })
console.log('Seed request sent — relays will replicate your content')

// Show available apps on the network. Each row is one (app, relay) pair —
// per-relay catalogs are local to each operator (no global merged view).
const apps = relay.getAvailableApps()
if (apps.length > 0) {
  console.log(`\n${apps.length} app row(s) across connected relays:`)
  for (const app of apps) {
    const id = app.appId || app.appKey.slice(0, 12) + '...'
    console.log(`  - ${id} (from relay ${app.source.relayPubkey.slice(0, 12)})`)
  }
}

// Keep running
console.log('\nApp is running. Press Ctrl+C to stop.')
console.log('Your content stays available on relay nodes even after you quit.')