45177e61316b06a6da720d7b7ce76f533baef1aa5e18fa9151363b5b1ff91fdaae225cf5bd3e4c5c0d13e20ef8becb9140e7e56c4a60299d1a9dc03fc5de7b 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. # 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/npm/cacache.svg)](https://travis-ci.org/npm/cacache) [![AppVeyor](https://ci.appveyor.com/api/projects/status/github/npm/cacache?svg=true)](https://ci.appveyor.com/project/npm/cacache) [![Coverage Status](https://coveralls.io/repos/github/npm/cacache/badge.svg?branch=latest)](https://coveralls.io/github/npm/cacache?branch=latest)
  2. [`cacache`](https://github.com/npm/cacache) is a Node.js library for managing
  3. local key and content address caches. It's really fast, really good at
  4. concurrency, and it will never give you corrupted data, even if cache files
  5. get corrupted or manipulated.
  6. On systems that support user and group settings on files, cacache will
  7. match the `uid` and `gid` values to the folder where the cache lives, even
  8. when running as `root`.
  9. It was written to be used as [npm](https://npm.im)'s local cache, but can
  10. just as easily be used on its own.
  11. ## Install
  12. `$ npm install --save cacache`
  13. ## Table of Contents
  14. * [Example](#example)
  15. * [Features](#features)
  16. * [Contributing](#contributing)
  17. * [API](#api)
  18. * [Using localized APIs](#localized-api)
  19. * Reading
  20. * [`ls`](#ls)
  21. * [`ls.stream`](#ls-stream)
  22. * [`get`](#get-data)
  23. * [`get.stream`](#get-stream)
  24. * [`get.info`](#get-info)
  25. * [`get.hasContent`](#get-hasContent)
  26. * Writing
  27. * [`put`](#put-data)
  28. * [`put.stream`](#put-stream)
  29. * [`rm.all`](#rm-all)
  30. * [`rm.entry`](#rm-entry)
  31. * [`rm.content`](#rm-content)
  32. * [`index.compact`](#index-compact)
  33. * [`index.insert`](#index-insert)
  34. * Utilities
  35. * [`clearMemoized`](#clear-memoized)
  36. * [`tmp.mkdir`](#tmp-mkdir)
  37. * [`tmp.withTmp`](#with-tmp)
  38. * Integrity
  39. * [Subresource Integrity](#integrity)
  40. * [`verify`](#verify)
  41. * [`verify.lastRun`](#verify-last-run)
  42. ### Example
  43. ```javascript
  44. const cacache = require('cacache')
  45. const fs = require('fs')
  46. const tarball = '/path/to/mytar.tgz'
  47. const cachePath = '/tmp/my-toy-cache'
  48. const key = 'my-unique-key-1234'
  49. // Cache it! Use `cachePath` as the root of the content cache
  50. cacache.put(cachePath, key, '10293801983029384').then(integrity => {
  51. console.log(`Saved content to ${cachePath}.`)
  52. })
  53. const destination = '/tmp/mytar.tgz'
  54. // Copy the contents out of the cache and into their destination!
  55. // But this time, use stream instead!
  56. cacache.get.stream(
  57. cachePath, key
  58. ).pipe(
  59. fs.createWriteStream(destination)
  60. ).on('finish', () => {
  61. console.log('done extracting!')
  62. })
  63. // The same thing, but skip the key index.
  64. cacache.get.byDigest(cachePath, integrityHash).then(data => {
  65. fs.writeFile(destination, data, err => {
  66. console.log('tarball data fetched based on its sha512sum and written out!')
  67. })
  68. })
  69. ```
  70. ### Features
  71. * Extraction by key or by content address (shasum, etc)
  72. * [Subresource Integrity](#integrity) web standard support
  73. * Multi-hash support - safely host sha1, sha512, etc, in a single cache
  74. * Automatic content deduplication
  75. * Fault tolerance (immune to corruption, partial writes, process races, etc)
  76. * Consistency guarantees on read and write (full data verification)
  77. * Lockless, high-concurrency cache access
  78. * Streaming support
  79. * Promise support
  80. * Fast -- sub-millisecond reads and writes including verification
  81. * Arbitrary metadata storage
  82. * Garbage collection and additional offline verification
  83. * Thorough test coverage
  84. * There's probably a bloom filter in there somewhere. Those are cool, right? 🤔
  85. ### Contributing
  86. The cacache team enthusiastically welcomes contributions and project participation! There's a bunch of things you can do if you want to contribute! The [Contributor Guide](CONTRIBUTING.md) has all the information you need for everything from reporting bugs to contributing entire new features. Please don't hesitate to jump in if you'd like to, or even ask us questions if something isn't clear.
  87. All participants and maintainers in this project are expected to follow [Code of Conduct](CODE_OF_CONDUCT.md), and just generally be excellent to each other.
  88. Please refer to the [Changelog](CHANGELOG.md) for project history details, too.
  89. Happy hacking!
  90. ### API
  91. #### <a name="ls"></a> `> cacache.ls(cache) -> Promise<Object>`
  92. Lists info for all entries currently in the cache as a single large object. Each
  93. entry in the object will be keyed by the unique index key, with corresponding
  94. [`get.info`](#get-info) objects as the values.
  95. ##### Example
  96. ```javascript
  97. cacache.ls(cachePath).then(console.log)
  98. // Output
  99. {
  100. 'my-thing': {
  101. key: 'my-thing',
  102. integrity: 'sha512-BaSe64/EnCoDED+HAsh=='
  103. path: '.testcache/content/deadbeef', // joined with `cachePath`
  104. time: 12345698490,
  105. size: 4023948,
  106. metadata: {
  107. name: 'blah',
  108. version: '1.2.3',
  109. description: 'this was once a package but now it is my-thing'
  110. }
  111. },
  112. 'other-thing': {
  113. key: 'other-thing',
  114. integrity: 'sha1-ANothER+hasH=',
  115. path: '.testcache/content/bada55',
  116. time: 11992309289,
  117. size: 111112
  118. }
  119. }
  120. ```
  121. #### <a name="ls-stream"></a> `> cacache.ls.stream(cache) -> Readable`
  122. Lists info for all entries currently in the cache as a single large object.
  123. This works just like [`ls`](#ls), except [`get.info`](#get-info) entries are
  124. returned as `'data'` events on the returned stream.
  125. ##### Example
  126. ```javascript
  127. cacache.ls.stream(cachePath).on('data', console.log)
  128. // Output
  129. {
  130. key: 'my-thing',
  131. integrity: 'sha512-BaSe64HaSh',
  132. path: '.testcache/content/deadbeef', // joined with `cachePath`
  133. time: 12345698490,
  134. size: 13423,
  135. metadata: {
  136. name: 'blah',
  137. version: '1.2.3',
  138. description: 'this was once a package but now it is my-thing'
  139. }
  140. }
  141. {
  142. key: 'other-thing',
  143. integrity: 'whirlpool-WoWSoMuchSupport',
  144. path: '.testcache/content/bada55',
  145. time: 11992309289,
  146. size: 498023984029
  147. }
  148. {
  149. ...
  150. }
  151. ```
  152. #### <a name="get-data"></a> `> cacache.get(cache, key, [opts]) -> Promise({data, metadata, integrity})`
  153. Returns an object with the cached data, digest, and metadata identified by
  154. `key`. The `data` property of this object will be a `Buffer` instance that
  155. presumably holds some data that means something to you. I'm sure you know what
  156. to do with it! cacache just won't care.
  157. `integrity` is a [Subresource
  158. Integrity](#integrity)
  159. string. That is, a string that can be used to verify `data`, which looks like
  160. `<hash-algorithm>-<base64-integrity-hash>`.
  161. If there is no content identified by `key`, or if the locally-stored data does
  162. not pass the validity checksum, the promise will be rejected.
  163. A sub-function, `get.byDigest` may be used for identical behavior, except lookup
  164. will happen by integrity hash, bypassing the index entirely. This version of the
  165. function *only* returns `data` itself, without any wrapper.
  166. See: [options](#get-options)
  167. ##### Note
  168. This function loads the entire cache entry into memory before returning it. If
  169. you're dealing with Very Large data, consider using [`get.stream`](#get-stream)
  170. instead.
  171. ##### Example
  172. ```javascript
  173. // Look up by key
  174. cache.get(cachePath, 'my-thing').then(console.log)
  175. // Output:
  176. {
  177. metadata: {
  178. thingName: 'my'
  179. },
  180. integrity: 'sha512-BaSe64HaSh',
  181. data: Buffer#<deadbeef>,
  182. size: 9320
  183. }
  184. // Look up by digest
  185. cache.get.byDigest(cachePath, 'sha512-BaSe64HaSh').then(console.log)
  186. // Output:
  187. Buffer#<deadbeef>
  188. ```
  189. #### <a name="get-stream"></a> `> cacache.get.stream(cache, key, [opts]) -> Readable`
  190. Returns a [Readable Stream](https://nodejs.org/api/stream.html#stream_readable_streams) of the cached data identified by `key`.
  191. If there is no content identified by `key`, or if the locally-stored data does
  192. not pass the validity checksum, an error will be emitted.
  193. `metadata` and `integrity` events will be emitted before the stream closes, if
  194. you need to collect that extra data about the cached entry.
  195. A sub-function, `get.stream.byDigest` may be used for identical behavior,
  196. except lookup will happen by integrity hash, bypassing the index entirely. This
  197. version does not emit the `metadata` and `integrity` events at all.
  198. See: [options](#get-options)
  199. ##### Example
  200. ```javascript
  201. // Look up by key
  202. cache.get.stream(
  203. cachePath, 'my-thing'
  204. ).on('metadata', metadata => {
  205. console.log('metadata:', metadata)
  206. }).on('integrity', integrity => {
  207. console.log('integrity:', integrity)
  208. }).pipe(
  209. fs.createWriteStream('./x.tgz')
  210. )
  211. // Outputs:
  212. metadata: { ... }
  213. integrity: 'sha512-SoMeDIGest+64=='
  214. // Look up by digest
  215. cache.get.stream.byDigest(
  216. cachePath, 'sha512-SoMeDIGest+64=='
  217. ).pipe(
  218. fs.createWriteStream('./x.tgz')
  219. )
  220. ```
  221. #### <a name="get-info"></a> `> cacache.get.info(cache, key) -> Promise`
  222. Looks up `key` in the cache index, returning information about the entry if
  223. one exists.
  224. ##### Fields
  225. * `key` - Key the entry was looked up under. Matches the `key` argument.
  226. * `integrity` - [Subresource Integrity hash](#integrity) for the content this entry refers to.
  227. * `path` - Filesystem path where content is stored, joined with `cache` argument.
  228. * `time` - Timestamp the entry was first added on.
  229. * `metadata` - User-assigned metadata associated with the entry/content.
  230. ##### Example
  231. ```javascript
  232. cacache.get.info(cachePath, 'my-thing').then(console.log)
  233. // Output
  234. {
  235. key: 'my-thing',
  236. integrity: 'sha256-MUSTVERIFY+ALL/THINGS=='
  237. path: '.testcache/content/deadbeef',
  238. time: 12345698490,
  239. size: 849234,
  240. metadata: {
  241. name: 'blah',
  242. version: '1.2.3',
  243. description: 'this was once a package but now it is my-thing'
  244. }
  245. }
  246. ```
  247. #### <a name="get-hasContent"></a> `> cacache.get.hasContent(cache, integrity) -> Promise`
  248. Looks up a [Subresource Integrity hash](#integrity) in the cache. If content
  249. exists for this `integrity`, it will return an object, with the specific single integrity hash
  250. 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`.
  251. ##### Example
  252. ```javascript
  253. cacache.get.hasContent(cachePath, 'sha256-MUSTVERIFY+ALL/THINGS==').then(console.log)
  254. // Output
  255. {
  256. sri: {
  257. source: 'sha256-MUSTVERIFY+ALL/THINGS==',
  258. algorithm: 'sha256',
  259. digest: 'MUSTVERIFY+ALL/THINGS==',
  260. options: []
  261. },
  262. size: 9001
  263. }
  264. cacache.get.hasContent(cachePath, 'sha521-NOT+IN/CACHE==').then(console.log)
  265. // Output
  266. false
  267. ```
  268. ##### <a name="get-options"></a> Options
  269. ##### `opts.integrity`
  270. If present, the pre-calculated digest for the inserted content. If this option
  271. is provided and does not match the post-insertion digest, insertion will fail
  272. with an `EINTEGRITY` error.
  273. ##### `opts.memoize`
  274. Default: null
  275. 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.
  276. ##### `opts.size`
  277. If provided, the data stream will be verified to check that enough data was
  278. passed through. If there's more or less data than expected, insertion will fail
  279. with an `EBADSIZE` error.
  280. #### <a name="put-data"></a> `> cacache.put(cache, key, data, [opts]) -> Promise`
  281. Inserts data passed to it into the cache. The returned Promise resolves with a
  282. digest (generated according to [`opts.algorithms`](#optsalgorithms)) after the
  283. cache entry has been successfully written.
  284. See: [options](#put-options)
  285. ##### Example
  286. ```javascript
  287. fetch(
  288. 'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz'
  289. ).then(data => {
  290. return cacache.put(cachePath, 'registry.npmjs.org|cacache@1.0.0', data)
  291. }).then(integrity => {
  292. console.log('integrity hash is', integrity)
  293. })
  294. ```
  295. #### <a name="put-stream"></a> `> cacache.put.stream(cache, key, [opts]) -> Writable`
  296. Returns a [Writable
  297. Stream](https://nodejs.org/api/stream.html#stream_writable_streams) that inserts
  298. data written to it into the cache. Emits an `integrity` event with the digest of
  299. written contents when it succeeds.
  300. See: [options](#put-options)
  301. ##### Example
  302. ```javascript
  303. request.get(
  304. 'https://registry.npmjs.org/cacache/-/cacache-1.0.0.tgz'
  305. ).pipe(
  306. cacache.put.stream(
  307. cachePath, 'registry.npmjs.org|cacache@1.0.0'
  308. ).on('integrity', d => console.log(`integrity digest is ${d}`))
  309. )
  310. ```
  311. ##### <a name="put-options"></a> Options
  312. ##### `opts.metadata`
  313. Arbitrary metadata to be attached to the inserted key.
  314. ##### `opts.size`
  315. If provided, the data stream will be verified to check that enough data was
  316. passed through. If there's more or less data than expected, insertion will fail
  317. with an `EBADSIZE` error.
  318. ##### `opts.integrity`
  319. If present, the pre-calculated digest for the inserted content. If this option
  320. is provided and does not match the post-insertion digest, insertion will fail
  321. with an `EINTEGRITY` error.
  322. `algorithms` has no effect if this option is present.
  323. ##### `opts.algorithms`
  324. Default: ['sha512']
  325. Hashing algorithms to use when calculating the [subresource integrity
  326. digest](#integrity)
  327. for inserted data. Can use any algorithm listed in `crypto.getHashes()` or
  328. `'omakase'`/`'お任せします'` to pick a random hash algorithm on each insertion. You
  329. may also use any anagram of `'modnar'` to use this feature.
  330. Currently only supports one algorithm at a time (i.e., an array length of
  331. exactly `1`). Has no effect if `opts.integrity` is present.
  332. ##### `opts.memoize`
  333. Default: null
  334. If provided, cacache will memoize the given cache insertion in memory, bypassing
  335. any filesystem checks for that key or digest in future cache fetches. Nothing
  336. will be written to the in-memory cache unless this option is explicitly truthy.
  337. If `opts.memoize` is an object or a `Map`-like (that is, an object with `get`
  338. and `set` methods), it will be written to instead of the global memoization
  339. cache.
  340. Reading from disk data can be forced by explicitly passing `memoize: false` to
  341. the reader functions, but their default will be to read from memory.
  342. ##### `opts.tmpPrefix`
  343. Default: null
  344. Prefix to append on the temporary directory name inside the cache's tmp dir.
  345. #### <a name="rm-all"></a> `> cacache.rm.all(cache) -> Promise`
  346. Clears the entire cache. Mainly by blowing away the cache directory itself.
  347. ##### Example
  348. ```javascript
  349. cacache.rm.all(cachePath).then(() => {
  350. console.log('THE APOCALYPSE IS UPON US 😱')
  351. })
  352. ```
  353. #### <a name="rm-entry"></a> `> cacache.rm.entry(cache, key, [opts]) -> Promise`
  354. Alias: `cacache.rm`
  355. Removes the index entry for `key`. Content will still be accessible if
  356. requested directly by content address ([`get.stream.byDigest`](#get-stream)).
  357. By default, this appends a new entry to the index with an integrity of `null`.
  358. If `opts.removeFully` is set to `true` then the index file itself will be
  359. physically deleted rather than appending a `null`.
  360. To remove the content itself (which might still be used by other entries), use
  361. [`rm.content`](#rm-content). Or, to safely vacuum any unused content, use
  362. [`verify`](#verify).
  363. ##### Example
  364. ```javascript
  365. cacache.rm.entry(cachePath, 'my-thing').then(() => {
  366. console.log('I did not like it anyway')
  367. })
  368. ```
  369. #### <a name="rm-content"></a> `> cacache.rm.content(cache, integrity) -> Promise`
  370. Removes the content identified by `integrity`. Any index entries referring to it
  371. will not be usable again until the content is re-added to the cache with an
  372. identical digest.
  373. ##### Example
  374. ```javascript
  375. cacache.rm.content(cachePath, 'sha512-SoMeDIGest/IN+BaSE64==').then(() => {
  376. console.log('data for my-thing is gone!')
  377. })
  378. ```
  379. #### <a name="index-compact"></a> `> cacache.index.compact(cache, key, matchFn, [opts]) -> Promise`
  380. Uses `matchFn`, which must be a synchronous function that accepts two entries
  381. and returns a boolean indicating whether or not the two entries match, to
  382. deduplicate all entries in the cache for the given `key`.
  383. If `opts.validateEntry` is provided, it will be called as a function with the
  384. only parameter being a single index entry. The function must return a Boolean,
  385. if it returns `true` the entry is considered valid and will be kept in the index,
  386. if it returns `false` the entry will be removed from the index.
  387. If `opts.validateEntry` is not provided, however, every entry in the index will
  388. be deduplicated and kept until the first `null` integrity is reached, removing
  389. all entries that were written before the `null`.
  390. The deduplicated list of entries is both written to the index, replacing the
  391. existing content, and returned in the Promise.
  392. #### <a name="index-insert"></a> `> cacache.index.insert(cache, key, integrity, opts) -> Promise`
  393. Writes an index entry to the cache for the given `key` without writing content.
  394. It is assumed if you are using this method, you have already stored the content
  395. some other way and you only wish to add a new index to that content. The `metadata`
  396. and `size` properties are read from `opts` and used as part of the index entry.
  397. Returns a Promise resolving to the newly added entry.
  398. #### <a name="clear-memoized"></a> `> cacache.clearMemoized()`
  399. Completely resets the in-memory entry cache.
  400. #### <a name="tmp-mkdir"></a> `> tmp.mkdir(cache, opts) -> Promise<Path>`
  401. Returns a unique temporary directory inside the cache's `tmp` dir. This
  402. directory will use the same safe user assignment that all the other stuff use.
  403. Once the directory is made, it's the user's responsibility that all files
  404. within are given the appropriate `gid`/`uid` ownership settings to match
  405. the rest of the cache. If not, you can ask cacache to do it for you by
  406. calling [`tmp.fix()`](#tmp-fix), which will fix all tmp directory
  407. permissions.
  408. If you want automatic cleanup of this directory, use
  409. [`tmp.withTmp()`](#with-tpm)
  410. See: [options](#tmp-options)
  411. ##### Example
  412. ```javascript
  413. cacache.tmp.mkdir(cache).then(dir => {
  414. fs.writeFile(path.join(dir, 'blablabla'), Buffer#<1234>, ...)
  415. })
  416. ```
  417. #### <a name="tmp-fix"></a> `> tmp.fix(cache) -> Promise`
  418. Sets the `uid` and `gid` properties on all files and folders within the tmp
  419. folder to match the rest of the cache.
  420. Use this after manually writing files into [`tmp.mkdir`](#tmp-mkdir) or
  421. [`tmp.withTmp`](#with-tmp).
  422. ##### Example
  423. ```javascript
  424. cacache.tmp.mkdir(cache).then(dir => {
  425. writeFile(path.join(dir, 'file'), someData).then(() => {
  426. // make sure we didn't just put a root-owned file in the cache
  427. cacache.tmp.fix().then(() => {
  428. // all uids and gids match now
  429. })
  430. })
  431. })
  432. ```
  433. #### <a name="with-tmp"></a> `> tmp.withTmp(cache, opts, cb) -> Promise`
  434. Creates a temporary directory with [`tmp.mkdir()`](#tmp-mkdir) and calls `cb`
  435. with it. The created temporary directory will be removed when the return value
  436. of `cb()` resolves, the tmp directory will be automatically deleted once that
  437. promise completes.
  438. The same caveats apply when it comes to managing permissions for the tmp dir's
  439. contents.
  440. See: [options](#tmp-options)
  441. ##### Example
  442. ```javascript
  443. cacache.tmp.withTmp(cache, dir => {
  444. return fs.writeFileAsync(path.join(dir, 'blablabla'), Buffer#<1234>, ...)
  445. }).then(() => {
  446. // `dir` no longer exists
  447. })
  448. ```
  449. ##### <a name="tmp-options"></a> Options
  450. ##### `opts.tmpPrefix`
  451. Default: null
  452. Prefix to append on the temporary directory name inside the cache's tmp dir.
  453. #### <a name="integrity"></a> Subresource Integrity Digests
  454. For content verification and addressing, cacache uses strings following the
  455. [Subresource
  456. Integrity spec](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
  457. That is, any time cacache expects an `integrity` argument or option, it
  458. should be in the format `<hashAlgorithm>-<base64-hash>`.
  459. One deviation from the current spec is that cacache will support any hash
  460. algorithms supported by the underlying Node.js process. You can use
  461. `crypto.getHashes()` to see which ones you can use.
  462. ##### Generating Digests Yourself
  463. If you have an existing content shasum, they are generally formatted as a
  464. hexadecimal string (that is, a sha1 would look like:
  465. `5f5513f8822fdbe5145af33b64d8d970dcf95c6e`). In order to be compatible with
  466. cacache, you'll need to convert this to an equivalent subresource integrity
  467. string. For this example, the corresponding hash would be:
  468. `sha1-X1UT+IIv2+UUWvM7ZNjZcNz5XG4=`.
  469. If you want to generate an integrity string yourself for existing data, you can
  470. use something like this:
  471. ```javascript
  472. const crypto = require('crypto')
  473. const hashAlgorithm = 'sha512'
  474. const data = 'foobarbaz'
  475. const integrity = (
  476. hashAlgorithm +
  477. '-' +
  478. crypto.createHash(hashAlgorithm).update(data).digest('base64')
  479. )
  480. ```
  481. You can also use [`ssri`](https://npm.im/ssri) to have a richer set of functionality
  482. around SRI strings, including generation, parsing, and translating from existing
  483. hex-formatted strings.
  484. #### <a name="verify"></a> `> cacache.verify(cache, opts) -> Promise`
  485. Checks out and fixes up your cache:
  486. * Cleans up corrupted or invalid index entries.
  487. * Custom entry filtering options.
  488. * Garbage collects any content entries not referenced by the index.
  489. * Checks integrity for all content entries and removes invalid content.
  490. * Fixes cache ownership.
  491. * Removes the `tmp` directory in the cache and all its contents.
  492. When it's done, it'll return an object with various stats about the verification
  493. process, including amount of storage reclaimed, number of valid entries, number
  494. of entries removed, etc.
  495. ##### <a name="verify-options"></a> Options
  496. ##### `opts.concurrency`
  497. Default: 20
  498. Number of concurrently read files in the filesystem while doing clean up.
  499. ##### `opts.filter`
  500. Receives a formatted entry. Return false to remove it.
  501. Note: might be called more than once on the same entry.
  502. ##### `opts.log`
  503. Custom logger function:
  504. ```
  505. log: { silly () {} }
  506. log.silly('verify', 'verifying cache at', cache)
  507. ```
  508. ##### Example
  509. ```sh
  510. echo somegarbage >> $CACHEPATH/content/deadbeef
  511. ```
  512. ```javascript
  513. cacache.verify(cachePath).then(stats => {
  514. // deadbeef collected, because of invalid checksum.
  515. console.log('cache is much nicer now! stats:', stats)
  516. })
  517. ```
  518. #### <a name="verify-last-run"></a> `> cacache.verify.lastRun(cache) -> Promise`
  519. Returns a `Date` representing the last time `cacache.verify` was run on `cache`.
  520. ##### Example
  521. ```javascript
  522. cacache.verify(cachePath).then(() => {
  523. cacache.verify.lastRun(cachePath).then(lastTime => {
  524. console.log('cacache.verify was last called on' + lastTime)
  525. })
  526. })
  527. ```