// Patch @holepunchto/keet-core-hyperdb's abi*.bundle.js files to inline
// the file content their resolution maps reference but don't include.
//
// Why: keet-core-hyperdb 1.22.0 ships with abi*.bundle.js files where
// each bundle's resolution map points at relative paths like /package.json
// or /lib/contract/foo.js, but the bundle itself only includes some of
// those targets as bundle entries. When bare-union-bundle's protocol.read
// hits a missing key it returns null, and bare-module's
// _extensions['.json'] then crashes on JSON.parse(null.toString()).
//
// The files exist on disk in keet-core-hyperdb's package tree — they just
// weren't inlined into the bundles. This script adds them. Idempotent;
// safe to re-run; no-op if the bundles are already complete.
//
// Run from hyper-tps build root: `node scripts/patch-keet-bundles.js`
//
// Drop this script when @holepunchto publishes a fixed keet-core-hyperdb.
const fs = require('fs')
const path = require('path')
const KEET_ROOT = path.resolve(
process.argv[2] || 'node_modules/@holepunchto/keet-core-hyperdb'
)
if (!fs.existsSync(path.join(KEET_ROOT, 'package.json'))) {
console.error('patch-keet-bundles: not a keet-core-hyperdb root: ' + KEET_ROOT)
process.exit(2)
}
// bare-bundle may be hoisted to top-level node_modules (typical npm flat
// install) or nested under keet-core-hyperdb's own node_modules. Try both.
function loadBareBundle () {
const candidates = [
path.join(KEET_ROOT, 'node_modules/bare-bundle/index.js'),
path.resolve(KEET_ROOT, '../../bare-bundle/index.js'),
path.resolve(KEET_ROOT, '../../../bare-bundle/index.js')
]
for (const p of candidates) {
if (fs.existsSync(p)) return require(p)
}
throw new Error('patch-keet-bundles: bare-bundle not found in any of:\n ' + candidates.join('\n '))
}
const Bundle = loadBareBundle()
const bundleDir = path.join(KEET_ROOT, 'bundle')
const abiFiles = fs.readdirSync(bundleDir)
.filter(f => /^abi\d+\.bundle\.js$/.test(f))
.sort()
let totalInlined = 0
let bundlesPatched = 0
const trulyMissing = []
for (const f of abiFiles) {
const fullPath = path.join(bundleDir, f)
// Bust any cached require of this exact file from prior iterations
delete require.cache[fullPath]
const b = require(fullPath)
const refs = new Set()
for (const map of Object.values(b.resolutions || {})) {
for (const v of Object.values(map)) {
if (typeof v === 'string' && v.startsWith('/')) refs.add(v)
}
}
let inlinedHere = 0
// For each newly inlined file we need to know its resolution map (its
// own imports). The bundle's existing resolutions describe how OTHER
// files refer to it, not what it itself imports. Without an explicit
// entry, _resolutions[file] becomes undefined; UnionBundle.load then
// hits `Object.entries(undefined)` mid-load and crashes.
//
// For JSON files: no imports, empty {} is correct.
// For JS files: would need bare-module-traverse to compute properly;
// here we use {} as a safe minimum — if the loaded module then does
// `require(...)`, it'll fail at that require with a clearer error
// than "Object.entries of undefined".
for (const p of refs) {
if (b.read(p) !== null) continue
if (p.startsWith('/node_modules/')) continue // bundle://host paths — out of scope
const diskPath = path.join(KEET_ROOT, p)
if (!fs.existsSync(diskPath)) {
trulyMissing.push(`${f}:${p}`)
continue
}
// imports: {} marks the file with an explicit (empty) resolution
// entry. Without this, b._resolutions[p] stays unset, and
// UnionBundle.load's `Object.entries(b.resolutions[k])` crashes
// on the undefined value.
b.write(p, fs.readFileSync(diskPath), { imports: {} })
inlinedHere++
}
if (inlinedHere === 0) continue
const buf = b.toBuffer()
const b64 = buf.toString('base64')
const newSource =
"const Bundle = require('bare-bundle')\n" +
"module.exports = Bundle.from(\n Buffer.from(\n '" + b64 + "',\n 'base64'\n )\n)\n"
fs.writeFileSync(fullPath, newSource)
console.log(' ' + f.padEnd(20) + ' inlined ' + inlinedHere + ' missing entries')
totalInlined += inlinedHere
bundlesPatched++
}
console.log('patch-keet-bundles: ' + bundlesPatched + '/' + abiFiles.length +
' bundles patched, ' + totalInlined + ' files inlined')
if (trulyMissing.length) {
console.log('patch-keet-bundles: ' + trulyMissing.length +
' references skipped (file not on disk; older-ABI bundle leftovers):')
trulyMissing.slice(0, 10).forEach(s => console.log(' ' + s))
}