dotrino-content 0.3.8 → 0.3.9
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.
- package/bin/cli.js +3 -2
- package/lib/ref.js +2 -2
- package/package.json +4 -4
- package/src/agent.js +2 -2
- package/src/announce.js +5 -5
- package/src/blobstore-s3.js +3 -3
- package/src/blobstore.js +2 -2
- package/src/node.js +3 -3
- package/src/s3.js +2 -2
- package/src/server.js +12 -12
- package/src/storage.js +9 -9
- package/src/vaultEnv.js +7 -7
package/bin/cli.js
CHANGED
|
@@ -100,8 +100,9 @@ if (cmd === 'enroll') {
|
|
|
100
100
|
console.log(' (el código NO viaja por la red: lo tipeas tú)')
|
|
101
101
|
}
|
|
102
102
|
})
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
// El papel ya no vence por tiempo: vale mientras el acta lo diga, y se rehace solo
|
|
104
|
+
// cuando cambias permisos. Decir «válido N días» era describir un reloj que ya no existe.
|
|
105
|
+
console.log(`\nlisto: node enlazado. El permiso vale mientras lo diga tu bóveda; si se lo quitas, deja de valer en el acto.`)
|
|
105
106
|
console.log(`identidad en ${serviceDir()} · enlace en ${linkDir()}`)
|
|
106
107
|
console.log(`\nahora carga su configuración en la bóveda (namespace «${NS}»):`)
|
|
107
108
|
console.log(' dotrino-vault secret set content CONTENT_STORAGE=local --public')
|
package/lib/ref.js
CHANGED
|
@@ -31,8 +31,8 @@ export const isValidCid = (cid) => typeof cid === 'string' && CID_RE.test(cid)
|
|
|
31
31
|
* @returns {string} `<owner>/<cid>` o `<owner>/<cid>/<llave>`
|
|
32
32
|
*/
|
|
33
33
|
export function buildRef ({ owner, cid, key = null }) {
|
|
34
|
-
if (!owner) throw new Error('buildRef:
|
|
35
|
-
if (!isValidCid(cid)) throw new Error(`buildRef: cid
|
|
34
|
+
if (!owner) throw new Error('buildRef: owner is required')
|
|
35
|
+
if (!isValidCid(cid)) throw new Error(`buildRef: invalid cid: ${cid}`)
|
|
36
36
|
return key ? `${owner}/${cid}/${key}` : `${owner}/${cid}`
|
|
37
37
|
}
|
|
38
38
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dotrino-content",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Nodo de contenido del ecosistema Dotrino: guarda los bytes del usuario direccionados por su hash (cid), en su propia maquina y, si el dueno quiere, respaldados en su propio bucket (R2, Backblaze, Hetzner, Storj o S3). Lo publico sale por URL directa; lo privado, cifrado y solo por la red Dotrino.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"typescript": "5.9.3"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@dotrino/identity": "0.
|
|
27
|
-
"@dotrino/remote-agent": "0.
|
|
28
|
-
"@dotrino/vault": "0.
|
|
26
|
+
"@dotrino/identity": "0.74.0",
|
|
27
|
+
"@dotrino/remote-agent": "0.6.2",
|
|
28
|
+
"@dotrino/vault": "0.44.0"
|
|
29
29
|
},
|
|
30
30
|
"keywords": [
|
|
31
31
|
"dotrino",
|
package/src/agent.js
CHANGED
|
@@ -53,10 +53,10 @@ export const isLinked = (dir = linkDir()) => {
|
|
|
53
53
|
export async function startContentAgent ({
|
|
54
54
|
node, dir = linkDir(), proxyUrl, version = null, client, quiet = false, onRevoked, announce = true
|
|
55
55
|
} = {}) {
|
|
56
|
-
if (!node) throw new Error('startContentAgent:
|
|
56
|
+
if (!node) throw new Error('startContentAgent: node is required')
|
|
57
57
|
const link = loadLink(dir)
|
|
58
58
|
if (!link?.iss) {
|
|
59
|
-
throw new Error('
|
|
59
|
+
throw new Error('this node is not linked to a vault. Run first: dotrino-content enroll <code>')
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// El node representa a la maestra que lo certificó: su huella es el `ownerId`.
|
package/src/announce.js
CHANGED
|
@@ -51,8 +51,8 @@ export const REPUBLISH_MS = 4 * 60 * 1000
|
|
|
51
51
|
* @returns {{ channels: () => string[], close: () => void }}
|
|
52
52
|
*/
|
|
53
53
|
export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPUBLISH_MS }) {
|
|
54
|
-
if (!client) throw new Error('startAnnounce:
|
|
55
|
-
if (!owner) throw new Error('startAnnounce:
|
|
54
|
+
if (!client) throw new Error('startAnnounce: client is required')
|
|
55
|
+
if (!owner) throw new Error('startAnnounce: owner is required')
|
|
56
56
|
|
|
57
57
|
let stopped = false
|
|
58
58
|
let current = []
|
|
@@ -73,7 +73,7 @@ export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPU
|
|
|
73
73
|
await client.publish(name, { app: 'content', owner })
|
|
74
74
|
done.push(name)
|
|
75
75
|
} catch (e) {
|
|
76
|
-
if (!quiet) console.error(`[content]
|
|
76
|
+
if (!quiet) console.error(`[content] could not announce on ${name}: ${e.message}`)
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
// Se avisa cuando CAMBIA en cuántos proxios está anunciado, no solo la primera vez.
|
|
@@ -82,7 +82,7 @@ export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPU
|
|
|
82
82
|
// estuviera en los dos. Leyendo ese log parecía una federación rota que no lo estaba.
|
|
83
83
|
const changed = done.length !== current.length
|
|
84
84
|
current = done
|
|
85
|
-
if (changed && !quiet) console.log(`[content]
|
|
85
|
+
if (changed && !quiet) console.log(`[content] announced as node for ${owner.slice(0, 16)} on ${done.length} proxio(s) · token ${client.token}`)
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
publishAll()
|
|
@@ -120,7 +120,7 @@ export function startAnnounce ({ client, owner, quiet = false, intervalMs = REPU
|
|
|
120
120
|
* @returns {Promise<string[]>} tokens (direcciones en el proxy)
|
|
121
121
|
*/
|
|
122
122
|
export async function findNodes ({ client, owner }) {
|
|
123
|
-
if (!client || !owner) throw new Error('findNodes:
|
|
123
|
+
if (!client || !owner) throw new Error('findNodes: client and owner are required')
|
|
124
124
|
const known = Array.isArray(client.knownNodes) && client.knownNodes.length
|
|
125
125
|
? client.knownNodes
|
|
126
126
|
: (client.node ? [client.node] : [])
|
package/src/blobstore-s3.js
CHANGED
|
@@ -33,7 +33,7 @@ const IMMUTABLE = 'public, max-age=31536000, immutable'
|
|
|
33
33
|
|
|
34
34
|
/** Del `cid` a la clave del objeto. Sin prefijos: el bucket ya separa público de privado. */
|
|
35
35
|
const keyOf = (cid) => {
|
|
36
|
-
if (!isValidCid(cid)) throw new Error(`cid
|
|
36
|
+
if (!isValidCid(cid)) throw new Error(`invalid cid: ${cid}`)
|
|
37
37
|
return cid
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -46,7 +46,7 @@ export class S3BlobStore {
|
|
|
46
46
|
* @param {(m:string)=>void} [o.log]
|
|
47
47
|
*/
|
|
48
48
|
constructor ({ root, priv, pub = null, log = () => {} }) {
|
|
49
|
-
if (!priv) throw new Error('S3BlobStore:
|
|
49
|
+
if (!priv) throw new Error('S3BlobStore: the private bucket is missing')
|
|
50
50
|
this.cache = new BlobStore(root)
|
|
51
51
|
this.priv = priv
|
|
52
52
|
this.pub = pub
|
|
@@ -63,7 +63,7 @@ export class S3BlobStore {
|
|
|
63
63
|
/** El bucket que le toca a un blob según su ACL. */
|
|
64
64
|
bucketFor (isPublic) {
|
|
65
65
|
if (!isPublic) return this.priv
|
|
66
|
-
if (!this.pub) throw new Error('
|
|
66
|
+
if (!this.pub) throw new Error('this node has no public bucket (CONTENT_S3_BUCKET_PUBLIC)')
|
|
67
67
|
return this.pub
|
|
68
68
|
}
|
|
69
69
|
|
package/src/blobstore.js
CHANGED
|
@@ -44,7 +44,7 @@ export class BlobStore {
|
|
|
44
44
|
|
|
45
45
|
/** Path en disco de un cid (no comprueba existencia). */
|
|
46
46
|
pathFor (cid) {
|
|
47
|
-
if (!isValidCid(cid)) throw new Error(`cid
|
|
47
|
+
if (!isValidCid(cid)) throw new Error(`invalid cid: ${cid}`)
|
|
48
48
|
const hex = cid.slice('sha256-'.length)
|
|
49
49
|
return path.join(this.blobsDir, hex.slice(0, 2), hex.slice(2, 4), cid)
|
|
50
50
|
}
|
|
@@ -73,7 +73,7 @@ export class BlobStore {
|
|
|
73
73
|
transform (chunk, _enc, cb) {
|
|
74
74
|
size += chunk.length
|
|
75
75
|
if (opts.maxBytes && size > opts.maxBytes) {
|
|
76
|
-
cb(Object.assign(new Error('blob
|
|
76
|
+
cb(Object.assign(new Error('blob too large'), { code: 'ETOOBIG' }))
|
|
77
77
|
return
|
|
78
78
|
}
|
|
79
79
|
hash.update(chunk)
|
package/src/node.js
CHANGED
|
@@ -22,7 +22,7 @@ export class ContentNode {
|
|
|
22
22
|
* store: almacén ya montado (`storage.js`); por defecto, disco
|
|
23
23
|
*/
|
|
24
24
|
constructor (opts) {
|
|
25
|
-
if (!opts?.dir) throw new Error('
|
|
25
|
+
if (!opts?.dir) throw new Error('opts.dir is required')
|
|
26
26
|
this.dir = opts.dir
|
|
27
27
|
this.maxBytes = opts.maxBytes || 0
|
|
28
28
|
this.maxBlobBytes = opts.maxBlobBytes || 0
|
|
@@ -61,7 +61,7 @@ export class ContentNode {
|
|
|
61
61
|
const over = (this.index.cachedBytes() + size) - this.maxBytes
|
|
62
62
|
if (over > 0 && this.gc({ needBytes: over }).freed < over) {
|
|
63
63
|
await this.store.remove(cid)
|
|
64
|
-
throw Object.assign(new Error('
|
|
64
|
+
throw Object.assign(new Error('disk quota exceeded'), { code: 'ENOSPC' })
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
this.index.upsert({ cid, size, mime, owner: this.owner, enc, acl, ttl, meta })
|
|
@@ -120,7 +120,7 @@ export class ContentNode {
|
|
|
120
120
|
const p = (prev ? prev.catch(() => {}) : Promise.resolve())
|
|
121
121
|
.then(() => this.store.upload(cid, meta))
|
|
122
122
|
.then(() => { this.index.setRemote(cid, true) })
|
|
123
|
-
.catch((e) => { this.log(`[
|
|
123
|
+
.catch((e) => { this.log(`[storage] could not upload ${cid.slice(0, 14)}…: ${e.message}`) })
|
|
124
124
|
.finally(() => this._uploading.delete(cid))
|
|
125
125
|
this._uploading.set(cid, p)
|
|
126
126
|
return p
|
package/src/s3.js
CHANGED
|
@@ -142,7 +142,7 @@ export class S3Bucket {
|
|
|
142
142
|
*/
|
|
143
143
|
constructor ({ endpoint, bucket, accessKeyId, secretAccessKey, region = 'auto', fetch: f = fetch }) {
|
|
144
144
|
if (!endpoint || !bucket || !accessKeyId || !secretAccessKey) {
|
|
145
|
-
throw new Error('S3Bucket:
|
|
145
|
+
throw new Error('S3Bucket: missing endpoint, bucket or credentials')
|
|
146
146
|
}
|
|
147
147
|
this.base = `${String(endpoint).replace(/\/+$/, '')}/${bucket}`
|
|
148
148
|
this.bucket = bucket
|
|
@@ -198,7 +198,7 @@ export class S3Bucket {
|
|
|
198
198
|
* @param {{ sha256?: string, size?: number, contentType?: string, cacheControl?: string }} [o]
|
|
199
199
|
*/
|
|
200
200
|
async put (key, body, { sha256 = '', size = 0, contentType = '', cacheControl = '' } = {}) {
|
|
201
|
-
if (!sha256) throw new Error('S3Bucket.put:
|
|
201
|
+
if (!sha256) throw new Error('S3Bucket.put: the sha256 of the content is required')
|
|
202
202
|
/** @type {Record<string,string>} */
|
|
203
203
|
const headers = {}
|
|
204
204
|
if (contentType) headers['content-type'] = contentType
|
package/src/server.js
CHANGED
|
@@ -49,8 +49,8 @@ export function createServer (node) {
|
|
|
49
49
|
await route(node, req, res)
|
|
50
50
|
} catch (err) {
|
|
51
51
|
if (res.headersSent) { res.destroy(); return }
|
|
52
|
-
if (err.code === 'ETOOBIG') return json(res, 413, { error: 'blob
|
|
53
|
-
if (err.code === 'ENOSPC') return json(res, 507, { error: '
|
|
52
|
+
if (err.code === 'ETOOBIG') return json(res, 413, { error: 'blob too large' })
|
|
53
|
+
if (err.code === 'ENOSPC') return json(res, 507, { error: 'disk quota exceeded' })
|
|
54
54
|
json(res, 500, { error: err.message })
|
|
55
55
|
}
|
|
56
56
|
})
|
|
@@ -71,16 +71,16 @@ async function route (node, req, res) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
if (top === 'c' && cid) {
|
|
74
|
-
if (!isValidCid(cid)) return json(res, 400, { error: 'cid
|
|
74
|
+
if (!isValidCid(cid)) return json(res, 400, { error: 'invalid cid' })
|
|
75
75
|
const meta = node.stat(cid)
|
|
76
|
-
if (!meta) return json(res, 404, { error: '
|
|
76
|
+
if (!meta) return json(res, 404, { error: 'not found' })
|
|
77
77
|
|
|
78
78
|
if (req.method === 'DELETE') {
|
|
79
79
|
await node.remove(cid)
|
|
80
80
|
return json(res, 200, { ok: true })
|
|
81
81
|
}
|
|
82
82
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
83
|
-
return json(res, 405, { error: '
|
|
83
|
+
return json(res, 405, { error: 'method not allowed' })
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
const headers = {
|
|
@@ -115,9 +115,9 @@ async function route (node, req, res) {
|
|
|
115
115
|
if (req.method === 'GET' && top === 'stats') return json(res, 200, node.stats())
|
|
116
116
|
|
|
117
117
|
if (req.method === 'POST' && (top === 'pin' || top === 'unpin') && cid) {
|
|
118
|
-
if (!isValidCid(cid)) return json(res, 400, { error: 'cid
|
|
118
|
+
if (!isValidCid(cid)) return json(res, 400, { error: 'invalid cid' })
|
|
119
119
|
const ok = node.pin(cid, top === 'pin')
|
|
120
|
-
return ok ? json(res, 200, { ok: true }) : json(res, 404, { error: '
|
|
120
|
+
return ok ? json(res, 200, { ok: true }) : json(res, 404, { error: 'not found' })
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// PUBLICAR / despublicar. Existía solo por el plano de control, y eso dejaba sin poder
|
|
@@ -127,16 +127,16 @@ async function route (node, req, res) {
|
|
|
127
127
|
// Con bucket detrás, marcar público MUEVE los bytes al bucket público, que es otro
|
|
128
128
|
// (§15.1): por eso pasa por `node.setAcl` y no por el índice a secas.
|
|
129
129
|
if (req.method === 'POST' && (top === 'public' || top === 'private') && cid) {
|
|
130
|
-
if (!isValidCid(cid)) return json(res, 400, { error: 'cid
|
|
130
|
+
if (!isValidCid(cid)) return json(res, 400, { error: 'invalid cid' })
|
|
131
131
|
const meta = node.stat(cid)
|
|
132
|
-
if (!meta) return json(res, 404, { error: '
|
|
132
|
+
if (!meta) return json(res, 404, { error: 'not found' })
|
|
133
133
|
// Un blob CIFRADO no puede ser público, y se rechaza aquí además de en el índice:
|
|
134
134
|
// es la misma frontera del §7.2, y una frontera que solo se comprueba en un sitio
|
|
135
135
|
// acaba teniendo un camino que no pasa por ese sitio.
|
|
136
|
-
if (top === 'public' && meta.enc) return json(res, 400, { error: '
|
|
136
|
+
if (top === 'public' && meta.enc) return json(res, 400, { error: 'an encrypted blob cannot be public' })
|
|
137
137
|
const ok = node.setAcl(cid, top === 'public' ? 'public' : null)
|
|
138
|
-
return ok ? json(res, 200, { ok: true, acl: top === 'public' ? 'public' : null }) : json(res, 404, { error: '
|
|
138
|
+
return ok ? json(res, 200, { ok: true, acl: top === 'public' ? 'public' : null }) : json(res, 404, { error: 'not found' })
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
json(res, 404, { error: '
|
|
141
|
+
json(res, 404, { error: 'unknown route' })
|
|
142
142
|
}
|
package/src/storage.js
CHANGED
|
@@ -83,7 +83,7 @@ export async function checkBuckets (cfg, { priv, pub }, f = fetch) {
|
|
|
83
83
|
|
|
84
84
|
// 1. El mismo bucket para las dos cosas: lo privado acabaría en el que tiene dominio.
|
|
85
85
|
if (cfg.pub && cfg.pub === cfg.priv) {
|
|
86
|
-
fatal.push('
|
|
86
|
+
fatal.push('the private and public buckets are the same: encrypted blobs would land in the one with a domain')
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// 2. El privado NO puede responder sin credenciales. Se pide un objeto que no existe:
|
|
@@ -98,7 +98,7 @@ export async function checkBuckets (cfg, { priv, pub }, f = fetch) {
|
|
|
98
98
|
try {
|
|
99
99
|
const r = await f(priv.urlFor('sha256-' + '0'.repeat(64)), { method: 'GET' })
|
|
100
100
|
if (r.status === 404 || r.ok) {
|
|
101
|
-
fatal.push(`
|
|
101
|
+
fatal.push(`the private bucket "${cfg.priv}" answers without credentials (HTTP ${r.status}): it is open to the world`)
|
|
102
102
|
}
|
|
103
103
|
} catch (e) {
|
|
104
104
|
warn.push(`no se pudo comprobar si el bucket privado está cerrado: ${e.message}`)
|
|
@@ -143,12 +143,12 @@ export async function openStore ({ dir, env = process.env, log = () => {}, check
|
|
|
143
143
|
if (cfg.kind === 'local') return { store: await new BlobStore(dir).init(), cfg }
|
|
144
144
|
|
|
145
145
|
if (!cfg.provider) {
|
|
146
|
-
log(`[
|
|
146
|
+
log(`[storage] CONTENT_STORAGE="${cfg.kind}" is not a known provider (${Object.keys(PROVIDERS).join(', ')}); staying on LOCAL`)
|
|
147
147
|
return { store: await new BlobStore(dir).init(), cfg }
|
|
148
148
|
}
|
|
149
149
|
if (cfg.missing.length) {
|
|
150
|
-
log(`[
|
|
151
|
-
log('[
|
|
150
|
+
log(`[storage] ${cfg.kind} requested but these variables are missing: ${cfg.missing.join(', ')}`)
|
|
151
|
+
log('[storage] staying on LOCAL: a half-configured store is worse than none')
|
|
152
152
|
return { store: await new BlobStore(dir).init(), cfg }
|
|
153
153
|
}
|
|
154
154
|
|
|
@@ -160,15 +160,15 @@ export async function openStore ({ dir, env = process.env, log = () => {}, check
|
|
|
160
160
|
|
|
161
161
|
if (check) {
|
|
162
162
|
const { ok, fatal, warn } = await checkBuckets(cfg, { priv, pub }, f)
|
|
163
|
-
for (const w of warn) log(`[
|
|
163
|
+
for (const w of warn) log(`[storage] ⚠ ${w}`)
|
|
164
164
|
if (!ok) {
|
|
165
|
-
for (const e of fatal) log(`[
|
|
166
|
-
log('[
|
|
165
|
+
for (const e of fatal) log(`[storage] ✖ ${e}`)
|
|
166
|
+
log('[storage] staying on LOCAL until that is fixed')
|
|
167
167
|
return { store: await new BlobStore(dir).init(), cfg }
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
log(`[
|
|
171
|
+
log(`[storage] ${cfg.kind}: private "${cfg.priv}"${cfg.pub ? `, public "${cfg.pub}" at ${cfg.baseUrl}` : ' (no public bucket: public reads go over the network)'}`)
|
|
172
172
|
return { store: await new S3BlobStore({ root: dir, priv, pub, log }).init(), cfg }
|
|
173
173
|
}
|
|
174
174
|
|
package/src/vaultEnv.js
CHANGED
|
@@ -95,7 +95,7 @@ export function startVaultConfig ({ dir = serviceDir(), onSecrets, log = console
|
|
|
95
95
|
let expired = false
|
|
96
96
|
const deadline = setTimeout(() => {
|
|
97
97
|
expired = true
|
|
98
|
-
log(`[vault]
|
|
98
|
+
log(`[vault] no answer in ${Math.round(firstWaitMs / 1000)}s: starting with the local config and restarting when it arrives`)
|
|
99
99
|
arrive(null)
|
|
100
100
|
}, firstWaitMs)
|
|
101
101
|
deadline.unref?.()
|
|
@@ -106,13 +106,13 @@ export function startVaultConfig ({ dir = serviceDir(), onSecrets, log = console
|
|
|
106
106
|
const secrets = await waitForSecrets({
|
|
107
107
|
dir,
|
|
108
108
|
ns: NS,
|
|
109
|
-
onRetry: (e, delay) => log(`[vault]
|
|
109
|
+
onRetry: (e, delay) => log(`[vault] no config yet (${e.message}); retrying in ${Math.round(delay / 1000)}s`)
|
|
110
110
|
})
|
|
111
111
|
if (stopped) return
|
|
112
112
|
|
|
113
113
|
const { injected, overridden } = applyEnv(secrets)
|
|
114
|
-
log(`[vault] ${injected.length}
|
|
115
|
-
if (overridden.length) log(`[vault]
|
|
114
|
+
log(`[vault] applied ${injected.length} value(s) from the vault to the environment`)
|
|
115
|
+
if (overridden.length) log(`[vault] these overrode the machine environment: ${overridden.join(', ')}`)
|
|
116
116
|
clearTimeout(deadline)
|
|
117
117
|
arrive(secrets)
|
|
118
118
|
onSecrets?.(secrets)
|
|
@@ -124,7 +124,7 @@ export function startVaultConfig ({ dir = serviceDir(), onSecrets, log = console
|
|
|
124
124
|
// configuración correcta puesta en el entorno y sin usarla. Se sale, y el
|
|
125
125
|
// supervisor lo levanta ya con todo.
|
|
126
126
|
if (expired) {
|
|
127
|
-
log('[vault]
|
|
127
|
+
log('[vault] config arrived after startup: restarting to pick it up')
|
|
128
128
|
setTimeout(() => process.exit(0), 300)
|
|
129
129
|
return
|
|
130
130
|
}
|
|
@@ -139,13 +139,13 @@ export function startVaultConfig ({ dir = serviceDir(), onSecrets, log = console
|
|
|
139
139
|
...(onChange
|
|
140
140
|
? {
|
|
141
141
|
onUpdate: ({ reason }) => {
|
|
142
|
-
log(`[vault] ${reason === 'revoked' ? '
|
|
142
|
+
log(`[vault] ${reason === 'revoked' ? 'this device was revoked' : 'new config arrived'}`)
|
|
143
143
|
onChange()
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
: {})
|
|
147
147
|
})
|
|
148
|
-
})().catch((e) => { log(`[vault]
|
|
148
|
+
})().catch((e) => { log(`[vault] could not read the config: ${e.message}`); clearTimeout(deadline); arrive(null) })
|
|
149
149
|
|
|
150
150
|
return {
|
|
151
151
|
enabled: true,
|