{"id":15641759,"url":"https://github.com/trygve-lie/ttl-mem-cache","last_synced_at":"2025-04-30T09:14:20.413Z","repository":{"id":57381998,"uuid":"102717135","full_name":"trygve-lie/ttl-mem-cache","owner":"trygve-lie","description":"A in memory time to live cache with streaming support.","archived":false,"fork":false,"pushed_at":"2023-05-02T17:19:43.000Z","size":191,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-29T15:11:59.642Z","etag":null,"topics":["cache","caching","javascript","nodejs","streams","ttl-cache"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trygve-lie.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-07T09:16:32.000Z","updated_at":"2023-07-30T18:37:43.000Z","dependencies_parsed_at":"2024-06-19T05:19:07.709Z","dependency_job_id":"5202466c-4cb7-474a-8577-2f55861cb8ed","html_url":"https://github.com/trygve-lie/ttl-mem-cache","commit_stats":{"total_commits":162,"total_committers":5,"mean_commits":32.4,"dds":0.3271604938271605,"last_synced_commit":"555f8ec4ff51d528fbd0bf0953ced3ee8332dce9"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trygve-lie%2Fttl-mem-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trygve-lie%2Fttl-mem-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trygve-lie%2Fttl-mem-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trygve-lie%2Fttl-mem-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trygve-lie","download_url":"https://codeload.github.com/trygve-lie/ttl-mem-cache/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233546487,"owners_count":18692228,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","caching","javascript","nodejs","streams","ttl-cache"],"created_at":"2024-10-03T11:45:00.124Z","updated_at":"2025-01-11T22:55:22.229Z","avatar_url":"https://github.com/trygve-lie.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ![ttl-mem-cache](logo.png)\n\nA in memory time to live cache with streaming support.\n\n[![GitHub Actions status](https://github.com/trygve-lie/ttl-mem-cache/workflows/test/badge.svg)](https://github.com/trygve-lie/ttl-mem-cache/actions?query=workflow%3A%22test%22)\n[![Known Vulnerabilities](https://snyk.io/test/github/trygve-lie/ttl-mem-cache/badge.svg?targetFile=package.json\u0026style=flat-square)](https://snyk.io/test/github/trygve-lie/ttl-mem-cache?targetFile=package.json)\n\n\n## Installation\n\n```bash\n$ npm install ttl-mem-cache\n```\n\n\n## Example\n\nSet an object and retrieve it.\n\n```js\nconst Cache = require('ttl-mem-cache');\n\nconst cache = new Cache();\n\ncache.set('a', {foo: 'bar'});\nconst obj = cache.get('a'); // returns {foo: 'bar'}\n```\n\n\n## Description\n\nThis is a in memory time to live key/value cache with streaming support. Items are\nnot pro-actively pruned out as they age but expires when they are too old when touched.\nIn other words; this module does not use `setTimeout()` or simmilar methods internally.\n\nThere is no restrictions on the values stored in the cache and there is no maximum limit\nof the amount of items in the cache. Whan that is said, the intention of this module is\nto act as a simple key/value cache where one need to cache small to medium amounts of\ndata.\n\n\n## Constructor\n\nCreate a new Cache instance.\n\n```js\nconst Cache = require('ttl-mem-cache');\nconst cache = new Cache(options);\n```\n\n### options (optional)\n\nAn Object containing misc configuration. The following values can be provided:\n\n * ttl - `Number` - Default time to live in milliseconds all items in the cache should be cached before expiering.\n * stale - `Boolean` - If expired items in cache should be returned when pruned from the cache. Default: `false`.\n * changelog - `Boolean` - If emitted `set` event and stream should contain both old and new value. Default: `false`.\n * id - `String` - Give the instanse a unique identifier. Default: `hash`\n\nIf an option Object with a `ttl` is not provided all items in the cache will by default\ncached for 5 minutes before they expire.\n\nItems can be cached forever by setting `ttl` to `Infinity`. Items cached forever can\nbe overwritten and manually deleted.\n\nPruning of items from the cache happend when they are touched by one of the methods\nfor retrieving (`.get()` and `.entries()`) items from the cache. By default pruning\nhappens before the method returns a value so if an item have expired, `null` will be\nreturned for expired items. By setting `stale` to `true`, these methods will return\nthe pruned item(s) before they are removed from the cache.\n\nInternally the cache has a unique ID created each time its instantiated. This ID is\nused to tell the origin of an cached item when streaming. The `id` will override\nthis generated ID. When using this, be carefull to not provide the same ID to multiple\ninstances of the cache.\n\nThe Cache instance inherit from Duplex Stream. Due to this the instance also take all\nconfig parameters which the Duplex Stream does. Please see the [documentation of Duplex Streams](https://nodejs.org/api/stream.html#stream_duplex_and_transform_streams)\nfor further documentation.\n\n\n## API\n\nThe Cache instance have the following API:\n\n\n### .set(key, value, ttl)\n\nSet an item in the cache on a given key.\n\n```js\nconst cache = new Cache();\ncache.set('a', {foo: 'bar'});\ncache.set('b', {foo: 'xyz'}, 20 * 60 * 1000);\n```\n\nThis method take the following arguments:\n\n * key - An unique key the value should be stored on in the cache. Required.\n * value - The value to store on the key in the cache. Required.\n * ttl - Time to live before the item should expire. Uses default if not given. Optional.\n\nAn item can be cached forever by setting `ttl` to `Infinity`.\n\n\n### .get(key)\n\nGet an item on a given key from the cache.\n\n```js\nconst cache = new Cache();\ncache.set('a', {foo: 'bar'});\nconst obj = cache.get('a'); // returns {foo: 'bar'}\n```\n\nThis method take the following arguments:\n\n * key - The unique key for the item in the cache. Required.\n\nTriggering `.get()` will check the expire on the item. If the item is older than\nthe time to live set on it, the item will be removed from the cache and this method\nwill return `null` unless `stale` is set to `true` on the constructor. Then the\nexpired item will be returned before its removed from the cache.\n\n\n### .del(key)\n\nExplicitly delete an item on a given key in the cache.\n\n```js\nconst cache = new Cache();\ncache.set('a', {foo: 'bar'});\ncache.del('a');\n```\n\nThis method take the following arguments:\n\n * key - The unique key for the item in the cache. Required.\n\n\n### .entries(mutator)\n\nGet all items in the cache. Returns an Array with all items.\n\n```js\nconst cache = new Cache();\ncache.set('a', {foo: 'bar'});\ncache.set('b', {foo: 'xyz'});\nconst all = cache.entries(); // returns [{foo: 'bar'}, {foo: 'xyz'}]\n```\n\nTriggering `.entries()` will check the expire on the items. If an item is older than\nthe time to live set on it, the item will be removed from the cache and it will not be\nincluded in the returned value of this methid unless `stale` is set to `true` on the\nconstructor. Then the expired item will be included before its removed from the cache.\n\nThis method take the following arguments:\n\n * mutator - A function for mutating the items returned. Optional.\n\nThe mutator attribute can be used to change the structure of the returned items. It\ntakes a function which will be called with an Object with the `key` and `value`. This\nfunction must return a value which then will be the value of the item in the returned\noutput.\n\n```js\nconst cache = new Cache();\ncache.set('a', {foo: 'bar'});\ncache.set('b', {foo: 'xyz'});\nconst all = cache.entries((item) =\u003e {\n    return item.value.foo;\n}); // returns ['bar', 'xyz']\n```\n\nThe advantage of using the mutator if one want to mutate the items is that the mutator\nis applied to each item in the same process as the expire is checked.\n\n\n### .prune()\n\nIterates over all items in the cache and proactively prunes expired items.\n\n\n### .clear()\n\nClears the entire cache. All items will be deleted.\n\n\n### .dump()\n\nReturns an Array of all items in the cache ready to be used by `.load()`.\n\n\n### .load(dump)\n\nLoads an Array of items, provided by `.dump()`, into the cache.\n\nThis method take the following arguments:\n\n * dump - Array of items to be imported.\n\nIf any of the items in the loaded Array contains a key which already are in\nthe cache the entry in the cache will be overwritten.\n\nIf any of the entries in the loaded Array are not compatible with the format\nwhich `.dump()` exports, they will not be inserted into the cache.\n\nReturns and Array with the keys which was inserted into the cache.\n\n\n### .length()\n\nThe number of items in the cache.\n\n\n## Events\n\nThe Cache instance inherit from Duplex Stream. Due to this the instance emits all the\nevents which Duplex Stream does when the streaming feature is used. Please see the\n[documentation of Duplex Streams](https://nodejs.org/api/stream.html#stream_duplex_and_transform_streams)\nfor further documentation.\n\nIn addition to this, the following events are emitted:\n\n\n### set\n\nWhen an item is set in the cache. Emits an Object with the `key` and `value` of the item.\n\n```js\nconst cache = new Cache();\ncache.on('set', (key, item) =\u003e {\n    console.log(key, item);  // outputs: \"a, {foo: 'bar'}\"\n});\ncache.set('a', {foo: 'bar'});\n```\n\nIf `changefeed` is set to be `true` on the constructor, the emitted Object will hold both\nold and new value for the key. See \"changelog\" for further info.\n\n### dispose\n\nWhen an item is disposed (deleted) from the cache. Emits the `key` of the item and the item itself.\n\n```js\nconst cache = new Cache();\ncache.on('dispose', (key, item) =\u003e {\n    console.log(key, item);  // outputs: \"a, {foo: 'bar'}\"\n});\ncache.set('a', {foo: 'bar'});\ncache.del('a');\n```\n\n### clear\n\nWhen the cache is cleared.\n\n\n## Streams\n\nThe Cache instance is a [Duplex Stream](https://nodejs.org/api/stream.html#stream_duplex_and_transform_streams). One can stream\nitems in and out of the cache.\n\nExample of streaming into the cache:\n\n```js\nconst cache = new Cache();\nconst source = new SomeReadableStream();  // a source streaming an item on key 'a' into the cache\n\nsource.pipe(cache);\n\ncache.get('a');  // returns the item for key 'a'\n```\n\nExample of streaming out of the cache:\n\n```js\nconst cache = new Cache();\nconst dest = new SomeWritableStream();  // a destination stream recieving items from the cache\n\ncache.pipe(dest);\n\ncache.set('a', {foo: 'bar'});  // pushes {foo: 'bar'} onto the writable stream\n```\n\nExample of streaming through the cache (all items streamed through will be kept in the cache):\n\n```js\nconst cache = new Cache();\nconst source = new SomeReadableStream();  // a source streaming items into the cache\nconst dest = new SomeWritableStream();  // a destination stream recieving items from the cache\n\nsource.pipe(cache).pipe(dest);\n\ncache.entries();  // returns all the items streamed through the cache\n```\n\n\n### Linking caches\n\nWith the stream API its possible to link caches together and distribute cached items between them.\n\n```js\nconst Cache = require('../');\n\nconst cacheA = new Cache();\nconst cacheB = new Cache();\nconst cacheC = new Cache();\n\n// Link all caches together\ncacheA.pipe(cacheB).pipe(cacheC).pipe(cacheA);\n\n// Set a value in cache C\ncacheC.set('foo', 'bar');\n\n// Retrieve the same value from all caches\nconsole.log(cacheA.get('foo'), cacheB.get('foo'), cacheC.get('foo'));\n\n// Delete the value in cache A\ncacheA.del('foo');\n\n// The value is deleted from all caches\nconsole.log(cacheA.get('foo'), cacheB.get('foo'), cacheC.get('foo'));\n```\n\n\n### Streaming Object type\n\nWhen using the Stream API to write to and read from the cache an [Entry Object](https://github.com/trygve-lie/ttl-mem-cache/blob/master/lib/entry.js)\nor an Object of simmilar character is used.\n\nThe [Entry Object](https://github.com/trygve-lie/ttl-mem-cache/blob/master/lib/entry.js)\nlooks like this:\n\n```js\n{\n    key: 'item key',\n    value: 'item value',\n    origin: 'cache instance ID',\n    ttl: 'time to live',\n    expires: 'time stamp'\n}\n```\n\nThe Stream API will always emit a full Entry Object. When writing to the Stream API one can provide\na full Entry Object, but a simmilar Object will also be accepted. Only `key` and `value` are required\nproperties when writing to the Stream API.\n\nIow; the following Object will be accepted by the Stream API:\n\n```js\n{\n    key: 'foo',\n    value: 'bar'\n}\n```\n\n`key` defines what key the value of `value` should be stored on in the cache. `key` is required\nand if not provided the stream will emit an error.\n\nWhen writing to the cache and a Object with `value` with a value is provided, it will be stored in\nthe cache on the provided `key`. If `value` is not provided or `null` or `undefined` on the\nObject when writing to the cache, any item with a matching `key` in the cache will be deleted.\n\nWhen the stream emits objects each object will have a `origin` key. The value is the unique ID of\nthe instance the object first was emitted on the stream. If the construcor was given a value for\nthe `id` argument, this will be used as `origin` value.\n\n`ttl` is how long the item is set to live in the cache.\n\n`expires` is the calculated timestamp for when the item should expire from the cache. This is\ncalculated when an item is set in the cache. If a value for `expires` is provided when writing\nto the Stream API this value will be set in the cache.\n\nIf the items you want to store in the cache does not fit your data type, its recommended to use\na [Transform Stream](https://nodejs.org/api/stream.html#stream_implementing_a_transform_stream)\nto transform it into the supported Object type.\n\nExample:\n\n```js\nconst cache = new Cache();\nconst source = new SomeReadableStream();  // contains Objects like this {id: 'a', item: 'bar'}\n\nconst convert = new stream.Transform({\n    objectMode: true,\n    transform(obj, encoding, callback) {\n        this.push({\n            key: obj.id,\n            value: obj.item\n        });\n        callback();\n    }\n});\n\nsource.pipe(convert).pipe(cache);\n```\n\nThe [Entry Object](https://github.com/trygve-lie/ttl-mem-cache/blob/master/lib/entry.js) does\nimplement `.toPrimitive` where a stringified JSON representation of the Object will be returned\nwhen call to the Entry Object with a String hint is done.\n\nThis can be used when one want to convert the Entry Object into a [Buffer](https://nodejs.org/api/buffer.html).\n\n```js\nconst cache = new Cache();\nconst dest = new SomeWritableStream();  // Some destination supporting Buffers\n\nconst convert = new stream.Transform({\n    writableObjectMode: true,\n    readableObjectMode: false,\n    transform(obj, encoding, callback) {\n        const buff = Buffer.from(obj);  // Convert Entry Object to a Buffer\n        this.push(buff);\n        callback();\n    }\n});\n\ncache.pipe(convert).pipe(dest);\n```\n\n### Object Mode\n\nBy default the stream are in object mode. Its also supported to run the stream in non-object\nmode. Object mode can be turned off by setting `objectMode` to `false` as an option to the\nconstructor.\n\nWhen using non-object mode the stream will emit `Buffers` containing a stringified JSON\nrepresentaion of the Entry Object.\n\n\n## Changelog\n\nIf the attribute `changelog` is set to `true` on the constructor, the `set` events will emit an\nobject holding both old and new values for the key.\n\nThe emitted object looks like this:\n\n```js\n{\n    oldVal: 'foo',\n    newVal: 'bar'\n}\n```\n\nExample:\n\n```js\nconst Cache = require('ttl-mem-cache');\n\nconst cache = new Cache({ changefeed: true });\ncache.on('set', (key, item) =\u003e {\n    // item will be in the format above\n});\ncache.set('a', 'foo');\ncache.set('a', 'bar');\n```\n\nIf a key does not hold a value in cache before, `oldVal` will be `null`.\nIf a key hold a value which has expired and `stale` is `false`, `oldVal` will be `null`.\nIf a key hold a value which has expired and `stale` is `true`, `oldVal` will be the old value.\n\n\n## error handling\n\nThis module does not handle errors for you, so you must handle errors on\nwhatever streams you pipe into this module. This is a general rule when\nprogramming with node.js streams: always handle errors on each and every stream.\n\nWe recommend using [`end-of-stream`](https://npmjs.org/end-of-stream) or [`pump`](https://npmjs.org/pump)\nfor writing error tolerant stream code.\n\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2017 - Trygve Lie - post@trygve-lie.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrygve-lie%2Fttl-mem-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrygve-lie%2Fttl-mem-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrygve-lie%2Fttl-mem-cache/lists"}