Build Core Utils

This commit is contained in:
Raven Scott
2026-04-26 05:40:05 -04:00
parent 1e313507fe
commit 4722e66f19
8 changed files with 244 additions and 10 deletions
+119 -2
View File
@@ -87,6 +87,121 @@ function bareOsEmitRaw(ctx, chunk) {
return false
}
function loginDecodeChunk(chunk) {
if (typeof chunk === 'string') return chunk
if (chunk instanceof Uint8Array) return new TextDecoder().decode(chunk)
if (
typeof Buffer !== 'undefined' &&
typeof Buffer.isBuffer === 'function' &&
Buffer.isBuffer(chunk)
) {
return chunk.toString('utf8')
}
return String(chunk)
}
async function loginReadMaskedLine(ctx, prompt) {
const stdin = ctx.stdin
const stdout = ctx.stdout || globalThis.process?.stdout
if (!stdin || !stdout || typeof stdin.on !== 'function' || typeof stdout.write !== 'function') {
if (typeof ctx.readLine === 'function') return String((await ctx.readLine(prompt)) || '')
return ''
}
stdout.write(prompt)
const ttyIn = stdin
if (!ttyIn.isTTY || typeof ttyIn.setRawMode !== 'function') {
return await new Promise((resolve) => {
let acc = ''
function onData(chunk) {
const s = loginDecodeChunk(chunk)
acc += s
const nl = acc.indexOf('\n')
if (nl >= 0) {
cleanup()
resolve(acc.slice(0, nl).replace(/\r$/, ''))
}
}
function onEnd() {
cleanup()
resolve(acc.replace(/\r$/, ''))
}
function cleanup() {
stdin.removeListener('data', onData)
stdin.removeListener('end', onEnd)
stdin.removeListener('error', onEnd)
}
stdin.on('data', onData)
stdin.once('end', onEnd)
stdin.once('error', onEnd)
if (typeof stdin.resume === 'function') stdin.resume()
})
}
return await new Promise((resolve, reject) => {
const chars = []
let done = false
function finish(ok, err) {
if (done) return
done = true
cleanup()
stdout.write('\n')
if (ok) resolve(chars.join(''))
else reject(err || new Error('masked_input_failed'))
}
function cleanup() {
stdin.removeListener('data', onData)
stdin.removeListener('end', onEnd)
stdin.removeListener('error', onErr)
try {
ttyIn.setRawMode(false)
} catch {
/* ignore */
}
}
function onEnd() {
finish(true)
}
function onErr(e) {
finish(false, e instanceof Error ? e : new Error(String(e)))
}
function onData(chunk) {
if (done) return
const s = loginDecodeChunk(chunk)
for (const ch of s) {
const code = ch.charCodeAt(0)
if (ch === '\r' || ch === '\n') {
finish(true)
return
}
if (ch === '\u0003') {
finish(false, new Error('interrupted'))
return
}
if (ch === '\u007f' || ch === '\b') {
if (chars.length) {
chars.pop()
stdout.write('\b \b')
}
continue
}
if (code >= 32 && code !== 127) {
chars.push(ch)
stdout.write('*')
}
}
}
try {
ttyIn.setRawMode(true)
} catch {
finish(true)
return
}
stdin.on('data', onData)
stdin.once('end', onEnd)
stdin.once('error', onErr)
if (typeof stdin.resume === 'function') stdin.resume()
})
}
async function run(ctx, argv) {
const rest = argv.slice(1)
let createNew = false
@@ -94,9 +209,11 @@ async function run(ctx, argv) {
createNew = true
rest.shift()
}
const passphrase = rest.join(' ')
const passphrase = rest.length
? rest.join(' ')
: await loginReadMaskedLine(ctx, createNew ? 'New passphrase: ' : 'Passphrase: ')
if (!passphrase) {
ctx.console.error('usage: login [--new] <passphrase>')
ctx.console.error('usage: login [--new] [passphrase]')
return
}
const reg = ctx.applyRegister