(staged as /lib/init/init-main.js); point bundle-kernel-init and verify scripts at the new path. Wire curl, wget, openssl, ssh-keygen, and tar through coreutils and booter host delegates with booter-side CLI helpers; refresh related bins, bare manifest, shell completion, and man DB (kernel + seeder). Add booter support modules for ACL evaluation, audit chain, secret handles, peer admission, replication priority, process table, swarm lifecycle, boot-graph proc, metrics, monotonic time, protomux alias registry, and swarm peer policy; extend extension resolver, VFS, swarm connection managers, IPC, identity-account, and initd. Harden bare-os-bare-libs build on esbuild failure; add verify scripts for extension manifest schema and runtime incomplete markers; extend ctx API typings, gen-ctx-client-stub, and verify-ctx-dts. Update boot hook fragment, bundled init.js, handbook and reference docs (incl. kernel security and VFS path classes).
109 lines
3.2 KiB
JavaScript
109 lines
3.2 KiB
JavaScript
/**
|
|
* Validated Protomux channel alias registry: logical name → actual channel name.
|
|
* Each actual channel name may be claimed by at most one logical alias at a time.
|
|
* Re-registering the same logical with a different actual overwrites and records history.
|
|
*/
|
|
|
|
const NAME_RE = /^[a-zA-Z][a-zA-Z0-9._-]{0,127}$/
|
|
|
|
/**
|
|
* @param {string} s
|
|
*/
|
|
export function assertValidProtomuxAliasName(s) {
|
|
const t = String(s || '').trim()
|
|
if (!t || t.length > 128) {
|
|
throw new Error('protomux alias: name length must be 1..128')
|
|
}
|
|
if (!NAME_RE.test(t)) {
|
|
throw new Error(
|
|
'protomux alias: name must match ' + NAME_RE.source + ' (logical/actual)'
|
|
)
|
|
}
|
|
return t
|
|
}
|
|
|
|
export function createBareOsProtomuxAliasRegistry() {
|
|
/** @type {Map<string, string>} */
|
|
const logicalToActual = new Map()
|
|
/** @type {Record<string, string>} */
|
|
const legacyMap = Object.create(null)
|
|
/** @type {{ atMs: number, logical: string, previousActual: string | null, actual: string }[]} */
|
|
const changeLog = []
|
|
/** @type {Map<string, string[]>} */
|
|
const actualToLogicals = new Map()
|
|
|
|
function reindexActual(logical, oldAct, newAct) {
|
|
if (oldAct) {
|
|
const arr = actualToLogicals.get(oldAct)
|
|
if (arr) {
|
|
const i = arr.indexOf(logical)
|
|
if (i >= 0) arr.splice(i, 1)
|
|
if (!arr.length) actualToLogicals.delete(oldAct)
|
|
}
|
|
}
|
|
if (newAct) {
|
|
const arr = actualToLogicals.get(newAct) || []
|
|
if (!arr.includes(logical)) arr.push(logical)
|
|
actualToLogicals.set(newAct, arr)
|
|
}
|
|
}
|
|
|
|
return {
|
|
/**
|
|
* @param {string} logicalName
|
|
* @param {string} actualName
|
|
* @returns {{ ok: boolean, conflict?: string, replaced?: boolean }}
|
|
*/
|
|
register(logicalName, actualName) {
|
|
const a = assertValidProtomuxAliasName(logicalName)
|
|
const b = assertValidProtomuxAliasName(actualName)
|
|
const prev = logicalToActual.get(a) || null
|
|
if (prev === b) {
|
|
return { ok: true, replaced: false }
|
|
}
|
|
const others = actualToLogicals.get(b) || []
|
|
if (others.some((o) => o !== a)) {
|
|
return {
|
|
ok: false,
|
|
conflict: `actual ${b} already mapped from logical: ${others.filter((o) => o !== a).join(', ')}`
|
|
}
|
|
}
|
|
reindexActual(a, prev, b)
|
|
logicalToActual.set(a, b)
|
|
legacyMap[a] = b
|
|
changeLog.push({
|
|
atMs: Date.now(),
|
|
logical: a,
|
|
previousActual: prev,
|
|
actual: b
|
|
})
|
|
if (changeLog.length > 256) changeLog.splice(0, changeLog.length - 256)
|
|
return { ok: true, replaced: Boolean(prev) }
|
|
},
|
|
|
|
get(logicalName) {
|
|
const a = String(logicalName || '').trim()
|
|
return logicalToActual.get(a) || null
|
|
},
|
|
|
|
snapshot() {
|
|
const aliases = {}
|
|
for (const [k, v] of logicalToActual.entries()) aliases[k] = v
|
|
return {
|
|
schema: 2,
|
|
aliases,
|
|
changeLogTail: changeLog.slice(-32),
|
|
reverseIndex: Object.fromEntries(
|
|
[...actualToLogicals.entries()].map(([act, logs]) => [act, [...logs]])
|
|
),
|
|
atMs: Date.now()
|
|
}
|
|
},
|
|
|
|
/** @returns {Record<string, string>} same object reference; updated on each register */
|
|
legacyMapView() {
|
|
return legacyMap
|
|
}
|
|
}
|
|
}
|