{"version":3,"sources":["jsdelivr-header.js","/npm/express-middleware-cache@0.0.1/index.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA,ACNA,IAAI,EAAI,QAAQ,UACZ,MAAQ,QAAQ,4BAChB,OAAS,QAAQ,UACjB,WAAa,QAAQ,cAQrB,IAAM,SAAS,EAAU,GAE5B,IAAI,EAAW,EAAE,MAAM,IAAI,UAC3B,GAAI,EAAE,SAAS,GACd,EAAE,MAAM,EAAU,QACZ,GAAI,EAAE,SAAS,IAAa,EAAE,SAAS,GAC7C,EAAS,SAAW,EACpB,EAAE,MAAM,EAAU,OACZ,KAAI,EAAE,SAAS,KAAa,EAAE,YAAY,GAGhD,MAAM,IAAI,MAAM,qCAAqC,YAAmB,KAFxE,EAAS,SAAW,CAGrB,CAIA,EAAS,WAA6C,IAAhC,WAAW,EAAS,UAI1C,EAAS,MAAQ,IAAI,MAAM,EAAS,OAIpC,IAAI,EAAM,EAAS,KAAO,EAAS,KAUnC,OATI,IACH,EAAS,OAAS,GAClB,EAAE,UAAU,GAAK,SAAQ,IAClB,IAAI,SAAS,KAAM,IAAI,SAAS,GAAO,IAC7C,IAAI,SAAS,GAAK,KAAK,EAAS,KAK3B,SAAS,EAAK,EAAK,GAEzB,IAAI,OAAO,KAAK,gBAAiB,GAGjC,IAAI,EAAO,EAAS,MAAM,KAAK,EAAS,WAAW,IAEnD,EAAS,MAAM,IAAI,EAAM,EAAS,eAAe,CAAC,EAAK,KACtD,GAAI,EAGH,OAFA,QAAQ,IAAI,6BAA8B,GAC1C,IAAI,OAAO,KAAK,sBAAuB,EAAK,GACrC,EAAI,WAAW,KAChB,GAAI,EAAS,MAAQ,EAAI,QAAQ,MAAQ,IAAa,EAAS,eAAiB,EAAS,MAAQ,EAAS,MAAQ,EAAI,QAAQ,KAKpI,OAJA,IAAI,OAAO,KAAK,iBAAkB,EAAK,CACtC,SAAS,EACT,KAAM,IAEA,EAAI,WAAW,KAChB,GAAI,IAAa,EAAS,cAO1B,CAEN,IAAI,EAAiB,EAAI,KA2BzB,OAzBA,EAAI,KAAO,WAEN,EAAS,QAAQ,EAAS,OAAO,KAAK,GAG1C,IAAI,EAAO,IAAI,aAAa,EAAM,GAClC,EAAS,MAAM,IACd,EACA,CACC,QAAS,UAAU,GACnB,KAAM,GAEP,IAAI,KAAK,KAAK,MAAQ,EAAS,aAC/B,IACC,IAAI,OAAO,KAAK,kBAAmB,EAAK,CACvC,SAAS,EACT,KAAM,IAEH,EAAS,MAAM,EAAI,IAAI,OAAQ,GACnC,EAAe,MAAM,KAAM,UAAU,GAGxC,EAGO,GACR,CApCC,IAAI,OAAO,KAAK,qBAAsB,EAAK,CAC1C,SAAS,EACT,KAAM,IAEH,EAAS,MAAM,EAAI,IAAI,OAAQ,EAAS,MAC5C,EAAI,KAAK,EAAS,QA+BnB,GAEF,CACD,EAWA,IAAI,SAAW,CACd,SAAU,KACV,WAAY,KACZ,MAAO,CAAC,EACR,WAAY,IAAO,CAClB,OAAQ,EAAI,OACZ,KAAM,EAAI,KACV,MAAO,EAAI,MACX,KAAM,EAAI,OAEX,cAAe,cACf,MAAM,GASP,IAAI,WAAa,IAAI,KACpB,IAAI,EAAU,EAcd,OAZA,EAAK,SAAQ,IACP,IAAI,SAAS,IAClB,IAAI,SAAS,GAAK,SAAQ,IACpB,EAAM,QACX,EAAM,OAAO,SAAQ,IACpB,IAAI,OAAO,KAAK,uBAAwB,EAAK,GAC7C,EAAM,MAAM,MAAM,GAClB,GAAS,GACR,GACD,IAGI,CAAO,EAYf,IAAI,aAAe,CAAC,EAAM,IAClB,EAAS,MAAM,KAAK,EAAO,IAAM,KAAK,OAS9C,IAAI,SAAW,CAAC,EAOhB,IAAI,OAAS,IAAI,OAAO,aAExB,OAAO,QAAU","file":"/npm/express-middleware-cache@0.0.1/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/express-middleware-cache@0.0.1/index.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 _ = require('lodash');\nvar cache = require('@momsfriendlydevco/cache');\nvar events = require('events');\nvar timestring = require('timestring');\n\n/**\n* Factory function which returns a caching object which returns an the Expres function\n* @param {string} [duration] timestring compatible duration to cache for (sets options.duration)\n* @param {Object} [options] Additional options to use, overrides emc.defaults\n* @see emc.defaults\n*/\nvar emc = function(duration, options) {\n\t// Argument mangling (sets `settings`) {{{\n\tvar settings = _.clone(emc.defaults);\n\tif (_.isObject(duration)) { // Given object\n\t\t_.merge(settings, duration);\n\t} else if (_.isString(duration) && _.isObject(options)) { // Given string + object, assume duration + settings\n\t\tsettings.duration = duration;\n\t\t_.merge(settings, options);\n\t} else if (_.isString(duration) && _.isUndefined(options)) { // Given string - assume its a duration\n\t\tsettings.duration = duration;\n\t} else {\n\t\tthrow new Error(`Unknown invokation method: ${typeof duration} ${typeof options}`);\n\t}\n\t// }}}\n\n\t// Settings parsing {{{\n\tsettings.durationMS = timestring(settings.duration) * 1000;\n\t// }}}\n\n\t// Make our caching object {{{\n\tsettings.cache = new cache(settings.cache);\n\t// }}}\n\n\t// Store the settings object in emc.tagStore if it has a valid tag/tags {{{\n\tvar tag = settings.tag || settings.tags;\n\tif (tag) {\n\t\tsettings.hashes = []; // Make storage for hashes (used to remember/forget future cache storage on .invalidate() calls)\n\t\t_.castArray(tag).forEach(tag => {\n\t\t\tif (! emc.tagStore[tag]) emc.tagStore[tag] = [];\n\t\t\temc.tagStore[tag].push(settings);\n\t\t});\n\t}\n\t// }}}\n\n\treturn function(req, res, next) {\n\t\t// Emit: routeCacheHit(req) {{{\n\t\temc.events.emit('routeCacheHit', req);\n\t\t// }}}\n\n\t\tvar hash = settings.cache.hash(settings.hashObject(req));\n\n\t\tsettings.cache.get(hash, settings.cacheFallback, (err, cacheRes) => {\n\t\t\tif (err) {\n\t\t\t\tconsole.log('Error while computing hash', err);\n\t\t\t\temc.events.emit('routeCacheHashError', err, req);\n\t\t\t\treturn res.sendStatus(500);\n\t\t\t} else if (settings.etag && req.headers.etag && cacheRes !== settings.cacheFallback && cacheRes.etag && cacheRes.etag == req.headers.etag) { // User is supplying an etag - compare it agasint the one we have cached\n\t\t\t\temc.events.emit('routeCacheEtag', req, {\n\t\t\t\t\tisFresh: false,\n\t\t\t\t\thash: hash,\n\t\t\t\t});\n\t\t\t\treturn res.sendStatus(304);\n\t\t\t} else if (cacheRes !== settings.cacheFallback) { // Got a hit\n\t\t\t\temc.events.emit('routeCacheExisting', req, {\n\t\t\t\t\tisFresh: false,\n\t\t\t\t\thash: hash,\n\t\t\t\t});\n\t\t\t\tif (settings.etag) res.set('etag', cacheRes.etag);\n\t\t\t\tres.send(cacheRes.content);\n\t\t\t} else { // No cache object - allow request to pass though\n\t\t\t\t// Replace res.json() with our own handler {{{\n\t\t\t\tvar oldJSONHandler = res.json;\n\t\t\t\tvar servedJSON;\n\t\t\t\tres.json = function() {\n\t\t\t\t\t// Are we storing hashes against tags? In which case we need to stash the hash we're about to set so we can forget it on demand {{{\n\t\t\t\t\tif (settings.hashes) settings.hashes.push(hash);\n\t\t\t\t\t// }}}\n\n\t\t\t\t\tvar etag = emc.generateEtag(hash, settings);\n\t\t\t\t\tsettings.cache.set(\n\t\t\t\t\t\thash,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontent: arguments[0],\n\t\t\t\t\t\t\tetag: etag,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tnew Date(Date.now() + settings.durationMS),\n\t\t\t\t\t\terr => {\n\t\t\t\t\t\t\temc.events.emit('routeCacheFresh', req, {\n\t\t\t\t\t\t\t\tisFresh: true,\n\t\t\t\t\t\t\t\thash: hash,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (settings.etag) res.set('etag', etag);\n\t\t\t\t\t\t\toldJSONHandler.apply(this, arguments); // Let the downstream serve the data as needed\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t\t// }}}\n\n\t\t\t\treturn next();\n\t\t\t}\n\t\t});\n\t};\n};\n\n\n/**\n* Default options to use when initalizing new EMC factories\n* @var {Object}\n* @param {string} [defaults.duration] Timestring compatible duration to cache the response for\n* @param {Object} [defaults.cache] Options passed to @momsfriendlydevco/cache to initalize a cache object\n* @param {function} [defaults.hashObject] Method which returns the hashable object to use as the key in the cache. Defaults to hashing `req.{method,path,query,body}`\n* @param {boolean} [defaults.etag] Transmit an etag header when sending the cache to the client\n*/\nemc.defaults = {\n\tduration: '1h', // Human parsable duration\n\tdurationMS: 1000 * 60 * 60, // Parsed version of duration in MS\n\tcache: {}, // Options passed to @momsfriendlydevco/cache\n\thashObject: req => ({ // How to extract the request keys to hash\n\t\tmethod: req.method,\n\t\tpath: req.path,\n\t\tquery: req.query,\n\t\tbody: req.body,\n\t}),\n\tcacheFallback: '!!NOCACHE!!', // Dummy value used via @momsfriendlydevco/cache that ensures the return has no value (as the undefined is a valid return for a cache result)\n\tetag: true,\n};\n\n\n/**\n* Invalidate all matching tags - effectively clearing the internal cache for anything matching the query\n* @param {array|string} ...tags The tag or tag strings to match against\n* @return {number} The number of cache hashes cleared (this does not necessarily equal the number of items removed from memory as some of the cleared items may already have expired depending on the individual cache modules used)\n*/\nemc.invalidate = (...tags) => {\n\tvar cleared = 0;\n\n\ttags.forEach(tag => {\n\t\tif (!emc.tagStore[tag]) return; // Tag doesn't exist anyway\n\t\temc.tagStore[tag].forEach(store => {\n\t\t\tif (!store.hashes) return;\n\t\t\tstore.hashes.forEach(hash => {\n\t\t\t\temc.events.emit('routeCacheInvalidate', tag, hash);\n\t\t\t\tstore.cache.unset(hash);\n\t\t\t\tcleared++;\n\t\t\t});\n\t\t});\n\t});\n\n\treturn cleared;\n};\n\n\n/**\n* Generate a 'fresh' etag based on the given hash result\n* This should take the hash, add some entropy and return the result\n* This function can be replaed with another entropy generating system if required\n* @param {string} hash The hash generated for the request\n* @param {Object} settings Settings objected used by the upstream hashing component\n* @return {string} The new etag to use\n*/\nemc.generateEtag = (hash, settings) => {\n\treturn settings.cache.hash(hash + '-' + Date.now());\n};\n\n\n/**\n* Storage for EMC objects against tags\n* Each key is the tag which contains an array of matching EMC objects against that tag\n* @var {Object}\n*/\nemc.tagStore = {};\n\n\n/**\n* Bindable EventEmitter which can receive EMC events\n* @var {EventEmitter}\n*/\nemc.events = new events.EventEmitter();\n\nmodule.exports = emc;\n"]}