# cacache [![npm version](https://img.shields.io/npm/v/cacache.svg)](https://npm.im/cacache) [![license](https://img.shields.io/npm/l/cacache.svg)](https://npm.im/cacache) [![Travis](https://img.shields.io/travis/zkat/cacache.svg)](https://travis-ci.org/zkat/cacache) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/zkat/cacache?svg=true)](https://ci.appveyor.com/project/zkat/cacache) [![Coverage Status](https://coveralls.io/repos/github/zkat/cacache/badge.svg?branch=latest)](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)
  })
})
```