1# cacache [](https://npm.im/cacache) [](https://npm.im/cacache) [](https://travis-ci.org/zkat/cacache) [](https://ci.appveyor.com/project/zkat/cacache) [](https://coveralls.io/github/zkat/cacache?branch=latest) 2 3[`cacache`](https://github.com/zkat/cacache) es una librería de Node.js para 4manejar caches locales en disco, con acceso tanto con claves únicas como 5direcciones de contenido (hashes/hacheos). Es súper rápida, excelente con el 6acceso concurrente, y jamás te dará datos incorrectos, aún si se corrompen o 7manipulan directamente los ficheros del cache. 8 9El propósito original era reemplazar el caché local de 10[npm](https://npm.im/npm), pero se puede usar por su propia cuenta. 11 12_Traducciones: [English](README.md)_ 13 14## Instalación 15 16`$ npm install --save cacache` 17 18## Índice 19 20* [Ejemplo](#ejemplo) 21* [Características](#características) 22* [Cómo Contribuir](#cómo-contribuir) 23* [API](#api) 24 * [Usando el API en español](#localized-api) 25 * Leer 26 * [`ls`](#ls) 27 * [`ls.flujo`](#ls-stream) 28 * [`saca`](#get-data) 29 * [`saca.flujo`](#get-stream) 30 * [`saca.info`](#get-info) 31 * [`saca.tieneDatos`](#get-hasContent) 32 * Escribir 33 * [`mete`](#put-data) 34 * [`mete.flujo`](#put-stream) 35 * [opciones para `mete*`](#put-options) 36 * [`rm.todo`](#rm-all) 37 * [`rm.entrada`](#rm-entry) 38 * [`rm.datos`](#rm-content) 39 * Utilidades 40 * [`ponLenguaje`](#set-locale) 41 * [`limpiaMemoizado`](#clear-memoized) 42 * [`tmp.hazdir`](#tmp-mkdir) 43 * [`tmp.conTmp`](#with-tmp) 44 * Integridad 45 * [Subresource Integrity](#integrity) 46 * [`verifica`](#verify) 47 * [`verifica.ultimaVez`](#verify-last-run) 48 49### Ejemplo 50 51```javascript 52const cacache = require('cacache/es') 53const fs = require('fs') 54 55const tarbol = '/ruta/a/mi-tar.tgz' 56const rutaCache = '/tmp/my-toy-cache' 57const clave = 'mi-clave-única-1234' 58 59// ¡Añádelo al caché! Usa `rutaCache` como raíz del caché. 60cacache.mete(rutaCache, clave, '10293801983029384').then(integrity => { 61 console.log(`Saved content to ${rutaCache}.`) 62}) 63 64const destino = '/tmp/mytar.tgz' 65 66// Copia el contenido del caché a otro fichero, pero esta vez con flujos. 67cacache.saca.flujo( 68 rutaCache, clave 69).pipe( 70 fs.createWriteStream(destino) 71).on('finish', () => { 72 console.log('extracción completada') 73}) 74 75// La misma cosa, pero accesando el contenido directamente, sin tocar el índice. 76cacache.saca.porHacheo(rutaCache, integridad).then(datos => { 77 fs.writeFile(destino, datos, err => { 78 console.log('datos del tarbol sacados basado en su sha512, y escrito a otro fichero') 79 }) 80}) 81``` 82 83### Características 84 85* Extracción por clave o por dirección de contenido (shasum, etc) 86* Usa el estándard de web, [Subresource Integrity](#integrity) 87* Compatible con multiples algoritmos - usa sha1, sha512, etc, en el mismo caché sin problema 88* Entradas con contenido idéntico comparten ficheros 89* Tolerancia de fallas (inmune a corrupción, ficheros parciales, carreras de proceso, etc) 90* Verificación completa de datos cuando (escribiendo y leyendo) 91* Concurrencia rápida, segura y "lockless" 92* Compatible con `stream`s (flujos) 93* Compatible con `Promise`s (promesas) 94* Bastante rápida -- acceso, incluyendo verificación, en microsegundos 95* Almacenaje de metadatos arbitrarios 96* Colección de basura y verificación adicional fuera de banda 97* Cobertura rigurosa de pruebas 98* Probablente hay un "Bloom filter" por ahí en algún lado. Eso le mola a la gente, ¿Verdad? 99 100### Cómo Contribuir 101 102El equipo de cacache felizmente acepta contribuciones de código y otras maneras de participación. ¡Hay muchas formas diferentes de contribuir! La [Guía de Colaboradores](CONTRIBUTING.md) (en inglés) tiene toda la información que necesitas para cualquier tipo de contribución: todo desde cómo reportar errores hasta cómo someter parches con nuevas características. Con todo y eso, no se preocupe por si lo que haces está exáctamente correcto: no hay ningún problema en hacer preguntas si algo no está claro, o no lo encuentras. 103 104El equipo de cacache tiene miembros hispanohablantes: es completamente aceptable crear `issues` y `pull requests` en español/castellano. 105 106Todos los participantes en este proyecto deben obedecer el [Código de Conducta](CODE_OF_CONDUCT.md) (en inglés), y en general actuar de forma amable y respetuosa mientras participan en esta comunidad. 107 108Por favor refiérase al [Historial de Cambios](CHANGELOG.md) (en inglés) para detalles sobre cambios importantes incluídos en cada versión. 109 110Finalmente, cacache tiene un sistema de localización de lenguaje. Si te interesa añadir lenguajes o mejorar los que existen, mira en el directorio `./locales` para comenzar. 111 112Happy hacking! 113 114### API 115 116#### <a name="localized-api"></a> Usando el API en español 117 118cacache incluye una traducción completa de su API al castellano, con las mismas 119características. Para usar el API como está documentado en este documento, usa 120`require('cacache/es')` 121 122cacache también tiene otros lenguajes: encuéntralos bajo `./locales`, y podrás 123usar el API en ese lenguaje con `require('cacache/<lenguaje>')` 124 125#### <a name="ls"></a> `> cacache.ls(cache) -> Promise<Object>` 126 127Enumera todas las entradas en el caché, dentro de un solo objeto. Cada entrada 128en el objeto tendrá como clave la clave única usada para el índice, el valor 129siendo un objeto de [`saca.info`](#get-info). 130 131##### Ejemplo 132 133```javascript 134cacache.ls(rutaCache).then(console.log) 135// Salida 136{ 137 'my-thing': { 138 key: 'my-thing', 139 integrity: 'sha512-BaSe64/EnCoDED+HAsh==' 140 path: '.testcache/content/deadbeef', // unido con `rutaCache` 141 time: 12345698490, 142 size: 4023948, 143 metadata: { 144 name: 'blah', 145 version: '1.2.3', 146 description: 'this was once a package but now it is my-thing' 147 } 148 }, 149 'other-thing': { 150 key: 'other-thing', 151 integrity: 'sha1-ANothER+hasH=', 152 path: '.testcache/content/bada55', 153 time: 11992309289, 154 size: 111112 155 } 156} 157``` 158 159#### <a name="ls-stream"></a> `> cacache.ls.flujo(cache) -> Readable` 160 161Enumera todas las entradas en el caché, emitiendo un objeto de 162[`saca.info`](#get-info) por cada evento de `data` en el flujo. 163 164##### Ejemplo 165 166```javascript 167cacache.ls.flujo(rutaCache).on('data', console.log) 168// Salida 169{ 170 key: 'my-thing', 171 integrity: 'sha512-BaSe64HaSh', 172 path: '.testcache/content/deadbeef', // unido con `rutaCache` 173 time: 12345698490, 174 size: 13423, 175 metadata: { 176 name: 'blah', 177 version: '1.2.3', 178 description: 'this was once a package but now it is my-thing' 179 } 180} 181 182{ 183 key: 'other-thing', 184 integrity: 'whirlpool-WoWSoMuchSupport', 185 path: '.testcache/content/bada55', 186 time: 11992309289, 187 size: 498023984029 188} 189 190{ 191 ... 192} 193``` 194 195#### <a name="get-data"></a> `> cacache.saca(cache, clave, [ops]) -> Promise({data, metadata, integrity})` 196 197Devuelve un objeto con los datos, hacheo de integridad y metadatos identificados 198por la `clave`. La propiedad `data` de este objeto será una instancia de 199`Buffer` con los datos almacenados en el caché. to do with it! cacache just 200won't care. 201 202`integrity` es un `string` de [Subresource Integrity](#integrity). Dígase, un 203`string` que puede ser usado para verificar a la `data`, que tiene como formato 204`<algoritmo>-<hacheo-integridad-base64>`. 205 206So no existe ninguna entrada identificada por `clave`, o se los datos 207almacenados localmente fallan verificación, el `Promise` fallará. 208 209Una sub-función, `saca.porHacheo`, tiene casi el mismo comportamiento, excepto 210que busca entradas usando el hacheo de integridad, sin tocar el índice general. 211Esta versión *sólo* devuelve `data`, sin ningún objeto conteniéndola. 212 213##### Nota 214 215Esta función lee la entrada completa a la memoria antes de devolverla. Si estás 216almacenando datos Muy Grandes, es posible que [`saca.flujo`](#get-stream) sea 217una mejor solución. 218 219##### Ejemplo 220 221```javascript 222// Busca por clave 223cache.saca(rutaCache, 'my-thing').then(console.log) 224// Salida: 225{ 226 metadata: { 227 thingName: 'my' 228 }, 229 integrity: 'sha512-BaSe64HaSh', 230 data: Buffer#<deadbeef>, 231 size: 9320 232} 233 234// Busca por hacheo 235cache.saca.porHacheo(rutaCache, 'sha512-BaSe64HaSh').then(console.log) 236// Salida: 237Buffer#<deadbeef> 238``` 239 240#### <a name="get-stream"></a> `> cacache.saca.flujo(cache, clave, [ops]) -> Readable` 241 242Devuelve un [Readable 243Stream](https://nodejs.org/api/stream.html#stream_readable_streams) de los datos 244almacenados bajo `clave`. 245 246So no existe ninguna entrada identificada por `clave`, o se los datos 247almacenados localmente fallan verificación, el `Promise` fallará. 248 249`metadata` y `integrity` serán emitidos como eventos antes de que el flujo 250cierre. 251 252Una sub-función, `saca.flujo.porHacheo`, tiene casi el mismo comportamiento, 253excepto que busca entradas usando el hacheo de integridad, sin tocar el índice 254general. Esta versión no emite eventos de `metadata` o `integrity`. 255 256##### Ejemplo 257 258```javascript 259// Busca por clave 260cache.saca.flujo( 261 rutaCache, 'my-thing' 262).on('metadata', metadata => { 263 console.log('metadata:', metadata) 264}).on('integrity', integrity => { 265 console.log('integrity:', integrity) 266}).pipe( 267 fs.createWriteStream('./x.tgz') 268) 269// Salidas: 270metadata: { ... } 271integrity: 'sha512-SoMeDIGest+64==' 272 273// Busca por hacheo 274cache.saca.flujo.porHacheo( 275 rutaCache, 'sha512-SoMeDIGest+64==' 276).pipe( 277 fs.createWriteStream('./x.tgz') 278) 279``` 280 281#### <a name="get-info"></a> `> cacache.saca.info(cache, clave) -> Promise` 282 283Busca la `clave` en el índice del caché, devolviendo información sobre la 284entrada si existe. 285 286##### Campos 287 288* `key` - Clave de la entrada. Igual al argumento `clave`. 289* `integrity` - [hacheo de Subresource Integrity](#integrity) del contenido al que se refiere esta entrada. 290* `path` - Dirección del fichero de datos almacenados, unida al argumento `cache`. 291* `time` - Hora de creación de la entrada 292* `metadata` - Metadatos asignados a esta entrada por el usuario 293 294##### Ejemplo 295 296```javascript 297cacache.saca.info(rutaCache, 'my-thing').then(console.log) 298 299// Salida 300{ 301 key: 'my-thing', 302 integrity: 'sha256-MUSTVERIFY+ALL/THINGS==' 303 path: '.testcache/content/deadbeef', 304 time: 12345698490, 305 size: 849234, 306 metadata: { 307 name: 'blah', 308 version: '1.2.3', 309 description: 'this was once a package but now it is my-thing' 310 } 311} 312``` 313 314#### <a name="get-hasContent"></a> `> cacache.saca.tieneDatos(cache, integrity) -> Promise` 315 316Busca un [hacheo Subresource Integrity](#integrity) en el caché. Si existe el 317contenido asociado con `integrity`, devuelve un objeto con dos campos: el hacheo 318_específico_ que se usó para la búsqueda, `sri`, y el tamaño total del 319contenido, `size`. Si no existe ningún contenido asociado con `integrity`, 320devuelve `false`. 321 322##### Ejemplo 323 324```javascript 325cacache.saca.tieneDatos(rutaCache, 'sha256-MUSTVERIFY+ALL/THINGS==').then(console.log) 326 327// Salida 328{ 329 sri: { 330 source: 'sha256-MUSTVERIFY+ALL/THINGS==', 331 algorithm: 'sha256', 332 digest: 'MUSTVERIFY+ALL/THINGS==', 333 options: [] 334 }, 335 size: 9001 336} 337 338cacache.saca.tieneDatos(rutaCache, 'sha521-NOT+IN/CACHE==').then(console.log) 339 340// Salida 341false 342``` 343 344#### <a name="put-data"></a> `> cacache.mete(cache, clave, datos, [ops]) -> Promise` 345 346Inserta `datos` en el caché. El `Promise` devuelto se resuelve con un hacheo 347(generado conforme a [`ops.algorithms`](#optsalgorithms)) después que la entrada 348haya sido escrita en completo. 349 350##### Ejemplo 351 352```javascript 353fetch( 354 'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz' 355).then(datos => { 356 return cacache.mete(rutaCache, 'registry.npmjs.org|cacache@1.0.0', datos) 357}).then(integridad => { 358 console.log('el hacheo de integridad es', integridad) 359}) 360``` 361 362#### <a name="put-stream"></a> `> cacache.mete.flujo(cache, clave, [ops]) -> Writable` 363 364Devuelve un [Writable 365Stream](https://nodejs.org/api/stream.html#stream_writable_streams) que inserta 366al caché los datos escritos a él. Emite un evento `integrity` con el hacheo del 367contenido escrito, cuando completa. 368 369##### Ejemplo 370 371```javascript 372request.get( 373 'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz' 374).pipe( 375 cacache.mete.flujo( 376 rutaCache, 'registry.npmjs.org|cacache@1.0.0' 377 ).on('integrity', d => console.log(`integrity digest is ${d}`)) 378) 379``` 380 381#### <a name="put-options"></a> `> opciones para cacache.mete` 382 383La funciones `cacache.mete` tienen un número de opciones en común. 384 385##### `ops.metadata` 386 387Metadatos del usuario que se almacenarán con la entrada. 388 389##### `ops.size` 390 391El tamaño declarado de los datos que se van a insertar. Si es proveído, cacache 392verificará que los datos escritos sean de ese tamaño, o si no, fallará con un 393error con código `EBADSIZE`. 394 395##### `ops.integrity` 396 397El hacheo de integridad de los datos siendo escritos. 398 399Si es proveído, y los datos escritos no le corresponden, la operación fallará 400con un error con código `EINTEGRITY`. 401 402`ops.algorithms` no tiene ningún efecto si esta opción está presente. 403 404##### `ops.algorithms` 405 406Por Defecto: `['sha512']` 407 408Algoritmos que se deben usar cuando se calcule el hacheo de [subresource 409integrity](#integrity) para los datos insertados. Puede usar cualquier algoritmo 410enumerado en `crypto.getHashes()`. 411 412Por el momento, sólo se acepta un algoritmo (dígase, un array con exáctamente un 413valor). No tiene ningún efecto si `ops.integrity` también ha sido proveido. 414 415##### `ops.uid`/`ops.gid` 416 417Si están presentes, cacache hará todo lo posible para asegurarse que todos los 418ficheros creados en el proceso de sus operaciones en el caché usen esta 419combinación en particular. 420 421##### `ops.memoize` 422 423Por Defecto: `null` 424 425Si es verdad, cacache tratará de memoizar los datos de la entrada en memoria. La 426próxima vez que el proceso corriente trate de accesar los datos o entrada, 427cacache buscará en memoria antes de buscar en disco. 428 429Si `ops.memoize` es un objeto regular o un objeto como `Map` (es decir, un 430objeto con métodos `get()` y `set()`), este objeto en sí sera usado en vez del 431caché de memoria global. Esto permite tener lógica específica a tu aplicación 432encuanto al almacenaje en memoria de tus datos. 433 434Si quieres asegurarte que los datos se lean del disco en vez de memoria, usa 435`memoize: false` cuando uses funciones de `cacache.saca`. 436 437#### <a name="rm-all"></a> `> cacache.rm.todo(cache) -> Promise` 438 439Borra el caché completo, incluyendo ficheros temporeros, ficheros de datos, y el 440índice del caché. 441 442##### Ejemplo 443 444```javascript 445cacache.rm.todo(rutaCache).then(() => { 446 console.log('THE APOCALYPSE IS UPON US ') 447}) 448``` 449 450#### <a name="rm-entry"></a> `> cacache.rm.entrada(cache, clave) -> Promise` 451 452Alias: `cacache.rm` 453 454Borra la entrada `clave` del índuce. El contenido asociado con esta entrada 455seguirá siendo accesible por hacheo usando 456[`saca.flujo.porHacheo`](#get-stream). 457 458Para borrar el contenido en sí, usa [`rm.datos`](#rm-content). Si quieres hacer 459esto de manera más segura (pues ficheros de contenido pueden ser usados por 460multiples entradas), usa [`verifica`](#verify) para borrar huérfanos. 461 462##### Ejemplo 463 464```javascript 465cacache.rm.entrada(rutaCache, 'my-thing').then(() => { 466 console.log('I did not like it anyway') 467}) 468``` 469 470#### <a name="rm-content"></a> `> cacache.rm.datos(cache, integrity) -> Promise` 471 472Borra el contenido identificado por `integrity`. Cualquier entrada que se 473refiera a este contenido quedarán huérfanas y se invalidarán si se tratan de 474accesar, al menos que contenido idéntico sea añadido bajo `integrity`. 475 476##### Ejemplo 477 478```javascript 479cacache.rm.datos(rutaCache, 'sha512-SoMeDIGest/IN+BaSE64==').then(() => { 480 console.log('los datos para `mi-cosa` se borraron') 481}) 482``` 483 484#### <a name="set-locale"></a> `> cacache.ponLenguaje(locale)` 485 486Configura el lenguaje usado para mensajes y errores de cacache. La lista de 487lenguajes disponibles está en el directorio `./locales` del proyecto. 488 489_Te interesa añadir más lenguajes? [Somete un PR](CONTRIBUTING.md)!_ 490 491#### <a name="clear-memoized"></a> `> cacache.limpiaMemoizado()` 492 493Completamente reinicializa el caché de memoria interno. Si estás usando tu 494propio objecto con `ops.memoize`, debes hacer esto de manera específica a él. 495 496#### <a name="tmp-mkdir"></a> `> tmp.hazdir(cache, ops) -> Promise<Path>` 497 498Alias: `tmp.mkdir` 499 500Devuelve un directorio único dentro del directorio `tmp` del caché. 501 502Una vez tengas el directorio, es responsabilidad tuya asegurarte que todos los 503ficheros escrito a él sean creados usando los permisos y `uid`/`gid` concordante 504con el caché. Si no, puedes pedirle a cacache que lo haga llamando a 505[`cacache.tmp.fix()`](#tmp-fix). Esta función arreglará todos los permisos en el 506directorio tmp. 507 508Si quieres que cacache limpie el directorio automáticamente cuando termines, usa 509[`cacache.tmp.conTmp()`](#with-tpm). 510 511##### Ejemplo 512 513```javascript 514cacache.tmp.mkdir(cache).then(dir => { 515 fs.writeFile(path.join(dir, 'blablabla'), Buffer#<1234>, ...) 516}) 517``` 518 519#### <a name="with-tmp"></a> `> tmp.conTmp(cache, ops, cb) -> Promise` 520 521Crea un directorio temporero con [`tmp.mkdir()`](#tmp-mkdir) y ejecuta `cb` con 522él como primer argumento. El directorio creado será removido automáticamente 523cuando el valor devolvido por `cb()` se resuelva. 524 525Las mismas advertencias aplican en cuanto a manejando permisos para los ficheros 526dentro del directorio. 527 528##### Ejemplo 529 530```javascript 531cacache.tmp.conTmp(cache, dir => { 532 return fs.writeFileAsync(path.join(dir, 'blablabla'), Buffer#<1234>, ...) 533}).then(() => { 534 // `dir` no longer exists 535}) 536``` 537 538#### <a name="integrity"></a> Hacheos de Subresource Integrity 539 540cacache usa strings que siguen la especificación de [Subresource Integrity 541spec](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). 542 543Es decir, donde quiera cacache espera un argumento o opción `integrity`, ese 544string debería usar el formato `<algoritmo>-<hacheo-base64>`. 545 546Una variación importante sobre los hacheos que cacache acepta es que acepta el 547nombre de cualquier algoritmo aceptado por el proceso de Node.js donde se usa. 548Puedes usar `crypto.getHashes()` para ver cuales están disponibles. 549 550##### Generando tus propios hacheos 551 552Si tienes un `shasum`, en general va a estar en formato de string hexadecimal 553(es decir, un `sha1` se vería como algo así: 554`5f5513f8822fdbe5145af33b64d8d970dcf95c6e`). 555 556Para ser compatible con cacache, necesitas convertir esto a su equivalente en 557subresource integrity. Por ejemplo, el hacheo correspondiente al ejemplo 558anterior sería: `sha1-X1UT+IIv2+UUWvM7ZNjZcNz5XG4=`. 559 560Puedes usar código así para generarlo por tu cuenta: 561 562```javascript 563const crypto = require('crypto') 564const algoritmo = 'sha512' 565const datos = 'foobarbaz' 566 567const integrity = ( 568 algorithm + 569 '-' + 570 crypto.createHash(algoritmo).update(datos).digest('base64') 571) 572``` 573 574También puedes usar [`ssri`](https://npm.im/ssri) para deferir el trabajo a otra 575librería que garantiza que todo esté correcto, pues maneja probablemente todas 576las operaciones que tendrías que hacer con SRIs, incluyendo convirtiendo entre 577hexadecimal y el formato SRI. 578 579#### <a name="verify"></a> `> cacache.verifica(cache, ops) -> Promise` 580 581Examina y arregla tu caché: 582 583* Limpia entradas inválidas, huérfanas y corrompidas 584* Te deja filtrar cuales entradas retener, con tu propio filtro 585* Reclama cualquier ficheros de contenido sin referencias en el índice 586* Verifica integridad de todos los ficheros de contenido y remueve los malos 587* Arregla permisos del caché 588* Remieve el directorio `tmp` en el caché, y todo su contenido. 589 590Cuando termine, devuelve un objeto con varias estadísticas sobre el proceso de 591verificación, por ejemplo la cantidad de espacio de disco reclamado, el número 592de entradas válidas, número de entradas removidas, etc. 593 594##### Opciones 595 596* `ops.uid` - uid para asignarle al caché y su contenido 597* `ops.gid` - gid para asignarle al caché y su contenido 598* `ops.filter` - recibe una entrada como argumento. Devuelve falso para removerla. Nota: es posible que esta función sea invocada con la misma entrada más de una vez. 599 600##### Example 601 602```sh 603echo somegarbage >> $RUTACACHE/content/deadbeef 604``` 605 606```javascript 607cacache.verifica(rutaCache).then(stats => { 608 // deadbeef collected, because of invalid checksum. 609 console.log('cache is much nicer now! stats:', stats) 610}) 611``` 612 613#### <a name="verify-last-run"></a> `> cacache.verifica.ultimaVez(cache) -> Promise` 614 615Alias: `últimaVez` 616 617Devuelve un `Date` que representa la última vez que `cacache.verifica` fue 618ejecutada en `cache`. 619 620##### Example 621 622```javascript 623cacache.verifica(rutaCache).then(() => { 624 cacache.verifica.ultimaVez(rutaCache).then(última => { 625 console.log('La última vez que se usó cacache.verifica() fue ' + última) 626 }) 627}) 628``` 629