Files
bare-operating-system/packages/bare-os-booter/lib/host/bare-os-disk-os-bridge.js
T
2026-08-18 18:11:28 -04:00

831 lines
27 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Swarm-disk peer RPC bridge: local Hyperdrive path search and whitelisted OS RPC.
* Wired onto {@link import('./swarm-disk.js').SwarmDisk} as `disk.os` after initd bring-up.
*/
import b4a from 'b4a'
import {
BARE_OS_KERNEL_CAPABILITY_WIRE_VERSION,
BARE_OS_KERNEL_CAPABILITY_WORDS_JSON_KEY,
BARE_OS_KERNEL_FEATURE_BITS_DOC,
BARE_OS_PROTOCOL_PACKAGE_VERSION,
BARE_OS_PROTOMUX_CHANNEL_SCHEMA_VERSION,
PROTOCOL_NAME,
getKernelCapabilityWords
} from 'bare-os-protocol'
import { listBareServices } from './bare-initd.js'
import { BareOsKernelError } from './bare-os-errors.js'
import { bareOsCorestoreSnapshotOperatorHint } from './corestore-host-lifecycle.js'
const MAX_SEARCH_RESULTS = 256
/** Allowed `action` values for `bare_os.replication_operator_intent` (P2P operator hints only; no central control). */
const REPLICATION_OPERATOR_INTENT_ACTIONS = new Set([
'pause_hint',
'resume_hint',
'audit_only',
'peer_preference_sketch'
])
const MAX_INTENT_REASON_LEN = 512
const MAX_INTENT_LABEL_LEN = 128
/**
* @param {import('hyperdrive').default | null | undefined} drive
* @param {string} q normalized lowercase query
* @param {string[]} matches mutates
* @param {number} cap
*/
async function collectSearchMatches(drive, q, matches, cap) {
if (!drive || typeof drive.list !== 'function') return
try {
for await (const ent of drive.list('/', { recursive: true })) {
const key = String(ent.key || '')
if (!key) continue
const norm = key.startsWith('/') ? key : `/${key}`
if (norm.toLowerCase().includes(q)) {
matches.push(norm)
if (matches.length >= cap) break
}
}
} catch {
/* drive list failure — skip this drive */
}
}
/** @type {WeakMap<object, { paths: string[], atMs: number }>} */
const pathManifestCache = new WeakMap()
/**
* @param {import('hyperdrive').default | null | undefined} drive
* @param {string} manifestRel absolute path on drive
* @param {number} ttlMs
* @returns {Promise<string[]>}
*/
async function loadPathManifestPaths(drive, manifestRel, ttlMs) {
if (!drive || typeof drive.get !== 'function' || !manifestRel) return []
const now = Date.now()
const cached = pathManifestCache.get(drive)
if (cached && now - cached.atMs < ttlMs) return cached.paths
/** @type {string[]} */
let paths = []
try {
const buf = await drive.get(manifestRel)
if (!buf || !(buf.byteLength > 0)) {
pathManifestCache.set(drive, { paths: [], atMs: now })
return []
}
const text = b4a.toString(buf)
const j = JSON.parse(text)
const arr = Array.isArray(j)
? j
: j && typeof j === 'object' && Array.isArray(j.paths)
? j.paths
: []
paths = arr
.map((p) => String(p || '').trim())
.filter((p) => p.startsWith('/'))
} catch {
paths = []
}
pathManifestCache.set(drive, { paths, atMs: now })
return paths
}
/**
* @param {string[]} manifestPaths
* @param {string} q normalized lowercase query
* @param {string[]} matches
* @param {number} cap
* @returns {number} number of manifest matches appended
*/
function collectManifestMatches(manifestPaths, q, matches, cap) {
let n = 0
for (const p of manifestPaths) {
if (matches.length >= cap) break
if (p.toLowerCase().includes(q)) {
matches.push(p)
n++
}
}
return n
}
/**
* @param {number} ms
* @returns {Promise<void>}
*/
function sleepMs(ms) {
return new Promise((r) => setTimeout(r, ms))
}
/**
* @typedef {{
* drive: import('hyperdrive').default | null | undefined
* auxiliaryDrives?: import('hyperdrive').default[] | null | undefined
* bareOsIpc: { list?: () => string[] } | null | undefined
* ctxApiVersion: string
* systemRevision: Readonly<{ currentId?: string; pendingId?: string; slot?: string }> | null | undefined
* bootStartedMs: number
* seedReplicationStatus?: Record<string, unknown> | null
* seedMirrorDriveHintV2?: Record<string, unknown> | null
* seedHttpDhtProxyHint?: Record<string, unknown> | null
* seedSnapshotHints?: Record<string, unknown> | null
* seedSnapshotManifestSlice?: Record<string, unknown> | null
* seedSnapshotChain?: Record<string, unknown> | null
* swarmPeerCount?: number | null
* swarmConnectionBudget?: Record<string, unknown> | null
* protomuxOperatorSketch?: Record<string, unknown> | null
* auditBatch?: (entries: unknown[]) => unknown
* booterPackageVersion?: string | null
* corestore?: unknown
* seedCapabilityInfo?: Record<string, unknown> | null
* peerSystemSeedMirror?: boolean
* peerSeedSnapshots?: Record<string, unknown | null> | null
* }} BareOsDiskOsBridgeOpts
*/
/**
* @param {BareOsDiskOsBridgeOpts} opts
* @returns {Record<string, unknown> | null}
*/
function buildPeerCapabilitiesBody(opts) {
const cap = opts.seedCapabilityInfo
if (!cap || typeof cap !== 'object') return null
const words = getKernelCapabilityWords(cap)
if (!words) return null
const c = /** @type {Record<string, unknown>} */ (cap)
const chat = c.chatChannel
const tip = c.imageTipId
return {
doc:
typeof c.doc === 'string' ? c.doc : BARE_OS_KERNEL_FEATURE_BITS_DOC,
featureBitsDoc:
typeof c.featureBitsDoc === 'string'
? c.featureBitsDoc
: typeof c.doc === 'string'
? c.doc
: BARE_OS_KERNEL_FEATURE_BITS_DOC,
kernelCapabilityWireVersion:
typeof c.kernelCapabilityWireVersion === 'number'
? c.kernelCapabilityWireVersion
: BARE_OS_KERNEL_CAPABILITY_WIRE_VERSION,
[BARE_OS_KERNEL_CAPABILITY_WORDS_JSON_KEY]: words,
protocolPackageVersion:
typeof c.protocolPackageVersion === 'string'
? c.protocolPackageVersion
: BARE_OS_PROTOCOL_PACKAGE_VERSION,
booterPackageVersion: opts.booterPackageVersion || undefined,
protocol: typeof c.protocol === 'string' ? c.protocol : PROTOCOL_NAME,
role: 'peer-system-seeder',
...(tip != null && String(tip).trim() !== ''
? { imageTipId: String(tip).trim() }
: {}),
...(chat && typeof chat === 'object' ? { chatChannel: chat } : {}),
note:
'Mirrored from publisher capabilities at this node boot; trust matches swarm trust.'
}
}
/**
* @param {BareOsDiskOsBridgeOpts} opts
*/
export function createBareOsDiskOsBridge(opts) {
/** Last `searchLocal` metrics for `disk_os_hints` (schema 3). */
const pathSearchLocalMetrics = {
schema: 1,
lastAtMs: 0,
lastQueryLen: 0,
manifestRel: /** @type {string | null} */ (null),
manifestOnly: false,
manifestEntryCount: 0,
manifestMatchCount: 0,
primaryScanMatchCount: 0,
auxiliaryScanMatchCount: 0
}
return {
/**
* @param {string} query
* @returns {Promise<string[]>}
*/
async searchLocal(query) {
const q = String(query || '').trim().toLowerCase()
if (!q) return []
const env = globalThis.process?.env
const throttleMs = Math.max(
0,
Math.min(500, Number(env?.BARE_OS_DISK_OS_SEARCH_THROTTLE_MS) || 0)
)
const manifestDefault = '/etc/bare-os/path-manifest.json'
const manifestRelRaw = String(
env?.BARE_OS_DISK_OS_PATH_MANIFEST != null
? env.BARE_OS_DISK_OS_PATH_MANIFEST
: manifestDefault
).trim()
const manifestRel =
manifestRelRaw === ''
? ''
: manifestRelRaw.startsWith('/')
? manifestRelRaw
: `/${manifestRelRaw}`
const manifestOnly =
String(env?.BARE_OS_DISK_OS_SEARCH_MANIFEST_ONLY || '') === '1' ||
String(env?.BARE_OS_DISK_OS_SEARCH_MANIFEST_ONLY || '') === 'true'
const cacheMs = Math.max(
0,
Math.min(3600000, Number(env?.BARE_OS_DISK_OS_MANIFEST_CACHE_MS) || 30000)
)
/** @type {import('hyperdrive').default[]} */
const drives = []
if (opts.drive && typeof opts.drive.list === 'function') {
drives.push(opts.drive)
}
if (Array.isArray(opts.auxiliaryDrives)) {
for (const d of opts.auxiliaryDrives) {
if (d && typeof d.list === 'function') drives.push(d)
}
}
/** @type {string[]} */
const raw = []
let manifestMatchCount = 0
let primaryScanCount = 0
let auxScanCount = 0
let manifestEntryCount = 0
const primary = drives[0]
if (primary && manifestRel) {
const mpaths = await loadPathManifestPaths(
primary,
manifestRel,
cacheMs
)
manifestEntryCount = mpaths.length
manifestMatchCount = collectManifestMatches(
mpaths,
q,
raw,
MAX_SEARCH_RESULTS
)
}
if (primary && raw.length < MAX_SEARCH_RESULTS && !manifestOnly) {
const before = raw.length
await collectSearchMatches(
primary,
q,
raw,
MAX_SEARCH_RESULTS - raw.length
)
primaryScanCount += raw.length - before
}
for (let i = 1; i < drives.length && raw.length < MAX_SEARCH_RESULTS; i++) {
if (throttleMs > 0) await sleepMs(throttleMs)
const before = raw.length
await collectSearchMatches(
drives[i],
q,
raw,
MAX_SEARCH_RESULTS - raw.length
)
auxScanCount += raw.length - before
}
pathSearchLocalMetrics.lastAtMs = Date.now()
pathSearchLocalMetrics.lastQueryLen = q.length
pathSearchLocalMetrics.manifestRel = manifestRel || null
pathSearchLocalMetrics.manifestOnly = manifestOnly
pathSearchLocalMetrics.manifestEntryCount = manifestEntryCount
pathSearchLocalMetrics.manifestMatchCount = manifestMatchCount
pathSearchLocalMetrics.primaryScanMatchCount = primaryScanCount
pathSearchLocalMetrics.auxiliaryScanMatchCount = auxScanCount
return [...new Set(raw)]
},
/**
* @param {string} module
* @param {string} method
* @param {string[]} args
* @returns {Promise<string>}
*/
async execRpc(module, method, args) {
const mod = String(module || '').trim()
const meth = String(method || '').trim()
const a = Array.isArray(args) ? args.map((x) => String(x)) : []
if (opts.peerSystemSeedMirror && mod === 'bare_os') {
if (meth === 'capabilities') {
const capB = buildPeerCapabilitiesBody(opts)
if (capB) return JSON.stringify(capB)
}
const snaps = opts.peerSeedSnapshots
if (
snaps &&
typeof snaps === 'object' &&
Object.prototype.hasOwnProperty.call(snaps, meth)
) {
const payload = snaps[meth]
if (payload != null && typeof payload === 'object') {
return JSON.stringify(payload)
}
return JSON.stringify({
schema: 1,
role: 'peer-system-seeder',
ok: false,
reason: 'not_captured_at_boot',
method: meth
})
}
}
if (mod === 'bare_os' && meth === 'ping') return 'pong'
if (mod === 'bare_os' && meth === 'ctx_api_version') {
return String(opts.ctxApiVersion || '')
}
if (mod === 'bare_os' && meth === 'uptime_ms') {
const t = Date.now() - (Number(opts.bootStartedMs) || 0)
return String(Math.max(0, t))
}
if (mod === 'bare_os' && meth === 'system_revision') {
const rev = opts.systemRevision || {}
return JSON.stringify({
currentId: String(rev.currentId || ''),
pendingId: String(rev.pendingId || ''),
slot: String(rev.slot || '')
})
}
if (mod === 'bare_os' && meth === 'ipc_list') {
try {
const ipc = opts.bareOsIpc
const list = typeof ipc?.list === 'function' ? ipc.list() : []
return JSON.stringify(list)
} catch (e) {
return JSON.stringify({
error: (e && /** @type {Error} */ (e).message) || String(e)
})
}
}
if (mod === 'bare_os' && meth === 'service_names') {
try {
const names = listBareServices().map((s) => s.name)
return JSON.stringify(names)
} catch {
return '[]'
}
}
if (mod === 'bare_os' && meth === 'echo') {
return JSON.stringify({ args: a })
}
if (mod === 'bare_os' && meth === 'disk_os_hints') {
const aux = Array.isArray(opts.auxiliaryDrives)
? opts.auxiliaryDrives.filter((d) => d && typeof d.list === 'function')
.length
: 0
const booterVer = String(opts.booterPackageVersion || '').trim()
return JSON.stringify({
schema: 3,
ok: true,
auxiliaryDriveCount: aux,
protocolPackageVersion: BARE_OS_PROTOCOL_PACKAGE_VERSION,
protomuxChannelSchemaVersion: BARE_OS_PROTOMUX_CHANNEL_SCHEMA_VERSION,
booterPackageVersion: booterVer || null,
mirrorDriveHintV2:
opts.seedMirrorDriveHintV2 &&
typeof opts.seedMirrorDriveHintV2 === 'object'
? opts.seedMirrorDriveHintV2
: null,
httpDhtProxyHint:
opts.seedHttpDhtProxyHint &&
typeof opts.seedHttpDhtProxyHint === 'object'
? opts.seedHttpDhtProxyHint
: null,
pathSearchLocal: { ...pathSearchLocalMetrics },
note: 'Schema 3: adds pathSearchLocal metrics (path-manifestaccelerated disk.os searchLocal). Schema 2 fields retained. Advisory hints only.'
})
}
if (mod === 'bare_os' && meth === 'replication_snapshot') {
const drive = opts.drive
if (!drive) {
return JSON.stringify({
schema: 2,
ok: false,
reason: 'no_system_drive'
})
}
const env = globalThis.process?.env
const parseEnvJson = (key) => {
const raw = String(env?.[key] ?? '').trim()
if (!raw) return null
try {
const o = JSON.parse(raw)
return o && typeof o === 'object' ? o : null
} catch {
return { schema: 1, error: 'invalid_json', key }
}
}
try {
const id = /** @type {{ id?: Uint8Array }} */ (drive).id
const dk = /** @type {{ discoveryKey?: Uint8Array }} */ (drive)
.discoveryKey
return JSON.stringify({
schema: 2,
ok: true,
writable: !!drive.writable,
idPrefix:
id && id.byteLength
? b4a.toString(id, 'hex').slice(0, 16)
: null,
discoveryKeyPrefix:
dk && dk.byteLength
? b4a.toString(dk, 'hex').slice(0, 16)
: null,
seedSnapshotHints:
opts.seedSnapshotHints &&
typeof opts.seedSnapshotHints === 'object'
? opts.seedSnapshotHints
: null,
seedSnapshotManifestSlice:
opts.seedSnapshotManifestSlice &&
typeof opts.seedSnapshotManifestSlice === 'object'
? opts.seedSnapshotManifestSlice
: null,
seedSnapshotChain:
opts.seedSnapshotChain &&
typeof opts.seedSnapshotChain === 'object'
? opts.seedSnapshotChain
: null,
corestoreSnapshotEnv: parseEnvJson(
'BARE_OS_CORESTORE_SNAPSHOT_JSON'
),
note:
'Schema 2: adds optional seed snapshot hints/manifest slice/chain (non-secret) plus BARE_OS_CORESTORE_SNAPSHOT_JSON merge for corestore-snapshotstyle operator signals. Hex prefixes unchanged.'
})
} catch (e) {
return JSON.stringify({
schema: 2,
ok: false,
error: (e && /** @type {Error} */ (e).message) || String(e)
})
}
}
if (mod === 'bare_os' && meth === 'replication_operator_sketch') {
const sr = opts.seedReplicationStatus
const env = globalThis.process?.env
const parseEnvJson = (key) => {
const raw = String(env?.[key] ?? '').trim()
if (!raw) return null
try {
const o = JSON.parse(raw)
return o && typeof o === 'object' ? o : null
} catch {
return { schema: 1, error: 'invalid_json', key }
}
}
const sp = Number(opts.swarmPeerCount)
const blindV3 = parseEnvJson('BARE_OS_BLIND_PEER_TOPOLOGY_V3_JSON')
const hblobs = parseEnvJson('BARE_OS_HYPERBLOBS_STATS_JSON')
const corestoreSketch = parseEnvJson('BARE_OS_CORESTORE_STATS_JSON')
const peerPrioritySketch = parseEnvJson(
'BARE_OS_REPLICATION_PEER_PRIORITY_JSON'
)
const hyperdhtAddressSketch = parseEnvJson(
'BARE_OS_HYPERDHT_ADDRESS_JSON'
)
return JSON.stringify({
schema: 8,
ok: true,
seedReplicationStatus:
sr && typeof sr === 'object' ? sr : null,
swarmPeerCount: Number.isFinite(sp) ? sp : null,
swarmConnectionBudget:
opts.swarmConnectionBudget &&
typeof opts.swarmConnectionBudget === 'object'
? opts.swarmConnectionBudget
: null,
protomuxOperatorSketch:
opts.protomuxOperatorSketch &&
typeof opts.protomuxOperatorSketch === 'object'
? opts.protomuxOperatorSketch
: null,
pkgIndexSurface: {
schema: 2,
diskOsRpc: 'bare_os.pkg_index_get',
hrpcRoute: 'bare_os.pkg_index_get',
defaultManifestPath: '/etc/bare-os/pkg-index.json',
envManifestPath: 'BARE_OS_PKG_INDEX_PATH',
listingKeyCap: 512,
note:
'Schema 2: listingKeyCap + manifest schema echo. Hyperbee-backed indexes replicate separately; drive JSON is a static manifest for operators.'
},
hyperdhtAddressSketch,
corestoreSnapshotUxHint: bareOsCorestoreSnapshotOperatorHint(
opts.corestore ?? null
),
corestoreSnapshotPackageRef: {
schema: 1,
npmPackage: 'corestore-snapshot',
upstreamOrg: 'holepunchto',
role:
'Host-side optional workflow; pair BARE_OS_CORESTORE_SNAPSHOT_JSON with BARE_OS_CORESTORE_STATS_JSON — corestoreSnapshotUxHint compares non-secret counts for operator rollback UX.'
},
corestoreSnapshotPaused:
String(env?.BARE_OS_CORESTORE_SNAPSHOT_PAUSED || '') === '1' ||
String(env?.BARE_OS_CORESTORE_SNAPSHOT_PAUSED || '') === 'true',
replicationPausedEnv:
String(env?.BARE_OS_REPLICATION_PAUSED || '') === '1' ||
String(env?.BARE_OS_REPLICATION_PAUSED || '') === 'true',
blindRelayStats: parseEnvJson('BARE_OS_BLIND_RELAY_STATS_JSON'),
replicationBackpressure: parseEnvJson(
'BARE_OS_REPLICATION_BACKPRESSURE_JSON'
),
blindTopologySketchV3: blindV3,
hyperblobsDedupSketch: hblobs,
corestoreOperatorSketch: corestoreSketch,
peerPrioritySketch,
note:
'Schema 8: hyperdhtAddressSketch from BARE_OS_HYPERDHT_ADDRESS_JSON (non-secret); pkgIndexSurface schema 2. Schema 7: corestoreSnapshotUxHint advisory counts. Schema 6: pkgIndexSurface. Schema 5: corestoreOperatorSketch from BARE_OS_CORESTORE_STATS_JSON.'
})
}
if (mod === 'bare_os' && meth === 'replication_operator_intent') {
const env = globalThis.process?.env
const on =
String(env?.BARE_OS_DISK_OS_OPERATOR_INTENT_RPC || '') === '1' ||
String(env?.BARE_OS_DISK_OS_OPERATOR_INTENT_RPC || '') === 'true'
if (!on) {
return JSON.stringify({
schema: 2,
ok: false,
code: 'EPERM',
note:
'replication_operator_intent is cap-gated: set BARE_OS_DISK_OS_OPERATOR_INTENT_RPC=1 on the host.'
})
}
/** @type {Record<string, unknown>} */
let payload = {}
if (a[0]) {
try {
const p = JSON.parse(a[0])
if (p && typeof p === 'object' && !Array.isArray(p)) {
payload = /** @type {Record<string, unknown>} */ (p)
} else {
return JSON.stringify({
schema: 2,
ok: false,
code: 'EINVAL',
note: 'First arg must be a JSON object string (non-array).'
})
}
} catch {
return JSON.stringify({
schema: 2,
ok: false,
code: 'EINVAL',
note: 'First arg must be a JSON object string.'
})
}
}
const act = String(payload.action ?? '').trim()
if (!act || !REPLICATION_OPERATOR_INTENT_ACTIONS.has(act)) {
return JSON.stringify({
schema: 2,
ok: false,
code: 'EINVAL',
note: `Unknown or missing action. Allowed: ${[...REPLICATION_OPERATOR_INTENT_ACTIONS].sort().join(', ')}.`,
allowedActions: [...REPLICATION_OPERATOR_INTENT_ACTIONS].sort()
})
}
const reason = String(payload.reason ?? '').trim()
if (reason.length > MAX_INTENT_REASON_LEN) {
return JSON.stringify({
schema: 2,
ok: false,
code: 'EINVAL',
note: `reason exceeds ${MAX_INTENT_REASON_LEN} chars`
})
}
const label = String(payload.label ?? '').trim()
if (label.length > MAX_INTENT_LABEL_LEN) {
return JSON.stringify({
schema: 2,
ok: false,
code: 'EINVAL',
note: `label exceeds ${MAX_INTENT_LABEL_LEN} chars`
})
}
const ttlRaw = payload.ttlSec
let ttlSec = null
if (ttlRaw != null && ttlRaw !== '') {
const n = Math.floor(Number(ttlRaw))
if (!Number.isFinite(n) || n < 0 || n > 86400 * 7) {
return JSON.stringify({
schema: 2,
ok: false,
code: 'EINVAL',
note: 'ttlSec must be between 0 and 604800 (7 days).'
})
}
ttlSec = n
}
/** @type {Record<string, unknown> | null} */
let backpressureSummary = null
const bpRaw = String(env?.BARE_OS_REPLICATION_BACKPRESSURE_JSON ?? '').trim()
if (bpRaw) {
try {
const bp = JSON.parse(bpRaw)
if (bp && typeof bp === 'object') {
backpressureSummary = {
schema: typeof bp.schema === 'number' ? bp.schema : 1,
keys: Object.keys(bp).slice(0, 24)
}
}
} catch {
backpressureSummary = { parseError: true }
}
}
const normalizedIntent = {
action: act,
...(reason ? { reason } : {}),
...(label ? { label } : {}),
...(ttlSec != null ? { ttlSec } : {})
}
if (typeof opts.auditBatch === 'function') {
try {
opts.auditBatch([
{
kind: 'disk_os.replication_operator_intent',
atMs: Date.now(),
intent: normalizedIntent
}
])
} catch {
/* ignore */
}
}
return JSON.stringify({
schema: 2,
ok: true,
audited: true,
normalizedIntent,
replicationBackpressureSummary: backpressureSummary,
note:
'Schema 2: validates action/reason/label/ttlSec; appends audit via ctx.bareOsAuditLogAppendBatch when wired. Hints only — host applies policy.'
})
}
if (mod === 'bare_os' && meth === 'path_exists') {
const drive = opts.drive
const raw = String(a[0] || '').trim()
if (!raw.startsWith('/')) {
return JSON.stringify({
schema: 1,
ok: false,
code: 'EINVAL',
note: 'path must be absolute'
})
}
if (!drive || typeof drive.get !== 'function') {
return JSON.stringify({
schema: 1,
ok: false,
reason: 'no_system_drive'
})
}
try {
const node = await drive.get(raw)
const exists = node != null
return JSON.stringify({
schema: 1,
ok: true,
path: raw,
exists
})
} catch (e) {
return JSON.stringify({
schema: 1,
ok: false,
error: (e && /** @type {Error} */ (e).message) || String(e)
})
}
}
if (mod === 'bare_os' && meth === 'boot_init_exists') {
const drive = opts.drive
if (!drive || typeof drive.get !== 'function') {
return JSON.stringify({
schema: 1,
ok: false,
reason: 'no_system_drive'
})
}
try {
const p = '/boot/init.js'
const node = await drive.get(p)
return JSON.stringify({
schema: 1,
ok: true,
path: p,
exists: node != null
})
} catch (e) {
return JSON.stringify({
schema: 1,
ok: false,
error: (e && /** @type {Error} */ (e).message) || String(e)
})
}
}
if (mod === 'bare_os' && meth === 'pkg_index_get') {
const drive = opts.drive
const env = globalThis.process?.env
const relRaw = String(
env?.BARE_OS_PKG_INDEX_PATH != null
? env.BARE_OS_PKG_INDEX_PATH
: '/etc/bare-os/pkg-index.json'
).trim()
const rel =
relRaw === ''
? '/etc/bare-os/pkg-index.json'
: relRaw.startsWith('/')
? relRaw
: `/${relRaw}`
const want = String(a[0] || '').trim()
if (!drive || typeof drive.get !== 'function') {
return JSON.stringify({
schema: 1,
ok: false,
reason: 'no_system_drive'
})
}
try {
const node = await drive.get(rel)
if (!node || !node.byteLength) {
return JSON.stringify({
schema: 1,
ok: false,
path: rel,
reason: 'missing_or_empty'
})
}
const j = JSON.parse(b4a.toString(node))
const pkgs =
j &&
typeof j === 'object' &&
j.packages &&
typeof j.packages === 'object'
? /** @type {Record<string, unknown>} */ (j.packages)
: {}
const manifestSchema =
j && typeof j === 'object' && typeof j.schema === 'number'
? j.schema
: 1
if (!want) {
return JSON.stringify({
schema: 2,
ok: true,
path: rel,
manifestSchema,
keys: Object.keys(pkgs).slice(0, 512)
})
}
const ent =
Object.prototype.hasOwnProperty.call(pkgs, want) ? pkgs[want] : null
return JSON.stringify({
schema: 2,
ok: ent != null,
path: rel,
manifestSchema,
key: want,
entry: ent
})
} catch (e) {
return JSON.stringify({
schema: 1,
ok: false,
error: (e && /** @type {Error} */ (e).message) || String(e)
})
}
}
throw new BareOsKernelError(
'BARE_OS_EXEC_RPC_UNKNOWN',
`execRpc: unknown module/method: ${mod}.${meth}`
)
}
}
}