# 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) [`cacache`](https://github.com/zkat/cacache) es una librer铆a de Node.js para manejar caches locales en disco, con acceso tanto con claves 煤nicas como direcciones de contenido (hashes/hacheos). Es s煤per r谩pida, excelente con el acceso concurrente, y jam谩s te dar谩 datos incorrectos, a煤n si se corrompen o manipulan directamente los ficheros del cache. El prop贸sito original era reemplazar el cach茅 local de [npm](https://npm.im/npm), pero se puede usar por su propia cuenta. _Traducciones: [English](README.md)_ ## Instalaci贸n `$ npm install --save cacache` ## 脥ndice * [Ejemplo](#ejemplo) * [Caracter铆sticas](#caracter铆sticas) * [C贸mo Contribuir](#c贸mo-contribuir) * [API](#api) * [Usando el API en espa帽ol](#localized-api) * Leer * [`ls`](#ls) * [`ls.flujo`](#ls-stream) * [`saca`](#get-data) * [`saca.flujo`](#get-stream) * [`saca.info`](#get-info) * [`saca.tieneDatos`](#get-hasContent) * Escribir * [`mete`](#put-data) * [`mete.flujo`](#put-stream) * [opciones para `mete*`](#put-options) * [`rm.todo`](#rm-all) * [`rm.entrada`](#rm-entry) * [`rm.datos`](#rm-content) * Utilidades * [`ponLenguaje`](#set-locale) * [`limpiaMemoizado`](#clear-memoized) * [`tmp.hazdir`](#tmp-mkdir) * [`tmp.conTmp`](#with-tmp) * Integridad * [Subresource Integrity](#integrity) * [`verifica`](#verify) * [`verifica.ultimaVez`](#verify-last-run) ### Ejemplo ```javascript const cacache = require('cacache/es') const fs = require('fs') const tarbol = '/ruta/a/mi-tar.tgz' const rutaCache = '/tmp/my-toy-cache' const clave = 'mi-clave-煤nica-1234' // 隆A帽谩delo al cach茅! Usa `rutaCache` como ra铆z del cach茅. cacache.mete(rutaCache, clave, '10293801983029384').then(integrity => { console.log(`Saved content to ${rutaCache}.`) }) const destino = '/tmp/mytar.tgz' // Copia el contenido del cach茅 a otro fichero, pero esta vez con flujos. cacache.saca.flujo( rutaCache, clave ).pipe( fs.createWriteStream(destino) ).on('finish', () => { console.log('extracci贸n completada') }) // La misma cosa, pero accesando el contenido directamente, sin tocar el 铆ndice. cacache.saca.porHacheo(rutaCache, integridad).then(datos => { fs.writeFile(destino, datos, err => { console.log('datos del tarbol sacados basado en su sha512, y escrito a otro fichero') }) }) ``` ### Caracter铆sticas * Extracci贸n por clave o por direcci贸n de contenido (shasum, etc) * Usa el est谩ndard de web, [Subresource Integrity](#integrity) * Compatible con multiples algoritmos - usa sha1, sha512, etc, en el mismo cach茅 sin problema * Entradas con contenido id茅ntico comparten ficheros * Tolerancia de fallas (inmune a corrupci贸n, ficheros parciales, carreras de proceso, etc) * Verificaci贸n completa de datos cuando (escribiendo y leyendo) * Concurrencia r谩pida, segura y "lockless" * Compatible con `stream`s (flujos) * Compatible con `Promise`s (promesas) * Bastante r谩pida -- acceso, incluyendo verificaci贸n, en microsegundos * Almacenaje de metadatos arbitrarios * Colecci贸n de basura y verificaci贸n adicional fuera de banda * Cobertura rigurosa de pruebas * Probablente hay un "Bloom filter" por ah铆 en alg煤n lado. Eso le mola a la gente, 驴Verdad? 馃 ### C贸mo Contribuir El 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. El equipo de cacache tiene miembros hispanohablantes: es completamente aceptable crear `issues` y `pull requests` en espa帽ol/castellano. Todos 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. Por favor refi茅rase al [Historial de Cambios](CHANGELOG.md) (en ingl茅s) para detalles sobre cambios importantes inclu铆dos en cada versi贸n. Finalmente, 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. Happy hacking! ### API #### <a name="localized-api"></a> Usando el API en espa帽ol cacache incluye una traducci贸n completa de su API al castellano, con las mismas caracter铆sticas. Para usar el API como est谩 documentado en este documento, usa `require('cacache/es')` cacache tambi茅n tiene otros lenguajes: encu茅ntralos bajo `./locales`, y podr谩s usar el API en ese lenguaje con `require('cacache/<lenguaje>')` #### <a name="ls"></a> `> cacache.ls(cache) -> Promise<Object>` Enumera todas las entradas en el cach茅, dentro de un solo objeto. Cada entrada en el objeto tendr谩 como clave la clave 煤nica usada para el 铆ndice, el valor siendo un objeto de [`saca.info`](#get-info). ##### Ejemplo ```javascript cacache.ls(rutaCache).then(console.log) // Salida { 'my-thing': { key: 'my-thing', integrity: 'sha512-BaSe64/EnCoDED+HAsh==' path: '.testcache/content/deadbeef', // unido con `rutaCache` time: 12345698490, size: 4023948, metadata: { name: 'blah', version: '1.2.3', description: 'this was once a package but now it is my-thing' } }, 'other-thing': { key: 'other-thing', integrity: 'sha1-ANothER+hasH=', path: '.testcache/content/bada55', time: 11992309289, size: 111112 } } ``` #### <a name="ls-stream"></a> `> cacache.ls.flujo(cache) -> Readable` Enumera todas las entradas en el cach茅, emitiendo un objeto de [`saca.info`](#get-info) por cada evento de `data` en el flujo. ##### Ejemplo ```javascript cacache.ls.flujo(rutaCache).on('data', console.log) // Salida { key: 'my-thing', integrity: 'sha512-BaSe64HaSh', path: '.testcache/content/deadbeef', // unido con `rutaCache` time: 12345698490, size: 13423, metadata: { name: 'blah', version: '1.2.3', description: 'this was once a package but now it is my-thing' } } { key: 'other-thing', integrity: 'whirlpool-WoWSoMuchSupport', path: '.testcache/content/bada55', time: 11992309289, size: 498023984029 } { ... } ``` #### <a name="get-data"></a> `> cacache.saca(cache, clave, [ops]) -> Promise({data, metadata, integrity})` Devuelve un objeto con los datos, hacheo de integridad y metadatos identificados por la `clave`. La propiedad `data` de este objeto ser谩 una instancia de `Buffer` con los datos almacenados en el cach茅. to do with it! cacache just won't care. `integrity` es un `string` de [Subresource Integrity](#integrity). D铆gase, un `string` que puede ser usado para verificar a la `data`, que tiene como formato `<algoritmo>-<hacheo-integridad-base64>`. So no existe ninguna entrada identificada por `clave`, o se los datos almacenados localmente fallan verificaci贸n, el `Promise` fallar谩. Una sub-funci贸n, `saca.porHacheo`, tiene casi el mismo comportamiento, excepto que busca entradas usando el hacheo de integridad, sin tocar el 铆ndice general. Esta versi贸n *s贸lo* devuelve `data`, sin ning煤n objeto conteni茅ndola. ##### Nota Esta funci贸n lee la entrada completa a la memoria antes de devolverla. Si est谩s almacenando datos Muy Grandes, es posible que [`saca.flujo`](#get-stream) sea una mejor soluci贸n. ##### Ejemplo ```javascript // Busca por clave cache.saca(rutaCache, 'my-thing').then(console.log) // Salida: { metadata: { thingName: 'my' }, integrity: 'sha512-BaSe64HaSh', data: Buffer#<deadbeef>, size: 9320 } // Busca por hacheo cache.saca.porHacheo(rutaCache, 'sha512-BaSe64HaSh').then(console.log) // Salida: Buffer#<deadbeef> ``` #### <a name="get-stream"></a> `> cacache.saca.flujo(cache, clave, [ops]) -> Readable` Devuelve un [Readable Stream](https://nodejs.org/api/stream.html#stream_readable_streams) de los datos almacenados bajo `clave`. So no existe ninguna entrada identificada por `clave`, o se los datos almacenados localmente fallan verificaci贸n, el `Promise` fallar谩. `metadata` y `integrity` ser谩n emitidos como eventos antes de que el flujo cierre. Una sub-funci贸n, `saca.flujo.porHacheo`, tiene casi el mismo comportamiento, excepto que busca entradas usando el hacheo de integridad, sin tocar el 铆ndice general. Esta versi贸n no emite eventos de `metadata` o `integrity`. ##### Ejemplo ```javascript // Busca por clave cache.saca.flujo( rutaCache, 'my-thing' ).on('metadata', metadata => { console.log('metadata:', metadata) }).on('integrity', integrity => { console.log('integrity:', integrity) }).pipe( fs.createWriteStream('./x.tgz') ) // Salidas: metadata: { ... } integrity: 'sha512-SoMeDIGest+64==' // Busca por hacheo cache.saca.flujo.porHacheo( rutaCache, 'sha512-SoMeDIGest+64==' ).pipe( fs.createWriteStream('./x.tgz') ) ``` #### <a name="get-info"></a> `> cacache.saca.info(cache, clave) -> Promise` Busca la `clave` en el 铆ndice del cach茅, devolviendo informaci贸n sobre la entrada si existe. ##### Campos * `key` - Clave de la entrada. Igual al argumento `clave`. * `integrity` - [hacheo de Subresource Integrity](#integrity) del contenido al que se refiere esta entrada. * `path` - Direcci贸n del fichero de datos almacenados, unida al argumento `cache`. * `time` - Hora de creaci贸n de la entrada * `metadata` - Metadatos asignados a esta entrada por el usuario ##### Ejemplo ```javascript cacache.saca.info(rutaCache, 'my-thing').then(console.log) // Salida { key: 'my-thing', integrity: 'sha256-MUSTVERIFY+ALL/THINGS==' path: '.testcache/content/deadbeef', time: 12345698490, size: 849234, metadata: { name: 'blah', version: '1.2.3', description: 'this was once a package but now it is my-thing' } } ``` #### <a name="get-hasContent"></a> `> cacache.saca.tieneDatos(cache, integrity) -> Promise` Busca un [hacheo Subresource Integrity](#integrity) en el cach茅. Si existe el contenido asociado con `integrity`, devuelve un objeto con dos campos: el hacheo _espec铆fico_ que se us贸 para la b煤squeda, `sri`, y el tama帽o total del contenido, `size`. Si no existe ning煤n contenido asociado con `integrity`, devuelve `false`. ##### Ejemplo ```javascript cacache.saca.tieneDatos(rutaCache, 'sha256-MUSTVERIFY+ALL/THINGS==').then(console.log) // Salida { sri: { source: 'sha256-MUSTVERIFY+ALL/THINGS==', algorithm: 'sha256', digest: 'MUSTVERIFY+ALL/THINGS==', options: [] }, size: 9001 } cacache.saca.tieneDatos(rutaCache, 'sha521-NOT+IN/CACHE==').then(console.log) // Salida false ``` #### <a name="put-data"></a> `> cacache.mete(cache, clave, datos, [ops]) -> Promise` Inserta `datos` en el cach茅. El `Promise` devuelto se resuelve con un hacheo (generado conforme a [`ops.algorithms`](#optsalgorithms)) despu茅s que la entrada haya sido escrita en completo. ##### Ejemplo ```javascript fetch( 'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz' ).then(datos => { return cacache.mete(rutaCache, 'registry.npmjs.org|cacache@1.0.0', datos) }).then(integridad => { console.log('el hacheo de integridad es', integridad) }) ``` #### <a name="put-stream"></a> `> cacache.mete.flujo(cache, clave, [ops]) -> Writable` Devuelve un [Writable Stream](https://nodejs.org/api/stream.html#stream_writable_streams) que inserta al cach茅 los datos escritos a 茅l. Emite un evento `integrity` con el hacheo del contenido escrito, cuando completa. ##### Ejemplo ```javascript request.get( 'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz' ).pipe( cacache.mete.flujo( rutaCache, 'registry.npmjs.org|cacache@1.0.0' ).on('integrity', d => console.log(`integrity digest is ${d}`)) ) ``` #### <a name="put-options"></a> `> opciones para cacache.mete` La funciones `cacache.mete` tienen un n煤mero de opciones en com煤n. ##### `ops.metadata` Metadatos del usuario que se almacenar谩n con la entrada. ##### `ops.size` El tama帽o declarado de los datos que se van a insertar. Si es prove铆do, cacache verificar谩 que los datos escritos sean de ese tama帽o, o si no, fallar谩 con un error con c贸digo `EBADSIZE`. ##### `ops.integrity` El hacheo de integridad de los datos siendo escritos. Si es prove铆do, y los datos escritos no le corresponden, la operaci贸n fallar谩 con un error con c贸digo `EINTEGRITY`. `ops.algorithms` no tiene ning煤n efecto si esta opci贸n est谩 presente. ##### `ops.algorithms` Por Defecto: `['sha512']` Algoritmos que se deben usar cuando se calcule el hacheo de [subresource integrity](#integrity) para los datos insertados. Puede usar cualquier algoritmo enumerado en `crypto.getHashes()`. Por el momento, s贸lo se acepta un algoritmo (d铆gase, un array con ex谩ctamente un valor). No tiene ning煤n efecto si `ops.integrity` tambi茅n ha sido proveido. ##### `ops.uid`/`ops.gid` Si est谩n presentes, cacache har谩 todo lo posible para asegurarse que todos los ficheros creados en el proceso de sus operaciones en el cach茅 usen esta combinaci贸n en particular. ##### `ops.memoize` Por Defecto: `null` Si es verdad, cacache tratar谩 de memoizar los datos de la entrada en memoria. La pr贸xima vez que el proceso corriente trate de accesar los datos o entrada, cacache buscar谩 en memoria antes de buscar en disco. Si `ops.memoize` es un objeto regular o un objeto como `Map` (es decir, un objeto con m茅todos `get()` y `set()`), este objeto en s铆 sera usado en vez del cach茅 de memoria global. Esto permite tener l贸gica espec铆fica a tu aplicaci贸n encuanto al almacenaje en memoria de tus datos. Si quieres asegurarte que los datos se lean del disco en vez de memoria, usa `memoize: false` cuando uses funciones de `cacache.saca`. #### <a name="rm-all"></a> `> cacache.rm.todo(cache) -> Promise` Borra el cach茅 completo, incluyendo ficheros temporeros, ficheros de datos, y el 铆ndice del cach茅. ##### Ejemplo ```javascript cacache.rm.todo(rutaCache).then(() => { console.log('THE APOCALYPSE IS UPON US 馃槺') }) ``` #### <a name="rm-entry"></a> `> cacache.rm.entrada(cache, clave) -> Promise` Alias: `cacache.rm` Borra la entrada `clave` del 铆nduce. El contenido asociado con esta entrada seguir谩 siendo accesible por hacheo usando [`saca.flujo.porHacheo`](#get-stream). Para borrar el contenido en s铆, usa [`rm.datos`](#rm-content). Si quieres hacer esto de manera m谩s segura (pues ficheros de contenido pueden ser usados por multiples entradas), usa [`verifica`](#verify) para borrar hu茅rfanos. ##### Ejemplo ```javascript cacache.rm.entrada(rutaCache, 'my-thing').then(() => { console.log('I did not like it anyway') }) ``` #### <a name="rm-content"></a> `> cacache.rm.datos(cache, integrity) -> Promise` Borra el contenido identificado por `integrity`. Cualquier entrada que se refiera a este contenido quedar谩n hu茅rfanas y se invalidar谩n si se tratan de accesar, al menos que contenido id茅ntico sea a帽adido bajo `integrity`. ##### Ejemplo ```javascript cacache.rm.datos(rutaCache, 'sha512-SoMeDIGest/IN+BaSE64==').then(() => { console.log('los datos para `mi-cosa` se borraron') }) ``` #### <a name="set-locale"></a> `> cacache.ponLenguaje(locale)` Configura el lenguaje usado para mensajes y errores de cacache. La lista de lenguajes disponibles est谩 en el directorio `./locales` del proyecto. _Te interesa a帽adir m谩s lenguajes? [Somete un PR](CONTRIBUTING.md)!_ #### <a name="clear-memoized"></a> `> cacache.limpiaMemoizado()` Completamente reinicializa el cach茅 de memoria interno. Si est谩s usando tu propio objecto con `ops.memoize`, debes hacer esto de manera espec铆fica a 茅l. #### <a name="tmp-mkdir"></a> `> tmp.hazdir(cache, ops) -> Promise<Path>` Alias: `tmp.mkdir` Devuelve un directorio 煤nico dentro del directorio `tmp` del cach茅. Una vez tengas el directorio, es responsabilidad tuya asegurarte que todos los ficheros escrito a 茅l sean creados usando los permisos y `uid`/`gid` concordante con el cach茅. Si no, puedes pedirle a cacache que lo haga llamando a [`cacache.tmp.fix()`](#tmp-fix). Esta funci贸n arreglar谩 todos los permisos en el directorio tmp. Si quieres que cacache limpie el directorio autom谩ticamente cuando termines, usa [`cacache.tmp.conTmp()`](#with-tpm). ##### Ejemplo ```javascript cacache.tmp.mkdir(cache).then(dir => { fs.writeFile(path.join(dir, 'blablabla'), Buffer#<1234>, ...) }) ``` #### <a name="with-tmp"></a> `> tmp.conTmp(cache, ops, cb) -> Promise` Crea un directorio temporero con [`tmp.mkdir()`](#tmp-mkdir) y ejecuta `cb` con 茅l como primer argumento. El directorio creado ser谩 removido autom谩ticamente cuando el valor devolvido por `cb()` se resuelva. Las mismas advertencias aplican en cuanto a manejando permisos para los ficheros dentro del directorio. ##### Ejemplo ```javascript cacache.tmp.conTmp(cache, dir => { return fs.writeFileAsync(path.join(dir, 'blablabla'), Buffer#<1234>, ...) }).then(() => { // `dir` no longer exists }) ``` #### <a name="integrity"></a> Hacheos de Subresource Integrity cacache usa strings que siguen la especificaci贸n de [Subresource Integrity spec](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity). Es decir, donde quiera cacache espera un argumento o opci贸n `integrity`, ese string deber铆a usar el formato `<algoritmo>-<hacheo-base64>`. Una variaci贸n importante sobre los hacheos que cacache acepta es que acepta el nombre de cualquier algoritmo aceptado por el proceso de Node.js donde se usa. Puedes usar `crypto.getHashes()` para ver cuales est谩n disponibles. ##### Generando tus propios hacheos Si tienes un `shasum`, en general va a estar en formato de string hexadecimal (es decir, un `sha1` se ver铆a como algo as铆: `5f5513f8822fdbe5145af33b64d8d970dcf95c6e`). Para ser compatible con cacache, necesitas convertir esto a su equivalente en subresource integrity. Por ejemplo, el hacheo correspondiente al ejemplo anterior ser铆a: `sha1-X1UT+IIv2+UUWvM7ZNjZcNz5XG4=`. Puedes usar c贸digo as铆 para generarlo por tu cuenta: ```javascript const crypto = require('crypto') const algoritmo = 'sha512' const datos = 'foobarbaz' const integrity = ( algorithm + '-' + crypto.createHash(algoritmo).update(datos).digest('base64') ) ``` Tambi茅n puedes usar [`ssri`](https://npm.im/ssri) para deferir el trabajo a otra librer铆a que garantiza que todo est茅 correcto, pues maneja probablemente todas las operaciones que tendr铆as que hacer con SRIs, incluyendo convirtiendo entre hexadecimal y el formato SRI. #### <a name="verify"></a> `> cacache.verifica(cache, ops) -> Promise` Examina y arregla tu cach茅: * Limpia entradas inv谩lidas, hu茅rfanas y corrompidas * Te deja filtrar cuales entradas retener, con tu propio filtro * Reclama cualquier ficheros de contenido sin referencias en el 铆ndice * Verifica integridad de todos los ficheros de contenido y remueve los malos * Arregla permisos del cach茅 * Remieve el directorio `tmp` en el cach茅, y todo su contenido. Cuando termine, devuelve un objeto con varias estad铆sticas sobre el proceso de verificaci贸n, por ejemplo la cantidad de espacio de disco reclamado, el n煤mero de entradas v谩lidas, n煤mero de entradas removidas, etc. ##### Opciones * `ops.uid` - uid para asignarle al cach茅 y su contenido * `ops.gid` - gid para asignarle al cach茅 y su contenido * `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. ##### Example ```sh echo somegarbage >> $RUTACACHE/content/deadbeef ``` ```javascript cacache.verifica(rutaCache).then(stats => { // deadbeef collected, because of invalid checksum. console.log('cache is much nicer now! stats:', stats) }) ``` #### <a name="verify-last-run"></a> `> cacache.verifica.ultimaVez(cache) -> Promise` Alias: `煤ltimaVez` Devuelve un `Date` que representa la 煤ltima vez que `cacache.verifica` fue ejecutada en `cache`. ##### Example ```javascript cacache.verifica(rutaCache).then(() => { cacache.verifica.ultimaVez(rutaCache).then(煤ltima => { console.log('La 煤ltima vez que se us贸 cacache.verifica() fue ' + 煤ltima) }) }) ```