OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-vdrive / example / publish.mjs

86 lines · javascript ref:
// T5 build — publish a pear-install-shaped app into a VIRTUAL drive (no blob bytes).
// Layout required by pear-install/index.js:
//   /package.json                       (name, version, bin)
//   /by-arch/<platform>-<arch>/app/<bin>
import { createRequire } from 'module'
const require = createRequire(import.meta.url)

const fs = require('fs')
const path = require('path')
const process = require('process')
const crypto = require('hypercore-crypto')
const idEnc = require('hypercore-id-encoding')
const Corestore = require('corestore')
const Hyperdrive = require('hyperdrive')
const { ContentStore, build } = require('../lib/storage.cjs')
const { chunk } = await import('../../hyper-overlay/lib/chunker.js')

const ROOT = process.argv[2]
const APP = 't5app'
const HOST = process.platform + '-' + process.arch
const srcDir = ROOT + '/src'
const dir = ROOT + '/virtual'

// The "overlay": real files on disk that stay canonical.
fs.mkdirSync(srcDir, { recursive: true })
const binBytes = Buffer.concat([
  Buffer.from('#!/bin/sh\necho t5app-ok\n'),
  crypto.randomBytes(6 * 1024 * 1024) // payload so replication is real work
])
const pkgBytes = Buffer.from(
  JSON.stringify({ name: APP, version: '1.0.0', bin: { [APP]: APP } }, null, 2)
)
fs.writeFileSync(path.join(srcDir, APP), binBytes)
fs.writeFileSync(path.join(srcDir, 'package.json'), pkgBytes)

const files = [
  { name: '/package.json', file: path.join(srcDir, 'package.json'), buf: pkgBytes },
  { name: '/by-arch/' + HOST + '/app/' + APP, file: path.join(srcDir, APP), buf: binBytes }
]

const content = new ContentStore()
for (const f of files) {
  f.chunks = chunk(f.buf)
  for (const c of f.chunks) content.add(c.hash, f.file, c.offset, c.length)
}

const Storage = build(content)
const store = new Corestore(new Storage(dir), { primaryKey: Buffer.alloc(32, 7), unsafe: true })
const drive = new Hyperdrive(store)
await drive.ready()

function write (ws, buf) {
  return new Promise((resolve) => {
    if (ws.write(buf)) return resolve()
    ws.once('drain', resolve)
  })
}

for (const f of files) {
  const ws = drive.createWriteStream(f.name, { dedup: true })
  for (const c of f.chunks) await write(ws, c.data)
  await new Promise((resolve, reject) => {
    ws.once('error', reject)
    ws.once('close', resolve)
    ws.end()
  })
}

await drive.getBlobs()
const key = drive.key
const info = {
  key: key.toString('hex'),
  link: 'pear://' + idEnc.normalize(key),
  blobsLength: drive.blobs.core.length,
  binSha: crypto.hash(binBytes).toString('hex'),
  binBytes: binBytes.length,
  host: HOST
}

await drive.close()
await store.close()
content.close()

fs.writeFileSync(ROOT + '/drive.json', JSON.stringify(info, null, 2))
console.log(JSON.stringify(info, null, 2))