UNPKG

express-aggressive-cache

Version:
1 lines 7.62 kB
!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var r=t();for(var n in r)("object"==typeof exports?exports:e)[n]=r[n]}}(global,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var s=t[n]={i:n,l:!1,exports:{}};return e[n].call(s.exports,s,s.exports,r),s.l=!0,s.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)r.d(n,s,function(t){return e[t]}.bind(null,s));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=8)}([function(e,t){},function(e,t){e.exports=require("url")},function(e,t){e.exports=require("nanoid")},function(e,t){e.exports=require("lru-cache")},function(e,t){e.exports=require("cache-control-parser")},function(e,t){e.exports=require("crypto")},function(e,t){e.exports=require("normalize-url")},function(e,t){e.exports=require("redlock")},function(e,t,r){"use strict";r.r(t);var n=r(2),s=r(3),a=r.n(s);const i={max:void 0},o=e=>{const{max:t}={...i,...e};return()=>{const e=new a.a({max:t});return{del:async t=>{e.del(t)},expire:async(t,r)=>{const n=e.peek(t);void 0!==n&&(r<=0?e.del(t):e.set(t,n,1e3*r))},get:async t=>e.get(t),has:async t=>{for(const r of t)if(!e.has(r))return!1;return!0},set:async(t,r,n)=>{e.set(t,r,n?1e3*n:void 0)}}}};var u=r(4),c=r.n(u),f=r(5),h=r.n(f);class d{constructor(){this.isRunning=!1,this.isDestroyed=!1,this.tasks=[],this.push=e=>this.isDestroyed?this:(this.tasks.push(e),this),this.run=async()=>{this.isDestroyed||this.isRunning||this.privateRun()},this.destroy=async()=>{this.tasks=[],this.isRunning=!1,this.isDestroyed=!0},this.privateRun=async()=>{this.isDestroyed||(this.tasks.length?(this.isRunning=!0,await this.tasks[0](),this.tasks.shift(),await this.privateRun()):this.isRunning=!1)}}}const l=(e,t)=>`${e}:${(e=>{return h.a.createHash("sha256").update(e).digest("hex")})(t)}`;var g=r(1),y=r(6),p=r.n(y);const w=({req:e})=>{const t=(e=>e.replace(/\.\./g,"_DOTDOT_"))(e.originalUrl),r=new g.URL(t,"http://localhost").toString(),{origin:n}=new g.URL(r);return(e=>e.replace(/_DOTDOT_/g,".."))((e=>p()(e,{removeQueryParameters:[/^utm_\w+/i]}))(r).replace(n,"").replace("/?",""))},v={maxAge:void 0,store:o(),getCacheKey:w,getCacheTag:void 0,onCacheHit:({res:e})=>{e.setHeader("x-cache","HIT")},onCacheMiss:({res:e})=>{e.setHeader("x-cache","MISS")}};var x=r(7),m=r.n(x);const k={prefix:"cache"},C=Math.max(...["string","buffer","object"].map(e=>e.length)),b=(e,t)=>[t,e].filter(e=>e).join(":"),S=e=>{const{client:t,prefix:r}={...k,...e},n=new m.a([t],{retryCount:0});return()=>{return{del:async e=>{await t.del(b(e,r))},expire:async(e,n)=>{await t.expire(b(e,r),n)},get:async e=>{const n=b(e,r),s=await t.getBuffer(n);if(null===s)return;const a=s.subarray(0,C).toString("utf8"),i=s.subarray(C,s.length);if("object"===a)return JSON.parse(i.toString("utf8"));if("string"===a)return i.toString("utf8");if("buffer"===a)return i;throw new Error("Unknown data type")},has:async e=>{const n=e.map(e=>b(e,r));return!(await Promise.all(n.map(async e=>1===await t.exists(e)))).includes(!1)},set:async(e,s,a)=>{let i;try{i=await n.lock(b(`locks:${e}`,r),5e3)}catch(e){if("LockError"===e.name)return;throw e}const o=b(e,r),u=((e,t)=>{let r,n;if(Buffer.isBuffer(t)?(r="buffer",n=t):"string"==typeof t?(r="string",n=Buffer.from(t,"utf8")):"object"==typeof t&&(r="object",n=Buffer.from(JSON.stringify(t),"utf8")),!r)throw new Error("unsupported data type");if(!n)throw new Error("unexpected error");const s=Buffer.from(r,"utf8");return Buffer.concat([s,n])})(0,s);a?await t.set(o,u,"EX",a):await t.set(o,u),await i.unlock()}}}};var q=r(0);r.d(t,"memoryStore",(function(){return o})),r.d(t,"redisStore",(function(){return S})),r.d(t,"GetCacheKey",(function(){return q.GetCacheKey})),r.d(t,"GetCacheTag",(function(){return q.GetCacheTag})),r.d(t,"OnCache",(function(){return q.OnCache})),r.d(t,"PurgeFunction",(function(){return q.PurgeFunction}));t.default=e=>{const{debug:t,maxAge:r,store:s,getCacheKey:a,getCacheTag:i,onCacheHit:o,onCacheMiss:u}={...v,...e},f=(...e)=>{t&&console.log(...e)},h=s(),g=s(),y=s(),p=async(e,t,r)=>{t.status(r.statusCode),t.set(r.headers),await o({req:e,res:t}),await(async(e,t)=>{for(const r of t.chunks){const t=await g.get(r);if(void 0===t)throw new Error(`missing chunk: ${r}`);e.write(t)}})(t,r),t.end()},x=async(e,t,r,n,s)=>{f("MISS - key not found:",s),await u({req:e,res:t});const a=t.write,i=t.end;t.write=function(...e){return n(e[0]),a.call(this,...e)},t.end=function(...e){return n(e[0]),i.call(this,...e)},t.on("finish",r)},m=(e,t,s)=>{const a=Object(n.nanoid)(),o=new d;return{onWrite:e=>{void 0!==e&&o.push(()=>(async({requestId:e,chunk:t,res:r,cacheKey:n,defaultMaxAge:s,log:a,responseBucket:i,chunkBucket:o,chunkQueue:u})=>{const f=`${r.getHeader("Cache-Control")||""}`,h=c()(f);if(!(e=>{const{noStore:t,isPrivate:r,maxAge:n,sharedMaxAge:s}=e;if(t)return!1;if(r)return!1;if(void 0!==s){if(0===s)return!1}else if(0===n)return!1;return!0})(h))return;const d=((e,t)=>e.sharedMaxAge||e.maxAge||t)(h,s),g=d?d+60:void 0,y=await i.get(n);if(y)if(y.requestId!==e)a("ALREADY CACHING:",n),await u.destroy();else{const e=l(n,t);try{var p,w;await o.set(e,t,g),null===(p=r.aggressiveCache)||void 0===p||null===(w=p.chunks)||void 0===w||w.push(e),a("CACHED CHUNK:",n)}catch(e){a(e),await u.destroy()}}else{const s=l(n,t);try{var v,x;await Promise.all([i.set(n,{requestId:e,chunks:[],statusCode:200,headers:{},isSealed:!1,maxAge:d},10),o.set(s,t,g)]),null===(v=r.aggressiveCache)||void 0===v||null===(x=v.chunks)||void 0===x||x.push(s),a("CACHED CHUNK (NEW CACHE ENTRY):",n)}catch(e){a(e),await u.destroy()}}})({requestId:a,chunk:e,res:t,cacheKey:s,defaultMaxAge:r,log:f,responseBucket:h,chunkBucket:g,chunkQueue:o})).run()},onFinish:async()=>{await(async(e,t,r)=>{if(i){const n=await i({req:e,res:t});void 0!==n&&await y.set(n,r)}})(e,t,s),o.push(()=>(async({requestId:e,cacheKey:t,res:r,log:n,responseBucket:s})=>{var a;const i=null===(a=r.aggressiveCache)||void 0===a?void 0:a.chunks;if(!(null==i?void 0:i.length))return;const o=await s.get(t);if((null==o?void 0:o.requestId)!==e)return;const u={...r.getHeaders()},c=r.statusCode;delete u["set-cookie"];try{await s.set(t,{...o,chunks:i,statusCode:c,headers:u,isSealed:!0},o.maxAge),n("SEALED CACHE:",t)}catch(e){n(e)}})({requestId:a,cacheKey:s,res:t,log:f,responseBucket:h})).run()}}};return{purge:async e=>{const t=await y.get(e);if(void 0!==t){await y.del(e);const r=await h.get(t);void 0!==r&&(await h.del(t),(async(e,t)=>{t.forEach(t=>{e.expire(t,60)})})(g,r.chunks))}},middleware:async(e,t,r)=>{if(await(async(e,t)=>"GET"!==e.method&&(f("MISS - not a GET request"),await u({req:e,res:t}),!0))(e,t))return r();const n=w({req:e}),s=await a({req:e,res:t,normalizedPath:n});t.aggressiveCache={chunks:[]};const{onFinish:i,onWrite:o}=m(e,t,s),c=await h.get(s);await(async(e,t,r,n)=>{if(null==e?void 0:e.isSealed){if(await g.has(e.chunks))return f("HIT:",n),await p(t,r,e),!0;f("chunk missing")}return!1})(c,e,t,s)||(await x(e,t,i,o,s),r())}}}}])}));