Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

cacache

npm122mISC19.0.1TypeScript support: definitely-typed

Fast, fault-tolerant, cross-platform, disk-based, data-agnostic, content-addressable cache.

cache, caching, content-addressable, sri, sri hash, subresource integrity, cache, storage, store, file store, filesystem, disk cache, disk storage

readme

cacache npm version license Travis AppVeyor Coverage Status

cacache is a Node.js library for managing local key and content address caches. It's really fast, really good at concurrency, and it will never give you corrupted data, even if cache files get corrupted or manipulated.

On systems that support user and group settings on files, cacache will match the uid and gid values to the folder where the cache lives, even when running as root.

It was written to be used as npm's local cache, but can just as easily be used on its own.

Install

$ npm install --save cacache

Table of Contents

Example

const cacache = require('cacache')
const fs = require('fs')

const cachePath = '/tmp/my-toy-cache'
const key = 'my-unique-key-1234'

// Cache it! Use `cachePath` as the root of the content cache
cacache.put(cachePath, key, '10293801983029384').then(integrity => {
  console.log(`Saved content to ${cachePath}.`)
})

const destination = '/tmp/mytar.tgz'

// Copy the contents out of the cache and into their destination!
// But this time, use stream instead!
cacache.get.stream(
  cachePath, key
).pipe(
  fs.createWriteStream(destination)
).on('finish', () => {
  console.log('done extracting!')
})

// The same thing, but skip the key index.
cacache.get.byDigest(cachePath, integrityHash).then(data => {
  fs.writeFile(destination, data, err => {
    console.log('tarball data fetched based on its sha512sum and written out!')
  })
})

Features

  • Extraction by key or by content address (shasum, etc)
  • Subresource Integrity web standard support
  • Multi-hash support - safely host sha1, sha512, etc, in a single cache
  • Automatic content deduplication
  • Fault tolerance (immune to corruption, partial writes, process races, etc)
  • Consistency guarantees on read and write (full data verification)
  • Lockless, high-concurrency cache access
  • Streaming support
  • Promise support
  • Fast -- sub-millisecond reads and writes including verification
  • Arbitrary metadata storage
  • Garbage collection and additional offline verification
  • Thorough test coverage
  • There's probably a bloom filter in there somewhere. Those are cool, right? 🤔

Contributing

The cacache team enthusiastically welcomes contributions and project participation! There's a bunch of things you can do if you want to contribute! Please don't hesitate to jump in if you'd like to, or even ask us questions if something isn't clear.

All participants and maintainers in this project are expected to follow Code of Conduct, and just generally be excellent to each other.

Please refer to the Changelog for project history details, too.

Happy hacking!

API

> cacache.ls(cache) -> Promise<Object>

Lists info for all entries currently in the cache as a single large object. Each entry in the object will be keyed by the unique index key, with corresponding get.info objects as the values.

Example
cacache.ls(cachePath).then(console.log)
// Output
{
  'my-thing': {
    key: 'my-thing',
    integrity: 'sha512-BaSe64/EnCoDED+HAsh=='
    path: '.testcache/content/deadbeef', // joined with `cachePath`
    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
  }
}

> cacache.ls.stream(cache) -> Readable

Lists info for all entries currently in the cache as a single large object.

This works just like ls, except get.info entries are returned as 'data' events on the returned stream.

Example
cacache.ls.stream(cachePath).on('data', console.log)
// Output
{
  key: 'my-thing',
  integrity: 'sha512-BaSe64HaSh',
  path: '.testcache/content/deadbeef', // joined with `cachePath`
  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
}

{
  ...
}

> cacache.get(cache, key, [opts]) -> Promise({data, metadata, integrity})

Returns an object with the cached data, digest, and metadata identified by key. The data property of this object will be a Buffer instance that presumably holds some data that means something to you. I'm sure you know what to do with it! cacache just won't care.

integrity is a Subresource Integrity string. That is, a string that can be used to verify data, which looks like <hash-algorithm>-<base64-integrity-hash>.

If there is no content identified by key, or if the locally-stored data does not pass the validity checksum, the promise will be rejected.

A sub-function, get.byDigest may be used for identical behavior, except lookup will happen by integrity hash, bypassing the index entirely. This version of the function only returns data itself, without any wrapper.

See: options

Note

This function loads the entire cache entry into memory before returning it. If you're dealing with Very Large data, consider using get.stream instead.

Example
// Look up by key
cache.get(cachePath, 'my-thing').then(console.log)
// Output:
{
  metadata: {
    thingName: 'my'
  },
  integrity: 'sha512-BaSe64HaSh',
  data: Buffer#<deadbeef>,
  size: 9320
}

// Look up by digest
cache.get.byDigest(cachePath, 'sha512-BaSe64HaSh').then(console.log)
// Output:
Buffer#<deadbeef>

> cacache.get.stream(cache, key, [opts]) -> Readable

Returns a Readable Stream of the cached data identified by key.

If there is no content identified by key, or if the locally-stored data does not pass the validity checksum, an error will be emitted.

metadata and integrity events will be emitted before the stream closes, if you need to collect that extra data about the cached entry.

A sub-function, get.stream.byDigest may be used for identical behavior, except lookup will happen by integrity hash, bypassing the index entirely. This version does not emit the metadata and integrity events at all.

See: options

Example
// Look up by key
cache.get.stream(
  cachePath, 'my-thing'
).on('metadata', metadata => {
  console.log('metadata:', metadata)
}).on('integrity', integrity => {
  console.log('integrity:', integrity)
}).pipe(
  fs.createWriteStream('./x.tgz')
)
// Outputs:
metadata: { ... }
integrity: 'sha512-SoMeDIGest+64=='

// Look up by digest
cache.get.stream.byDigest(
  cachePath, 'sha512-SoMeDIGest+64=='
).pipe(
  fs.createWriteStream('./x.tgz')
)

> cacache.get.info(cache, key) -> Promise

Looks up key in the cache index, returning information about the entry if one exists.

Fields
  • key - Key the entry was looked up under. Matches the key argument.
  • integrity - Subresource Integrity hash for the content this entry refers to.
  • path - Filesystem path where content is stored, joined with cache argument.
  • time - Timestamp the entry was first added on.
  • metadata - User-assigned metadata associated with the entry/content.
Example
cacache.get.info(cachePath, 'my-thing').then(console.log)

// Output
{
  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'
  }
}

> cacache.get.hasContent(cache, integrity) -> Promise

Looks up a Subresource Integrity hash in the cache. If content exists for this integrity, it will return an object, with the specific single integrity hash that was found in sri key, and the size of the found content as size. If no content exists for this integrity, it will return false.

Example
cacache.get.hasContent(cachePath, 'sha256-MUSTVERIFY+ALL/THINGS==').then(console.log)

// Output
{
  sri: {
    source: 'sha256-MUSTVERIFY+ALL/THINGS==',
    algorithm: 'sha256',
    digest: 'MUSTVERIFY+ALL/THINGS==',
    options: []
  },
  size: 9001
}

cacache.get.hasContent(cachePath, 'sha521-NOT+IN/CACHE==').then(console.log)

// Output
false
Options
opts.integrity

If present, the pre-calculated digest for the inserted content. If this option is provided and does not match the post-insertion digest, insertion will fail with an EINTEGRITY error.

opts.memoize

Default: null

If explicitly truthy, cacache will read from memory and memoize data on bulk read. If false, cacache will read from disk data. Reader functions by default read from in-memory cache.

opts.size

If provided, the data stream will be verified to check that enough data was passed through. If there's more or less data than expected, insertion will fail with an EBADSIZE error.

> cacache.put(cache, key, data, [opts]) -> Promise

Inserts data passed to it into the cache. The returned Promise resolves with a digest (generated according to opts.algorithms) after the cache entry has been successfully written.

See: options

Example
fetch(
  'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz'
).then(data => {
  return cacache.put(cachePath, 'registry.npmjs.org|cacache@1.0.0', data)
}).then(integrity => {
  console.log('integrity hash is', integrity)
})

> cacache.put.stream(cache, key, [opts]) -> Writable

Returns a Writable Stream that inserts data written to it into the cache. Emits an integrity event with the digest of written contents when it succeeds.

See: options

Example
request.get(
  'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz'
).pipe(
  cacache.put.stream(
    cachePath, 'registry.npmjs.org|cacache@1.0.0'
  ).on('integrity', d => console.log(`integrity digest is ${d}`))
)
Options
opts.metadata

Arbitrary metadata to be attached to the inserted key.

opts.size

If provided, the data stream will be verified to check that enough data was passed through. If there's more or less data than expected, insertion will fail with an EBADSIZE error.

opts.integrity

If present, the pre-calculated digest for the inserted content. If this option is provided and does not match the post-insertion digest, insertion will fail with an EINTEGRITY error.

algorithms has no effect if this option is present.

opts.integrityEmitter

Streaming only If present, uses the provided event emitter as a source of truth for both integrity and size. This allows use cases where integrity is already being calculated outside of cacache to reuse that data instead of calculating it a second time.

The emitter must emit both the 'integrity' and 'size' events.

NOTE: If this option is provided, you must verify that you receive the correct integrity value yourself and emit an 'error' event if there is a mismatch. ssri Integrity Streams do this for you when given an expected integrity.

opts.algorithms

Default: ['sha512']

Hashing algorithms to use when calculating the subresource integrity digest for inserted data. Can use any algorithm listed in crypto.getHashes() or 'omakase'/'お任せします' to pick a random hash algorithm on each insertion. You may also use any anagram of 'modnar' to use this feature.

Currently only supports one algorithm at a time (i.e., an array length of exactly 1). Has no effect if opts.integrity is present.

opts.memoize

Default: null

If provided, cacache will memoize the given cache insertion in memory, bypassing any filesystem checks for that key or digest in future cache fetches. Nothing will be written to the in-memory cache unless this option is explicitly truthy.

If opts.memoize is an object or a Map-like (that is, an object with get and set methods), it will be written to instead of the global memoization cache.

Reading from disk data can be forced by explicitly passing memoize: false to the reader functions, but their default will be to read from memory.

opts.tmpPrefix

Default: null

Prefix to append on the temporary directory name inside the cache's tmp dir.

> cacache.rm.all(cache) -> Promise

Clears the entire cache. Mainly by blowing away the cache directory itself.

Example
cacache.rm.all(cachePath).then(() => {
  console.log('THE APOCALYPSE IS UPON US 😱')
})

> cacache.rm.entry(cache, key, [opts]) -> Promise

Alias: cacache.rm

Removes the index entry for key. Content will still be accessible if requested directly by content address (get.stream.byDigest).

By default, this appends a new entry to the index with an integrity of null. If opts.removeFully is set to true then the index file itself will be physically deleted rather than appending a null.

To remove the content itself (which might still be used by other entries), use rm.content. Or, to safely vacuum any unused content, use verify.

Example
cacache.rm.entry(cachePath, 'my-thing').then(() => {
  console.log('I did not like it anyway')
})

> cacache.rm.content(cache, integrity) -> Promise

Removes the content identified by integrity. Any index entries referring to it will not be usable again until the content is re-added to the cache with an identical digest.

Example
cacache.rm.content(cachePath, 'sha512-SoMeDIGest/IN+BaSE64==').then(() => {
  console.log('data for my-thing is gone!')
})

> cacache.index.compact(cache, key, matchFn, [opts]) -> Promise

Uses matchFn, which must be a synchronous function that accepts two entries and returns a boolean indicating whether or not the two entries match, to deduplicate all entries in the cache for the given key.

If opts.validateEntry is provided, it will be called as a function with the only parameter being a single index entry. The function must return a Boolean, if it returns true the entry is considered valid and will be kept in the index, if it returns false the entry will be removed from the index.

If opts.validateEntry is not provided, however, every entry in the index will be deduplicated and kept until the first null integrity is reached, removing all entries that were written before the null.

The deduplicated list of entries is both written to the index, replacing the existing content, and returned in the Promise.

> cacache.index.insert(cache, key, integrity, opts) -> Promise

Writes an index entry to the cache for the given key without writing content.

It is assumed if you are using this method, you have already stored the content some other way and you only wish to add a new index to that content. The metadata and size properties are read from opts and used as part of the index entry.

Returns a Promise resolving to the newly added entry.

> cacache.clearMemoized()

Completely resets the in-memory entry cache.

> tmp.mkdir(cache, opts) -> Promise<Path>

Returns a unique temporary directory inside the cache's tmp dir. This directory will use the same safe user assignment that all the other stuff use.

Once the directory is made, it's the user's responsibility that all files within are given the appropriate gid/uid ownership settings to match the rest of the cache. If not, you can ask cacache to do it for you by calling tmp.fix(), which will fix all tmp directory permissions.

If you want automatic cleanup of this directory, use tmp.withTmp()

See: options

Example
cacache.tmp.mkdir(cache).then(dir => {
  fs.writeFile(path.join(dir, 'blablabla'), Buffer#<1234>, ...)
})

> tmp.fix(cache) -> Promise

Sets the uid and gid properties on all files and folders within the tmp folder to match the rest of the cache.

Use this after manually writing files into tmp.mkdir or tmp.withTmp.

Example
cacache.tmp.mkdir(cache).then(dir => {
  writeFile(path.join(dir, 'file'), someData).then(() => {
    // make sure we didn't just put a root-owned file in the cache
    cacache.tmp.fix().then(() => {
      // all uids and gids match now
    })
  })
})

> tmp.withTmp(cache, opts, cb) -> Promise

Creates a temporary directory with tmp.mkdir() and calls cb with it. The created temporary directory will be removed when the return value of cb() resolves, the tmp directory will be automatically deleted once that promise completes.

The same caveats apply when it comes to managing permissions for the tmp dir's contents.

See: options

Example
cacache.tmp.withTmp(cache, dir => {
  return fs.writeFile(path.join(dir, 'blablabla'), 'blabla contents', { encoding: 'utf8' })
}).then(() => {
  // `dir` no longer exists
})
Options
opts.tmpPrefix

Default: null

Prefix to append on the temporary directory name inside the cache's tmp dir.

Subresource Integrity Digests

For content verification and addressing, cacache uses strings following the Subresource Integrity spec. That is, any time cacache expects an integrity argument or option, it should be in the format <hashAlgorithm>-<base64-hash>.

One deviation from the current spec is that cacache will support any hash algorithms supported by the underlying Node.js process. You can use crypto.getHashes() to see which ones you can use.

Generating Digests Yourself

If you have an existing content shasum, they are generally formatted as a hexadecimal string (that is, a sha1 would look like: 5f5513f8822fdbe5145af33b64d8d970dcf95c6e). In order to be compatible with cacache, you'll need to convert this to an equivalent subresource integrity string. For this example, the corresponding hash would be: sha1-X1UT+IIv2+UUWvM7ZNjZcNz5XG4=.

If you want to generate an integrity string yourself for existing data, you can use something like this:

const crypto = require('crypto')
const hashAlgorithm = 'sha512'
const data = 'foobarbaz'

const integrity = (
  hashAlgorithm +
  '-' +
  crypto.createHash(hashAlgorithm).update(data).digest('base64')
)

You can also use ssri to have a richer set of functionality around SRI strings, including generation, parsing, and translating from existing hex-formatted strings.

> cacache.verify(cache, opts) -> Promise

Checks out and fixes up your cache:

  • Cleans up corrupted or invalid index entries.
  • Custom entry filtering options.
  • Garbage collects any content entries not referenced by the index.
  • Checks integrity for all content entries and removes invalid content.
  • Fixes cache ownership.
  • Removes the tmp directory in the cache and all its contents.

When it's done, it'll return an object with various stats about the verification process, including amount of storage reclaimed, number of valid entries, number of entries removed, etc.

Options
opts.concurrency

Default: 20

Number of concurrently read files in the filesystem while doing clean up.

opts.filter

Receives a formatted entry. Return false to remove it. Note: might be called more than once on the same entry.

opts.log

Custom logger function:

  log: { silly () {} }
  log.silly('verify', 'verifying cache at', cache)
Example
echo somegarbage >> $CACHEPATH/content/deadbeef
cacache.verify(cachePath).then(stats => {
  // deadbeef collected, because of invalid checksum.
  console.log('cache is much nicer now! stats:', stats)
})

> cacache.verify.lastRun(cache) -> Promise

Returns a Date representing the last time cacache.verify was run on cache.

Example
cacache.verify(cachePath).then(() => {
  cacache.verify.lastRun(cachePath).then(lastTime => {
    console.log('cacache.verify was last called on' + lastTime)
  })
})

changelog

Changelog

19.0.1 (2024-09-26)

Dependencies

  • e56c7fc #302 update p-map from ^4.0.0 to ^7.0.2 (#302)

19.0.0 (2024-09-26)

⚠️ BREAKING CHANGES

18.0.4 (2024-07-11)

Bug Fixes

  • 5f2166a #285 Limit concurrent open files during lsstream (#285) (@oikumene)

18.0.3 (2024-05-04)

Bug Fixes

Chores

  • b685cb5 #269 bump @npmcli/template-oss to 4.22.0 (@lukekarrys)
  • 4a66453 #269 postinstall for dependabot template-oss PR (@lukekarrys)
  • 4359f2c #264 bump @npmcli/template-oss from 4.21.3 to 4.21.4 (@dependabot[bot])

18.0.2 (2024-01-03)

Bug Fixes

Chores

  • 7eab139 #252 postinstall for dependabot template-oss PR (@lukekarrys)
  • 44bedb2 #252 bump @npmcli/template-oss from 4.21.1 to 4.21.3 (@dependabot[bot])
  • a12bdf3 #248 postinstall for dependabot template-oss PR (@lukekarrys)
  • 62e5a94 #248 bump @npmcli/template-oss from 4.19.0 to 4.21.1 (@dependabot[bot])

18.0.1 (2023-11-27)

Bug Fixes

  • 6755c0e #250 attach a catch handler to the handleContentP promise (#250) (@kalinkrustev)

Dependencies

  • 0a5c204 #221 bump minipass-collect from 1.0.2 to 2.0.1

18.0.0 (2023-08-14)

⚠️ BREAKING CHANGES

  • support for node 14 has been removed

Bug Fixes

Dependencies

17.1.4 (2023-08-14)

Dependencies

17.1.3 (2023-05-18)

Bug Fixes

  • a0a5e58 #209 normalize win32 paths to use on glob expressions (#209) (@supita)

17.1.2 (2023-05-16)

Bug Fixes

  • bd846d0 #206 catch eexists in moveOperations promise (#206) (@wraithgar)

17.1.1 (2023-05-16)

Bug Fixes

  • 988d77a #203 deduplicate move operations (#203) (@wraithgar)

17.1.0 (2023-05-02)

Features

  • 2e83cfc #200 write: accept multiple integrity algorithms (#200) (@wraithgar)

Bug Fixes

  • 62b2d8d #199 don't clobber time when verifying cache (#199) (@wraithgar)
  • e227c50 #197 verify: allow for entries with multiple hashes (#197) (@wraithgar)

Documentation

17.0.7 (2023-05-01)

Bug Fixes

  • 265e4ae #195 Trust the filesystem to move files (@wraithgar)

Dependencies

17.0.6 (2023-04-27)

Dependencies

17.0.5 (2023-03-21)

Dependencies

17.0.4 (2022-12-14)

Dependencies

17.0.3 (2022-12-07)

Dependencies

17.0.2 (2022-11-04)

Bug Fixes

  • 4a7382f #152 replace @npmcli/move-file with @npmcli/fs (@lukekarrys)

17.0.1 (2022-10-17)

Dependencies

17.0.0 (2022-10-13)

⚠️ BREAKING CHANGES

  • this module no longer attempts to change file ownership automatically
  • this package is now async only, all synchronous methods have been removed
  • cacache is now compatible with the following semver range for node: ^14.17.0 || ^16.13.0 || >=18.0.0

Features

  • 479b135 #141 do not alter file ownership (#141) (@nlf)
  • f57bb4d #140 remove sync methods (#140) (@nlf)
  • cfebcde #133 postinstall for dependabot template-oss PR (@lukekarrys)

16.1.3 (2022-08-23)

Dependencies

  • bump unique-filename from 1.1.1 to 2.0.0 (#123) (6235554)

16.1.2 (2022-08-15)

Bug Fixes

16.1.1 (2022-06-02)

Bug Fixes

  • read: change lstat to stat to correctly evaluate file size (#114) (e3a2928)

16.1.0 (2022-05-17)

Features

  • allow external integrity/size source (#110) (61785e1)

Bug Fixes

  • move to async functions where possible (#106) (71d4389)

16.0.7 (2022-04-27)

Bug Fixes

  • put: don't flush if an error happened (e870016)
  • remove disposer (76ab648)
  • remove fs.copyFile checks (90776fd)

16.0.6 (2022-04-21)

Bug Fixes

  • normalize win32 paths before globbing (4bdd5d5)

16.0.5 (2022-04-20)

Dependencies

16.0.4 (2022-04-05)

Dependencies

  • bump @npmcli/move-file from 1.1.2 to 2.0.0 (#94) (f3d64f6)
  • bump ssri from 8.0.1 to 9.0.0 (#95) (fb44f5f)

16.0.3 (2022-03-22)

Dependencies

  • bump @npmcli/fs from 1.1.1 to 2.1.0 (#88) (9c9c91c)
  • update lru-cache requirement from ^7.5.1 to ^7.7.1 (#87) (800079f)

16.0.2 (2022-03-16)

Bug Fixes

16.0.1 (2022-03-15)

Dependencies

  • bump lru-cache from 6.0.0 to 7.5.1 (#77) (6a3a886)
  • update glob requirement from ^7.1.4 to ^7.2.0 (#74) (27f1a63)
  • update minipass requirement from ^3.1.1 to ^3.1.6 (#76) (954a430)

16.0.0 (2022-03-14)

⚠ BREAKING CHANGES

  • this drops support for node10 and non-LTS versions of node12 and node14.

Bug Fixes

Dependencies

15.2.0 (2021-05-25)

  • 8892a92 add a validateEntry option to compact
  • 460b951 allow fully deleting indexes

15.1.0 (2021-05-19)

Features

  • allow formatEntry to keep entries with no integrity value (930f531), closes #53
  • expose index.insert, implement and expose index.compact (c4efb74)

15.0.6 (2021-03-22)

15.0.5 (2020-07-11)

15.0.4 (2020-06-03)

Bug Fixes

  • replace move-file dep with @npmcli/move-file (bf88af0), closes #37

15.0.3 (2020-04-28)

Bug Fixes

  • actually remove move-concurrently dep (29e6eec)

15.0.2 (2020-04-28)

Bug Fixes

  • tacks should be a dev dependency (93ec158)

15.0.1 (2020-04-27)

  • deps: Use move-file instead of move-file-concurrently. (92b125)

15.0.0 (2020-02-18)

⚠ BREAKING CHANGES

  • drop figgy-pudding and use canonical option names.

Features

14.0.0 (2020-01-28)

⚠ BREAKING CHANGES

  • deps: bumps engines to >= 10

  • deps: tar v6 and mkdirp v1 (5a66e7a)

13.0.1 (2019-09-30)

Bug Fixes

  • fix-owner: chownr.sync quits on non-root uid (08801be)

13.0.0 (2019-09-25)

⚠ BREAKING CHANGES

  • This subtly changes the streaming interface of everything in cacache that streams, which is, well, everything in cacache. Most users will probably not notice, but any code that depended on stream behavior always being deferred until next tick will need to adjust.

The mississippi methods 'to', 'from', 'through', and so on, have been replaced with their Minipass counterparts, and streaming interaction with the file system is done via fs-minipass.

The following modules are of interest here:

  • minipass The core stream library.

  • fs-minipass Note that the 'WriteStream' class from fs-minipass is not a Minipass stream, but rather a plain old EventEmitter that duck types as a Writable.

  • minipass-collect Gather up all the data from a stream. Cacache only uses Collect.PassThrough, which is a basic Minipass passthrough stream which emits a 'collect' event with the completed data just before the 'end' event.

  • minipass-pipeline Connect one or more streams into a pipe chain. Errors anywhere in the pipeline are proxied down the chain and then up to the Pipeline object itself. Writes go into the head, reads go to the tail. Used in place of pump() and pumpify().

  • minipass-flush A Minipass passthrough stream that defers its 'end' event until after a flush() method has completed (either calling the supplied callback, or returning a promise.) Use in place of flush-write-stream (aka mississippi.to).

Streams from through2, concat-stream, and the behavior provided by end-of-stream are all implemented in Minipass itself.

Features of interest to cacache, which make Minipass a particularly good fit:

  • All of the 'endish' events are normalized, so we can just listen on 'end' and know that finish, prefinish, and close will be handled as well.
  • Minipass doesn't waste time containing zalgo.
  • Minipass has built-in support for promises that indicate the end or error: stream.promise(), stream.collect(), and stream.concat().
  • With reliable and consistent timing guarantees, much less error-checking logic is required. We can be more confident that an error is being thrown or emitted in the correct place, rather than in a callback which is deferred, resulting in a hung promise or uncaughtException.

The biggest downside of Minipass is that it lacks some of the internal characteristics of node-core streams, which many community modules use to identify streams. They have no _writableState or _readableState objects, or _read or _write methods. As a result, the is-stream module (at least, at the time of this commit) doesn't recognize Minipass streams as readable or writable streams.

All in all, the changes required of downstream users should be minimal, but are unlikely to be zero. Hence the semver major change.

Features

  • replace all streams with Minipass streams (f4c0962)
  • deps: Add minipass and minipass-pipeline (a6545a9)
  • promise: converted .resolve to native promise, converted .map and .reduce to native (220c56d)
  • promise: individually promisifing functions as needed (74b939e)
  • promise: moved .reject from bluebird to native promise (1d56da1)
  • promise: removed .fromNode, removed .join (9c457a0)
  • promise: removed .map, replaced with p-map. removed .try (cc3ee05)
  • promise: removed .tap (0260f12)
  • promise: removed .using/.disposer (5d832f3)
  • promise: removed bluebird (c21298c)
  • promise: removed bluebird specific .catch calls (28aeeac)
  • promise: replaced .reduce and .mapSeries (478f5cb)

12.0.3 (2019-08-19)

Bug Fixes

  • do not chown if not running as root (2d80af9)

12.0.2 (2019-07-19)

12.0.1 (2019-07-19)

  • deps Abstracted out lib/util/infer-owner.js to @npmcli/infer-owner so that it could be more easily used in other parts of the npm CLI.

12.0.0 (2019-07-15)

Features

  • infer uid/gid instead of accepting as options (ac84d14)
  • i18n: add another error message (676cb32)

BREAKING CHANGES

  • the uid gid options are no longer respected or necessary. As of this change, cacache will always match the cache contents to the ownership of the cache directory (or its parent directory), regardless of what the caller passes in.

Reasoning:

The number one reason to use a uid or gid option was to keep root-owned files from causing problems in the cache. In npm's case, this meant that CLI's ./lib/command.js had to work out the appropriate uid and gid, then pass it to the libnpmcommand module, which had to in turn pass the uid and gid to npm-registry-fetch, which then passed it to make-fetch-happen, which passed it to cacache. (For package fetching, pacote would be in that mix as well.)

Added to that, cacache.rm() will actually write a file into the cache index, but has no way to accept an option so that its call to entry-index.js will write the index with the appropriate uid/gid. Little ownership bugs were all over the place, and tricky to trace through. (Why should make-fetch-happen even care about accepting or passing uids and gids? It's an http library.)

This change allows us to keep the cache from having mixed ownership in any situation.

Of course, this does mean that if you have a root-owned but user-writable folder (for example, /tmp), then the cache will try to chown everything to root.

The solution is for the user to create a folder, make it user-owned, and use that, rather than relying on cacache to create the root cache folder.

If we decide to restore the uid/gid opts, and use ownership inference only when uid/gid are unset, then take care to also make rm take an option object, and pass it through to entry-index.js.

11.3.3 (2019-06-17)

Bug Fixes

  • audit: npm audit fix (200a6d5)
  • config: Add ssri config 'error' option (#146) (47de8f5)
  • deps: npm audit fix (481a7dc)
  • standard: standard --fix (7799149)
  • write: avoid another cb never called situation (5156561)

11.3.2 (2018-12-21)

Bug Fixes

  • get: make sure to handle errors in the .then (b10bcd0)

11.3.1 (2018-11-05)

Bug Fixes

  • get: export hasContent.sync properly (d76c920)

11.3.0 (2018-11-05)

Features

  • get: add sync API for reading (db1e094)

11.2.0 (2018-08-08)

Features

  • read: add sync support to other internal read.js fns (fe638b6)

11.1.0 (2018-08-01)

Features

  • read: add sync support for low-level content read (b43af83)

11.0.3 (2018-08-01)

Bug Fixes

  • config: add ssri config options (#136) (10d5d9a)
  • perf: refactor content.read to avoid lstats (c5ac10e)
  • test: oops when removing safe-buffer (1950490)

11.0.2 (2018-05-07)

Bug Fixes

  • verify: size param no longer lost in a verify (#131) (c614a19), closes #130

11.0.1 (2018-04-10)

11.0.0 (2018-04-09)

Features

meta

  • drop support for node@4 (529f347)

BREAKING CHANGES

  • node@4 is no longer supported

10.0.4 (2018-02-16)

10.0.3 (2018-02-16)

Bug Fixes

  • content: rethrow aggregate errors as ENOENT (fa918f5)

10.0.2 (2018-01-07)

Bug Fixes

  • ls: deleted entries could cause a premature stream EOF (347dc36)

10.0.1 (2017-11-15)

Bug Fixes

  • move-file: actually use the fallback to move-concurrently (#110) (073fbe1)

10.0.0 (2017-10-23)

Features

  • license: relicense to ISC (#111) (fdbb4e5)

Performance Improvements

  • more copyFile benchmarks (63787bb)

BREAKING CHANGES

  • license: the license has been changed from CC0-1.0 to ISC.

9.3.0 (2017-10-07)

Features

  • copy: added cacache.get.copy api for fast copies (#107) (067b5f6)

9.2.9 (2017-06-17)

9.2.8 (2017-06-05)

Bug Fixes

  • ssri: bump ssri for bugfix (c3232ea)

9.2.7 (2017-06-05)

Bug Fixes

  • content: make verified content completely read-only (#96) (4131196)

9.2.6 (2017-05-31)

Bug Fixes

  • node: update ssri to prevent old node 4 crash (5209ffe)

9.2.5 (2017-05-25)

Bug Fixes

  • deps: fix lockfile issues and bump ssri (84e1d7e)

9.2.4 (2017-05-24)

Bug Fixes

9.2.3 (2017-05-24)

Bug Fixes

  • rm: stop crashing if content is missing on rm (ac90bc0)

9.2.2 (2017-05-14)

Bug Fixes

  • i18n: lets pretend this didn't happen (519b4ee)

9.2.1 (2017-05-14)

Bug Fixes

  • docs: fixing translation messup (bb9e4f9)

9.2.0 (2017-05-14)

Features

  • i18n: add Spanish translation for API (531f9a4)

9.1.0 (2017-05-14)

Features

  • i18n: Add Spanish translation and i18n setup (#91) (323b90c)

9.0.0 (2017-04-28)

Bug Fixes

  • memoization: actually use the LRU (0e55dc9)

Features

  • memoization: memoizers can be injected through opts.memoize (#90) (e5614c7)

BREAKING CHANGES

  • memoization: If you were passing an object to opts.memoize, it will now be used as an injected memoization object. If you were only passing booleans and other non-objects through that option, no changes are needed.

8.0.0 (2017-04-22)

Features

  • read: change hasContent to return {sri, size} (#88) (bad6c49), closes #87

BREAKING CHANGES

  • read: hasContent now returns an object with {sri, size} instead of sri. Use result.sri anywhere that needed the old return value.

7.1.0 (2017-04-20)

Features

  • size: handle content size info (#49) (91230af)

7.0.5 (2017-04-18)

Bug Fixes

  • integrity: new ssri with fixed integrity stream (6d13e8e)
  • write: wrap stuff in promises to improve errors (3624fc5)

7.0.4 (2017-04-15)

Bug Fixes

  • fix-owner: throw away ENOENTs on chownr (d49bbcd)

7.0.3 (2017-04-05)

Bug Fixes

  • read: fixing error message for integrity verification failures (9d4f0a5)

7.0.2 (2017-04-03)

Bug Fixes

  • integrity: use EINTEGRITY error code and update ssri (8dc2e62)

7.0.1 (2017-04-03)

Bug Fixes

  • docs: fix header name conflict in readme (afcd456)

7.0.0 (2017-04-03)

Bug Fixes

  • test: fix content.write tests when running in docker (d2e9b6a)

Features

  • integrity: subresource integrity support (#78) (b1e731f)

BREAKING CHANGES

  • integrity: The entire API has been overhauled to use SRI hashes instead of digest/hashAlgorithm pairs. SRI hashes follow the Subresource Integrity standard and support strings and objects compatible with ssri.

  • This change bumps the index version, which will invalidate all previous index entries. Content entries will remain intact, and existing caches will automatically reuse any content from before this breaking change.

  • cacache.get.info(), cacache.ls(), and cacache.ls.stream() will now return objects that looks like this:

{
  key: String,
  integrity: '<algorithm>-<base64hash>',
  path: ContentPath,
  time: Date<ms>,
  metadata: Any
}
  • opts.digest and opts.hashAlgorithm are obsolete for any API calls that used them.

  • Anywhere opts.digest was accepted, opts.integrity is now an option. Any valid SRI hash is accepted here -- multiple hash entries will be resolved according to the standard: first, the "strongest" hash algorithm will be picked, and then each of the entries for that algorithm will be matched against the content. Content will be validated if any of the entries match (so, a single integrity string can be used for multiple "versions" of the same document/data).

  • put.byDigest(), put.stream.byDigest, get.byDigest() and get.stream.byDigest() now expect an SRI instead of a digest + opts.hashAlgorithm pairing.

  • get.hasContent() now expects an integrity hash instead of a digest. If content exists, it will return the specific single integrity hash that was found in the cache.

  • verify() has learned to handle integrity-based caches, and forgotten how to handle old-style cache indices due to the format change.

  • cacache.rm.content() now expects an integrity hash instead of a hex digest.

6.3.0 (2017-04-01)

Bug Fixes

  • fixOwner: ignore EEXIST race condition from mkdirp (4670e9b)
  • index: ignore index removal races when inserting (b9d2fa2)
  • memo: use lru-cache for better mem management (#75) (d8ac5aa)

Features

  • dependencies: Switch to move-concurrently (#77) (dc6482d)

6.2.0 (2017-03-15)

Bug Fixes

  • index: additional bucket entry verification with checksum (#72) (f8e0f25)
  • verify: return fixOwner.chownr promise (6818521)

Features

  • tmp: safe tmp dir creation/management util (#73) (c42da71)

6.1.2 (2017-03-13)

Bug Fixes

  • index: set default hashAlgorithm (d6eb2f0)

6.1.1 (2017-03-13)

Bug Fixes

  • coverage: bumping coverage for verify (#71) (0b7faf6)
  • deps: glob should have been a regular dep :< (0640bc4)

6.1.0 (2017-03-12)

Bug Fixes

  • coverage: more coverage for content reads (#70) (ef4f70a)
  • tests: use safe-buffer because omfg (#69) (6ab8132)

Features

  • rm: limited rm.all and fixed bugs (#66) (d5d25ba), closes #66
  • verify: tested, working cache verifier/gc (#68) (45ad77a)

6.0.2 (2017-03-11)

Bug Fixes

  • index: segment cache items with another subbucket (#64) (c3644e5)

6.0.1 (2017-03-05)

Bug Fixes

  • docs: Missed spots in README (8ffb7fa)

6.0.0 (2017-03-05)

Bug Fixes

Features

  • api: converted external api (7bf032f)
  • cacache: exported clearMemoized() utility (8d2c5b6)
  • cache: add versioning to content and index (31bc549)
  • content: collate content files into subdirs (c094d9f)
  • deps: @npmcorp/move@1.0.0 (bdd00bf)
  • deps: `bluebird@3.4.7` (3a17aff)
  • deps: `promise-inflight@1.0.1` (a004fe6)
  • get: added memoization support for get (c77d794)
  • get: export hasContent (2956ec3)
  • index: add hashAlgorithm and format insert ret val (b639746)
  • index: collate index files into subdirs (e8402a5)
  • index: promisify entry index (cda3335)
  • memo: added memoization lib (da07b92)
  • memo: export memoization api (954b1b3)
  • move-file: add move fallback for weird errors (5cf4616)
  • perf: bulk content write api (51b536e)
  • put: added memoization support to put (b613a70)
  • read: switched to promises (a869362)
  • rm: added memoization support to rm (4205cf0)
  • rm: switched to promises (a000d24)
  • util: promise-inflight ownership fix requests (9517cd7)
  • util: use promises for api (ae204bb)
  • verify: converted to Promises (f0b3974)

BREAKING CHANGES

  • cache: index/content directories are now versioned. Previous caches are no longer compatible and cannot be migrated.
  • util: fix-owner now uses Promises instead of callbacks
  • index: Previously-generated index entries are no longer compatible and the index must be regenerated.
  • index: The index format has changed and previous caches are no longer compatible. Existing caches will need to be regenerated.
  • hashes: Default hashAlgorithm changed from sha1 to sha512. If you rely on the prior setting, pass opts.hashAlgorithm in explicitly.
  • content: Previously-generated content directories are no longer compatible and must be regenerated.
  • verify: API is now promise-based
  • read: Switches to a Promise-based API and removes callback stuff
  • rm: Switches to a Promise-based API and removes callback stuff
  • index: this changes the API to work off promises instead of callbacks
  • api: this means we are going all in on promises now