UNPKG

@rescale/nemo

Version:

A middleware composition library for Next.js applications that allows you to organize and chain middleware functions based on URL patterns.

2 lines (1 loc) 7.85 kB
import{a as C}from"./chunk-M7IZWBOS.js";import{d as E}from"./chunk-WNRK2FI2.js";import{a as _}from"./chunk-76CL4F3Q.js";import"./chunk-6F4PWJZI.js";import{a as A}from"./chunk-BJCGO5DD.js";import{a as S}from"./chunk-AEIWJISK.js";import"./chunk-JRB5LDYT.js";import{pathToRegexp as F}from"path-to-regexp";import{NextResponse as v}from"next/server";var b=class{config;middlewares;globalMiddleware;logger;storage;storageFactory;constructor(e,t,r){this.config={debug:!1,silent:!1,enableTiming:!1,...r},this.middlewares=e,this.globalMiddleware=t,this.logger=new _(this.config.debug||!1),this.config.storage?typeof this.config.storage=="function"?(this.storage=this.config.storage,this.storageFactory=!0):(this.storage=this.config.storage,this.storageFactory=!1):(this.storage=new S,this.storageFactory=!1);let i=this.storageFactory?void 0:this.storage;this.logger.log("Initialized with config:",{debug:this.config.debug,silent:this.config.silent,enableTiming:this.config.enableTiming,middlewareCount:Object.keys(e).length,hasGlobalMiddleware:!!t,storageAdapter:i?i.constructor.name:"factory function",storageIsFactory:this.storageFactory})}computePathMatch(e,t,r=!1){if(e==="/")return r?t==="/"||t==="":!0;let i,a;try{i=decodeURIComponent(t)}catch(n){this.logger.error(`Error decoding path ${t}:`,n),i=t}try{a=decodeURIComponent(e)}catch(n){this.logger.error(`Error decoding pattern ${e}:`,n),a=e}if(!e.includes(":")&&!e.includes("*")&&!e.includes("("))return r?i===a:i===a||i.startsWith(a+"/");try{return F(a,[],{end:r,strict:!1,sensitive:!1}).test(i)}catch(n){return this.logger.error(`Error creating regexp for pattern ${a}:`,n),!1}}getHeadersDiff(e,t){let r=[],i=new Set;return t.forEach((a,n)=>{i.add(n);let l=e.get(n);(!l||l!==a)&&r.push([n,a])}),e.forEach((a,n)=>{i.has(n)||r.push([n,""])}),Object.fromEntries(r)}attachMetadata(e,t){let r=e;return r.__nemo=t,r}createFullPattern(e,t){return t?e==="/"?t:`${t}${e}`:e}propagateQueue(e){let t=e.nextUrl.pathname;this.logger.log("Processing request for path:",t);let r=[],i=new Set,a=[];this.globalMiddleware?.before&&(a=Array.isArray(this.globalMiddleware.before)?this.globalMiddleware.before:[this.globalMiddleware.before]);let n=a.map((o,s)=>this.attachMetadata(o,{chain:"before",index:s,pathname:t,routeKey:"global:before"}));r.push(...n);let l=[],f=this.middlewares["/"];if(f&&(t==="/"||t==="")){let o=f;i.add("/"),typeof o=="function"||Array.isArray(o)?l.push({pattern:"/",middleware:o,nestLevel:0,isExactMatch:!0}):typeof o=="object"&&o!==null&&"middleware"in o&&l.push({pattern:"/",middleware:o.middleware,nestLevel:0,isExactMatch:!0})}let u=(o,s="",p=0)=>{let y=(c,d)=>!(c==="middleware"||c==="/"&&(s!==""||i.has("/")||t!=="/"&&t!=="")||i.has(d)),x=(c,d,h)=>{l.push({pattern:c,middleware:d,nestLevel:p,isExactMatch:h})};Object.entries(o).forEach(([c,d])=>{let h=this.createFullPattern(c,s);if(!y(c,h))return;i.add(h);let N=this.computePathMatch(h,t,!0),T=typeof d=="object"&&d!==null&&!Array.isArray(d)&&Object.keys(d).some(w=>w!=="middleware"),R=!1;if(p===0&&!T?R=N:R=this.computePathMatch(h,t,!1),R&&(typeof d=="function"||Array.isArray(d)?x(h,d,N):typeof d=="object"&&d!==null&&"middleware"in d&&x(h,d.middleware,N)),T){let w={...d};delete w.middleware,Object.keys(w).length>0&&u(w,h,p+1)}})};u(this.middlewares),l.sort((o,s)=>o.pattern==="/"?-1:s.pattern==="/"?1:o.nestLevel!==s.nestLevel?o.nestLevel-s.nestLevel:o.isExactMatch!==s.isExactMatch?o.isExactMatch?1:-1:s.pattern.length-o.pattern.length),l.forEach(({pattern:o,middleware:s,nestLevel:p})=>{Array.isArray(s)?s.forEach((y,x)=>{r.push(this.attachMetadata(y,{chain:"main",index:x,pathname:t,routeKey:o,nestLevel:p}))}):typeof s=="function"&&r.push(this.attachMetadata(s,{chain:"main",index:r.length-n.length,pathname:t,routeKey:o,nestLevel:p}))});let m=[];this.globalMiddleware?.after&&(m=Array.isArray(this.globalMiddleware.after)?this.globalMiddleware.after:[this.globalMiddleware.after]);let g=m.map((o,s)=>this.attachMetadata(o,{chain:"after",index:s,pathname:t,routeKey:"global:after"}));return r.push(...g),this.logger.log("Generated middleware queue:",{total:r.length,before:n.length,main:r.length-n.length-g.length,after:g.length}),r}async processQueue(e,t,r){let i=new Headers(t.headers),a=this.initializeTimingTracking();this.logger.log("Starting middleware queue processing");let n=await this.executeMiddlewareChain(e,t,r,a);return this.logFinalTiming(a),n||this.createFinalResponse(i,t)}initializeTimingTracking(){return this.config.enableTiming?{before:0,main:0,after:0}:null}shouldSkipMiddleware(e,t,r,i){return!!(r&&e===t||e==="after"&&i.shouldSkipAfterChain())}handleChainTransition(e,t,r){return!e||e===t?{newChain:t,shouldResetSkip:!1}:t!==void 0?(r.resetSkip(),{newChain:e,shouldResetSkip:!0}):{newChain:e,shouldResetSkip:!1}}processMiddlewareResult(e,t,r,i){return this.isTerminatingResult(e)?Promise.resolve({shouldTerminate:!0,shouldSkipChain:!1}):(this.applyHeadersToRequest(e,t),r.shouldSkip()?(this.logger.log("Skipping remaining middlewares in chain:",{chain:i}),Promise.resolve({shouldTerminate:!1,shouldSkipChain:!0})):Promise.resolve({shouldTerminate:!1,shouldSkipChain:!1}))}async executeMiddlewareChain(e,t,r,i){let a,n=!1;for(let l of e)try{let f=l.__nemo?.chain,u=this.handleChainTransition(f,a,r);if(a=u.newChain,u.shouldResetSkip&&(n=!1),this.shouldSkipMiddleware(f,a,n,r))continue;let m=await this.executeMiddleware(l,t,r,i),g=await this.processMiddlewareResult(m,t,r,f);if(g.shouldTerminate)return m;g.shouldSkipChain&&(n=!0)}catch(f){let u=await this.handleMiddlewareError(f,l);if(u)return u}return null}async executeMiddleware(e,t,r,i){let a=this.config.enableTiming?performance.now():0;this.logMiddlewareExecution(e),e.__nemo&&r.setCurrentMetadata(e.__nemo);let n=await e(t,r);return this.updateTimingStats(a,e,i),n}logMiddlewareExecution(e){this.logger.log("Executing middleware:",{chain:e.__nemo?.chain,index:e.__nemo?.index,pathname:e.__nemo?.pathname,routeKey:e.__nemo?.routeKey,nestLevel:e.__nemo?.nestLevel})}isTerminatingResult(e){return e?!(e instanceof v&&!e.headers.has("x-middleware-rewrite")&&!e.headers.has("Location")&&!e.headers.get("content-type")?.includes("application/json")):!1}applyHeadersToRequest(e,t){e instanceof v&&e.headers.forEach((r,i)=>{if(i.startsWith("x-middleware-request-")){let a=i.replace("x-middleware-request-","");t.headers.set(a,r)}else i.startsWith("x-middleware-")||(i.toLowerCase()==="set-cookie"?t.headers.append(i,r):t.headers.set(i,r))})}updateTimingStats(e,t,r){if(this.config.enableTiming&&r&&t.__nemo?.chain){let i=performance.now()-e,a=t.__nemo.chain;r[a]+=i,this.logger.log(`Middleware execution time: ${i.toFixed(2)}ms`)}}async handleMiddlewareError(e,t){if(this.logger.error("Middleware execution failed:",{error:e,metadata:t.__nemo}),this.config.errorHandler){let r=await this.config.errorHandler(e,t.__nemo);if(r)return this.logger.log("Error handled by custom handler"),r}if(!this.config.silent)throw new C("Middleware execution failed",t.__nemo,e);return null}logFinalTiming(e){if(this.config.enableTiming&&e){let t=e.before+e.main+e.after;this.logger.log("Chain timing summary:",{before:`${e.before.toFixed(2)}ms`,main:`${e.main.toFixed(2)}ms`,after:`${e.after.toFixed(2)}ms`,total:`${t.toFixed(2)}ms`})}}createFinalResponse(e,t){let r=new Headers(t.headers),i=this.getHeadersDiff(e,r);return this.logger.log("Headers modified:",i),v.next({headers:new Headers(i),request:{headers:r}})}middleware=async(e,t)=>{let r=this.storageFactory?this.storage():this.storage,i=E.from(t,{},r),a=this.propagateQueue(e);return this.processQueue(a,e,i)}};function G(M,e,t){return console.warn("[NEMO] `createMiddleware` is deprecated. Use `createNEMO` instead."),new b(M,e,t).middleware}function O(M,e,t){return new b(M,e,t).middleware}export{b as NEMO,E as NemoEvent,C as NemoMiddlewareError,A as areResponsesEqual,G as createMiddleware,O as createNEMO};