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) 6.64 kB
import{a as N}from"./chunk-M7IZWBOS.js";import{d as y}from"./chunk-YO567KVC.js";import{a as _}from"./chunk-76CL4F3Q.js";import"./chunk-6F4PWJZI.js";import{a as T}from"./chunk-BJCGO5DD.js";import{a as A}from"./chunk-AEIWJISK.js";import"./chunk-JRB5LDYT.js";import{NextResponse as R}from"next/server";import{pathToRegexp as F}from"path-to-regexp";var M=class{config;middlewares;globalMiddleware;logger;storage;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?this.storage=typeof this.config.storage=="function"?this.config.storage():this.config.storage:this.storage=new A,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:this.storage.constructor.name})}computePathMatch(e,t,r=!1){if(e==="/")return r?t==="/"||t==="":!0;let i,n;try{i=decodeURIComponent(t)}catch(a){this.logger.error(`Error decoding path ${t}:`,a),i=t}try{n=decodeURIComponent(e)}catch(a){this.logger.error(`Error decoding pattern ${e}:`,a),n=e}if(!e.includes(":")&&!e.includes("*")&&!e.includes("("))return r?i===n:i===n||i.startsWith(n+"/");try{return F(n,[],{end:r,strict:!1,sensitive:!1}).test(i)}catch(a){return this.logger.error(`Error creating regexp for pattern ${n}:`,a),!1}}getHeadersDiff(e,t){let r=[],i=new Set;return t.forEach((n,a)=>{i.add(a);let l=e.get(a);(!l||l!==n)&&r.push([a,n])}),e.forEach((n,a)=>{i.has(a)||r.push([a,""])}),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,n=[];this.globalMiddleware?.before&&(n=Array.isArray(this.globalMiddleware.before)?this.globalMiddleware.before:[this.globalMiddleware.before]);let a=n.map((o,s)=>this.attachMetadata(o,{chain:"before",index:s,pathname:t,routeKey:"global:before"}));r.push(...a);let l=[];if(this.middlewares["/"]&&(t==="/"||t==="")){let o=this.middlewares["/"];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 E=(o,s="",g=0)=>{let p=(f,d)=>!(f==="middleware"||f==="/"&&(s!==""||i.has("/")||t!=="/"&&t!=="")||i.has(d)),m=(f,d,c)=>{l.push({pattern:f,middleware:d,nestLevel:g,isExactMatch:c})};Object.entries(o).forEach(([f,d])=>{let c=this.createFullPattern(f,s);if(!p(f,c))return;i.add(c);let x=this.computePathMatch(c,t,!0),C=typeof d=="object"&&d!==null&&!Array.isArray(d)&&Object.keys(d).some(h=>h!=="middleware"),b=!1;if(g===0&&!C?b=x:b=this.computePathMatch(c,t,!1),b&&(typeof d=="function"||Array.isArray(d)?m(c,d,x):typeof d=="object"&&d!==null&&"middleware"in d&&m(c,d.middleware,x)),C){let h={...d};delete h.middleware,Object.keys(h).length>0&&E(h,c,g+1)}})};E(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:g})=>{Array.isArray(s)?s.forEach((p,m)=>{r.push(this.attachMetadata(p,{chain:"main",index:m,pathname:t,routeKey:o,nestLevel:g}))}):typeof s=="function"&&r.push(this.attachMetadata(s,{chain:"main",index:r.length-a.length,pathname:t,routeKey:o,nestLevel:g}))});let v=[];this.globalMiddleware?.after&&(v=Array.isArray(this.globalMiddleware.after)?this.globalMiddleware.after:[this.globalMiddleware.after]);let w=v.map((o,s)=>this.attachMetadata(o,{chain:"after",index:s,pathname:t,routeKey:"global:after"}));return r.push(...w),this.logger.log("Generated middleware queue:",{total:r.length,before:a.length,main:r.length-a.length-w.length,after:w.length}),r}async processQueue(e,t,r){let i=new Headers(t.headers),n=this.initializeTimingTracking();this.logger.log("Starting middleware queue processing");let a=await this.executeMiddlewareChain(e,t,r,n);return this.logFinalTiming(n),a||this.createFinalResponse(i,t)}initializeTimingTracking(){return this.config.enableTiming?{before:0,main:0,after:0}:null}async executeMiddlewareChain(e,t,r,i){for(let n of e)try{let a=await this.executeMiddleware(n,t,r,i);if(this.isTerminatingResult(a))return a;this.applyHeadersToRequest(a,t)}catch(a){let l=await this.handleMiddlewareError(a,n);if(l)return l}return null}async executeMiddleware(e,t,r,i){let n=this.config.enableTiming?performance.now():0;this.logMiddlewareExecution(e),e.__nemo&&r.setCurrentMetadata(e.__nemo);let a=await e(t,r);return this.updateTimingStats(n,e,i),a}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 R&&!e.headers.has("x-middleware-rewrite")&&!e.headers.has("Location")&&!e.headers.get("content-type")?.includes("application/json")):!1}applyHeadersToRequest(e,t){e instanceof R&&e.headers.forEach((r,i)=>{i.startsWith("x-middleware-")||t.headers.set(i,r)})}updateTimingStats(e,t,r){if(this.config.enableTiming&&r&&t.__nemo?.chain){let i=performance.now()-e,n=t.__nemo.chain;r[n]+=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 N("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),R.next({headers:new Headers(i),request:t})}middleware=async(e,t)=>{let r=y.from(t),i=this.propagateQueue(e);return this.processQueue(i,e,r)}};function O(u,e,t){return console.warn("[NEMO] `createMiddleware` is deprecated. Use `createNEMO` instead."),new M(u,e,t).middleware}function K(u,e,t){return new M(u,e,t).middleware}export{M as NEMO,y as NemoEvent,N as NemoMiddlewareError,T as areResponsesEqual,O as createMiddleware,K as createNEMO};