[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"@babel/env\",\n      {\n        \"modules\": false\n      }\n    ]\n  ],\n  \"env\": {\n    \"test\": {\n      \"presets\": [\n        \"@babel/env\"\n      ],\n      \"plugins\": [\n        \"@babel/plugin-transform-runtime\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": ".github/workflows/run-coverage.yml",
    "content": "# This workflow will do a clean installation of node dependencies and run code coverage across different versions of node\n\nname: Run Code Coverage\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v3\n\n      - name: Use Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v3\n        with:\n          node-version: 18.x\n\n      - name: Start Redis ${{ matrix.redis-version }}\n        uses: supercharge/redis-github-action@1.4.0\n        with:\n          redis-version: 6\n\n      - name: Install dependencies\n        run: npm install\n\n      - name: Run the tests\n        run: npm test -- --coverage\n\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v3\n"
  },
  {
    "path": ".github/workflows/run-tests.yml",
    "content": "# This workflow will do a clean installation of node dependencies and run tests across different versions of node\n\nname: Run tests\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [16.x, 18.x]\n        redis-version: [4, 5, 6]\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v3\n\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions/setup-node@v3\n      with:\n        node-version: ${{ matrix.node-version }}\n\n    - name: Start Redis ${{ matrix.redis-version }}\n      uses: supercharge/redis-github-action@1.4.0\n      with:\n        redis-version: ${{ matrix.redis-version }}\n\n    - name: Install dependencies\n      run: npm install\n\n    - name: Run the tests\n      run: npm run test\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules/\ncoverage/\n.idea/\n*.log"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## v3.0.1 - 17 Oct, 2022\n\nFixed bug where the `redisStore.del` would no longer accept an options object, which broke the multiCaching interface.\n\n## v3.0.0 - 15 Oct, 2022\n\nUpgraded to redis@^4\n\n### Breaking Changes\n\n- The store needs to be instantiated before passing it to cache-manager and can no longer be instantiated with the factory method\n- Dropped support for Node.js < 16.18\n\n## v2.0.0 - 13 Feb, 2020\n\nUpdates all outdated dependencies. Updating Jest from v20 to v25 revealed that not all tests that asserted a promise rejecting were succeeding as expected. This resulted in the breaking change mentioned below.\n\n### Breaking Changes\n\n- The `set` method now actually checks `isCacheableValue` before setting a value\n- Dropped support for Node.js < 8.3\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Matthijs Dabroek\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 all\ncopies 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 THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "[![npm version](https://badge.fury.io/js/cache-manager-redis-store.svg)](https://badge.fury.io/js/cache-manager-redis-store)\n[![GitHub issues](https://img.shields.io/github/issues/dabroek/node-cache-manager-redis-store.svg)](https://github.com/dabroek/node-cache-manager-redis-store/issues)\n[![codecov](https://codecov.io/github/dabroek/node-cache-manager-redis-store/branch/master/graph/badge.svg?token=QmCNGyCLlD)](https://codecov.io/github/dabroek/node-cache-manager-redis-store)\n\nRedis store for node cache manager\n==================================\n\nRedis cache store for [node-cache-manager](https://github.com/BryanDonovan/node-cache-manager).\n\nHow is this package different from `node-cache-manager-redis`?\n----------------------------------------------------------------------------------\nThis is a **completely different version** than the earlier [node-cache-manager-redis](https://github.com/dial-once/node-cache-manager-redis). This package does not use `redis-pool` which is unnecessary and not actively maintained.\n\nThis package aims to provide **the most simple wrapper possible** by just passing the configuration to the underlying `node_redis` package.\n\nInstallation\n------------\n\n```sh\nnpm install cache-manager-redis-store --save\n```\nor\n```sh\nyarn add cache-manager-redis-store\n```\n\nUsage Examples\n--------------\n\nSee examples below on how to implement the Redis cache store.\n\n### Single store\n\n```js\nvar cacheManager = require('cache-manager');\nvar redisStore = require('cache-manager-redis-store').redisStore;\n\nvar config = {\n  socket: {\n    host: 'localhost', // default value\n    port: 6379, // default value\n  },\n  password: 'XXXXX',\n  db: 0,\n  ttl: 600\n};\n\nvar redisCache = cacheManager.caching({\n  store: await redisStore(config),\n});\n\n// listen for redis connection error event\nvar redisClient = redisCache.store.getClient();\n\nredisClient.on('error', (error) => {\n  // handle error here\n  console.log(error);\n});\n\nvar ttl = 5;\n\nawait redisCache.set('foo', 'bar', { ttl: ttl });\n\n// You can use either a Promise...\nvar result = await redisCache.get('foo');\nconsole.log(result);\n\n// ...or a callback\nredisCache.get('foo', (err, result) => {\n  if (err) {\n    // handle error here\n  }\n  console.log(result);\n});\n\n// >> 'bar'\nconsole.log(await redisCache.del('foo'));\n// >> 1\n\nfunction getUser(id, cb) {\n  setTimeout(() => {\n    console.log(\"Returning user from slow database.\");\n    cb(null, { id: id, name: 'Bob' });\n  }, 100);\n}\n\nvar userId = 123;\nvar key = `user_${userId}`;\n\n// Note: ttl is optional in wrap()\nredisCache.wrap(key, (cb) => {\n  getUser(userId, cb);\n}, { ttl: ttl }, (err, user) => {\n  console.log(user);\n\n  // Second time fetches user from redisCache\n  redisCache\n    .wrap(key, () => getUser(userId))\n    .then(console.log)\n    .catch(err => {\n      // handle error\n    });\n});\n```\n\n### Multi-store\n\n```js\nvar cacheManager = require('cache-manager');\nvar redisStore = require('cache-manager-redis-store').redisStore;\n\nvar redisCache = cacheManager.caching({ store: await redisStore({ ...config, db: 0, ttl: 600 }) });\nvar memoryCache = cacheManager.caching({ store: 'memory', max: 100, ttl: 60 });\n\nvar multiCache = cacheManager.multiCaching([memoryCache, redisCache]);\n\nvar userId2 = 456;\nvar key2 = `user_${userId2}`;\n\n// Set value in all caches\nawait multiCache.set('foo2', 'bar2', { ttl: ttl });\n// Fetches from highest priority cache that has the key\nvar result = await multiCache.get('foo2');\nconsole.log(result);\n// >> 'bar2'\n\n// Delete from all caches\nawait multiCache.del('foo2');\n\n// Note: ttl is optional in wrap\nmultiCache.wrap(key2, (cb) => {\n  getUser(userId2, cb);\n}, (err, user) => {\n  console.log(user);\n\n  // Second time fetches user from memoryCache, since it's highest priority.\n  // If the data expires in the memory cache, the next fetch would pull it from\n  // the 'someOtherCache', and set the data in memory again.\n  multiCache.wrap(key2, (cb) => {\n    getUser(userId2, cb);\n  }, (err, user) => {\n    console.log(user);\n  });\n});\n```\n\nContribution\n------------\n\nWant to help improve this package? We take [pull requests](https://github.com/dabroek/node-cache-manager-redis-store/pulls).\n\n\nLicense\n-------\n\nThe `node-cache-manager-redis-store` is licensed under the MIT license."
  },
  {
    "path": "dist/index.d.ts",
    "content": "import type { Store, StoreConfig } from \"cache-manager\";\nimport type { RedisClientType, RedisClientOptions } from \"redis\";\n\ninterface RedisStore extends Store {\n    name: string;\n    getClient: () => RedisClientType;\n    isCacheableValue: any;\n    set: (key: any, value: any, options: any, cb: any) => Promise<any>;\n    get: (key: any, options: any, cb: any) => Promise<any>;\n    del: (...args: any[]) => Promise<any>;\n    mset: (...args: any[]) => Promise<any>;\n    mget: (...args: any[]) => Promise<any>;\n    mdel: (...args: any[]) => Promise<any>;\n    reset: (cb: any) => Promise<any>;\n    keys: (pattern: string, cb: any) => Promise<any>;\n    ttl: (key: any, cb: any) => Promise<any>;\n}\n\nexport function redisStore(config: RedisClientOptions & StoreConfig): Promise<RedisStore>;\n"
  },
  {
    "path": "dist/index.js",
    "content": "'use strict';\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\nvar node_util = require('node:util');\nvar redis = require('redis');\n\nfunction _regeneratorRuntime() {\n  _regeneratorRuntime = function () {\n    return exports;\n  };\n  var exports = {},\n    Op = Object.prototype,\n    hasOwn = Op.hasOwnProperty,\n    $Symbol = \"function\" == typeof Symbol ? Symbol : {},\n    iteratorSymbol = $Symbol.iterator || \"@@iterator\",\n    asyncIteratorSymbol = $Symbol.asyncIterator || \"@@asyncIterator\",\n    toStringTagSymbol = $Symbol.toStringTag || \"@@toStringTag\";\n  function define(obj, key, value) {\n    return Object.defineProperty(obj, key, {\n      value: value,\n      enumerable: !0,\n      configurable: !0,\n      writable: !0\n    }), obj[key];\n  }\n  try {\n    define({}, \"\");\n  } catch (err) {\n    define = function (obj, key, value) {\n      return obj[key] = value;\n    };\n  }\n  function wrap(innerFn, outerFn, self, tryLocsList) {\n    var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator,\n      generator = Object.create(protoGenerator.prototype),\n      context = new Context(tryLocsList || []);\n    return generator._invoke = function (innerFn, self, context) {\n      var state = \"suspendedStart\";\n      return function (method, arg) {\n        if (\"executing\" === state) throw new Error(\"Generator is already running\");\n        if (\"completed\" === state) {\n          if (\"throw\" === method) throw arg;\n          return doneResult();\n        }\n        for (context.method = method, context.arg = arg;;) {\n          var delegate = context.delegate;\n          if (delegate) {\n            var delegateResult = maybeInvokeDelegate(delegate, context);\n            if (delegateResult) {\n              if (delegateResult === ContinueSentinel) continue;\n              return delegateResult;\n            }\n          }\n          if (\"next\" === context.method) context.sent = context._sent = context.arg;else if (\"throw\" === context.method) {\n            if (\"suspendedStart\" === state) throw state = \"completed\", context.arg;\n            context.dispatchException(context.arg);\n          } else \"return\" === context.method && context.abrupt(\"return\", context.arg);\n          state = \"executing\";\n          var record = tryCatch(innerFn, self, context);\n          if (\"normal\" === record.type) {\n            if (state = context.done ? \"completed\" : \"suspendedYield\", record.arg === ContinueSentinel) continue;\n            return {\n              value: record.arg,\n              done: context.done\n            };\n          }\n          \"throw\" === record.type && (state = \"completed\", context.method = \"throw\", context.arg = record.arg);\n        }\n      };\n    }(innerFn, self, context), generator;\n  }\n  function tryCatch(fn, obj, arg) {\n    try {\n      return {\n        type: \"normal\",\n        arg: fn.call(obj, arg)\n      };\n    } catch (err) {\n      return {\n        type: \"throw\",\n        arg: err\n      };\n    }\n  }\n  exports.wrap = wrap;\n  var ContinueSentinel = {};\n  function Generator() {}\n  function GeneratorFunction() {}\n  function GeneratorFunctionPrototype() {}\n  var IteratorPrototype = {};\n  define(IteratorPrototype, iteratorSymbol, function () {\n    return this;\n  });\n  var getProto = Object.getPrototypeOf,\n    NativeIteratorPrototype = getProto && getProto(getProto(values([])));\n  NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype);\n  var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);\n  function defineIteratorMethods(prototype) {\n    [\"next\", \"throw\", \"return\"].forEach(function (method) {\n      define(prototype, method, function (arg) {\n        return this._invoke(method, arg);\n      });\n    });\n  }\n  function AsyncIterator(generator, PromiseImpl) {\n    function invoke(method, arg, resolve, reject) {\n      var record = tryCatch(generator[method], generator, arg);\n      if (\"throw\" !== record.type) {\n        var result = record.arg,\n          value = result.value;\n        return value && \"object\" == typeof value && hasOwn.call(value, \"__await\") ? PromiseImpl.resolve(value.__await).then(function (value) {\n          invoke(\"next\", value, resolve, reject);\n        }, function (err) {\n          invoke(\"throw\", err, resolve, reject);\n        }) : PromiseImpl.resolve(value).then(function (unwrapped) {\n          result.value = unwrapped, resolve(result);\n        }, function (error) {\n          return invoke(\"throw\", error, resolve, reject);\n        });\n      }\n      reject(record.arg);\n    }\n    var previousPromise;\n    this._invoke = function (method, arg) {\n      function callInvokeWithMethodAndArg() {\n        return new PromiseImpl(function (resolve, reject) {\n          invoke(method, arg, resolve, reject);\n        });\n      }\n      return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();\n    };\n  }\n  function maybeInvokeDelegate(delegate, context) {\n    var method = delegate.iterator[context.method];\n    if (undefined === method) {\n      if (context.delegate = null, \"throw\" === context.method) {\n        if (delegate.iterator.return && (context.method = \"return\", context.arg = undefined, maybeInvokeDelegate(delegate, context), \"throw\" === context.method)) return ContinueSentinel;\n        context.method = \"throw\", context.arg = new TypeError(\"The iterator does not provide a 'throw' method\");\n      }\n      return ContinueSentinel;\n    }\n    var record = tryCatch(method, delegate.iterator, context.arg);\n    if (\"throw\" === record.type) return context.method = \"throw\", context.arg = record.arg, context.delegate = null, ContinueSentinel;\n    var info = record.arg;\n    return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, \"return\" !== context.method && (context.method = \"next\", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = \"throw\", context.arg = new TypeError(\"iterator result is not an object\"), context.delegate = null, ContinueSentinel);\n  }\n  function pushTryEntry(locs) {\n    var entry = {\n      tryLoc: locs[0]\n    };\n    1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry);\n  }\n  function resetTryEntry(entry) {\n    var record = entry.completion || {};\n    record.type = \"normal\", delete record.arg, entry.completion = record;\n  }\n  function Context(tryLocsList) {\n    this.tryEntries = [{\n      tryLoc: \"root\"\n    }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0);\n  }\n  function values(iterable) {\n    if (iterable) {\n      var iteratorMethod = iterable[iteratorSymbol];\n      if (iteratorMethod) return iteratorMethod.call(iterable);\n      if (\"function\" == typeof iterable.next) return iterable;\n      if (!isNaN(iterable.length)) {\n        var i = -1,\n          next = function next() {\n            for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next;\n            return next.value = undefined, next.done = !0, next;\n          };\n        return next.next = next;\n      }\n    }\n    return {\n      next: doneResult\n    };\n  }\n  function doneResult() {\n    return {\n      value: undefined,\n      done: !0\n    };\n  }\n  return GeneratorFunction.prototype = GeneratorFunctionPrototype, define(Gp, \"constructor\", GeneratorFunctionPrototype), define(GeneratorFunctionPrototype, \"constructor\", GeneratorFunction), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, \"GeneratorFunction\"), exports.isGeneratorFunction = function (genFun) {\n    var ctor = \"function\" == typeof genFun && genFun.constructor;\n    return !!ctor && (ctor === GeneratorFunction || \"GeneratorFunction\" === (ctor.displayName || ctor.name));\n  }, exports.mark = function (genFun) {\n    return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, \"GeneratorFunction\")), genFun.prototype = Object.create(Gp), genFun;\n  }, exports.awrap = function (arg) {\n    return {\n      __await: arg\n    };\n  }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () {\n    return this;\n  }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {\n    void 0 === PromiseImpl && (PromiseImpl = Promise);\n    var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);\n    return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) {\n      return result.done ? result.value : iter.next();\n    });\n  }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, \"Generator\"), define(Gp, iteratorSymbol, function () {\n    return this;\n  }), define(Gp, \"toString\", function () {\n    return \"[object Generator]\";\n  }), exports.keys = function (object) {\n    var keys = [];\n    for (var key in object) keys.push(key);\n    return keys.reverse(), function next() {\n      for (; keys.length;) {\n        var key = keys.pop();\n        if (key in object) return next.value = key, next.done = !1, next;\n      }\n      return next.done = !0, next;\n    };\n  }, exports.values = values, Context.prototype = {\n    constructor: Context,\n    reset: function (skipTempReset) {\n      if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = \"next\", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) \"t\" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined);\n    },\n    stop: function () {\n      this.done = !0;\n      var rootRecord = this.tryEntries[0].completion;\n      if (\"throw\" === rootRecord.type) throw rootRecord.arg;\n      return this.rval;\n    },\n    dispatchException: function (exception) {\n      if (this.done) throw exception;\n      var context = this;\n      function handle(loc, caught) {\n        return record.type = \"throw\", record.arg = exception, context.next = loc, caught && (context.method = \"next\", context.arg = undefined), !!caught;\n      }\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i],\n          record = entry.completion;\n        if (\"root\" === entry.tryLoc) return handle(\"end\");\n        if (entry.tryLoc <= this.prev) {\n          var hasCatch = hasOwn.call(entry, \"catchLoc\"),\n            hasFinally = hasOwn.call(entry, \"finallyLoc\");\n          if (hasCatch && hasFinally) {\n            if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);\n            if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);\n          } else if (hasCatch) {\n            if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0);\n          } else {\n            if (!hasFinally) throw new Error(\"try statement without catch or finally\");\n            if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc);\n          }\n        }\n      }\n    },\n    abrupt: function (type, arg) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.tryLoc <= this.prev && hasOwn.call(entry, \"finallyLoc\") && this.prev < entry.finallyLoc) {\n          var finallyEntry = entry;\n          break;\n        }\n      }\n      finallyEntry && (\"break\" === type || \"continue\" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null);\n      var record = finallyEntry ? finallyEntry.completion : {};\n      return record.type = type, record.arg = arg, finallyEntry ? (this.method = \"next\", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record);\n    },\n    complete: function (record, afterLoc) {\n      if (\"throw\" === record.type) throw record.arg;\n      return \"break\" === record.type || \"continue\" === record.type ? this.next = record.arg : \"return\" === record.type ? (this.rval = this.arg = record.arg, this.method = \"return\", this.next = \"end\") : \"normal\" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel;\n    },\n    finish: function (finallyLoc) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel;\n      }\n    },\n    catch: function (tryLoc) {\n      for (var i = this.tryEntries.length - 1; i >= 0; --i) {\n        var entry = this.tryEntries[i];\n        if (entry.tryLoc === tryLoc) {\n          var record = entry.completion;\n          if (\"throw\" === record.type) {\n            var thrown = record.arg;\n            resetTryEntry(entry);\n          }\n          return thrown;\n        }\n      }\n      throw new Error(\"illegal catch attempt\");\n    },\n    delegateYield: function (iterable, resultName, nextLoc) {\n      return this.delegate = {\n        iterator: values(iterable),\n        resultName: resultName,\n        nextLoc: nextLoc\n      }, \"next\" === this.method && (this.arg = undefined), ContinueSentinel;\n    }\n  }, exports;\n}\nfunction _typeof(obj) {\n  \"@babel/helpers - typeof\";\n\n  return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) {\n    return typeof obj;\n  } : function (obj) {\n    return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n  }, _typeof(obj);\n}\nfunction asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {\n  try {\n    var info = gen[key](arg);\n    var value = info.value;\n  } catch (error) {\n    reject(error);\n    return;\n  }\n  if (info.done) {\n    resolve(value);\n  } else {\n    Promise.resolve(value).then(_next, _throw);\n  }\n}\nfunction _asyncToGenerator(fn) {\n  return function () {\n    var self = this,\n      args = arguments;\n    return new Promise(function (resolve, reject) {\n      var gen = fn.apply(self, args);\n      function _next(value) {\n        asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value);\n      }\n      function _throw(err) {\n        asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err);\n      }\n      _next(undefined);\n    });\n  };\n}\nfunction _slicedToArray(arr, i) {\n  return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();\n}\nfunction _arrayWithHoles(arr) {\n  if (Array.isArray(arr)) return arr;\n}\nfunction _iterableToArrayLimit(arr, i) {\n  var _i = arr == null ? null : typeof Symbol !== \"undefined\" && arr[Symbol.iterator] || arr[\"@@iterator\"];\n  if (_i == null) return;\n  var _arr = [];\n  var _n = true;\n  var _d = false;\n  var _s, _e;\n  try {\n    for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {\n      _arr.push(_s.value);\n      if (i && _arr.length === i) break;\n    }\n  } catch (err) {\n    _d = true;\n    _e = err;\n  } finally {\n    try {\n      if (!_n && _i[\"return\"] != null) _i[\"return\"]();\n    } finally {\n      if (_d) throw _e;\n    }\n  }\n  return _arr;\n}\nfunction _unsupportedIterableToArray(o, minLen) {\n  if (!o) return;\n  if (typeof o === \"string\") return _arrayLikeToArray(o, minLen);\n  var n = Object.prototype.toString.call(o).slice(8, -1);\n  if (n === \"Object\" && o.constructor) n = o.constructor.name;\n  if (n === \"Map\" || n === \"Set\") return Array.from(o);\n  if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);\n}\nfunction _arrayLikeToArray(arr, len) {\n  if (len == null || len > arr.length) len = arr.length;\n  for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];\n  return arr2;\n}\nfunction _nonIterableRest() {\n  throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\nfunction _createForOfIteratorHelper(o, allowArrayLike) {\n  var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"];\n  if (!it) {\n    if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") {\n      if (it) o = it;\n      var i = 0;\n      var F = function () {};\n      return {\n        s: F,\n        n: function () {\n          if (i >= o.length) return {\n            done: true\n          };\n          return {\n            done: false,\n            value: o[i++]\n          };\n        },\n        e: function (e) {\n          throw e;\n        },\n        f: F\n      };\n    }\n    throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n  }\n  var normalCompletion = true,\n    didErr = false,\n    err;\n  return {\n    s: function () {\n      it = it.call(o);\n    },\n    n: function () {\n      var step = it.next();\n      normalCompletion = step.done;\n      return step;\n    },\n    e: function (e) {\n      didErr = true;\n      err = e;\n    },\n    f: function () {\n      try {\n        if (!normalCompletion && it.return != null) it.return();\n      } finally {\n        if (didErr) throw err;\n      }\n    }\n  };\n}\n\nfunction redisStore(_x) {\n  return _redisStore.apply(this, arguments);\n}\nfunction _redisStore() {\n  _redisStore = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10(config) {\n    var redisCache;\n    return _regeneratorRuntime().wrap(function _callee10$(_context10) {\n      while (1) {\n        switch (_context10.prev = _context10.next) {\n          case 0:\n            redisCache = redis.createClient(config);\n            _context10.next = 3;\n            return redisCache.connect();\n          case 3:\n            return _context10.abrupt(\"return\", buildRedisStoreWithConfig(redisCache, config));\n          case 4:\n          case \"end\":\n            return _context10.stop();\n        }\n      }\n    }, _callee10);\n  }));\n  return _redisStore.apply(this, arguments);\n}\nvar buildRedisStoreWithConfig = function buildRedisStoreWithConfig(redisCache, config) {\n  var isCacheableValue = config.isCacheableValue || function (value) {\n    return value !== undefined && value !== null;\n  };\n  var _set = /*#__PURE__*/function () {\n    var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(key, value, options) {\n      var ttl;\n      return _regeneratorRuntime().wrap(function _callee$(_context) {\n        while (1) {\n          switch (_context.prev = _context.next) {\n            case 0:\n              if (isCacheableValue(value)) {\n                _context.next = 2;\n                break;\n              }\n              throw new Error(\"\\\"\".concat(value, \"\\\" is not a cacheable value\"));\n            case 2:\n              ttl = options !== null && options !== void 0 && options.ttl || (options === null || options === void 0 ? void 0 : options.ttl) === 0 ? options.ttl : config.ttl;\n              if (!ttl) {\n                _context.next = 7;\n                break;\n              }\n              return _context.abrupt(\"return\", redisCache.setEx(key, ttl, encodeValue(value)));\n            case 7:\n              return _context.abrupt(\"return\", redisCache.set(key, encodeValue(value)));\n            case 8:\n            case \"end\":\n              return _context.stop();\n          }\n        }\n      }, _callee);\n    }));\n    return function set(_x2, _x3, _x4) {\n      return _ref.apply(this, arguments);\n    };\n  }();\n  var _get = /*#__PURE__*/function () {\n    var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(key, options) {\n      var val;\n      return _regeneratorRuntime().wrap(function _callee2$(_context2) {\n        while (1) {\n          switch (_context2.prev = _context2.next) {\n            case 0:\n              _context2.next = 2;\n              return redisCache.get(key);\n            case 2:\n              val = _context2.sent;\n              if (!(val === null)) {\n                _context2.next = 5;\n                break;\n              }\n              return _context2.abrupt(\"return\", null);\n            case 5:\n              return _context2.abrupt(\"return\", options.parse !== false ? decodeValue(val) : val);\n            case 6:\n            case \"end\":\n              return _context2.stop();\n          }\n        }\n      }, _callee2);\n    }));\n    return function get(_x5, _x6) {\n      return _ref2.apply(this, arguments);\n    };\n  }();\n  var _del = /*#__PURE__*/function () {\n    var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(args) {\n      return _regeneratorRuntime().wrap(function _callee3$(_context3) {\n        while (1) {\n          switch (_context3.prev = _context3.next) {\n            case 0:\n              if (isObject(args.at(-1))) {\n                args.pop();\n              }\n              return _context3.abrupt(\"return\", redisCache.del(args));\n            case 3:\n            case \"end\":\n              return _context3.stop();\n          }\n        }\n      }, _callee3);\n    }));\n    return function del(_x7) {\n      return _ref3.apply(this, arguments);\n    };\n  }();\n  var _mset = /*#__PURE__*/function () {\n    var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(args) {\n      var options, ttl, items, multi, _iterator, _step, kv, _kv, key, value;\n      return _regeneratorRuntime().wrap(function _callee4$(_context4) {\n        while (1) {\n          switch (_context4.prev = _context4.next) {\n            case 0:\n              options = {};\n              if (isObject(args.at(-1))) {\n                options = args.pop();\n              }\n              ttl = options.ttl || options.ttl === 0 ? options.ttl : config.ttl; // Zips even and odd array items into tuples\n              items = args.map(function (key, index) {\n                if (index % 2 !== 0) return null;\n                var value = args[index + 1];\n                if (!isCacheableValue(value)) {\n                  throw new Error(\"\\\"\".concat(value, \"\\\" is not a cacheable value\"));\n                }\n                return [key, encodeValue(value)];\n              }).filter(function (key) {\n                return key !== null;\n              });\n              if (!ttl) {\n                _context4.next = 11;\n                break;\n              }\n              multi = redisCache.multi();\n              _iterator = _createForOfIteratorHelper(items);\n              try {\n                for (_iterator.s(); !(_step = _iterator.n()).done;) {\n                  kv = _step.value;\n                  _kv = _slicedToArray(kv, 2), key = _kv[0], value = _kv[1];\n                  multi.setEx(key, ttl, value);\n                }\n              } catch (err) {\n                _iterator.e(err);\n              } finally {\n                _iterator.f();\n              }\n              return _context4.abrupt(\"return\", multi.exec());\n            case 11:\n              return _context4.abrupt(\"return\", redisCache.mSet(items));\n            case 12:\n            case \"end\":\n              return _context4.stop();\n          }\n        }\n      }, _callee4);\n    }));\n    return function mset(_x8) {\n      return _ref4.apply(this, arguments);\n    };\n  }();\n  var _mget = /*#__PURE__*/function () {\n    var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5() {\n      var options,\n        _len,\n        args,\n        _key,\n        _args5 = arguments;\n      return _regeneratorRuntime().wrap(function _callee5$(_context5) {\n        while (1) {\n          switch (_context5.prev = _context5.next) {\n            case 0:\n              options = {};\n              for (_len = _args5.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n                args[_key] = _args5[_key];\n              }\n              if (isObject(args.at(-1))) {\n                options = args.pop();\n              }\n              return _context5.abrupt(\"return\", redisCache.mGet(args).then(function (res) {\n                return res.map(function (val) {\n                  if (val === null) {\n                    return null;\n                  }\n                  return options.parse !== false ? decodeValue(val) : val;\n                });\n              }));\n            case 4:\n            case \"end\":\n              return _context5.stop();\n          }\n        }\n      }, _callee5);\n    }));\n    return function mget() {\n      return _ref5.apply(this, arguments);\n    };\n  }();\n  var _mdel = /*#__PURE__*/function () {\n    var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() {\n      var _len2,\n        args,\n        _key2,\n        _args6 = arguments;\n      return _regeneratorRuntime().wrap(function _callee6$(_context6) {\n        while (1) {\n          switch (_context6.prev = _context6.next) {\n            case 0:\n              for (_len2 = _args6.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n                args[_key2] = _args6[_key2];\n              }\n              if (isObject(args.at(-1))) {\n                args.pop();\n              }\n              if (Array.isArray(args)) {\n                args = args.flat();\n              }\n              return _context6.abrupt(\"return\", redisCache.del(args));\n            case 5:\n            case \"end\":\n              return _context6.stop();\n          }\n        }\n      }, _callee6);\n    }));\n    return function mdel() {\n      return _ref6.apply(this, arguments);\n    };\n  }();\n  var _reset = /*#__PURE__*/function () {\n    var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7() {\n      return _regeneratorRuntime().wrap(function _callee7$(_context7) {\n        while (1) {\n          switch (_context7.prev = _context7.next) {\n            case 0:\n              return _context7.abrupt(\"return\", redisCache.flushDb());\n            case 1:\n            case \"end\":\n              return _context7.stop();\n          }\n        }\n      }, _callee7);\n    }));\n    return function reset() {\n      return _ref7.apply(this, arguments);\n    };\n  }();\n  var _keys = /*#__PURE__*/function () {\n    var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8(pattern) {\n      return _regeneratorRuntime().wrap(function _callee8$(_context8) {\n        while (1) {\n          switch (_context8.prev = _context8.next) {\n            case 0:\n              return _context8.abrupt(\"return\", redisCache.keys(pattern));\n            case 1:\n            case \"end\":\n              return _context8.stop();\n          }\n        }\n      }, _callee8);\n    }));\n    return function keys(_x9) {\n      return _ref8.apply(this, arguments);\n    };\n  }();\n  var _ttl = /*#__PURE__*/function () {\n    var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(key) {\n      return _regeneratorRuntime().wrap(function _callee9$(_context9) {\n        while (1) {\n          switch (_context9.prev = _context9.next) {\n            case 0:\n              return _context9.abrupt(\"return\", redisCache.ttl(key));\n            case 1:\n            case \"end\":\n              return _context9.stop();\n          }\n        }\n      }, _callee9);\n    }));\n    return function ttl(_x10) {\n      return _ref9.apply(this, arguments);\n    };\n  }();\n  return {\n    name: 'redis',\n    getClient: function getClient() {\n      return redisCache;\n    },\n    isCacheableValue: isCacheableValue,\n    set: function set(key, value, options, cb) {\n      if (typeof options === 'function') {\n        cb = options;\n        options = {};\n      }\n      options = options || {};\n      if (typeof cb === 'function') {\n        node_util.callbackify(_set)(key, value, options, cb);\n      } else {\n        return _set(key, value, options);\n      }\n    },\n    get: function get(key, options, cb) {\n      if (typeof options === 'function') {\n        cb = options;\n        options = {};\n      }\n      options = options || {};\n      if (typeof cb === 'function') {\n        node_util.callbackify(_get)(key, options, cb);\n      } else {\n        return _get(key, options);\n      }\n    },\n    del: function del() {\n      for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n        args[_key3] = arguments[_key3];\n      }\n      if (typeof args.at(-1) === 'function') {\n        var cb = args.pop();\n        node_util.callbackify(_del)(args, cb);\n      } else {\n        return _del(args);\n      }\n    },\n    mset: function mset() {\n      for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {\n        args[_key4] = arguments[_key4];\n      }\n      if (typeof args.at(-1) === 'function') {\n        var cb = args.pop();\n        node_util.callbackify(_mset)(args, cb);\n      } else {\n        return _mset(args);\n      }\n    },\n    mget: function mget() {\n      for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {\n        args[_key5] = arguments[_key5];\n      }\n      if (typeof args.at(-1) === 'function') {\n        var cb = args.pop();\n        node_util.callbackify(function () {\n          return _mget.apply(void 0, args);\n        })(cb);\n      } else {\n        return _mget.apply(void 0, args);\n      }\n    },\n    mdel: function mdel() {\n      for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {\n        args[_key6] = arguments[_key6];\n      }\n      if (typeof args.at(-1) === 'function') {\n        var cb = args.pop();\n        node_util.callbackify(function () {\n          return _mdel.apply(void 0, args);\n        })(cb);\n      } else {\n        return _mdel.apply(void 0, args);\n      }\n    },\n    reset: function reset(cb) {\n      if (typeof cb === 'function') {\n        node_util.callbackify(_reset)(cb);\n      } else {\n        return _reset();\n      }\n    },\n    keys: function keys() {\n      var pattern = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '*';\n      var cb = arguments.length > 1 ? arguments[1] : undefined;\n      if (typeof cb === 'function') {\n        node_util.callbackify(function () {\n          return _keys(pattern);\n        })(cb);\n      } else {\n        return _keys(pattern);\n      }\n    },\n    ttl: function ttl(key, cb) {\n      if (typeof cb === 'function') {\n        node_util.callbackify(function () {\n          return _ttl(key);\n        })(cb);\n      } else {\n        return _ttl(key);\n      }\n    }\n  };\n};\nfunction encodeValue(value) {\n  return JSON.stringify(value) || '\"undefined\"';\n}\nfunction decodeValue(val) {\n  return JSON.parse(val);\n}\nfunction isObject(object) {\n  return _typeof(object) === 'object' && !Array.isArray(object) && object !== null;\n}\n\nexports.redisStore = redisStore;\n"
  },
  {
    "path": "index.js",
    "content": "import {callbackify} from 'node:util';\nimport {createClient} from 'redis';\n\nexport async function redisStore(config) {\n  const redisCache = createClient(config);\n  await redisCache.connect();\n\n  return buildRedisStoreWithConfig(redisCache, config);\n}\n\nconst buildRedisStoreWithConfig = (redisCache, config) => {\n  const isCacheableValue =\n    config.isCacheableValue || (value => value !== undefined && value !== null);\n  const set = async (key, value, options) => {\n    if (!isCacheableValue(value)) {\n      throw new Error(`\"${value}\" is not a cacheable value`);\n    }\n\n    const ttl = (options?.ttl || options?.ttl === 0) ? options.ttl : config.ttl;\n\n    if (ttl) {\n      return redisCache.setEx(key, ttl, encodeValue(value));\n    } else {\n      return redisCache.set(key, encodeValue(value));\n    }\n  };\n  const get = async (key, options) => {\n    const val = await redisCache.get(key);\n\n    if (val === null) {\n      return null;\n    }\n    return options.parse !== false ? decodeValue(val) : val;\n  };\n  const del = async (args) => {\n    let options = {};\n    if (isObject(args.at(-1))) {\n      options = args.pop();\n    }\n    return redisCache.del(args);\n  };\n  const mset = async (args) => {\n    let options = {};\n    if (isObject(args.at(-1))) {\n      options = args.pop();\n    }\n    const ttl = (options.ttl || options.ttl === 0) ? options.ttl : config.ttl;\n\n    // Zips even and odd array items into tuples\n    const items = args\n      .map((key, index) => {\n        if (index % 2 !== 0) return null;\n        const value = args[index + 1];\n        if (!isCacheableValue(value)) {\n          throw new Error(`\"${value}\" is not a cacheable value`);\n        }\n        return [key, encodeValue(value)];\n      })\n      .filter((key) => key !== null);\n\n    if (ttl) {\n      const multi = redisCache.multi();\n      for (const kv of items) {\n        const [key, value] = kv;\n        multi.setEx(key, ttl, value);\n      }\n      return multi.exec();\n    } else {\n      return redisCache.mSet(items);\n    }\n  };\n  const mget = async (...args) => {\n    let options = {};\n    if (isObject(args.at(-1))) {\n      options = args.pop();\n    }\n    return redisCache\n      .mGet(args)\n      .then((res) =>\n        res.map((val) => {\n          if (val === null) {\n            return null;\n          }\n\n          return options.parse !== false ? decodeValue(val) : val;\n        }),\n      );\n  };\n  const mdel = async (...args) => {\n    let options = {};\n    if (isObject(args.at(-1))) {\n      options = args.pop();\n    }\n    if (Array.isArray(args)) {\n      args = args.flat();\n    }\n    return redisCache.del(args);\n  };\n  const reset = async () => {\n    return redisCache.flushDb();\n  };\n  const keys = async (pattern) => {\n    return redisCache.keys(pattern);\n  };\n  const ttl = async (key) => {\n    return redisCache.ttl(key);\n  };\n\n  return {\n    name: 'redis',\n    getClient: () => redisCache,\n    isCacheableValue,\n    set: (key, value, options, cb) => {\n      if (typeof options === 'function') {\n        cb = options;\n        options = {};\n      }\n      options = options || {};\n\n      if (typeof cb === 'function') {\n        callbackify(set)(key, value, options, cb);\n      } else {\n        return set(key, value, options);\n      }\n    },\n    get: (key, options, cb) => {\n      if (typeof options === 'function') {\n        cb = options;\n        options = {};\n      }\n      options = options || {};\n\n      if (typeof cb === 'function') {\n        callbackify(get)(key, options, cb);\n      } else {\n        return get(key, options);\n      }\n    },\n    del: (...args) => {\n      if (typeof args.at(-1) === 'function') {\n        const cb = args.pop();\n        callbackify(del)(args, cb);\n      } else {\n        return del(args);\n      }\n    },\n    mset: (...args) => {\n      if (typeof args.at(-1) === 'function') {\n        const cb = args.pop();\n        callbackify(mset)(args, cb);\n      } else {\n        return mset(args);\n      }\n    },\n    mget: (...args) => {\n      if (typeof args.at(-1) === 'function') {\n        const cb = args.pop();\n        callbackify(() => mget(...args))(cb);\n      } else {\n        return mget(...args);\n      }\n    },\n    mdel: (...args) => {\n      if (typeof args.at(-1) === 'function') {\n        const cb = args.pop();\n        callbackify(() => mdel(...args))(cb);\n      } else {\n        return mdel(...args);\n      }\n    },\n    reset: (cb) => {\n      if (typeof cb === 'function') {\n        callbackify(reset)(cb);\n      } else {\n        return reset();\n      }\n    },\n    keys: (pattern = '*', cb) => {\n      if (typeof cb === 'function') {\n        callbackify(() => keys(pattern))(cb);\n      } else {\n        return keys(pattern);\n      }\n    },\n    ttl: (key, cb) => {\n      if (typeof cb === 'function') {\n        callbackify(() => ttl(key))(cb);\n      } else {\n        return ttl(key);\n      }\n    },\n  };\n};\n\nfunction encodeValue(value) {\n  return JSON.stringify(value) || '\"undefined\"';\n}\n\nfunction decodeValue(val) {\n  return JSON.parse(val);\n}\n\nfunction isObject(object) {\n  return typeof object === 'object'\n    && !Array.isArray(object)\n    && object !== null;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"cache-manager-redis-store\",\n  \"author\": \"Matthijs Dabroek <dabroek@gmail.com>\",\n  \"description\": \"Redis store for node-cache-manager\",\n  \"version\": \"3.0.1\",\n  \"license\": \"MIT\",\n  \"main\": \"dist/index.js\",\n  \"types\": \"dist/index.d.ts\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/dabroek/node-cache-manager-redis-store.git\"\n  },\n  \"scripts\": {\n    \"prepare\": \"npm prune\",\n    \"test\": \"jest --forceExit\",\n    \"test-cov\": \"jest --forceExit --coverage\",\n    \"build\": \"rollup -c\"\n  },\n  \"dependencies\": {\n    \"redis\": \"^4.3.1\"\n  },\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.19.3\",\n    \"@babel/core\": \"^7.19.3\",\n    \"@babel/plugin-transform-runtime\": \"^7.19.1\",\n    \"@babel/preset-env\": \"^7.19.4\",\n    \"@babel/runtime\": \"^7.19.4\",\n    \"@rollup/plugin-babel\": \"^6.0.0\",\n    \"@types/cache-manager\": \"^4.0.2\",\n    \"babel-jest\": \"^29.2.0\",\n    \"cache-manager\": \"^4.1.0\",\n    \"jest\": \"^29.2.0\",\n    \"rollup\": \"^2.79.1\"\n  },\n  \"engines\": {\n    \"node\": \">= 16.18.0\"\n  }\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import babel from '@rollup/plugin-babel';\n\nexport default {\n  input: 'index.js',\n  output: {\n    format: 'cjs',\n    file: 'dist/index.js'\n  },\n  plugins: [\n    babel({\n      exclude: 'node_modules/**'\n    }),\n  ],\n};\n"
  },
  {
    "path": "test/index.test.js",
    "content": "import cacheManager from 'cache-manager';\nimport {redisStore} from '../index';\n\nlet redisCache;\nlet customRedisCache;\n\nconst config = {\n  socket: {\n    host: '127.0.0.1',\n    port: 6379\n  },\n  password: undefined,\n  db: 0,\n  ttl: 5,\n};\n\nbeforeEach(async () => {\n  redisCache = cacheManager.caching({\n    store: await redisStore(config),\n  });\n  await redisCache.reset();\n\n  const customConfig = {\n    ...config,\n    isCacheableValue: (val) => {\n      if (val === undefined) { // allow undefined\n        return true;\n      } else if (val === 'FooBarString') { // disallow FooBarString\n        return false;\n      }\n      return redisCache.store.isCacheableValue(val);\n    }\n  };\n\n  customRedisCache = cacheManager.caching({\n    store: await redisStore(customConfig),\n  });\n  await customRedisCache.reset();\n});\n\ndescribe('initialization', () => {\n  it('should create a store with the options that were provided', async () => {\n    const redisPwdCache = cacheManager.caching({\n      store: await redisStore(config),\n      ...config\n    });\n\n    expect(redisPwdCache.store.getClient().options.socket.host).toEqual(config.socket.host);\n    expect(redisPwdCache.store.getClient().options.socket.port).toEqual(config.socket.port);\n  });\n});\n\ndescribe('set', () => {\n  it('should return a promise', () => {\n    expect(redisCache.set('foo', 'bar')).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.set('foo', 'bar', function (err, res) {\n      expect(err).toBeNull();\n      expect(res).toEqual(\"OK\");\n      done();\n    });\n  });\n\n  it('should store a value without ttl', async () => {\n    await redisCache.set('foo', 'bar');\n    await expect(redisCache.get('foo')).resolves.toEqual('bar');\n    await expect(redisCache.ttl('foo')).resolves.toEqual(config.ttl);\n  });\n\n  it('should store a value with a specific ttl', async () => {\n    await redisCache.set('foo', 'bar', {ttl: 5});\n    await expect(redisCache.ttl('foo')).resolves.toEqual(5);\n  });\n\n  it('should store a value with a infinite ttl', async () => {\n    await redisCache.set('foo', 'bar', {ttl: 0});\n    await expect(redisCache.ttl('foo')).resolves.toEqual(-1);\n  });\n\n  it('should not be able to store a null value (not cacheable)', async () => {\n    await expect(redisCache.set('foo', null)).rejects.toThrowError('\"null\" is not a cacheable value');\n  });\n\n  it('should not store an invalid value', async () => {\n    await expect(redisCache.set('foo1', undefined)).rejects.toThrowError('\"undefined\" is not a cacheable value');\n  });\n\n  it('should store an undefined value if permitted by isCacheableValue', async () => {\n    expect(customRedisCache.store.isCacheableValue(undefined)).toBe(true);\n    await customRedisCache.set('foo3', undefined);\n  });\n\n  it('should not store a value disallowed by isCacheableValue', async () => {\n    expect(customRedisCache.store.isCacheableValue('FooBarString')).toBe(false);\n    await expect(customRedisCache.set('foobar', 'FooBarString')).rejects.toThrowError('\"FooBarString\" is not a cacheable value');\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.store.getClient().disconnect();\n    await expect(redisCache.set('foo', 'bar')).rejects.toBeDefined();\n  });\n});\n\ndescribe('get', () => {\n  it('should return a promise', async () => {\n    expect(redisCache.get('foo')).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.set('foo', 'bar')\n      .then(() => {\n        redisCache.get('foo', function (err, res) {\n          expect(err).toBeNull();\n          expect(res).toEqual('bar');\n          done();\n        });\n      })\n      .catch(err => done(err));\n  });\n\n  it('should retrieve a value for a given key', async () => {\n    const value = 'bar';\n    await redisCache.set('foo', value);\n    await expect(redisCache.get('foo')).resolves.toEqual(value);\n  });\n\n  it('should retrieve a value for a given key if options provided', async () => {\n    const value = 'bar';\n    await redisCache.set('foo', value);\n    await expect(redisCache.get('foo', {})).resolves.toEqual(value);\n  });\n\n  it('should retrieve a value for a given key unparsed', async () => {\n    const value = 'bar';\n    await redisCache.set('foo', value);\n    await expect(redisCache.get('foo', {parse:false})).resolves.toEqual('\\\"bar\\\"');\n  });\n\n  it('should return null when the key is invalid', async () => {\n    await expect(redisCache.get('invalidKey')).resolves.toEqual(null);\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.store.getClient().disconnect();\n    await expect(redisCache.get('foo')).rejects.toThrowError('The client is closed');\n  });\n});\n\ndescribe('del', () => {\n  it('should return a promise', async () => {\n    expect(redisCache.del('foo')).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.set('foo', 'bar')\n      .then(() => {\n        redisCache.del('foo', function (err, res) {\n          expect(err).toBeNull();\n          expect(res).toEqual(1);\n          done();\n        });\n      })\n      .catch(err => done(err));\n  });\n\n  it('should delete a value for a given key', async () => {\n    await redisCache.set('foo', 'bar');\n    await expect(redisCache.get('foo')).resolves.toEqual('bar');\n    await redisCache.del('foo');\n    await expect(redisCache.get('foo')).resolves.toEqual(null);\n  });\n\n  it('should delete a value for a given key if options provided', async () => {\n    await redisCache.set('foo', 'bar');\n    await expect(redisCache.get('foo')).resolves.toEqual('bar');\n    await redisCache.del('foo', {});\n    await expect(redisCache.get('foo')).resolves.toEqual(null);\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.store.getClient().disconnect();\n    await expect(redisCache.del('foo')).rejects.toThrowError('The client is closed');\n  });\n});\n\ndescribe('mset', () => {\n  it('should return a promise', () => {\n    expect(redisCache.mset('foo', 'bar')).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.mset('foo', 'bar', 'baz', 'qux', function (err, res) {\n      expect(err).toBeNull();\n      expect(res).toEqual([\"OK\", \"OK\"]);\n      redisCache.mget('foo', 'baz')\n        .then((res) => {\n          expect(res).toEqual(['bar', 'qux']);\n          done();\n        })\n        .catch(err => done(err));\n    });\n  });\n\n  it('should store a value without ttl', async () => {\n    await expect(redisCache.mset('foo', 'bar', 'foo2', 'bar2')).resolves.toEqual([\"OK\", \"OK\"]);\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual(['bar', 'bar2']);\n  });\n\n  it('should store a value with a specific ttl', async () => {\n    await redisCache.mset('foo', 'bar', 'foo2', 'bar2', {ttl: 60});\n    await expect(redisCache.ttl('foo')).resolves.toEqual(60);\n    await expect(redisCache.ttl('foo2')).resolves.toEqual(60);\n  });\n\n  it('should store a value with a infinite ttl', async () => {\n    await redisCache.mset('foo', 'bar', {ttl: 0});\n    await expect(redisCache.ttl('foo')).resolves.toEqual(-1);\n  });\n\n  it('should not be able to store a null value (not cacheable)', async () => {\n    await expect(redisCache.mset('foo2', null)).rejects.toThrowError('\"null\" is not a cacheable value');\n  });\n\n  it('should store a value without callback', async () => {\n    await expect(redisCache.mset('foo', 'baz', 'foo2', 'baz2')).resolves.toEqual([\"OK\", \"OK\"]);\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual(['baz', 'baz2']);\n  });\n\n  it('should not store an invalid value', async () => {\n    await expect(redisCache.mset('foo1', undefined)).rejects.toThrowError('\"undefined\" is not a cacheable value');\n  });\n\n  it('should store an undefined value if permitted by isCacheableValue', async () => {\n    expect(customRedisCache.store.isCacheableValue(undefined)).toBe(true);\n    await customRedisCache.mset('foo3', undefined, 'foo4', undefined);\n    await expect(customRedisCache.mget('foo3', 'foo4')).resolves.toEqual(['undefined', 'undefined']);\n  });\n\n  it('should not store a value disallowed by isCacheableValue', async () => {\n    expect(customRedisCache.store.isCacheableValue('FooBarString')).toBe(false);\n    await expect(customRedisCache.mset('foobar', 'FooBarString')).rejects.toThrowError('\"FooBarString\" is not a cacheable value');\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.store.getClient().disconnect();\n    /**\n     * Waiting for a pull request to be merged in order to uncomment the following assertion. The multi.exec() is\n     * currently not rejecting the promise on client disconnect.\n     *\n     * @see https://github.com/redis/node-redis/pull/2293\n     */\n    // await expect(redisCache.mset('foo', 'bar')).rejects.toThrowError('The client is closed');\n  });\n});\n\ndescribe('mget', () => {\n  it('should return a promise', () => {\n    expect(redisCache.mget('foo', 'foo2')).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.mset('foo', 'bar', 'baz', 'qux')\n      .then((res) => {\n        expect(res).toEqual([\"OK\", \"OK\"]);\n        redisCache.mget('foo', 'baz', function (err, res) {\n          expect(err).toBeNull();\n          expect(res).toEqual(['bar', 'qux']);\n          done();\n        });\n      })\n      .catch(err => done(err));\n  });\n\n  it('should retrieve a value for a given key', async () => {\n    const value = 'bar';\n    const value2 = 'bar2';\n    await redisCache.mset('foo', value, 'foo2', value2);\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual([value, value2]);\n  });\n\n  it('should retrieve a value for a given key if options provided', async () => {\n    const value = 'bar';\n    await redisCache.mset('foo', value);\n    await expect(redisCache.mget('foo', {someConfig: true})).resolves.toEqual([value]);\n  });\n\n  it('should retrieve a value for a given key unparsed', async () => {\n    const value = 'bar';\n    await redisCache.mset('foo', value);\n    await expect(redisCache.mget('foo', {parse: false})).resolves.toEqual(['\\\"bar\\\"']);\n  });\n\n  it('should return null when the key is invalid', async () => {\n    await expect(redisCache.mget('invalidKey', 'otherInvalidKey')).resolves.toEqual([null, null]);\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.store.getClient().disconnect();\n    await expect(redisCache.mget('foo')).rejects.toThrowError('The client is closed');\n  });\n});\n\n\ndescribe('mdel', () => {\n  it('should return a promise', async () => {\n    expect(redisCache.store.mdel('foo', 'bar')).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.mset('foo', 'bar', 'baz', 'qux')\n      .then((res) => {\n        expect(res).toEqual([\"OK\", \"OK\"]);\n        redisCache.store.mdel('foo', 'baz', function (err, res) {\n          expect(err).toBeNull();\n          expect(res).toEqual(2);\n          redisCache.mget('foo', 'baz')\n            .then((res) => {\n              expect(res).toEqual([null, null]);\n              done();\n            })\n            .catch(err => done(err))\n        });\n      })\n      .catch(err => done(err));\n  });\n\n  it('should delete a unlimited number of keys', async () => {\n    await redisCache.mset('foo', 'bar', 'foo2', 'bar2');\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual(['bar', 'bar2']);\n    await redisCache.store.mdel('foo', 'foo2');\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual([null, null]);\n  });\n\n  it('should delete a unlimited number of keys if options provided', async () => {\n    await redisCache.mset('foo', 'bar', 'foo2', 'bar2');\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual(['bar', 'bar2']);\n    await redisCache.store.mdel('foo', 'foo2', {});\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual([null, null]);\n  });\n\n  it('should delete an array of keys', async () => {\n    await redisCache.mset('foo', 'bar', 'foo2', 'bar2');\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual(['bar', 'bar2']);\n    await redisCache.store.mdel(['foo', 'foo2']);\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual([null, null]);\n  });\n\n  it('should delete an array of keys if options provided', async () => {\n    await redisCache.mset('foo', 'bar', 'foo2', 'bar2');\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual(['bar', 'bar2']);\n    await redisCache.store.mdel(['foo', 'foo2'], {});\n    await expect(redisCache.mget('foo', 'foo2')).resolves.toEqual([null, null]);\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.store.getClient().disconnect();\n    await expect(redisCache.store.mdel('foo')).rejects.toThrowError('The client is closed');\n  });\n});\n\ndescribe('reset', () => {\n  it('should return a promise', async () => {\n    expect(redisCache.reset()).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.mset('foo', 'bar', 'baz', 'qux')\n      .then((res) => {\n        expect(res).toEqual([\"OK\", \"OK\"]);\n        redisCache.reset(function (err, res) {\n          expect(err).toBeNull();\n          expect(res).toEqual(\"OK\");\n          redisCache.mget('foo', 'baz')\n            .then((res) => {\n              expect(res).toEqual([null, null]);\n              done();\n            })\n            .catch(err => done(err))\n        });\n      })\n      .catch(err => done(err));\n  });\n\n  it('should flush underlying db', async () => {\n    await redisCache.set('foo', 'bar');\n    await redisCache.set('baz', 'qux');\n    await redisCache.reset();\n    await expect(redisCache.mget('foo', 'baz')).resolves.toEqual([null, null]);\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.store.getClient().disconnect();\n    await expect(redisCache.reset()).rejects.toThrowError('The client is closed');\n  });\n});\n\ndescribe('keys', () => {\n  it('should return a promise', async () => {\n    expect(redisCache.keys('foo')).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.mset('foo', 'bar', 'baz', 'qux')\n      .then((res) => {\n        expect(res).toEqual([\"OK\", \"OK\"]);\n        redisCache.keys('*', function (err, res) {\n          expect(err).toBeNull();\n          expect(res).toEqual(expect.arrayContaining(['foo', 'baz']));\n          done();\n        });\n      })\n      .catch(err => done(err));\n  });\n\n  it('should return an array of keys for the given pattern', async () => {\n    await redisCache.set('foo', 'bar');\n    await expect(redisCache.keys('foo')).resolves.toContainEqual('foo');\n  });\n\n  it('should return an array of all keys if called without a pattern', async () => {\n    await redisCache.mset('foo', 'bar', 'foo2', 'bar2', 'foo3', 'bar3');\n    await expect(redisCache.keys()).resolves.toHaveLength(3);\n    await expect(redisCache.keys()).resolves.toEqual(expect.arrayContaining(['foo', 'foo2', 'foo3']));\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.store.getClient().disconnect();\n    await expect(redisCache.keys('foo')).rejects.toThrowError('The client is closed');\n  });\n});\n\ndescribe('ttl', () => {\n  it('should return a promise', async () => {\n    expect(redisCache.ttl('foo')).toBeInstanceOf(Promise);\n  });\n\n  it('can be used with a callback', (done) => {\n    redisCache.set('foo', 'bar')\n      .then((res) => {\n        expect(res).toEqual(\"OK\");\n        redisCache.ttl('foo', function (err, res) {\n          expect(err).toBeNull();\n          expect(res).toEqual(config.ttl);\n          done();\n        });\n      })\n      .catch(err => done(err));\n  });\n\n  it('should retrieve ttl for a given key', async () => {\n    await redisCache.set('foo', 'bar');\n    await expect(redisCache.ttl('foo')).resolves.toEqual(config.ttl);\n  });\n\n  it('should retrieve ttl for an invalid key', async () => {\n    await expect(redisCache.ttl('invalidKey')).resolves.toEqual(-2);\n  });\n\n  it('should return an error if there is an error acquiring a connection', async () => {\n    await redisCache.set('foo', 'bar');\n    await redisCache.store.getClient().disconnect();\n    await expect(redisCache.ttl('foo')).rejects.toThrowError('The client is closed');\n  });\n});\n\ndescribe('isCacheableValue', () => {\n  it('should return true when the value is not undefined', () => {\n    expect(redisCache.store.isCacheableValue(0)).toBe(true);\n    expect(redisCache.store.isCacheableValue(100)).toBe(true);\n    expect(redisCache.store.isCacheableValue('')).toBe(true);\n    expect(redisCache.store.isCacheableValue('test')).toBe(true);\n  });\n\n  it('should return false when the value is undefined', () => {\n    expect(redisCache.store.isCacheableValue(undefined)).toBe(false);\n  });\n\n  it('should return false when the value is null', () => {\n    expect(redisCache.store.isCacheableValue(null)).toBe(false);\n  });\n});\n\ndescribe('redis error event', () => {\n  it('should return an error when the redis server is unavailable', (done) => {\n    redisCache.store.getClient().on('error', (err) => {\n      expect(err).not.toEqual(null);\n      done();\n    });\n    redisCache.store.getClient().emit('error', 'Something unexpected');\n  });\n});\n\ndescribe('overridable isCacheableValue function', () => {\n  let redisCache2;\n\n  beforeEach(async () => {\n    redisCache2 = cacheManager.caching({\n      store: await redisStore({\n        ...config,\n        isCacheableValue: () => {\n          return 'I was overridden';\n        }\n      }),\n      password: config.password\n    });\n  });\n\n  it('should return its return value instead of the built-in function', () => {\n    expect(redisCache2.store.isCacheableValue(0)).toEqual('I was overridden');\n  });\n});\n\ndescribe('wrap function', () => {\n  // Simulate retrieving a user from a database\n  function getUser(id, cb) {\n    setTimeout(() => {\n      cb(null, {id: id});\n    }, 100);\n  }\n\n  // Simulate retrieving a user from a database with Promise\n  function getUserPromise(id) {\n    return new Promise((resolve) => {\n      setTimeout(() => {\n        resolve({id: id});\n      }, 100);\n    });\n  }\n\n  it('should be able to cache objects', (done) => {\n    const userId = 123;\n\n    // First call to wrap should run the code\n    redisCache.wrap('wrap-user', (cb) => {\n      getUser(userId, cb);\n    }, (err, user) => {\n      expect(user.id).toEqual(userId);\n\n      // Second call to wrap should retrieve from cache\n      redisCache.wrap('wrap-user', (cb) => {\n        getUser(userId + 1, cb);\n      }, (err, user) => {\n        expect(user.id).toEqual(userId);\n        done();\n      });\n    });\n  });\n\n  it('should work with promises', async () => {\n    const userId = 123;\n\n    // First call to wrap should run the code\n    return redisCache\n      .wrap(\n        'wrap-promise',\n        () => getUserPromise(userId),\n      )\n      .then((user) => {\n        expect(user.id).toEqual(userId);\n\n        // Second call to wrap should retrieve from cache\n        return redisCache.wrap(\n          'wrap-promise',\n          () => getUserPromise(userId + 1),\n        )\n          .then((user) => expect(user.id).toEqual(userId));\n      });\n  });\n});\n"
  }
]