/** * Host-resolved Bare / companion npm modules for in-image scripts (`ctx.bare`), * plus optional merge from trusted IIFE bundles on the system drive. */ import { readFileSync, statSync } from 'fs' import { dirname, join, resolve } from 'path' import { fileURLToPath } from 'url' /** * `fileURLToPath` only accepts `file:` URLs. Pear uses `pear://dev/...` for `import.meta.url`, * so we must not call it at load time or when running under `pear run`. * @returns {string | null} */ function bareOsBooterPackageJsonPathForCreateRequire() { const href = String(import.meta.url) if (!href.startsWith('file:')) return null try { return fileURLToPath(new URL('../package.json', import.meta.url)) } catch { return null } } /** * Drive IIFEs call `require("events")`, `require("bare-stream")`, …; `new Function` has no * lexical `require`, so they look at **`globalThis.require`**. On **`file:`** dev trees, install * Node's `createRequire` for the booter package for the duration of bundle eval. Under Pear * (`pear://`), skip — runtime `require` or `tryBareFetchImportWhenDriveMissing` covers fetch. * @param {() => void | Promise} fn */ async function withDriveBundleGlobalRequire(fn) { if (typeof globalThis.require === 'function') return fn() const pkgJson = bareOsBooterPackageJsonPathForCreateRequire() let installed = false if (pkgJson) { try { const { createRequire } = await import('node:module') globalThis.require = createRequire(pkgJson) installed = true } catch { /* no node:module / createRequire */ } } try { return await fn() } finally { if (installed) { delete globalThis.require } } } export const BARE_OS_STDLIB_GLOBAL = '__bare_os_stdlib__' const MANIFEST_NAME = 'bare-module-manifest.json' /** @param {string} root */ function libDirIfManifestAtRoot(root) { if (!root || root === '/' || root === '') return null const tries = [ join(root, 'lib', MANIFEST_NAME), join(root, 'packages', 'bare-os-booter', 'lib', MANIFEST_NAME) ] for (const f of tries) { try { if (statSync(f).isFile()) return dirname(f) } catch { /* continue */ } } return null } /** * `pear://app/lib/foo.js` → try **`join(mount, 'lib')`** for each bundle mount (manifest must exist). * @param {string} href * @param {string[]} mounts */ function pearUrlLibDir(href, mounts) { if (!href.startsWith('pear:')) return null let u try { u = new URL(href) } catch { return null } const segs = u.pathname.split('/').filter(Boolean) if (segs.length < 2) return null segs.pop() const rel = segs.join('/') if (!rel) return null for (const m of mounts) { if (!m || m === '/') continue const candidate = resolve(join(String(m), rel)) try { if (statSync(join(candidate, MANIFEST_NAME)).isFile()) return candidate } catch { /* continue */ } } return null } /** * Directory containing `bare-module-manifest.json`. Resolved lazily so Pear **`cwd`** / mounts are valid. * Never fall back to **`/lib`** (happens when **`join('/', 'lib')`** after a bogus **`/`** candidate). */ function resolveBareCtxLibDir() { const href = String(import.meta.url) if (href.startsWith('file:')) { return dirname(fileURLToPath(href)) } const rti = globalThis.Pear?.constructor?.RTI?.mount const swap = globalThis.Pear?.config?.swapDir const cwdRaw = typeof globalThis.process?.cwd === 'function' ? globalThis.process.cwd() : '' const cwd = cwdRaw ? resolve(String(cwdRaw)) : resolve('.') let d = cwd for (let i = 0; i < 48; i++) { const found = libDirIfManifestAtRoot(d) if (found) return found const parent = dirname(d) if (parent === d) break d = parent } const mounts = [] const seenM = new Set() for (const c of [rti, swap].filter(Boolean)) { const p = resolve(String(c)) if (p === '/' || !p || seenM.has(p)) continue seenM.add(p) mounts.push(p) } const fromPear = pearUrlLibDir(href, mounts) if (fromPear) return fromPear const seen = new Set() for (const c of [cwd, ...mounts].filter(Boolean)) { const p = resolve(String(c)) if (p === '/' || !p || seen.has(p)) continue seen.add(p) const found = libDirIfManifestAtRoot(p) if (found) return found } throw new Error( `[bare-os-booter] Cannot find ${MANIFEST_NAME}. ` + `cwd=${JSON.stringify(cwdRaw)} pearMount=${JSON.stringify(rti ?? null)} import.meta.url=${JSON.stringify(href.slice(0, 120))}` ) } /** @type {{ version: number, entries: Array<{ ctxKey: string, package: string, export?: string, bundle?: boolean, optional?: boolean, tier?: string }> }} */ let _cachedManifest = null export function loadBareModuleManifest() { if (_cachedManifest) return _cachedManifest const libDir = resolveBareCtxLibDir() const raw = readFileSync(join(libDir, MANIFEST_NAME), 'utf8') _cachedManifest = JSON.parse(raw) return _cachedManifest } /** * @param {Record} shellEnv */ export function bareOsBareModulesEnabled(shellEnv) { if (!shellEnv || typeof shellEnv !== 'object') return true const v = shellEnv.BARE_OS_BARE_MODULES return v !== '0' && v !== 'false' } /** * @param {Record} shellEnv */ export function bareOsBareDriveBundlesEnabled(shellEnv) { if (!shellEnv || typeof shellEnv !== 'object') return true const v = shellEnv.BARE_OS_BARE_DRIVE_BUNDLES if (v === '0' || v === 'false') return false return bareOsBareModulesEnabled(shellEnv) } /** * When false, skip host `import(pkg)` for ctx.bare (use only `/lib/bare` IIFEs). * Set **`BARE_OS_BARE_HOST_IMPORTS=0`** for a fully image-local stdlib. */ export function bareOsBareHostImportsEnabled(shellEnv) { if (!shellEnv || typeof shellEnv !== 'object') return true const v = shellEnv.BARE_OS_BARE_HOST_IMPORTS if (v === '0' || v === 'false') return false return true } /** * Populate object with host `import()` results (per manifest). Mutates `target`. * @param {Record} shellEnv * @param {Record} target */ function bareHostRuntime() { if (typeof globalThis.Bare !== 'undefined') return true const v = globalThis.process?.versions return Boolean(v && typeof v.bare === 'string') } export async function buildBareCtxObjectFromHost(shellEnv, target) { if (!bareOsBareModulesEnabled(shellEnv)) return if (!bareOsBareHostImportsEnabled(shellEnv)) return const { entries } = loadBareModuleManifest() const onBare = bareHostRuntime() const tasks = entries.map(async (ent) => { if (!onBare && ent.nativeHint === true) return null const key = ent.ctxKey if (!key || target[key] !== undefined) return null try { const mod = await import(/* webpackIgnore: true */ ent.package) const val = ent.sideEffectImport ? mod?.default !== undefined ? mod.default : true : ent.export === '*' ? mod : mod?.default !== undefined ? mod.default : mod return { key, ent, val } } catch (err) { return { key, ent, err } } }) const settled = await Promise.all(tasks) for (const r of settled) { if (!r) continue const { key, ent, val, err } = r if (err) { if (!ent.optional) { console.warn( `[bare-os-booter] ctx.bare.${key}: failed to load "${ent.package}":`, err?.message || err ) } continue } if (val !== undefined) target[key] = val } } /** * Execute trusted bundle sources that assign `globalThis.__bare_os_stdlib__[ctxKey]`. * Fills missing keys on `target` only. * @param {Record} shellEnv * @param {{ readFile: (p: string, opts?: unknown) => Promise }} vfs * @param {Record} target */ /** * Optional `/lib/bare/bare-module-lock.json` on the system image: `{ "pins": { "ctxKey": "semver" } }`. * Emits warnings for pins whose `ctxKey` is still missing after drive merge + host import. * @param {{ readFile: (p: string) => Promise }} vfs * @param {Record} target * @returns {Promise} */ export async function verifyBareModuleLockfile(vfs, target) { /** @type {string[]} */ const warnings = [] if (!vfs || typeof vfs.readFile !== 'function') return warnings let buf try { buf = await vfs.readFile('/lib/bare/bare-module-lock.json') } catch { return warnings } if (!buf || !buf.byteLength) return warnings let j try { j = JSON.parse(new TextDecoder().decode(buf)) } catch { warnings.push('bare-module-lock.json: invalid JSON') return warnings } const pins = j && typeof j === 'object' ? j.pins : null if (!pins || typeof pins !== 'object') return warnings for (const [k, ver] of Object.entries(pins)) { if (target[k] === undefined) { warnings.push( `bare-module-lock: ctx.bare.${k} missing (pinned ${String(ver)})` ) } } return warnings } /** * esbuild IIFE assigns `__bare_os_bundle_exports__` (CJS interop object), not the * default export itself. Entries use `export default ` → `{ default: binding }`. * @param {unknown} val */ function unwrapDriveBundleExport(val) { if (val === null || val === undefined) return val if (typeof val !== 'object') return val if (Object.prototype.hasOwnProperty.call(val, 'default')) { const d = /** @type {{ default?: unknown }} */ (val).default if (d !== undefined) return d } return val } export async function maybeMergeBareFromDrive(shellEnv, vfs, target) { if (!bareOsBareModulesEnabled(shellEnv)) return if (!bareOsBareDriveBundlesEnabled(shellEnv)) return if (!vfs || typeof vfs.readFile !== 'function') return let metaBuf try { metaBuf = await vfs.readFile('/lib/bare/manifest.json') } catch { metaBuf = null } if (!metaBuf || metaBuf.byteLength === 0) return let meta try { const text = new TextDecoder().decode(metaBuf) meta = JSON.parse(text) } catch { return } const bundles = meta?.bundles if (!Array.isArray(bundles)) return const g = globalThis const sym = BARE_OS_STDLIB_GLOBAL g[sym] = g[sym] && typeof g[sym] === 'object' ? g[sym] : {} await withDriveBundleGlobalRequire(async () => { for (const b of bundles) { const path = typeof b?.path === 'string' ? b.path : '' const keys = Array.isArray(b?.keys) ? b.keys : [] if (!path.startsWith('/lib/bare/')) continue let srcBuf try { srcBuf = await vfs.readFile(path) } catch { srcBuf = null } if (!srcBuf || srcBuf.byteLength === 0) continue const source = new TextDecoder().decode(srcBuf) if (source.length > 12 * 1024 * 1024) continue try { const run = new Function( `"use strict"; ${source}\n//# sourceURL=bare-drive-bundle:${path}` ) run() } catch (err) { console.warn( `[bare-os-booter] drive bundle failed ${path}:`, err?.message || err ) continue } const snap = g[sym] if (!snap || typeof snap !== 'object') continue for (const k of keys) { if (typeof k !== 'string' || !k) continue if (target[k] !== undefined) continue if (Object.prototype.hasOwnProperty.call(snap, k)) { target[k] = unwrapDriveBundleExport(snap[k]) } } } }) await tryBareFetchImportWhenDriveMissing(target) } /** * When drive `fetch.js` eval fails (no `globalThis.require` or native addons), Bare can still * `import('bare-fetch')` from the booter — same as `buildBareCtxObjectFromHost`, but runs even * when the manifest marks the entry host-only. * @param {Record} target */ async function tryBareFetchImportWhenDriveMissing(target) { if (target.fetch !== undefined) return if (!bareHostRuntime()) return try { let mod if (typeof import.meta.resolve === 'function') { try { mod = await import(import.meta.resolve('bare-fetch')) } catch { mod = await import('bare-fetch') } } else { mod = await import('bare-fetch') } const f = mod?.default if (typeof f === 'function') target.fetch = f } catch { /* optional */ } }