{"version":3,"sources":["jsdelivr-header.js","/npm/apicache-plus@2.3.1/src/apicache.js"],"names":[],"mappings":"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","file":"/npm/apicache-plus@2.3.1/src/apicache.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/apicache-plus@2.3.1/src/apicache.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","var zlib = require('zlib')\nvar accepts = require('accepts')\nvar stream = require('stream')\nvar querystring = require('querystring')\nvar jsonSortify = require('json.sortify')\nvar generateUuidV4 = require('uuid').v4\nvar MemoryCache = require('./memory-cache')\nvar RedisCache = require('./redis-cache')\nvar Compressor = require('./compressor')\nvar pkg = require('../package.json')\nvar helpers = require('./helpers')\nvar setLongTimeout = helpers.setLongTimeout\nvar clearLongTimeout = helpers.clearLongTimeout\nvar delegateLazily = helpers.delegateLazily\nvar isKoa = helpers.isKoa\n\nvar FIVE_MINUTES = 5 * 60 * 1000\nvar SAFE_HTTP_METHODS = ['GET', 'HEAD', 'OPTIONS']\nvar CACHEABLE_STATUS_CODES = {\n  200: null,\n  201: null,\n  202: null,\n  203: null,\n  204: null,\n  205: null,\n  300: null,\n  301: null,\n  302: null,\n  305: null,\n  307: null,\n}\n\nvar t = {\n  ms: 1,\n  second: 1000,\n  minute: 60000,\n  hour: 3600000,\n  day: 3600000 * 24,\n  week: 3600000 * 24 * 7,\n  month: 3600000 * 24 * 30,\n  year: 3600000 * 24 * 365,\n}\n\nvar instances = []\n\nvar matches = function(a) {\n  return function(b) {\n    return a === b\n  }\n}\n\nvar doesntMatch = function(a) {\n  return function(b) {\n    return !matches(a)(b)\n  }\n}\n\nvar logDuration = function(d, prefix) {\n  var str = d > 1000 ? (d / 1000).toFixed(2) + 'sec' : d + 'ms'\n  return '\\x1b[33m- ' + (prefix ? prefix + ' ' : '') + str + '\\x1b[0m'\n}\n\nfunction getSafeHeaders(res) {\n  // getHeaders added in node v7.7.0\n  return Object.assign({}, res.getHeaders ? res.getHeaders() : res._headers)\n}\n\nfunction ApiCache() {\n  var memCache = new MemoryCache()\n  var redisCache\n\n  var globalOptions = {\n    debug: false,\n    defaultDuration: 3600000,\n    enabled: true,\n    isBypassable: false,\n    append: null,\n    interceptKeyParts: null,\n    jsonp: false,\n    redisClient: false,\n    redisPrefix: '',\n    headerBlacklist: [],\n    statusCodes: {\n      include: [],\n      exclude: [],\n    },\n    events: {\n      expire: undefined,\n    },\n    headers: {\n      // 'cache-control':  'no-cache' // example of header overwrite\n    },\n    shouldSyncExpiration: false,\n    afterHit: null,\n    trackPerformance: false,\n    optimizeDuration: false,\n  }\n\n  var middlewareOptions = []\n  var instance = this\n  var index = null\n  var timers = {}\n  var performanceArray = [] // for tracking cache hit rate\n\n  instances.push(this)\n  this.id = instances.length\n\n  function shouldDebug() {\n    var debugEnv = process.env.DEBUG && process.env.DEBUG.split(',').indexOf('apicache') !== -1\n\n    return !!(globalOptions.debug || debugEnv)\n  }\n\n  function debug(a, b, c, d) {\n    if (!shouldDebug()) return\n    var arr = ['\\x1b[36m[apicache]\\x1b[0m', a, b, c, d].filter(function(arg) {\n      return arg !== undefined\n    })\n    console.log.apply(null, arr)\n  }\n\n  function shouldCacheResponse(request, response, toggle, options) {\n    if (!response) return false\n    var codes = (options || globalOptions).statusCodes\n\n    if (toggle && !toggle(request, response)) {\n      return false\n    }\n\n    if ((!codes.exclude || !codes.exclude.length) && (!codes.include || !codes.include.length)) {\n      return response.statusCode in CACHEABLE_STATUS_CODES\n    }\n    if (\n      codes.exclude &&\n      codes.exclude.length &&\n      codes.exclude.indexOf(response.statusCode) !== -1\n    ) {\n      return false\n    }\n    if (\n      codes.include &&\n      codes.include.length &&\n      codes.include.indexOf(response.statusCode) === -1\n    ) {\n      return false\n    }\n\n    return true\n  }\n\n  function addIndexEntries(key, req) {\n    var groupName = req.apicacheGroup\n\n    if (groupName) {\n      debug('group detected \"' + groupName + '\"')\n      var group = (index.groups[groupName] = index.groups[groupName] || [])\n      group.unshift(key)\n    }\n\n    index.all.unshift(key)\n  }\n\n  function filterBlacklistedHeaders(headers, options) {\n    return Object.keys(headers)\n      .filter(function(key) {\n        return (options || globalOptions).headerBlacklist.indexOf(key) === -1\n      })\n      .reduce(function(acc, header) {\n        acc[header] = headers[header]\n        return acc\n      }, {})\n  }\n\n  function createCacheObject(status, headers, data, encoding, options) {\n    return {\n      status: status,\n      headers: filterBlacklistedHeaders(headers, options),\n      data: data,\n      encoding: encoding,\n      timestamp: Date.now(), // This is used to properly decrement max-age headers in cached responses\n    }\n  }\n\n  function cacheResponse(key, value, duration) {\n    var expireCallback = globalOptions.events.expire\n    memCache.add(key, value, duration, expireCallback)\n\n    // add automatic cache clearing from duration\n    timers[key] = setLongTimeout(function() {\n      instance.clear(key, true)\n    }, duration)\n  }\n\n  function debugCacheAddition(cache, key, strDuration, req, res, options) {\n    if (!shouldDebug()) return Promise.resolve()\n\n    var elapsed = new Date() - req.apicacheTimer\n    return Promise.resolve(cache.get(key))\n      .then(function(cached) {\n        var cacheObject\n        if (cached && cached.value) {\n          cached = cached.value\n          cacheObject = createCacheObject(\n            cached.status,\n            cached.headers,\n            cached.data && cached.data.toString(cached.encoding),\n            cached.encoding,\n            options\n          )\n          cacheObject.timestamp = cached.timestamp\n        } else cacheObject = {}\n\n        debug('adding cache entry for \"' + key + '\" @ ' + strDuration, logDuration(elapsed))\n        debug('cacheObject: ', cacheObject)\n      })\n      .catch(function(err) {\n        debug('error debugging cache addition', err)\n      })\n  }\n\n  var isNodeLte7 = (function(ret) {\n    return function() {\n      if (ret !== undefined) return ret\n\n      return (ret = parseInt(process.versions.node.split('.')[0], 10) <= 7)\n    }\n  })()\n\n  function getHeadersFromParams(res, statusMsgOrHeaders, maybeHeaders) {\n    if (statusMsgOrHeaders && typeof statusMsgOrHeaders !== 'string') {\n      maybeHeaders = statusMsgOrHeaders\n    }\n    if (!maybeHeaders) maybeHeaders = {}\n\n    return Object.keys(maybeHeaders).reduce(function(memo, item) {\n      memo[item.toLowerCase()] = maybeHeaders[item]\n      return memo\n      // some framework writeHead patches remove headers from params, so merge with res.getHeaders()\n    }, getSafeHeaders(res))\n  }\n\n  function preWriteHead(res, statusCode, statusMsgOrHeaders, maybeHeaders) {\n    if (statusCode) res.statusCode = statusCode\n    if (statusMsgOrHeaders && typeof statusMsgOrHeaders !== 'string') {\n      maybeHeaders = statusMsgOrHeaders\n    } else if (statusMsgOrHeaders) res.statusMessage = statusMsgOrHeaders\n    if (!maybeHeaders) maybeHeaders = {}\n\n    Object.keys(maybeHeaders).forEach(function(name) {\n      res.setHeader(name, maybeHeaders[name])\n    })\n  }\n\n  function fixEncodingHeaders(chunk, headers) {\n    if (!chunk || !headers) return\n    if (Compressor.isReallyCompressed(chunk, headers['content-encoding'])) {\n      delete headers['content-length']\n    } else {\n      delete headers['content-encoding']\n    }\n  }\n\n  function getCacheControlMaxAge(syncedMaxAge, group, options) {\n    var maxAge\n    if (group) maxAge = Math.min(3, syncedMaxAge)\n    else if (!options.shouldSyncExpiration) maxAge = Math.min(30, syncedMaxAge)\n    else maxAge = syncedMaxAge\n\n    var directive = options.append || options.appendKey ? 'private, ' : '' // public is default\n    return directive + 'max-age=' + maxAge.toFixed(0) + ', must-revalidate'\n  }\n\n  function makeResponseCacheable(\n    req,\n    res,\n    next,\n    key,\n    duration,\n    strDuration,\n    toggle,\n    options,\n    afterFn\n  ) {\n    if (!afterFn) afterFn = Promise.resolve.bind(Promise)\n    var afterTryingToCache = (function(isCalled) {\n      return function() {\n        if (isCalled !== undefined) return isCalled\n        return (isCalled = afterFn())\n      }\n    })()\n    var shouldCacheRes = (function(shouldIt) {\n      return function(req, res, toggle, options) {\n        if (shouldIt !== undefined) return shouldIt\n        return (shouldIt = shouldCacheResponse(req, res, toggle, options))\n      }\n    })()\n\n    // monkeypatch res to create cache object\n    var apicacheResPatches = {\n      write: res.write,\n      writeHead: res.writeHead,\n      end: res.end,\n    }\n    if (!req.apicacheResPatches) {\n      req.apicacheResPatches = apicacheResPatches\n      req.customWriteHeads = []\n      req.runReversedCustomWriteHeadsOnce = (function(isCalled) {\n        return function() {\n          if (isCalled) return\n          isCalled = true\n          var fn\n          while ((fn = req.customWriteHeads.pop())) {\n            fn.apply(null, arguments)\n          }\n        }\n      })()\n    }\n\n    function customWriteHead(statusCode, statusMsgOrHeaders, maybeHeaders) {\n      if (res._shouldCacheResWriteHeadVersionAlreadyRun) return\n      // to use with shouldCacheRes()\n      res.statusCode = statusCode\n\n      if (!res._currentResponseHeaders) {\n        // these most likely (if default node writeHead implementation) won't be available at res.getHeaders() yet\n        res._currentResponseHeaders = getHeadersFromParams(res, statusMsgOrHeaders, maybeHeaders)\n      }\n\n      // add cache control headers\n      if (!options.headers['cache-control'] && !res._currentResponseHeaders['cache-control']) {\n        if (shouldCacheRes(req, res, toggle, options)) {\n          var cacheControl\n          if (SAFE_HTTP_METHODS.indexOf(req.method) !== -1) {\n            var syncedMaxAge = Math.ceil(duration / 1000)\n            cacheControl = getCacheControlMaxAge(syncedMaxAge, req.apicacheGroup, options)\n          } else {\n            cacheControl = 'no-store'\n          }\n\n          res.setHeader('cache-control', cacheControl)\n          res._currentResponseHeaders['cache-control'] = cacheControl\n        } else {\n          res.setHeader('cache-control', 'no-store')\n        }\n      }\n\n      if (shouldCacheRes(req, res, toggle, options)) {\n        res._shouldCacheResWriteHeadVersionAlreadyRun = true\n\n        // append header overwrites if applicable\n        Object.keys(options.headers).forEach(function(name) {\n          res.setHeader(name, options.headers[name])\n          res._currentResponseHeaders[name.toLowerCase()] = options.headers[name]\n        })\n      }\n    }\n\n    req.customWriteHeads.unshift(customWriteHead)\n\n    res.writeHead = function(statusCode, statusMsgOrHeaders, maybeHeaders) {\n      req.runReversedCustomWriteHeadsOnce(statusCode, statusMsgOrHeaders, maybeHeaders)\n\n      return apicacheResPatches.writeHead.apply(this, arguments)\n    }\n\n    var getWstream = (function(wstream) {\n      return function(method, chunk, encoding) {\n        if (wstream) return wstream\n\n        if (\n          res._shouldCacheResWriteOrEndVersionAlreadyRun ||\n          !shouldCacheRes(req, res, toggle, options)\n        ) {\n          var emptyWstream = new stream.Writable({\n            write(_c, _e, cb) {\n              cb()\n            },\n          }).on('finish', afterTryingToCache)\n          return (wstream = Promise.resolve(emptyWstream))\n        }\n\n        res._shouldCacheResWriteOrEndVersionAlreadyRun = true\n\n        var getCacheObject = function() {\n          return createCacheObject(res.statusCode, res._currentResponseHeaders, null, null, options)\n        }\n        var getGroup = function() {\n          return req.apicacheGroup\n        }\n        var expireCallback = globalOptions.events.expire\n        var cache = redisCache || memCache\n        var chunkSize = Buffer.byteLength(chunk || '', encoding)\n        // if res.end was called first (without calling write), it will have only one chunk\n        // res.socket.writableHighWaterMark is node gte 9\n        var highWaterMark =\n          method === 'end'\n            ? chunkSize\n            : res.socket.writableHighWaterMark || res.socket._writableState.highWaterMark\n\n        var cacheWstream = cache\n          .createWriteStream(\n            key,\n            getCacheObject,\n            duration,\n            expireCallback,\n            getGroup,\n            highWaterMark,\n            // this is needed while memCache index/groups are still handled externally\n            !redisCache &&\n              function(statusCode, headers, data, encoding) {\n                addIndexEntries(key, req)\n                var cacheObject = createCacheObject(statusCode, headers, data, encoding, options)\n                cacheResponse(key, cacheObject, duration)\n              }\n          )\n          .then(function(wstream) {\n            return wstream\n              .on('error', function(err) {\n                debug('error in makeResponseCacheable function', err)\n              })\n              .on('finish', function() {\n                afterTryingToCache()\n                if (!wstream.isLocked) {\n                  debugCacheAddition(cache, key, strDuration, req, res, options)\n                }\n              })\n              .on('unpipe', afterTryingToCache)\n          })\n\n        return (wstream = cacheWstream.then(function(wstream) {\n          if (wstream.isLocked) return wstream\n\n          // also indicates it may be already compressed\n          var otherMiddlewareMayWantToChangeCompression =\n            Compressor.getFirstContentEncoding(res._currentResponseHeaders['content-encoding']) !==\n            'identity'\n          // some middlewares will preset content-encoding to e.g. gzip too early\n          // even if apicache is about to receive uncompressed response stream (middleware attached before apicache's one)\n          fixEncodingHeaders(chunk, res._currentResponseHeaders)\n          // don't compress before caching\n          if (otherMiddlewareMayWantToChangeCompression) return wstream\n\n          var tstream = Compressor.run(\n            {\n              chunkSize: chunkSize,\n              requestMehod: req.method,\n              responseStatusCode: res.statusCode,\n              responseMethod: method,\n              responseHeaders: res._currentResponseHeaders,\n            },\n            debug\n          ).on('error', function(err) {\n            debug('error in makeResponseCacheable function', err)\n            wstream.emit('error')\n          })\n          tstream.pipe(wstream)\n          return tstream\n        }))\n      }\n    })()\n\n    ;['write', 'end'].forEach(function(method) {\n      var ret\n      res[method] = function(chunk, encoding) {\n        if (!this.headersSent) {\n          req.runReversedCustomWriteHeadsOnce(\n            res.statusCode,\n            res.statusMsgOrHeaders,\n            getSafeHeaders(res)\n          )\n        }\n\n        ret = apicacheResPatches[method].apply(this, arguments)\n        getWstream(method, chunk, encoding).then(function(wstream) {\n          wstream[method](chunk, encoding)\n        })\n        return ret\n      }\n    })\n\n    // res.end(data) writes data twice\n    if (isNodeLte7()) {\n      var _end = res.end\n      res.end = function(chunk, encoding) {\n        if (Buffer.byteLength(chunk || '') > 0) {\n          this.write(chunk, encoding)\n          arguments[0] = undefined\n        }\n        return _end.apply(this, arguments)\n      }\n    }\n\n    return next()\n  }\n\n  var CACHE_CONTROL_NO_TRANSFORM_REGEX = /(?:^|,)\\s*?no-transform\\s*?(?:,|$)/\n  var CACHE_CONTROL_NO_CACHE_REGEXP = /(?:^|,)\\s*?no-cache\\s*?(?:,|$)/\n  function sendCachedResponse(request, response, cacheObject, toggle, next, duration, options) {\n    if (toggle && !toggle(request, response)) {\n      return next()\n    }\n    if (isKoa(request)) request.respond = false\n\n    var isMarkedToCache = !!request.apicacheResPatches\n    if (isMarkedToCache) {\n      // undo patches\n      Object.keys(request.apicacheResPatches).forEach(function(key) {\n        response[key] = request.apicacheResPatches[key]\n      })\n    }\n\n    if (options.afterHit) {\n      response.on('finish', function() {\n        isKoa(request) ? options.afterHit(request) : options.afterHit(request, response)\n      })\n    }\n\n    var elapsed = new Date() - request.apicacheTimer\n    debug(\n      'sending cached',\n      redisCache ? '(redis)' : '(memory-cache)',\n      'version of',\n      cacheObject.key,\n      logDuration(elapsed)\n    )\n\n    var headers = getSafeHeaders(response)\n    var cacheObjectHeaders = cacheObject.headers || {}\n\n    var cacheControl\n    // sync max-age with the cache expiration.\n    var elapsedMs = Date.now() - cacheObject.timestamp\n    var updatedMaxAge = Math.ceil((duration - elapsedMs) / 1000)\n    // when caching with options.interceptKeyParts,\n    // same key/cache could be reused for responding\n    // with different middleware options.headers\n    // and to different request methods, so recheck\n    if (options.headers['cache-control']) cacheControl = options.headers['cache-control']\n    else if (SAFE_HTTP_METHODS.indexOf(request.method) !== -1) {\n      if (cacheObjectHeaders['cache-control']) cacheControl = cacheObjectHeaders['cache-control']\n      else {\n        cacheControl = getCacheControlMaxAge(updatedMaxAge, request.apicacheGroup, options)\n      }\n    } else cacheControl = 'no-store'\n\n    Object.assign(headers, filterBlacklistedHeaders(cacheObjectHeaders, options), {\n      'cache-control': cacheControl.replace(/max-age=\\s*([+-]?\\d+)/, function(_match, maxAge) {\n        return 'max-age=' + Math.max(0, Math.min(parseInt(maxAge, 10), updatedMaxAge))\n      }),\n    })\n\n    // only embed apicache headers when not in production environment\n    if (process.env.NODE_ENV !== 'production') {\n      Object.assign(headers, {\n        'apicache-store': globalOptions.redisClient ? 'redis' : 'memory',\n        'apicache-version': pkg.version,\n      })\n    }\n\n    function hasNoBodyRequestingPreconditionCheck() {\n      return (\n        !request.headers['if-match'] &&\n        !request.headers['if-unmodified-since'] &&\n        !request.headers['if-range']\n      )\n    }\n    function clientDoesntWantToReloadItsCache() {\n      return (\n        !request.headers['cache-control'] ||\n        !CACHE_CONTROL_NO_CACHE_REGEXP.test(request.headers['cache-control'])\n      )\n    }\n    // test Etag against If-None-Match for 304\n    function isEtagFresh() {\n      var cachedEtag = cacheObjectHeaders.etag\n      var requestEtags = (request.headers['if-none-match'] || '').replace('*', '').split(/\\s*,\\s*/)\n      return Boolean(\n        cachedEtag &&\n          requestEtags.length > 0 &&\n          (requestEtags.indexOf(cachedEtag) !== -1 ||\n            requestEtags.indexOf('W/' + cachedEtag) !== -1 ||\n            requestEtags\n              .map(function(rEtag) {\n                return 'W/' + rEtag\n              })\n              .indexOf(cachedEtag) !== -1)\n      )\n    }\n    function isResourceFresh() {\n      var cachedLastModified = cacheObjectHeaders['last-modified']\n      var requestModifiedSince = request.headers['if-modified-since']\n      if (!cachedLastModified || !requestModifiedSince) return false\n\n      try {\n        return Date.parse(cachedLastModified) <= Date.parse(requestModifiedSince)\n      } catch (err) {\n        return false\n      }\n    }\n    if (\n      hasNoBodyRequestingPreconditionCheck() &&\n      clientDoesntWantToReloadItsCache() &&\n      (isEtagFresh() || isResourceFresh())\n    ) {\n      if ('content-length' in headers) delete headers['content-length']\n      response.writeHead(304, headers)\n      return response.end()\n    }\n\n    if (request.method === 'HEAD') {\n      response.writeHead(cacheObject.status || 200, headers)\n      // skip body for HEAD\n      return response.end()\n    }\n\n    function getRstream() {\n      return (redisCache || memCache)\n        .createReadStream(\n          cacheObject.key,\n          cacheObject['data-token'] || cacheObject.data,\n          cacheObject.encoding,\n          // res.socket.writableHighWaterMark is node gte 9\n          response.socket.writableHighWaterMark || response.socket._writableState.highWaterMark\n        )\n        .on('error', function() {\n          debug('error in sendCachedResponse function')\n          response.end()\n        })\n    }\n\n    // dont use headers['content-encoding'] as it may be already changed to e.g. gzip by some middleware\n    var cachedEncoding = (cacheObjectHeaders['content-encoding'] || 'identity').split(',')[0]\n    var currentResCacheEncoding = (headers['content-encoding'] || 'identity').split(',')[0]\n    var noOtherMiddlewareMayWantToChangeCompression = cachedEncoding === currentResCacheEncoding\n    var requestAccepts = accepts(request)\n    if (\n      (cachedEncoding === 'identity' ||\n        (noOtherMiddlewareMayWantToChangeCompression &&\n          !CACHE_CONTROL_NO_TRANSFORM_REGEX.test(headers['cache-control'] || ''))) &&\n      requestAccepts.encodings(cachedEncoding)\n    ) {\n      // Doing response.writeHead(cacheObject.status || 200, headers)\n      // can make writeHead patch from some compression middlewares fail\n      // (although using res.writeHead with headers that don't mess with content-length / content-encoding\n      // would mostly be ok)\n      preWriteHead(response, cacheObject.status || 200, headers)\n      return getRstream().pipe(response)\n      // try to decompress\n    } else if (cachedEncoding !== 'identity' && requestAccepts.encodings('identity')) {\n      var tstream\n      if (cachedEncoding === 'br' && zlib.createBrotliDecompress) {\n        tstream = zlib.createBrotliDecompress()\n      } else if (['gzip', 'deflate'].indexOf(cachedEncoding) !== -1) {\n        tstream = zlib.createUnzip()\n      } else {\n        var errorMessage = \"can't decompress\" + cachedEncoding + 'encoding'\n        throw new Error(errorMessage)\n      }\n\n      delete headers['content-encoding']\n      preWriteHead(response, cacheObject.status || 200, headers)\n      tstream.on('error', function() {\n        debug('error in decompression stream')\n        this.unpipe()\n        // if erroed cause didn't need to decompress\n        // try sending it without transforming\n        getRstream()\n          .on('error', function() {\n            debug('error in decompression stream')\n            this.unpipe()\n            response.end()\n            // if node < 8\n            if (!this.destroy) return this.pause()\n            this.destroy()\n          })\n          .pipe(response)\n        // if node < 8\n        if (!this.destroy) return this.pause()\n        this.destroy()\n      })\n      return getRstream()\n        .pipe(tstream)\n        .pipe(response)\n    } else {\n      var contentEncodings = Array.from(new Set([cachedEncoding, 'identity']))\n      var statusMessage =\n        'Please accept' +\n        contentEncodings.slice(0, -1).join(', ') +\n        contentEncodings.slice(-1).join(', or ')\n\n      response.writeHead(406, statusMessage)\n      return response.end()\n    }\n  }\n\n  var syncOptions = (function() {\n    function syncOptionsByIndex(i) {\n      Object.assign(middlewareOptions[i].options, globalOptions, middlewareOptions[i].localOptions)\n      var options = middlewareOptions[i].options\n      if (options.headerBlacklist) {\n        options.headerBlacklist = options.headerBlacklist.map(function(v) {\n          return v.toLowerCase()\n        })\n      }\n    }\n\n    return function(i) {\n      if (i) return syncOptionsByIndex(i)\n      else {\n        for (i in middlewareOptions) {\n          syncOptionsByIndex(i)\n        }\n      }\n    }\n  })()\n\n  function getAppendice(append, req, res) {\n    if (!append) return ''\n\n    var appendice\n    if (typeof append === 'function') {\n      appendice = isKoa(req) ? append(req) : append(req, res)\n      // ['x', 'y'] => req?.x?.y\n    } else if (append.length > 0) {\n      appendice = req\n      for (var i = 0; i < append.length; i++) {\n        if (!appendice) break\n        appendice = appendice[append[i]]\n      }\n    }\n\n    return appendice || ''\n  }\n\n  function getKeyParts(req, res, options) {\n    var query\n    if (req.query !== null && typeof req.query === 'object') query = Object.assign({}, req.query)\n    // In Express,the url is ambiguous based on where a router is mounted.  originalUrl will give the full Url\n    var url = (req.originalUrl || req.url).replace(/\\/?(?:\\?([^#]*)(?:#.*)?)?$/, function(\n      _match,\n      qs\n    ) {\n      if (!query) {\n        query = querystring.parse(qs)\n        delete query['']\n      }\n      return ''\n    })\n    // couldn't use (?:(?<!^)\\/)? negative look-behind instead of \\/? at regexp above to keep / if at beginning (node gte 9)\n    // also, it will consider a maybe possible req.originalUrl || req.url '' as '/'\n    if (url === '') url = '/'\n    if (options.jsonp) {\n      if ([true, false].indexOf(options.jsonp) === -1) {\n        delete query.jsonp\n        delete query.callback\n      } else delete query[options.jsonp]\n    }\n\n    var parts = {\n      method: req.method,\n      url: url,\n      params: Object.assign(query, typeof req.body === 'object' ? Object.assign({}, req.body) : {}),\n      appendice: getAppendice(options.append || options.appendKey, req, res),\n    }\n\n    if (options.interceptKeyParts) {\n      parts =\n        (isKoa(req)\n          ? options.interceptKeyParts(req, parts)\n          : options.interceptKeyParts(req, res, parts)) || parts\n    }\n    return parts\n  }\n\n  function getSimilarKeyFromOtherMethod(key, method, otherMethod) {\n    return key.replace(method.toLowerCase(), otherMethod.toLowerCase())\n  }\n\n  this.getKey = function(keyParts) {\n    if (!keyParts || typeof keyParts !== 'object') return '{}'\n\n    var url\n    if (typeof keyParts.url === 'string') {\n      url = keyParts.url.trim()\n      if (url[0] !== '/') url = '/' + url\n      if (url.length > 1) url = url.replace(/\\/$/, '')\n    } else url = ''\n\n    var appendice\n    if (typeof keyParts.appendice === 'string') appendice = keyParts.appendice\n    else if (Number.isNaN(keyParts.appendice)) appendice = 'NaN'\n    else if ([null, undefined].indexOf(keyParts.appendice) === -1) {\n      try {\n        appendice = jsonSortify(keyParts.appendice)\n      } catch (err) {\n        appendice = ''\n      }\n    } else appendice = ''\n\n    return (\n      (typeof keyParts.method === 'string' ? keyParts.method.toLowerCase() : '') +\n      url +\n      (keyParts.params !== null && typeof keyParts.params === 'object'\n        ? jsonSortify(keyParts.params)\n        : '{}') +\n      appendice\n    )\n  }\n\n  this.has = function(key) {\n    if ([null, undefined].indexOf(key) !== -1) return Promise.resolve(false)\n\n    return (redisCache || memCache).has(key)\n  }\n\n  this.get = function(key) {\n    if ([null, undefined].indexOf(key) !== -1) return Promise.resolve(false)\n\n    return Promise.resolve((redisCache || memCache).get(key)).then(function(cached) {\n      if (!cached) return null\n\n      cached = cached.value\n      // this.set can store any value, so return raw cached if not what apicache regularly stores\n      if (\n        cached === null ||\n        typeof cached !== 'object' ||\n        !['status', 'headers', 'data', 'encoding', 'timestamp'].every(function(k) {\n          return k in cached\n        })\n      ) {\n        return cached\n      }\n\n      // try formatting and decompressing\n      try {\n        var data = cached.data\n        if ([null, undefined].indexOf(data) === -1) {\n          if (Buffer.byteLength(data) === 0) data = ''\n          else {\n            var cachedEncoding = cached.headers['content-encoding']\n            if (cachedEncoding && cachedEncoding !== 'identity') {\n              var decompress = {\n                br: zlib.brotliDecompressSync,\n                gzip: zlib.unzipSync,\n                deflate: zlib.unzipSync,\n              }[cachedEncoding]\n              if (decompress) data = decompress(data)\n            }\n            data = data.toString(cached.encoding)\n            try {\n              data = JSON.parse(data)\n            } catch (err) {}\n          }\n        }\n\n        // don't send with all properties if it's really what apicache regularly stores\n        // (e.g. encoding as it was already used above for parsing and redis data-extra-pttl prop)\n        return {\n          status: cached.status,\n          headers: cached.headers,\n          data: data,\n          timestamp: cached.timestamp,\n        }\n      } catch (err) {\n        return cached\n      }\n    })\n  }\n\n  this.set = function(key, value, duration, group, expirationCallback) {\n    if ([null, undefined].indexOf(key) !== -1) return Promise.resolve(false)\n\n    duration = this.getDuration(duration)\n    return (\n      // for now, this is the way we make sure .set can safely modify an already existing item\n      // e.g. it will remove from old group\n      Promise.resolve(this.clear(key))\n        .then(function() {\n          return Promise.resolve(\n            (redisCache || memCache).add(key, value, duration, expirationCallback, group)\n          )\n        })\n        // this is needed while memCache index/groups are still handled externally\n        .then(function() {\n          if (!redisCache) {\n            addIndexEntries(key, { apicacheGroup: group })\n          }\n          return value\n        })\n        .catch(function() {\n          return false\n        })\n    )\n  }\n\n  this.clear = function(target, isAutomatic) {\n    if (redisCache) {\n      return redisCache\n        .clear(target)\n        .then(function(deleteCount) {\n          debug(deleteCount, 'keys cleared')\n          return deleteCount\n        })\n        .catch(function() {\n          debug('error in clear function')\n        })\n    }\n\n    var group = index.groups[target]\n    if (group) {\n      debug('clearing group \"' + target + '\"')\n\n      group.forEach(function(key) {\n        debug('clearing cached entry for \"' + key + '\"')\n        clearLongTimeout(timers[key])\n        delete timers[key]\n        memCache.delete(key)\n\n        index.all = index.all.filter(doesntMatch(key))\n      })\n\n      delete index.groups[target]\n    } else if (target || target === '') {\n      debug('clearing ' + (isAutomatic ? 'expired' : 'cached') + ' entry for \"' + target + '\"')\n      clearLongTimeout(timers[target])\n      delete timers[target]\n      // clear actual cached entry\n      memCache.delete(target)\n\n      // remove from global index\n      index.all = index.all.filter(doesntMatch(target))\n\n      // remove target from each group that it may exist in\n      Object.keys(index.groups).forEach(function(groupName) {\n        index.groups[groupName] = index.groups[groupName].filter(doesntMatch(target))\n\n        var isGroupEmpty = !index.groups[groupName].length\n        // delete group if now empty\n        if (isGroupEmpty) {\n          delete index.groups[groupName]\n        }\n      })\n    } else {\n      debug('clearing entire index')\n\n      memCache.clear()\n\n      this.resetIndex()\n    }\n\n    return this.getIndex()\n  }\n\n  function parseDuration(duration, defaultDuration) {\n    if (typeof duration === 'number') return duration\n\n    if (typeof duration === 'string') {\n      var split = duration.match(/^([\\d.,]+)\\s?(\\w+)$/)\n\n      if (split.length === 3) {\n        var len = parseFloat(split[1])\n        var unit = split[2].replace(/s$/i, '').toLowerCase()\n        if (unit === 'm') {\n          unit = 'ms'\n        }\n\n        return (len || 1) * (t[unit] || 0)\n      }\n    }\n\n    return defaultDuration\n  }\n\n  this.getDuration = function(duration) {\n    return parseDuration(duration, globalOptions.defaultDuration)\n  }\n\n  /**\n   * Return cache performance statistics (hit rate).  Suitable for putting into a route:\n   * <code>\n   * app.get('/api/cache/performance', (req, res) => {\n   *    res.json(apicache.getPerformance())\n   * })\n   * </code>\n   */\n  this.getPerformance = function() {\n    return performanceArray.map(function(p) {\n      return p.report()\n    })\n  }\n\n  this.getIndex = function(group) {\n    if (redisCache) return redisCache.getIndex(group)\n    if (group) {\n      return index.groups[group]\n    } else {\n      return index\n    }\n  }\n\n  function isLocalOptions(value) {\n    return value !== null && typeof value === 'object'\n  }\n  function isMiddlewareToggle(value) {\n    return typeof value === 'function'\n  }\n  this.middleware = function cache(strDuration, middlewareToggle, localOptions) {\n    // Apicache#middleware(localOptions)\n    if (isLocalOptions(strDuration)) {\n      localOptions = strDuration\n      middlewareToggle = null\n      strDuration = null\n      // Apicache#middleware(middlewareToggle[, localOptions])\n    } else if (isMiddlewareToggle(strDuration)) {\n      localOptions = middlewareToggle\n      middlewareToggle = strDuration\n      strDuration = null\n      // Apicache#middleware([strDuration[, middlewareToggle[, localOptions]]])\n    } else if (isLocalOptions(middlewareToggle)) {\n      localOptions = middlewareToggle\n      middlewareToggle = null\n    }\n\n    if (!localOptions) localOptions = {}\n    var duration = parseDuration(strDuration)\n    var opt = {}\n\n    var middlewareOptionsIndex = middlewareOptions.length\n    middlewareOptions.push({\n      options: opt,\n    })\n\n    var options = function(localOptions) {\n      if (localOptions) {\n        if (localOptions.defaultDuration) {\n          localOptions.defaultDuration = parseDuration(localOptions.defaultDuration)\n          if ([null, undefined].indexOf(strDuration) !== -1) duration = localOptions.defaultDuration\n        }\n        middlewareOptions[middlewareOptionsIndex].localOptions = localOptions\n        syncOptions(middlewareOptionsIndex)\n      }\n      return opt\n    }\n\n    options(localOptions)\n\n    /**\n     * A Function for non tracking performance\n     */\n    function NOOPCachePerformance() {\n      this.report = this.hit = this.miss = function() {} // noop;\n    }\n\n    /**\n     * A function for tracking and reporting hit rate.  These statistics are returned by the getPerformance() call above.\n     */\n    function CachePerformance() {\n      /**\n       * Tracks the hit rate for the last 100 requests.\n       * If there have been fewer than 100 requests, the hit rate just considers the requests that have happened.\n       */\n      this.hitsLast100 = new Uint8Array(100 / 4) // each hit is 2 bits\n\n      /**\n       * Tracks the hit rate for the last 1000 requests.\n       * If there have been fewer than 1000 requests, the hit rate just considers the requests that have happened.\n       */\n      this.hitsLast1000 = new Uint8Array(1000 / 4) // each hit is 2 bits\n\n      /**\n       * Tracks the hit rate for the last 10000 requests.\n       * If there have been fewer than 10000 requests, the hit rate just considers the requests that have happened.\n       */\n      this.hitsLast10000 = new Uint8Array(10000 / 4) // each hit is 2 bits\n\n      /**\n       * Tracks the hit rate for the last 100000 requests.\n       * If there have been fewer than 100000 requests, the hit rate just considers the requests that have happened.\n       */\n      this.hitsLast100000 = new Uint8Array(100000 / 4) // each hit is 2 bits\n\n      /**\n       * The number of calls that have passed through the middleware since the server started.\n       */\n      this.callCount = 0\n\n      /**\n       * The total number of hits since the server started\n       */\n      this.hitCount = 0\n\n      /**\n       * The key from the last cache hit.  This is useful in identifying which route these statistics apply to.\n       */\n      this.lastCacheHit = null\n\n      /**\n       * The key from the last cache miss.  This is useful in identifying which route these statistics apply to.\n       */\n      this.lastCacheMiss = null\n\n      /**\n       * Return performance statistics\n       */\n      this.report = function() {\n        return {\n          lastCacheHit: this.lastCacheHit,\n          lastCacheMiss: this.lastCacheMiss,\n          callCount: this.callCount,\n          hitCount: this.hitCount,\n          missCount: this.callCount - this.hitCount,\n          hitRate: this.callCount === 0 ? null : this.hitCount / this.callCount,\n          hitRateLast100: this.hitRate(this.hitsLast100),\n          hitRateLast1000: this.hitRate(this.hitsLast1000),\n          hitRateLast10000: this.hitRate(this.hitsLast10000),\n          hitRateLast100000: this.hitRate(this.hitsLast100000),\n        }\n      }\n\n      /**\n       * Computes a cache hit rate from an array of hits and misses.\n       * @param {Uint8Array} array An array representing hits and misses.\n       * @returns a number between 0 and 1, or null if the array has no hits or misses\n       */\n      this.hitRate = function(array) {\n        var hits = 0\n        var misses = 0\n        for (var i = 0; i < array.length; i++) {\n          var n8 = array[i]\n          for (var j = 0; j < 4; j++) {\n            switch (n8 & 3) {\n              case 1:\n                hits++\n                break\n              case 2:\n                misses++\n                break\n            }\n            n8 >>= 2\n          }\n        }\n        var total = hits + misses\n        if (total === 0) return null\n        return hits / total\n      }\n\n      /**\n       * Record a hit or miss in the given array.  It will be recorded at a position determined\n       * by the current value of the callCount variable.\n       * @param {Uint8Array} array An array representing hits and misses.\n       * @param {boolean} hit true for a hit, false for a miss\n       * Each element in the array is 8 bits, and encodes 4 hit/miss records.\n       * Each hit or miss is encoded as to bits as follows:\n       * 00 means no hit or miss has been recorded in these bits\n       * 01 encodes a hit\n       * 10 encodes a miss\n       */\n      this.recordHitInArray = function(array, hit) {\n        var arrayIndex = ~~(this.callCount / 4) % array.length\n        var bitOffset = (this.callCount % 4) * 2 // 2 bits per record, 4 records per uint8 array element\n        var clearMask = ~(3 << bitOffset)\n        var record = (hit ? 1 : 2) << bitOffset\n        array[arrayIndex] = (array[arrayIndex] & clearMask) | record\n      }\n\n      /**\n       * Records the hit or miss in the tracking arrays and increments the call count.\n       * @param {boolean} hit true records a hit, false records a miss\n       */\n      this.recordHit = function(hit) {\n        this.recordHitInArray(this.hitsLast100, hit)\n        this.recordHitInArray(this.hitsLast1000, hit)\n        this.recordHitInArray(this.hitsLast10000, hit)\n        this.recordHitInArray(this.hitsLast100000, hit)\n        if (hit) this.hitCount++\n        this.callCount++\n      }\n\n      /**\n       * Records a hit event, setting lastCacheMiss to the given key\n       * @param {string} key The key that had the cache hit\n       */\n      this.hit = function(key) {\n        this.recordHit(true)\n        this.lastCacheHit = key\n      }\n\n      /**\n       * Records a miss event, setting lastCacheMiss to the given key\n       * @param {string} key The key that had the cache miss\n       */\n      this.miss = function(key) {\n        this.recordHit(false)\n        this.lastCacheMiss = key\n      }\n    }\n\n    var perf = globalOptions.trackPerformance ? new CachePerformance() : new NOOPCachePerformance()\n\n    performanceArray.push(perf)\n\n    var cache = function(req, res, next) {\n      if (isKoa(req)) {\n        var ctx = req\n        next = res\n        res = ctx.res\n\n        if (req.apicacheIsFrameworkAdapted) {\n          req = ctx.req\n        } else {\n          req.apicacheIsFrameworkAdapted = true\n          ;[ctx, ctx.req, ctx.request, ctx.res, ctx.response].forEach(function(obj) {\n            if ('apicacheGroup' in obj && !('apicacheGroup' in ctx.state)) {\n              ctx.state.apicacheGroup = obj.apicacheGroup\n            }\n            Object.defineProperty(obj, 'apicacheGroup', {\n              get() {\n                return ctx.state.apicacheGroup\n              },\n              set(v) {\n                ctx.state.apicacheGroup = v\n              },\n            })\n          })\n\n          // It will e.g. delegate req.query to ctx.query which delegates to ctx.request.query\n          // And make it work as ctx for getting it's future props at options.append, for instance\n          // at a downstream apicache middleware\n          req = delegateLazily(ctx.req, ctx)\n        }\n      }\n\n      function bypass() {\n        debug('bypass detected, skipping cache.')\n        return next()\n      }\n\n      // initial bypass chances\n      if (!opt.enabled) return bypass()\n      if (\n        opt.isBypassable &&\n        (req.headers['cache-control'] === 'no-store' ||\n          ['1', 'true'].indexOf(req.headers['x-apicache-bypass']) !== -1 ||\n          ['1', 'true'].indexOf(req.headers['x-apicache-force-fetch']) !== -1)\n      ) {\n        return bypass()\n      }\n\n      // this can change at runtime\n      duration = instance.getDuration(duration)\n      if (opt.optimizeDuration && opt.append && duration > FIVE_MINUTES) {\n        duration = FIVE_MINUTES\n      }\n\n      // embed timer\n      req.apicacheTimer = new Date()\n\n      var keyParts = getKeyParts(req, res, opt)\n      var key = instance.getKey(keyParts)\n      var cache = redisCache || memCache\n\n      // can have different keys e.g. one middleware has appendice while the other one doesn't\n      var makeResponseCacheableCount = `makeResponseCacheableCount${key}`\n      function _makeResponseCacheable() {\n        try {\n          perf.miss(key)\n          req[makeResponseCacheableCount] = (req[makeResponseCacheableCount] || 0) + 1\n          return makeResponseCacheable(\n            req,\n            res,\n            next,\n            key,\n            duration,\n            strDuration,\n            middlewareToggle,\n            opt,\n            function() {\n              if (--req[makeResponseCacheableCount] > 0) return Promise.resolve()\n              return cache.releaseLockWithId(\n                'make-cacheable:' + key,\n                typeof req.id === 'function' ? req.id() : req.id\n              )\n            }\n          )\n        } catch (err) {\n          debug(err)\n          return next()\n        }\n      }\n\n      function isSameRequestStackAllowedToMakeResponseCacheable() {\n        return cache.acquireLockWithId(\n          'make-cacheable:' + key,\n          typeof req.id === 'function' ? req.id() : req.id\n        )\n      }\n\n      function maybeMakeResponseCacheable() {\n        if (!req.id) {\n          req.id = generateUuidV4()\n        }\n\n        return isSameRequestStackAllowedToMakeResponseCacheable().then(function(isAllowed) {\n          if (isAllowed) return Promise.resolve(_makeResponseCacheable())\n          else {\n            // don't wait for first concurrent request finish its response\n            // (e.g. don't wait for a full download of a large file),\n            // but also don't let this one add to cache\n            if (SAFE_HTTP_METHODS.indexOf(req.method) !== -1) return next()\n\n            // give time to prior request finish caching\n            return new Promise(function(resolve) {\n              setLongTimeout(function() {\n                resolve(attemptCacheHit())\n              }, 10)\n            })\n          }\n        })\n      }\n\n      function getCached(key, withFallback) {\n        if (withFallback === undefined) withFallback = true\n        return Promise.resolve(cache.getValue(key)).then(function(cached) {\n          if (cached) {\n            cached.key = key\n          } else if (req.method === 'HEAD' && withFallback) {\n            var getMethodKey = getSimilarKeyFromOtherMethod(key, 'head', 'get')\n            return getCached(getMethodKey, false)\n          }\n\n          return cached\n        })\n      }\n\n      function attemptCacheHit() {\n        return getCached(key)\n          .then(function(cached) {\n            if (cached) {\n              perf.hit(key)\n              try {\n                return sendCachedResponse(req, res, cached, middlewareToggle, next, duration, opt)\n              } catch (err) {\n                debug(err)\n                if (res.headersSent) {\n                  perf.miss(key)\n                  if (isKoa(req)) req.respond = false\n                  return res.end()\n                }\n\n                return maybeMakeResponseCacheable()\n              }\n            } else {\n              return maybeMakeResponseCacheable()\n            }\n          })\n          .catch(function(err) {\n            debug(err)\n            perf.miss(key)\n            if (res.headersSent) {\n              if (isKoa(req)) req.respond = false\n              res.end()\n            } else return next()\n          })\n      }\n\n      return attemptCacheHit()\n    }\n\n    cache.options = options\n\n    return cache\n  }\n\n  this.options = function(options) {\n    if (options) {\n      var redisConnectionChanged =\n        (options.redisClient !== undefined && globalOptions.redisClient !== options.redisClient) ||\n        (options.redisPrefix !== undefined && globalOptions.redisPrefix !== options.redisPrefix)\n      Object.assign(globalOptions, options)\n      if ('defaultDuration' in options) {\n        // Convert the default duration to a number in milliseconds (if needed)\n        globalOptions.defaultDuration = parseDuration(globalOptions.defaultDuration, 3600000)\n      }\n      syncOptions()\n\n      if (globalOptions.trackPerformance) {\n        debug('WARNING: using trackPerformance flag can cause high memory usage!')\n      }\n\n      if (redisConnectionChanged) this.initRedis()\n      return this\n    } else {\n      return globalOptions\n    }\n  }\n\n  this.resetIndex = function() {\n    index = {\n      all: [],\n      groups: {},\n    }\n  }\n\n  this.initRedis = function() {\n    if (!globalOptions.redisClient) redisCache = null\n    else redisCache = new RedisCache(globalOptions, debug)\n  }\n\n  this.newInstance = function(config) {\n    var instance = new ApiCache()\n\n    if (config) {\n      instance.options(config)\n    }\n\n    return instance\n  }\n\n  this.clone = function() {\n    return this.newInstance(this.options())\n  }\n\n  // initialize index\n  this.resetIndex()\n  this.initRedis()\n\n  function _this() {\n    return this.middleware.apply(this, arguments)\n  }\n  return Object.assign(_this.bind(this), this)\n}\n\nmodule.exports = new ApiCache()\n"]}