@dotrino/vault 0.93.0 → 0.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -46,17 +46,17 @@ const argv = process.argv.slice(2)
46
46
  * La línea va por STDERR: `dotrino-env run` le cede stdout a otro programa, y colarle ahí
47
47
  * una cortesía es romperle la tubería a quien lo esté canalizando.
48
48
  */
49
- const avisoVersion = updateNotice({
49
+ const versionNotice = updateNotice({
50
50
  current: VERSION, source: 'npm', pkg: '@dotrino/env', product: 'dotrino-env'
51
51
  }).catch(() => null)
52
52
 
53
53
  /** Lo dice, si hay algo que decir, con un tope: nunca retiene la salida más de 1,5 s. */
54
- let avisoDicho = false
55
- async function decirAvisoVersion () {
56
- if (avisoDicho) return
57
- avisoDicho = true
58
- const linea = await Promise.race([avisoVersion, new Promise((resolve) => setTimeout(() => resolve(null), 1500).unref())])
59
- if (linea) process.stderr.write(`\n[dotrino-env] ${linea} · actualiza con: npm i -g @dotrino/env\n`)
54
+ let noticeShown = false
55
+ async function showVersionNotice () {
56
+ if (noticeShown) return
57
+ noticeShown = true
58
+ const line = await Promise.race([versionNotice, new Promise((resolve) => setTimeout(() => resolve(null), 1500).unref())])
59
+ if (line) process.stderr.write(`\n[dotrino-env] ${line} · actualiza con: npm i -g @dotrino/env\n`)
60
60
  }
61
61
  const flag = (name) => { const i = argv.indexOf('--' + name); return i >= 0 ? argv[i + 1] : undefined }
62
62
 
@@ -68,7 +68,7 @@ const flag = (name) => { const i = argv.indexOf('--' + name); return i >= 0 ? ar
68
68
  * lo que suena en el bolsillo — y con dos ventanas abiertas eso es exactamente lo que hay que
69
69
  * distinguir antes de decir que sí.
70
70
  */
71
- function esperandoAprobacion () {
71
+ function awaitingApproval () {
72
72
  const ctx = selfContext()
73
73
  console.error('[dotrino-env] the vault asks for approval — approve it on a device with «aprueba» (up to 5 min)')
74
74
  console.error('[dotrino-env] %s', commandLine(ctx, 160))
@@ -154,10 +154,10 @@ async function readInvite () {
154
154
  * creando el directorio y hay que decir de quién es. Para USARLO no: el `ns` se busca entre
155
155
  * las bóvedas enroladas y solo hace falta elegir si está en más de una (dueño, 2026-09-01).
156
156
  */
157
- function etiquetaBoveda ({ exigida = false } = {}) {
157
+ function vaultLabel ({ exigida: demanded = false } = {}) {
158
158
  const v = resolveVaultLabel(flag('vault'))
159
159
  if (!v) {
160
- if (!exigida) return null
160
+ if (!demanded) return null
161
161
  console.error('falta --vault <nombre> (o DOTRINO_ENV_VAULT)')
162
162
  console.error('')
163
163
  console.error(' Dice DE QUÉ BÓVEDA es este cajón. Es una etiqueta tuya, de esta máquina:')
@@ -191,23 +191,23 @@ async function cmdEnroll () {
191
191
  // La etiqueta es solo el nombre de una carpeta de esta máquina, así que el nombre de la
192
192
  // cuenta se lleva a minúsculas y se le quitan los caracteres que no valen. Si de ahí no
193
193
  // sale nada utilizable, se pide — no se inventa un nombre.
194
- let boveda = etiquetaBoveda()
195
- if (!boveda) {
194
+ let vault = vaultLabel()
195
+ if (!vault) {
196
196
  const { vaultHello } = await import('../src/service.js')
197
197
  // Se REUSA el qr que vuelve del hello: la cita se quema al canjearla, así que
198
198
  // preguntar el nombre y después enrolar con el qr original gastaba la invitación
199
199
  // en la pregunta y dejaba al enrolamiento sin nada que canjear.
200
200
  qr = await vaultHello(qr).catch(() => qr)
201
- const nombre = qr.acct || ''
202
- boveda = String(nombre || '').toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 32)
203
- if (!boveda) {
201
+ const name = qr.acct || ''
202
+ vault = String(name || '').toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 32)
203
+ if (!vault) {
204
204
  console.error('esa bóveda no dice cómo se llama su cuenta: dime tú la etiqueta')
205
205
  console.error(' ej.: dotrino-env enroll --ns %s --vault mi-boveda --code …', ns)
206
206
  process.exit(2)
207
207
  }
208
- console.log(' bóveda: «%s» (el nombre de la cuenta; se guarda en ~/.dotrino/service/%s/%s)', boveda, boveda, ns)
208
+ console.log(' bóveda: «%s» (el nombre de la cuenta; se guarda en ~/.dotrino/service/%s/%s)', vault, vault, ns)
209
209
  }
210
- const dir = flag('dir') || serviceDir(boveda, ns)
210
+ const dir = flag('dir') || serviceDir(vault, ns)
211
211
 
212
212
  console.log('\nEnrolando el servicio "%s" contra el vault…', ns)
213
213
  const { cert } = await enrollService({
@@ -252,9 +252,9 @@ async function cmdStatus () {
252
252
  // LO QUE QUEDÓ EN EL FORMATO VIEJO se dice y no se usa. Repescarlo en silencio sería
253
253
  // fingir que la migración no hace falta; callarlo dejaría un servicio «desaparecido».
254
254
  if (e.legacy) {
255
- const viejo = path.join(serviceRoot(), e.ns)
255
+ const old = path.join(serviceRoot(), e.ns)
256
256
  console.log('%s ⚠ del formato anterior, sin la bóveda — no se usa', e.ns)
257
- console.log(' muévelo: mkdir -p %s/<bóveda> && mv %s %s/<bóveda>/', serviceRoot(), viejo, serviceRoot())
257
+ console.log(' muévelo: mkdir -p %s/<bóveda> && mv %s %s/<bóveda>/', serviceRoot(), old, serviceRoot())
258
258
  continue
259
259
  }
260
260
  const dir = serviceDir(e.vault, e.ns)
@@ -263,13 +263,13 @@ async function cmdStatus () {
263
263
  // El papel se describe por el ACTA a la que se ató. Uno del modelo viejo se dice tal
264
264
  // cual, con su fecha, porque ESO sí importa: es lo único que todavía caduca, y sabrá
265
265
  // el operador que le queda una migración por hacer.
266
- const papel = typeof c?.seq === 'number'
266
+ const paper = typeof c?.seq === 'number'
267
267
  ? `acta #${c.seq}`
268
268
  : (typeof c?.exp === 'number' ? `modelo viejo · vence ${new Date(c.exp).toISOString().slice(0, 10)}` : '?')
269
- const aparato = id?.device?.publickey ? await shortId(id.device.publickey) : '?'
270
- const boveda = id?.iss ? await shortId(id.iss) : '?'
269
+ const device = id?.device?.publickey ? await shortId(id.device.publickey) : '?'
270
+ const vault = id?.iss ? await shortId(id.iss) : '?'
271
271
  console.log('%s/%s\n id: %s\n dir: %s\n vault: %s\n scope: %s\n cert: %s',
272
- e.vault, e.ns, aparato, dir, boveda, (c?.scope || []).join(', '), papel)
272
+ e.vault, e.ns, device, dir, vault, (c?.scope || []).join(', '), paper)
273
273
  }
274
274
  }
275
275
 
@@ -328,10 +328,10 @@ async function cmdStore (fromFile) {
328
328
  process.exit(1)
329
329
  }
330
330
  const allPublic = argv.includes('--all-public')
331
- const publicas = new Set(String(flag('public') || '').split(',').map((k) => k.trim()).filter(Boolean))
332
- const desconocidas = [...publicas].filter((k) => !parsed.items.some((it) => it.key === k))
333
- if (desconocidas.length) { console.error('--public nombra variables que no se van a subir: %s', desconocidas.join(', ')); process.exit(2) }
334
- const vars = parsed.items.map((it) => ({ key: it.key, value: it.value, public: allPublic || publicas.has(it.key) }))
331
+ const publicOnes = new Set(String(flag('public') || '').split(',').map((k) => k.trim()).filter(Boolean))
332
+ const unknown = [...publicOnes].filter((k) => !parsed.items.some((it) => it.key === k))
333
+ if (unknown.length) { console.error('--public nombra variables que no se van a subir: %s', unknown.join(', ')); process.exit(2) }
334
+ const vars = parsed.items.map((it) => ({ key: it.key, value: it.value, public: allPublic || publicOnes.has(it.key) }))
335
335
 
336
336
  // DE QUIÉN: la identidad de dotrino-env o, con --link, el enlace de un agente (terminal,
337
337
  // ia, content…), que es un aparato con cajón igual que cualquier servicio.
@@ -345,17 +345,17 @@ async function cmdStore (fromFile) {
345
345
  who = { ns, proxyUrl: link.proxy, masterPubkey: link.iss, device: link.device, cert: link.cert, dondeDice: `${linkDir} (cajón ${ns})` }
346
346
  } else {
347
347
  const ns = resolveNs(flag('ns'))
348
- const dir = serviceDir(etiquetaBoveda(), ns)
348
+ const dir = serviceDir(vaultLabel(), ns)
349
349
  who = { dir, ns, dondeDice: `${path.basename(path.dirname(dir))}/${ns}` }
350
350
  }
351
351
 
352
352
  const pub = vars.filter((v) => v.public).map((v) => v.key)
353
353
  console.log('Subiendo %d variable(s) a %s: %s', vars.length, who.dondeDice, vars.map((v) => v.key).join(', '))
354
354
  if (pub.length) console.log(' públicas: %s', pub.join(', '))
355
- const { dondeDice, ...ident } = who
355
+ const { dondeDice: whereItSays, ...ident } = who
356
356
  const r = await storeVars({ ...ident, vars }).catch((e) => {
357
357
  if (e.code === 'exists') {
358
- console.error('\n%s\nSin nadie que pueda aprobar, desde aquí solo se añaden variables nuevas. Para cambiar una que ya existe, hazlo en la bóveda (dotrino-vault secret set) o dale a alguien el permiso de aprobar.', e.message)
358
+ console.error('\n%s\nSin nadie que pueda aprobar, desde aquí solo se añaden variables nuevas. Para cambiar una que ya existe, hazlo en la bóveda (dotrino-vault secret set) o asígnale a alguien el permiso de aprobar.', e.message)
359
359
  } else console.error('\nno se pudo subir: %s', e.message)
360
360
  process.exit(1)
361
361
  })
@@ -380,8 +380,8 @@ async function cmdCheck () {
380
380
  // bóveda contestó, que lo que falta es un permiso, ni cuánto va a esperar. `run` sí lo
381
381
  // decía; `check`, que es el comando de DIAGNÓSTICO, era el único que no. Le pasó al dueño
382
382
  // el 2026-09-05 con un cajón cuyo servicio no tenía a nadie que pudiera aprobarle.
383
- const onPending = () => esperandoAprobacion()
384
- const secrets = await fetchSecrets({ dir: serviceDir(etiquetaBoveda(), ns), ns, publicOnly, onPending })
383
+ const onPending = () => awaitingApproval()
384
+ const secrets = await fetchSecrets({ dir: serviceDir(vaultLabel(), ns), ns, publicOnly, onPending })
385
385
  const keys = Object.keys(secrets)
386
386
  console.log('ns "%s": %d %s%s', ns, keys.length,
387
387
  publicOnly ? 'variable(s) pública(s)' : 'secreto(s)', keys.length ? ':' : '')
@@ -397,7 +397,7 @@ async function cmdRun () {
397
397
  const sep = argv.indexOf('--')
398
398
  const cmd = sep >= 0 ? argv.slice(sep + 1) : []
399
399
  if (!cmd.length) { console.error('uso: dotrino-env run [--vault <bóveda>] [--ns <ns>] [--public] -- <cmd> [args…]'); process.exit(2) }
400
- const onPending = () => esperandoAprobacion()
400
+ const onPending = () => awaitingApproval()
401
401
  // POR QUÉ SE REINTENTA, SIEMPRE. Sin esto la espera es muda: la bóveda contestaba, la
402
402
  // respuesta se caía por un motivo concreto —un aparato sin sobre en su cajón, por
403
403
  // ejemplo— y por fuera solo se veía «waiting for approval» una y otra vez, aunque el
@@ -412,12 +412,12 @@ async function cmdRun () {
412
412
  // ya la ve quien administra. Es lo que quiere un arranque que solo necesita configuración
413
413
  // —una URL, un puerto— y no tiene por qué despertar al dueño.
414
414
  const publicOnly = argv.includes('--public')
415
- const { injected, overridden } = await loadEnv({ ns: flag('ns'), vault: etiquetaBoveda(), onPending, onRetry, publicOnly })
415
+ const { injected, overridden } = await loadEnv({ ns: flag('ns'), vault: vaultLabel(), onPending, onRetry, publicOnly })
416
416
  console.error('[dotrino-env] %d valor(es) en el entorno de %s%s', injected.length, cmd[0],
417
417
  overridden.length ? ` (pisados: ${overridden.join(', ')})` : '')
418
418
  const child = spawn(cmd[0], cmd.slice(1), { stdio: 'inherit', env: process.env })
419
419
  // Al terminar el programa, no antes: mientras corría, la consulta ya se contestó.
420
- child.on('exit', async (code, signal) => { await decirAvisoVersion(); process.exit(signal ? 1 : (code ?? 0)) })
420
+ child.on('exit', async (code, signal) => { await showVersionNotice(); process.exit(signal ? 1 : (code ?? 0)) })
421
421
  }
422
422
 
423
423
  /**
@@ -435,10 +435,10 @@ async function cmdSshAgent () {
435
435
  const { serviceDir, resolveNs } = await import('../src/env.js')
436
436
  const { waitForSecrets } = await import('../src/service.js')
437
437
  const ns = resolveNs(flag('ns') || undefined)
438
- const dir = flag('dir') || serviceDir(etiquetaBoveda(), ns)
438
+ const dir = flag('dir') || serviceDir(vaultLabel(), ns)
439
439
  const socketPath = flag('socket') || defaultSocketPath(dir)
440
440
  console.error('[dotrino-env] asking the vault for the keys of «%s»…', ns)
441
- const secrets = await waitForSecrets({ dir, ns, onPending: () => esperandoAprobacion() })
441
+ const secrets = await waitForSecrets({ dir, ns, onPending: () => awaitingApproval() })
442
442
  const keys = []
443
443
  for (const [name, value] of Object.entries(secrets)) {
444
444
  if (!/^SSH_KEY_[A-Z0-9_]*$/.test(name)) continue
@@ -479,5 +479,5 @@ run()
479
479
  // termina en cuanto LANZA el programa, así que este `.then` lo diría mientras el programa
480
480
  // aún corre, mezclado con su salida. `run` avisa cuando su hijo sale; `ssh-agent` no
481
481
  // termina nunca. Aquí llegan las órdenes cortas.
482
- .then(() => (['run', 'ssh-agent'].includes(argv[0]) ? null : decirAvisoVersion()))
482
+ .then(() => (['run', 'ssh-agent'].includes(argv[0]) ? null : showVersionNotice()))
483
483
  .catch((e) => { console.error('\n[dotrino-env] ' + e.message); process.exit(1) })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/vault",
3
- "version": "0.93.0",
3
+ "version": "0.94.0",
4
4
  "description": "La bóveda de Dotrino como librería: el MISMO núcleo que el binario corriendo en el navegador (`@dotrino/vault/browser`), el mostrador de emparejamiento y el cliente de SERVICIO (Node): un proyecto se enrola una vez y jala sus credenciales del vault en vez del .env (`import '@dotrino/vault/config'`).",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -66,7 +66,7 @@
66
66
  ],
67
67
  "peerDependencies": {
68
68
  "@dotrino/identity": ">=0.118.0",
69
- "@dotrino/proxy-client": ">=0.38.0",
69
+ "@dotrino/proxy-client": ">=0.39.0",
70
70
  "@dotrino/store": ">=0.12.3"
71
71
  },
72
72
  "license": "MIT",
package/src/admin.js CHANGED
@@ -157,7 +157,7 @@ export function createAdminDesk ({
157
157
  now = () => Date.now()
158
158
  }) {
159
159
  const ops = new Set(ADMIN_OPS)
160
- const mientrasCerrada = new Set(ADMIN_OPS_WHILE_LOCKED)
160
+ const whileLocked = new Set(ADMIN_OPS_WHILE_LOCKED)
161
161
 
162
162
  // NONCE de un solo uso. `sign`/`get` son idempotentes y les basta la ventana de ±5
163
163
  // min; `revoke` y `var.set` CAMBIAN ESTADO, así que reproducir uno dentro de esa
@@ -196,7 +196,7 @@ export function createAdminDesk ({
196
196
  //
197
197
  // El código va aparte del texto porque el texto se traduce y el código no: quien
198
198
  // llama distingue «está cerrada, ábrela» de «no tienes permiso» sin leer la frase.
199
- if (isLocked() && !mientrasCerrada.has(data.op)) {
199
+ if (isLocked() && !whileLocked.has(data.op)) {
200
200
  audit('rejected', { what: 'admin', op: data.op, by, reason: 'locked' })
201
201
  return {
202
202
  ok: false,
package/src/browser.js CHANGED
@@ -69,7 +69,7 @@ export async function startBrowserVault ({ core, proxyUrl = DEFAULT_PROXY, makeC
69
69
  }
70
70
  }
71
71
 
72
- const avisar = () => { try { onPendingChange() } catch (_) {} }
72
+ const notify = () => { try { onPendingChange() } catch (_) {} }
73
73
  const vault = await startVault({
74
74
  platform: {
75
75
  disk,
@@ -87,7 +87,7 @@ export async function startBrowserVault ({ core, proxyUrl = DEFAULT_PROXY, makeC
87
87
  // El navegador no tiene la contraseña del perfil con la que el binario cierra la copia
88
88
  // de recuperación: se cierra con la llave de este almacén, y el núcleo lo dice.
89
89
  hasPassword: () => false,
90
- onEnrollChallenge: avisar,
90
+ onEnrollChallenge: notify,
91
91
  onAdopted: (info) => { try { onAdopted(info) } catch (_) {} }
92
92
  })
93
93
 
@@ -109,7 +109,7 @@ export async function startBrowserVault ({ core, proxyUrl = DEFAULT_PROXY, makeC
109
109
  * acta: es verdad que este navegador administra la cuenta. `aprueba` NO, a propósito: con
110
110
  * él los servicios pasarían a esperar el visto bueno de una pestaña que puede no estar.
111
111
  */
112
- const asegurarAdmin = async () => {
112
+ const ensureAdmin = async () => {
113
113
  if (core.masterLocked) return
114
114
  const acta = (await identity.profileActa().catch(() => null))?.acta || null
115
115
  const yo = (acta?.members || []).find((m) => m.pub === master)
@@ -119,15 +119,15 @@ export async function startBrowserVault ({ core, proxyUrl = DEFAULT_PROXY, makeC
119
119
  log('[vault] this browser administers the account: admin added to its own key')
120
120
  }
121
121
  const open = (onReply) => vault.localChannel(onReply)
122
- const presentar = async () => {
122
+ const present = async () => {
123
123
  try {
124
- await asegurarAdmin()
124
+ await ensureAdmin()
125
125
  const cert = await selfCert()
126
126
  core.setSelfVault?.(cert ? { cert, proxy: proxyUrl, open } : null)
127
127
  } catch (e) { log('[vault] the console in this browser cannot administer this vault yet: ' + (e?.message || e)) }
128
128
  }
129
- await presentar()
130
- const refresco = setInterval(presentar, SELF_CERT_EVERY_MS)
129
+ await present()
130
+ const refresh = setInterval(present, SELF_CERT_EVERY_MS)
131
131
 
132
132
  return {
133
133
  ...vault,
@@ -135,8 +135,8 @@ export async function startBrowserVault ({ core, proxyUrl = DEFAULT_PROXY, makeC
135
135
  proxy: proxyUrl,
136
136
  disk,
137
137
  /** Aprueba TIPEANDO el código que muestra el aparato (el núcleo comprueba el compromiso). */
138
- approve: async (_deviceId, code) => { try { return await vault.approveDevice(code) } finally { avisar() } },
139
- reject: (deviceId) => { try { return vault.rejectDevice(deviceId) } finally { avisar() } },
138
+ approve: async (_deviceId, code) => { try { return await vault.approveDevice(code) } finally { notify() } },
139
+ reject: (deviceId) => { try { return vault.rejectDevice(deviceId) } finally { notify() } },
140
140
  /**
141
141
  * Las máquinas con papel de firma de esta cuenta (excluye los navegadores enrolados con
142
142
  * etiqueta `cli`, que no atienden pedidos). Se queda el papel del acta más nueva.
@@ -155,7 +155,7 @@ export async function startBrowserVault ({ core, proxyUrl = DEFAULT_PROXY, makeC
155
155
  revokeDevice: (sub) => vault.revokeDevice({ sub }),
156
156
  revoke: (nonce) => vault.revokeDevice(nonce),
157
157
  async close () {
158
- clearInterval(refresco)
158
+ clearInterval(refresh)
159
159
  try { core.setSelfVault?.(null) } catch (_) {}
160
160
  vault.close()
161
161
  try { await disk.flush() } catch (e) { log('[vault] some changes could not be saved: ' + (e?.message || e)) }
@@ -84,7 +84,7 @@ export function createApprovals ({ now = Date.now, pendingTtlMs = PENDING_TTL_MS
84
84
  * apruebe— y tiene que volver por el mismo sitio: desde que la bóveda atiende también
85
85
  * por un socket local, mandarla siempre por el proxio la dejaba en el vacío.
86
86
  */
87
- request ({ ns, device, deviceId, label = '', ek, ctx = null, from = null, ttlMs = null, kind = 'read' }) {
87
+ request ({ ns, device, deviceId, label = '', ek, ctx = null, from = null, ttlMs = null, kind = 'read', re = null }) {
88
88
  // Pedir las claves otra vez reemplaza al pedido anterior: es la misma pregunta. Una
89
89
  // ESCRITURA no: cada una lleva su propio valor, y reemplazarla tiraría la anterior
90
90
  // sin que nadie dijera que no.
@@ -92,7 +92,8 @@ export function createApprovals ({ now = Date.now, pendingTtlMs = PENDING_TTL_MS
92
92
  const ts = now()
93
93
  // `ttlMs` lo pone quien pide: una actualización aguanta un día y un comando cinco
94
94
  // minutos, y la mesa no tiene por qué saber cuál es cuál (ver `PENDING_TTL_MS`).
95
- const p = { id: rnd(), ns, kind, device, deviceId, label, ek, ctx, ts, exp: ts + (ttlMs || pendingTtlMs), from }
95
+ // `re`: la huella de la petición, para firmarle al que pidió el «denegado» (ver `signError`).
96
+ const p = { id: rnd(), ns, kind, device, deviceId, label, ek, ctx, ts, exp: ts + (ttlMs || pendingTtlMs), from, re }
96
97
  pending.set(p.id, p)
97
98
  return publicOf(p)
98
99
  },
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * LA VERSIÓN DE `@dotrino/vault`, escrita aquí porque el navegador no puede leer el
3
3
  * `package.json`. Con esta se anuncia la bóveda de la pestaña y de la extensión
4
- * (`@dotrino/compat`). Una prueba (`test/version-del-navegador.test.mjs`) para el release
4
+ * (`@dotrino/compat`). Una prueba (`test/browser-version.test.mjs`) para el release
5
5
  * si no coincide con la del paquete: una versión anunciada que no es la que corre es peor
6
6
  * que no anunciar ninguna.
7
7
  */
8
- export const LIB_VERSION = '0.93.0'
8
+ export const LIB_VERSION = '0.94.0'
@@ -163,8 +163,8 @@ export function makeSealer () {
163
163
  * síntoma sería un servicio arrancando sin configuración y sin decir por qué.
164
164
  */
165
165
  async wrapFor (cek, members) {
166
- const { generation, sinLlave } = await makeGeneration({ members, cek })
167
- return { wraps: generation.wraps, sinLlave }
166
+ const { generation, sinLlave: noKey } = await makeGeneration({ members, cek })
167
+ return { wraps: generation.wraps, sinLlave: noKey }
168
168
  }
169
169
  }
170
170
  }
@@ -59,7 +59,7 @@ export function startSealersPublisher ({ identity, client, log = console.log, re
59
59
  if (!registryId) return () => {}
60
60
 
61
61
  /** Una respuesta a `sealers.whois`, o null si no contesta a tiempo. */
62
- function preguntarQuienEs (token, timeoutMs = 8000) {
62
+ function askWhoItIs (token, timeoutMs = 8000) {
63
63
  return new Promise((resolve) => {
64
64
  const fin = (v) => { try { off() } catch (_) {} ; clearTimeout(t); resolve(v) }
65
65
  const off = client.on('message', (_f, p) => { if (p?.op === WHOIS + '.result') fin(p) })
@@ -82,11 +82,11 @@ export function startSealersPublisher ({ identity, client, log = console.log, re
82
82
  * filtraría nada —el eslabón es público— pero se los tragaría EN SILENCIO, que es peor
83
83
  * que un error.
84
84
  */
85
- async function testigo () {
85
+ async function witness () {
86
86
  let tokens
87
87
  try { tokens = await client.list(canal) } catch (_) { return null }
88
88
  for (const token of tokens || []) {
89
- const r = await preguntarQuienEs(token)
89
+ const r = await askWhoItIs(token)
90
90
  const cert = r?.cert
91
91
  if (!cert?.sub || cert.iss !== registryId) continue
92
92
  // AQUÍ SOMOS EXTRAÑOS: no tenemos el acta del registro, así que no podemos preguntarle
@@ -107,11 +107,11 @@ export function startSealersPublisher ({ identity, client, log = console.log, re
107
107
  return null
108
108
  }
109
109
 
110
- let ultima = null
110
+ let latest = null
111
111
 
112
- let avisadoDeOtroTestigo = false
112
+ let warnedOtherWitness = false
113
113
 
114
- async function publicar (motivo) {
114
+ async function publish (reason) {
115
115
  let actas
116
116
  try { actas = await identity.sealerChain?.() } catch (_) { return }
117
117
  if (!Array.isArray(actas)) return
@@ -122,8 +122,8 @@ export function startSealersPublisher ({ identity, client, log = console.log, re
122
122
  // exactamente lo que ese campo existe para impedir. Se dice una vez y se calla.
123
123
  const genesis = actas[0]
124
124
  if (genesis?.chainUrl && registryId === DOTRINO_REGISTRY_ID) {
125
- if (!avisadoDeOtroTestigo) {
126
- avisadoDeOtroTestigo = true
125
+ if (!warnedOtherWitness) {
126
+ warnedOtherWitness = true
127
127
  log(`[sealers] this account names its own registry (${genesis.chainUrl}): not depositing into Dotrino's`)
128
128
  }
129
129
  return
@@ -136,14 +136,14 @@ export function startSealersPublisher ({ identity, client, log = console.log, re
136
136
  // aparece en el registro hasta que selle un acta nueva.
137
137
  if (chain.length < 2) return
138
138
 
139
- const cabeza = chain[chain.length - 1]?.seq
140
- if (cabeza === ultima) return
139
+ const head = chain[chain.length - 1]?.seq
140
+ if (head === latest) return
141
141
  try {
142
- const a = await testigo()
142
+ const a = await witness()
143
143
  if (!a) { log('[sealers] no witness announced in ' + canal + ': the chain stays for the next time'); return }
144
144
  await client.sendByPubkey(a, { op: OP, chain })
145
- ultima = cabeza
146
- log(`[sealers] chain up to #${cabeza} deposited (${motivo})`)
145
+ latest = head
146
+ log(`[sealers] chain up to #${head} deposited (${reason})`)
147
147
  } catch (e) {
148
148
  // Que no se pueda depositar no rompe nada de lo que la bóveda hace: el registro es
149
149
  // una comodidad para terceros, no una dependencia. Se reintenta en la próxima acta.
@@ -151,8 +151,8 @@ export function startSealersPublisher ({ identity, client, log = console.log, re
151
151
  }
152
152
  }
153
153
 
154
- publicar('startup').catch(() => {})
155
- const off = identity.onVault?.((e) => { if (e?.phase === 'acta') publicar(`record #${e.seq}`).catch(() => {}) })
154
+ publish('startup').catch(() => {})
155
+ const off = identity.onVault?.((e) => { if (e?.phase === 'acta') publish(`record #${e.seq}`).catch(() => {}) })
156
156
  return () => { try { off?.() } catch (_) {} }
157
157
  }
158
158